X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Faarch64-linux-tdep.c;h=d8476c907e80cb34af2c2e4a70a1c6e0ba80ed20;hb=79cc99f69b97e8bc6aa109c937095d34ecdf3762;hp=7f2193f2fa5781ef4ee1f78828f749efa5671f8b;hpb=0f83012ea0fb84d86d2a84a5feb51c0d63f0b7eb;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index 7f2193f2fa..d8476c907e 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -1,6 +1,6 @@ /* Target-dependent code for GNU/Linux AArch64. - Copyright (C) 2009-2019 Free Software Foundation, Inc. + Copyright (C) 2009-2021 Free Software Foundation, Inc. Contributed by ARM Ltd. This file is part of GDB. @@ -21,7 +21,6 @@ #include "defs.h" #include "gdbarch.h" -#include "arch-utils.h" #include "glibc-tdep.h" #include "linux-tdep.h" #include "aarch64-tdep.h" @@ -31,12 +30,12 @@ #include "symtab.h" #include "tramp-frame.h" #include "trad-frame.h" +#include "target/target.h" +#include "expop.h" -#include "inferior.h" #include "regcache.h" #include "regset.h" -#include "cli/cli-utils.h" #include "stap-probe.h" #include "parser-defs.h" #include "user-regs.h" @@ -45,8 +44,6 @@ #include "record-full.h" #include "linux-record.h" -#include "auxv.h" -#include "elf/common.h" /* Signal frame handling. @@ -184,6 +181,93 @@ read_aarch64_ctx (CORE_ADDR ctx_addr, enum bfd_endian byte_order, return magic; } +/* Given CACHE, use the trad_frame* functions to restore the FPSIMD + registers from a signal frame. + + VREG_NUM is the number of the V register being restored, OFFSET is the + address containing the register value, BYTE_ORDER is the endianness and + HAS_SVE tells us if we have a valid SVE context or not. */ + +static void +aarch64_linux_restore_vreg (struct trad_frame_cache *cache, int num_regs, + int vreg_num, CORE_ADDR offset, + enum bfd_endian byte_order, bool has_sve) +{ + /* WARNING: SIMD state is laid out in memory in target-endian format. + + So we have a couple cases to consider: + + 1 - If the target is big endian, then SIMD state is big endian, + requiring a byteswap. + + 2 - If the target is little endian, then SIMD state is little endian, so + no byteswap is needed. */ + + if (byte_order == BFD_ENDIAN_BIG) + { + gdb_byte buf[V_REGISTER_SIZE]; + + if (target_read_memory (offset, buf, V_REGISTER_SIZE) != 0) + { + size_t size = V_REGISTER_SIZE/2; + + /* Read the two halves of the V register in reverse byte order. */ + CORE_ADDR u64 = extract_unsigned_integer (buf, size, + byte_order); + CORE_ADDR l64 = extract_unsigned_integer (buf + size, size, + byte_order); + + /* Copy the reversed bytes to the buffer. */ + store_unsigned_integer (buf, size, BFD_ENDIAN_LITTLE, l64); + store_unsigned_integer (buf + size , size, BFD_ENDIAN_LITTLE, u64); + + /* Now we can store the correct bytes for the V register. */ + trad_frame_set_reg_value_bytes (cache, AARCH64_V0_REGNUM + vreg_num, + {buf, V_REGISTER_SIZE}); + trad_frame_set_reg_value_bytes (cache, + num_regs + AARCH64_Q0_REGNUM + + vreg_num, {buf, Q_REGISTER_SIZE}); + trad_frame_set_reg_value_bytes (cache, + num_regs + AARCH64_D0_REGNUM + + vreg_num, {buf, D_REGISTER_SIZE}); + trad_frame_set_reg_value_bytes (cache, + num_regs + AARCH64_S0_REGNUM + + vreg_num, {buf, S_REGISTER_SIZE}); + trad_frame_set_reg_value_bytes (cache, + num_regs + AARCH64_H0_REGNUM + + vreg_num, {buf, H_REGISTER_SIZE}); + trad_frame_set_reg_value_bytes (cache, + num_regs + AARCH64_B0_REGNUM + + vreg_num, {buf, B_REGISTER_SIZE}); + + if (has_sve) + trad_frame_set_reg_value_bytes (cache, + num_regs + AARCH64_SVE_V0_REGNUM + + vreg_num, {buf, V_REGISTER_SIZE}); + } + return; + } + + /* Little endian, just point at the address containing the register + value. */ + trad_frame_set_reg_addr (cache, AARCH64_V0_REGNUM + vreg_num, offset); + trad_frame_set_reg_addr (cache, num_regs + AARCH64_Q0_REGNUM + vreg_num, + offset); + trad_frame_set_reg_addr (cache, num_regs + AARCH64_D0_REGNUM + vreg_num, + offset); + trad_frame_set_reg_addr (cache, num_regs + AARCH64_S0_REGNUM + vreg_num, + offset); + trad_frame_set_reg_addr (cache, num_regs + AARCH64_H0_REGNUM + vreg_num, + offset); + trad_frame_set_reg_addr (cache, num_regs + AARCH64_B0_REGNUM + vreg_num, + offset); + + if (has_sve) + trad_frame_set_reg_addr (cache, num_regs + AARCH64_SVE_V0_REGNUM + + vreg_num, offset); + +} + /* Implement the "init" method of struct tramp_frame. */ static void @@ -336,27 +420,16 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self, /* If there was no SVE section then set up the V registers. */ if (sve_regs == 0) - for (int i = 0; i < 32; i++) - { - CORE_ADDR offset = (fpsimd + AARCH64_FPSIMD_V0_OFFSET + { + for (int i = 0; i < 32; i++) + { + CORE_ADDR offset = (fpsimd + AARCH64_FPSIMD_V0_OFFSET + (i * AARCH64_FPSIMD_VREG_SIZE)); - trad_frame_set_reg_addr (this_cache, AARCH64_V0_REGNUM + i, offset); - trad_frame_set_reg_addr (this_cache, - num_regs + AARCH64_Q0_REGNUM + i, offset); - trad_frame_set_reg_addr (this_cache, - num_regs + AARCH64_D0_REGNUM + i, offset); - trad_frame_set_reg_addr (this_cache, - num_regs + AARCH64_S0_REGNUM + i, offset); - trad_frame_set_reg_addr (this_cache, - num_regs + AARCH64_H0_REGNUM + i, offset); - trad_frame_set_reg_addr (this_cache, - num_regs + AARCH64_B0_REGNUM + i, offset); - if (tdep->has_sve ()) - trad_frame_set_reg_addr (this_cache, - num_regs + AARCH64_SVE_V0_REGNUM + i, - offset); - } + aarch64_linux_restore_vreg (this_cache, num_regs, i, offset, + byte_order, tdep->has_sve ()); + } + } } trad_frame_set_id (this_cache, frame_id_build (sp, func)); @@ -452,7 +525,7 @@ aarch64_linux_core_read_vq (struct gdbarch *gdbarch, bfd *abfd) return 0; } - size_t size = bfd_section_size (abfd, sve_section); + size_t size = bfd_section_size (sve_section); /* Check extended state size. */ if (size < SVE_HEADER_SIZE) @@ -586,7 +659,7 @@ aarch64_linux_collect_sve_regset (const struct regset *regset, size - SVE_HEADER_SIZE); } -/* Implement the "regset_from_core_section" gdbarch method. */ +/* Implement the "iterate_over_regset_sections" gdbarch method. */ static void aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, @@ -681,7 +754,7 @@ aarch64_stap_is_single_operand (struct gdbarch *gdbarch, const char *s) It returns one if the special token has been parsed successfully, or zero if the current token is not considered special. */ -static int +static expr::operation_up aarch64_stap_parse_special_token (struct gdbarch *gdbarch, struct stap_parse_info *p) { @@ -692,11 +765,9 @@ aarch64_stap_parse_special_token (struct gdbarch *gdbarch, char *endp; /* Used to save the register name. */ const char *start; - char *regname; int len; int got_minus = 0; long displacement; - struct stoken str; ++tmp; start = tmp; @@ -706,17 +777,14 @@ aarch64_stap_parse_special_token (struct gdbarch *gdbarch, ++tmp; if (*tmp != ',') - return 0; + return {}; len = tmp - start; - regname = (char *) alloca (len + 2); + std::string regname (start, len); - strncpy (regname, start, len); - regname[len] = '\0'; - - if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1) + if (user_reg_map_name_to_regnum (gdbarch, regname.c_str (), len) == -1) error (_("Invalid register name `%s' on expression `%s'."), - regname, p->saved_arg); + regname.c_str (), p->saved_arg); ++tmp; tmp = skip_spaces (tmp); @@ -734,50 +802,44 @@ aarch64_stap_parse_special_token (struct gdbarch *gdbarch, ++tmp; if (!isdigit (*tmp)) - return 0; + return {}; displacement = strtol (tmp, &endp, 10); tmp = endp; /* Skipping last `]'. */ if (*tmp++ != ']') - return 0; + return {}; + p->arg = tmp; + + using namespace expr; /* The displacement. */ - write_exp_elt_opcode (&p->pstate, OP_LONG); - write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long); - write_exp_elt_longcst (&p->pstate, displacement); - write_exp_elt_opcode (&p->pstate, OP_LONG); + struct type *long_type = builtin_type (gdbarch)->builtin_long; if (got_minus) - write_exp_elt_opcode (&p->pstate, UNOP_NEG); + displacement = -displacement; + operation_up disp = make_operation (long_type, + displacement); /* The register name. */ - write_exp_elt_opcode (&p->pstate, OP_REGISTER); - str.ptr = regname; - str.length = len; - write_exp_string (&p->pstate, str); - write_exp_elt_opcode (&p->pstate, OP_REGISTER); + operation_up reg + = make_operation (std::move (regname)); - write_exp_elt_opcode (&p->pstate, BINOP_ADD); + operation_up sum + = make_operation (std::move (reg), std::move (disp)); /* Casting to the expected type. */ - write_exp_elt_opcode (&p->pstate, UNOP_CAST); - write_exp_elt_type (&p->pstate, lookup_pointer_type (p->arg_type)); - write_exp_elt_opcode (&p->pstate, UNOP_CAST); - - write_exp_elt_opcode (&p->pstate, UNOP_IND); - - p->arg = tmp; + struct type *arg_ptr_type = lookup_pointer_type (p->arg_type); + sum = make_operation (std::move (sum), + arg_ptr_type); + return make_operation (std::move (sum)); } - else - return 0; - - return 1; + return {}; } /* AArch64 process record-replay constructs: syscall, signal etc. */ -struct linux_record_tdep aarch64_linux_record_tdep; +static linux_record_tdep aarch64_linux_record_tdep; /* Enum that defines the AArch64 linux specific syscall identifiers used for process record/replay. */ @@ -1347,7 +1409,7 @@ aarch64_linux_get_syscall_number (struct gdbarch *gdbarch, thread_info *thread) This function will only ever get called when stopped at the entry or exit of a syscall, so by checking for 0 in x0 (arg0/retval), x1 (arg1), x8 (syscall), x29 (FP) and x30 (LR) we can infer: - 1) Either inferior is at exit from sucessful execve. + 1) Either inferior is at exit from successful execve. 2) Or inferior is at entry to a call to io_setup with invalid arguments and a corrupted FP and LR. It should be safe enough to assume case 1. */ @@ -1429,11 +1491,11 @@ aarch64_linux_syscall_record (struct regcache *regcache, /* Implement the "gcc_target_options" gdbarch method. */ -static char * +static std::string aarch64_linux_gcc_target_options (struct gdbarch *gdbarch) { /* GCC doesn't know "-m64". */ - return NULL; + return {}; } static void @@ -1449,14 +1511,14 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) tdep->lowest_pc = 0x8000; - linux_init_abi (info, gdbarch); + linux_init_abi (info, gdbarch, 1); set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_lp64_fetch_link_map_offsets); /* Enable TLS support. */ set_gdbarch_fetch_tls_load_module_address (gdbarch, - svr4_fetch_objfile_link_map); + svr4_fetch_objfile_link_map); /* Shared library handling. */ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); @@ -1658,19 +1720,19 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_gdbarch_get_syscall_number (gdbarch, aarch64_linux_get_syscall_number); /* Displaced stepping. */ - set_gdbarch_max_insn_length (gdbarch, 4 * DISPLACED_MODIFIED_INSNS); + set_gdbarch_max_insn_length (gdbarch, 4 * AARCH64_DISPLACED_MODIFIED_INSNS); set_gdbarch_displaced_step_copy_insn (gdbarch, aarch64_displaced_step_copy_insn); set_gdbarch_displaced_step_fixup (gdbarch, aarch64_displaced_step_fixup); - set_gdbarch_displaced_step_location (gdbarch, linux_displaced_step_location); set_gdbarch_displaced_step_hw_singlestep (gdbarch, aarch64_displaced_step_hw_singlestep); set_gdbarch_gcc_target_options (gdbarch, aarch64_linux_gcc_target_options); } +void _initialize_aarch64_linux_tdep (); void -_initialize_aarch64_linux_tdep (void) +_initialize_aarch64_linux_tdep () { gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_LINUX, aarch64_linux_init_abi);