Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.32-rc3 651 lines 16 kB view raw
1#include <stdio.h> 2#include <stdarg.h> 3#include <stdlib.h> 4#include <stdint.h> 5#include <string.h> 6#include <errno.h> 7#include <unistd.h> 8#include <elf.h> 9#include <byteswap.h> 10#define USE_BSD 11#include <endian.h> 12 13#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 14static Elf32_Ehdr ehdr; 15static unsigned long reloc_count, reloc_idx; 16static unsigned long *relocs; 17 18struct section { 19 Elf32_Shdr shdr; 20 struct section *link; 21 Elf32_Sym *symtab; 22 Elf32_Rel *reltab; 23 char *strtab; 24}; 25static struct section *secs; 26 27/* 28 * Following symbols have been audited. There values are constant and do 29 * not change if bzImage is loaded at a different physical address than 30 * the address for which it has been compiled. Don't warn user about 31 * absolute relocations present w.r.t these symbols. 32 */ 33static const char* safe_abs_relocs[] = { 34 "xen_irq_disable_direct_reloc", 35 "xen_save_fl_direct_reloc", 36}; 37 38static int is_safe_abs_reloc(const char* sym_name) 39{ 40 int i; 41 42 for (i = 0; i < ARRAY_SIZE(safe_abs_relocs); i++) { 43 if (!strcmp(sym_name, safe_abs_relocs[i])) 44 /* Match found */ 45 return 1; 46 } 47 if (strncmp(sym_name, "VDSO", 4) == 0) 48 return 1; 49 if (strncmp(sym_name, "__crc_", 6) == 0) 50 return 1; 51 return 0; 52} 53 54static void die(char *fmt, ...) 55{ 56 va_list ap; 57 va_start(ap, fmt); 58 vfprintf(stderr, fmt, ap); 59 va_end(ap); 60 exit(1); 61} 62 63static const char *sym_type(unsigned type) 64{ 65 static const char *type_name[] = { 66#define SYM_TYPE(X) [X] = #X 67 SYM_TYPE(STT_NOTYPE), 68 SYM_TYPE(STT_OBJECT), 69 SYM_TYPE(STT_FUNC), 70 SYM_TYPE(STT_SECTION), 71 SYM_TYPE(STT_FILE), 72 SYM_TYPE(STT_COMMON), 73 SYM_TYPE(STT_TLS), 74#undef SYM_TYPE 75 }; 76 const char *name = "unknown sym type name"; 77 if (type < ARRAY_SIZE(type_name)) { 78 name = type_name[type]; 79 } 80 return name; 81} 82 83static const char *sym_bind(unsigned bind) 84{ 85 static const char *bind_name[] = { 86#define SYM_BIND(X) [X] = #X 87 SYM_BIND(STB_LOCAL), 88 SYM_BIND(STB_GLOBAL), 89 SYM_BIND(STB_WEAK), 90#undef SYM_BIND 91 }; 92 const char *name = "unknown sym bind name"; 93 if (bind < ARRAY_SIZE(bind_name)) { 94 name = bind_name[bind]; 95 } 96 return name; 97} 98 99static const char *sym_visibility(unsigned visibility) 100{ 101 static const char *visibility_name[] = { 102#define SYM_VISIBILITY(X) [X] = #X 103 SYM_VISIBILITY(STV_DEFAULT), 104 SYM_VISIBILITY(STV_INTERNAL), 105 SYM_VISIBILITY(STV_HIDDEN), 106 SYM_VISIBILITY(STV_PROTECTED), 107#undef SYM_VISIBILITY 108 }; 109 const char *name = "unknown sym visibility name"; 110 if (visibility < ARRAY_SIZE(visibility_name)) { 111 name = visibility_name[visibility]; 112 } 113 return name; 114} 115 116static const char *rel_type(unsigned type) 117{ 118 static const char *type_name[] = { 119#define REL_TYPE(X) [X] = #X 120 REL_TYPE(R_386_NONE), 121 REL_TYPE(R_386_32), 122 REL_TYPE(R_386_PC32), 123 REL_TYPE(R_386_GOT32), 124 REL_TYPE(R_386_PLT32), 125 REL_TYPE(R_386_COPY), 126 REL_TYPE(R_386_GLOB_DAT), 127 REL_TYPE(R_386_JMP_SLOT), 128 REL_TYPE(R_386_RELATIVE), 129 REL_TYPE(R_386_GOTOFF), 130 REL_TYPE(R_386_GOTPC), 131#undef REL_TYPE 132 }; 133 const char *name = "unknown type rel type name"; 134 if (type < ARRAY_SIZE(type_name)) { 135 name = type_name[type]; 136 } 137 return name; 138} 139 140static const char *sec_name(unsigned shndx) 141{ 142 const char *sec_strtab; 143 const char *name; 144 sec_strtab = secs[ehdr.e_shstrndx].strtab; 145 name = "<noname>"; 146 if (shndx < ehdr.e_shnum) { 147 name = sec_strtab + secs[shndx].shdr.sh_name; 148 } 149 else if (shndx == SHN_ABS) { 150 name = "ABSOLUTE"; 151 } 152 else if (shndx == SHN_COMMON) { 153 name = "COMMON"; 154 } 155 return name; 156} 157 158static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym) 159{ 160 const char *name; 161 name = "<noname>"; 162 if (sym->st_name) { 163 name = sym_strtab + sym->st_name; 164 } 165 else { 166 name = sec_name(secs[sym->st_shndx].shdr.sh_name); 167 } 168 return name; 169} 170 171 172 173#if BYTE_ORDER == LITTLE_ENDIAN 174#define le16_to_cpu(val) (val) 175#define le32_to_cpu(val) (val) 176#endif 177#if BYTE_ORDER == BIG_ENDIAN 178#define le16_to_cpu(val) bswap_16(val) 179#define le32_to_cpu(val) bswap_32(val) 180#endif 181 182static uint16_t elf16_to_cpu(uint16_t val) 183{ 184 return le16_to_cpu(val); 185} 186 187static uint32_t elf32_to_cpu(uint32_t val) 188{ 189 return le32_to_cpu(val); 190} 191 192static void read_ehdr(FILE *fp) 193{ 194 if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) { 195 die("Cannot read ELF header: %s\n", 196 strerror(errno)); 197 } 198 if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) { 199 die("No ELF magic\n"); 200 } 201 if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) { 202 die("Not a 32 bit executable\n"); 203 } 204 if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) { 205 die("Not a LSB ELF executable\n"); 206 } 207 if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) { 208 die("Unknown ELF version\n"); 209 } 210 /* Convert the fields to native endian */ 211 ehdr.e_type = elf16_to_cpu(ehdr.e_type); 212 ehdr.e_machine = elf16_to_cpu(ehdr.e_machine); 213 ehdr.e_version = elf32_to_cpu(ehdr.e_version); 214 ehdr.e_entry = elf32_to_cpu(ehdr.e_entry); 215 ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff); 216 ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff); 217 ehdr.e_flags = elf32_to_cpu(ehdr.e_flags); 218 ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize); 219 ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize); 220 ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum); 221 ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize); 222 ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum); 223 ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx); 224 225 if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) { 226 die("Unsupported ELF header type\n"); 227 } 228 if (ehdr.e_machine != EM_386) { 229 die("Not for x86\n"); 230 } 231 if (ehdr.e_version != EV_CURRENT) { 232 die("Unknown ELF version\n"); 233 } 234 if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) { 235 die("Bad Elf header size\n"); 236 } 237 if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) { 238 die("Bad program header entry\n"); 239 } 240 if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) { 241 die("Bad section header entry\n"); 242 } 243 if (ehdr.e_shstrndx >= ehdr.e_shnum) { 244 die("String table index out of bounds\n"); 245 } 246} 247 248static void read_shdrs(FILE *fp) 249{ 250 int i; 251 Elf32_Shdr shdr; 252 253 secs = calloc(ehdr.e_shnum, sizeof(struct section)); 254 if (!secs) { 255 die("Unable to allocate %d section headers\n", 256 ehdr.e_shnum); 257 } 258 if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) { 259 die("Seek to %d failed: %s\n", 260 ehdr.e_shoff, strerror(errno)); 261 } 262 for (i = 0; i < ehdr.e_shnum; i++) { 263 struct section *sec = &secs[i]; 264 if (fread(&shdr, sizeof shdr, 1, fp) != 1) 265 die("Cannot read ELF section headers %d/%d: %s\n", 266 i, ehdr.e_shnum, strerror(errno)); 267 sec->shdr.sh_name = elf32_to_cpu(shdr.sh_name); 268 sec->shdr.sh_type = elf32_to_cpu(shdr.sh_type); 269 sec->shdr.sh_flags = elf32_to_cpu(shdr.sh_flags); 270 sec->shdr.sh_addr = elf32_to_cpu(shdr.sh_addr); 271 sec->shdr.sh_offset = elf32_to_cpu(shdr.sh_offset); 272 sec->shdr.sh_size = elf32_to_cpu(shdr.sh_size); 273 sec->shdr.sh_link = elf32_to_cpu(shdr.sh_link); 274 sec->shdr.sh_info = elf32_to_cpu(shdr.sh_info); 275 sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign); 276 sec->shdr.sh_entsize = elf32_to_cpu(shdr.sh_entsize); 277 if (sec->shdr.sh_link < ehdr.e_shnum) 278 sec->link = &secs[sec->shdr.sh_link]; 279 } 280 281} 282 283static void read_strtabs(FILE *fp) 284{ 285 int i; 286 for (i = 0; i < ehdr.e_shnum; i++) { 287 struct section *sec = &secs[i]; 288 if (sec->shdr.sh_type != SHT_STRTAB) { 289 continue; 290 } 291 sec->strtab = malloc(sec->shdr.sh_size); 292 if (!sec->strtab) { 293 die("malloc of %d bytes for strtab failed\n", 294 sec->shdr.sh_size); 295 } 296 if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { 297 die("Seek to %d failed: %s\n", 298 sec->shdr.sh_offset, strerror(errno)); 299 } 300 if (fread(sec->strtab, 1, sec->shdr.sh_size, fp) 301 != sec->shdr.sh_size) { 302 die("Cannot read symbol table: %s\n", 303 strerror(errno)); 304 } 305 } 306} 307 308static void read_symtabs(FILE *fp) 309{ 310 int i,j; 311 for (i = 0; i < ehdr.e_shnum; i++) { 312 struct section *sec = &secs[i]; 313 if (sec->shdr.sh_type != SHT_SYMTAB) { 314 continue; 315 } 316 sec->symtab = malloc(sec->shdr.sh_size); 317 if (!sec->symtab) { 318 die("malloc of %d bytes for symtab failed\n", 319 sec->shdr.sh_size); 320 } 321 if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { 322 die("Seek to %d failed: %s\n", 323 sec->shdr.sh_offset, strerror(errno)); 324 } 325 if (fread(sec->symtab, 1, sec->shdr.sh_size, fp) 326 != sec->shdr.sh_size) { 327 die("Cannot read symbol table: %s\n", 328 strerror(errno)); 329 } 330 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) { 331 Elf32_Sym *sym = &sec->symtab[j]; 332 sym->st_name = elf32_to_cpu(sym->st_name); 333 sym->st_value = elf32_to_cpu(sym->st_value); 334 sym->st_size = elf32_to_cpu(sym->st_size); 335 sym->st_shndx = elf16_to_cpu(sym->st_shndx); 336 } 337 } 338} 339 340 341static void read_relocs(FILE *fp) 342{ 343 int i,j; 344 for (i = 0; i < ehdr.e_shnum; i++) { 345 struct section *sec = &secs[i]; 346 if (sec->shdr.sh_type != SHT_REL) { 347 continue; 348 } 349 sec->reltab = malloc(sec->shdr.sh_size); 350 if (!sec->reltab) { 351 die("malloc of %d bytes for relocs failed\n", 352 sec->shdr.sh_size); 353 } 354 if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { 355 die("Seek to %d failed: %s\n", 356 sec->shdr.sh_offset, strerror(errno)); 357 } 358 if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) 359 != sec->shdr.sh_size) { 360 die("Cannot read symbol table: %s\n", 361 strerror(errno)); 362 } 363 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { 364 Elf32_Rel *rel = &sec->reltab[j]; 365 rel->r_offset = elf32_to_cpu(rel->r_offset); 366 rel->r_info = elf32_to_cpu(rel->r_info); 367 } 368 } 369} 370 371 372static void print_absolute_symbols(void) 373{ 374 int i; 375 printf("Absolute symbols\n"); 376 printf(" Num: Value Size Type Bind Visibility Name\n"); 377 for (i = 0; i < ehdr.e_shnum; i++) { 378 struct section *sec = &secs[i]; 379 char *sym_strtab; 380 Elf32_Sym *sh_symtab; 381 int j; 382 383 if (sec->shdr.sh_type != SHT_SYMTAB) { 384 continue; 385 } 386 sh_symtab = sec->symtab; 387 sym_strtab = sec->link->strtab; 388 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) { 389 Elf32_Sym *sym; 390 const char *name; 391 sym = &sec->symtab[j]; 392 name = sym_name(sym_strtab, sym); 393 if (sym->st_shndx != SHN_ABS) { 394 continue; 395 } 396 printf("%5d %08x %5d %10s %10s %12s %s\n", 397 j, sym->st_value, sym->st_size, 398 sym_type(ELF32_ST_TYPE(sym->st_info)), 399 sym_bind(ELF32_ST_BIND(sym->st_info)), 400 sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)), 401 name); 402 } 403 } 404 printf("\n"); 405} 406 407static void print_absolute_relocs(void) 408{ 409 int i, printed = 0; 410 411 for (i = 0; i < ehdr.e_shnum; i++) { 412 struct section *sec = &secs[i]; 413 struct section *sec_applies, *sec_symtab; 414 char *sym_strtab; 415 Elf32_Sym *sh_symtab; 416 int j; 417 if (sec->shdr.sh_type != SHT_REL) { 418 continue; 419 } 420 sec_symtab = sec->link; 421 sec_applies = &secs[sec->shdr.sh_info]; 422 if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { 423 continue; 424 } 425 sh_symtab = sec_symtab->symtab; 426 sym_strtab = sec_symtab->link->strtab; 427 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { 428 Elf32_Rel *rel; 429 Elf32_Sym *sym; 430 const char *name; 431 rel = &sec->reltab[j]; 432 sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; 433 name = sym_name(sym_strtab, sym); 434 if (sym->st_shndx != SHN_ABS) { 435 continue; 436 } 437 438 /* Absolute symbols are not relocated if bzImage is 439 * loaded at a non-compiled address. Display a warning 440 * to user at compile time about the absolute 441 * relocations present. 442 * 443 * User need to audit the code to make sure 444 * some symbols which should have been section 445 * relative have not become absolute because of some 446 * linker optimization or wrong programming usage. 447 * 448 * Before warning check if this absolute symbol 449 * relocation is harmless. 450 */ 451 if (is_safe_abs_reloc(name)) 452 continue; 453 454 if (!printed) { 455 printf("WARNING: Absolute relocations" 456 " present\n"); 457 printf("Offset Info Type Sym.Value " 458 "Sym.Name\n"); 459 printed = 1; 460 } 461 462 printf("%08x %08x %10s %08x %s\n", 463 rel->r_offset, 464 rel->r_info, 465 rel_type(ELF32_R_TYPE(rel->r_info)), 466 sym->st_value, 467 name); 468 } 469 } 470 471 if (printed) 472 printf("\n"); 473} 474 475static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym)) 476{ 477 int i; 478 /* Walk through the relocations */ 479 for (i = 0; i < ehdr.e_shnum; i++) { 480 char *sym_strtab; 481 Elf32_Sym *sh_symtab; 482 struct section *sec_applies, *sec_symtab; 483 int j; 484 struct section *sec = &secs[i]; 485 486 if (sec->shdr.sh_type != SHT_REL) { 487 continue; 488 } 489 sec_symtab = sec->link; 490 sec_applies = &secs[sec->shdr.sh_info]; 491 if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { 492 continue; 493 } 494 sh_symtab = sec_symtab->symtab; 495 sym_strtab = sec_symtab->link->strtab; 496 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { 497 Elf32_Rel *rel; 498 Elf32_Sym *sym; 499 unsigned r_type; 500 rel = &sec->reltab[j]; 501 sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; 502 r_type = ELF32_R_TYPE(rel->r_info); 503 /* Don't visit relocations to absolute symbols */ 504 if (sym->st_shndx == SHN_ABS) { 505 continue; 506 } 507 if (r_type == R_386_NONE || r_type == R_386_PC32) { 508 /* 509 * NONE can be ignored and and PC relative 510 * relocations don't need to be adjusted. 511 */ 512 } 513 else if (r_type == R_386_32) { 514 /* Visit relocations that need to be adjusted */ 515 visit(rel, sym); 516 } 517 else { 518 die("Unsupported relocation type: %d\n", r_type); 519 } 520 } 521 } 522} 523 524static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym) 525{ 526 reloc_count += 1; 527} 528 529static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym) 530{ 531 /* Remember the address that needs to be adjusted. */ 532 relocs[reloc_idx++] = rel->r_offset; 533} 534 535static int cmp_relocs(const void *va, const void *vb) 536{ 537 const unsigned long *a, *b; 538 a = va; b = vb; 539 return (*a == *b)? 0 : (*a > *b)? 1 : -1; 540} 541 542static void emit_relocs(int as_text) 543{ 544 int i; 545 /* Count how many relocations I have and allocate space for them. */ 546 reloc_count = 0; 547 walk_relocs(count_reloc); 548 relocs = malloc(reloc_count * sizeof(relocs[0])); 549 if (!relocs) { 550 die("malloc of %d entries for relocs failed\n", 551 reloc_count); 552 } 553 /* Collect up the relocations */ 554 reloc_idx = 0; 555 walk_relocs(collect_reloc); 556 557 /* Order the relocations for more efficient processing */ 558 qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs); 559 560 /* Print the relocations */ 561 if (as_text) { 562 /* Print the relocations in a form suitable that 563 * gas will like. 564 */ 565 printf(".section \".data.reloc\",\"a\"\n"); 566 printf(".balign 4\n"); 567 for (i = 0; i < reloc_count; i++) { 568 printf("\t .long 0x%08lx\n", relocs[i]); 569 } 570 printf("\n"); 571 } 572 else { 573 unsigned char buf[4]; 574 buf[0] = buf[1] = buf[2] = buf[3] = 0; 575 /* Print a stop */ 576 printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]); 577 /* Now print each relocation */ 578 for (i = 0; i < reloc_count; i++) { 579 buf[0] = (relocs[i] >> 0) & 0xff; 580 buf[1] = (relocs[i] >> 8) & 0xff; 581 buf[2] = (relocs[i] >> 16) & 0xff; 582 buf[3] = (relocs[i] >> 24) & 0xff; 583 printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]); 584 } 585 } 586} 587 588static void usage(void) 589{ 590 die("relocs [--abs-syms |--abs-relocs | --text] vmlinux\n"); 591} 592 593int main(int argc, char **argv) 594{ 595 int show_absolute_syms, show_absolute_relocs; 596 int as_text; 597 const char *fname; 598 FILE *fp; 599 int i; 600 601 show_absolute_syms = 0; 602 show_absolute_relocs = 0; 603 as_text = 0; 604 fname = NULL; 605 for (i = 1; i < argc; i++) { 606 char *arg = argv[i]; 607 if (*arg == '-') { 608 if (strcmp(argv[1], "--abs-syms") == 0) { 609 show_absolute_syms = 1; 610 continue; 611 } 612 613 if (strcmp(argv[1], "--abs-relocs") == 0) { 614 show_absolute_relocs = 1; 615 continue; 616 } 617 else if (strcmp(argv[1], "--text") == 0) { 618 as_text = 1; 619 continue; 620 } 621 } 622 else if (!fname) { 623 fname = arg; 624 continue; 625 } 626 usage(); 627 } 628 if (!fname) { 629 usage(); 630 } 631 fp = fopen(fname, "r"); 632 if (!fp) { 633 die("Cannot open %s: %s\n", 634 fname, strerror(errno)); 635 } 636 read_ehdr(fp); 637 read_shdrs(fp); 638 read_strtabs(fp); 639 read_symtabs(fp); 640 read_relocs(fp); 641 if (show_absolute_syms) { 642 print_absolute_symbols(); 643 return 0; 644 } 645 if (show_absolute_relocs) { 646 print_absolute_relocs(); 647 return 0; 648 } 649 emit_relocs(as_text); 650 return 0; 651}