From af9adba57ae3e14f945c89d0a27791b620592ce3 Mon Sep 17 00:00:00 2001 From: Cary Coutant Date: Tue, 6 Jan 2015 16:56:43 -0800 Subject: [PATCH] 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 binutils/ * 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. (fetch_indirect_line_string): New function. (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. (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 (DWARF2_Internal_LineInfo): Add li_actuals_table_offset field. (dwarf_section_display_enum): Add line_str. * readelf.c (process_section_headers): Add .debug_line_str. --- binutils/dwarf.c | 873 ++++++++++++++++++++++++++++++++------------- binutils/dwarf.h | 2 + binutils/readelf.c | 1 + 3 files changed, 622 insertions(+), 254 deletions(-) diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 3d3f4ccdc8f..a86492961bc 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -381,6 +381,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; @@ -400,19 +403,54 @@ 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; +} + +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; +} + /* 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; @@ -439,6 +477,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; @@ -597,6 +637,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 *) _(""); + + if (offset > section->size) + { + warn (_("DW_FORM_line_strp offset too big: %s\n"), + dwarf_vmatoa ("x", offset)); + return (const unsigned char *) _(""); + } + + 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) @@ -2670,6 +2728,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. @@ -2680,7 +2742,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; @@ -2705,6 +2769,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) { @@ -2727,15 +2793,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 != 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; } SAFE_BYTE_GET_AND_INC (linfo->li_prologue_length, hdrptr, offset_size, end); + + if (linfo->li_version != DWARF2_LINE_EXPERIMENTAL_VERSION) + linfo->li_actuals_table_offset = 0; + else + SAFE_BYTE_GET_AND_INC (linfo->li_actuals_table_offset, hdrptr, + offset_size, end); + SAFE_BYTE_GET_AND_INC (linfo->li_min_insn_length, hdrptr, 1, end); if (linfo->li_version >= 4) @@ -2769,12 +2845,468 @@ 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%d", 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 (); + } + 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 (); + 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_context: + /* This opcode is aliased with: */ + /* case DW_LNS_set_address_from_logical: */ + if (is_logical) + { + /* DW_LNS_set_context */ + state_machine_regs.context = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + state_machine_regs.subprogram = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + printf (_(" Set context to %d\n"), state_machine_regs.context); + } + else + { + /* DW_LNS_set_address_from_logical */ + adv = read_uleb128 (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 %d and set address from logical to 0x%s[%d]\n"), + dwarf_vmatoa ("d", adv), + logical, + dwarf_vmatoa ("x", state_machine_regs.address), + state_machine_regs.op_index); + } + break; + + case DW_LNS_set_subprogram: + state_machine_regs.subprogram = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + printf (_(" Set subprogram to %d\n"), state_machine_regs.subprogram); + break; + + case DW_LNS_pop_context: + uladv = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + logical = state_machine_regs.context; + printf (_(" Pop context to logical %d\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); @@ -2783,10 +3315,13 @@ display_debug_lines_raw (struct dwarf_section *section, { static DWARF2_Internal_LineInfo saved_linfo; DWARF2_Internal_LineInfo linfo; + 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. @@ -2809,23 +3344,25 @@ display_debug_lines_raw (struct dwarf_section *section, /* PR 17531: file: 0522b371. */ if (linfo.li_line_range == 0) { - warn (_("Partial .debug_line. section encountered without a prior full .debug_line section")); + warn (_("Partial .debug_line. section encountered without a prior full .debug_line section\n")); return 0; } reset_state_machine (linfo.li_default_is_stmt); } 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); printf (_(" Prologue Length: %d\n"), linfo.li_prologue_length); + if (linfo.li_version == DWARF2_LINE_EXPERIMENTAL_VERSION) + printf (_(" Actuals Table Offset: 0x%x\n"), linfo.li_actuals_table_offset); printf (_(" Minimum Instruction Length: %d\n"), linfo.li_min_insn_length); if (linfo.li_version >= 4) printf (_(" Maximum Ops per Instruction: %d\n"), linfo.li_max_ops_per_insn); @@ -2834,6 +3371,14 @@ 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; + start_of_line_program = end_of_header_length + linfo.li_prologue_length; + if (linfo.li_version == DWARF2_LINE_EXPERIMENTAL_VERSION + && linfo.li_actuals_table_offset > 0) + end_of_logicals = end_of_header_length + linfo.li_actuals_table_offset; + else + end_of_logicals = end; + /* PR 17512: file: 1665-6428-0.004. */ if (linfo.li_line_range == 0) { @@ -2858,265 +3403,77 @@ 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")); + /* Display the contents of the Directory table. */ + if (linfo.li_version >= 5) + display_dir_file_table_v5 (start, end, &data, _("Directory"), + offset_size); 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; - } - - /* PR 17512: file: 002-132094-0.004. */ - if (data >= end - 1) - break; - } + display_directory_table_v4 (start, end, &data); - /* Skip the NUL at the end of the table. */ - data++; + /* PR 17512: file: 002-132094-0.004. */ + if (data >= end - 1) + break; /* Display the contents of the File Name table. */ - if (*data == 0) - printf (_("\n The File Name Table is empty.\n")); - else + if (linfo.li_version >= 5) { - 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; + unsigned int count; - 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; - } - } + 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")); + 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 + && linfo.li_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", linfo.li_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; @@ -3138,6 +3495,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); @@ -3166,7 +3525,7 @@ display_debug_lines_decoded (struct dwarf_section *section, /* PR 17531: file: 0522b371. */ if (linfo.li_line_range == 0) { - warn (_("Partial .debug_line. section encountered without a prior full .debug_line section")); + warn (_("Partial .debug_line. section encountered without a prior full .debug_line section\n")); return 0; } reset_state_machine (linfo.li_default_is_stmt); @@ -3176,7 +3535,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. */ @@ -3600,7 +3961,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; @@ -3610,6 +3971,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); @@ -7353,6 +7716,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 d43f0968de3..9c7c59c384e 100644 --- a/binutils/dwarf.h +++ b/binutils/dwarf.h @@ -41,6 +41,7 @@ typedef struct dwarf_vma li_length; unsigned short li_version; unsigned int li_prologue_length; + unsigned int li_actuals_table_offset; unsigned char li_min_insn_length; unsigned char li_max_ops_per_insn; unsigned char li_default_is_stmt; @@ -123,6 +124,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 6c47d9a65ca..5d0fe68cdda 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -5503,6 +5503,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")) -- 2.47.2