/* dwarf.c -- display DWARF contents of a BFD binary file
- Copyright 2005, 2006, 2007
+ Copyright 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GNU Binutils.
#include "libiberty.h"
#include "bfd.h"
#include "bucomm.h"
+#include "elf/common.h"
#include "elf/dwarf2.h"
#include "dwarf.h"
static unsigned int num_debug_info_entries = 0;
static debug_info *debug_information = NULL;
+/* Special value for num_debug_info_entries to indicate
+ that the .debug_info section could not be loaded/parsed. */
+#define DEBUG_INFO_UNAVAILABLE (unsigned int) -1
-dwarf_vma eh_addr_size;
+int eh_addr_size;
int do_debug_info;
int do_debug_abbrevs;
int do_debug_macinfo;
int do_debug_str;
int do_debug_loc;
+int do_wide;
+
+/* Values for do_debug_lines. */
+#define FLAG_DEBUG_LINES_RAW 1
+#define FLAG_DEBUG_LINES_DECODED 2
dwarf_vma (*byte_get) (unsigned char *, int);
}
}
+static int
+size_of_encoded_value (int encoding)
+{
+ switch (encoding & 0x7)
+ {
+ default: /* ??? */
+ case 0: return eh_addr_size;
+ case 2: return 2;
+ case 3: return 4;
+ case 4: return 8;
+ }
+}
+
+static dwarf_vma
+get_encoded_value (unsigned char *data, int encoding)
+{
+ int size = size_of_encoded_value (encoding);
+
+ if (encoding & DW_EH_PE_signed)
+ return byte_get_signed (data, size);
+ else
+ return byte_get (data, size);
+}
+
+/* Print a dwarf_vma value (typically an address, offset or length) in
+ hexadecimal format, followed by a space. The length of the value (and
+ hence the precision displayed) is determined by the byte_size parameter. */
+
+static void
+print_dwarf_vma (dwarf_vma val, unsigned byte_size)
+{
+ static char buff[18];
+
+ /* Printf does not have a way of specifiying a maximum field width for an
+ integer value, so we print the full value into a buffer and then select
+ the precision we need. */
+#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
+#ifndef __MSVCRT__
+ snprintf (buff, sizeof (buff), "%16.16llx ", val);
+#else
+ snprintf (buff, sizeof (buff), "%016I64x ", val);
+#endif
+#else
+ snprintf (buff, sizeof (buff), "%16.16lx ", val);
+#endif
+
+ fputs (buff + (byte_size == 4 ? 8 : 0), stdout);
+}
+
static unsigned long int
read_leb128 (unsigned char *data, unsigned int *length_return, int sign)
{
printf (_("%s\n\n"), name);
break;
+ case DW_LNE_set_discriminator:
+ printf (_("set Discriminator to %lu\n"),
+ read_leb128 (data, & bytes_read, 0));
+ break;
+
/* HP extensions. */
case DW_LNE_HP_negate_is_UV_update:
- printf ("DW_LNE_HP_negate_is_UV_update");
+ printf ("DW_LNE_HP_negate_is_UV_update\n");
break;
case DW_LNE_HP_push_context:
- printf ("DW_LNE_HP_push_context");
+ printf ("DW_LNE_HP_push_context\n");
break;
case DW_LNE_HP_pop_context:
- printf ("DW_LNE_HP_pop_context");
+ printf ("DW_LNE_HP_pop_context\n");
break;
case DW_LNE_HP_set_file_line_column:
- printf ("DW_LNE_HP_set_file_line_column");
+ printf ("DW_LNE_HP_set_file_line_column\n");
break;
case DW_LNE_HP_set_routine_name:
- printf ("DW_LNE_HP_set_routine_name");
+ printf ("DW_LNE_HP_set_routine_name\n");
break;
case DW_LNE_HP_set_sequence:
- printf ("DW_LNE_HP_set_sequence");
+ printf ("DW_LNE_HP_set_sequence\n");
break;
case DW_LNE_HP_negate_post_semantics:
- printf ("DW_LNE_HP_negate_post_semantics");
+ printf ("DW_LNE_HP_negate_post_semantics\n");
break;
case DW_LNE_HP_negate_function_exit:
- printf ("DW_LNE_HP_negate_function_exit");
+ printf ("DW_LNE_HP_negate_function_exit\n");
break;
case DW_LNE_HP_negate_front_end_logical:
- printf ("DW_LNE_HP_negate_front_end_logical");
+ printf ("DW_LNE_HP_negate_front_end_logical\n");
break;
case DW_LNE_HP_define_proc:
- printf ("DW_LNE_HP_define_proc");
+ printf ("DW_LNE_HP_define_proc\n");
break;
-
+
default:
if (op_code >= DW_LNE_lo_user
/* The test against DW_LNW_hi_user is redundant due to
decode_location_expression (unsigned char * data,
unsigned int pointer_size,
unsigned long length,
- unsigned long cu_offset)
+ unsigned long cu_offset,
+ struct dwarf_section * section)
{
unsigned op;
unsigned int bytes_read;
printf ("DW_OP_GNU_uninit");
/* FIXME: Is there data associated with this OP ? */
break;
+ case DW_OP_GNU_encoded_addr:
+ {
+ int encoding;
+ dwarf_vma addr;
+
+ encoding = *data++;
+ addr = get_encoded_value (data, encoding);
+ if ((encoding & 0x70) == DW_EH_PE_pcrel)
+ addr += section->address + (data - section->start);
+ data += size_of_encoded_value (encoding);
+
+ printf ("DW_OP_GNU_encoded_addr: fmt:%02x addr:", encoding);
+ print_dwarf_vma (addr, pointer_size);
+ }
+ break;
/* HP extensions. */
case DW_OP_HP_is_value:
/* FIXME: Is there data associated with this OP ? */
break;
+ /* PGI (STMicroelectronics) extensions. */
+ case DW_OP_PGI_omp_thread_num:
+ /* Pushes the thread number for the current thread as it would be
+ returned by the standard OpenMP library function:
+ omp_get_thread_num(). The "current thread" is the thread for
+ which the expression is being evaluated. */
+ printf ("DW_OP_PGI_omp_thread_num");
+ break;
+
default:
if (op >= DW_OP_lo_user
&& op <= DW_OP_hi_user)
static unsigned char *
read_and_display_attr_value (unsigned long attribute,
unsigned long form,
- unsigned char *data,
+ unsigned char * data,
unsigned long cu_offset,
unsigned long pointer_size,
unsigned long offset_size,
int dwarf_version,
- debug_info *debug_info_p,
- int do_loc)
+ debug_info * debug_info_p,
+ int do_loc,
+ struct dwarf_section * section)
{
unsigned long uvalue = 0;
unsigned char *block_start = NULL;
+ unsigned char * orig_data = data;
unsigned int bytes_read;
switch (form)
return read_and_display_attr_value (attribute, form, data,
cu_offset, pointer_size,
offset_size, dwarf_version,
- debug_info_p, do_loc);
+ debug_info_p, do_loc,
+ section);
}
switch (form)
{
case DW_FORM_ref_addr:
if (!do_loc)
- printf (" <#%lx>", uvalue);
+ printf (" <0x%lx>", uvalue);
break;
case DW_FORM_ref1:
case DW_FORM_ref4:
case DW_FORM_ref_udata:
if (!do_loc)
- printf (" <%lx>", uvalue + cu_offset);
+ printf (" <0x%lx>", uvalue + cu_offset);
break;
case DW_FORM_data4:
case DW_FORM_addr:
if (!do_loc)
- printf (" %#lx", uvalue);
+ printf (" 0x%lx", uvalue);
break;
case DW_FORM_flag:
if (!do_loc)
{
uvalue = byte_get (data, 4);
- printf (" %lx", uvalue);
- printf (" %lx", (unsigned long) byte_get (data + 4, 4));
+ printf (" 0x%lx", uvalue);
+ printf (" 0x%lx", (unsigned long) byte_get (data + 4, 4));
}
if ((do_loc || do_debug_loc || do_debug_ranges)
&& num_debug_info_entries == 0)
break;
}
- /* For some attributes we can display further information. */
if ((do_loc || do_debug_loc || do_debug_ranges)
&& num_debug_info_entries == 0)
{
if (do_loc)
return data;
+ /* For some attributes we can display further information. */
printf ("\t");
switch (attribute)
case DW_AT_data_location:
case DW_AT_stride:
case DW_AT_upper_bound:
- case DW_AT_lower_bound:
+ case DW_AT_lower_bound:
if (block_start)
{
int need_frame_base;
need_frame_base = decode_location_expression (block_start,
pointer_size,
uvalue,
- cu_offset);
+ cu_offset, section);
printf (")");
if (need_frame_base && !have_frame_base)
printf (_(" [without DW_AT_frame_base]"));
}
break;
+ case DW_AT_import:
+ {
+ if (form == DW_FORM_ref1
+ || form == DW_FORM_ref2
+ || form == DW_FORM_ref4)
+ uvalue += cu_offset;
+
+ if (uvalue >= section->size)
+ warn (_("Offset %lx used as value for DW_AT_import attribute of DIE at offset %lx is too big.\n"),
+ uvalue, (unsigned long) (orig_data - section->start));
+ else
+ {
+ unsigned long abbrev_number;
+ abbrev_entry * entry;
+
+ abbrev_number = read_leb128 (section->start + uvalue, NULL, 0);
+
+ printf ("[Abbrev Number: %ld", abbrev_number);
+ for (entry = first_abbrev; entry != NULL; entry = entry->next)
+ if (entry->entry == abbrev_number)
+ break;
+ if (entry != NULL)
+ printf (" (%s)", get_TAG_name (entry->tag));
+ printf ("]");
+ }
+ }
+ break;
+
default:
break;
}
case DW_AT_MIPS_has_inlines: return "DW_AT_MIPS_has_inlines";
/* HP Extensions. */
- case DW_AT_HP_block_index: return "DW_AT_HP_block_index";
+ case DW_AT_HP_block_index: return "DW_AT_HP_block_index";
case DW_AT_HP_actuals_stmt_list: return "DW_AT_HP_actuals_stmt_list";
case DW_AT_HP_proc_per_section: return "DW_AT_HP_proc_per_section";
case DW_AT_HP_raw_data_ptr: return "DW_AT_HP_raw_data_ptr";
/* One value is shared by the MIPS and HP extensions: */
case DW_AT_MIPS_fde: return "DW_AT_MIPS_fde or DW_AT_HP_unmodifiable";
-
+
/* GNU extensions. */
case DW_AT_sf_names: return "DW_AT_sf_names";
case DW_AT_src_info: return "DW_AT_src_info";
static unsigned char *
read_and_display_attr (unsigned long attribute,
unsigned long form,
- unsigned char *data,
+ unsigned char * data,
unsigned long cu_offset,
unsigned long pointer_size,
unsigned long offset_size,
int dwarf_version,
- debug_info *debug_info_p,
- int do_loc)
+ debug_info * debug_info_p,
+ int do_loc,
+ struct dwarf_section * section)
{
if (!do_loc)
printf (" %-18s:", get_AT_name (attribute));
data = read_and_display_attr_value (attribute, form, data, cu_offset,
pointer_size, offset_size,
dwarf_version, debug_info_p,
- do_loc);
+ do_loc, section);
if (!do_loc)
printf ("\n");
return data;
anything to the user. */
static int
-process_debug_info (struct dwarf_section *section, void *file,
+process_debug_info (struct dwarf_section *section,
+ void *file,
int do_loc)
{
unsigned char *start = section->start;
length = byte_get (section_begin + 4, 8);
section_begin += length + 12;
}
+ else if (length >= 0xfffffff0 && length < 0xffffffff)
+ {
+ warn (_("Reserved length value (%lx) found in section %s\n"), length, section->name);
+ return 0;
+ }
else
section_begin += length + 4;
if (!do_loc)
{
- printf (_("The section %s contains:\n\n"), section->name);
+ printf (_("Contents of the %s section:\n\n"), section->name);
load_debug_section (str, file);
}
if (!do_loc)
{
printf (_(" Compilation Unit @ offset 0x%lx:\n"), cu_offset);
- printf (_(" Length: %ld\n"), compunit.cu_length);
+ printf (_(" Length: 0x%lx (%s)\n"), compunit.cu_length,
+ initial_length_size == 8 ? "64-bit" : "32-bit");
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 (cu_offset + compunit.cu_length + initial_length_size
> section->size)
{
- warn (_("Debug info is corrupted, length is invalid (section is %lu bytes)\n"),
- (unsigned long)section->size);
+ warn (_("Debug info is corrupted, length of CU at %lx extends beyond end of section (length = %lx)\n"),
+ cu_offset, compunit.cu_length);
break;
}
tags = hdrptr;
if (compunit.cu_version != 2 && compunit.cu_version != 3)
{
- warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n"));
+ warn (_("CU at offset %lx contains corrupt or unsupported version number: %d.\n"),
+ cu_offset, compunit.cu_version);
continue;
}
/* Process the abbrevs used by this compilation unit. DWARF
sections under Mach-O have non-zero addresses. */
if (compunit.cu_abbrev_offset >= debug_displays [abbrev].section.size)
- warn (_("Debug info is corrupted, abbrev offset is invalid (section is %lu bytes)\n"),
- (unsigned long)debug_displays [abbrev].section.size);
+ warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than abbrev section size (%lx)\n"),
+ (unsigned long) compunit.cu_abbrev_offset,
+ (unsigned long) debug_displays [abbrev].section.size);
else
process_abbrev_section
((unsigned char *) debug_displays [abbrev].section.start
{
unsigned int bytes_read;
unsigned long abbrev_number;
+ unsigned long die_offset;
abbrev_entry *entry;
abbrev_attr *attr;
+ die_offset = tags - section_begin;
+
abbrev_number = read_leb128 (tags, & bytes_read, 0);
tags += bytes_read;
- /* A null DIE marks the end of a list of children. */
+ /* A null DIE marks the end of a list of siblings. */
if (abbrev_number == 0)
{
--level;
+ if (level < 0)
+ {
+ static unsigned num_bogus_warns = 0;
+
+ if (num_bogus_warns < 3)
+ {
+ warn (_("Bogus end-of-siblings marker detected at offset %lx in .debug_info section\n"),
+ die_offset);
+ num_bogus_warns ++;
+ if (num_bogus_warns == 3)
+ warn (_("Further warnings about bogus end-of-sibling markers suppressed\n"));
+ }
+ }
continue;
}
if (!do_loc)
printf (_(" <%d><%lx>: Abbrev Number: %lu"),
- level,
- (unsigned long) (tags - section_begin
- - bytes_read),
- abbrev_number);
-
+ level, die_offset, abbrev_number);
+
/* Scan through the abbreviation list until we reach the
correct entry. */
for (entry = first_abbrev;
printf ("\n");
fflush (stdout);
}
- warn (_("Unable to locate entry %lu in the abbreviation table\n"),
- abbrev_number);
+ warn (_("DIE at offset %lx refers to abbreviation number %lu which does not exist\n"),
+ die_offset, abbrev_number);
return 0;
}
if (!do_loc)
printf (_(" (%s)\n"), get_TAG_name (entry->tag));
-
+
switch (entry->tag)
{
default:
compunit.cu_pointer_size,
offset_size,
compunit.cu_version,
- &debug_information [unit],
- do_loc);
+ debug_information + unit,
+ do_loc, section);
}
-
+
if (entry->children)
++level;
}
}
-
+
/* Set num_debug_info_entries here so that it can be used to check if
we need to process .debug_loc and .debug_ranges sections. */
if ((do_loc || do_debug_loc || do_debug_ranges)
&& num_debug_info_entries == 0)
num_debug_info_entries = num_units;
-
+
if (!do_loc)
{
printf ("\n");
}
-
+
return 1;
}
last_pointer_size = 0;
warned_about_missing_comp_units = FALSE;
+ /* If we have already tried and failed to load the .debug_info
+ section then do not bother to repear the task. */
+ if (num_debug_info_entries == DEBUG_INFO_UNAVAILABLE)
+ return 0;
+
/* If we already have the information there is nothing else to do. */
if (num_debug_info_entries > 0)
return num_debug_info_entries;
if (load_debug_section (info, file)
&& process_debug_info (&debug_displays [info].section, file, 1))
return num_debug_info_entries;
- else
- return 0;
+
+ num_debug_info_entries = DEBUG_INFO_UNAVAILABLE;
+ return 0;
}
static int
-display_debug_lines (struct dwarf_section *section, void *file)
+display_debug_lines_raw (struct dwarf_section *section,
+ unsigned char *data,
+ unsigned char *end)
{
unsigned char *start = section->start;
- unsigned char *data = start;
- unsigned char *end = start + section->size;
- printf (_("\nDump of debug contents of section %s:\n\n"),
- section->name);
-
- load_debug_info (file);
+ printf (_("Raw dump of debug contents of section %s:\n\n"),
+ section->name);
while (data < end)
{
return 1;
}
+typedef struct
+{
+ unsigned char *name;
+ unsigned int directory_index;
+ unsigned int modification_date;
+ unsigned int length;
+} File_Entry;
+
+/* Output a decoded representation of the .debug_line section. */
+
+static int
+display_debug_lines_decoded (struct dwarf_section *section,
+ unsigned char *data,
+ unsigned char *end)
+{
+ printf (_("Decoded dump of debug contents of section %s:\n\n"),
+ section->name);
+
+ while (data < end)
+ {
+ /* This loop amounts to one iteration per compilation unit. */
+ DWARF2_Internal_LineInfo info;
+ unsigned char *standard_opcodes;
+ unsigned char *end_of_sequence;
+ unsigned char *hdrptr;
+ int initial_length_size;
+ int offset_size;
+ int i;
+ File_Entry *file_table = NULL;
+ unsigned char **directory_table = NULL;
+ unsigned int prev_line = 0;
+
+ hdrptr = data;
+
+ /* Extract information from the Line Number Program Header.
+ (section 6.2.4 in the Dwarf3 doc). */
+
+ /* Get the length of this CU's line number information block. */
+ info.li_length = byte_get (hdrptr, 4);
+ hdrptr += 4;
+
+ if (info.li_length == 0xffffffff)
+ {
+ /* This section is 64-bit DWARF 3. */
+ info.li_length = byte_get (hdrptr, 8);
+ hdrptr += 8;
+ offset_size = 8;
+ initial_length_size = 12;
+ }
+ else
+ {
+ offset_size = 4;
+ initial_length_size = 4;
+ }
+
+ if (info.li_length + initial_length_size > section->size)
+ {
+ warn (_("The line info appears to be corrupt - "
+ "the section is too small\n"));
+ return 0;
+ }
+
+ /* Get this CU's Line Number Block version number. */
+ info.li_version = byte_get (hdrptr, 2);
+ hdrptr += 2;
+ if (info.li_version != 2 && info.li_version != 3)
+ {
+ warn (_("Only DWARF version 2 and 3 line info is currently "
+ "supported.\n"));
+ return 0;
+ }
+
+ info.li_prologue_length = byte_get (hdrptr, offset_size);
+ hdrptr += offset_size;
+ info.li_min_insn_length = byte_get (hdrptr, 1);
+ hdrptr++;
+ info.li_default_is_stmt = byte_get (hdrptr, 1);
+ hdrptr++;
+ info.li_line_base = byte_get (hdrptr, 1);
+ hdrptr++;
+ info.li_line_range = byte_get (hdrptr, 1);
+ hdrptr++;
+ info.li_opcode_base = byte_get (hdrptr, 1);
+ hdrptr++;
+
+ /* Sign extend the line base field. */
+ info.li_line_base <<= 24;
+ info.li_line_base >>= 24;
+
+ /* Find the end of this CU's Line Number Information Block. */
+ end_of_sequence = data + info.li_length + initial_length_size;
+
+ reset_state_machine (info.li_default_is_stmt);
+
+ /* Save a pointer to the contents of the Opcodes table. */
+ standard_opcodes = hdrptr;
+
+ /* Traverse the Directory table just to count entries. */
+ data = standard_opcodes + info.li_opcode_base - 1;
+ if (*data != 0)
+ {
+ unsigned int n_directories = 0;
+ unsigned char *ptr_directory_table = data;
+ int i;
+
+ while (*data != 0)
+ {
+ data += strlen ((char *) data) + 1;
+ n_directories++;
+ }
+
+ /* Go through the directory table again to save the directories. */
+ directory_table = xmalloc (n_directories * sizeof (unsigned char *));
+
+ i = 0;
+ while (*ptr_directory_table != 0)
+ {
+ directory_table[i] = ptr_directory_table;
+ ptr_directory_table += strlen ((char *) ptr_directory_table) + 1;
+ i++;
+ }
+ }
+ /* Skip the NUL at the end of the table. */
+ data++;
+
+ /* Traverse the File Name table just to count the entries. */
+ if (*data != 0)
+ {
+ unsigned int n_files = 0;
+ unsigned char *ptr_file_name_table = data;
+ int i;
+
+ while (*data != 0)
+ {
+ unsigned int bytes_read;
+
+ /* Skip Name, directory index, last modification time and length
+ of file. */
+ data += strlen ((char *) data) + 1;
+ read_leb128 (data, & bytes_read, 0);
+ data += bytes_read;
+ read_leb128 (data, & bytes_read, 0);
+ data += bytes_read;
+ read_leb128 (data, & bytes_read, 0);
+ data += bytes_read;
+
+ n_files++;
+ }
+
+ /* Go through the file table again to save the strings. */
+ file_table = xmalloc (n_files * sizeof (File_Entry));
+
+ i = 0;
+ while (*ptr_file_name_table != 0)
+ {
+ unsigned int bytes_read;
+
+ file_table[i].name = ptr_file_name_table;
+ ptr_file_name_table += strlen ((char *) ptr_file_name_table) + 1;
+
+ /* We are not interested in directory, time or size. */
+ file_table[i].directory_index = read_leb128 (ptr_file_name_table,
+ & bytes_read, 0);
+ ptr_file_name_table += bytes_read;
+ file_table[i].modification_date = read_leb128 (ptr_file_name_table,
+ & bytes_read, 0);
+ ptr_file_name_table += bytes_read;
+ file_table[i].length = read_leb128 (ptr_file_name_table, & bytes_read, 0);
+ ptr_file_name_table += bytes_read;
+ i++;
+ }
+ i = 0;
+
+ /* Print the Compilation Unit's name and a header. */
+ if (directory_table == NULL)
+ {
+ printf (_("CU: %s:\n"), file_table[0].name);
+ printf (_("File name Line number Starting address\n"));
+ }
+ else
+ {
+ if (do_wide || strlen ((char *) directory_table[0]) < 76)
+ {
+ printf (_("CU: %s/%s:\n"), directory_table[0],
+ file_table[0].name);
+ }
+ else
+ {
+ printf (_("%s:\n"), file_table[0].name);
+ }
+ printf (_("File name Line number Starting address\n"));
+ }
+ }
+
+ /* Skip the NUL at the end of the table. */
+ data++;
+
+ /* This loop iterates through the Dwarf Line Number Program. */
+ while (data < end_of_sequence)
+ {
+ unsigned char op_code;
+ int adv;
+ unsigned long int uladv;
+ unsigned int bytes_read;
+ int is_special_opcode = 0;
+
+ op_code = *data++;
+ prev_line = state_machine_regs.line;
+
+ if (op_code >= info.li_opcode_base)
+ {
+ op_code -= info.li_opcode_base;
+ uladv = (op_code / info.li_line_range) * info.li_min_insn_length;
+ state_machine_regs.address += uladv;
+
+ adv = (op_code % info.li_line_range) + info.li_line_base;
+ state_machine_regs.line += adv;
+ is_special_opcode = 1;
+ }
+ else switch (op_code)
+ {
+ case DW_LNS_extended_op:
+ {
+ unsigned int ext_op_code_len;
+ unsigned int bytes_read;
+ unsigned char ext_op_code;
+ unsigned char *op_code_data = data;
+
+ ext_op_code_len = read_leb128 (op_code_data, &bytes_read, 0);
+ op_code_data += bytes_read;
+
+ if (ext_op_code_len == 0)
+ {
+ warn (_("badly formed extended line op encountered!\n"));
+ break;
+ }
+ ext_op_code_len += bytes_read;
+ ext_op_code = *op_code_data++;
+
+ switch (ext_op_code)
+ {
+ case DW_LNE_end_sequence:
+ reset_state_machine (info.li_default_is_stmt);
+ break;
+ case DW_LNE_set_address:
+ state_machine_regs.address =
+ byte_get (op_code_data, ext_op_code_len - bytes_read - 1);
+ break;
+ case DW_LNE_define_file:
+ {
+ unsigned int dir_index = 0;
+
+ ++state_machine_regs.last_file_entry;
+ op_code_data += strlen ((char *) op_code_data) + 1;
+ dir_index = read_leb128 (op_code_data, & bytes_read, 0);
+ op_code_data += bytes_read;
+ read_leb128 (op_code_data, & bytes_read, 0);
+ op_code_data += bytes_read;
+ read_leb128 (op_code_data, & bytes_read, 0);
+
+ printf (_("%s:\n"), directory_table[dir_index]);
+ break;
+ }
+ default:
+ printf (_("UNKNOWN: length %d\n"), ext_op_code_len - bytes_read);
+ break;
+ }
+ data += ext_op_code_len;
+ break;
+ }
+ case DW_LNS_copy:
+ break;
+
+ case DW_LNS_advance_pc:
+ uladv = read_leb128 (data, & bytes_read, 0);
+ uladv *= info.li_min_insn_length;
+ data += bytes_read;
+ state_machine_regs.address += uladv;
+ break;
+
+ case DW_LNS_advance_line:
+ adv = read_leb128 (data, & bytes_read, 1);
+ data += bytes_read;
+ state_machine_regs.line += adv;
+ break;
+
+ case DW_LNS_set_file:
+ adv = read_leb128 (data, & bytes_read, 0);
+ data += bytes_read;
+ state_machine_regs.file = adv;
+ if (file_table[state_machine_regs.file - 1].directory_index == 0)
+ {
+ /* If directory index is 0, that means current directory. */
+ printf (_("\n./%s:[++]\n"),
+ file_table[state_machine_regs.file - 1].name);
+ }
+ else
+ {
+ /* The directory index starts counting at 1. */
+ printf (_("\n%s/%s:\n"),
+ directory_table[file_table[state_machine_regs.file - 1].directory_index - 1],
+ file_table[state_machine_regs.file - 1].name);
+ }
+ break;
+
+ case DW_LNS_set_column:
+ uladv = read_leb128 (data, & bytes_read, 0);
+ data += bytes_read;
+ state_machine_regs.column = uladv;
+ break;
+
+ case DW_LNS_negate_stmt:
+ adv = state_machine_regs.is_stmt;
+ adv = ! adv;
+ state_machine_regs.is_stmt = adv;
+ break;
+
+ case DW_LNS_set_basic_block:
+ state_machine_regs.basic_block = 1;
+ break;
+
+ case DW_LNS_const_add_pc:
+ uladv = (((255 - info.li_opcode_base) / info.li_line_range)
+ * info.li_min_insn_length);
+ state_machine_regs.address += uladv;
+ break;
+
+ case DW_LNS_fixed_advance_pc:
+ uladv = byte_get (data, 2);
+ data += 2;
+ state_machine_regs.address += uladv;
+ break;
+
+ case DW_LNS_set_prologue_end:
+ break;
+
+ case DW_LNS_set_epilogue_begin:
+ break;
+
+ case DW_LNS_set_isa:
+ uladv = read_leb128 (data, & bytes_read, 0);
+ data += bytes_read;
+ printf (_(" Set ISA to %lu\n"), uladv);
+ break;
+
+ default:
+ printf (_(" Unknown opcode %d with operands: "), op_code);
+
+ 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;
+ }
+
+ /* Only Special opcodes, DW_LNS_copy and DW_LNE_end_sequence adds a row
+ to the DWARF address/line matrix. */
+ if ((is_special_opcode) || (op_code == DW_LNE_end_sequence)
+ || (op_code == DW_LNS_copy))
+ {
+ const unsigned int MAX_FILENAME_LENGTH = 35;
+ char *fileName = (char *)file_table[state_machine_regs.file - 1].name;
+ char *newFileName = NULL;
+ size_t fileNameLength = strlen (fileName);
+
+ if ((fileNameLength > MAX_FILENAME_LENGTH) && (!do_wide))
+ {
+ newFileName = xmalloc (MAX_FILENAME_LENGTH + 1);
+ /* Truncate file name */
+ strncpy (newFileName,
+ fileName + fileNameLength - MAX_FILENAME_LENGTH,
+ MAX_FILENAME_LENGTH + 1);
+ }
+ else
+ {
+ newFileName = xmalloc (fileNameLength + 1);
+ strncpy (newFileName, fileName, fileNameLength + 1);
+ }
+
+ if (!do_wide || (fileNameLength <= MAX_FILENAME_LENGTH))
+ {
+ printf (_("%-35s %11d %#18lx\n"), newFileName,
+ state_machine_regs.line, state_machine_regs.address);
+ }
+ else
+ {
+ printf (_("%s %11d %#18lx\n"), newFileName,
+ state_machine_regs.line, state_machine_regs.address);
+ }
+
+ if (op_code == DW_LNE_end_sequence)
+ printf ("\n");
+
+ free (newFileName);
+ }
+ }
+ free (file_table);
+ file_table = NULL;
+ free (directory_table);
+ directory_table = NULL;
+ putchar ('\n');
+ }
+
+ return 1;
+}
+
+static int
+display_debug_lines (struct dwarf_section *section, void *file)
+{
+ unsigned char *data = section->start;
+ unsigned char *end = data + section->size;
+ int retValRaw = 1;
+ int retValDecoded = 1;
+
+ if (load_debug_info (file) == 0)
+ {
+ warn (_("Unable to load/parse the .debug_info section, so cannot interpret the %s section.\n"),
+ section->name);
+ return 0;
+ }
+
+ if (do_debug_lines & FLAG_DEBUG_LINES_RAW)
+ retValRaw = display_debug_lines_raw (section, data, end);
+
+ if (do_debug_lines & FLAG_DEBUG_LINES_DECODED)
+ retValDecoded = display_debug_lines_decoded (section, data, end);
+
+ if (!retValRaw || !retValDecoded)
+ return 0;
+
+ return 1;
+}
+
+static debug_info *
+find_debug_info_for_offset (unsigned long offset)
+{
+ unsigned int i;
+
+ if (num_debug_info_entries == DEBUG_INFO_UNAVAILABLE)
+ return NULL;
+
+ for (i = 0; i < num_debug_info_entries; i++)
+ if (debug_information[i].cu_offset == offset)
+ return debug_information + i;
+
+ return NULL;
+}
+
static int
display_debug_pubnames (struct dwarf_section *section,
void *file ATTRIBUTE_UNUSED)
unsigned char *start = section->start;
unsigned char *end = start + section->size;
+ /* It does not matter if this load fails,
+ we test for that later on. */
+ load_debug_info (file);
+
printf (_("Contents of the %s section:\n\n"), section->name);
while (start < end)
pubnames.pn_version = byte_get (data, 2);
data += 2;
+
pubnames.pn_offset = byte_get (data, offset_size);
data += offset_size;
+
+ if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE
+ && num_debug_info_entries > 0
+ && find_debug_info_for_offset (pubnames.pn_offset) == NULL)
+ warn (_(".debug_info offset of 0x%lx in %s section does not point to a CU header.\n"),
+ pubnames.pn_offset, section->name);
+
pubnames.pn_size = byte_get (data, offset_size);
data += offset_size;
pubnames.pn_length);
printf (_(" Version: %d\n"),
pubnames.pn_version);
- printf (_(" Offset into .debug_info section: %ld\n"),
+ printf (_(" Offset into .debug_info section: 0x%lx\n"),
pubnames.pn_offset);
printf (_(" Size of area in .debug_info section: %ld\n"),
pubnames.pn_size);
if (offset != 0)
{
data += offset_size;
- printf (" %-6ld\t\t%s\n", offset, data);
+ printf (" %-6lx\t%s\n", offset, data);
data += strlen ((char *) data) + 1;
}
}
return 0;
}
- load_debug_info (file);
+ if (load_debug_info (file) == 0)
+ {
+ warn (_("Unable to load/parse the .debug_info section, so cannot interpret the %s section.\n"),
+ section->name);
+ return 0;
+ }
/* Check the order of location list in .debug_info section. If
offsets of location lists are in the ascending order, we can
seen_first_offset = 0;
for (i = first; i < num_debug_info_entries; i++)
{
- unsigned long begin;
- unsigned long end;
+ dwarf_vma begin;
+ dwarf_vma end;
unsigned short length;
unsigned long offset;
unsigned int pointer_size;
{
has_frame_base = debug_information [i].have_frame_base [j];
/* DWARF sections under Mach-O have non-zero addresses. */
- offset = debug_information [i].loc_offsets [j] - section->address;
+ offset = debug_information [i].loc_offsets [j] - section->address;
next = section_begin + offset;
base_address = debug_information [i].base_address;
{
if (start < next)
warn (_("There is a hole [0x%lx - 0x%lx] in .debug_loc section.\n"),
- (long)(start - section_begin), (long)(next - section_begin));
+ (unsigned long) (start - section_begin),
+ (unsigned long) (next - section_begin));
else if (start > next)
warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"),
- (long)(start - section_begin), (long)(next - section_begin));
+ (unsigned long) (start - section_begin),
+ (unsigned long) (next - section_begin));
}
start = next;
break;
}
- begin = byte_get (start, pointer_size);
+ /* Note: we use sign extension here in order to be sure that
+ we can detect the -1 escape value. Sign extension into the
+ top 32 bits of a 32-bit address will not affect the values
+ that we display since we always show hex values, and always
+ the bottom 32-bits. */
+ begin = byte_get_signed (start, pointer_size);
start += pointer_size;
- end = byte_get (start, pointer_size);
+ end = byte_get_signed (start, pointer_size);
start += pointer_size;
+ printf (" %8.8lx ", offset);
+
if (begin == 0 && end == 0)
{
- printf (_(" %8.8lx <End of list>\n"), offset);
+ printf (_("<End of list>\n"));
break;
}
/* Check base address specifiers. */
- if (begin == -1UL && end != -1UL)
+ if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1)
{
base_address = end;
- printf (_(" %8.8lx %8.8lx %8.8lx (base address)\n"),
- offset, begin, end);
+ print_dwarf_vma (begin, pointer_size);
+ print_dwarf_vma (end, pointer_size);
+ printf (_("(base address)\n"));
continue;
}
break;
}
- printf (" %8.8lx %8.8lx %8.8lx (",
- offset, begin + base_address, end + base_address);
+ print_dwarf_vma (begin + base_address, pointer_size);
+ print_dwarf_vma (end + base_address, pointer_size);
+
+ putchar ('(');
need_frame_base = decode_location_expression (start,
pointer_size,
length,
- cu_offset);
+ cu_offset, section);
putchar (')');
if (need_frame_base && !has_frame_base)
unsigned char *start = section->start;
unsigned char *end = start + section->size;
- printf (_("The section %s contains:\n\n"), section->name);
+ printf (_("Contents of the %s section:\n\n"), section->name);
+
+ /* It does not matter if this load fails,
+ we test for that later on. */
+ load_debug_info (file);
while (start < end)
{
unsigned char *hdrptr;
DWARF2_Internal_ARange arange;
unsigned char *ranges;
- unsigned long length;
- unsigned long address;
+ dwarf_vma length;
+ dwarf_vma address;
unsigned char address_size;
int excess;
int offset_size;
arange.ar_info_offset = byte_get (hdrptr, offset_size);
hdrptr += offset_size;
+ if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE
+ && num_debug_info_entries > 0
+ && find_debug_info_for_offset (arange.ar_info_offset) == NULL)
+ warn (_(".debug_info offset of 0x%lx in %s section does not point to a CU header.\n"),
+ arange.ar_info_offset, section->name);
+
arange.ar_pointer_size = byte_get (hdrptr, 1);
hdrptr += 1;
printf (_(" Length: %ld\n"), arange.ar_length);
printf (_(" Version: %d\n"), arange.ar_version);
- printf (_(" Offset into .debug_info: %lx\n"), arange.ar_info_offset);
+ printf (_(" Offset into .debug_info: 0x%lx\n"), arange.ar_info_offset);
printf (_(" Pointer Size: %d\n"), arange.ar_pointer_size);
printf (_(" Segment Size: %d\n"), arange.ar_segment_size);
warn (_("Pointer size + Segment size is not a power of two.\n"));
break;
}
-
+
if (address_size > 4)
printf (_("\n Address Length\n"));
else
ranges += address_size;
- if (address_size > 4)
- printf (" 0x%16.16lx 0x%lx\n", address, length);
- else
- printf (" 0x%8.8lx 0x%lx\n", address, length);
+ printf (" ");
+ print_dwarf_vma (address, address_size);
+ print_dwarf_vma (length, address_size);
+ putchar ('\n');
}
}
return 0;
}
- load_debug_info (file);
+ if (load_debug_info (file) == 0)
+ {
+ warn (_("Unable to load/parse the .debug_info section, so cannot interpret the %s section.\n"),
+ section->name);
+ return 0;
+ }
/* Check the order of range list in .debug_info section. If
offsets of range lists are in the ascending order, we can
seen_first_offset = 0;
for (i = first; i < num_debug_info_entries; i++)
{
- unsigned long begin;
- unsigned long end;
+ dwarf_vma begin;
+ dwarf_vma end;
unsigned long offset;
unsigned int pointer_size;
unsigned long base_address;
{
if (start < next)
warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"),
- (long)(start - section_begin),
- (long)(next - section_begin), section->name);
+ (unsigned long) (start - section_begin),
+ (unsigned long) (next - section_begin), section->name);
else if (start > next)
warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"),
- (long)(start - section_begin),
- (long)(next - section_begin), section->name);
+ (unsigned long) (start - section_begin),
+ (unsigned long) (next - section_begin), section->name);
}
start = next;
while (1)
{
- begin = byte_get (start, pointer_size);
+ /* Note: we use sign extension here in order to be sure that
+ we can detect the -1 escape value. Sign extension into the
+ top 32 bits of a 32-bit address will not affect the values
+ that we display since we always show hex values, and always
+ the bottom 32-bits. */
+ begin = byte_get_signed (start, pointer_size);
start += pointer_size;
- end = byte_get (start, pointer_size);
+ end = byte_get_signed (start, pointer_size);
start += pointer_size;
+ printf (" %8.8lx ", offset);
+
if (begin == 0 && end == 0)
{
- printf (_(" %8.8lx <End of list>\n"), offset);
+ printf (_("<End of list>\n"));
break;
}
/* Check base address specifiers. */
- if (begin == -1UL && end != -1UL)
+ if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1)
{
base_address = end;
- printf (" %8.8lx %8.8lx %8.8lx (base address)\n",
- offset, begin, end);
+ print_dwarf_vma (begin, pointer_size);
+ print_dwarf_vma (end, pointer_size);
+ printf ("(base address)\n");
continue;
}
- printf (" %8.8lx %8.8lx %8.8lx",
- offset, begin + base_address, end + base_address);
+ print_dwarf_vma (begin + base_address, pointer_size);
+ print_dwarf_vma (end + base_address, pointer_size);
if (begin == end)
- fputs (_(" (start == end)"), stdout);
+ fputs (_("(start == end)"), stdout);
else if (begin > end)
- fputs (_(" (start > end)"), stdout);
+ fputs (_("(start > end)"), stdout);
putchar ('\n');
}
}
Frame_Chunk;
+static const char *const *dwarf_regnames;
+static unsigned int dwarf_regnames_count;
+
/* 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 (Frame_Chunk *fc, int reg)
+/* Return 0 if not more space is needed, 1 if more space is needed,
+ -1 for invalid reg. */
+
+static int
+frame_need_space (Frame_Chunk *fc, unsigned int reg)
{
int prev = fc->ncols;
- if (reg < fc->ncols)
- return;
+ if (reg < (unsigned int) fc->ncols)
+ return 0;
+
+ if (dwarf_regnames_count
+ && reg > dwarf_regnames_count)
+ return -1;
fc->ncols = reg + 1;
fc->col_type = xcrealloc (fc->col_type, fc->ncols, sizeof (short int));
fc->col_offset[prev] = 0;
prev++;
}
+ return 1;
+}
+
+static const char *const dwarf_regnames_i386[] =
+{
+ "eax", "ecx", "edx", "ebx",
+ "esp", "ebp", "esi", "edi",
+ "eip", "eflags", NULL,
+ "st0", "st1", "st2", "st3",
+ "st4", "st5", "st6", "st7",
+ NULL, NULL,
+ "xmm0", "xmm1", "xmm2", "xmm3",
+ "xmm4", "xmm5", "xmm6", "xmm7",
+ "mm0", "mm1", "mm2", "mm3",
+ "mm4", "mm5", "mm6", "mm7",
+ "fcw", "fsw", "mxcsr",
+ "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL,
+ "tr", "ldtr"
+};
+
+static const char *const dwarf_regnames_x86_64[] =
+{
+ "rax", "rdx", "rcx", "rbx",
+ "rsi", "rdi", "rbp", "rsp",
+ "r8", "r9", "r10", "r11",
+ "r12", "r13", "r14", "r15",
+ "rip",
+ "xmm0", "xmm1", "xmm2", "xmm3",
+ "xmm4", "xmm5", "xmm6", "xmm7",
+ "xmm8", "xmm9", "xmm10", "xmm11",
+ "xmm12", "xmm13", "xmm14", "xmm15",
+ "st0", "st1", "st2", "st3",
+ "st4", "st5", "st6", "st7",
+ "mm0", "mm1", "mm2", "mm3",
+ "mm4", "mm5", "mm6", "mm7",
+ "rflags",
+ "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL,
+ "fs.base", "gs.base", NULL, NULL,
+ "tr", "ldtr",
+ "mxcsr", "fcw", "fsw"
+};
+
+void
+init_dwarf_regnames (unsigned int e_machine)
+{
+ switch (e_machine)
+ {
+ case EM_386:
+ case EM_486:
+ dwarf_regnames = dwarf_regnames_i386;
+ dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_i386);
+ break;
+
+ case EM_X86_64:
+ dwarf_regnames = dwarf_regnames_x86_64;
+ dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_x86_64);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static const char *
+regname (unsigned int regno, int row)
+{
+ static char reg[64];
+ if (dwarf_regnames
+ && regno < dwarf_regnames_count
+ && dwarf_regnames [regno] != NULL)
+ {
+ if (row)
+ return dwarf_regnames [regno];
+ snprintf (reg, sizeof (reg), "r%d (%s)", regno,
+ dwarf_regnames [regno]);
+ }
+ else
+ snprintf (reg, sizeof (reg), "r%d", regno);
+ return reg;
}
static void
if (*need_col_headers)
{
+ static const char *loc = " LOC";
+
*need_col_headers = 0;
- printf (" LOC CFA ");
+ printf ("%-*s CFA ", eh_addr_size * 2, loc);
for (r = 0; r < *max_regs; r++)
if (fc->col_type[r] != DW_CFA_unreferenced)
{
if (r == fc->ra)
- printf ("ra ");
+ printf ("ra ");
else
- printf ("r%-4d", r);
+ printf ("%-5s ", regname (r, 1));
}
printf ("\n");
}
- printf ("%08lx ", fc->pc_begin);
+ printf ("%0*lx ", eh_addr_size * 2, fc->pc_begin);
if (fc->cfa_exp)
strcpy (tmp, "exp");
else
- sprintf (tmp, "r%d%+d", fc->cfa_reg, fc->cfa_offset);
+ sprintf (tmp, "%s%+d", regname (fc->cfa_reg, 1), fc->cfa_offset);
printf ("%-8s ", tmp);
for (r = 0; r < fc->ncols; r++)
sprintf (tmp, "v%+d", fc->col_offset[r]);
break;
case DW_CFA_register:
- sprintf (tmp, "r%d", fc->col_offset[r]);
+ sprintf (tmp, "%s", regname (fc->col_offset[r], 0));
break;
case DW_CFA_expression:
strcpy (tmp, "exp");
strcpy (tmp, "n/a");
break;
}
- printf ("%-5s", tmp);
+ printf ("%-5s ", tmp);
}
}
printf ("\n");
}
-static int
-size_of_encoded_value (int encoding)
-{
- switch (encoding & 0x7)
- {
- default: /* ??? */
- case 0: return eh_addr_size;
- case 2: return 2;
- case 3: return 4;
- case 4: return 8;
- }
-}
-
-static dwarf_vma
-get_encoded_value (unsigned char *data, int encoding)
-{
- int size = size_of_encoded_value (encoding);
-
- if (encoding & DW_EH_PE_signed)
- return byte_get_signed (data, size);
- else
- return byte_get (data, size);
-}
-
#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
int is_eh = strcmp (section->name, ".eh_frame") == 0;
unsigned int length_return;
int max_regs = 0;
+ const char *bad_reg = _("bad register: ");
- printf (_("The section %s contains:\n"), section->name);
+ printf (_("Contents of the %s section:\n"), section->name);
while (start < end)
{
fc->ncols = 0;
fc->col_type = xmalloc (sizeof (short int));
fc->col_offset = xmalloc (sizeof (int));
- frame_need_space (fc, max_regs-1);
+ frame_need_space (fc, max_regs - 1);
version = *start++;
fc->cfa_reg = cie->cfa_reg;
fc->cfa_offset = cie->cfa_offset;
fc->ra = cie->ra;
- frame_need_space (fc, max_regs-1);
+ frame_need_space (fc, max_regs - 1);
fc->fde_encoding = cie->fde_encoding;
}
break;
case DW_CFA_offset:
LEB ();
- frame_need_space (fc, opa);
- fc->col_type[opa] = DW_CFA_undefined;
+ if (frame_need_space (fc, opa) >= 0)
+ fc->col_type[opa] = DW_CFA_undefined;
break;
case DW_CFA_restore:
- frame_need_space (fc, opa);
- fc->col_type[opa] = DW_CFA_undefined;
+ if (frame_need_space (fc, opa) >= 0)
+ fc->col_type[opa] = DW_CFA_undefined;
break;
case DW_CFA_set_loc:
start += encoded_ptr_size;
case DW_CFA_offset_extended:
case DW_CFA_val_offset:
reg = LEB (); LEB ();
- frame_need_space (fc, reg);
- fc->col_type[reg] = DW_CFA_undefined;
+ if (frame_need_space (fc, reg) >= 0)
+ 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;
+ if (frame_need_space (fc, reg) >= 0)
+ 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;
+ if (frame_need_space (fc, reg) >= 0)
+ 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;
+ if (frame_need_space (fc, reg) >= 0)
+ 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;
+ if (frame_need_space (fc, reg) >= 0)
+ fc->col_type[reg] = DW_CFA_undefined;
break;
case DW_CFA_def_cfa:
LEB (); LEB ();
reg = LEB ();
tmp = LEB ();
start += tmp;
- frame_need_space (fc, reg);
- fc->col_type[reg] = DW_CFA_undefined;
+ if (frame_need_space (fc, reg) >= 0)
+ fc->col_type[reg] = DW_CFA_undefined;
break;
case DW_CFA_offset_extended_sf:
case DW_CFA_val_offset_sf:
reg = LEB (); SLEB ();
- frame_need_space (fc, reg);
- fc->col_type[reg] = DW_CFA_undefined;
+ if (frame_need_space (fc, reg) >= 0)
+ fc->col_type[reg] = DW_CFA_undefined;
break;
case DW_CFA_def_cfa_sf:
LEB (); SLEB ();
break;
case DW_CFA_GNU_negative_offset_extended:
reg = LEB (); LEB ();
- frame_need_space (fc, reg);
- fc->col_type[reg] = DW_CFA_undefined;
-
+ if (frame_need_space (fc, reg) >= 0)
+ fc->col_type[reg] = DW_CFA_undefined;
+ break;
default:
break;
}
unsigned long ul, reg, roffs;
long l, ofs;
dwarf_vma vma;
+ const char *reg_prefix = "";
op = *start++;
opa = op & 0x3f;
case DW_CFA_offset:
roffs = LEB ();
- if (! do_debug_frames_interp)
- printf (" DW_CFA_offset: r%d at cfa%+ld\n",
- opa, roffs * fc->data_factor);
- fc->col_type[opa] = DW_CFA_offset;
- fc->col_offset[opa] = roffs * fc->data_factor;
+ if (opa >= (unsigned int) fc->ncols)
+ reg_prefix = bad_reg;
+ if (! do_debug_frames_interp || *reg_prefix != '\0')
+ printf (" DW_CFA_offset: %s%s at cfa%+ld\n",
+ reg_prefix, regname (opa, 0),
+ roffs * fc->data_factor);
+ if (*reg_prefix == '\0')
+ {
+ fc->col_type[opa] = DW_CFA_offset;
+ fc->col_offset[opa] = roffs * fc->data_factor;
+ }
break;
case DW_CFA_restore:
- if (! do_debug_frames_interp)
- printf (" DW_CFA_restore: r%d\n", opa);
- fc->col_type[opa] = cie->col_type[opa];
- fc->col_offset[opa] = cie->col_offset[opa];
+ if (opa >= (unsigned int) cie->ncols
+ || opa >= (unsigned int) fc->ncols)
+ reg_prefix = bad_reg;
+ if (! do_debug_frames_interp || *reg_prefix != '\0')
+ printf (" DW_CFA_restore: %s%s\n",
+ reg_prefix, regname (opa, 0));
+ if (*reg_prefix == '\0')
+ {
+ fc->col_type[opa] = cie->col_type[opa];
+ fc->col_offset[opa] = cie->col_offset[opa];
+ }
break;
case DW_CFA_set_loc:
case DW_CFA_offset_extended:
reg = LEB ();
roffs = LEB ();
- if (! do_debug_frames_interp)
- printf (" DW_CFA_offset_extended: r%ld at cfa%+ld\n",
- reg, roffs * fc->data_factor);
- fc->col_type[reg] = DW_CFA_offset;
- fc->col_offset[reg] = roffs * fc->data_factor;
+ if (reg >= (unsigned int) fc->ncols)
+ reg_prefix = bad_reg;
+ if (! do_debug_frames_interp || *reg_prefix != '\0')
+ printf (" DW_CFA_offset_extended: %s%s at cfa%+ld\n",
+ reg_prefix, regname (reg, 0),
+ roffs * fc->data_factor);
+ if (*reg_prefix == '\0')
+ {
+ fc->col_type[reg] = DW_CFA_offset;
+ fc->col_offset[reg] = roffs * fc->data_factor;
+ }
break;
case DW_CFA_val_offset:
reg = LEB ();
roffs = LEB ();
- if (! do_debug_frames_interp)
- printf (" DW_CFA_val_offset: r%ld at cfa%+ld\n",
- reg, roffs * fc->data_factor);
- fc->col_type[reg] = DW_CFA_val_offset;
- fc->col_offset[reg] = roffs * fc->data_factor;
+ if (reg >= (unsigned int) fc->ncols)
+ reg_prefix = bad_reg;
+ if (! do_debug_frames_interp || *reg_prefix != '\0')
+ printf (" DW_CFA_val_offset: %s%s at cfa%+ld\n",
+ reg_prefix, regname (reg, 0),
+ roffs * fc->data_factor);
+ if (*reg_prefix == '\0')
+ {
+ fc->col_type[reg] = DW_CFA_val_offset;
+ fc->col_offset[reg] = roffs * fc->data_factor;
+ }
break;
case DW_CFA_restore_extended:
reg = LEB ();
- if (! do_debug_frames_interp)
- printf (" DW_CFA_restore_extended: r%ld\n", reg);
- fc->col_type[reg] = cie->col_type[reg];
- fc->col_offset[reg] = cie->col_offset[reg];
+ if (reg >= (unsigned int) cie->ncols
+ || reg >= (unsigned int) fc->ncols)
+ reg_prefix = bad_reg;
+ if (! do_debug_frames_interp || *reg_prefix != '\0')
+ printf (" DW_CFA_restore_extended: %s%s\n",
+ reg_prefix, regname (reg, 0));
+ if (*reg_prefix == '\0')
+ {
+ fc->col_type[reg] = cie->col_type[reg];
+ fc->col_offset[reg] = cie->col_offset[reg];
+ }
break;
case DW_CFA_undefined:
reg = LEB ();
- if (! do_debug_frames_interp)
- printf (" DW_CFA_undefined: r%ld\n", reg);
- fc->col_type[reg] = DW_CFA_undefined;
- fc->col_offset[reg] = 0;
+ if (reg >= (unsigned int) fc->ncols)
+ reg_prefix = bad_reg;
+ if (! do_debug_frames_interp || *reg_prefix != '\0')
+ printf (" DW_CFA_undefined: %s%s\n",
+ reg_prefix, regname (reg, 0));
+ if (*reg_prefix == '\0')
+ {
+ fc->col_type[reg] = DW_CFA_undefined;
+ fc->col_offset[reg] = 0;
+ }
break;
case DW_CFA_same_value:
reg = LEB ();
- if (! do_debug_frames_interp)
- printf (" DW_CFA_same_value: r%ld\n", reg);
- fc->col_type[reg] = DW_CFA_same_value;
- fc->col_offset[reg] = 0;
+ if (reg >= (unsigned int) fc->ncols)
+ reg_prefix = bad_reg;
+ if (! do_debug_frames_interp || *reg_prefix != '\0')
+ printf (" DW_CFA_same_value: %s%s\n",
+ reg_prefix, regname (reg, 0));
+ if (*reg_prefix == '\0')
+ {
+ fc->col_type[reg] = DW_CFA_same_value;
+ fc->col_offset[reg] = 0;
+ }
break;
case DW_CFA_register:
reg = LEB ();
roffs = LEB ();
- if (! do_debug_frames_interp)
- printf (" DW_CFA_register: r%ld in r%ld\n", reg, roffs);
- fc->col_type[reg] = DW_CFA_register;
- fc->col_offset[reg] = roffs;
+ if (reg >= (unsigned int) fc->ncols)
+ reg_prefix = bad_reg;
+ if (! do_debug_frames_interp || *reg_prefix != '\0')
+ {
+ printf (" DW_CFA_register: %s%s in ",
+ reg_prefix, regname (reg, 0));
+ puts (regname (roffs, 0));
+ }
+ if (*reg_prefix == '\0')
+ {
+ fc->col_type[reg] = DW_CFA_register;
+ fc->col_offset[reg] = roffs;
+ }
break;
case DW_CFA_remember_state:
if (rs)
{
remembered_state = rs->next;
- frame_need_space (fc, rs->ncols-1);
+ frame_need_space (fc, rs->ncols - 1);
memcpy (fc->col_type, rs->col_type, rs->ncols);
memcpy (fc->col_offset, rs->col_offset,
rs->ncols * sizeof (int));
fc->cfa_offset = LEB ();
fc->cfa_exp = 0;
if (! do_debug_frames_interp)
- printf (" DW_CFA_def_cfa: r%d ofs %d\n",
- fc->cfa_reg, fc->cfa_offset);
+ printf (" DW_CFA_def_cfa: %s ofs %d\n",
+ regname (fc->cfa_reg, 0), fc->cfa_offset);
break;
case DW_CFA_def_cfa_register:
fc->cfa_reg = LEB ();
fc->cfa_exp = 0;
if (! do_debug_frames_interp)
- printf (" DW_CFA_def_cfa_reg: r%d\n", fc->cfa_reg);
+ printf (" DW_CFA_def_cfa_register: %s\n",
+ regname (fc->cfa_reg, 0));
break;
case DW_CFA_def_cfa_offset:
if (! do_debug_frames_interp)
{
printf (" DW_CFA_def_cfa_expression (");
- decode_location_expression (start, eh_addr_size, ul, 0);
+ decode_location_expression (start, eh_addr_size, ul, 0,
+ section);
printf (")\n");
}
fc->cfa_exp = 1;
case DW_CFA_expression:
reg = LEB ();
ul = LEB ();
- if (! do_debug_frames_interp)
+ if (reg >= (unsigned int) fc->ncols)
+ reg_prefix = bad_reg;
+ if (! do_debug_frames_interp || *reg_prefix != '\0')
{
- printf (" DW_CFA_expression: r%ld (", reg);
- decode_location_expression (start, eh_addr_size, ul, 0);
+ printf (" DW_CFA_expression: %s%s (",
+ reg_prefix, regname (reg, 0));
+ decode_location_expression (start, eh_addr_size,
+ ul, 0, section);
printf (")\n");
}
- fc->col_type[reg] = DW_CFA_expression;
+ if (*reg_prefix == '\0')
+ fc->col_type[reg] = DW_CFA_expression;
start += ul;
break;
case DW_CFA_val_expression:
reg = LEB ();
ul = LEB ();
- if (! do_debug_frames_interp)
+ if (reg >= (unsigned int) fc->ncols)
+ reg_prefix = bad_reg;
+ if (! do_debug_frames_interp || *reg_prefix != '\0')
{
- printf (" DW_CFA_val_expression: r%ld (", reg);
- decode_location_expression (start, eh_addr_size, ul, 0);
+ printf (" DW_CFA_val_expression: %s%s (",
+ reg_prefix, regname (reg, 0));
+ decode_location_expression (start, eh_addr_size, ul, 0,
+ section);
printf (")\n");
}
- fc->col_type[reg] = DW_CFA_val_expression;
+ if (*reg_prefix == '\0')
+ fc->col_type[reg] = DW_CFA_val_expression;
start += ul;
break;
case DW_CFA_offset_extended_sf:
reg = LEB ();
l = SLEB ();
- frame_need_space (fc, reg);
- if (! do_debug_frames_interp)
- printf (" DW_CFA_offset_extended_sf: r%ld at cfa%+ld\n",
- reg, l * fc->data_factor);
- fc->col_type[reg] = DW_CFA_offset;
- fc->col_offset[reg] = l * fc->data_factor;
+ if (frame_need_space (fc, reg) < 0)
+ reg_prefix = bad_reg;
+ if (! do_debug_frames_interp || *reg_prefix != '\0')
+ printf (" DW_CFA_offset_extended_sf: %s%s at cfa%+ld\n",
+ reg_prefix, regname (reg, 0),
+ l * fc->data_factor);
+ if (*reg_prefix == '\0')
+ {
+ fc->col_type[reg] = DW_CFA_offset;
+ fc->col_offset[reg] = l * fc->data_factor;
+ }
break;
case DW_CFA_val_offset_sf:
reg = LEB ();
l = SLEB ();
- frame_need_space (fc, reg);
- if (! do_debug_frames_interp)
- printf (" DW_CFA_val_offset_sf: r%ld at cfa%+ld\n",
- reg, l * fc->data_factor);
- fc->col_type[reg] = DW_CFA_val_offset;
- fc->col_offset[reg] = l * fc->data_factor;
+ if (frame_need_space (fc, reg) < 0)
+ reg_prefix = bad_reg;
+ if (! do_debug_frames_interp || *reg_prefix != '\0')
+ printf (" DW_CFA_val_offset_sf: %s%s at cfa%+ld\n",
+ reg_prefix, regname (reg, 0),
+ l * fc->data_factor);
+ if (*reg_prefix == '\0')
+ {
+ fc->col_type[reg] = DW_CFA_val_offset;
+ fc->col_offset[reg] = l * fc->data_factor;
+ }
break;
case DW_CFA_def_cfa_sf:
fc->cfa_offset = fc->cfa_offset * fc->data_factor;
fc->cfa_exp = 0;
if (! do_debug_frames_interp)
- printf (" DW_CFA_def_cfa_sf: r%d ofs %d\n",
- fc->cfa_reg, fc->cfa_offset);
+ printf (" DW_CFA_def_cfa_sf: %s ofs %d\n",
+ regname (fc->cfa_reg, 0), fc->cfa_offset);
break;
case DW_CFA_def_cfa_offset_sf:
case DW_CFA_GNU_negative_offset_extended:
reg = LEB ();
l = - LEB ();
- frame_need_space (fc, reg);
- if (! do_debug_frames_interp)
- printf (" DW_CFA_GNU_negative_offset_extended: r%ld at cfa%+ld\n",
- reg, l * fc->data_factor);
- fc->col_type[reg] = DW_CFA_offset;
- fc->col_offset[reg] = l * fc->data_factor;
+ if (frame_need_space (fc, reg) < 0)
+ reg_prefix = bad_reg;
+ if (! do_debug_frames_interp || *reg_prefix != '\0')
+ printf (" DW_CFA_GNU_negative_offset_extended: %s%s at cfa%+ld\n",
+ reg_prefix, regname (reg, 0),
+ l * fc->data_factor);
+ if (*reg_prefix == '\0')
+ {
+ fc->col_type[reg] = DW_CFA_offset;
+ fc->col_offset[reg] = l * fc->data_factor;
+ }
break;
default:
if (op >= DW_CFA_lo_user && op <= DW_CFA_hi_user)
printf (_(" DW_CFA_??? (User defined call frame op: %#x)\n"), op);
else
- warn (_("unsupported or unknown Dwarf Call Frame Instruction number: %#x\n"), op);
+ warn (_("unsupported or unknown Dwarf Call Frame Instruction number: %#x\n"), op);
start = block_end;
}
}
for (i = 0; i < max; i++)
free_debug_section (i);
- if (debug_information)
+ if (debug_information != NULL)
{
- for (i = 0; i < num_debug_info_entries; i++)
+ if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE)
{
- if (!debug_information [i].max_loc_offsets)
+ for (i = 0; i < num_debug_info_entries; i++)
{
- free (debug_information [i].loc_offsets);
- free (debug_information [i].have_frame_base);
+ if (!debug_information [i].max_loc_offsets)
+ {
+ free (debug_information [i].loc_offsets);
+ free (debug_information [i].have_frame_base);
+ }
+ if (!debug_information [i].max_range_lists)
+ free (debug_information [i].range_lists);
}
- if (!debug_information [i].max_range_lists)
- free (debug_information [i].range_lists);
}
+
free (debug_information);
debug_information = NULL;
num_debug_info_entries = 0;
}
+}
+
+void
+dwarf_select_sections_by_names (const char *names)
+{
+ typedef struct
+ {
+ const char * option;
+ int * variable;
+ int val;
+ }
+ debug_dump_long_opts;
+
+ static const debug_dump_long_opts opts_table [] =
+ {
+ /* Please keep this table alpha- sorted. */
+ { "Ranges", & do_debug_ranges, 1 },
+ { "abbrev", & do_debug_abbrevs, 1 },
+ { "aranges", & do_debug_aranges, 1 },
+ { "frames", & do_debug_frames, 1 },
+ { "frames-interp", & do_debug_frames_interp, 1 },
+ { "info", & do_debug_info, 1 },
+ { "line", & do_debug_lines, FLAG_DEBUG_LINES_RAW }, /* For backwards compatibility. */
+ { "rawline", & do_debug_lines, FLAG_DEBUG_LINES_RAW },
+ { "decodedline", & do_debug_lines, FLAG_DEBUG_LINES_DECODED },
+ { "loc", & do_debug_loc, 1 },
+ { "macro", & do_debug_macinfo, 1 },
+ { "pubnames", & do_debug_pubnames, 1 },
+ /* This entry is for compatability
+ with earlier versions of readelf. */
+ { "ranges", & do_debug_aranges, 1 },
+ { "str", & do_debug_str, 1 },
+ { NULL, NULL, 0 }
+ };
+
+ const char *p;
+
+ p = names;
+ while (*p)
+ {
+ const debug_dump_long_opts * entry;
+
+ for (entry = opts_table; entry->option; entry++)
+ {
+ size_t len = strlen (entry->option);
+
+ if (strncmp (p, entry->option, len) == 0
+ && (p[len] == ',' || p[len] == '\0'))
+ {
+ * entry->variable |= entry->val;
+
+ /* 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 (entry->option == NULL)
+ {
+ warn (_("Unrecognized debug option '%s'\n"), p);
+ p = strchr (p, ',');
+ if (p == NULL)
+ break;
+ }
+
+ if (*p == ',')
+ p++;
+ }
+}
+
+void
+dwarf_select_sections_by_letters (const char *letters)
+{
+ unsigned int index = 0;
+ while (letters[index])
+ switch (letters[index++])
+ {
+ case 'i':
+ do_debug_info = 1;
+ break;
+
+ case 'a':
+ do_debug_abbrevs = 1;
+ break;
+
+ case 'l':
+ do_debug_lines |= FLAG_DEBUG_LINES_RAW;
+ break;
+
+ case 'L':
+ do_debug_lines |= FLAG_DEBUG_LINES_DECODED;
+ break;
+
+ case 'p':
+ do_debug_pubnames = 1;
+ break;
+
+ case 'r':
+ do_debug_aranges = 1;
+ break;
+
+ case 'R':
+ do_debug_ranges = 1;
+ break;
+
+ case 'F':
+ do_debug_frames_interp = 1;
+ case 'f':
+ do_debug_frames = 1;
+ break;
+
+ case 'm':
+ do_debug_macinfo = 1;
+ break;
+
+ case 's':
+ do_debug_str = 1;
+ break;
+
+ case 'o':
+ do_debug_loc = 1;
+ break;
+
+ default:
+ warn (_("Unrecognized debug option '%s'\n"), optarg);
+ break;
+ }
+}
+
+void
+dwarf_select_sections_all (void)
+{
+ do_debug_info = 1;
+ do_debug_abbrevs = 1;
+ do_debug_lines = FLAG_DEBUG_LINES_RAW;
+ do_debug_pubnames = 1;
+ do_debug_aranges = 1;
+ do_debug_ranges = 1;
+ do_debug_frames = 1;
+ do_debug_macinfo = 1;
+ do_debug_str = 1;
+ do_debug_loc = 1;
}
struct dwarf_section_display debug_displays[] =
{
- { { ".debug_abbrev", NULL, 0, 0 },
- display_debug_abbrev, 0, 0 },
- { { ".debug_aranges", NULL, 0, 0 },
- display_debug_aranges, 0, 0 },
- { { ".debug_frame", NULL, 0, 0 },
- display_debug_frames, 1, 0 },
- { { ".debug_info", NULL, 0, 0 },
- display_debug_info, 1, 0 },
- { { ".debug_line", NULL, 0, 0 },
- display_debug_lines, 0, 0 },
- { { ".debug_pubnames", NULL, 0, 0 },
- display_debug_pubnames, 0, 0 },
- { { ".eh_frame", NULL, 0, 0 },
- display_debug_frames, 1, 1 },
- { { ".debug_macinfo", NULL, 0, 0 },
- display_debug_macinfo, 0, 0 },
- { { ".debug_str", NULL, 0, 0 },
- display_debug_str, 0, 0 },
- { { ".debug_loc", NULL, 0, 0 },
- display_debug_loc, 0, 0 },
- { { ".debug_pubtypes", NULL, 0, 0 },
- display_debug_pubnames, 0, 0 },
- { { ".debug_ranges", NULL, 0, 0 },
- display_debug_ranges, 0, 0 },
- { { ".debug_static_func", NULL, 0, 0 },
- display_debug_not_supported, 0, 0 },
- { { ".debug_static_vars", NULL, 0, 0 },
- display_debug_not_supported, 0, 0 },
- { { ".debug_types", NULL, 0, 0 },
- display_debug_not_supported, 0, 0 },
- { { ".debug_weaknames", NULL, 0, 0 },
- display_debug_not_supported, 0, 0 }
+ { { ".debug_abbrev", ".zdebug_abbrev", NULL, NULL, 0, 0 },
+ display_debug_abbrev, &do_debug_abbrevs, 0, 0 },
+ { { ".debug_aranges", ".zdebug_aranges", NULL, NULL, 0, 0 },
+ display_debug_aranges, &do_debug_aranges, 0, 0 },
+ { { ".debug_frame", ".zdebug_frame", NULL, NULL, 0, 0 },
+ display_debug_frames, &do_debug_frames, 1, 0 },
+ { { ".debug_info", ".zdebug_info", NULL, NULL, 0, 0 },
+ display_debug_info, &do_debug_info, 1, 0 },
+ { { ".debug_line", ".zdebug_line", NULL, NULL, 0, 0 },
+ display_debug_lines, &do_debug_lines, 0, 0 },
+ { { ".debug_pubnames", ".zdebug_pubnames", NULL, NULL, 0, 0 },
+ display_debug_pubnames, &do_debug_pubnames, 0, 0 },
+ { { ".eh_frame", "", NULL, NULL, 0, 0 },
+ display_debug_frames, &do_debug_frames, 1, 1 },
+ { { ".debug_macinfo", ".zdebug_macinfo", NULL, NULL, 0, 0 },
+ display_debug_macinfo, &do_debug_macinfo, 0, 0 },
+ { { ".debug_str", ".zdebug_str", NULL, NULL, 0, 0 },
+ display_debug_str, &do_debug_str, 0, 0 },
+ { { ".debug_loc", ".zdebug_loc", NULL, NULL, 0, 0 },
+ display_debug_loc, &do_debug_loc, 0, 0 },
+ { { ".debug_pubtypes", ".zdebug_pubtypes", NULL, NULL, 0, 0 },
+ display_debug_pubnames, &do_debug_pubnames, 0, 0 },
+ { { ".debug_ranges", ".zdebug_ranges", NULL, NULL, 0, 0 },
+ display_debug_ranges, &do_debug_ranges, 0, 0 },
+ { { ".debug_static_func", ".zdebug_static_func", NULL, NULL, 0, 0 },
+ display_debug_not_supported, NULL, 0, 0 },
+ { { ".debug_static_vars", ".zdebug_static_vars", NULL, NULL, 0, 0 },
+ display_debug_not_supported, NULL, 0, 0 },
+ { { ".debug_types", ".zdebug_types", NULL, NULL, 0, 0 },
+ display_debug_not_supported, NULL, 0, 0 },
+ { { ".debug_weaknames", ".zdebug_weaknames", NULL, NULL, 0, 0 },
+ display_debug_not_supported, NULL, 0, 0 }
};