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 COMMITTED: Add --strip-debug-non-line


I've committed this patch go gold on behalf of Caleb Howe.  It adds a
new option: --strip-debug-non-line.  It strips debugging information
other than what is needed to map program counter values to line
numbers.  The result is an executable which can produce backtraces and
work with addr2line.

Ian


elfcpp/ChangeLog:
2008-05-28  Caleb Howe  <cshowe@google.com>

	* dwarf.h (enum DW_FORM): Define.

gold/ChangeLog:
2008-05-28  Caleb Howe  <cshowe@google.com>

	* reduced_debug_output.cc: New file.
	* reduced_debug_output.h: New file.
	* options.h (class General_optoins): Add --strip-debug-non-line.
	* options.cc (General_options::finalize): Add strip_debug_non_line
	to the strip heirarchy.
	* layout.h (class Layout): Add debug_abbrev_ and debug_info_
	fields.
	* layout.cc: Include "reduced_debug_output.h".
	(Layout::Layout): Initialize new fields.
	(line_only_debug_sections): New static array.
	(is_lines_only_debug_sections): New static inline function.
	(Layout::include_section): Handle --strip-debug-non-line.
	(Layout::make_output_section): If --strip-debug-non-line, build
	new output sections for .debug_abbrev and .debug_info.
	* dwarf_reader.cc (read_unsigned_LEB_128): Move to namespace
	gold.  Warn about possible overflow.
	(read_signed_LEB_128): Likewise.
	* dwarf_reader.h: (read_unsigned_LEB_128): Declare.
	(read_signed_LEB_128): Declare.
	* Makefile.am (CCFILES): Add reduced_debug_output.cc.
	(HFILES): Add reduced_debug_output.h.
	* Makefile.in: Rebuild.


Index: elfcpp/dwarf.h
===================================================================
RCS file: /cvs/src/src/elfcpp/dwarf.h,v
retrieving revision 1.3
diff -u -p -r1.3 dwarf.h
--- elfcpp/dwarf.h	2 Nov 2007 23:02:43 -0000	1.3
+++ elfcpp/dwarf.h	28 May 2008 20:40:04 -0000
@@ -4,7 +4,7 @@
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of elfcpp.
-   
+
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Library General Public License
 // as published by the Free Software Foundation; either version 2, or
@@ -124,6 +124,32 @@ enum DW_TAG
   DW_TAG_PGI_interface_block = 0xA020
 };
 
+enum DW_FORM
+{
+  DW_FORM_null = 0x00,
+  DW_FORM_addr = 0x01,
+  DW_FORM_block2 = 0x03,
+  DW_FORM_block4 = 0x04,
+  DW_FORM_data2 = 0x05,
+  DW_FORM_data4 = 0x06,
+  DW_FORM_data8 = 0x07,
+  DW_FORM_string = 0x08,
+  DW_FORM_block = 0x09,
+  DW_FORM_block1 = 0x0a,
+  DW_FORM_data1 = 0x0b,
+  DW_FORM_flag = 0x0c,
+  DW_FORM_sdata = 0x0d,
+  DW_FORM_strp = 0x0e,
+  DW_FORM_udata = 0x0f,
+  DW_FORM_ref_addr = 0x10,
+  DW_FORM_ref1 = 0x11,
+  DW_FORM_ref2 = 0x12,
+  DW_FORM_ref4 = 0x13,
+  DW_FORM_ref8 = 0x14,
+  DW_FORM_ref_udata = 0x15,
+  DW_FORM_indirect = 0x16
+};
+
 // Frame unwind information.
 
 enum DW_EH_PE
@@ -372,7 +398,7 @@ enum DW_OP
   DW_OP_call_frame_cfa               =0x9c,
   DW_OP_bit_piece                    =0x9d,
   DW_OP_lo_user                      =0xe0,
-  DW_OP_hi_user                      =0xff,  
+  DW_OP_hi_user                      =0xff,
   // GNU extensions
   DW_OP_GNU_push_tls_address         =0xe0
 };
Index: gold/Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/Makefile.am,v
retrieving revision 1.36
diff -u -p -r1.36 Makefile.am
--- gold/Makefile.am	21 May 2008 21:37:44 -0000	1.36
+++ gold/Makefile.am	28 May 2008 20:40:04 -0000
@@ -52,6 +52,7 @@ CCFILES = \
 	output.cc \
 	parameters.cc \
 	readsyms.cc \
