This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix .debug_line version 4 handling


Hi!

As pointed out by Cary, version 4 unfortunately adds a field
into the middle of .debug_line header.
This patch handles that and attempts to also support
the new op_index state machine register if the new field is
not 1 (well, on the ld side it will just record it in the table, but the
querying routines still will not use it, on the readelf side
it will dump it).  GCC won't generate max_ops_per_insn != 1
for the time being though, gas probably should eventually for ia64
and other VLIW arches.

Tested on x86_64-linux, ok to commit?

2010-04-01  Jakub Jelinek  <jakub@redhat.com>

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.

--- include/dwarf2.h.jj	2010-01-13 12:09:31.000000000 +0100
+++ include/dwarf2.h	2010-04-01 13:58:13.000000000 +0200
@@ -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;
--- bfd/dwarf2.c.jj	2010-03-31 19:01:18.000000000 +0200
+++ bfd/dwarf2.c	2010-04-01 14:27:57.000000000 +0200
@@ -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 *
 {
   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 *
 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 *t
 
   /* 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 *t
 
   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 
   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
     }
   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
   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
     {
       /* 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
 	    {
 	      /* 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
 		{
 		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
 		  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
 		}
 	      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
 		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
 	    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:
--- binutils/dwarf.c.jj	2010-03-31 16:01:43.000000000 +0200
+++ binutils/dwarf.c	2010-04-01 14:26:40.000000000 +0200
@@ -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 
       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_se
       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_se
       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_se
 	  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_se
 
 	    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_se
 	      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 dwar
       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 dwar
           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 dwar
                   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 dwar
 
             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 dwar
               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 dwar
 
               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)


	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]