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