bfd_size_type dynamic_size;
unsigned int dynamic_nent;
char *dynamic_strings;
+unsigned long dynamic_strings_length;
char *string_table;
unsigned long string_table_length;
unsigned long num_dynamic_syms;
int do_debug_lines;
int do_debug_pubnames;
int do_debug_aranges;
+int do_debug_ranges;
int do_debug_frames;
int do_debug_frames_interp;
int do_debug_macinfo;
struct group **section_headers_groups;
-/* A dynamic array of flags indicating which sections require dumping. */
+/* A dynamic array of flags indicating for which sections a hex dump
+ has been requested (via the -x switch) and/or a disassembly dump
+ (via the -i switch). */
+char *cmdline_dump_sects = NULL;
+unsigned num_cmdline_dump_sects = 0;
+
+/* A dynamic array of flags indicating for which sections a dump of
+ some kind has been requested. It is reset on a per-object file
+ basis and then initialised from the cmdline_dump_sects array and
+ the results of interpreting the -w switch. */
char *dump_sects = NULL;
unsigned int num_dump_sects = 0;
#define UNKNOWN -1
#define SECTION_NAME(X) ((X) == NULL ? "<none>" : \
- ((X)->sh_name >= string_table_length \
- ? "<corrupt>" : string_table + (X)->sh_name))
+ ((X)->sh_name >= string_table_length \
+ ? "<corrupt>" : string_table + (X)->sh_name))
/* Given st_shndx I, map to section_headers index. */
#define SECTION_HEADER_INDEX(I) \
(is_32bit_elf ? get_32bit_elf_symbols (file, section) \
: get_64bit_elf_symbols (file, section))
+#define VALID_DYNAMIC_NAME(offset) ((dynamic_strings != NULL) && (offset < dynamic_strings_length))
+/* GET_DYNAMIC_NAME asssumes that VALID_DYNAMIC_NAME has
+ already been called and verified that the string exists. */
+#define GET_DYNAMIC_NAME(offset) (dynamic_strings + offset)
+/* This is just a bit of syntatic sugar. */
+#define streq(a,b) (strcmp ((a), (b)) == 0)
+#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0)
+\f
static void
error (const char *message, ...)
{
#ifndef BFD64
case 8:
- /* Although we are extracing data from an 8 byte wide field, we
- are returning only 4 bytes of data. */
+ /* Although we are extracing data from an 8 byte wide field,
+ we are returning only 4 bytes of data. */
return ((unsigned long) (field[7]))
| (((unsigned long) (field[6])) << 8)
| (((unsigned long) (field[5])) << 16)
if (relas == NULL)
{
- error(_("out of memory parsing relocs"));
+ error (_("out of memory parsing relocs"));
return 0;
}
if (relas == NULL)
{
- error(_("out of memory parsing relocs"));
+ error (_("out of memory parsing relocs"));
return 0;
}
if (rels == NULL)
{
- error(_("out of memory parsing relocs"));
+ error (_("out of memory parsing relocs"));
return 0;
}
if (rels == NULL)
{
- error(_("out of memory parsing relocs"));
+ error (_("out of memory parsing relocs"));
return 0;
}
Elf_Internal_Sym *symtab,
unsigned long nsyms,
char *strtab,
+ unsigned long strtablen,
int is_rela)
{
unsigned int i;
print_symbol (22, sec_name);
}
else if (strtab == NULL)
- printf (_("<string table index %3ld>"), psym->st_name);
+ printf (_("<string table index: %3ld>"), psym->st_name);
+ else if (psym->st_name > strtablen)
+ printf (_("<corrupt string table index: %3ld>"), psym->st_name);
else
print_symbol (22, strtab + psym->st_name);
}
else if (is_rela)
{
- printf ("%*c", is_32bit_elf ? (do_wide ? 34 : 28) : (do_wide ? 26 : 20), ' ');
+ printf ("%*c", is_32bit_elf ?
+ (do_wide ? 34 : 28) : (do_wide ? 26 : 20), ' ');
print_vma (rels[i].r_addend, LONG_HEX);
}
if (elf_header.e_machine == EM_SPARCV9
- && !strcmp (rtype, "R_SPARC_OLO10"))
+ && streq (rtype, "R_SPARC_OLO10"))
printf (" + %lx", (unsigned long) ELF64_R_TYPE_DATA (info));
putchar ('\n');
else
printf ("%-17.17s", rtype2);
- printf("\n Type3: ");
+ printf ("\n Type3: ");
if (rtype3 == NULL)
#ifdef _bfd_int64_low
case EF_ARM_EABI_VER3:
strcat (buf, ", Version3 EABI");
+ break;
+
+ case EF_ARM_EABI_VER4:
+ strcat (buf, ", Version4 EABI");
while (e_flags)
{
unsigned flag;
default:
strcat (buf, ", fr???");
break;
-
+
case EF_FRV_CPU_FR300:
strcat (buf, ", fr300");
break;
}
break;
-
+
case EM_SPARCV9:
if (e_flags & EF_SPARC_32PLUS)
strcat (buf, ", v8+");
static const char *
get_ia64_section_type_name (unsigned int sh_type)
{
- /* If the top 8 bits are 0x78 the next 8 are the os/abi ID. */
+ /* If the top 8 bits are 0x78 the next 8 are the os/abi ID. */
if ((sh_type & 0xFF000000) == SHT_IA_64_LOPSREG)
return get_osabi_name ((sh_type & 0x00FF0000) >> 16);
-A --arch-specific Display architecture specific information (if any).\n\
-D --use-dynamic Use the dynamic section info when displaying symbols\n\
-x --hex-dump=<number> Dump the contents of section <number>\n\
- -w[liaprmfFso] or\n\
- --debug-dump[=line,=info,=abbrev,=pubnames,=ranges,=macro,=frames,=str,=loc]\n\
+ -w[liaprmfFsoR] or\n\
+ --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=str,=loc,=Ranges]\n\
Display the contents of DWARF2 debug sections\n"));
#ifdef SUPPORT_DISASSEMBLY
fprintf (stdout, _("\
exit (0);
}
+/* Record the fact that the user wants the contents of section number
+ SECTION to be displayed using the method(s) encoded as flags bits
+ in TYPE. Note, TYPE can be zero if we are creating the array for
+ the first time. */
+
static void
request_dump (unsigned int section, int type)
{
break;
case 'r':
- case 'R':
do_debug_aranges = 1;
break;
+ case 'R':
+ do_debug_ranges = 1;
+ break;
+
case 'F':
do_debug_frames_interp = 1;
case 'f':
do_debugging = 1;
else
{
- static const char *debug_dump_opt[]
- = { "line", "info", "abbrev", "pubnames", "ranges",
- "macro", "frames", "frames-interp", "str", "loc", NULL };
- unsigned int index;
+ typedef struct
+ {
+ const char * option;
+ int * variable;
+ }
+ debug_dump_long_opts;
+
+ debug_dump_long_opts opts_table [] =
+ {
+ /* Please keep this table alpha- sorted. */
+ { "Ranges", & do_debug_ranges },
+ { "abbrev", & do_debug_abbrevs },
+ { "aranges", & do_debug_aranges },
+ { "frames", & do_debug_frames },
+ { "frames-interp", & do_debug_frames_interp },
+ { "info", & do_debug_info },
+ { "line", & do_debug_lines },
+ { "loc", & do_debug_loc },
+ { "macro", & do_debug_macinfo },
+ { "pubnames", & do_debug_pubnames },
+ /* This entry is for compatability
+ with earlier versions of readelf. */
+ { "ranges", & do_debug_aranges },
+ { "str", & do_debug_str },
+ { NULL, NULL }
+ };
+
const char *p;
do_debugging = 0;
p = optarg;
while (*p)
{
- for (index = 0; debug_dump_opt[index]; index++)
+ debug_dump_long_opts * entry;
+
+ for (entry = opts_table; entry->option; entry++)
{
- size_t len = strlen (debug_dump_opt[index]);
+ size_t len = strlen (entry->option);
- if (strncmp (p, debug_dump_opt[index], len) == 0
+ if (strneq (p, entry->option, len)
&& (p[len] == ',' || p[len] == '\0'))
{
- switch (p[0])
- {
- case 'i':
- do_debug_info = 1;
- break;
-
- case 'a':
- do_debug_abbrevs = 1;
- break;
-
- case 'l':
- if (p[1] == 'i')
- do_debug_lines = 1;
- else
- do_debug_loc = 1;
- break;
-
- case 'p':
- do_debug_pubnames = 1;
- break;
-
- case 'r':
- do_debug_aranges = 1;
- break;
-
- case 'f':
- if (len > 6)
- do_debug_frames_interp = 1;
- do_debug_frames = 1;
- break;
-
- case 'm':
- do_debug_macinfo = 1;
- break;
-
- case 's':
- do_debug_str = 1;
- break;
- }
+ * entry->variable = 1;
+
+ /* The --debug-dump=frames-interp option also
+ enables the --debug-dump=frames option. */
+ if (do_debug_frames_interp)
+ do_debug_frames = 1;
p += len;
break;
}
}
- if (debug_dump_opt[index] == NULL)
+ if (entry->option == NULL)
{
warn (_("Unrecognized debug option '%s'\n"), p);
p = strchr (p, ',');
else if (argc < 3)
{
warn (_("Nothing to do.\n"));
- usage();
+ usage ();
}
}
for (j = 0, sec = section_headers;
j < elf_header.e_shnum;
j++, sec++)
- if (strcmp (SECTION_NAME (sec), ".dynamic") == 0)
+ if (streq (SECTION_NAME (sec), ".dynamic"))
break;
if (j == elf_header.e_shnum || sec->sh_size == 0)
dynamic_symbols = GET_ELF_SYMBOLS (file, section);
}
else if (section->sh_type == SHT_STRTAB
- && strcmp (name, ".dynstr") == 0)
+ && streq (name, ".dynstr"))
{
if (dynamic_strings != NULL)
{
dynamic_strings = get_data (NULL, file, section->sh_offset,
section->sh_size, _("dynamic strings"));
+ dynamic_strings_length = section->sh_size;
}
else if (section->sh_type == SHT_SYMTAB_SHNDX)
{
else if ((do_debugging || do_debug_info || do_debug_abbrevs
|| do_debug_lines || do_debug_pubnames || do_debug_aranges
|| do_debug_frames || do_debug_macinfo || do_debug_str
- || do_debug_loc)
- && strncmp (name, ".debug_", 7) == 0)
+ || do_debug_loc || do_debug_ranges)
+ && strneq (name, ".debug_", 7))
{
name += 7;
if (do_debugging
- || (do_debug_info && (strcmp (name, "info") == 0))
- || (do_debug_abbrevs && (strcmp (name, "abbrev") == 0))
- || (do_debug_lines && (strcmp (name, "line") == 0))
- || (do_debug_pubnames && (strcmp (name, "pubnames") == 0))
- || (do_debug_aranges && (strcmp (name, "aranges") == 0))
- || (do_debug_frames && (strcmp (name, "frame") == 0))
- || (do_debug_macinfo && (strcmp (name, "macinfo") == 0))
- || (do_debug_str && (strcmp (name, "str") == 0))
- || (do_debug_loc && (strcmp (name, "loc") == 0))
+ || (do_debug_info && streq (name, "info"))
+ || (do_debug_abbrevs && streq (name, "abbrev"))
+ || (do_debug_lines && streq (name, "line"))
+ || (do_debug_pubnames && streq (name, "pubnames"))
+ || (do_debug_aranges && streq (name, "aranges"))
+ || (do_debug_ranges && streq (name, "ranges"))
+ || (do_debug_frames && streq (name, "frame"))
+ || (do_debug_macinfo && streq (name, "macinfo"))
+ || (do_debug_str && streq (name, "str"))
+ || (do_debug_loc && streq (name, "loc"))
)
request_dump (i, DEBUG_DUMP);
}
/* linkonce section to be combined with .debug_info at link time. */
else if ((do_debugging || do_debug_info)
- && strncmp (name, ".gnu.linkonce.wi.", 17) == 0)
+ && strneq (name, ".gnu.linkonce.wi.", 17))
request_dump (i, DEBUG_DUMP);
- else if (do_debug_frames && strcmp (name, ".eh_frame") == 0)
+ else if (do_debug_frames && streq (name, ".eh_frame"))
request_dump (i, DEBUG_DUMP);
}
group->root = g;
}
+ if (symtab)
+ free (symtab);
if (strtab)
free (strtab);
if (start)
};
/* Process the reloc section. */
+
static int
process_relocs (FILE *file)
{
offset_from_vma (file, rel_offset, rel_size),
rel_size,
dynamic_symbols, num_dynamic_syms,
- dynamic_strings, is_rela);
+ dynamic_strings, dynamic_strings_length, is_rela);
}
}
if (rel_size)
{
Elf_Internal_Shdr *strsec;
- Elf_Internal_Sym *symtab;
- char *strtab;
int is_rela;
- unsigned long nsyms;
printf (_("\nRelocation section "));
printf (_(" at offset 0x%lx contains %lu entries:\n"),
rel_offset, (unsigned long) (rel_size / section->sh_entsize));
- symtab = NULL;
- strtab = NULL;
- nsyms = 0;
+ is_rela = section->sh_type == SHT_RELA;
+
if (section->sh_link)
{
Elf_Internal_Shdr *symsec;
+ Elf_Internal_Sym *symtab;
+ unsigned long nsyms;
+ unsigned long strtablen;
+ char *strtab = NULL;
symsec = SECTION_HEADER (section->sh_link);
nsyms = symsec->sh_size / symsec->sh_entsize;
strtab = get_data (NULL, file, strsec->sh_offset,
strsec->sh_size, _("string table"));
- }
- is_rela = section->sh_type == SHT_RELA;
-
- dump_relocations (file, rel_offset, rel_size,
- symtab, nsyms, strtab, is_rela);
+ strtablen = strtab == NULL ? 0 : strsec->sh_size;
- if (strtab)
- free (strtab);
- if (symtab)
- free (symtab);
+ dump_relocations (file, rel_offset, rel_size,
+ symtab, nsyms, strtab, strtablen, is_rela);
+ if (strtab)
+ free (strtab);
+ free (symtab);
+ }
+ else
+ dump_relocations (file, rel_offset, rel_size,
+ NULL, 0, NULL, 0, is_rela);
found = 1;
}
return 1;
}
+/* Process the unwind section. */
+
#include "unwind-ia64.h"
/* An absolute address consists of a section and an offset. If the
bfd_vma offset;
};
-struct unw_aux_info
+struct ia64_unw_aux_info
{
- struct unw_table_entry
+ struct ia64_unw_table_entry
{
struct absaddr start;
struct absaddr end;
};
static void
-find_symbol_for_address (struct unw_aux_info *aux,
+find_symbol_for_address (Elf_Internal_Sym *symtab,
+ unsigned long nsyms,
+ const char *strtab,
+ unsigned long strtab_size,
struct absaddr addr,
const char **symname,
bfd_vma *offset)
Elf_Internal_Sym *sym, *best = NULL;
unsigned long i;
- for (i = 0, sym = aux->symtab; i < aux->nsyms; ++i, ++sym)
+ for (i = 0, sym = symtab; i < nsyms; ++i, ++sym)
{
if (ELF_ST_TYPE (sym->st_info) == STT_FUNC
&& sym->st_name != 0
}
if (best)
{
- *symname = (best->st_name >= aux->strtab_size
- ? "<corrupt>" : aux->strtab + best->st_name);
+ *symname = (best->st_name >= strtab_size
+ ? "<corrupt>" : strtab + best->st_name);
*offset = dist;
return;
}
}
static void
-dump_ia64_unwind (struct unw_aux_info *aux)
+dump_ia64_unwind (struct ia64_unw_aux_info *aux)
{
bfd_vma addr_size;
- struct unw_table_entry *tp;
+ struct ia64_unw_table_entry *tp;
int in_body;
addr_size = is_32bit_elf ? 4 : 8;
const unsigned char *head;
const char *procname;
- find_symbol_for_address (aux, tp->start, &procname, &offset);
+ find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab,
+ aux->strtab_size, tp->start, &procname, &offset);
fputs ("\n<", stdout);
static int
slurp_ia64_unwind_table (FILE *file,
- struct unw_aux_info *aux,
+ struct ia64_unw_aux_info *aux,
Elf_Internal_Shdr *sec)
{
unsigned long size, addr_size, nrelas, i;
Elf_Internal_Phdr *seg;
- struct unw_table_entry *tep;
+ struct ia64_unw_table_entry *tep;
Elf_Internal_Shdr *relsec;
Elf_Internal_Rela *rela, *rp;
unsigned char *table, *tp;
{
relname = elf_ia64_reloc_type (ELF32_R_TYPE (rp->r_info));
sym = aux->symtab + ELF32_R_SYM (rp->r_info);
-
- if (ELF32_ST_TYPE (sym->st_info) != STT_SECTION)
- {
- warn (_("Skipping unexpected symbol type %u\n"),
- ELF32_ST_TYPE (sym->st_info));
- continue;
- }
}
else
{
relname = elf_ia64_reloc_type (ELF64_R_TYPE (rp->r_info));
sym = aux->symtab + ELF64_R_SYM (rp->r_info);
-
- if (ELF64_ST_TYPE (sym->st_info) != STT_SECTION)
- {
- warn (_("Skipping unexpected symbol type %u\n"),
- ELF64_ST_TYPE (sym->st_info));
- continue;
- }
}
- if (strncmp (relname, "R_IA64_SEGREL", 13) != 0)
+ if (! strneq (relname, "R_IA64_SEGREL", 13))
{
warn (_("Skipping unexpected relocation type %s\n"), relname);
continue;
{
case 0:
aux->table[i].start.section = sym->st_shndx;
- aux->table[i].start.offset += rp->r_addend;
+ aux->table[i].start.offset += rp->r_addend + sym->st_value;
break;
case 1:
aux->table[i].end.section = sym->st_shndx;
- aux->table[i].end.offset += rp->r_addend;
+ aux->table[i].end.offset += rp->r_addend + sym->st_value;
break;
case 2:
aux->table[i].info.section = sym->st_shndx;
- aux->table[i].info.offset += rp->r_addend;
+ aux->table[i].info.offset += rp->r_addend + sym->st_value;
break;
default:
break;
}
static int
-process_unwind (FILE *file)
+ia64_process_unwind (FILE *file)
{
Elf_Internal_Shdr *sec, *unwsec = NULL, *strsec;
unsigned long i, addr_size, unwcount = 0, unwstart = 0;
- struct unw_aux_info aux;
-
- if (!do_unwind)
- return 1;
-
- if (elf_header.e_machine != EM_IA_64)
- {
- printf (_("\nThere are no unwind sections in this file.\n"));
- return 1;
- }
+ struct ia64_unw_aux_info aux;
memset (& aux, 0, sizeof (aux));
for (; g != NULL; g = g->next)
{
sec = SECTION_HEADER (g->section_index);
- if (strcmp (SECTION_NAME (sec),
- ELF_STRING_ia64_unwind_info) == 0)
- break;
+
+ if (streq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info))
+ break;
}
if (g == NULL)
i = elf_header.e_shnum;
}
- else if (strncmp (SECTION_NAME (unwsec),
- ELF_STRING_ia64_unwind_once, len) == 0)
+ else if (strneq (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind_once, len))
{
- /* .gnu.linkonce.ia64unw.FOO -> .gnu.linkonce.ia64unwi.FOO */
+ /* .gnu.linkonce.ia64unw.FOO -> .gnu.linkonce.ia64unwi.FOO. */
len2 = sizeof (ELF_STRING_ia64_unwind_info_once) - 1;
suffix = SECTION_NAME (unwsec) + len;
for (i = 0, sec = section_headers; i < elf_header.e_shnum;
++i, ++sec)
- if (strncmp (SECTION_NAME (sec),
- ELF_STRING_ia64_unwind_info_once, len2) == 0
- && strcmp (SECTION_NAME (sec) + len2, suffix) == 0)
+ if (strneq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info_once, len2)
+ && streq (SECTION_NAME (sec) + len2, suffix))
break;
}
else
{
/* .IA_64.unwindFOO -> .IA_64.unwind_infoFOO
- .IA_64.unwind or BAR -> .IA_64.unwind_info */
+ .IA_64.unwind or BAR -> .IA_64.unwind_info. */
len = sizeof (ELF_STRING_ia64_unwind) - 1;
len2 = sizeof (ELF_STRING_ia64_unwind_info) - 1;
suffix = "";
- if (strncmp (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind,
- len) == 0)
+ if (strneq (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind, len))
suffix = SECTION_NAME (unwsec) + len;
for (i = 0, sec = section_headers; i < elf_header.e_shnum;
++i, ++sec)
- if (strncmp (SECTION_NAME (sec),
- ELF_STRING_ia64_unwind_info, len2) == 0
- && strcmp (SECTION_NAME (sec) + len2, suffix) == 0)
+ if (strneq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info, len2)
+ && streq (SECTION_NAME (sec) + len2, suffix))
break;
}
return 1;
}
+struct hppa_unw_aux_info
+ {
+ struct hppa_unw_table_entry
+ {
+ struct absaddr start;
+ struct absaddr end;
+ unsigned int Cannot_unwind:1; /* 0 */
+ unsigned int Millicode:1; /* 1 */
+ unsigned int Millicode_save_sr0:1; /* 2 */
+ unsigned int Region_description:2; /* 3..4 */
+ unsigned int reserved1:1; /* 5 */
+ unsigned int Entry_SR:1; /* 6 */
+ unsigned int Entry_FR:4; /* number saved */ /* 7..10 */
+ unsigned int Entry_GR:5; /* number saved */ /* 11..15 */
+ unsigned int Args_stored:1; /* 16 */
+ unsigned int Variable_Frame:1; /* 17 */
+ unsigned int Separate_Package_Body:1; /* 18 */
+ unsigned int Frame_Extension_Millicode:1; /* 19 */
+ unsigned int Stack_Overflow_Check:1; /* 20 */
+ unsigned int Two_Instruction_SP_Increment:1; /* 21 */
+ unsigned int Ada_Region:1; /* 22 */
+ unsigned int cxx_info:1; /* 23 */
+ unsigned int cxx_try_catch:1; /* 24 */
+ unsigned int sched_entry_seq:1; /* 25 */
+ unsigned int reserved2:1; /* 26 */
+ unsigned int Save_SP:1; /* 27 */
+ unsigned int Save_RP:1; /* 28 */
+ unsigned int Save_MRP_in_frame:1; /* 29 */
+ unsigned int extn_ptr_defined:1; /* 30 */
+ unsigned int Cleanup_defined:1; /* 31 */
+
+ unsigned int MPE_XL_interrupt_marker:1; /* 0 */
+ unsigned int HP_UX_interrupt_marker:1; /* 1 */
+ unsigned int Large_frame:1; /* 2 */
+ unsigned int Pseudo_SP_Set:1; /* 3 */
+ unsigned int reserved4:1; /* 4 */
+ unsigned int Total_frame_size:27; /* 5..31 */
+ }
+ *table; /* Unwind table. */
+ unsigned long table_len; /* Length of unwind table. */
+ bfd_vma seg_base; /* Starting address of segment. */
+ Elf_Internal_Sym *symtab; /* The symbol table. */
+ unsigned long nsyms; /* Number of symbols. */
+ char *strtab; /* The string table. */
+ unsigned long strtab_size; /* Size of string table. */
+ };
+
+static void
+dump_hppa_unwind (struct hppa_unw_aux_info *aux)
+{
+ bfd_vma addr_size;
+ struct hppa_unw_table_entry *tp;
+
+ addr_size = is_32bit_elf ? 4 : 8;
+ for (tp = aux->table; tp < aux->table + aux->table_len; ++tp)
+ {
+ bfd_vma offset;
+ const char *procname;
+
+ find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab,
+ aux->strtab_size, tp->start, &procname,
+ &offset);
+
+ fputs ("\n<", stdout);
+
+ if (procname)
+ {
+ fputs (procname, stdout);
+
+ if (offset)
+ printf ("+%lx", (unsigned long) offset);
+ }
+
+ fputs (">: [", stdout);
+ print_vma (tp->start.offset, PREFIX_HEX);
+ fputc ('-', stdout);
+ print_vma (tp->end.offset, PREFIX_HEX);
+ printf ("]\n\t");
+
+#define PF(_m) if (tp->_m) printf (#_m " ");
+#define PV(_m) if (tp->_m) printf (#_m "=%d ", tp->_m);
+ PF(Cannot_unwind);
+ PF(Millicode);
+ PF(Millicode_save_sr0);
+ /* PV(Region_description); */
+ PF(Entry_SR);
+ PV(Entry_FR);
+ PV(Entry_GR);
+ PF(Args_stored);
+ PF(Variable_Frame);
+ PF(Separate_Package_Body);
+ PF(Frame_Extension_Millicode);
+ PF(Stack_Overflow_Check);
+ PF(Two_Instruction_SP_Increment);
+ PF(Ada_Region);
+ PF(cxx_info);
+ PF(cxx_try_catch);
+ PF(sched_entry_seq);
+ PF(Save_SP);
+ PF(Save_RP);
+ PF(Save_MRP_in_frame);
+ PF(extn_ptr_defined);
+ PF(Cleanup_defined);
+ PF(MPE_XL_interrupt_marker);
+ PF(HP_UX_interrupt_marker);
+ PF(Large_frame);
+ PF(Pseudo_SP_Set);
+ PV(Total_frame_size);
+#undef PF
+#undef PV
+ }
+
+ printf ("\n");
+}
+
+static int
+slurp_hppa_unwind_table (FILE *file,
+ struct hppa_unw_aux_info *aux,
+ Elf_Internal_Shdr *sec)
+{
+ unsigned long size, unw_ent_size, addr_size, nrelas, i;
+ Elf_Internal_Phdr *seg;
+ struct hppa_unw_table_entry *tep;
+ Elf_Internal_Shdr *relsec;
+ Elf_Internal_Rela *rela, *rp;
+ unsigned char *table, *tp;
+ Elf_Internal_Sym *sym;
+ const char *relname;
+
+ addr_size = is_32bit_elf ? 4 : 8;
+
+ /* First, find the starting address of the segment that includes
+ this section. */
+
+ if (elf_header.e_phnum)
+ {
+ if (! get_program_headers (file))
+ return 0;
+
+ for (seg = program_headers;
+ seg < program_headers + elf_header.e_phnum;
+ ++seg)
+ {
+ if (seg->p_type != PT_LOAD)
+ continue;
+
+ if (sec->sh_addr >= seg->p_vaddr
+ && (sec->sh_addr + sec->sh_size <= seg->p_vaddr + seg->p_memsz))
+ {
+ aux->seg_base = seg->p_vaddr;
+ break;
+ }
+ }
+ }
+
+ /* Second, build the unwind table from the contents of the unwind
+ section. */
+ size = sec->sh_size;
+ table = get_data (NULL, file, sec->sh_offset, size, _("unwind table"));
+ if (!table)
+ return 0;
+
+ unw_ent_size = 2 * addr_size + 8;
+
+ tep = aux->table = xmalloc (size / unw_ent_size * sizeof (aux->table[0]));
+
+ for (tp = table; tp < table + size; tp += (2 * addr_size + 8), ++tep)
+ {
+ unsigned int tmp1, tmp2;
+
+ tep->start.section = SHN_UNDEF;
+ tep->end.section = SHN_UNDEF;
+
+ if (is_32bit_elf)
+ {
+ tep->start.offset = byte_get ((unsigned char *) tp + 0, 4);
+ tep->end.offset = byte_get ((unsigned char *) tp + 4, 4);
+ tmp1 = byte_get ((unsigned char *) tp + 8, 4);
+ tmp2 = byte_get ((unsigned char *) tp + 12, 4);
+ }
+ else
+ {
+ tep->start.offset = BYTE_GET8 ((unsigned char *) tp + 0);
+ tep->end.offset = BYTE_GET8 ((unsigned char *) tp + 8);
+ tmp1 = byte_get ((unsigned char *) tp + 16, 4);
+ tmp2 = byte_get ((unsigned char *) tp + 20, 4);
+ }
+
+ tep->Cannot_unwind = (tmp1 >> 31) & 0x1;
+ tep->Millicode = (tmp1 >> 30) & 0x1;
+ tep->Millicode_save_sr0 = (tmp1 >> 29) & 0x1;
+ tep->Region_description = (tmp1 >> 27) & 0x3;
+ tep->reserved1 = (tmp1 >> 26) & 0x1;
+ tep->Entry_SR = (tmp1 >> 25) & 0x1;
+ tep->Entry_FR = (tmp1 >> 21) & 0xf;
+ tep->Entry_GR = (tmp1 >> 16) & 0x1f;
+ tep->Args_stored = (tmp1 >> 15) & 0x1;
+ tep->Variable_Frame = (tmp1 >> 14) & 0x1;
+ tep->Separate_Package_Body = (tmp1 >> 13) & 0x1;
+ tep->Frame_Extension_Millicode = (tmp1 >> 12) & 0x1;
+ tep->Stack_Overflow_Check = (tmp1 >> 11) & 0x1;
+ tep->Two_Instruction_SP_Increment = (tmp1 >> 10) & 0x1;
+ tep->Ada_Region = (tmp1 >> 9) & 0x1;
+ tep->cxx_info = (tmp1 >> 8) & 0x1;
+ tep->cxx_try_catch = (tmp1 >> 7) & 0x1;
+ tep->sched_entry_seq = (tmp1 >> 6) & 0x1;
+ tep->reserved2 = (tmp1 >> 5) & 0x1;
+ tep->Save_SP = (tmp1 >> 4) & 0x1;
+ tep->Save_RP = (tmp1 >> 3) & 0x1;
+ tep->Save_MRP_in_frame = (tmp1 >> 2) & 0x1;
+ tep->extn_ptr_defined = (tmp1 >> 1) & 0x1;
+ tep->Cleanup_defined = tmp1 & 0x1;
+
+ tep->MPE_XL_interrupt_marker = (tmp2 >> 31) & 0x1;
+ tep->HP_UX_interrupt_marker = (tmp2 >> 30) & 0x1;
+ tep->Large_frame = (tmp2 >> 29) & 0x1;
+ tep->Pseudo_SP_Set = (tmp2 >> 28) & 0x1;
+ tep->reserved4 = (tmp2 >> 27) & 0x1;
+ tep->Total_frame_size = tmp2 & 0x7ffffff;
+
+ tep->start.offset += aux->seg_base;
+ tep->end.offset += aux->seg_base;
+ }
+ free (table);
+
+ /* Third, apply any relocations to the unwind table. */
+
+ for (relsec = section_headers;
+ relsec < section_headers + elf_header.e_shnum;
+ ++relsec)
+ {
+ if (relsec->sh_type != SHT_RELA
+ || SECTION_HEADER (relsec->sh_info) != sec)
+ continue;
+
+ if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
+ & rela, & nrelas))
+ return 0;
+
+ for (rp = rela; rp < rela + nrelas; ++rp)
+ {
+ if (is_32bit_elf)
+ {
+ relname = elf_hppa_reloc_type (ELF32_R_TYPE (rp->r_info));
+ sym = aux->symtab + ELF32_R_SYM (rp->r_info);
+ }
+ else
+ {
+ relname = elf_hppa_reloc_type (ELF64_R_TYPE (rp->r_info));
+ sym = aux->symtab + ELF64_R_SYM (rp->r_info);
+ }
+
+ /* R_PARISC_SEGREL32 or R_PARISC_SEGREL64. */
+ if (strncmp (relname, "R_PARISC_SEGREL", 15) != 0)
+ {
+ warn (_("Skipping unexpected relocation type %s\n"), relname);
+ continue;
+ }
+
+ i = rp->r_offset / unw_ent_size;
+
+ switch ((rp->r_offset % unw_ent_size) / addr_size)
+ {
+ case 0:
+ aux->table[i].start.section = sym->st_shndx;
+ aux->table[i].start.offset += sym->st_value + rp->r_addend;
+ break;
+ case 1:
+ aux->table[i].end.section = sym->st_shndx;
+ aux->table[i].end.offset += sym->st_value + rp->r_addend;
+ break;
+ default:
+ break;
+ }
+ }
+
+ free (rela);
+ }
+
+ aux->table_len = size / unw_ent_size;
+
+ return 1;
+}
+
+static int
+hppa_process_unwind (FILE *file)
+{
+ struct hppa_unw_aux_info aux;
+ Elf_Internal_Shdr *unwsec = NULL;
+ Elf_Internal_Shdr *strsec;
+ Elf_Internal_Shdr *sec;
+ unsigned long addr_size;
+ unsigned long i;
+
+ memset (& aux, 0, sizeof (aux));
+
+ assert (string_table != NULL);
+ addr_size = is_32bit_elf ? 4 : 8;
+
+ for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
+ {
+ if (sec->sh_type == SHT_SYMTAB)
+ {
+ aux.nsyms = sec->sh_size / sec->sh_entsize;
+ aux.symtab = GET_ELF_SYMBOLS (file, sec);
+
+ strsec = SECTION_HEADER (sec->sh_link);
+ aux.strtab_size = strsec->sh_size;
+ aux.strtab = get_data (NULL, file, strsec->sh_offset,
+ aux.strtab_size, _("string table"));
+ }
+ else if (streq (SECTION_NAME (sec), ".PARISC.unwind"))
+ unwsec = sec;
+ }
+
+ if (!unwsec)
+ printf (_("\nThere are no unwind sections in this file.\n"));
+
+ for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
+ {
+ if (streq (SECTION_NAME (sec), ".PARISC.unwind"))
+ {
+ printf (_("\nUnwind section "));
+ printf (_("'%s'"), SECTION_NAME (sec));
+
+ printf (_(" at offset 0x%lx contains %lu entries:\n"),
+ (unsigned long) sec->sh_offset,
+ (unsigned long) (sec->sh_size / (2 * addr_size + 8)));
+
+ slurp_hppa_unwind_table (file, &aux, sec);
+ if (aux.table_len > 0)
+ dump_hppa_unwind (&aux);
+
+ if (aux.table)
+ free ((char *) aux.table);
+ aux.table = NULL;
+ }
+ }
+
+ if (aux.symtab)
+ free (aux.symtab);
+ if (aux.strtab)
+ free ((char *) aux.strtab);
+
+ return 1;
+}
+
+static int
+process_unwind (FILE *file)
+{
+ struct unwind_handler {
+ int machtype;
+ int (*handler)(FILE *file);
+ } handlers[] = {
+ { EM_IA_64, ia64_process_unwind },
+ { EM_PARISC, hppa_process_unwind },
+ { 0, 0 }
+ };
+ int i;
+
+ if (!do_unwind)
+ return 1;
+
+ for (i = 0; handlers[i].handler != NULL; i++)
+ if (elf_header.e_machine == handlers[i].machtype)
+ return handlers[i].handler (file);
+
+ printf (_("\nThere are no unwind sections in this file.\n"));
+ return 1;
+}
+
static void
dynamic_section_mips_val (Elf_Internal_Dyn *entry)
{
break;
case DT_MIPS_IVERSION:
- if (dynamic_strings != NULL)
- printf ("Interface Version: %s\n",
- dynamic_strings + entry->d_un.d_val);
+ if (VALID_DYNAMIC_NAME (entry->d_un.d_val))
+ printf ("Interface Version: %s\n", GET_DYNAMIC_NAME (entry->d_un.d_val));
else
- printf ("%ld\n", (long) entry->d_un.d_ptr);
+ printf ("<corrupt: %ld>\n", (long) entry->d_un.d_ptr);
break;
case DT_MIPS_TIME_STAMP:
dynamic_strings = get_data (NULL, file, offset, str_tab_len,
_("dynamic string table"));
+ dynamic_strings_length = str_tab_len;
break;
}
}
break;
}
- if (dynamic_strings)
- printf (": [%s]\n", dynamic_strings + entry->d_un.d_val);
+ if (VALID_DYNAMIC_NAME (entry->d_un.d_val))
+ printf (": [%s]\n", GET_DYNAMIC_NAME (entry->d_un.d_val));
else
{
printf (": ");
{
char *name;
- if (dynamic_strings == NULL)
- name = NULL;
+ if (VALID_DYNAMIC_NAME (entry->d_un.d_val))
+ name = GET_DYNAMIC_NAME (entry->d_un.d_val);
else
- name = dynamic_strings + entry->d_un.d_val;
+ name = NULL;
if (name)
{
case DT_NEEDED:
printf (_("Shared library: [%s]"), name);
- if (strcmp (name, program_interpreter) == 0)
+ if (streq (name, program_interpreter))
printf (_(" program interpreter"));
break;
case DT_FINI_ARRAY:
if (do_dynamic)
{
- if (dynamic_strings != NULL && entry->d_tag == DT_USED)
+ if (entry->d_tag == DT_USED
+ && VALID_DYNAMIC_NAME (entry->d_un.d_val))
{
- char *name;
-
- name = dynamic_strings + entry->d_un.d_val;
+ char *name = GET_DYNAMIC_NAME (entry->d_un.d_val);
if (*name)
{
aux.vda_name = BYTE_GET (eaux->vda_name);
aux.vda_next = BYTE_GET (eaux->vda_next);
- if (dynamic_strings)
- printf (_("Name: %s\n"), dynamic_strings + aux.vda_name);
+ if (VALID_DYNAMIC_NAME (aux.vda_name))
+ printf (_("Name: %s\n"), GET_DYNAMIC_NAME (aux.vda_name));
else
printf (_("Name index: %ld\n"), aux.vda_name);
aux.vda_name = BYTE_GET (eaux->vda_name);
aux.vda_next = BYTE_GET (eaux->vda_next);
- if (dynamic_strings)
+ if (VALID_DYNAMIC_NAME (aux.vda_name))
printf (_(" %#06x: Parent %d: %s\n"),
- isum, j, dynamic_strings + aux.vda_name);
+ isum, j, GET_DYNAMIC_NAME (aux.vda_name));
else
printf (_(" %#06x: Parent %d, name index: %ld\n"),
isum, j, aux.vda_name);
printf (_(" %#06x: Version: %d"), idx, ent.vn_version);
- if (dynamic_strings)
- printf (_(" File: %s"), dynamic_strings + ent.vn_file);
+ if (VALID_DYNAMIC_NAME (ent.vn_file))
+ printf (_(" File: %s"), GET_DYNAMIC_NAME (ent.vn_file));
else
printf (_(" File: %lx"), ent.vn_file);
aux.vna_name = BYTE_GET (eaux->vna_name);
aux.vna_next = BYTE_GET (eaux->vna_next);
- if (dynamic_strings)
+ if (VALID_DYNAMIC_NAME (aux.vna_name))
printf (_(" %#06x: Name: %s"),
- isum, dynamic_strings + aux.vna_name);
+ isum, GET_DYNAMIC_NAME (aux.vna_name));
else
printf (_(" %#06x: Name index: %lx"),
isum, aux.vna_name);
printf (" %6s", get_symbol_binding (ELF_ST_BIND (psym->st_info)));
printf (" %3s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other)));
printf (" %3.3s ", get_symbol_index_type (psym->st_shndx));
- print_symbol (25, dynamic_strings + psym->st_name);
+ if (VALID_DYNAMIC_NAME (psym->st_name))
+ print_symbol (25, GET_DYNAMIC_NAME (psym->st_name));
+ else
+ printf (" <corrupt: %14ld>", psym->st_name);
putchar ('\n');
}
}
unsigned short int flags = dynamic_syminfo[i].si_flags;
printf ("%4d: ", i);
- print_symbol (30, dynamic_strings + dynamic_symbols[i].st_name);
+ if (VALID_DYNAMIC_NAME (dynamic_symbols[i].st_name))
+ print_symbol (30, GET_DYNAMIC_NAME (dynamic_symbols[i].st_name));
+ else
+ printf ("<corrupt: %19ld>", dynamic_symbols[i].st_name);
putchar (' ');
switch (dynamic_syminfo[i].si_boundto)
break;
default:
if (dynamic_syminfo[i].si_boundto > 0
- && dynamic_syminfo[i].si_boundto < dynamic_nent)
+ && dynamic_syminfo[i].si_boundto < dynamic_nent
+ && VALID_DYNAMIC_NAME (dynamic_section[dynamic_syminfo[i].si_boundto].d_un.d_val))
{
- print_symbol (10,
- dynamic_strings
- + (dynamic_section
- [dynamic_syminfo[i].si_boundto].d_un.d_val));
+ print_symbol (10, GET_DYNAMIC_NAME (dynamic_section[dynamic_syminfo[i].si_boundto].d_un.d_val));
putchar (' ' );
}
else
}
#ifdef SUPPORT_DISASSEMBLY
-static void
+static int
disassemble_section (Elf_Internal_Shdr *section, FILE *file)
{
printf (_("\nAssembly dump of section %s\n"),
/* Handled an extend line op. Returns true if this is the end
of sequence. */
+
static int
process_extended_line_op (unsigned char *data, int is_stmt, int pointer_size)
{
for (i = elf_header.e_shnum, sec = section_headers + i - 1;
i; --i, --sec)
- if (strcmp (SECTION_NAME (sec), name) == 0)
+ if (streq (SECTION_NAME (sec), name))
break;
if (i && sec && sec->sh_size != 0)
return NULL;
}
-/* Size of pointers in the .debug_line section. This information is not
- really present in that section. It's obtained before dumping the debug
- sections by doing some pre-scan of the .debug_info section. */
-static unsigned int * debug_line_pointer_sizes = NULL;
-static unsigned int num_debug_line_pointer_sizes = 0;
+/* This could just be an array of unsigned integers, but I expect
+ that we will want to extend the structure to contain other
+ information. */
+typedef struct
+{
+ unsigned int pointer_size;
+}
+debug_info;
+
+static debug_info * debug_information = NULL;
+static unsigned int num_debug_info_entries = 0;
+
+static unsigned int
+get_pointer_size_of_comp_unit (unsigned int comp_unit)
+{
+ if (num_debug_info_entries == 0
+ || comp_unit >= num_debug_info_entries)
+ return 0;
+
+ return debug_information [comp_unit].pointer_size;
+}
/* Locate and scan the .debug_info section in the file and record the pointer
sizes for the compilation units in it. Usually an executable will have
compilation units upon success. */
static unsigned int
-get_debug_line_pointer_sizes (FILE * file)
+get_debug_info (FILE * file)
{
Elf_Internal_Shdr * section;
unsigned char * start;
unsigned int num_units;
unsigned int unit;
+ /* If we already have the information there is nothing else to do. */
+ if (num_debug_info_entries > 0)
+ return num_debug_info_entries;
+
section = find_section (".debug_info");
if (section == NULL)
return 0;
length = section->sh_size;
start = get_data (NULL, file, section->sh_offset, section->sh_size,
- _("extracting pointer sizes from .debug_info section"));
+ _("extracting information from .debug_info section"));
if (start == NULL)
return 0;
return 0;
}
- /* Then allocate an array to hold the pointer sizes. */
- debug_line_pointer_sizes = malloc (num_units * sizeof * debug_line_pointer_sizes);
- if (debug_line_pointer_sizes == NULL)
+ /* Then allocate an array to hold the information. */
+ debug_information = malloc (num_units * sizeof * debug_information);
+ if (debug_information == NULL)
{
- error (_("Not enough memory for a pointer size array of %u entries"),
+ error (_("Not enough memory for a debug info array of %u entries"),
num_units);
free (start);
return 0;
-----------------------------
Total: 22 bytes */
- debug_line_pointer_sizes [unit] = byte_get (begin + 22, 1);
+ debug_information [unit].pointer_size = byte_get (begin + 22, 1);
length = byte_get (begin + 4, 8);
begin += length + 12;
}
-----------------------------
Total: 10 bytes */
- debug_line_pointer_sizes [unit] = byte_get (begin + 10, 1);
+ debug_information [unit].pointer_size = byte_get (begin + 10, 1);
begin += length + 4;
}
}
free (start);
- num_debug_line_pointer_sizes = num_units;
- return num_units;
+
+ return num_debug_info_entries = num_units;
}
static int
display_debug_lines (Elf_Internal_Shdr *section,
unsigned char *start, FILE *file)
{
- unsigned char *hdrptr;
- DWARF2_Internal_LineInfo info;
- unsigned char *standard_opcodes;
unsigned char *data = start;
unsigned char *end = start + section->sh_size;
- unsigned char *end_of_sequence;
- int i;
- int offset_size;
- int initial_length_size;
unsigned int comp_unit = 0;
printf (_("\nDump of debug contents of section %s:\n\n"),
SECTION_NAME (section));
- if (num_debug_line_pointer_sizes == 0)
- get_debug_line_pointer_sizes (file);
+ get_debug_info (file);
while (data < end)
{
+ DWARF2_Internal_LineInfo info;
+ unsigned char *standard_opcodes;
+ unsigned char *end_of_sequence;
+ unsigned char *hdrptr;
unsigned int pointer_size;
+ int initial_length_size;
+ int offset_size;
+ int i;
hdrptr = data;
/* Get the pointer size from the comp unit associated
with this block of line number information. */
- if (comp_unit >= num_debug_line_pointer_sizes)
+ pointer_size = get_pointer_size_of_comp_unit (comp_unit);
+ if (pointer_size == 0)
{
- error (_("Not enough comp units for .debug_lines section\n"));
+ error (_("Not enough comp units for .debug_line section\n"));
return 0;
}
- else
- {
- pointer_size = debug_line_pointer_sizes [comp_unit];
- comp_unit ++;
- }
+ comp_unit ++;
printf (_(" Length: %ld\n"), info.li_length);
printf (_(" DWARF Version: %d\n"), info.li_version);
/* Now display the statements. */
printf (_("\n Line Number Statements:\n"));
-
while (data < end_of_sequence)
{
unsigned char op_code;
default:
printf (_(" Unknown opcode %d with operands: "), op_code);
- {
- int i;
- for (i = standard_opcodes[op_code - 1]; i > 0 ; --i)
- {
- printf ("0x%lx%s", read_leb128 (data, &bytes_read, 0),
- i == 1 ? "" : ", ");
- data += bytes_read;
- }
- putchar ('\n');
- }
+
+ for (i = standard_opcodes[op_code - 1]; i > 0 ; --i)
+ {
+ printf ("0x%lx%s", read_leb128 (data, &bytes_read, 0),
+ i == 1 ? "" : ", ");
+ data += bytes_read;
+ }
+ putchar ('\n');
break;
}
}
filenum = read_leb128 (curr, & bytes_read, 0);
curr += bytes_read;
- printf (_(" DW_MACINFO_start_file - lineno: %d filenum: %d\n"), lineno, filenum);
+ printf (_(" DW_MACINFO_start_file - lineno: %d filenum: %d\n"),
+ lineno, filenum);
}
break;
curr += bytes_read;
string = curr;
curr += strlen (string) + 1;
- printf (_(" DW_MACINFO_define - lineno : %d macro : %s\n"), lineno, string);
+ printf (_(" DW_MACINFO_define - lineno : %d macro : %s\n"),
+ lineno, string);
break;
case DW_MACINFO_undef:
curr += bytes_read;
string = curr;
curr += strlen (string) + 1;
- printf (_(" DW_MACINFO_undef - lineno : %d macro : %s\n"), lineno, string);
+ printf (_(" DW_MACINFO_undef - lineno : %d macro : %s\n"),
+ lineno, string);
break;
case DW_MACINFO_vendor_ext:
curr += bytes_read;
string = curr;
curr += strlen (string) + 1;
- printf (_(" DW_MACINFO_vendor_ext - constant : %d string : %s\n"), constant, string);
+ printf (_(" DW_MACINFO_vendor_ext - constant : %d string : %s\n"),
+ constant, string);
}
break;
}
entry->children ? _("has children") : _("no children"));
for (attr = entry->first_attr; attr; attr = attr->next)
- {
- printf (_(" %-18s %s\n"),
- get_AT_name (attr->attribute),
- get_FORM_name (attr->form));
- }
+ printf (_(" %-18s %s\n"),
+ get_AT_name (attr->attribute),
+ get_FORM_name (attr->form));
}
free_abbrevs ();
return 0;
}
- if (num_debug_line_pointer_sizes == 0)
- get_debug_line_pointer_sizes (file);
+ get_debug_info (file);
printf (_("Contents of the .debug_loc section:\n\n"));
printf (_("\n Offset Begin End Expression\n"));
/* Get the pointer size from the comp unit associated
with this block of location information. */
- if (comp_unit >= num_debug_line_pointer_sizes)
+ pointer_size = get_pointer_size_of_comp_unit (comp_unit);
+ if (pointer_size == 0)
{
error (_("Not enough comp units for .debug_loc section\n"));
return 0;
}
- else
- {
- pointer_size = debug_line_pointer_sizes [comp_unit];
- comp_unit ++;
- }
+ comp_unit ++;
while (1)
{
return 1;
}
+static const char * debug_range_contents;
+static unsigned long debug_range_size;
+
+static void
+load_debug_range (FILE *file)
+{
+ Elf_Internal_Shdr *sec;
+
+ /* If it is already loaded, do nothing. */
+ if (debug_range_contents != NULL)
+ return;
+
+ /* Locate the .debug_str section. */
+ sec = find_section (".debug_ranges");
+ if (sec == NULL)
+ return;
+
+ debug_range_size = sec->sh_size;
+
+ debug_range_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size,
+ _("debug_range section data"));
+}
+
+static void
+free_debug_range (void)
+{
+ if (debug_range_contents == NULL)
+ return;
+
+ free ((char *) debug_range_contents);
+ debug_range_contents = NULL;
+ debug_range_size = 0;
+}
+
+
+/* Decode a DW_AT_ranges attribute for 64bit DWARF3 . */
+
+static void
+decode_64bit_range (unsigned long offset, bfd_vma base_address)
+{
+ const char * start = debug_range_contents + offset;
+ const char * end = debug_range_contents + debug_range_size;
+
+ do
+ {
+ bfd_vma a;
+ bfd_vma b;
+
+ a = byte_get ((unsigned char *) start, 8);
+ b = byte_get ((unsigned char *) start + 8, 8);
+
+ if (a == 0xffffffff)
+ {
+ base_address = b;
+ }
+ else if (a == 0 && b == 0)
+ break;
+ else if (a > b)
+ printf (_(" [corrupt: start > end]"));
+ else
+ {
+ printf (" ");
+ print_vma (base_address + a, PREFIX_HEX);
+ printf (" - ");
+ print_vma (base_address + b, PREFIX_HEX);
+ printf (", ");
+ }
+
+ start += 16;
+ }
+ while (start < end);
+}
+
+/* Decode a DW_AT_ranges attribute. */
+
+static void
+decode_range (unsigned long offset, bfd_vma base_address)
+{
+ const char * start;
+ const char * end;
+
+ if (offset >= (debug_range_size - 8))
+ {
+ printf (_("[corrupt: offset is outside the .debug_ranges section]"));
+ return;
+ }
+
+ /* Since all entries in the .debug_ranges section are pairs of either
+ 4-byte integers (32-bit DWARF3) or 8-byte integers (64-bit DWARF3)
+ the offset should always be a multiple of 8 bytes. */
+ if (offset % 8)
+ {
+ printf (_("[corrupt: offset is not a multiple of 8]"));
+ return;
+ }
+
+ start = debug_range_contents + offset;
+
+ if (offset > 0
+ /* Be paranoid - check to see if the previous
+ two words were and end-of-range marker. */
+ && (byte_get ((unsigned char *) start - 4, 4) != 0
+ || byte_get ((unsigned char *) start - 8, 4) != 0))
+ {
+ printf (_("[corrupt: offset is not at the start of a range]"));
+ return;
+ }
+
+ end = debug_range_contents + debug_range_size;
+
+ printf ("(");
+ do
+ {
+ unsigned long a;
+ unsigned long b;
+
+ a = byte_get ((unsigned char *) start, 4);
+ b = byte_get ((unsigned char *) start + 4, 4);
+
+ if (a == 0xffffffff)
+ {
+ if (b == 0xffffffff)
+ {
+ decode_64bit_range (offset, base_address);
+ return;
+ }
+
+ base_address = b;
+ }
+ else if (a == 0 && b == 0)
+ break;
+ else if (a > b)
+ printf (_("[corrupt: start > end]"));
+ else
+ {
+ if (start > debug_range_contents + offset)
+ printf (", ");
+
+ printf (_("0x%lx - 0x%lx"),
+ (unsigned long) base_address + a,
+ (unsigned long) base_address + b);
+ }
+
+ start += 8;
+ }
+ while (start < end);
+ printf (")");
+}
+
+
static unsigned char *
read_and_display_attr_value (unsigned long attribute,
unsigned long form,
unsigned long offset_size,
int dwarf_version)
{
+ static unsigned long saved_DW_AT_low_pc = 0;
unsigned long uvalue = 0;
unsigned char *block_start = NULL;
int bytes_read;
printf (")");
}
else if (form == DW_FORM_data4 || form == DW_FORM_data8)
- {
- printf ("(");
- printf ("location list");
- printf (")");
- }
+ printf (_("(location list)"));
+
+ break;
+
+ case DW_AT_low_pc:
+ /* This is a hack. We keep track of the DW_AT_low_pc attributes
+ and use them when decoding DW_AT_ranges attributes. The
+ assumption here is that we are decoding the attributes in order
+ and so the correct base address for the range is the low_pc. */
+ saved_DW_AT_low_pc = uvalue;
+ break;
+
+ case DW_AT_ranges:
+ decode_range (uvalue, saved_DW_AT_low_pc);
break;
default:
sym = symtab + ELF32_R_SYM (rp->r_info);
if (ELF32_R_SYM (rp->r_info) != 0
- && ELF32_ST_TYPE (sym->st_info) != STT_SECTION)
+ && ELF32_ST_TYPE (sym->st_info) != STT_SECTION
+ /* Relocations against object symbols can happen,
+ eg when referencing a global array. For an
+ example of this see the _clz.o binary in libgcc.a. */
+ && ELF32_ST_TYPE (sym->st_info) != STT_OBJECT)
{
- warn (_("Skipping unexpected symbol type %u\n"),
- ELF32_ST_TYPE (sym->st_info));
+ warn (_("%s: skipping unexpected symbol type %s in relocation in section .rela%s\n"),
+ get_symbol_type (ELF32_ST_TYPE (sym->st_info)),
+ SECTION_NAME (section));
continue;
}
}
sym = symtab + ELF64_R_SYM (rp->r_info);
if (ELF64_R_SYM (rp->r_info) != 0
- && ELF64_ST_TYPE (sym->st_info) != STT_SECTION)
+ && ELF64_ST_TYPE (sym->st_info) != STT_SECTION
+ && ELF64_ST_TYPE (sym->st_info) != STT_OBJECT)
{
- warn (_("Skipping unexpected symbol type %u\n"),
- ELF64_ST_TYPE (sym->st_info));
+ warn (_("skipping unexpected symbol type %s in relocation in section .rela.%s\n"),
+ get_symbol_type (ELF64_ST_TYPE (sym->st_info)),
+ SECTION_NAME (section));
continue;
}
}
load_debug_str (file);
load_debug_loc (file);
+ load_debug_range (file);
while (start < end)
{
}
}
+ free_debug_range ();
free_debug_str ();
free_debug_loc ();
return 1;
}
+static int
+display_64bit_debug_ranges (unsigned char * start, unsigned char * end)
+{
+ bfd_vma base_address = 0;
+
+ while (start < end)
+ {
+ bfd_vma a, b;
+
+ a = byte_get (start, 8);
+ b = byte_get (start + 8, 8);
+
+ if (a == 0xffffffffffffffffLL)
+ {
+ printf (_(" set base address to "));
+ print_vma (b, PREFIX_HEX);
+ base_address = b;
+ }
+ else if (a == 0 && b == 0)
+ printf ( _("end of range"));
+ else if (a > b)
+ printf (_(" <corrupt range entry, start is greater than end>"));
+ else if (base_address == 0)
+ {
+ printf ("range from base address + ");
+ print_vma (a, PREFIX_HEX);
+ printf (" to base address + ");
+ print_vma (b, PREFIX_HEX);
+ }
+ else
+ {
+ printf ("range from ");
+ print_vma (base_address + a, PREFIX_HEX);
+ printf (" to ");
+ print_vma (base_address + b, PREFIX_HEX);
+ }
+
+ start += 16;
+ printf ("\n");
+ }
+
+ return 1;
+}
+
+static int
+display_debug_ranges (Elf_Internal_Shdr *section,
+ unsigned char *start,
+ FILE *file ATTRIBUTE_UNUSED)
+{
+ unsigned long base_address = 0;
+ unsigned char *end = start + section->sh_size;
+
+ printf (_("The section %s contains:\n\n"), SECTION_NAME (section));
+
+ while (start < end)
+ {
+ unsigned long a;
+ unsigned long b;
+
+ a = byte_get (start, 4);
+ b = byte_get (start + 4, 4);
+
+ if (a == 0xffffffff)
+ {
+ /* Attempt to handle 64-bit DWARF3 format. This assumes
+ that in a 32-bit DWARF3 file the base address will
+ never be 0xffffffff, and that the .debug_ranges section
+ will never contain a mixture of 32-bit and 64-bit entries. */
+ if (b == 0xffffffff)
+ return display_64bit_debug_ranges (start, end);
+
+ printf (_(" set base address to 0x%lx\n"), b);
+ base_address = b;
+ }
+ else if (a == 0 && b == 0)
+ printf (_(" end of range\n"));
+ else if (a > b)
+ printf (_(" <corrupt range entry, start is greater than end>\n"));
+ else if (base_address == 0)
+ printf (_(" range from base address + 0x%lx to base address + 0x%lx\n"), a, b);
+ else
+ printf (_(" range from 0x%lx to 0x%lx\n"), base_address + a, base_address + b);
+
+ start += 8;
+ }
+
+ return 1;
+}
+
typedef struct Frame_Chunk
{
struct Frame_Chunk *next;
Frame_Chunk *chunks = 0;
Frame_Chunk *remembered_state = 0;
Frame_Chunk *rs;
- int is_eh = (strcmp (SECTION_NAME (section), ".eh_frame") == 0);
+ int is_eh = streq (SECTION_NAME (section), ".eh_frame");
int length_return;
int max_regs = 0;
int addr_size = is_32bit_elf ? 4 : 8;
augmentation_data = start;
start += augmentation_data_len;
}
- else if (strcmp (fc->augmentation, "eh") == 0)
+ else if (streq (fc->augmentation, "eh"))
{
start += addr_size;
fc->code_factor = LEB ();
}
}
- /* At this point, fc is the current chunk, cie (if any) is set, and we're
- about to interpret instructions for the chunk. */
+ /* At this point, fc is the current chunk, cie (if any) is set, and
+ we're about to interpret instructions for the chunk. */
/* ??? At present we need to do this always, since this sizes the
fc->col_type and fc->col_offset arrays, which we write into always.
We should probably split the interpreted and non-interpreted bits
break;
default:
- fprintf (stderr, "unsupported or unknown DW_CFA_%d\n", op);
+ warn (_("unsupported or unknown DW_CFA_%d\n"), op);
start = block_end;
}
}
{ ".debug_str", display_debug_str },
{ ".debug_loc", display_debug_loc },
{ ".debug_pubtypes", display_debug_pubnames },
- { ".debug_ranges", display_debug_not_supported },
+ { ".debug_ranges", display_debug_ranges },
{ ".debug_static_func", display_debug_not_supported },
{ ".debug_static_vars", display_debug_not_supported },
{ ".debug_types", display_debug_not_supported },
{
char *name = SECTION_NAME (section);
bfd_size_type length;
- unsigned char *start;
+ int result = 1;
int i;
length = section->sh_size;
return 0;
}
- start = get_data (NULL, file, section->sh_offset, length,
- _("debug section data"));
- if (!start)
- return 0;
-
- /* See if we know how to display the contents of this section. */
- if (strncmp (name, ".gnu.linkonce.wi.", 17) == 0)
+ if (strneq (name, ".gnu.linkonce.wi.", 17))
name = ".debug_info";
+ /* See if we know how to display the contents of this section. */
for (i = NUM_ELEM (debug_displays); i--;)
- if (strcmp (debug_displays[i].name, name) == 0)
+ if (streq (debug_displays[i].name, name))
{
- debug_displays[i].display (section, start, file);
+ unsigned char *start;
+
+ start = get_data (NULL, file, section->sh_offset, length,
+ _("debug section data"));
+ if (start == NULL)
+ {
+ result = 0;
+ break;
+ }
+
+ result &= debug_displays[i].display (section, start, file);
+ free (start);
+
+ /* If we loaded in the abbrev section
+ at some point, we must release it here. */
+ free_abbrevs ();
+
break;
}
if (i == -1)
- printf (_("Unrecognized debug section: %s\n"), name);
-
- free (start);
-
- /* If we loaded in the abbrev section at some point,
- we must release it here. */
- free_abbrevs ();
+ {
+ printf (_("Unrecognized debug section: %s\n"), name);
+ result = 0;
+ }
- return 1;
+ return result;
}
-static int
+static void
process_section_contents (FILE *file)
{
Elf_Internal_Shdr *section;
unsigned int i;
if (! do_dump)
- return 1;
+ return;
for (i = 0, section = section_headers;
i < elf_header.e_shnum && i < num_dump_sects;
display_debug_section (section, file);
}
- if (i < num_dump_sects)
- warn (_("Some sections were not dumped because they do not exist!\n"));
-
- return 1;
+ /* Check to see if the user requested a
+ dump of a section that does not exist. */
+ while (i++ < num_dump_sects)
+ if (dump_sects[i])
+ warn (_("Section %d was not dumped because it does not exist!\n"), i);
}
static void
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
printf ("%3lu: ", (unsigned long) cnt);
- print_symbol (20, dynamic_strings + liblist.l_name);
+ if (VALID_DYNAMIC_NAME (liblist.l_name))
+ print_symbol (20, GET_DYNAMIC_NAME (liblist.l_name));
+ else
+ printf ("<corrupt: %9ld>", liblist.l_name);
printf (" %s %#10lx %-7ld", timebuf, liblist.l_checksum,
liblist.l_version);
printf ("%5lu: %8lu ", (unsigned long) cnt, iconf[cnt]);
print_vma (psym->st_value, FULL_HEX);
putchar (' ');
- print_symbol (25, dynamic_strings + psym->st_name);
+ if (VALID_DYNAMIC_NAME (psym->st_name))
+ print_symbol (25, GET_DYNAMIC_NAME (psym->st_name));
+ else
+ printf ("<corrupt: %14ld>", psym->st_name);
putchar ('\n');
}
{
static char buff[64];
- switch (e_type)
- {
- case NT_AUXV: return _("NT_AUXV (auxiliary vector)");
- case NT_PRSTATUS: return _("NT_PRSTATUS (prstatus structure)");
- case NT_FPREGSET: return _("NT_FPREGSET (floating point registers)");
- case NT_PRPSINFO: return _("NT_PRPSINFO (prpsinfo structure)");
- case NT_TASKSTRUCT: return _("NT_TASKSTRUCT (task structure)");
- case NT_PRXFPREG: return _("NT_PRXFPREG (user_xfpregs structure)");
- case NT_PSTATUS: return _("NT_PSTATUS (pstatus structure)");
- case NT_FPREGS: return _("NT_FPREGS (floating point registers)");
- case NT_PSINFO: return _("NT_PSINFO (psinfo structure)");
- case NT_LWPSTATUS: return _("NT_LWPSTATUS (lwpstatus_t structure)");
- case NT_LWPSINFO: return _("NT_LWPSINFO (lwpsinfo_t structure)");
- case NT_WIN32PSTATUS: return _("NT_WIN32PSTATUS (win32_pstatus structure)");
- default:
- sprintf (buff, _("Unknown note type: (0x%08x)"), e_type);
- return buff;
- }
+ if (elf_header.e_type == ET_CORE)
+ switch (e_type)
+ {
+ case NT_AUXV:
+ return _("NT_AUXV (auxiliary vector)");
+ case NT_PRSTATUS:
+ return _("NT_PRSTATUS (prstatus structure)");
+ case NT_FPREGSET:
+ return _("NT_FPREGSET (floating point registers)");
+ case NT_PRPSINFO:
+ return _("NT_PRPSINFO (prpsinfo structure)");
+ case NT_TASKSTRUCT:
+ return _("NT_TASKSTRUCT (task structure)");
+ case NT_PRXFPREG:
+ return _("NT_PRXFPREG (user_xfpregs structure)");
+ case NT_PSTATUS:
+ return _("NT_PSTATUS (pstatus structure)");
+ case NT_FPREGS:
+ return _("NT_FPREGS (floating point registers)");
+ case NT_PSINFO:
+ return _("NT_PSINFO (psinfo structure)");
+ case NT_LWPSTATUS:
+ return _("NT_LWPSTATUS (lwpstatus_t structure)");
+ case NT_LWPSINFO:
+ return _("NT_LWPSINFO (lwpsinfo_t structure)");
+ case NT_WIN32PSTATUS:
+ return _("NT_WIN32PSTATUS (win32_pstatus structure)");
+ default:
+ break;
+ }
+ else
+ switch (e_type)
+ {
+ case NT_VERSION:
+ return _("NT_VERSION (version)");
+ case NT_ARCH:
+ return _("NT_ARCH (architecture)");
+ default:
+ break;
+ }
+
+ sprintf (buff, _("Unknown note type: (0x%08x)"), e_type);
+ return buff;
}
static const char *
const char *nt;
if (pnote->namesz == 0)
- {
- /* If there is no note name, then use the default set of
- note type strings. */
- nt = get_note_type (pnote->type);
- }
- else if (strncmp (pnote->namedata, "NetBSD-CORE", 11) == 0)
- {
- /* NetBSD-specific core file notes. */
- nt = get_netbsd_elfcore_note_type (pnote->type);
- }
+ /* If there is no note name, then use the default set of
+ note type strings. */
+ nt = get_note_type (pnote->type);
+
+ else if (strneq (pnote->namedata, "NetBSD-CORE", 11))
+ /* NetBSD-specific core file notes. */
+ nt = get_netbsd_elfcore_note_type (pnote->type);
+
else
- {
- /* Don't recognize this note name; just use the default set of
- note type strings. */
+ /* Don't recognize this note name; just use the default set of
+ note type strings. */
nt = get_note_type (pnote->type);
- }
printf (" %s\t\t0x%08lx\t%s\n",
pnote->namesz ? pnote->namedata : "(NONE)",
}
static int
-process_corefile_contents (FILE *file)
+process_note_sections (FILE *file)
+{
+ Elf_Internal_Shdr *section;
+ unsigned long i;
+ int res = 1;
+
+ for (i = 0, section = section_headers;
+ i < elf_header.e_shnum;
+ i++, section++)
+ if (section->sh_type == SHT_NOTE)
+ res &= process_corefile_note_segment (file,
+ (bfd_vma) section->sh_offset,
+ (bfd_vma) section->sh_size);
+
+ return res;
+}
+
+static int
+process_notes (FILE *file)
{
/* If we have not been asked to display the notes then do nothing. */
if (! do_notes)
return 1;
- /* If file is not a core file then exit. */
if (elf_header.e_type != ET_CORE)
- return 1;
+ return process_note_sections (file);
/* No program headers means no NOTE segment. */
- if (elf_header.e_phnum == 0)
- {
- printf (_("No note segments present in the core file.\n"));
- return 1;
- }
+ if (elf_header.e_phnum > 0)
+ return process_corefile_note_segments (file);
- return process_corefile_note_segments (file);
+ printf (_("No note segments present in the core file.\n"));
+ return 1;
}
static int
if (show_name)
printf (_("\nFile: %s\n"), file_name);
+ /* Initialise the dump_sects array from the cmdline_dump_sects array.
+ Note we do this even if cmdline_dump_sects is empty because we
+ must make sure that the dump_sets array is zeroed out before each
+ object file is processed. */
+ if (num_dump_sects > num_cmdline_dump_sects)
+ memset (dump_sects, 0, num_dump_sects);
+
+ if (num_cmdline_dump_sects > 0)
+ {
+ if (num_dump_sects == 0)
+ /* A sneaky way of allocating the dump_sects array. */
+ request_dump (num_cmdline_dump_sects, 0);
+
+ assert (num_dump_sects >= num_cmdline_dump_sects);
+ memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects);
+ }
+
if (! process_file_header ())
return 1;
process_section_contents (file);
- process_corefile_contents (file);
+ process_notes (file);
process_gnu_liblist (file);
{
free (dynamic_strings);
dynamic_strings = NULL;
+ dynamic_strings_length = 0;
}
if (dynamic_symbols)
section_groups = NULL;
}
+ if (debug_information)
+ {
+ free (debug_information);
+ debug_information = NULL;
+ num_debug_info_entries = 0;
+ }
+
return 0;
}
if (fread (longnames, longnames_size, 1, file) != 1)
{
free (longnames);
- error(_("%s: failed to read string table\n"), file_name);
+ error (_("%s: failed to read string table\n"), file_name);
return 1;
}
archive_file_offset = ftell (file);
archive_file_size = strtoul (arhdr.ar_size, NULL, 10);
-
+
ret |= process_object (namealc, file);
free (namealc);
main (int argc, char **argv)
{
int err;
- char *cmdline_dump_sects = NULL;
- unsigned num_cmdline_dump_sects = 0;
#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
setlocale (LC_MESSAGES, "");
parse_args (argc, argv);
- if (optind < (argc - 1))
- show_name = 1;
-
- /* When processing more than one file remember the dump requests
- issued on command line to reset them after each file. */
- if (optind + 1 < argc && dump_sects != NULL)
+ if (num_dump_sects > 0)
{
+ /* Make a copy of the dump_sects array. */
cmdline_dump_sects = malloc (num_dump_sects);
if (cmdline_dump_sects == NULL)
error (_("Out of memory allocating dump request table."));
}
}
+ if (optind < (argc - 1))
+ show_name = 1;
+
err = 0;
while (optind < argc)
- {
- err |= process_file (argv[optind++]);
-
- /* Reset dump requests. */
- if (optind < argc && dump_sects != NULL)
- {
- num_dump_sects = num_cmdline_dump_sects;
- if (num_cmdline_dump_sects > 0)
- memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects);
- }
- }
+ err |= process_file (argv[optind++]);
if (dump_sects != NULL)
free (dump_sects);