bfd/
[binutils-gdb.git] / bfd / dwarf2.c
index adc8314fd08979c83168f1099b0b9aa0d713e626..ffe110857efb87a8558df6395ea0af4e3ac1f5b8 100644 (file)
@@ -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;
@@ -404,6 +405,54 @@ lookup_info_hash_table (struct info_hash_table *hash_table, const char *key)
   return entry ? entry->head : NULL;
 }
 
+/* Read a section, uncompress it if necessary, and relocate it.  */
+
+static bfd_boolean
+read_and_uncompress_section (bfd *           abfd,
+                            asection *      msec,
+                            bfd_boolean     section_is_compressed,
+                            asymbol **      syms,
+                            bfd_byte **     section_buffer,
+                            bfd_size_type * section_size)
+{
+  /* Get the unrelocated contents of the section.  */
+  *section_buffer = (bfd_byte *) bfd_malloc (*section_size);
+  if (! *section_buffer)
+    return FALSE;
+  if (! bfd_get_section_contents (abfd, msec, *section_buffer,
+                                 0, *section_size))
+    return FALSE;
+
+  if (section_is_compressed)
+    {
+      if (! bfd_uncompress_section_contents (section_buffer, section_size))
+       {
+         (*_bfd_error_handler) (_("Dwarf Error: unable to decompress %s section."),
+                                bfd_get_section_name (abfd, msec));
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
+       }
+    }
+
+  if (syms)
+    {
+      /* We want to relocate the data we've already read (and
+        decompressed), so we store a pointer to the data in
+        the bfd_section, and tell it that the contents are
+        already in memory.  */
+      BFD_ASSERT (msec->contents == NULL && (msec->flags & SEC_IN_MEMORY) == 0);
+      msec->contents = *section_buffer;
+      msec->flags |= SEC_IN_MEMORY;
+      msec->size = *section_size;
+      *section_buffer
+         = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms);
+      if (! *section_buffer)
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
 /* Read a section into its appropriate place in the dwarf2_debug
    struct (indicated by SECTION_BUFFER and SECTION_SIZE).  If SYMS is
    not NULL, use bfd_simple_get_relocated_section_contents to read the
@@ -439,32 +488,10 @@ read_section (bfd *           abfd,
        }
 
       *section_size = msec->rawsize ? msec->rawsize : msec->size;
-      if (syms)
-       {
-         *section_buffer
-             = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms);
-         if (! *section_buffer)
-           return FALSE;
-       }
-      else
-       {
-         *section_buffer = (bfd_byte *) bfd_malloc (*section_size);
-         if (! *section_buffer)
-           return FALSE;
-         if (! bfd_get_section_contents (abfd, msec, *section_buffer,
-                                         0, *section_size))
-           return FALSE;
-       }
 
-      if (section_is_compressed)
-       {
-         if (! bfd_uncompress_section_contents (section_buffer, section_size))
-           {
-             (*_bfd_error_handler) (_("Dwarf Error: unable to decompress %s section."), compressed_section_name);
-             bfd_set_error (bfd_error_bad_value);
-             return FALSE;
-           }
-       }
+      if (! read_and_uncompress_section (abfd, msec, section_is_compressed,
+                                        syms, section_buffer, section_size))
+       return FALSE;
     }
 
   /* It is possible to get a bad value for the offset into the section
@@ -928,7 +955,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 +1030,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 +1044,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 +1059,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 +1091,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 +1287,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 +1422,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 +1437,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 +1531,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 +1555,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 +1588,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 +1600,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 +1643,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 +1652,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 +1693,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:
@@ -1885,13 +1976,15 @@ find_abstract_instance_name (struct comp_unit *unit,
              switch (attr.name)
                {
                case DW_AT_name:
-                 /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name.  */
+                 /* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name
+                    over DW_AT_name.  */
                  if (name == NULL)
                    name = attr.u.str;
                  break;
                case DW_AT_specification:
                  name = find_abstract_instance_name (unit, &attr);
                  break;
+               case DW_AT_linkage_name:
                case DW_AT_MIPS_linkage_name:
                  name = attr.u.str;
                  break;
@@ -2061,11 +2154,13 @@ scan_unit_for_symbols (struct comp_unit *unit)
                  break;
 
                case DW_AT_name:
-                 /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name.  */
+                 /* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name
+                    over DW_AT_name.  */
                  if (func->name == NULL)
                    func->name = attr.u.str;
                  break;
 
+               case DW_AT_linkage_name:
                case DW_AT_MIPS_linkage_name:
                  func->name = attr.u.str;
                  break;
@@ -3173,23 +3268,17 @@ find_line (bfd *abfd,
                {
                  bfd_size_type size = msec->size;
                  bfd_byte *buffer, *tmp;
+                 bfd_boolean is_compressed =
+                     strcmp (msec->name, DWARF2_COMPRESSED_DEBUG_INFO) == 0;
 
                  if (size == 0)
                    continue;
 
-                 buffer = (bfd_simple_get_relocated_section_contents
-                           (debug_bfd, msec, NULL, symbols));
-                 if (! buffer)
+                 if (! read_and_uncompress_section (debug_bfd, msec,
+                                                    is_compressed, symbols,
+                                                    &buffer, &size))
                    goto done;
 
-                 if (strcmp (msec->name, DWARF2_COMPRESSED_DEBUG_INFO) == 0)
-                   {
-                     if (! bfd_uncompress_section_contents (&buffer, &size))
-                       {
-                         free (buffer);
-                         goto done;
-                       }
-                   }
                  tmp = (bfd_byte *) bfd_realloc (stash->info_ptr_memory,
                                                  total_size + size);
                  if (tmp == NULL)