1 // incremental.cc -- incremental linking test/debug tool 2 3 // Copyright 2009, 2010 Free Software Foundation, Inc. 4 // Written by Rafael Avila de Espindola <rafael.espindola@gmail.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 24 // This file is a (still incomplete) test/debug tool that should display 25 // all information available in the incremental linking sections in a 26 // format that is easy to read. 27 // Once the format is a bit more stable, this should probably be moved to 28 // readelf. Because of that, the use of gold's data structures and functions 29 // is just a short term convenience and not a design decision. 30 31 #include "gold.h" 32 33 #include <stdio.h> 34 #include <errno.h> 35 #include <time.h> 36 37 #include "incremental.h" 38 39 namespace gold 40 { 41 class Output_file; 42 } 43 44 using namespace gold; 45 46 template<int size, bool big_endian> 47 static typename Incremental_inputs_reader<size, big_endian>:: 48 Incremental_input_entry_reader 49 find_input_containing_global( 50 Incremental_inputs_reader<size, big_endian>& incremental_inputs, 51 unsigned int offset, 52 unsigned int* symndx) 53 { 54 typedef Incremental_inputs_reader<size, big_endian> Inputs_reader; 55 for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) 56 { 57 typename Inputs_reader::Incremental_input_entry_reader input_file = 58 incremental_inputs.input_file(i); 59 if (input_file.type() != INCREMENTAL_INPUT_OBJECT 60 && input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER) 61 continue; 62 unsigned int nsyms = input_file.get_global_symbol_count(); 63 if (offset >= input_file.get_symbol_offset(0) 64 && offset < input_file.get_symbol_offset(nsyms)) 65 { 66 *symndx = (offset - input_file.get_symbol_offset(0)) / 16; 67 return input_file; 68 } 69 } 70 gold_unreachable(); 71 } 72 73 template<int size, bool big_endian> 74 static void 75 dump_incremental_inputs(const char* argv0, const char* filename, 76 Incremental_binary* inc) 77 { 78 bool t; 79 unsigned int inputs_shndx; 80 unsigned int isymtab_shndx; 81 unsigned int irelocs_shndx; 82 unsigned int igot_plt_shndx; 83 unsigned int istrtab_shndx; 84 typedef Incremental_binary::Location Location; 85 typedef Incremental_binary::View View; 86 typedef Incremental_inputs_reader<size, big_endian> Inputs_reader; 87 typedef typename Inputs_reader::Incremental_input_entry_reader Entry_reader; 88 89 // Find the .gnu_incremental_inputs, _symtab, _relocs, and _strtab sections. 90 91 t = inc->find_incremental_inputs_sections(&inputs_shndx, &isymtab_shndx, 92 &irelocs_shndx, &igot_plt_shndx, 93 &istrtab_shndx); 94 if (!t) 95 { 96 fprintf(stderr, "%s: %s: no .gnu_incremental_inputs section\n", argv0, 97 filename); 98 exit(1); 99 } 100 101 elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file(inc); 102 103 // Get a view of the .gnu_incremental_inputs section. 104 105 Location inputs_location(elf_file.section_contents(inputs_shndx)); 106 View inputs_view(inc->view(inputs_location)); 107 108 // Get the .gnu_incremental_strtab section as a string table. 109 110 Location istrtab_location(elf_file.section_contents(istrtab_shndx)); 111 View istrtab_view(inc->view(istrtab_location)); 112 elfcpp::Elf_strtab istrtab(istrtab_view.data(), istrtab_location.data_size); 113 114 // Create a reader object for the .gnu_incremental_inputs section. 115 116 Incremental_inputs_reader<size, big_endian> 117 incremental_inputs(inputs_view.data(), istrtab); 118 119 if (incremental_inputs.version() != 1) 120 { 121 fprintf(stderr, "%s: %s: unknown incremental version %d\n", argv0, 122 filename, incremental_inputs.version()); 123 exit(1); 124 } 125 126 const char* command_line = incremental_inputs.command_line(); 127 if (command_line == NULL) 128 { 129 fprintf(stderr, 130 "%s: %s: failed to get link command line\n", 131 argv0, filename); 132 exit(1); 133 } 134 printf("Link command line: %s\n", command_line); 135 136 printf("\nInput files:\n"); 137 for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) 138 { 139 Entry_reader input_file = incremental_inputs.input_file(i); 140 141 const char* objname = input_file.filename(); 142 if (objname == NULL) 143 { 144 fprintf(stderr,"%s: %s: failed to get file name for object %u\n", 145 argv0, filename, i); 146 exit(1); 147 } 148 printf("[%d] %s\n", i, objname); 149 150 Timespec mtime = input_file.get_mtime(); 151 printf(" Timestamp: %llu.%09d %s", 152 static_cast<unsigned long long>(mtime.seconds), 153 mtime.nanoseconds, 154 ctime(&mtime.seconds)); 155 156 Incremental_input_type input_type = input_file.type(); 157 printf(" Type: "); 158 switch (input_type) 159 { 160 case INCREMENTAL_INPUT_OBJECT: 161 { 162 printf("Object\n"); 163 printf(" Input section count: %d\n", 164 input_file.get_input_section_count()); 165 printf(" Symbol count: %d\n", 166 input_file.get_global_symbol_count()); 167 } 168 break; 169 case INCREMENTAL_INPUT_ARCHIVE_MEMBER: 170 { 171 printf("Archive member\n"); 172 printf(" Input section count: %d\n", 173 input_file.get_input_section_count()); 174 printf(" Symbol count: %d\n", 175 input_file.get_global_symbol_count()); 176 } 177 break; 178 case INCREMENTAL_INPUT_ARCHIVE: 179 { 180 printf("Archive\n"); 181 printf(" Member count: %d\n", input_file.get_member_count()); 182 printf(" Unused symbol count: %d\n", 183 input_file.get_unused_symbol_count()); 184 } 185 break; 186 case INCREMENTAL_INPUT_SHARED_LIBRARY: 187 { 188 printf("Shared library\n"); 189 printf(" Symbol count: %d\n", 190 input_file.get_global_symbol_count()); 191 } 192 break; 193 case INCREMENTAL_INPUT_SCRIPT: 194 printf("Linker script\n"); 195 break; 196 default: 197 fprintf(stderr, "%s: invalid file type for object %u: %d\n", 198 argv0, i, input_type); 199 exit(1); 200 } 201 } 202 203 printf("\nInput sections:\n"); 204 for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) 205 { 206 Entry_reader input_file(incremental_inputs.input_file(i)); 207 208 if (input_file.type() != INCREMENTAL_INPUT_OBJECT 209 && input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER) 210 continue; 211 212 const char* objname = input_file.filename(); 213 if (objname == NULL) 214 { 215 fprintf(stderr,"%s: %s: failed to get file name for object %u\n", 216 argv0, filename, i); 217 exit(1); 218 } 219 220 printf("[%d] %s\n", i, objname); 221 222 printf(" %3s %6s %8s %8s %s\n", 223 "n", "outndx", "offset", "size", "name"); 224 unsigned int nsections = input_file.get_input_section_count(); 225 for (unsigned int shndx = 0; shndx < nsections; ++shndx) 226 { 227 typename Entry_reader::Input_section_info info( 228 input_file.get_input_section(shndx)); 229 printf(" %3d %6d %8lld %8lld %s\n", shndx, 230 info.output_shndx, 231 static_cast<long long>(info.sh_offset), 232 static_cast<long long>(info.sh_size), 233 info.name); 234 } 235 } 236 237 printf("\nGlobal symbols per input file:\n"); 238 for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) 239 { 240 Entry_reader input_file(incremental_inputs.input_file(i)); 241 242 if (input_file.type() != INCREMENTAL_INPUT_OBJECT 243 && input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER) 244 continue; 245 246 const char* objname = input_file.filename(); 247 if (objname == NULL) 248 { 249 fprintf(stderr,"%s: %s: failed to get file name for object %u\n", 250 argv0, filename, i); 251 exit(1); 252 } 253 254 printf("[%d] %s\n", i, objname); 255 256 unsigned int nsyms = input_file.get_global_symbol_count(); 257 if (nsyms > 0) 258 printf(" %6s %8s %8s %8s %8s\n", 259 "outndx", "offset", "chain", "#relocs", "rbase"); 260 for (unsigned int symndx = 0; symndx < nsyms; ++symndx) 261 { 262 typename Entry_reader::Global_symbol_info info( 263 input_file.get_global_symbol_info(symndx)); 264 printf(" %6d %8d %8d %8d %8d\n", 265 info.output_symndx, 266 input_file.get_symbol_offset(symndx), 267 info.next_offset, 268 info.reloc_count, 269 info.reloc_offset); 270 } 271 } 272 273 // Get a view of the .symtab section. 274 275 unsigned int symtab_shndx = elf_file.find_section_by_type(elfcpp::SHT_SYMTAB); 276 if (symtab_shndx == elfcpp::SHN_UNDEF) // Not found. 277 { 278 fprintf(stderr, "%s: %s: no symbol table section\n", argv0, filename); 279 exit(1); 280 } 281 Location symtab_location(elf_file.section_contents(symtab_shndx)); 282 View symtab_view(inc->view(symtab_location)); 283 284 // Get a view of the .strtab section. 285 286 unsigned int strtab_shndx = elf_file.section_link(symtab_shndx); 287 if (strtab_shndx == elfcpp::SHN_UNDEF 288 || strtab_shndx > elf_file.shnum() 289 || elf_file.section_type(strtab_shndx) != elfcpp::SHT_STRTAB) 290 { 291 fprintf(stderr, "%s: %s: no string table section\n", argv0, filename); 292 exit(1); 293 } 294 Location strtab_location(elf_file.section_contents(strtab_shndx)); 295 View strtab_view(inc->view(strtab_location)); 296 elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size); 297 298 // Get a view of the .gnu_incremental_symtab section. 299 300 Location isymtab_location(elf_file.section_contents(isymtab_shndx)); 301 View isymtab_view(inc->view(isymtab_location)); 302 303 // Get a view of the .gnu_incremental_relocs section. 304 305 Location irelocs_location(elf_file.section_contents(irelocs_shndx)); 306 View irelocs_view(inc->view(irelocs_location)); 307 308 // The .gnu_incremental_symtab section contains entries that parallel 309 // the global symbols of the main symbol table. The sh_info field 310 // of the main symbol table's section header tells us how many global 311 // symbols there are, but that count does not include any global 312 // symbols that were forced local during the link. Therefore, we 313 // use the size of the .gnu_incremental_symtab section to deduce 314 // the number of global symbols + forced-local symbols there are 315 // in the symbol table. 316 unsigned int sym_size = elfcpp::Elf_sizes<size>::sym_size; 317 unsigned int nsyms = symtab_location.data_size / sym_size; 318 unsigned int nglobals = isymtab_location.data_size / 4; 319 unsigned int first_global = nsyms - nglobals; 320 unsigned const char* sym_p = symtab_view.data() + first_global * sym_size; 321 unsigned const char* isym_p = isymtab_view.data(); 322 323 Incremental_symtab_reader<big_endian> isymtab(isymtab_view.data()); 324 Incremental_relocs_reader<size, big_endian> irelocs(irelocs_view.data()); 325 326 printf("\nGlobal symbol table:\n"); 327 for (unsigned int i = 0; i < nglobals; i++) 328 { 329 elfcpp::Sym<size, big_endian> sym(sym_p); 330 const char* symname; 331 if (!strtab.get_c_string(sym.get_st_name(), &symname)) 332 symname = "<unknown>"; 333 printf("[%d] %s\n", first_global + i, symname); 334 unsigned int offset = isymtab.get_list_head(i); 335 while (offset > 0) 336 { 337 unsigned int sym_ndx; 338 Entry_reader input_file = 339 find_input_containing_global<size, big_endian>(incremental_inputs, 340 offset, &sym_ndx); 341 typename Entry_reader::Global_symbol_info sym_info( 342 input_file.get_global_symbol_info(sym_ndx)); 343 printf(" %s (first reloc: %d, reloc count: %d)", 344 input_file.filename(), sym_info.reloc_offset, 345 sym_info.reloc_count); 346 if (sym_info.output_symndx != first_global + i) 347 printf(" ** wrong output symndx (%d) **", sym_info.output_symndx); 348 printf("\n"); 349 // Dump the relocations from this input file for this symbol. 350 unsigned int r_off = sym_info.reloc_offset; 351 for (unsigned int j = 0; j < sym_info.reloc_count; j++) 352 { 353 printf(" %4d relocation type %3d shndx %d" 354 " offset %016llx addend %016llx %s\n", 355 r_off, 356 irelocs.get_r_type(r_off), 357 irelocs.get_r_shndx(r_off), 358 static_cast<long long>(irelocs.get_r_offset(r_off)), 359 static_cast<long long>(irelocs.get_r_addend(r_off)), 360 symname); 361 r_off += irelocs.reloc_size; 362 } 363 offset = sym_info.next_offset; 364 } 365 sym_p += sym_size; 366 isym_p += 4; 367 } 368 369 // Get a view of the .gnu_incremental_got_plt section. 370 371 Location igot_plt_location(elf_file.section_contents(igot_plt_shndx)); 372 View igot_plt_view(inc->view(igot_plt_location)); 373 374 Incremental_got_plt_reader<big_endian> igot_plt(igot_plt_view.data()); 375 unsigned int ngot = igot_plt.get_got_entry_count(); 376 unsigned int nplt = igot_plt.get_plt_entry_count(); 377 378 printf("\nGOT entries:\n"); 379 for (unsigned int i = 0; i < ngot; ++i) 380 { 381 unsigned int got_type = igot_plt.get_got_type(i); 382 unsigned int got_desc = igot_plt.get_got_desc(i); 383 printf("[%d] type %02x, ", i, got_type & 0x7f); 384 if (got_type == 0x7f) 385 printf("reserved"); 386 else if (got_type & 0x80) 387 { 388 Entry_reader input_file = incremental_inputs.input_file(got_desc); 389 const char* objname = input_file.filename(); 390 printf("local: %s (%d)", objname, got_desc); 391 } 392 else 393 { 394 sym_p = symtab_view.data() + got_desc * sym_size; 395 elfcpp::Sym<size, big_endian> sym(sym_p); 396 const char* symname; 397 if (!strtab.get_c_string(sym.get_st_name(), &symname)) 398 symname = "<unknown>"; 399 printf("global %s (%d)", symname, got_desc); 400 } 401 printf("\n"); 402 } 403 404 printf("\nPLT entries:\n"); 405 for (unsigned int i = 0; i < nplt; ++i) 406 { 407 unsigned int plt_desc = igot_plt.get_plt_desc(i); 408 printf("[%d] ", i); 409 sym_p = symtab_view.data() + plt_desc * sym_size; 410 elfcpp::Sym<size, big_endian> sym(sym_p); 411 const char* symname; 412 if (!strtab.get_c_string(sym.get_st_name(), &symname)) 413 symname = "<unknown>"; 414 printf("%s (%d)\n", symname, plt_desc); 415 } 416 417 printf("\nUnused archive symbols:\n"); 418 for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) 419 { 420 Entry_reader input_file(incremental_inputs.input_file(i)); 421 422 if (input_file.type() != INCREMENTAL_INPUT_ARCHIVE) 423 continue; 424 425 const char* objname = input_file.filename(); 426 if (objname == NULL) 427 { 428 fprintf(stderr,"%s: %s: failed to get file name for object %u\n", 429 argv0, filename, i); 430 exit(1); 431 } 432 433 printf("[%d] %s\n", i, objname); 434 unsigned int nsyms = input_file.get_unused_symbol_count(); 435 for (unsigned int symndx = 0; symndx < nsyms; ++symndx) 436 printf(" %s\n", input_file.get_unused_symbol(symndx)); 437 } 438 439 } 440 441 int 442 main(int argc, char** argv) 443 { 444 if (argc != 2) 445 { 446 fprintf(stderr, "Usage: %s <file>\n", argv[0]); 447 return 1; 448 } 449 const char* filename = argv[1]; 450 451 Output_file* file = new Output_file(filename); 452 453 bool t = file->open_for_modification(); 454 if (!t) 455 { 456 fprintf(stderr, "%s: open_for_modification(%s): %s\n", argv[0], filename, 457 strerror(errno)); 458 return 1; 459 } 460 461 Incremental_binary* inc = open_incremental_binary(file); 462 463 if (inc == NULL) 464 { 465 fprintf(stderr, "%s: open_incremental_binary(%s): %s\n", argv[0], 466 filename, strerror(errno)); 467 return 1; 468 } 469 470 switch (parameters->size_and_endianness()) 471 { 472 #ifdef HAVE_TARGET_32_LITTLE 473 case Parameters::TARGET_32_LITTLE: 474 dump_incremental_inputs<32, false>(argv[0], filename, inc); 475 break; 476 #endif 477 #ifdef HAVE_TARGET_32_BIG 478 case Parameters::TARGET_32_BIG: 479 dump_incremental_inputs<32, true>(argv[0], filename, inc); 480 break; 481 #endif 482 #ifdef HAVE_TARGET_64_LITTLE 483 case Parameters::TARGET_64_LITTLE: 484 dump_incremental_inputs<64, false>(argv[0], filename, inc); 485 break; 486 #endif 487 #ifdef HAVE_TARGET_64_BIG 488 case Parameters::TARGET_64_BIG: 489 dump_incremental_inputs<64, true>(argv[0], filename, inc); 490 break; 491 #endif 492 default: 493 gold_unreachable(); 494 } 495 496 return 0; 497 } 498