From cfd2c4eb80832d5edd1da4a226cd2bc5149ef9ba Mon Sep 17 00:00:00 2001 From: Luis Machado Date: Tue, 9 Mar 2021 14:56:15 -0300 Subject: [PATCH] Fix disassembly of C64 instructions in GDB Disassembling of C64 instructions in GDB does not work correctly. It needs to pass the proper information to opcodes. This patch accomplishes that. gdb/ChangeLog: 2021-03-17 Luis Machado * aarch64-tdep.c (aarch64_find_mapping_symbol, aarch64_pc_is_c64): New functions. (aarch64_gdb_print_insn): Pass map type to disassembler. include/ChangeLog: 2021-03-17 Luis Machado * opcode/aarch64.h (enum map_type): Moved from opcodes/aarch64-dis.c. Renamed fields. (struct aarch64_private_data): New struct. opcodes/ChangeLog: 2021-03-17 Luis Machado * aarch64-dis.c (enum map_type): Moved to include/opcode/aarch64.h. (MAYBE_C64): Adjust. (get_sym_code_type): Adjust. (print_insn_aarch64): Use private data when available. --- gdb/aarch64-tdep.c | 100 +++++++++++++++++++++++++++++++++++++++ include/ChangeLog | 6 +++ include/opcode/aarch64.h | 14 ++++++ opcodes/ChangeLog | 7 +++ opcodes/aarch64-dis.c | 55 +++++++++++---------- 5 files changed, 156 insertions(+), 26 deletions(-) diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index e656cc562d1..14531b27009 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -2639,12 +2639,112 @@ aarch64_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg) return -1; } +/* Search for the mapping symbol covering MEMADDR. If one is found, + return its type. Otherwise, return 0. If START is non-NULL, + set *START to the location of the mapping symbol. */ + +static char +aarch64_find_mapping_symbol (CORE_ADDR memaddr, CORE_ADDR *start) +{ + struct obj_section *sec; + + /* If there are mapping symbols, consult them. */ + sec = find_pc_section (memaddr); + if (sec != NULL) + { + aarch64_per_bfd *data = aarch64_bfd_data_key.get (sec->objfile->obfd); + if (data != NULL) + { + unsigned int section_idx = sec->the_bfd_section->index; + aarch64_mapping_symbol_vec &map + = data->section_maps[section_idx]; + + /* Sort the vector on first use. */ + if (!data->section_maps_sorted[section_idx]) + { + std::sort (map.begin (), map.end ()); + data->section_maps_sorted[section_idx] = true; + } + + aarch64_mapping_symbol map_key = { memaddr - sec->addr (), 0 }; + aarch64_mapping_symbol_vec::const_iterator it + = std::lower_bound (map.begin (), map.end (), map_key); + + /* std::lower_bound finds the earliest ordered insertion + point. If the symbol at this position starts at this exact + address, we use that; otherwise, the preceding + mapping symbol covers this address. */ + if (it < map.end ()) + { + if (it->value == map_key.value) + { + if (start) + *start = it->value + sec->addr (); + return it->type; + } + } + + if (it > map.begin ()) + { + aarch64_mapping_symbol_vec::const_iterator prev_it + = it - 1; + + if (start) + *start = prev_it->value + sec->addr (); + return prev_it->type; + } + } + } + + return 0; +} + +/* Determine if the program counter specified in MEMADDR is in a C64 + function. This function should be called for addresses unrelated to + any executing frame. */ + +static bool +aarch64_pc_is_c64 (struct gdbarch *gdbarch, CORE_ADDR memaddr) +{ + aarch64_gdbarch_tdep *tdep = (aarch64_gdbarch_tdep *) gdbarch_tdep (gdbarch); + + /* If we're using the AAPCS64-CAP ABI, then this is pure-cap and it is + always C64. */ + if (tdep->abi == AARCH64_ABI_AAPCS64_CAP) + return true; + + /* If there are mapping symbols, consult them. */ + char type = aarch64_find_mapping_symbol (memaddr, NULL); + if (type) + return type == 'c'; + + /* C64 functions have a "special" bit set in minimal symbols. */ + struct bound_minimal_symbol sym; + sym = lookup_minimal_symbol_by_pc (memaddr); + if (sym.minsym) + return (MSYMBOL_IS_SPECIAL (sym.minsym)); + + /* Otherwise we're out of luck; we assume A64. */ + return false; +} + /* Implement the "print_insn" gdbarch method. */ static int aarch64_gdb_print_insn (bfd_vma memaddr, disassemble_info *info) { + gdb_disassembler *di + = static_cast(info->application_data); + struct gdbarch *gdbarch = di->arch (); + struct aarch64_private_data data; + + info->private_data = static_cast (&data); + + if (aarch64_pc_is_c64 (gdbarch, memaddr)) + data.instruction_type = MAP_TYPE_C64; + info->symbols = NULL; + return default_print_insn (memaddr, info); } diff --git a/include/ChangeLog b/include/ChangeLog index a28667ae61f..c46dea99b16 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,9 @@ +2021-03-17 Luis Machado + + * opcode/aarch64.h (enum map_type): Moved from opcodes/aarch64-dis.c. + Renamed fields. + (struct aarch64_private_data): New struct. + 2020-10-20 Luis Machado * elf/common.h (NT_ARM_MORELLO): Define. diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h index f46cb379fbf..bc50d11e404 100644 --- a/include/opcode/aarch64.h +++ b/include/opcode/aarch64.h @@ -1453,6 +1453,20 @@ struct aarch64_instr_sequence int num_allocated_insns; }; +/* Cached mapping symbol state. */ +enum map_type +{ + MAP_TYPE_INSN, + MAP_TYPE_DATA, + MAP_TYPE_C64 +}; + +/* AArch64-specific data to help proper disassembling of instructions. */ +struct aarch64_private_data +{ + enum map_type instruction_type; +}; + /* Encoding entrypoint. */ extern bool diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index e913cffb9ac..e0fdda45f76 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,10 @@ +2021-03-17 Luis Machado + + * aarch64-dis.c (enum map_type): Moved to include/opcode/aarch64.h. + (MAYBE_C64): Adjust. + (get_sym_code_type): Adjust. + (print_insn_aarch64): Use private data when available. + 2020-10-20 Luis Machado * aarch64-tbl.h (aarch64_opcode_table): Update iclass field diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c index 2e8c7824da8..80713e1e69f 100644 --- a/opcodes/aarch64-dis.c +++ b/opcodes/aarch64-dis.c @@ -29,21 +29,13 @@ #define INSNLEN 4 -/* Cached mapping symbol state. */ -enum map_type -{ - MAP_INSN, - MAP_DATA, - MAP_C64 -}; - static aarch64_feature_set arch_variant; /* See select_aarch64_variant. */ static enum map_type last_type; static int last_mapping_sym = -1; static bfd_vma last_stop_offset = 0; static bfd_vma last_mapping_addr = 0; -#define MAYBE_C64 (last_type == MAP_C64 ? AARCH64_FEATURE_C64 : 0) +#define MAYBE_C64 (last_type == MAP_TYPE_C64 ? AARCH64_FEATURE_C64 : 0) /* Other options */ static int no_aliases = 0; /* If set disassemble as most general inst. */ @@ -3786,7 +3778,7 @@ get_sym_code_type (struct disassemble_info *info, int n, if (type == STT_FUNC && !(es->symbol.flags & BSF_SYNTHETIC)) { *map_type = (es->internal_elf_sym.st_target_internal & ST_BRANCH_TO_C64 - ? MAP_C64 : MAP_INSN); + ? MAP_TYPE_C64 : MAP_TYPE_INSN); return true; } @@ -3799,13 +3791,13 @@ get_sym_code_type (struct disassemble_info *info, int n, switch (name[1]) { case 'd': - *map_type = MAP_DATA; + *map_type = MAP_TYPE_DATA; break; case 'x': - *map_type = MAP_INSN; + *map_type = MAP_TYPE_INSN; break; case 'c': - *map_type = MAP_C64; + *map_type = MAP_TYPE_C64; break; default: abort (); @@ -3871,17 +3863,28 @@ print_insn_aarch64 (bfd_vma pc, /* Aarch64 instructions are always little-endian */ info->endian_code = BFD_ENDIAN_LITTLE; - /* Default to DATA. A text section is required by the ABI to contain an - INSN mapping symbol at the start. A data section has no such - requirement, hence if no mapping symbol is found the section must - contain only data. This however isn't very useful if the user has - fully stripped the binaries. If this is the case use the section - attributes to determine the default. If we have no section default to - INSN as well, as we may be disassembling some raw bytes on a baremetal - HEX file or similar. */ - enum map_type type = MAP_DATA; - if ((info->section && info->section->flags & SEC_CODE) || !info->section) - type = last_type == MAP_C64 ? MAP_C64 : MAP_INSN; + enum map_type type; + + if (info->private_data != NULL) + { + struct aarch64_private_data *aarch64_data + = (struct aarch64_private_data *) info->private_data; + type = aarch64_data->instruction_type; + } + else + { + /* Default to DATA. A text section is required by the ABI to contain an + INSN mapping symbol at the start. A data section has no such + requirement, hence if no mapping symbol is found the section must + contain only data. This however isn't very useful if the user has + fully stripped the binaries. If this is the case use the section + attributes to determine the default. If we have no section default to + INSN as well, as we may be disassembling some raw bytes on a baremetal + HEX file or similar. */ + type = MAP_TYPE_DATA; + if ((info->section && info->section->flags & SEC_CODE) || !info->section) + type = last_type == MAP_TYPE_C64 ? MAP_TYPE_C64 : MAP_TYPE_INSN; + } /* First check the full symtab for a mapping symbol, even if there are no usable non-mapping symbols for this address. */ @@ -3963,7 +3966,7 @@ print_insn_aarch64 (bfd_vma pc, less than four bytes of data. If there's a symbol, mapping or otherwise, after two bytes then don't print more. */ - if (last_type == MAP_DATA) + if (last_type == MAP_TYPE_DATA) { size = 4 - (pc & 3); for (n = last_sym + 1; n < info->symtab_size; n++) @@ -3987,7 +3990,7 @@ print_insn_aarch64 (bfd_vma pc, last_type = type; /* PR 10263: Disassemble data if requested to do so by the user. */ - if (last_type == MAP_DATA && ((info->flags & DISASSEMBLE_DATA) == 0)) + if (last_type == MAP_TYPE_DATA && ((info->flags & DISASSEMBLE_DATA) == 0)) { /* size was set above. */ info->bytes_per_chunk = size; -- 2.47.2