/* 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;
};
%E print the lsb and width fields of a bfc/bfi instruction
%F print the lsb and width fields of a sbfx/ubfx instruction
+ %G print a fallback offset for Branch Future instructions
+ %W print an offset for BF instruction
+ %Y print an offset for BFL instruction
%b print a conditional branch offset
%B print an unconditional branch offset
%s print the shift field of an SSAT instruction
%<bitfield>W print bitfield*4 in decimal
%<bitfield>r print bitfield as an ARM register
%<bitfield>R as %<>r but r15 is UNPREDICTABLE
+ %<bitfield>S as %<>r but r13 and r15 is UNPREDICTABLE
%<bitfield>c print bitfield as a condition code
%<bitfield>'c print specified char iff bitfield is all ones
makes heavy use of special-case bit patterns. */
static const struct opcode32 thumb32_opcodes[] =
{
+ /* Armv8.1-M Mainline instructions. */
+ {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
+ 0xf040e001, 0xf860f001, "bf%c\t%G, %W"},
+ {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
+ 0xf060e001, 0xf8f0f001, "bfx%c\t%G, %16-19S"},
+ {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
+ 0xf070e001, 0xf8f0f001, "bflx%c\t%G, %16-19S"},
+
+
/* ARMv8-M and ARMv8-M Security Extensions instructions. */
{ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M), 0xe97fe97f, 0xffffffff, "sg"},
{ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8M),
info->print_address_func (offset + pc
+ info->bytes_per_chunk * 2
- (pc & 3),
- info);
+ info);
}
}
break;
default:
abort ();
}
- break;
-
- case 'y':
- case 'z':
- {
- int single = *c++ == 'y';
- int regno;
+ }
+ break;
- switch (*c)
- {
- case '4': /* Sm pair */
- case '0': /* Sm, Dm */
- regno = given & 0x0000000f;
- if (single)
- {
- regno <<= 1;
- regno += (given >> 5) & 1;
- }
- else
- regno += ((given >> 5) & 1) << 4;
- break;
+ case 'y':
+ case 'z':
+ {
+ int single = *c++ == 'y';
+ int regno;
- case '1': /* Sd, Dd */
- regno = (given >> 12) & 0x0000000f;
- if (single)
- {
- regno <<= 1;
- regno += (given >> 22) & 1;
- }
- else
- regno += ((given >> 22) & 1) << 4;
- break;
+ switch (*c)
+ {
+ case '4': /* Sm pair */
+ case '0': /* Sm, Dm */
+ regno = given & 0x0000000f;
+ if (single)
+ {
+ regno <<= 1;
+ regno += (given >> 5) & 1;
+ }
+ else
+ regno += ((given >> 5) & 1) << 4;
+ break;
- case '2': /* Sn, Dn */
- regno = (given >> 16) & 0x0000000f;
- if (single)
- {
- regno <<= 1;
- regno += (given >> 7) & 1;
- }
- else
- regno += ((given >> 7) & 1) << 4;
- break;
+ case '1': /* Sd, Dd */
+ regno = (given >> 12) & 0x0000000f;
+ if (single)
+ {
+ regno <<= 1;
+ regno += (given >> 22) & 1;
+ }
+ else
+ regno += ((given >> 22) & 1) << 4;
+ break;
- case '3': /* List */
- func (stream, "{");
- regno = (given >> 12) & 0x0000000f;
- if (single)
- {
- regno <<= 1;
- regno += (given >> 22) & 1;
- }
- else
- regno += ((given >> 22) & 1) << 4;
- break;
+ case '2': /* Sn, Dn */
+ regno = (given >> 16) & 0x0000000f;
+ if (single)
+ {
+ regno <<= 1;
+ regno += (given >> 7) & 1;
+ }
+ else
+ regno += ((given >> 7) & 1) << 4;
+ break;
- default:
- abort ();
- }
+ case '3': /* List */
+ func (stream, "{");
+ regno = (given >> 12) & 0x0000000f;
+ if (single)
+ {
+ regno <<= 1;
+ regno += (given >> 22) & 1;
+ }
+ else
+ regno += ((given >> 22) & 1) << 4;
+ break;
- func (stream, "%c%d", single ? 's' : 'd', regno);
+ default:
+ abort ();
+ }
- if (*c == '3')
- {
- int count = given & 0xff;
+ func (stream, "%c%d", single ? 's' : 'd', regno);
- if (single == 0)
- count >>= 1;
+ if (*c == '3')
+ {
+ int count = given & 0xff;
- if (--count)
- {
- func (stream, "-%c%d",
- single ? 's' : 'd',
- regno + count);
- }
+ if (single == 0)
+ count >>= 1;
- func (stream, "}");
- }
- else if (*c == '4')
- func (stream, ", %c%d", single ? 's' : 'd',
- regno + 1);
- }
- break;
+ if (--count)
+ {
+ func (stream, "-%c%d",
+ single ? 's' : 'd',
+ regno + count);
+ }
- case 'L':
- switch (given & 0x00400100)
- {
- case 0x00000000: func (stream, "b"); break;
- case 0x00400000: func (stream, "h"); break;
- case 0x00000100: func (stream, "w"); break;
- case 0x00400100: func (stream, "d"); break;
- default:
- break;
+ func (stream, "}");
}
- break;
+ else if (*c == '4')
+ func (stream, ", %c%d", single ? 's' : 'd',
+ regno + 1);
+ }
+ break;
- case 'Z':
+ case 'L':
+ switch (given & 0x00400100)
{
- /* given (20, 23) | given (0, 3) */
- value = ((given >> 16) & 0xf0) | (given & 0xf);
- func (stream, "%d", (int) value);
+ case 0x00000000: func (stream, "b"); break;
+ case 0x00400000: func (stream, "h"); break;
+ case 0x00000100: func (stream, "w"); break;
+ case 0x00400100: func (stream, "d"); break;
+ default:
+ break;
}
- break;
+ break;
- case 'l':
- /* This is like the 'A' operator, except that if
- the width field "M" is zero, then the offset is
- *not* multiplied by four. */
- {
- int offset = given & 0xff;
- int multiplier = (given & 0x00000100) ? 4 : 1;
+ case 'Z':
+ {
+ /* given (20, 23) | given (0, 3) */
+ value = ((given >> 16) & 0xf0) | (given & 0xf);
+ func (stream, "%d", (int) value);
+ }
+ break;
- func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
+ case 'l':
+ /* This is like the 'A' operator, except that if
+ the width field "M" is zero, then the offset is
+ *not* multiplied by four. */
+ {
+ int offset = given & 0xff;
+ int multiplier = (given & 0x00000100) ? 4 : 1;
- if (multiplier > 1)
- {
- value_in_comment = offset * multiplier;
- if (NEGATIVE_BIT_SET)
- value_in_comment = - value_in_comment;
- }
+ func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
- if (offset)
- {
- if (PRE_BIT_SET)
- func (stream, ", #%s%d]%s",
- NEGATIVE_BIT_SET ? "-" : "",
- offset * multiplier,
- WRITEBACK_BIT_SET ? "!" : "");
- else
- func (stream, "], #%s%d",
- NEGATIVE_BIT_SET ? "-" : "",
- offset * multiplier);
- }
- else
- func (stream, "]");
- }
- break;
+ if (multiplier > 1)
+ {
+ value_in_comment = offset * multiplier;
+ if (NEGATIVE_BIT_SET)
+ value_in_comment = - value_in_comment;
+ }
- case 'r':
- {
- int imm4 = (given >> 4) & 0xf;
- int puw_bits = ((given >> 22) & 6) | ((given >> W_BIT) & 1);
- int ubit = ! NEGATIVE_BIT_SET;
- const char *rm = arm_regnames [given & 0xf];
- const char *rn = arm_regnames [(given >> 16) & 0xf];
+ if (offset)
+ {
+ if (PRE_BIT_SET)
+ func (stream, ", #%s%d]%s",
+ NEGATIVE_BIT_SET ? "-" : "",
+ offset * multiplier,
+ WRITEBACK_BIT_SET ? "!" : "");
+ else
+ func (stream, "], #%s%d",
+ NEGATIVE_BIT_SET ? "-" : "",
+ offset * multiplier);
+ }
+ else
+ func (stream, "]");
+ }
+ break;
- switch (puw_bits)
- {
- case 1:
- case 3:
- func (stream, "[%s], %c%s", rn, ubit ? '+' : '-', rm);
- if (imm4)
- func (stream, ", lsl #%d", imm4);
- break;
+ case 'r':
+ {
+ int imm4 = (given >> 4) & 0xf;
+ int puw_bits = ((given >> 22) & 6) | ((given >> W_BIT) & 1);
+ int ubit = ! NEGATIVE_BIT_SET;
+ const char *rm = arm_regnames [given & 0xf];
+ const char *rn = arm_regnames [(given >> 16) & 0xf];
- case 4:
- case 5:
- case 6:
- case 7:
- func (stream, "[%s, %c%s", rn, ubit ? '+' : '-', rm);
- if (imm4 > 0)
- func (stream, ", lsl #%d", imm4);
- func (stream, "]");
- if (puw_bits == 5 || puw_bits == 7)
- func (stream, "!");
- break;
+ switch (puw_bits)
+ {
+ case 1:
+ case 3:
+ func (stream, "[%s], %c%s", rn, ubit ? '+' : '-', rm);
+ if (imm4)
+ func (stream, ", lsl #%d", imm4);
+ break;
- default:
- func (stream, "INVALID");
- }
- }
- break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ func (stream, "[%s, %c%s", rn, ubit ? '+' : '-', rm);
+ if (imm4 > 0)
+ func (stream, ", lsl #%d", imm4);
+ func (stream, "]");
+ if (puw_bits == 5 || puw_bits == 7)
+ func (stream, "!");
+ break;
- case 'i':
- {
- long imm5;
- imm5 = ((given & 0x100) >> 4) | (given & 0xf);
- func (stream, "%ld", (imm5 == 0) ? 32 : imm5);
- }
- break;
+ default:
+ func (stream, "INVALID");
+ }
+ }
+ break;
- default:
- abort ();
+ case 'i':
+ {
+ long imm5;
+ imm5 = ((given & 0x100) >> 4) | (given & 0xf);
+ func (stream, "%ld", (imm5 == 0) ? 32 : imm5);
}
+ break;
+
+ default:
+ abort ();
}
}
else
default:
abort ();
}
- break;
-
- default:
- abort ();
}
+ break;
+
+ default:
+ abort ();
}
}
else
default:
abort ();
}
- break;
-
- case 'e':
- {
- int imm;
+ }
+ break;
- imm = (given & 0xf) | ((given & 0xfff00) >> 4);
- func (stream, "%d", imm);
- value_in_comment = imm;
- }
- break;
+ case 'e':
+ {
+ int imm;
- case 'E':
- /* LSB and WIDTH fields of BFI or BFC. The machine-
- language instruction encodes LSB and MSB. */
- {
- long msb = (given & 0x001f0000) >> 16;
- long lsb = (given & 0x00000f80) >> 7;
- long w = msb - lsb + 1;
+ imm = (given & 0xf) | ((given & 0xfff00) >> 4);
+ func (stream, "%d", imm);
+ value_in_comment = imm;
+ }
+ break;
- if (w > 0)
- func (stream, "#%lu, #%lu", lsb, w);
- else
- func (stream, "(invalid: %lu:%lu)", lsb, msb);
- }
- break;
+ case 'E':
+ /* LSB and WIDTH fields of BFI or BFC. The machine-
+ language instruction encodes LSB and MSB. */
+ {
+ long msb = (given & 0x001f0000) >> 16;
+ long lsb = (given & 0x00000f80) >> 7;
+ long w = msb - lsb + 1;
- case 'R':
- /* Get the PSR/banked register name. */
- {
- const char * name;
- unsigned sysm = (given & 0x004f0000) >> 16;
+ if (w > 0)
+ func (stream, "#%lu, #%lu", lsb, w);
+ else
+ func (stream, "(invalid: %lu:%lu)", lsb, msb);
+ }
+ break;
- sysm |= (given & 0x300) >> 4;
- name = banked_regname (sysm);
+ case 'R':
+ /* Get the PSR/banked register name. */
+ {
+ const char * name;
+ unsigned sysm = (given & 0x004f0000) >> 16;
- if (name != NULL)
- func (stream, "%s", name);
- else
- func (stream, "(UNDEF: %lu)", (unsigned long) sysm);
- }
- break;
+ sysm |= (given & 0x300) >> 4;
+ name = banked_regname (sysm);
- case 'V':
- /* 16-bit unsigned immediate from a MOVT or MOVW
- instruction, encoded in bits 0:11 and 15:19. */
- {
- long hi = (given & 0x000f0000) >> 4;
- long lo = (given & 0x00000fff);
- long imm16 = hi | lo;
+ if (name != NULL)
+ func (stream, "%s", name);
+ else
+ func (stream, "(UNDEF: %lu)", (unsigned long) sysm);
+ }
+ break;
- func (stream, "#%lu", imm16);
- value_in_comment = imm16;
- }
- break;
+ case 'V':
+ /* 16-bit unsigned immediate from a MOVT or MOVW
+ instruction, encoded in bits 0:11 and 15:19. */
+ {
+ long hi = (given & 0x000f0000) >> 4;
+ long lo = (given & 0x00000fff);
+ long imm16 = hi | lo;
- default:
- abort ();
+ func (stream, "#%lu", imm16);
+ value_in_comment = imm16;
}
+ break;
+
+ default:
+ abort ();
}
}
else
mask. */
if ((given & (1 << ((given & 0x0700) >> 8))) == 0)
func (stream, "!");
- break;
+ break;
case 'b':
/* Print ARM V6T2 CZB address: pc+4+6 bits. */
}
break;
+ case 'G':
+ {
+ unsigned int boff = (((given & 0x07800000) >> 23) << 1);
+ func (stream, "%x", boff);
+ }
+ break;
+
+ case 'W':
+ {
+ unsigned int immA = (given & 0x001f0000u) >> 16;
+ unsigned int immB = (given & 0x000007feu) >> 1;
+ unsigned int immC = (given & 0x00000800u) >> 11;
+ bfd_vma offset = 0;
+
+ offset |= immA << 12;
+ offset |= immB << 2;
+ offset |= immC << 1;
+ /* Sign extend. */
+ offset = (offset & 0x10000) ? offset - (1 << 17) : offset;
+
+ info->print_address_func (pc + 4 + offset, info);
+ }
+ break;
+
+ case 'Y':
+ {
+ unsigned int immA = (given & 0x007f0000u) >> 16;
+ unsigned int immB = (given & 0x000007feu) >> 1;
+ unsigned int immC = (given & 0x00000800u) >> 11;
+ bfd_vma offset = 0;
+
+ offset |= immA << 12;
+ offset |= immB << 2;
+ offset |= immC << 1;
+ /* Sign extend. */
+ offset = (offset & 0x40000) ? offset - (1 << 19) : offset;
+
+ info->print_address_func (pc + 4 + offset, info);
+ }
+ break;
+
case 'b':
{
unsigned int S = (given & 0x04000000u) >> 26;
value_in_comment = val * 4;
break;
+ case 'S':
+ if (val == 13)
+ is_unpredictable = TRUE;
+ /* Fall through. */
case 'R':
if (val == 15)
is_unpredictable = TRUE;
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 (!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 (pc >= addr)
- {
- if (get_map_sym_type (info, start, &type))
- found = TRUE;
- }
- else
+ 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;
case bfd_mach_arm_8R: ARM_SET_FEATURES (ARM_ARCH_V8R); break;
case bfd_mach_arm_8M_BASE: ARM_SET_FEATURES (ARM_ARCH_V8M_BASE); break;
case bfd_mach_arm_8M_MAIN: ARM_SET_FEATURES (ARM_ARCH_V8M_MAIN); break;
+ case bfd_mach_arm_8_1M_MAIN: ARM_SET_FEATURES (ARM_ARCH_V8_1M_MAIN); break;
/* If the machine type is unknown allow all architecture types and all
extensions. */
case bfd_mach_arm_unknown: ARM_SET_FEATURES (ARM_FEATURE_ALL); break;
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;
}
&& 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);