blob: aff15a49a27552d23d09b92528f50bd05ee12709 [file] [log] [blame]
From 58c1565328927ed2b6966d695e8bc377b584cd5d Mon Sep 17 00:00:00 2001
From: Cary Coutant <ccoutant@google.com>
Date: Tue, 6 Jan 2015 16:56:43 -0800
Subject: [PATCH 04/14] readelf: add support for DWARF-5 and experimental
two-level line number tables.
This change is forward-port of commit d80608344a0908445af29b6db5266394c0376076
- https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=d80608344a0908445af29b6db5266394c0376076
from upstream branch users/ccoutant/two-level-line-150331
- https://sourceware.org/git/?p=binutils-gdb.git;a=shortlog;h=refs/heads/users/ccoutant/two-level-line-150331
to binutils-2_27-branch.
[Adrian Ratiu: rebased from v2.27 to v2.35.1]
[TODO: make more use of the upstream implementation to slim our diff further]
Change-Id: I26158b22c6a6652154b317db1ecf6d5c27d29337
---
binutils/dwarf.c | 992 +++++++++++++++++++++++++++------------------
binutils/readelf.c | 1 +
2 files changed, 595 insertions(+), 398 deletions(-)
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index 91b61e3fdfe..eb59da29eaf 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -478,6 +478,9 @@ typedef struct State_Machine_Registers
unsigned int file;
unsigned int line;
unsigned int column;
+ unsigned int discriminator;
+ unsigned int context;
+ unsigned int subprogram;
int is_stmt;
int basic_block;
unsigned char op_index;
@@ -498,19 +501,65 @@ reset_state_machine (int is_stmt)
state_machine_regs.file = 1;
state_machine_regs.line = 1;
state_machine_regs.column = 0;
+ state_machine_regs.discriminator = 0;
+ state_machine_regs.context = 0;
+ state_machine_regs.subprogram = 0;
state_machine_regs.is_stmt = is_stmt;
state_machine_regs.basic_block = 0;
state_machine_regs.end_sequence = 0;
state_machine_regs.last_file_entry = 0;
}
+/* Build a logicals table for reference when reading the actuals table. */
+
+static SMR *logicals_table = NULL;
+static unsigned int logicals_allocated = 0;
+static unsigned int logicals_count = 0;
+
+static void
+free_logicals (void)
+{
+ free (logicals_table);
+ logicals_allocated = 0;
+ logicals_count = 0;
+ logicals_table = NULL;
+}
+
+static void
+append_logical (void)
+{
+ if (logicals_allocated == 0)
+ {
+ logicals_allocated = 4;
+ logicals_table = (SMR *) xmalloc (logicals_allocated * sizeof (SMR));
+ }
+ if (logicals_count >= logicals_allocated)
+ {
+ logicals_allocated *= 2;
+ logicals_table = (SMR *)
+ xrealloc (logicals_table, logicals_allocated * sizeof (SMR));
+ }
+ logicals_table[logicals_count++] = state_machine_regs;
+ printf (_("\t\tLogical %u: 0x%s[%u] file %u line %u discrim %u context %u subprog %u is_stmt %d\n"),
+ logicals_count,
+ dwarf_vmatoa ("x", state_machine_regs.address),
+ state_machine_regs.op_index,
+ state_machine_regs.file,
+ state_machine_regs.line,
+ state_machine_regs.discriminator,
+ state_machine_regs.context,
+ state_machine_regs.subprogram,
+ state_machine_regs.is_stmt);
+}
+
/* Handled an extend line op.
Returns the number of bytes read. */
static size_t
process_extended_line_op (unsigned char * data,
int is_stmt,
- unsigned char * end)
+ unsigned char * end,
+ int is_logical)
{
unsigned char op_code;
size_t len, header_len;
@@ -535,6 +584,8 @@ process_extended_line_op (unsigned char * data,
{
case DW_LNE_end_sequence:
printf (_("End of Sequence\n\n"));
+ if (is_logical)
+ append_logical ();
reset_state_machine (is_stmt);
break;
@@ -579,8 +630,11 @@ process_extended_line_op (unsigned char * data,
break;
case DW_LNE_set_discriminator:
- READ_ULEB (val, data, end);
- printf (_("set Discriminator to %s\n"), dwarf_vmatoa ("u", val));
+ {
+ READ_ULEB (val, data, end);
+ printf (_("set Discriminator to %s\n"), dwarf_vmatoa ("u", val));
+ state_machine_regs.discriminator = val;
+ }
break;
/* HP extensions. */
@@ -798,8 +852,7 @@ fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set,
if (this_set != NULL)
index_offset += this_set->section_offsets [DW_SECT_STR_OFFSETS];
-
- if (index_offset >= length)
+ if (index_offset + offset_size >= length)
{
warn (_("DW_FORM_GNU_str_index offset too big: %s vs %s\n"),
dwarf_vmatoa ("x", index_offset),
@@ -4010,6 +4063,10 @@ load_debug_info (void * file)
return 0;
}
+/* Experimental DWARF 5 extensions.
+ See http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables. */
+#define DWARF2_LINE_EXPERIMENTAL_VERSION 0xf006
+
/* Read a DWARF .debug_line section header starting at DATA.
Upon success returns an updated DATA pointer and the LINFO
structure and the END_OF_SEQUENCE pointer will be filled in.
@@ -4020,7 +4077,9 @@ read_debug_line_header (struct dwarf_section * section,
unsigned char * data,
unsigned char * end,
DWARF2_Internal_LineInfo * linfo,
- unsigned char ** end_of_sequence)
+ unsigned char ** end_of_sequence,
+ unsigned int * pinitial_length_size,
+ unsigned int * poffset_size)
{
unsigned char *hdrptr;
unsigned int initial_length_size;
@@ -4044,6 +4103,8 @@ read_debug_line_header (struct dwarf_section * section,
linfo->li_offset_size = 4;
initial_length_size = 4;
}
+ *pinitial_length_size = initial_length_size;
+ *poffset_size = linfo->li_offset_size;
if (linfo->li_length + initial_length_size > section->size)
{
@@ -4068,17 +4129,25 @@ read_debug_line_header (struct dwarf_section * section,
/* Get and check the version number. */
SAFE_BYTE_GET_AND_INC (linfo->li_version, hdrptr, 2, end);
+ /* Version 0xf006 is for experimental two-level line tables. */
if (linfo->li_version != 2
&& linfo->li_version != 3
&& linfo->li_version != 4
- && linfo->li_version != 5)
+ && linfo->li_version != 5
+ && linfo->li_version != DWARF2_LINE_EXPERIMENTAL_VERSION)
{
warn (_("Only DWARF version 2, 3, 4 and 5 line info "
"is currently supported.\n"));
return NULL;
}
- if (linfo->li_version >= 5)
+ if (linfo->li_version < 5)
+ {
+ linfo->li_address_size = 0;
+ linfo->li_segment_size = 0;
+ }
+ else if (linfo->li_version >= 5 &&
+ linfo->li_version != DWARF2_LINE_EXPERIMENTAL_VERSION)
{
SAFE_BYTE_GET_AND_INC (linfo->li_address_size, hdrptr, 1, end);
@@ -4127,131 +4196,448 @@ read_debug_line_header (struct dwarf_section * section,
return hdrptr;
}
-static unsigned char *
-display_formatted_table (unsigned char * data,
- unsigned char * start,
- unsigned char * end,
- const DWARF2_Internal_LineInfo * linfo,
- struct dwarf_section * section,
- bfd_boolean is_dir)
-{
- unsigned char *format_start, format_count, *format, formati;
- dwarf_vma data_count, datai;
- unsigned int namepass, last_entry = 0;
- const char * table_name = is_dir ? N_("Directory Table") : N_("File Name Table");
-
- SAFE_BYTE_GET_AND_INC (format_count, data, 1, end);
- if (do_checks && format_count > 5)
- warn (_("Unexpectedly large number of columns in the %s (%u)\n"),
- table_name, format_count);
+static void
+display_directory_table_v4 (unsigned char *start, unsigned char *end,
+ unsigned char **pdata)
+{
+ unsigned char *data = *pdata;
+ unsigned int last_dir_entry = 0;
- format_start = data;
- for (formati = 0; formati < format_count; formati++)
+ if (*data == 0)
+ printf (_("\n The Directory Table is empty.\n"));
+ else
{
- SKIP_ULEB (data, end);
- SKIP_ULEB (data, end);
- if (data == end)
+ printf (_("\n The Directory Table (offset 0x%lx):\n"),
+ (long)(data - start));
+
+ while (data < end && *data != 0)
{
- warn (_("%s: Corrupt format description entry\n"), table_name);
- return data;
+ printf (" %d\t%.*s\n", ++last_dir_entry, (int) (end - data), data);
+
+ data += strnlen ((char *) data, end - data) + 1;
}
}
- READ_ULEB (data_count, data, end);
- if (data_count == 0)
+ /* Skip the NUL at the end of the table. */
+ *pdata = data + 1;
+}
+
+static void
+display_file_name_table_v4 (unsigned char *start, unsigned char *end,
+ unsigned char **pdata)
+{
+ unsigned char *data = *pdata;
+
+ if (*data == 0)
+ printf (_("\n The File Name Table is empty.\n"));
+ else
{
- printf (_("\n The %s is empty.\n"), table_name);
- return data;
+ printf (_("\n The File Name Table (offset 0x%lx):\n"),
+ (long)(data - start));
+ printf (_(" Entry\tDir\tTime\tSize\tName\n"));
+
+ while (data < end && *data != 0)
+ {
+ unsigned char *name;
+ dwarf_vma uladv;
+
+ printf (" %d\t", ++state_machine_regs.last_file_entry);
+ name = data;
+ data += strnlen ((char *) data, end - data) + 1;
+
+ READ_ULEB (uladv, data, end);
+ printf ("%s\t", dwarf_vmatoa ("u", uladv));
+ READ_ULEB (uladv, data, end);
+ printf ("%s\t", dwarf_vmatoa ("u", uladv));
+ READ_ULEB (uladv, data, end);
+ printf ("%s\t", dwarf_vmatoa ("u", uladv));
+ printf ("%.*s\n", (int)(end - name), name);
+
+ if (data == end)
+ {
+ warn (_("Corrupt file name table entry\n"));
+ break;
+ }
+ }
}
- else if (data == end)
+
+ /* Skip the NUL at the end of the table. */
+ *pdata = data + 1;
+}
+
+static int
+display_dir_file_table_v5 (unsigned char *start, unsigned char *end,
+ unsigned char **pdata, char *table_name,
+ unsigned int offset_size)
+{
+ unsigned char *data = *pdata;
+ unsigned int format_count;
+ unsigned int *content_types;
+ unsigned int *content_forms;
+ unsigned int entry_count;
+ unsigned int i, j;
+ const unsigned char *name;
+ dwarf_vma offset;
+ unsigned int val;
+
+ READ_ULEB (format_count, data, end);
+ content_types = (unsigned int *) xmalloc (format_count *
+ sizeof (unsigned int));
+ content_forms = (unsigned int *) xmalloc (format_count *
+ sizeof (unsigned int));
+ for (j = 0; j < format_count; j++)
+ {
+ READ_ULEB (content_types[j], data, end);
+ READ_ULEB (content_forms[j], data, end);
+ }
+
+ READ_ULEB (entry_count, data, end);
+
+ if (entry_count == 0)
+ printf (_("\n The %s Table is empty.\n"), table_name);
+ else
{
- warn (_("%s: Corrupt entry count - expected %s but none found\n"),
- table_name, dwarf_vmatoa ("x", data_count));
- return data;
+ printf (_("\n The %s Table (offset 0x%lx):\n"),
+ table_name, (long)(data - start));
+
+ printf (_(" Entry"));
+ for (j = 0; j < format_count; j++)
+ {
+ printf ("\t");
+ switch (content_types[j])
+ {
+ case DW_LNCT_path:
+ printf (_("Path"));
+ break;
+ case DW_LNCT_subprogram_name:
+ printf (_("Name"));
+ break;
+ case DW_LNCT_directory_index:
+ printf (_("Dir"));
+ break;
+ case DW_LNCT_decl_file:
+ printf (_("File"));
+ break;
+ case DW_LNCT_decl_line:
+ printf (_("Line"));
+ break;
+ }
+ }
+ printf ("\n");
}
- else if (format_count == 0)
+ for (i = 0; i < entry_count; i++)
{
- warn (_("%s: format count is zero, but the table is not empty\n"),
- table_name);
- return end;
+ printf (" %d", i + 1);
+ for (j = 0; j < format_count; j++)
+ {
+ if (data >= end)
+ break;
+ switch (content_forms[j])
+ {
+ case DW_FORM_string:
+ printf ("\t%.*s", (int) (end - data), data);
+ data += strnlen ((char *) data, end - data) + 1;
+ break;
+ case DW_FORM_line_strp:
+ SAFE_BYTE_GET_AND_INC (offset, data, offset_size, end);
+ name = fetch_indirect_line_string (offset);
+ printf ("\t%s", name);
+ break;
+ case DW_FORM_udata:
+ READ_ULEB (val, data, end);
+ printf ("\t%u", val);
+ break;
+ default:
+ printf ("\t%s", _("(unrecognized FORM code)"));
+ data = end;
+ break;
+ }
+ }
+ printf ("\n");
+
+ /* PR 17512: file: 002-132094-0.004. */
+ if (data >= end - 1)
+ break;
}
- printf (_("\n The %s (offset 0x%lx, lines %s, columns %u):\n"),
- table_name, (long) (data - start), dwarf_vmatoa ("u", data_count),
- format_count);
+ free (content_types);
+ free (content_forms);
- printf (_(" Entry"));
- /* Delay displaying name as the last entry for better screen layout. */
- for (namepass = 0; namepass < 2; namepass++)
- {
- format = format_start;
- for (formati = 0; formati < format_count; formati++)
- {
- dwarf_vma content_type;
+ *pdata = data;
+ return entry_count;
+}
- READ_ULEB (content_type, format, end);
- if ((content_type == DW_LNCT_path) == (namepass == 1))
- switch (content_type)
- {
- case DW_LNCT_path:
- printf (_("\tName"));
- break;
- case DW_LNCT_directory_index:
- printf (_("\tDir"));
- break;
- case DW_LNCT_timestamp:
- printf (_("\tTime"));
- break;
- case DW_LNCT_size:
- printf (_("\tSize"));
- break;
- case DW_LNCT_MD5:
- printf (_("\tMD5\t\t\t"));
- break;
- default:
- printf (_("\t(Unknown format content type %s)"),
- dwarf_vmatoa ("u", content_type));
- }
- SKIP_ULEB (format, end);
- }
+static void
+display_line_program (unsigned char *start, unsigned char *end,
+ unsigned char **pdata, char *table_name,
+ DWARF2_Internal_LineInfo *linfo,
+ unsigned char *standard_opcodes,
+ int is_logical)
+{
+ unsigned char *data = *pdata;
+
+ if (data >= end)
+ {
+ printf (_(" No %s.\n"), table_name);
+ return;
}
- putchar ('\n');
- for (datai = 0; datai < data_count; datai++)
+ printf (" %s:\n", table_name);
+
+ while (data < end)
{
- unsigned char *datapass = data;
+ unsigned char op_code;
+ dwarf_signed_vma adv;
+ dwarf_vma uladv;
+ unsigned int logical;
+ int i;
- printf (" %d", last_entry++);
- /* Delay displaying name as the last entry for better screen layout. */
- for (namepass = 0; namepass < 2; namepass++)
+ printf (" [0x%08lx]", (long)(data - start));
+
+ op_code = *data++;
+
+ if (op_code >= linfo->li_opcode_base)
{
- format = format_start;
- data = datapass;
- for (formati = 0; formati < format_count; formati++)
+ op_code -= linfo->li_opcode_base;
+ uladv = (op_code / linfo->li_line_range);
+ if (linfo->li_max_ops_per_insn == 1)
{
- dwarf_vma content_type, form;
-
- READ_ULEB (content_type, format, end);
- READ_ULEB (form, format, end);
- data = read_and_display_attr_value (0, form, 0, start, data, end,
- 0, 0, linfo->li_offset_size,
- linfo->li_version, NULL,
- ((content_type == DW_LNCT_path) != (namepass == 1)),
- section, NULL, '\t', -1);
+ uladv *= linfo->li_min_insn_length;
+ state_machine_regs.address += uladv;
+ printf (_(" Special opcode %d: "
+ "advance Address by %s to 0x%s"),
+ op_code, dwarf_vmatoa ("u", uladv),
+ dwarf_vmatoa ("x", state_machine_regs.address));
}
+ else
+ {
+ state_machine_regs.address
+ += ((state_machine_regs.op_index + uladv)
+ / linfo->li_max_ops_per_insn)
+ * linfo->li_min_insn_length;
+ state_machine_regs.op_index
+ = (state_machine_regs.op_index + uladv)
+ % linfo->li_max_ops_per_insn;
+ printf (_(" Special opcode %d: "
+ "advance Address by %s to 0x%s[%d]"),
+ op_code, dwarf_vmatoa ("u", uladv),
+ dwarf_vmatoa ("x", state_machine_regs.address),
+ state_machine_regs.op_index);
+ }
+ adv = (op_code % linfo->li_line_range) + linfo->li_line_base;
+ state_machine_regs.line += adv;
+ printf (_(" and Line by %s to %d\n"),
+ dwarf_vmatoa ("d", adv), state_machine_regs.line);
+ if (is_logical)
+ append_logical ();
+ state_machine_regs.discriminator = 0;
}
-
- if (data == end && (datai < data_count - 1))
+ else
{
- warn (_("\n%s: Corrupt entries list\n"), table_name);
- return data;
- }
- putchar ('\n');
+ switch (op_code)
+ {
+ case DW_LNS_extended_op:
+ data += process_extended_line_op (data, linfo->li_default_is_stmt,
+ end, is_logical);
+ break;
+
+ case DW_LNS_copy:
+ printf (_(" Copy\n"));
+ if (is_logical)
+ append_logical ();
+ state_machine_regs.discriminator = 0;
+ break;
+
+ case DW_LNS_advance_pc:
+ READ_ULEB (uladv, data, end);
+ if (linfo->li_max_ops_per_insn == 1)
+ {
+ uladv *= linfo->li_min_insn_length;
+ state_machine_regs.address += uladv;
+ printf (_(" Advance PC by %s to 0x%s\n"),
+ dwarf_vmatoa ("u", uladv),
+ dwarf_vmatoa ("x", state_machine_regs.address));
+ }
+ else
+ {
+ state_machine_regs.address
+ += ((state_machine_regs.op_index + uladv)
+ / linfo->li_max_ops_per_insn)
+ * linfo->li_min_insn_length;
+ state_machine_regs.op_index
+ = (state_machine_regs.op_index + uladv)
+ % linfo->li_max_ops_per_insn;
+ printf (_(" Advance PC by %s to 0x%s[%d]\n"),
+ dwarf_vmatoa ("u", uladv),
+ dwarf_vmatoa ("x", state_machine_regs.address),
+ state_machine_regs.op_index);
+ }
+ break;
+
+ case DW_LNS_advance_line:
+ READ_SLEB (adv, data, end);
+ state_machine_regs.line += adv;
+ printf (_(" Advance Line by %s to %d\n"),
+ dwarf_vmatoa ("d", adv),
+ state_machine_regs.line);
+ break;
+
+ case DW_LNS_set_file:
+ READ_ULEB (uladv, data, end);
+ printf (_(" Set File Name to entry %s in the File Name Table\n"),
+ dwarf_vmatoa ("d", uladv));
+ state_machine_regs.file = uladv;
+ break;
+
+ case DW_LNS_set_column:
+ READ_ULEB (uladv, data, end);
+ printf (_(" Set column to %s\n"),
+ dwarf_vmatoa ("u", uladv));
+ state_machine_regs.column = uladv;
+ break;
+
+ case DW_LNS_negate_stmt:
+ adv = state_machine_regs.is_stmt;
+ adv = ! adv;
+ printf (_(" Set is_stmt to %s\n"), dwarf_vmatoa ("d", adv));
+ state_machine_regs.is_stmt = adv;
+ break;
+
+ case DW_LNS_set_basic_block:
+ printf (_(" Set basic block\n"));
+ state_machine_regs.basic_block = 1;
+ break;
+
+ case DW_LNS_const_add_pc:
+ uladv = ((255 - linfo->li_opcode_base) / linfo->li_line_range);
+ if (linfo->li_max_ops_per_insn)
+ {
+ uladv *= linfo->li_min_insn_length;
+ state_machine_regs.address += uladv;
+ printf (_(" Advance PC by constant %s to 0x%s\n"),
+ dwarf_vmatoa ("u", uladv),
+ dwarf_vmatoa ("x", state_machine_regs.address));
+ }
+ else
+ {
+ state_machine_regs.address
+ += ((state_machine_regs.op_index + uladv)
+ / linfo->li_max_ops_per_insn)
+ * linfo->li_min_insn_length;
+ state_machine_regs.op_index
+ = (state_machine_regs.op_index + uladv)
+ % linfo->li_max_ops_per_insn;
+ printf (_(" Advance PC by constant %s to 0x%s[%d]\n"),
+ dwarf_vmatoa ("u", uladv),
+ dwarf_vmatoa ("x", state_machine_regs.address),
+ state_machine_regs.op_index);
+ }
+ break;
+
+ case DW_LNS_fixed_advance_pc:
+ SAFE_BYTE_GET_AND_INC (uladv, data, 2, end);
+ state_machine_regs.address += uladv;
+ state_machine_regs.op_index = 0;
+ printf (_(" Advance PC by fixed size amount %s to 0x%s\n"),
+ dwarf_vmatoa ("u", uladv),
+ dwarf_vmatoa ("x", state_machine_regs.address));
+ break;
+
+ case DW_LNS_set_prologue_end:
+ printf (_(" Set prologue_end to true\n"));
+ break;
+
+ case DW_LNS_set_epilogue_begin:
+ printf (_(" Set epilogue_begin to true\n"));
+ break;
+
+ case DW_LNS_set_isa:
+ READ_ULEB (uladv, data, end);
+ printf (_(" Set ISA to %s\n"), dwarf_vmatoa ("u", uladv));
+ break;
+
+ case DW_LNS_set_subprogram:
+ /* This opcode is aliased with: */
+ /* case DW_LNS_set_address_from_logical: */
+ if (is_logical)
+ {
+ /* DW_LNS_set_subprogram */
+ state_machine_regs.context = 0;
+ READ_ULEB (state_machine_regs.subprogram, data, end);
+ printf (_(" Set subprogram to %u and reset context to 0\n"),
+ state_machine_regs.subprogram);
+ }
+ else
+ {
+ /* DW_LNS_set_address_from_logical */
+ READ_SLEB (adv, data, end);
+ state_machine_regs.line += adv;
+ logical = state_machine_regs.line;
+ if (logical - 1 < logicals_count)
+ {
+ state_machine_regs.address = logicals_table[logical - 1].address;
+ state_machine_regs.op_index = logicals_table[logical - 1].op_index;
+ }
+ else
+ warn (_("Logical row number outside range of logicals table\n"));
+ printf (_(" Advance Line by %s to %u and set address from logical to 0x%s[%u]\n"),
+ dwarf_vmatoa ("d", adv),
+ logical,
+ dwarf_vmatoa ("x", state_machine_regs.address),
+ state_machine_regs.op_index);
+ }
+ break;
+
+ case DW_LNS_inlined_call:
+ READ_SLEB (adv, data, end);
+ state_machine_regs.context = logicals_count + adv;
+ READ_ULEB (state_machine_regs.subprogram, data, end);
+ printf (_(" Set context to %u and subprogram to %u\n"),
+ state_machine_regs.context,
+ state_machine_regs.subprogram);
+ break;
+
+ case DW_LNS_pop_context:
+ logical = state_machine_regs.context;
+ printf (_(" Pop context to logical %u\n"), logical);
+ if (logical - 1 < logicals_count)
+ {
+ state_machine_regs.file = logicals_table[logical - 1].file;
+ state_machine_regs.line = logicals_table[logical - 1].line;
+ state_machine_regs.column = logicals_table[logical - 1].column;
+ state_machine_regs.discriminator = logicals_table[logical - 1].discriminator;
+ state_machine_regs.is_stmt = logicals_table[logical - 1].is_stmt;
+ state_machine_regs.context = logicals_table[logical - 1].context;
+ state_machine_regs.subprogram = logicals_table[logical - 1].subprogram;
+ }
+ else
+ warn (_("Context register outside range of logicals table\n"));
+ break;
+
+ default:
+ printf (_(" Unknown opcode %d with operands: "), op_code);
+
+ if (standard_opcodes != NULL)
+ for (i = standard_opcodes[op_code - 1]; i > 0 ; --i)
+ {
+ dwarf_vma val;
+ READ_ULEB (val, data, end);
+ printf ("0x%s%s", dwarf_vmatoa ("x", val),
+ i == 1 ? "" : ", ");
+ }
+ putchar ('\n');
+ break;
+ }
+ }
}
- return data;
+
+ putchar ('\n');
+ *pdata = data;
}
+#define UNUSED(x) (void)(x)
+
static int
display_debug_lines_raw (struct dwarf_section * section,
unsigned char * data,
@@ -4259,7 +4645,9 @@ display_debug_lines_raw (struct dwarf_section * section,
void * file)
{
unsigned char *start = section->start;
- int verbose_view = 0;
+ unsigned int initial_length_size;
+ unsigned int offset_size;
+ UNUSED(file);
introduce (section, TRUE);
@@ -4267,9 +4655,15 @@ display_debug_lines_raw (struct dwarf_section * section,
{
static DWARF2_Internal_LineInfo saved_linfo;
DWARF2_Internal_LineInfo linfo;
+ unsigned int logicals_table_offset = 0;
+ unsigned int actuals_table_offset = 0;
+ unsigned char *end_of_header_length;
unsigned char *standard_opcodes;
+ unsigned char *start_of_line_program;
+ unsigned char *end_of_logicals;
unsigned char *end_of_sequence;
int i;
+ unsigned char *hdrptr = NULL;
if (const_strneq (section->name, ".debug_line.")
/* Note: the following does not apply to .debug_line.dwo sections.
@@ -4286,7 +4680,9 @@ display_debug_lines_raw (struct dwarf_section * section,
Since the section is a fragment it does not have the details
needed to fill out a LineInfo structure, so instead we use the
details from the last full debug_line section that we processed. */
+ start_of_line_program = data;
end_of_sequence = end;
+ end_of_logicals = end;
standard_opcodes = NULL;
linfo = saved_linfo;
/* PR 17531: file: 0522b371. */
@@ -4299,16 +4695,17 @@ display_debug_lines_raw (struct dwarf_section * section,
}
else
{
- unsigned char * hdrptr;
-
if ((hdrptr = read_debug_line_header (section, data, end, & linfo,
- & end_of_sequence)) == NULL)
+ & end_of_sequence,
+ & initial_length_size,
+ & offset_size)) == NULL)
return 0;
printf (_(" Offset: 0x%lx\n"), (long)(data - start));
printf (_(" Length: %ld\n"), (long) linfo.li_length);
printf (_(" DWARF Version: %d\n"), linfo.li_version);
- if (linfo.li_version >= 5)
+ if (linfo.li_version >= 5
+ && linfo.li_version != DWARF2_LINE_EXPERIMENTAL_VERSION)
{
printf (_(" Address size (bytes): %d\n"), linfo.li_address_size);
printf (_(" Segment selector (bytes): %d\n"), linfo.li_segment_size);
@@ -4322,6 +4719,13 @@ display_debug_lines_raw (struct dwarf_section * section,
printf (_(" Line Range: %d\n"), linfo.li_line_range);
printf (_(" Opcode Base: %d\n"), linfo.li_opcode_base);
+ end_of_header_length = data + initial_length_size + 2 + offset_size;
+ if (linfo.li_version >= 5
+ && linfo.li_version != DWARF2_LINE_EXPERIMENTAL_VERSION)
+ end_of_header_length += 2;
+ start_of_line_program = end_of_header_length + linfo.li_prologue_length;
+ end_of_logicals = end;
+
/* PR 17512: file: 1665-6428-0.004. */
if (linfo.li_line_range == 0)
{
@@ -4349,314 +4753,100 @@ display_debug_lines_raw (struct dwarf_section * section,
standard_opcodes[i - 1]),
i, standard_opcodes[i - 1]);
- /* Display the contents of the Directory table. */
data = standard_opcodes + linfo.li_opcode_base - 1;
- if (linfo.li_version >= 5)
- {
- load_debug_section_with_follow (line_str, file);
-
- data = display_formatted_table (data, start, end, &linfo, section,
- TRUE);
- data = display_formatted_table (data, start, end, &linfo, section,
- FALSE);
- }
- else
+ if (linfo.li_version == DWARF2_LINE_EXPERIMENTAL_VERSION)
{
- if (*data == 0)
- printf (_("\n The Directory Table is empty.\n"));
- else
- {
- unsigned int last_dir_entry = 0;
-
- printf (_("\n The Directory Table (offset 0x%lx):\n"),
- (long)(data - start));
+ /* Skip the fake directory and filename table. */
+ data += 2;
- while (data < end && *data != 0)
- {
- printf (" %d\t%.*s\n", ++last_dir_entry, (int) (end - data), data);
+ /* Skip the fake extended opcode that wraps the rest
+ of the section. */
+ data += 5;
- data += strnlen ((char *) data, end - data) + 1;
- }
-
- /* PR 17512: file: 002-132094-0.004. */
- if (data >= end - 1)
- break;
- }
+ /* Read the logicals table offset and actuals table offset. */
+ SAFE_BYTE_GET_AND_INC (logicals_table_offset, data, offset_size, end);
+ SAFE_BYTE_GET_AND_INC (actuals_table_offset, data, offset_size, end);
- /* Skip the NUL at the end of the table. */
- data++;
+ start_of_line_program = end_of_header_length + logicals_table_offset;
- /* Display the contents of the File Name table. */
- if (*data == 0)
- printf (_("\n The File Name Table is empty.\n"));
- else
- {
- printf (_("\n The File Name Table (offset 0x%lx):\n"),
- (long)(data - start));
- printf (_(" Entry\tDir\tTime\tSize\tName\n"));
+ if (actuals_table_offset > 0)
+ end_of_logicals = end_of_header_length + actuals_table_offset;
- while (data < end && *data != 0)
- {
- unsigned char *name;
- dwarf_vma val;
+ putchar ('\n');
+ printf (_(" Logicals Table Offset: 0x%x\n"), logicals_table_offset);
+ printf (_(" Actuals Table Offset: 0x%x\n"), actuals_table_offset);
+ }
- printf (" %d\t", ++state_machine_regs.last_file_entry);
- name = data;
- data += strnlen ((char *) data, end - data) + 1;
+ /* Display the contents of the Directory table. */
+ if (linfo.li_version >= 5)
+ display_dir_file_table_v5 (start, end, &data, _("Directory"),
+ offset_size);
+ else
+ display_directory_table_v4 (start, end, &data);
- READ_ULEB (val, data, end);
- printf ("%s\t", dwarf_vmatoa ("u", val));
- READ_ULEB (val, data, end);
- printf ("%s\t", dwarf_vmatoa ("u", val));
- READ_ULEB (val, data, end);
- printf ("%s\t", dwarf_vmatoa ("u", val));
- printf ("%.*s\n", (int)(end - name), name);
+ /* PR 17512: file: 002-132094-0.004. */
+ if (data >= end - 1)
+ break;
- if (data == end)
- {
- warn (_("Corrupt file name table entry\n"));
- break;
- }
- }
- }
+ /* Display the contents of the File Name table. */
+ if (linfo.li_version >= 5)
+ {
+ unsigned int count;
- /* Skip the NUL at the end of the table. */
- data++;
+ count = display_dir_file_table_v5 (start, end, &data,
+ _("File Name"), offset_size);
+ state_machine_regs.last_file_entry = count - 1;
}
+ else
+ display_file_name_table_v4 (start, end, &data);
+
+ /* Display the contents of the Subprogram table. */
+ if (linfo.li_version == DWARF2_LINE_EXPERIMENTAL_VERSION)
+ display_dir_file_table_v5 (start, end, &data, _("Subprogram"),
+ offset_size);
putchar ('\n');
saved_linfo = linfo;
}
- /* Now display the statements. */
- if (data >= end_of_sequence)
- printf (_(" No Line Number Statements.\n"));
- else
- {
- printf (_(" Line Number Statements:\n"));
+ if (data > start_of_line_program)
+ warn (_("Line table header is longer than header_length indicates\n"));
+ else if (data < start_of_line_program)
+ warn (_("Line table header is shorter than header_length indicates\n"));
+ data = start_of_line_program;
- while (data < end_of_sequence)
+ if (linfo.li_version == DWARF2_LINE_EXPERIMENTAL_VERSION
+ && hdrptr != NULL
+ && actuals_table_offset > 0)
+ {
+ if (end_of_logicals > end)
{
- unsigned char op_code;
- dwarf_signed_vma adv;
- dwarf_vma uladv;
-
- printf (" [0x%08lx]", (long)(data - start));
-
- op_code = *data++;
-
- if (op_code >= linfo.li_opcode_base)
- {
- op_code -= linfo.li_opcode_base;
- uladv = (op_code / linfo.li_line_range);
- if (linfo.li_max_ops_per_insn == 1)
- {
- uladv *= linfo.li_min_insn_length;
- state_machine_regs.address += uladv;
- if (uladv)
- state_machine_regs.view = 0;
- printf (_(" Special opcode %d: "
- "advance Address by %s to 0x%s%s"),
- op_code, dwarf_vmatoa ("u", uladv),
- dwarf_vmatoa ("x", state_machine_regs.address),
- verbose_view && uladv
- ? _(" (reset view)") : "");
- }
- else
- {
- unsigned addrdelta
- = ((state_machine_regs.op_index + uladv)
- / linfo.li_max_ops_per_insn)
- * linfo.li_min_insn_length;
-
- state_machine_regs.address += addrdelta;
- state_machine_regs.op_index
- = (state_machine_regs.op_index + uladv)
- % linfo.li_max_ops_per_insn;
- if (addrdelta)
- state_machine_regs.view = 0;
- printf (_(" Special opcode %d: "
- "advance Address by %s to 0x%s[%d]%s"),
- op_code, dwarf_vmatoa ("u", uladv),
- dwarf_vmatoa ("x", state_machine_regs.address),
- state_machine_regs.op_index,
- verbose_view && addrdelta
- ? _(" (reset view)") : "");
- }
- adv = (op_code % linfo.li_line_range) + linfo.li_line_base;
- state_machine_regs.line += adv;
- printf (_(" and Line by %s to %d"),
- dwarf_vmatoa ("d", adv), state_machine_regs.line);
- if (verbose_view || state_machine_regs.view)
- printf (_(" (view %u)\n"), state_machine_regs.view);
- else
- putchar ('\n');
- state_machine_regs.view++;
- }
- else
- switch (op_code)
- {
- case DW_LNS_extended_op:
- data += process_extended_line_op (data,
- linfo.li_default_is_stmt,
- end);
- break;
-
- case DW_LNS_copy:
- printf (_(" Copy"));
- if (verbose_view || state_machine_regs.view)
- printf (_(" (view %u)\n"), state_machine_regs.view);
- else
- putchar ('\n');
- state_machine_regs.view++;
- break;
-
- case DW_LNS_advance_pc:
- READ_ULEB (uladv, data, end);
- if (linfo.li_max_ops_per_insn == 1)
- {
- uladv *= linfo.li_min_insn_length;
- state_machine_regs.address += uladv;
- if (uladv)
- state_machine_regs.view = 0;
- printf (_(" Advance PC by %s to 0x%s%s\n"),
- dwarf_vmatoa ("u", uladv),
- dwarf_vmatoa ("x", state_machine_regs.address),
- verbose_view && uladv
- ? _(" (reset view)") : "");
- }
- else
- {
- unsigned addrdelta
- = ((state_machine_regs.op_index + uladv)
- / linfo.li_max_ops_per_insn)
- * linfo.li_min_insn_length;
- state_machine_regs.address
- += addrdelta;
- state_machine_regs.op_index
- = (state_machine_regs.op_index + uladv)
- % linfo.li_max_ops_per_insn;
- if (addrdelta)
- state_machine_regs.view = 0;
- printf (_(" Advance PC by %s to 0x%s[%d]%s\n"),
- dwarf_vmatoa ("u", uladv),
- dwarf_vmatoa ("x", state_machine_regs.address),
- state_machine_regs.op_index,
- verbose_view && addrdelta
- ? _(" (reset view)") : "");
- }
- break;
-
- case DW_LNS_advance_line:
- READ_SLEB (adv, data, end);
- state_machine_regs.line += adv;
- printf (_(" Advance Line by %s to %d\n"),
- dwarf_vmatoa ("d", adv),
- state_machine_regs.line);
- break;
-
- case DW_LNS_set_file:
- READ_ULEB (uladv, data, end);
- printf (_(" Set File Name to entry %s in the File Name Table\n"),
- dwarf_vmatoa ("u", uladv));
- state_machine_regs.file = uladv;
- break;
-
- case DW_LNS_set_column:
- READ_ULEB (uladv, data, end);
- printf (_(" Set column to %s\n"),
- dwarf_vmatoa ("u", uladv));
- state_machine_regs.column = uladv;
- break;
-
- case DW_LNS_negate_stmt:
- adv = state_machine_regs.is_stmt;
- adv = ! adv;
- printf (_(" Set is_stmt to %s\n"), dwarf_vmatoa ("d", adv));
- state_machine_regs.is_stmt = adv;
- break;
-
- case DW_LNS_set_basic_block:
- printf (_(" Set basic block\n"));
- state_machine_regs.basic_block = 1;
- break;
-
- case DW_LNS_const_add_pc:
- uladv = ((255 - linfo.li_opcode_base) / linfo.li_line_range);
- if (linfo.li_max_ops_per_insn)
- {
- uladv *= linfo.li_min_insn_length;
- state_machine_regs.address += uladv;
- if (uladv)
- state_machine_regs.view = 0;
- printf (_(" Advance PC by constant %s to 0x%s%s\n"),
- dwarf_vmatoa ("u", uladv),
- dwarf_vmatoa ("x", state_machine_regs.address),
- verbose_view && uladv
- ? _(" (reset view)") : "");
- }
- else
- {
- unsigned addrdelta
- = ((state_machine_regs.op_index + uladv)
- / linfo.li_max_ops_per_insn)
- * linfo.li_min_insn_length;
- state_machine_regs.address
- += addrdelta;
- state_machine_regs.op_index
- = (state_machine_regs.op_index + uladv)
- % linfo.li_max_ops_per_insn;
- if (addrdelta)
- state_machine_regs.view = 0;
- printf (_(" Advance PC by constant %s to 0x%s[%d]%s\n"),
- dwarf_vmatoa ("u", uladv),
- dwarf_vmatoa ("x", state_machine_regs.address),
- state_machine_regs.op_index,
- verbose_view && addrdelta
- ? _(" (reset view)") : "");
- }
- break;
-
- case DW_LNS_fixed_advance_pc:
- SAFE_BYTE_GET_AND_INC (uladv, data, 2, end);
- state_machine_regs.address += uladv;
- state_machine_regs.op_index = 0;
- printf (_(" Advance PC by fixed size amount %s to 0x%s\n"),
- dwarf_vmatoa ("u", uladv),
- dwarf_vmatoa ("x", state_machine_regs.address));
- /* Do NOT reset view. */
- break;
-
- case DW_LNS_set_prologue_end:
- printf (_(" Set prologue_end to true\n"));
- break;
-
- case DW_LNS_set_epilogue_begin:
- printf (_(" Set epilogue_begin to true\n"));
- break;
-
- case DW_LNS_set_isa:
- READ_ULEB (uladv, data, end);
- printf (_(" Set ISA to %s\n"), dwarf_vmatoa ("u", uladv));
- break;
-
- default:
- printf (_(" Unknown opcode %d with operands: "), op_code);
-
- if (standard_opcodes != NULL)
- for (i = standard_opcodes[op_code - 1]; i > 0 ; --i)
- {
- READ_ULEB (uladv, data, end);
- printf ("0x%s%s", dwarf_vmatoa ("x", uladv),
- i == 1 ? "" : ", ");
- }
- putchar ('\n');
- break;
- }
+ warn (_("Actuals table offset %s extends beyond end of section\n"),
+ dwarf_vmatoa ("u", actuals_table_offset));
+ end_of_logicals = end;
}
- putchar ('\n');
- }
+ display_line_program (start, end_of_logicals, &data,
+ _("Logicals Statements"),
+ &linfo, standard_opcodes, 1);
+ if (data > end_of_logicals)
+ warn (_("Logicals table is longer than actuals_table_offset indicates\n"));
+ else if (data < end_of_logicals)
+ warn (_("Line table header is shorter than actuals_table_offset indicates\n"));
+ data = end_of_logicals;
+ reset_state_machine (linfo.li_default_is_stmt);
+ display_line_program (start, end_of_sequence, &data,
+ _("Actuals Statements"),
+ &linfo, standard_opcodes, 0);
+ free_logicals ();
+ }
+ else
+ {
+ display_line_program (start, end_of_sequence, &data,
+ _("Line Number Statements"),
+ &linfo, standard_opcodes, 0);
+ }
+
}
return 1;
@@ -4680,6 +4870,8 @@ display_debug_lines_decoded (struct dwarf_section * section,
void * fileptr)
{
static DWARF2_Internal_LineInfo saved_linfo;
+ unsigned int initial_length_size;
+ unsigned int offset_size;
introduce (section, FALSE);
@@ -4717,7 +4909,9 @@ display_debug_lines_decoded (struct dwarf_section * section,
unsigned char *hdrptr;
if ((hdrptr = read_debug_line_header (section, data, end, & linfo,
- & end_of_sequence)) == NULL)
+ & end_of_sequence,
+ & initial_length_size,
+ & offset_size)) == NULL)
return 0;
/* PR 17531: file: 0522b371. */
@@ -5413,6 +5607,8 @@ display_debug_lines (struct dwarf_section *section, void *file)
if (do_debug_lines == 0)
do_debug_lines |= FLAG_DEBUG_LINES_RAW;
+ load_debug_section (line_str, file);
+
if (do_debug_lines & FLAG_DEBUG_LINES_RAW)
retValRaw = display_debug_lines_raw (section, data, end, file);
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 41547a2594b..4af4c0c6e1a 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -6443,6 +6443,7 @@ process_section_headers (Filedata * filedata)
|| (do_debug_macinfo && const_strneq (name, "macro"))
|| (do_debug_str && const_strneq (name, "str"))
|| (do_debug_str_offsets && const_strneq (name, "str_offsets"))
+ || (do_debug_str && const_strneq (name, "line_str"))
|| (do_debug_loc && const_strneq (name, "loc"))
|| (do_debug_loc && const_strneq (name, "loclists"))
|| (do_debug_addr && const_strneq (name, "addr"))
--
2.31.1