+	reduced_debug_output.cc \
 	reloc.cc \
 	resolve.cc \
 	script-sections.cc \
@@ -86,6 +87,7 @@ HFILES = \
 	output.h \
 	parameters.h \
 	readsyms.h \
+	reduced_debug_output.h \
 	reloc.h \
 	reloc-types.h \
 	script-c.h \
Index: gold/dwarf_reader.cc
===================================================================
RCS file: /cvs/src/src/gold/dwarf_reader.cc,v
retrieving revision 1.21
diff -u -p -r1.21 dwarf_reader.cc
--- gold/dwarf_reader.cc	1 May 2008 00:25:33 -0000	1.21
+++ gold/dwarf_reader.cc	28 May 2008 20:40:04 -0000
@@ -32,7 +32,7 @@
 #include "reloc.h"
 #include "dwarf_reader.h"
 
-namespace {
+namespace gold {
 
 // Read an unsigned LEB128 number.  Each byte contains 7 bits of
 // information, plus one bit saying whether the number continues or
@@ -48,6 +48,12 @@ read_unsigned_LEB_128(const unsigned cha
 
   do
     {
+      if (num_read >= 64 / 7) 
+        {
+          gold_warning(_("Unusually large LEB128 decoded, "
+			 "debug information may be corrupted"));
+          break;
+        }
       byte = *buffer++;
       num_read++;
       result |= (static_cast<uint64_t>(byte & 0x7f)) << shift;
@@ -73,6 +79,12 @@ read_signed_LEB_128(const unsigned char*
 
   do
     {
+      if (num_read >= 64 / 7) 
+        {
+          gold_warning(_("Unusually large LEB128 decoded, "
+			 "debug information may be corrupted"));
+          break;
+        }
       byte = *buffer++;
       num_read++;
       result |= (static_cast<uint64_t>(byte & 0x7f) << shift);
@@ -86,11 +98,6 @@ read_signed_LEB_128(const unsigned char*
   return result;
 }
 
-} // End anonymous namespace.
-
-
-namespace gold {
-
 // This is the format of a DWARF2/3 line state machine that we process
 // opcodes using.  There is no need for anything outside the lineinfo
 // processor to know how this works.
Index: gold/dwarf_reader.h
===================================================================
RCS file: /cvs/src/src/gold/dwarf_reader.h,v
retrieving revision 1.14
diff -u -p -r1.14 dwarf_reader.h
--- gold/dwarf_reader.h	1 May 2008 00:25:33 -0000	1.14
+++ gold/dwarf_reader.h	28 May 2008 20:40:04 -0000
@@ -38,6 +38,12 @@ template<int size, bool big_endian>
 class Track_relocs;
 struct LineStateMachine;
 
+uint64_t
+read_unsigned_LEB_128(const unsigned char* buffer, size_t* len);
+
+int64_t
+read_signed_LEB_128(const unsigned char* buffer, size_t* len);
+
 // We can't do better than to keep the offsets in a sorted vector.
 // Here, offset is the key, and file_num/line_num is the value.
 struct Offset_to_lineno_entry
Index: gold/layout.cc
===================================================================
RCS file: /cvs/src/src/gold/layout.cc,v
retrieving revision 1.105
diff -u -p -r1.105 layout.cc
--- gold/layout.cc	21 May 2008 21:37:44 -0000	1.105
+++ gold/layout.cc	28 May 2008 20:40:04 -0000
@@ -43,6 +43,7 @@
 #include "dynobj.h"
 #include "ehframe.h"
 #include "compressed_output.h"
+#include "reduced_debug_output.h"
 #include "reloc.h"
 #include "layout.h"
 
@@ -110,6 +111,8 @@ Layout::Layout(const General_options& op
     added_eh_frame_data_(false),
     eh_frame_hdr_section_(NULL),
     build_id_note_(NULL),
+    debug_abbrev_(NULL),
+    debug_info_(NULL),
     group_signatures_(),
     output_file_size_(-1),
     input_requires_executable_stack_(false),
@@ -160,6 +163,19 @@ static const char* gdb_sections[] =
   ".debug_str",
 };
 
+static const char* lines_only_debug_sections[] =
+{ ".debug_abbrev",
+  // ".debug_aranges",   // not used by gdb as of 6.7.1
+  // ".debug_frame",
+  ".debug_info",
+  ".debug_line",
+  // ".debug_loc",
+  // ".debug_macinfo",
+  // ".debug_pubnames",  // not used by gdb as of 6.7.1
+  // ".debug_ranges",
+  ".debug_str",
+};
+
 static inline bool
 is_gdb_debug_section(const char* str)
 {
@@ -170,6 +186,18 @@ is_gdb_debug_section(const char* str)
   return false;
 }
 
+static inline bool
+is_lines_only_debug_section(const char* str)
+{
+  // We can do this faster: binary search or a hashtable.  But why bother?
+  for (size_t i = 0;
+       i < sizeof(lines_only_debug_sections)/sizeof(*lines_only_debug_sections);
+       ++i)
+    if (strcmp(str, lines_only_debug_sections[i]) == 0)
+      return true;
+  return false;
+}
+
 // Whether to include this section in the link.
 
 template<int size, bool big_endian>
@@ -204,6 +232,14 @@ Layout::include_section(Sized_relobj<siz
 	  if (is_debug_info_section(name))
 	    return false;
 	}
+      if (parameters->options().strip_debug_non_line()
+	  && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
+	{
+	  // Debugging sections can only be recognized by name.
+	  if (is_prefix_of(".debug", name)
+              && !is_lines_only_debug_section(name))
+	    return false;
+	}
       if (parameters->options().strip_debug_gdb()
 	  && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
 	{
@@ -702,7 +738,26 @@ Layout::make_output_section(const char* 
       && strcmp(this->options_.compress_debug_sections(), "none") != 0
       && is_compressible_debug_section(name))
     os = new Output_compressed_section(&this->options_, name, type, flags);
-  else
+
+  else if ((flags & elfcpp::SHF_ALLOC) == 0
+           && this->options_.strip_debug_non_line()
+           && strcmp(".debug_abbrev", name) == 0)
+    {
+      os = this->debug_abbrev_ = new Output_reduced_debug_abbrev_section(
+          name, type, flags);
+      if (this->debug_info_)
+        this->debug_info_->set_abbreviations(this->debug_abbrev_);
+    }
+  else if ((flags & elfcpp::SHF_ALLOC) == 0
+           && this->options_.strip_debug_non_line()
+           && strcmp(".debug_info", name) == 0)
+    {
+      os = this->debug_info_ = new Output_reduced_debug_info_section(
+          name, type, flags);
+      if (this->debug_abbrev_)
+        this->debug_info_->set_abbreviations(this->debug_abbrev_);
+    }
+ else
     os = new Output_section(name, type, flags);
 
   this->section_list_.push_back(os);
Index: gold/layout.h
===================================================================
RCS file: /cvs/src/src/gold/layout.h,v
retrieving revision 1.59
diff -u -p -r1.59 layout.h
--- gold/layout.h	21 May 2008 21:37:44 -0000	1.59
+++ gold/layout.h	28 May 2008 20:40:04 -0000
@@ -49,6 +49,8 @@ class Output_segment;
 class Output_data;
 class Output_data_dynamic;
 class Output_symtab_xindex;
+class Output_reduced_debug_abbrev_section;
+class Output_reduced_debug_info_section;
 class Eh_frame;
 class Target;
 
@@ -667,6 +669,10 @@ class Layout
   Output_section* eh_frame_hdr_section_;
   // The space for the build ID checksum if there is one.
   Output_section_data* build_id_note_;
+  // The output section containing dwarf abbreviations
+  Output_reduced_debug_abbrev_section* debug_abbrev_;
+  // The output section containing the dwarf debug info tree
+  Output_reduced_debug_info_section* debug_info_;
   // A list of group sections and their signatures.
   Group_signatures group_signatures_;
   // The size of the output file.
Index: gold/options.cc
===================================================================
RCS file: /cvs/src/src/gold/options.cc,v
retrieving revision 1.73
diff -u -p -r1.73 options.cc
--- gold/options.cc	21 May 2008 21:37:44 -0000	1.73
+++ gold/options.cc	28 May 2008 20:40:04 -0000
@@ -640,11 +640,13 @@ void
 General_options::finalize()
 {
   // Normalize the strip modifiers.  They have a total order:
-  // strip_all > strip_debug > strip_debug_gdb.  If one is true, set
-  // all beneath it to true as well.
+  // strip_all > strip_debug > strip_non_line > strip_debug_gdb.
+  // If one is true, set all beneath it to true as well.
   if (this->strip_all())
     this->set_strip_debug(true);
   if (this->strip_debug())
+    this->set_strip_debug_non_line(true);
+  if (this->strip_debug_non_line())
     this->set_strip_debug_gdb(true);
 
   // If the user specifies both -s and -r, convert the -s to -S.
Index: gold/options.h
===================================================================
RCS file: /cvs/src/src/gold/options.h,v
retrieving revision 1.79
diff -u -p -r1.79 options.h
--- gold/options.h	21 May 2008 21:37:44 -0000	1.79
+++ gold/options.h	28 May 2008 20:40:04 -0000
@@ -708,6 +708,8 @@ class General_options
               N_("Strip all symbols"), NULL);
   DEFINE_bool(strip_debug, options::TWO_DASHES, 'S', false,
               N_("Strip debugging information"), NULL);
+  DEFINE_bool(strip_debug_non_line, options::TWO_DASHES, '\0', false,
+              N_("Emit only debug line number information"), NULL);
   DEFINE_bool(strip_debug_gdb, options::TWO_DASHES, '\0', false,
               N_("Strip debug symbols that are unused by gdb "
                  "(at least versions <= 6.7)"), NULL);
Index: gold/reduced_debug_output.cc
===================================================================
RCS file: gold/reduced_debug_output.cc
diff -N gold/reduced_debug_output.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/reduced_debug_output.cc	28 May 2008 20:40:04 -0000
@@ -0,0 +1,429 @@
+// reduced_debug_output.cc -- output reduced debugging information to save space
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Caleb Howe <cshowe@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include "gold.h"
+
+#include "parameters.h"
+#include "options.h"
+#include "dwarf.h"
+#include "dwarf_reader.h"
+#include "reduced_debug_output.h"
+
+#include <vector>
+
+namespace gold
+{
+
+void
+write_unsigned_LEB_128(std::vector<unsigned char>* buffer, uint64_t value)
+{
+  do
+    {
+      unsigned char current_byte = value & 0x7f;
+      value >>= 7;
+      if (value != 0)
+        {
+          current_byte |= 0x80;
+        }
+      buffer->push_back(current_byte);
+    }
+  while (value != 0);
+}
+
+size_t
+get_length_as_unsigned_LEB_128(uint64_t value)
+{
+  size_t length = 0;
+  do
+    {
+      unsigned char current_byte = value & 0x7f;
+      value >>= 7;
+      if (value != 0)
+        {
+          current_byte |= 0x80;
+        }
+      length++;
+    }
+  while (value != 0);
+  return length;
+}
+
+template <int valsize>
+void Insert_into_vector(std::vector<unsigned char>* destination,
+                        typename elfcpp::Valtype_base<valsize>::Valtype value)
+{
+  union
+    {
+      unsigned char buffer[valsize / 8];
+      long long align;
+    } u;
+  if (parameters->target().is_big_endian())
+    elfcpp::Swap<valsize, true>::writeval(u.buffer, value);
+  else
+    elfcpp::Swap<valsize, false>::writeval(u.buffer, value);
+  destination->insert(destination->end(), u.buffer, u.buffer + valsize / 8);
+}
+
+template <int valsize>
+typename elfcpp::Valtype_base<valsize>::Valtype
+read_from_pointer(unsigned char** source)
+{
+  typename elfcpp::Valtype_base<valsize>::Valtype return_value;
+  if (parameters->target().is_big_endian())
+    return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source);
+  else
+    return_value = elfcpp::Swap_unaligned<valsize, false>::readval(*source);
+  *source += valsize / 8;
+  return return_value;
+}
+
+// Given a pointer to the beginning of a die and the beginning of the associated
+// abbreviation fills in die_end with the end of the information entry.  If
+// successful returns true.  Get_die_end also takes a pointer to the end of the
+// buffer containing the die.  If die_end would be beyond the end of the
+// buffer, or if an unsupported dwarf form is encountered returns false.
+bool
+Output_reduced_debug_info_section::get_die_end(
+    unsigned char* die, unsigned char* abbrev, unsigned char** die_end,
+    unsigned char* buffer_end, int address_size, bool is64)
+{
+  size_t LEB_size;
+  uint64_t LEB_decoded;
+  for(;;)
+    {
+      uint64_t attribute = read_unsigned_LEB_128(abbrev, &LEB_size);
+      abbrev += LEB_size;
+      elfcpp::DW_FORM form =
+          static_cast<elfcpp::DW_FORM>(read_unsigned_LEB_128(abbrev,
+                                                             &LEB_size));
+      abbrev += LEB_size;
+      if (!(attribute || form))
+        break;
+      if (die >= buffer_end)
+        return false;
+      switch(form)
+        {
+          case elfcpp::DW_FORM_null:
+            break;
+          case elfcpp::DW_FORM_strp:
+            die += is64 ? 8 : 4;
+            break;
+          case elfcpp::DW_FORM_addr:
+          case elfcpp::DW_FORM_ref_addr:
+            die += address_size;
+            break;
+          case elfcpp::DW_FORM_block1:
+            die += *die;
+            die += 1;
+            break;
+          case elfcpp::DW_FORM_block2:
+            {
+              uint16_t block_size;
+              block_size = read_from_pointer<16>(&die);
+              die += block_size;
+              break;
+            }
+          case elfcpp::DW_FORM_block4:
+            {
+              uint32_t block_size;
+              block_size = read_from_pointer<32>(&die);
+              die += block_size;
+              break;
+            }
+          case elfcpp::DW_FORM_block:
+            LEB_decoded = read_unsigned_LEB_128(die, &LEB_size);
+            die += (LEB_decoded + LEB_size);
+            break;
+          case elfcpp::DW_FORM_data1:
+          case elfcpp::DW_FORM_ref1:
+          case elfcpp::DW_FORM_flag:
+            die += 1;
+            break;
+          case elfcpp::DW_FORM_data2:
+          case elfcpp::DW_FORM_ref2:
+            die += 2;
+            break;
+          case elfcpp::DW_FORM_data4:
+          case elfcpp::DW_FORM_ref4:
+            die += 4;
+            break;
+          case elfcpp::DW_FORM_data8:
+          case elfcpp::DW_FORM_ref8:
+            die += 8;
+            break;
+          case elfcpp::DW_FORM_ref_udata:
+          case elfcpp::DW_FORM_udata:
+            read_unsigned_LEB_128(die, &LEB_size);
+            die += LEB_size;
+            break;
+          case elfcpp::DW_FORM_string:
+            {
+              size_t length = strlen(reinterpret_cast<char*>(die));
+              die += length + 1;
+              break;
+            }
+          case elfcpp::DW_FORM_sdata:
+          case elfcpp::DW_FORM_indirect:
+            return false;
+      }
+    }
+  *die_end = die;
+  return true;
+}
+
+void
+Output_reduced_debug_abbrev_section::set_final_data_size()
+{
+  if (this->sized_ || this->failed_)
+    return;
+
+  uint64_t abbrev_number;
+  size_t LEB_size;
+  unsigned char* abbrev_data = this->postprocessing_buffer();
+  unsigned char* abbrev_end = this->postprocessing_buffer() +
+                              this->postprocessing_buffer_size();
+  this->write_to_postprocessing_buffer();
+  while(abbrev_data < abbrev_end)
+    {
+      uint64_t abbrev_offset = abbrev_data - this->postprocessing_buffer();
+      while((abbrev_number = read_unsigned_LEB_128(abbrev_data, &LEB_size)))
+        {
+          if (abbrev_data >= abbrev_end)
+            {
+              failed("Debug abbreviations extend beyond .debug_abbrev "
+                     "section; failed to reduce debug abbreviations");
+              return;
+            }
+          abbrev_data += LEB_size;
+
+          // Together with the abbreviation number these fields make up
+          // the header for each abbreviation
+          uint64_t abbrev_type = read_unsigned_LEB_128(abbrev_data, &LEB_size);
+          abbrev_data += LEB_size;
+
+          // This would ordinarily be the has_children field of the
+          // abbreviation.  But it's going to be false after reducting the
+          // information, so there's no point in storing it
+          abbrev_data++;
+
+          // Read to the end of the current abbreviation
+          // This is indicated by two zero unsigned LEBs in a row.  We don't
+          // need to parse the data yet, so we just scan through the data
+          // looking for two consecutive 0 bytes indicating the end of the
+          // abbreviation
+          unsigned char* current_abbrev;
+          for (current_abbrev = abbrev_data;
+               current_abbrev[0] || current_abbrev[1];
+               current_abbrev++)
+            {
+              if (current_abbrev >= abbrev_end)
+                {
+                  this->failed(_("Debug abbreviations extend beyond "
+				 ".debug_abbrev section; failed to reduce "
+				 "debug abbreviations"));
+                  return;
+                }
+            }
+          // Account for the two nulls and advance to the start of the
+          // next abbreviation.
+          current_abbrev += 2;
+
+          // We're eliminating every entry except for compile units, so we
+          // only need to store abbreviations that describe them
+          if (abbrev_type == elfcpp::DW_TAG_compile_unit)
+            {
+              write_unsigned_LEB_128(&this->data_, ++this->abbrev_count_);
+              write_unsigned_LEB_128(&this->data_, abbrev_type);
+              // has_children is false for all entries
+              this->data_.push_back(0);
+              this->abbrev_mapping_[std::make_pair(abbrev_offset,
+                                                   abbrev_number)] =
+                  std::make_pair(abbrev_count_, this->data_.size());
+              this->data_.insert(this->data_.end(), abbrev_data,
+                                 current_abbrev);
+            }
+          abbrev_data = current_abbrev;
+        }
+      gold_assert(LEB_size == 1);
+      abbrev_data += LEB_size;
+    }
+  // Null terminate the list of abbreviations
+  this->data_.push_back(0);
+  this->set_data_size(data_.size());
+  this->sized_ = true;
+}
+
+void
+Output_reduced_debug_abbrev_section::do_write(Output_file* of)
+{
+  off_t offset = this->offset();
+  off_t data_size = this->data_size();
+  unsigned char* view = of->get_output_view(offset, data_size);
+  if (this->failed_)
+    memcpy(view, this->postprocessing_buffer(),
+           this->postprocessing_buffer_size());
+  else
+    memcpy(view, &this->data_.front(), data_size);
+  of->write_output_view(offset, data_size, view);
+}
+
+// Locates the abbreviation with abbreviation_number abbrev_number in the
+// abbreviation table at offset abbrev_offset.  abbrev_number is updated with
+// its new abbreviation number and a pointer to the beginning of the
+// abbreviation is returned.
+unsigned char*
+Output_reduced_debug_abbrev_section::get_new_abbrev(
+  uint64_t* abbrev_number, uint64_t abbrev_offset)
+{
+  set_final_data_size();
+  std::pair<uint64_t, uint64_t> abbrev_info =
+      this->abbrev_mapping_[std::make_pair(abbrev_offset, *abbrev_number)];
+  *abbrev_number = abbrev_info.first;
+  return &this->data_[abbrev_info.second];
+}
+
+void Output_reduced_debug_info_section::set_final_data_size()
+{
+  if (this->failed_)
+    return;
+  unsigned char* debug_info = this->postprocessing_buffer();
+  unsigned char* debug_info_end = (this->postprocessing_buffer()
+				   + this->postprocessing_buffer_size());
+  unsigned char* next_compile_unit;
+  this->write_to_postprocessing_buffer();
+
+  while (debug_info < debug_info_end)
+    {
+      uint32_t compile_unit_start = read_from_pointer<32>(&debug_info);
+      // The first 4 bytes of each compile unit determine whether or
+      // not we're using dwarf32 or dwarf64.  This is not necessarily
+      // related to whether the binary is 32 or 64 bits.
+      if (compile_unit_start == 0xFFFFFFFF)
+        {
+          // Technically the size can be up to 96 bits.  Rather than handle
+          // 96/128 bit integers we just truncate the size at 64 bits.
+          if (0 != read_from_pointer<32>(&debug_info))
+            {
+              this->failed(_("Extremely large compile unit in debug info; "
+			     "failed to reduce debug info"));
+              return;
+            }
+          const int dwarf64_header_size = sizeof(uint64_t) + sizeof(uint16_t) +
+                                          sizeof(uint64_t) + sizeof(uint8_t);
+          if (debug_info + dwarf64_header_size >= debug_info_end)
+            {
+              this->failed(_("Debug info extends beyond .debug_info section;"
+			     "failed to reduce debug info"));
+              return;
+            }
+
+          uint64_t compile_unit_size = read_from_pointer<64>(&debug_info);
+          next_compile_unit = debug_info + compile_unit_size;
+          uint16_t version = read_from_pointer<16>(&debug_info);
+          uint64_t abbrev_offset = read_from_pointer<64>(&debug_info);
+          uint8_t address_size = read_from_pointer<8>(&debug_info);
+          size_t LEB_size;
+          uint64_t abbreviation_number = read_unsigned_LEB_128(debug_info,
+                                                               &LEB_size);
+          debug_info += LEB_size;
+          unsigned char* die_abbrev = this->associated_abbrev_->get_new_abbrev(
+              &abbreviation_number, abbrev_offset);
+          unsigned char* die_end;
+          if (!this->get_die_end(debug_info, die_abbrev, &die_end,
+                                 debug_info_end, address_size, true))
+            {
+              this->failed(_("Invalid DIE in debug info; "
+			     "failed to reduce debug info"));
+              return;
+            }
+
+          Insert_into_vector<32>(&this->data_, 0xFFFFFFFF);
+          Insert_into_vector<32>(&this->data_, 0);
+          Insert_into_vector<64>(
+              &this->data_,
+              (11 + get_length_as_unsigned_LEB_128(abbreviation_number)
+	       + die_end - debug_info));
+          Insert_into_vector<16>(&this->data_, version);
+          Insert_into_vector<64>(&this->data_, 0);
+          Insert_into_vector<8>(&this->data_, address_size);
+          write_unsigned_LEB_128(&this->data_, abbreviation_number);
+          this->data_.insert(this->data_.end(), debug_info, die_end);
+        }
+      else
+        {
+          const int dwarf32_header_size =
+              sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint8_t);
+          if (debug_info + dwarf32_header_size >= debug_info_end)
+            {
+              this->failed(_("Debug info extends beyond .debug_info section; "
+			     "failed to reduce debug info"));
+              return;
+            }
+          uint32_t compile_unit_size = compile_unit_start;
+          next_compile_unit = debug_info + compile_unit_size;
+          uint16_t version = read_from_pointer<16>(&debug_info);
+          uint32_t abbrev_offset = read_from_pointer<32>(&debug_info);
+          uint8_t address_size = read_from_pointer<8>(&debug_info);
+          size_t LEB_size;
+          uint64_t abbreviation_number = read_unsigned_LEB_128(debug_info,
+                                                               &LEB_size);
+          debug_info += LEB_size;
+          unsigned char* die_abbrev = this->associated_abbrev_->get_new_abbrev(
+              &abbreviation_number, abbrev_offset);
+          unsigned char* die_end;
+          if (!this->get_die_end(debug_info, die_abbrev, &die_end,
+                                 debug_info_end, address_size, false))
+            {
+              this->failed(_("Invalid DIE in debug info; "
+			     "failed to reduce debug info"));
+              return;
+            }
+
+          Insert_into_vector<32>(
+              &this->data_,
+              (7 + get_length_as_unsigned_LEB_128(abbreviation_number)
+	       + die_end - debug_info));
+          Insert_into_vector<16>(&this->data_, version);
+          Insert_into_vector<32>(&this->data_, 0);
+          Insert_into_vector<8>(&this->data_, address_size);
+          write_unsigned_LEB_128(&this->data_, abbreviation_number);
+          this->data_.insert(this->data_.end(), debug_info, die_end);
+        }
+      debug_info = next_compile_unit;
+    }
+  this->set_data_size(data_.size());
+}
+
+void Output_reduced_debug_info_section::do_write(Output_file* of)
+{
+  off_t offset = this->offset();
+  off_t data_size = this->data_size();
+  unsigned char* view = of->get_output_view(offset, data_size);
+  if (this->failed_)
+    memcpy(view, this->postprocessing_buffer(),
+           this->postprocessing_buffer_size());
+  else
+    memcpy(view, &this->data_.front(), data_size);
+  of->write_output_view(offset, data_size, view);
+}
+
+} // End namespace gold.
Index: gold/reduced_debug_output.h
===================================================================
RCS file: gold/reduced_debug_output.h
diff -N gold/reduced_debug_output.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/reduced_debug_output.h	28 May 2008 20:40:04 -0000
@@ -0,0 +1,140 @@
+// reduced_debug_output.h -- reduce debugging information  -*- C++ -*-
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Caleb Howe <cshowe@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+// Reduce the size of the debug sections by emitting only debug line number
+// information.  We still need to emit skeleton debug_info and debug_abbrev
+// sections for standard tools to parse the debug information correctly.  These
+// classes remove all debug information entries from the .debug_info section
+// except for those describing compilation units as these DIEs contain
+// references to the debug line information needed by most parsers.
+
+#ifndef GOLD_REDUCED_DEBUG_OUTPUT_H
+#define GOLD_REDUCED_DEBUG_OUTPUT_H
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "output.h"
+
+namespace gold
+{
+
+class Output_reduced_debug_abbrev_section : public Output_section
+{
+ public:
+  Output_reduced_debug_abbrev_section(const char* name, elfcpp::Elf_Word flags,
+			              elfcpp::Elf_Xword type)
+    : Output_section(name, flags, type), sized_(false),
+      abbrev_count_(0), failed_(false)
+  { this->set_requires_postprocessing(); }
+
+  unsigned char* get_new_abbrev(uint64_t* abbrev_number,
+                                uint64_t abbrev_offset);
+
+ protected:
+  // Set the final data size.
+  void
+  set_final_data_size();
+
+  // Write out the new debug abbreviations
+  void
+  do_write(Output_file*);
+
+ private:
+  void
+  failed(std::string reason)
+  {
+    gold_warning(reason.c_str());
+    failed_ = true;
+  }
+
+  // The reduced debug abbreviations
+  std::vector<unsigned char> data_;
+
+  // We map the abbreviation table offset and abbreviation number of the
+  // old abbreviation to the number and size of the new abbreviation.
+  std::map<std::pair<uint64_t, uint64_t>,
+           std::pair<uint64_t, uint64_t> > abbrev_mapping_;
+
+  bool sized_;
+
+  // The count of abbreviations in the output data
+  int abbrev_count_;
+
+  // Whether or not the debug reduction has failed for any reason
+  bool failed_;
+};
+
+class Output_reduced_debug_info_section : public Output_section
+{
+ public:
+  Output_reduced_debug_info_section(const char* name, elfcpp::Elf_Word flags,
+			            elfcpp::Elf_Xword type)
+    : Output_section(name, flags, type), failed_(false)
+  { this->set_requires_postprocessing(); }
+
+  void
+  set_abbreviations(Output_reduced_debug_abbrev_section* abbrevs)
+  { associated_abbrev_ = abbrevs; }
+
+ protected:
+  // Set the final data size.
+  void
+  set_final_data_size();
+
+  // Write out the new debug info
+  void
+  do_write(Output_file*);
+
+ private:
+  void
+  failed(std::string reason)
+  {
+    gold_warning(reason.c_str());
+    this->failed_ = true;
+  }
+
+  // Given a pointer to the beginning of a die and the beginning of the
+  // associated abbreviation fills in die_end with the end of the information
+  // entry.  If successful returns true.  Get_die_end also takes a pointer to
+  // the end of the buffer containing the die. If die_end would be beyond the
+  // end of the buffer, or if an unsupported dwarf form is encountered returns
+  // false.
+  bool
+  get_die_end(unsigned char* die, unsigned char* abbrev,
+	      unsigned char** die_end, unsigned char* buffer_end,
+	      int address_size, bool is64);
+
+  // The reduced debug info
+  std::vector<unsigned char> data_;
+
+  // Each debug info section needs to be associated with a debug abbrev section
+  Output_reduced_debug_abbrev_section* associated_abbrev_;
+
+  // Whether or not the debug reduction has failed for any reason
+  bool failed_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_REDUCED_DEBUG_OUTPUT_H)

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