/* readelf.c -- display contents of an ELF format file
- Copyright (C) 1998, 99, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1998, 99, 2000, 2001 Free Software Foundation, Inc.
Originally developed by Eric Youngdale <eric@andante.jic.com>
Modifications by Nick Clifton <nickc@cygnus.com>
#include "elf/ia64.h"
#include "elf/cris.h"
#include "elf/i860.h"
+#include "elf/x86-64.h"
#include "bucomm.h"
#include "getopt.h"
unsigned int rela_size;
char * dynamic_strings;
char * string_table;
+unsigned long string_table_length;
unsigned long num_dynamic_syms;
Elf_Internal_Sym * dynamic_symbols;
Elf_Internal_Syminfo * dynamic_syminfo;
#endif
#define UNKNOWN -1
-#define SECTION_NAME(X) (string_table + (X)->sh_name)
+#define SECTION_NAME(X) ((X) == NULL ? "<none>" : \
+ ((X)->sh_name >= string_table_length \
+ ? "<corrupt>" : string_table + (X)->sh_name))
#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
}
}
+/* Guess the relocation size commonly used by the specific machines. */
-/* Guess the relocation sized based on the sized commonly used by the specific machine. */
static int
guess_is_rela (e_machine)
unsigned long e_machine;
case EM_AVR:
case EM_CRIS:
case EM_860:
+ case EM_X86_64:
return TRUE;
case EM_MMA:
break;
case EM_CYGNUS_ARC:
+ case EM_ARC:
rtype = elf_arc_reloc_type (type);
break;
case EM_860:
rtype = elf_i860_reloc_type (type);
break;
+
+ case EM_X86_64:
+ rtype = elf_x86_64_reloc_type (type);
+ break;
}
if (rtype == NULL)
case EM_SH: return "Hitachi SH";
case EM_SPARCV9: return "Sparc v9";
case EM_TRICORE: return "Siemens Tricore";
- case EM_ARC: return "Argonaut RISC Core";
+ case EM_ARC: return "ARC";
case EM_H8_300: return "Hitachi H8/300";
case EM_H8_300H: return "Hitachi H8/300H";
case EM_H8S: return "Hitachi H8S";
case EM_ALPHA: return "Alpha";
case EM_CYGNUS_D10V: return "d10v";
case EM_CYGNUS_D30V: return "d30v";
- case EM_CYGNUS_ARC: return "Arc";
+ case EM_CYGNUS_ARC: return "ARC";
case EM_CYGNUS_M32R: return "Mitsubishi M32r";
case EM_CYGNUS_V850: return "NEC v850";
case EM_CYGNUS_MN10300: return "mn10300";
case EM_MMIX: return "Donald Knuth's educational 64-bit processor";
case EM_HUANY: return "Harvard Universitys's machine-independent object format";
case EM_PRISM: return "SiTera Prism";
-
+ case EM_X86_64: return "Advanced Micro Devices X86-64";
default:
sprintf (buff, _("<unknown>: %x"), e_machine);
return buff;
if (section->sh_size != 0)
{
- unsigned long string_table_offset;
-
- string_table_offset = section->sh_offset;
-
GET_DATA_ALLOC (section->sh_offset, section->sh_size,
string_table, char *, "string table");
+
+ string_table_length = section->sh_size;
}
/* Scan the sections for the dynamic symbol table
)
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)
+ request_dump (i, DEBUG_DUMP);
else if (do_debug_frames && strcmp (name, ".eh_frame") == 0)
request_dump (i, DEBUG_DUMP);
}
if (do_histogram && buckets != NULL)
{
- int *lengths;
- int *counts;
- int hn;
- int si;
- int maxlength = 0;
- int nzero_counts = 0;
- int nsyms = 0;
+ int * lengths;
+ int * counts;
+ int hn;
+ int si;
+ int maxlength = 0;
+ int nzero_counts = 0;
+ int nsyms = 0;
printf (_("\nHistogram for bucket list length (total of %d buckets):\n"),
nbuckets);
unsigned char * start;
FILE * file ATTRIBUTE_UNUSED;
{
- abbrev_entry * entry;
+ abbrev_entry * entry;
unsigned char * end = start + section->sh_size;
printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section));
decode_location_expression (data, pointer_size, length)
unsigned char * data;
unsigned int pointer_size;
- unsigned long length;
+ unsigned long length;
{
- unsigned op;
- int bytes_read;
- unsigned long uvalue;
- unsigned char *end = data + length;
+ unsigned op;
+ int bytes_read;
+ unsigned long uvalue;
+ unsigned char * end = data + length;
while (data < end)
{
cu_offset = start - section_begin;
start += compunit.cu_length + sizeof (external->cu_length);
+ printf (_(" Compilation Unit @ %lx:\n"), cu_offset);
+ printf (_(" Length: %ld\n"), compunit.cu_length);
+ printf (_(" Version: %d\n"), compunit.cu_version);
+ printf (_(" Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset);
+ printf (_(" Pointer Size: %d\n"), compunit.cu_pointer_size);
+
if (compunit.cu_version != 2)
{
warn (_("Only version 2 DWARF debug information is currently supported.\n"));
continue;
}
- printf (_(" Compilation Unit:\n"));
- printf (_(" Length: %ld\n"), compunit.cu_length);
- printf (_(" Version: %d\n"), compunit.cu_version);
- printf (_(" Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset);
- printf (_(" Pointer Size: %d\n"), compunit.cu_pointer_size);
-
if (first_abbrev != NULL)
free_abbrevs ();
ranges = start + sizeof (* external);
/* Must pad to an alignment boundary that is twice the pointer size. */
- excess = sizeof (*external) % (2 * arange.ar_pointer_size);
+ excess = sizeof (* external) % (2 * arange.ar_pointer_size);
if (excess)
ranges += (2 * arange.ar_pointer_size) - excess;
typedef struct Frame_Chunk
{
- struct Frame_Chunk *next;
- unsigned char *chunk_start;
- int ncols;
- /* DW_CFA_{undefined,same_value,offset,register} */
- unsigned char *col_type;
- int *col_offset;
- char *augmentation;
- unsigned int code_factor;
- unsigned int data_factor;
- unsigned long pc_begin;
- unsigned long pc_range;
- int cfa_reg;
- int cfa_offset;
- int ra;
+ struct Frame_Chunk * next;
+ unsigned char * chunk_start;
+ int ncols;
+ /* DW_CFA_{undefined,same_value,offset,register,unreferenced} */
+ short int * col_type;
+ int * col_offset;
+ char * augmentation;
+ unsigned int code_factor;
+ unsigned int data_factor;
+ unsigned long pc_begin;
+ unsigned long pc_range;
+ int cfa_reg;
+ int cfa_offset;
+ int ra;
}
Frame_Chunk;
+/* A marker for a col_type that means this column was never referenced
+ in the frame info. */
+#define DW_CFA_unreferenced (-1)
+
static void
frame_need_space (fc, reg)
- Frame_Chunk *fc;
+ Frame_Chunk * fc;
int reg;
{
int prev = fc->ncols;
if (reg < fc->ncols)
return;
+
fc->ncols = reg + 1;
- fc->col_type = (unsigned char *) xrealloc (fc->col_type,
- fc->ncols * sizeof (unsigned char));
+ fc->col_type = (short int *) xrealloc (fc->col_type,
+ fc->ncols * sizeof (short int));
fc->col_offset = (int *) xrealloc (fc->col_offset,
fc->ncols * sizeof (int));
while (prev < fc->ncols)
{
- fc->col_type[prev] = DW_CFA_undefined;
+ fc->col_type[prev] = DW_CFA_unreferenced;
fc->col_offset[prev] = 0;
prev++;
}
static void
frame_display_row (fc, need_col_headers, max_regs)
- Frame_Chunk *fc;
- int *need_col_headers;
- int *max_regs;
+ Frame_Chunk * fc;
+ int * need_col_headers;
+ int * max_regs;
{
int r;
char tmp[100];
- if (*max_regs < fc->ncols)
- *max_regs = fc->ncols;
- if (*need_col_headers)
+ if (* max_regs < fc->ncols)
+ * max_regs = fc->ncols;
+
+ if (* need_col_headers)
{
- *need_col_headers = 0;
+ * need_col_headers = 0;
+
printf (" LOC CFA ");
- for (r=0; r<*max_regs; r++)
- if (r == fc->ra)
- printf ("ra ");
- else
- printf ("r%-4d", r);
+
+ for (r = 0; r < * max_regs; r++)
+ if (fc->col_type[r] != DW_CFA_unreferenced)
+ {
+ if (r == fc->ra)
+ printf ("ra ");
+ else
+ printf ("r%-4d", r);
+ }
+
printf ("\n");
}
+
printf ("%08x ", (unsigned int) fc->pc_begin);
sprintf (tmp, "r%d%+d", fc->cfa_reg, fc->cfa_offset);
printf ("%-8s ", tmp);
- for (r=0; r<fc->ncols; r++)
+
+ for (r = 0; r < fc->ncols; r++)
{
- switch (fc->col_type[r])
+ if (fc->col_type[r] != DW_CFA_unreferenced)
{
- case DW_CFA_undefined:
- strcpy (tmp, "u");
- break;
- case DW_CFA_same_value:
- strcpy (tmp, "s");
- break;
- case DW_CFA_offset:
- sprintf (tmp, "c%+d", fc->col_offset[r]);
- break;
- case DW_CFA_register:
- sprintf (tmp, "r%d", fc->col_offset[r]);
- break;
- default:
- strcpy (tmp, "n/a");
- break;
+ switch (fc->col_type[r])
+ {
+ case DW_CFA_undefined:
+ strcpy (tmp, "u");
+ break;
+ case DW_CFA_same_value:
+ strcpy (tmp, "s");
+ break;
+ case DW_CFA_offset:
+ sprintf (tmp, "c%+d", fc->col_offset[r]);
+ break;
+ case DW_CFA_register:
+ sprintf (tmp, "r%d", fc->col_offset[r]);
+ break;
+ default:
+ strcpy (tmp, "n/a");
+ break;
+ }
+ printf ("%-5s", tmp);
}
- printf ("%-5s", tmp);
}
printf ("\n");
}
#define GET(N) byte_get (start, N); start += N
-#define LEB() read_leb128 (start, &length_return, 0); start += length_return
-#define SLEB() read_leb128 (start, &length_return, 1); start += length_return
+#define LEB() read_leb128 (start, & length_return, 0); start += length_return
+#define SLEB() read_leb128 (start, & length_return, 1); start += length_return
static int
display_debug_frames (section, start, file)
FILE * file ATTRIBUTE_UNUSED;
{
unsigned char * end = start + section->sh_size;
- unsigned char *section_start = start;
- Frame_Chunk *chunks = 0;
- Frame_Chunk *remembered_state = 0, *rs;
- int is_eh = (strcmp (SECTION_NAME (section), ".eh_frame") == 0);
- int length_return;
- int max_regs = 0;
+ unsigned char * section_start = start;
+ Frame_Chunk * chunks = 0;
+ Frame_Chunk * remembered_state = 0;
+ Frame_Chunk * rs;
+ int is_eh = (strcmp (SECTION_NAME (section), ".eh_frame") == 0);
+ int length_return;
+ int max_regs = 0;
printf (_("The section %s contains:\n"), SECTION_NAME (section));
while (start < end)
{
- unsigned char *saved_start, *block_end;
- unsigned long length, cie_id;
- Frame_Chunk *fc, *cie;
- int need_col_headers = 1;
+ unsigned char * saved_start;
+ unsigned char * block_end;
+ unsigned long length;
+ unsigned long cie_id;
+ Frame_Chunk * fc;
+ Frame_Chunk * cie;
+ int need_col_headers = 1;
saved_start = start;
length = byte_get (start, 4); start += 4;
chunks = fc;
fc->chunk_start = saved_start;
fc->ncols = 0;
- fc->col_type = (unsigned char *) xmalloc (sizeof (unsigned char));
+ fc->col_type = (short int *) xmalloc (sizeof (short int));
fc->col_offset = (int *) xmalloc (sizeof (int));
frame_need_space (fc, max_regs-1);
start ++; /* version */
fc->augmentation = start;
- while (*start) start++; start++; /* skip past NUL */
+
+ while (* start)
+ start++;
+
+ start++; /* skip past NUL */
+
if (fc->augmentation[0] == 'z')
{
int xtra;
}
else
{
- unsigned char *look_for;
+ unsigned char * look_for;
static Frame_Chunk fde_fc;
- fc = &fde_fc;
+
+ fc = & fde_fc;
memset (fc, 0, sizeof (Frame_Chunk));
look_for = is_eh ? start-4-cie_id : (unsigned char *) cie_id;
warn ("Invalid CIE pointer %08x in FDE at %08x\n", cie_id, saved_start);
start = block_end;
fc->ncols = 0;
- fc->col_type = (unsigned char *) xmalloc (sizeof (unsigned char));
+ fc->col_type = (short int *) xmalloc (sizeof (short int));
fc->col_offset = (int *) xmalloc (sizeof (int));
- frame_need_space (fc, max_regs-1);
+ frame_need_space (fc, max_regs - 1);
cie = fc;
fc->augmentation = "";
}
else
{
fc->ncols = cie->ncols;
- fc->col_type = (unsigned char *) xmalloc (fc->ncols * sizeof (unsigned char));
+ fc->col_type = (short int *) xmalloc (fc->ncols * sizeof (short int));
fc->col_offset = (int *) xmalloc (fc->ncols * sizeof (int));
- memcpy (fc->col_type, cie->col_type, fc->ncols);
+ memcpy (fc->col_type, cie->col_type, fc->ncols * sizeof (short int));
memcpy (fc->col_offset, cie->col_offset, fc->ncols * sizeof (int));
fc->augmentation = cie->augmentation;
fc->code_factor = cie->code_factor;
/* This exists for readelf maintainers. */
#define FDEBUG 0
+ {
+ /* Start by making a pass over the chunk, allocating storage
+ and taking note of what registers are used. */
+ unsigned char * tmp = start;
+
+ while (start < block_end)
+ {
+ unsigned op, opa;
+ unsigned long reg;
+ bfd_vma vma;
+
+ op = * start ++;
+ opa = op & 0x3f;
+ if (op & 0xc0)
+ op &= 0xc0;
+
+ /* Warning: if you add any more cases to this switch, be
+ sure to add them to the corresponding switch below. */
+ switch (op)
+ {
+ case DW_CFA_advance_loc:
+ break;
+ case DW_CFA_offset:
+ LEB ();
+ frame_need_space (fc, opa);
+ fc->col_type[opa] = DW_CFA_undefined;
+ break;
+ case DW_CFA_restore:
+ frame_need_space (fc, opa);
+ fc->col_type[opa] = DW_CFA_undefined;
+ break;
+ case DW_CFA_set_loc:
+ start += sizeof (vma);
+ break;
+ case DW_CFA_advance_loc1:
+ start += 1;
+ break;
+ case DW_CFA_advance_loc2:
+ start += 2;
+ break;
+ case DW_CFA_advance_loc4:
+ start += 4;
+ break;
+ case DW_CFA_offset_extended:
+ reg = LEB (); LEB ();
+ frame_need_space (fc, reg);
+ fc->col_type[reg] = DW_CFA_undefined;
+ break;
+ case DW_CFA_restore_extended:
+ reg = LEB ();
+ frame_need_space (fc, reg);
+ fc->col_type[reg] = DW_CFA_undefined;
+ break;
+ case DW_CFA_undefined:
+ reg = LEB ();
+ frame_need_space (fc, reg);
+ fc->col_type[reg] = DW_CFA_undefined;
+ break;
+ case DW_CFA_same_value:
+ reg = LEB ();
+ frame_need_space (fc, reg);
+ fc->col_type[reg] = DW_CFA_undefined;
+ break;
+ case DW_CFA_register:
+ reg = LEB (); LEB ();
+ frame_need_space (fc, reg);
+ fc->col_type[reg] = DW_CFA_undefined;
+ break;
+ case DW_CFA_def_cfa:
+ LEB (); LEB ();
+ break;
+ case DW_CFA_def_cfa_register:
+ LEB ();
+ break;
+ case DW_CFA_def_cfa_offset:
+ LEB ();
+ break;
+#ifndef DW_CFA_GNU_args_size
+#define DW_CFA_GNU_args_size 0x2e
+#endif
+ case DW_CFA_GNU_args_size:
+ LEB ();
+ break;
+#ifndef DW_CFA_GNU_negative_offset_extended
+#define DW_CFA_GNU_negative_offset_extended 0x2f
+#endif
+ case DW_CFA_GNU_negative_offset_extended:
+ reg = LEB (); LEB ();
+ frame_need_space (fc, reg);
+ fc->col_type[reg] = DW_CFA_undefined;
+
+ default:
+ break;
+ }
+ }
+ start = tmp;
+ }
+
+ /* Now we know what registers are used, make a second pass over
+ the chunk, this time actually printing out the info. */
+
while (start < block_end)
{
unsigned op, opa;
if (op & 0xc0)
op &= 0xc0;
+ /* Warning: if you add any more cases to this switch, be
+ sure to add them to the corresponding switch above. */
switch (op)
{
case DW_CFA_advance_loc:
break;
case DW_CFA_offset:
- frame_need_space (fc, opa);
roffs = LEB ();
#if FDEBUG
printf (" DW_CFA_offset: r%d = cfa[%d*%d]\n", opa, roffs, fc->data_factor);
break;
case DW_CFA_restore:
- frame_need_space (fc, opa);
#if FDEBUG
printf (" DW_CFA_restore: r%d\n", opa);
#endif
case DW_CFA_offset_extended:
reg = LEB ();
roffs = LEB ();
- frame_need_space (fc, reg);
#if FDEBUG
printf (" DW_CFA_offset_extended: r%d = cfa[%d*%d]\n", reg, roffs, fc->data_factor);
#endif
case DW_CFA_restore_extended:
reg = LEB ();
- frame_need_space (fc, reg);
#if FDEBUG
printf (" DW_CFA_restore_extended: r%d\n", reg);
#endif
case DW_CFA_undefined:
reg = LEB ();
- frame_need_space (fc, reg);
#if FDEBUG
printf (" DW_CFA_undefined: r%d\n", reg);
#endif
case DW_CFA_same_value:
reg = LEB ();
- frame_need_space (fc, reg);
#if FDEBUG
printf (" DW_CFA_same_value: r%d\n", reg);
#endif
case DW_CFA_register:
reg = LEB ();
roffs = LEB ();
- frame_need_space (fc, reg);
#if FDEBUG
- printf (" DW_CFA_ame_value: r%d\n", reg);
+ printf (" DW_CFA_register: r%d\n", reg);
#endif
fc->col_type[reg] = DW_CFA_register;
fc->col_offset[reg] = roffs;
#endif
rs = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk));
rs->ncols = fc->ncols;
- rs->col_type = (unsigned char *) xmalloc (rs->ncols);
+ rs->col_type = (short int *) xmalloc (rs->ncols * sizeof (short int));
rs->col_offset = (int *) xmalloc (rs->ncols * sizeof (int));
memcpy (rs->col_type, fc->col_type, rs->ncols);
memcpy (rs->col_offset, fc->col_offset, rs->ncols * sizeof (int));
"debug section data");
/* See if we know how to display the contents of this section. */
+ if (strncmp (name, ".gnu.linkonce.wi.", 17) == 0)
+ name = ".debug_info";
+
for (i = NUM_ELEM (debug_displays); i--;)
if (strcmp (debug_displays[i].name, name) == 0)
{
Elf_External_Options *, "options");
iopt = (Elf_Internal_Options *) malloc ((sect->sh_size / sizeof (eopt))
- * sizeof (*iopt));
+ * sizeof (* iopt));
if (iopt == NULL)
{
error (_("Out of memory"));
}
printf (_("\nSection '%s' contains %d entries:\n"),
- string_table + sect->sh_name, cnt);
+ SECTION_NAME (sect), cnt);
option = iopt;
if (elf_header.e_machine == EM_MIPS)
{
/* 32bit form. */
- Elf32_External_RegInfo *ereg;
- Elf32_RegInfo reginfo;
+ Elf32_External_RegInfo * ereg;
+ Elf32_RegInfo reginfo;
ereg = (Elf32_External_RegInfo *) (option + 1);
reginfo.ri_gprmask = BYTE_GET (ereg->ri_gprmask);
break;
}
- len = sizeof (*eopt);
+ len = sizeof (* eopt);
while (len < option->size)
if (((char *) option)[len] >= ' '
&& ((char *) option)[len] < 0x7f)
return 0;
}
- iconf = (Elf32_Conflict *) malloc (conflictsno * sizeof (*iconf));
+ iconf = (Elf32_Conflict *) malloc (conflictsno * sizeof (* iconf));
if (iconf == NULL)
{
error (_("Out of memory"));
if (is_32bit_elf)
{
- GET_DATA_ALLOC (conflicts_offset, conflictsno * sizeof (*econf32),
+ GET_DATA_ALLOC (conflicts_offset, conflictsno * sizeof (* econf32),
econf32, Elf32_External_Conflict *, "conflict");
for (cnt = 0; cnt < conflictsno; ++cnt)
}
else
{
- GET_DATA_ALLOC (conflicts_offset, conflictsno * sizeof (*econf64),
+ GET_DATA_ALLOC (conflicts_offset, conflictsno * sizeof (* econf64),
econf64, Elf64_External_Conflict *, "conflict");
for (cnt = 0; cnt < conflictsno; ++cnt)
{
free (string_table);
string_table = NULL;
+ string_table_length = 0;
}
if (dynamic_strings)