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