reduced_debug_output.cc revision 1.1
1// reduced_debug_output.cc -- output reduced debugging information to save space
2
3// Copyright 2008 Free Software Foundation, Inc.
4// Written by Caleb Howe <cshowe@google.com>.
5
6// This file is part of gold.
7
8// This program is free software; you can redistribute it and/or modify
9// it under the terms of the GNU General Public License as published by
10// the Free Software Foundation; either version 3 of the License, or
11// (at your option) any later version.
12
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16// GNU General Public License for more details.
17
18// You should have received a copy of the GNU General Public License
19// along with this program; if not, write to the Free Software
20// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21// MA 02110-1301, USA.
22
23#include "gold.h"
24
25#include "parameters.h"
26#include "options.h"
27#include "dwarf.h"
28#include "dwarf_reader.h"
29#include "reduced_debug_output.h"
30
31#include <vector>
32
33namespace gold
34{
35
36void
37write_unsigned_LEB_128(std::vector<unsigned char>* buffer, uint64_t value)
38{
39  do
40    {
41      unsigned char current_byte = value & 0x7f;
42      value >>= 7;
43      if (value != 0)
44        {
45          current_byte |= 0x80;
46        }
47      buffer->push_back(current_byte);
48    }
49  while (value != 0);
50}
51
52size_t
53get_length_as_unsigned_LEB_128(uint64_t value)
54{
55  size_t length = 0;
56  do
57    {
58      unsigned char current_byte = value & 0x7f;
59      value >>= 7;
60      if (value != 0)
61        {
62          current_byte |= 0x80;
63        }
64      length++;
65    }
66  while (value != 0);
67  return length;
68}
69
70template <int valsize>
71void Insert_into_vector(std::vector<unsigned char>* destination,
72                        typename elfcpp::Valtype_base<valsize>::Valtype value)
73{
74  union
75    {
76      unsigned char buffer[valsize / 8];
77      long long align;
78    } u;
79  if (parameters->target().is_big_endian())
80    elfcpp::Swap<valsize, true>::writeval(u.buffer, value);
81  else
82    elfcpp::Swap<valsize, false>::writeval(u.buffer, value);
83  destination->insert(destination->end(), u.buffer, u.buffer + valsize / 8);
84}
85
86template <int valsize>
87typename elfcpp::Valtype_base<valsize>::Valtype
88read_from_pointer(unsigned char** source)
89{
90  typename elfcpp::Valtype_base<valsize>::Valtype return_value;
91  if (parameters->target().is_big_endian())
92    return_value = elfcpp::Swap_unaligned<valsize, true>::readval(*source);
93  else
94    return_value = elfcpp::Swap_unaligned<valsize, false>::readval(*source);
95  *source += valsize / 8;
96  return return_value;
97}
98
99// Given a pointer to the beginning of a die and the beginning of the associated
100// abbreviation fills in die_end with the end of the information entry.  If
101// successful returns true.  Get_die_end also takes a pointer to the end of the
102// buffer containing the die.  If die_end would be beyond the end of the
103// buffer, or if an unsupported dwarf form is encountered returns false.
104bool
105Output_reduced_debug_info_section::get_die_end(
106    unsigned char* die, unsigned char* abbrev, unsigned char** die_end,
107    unsigned char* buffer_end, int address_size, bool is64)
108{
109  size_t LEB_size;
110  uint64_t LEB_decoded;
111  for(;;)
112    {
113      uint64_t attribute = read_unsigned_LEB_128(abbrev, &LEB_size);
114      abbrev += LEB_size;
115      elfcpp::DW_FORM form =
116          static_cast<elfcpp::DW_FORM>(read_unsigned_LEB_128(abbrev,
117                                                             &LEB_size));
118      abbrev += LEB_size;
119      if (!(attribute || form))
120        break;
121      if (die >= buffer_end)
122        return false;
123      switch(form)
124        {
125          case elfcpp::DW_FORM_null:
126            break;
127          case elfcpp::DW_FORM_strp:
128            die += is64 ? 8 : 4;
129            break;
130          case elfcpp::DW_FORM_addr:
131          case elfcpp::DW_FORM_ref_addr:
132            die += address_size;
133            break;
134          case elfcpp::DW_FORM_block1:
135            die += *die;
136            die += 1;
137            break;
138          case elfcpp::DW_FORM_block2:
139            {
140              uint16_t block_size;
141              block_size = read_from_pointer<16>(&die);
142              die += block_size;
143              break;
144            }
145          case elfcpp::DW_FORM_block4:
146            {
147              uint32_t block_size;
148              block_size = read_from_pointer<32>(&die);
149              die += block_size;
150              break;
151            }
152          case elfcpp::DW_FORM_block:
153            LEB_decoded = read_unsigned_LEB_128(die, &LEB_size);
154            die += (LEB_decoded + LEB_size);
155            break;
156          case elfcpp::DW_FORM_data1:
157          case elfcpp::DW_FORM_ref1:
158          case elfcpp::DW_FORM_flag:
159            die += 1;
160            break;
161          case elfcpp::DW_FORM_data2:
162          case elfcpp::DW_FORM_ref2:
163            die += 2;
164            break;
165          case elfcpp::DW_FORM_data4:
166          case elfcpp::DW_FORM_ref4:
167            die += 4;
168            break;
169          case elfcpp::DW_FORM_data8:
170          case elfcpp::DW_FORM_ref8:
171            die += 8;
172            break;
173          case elfcpp::DW_FORM_ref_udata:
174          case elfcpp::DW_FORM_udata:
175            read_unsigned_LEB_128(die, &LEB_size);
176            die += LEB_size;
177            break;
178          case elfcpp::DW_FORM_string:
179            {
180              size_t length = strlen(reinterpret_cast<char*>(die));
181              die += length + 1;
182              break;
183            }
184          case elfcpp::DW_FORM_sdata:
185          case elfcpp::DW_FORM_indirect:
186            return false;
187      }
188    }
189  *die_end = die;
190  return true;
191}
192
193void
194Output_reduced_debug_abbrev_section::set_final_data_size()
195{
196  if (this->sized_ || this->failed_)
197    return;
198
199  uint64_t abbrev_number;
200  size_t LEB_size;
201  unsigned char* abbrev_data = this->postprocessing_buffer();
202  unsigned char* abbrev_end = this->postprocessing_buffer() +
203                              this->postprocessing_buffer_size();
204  this->write_to_postprocessing_buffer();
205  while(abbrev_data < abbrev_end)
206    {
207      uint64_t abbrev_offset = abbrev_data - this->postprocessing_buffer();
208      while((abbrev_number = read_unsigned_LEB_128(abbrev_data, &LEB_size)))
209        {
210          if (abbrev_data >= abbrev_end)
211            {
212              failed("Debug abbreviations extend beyond .debug_abbrev "
213                     "section; failed to reduce debug abbreviations");
214              return;
215            }
216          abbrev_data += LEB_size;
217
218          // Together with the abbreviation number these fields make up
219          // the header for each abbreviation
220          uint64_t abbrev_type = read_unsigned_LEB_128(abbrev_data, &LEB_size);
221          abbrev_data += LEB_size;
222
223          // This would ordinarily be the has_children field of the
224          // abbreviation.  But it's going to be false after reducting the
225          // information, so there's no point in storing it
226          abbrev_data++;
227
228          // Read to the end of the current abbreviation
229          // This is indicated by two zero unsigned LEBs in a row.  We don't
230          // need to parse the data yet, so we just scan through the data
231          // looking for two consecutive 0 bytes indicating the end of the
232          // abbreviation
233          unsigned char* current_abbrev;
234          for (current_abbrev = abbrev_data;
235               current_abbrev[0] || current_abbrev[1];
236               current_abbrev++)
237            {
238              if (current_abbrev >= abbrev_end)
239                {
240                  this->failed(_("Debug abbreviations extend beyond "
241				 ".debug_abbrev section; failed to reduce "
242				 "debug abbreviations"));
243                  return;
244                }
245            }
246          // Account for the two nulls and advance to the start of the
247          // next abbreviation.
248          current_abbrev += 2;
249
250          // We're eliminating every entry except for compile units, so we
251          // only need to store abbreviations that describe them
252          if (abbrev_type == elfcpp::DW_TAG_compile_unit)
253            {
254              write_unsigned_LEB_128(&this->data_, ++this->abbrev_count_);
255              write_unsigned_LEB_128(&this->data_, abbrev_type);
256              // has_children is false for all entries
257              this->data_.push_back(0);
258              this->abbrev_mapping_[std::make_pair(abbrev_offset,
259                                                   abbrev_number)] =
260                  std::make_pair(abbrev_count_, this->data_.size());
261              this->data_.insert(this->data_.end(), abbrev_data,
262                                 current_abbrev);
263            }
264          abbrev_data = current_abbrev;
265        }
266      gold_assert(LEB_size == 1);
267      abbrev_data += LEB_size;
268    }
269  // Null terminate the list of abbreviations
270  this->data_.push_back(0);
271  this->set_data_size(data_.size());
272  this->sized_ = true;
273}
274
275void
276Output_reduced_debug_abbrev_section::do_write(Output_file* of)
277{
278  off_t offset = this->offset();
279  off_t data_size = this->data_size();
280  unsigned char* view = of->get_output_view(offset, data_size);
281  if (this->failed_)
282    memcpy(view, this->postprocessing_buffer(),
283           this->postprocessing_buffer_size());
284  else
285    memcpy(view, &this->data_.front(), data_size);
286  of->write_output_view(offset, data_size, view);
287}
288
289// Locates the abbreviation with abbreviation_number abbrev_number in the
290// abbreviation table at offset abbrev_offset.  abbrev_number is updated with
291// its new abbreviation number and a pointer to the beginning of the
292// abbreviation is returned.
293unsigned char*
294Output_reduced_debug_abbrev_section::get_new_abbrev(
295  uint64_t* abbrev_number, uint64_t abbrev_offset)
296{
297  set_final_data_size();
298  std::pair<uint64_t, uint64_t> abbrev_info =
299      this->abbrev_mapping_[std::make_pair(abbrev_offset, *abbrev_number)];
300  *abbrev_number = abbrev_info.first;
301  return &this->data_[abbrev_info.second];
302}
303
304void Output_reduced_debug_info_section::set_final_data_size()
305{
306  if (this->failed_)
307    return;
308  unsigned char* debug_info = this->postprocessing_buffer();
309  unsigned char* debug_info_end = (this->postprocessing_buffer()
310				   + this->postprocessing_buffer_size());
311  unsigned char* next_compile_unit;
312  this->write_to_postprocessing_buffer();
313
314  while (debug_info < debug_info_end)
315    {
316      uint32_t compile_unit_start = read_from_pointer<32>(&debug_info);
317      // The first 4 bytes of each compile unit determine whether or
318      // not we're using dwarf32 or dwarf64.  This is not necessarily
319      // related to whether the binary is 32 or 64 bits.
320      if (compile_unit_start == 0xFFFFFFFF)
321        {
322          // Technically the size can be up to 96 bits.  Rather than handle
323          // 96/128 bit integers we just truncate the size at 64 bits.
324          if (0 != read_from_pointer<32>(&debug_info))
325            {
326              this->failed(_("Extremely large compile unit in debug info; "
327			     "failed to reduce debug info"));
328              return;
329            }
330          const int dwarf64_header_size = sizeof(uint64_t) + sizeof(uint16_t) +
331                                          sizeof(uint64_t) + sizeof(uint8_t);
332          if (debug_info + dwarf64_header_size >= debug_info_end)
333            {
334              this->failed(_("Debug info extends beyond .debug_info section;"
335			     "failed to reduce debug info"));
336              return;
337            }
338
339          uint64_t compile_unit_size = read_from_pointer<64>(&debug_info);
340          next_compile_unit = debug_info + compile_unit_size;
341          uint16_t version = read_from_pointer<16>(&debug_info);
342          uint64_t abbrev_offset = read_from_pointer<64>(&debug_info);
343          uint8_t address_size = read_from_pointer<8>(&debug_info);
344          size_t LEB_size;
345          uint64_t abbreviation_number = read_unsigned_LEB_128(debug_info,
346                                                               &LEB_size);
347          debug_info += LEB_size;
348          unsigned char* die_abbrev = this->associated_abbrev_->get_new_abbrev(
349              &abbreviation_number, abbrev_offset);
350          unsigned char* die_end;
351          if (!this->get_die_end(debug_info, die_abbrev, &die_end,
352                                 debug_info_end, address_size, true))
353            {
354              this->failed(_("Invalid DIE in debug info; "
355			     "failed to reduce debug info"));
356              return;
357            }
358
359          Insert_into_vector<32>(&this->data_, 0xFFFFFFFF);
360          Insert_into_vector<32>(&this->data_, 0);
361          Insert_into_vector<64>(
362              &this->data_,
363              (11 + get_length_as_unsigned_LEB_128(abbreviation_number)
364	       + die_end - debug_info));
365          Insert_into_vector<16>(&this->data_, version);
366          Insert_into_vector<64>(&this->data_, 0);
367          Insert_into_vector<8>(&this->data_, address_size);
368          write_unsigned_LEB_128(&this->data_, abbreviation_number);
369          this->data_.insert(this->data_.end(), debug_info, die_end);
370        }
371      else
372        {
373          const int dwarf32_header_size =
374              sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint8_t);
375          if (debug_info + dwarf32_header_size >= debug_info_end)
376            {
377              this->failed(_("Debug info extends beyond .debug_info section; "
378			     "failed to reduce debug info"));
379              return;
380            }
381          uint32_t compile_unit_size = compile_unit_start;
382          next_compile_unit = debug_info + compile_unit_size;
383          uint16_t version = read_from_pointer<16>(&debug_info);
384          uint32_t abbrev_offset = read_from_pointer<32>(&debug_info);
385          uint8_t address_size = read_from_pointer<8>(&debug_info);
386          size_t LEB_size;
387          uint64_t abbreviation_number = read_unsigned_LEB_128(debug_info,
388                                                               &LEB_size);
389          debug_info += LEB_size;
390          unsigned char* die_abbrev = this->associated_abbrev_->get_new_abbrev(
391              &abbreviation_number, abbrev_offset);
392          unsigned char* die_end;
393          if (!this->get_die_end(debug_info, die_abbrev, &die_end,
394                                 debug_info_end, address_size, false))
395            {
396              this->failed(_("Invalid DIE in debug info; "
397			     "failed to reduce debug info"));
398              return;
399            }
400
401          Insert_into_vector<32>(
402              &this->data_,
403              (7 + get_length_as_unsigned_LEB_128(abbreviation_number)
404	       + die_end - debug_info));
405          Insert_into_vector<16>(&this->data_, version);
406          Insert_into_vector<32>(&this->data_, 0);
407          Insert_into_vector<8>(&this->data_, address_size);
408          write_unsigned_LEB_128(&this->data_, abbreviation_number);
409          this->data_.insert(this->data_.end(), debug_info, die_end);
410        }
411      debug_info = next_compile_unit;
412    }
413  this->set_data_size(data_.size());
414}
415
416void Output_reduced_debug_info_section::do_write(Output_file* of)
417{
418  off_t offset = this->offset();
419  off_t data_size = this->data_size();
420  unsigned char* view = of->get_output_view(offset, data_size);
421  if (this->failed_)
422    memcpy(view, this->postprocessing_buffer(),
423           this->postprocessing_buffer_size());
424  else
425    memcpy(view, &this->data_.front(), data_size);
426  of->write_output_view(offset, data_size, view);
427}
428
429} // End namespace gold.
430