From a233b20c0e8f6e841c67b54b788f2649942eb7ed Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 5 Apr 2010 19:30:00 +0000 Subject: [PATCH] include/ * dwarf2.h (DWARF2_Internal_LineInfo): Add li_max_ops_per_insn field. bfd/ * dwarf2.c (struct line_head): Add maximum_ops_per_insn field. (struct line_info): Add op_index field, change end_sequence type to unsigned char. (new_line_sorts_after): For the same address compare op_index. (add_line_info): Add op_index argument, store it into the structure. (decode_line_info): Complain about unknown versions of .debug_line. Initialize maximum_ops_per_insn. Add op_index state register and track it. binutils/ * dwarf.c (struct State_Machine_Registers): Add op_index field, change end_sequence type to unsigned char. (reset_state_machine): Clear op_index. (process_extended_line_op): For DW_LNE_set_address clear op_index. (display_debug_lines_raw): Initialize li_max_ops_per_insn. Track op_index state machine register and print it if li_max_ops_per_insn is != 1. (display_debug_lines_decoded): Likewise. --- bfd/ChangeLog | 11 +++ bfd/dwarf2.c | 89 +++++++++++++++++++--- binutils/ChangeLog | 11 +++ binutils/dwarf.c | 185 +++++++++++++++++++++++++++++++++++++++------ include/ChangeLog | 5 ++ include/dwarf2.h | 1 + 6 files changed, 265 insertions(+), 37 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index aa3214496d1..33139c3e6f7 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,14 @@ +2010-04-05 Jakub Jelinek + + * dwarf2.c (struct line_head): Add maximum_ops_per_insn field. + (struct line_info): Add op_index field, change end_sequence type to + unsigned char. + (new_line_sorts_after): For the same address compare op_index. + (add_line_info): Add op_index argument, store it into the structure. + (decode_line_info): Complain about unknown versions of .debug_line. + Initialize maximum_ops_per_insn. Add op_index state register and + track it. + 2010-04-01 Nathan Sidwell * elf32-ppc.c (apuinfo_set): New static var. diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c index adc8314fd08..11618c08125 100644 --- a/bfd/dwarf2.c +++ b/bfd/dwarf2.c @@ -45,6 +45,7 @@ struct line_head unsigned short version; bfd_vma prologue_length; unsigned char minimum_instruction_length; + unsigned char maximum_ops_per_insn; unsigned char default_is_stmt; int line_base; unsigned char line_range; @@ -928,7 +929,8 @@ struct line_info char *filename; unsigned int line; unsigned int column; - int end_sequence; /* End of (sequential) code sequence. */ + unsigned char op_index; + unsigned char end_sequence; /* End of (sequential) code sequence. */ }; struct fileinfo @@ -1002,7 +1004,9 @@ new_line_sorts_after (struct line_info *new_line, struct line_info *line) { return (new_line->address > line->address || (new_line->address == line->address - && new_line->end_sequence < line->end_sequence)); + && (new_line->op_index > line->op_index + || (new_line->op_index == line->op_index + && new_line->end_sequence < line->end_sequence)))); } @@ -1014,6 +1018,7 @@ new_line_sorts_after (struct line_info *new_line, struct line_info *line) static bfd_boolean add_line_info (struct line_info_table *table, bfd_vma address, + unsigned char op_index, char *filename, unsigned int line, unsigned int column, @@ -1028,6 +1033,7 @@ add_line_info (struct line_info_table *table, /* Set member data of 'info'. */ info->address = address; + info->op_index = op_index; info->line = line; info->column = column; info->end_sequence = end_sequence; @@ -1059,6 +1065,7 @@ add_line_info (struct line_info_table *table, if (seq && seq->last_line->address == address + && seq->last_line->op_index == op_index && seq->last_line->end_sequence == end_sequence) { /* We only keep the last entry with the same address and end @@ -1254,6 +1261,11 @@ compare_sequences (const void* a, const void* b) if (seq1->last_line->address > seq2->last_line->address) return -1; + if (seq1->last_line->op_index < seq2->last_line->op_index) + return 1; + if (seq1->last_line->op_index > seq2->last_line->op_index) + return -1; + return 0; } @@ -1384,6 +1396,13 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) } line_end = line_ptr + lh.total_length; lh.version = read_2_bytes (abfd, line_ptr); + if (lh.version < 2 || lh.version > 4) + { + (*_bfd_error_handler) + (_("Dwarf Error: Unhandled .debug_line version %d."), lh.version); + bfd_set_error (bfd_error_bad_value); + return NULL; + } line_ptr += 2; if (offset_size == 4) lh.prologue_length = read_4_bytes (abfd, line_ptr); @@ -1392,6 +1411,20 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) line_ptr += offset_size; lh.minimum_instruction_length = read_1_byte (abfd, line_ptr); line_ptr += 1; + if (lh.version >= 4) + { + lh.maximum_ops_per_insn = read_1_byte (abfd, line_ptr); + line_ptr += 1; + } + else + lh.maximum_ops_per_insn = 1; + if (lh.maximum_ops_per_insn == 0) + { + (*_bfd_error_handler) + (_("Dwarf Error: Invalid maximum operations per instruction.")); + bfd_set_error (bfd_error_bad_value); + return NULL; + } lh.default_is_stmt = read_1_byte (abfd, line_ptr); line_ptr += 1; lh.line_base = read_1_signed_byte (abfd, line_ptr); @@ -1472,6 +1505,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) { /* State machine registers. */ bfd_vma address = 0; + unsigned char op_index = 0; char * filename = table->num_files ? concat_filename (table, 1) : NULL; unsigned int line = 1; unsigned int column = 0; @@ -1495,11 +1529,21 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) { /* Special operand. */ adj_opcode = op_code - lh.opcode_base; - address += (adj_opcode / lh.line_range) - * lh.minimum_instruction_length; + if (lh.maximum_ops_per_insn == 1) + address += (adj_opcode / lh.line_range) + * lh.minimum_instruction_length; + else + { + address += ((op_index + (adj_opcode / lh.line_range)) + / lh.maximum_ops_per_insn) + * lh.minimum_instruction_length; + op_index = (op_index + (adj_opcode / lh.line_range)) + % lh.maximum_ops_per_insn; + } line += lh.line_base + (adj_opcode % lh.line_range); /* Append row to matrix using current values. */ - if (!add_line_info (table, address, filename, line, column, 0)) + if (!add_line_info (table, address, op_index, filename, + line, column, 0)) goto line_fail; if (address < low_pc) low_pc = address; @@ -1518,8 +1562,8 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) { case DW_LNE_end_sequence: end_sequence = 1; - if (!add_line_info (table, address, filename, line, column, - end_sequence)) + if (!add_line_info (table, address, op_index, filename, + line, column, end_sequence)) goto line_fail; if (address < low_pc) low_pc = address; @@ -1530,6 +1574,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) break; case DW_LNE_set_address: address = read_address (unit, line_ptr); + op_index = 0; line_ptr += unit->addr_size; break; case DW_LNE_define_file: @@ -1572,7 +1617,8 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) } break; case DW_LNS_copy: - if (!add_line_info (table, address, filename, line, column, 0)) + if (!add_line_info (table, address, op_index, + filename, line, column, 0)) goto line_fail; if (address < low_pc) low_pc = address; @@ -1580,8 +1626,18 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) high_pc = address; break; case DW_LNS_advance_pc: - address += lh.minimum_instruction_length - * read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + if (lh.maximum_ops_per_insn == 1) + address += lh.minimum_instruction_length + * read_unsigned_leb128 (abfd, line_ptr, + &bytes_read); + else + { + bfd_vma adjust = read_unsigned_leb128 (abfd, line_ptr, + &bytes_read); + address = ((op_index + adjust) / lh.maximum_ops_per_insn) + * lh.minimum_instruction_length; + op_index = (op_index + adjust) % lh.maximum_ops_per_insn; + } line_ptr += bytes_read; break; case DW_LNS_advance_line: @@ -1611,11 +1667,20 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash) case DW_LNS_set_basic_block: break; case DW_LNS_const_add_pc: - address += lh.minimum_instruction_length - * ((255 - lh.opcode_base) / lh.line_range); + if (lh.maximum_ops_per_insn == 1) + address += lh.minimum_instruction_length + * ((255 - lh.opcode_base) / lh.line_range); + else + { + bfd_vma adjust = ((255 - lh.opcode_base) / lh.line_range); + address += lh.minimum_instruction_length + * ((op_index + adjust) / lh.maximum_ops_per_insn); + op_index = (op_index + adjust) % lh.maximum_ops_per_insn; + } break; case DW_LNS_fixed_advance_pc: address += read_2_bytes (abfd, line_ptr); + op_index = 0; line_ptr += 2; break; default: diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 279fd5ef683..385586b3b89 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,14 @@ +2010-04-05 Jakub Jelinek + + * dwarf.c (struct State_Machine_Registers): Add op_index field, + change end_sequence type to unsigned char. + (reset_state_machine): Clear op_index. + (process_extended_line_op): For DW_LNE_set_address clear op_index. + (display_debug_lines_raw): Initialize li_max_ops_per_insn. + Track op_index state machine register and print it if + li_max_ops_per_insn is != 1. + (display_debug_lines_decoded): Likewise. + 2010-04-01 Jakub Jelinek * dwarf.c (read_and_display_attr_value): Don't reject diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 498ff28c7b6..6e49cac472b 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -264,7 +264,8 @@ typedef struct State_Machine_Registers unsigned int column; int is_stmt; int basic_block; - int end_sequence; + unsigned char op_index; + unsigned char end_sequence; /* This variable hold the number of the last entry seen in the File Table. */ unsigned int last_file_entry; @@ -276,6 +277,7 @@ static void reset_state_machine (int is_stmt) { state_machine_regs.address = 0; + state_machine_regs.op_index = 0; state_machine_regs.file = 1; state_machine_regs.line = 1; state_machine_regs.column = 0; @@ -322,6 +324,7 @@ process_extended_line_op (unsigned char *data, int is_stmt) adr = byte_get (data, len - bytes_read - 1); printf (_("set Address to 0x%lx\n"), adr); state_machine_regs.address = adr; + state_machine_regs.op_index = 0; break; case DW_LNE_define_file: @@ -2297,6 +2300,18 @@ display_debug_lines_raw (struct dwarf_section *section, hdrptr += offset_size; linfo.li_min_insn_length = byte_get (hdrptr, 1); hdrptr++; + if (linfo.li_version >= 4) + { + linfo.li_max_ops_per_insn = byte_get (hdrptr, 1); + hdrptr++; + if (linfo.li_max_ops_per_insn == 0) + { + warn (_("Invalid maximum operations per insn.\n")); + return 0; + } + } + else + linfo.li_max_ops_per_insn = 1; linfo.li_default_is_stmt = byte_get (hdrptr, 1); hdrptr++; linfo.li_line_base = byte_get (hdrptr, 1); @@ -2315,6 +2330,8 @@ display_debug_lines_raw (struct dwarf_section *section, printf (_(" DWARF Version: %d\n"), linfo.li_version); printf (_(" Prologue Length: %d\n"), linfo.li_prologue_length); 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); printf (_(" Initial value of 'is_stmt': %d\n"), linfo.li_default_is_stmt); printf (_(" Line Base: %d\n"), linfo.li_line_base); printf (_(" Line Range: %d\n"), linfo.li_line_range); @@ -2398,10 +2415,27 @@ display_debug_lines_raw (struct dwarf_section *section, if (op_code >= linfo.li_opcode_base) { op_code -= linfo.li_opcode_base; - uladv = (op_code / linfo.li_line_range) * linfo.li_min_insn_length; - state_machine_regs.address += uladv; - printf (_(" Special opcode %d: advance Address by %lu to 0x%lx"), - op_code, uladv, state_machine_regs.address); + 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 %lu to 0x%lx"), + op_code, uladv, 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 %lu to 0x%lx[%d]"), + op_code, uladv, 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 %d to %d\n"), @@ -2419,11 +2453,27 @@ display_debug_lines_raw (struct dwarf_section *section, case DW_LNS_advance_pc: uladv = read_leb128 (data, & bytes_read, 0); - uladv *= linfo.li_min_insn_length; data += bytes_read; - state_machine_regs.address += uladv; - printf (_(" Advance PC by %lu to 0x%lx\n"), uladv, - state_machine_regs.address); + if (linfo.li_max_ops_per_insn == 1) + { + uladv *= linfo.li_min_insn_length; + state_machine_regs.address += uladv; + printf (_(" Advance PC by %lu to 0x%lx\n"), uladv, + 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 %lu to 0x%lx[%d]\n"), uladv, + state_machine_regs.address, + state_machine_regs.op_index); + } break; case DW_LNS_advance_line: @@ -2462,17 +2512,34 @@ display_debug_lines_raw (struct dwarf_section *section, break; case DW_LNS_const_add_pc: - uladv = (((255 - linfo.li_opcode_base) / linfo.li_line_range) - * linfo.li_min_insn_length); - state_machine_regs.address += uladv; - printf (_(" Advance PC by constant %lu to 0x%lx\n"), uladv, - state_machine_regs.address); + 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 %lu to 0x%lx\n"), uladv, + 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 %lu to 0x%lx[%d]\n"), + uladv, state_machine_regs.address, + state_machine_regs.op_index); + } break; case DW_LNS_fixed_advance_pc: uladv = byte_get (data, 2); data += 2; state_machine_regs.address += uladv; + state_machine_regs.op_index = 0; printf (_(" Advance PC by fixed size amount %lu to 0x%lx\n"), uladv, state_machine_regs.address); break; @@ -2588,6 +2655,18 @@ display_debug_lines_decoded (struct dwarf_section *section, hdrptr += offset_size; linfo.li_min_insn_length = byte_get (hdrptr, 1); hdrptr++; + if (linfo.li_version >= 4) + { + linfo.li_max_ops_per_insn = byte_get (hdrptr, 1); + hdrptr++; + if (linfo.li_max_ops_per_insn == 0) + { + warn (_("Invalid maximum operations per insn.\n")); + return 0; + } + } + else + linfo.li_max_ops_per_insn = 1; linfo.li_default_is_stmt = byte_get (hdrptr, 1); hdrptr++; linfo.li_line_base = byte_get (hdrptr, 1); @@ -2723,8 +2802,22 @@ display_debug_lines_decoded (struct dwarf_section *section, if (op_code >= linfo.li_opcode_base) { op_code -= linfo.li_opcode_base; - uladv = (op_code / linfo.li_line_range) * linfo.li_min_insn_length; - state_machine_regs.address += uladv; + 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; + } + 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; + } adv = (op_code % linfo.li_line_range) + linfo.li_line_base; state_machine_regs.line += adv; @@ -2757,6 +2850,7 @@ display_debug_lines_decoded (struct dwarf_section *section, case DW_LNE_set_address: state_machine_regs.address = byte_get (op_code_data, ext_op_code_len - bytes_read - 1); + state_machine_regs.op_index = 0; break; case DW_LNE_define_file: { @@ -2785,9 +2879,22 @@ display_debug_lines_decoded (struct dwarf_section *section, case DW_LNS_advance_pc: uladv = read_leb128 (data, & bytes_read, 0); - uladv *= linfo.li_min_insn_length; data += bytes_read; - state_machine_regs.address += uladv; + if (linfo.li_max_ops_per_insn == 1) + { + uladv *= linfo.li_min_insn_length; + state_machine_regs.address += uladv; + } + 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; + } break; case DW_LNS_advance_line: @@ -2832,15 +2939,29 @@ display_debug_lines_decoded (struct dwarf_section *section, break; case DW_LNS_const_add_pc: - uladv = (((255 - linfo.li_opcode_base) / linfo.li_line_range) - * linfo.li_min_insn_length); - state_machine_regs.address += uladv; + uladv = ((255 - linfo.li_opcode_base) / linfo.li_line_range); + if (linfo.li_max_ops_per_insn == 1) + { + uladv *= linfo.li_min_insn_length; + state_machine_regs.address += uladv; + } + 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; + } break; case DW_LNS_fixed_advance_pc: uladv = byte_get (data, 2); data += 2; state_machine_regs.address += uladv; + state_machine_regs.op_index = 0; break; case DW_LNS_set_prologue_end: @@ -2894,13 +3015,27 @@ display_debug_lines_decoded (struct dwarf_section *section, if (!do_wide || (fileNameLength <= MAX_FILENAME_LENGTH)) { - printf (_("%-35s %11d %#18lx\n"), newFileName, - state_machine_regs.line, state_machine_regs.address); + if (linfo.li_max_ops_per_insn == 1) + printf (_("%-35s %11d %#18lx\n"), newFileName, + state_machine_regs.line, + state_machine_regs.address); + else + printf (_("%-35s %11d %#18lx[%d]\n"), newFileName, + state_machine_regs.line, + state_machine_regs.address, + state_machine_regs.op_index); } else { - printf (_("%s %11d %#18lx\n"), newFileName, - state_machine_regs.line, state_machine_regs.address); + if (linfo.li_max_ops_per_insn == 1) + printf (_("%s %11d %#18lx\n"), newFileName, + state_machine_regs.line, + state_machine_regs.address); + else + printf (_("%s %11d %#18lx[%d]\n"), newFileName, + state_machine_regs.line, + state_machine_regs.address, + state_machine_regs.op_index); } if (op_code == DW_LNE_end_sequence) diff --git a/include/ChangeLog b/include/ChangeLog index 584512d3595..e8f37176b21 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,8 @@ +2010-04-05 Jakub Jelinek + + * dwarf2.h (DWARF2_Internal_LineInfo): Add li_max_ops_per_insn + field. + 2010-03-25 Joseph Myers * dis-asm.h (print_insn_tic6x): Declare. diff --git a/include/dwarf2.h b/include/dwarf2.h index 303af70be1c..df766c1e92b 100644 --- a/include/dwarf2.h +++ b/include/dwarf2.h @@ -66,6 +66,7 @@ typedef struct unsigned short li_version; unsigned int li_prologue_length; unsigned char li_min_insn_length; + unsigned char li_max_ops_per_insn; unsigned char li_default_is_stmt; int li_line_base; unsigned char li_line_range; -- 2.30.2