diff options
Diffstat (limited to 'opcodes')
-rw-r--r-- | opcodes/ChangeLog | 6 | ||||
-rw-r--r-- | opcodes/arm-dis.c | 249 |
2 files changed, 107 insertions, 148 deletions
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 433e43f..7b7237f 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,5 +1,11 @@ 2019-03-25 Tamar Christina <tamar.christina@arm.com> + * arm-dis.c (struct arm_private_data): Remove has_mapping_symbols. + (mapping_symbol_for_insn): Implement new algorithm. + (print_insn): Remove duplicate code. + +2019-03-25 Tamar Christina <tamar.christina@arm.com> + * aarch64-dis.c (print_insn_aarch64): Implement override. diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c index 71d7c52..d47ef32 100644 --- a/opcodes/arm-dis.c +++ b/opcodes/arm-dis.c @@ -56,15 +56,14 @@ struct arm_private_data /* The features to use when disassembling optional instructions. */ arm_feature_set features; - /* Whether any mapping symbols are present in the provided symbol - table. -1 if we do not know yet, otherwise 0 or 1. */ - int has_mapping_symbols; - /* Track the last type (although this doesn't seem to be useful) */ enum map_type last_type; /* Tracking symbol table information */ int last_mapping_sym; + + /* The end range of the current range being disassembled. */ + bfd_vma last_stop_offset; bfd_vma last_mapping_addr; }; @@ -6351,52 +6350,114 @@ static bfd_boolean mapping_symbol_for_insn (bfd_vma pc, struct disassemble_info *info, enum map_type *map_symbol) { - bfd_vma addr; - int n, start = 0; + bfd_vma addr, section_vma = 0; + int n, last_sym = -1; bfd_boolean found = FALSE; - enum map_type type = MAP_ARM; + bfd_boolean can_use_search_opt_p = FALSE; + + /* 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 = MAP_ARM; struct arm_private_data *private_data; - if (info->private_data == NULL || info->symtab_size == 0 + if (info->private_data == NULL || bfd_asymbol_flavour (*info->symtab) != bfd_target_elf_flavour) return FALSE; private_data = info->private_data; - if (pc == 0) - start = 0; - else - start = private_data->last_mapping_sym; - start = (start == -1)? 0 : start; - addr = bfd_asymbol_value (info->symtab[start]); + /* First, look for mapping symbols. */ + if (info->symtab_size != 0) + { + if (pc <= private_data->last_mapping_addr) + private_data->last_mapping_sym = -1; + + /* Start scanning at the start of the function, or wherever + we finished last time. */ + n = info->symtab_pos + 1; + + /* If the last stop offset is different from the current one it means we + are disassembling a different glob of bytes. As such the optimization + would not be safe and we should start over. */ + can_use_search_opt_p + = private_data->last_mapping_sym >= 0 + && info->stop_offset == private_data->last_stop_offset; + + if (n >= private_data->last_mapping_sym && can_use_search_opt_p) + n = private_data->last_mapping_sym; + + /* Look down while we haven't passed the location being disassembled. + The reason for this is that there's no defined order between a symbol + and an mapping symbol that may be at the same address. We may have to + look at least one position ahead. */ + for (; n < info->symtab_size; n++) + { + addr = bfd_asymbol_value (info->symtab[n]); + if (addr > pc) + break; + if (get_map_sym_type (info, n, &type)) + { + last_sym = n; + found = TRUE; + } + } - if (pc >= addr) - { - if (get_map_sym_type (info, start, &type)) - found = TRUE; - } - else + if (!found) + { + n = info->symtab_pos; + if (n >= private_data->last_mapping_sym && can_use_search_opt_p) + n = private_data->last_mapping_sym; + + /* No mapping symbol found at this address. Look backwards + for a preceeding one, but don't go pass the section start + otherwise a data section with no mapping symbol can pick up + a text mapping symbol of a preceeding section. The documentation + says section can be NULL, in which case we will seek up all the + way to the top. */ + if (info->section) + section_vma = info->section->vma; + + for (; n >= 0; n--) + { + addr = bfd_asymbol_value (info->symtab[n]); + if (addr < section_vma) + break; + + if (get_map_sym_type (info, n, &type)) + { + last_sym = n; + found = TRUE; + break; + } + } + } + } + + /* If no mapping symbol was found, try looking up without a mapping + symbol. This is done by walking up from the current PC to the nearest + symbol. We don't actually have to loop here since symtab_pos will + contain the nearest symbol already. */ + if (!found) { - for (n = start - 1; n >= 0; n--) + n = info->symtab_pos; + if (n >= 0 && get_sym_code_type (info, n, &type)) { - if (get_map_sym_type (info, n, &type)) - { - found = TRUE; - break; - } + last_sym = n; + found = TRUE; } } - /* No mapping symbols were found. A leading $d may be - omitted for sections which start with data; but for - compatibility with legacy and stripped binaries, only - assume the leading $d if there is at least one mapping - symbol in the file. */ - if (!found && private_data->has_mapping_symbols == 1) - { - type = MAP_DATA; - found = TRUE; - } + private_data->last_mapping_sym = last_sym; + private_data->last_type = type; + private_data->last_stop_offset = info->stop_offset; *map_symbol = type; return found; @@ -6535,9 +6596,9 @@ print_insn (bfd_vma pc, struct disassemble_info *info, bfd_boolean little) during disassembly.... */ select_arm_features (info->mach, & private.features); - private.has_mapping_symbols = -1; private.last_mapping_sym = -1; private.last_mapping_addr = 0; + private.last_stop_offset = 0; info->private_data = & private; } @@ -6554,121 +6615,13 @@ print_insn (bfd_vma pc, struct disassemble_info *info, bfd_boolean little) && bfd_asymbol_flavour (*info->symtab) == bfd_target_elf_flavour) { bfd_vma addr; - int n, start; + int n; int last_sym = -1; enum map_type type = MAP_ARM; - /* Start scanning at the start of the function, or wherever - we finished last time. */ - /* PR 14006. When the address is 0 we are either at the start of the - very first function, or else the first function in a new, unlinked - executable section (eg because of -ffunction-sections). Either way - start scanning from the beginning of the symbol table, not where we - left off last time. */ - if (pc == 0) - start = 0; - else - { - start = info->symtab_pos + 1; - if (start < private_data->last_mapping_sym) - start = private_data->last_mapping_sym; - } - found = FALSE; - - /* First, look for mapping symbols. */ - if (private_data->has_mapping_symbols != 0) - { - /* Scan up to the location being disassembled. */ - for (n = start; n < info->symtab_size; n++) - { - addr = bfd_asymbol_value (info->symtab[n]); - if (addr > pc) - break; - if (get_map_sym_type (info, n, &type)) - { - last_sym = n; - found = TRUE; - } - } - - if (!found) - { - /* No mapping symbol found at this address. Look backwards - for a preceding one. */ - for (n = start - 1; n >= 0; n--) - { - if (get_map_sym_type (info, n, &type)) - { - last_sym = n; - found = TRUE; - break; - } - } - } - - if (found) - private_data->has_mapping_symbols = 1; - - /* No mapping symbols were found. A leading $d may be - omitted for sections which start with data; but for - compatibility with legacy and stripped binaries, only - assume the leading $d if there is at least one mapping - symbol in the file. */ - if (!found && private_data->has_mapping_symbols == -1) - { - /* Look for mapping symbols, in any section. */ - for (n = 0; n < info->symtab_size; n++) - if (is_mapping_symbol (info, n, &type)) - { - private_data->has_mapping_symbols = 1; - break; - } - if (private_data->has_mapping_symbols == -1) - private_data->has_mapping_symbols = 0; - } - - if (!found && private_data->has_mapping_symbols == 1) - { - type = MAP_DATA; - found = TRUE; - } - } - - /* Next search for function symbols to separate ARM from Thumb - in binaries without mapping symbols. */ - if (!found) - { - /* Scan up to the location being disassembled. */ - for (n = start; n < info->symtab_size; n++) - { - addr = bfd_asymbol_value (info->symtab[n]); - if (addr > pc) - break; - if (get_sym_code_type (info, n, &type)) - { - last_sym = n; - found = TRUE; - } - } - - if (!found) - { - /* No mapping symbol found at this address. Look backwards - for a preceding one. */ - for (n = start - 1; n >= 0; n--) - { - if (get_sym_code_type (info, n, &type)) - { - last_sym = n; - found = TRUE; - break; - } - } - } - } + found = mapping_symbol_for_insn (pc, info, &type); + last_sym = private_data->last_mapping_sym; - private_data->last_mapping_sym = last_sym; - private_data->last_type = type; is_thumb = (private_data->last_type == MAP_THUMB); is_data = (private_data->last_type == MAP_DATA); |