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