diff options
author | Cary Coutant <ccoutant@google.com> | 2015-01-06 16:56:43 -0800 |
---|---|---|
committer | Cary Coutant <ccoutant@google.com> | 2015-03-31 10:51:10 -0700 |
commit | d80608344a0908445af29b6db5266394c0376076 (patch) | |
tree | 52dde9080342b62894d2f72d0ba0332fc725a1c2 | |
parent | a7c7bcafd2add7ecf8ea2ad7d3d77cf38d46c195 (diff) | |
download | fsf-binutils-gdb-d80608344a0908445af29b6db5266394c0376076.zip fsf-binutils-gdb-d80608344a0908445af29b6db5266394c0376076.tar.gz fsf-binutils-gdb-d80608344a0908445af29b6db5266394c0376076.tar.bz2 |
Add support for DWARF-5 and experimental two-level line number tables.
http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables
2015-01-06 Cary Coutant <ccoutant@google.com>
binutils/
* dwarf.h (struct DWARF2_Internal_LineInfo): Add li_address_size and
li_segment_size.
* dwarf.c (struct State_Machine_Registers): Add discriminator,
context, and subprogram.
(reset_state_machine): Likewise.
(logicals_table, logicals_allocated, logicals_count): New variables.
(free_logicals): New function.
(append_logical): New function.
(process_extended_line_op): Add is_logical parameter; track
discriminator.
(fetch_indirect_string): Correct boundary check.
(fetch_indirect_line_string): New function.
(fetch_indexed_string): Corrrect boundary check.
(DWARF2_LINE_EXPERIMENTAL_VERSION): New macro.
(read_debug_line_header): Add pinitial_length_size, poffset_size
parameters. Update all callers. Check for new line table versions.
Read li_address_size and li_segment_size.
(display_directory_table_v4): New function, factored out from
display_debug_lines_raw.
(display_file_name_table_v4): Likewise.
(display_dir_file_table_v5): New function.
(display_line_program): New function, factored out from
display_debug_lines_raw.
(display_debug_lines_raw): Support new line table versions.
(display_debug_lines_decoded): Add missing newline to warning.
(display_debug_lines): Load .debug_line_str section.
(debug_displays): Add .debug_line_str section.
* dwarf.h (dwarf_section_display_enum): Add line_str.
* readelf.c (process_section_headers): Add .debug_line_str.
-rw-r--r-- | binutils/dwarf.c | 930 | ||||
-rw-r--r-- | binutils/dwarf.h | 3 | ||||
-rw-r--r-- | binutils/readelf.c | 1 |
3 files changed, 680 insertions, 254 deletions
diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 5884140..0e33e99 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -387,6 +387,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; @@ -406,19 +409,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 int process_extended_line_op (unsigned char * data, int is_stmt, - unsigned char * end) + unsigned char * end, + int is_logical) { unsigned char op_code; unsigned int bytes_read; @@ -445,6 +494,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; @@ -483,8 +534,14 @@ process_extended_line_op (unsigned char * data, break; case DW_LNE_set_discriminator: - printf (_("set Discriminator to %s\n"), - dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); + { + unsigned int discrim; + + discrim = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + printf (_("set Discriminator to %u\n"), discrim); + state_machine_regs.discriminator = discrim; + } break; /* HP extensions. */ @@ -597,7 +654,7 @@ fetch_indirect_string (dwarf_vma offset) if (section->start == NULL) return (const unsigned char *) _("<no .debug_str section>"); - if (offset > section->size) + if (offset >= section->size) { warn (_("DW_FORM_strp offset too big: %s\n"), dwarf_vmatoa ("x", offset)); @@ -607,6 +664,24 @@ fetch_indirect_string (dwarf_vma offset) return (const unsigned char *) section->start + offset; } +static const unsigned char * +fetch_indirect_line_string (dwarf_vma offset) +{ + struct dwarf_section *section = &debug_displays [line_str].section; + + if (section->start == NULL) + return (const unsigned char *) _("<no .debug_line_str section>"); + + if (offset >= section->size) + { + warn (_("DW_FORM_line_strp offset too big: %s\n"), + dwarf_vmatoa ("x", offset)); + return (const unsigned char *) _("<offset is too big>"); + } + + return (const unsigned char *) section->start + offset; +} + static const char * fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set, dwarf_vma offset_size, int dwo) @@ -624,7 +699,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 > index_section->size) + if (index_offset + offset_size > index_section->size) { warn (_("DW_FORM_GNU_str_index offset too big: %s\n"), dwarf_vmatoa ("x", index_offset)); @@ -637,7 +712,7 @@ fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set, str_offset = byte_get (index_section->start + index_offset, offset_size); str_offset -= str_section->address; - if (str_offset > str_section->size) + if (str_offset >= str_section->size) { warn (_("DW_FORM_GNU_str_index indirect offset too big: %s\n"), dwarf_vmatoa ("x", str_offset)); @@ -2721,6 +2796,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. @@ -2731,7 +2810,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 offset_size; @@ -2756,6 +2837,8 @@ read_debug_line_header (struct dwarf_section * section, offset_size = 4; initial_length_size = 4; } + *pinitial_length_size = initial_length_size; + *poffset_size = offset_size; if (linfo->li_length + initial_length_size > section->size) { @@ -2778,15 +2861,30 @@ 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 != 4 + && linfo->li_version != 5 + && linfo->li_version != DWARF2_LINE_EXPERIMENTAL_VERSION) { - warn (_("Only DWARF version 2, 3 and 4 line info is currently supported.\n")); + warn (_("Only DWARF versions 2-5 line info are currently supported.\n")); return NULL; } + if (linfo->li_version < 5) + { + linfo->li_address_size = 0; + linfo->li_segment_size = 0; + } + else if (linfo->li_version != DWARF2_LINE_EXPERIMENTAL_VERSION) + { + SAFE_BYTE_GET_AND_INC (linfo->li_address_size, hdrptr, 1, end); + SAFE_BYTE_GET_AND_INC (linfo->li_segment_size, hdrptr, 1, end); + } + SAFE_BYTE_GET_AND_INC (linfo->li_prologue_length, hdrptr, offset_size, end); + SAFE_BYTE_GET_AND_INC (linfo->li_min_insn_length, hdrptr, 1, end); if (linfo->li_version >= 4) @@ -2820,12 +2918,473 @@ read_debug_line_header (struct dwarf_section * section, return hdrptr; } +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; + + if (*data == 0) + printf (_("\n The Directory Table is empty.\n")); + else + { + printf (_("\n The Directory Table (offset 0x%lx):\n"), + (long)(data - start)); + + while (data < end && *data != 0) + { + printf (" %d\t%.*s\n", ++last_dir_entry, (int) (end - data), data); + + data += strnlen ((char *) data, end - data) + 1; + } + } + + /* 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 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; + unsigned int bytes_read; + + printf (" %d\t", ++state_machine_regs.last_file_entry); + name = data; + data += strnlen ((char *) data, end - data) + 1; + + printf ("%s\t", + dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); + data += bytes_read; + printf ("%s\t", + dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); + data += bytes_read; + printf ("%s\t", + dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); + data += bytes_read; + printf ("%.*s\n", (int)(end - name), name); + + if (data == end) + { + warn (_("Corrupt file name table entry\n")); + break; + } + } + } + + /* 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 bytes_read; + 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; + + format_count = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + 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++) + { + content_types[j] = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + content_forms[j] = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + } + + entry_count = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + + if (entry_count == 0) + printf (_("\n The %s Table is empty.\n"), table_name); + else + { + 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"); + } + + for (i = 0; i < entry_count; i++) + { + 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: + val = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + 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; + } + + free (content_types); + free (content_forms); + + *pdata = data; + return entry_count; +} + +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; + } + + printf (" %s:\n", table_name); + + while (data < end) + { + unsigned char op_code; + dwarf_signed_vma adv; + dwarf_vma uladv; + unsigned int bytes_read; + unsigned int logical; + int i; + + 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; + 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; + } + else + { + 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: + uladv = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + 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: + adv = read_sleb128 (data, & bytes_read, end); + data += bytes_read; + 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: + adv = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + printf (_(" Set File Name to entry %s in the File Name Table\n"), + dwarf_vmatoa ("d", adv)); + state_machine_regs.file = adv; + break; + + case DW_LNS_set_column: + uladv = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + 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: + uladv = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + 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; + state_machine_regs.subprogram = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + printf (_(" Set subprogram to %u and reset context to 0\n"), + state_machine_regs.subprogram); + } + else + { + /* DW_LNS_set_address_from_logical */ + adv = read_sleb128 (data, & bytes_read, end); + data += bytes_read; + 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: + adv = read_sleb128 (data, & bytes_read, end); + data += bytes_read; + state_machine_regs.context = logicals_count + adv; + state_machine_regs.subprogram = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + 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) + { + printf ("0x%s%s", dwarf_vmatoa ("x", read_uleb128 (data, + &bytes_read, end)), + i == 1 ? "" : ", "); + data += bytes_read; + } + putchar ('\n'); + break; + } + } + } + + putchar ('\n'); + *pdata = data; +} + static int display_debug_lines_raw (struct dwarf_section *section, unsigned char *data, unsigned char *end) { unsigned char *start = section->start; + unsigned int initial_length_size; + unsigned int offset_size; printf (_("Raw dump of debug contents of section %s:\n\n"), section->name); @@ -2834,10 +3393,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; - unsigned int last_dir_entry = 0; int i; + unsigned char *hdrptr = NULL; if (const_strneq (section->name, ".debug_line.") /* Note: the following does not apply to .debug_line.dwo sections. @@ -2854,7 +3418,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. */ @@ -2867,15 +3433,21 @@ 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 + && linfo.li_version != DWARF2_LINE_EXPERIMENTAL_VERSION) + { + printf (_(" Address Size: %u\n"), linfo.li_address_size); + printf (_(" Segment Size: %u\n"), linfo.li_segment_size); + } printf (_(" Prologue Length: %d\n"), (int) linfo.li_prologue_length); printf (_(" Minimum Instruction Length: %d\n"), linfo.li_min_insn_length); if (linfo.li_version >= 4) @@ -2885,6 +3457,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) { @@ -2909,265 +3488,100 @@ display_debug_lines_raw (struct dwarf_section *section, for (i = 1; i < linfo.li_opcode_base; i++) printf (_(" Opcode %d has %d args\n"), i, standard_opcodes[i - 1]); - /* Display the contents of the Directory table. */ data = standard_opcodes + linfo.li_opcode_base - 1; - if (*data == 0) - printf (_("\n The Directory Table is empty.\n")); - else + if (linfo.li_version == DWARF2_LINE_EXPERIMENTAL_VERSION) { - 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; - } + /* 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); - /* PR 17512: file: 002-132094-0.004. */ - if (data >= end - 1) - break; - } + start_of_line_program = end_of_header_length + logicals_table_offset; - /* Skip the NUL at the end of the table. */ - data++; + if (actuals_table_offset > 0) + end_of_logicals = end_of_header_length + actuals_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")); + putchar ('\n'); + printf (_(" Logicals Table Offset: 0x%x\n"), logicals_table_offset); + printf (_(" Actuals Table Offset: 0x%x\n"), actuals_table_offset); + } - while (data < end && *data != 0) - { - unsigned char *name; - unsigned int bytes_read; + /* 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); - printf (" %d\t", ++state_machine_regs.last_file_entry); - name = data; - data += strnlen ((char *) data, end - data) + 1; + /* PR 17512: file: 002-132094-0.004. */ + if (data >= end - 1) + break; - printf ("%s\t", - dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); - data += bytes_read; - printf ("%s\t", - dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); - data += bytes_read; - printf ("%s\t", - dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); - data += bytes_read; - printf ("%.*s\n", (int)(end - name), name); + /* Display the contents of the File Name table. */ + if (linfo.li_version >= 5) + { + unsigned int count; - if (data == end) - { - warn (_("Corrupt file name table entry\n")); - break; - } - } + 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); - /* Skip the NUL at the end of the table. */ - data++; 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")); - - while (data < end_of_sequence) + 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; + + 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; - unsigned int bytes_read; - - 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; - 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); - } - 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\n")); - break; - - case DW_LNS_advance_pc: - uladv = read_uleb128 (data, & bytes_read, end); - data += bytes_read; - 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: - adv = read_sleb128 (data, & bytes_read, end); - data += bytes_read; - 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: - adv = read_uleb128 (data, & bytes_read, end); - data += bytes_read; - printf (_(" Set File Name to entry %s in the File Name Table\n"), - dwarf_vmatoa ("d", adv)); - state_machine_regs.file = adv; - break; - - case DW_LNS_set_column: - uladv = read_uleb128 (data, & bytes_read, end); - data += bytes_read; - 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: - uladv = read_uleb128 (data, & bytes_read, end); - data += bytes_read; - 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) - { - printf ("0x%s%s", dwarf_vmatoa ("x", read_uleb128 (data, - &bytes_read, end)), - i == 1 ? "" : ", "); - data += bytes_read; - } - 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; @@ -3189,6 +3603,8 @@ display_debug_lines_decoded (struct dwarf_section *section, unsigned char *end) { static DWARF2_Internal_LineInfo saved_linfo; + unsigned int initial_length_size; + unsigned int offset_size; printf (_("Decoded dump of debug contents of section %s:\n\n"), section->name); @@ -3227,7 +3643,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. */ @@ -3651,7 +4069,7 @@ display_debug_lines_decoded (struct dwarf_section *section, } static int -display_debug_lines (struct dwarf_section *section, void *file ATTRIBUTE_UNUSED) +display_debug_lines (struct dwarf_section *section, void *file) { unsigned char *data = section->start; unsigned char *end = data + section->size; @@ -3661,6 +4079,8 @@ display_debug_lines (struct dwarf_section *section, void *file ATTRIBUTE_UNUSED) 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); @@ -7550,6 +7970,8 @@ struct dwarf_section_display debug_displays[] = display_debug_macro, &do_debug_macinfo, 1 }, { { ".debug_str", ".zdebug_str", NULL, NULL, 0, 0, 0, NULL }, display_debug_str, &do_debug_str, 0 }, + { { ".debug_line_str", ".zdebug_line_str", NULL, NULL, 0, 0, 0, NULL }, + display_debug_str, &do_debug_str, 0 }, { { ".debug_loc", ".zdebug_loc", NULL, NULL, 0, 0, 0, NULL }, display_debug_loc, &do_debug_loc, 1 }, { { ".debug_pubtypes", ".zdebug_pubtypes", NULL, NULL, 0, 0, 0, NULL }, diff --git a/binutils/dwarf.h b/binutils/dwarf.h index 45f9927..ce626de 100644 --- a/binutils/dwarf.h +++ b/binutils/dwarf.h @@ -27,6 +27,8 @@ typedef struct { dwarf_vma li_length; unsigned short li_version; + unsigned char li_address_size; + unsigned char li_segment_size; dwarf_vma li_prologue_length; unsigned char li_min_insn_length; unsigned char li_max_ops_per_insn; @@ -83,6 +85,7 @@ enum dwarf_section_display_enum macinfo, macro, str, + line_str, loc, pubtypes, gnu_pubtypes, diff --git a/binutils/readelf.c b/binutils/readelf.c index 17d4fd4..4044d29 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -5557,6 +5557,7 @@ process_section_headers (FILE * file) || (do_debug_macinfo && const_strneq (name, "macinfo")) || (do_debug_macinfo && const_strneq (name, "macro")) || (do_debug_str && const_strneq (name, "str")) + || (do_debug_str && const_strneq (name, "line_str")) || (do_debug_loc && const_strneq (name, "loc")) || (do_debug_addr && const_strneq (name, "addr")) || (do_debug_cu_index && const_strneq (name, "cu_index")) |