00001 #include "system.h"
00002
00003 #ifdef BUILTIN_ELF
00004 #include "file.h"
00005 #include "readelf.h"
00006 #include "debug.h"
00007
00008 FILE_RCSID("@(#)Id: readelf.c,v 1.22 2002/07/03 18:26:38 christos Exp ")
00009
00010
00011
00012
00013 static uint16_t
00014 getu16(const fmagic fm, uint16_t value)
00015
00016 {
00017 union {
00018 uint16_t ui;
00019 char c[2];
00020 } retval, tmpval;
00021
00022 if (fm->swap) {
00023 tmpval.ui = value;
00024
00025 retval.c[0] = tmpval.c[1];
00026 retval.c[1] = tmpval.c[0];
00027
00028 return retval.ui;
00029 } else
00030 return value;
00031 }
00032
00033 static uint32_t
00034 getu32(const fmagic fm, uint32_t value)
00035
00036 {
00037 union {
00038 uint32_t ui;
00039 char c[4];
00040 } retval, tmpval;
00041
00042 if (fm->swap) {
00043 tmpval.ui = value;
00044
00045 retval.c[0] = tmpval.c[3];
00046 retval.c[1] = tmpval.c[2];
00047 retval.c[2] = tmpval.c[1];
00048 retval.c[3] = tmpval.c[0];
00049
00050 return retval.ui;
00051 } else
00052 return value;
00053 }
00054
00055 static uint64_t
00056 getu64(const fmagic fm, uint64_t value)
00057
00058 {
00059 union {
00060 uint64_t ui;
00061 char c[8];
00062 } retval, tmpval;
00063
00064 if (fm->swap) {
00065 tmpval.ui = value;
00066
00067 retval.c[0] = tmpval.c[7];
00068 retval.c[1] = tmpval.c[6];
00069 retval.c[2] = tmpval.c[5];
00070 retval.c[3] = tmpval.c[4];
00071 retval.c[4] = tmpval.c[3];
00072 retval.c[5] = tmpval.c[2];
00073 retval.c[6] = tmpval.c[1];
00074 retval.c[7] = tmpval.c[0];
00075
00076 return retval.ui;
00077 } else
00078 return value;
00079 }
00080
00081
00082 #define sh_addr (fm->cls == ELFCLASS32 \
00083 ? (void *) &sh32 \
00084 : (void *) &sh64)
00085 #define sh_size (fm->cls == ELFCLASS32 \
00086 ? sizeof sh32 \
00087 : sizeof sh64)
00088 #define shs_type (fm->cls == ELFCLASS32 \
00089 ? getu32(fm, sh32.sh_type) \
00090 : getu32(fm, sh64.sh_type))
00091
00092 #define ph_addr (fm->cls == ELFCLASS32 \
00093 ? (void *) &ph32 \
00094 : (void *) &ph64)
00095 #define ph_size (fm->cls == ELFCLASS32 \
00096 ? sizeof ph32 \
00097 : sizeof ph64)
00098 #define ph_type (fm->cls == ELFCLASS32 \
00099 ? getu32(fm, ph32.p_type) \
00100 : getu32(fm, ph64.p_type))
00101 #define ph_offset (fm->cls == ELFCLASS32 \
00102 ? getu32(fm, ph32.p_offset) \
00103 : getu64(fm, ph64.p_offset))
00104 #define ph_align (fm->cls == ELFCLASS32 \
00105 ? (ph32.p_align ? getu32(fm, ph32.p_align) : 4) \
00106 : (ph64.p_align ? getu64(fm, ph64.p_align) : 4))
00107 #define ph_filesz (fm->cls == ELFCLASS32 \
00108 ? getu32(fm, ph32.p_filesz) \
00109 : getu64(fm, ph64.p_filesz))
00110
00111 #define nh_type (fm->cls == ELFCLASS32 \
00112 ? getu32(fm, nh32->n_type) \
00113 : getu32(fm, nh64->n_type))
00114 #define nh_namesz (fm->cls == ELFCLASS32 \
00115 ? getu32(fm, nh32->n_namesz) \
00116 : getu32(fm, nh64->n_namesz))
00117 #define nh_descsz (fm->cls == ELFCLASS32 \
00118 ? getu32(fm, nh32->n_descsz) \
00119 : getu32(fm, nh64->n_descsz))
00120 #define prpsoffsets(i) (fm->cls == ELFCLASS32 \
00121 ? prpsoffsets32[i] \
00122 : prpsoffsets64[i])
00123
00124
00125 static void
00126 doshn(fmagic fm, off_t off, int num, size_t size)
00127
00128
00129 {
00130 Elf32_Shdr sh32;
00131 Elf64_Shdr sh64;
00132
00133 if (size != sh_size) {
00134 error(EXIT_FAILURE, 0, "corrupted program header size.\n");
00135
00136 }
00137
00138 if (lseek(fm->fd, off, SEEK_SET) == -1) {
00139 error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
00140
00141 }
00142
00143 for ( ; num; num--) {
00144 if (read(fm->fd, sh_addr, size) == -1) {
00145 error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno));
00146
00147 }
00148 if (shs_type == SHT_SYMTAB ) {
00149 file_printf(fm, ", not stripped");
00150 return;
00151 }
00152 }
00153 file_printf(fm, ", stripped");
00154 }
00155
00156
00157
00158
00159
00160
00161
00162
00163 static void
00164 dophn_exec(fmagic fm, off_t off, int num, size_t size)
00165
00166
00167 {
00168 Elf32_Phdr ph32;
00169 Elf32_Nhdr *nh32 = NULL;
00170 Elf64_Phdr ph64;
00171 Elf64_Nhdr *nh64 = NULL;
00172 char *linking_style = "statically";
00173 char *shared_libraries = "";
00174 char nbuf[BUFSIZ];
00175 int nb;
00176 size_t nbufsize, offset, end, noff, doff;
00177 size_t align = (fm->cls == ELFCLASS32 ? 4 : 8);
00178 #define ALIGNED_LEN(len) (((len) + align - 1) & ~(align - 1))
00179 int printed;
00180
00181 if (size != ph_size) {
00182 error(EXIT_FAILURE, 0, "corrupted program header size.\n");
00183
00184 }
00185
00186 if (lseek(fm->fd, off, SEEK_SET) == -1) {
00187 error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
00188
00189 }
00190
00191 for ( ; num; num--) {
00192
00193 nb = read(fm->fd, ph_addr, size);
00194 if (nb == -1) {
00195 error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno));
00196
00197 }
00198
00199
00200 #if !defined(__i386__)
00201 if (ph_type == PT_NOTE)
00202 break;
00203 #endif
00204
00205 switch (ph_type) {
00206 case PT_DYNAMIC:
00207 linking_style = "dynamically";
00208 break;
00209 case PT_INTERP:
00210 shared_libraries = " (uses shared libs)";
00211 break;
00212 case PT_NOTE:
00213
00214
00215
00216
00217 if (lseek(fm->fd, (off_t) ph_offset, SEEK_SET) == -1) {
00218 error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
00219
00220 }
00221
00222
00223 nbufsize = (ph_filesz < sizeof(nbuf)
00224 ? ph_filesz : sizeof(nbuf));
00225 nb = read(fm->fd, nbuf, nbufsize);
00226 if (nb == -1) {
00227 error(EXIT_FAILURE, 0, ": " "read failed (%s).\n",
00228 strerror(errno));
00229
00230 }
00231 offset = 0;
00232 printed = 0;
00233 for (;;) {
00234 end = offset + 12;
00235 if (end >= nb)
00236 break;
00237
00238 if (fm->cls == ELFCLASS32)
00239 nh32 = (Elf32_Nhdr *)&nbuf[offset];
00240 else
00241 nh64 = (Elf64_Nhdr *)&nbuf[offset];
00242
00243 offset = end;
00244
00245
00246 if (nh_namesz <= 0 || nh_descsz <= 0)
00247 break;
00248 if (nh_namesz > 16 || nh_descsz > 16)
00249 break;
00250
00251 end = offset + ALIGNED_LEN (nh_namesz)
00252 + ALIGNED_LEN (nh_descsz);
00253 if (end > nb)
00254 break;
00255
00256 noff = offset;
00257 doff = ALIGNED_LEN(offset + nh_namesz);
00258 offset = end;
00259
00260 if (printed)
00261 continue;
00262
00263 if (nh_namesz == 4 &&
00264 strcmp(&nbuf[noff], "GNU") == 0 &&
00265 nh_type == NT_GNU_VERSION &&
00266 nh_descsz == 16) {
00267 uint32_t *desc =
00268 (uint32_t *)&nbuf[doff];
00269
00270 if (!printed)
00271 file_printf(fm, ", for GNU/");
00272 switch (getu32(fm, desc[0])) {
00273 case GNU_OS_LINUX:
00274 file_printf(fm, "Linux");
00275 break;
00276 case GNU_OS_HURD:
00277 file_printf(fm, "Hurd");
00278 break;
00279 case GNU_OS_SOLARIS:
00280 file_printf(fm, "Solaris");
00281 break;
00282 default:
00283 file_printf(fm, "<unknown>");
00284 break;
00285 }
00286 file_printf(fm, " %d.%d.%d",
00287 getu32(fm, desc[1]),
00288 getu32(fm, desc[2]),
00289 getu32(fm, desc[3]));
00290 printed = 1;
00291 }
00292
00293 if (nh_namesz == 7 &&
00294 strcmp(&nbuf[noff], "NetBSD") == 0 &&
00295 nh_type == NT_NETBSD_VERSION &&
00296 nh_descsz == 4) {
00297 file_printf(fm, ", for NetBSD");
00298
00299
00300
00301
00302 printed = 1;
00303 }
00304
00305 if (nh_namesz == 8 &&
00306 strcmp(&nbuf[noff], "FreeBSD") == 0 &&
00307 nh_type == NT_FREEBSD_VERSION &&
00308 nh_descsz == 4) {
00309 uint32_t desc = getu32(fm,
00310 *(uint32_t *)&nbuf[doff]);
00311 file_printf(fm, ", for FreeBSD");
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 file_printf(fm, " %d.%d", desc / 100000,
00323 desc / 10000 % 10);
00324 if (desc / 1000 % 10 > 0)
00325 file_printf(fm, ".%d",
00326 desc / 1000 % 10);
00327 printed = 1;
00328 }
00329
00330 if (nh_namesz == 8 &&
00331 strcmp(&nbuf[noff], "OpenBSD") == 0 &&
00332 nh_type == NT_OPENBSD_VERSION &&
00333 nh_descsz == 4) {
00334 file_printf(fm, ", for OpenBSD");
00335
00336 printed = 1;
00337 }
00338 }
00339 if ((lseek(fm->fd, ph_offset + offset, SEEK_SET)) == -1) {
00340 error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
00341
00342 }
00343 break;
00344 }
00345 }
00346 file_printf(fm, ", %s linked%s", linking_style, shared_libraries);
00347 }
00348
00349
00350 #ifdef ELFCORE
00351
00352 static size_t prpsoffsets32[] = {
00353 8,
00354 28,
00355 32,
00356 84
00357 };
00358
00359
00360 static size_t prpsoffsets64[] = {
00361 120
00362 };
00363
00364 #define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
00365 #define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
00366
00367 #define NOFFSETS (fm->cls == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390 #define OS_STYLE_SVR4 0
00391 #define OS_STYLE_FREEBSD 1
00392 #define OS_STYLE_NETBSD 2
00393
00394
00395 static const char *os_style_names[] = {
00396 "SVR4",
00397 "FreeBSD",
00398 "NetBSD",
00399 };
00400
00401
00402 static void
00403 dophn_core(fmagic fm, off_t off, int num, size_t size)
00404
00405
00406 {
00407 Elf32_Phdr ph32;
00408 Elf32_Nhdr *nh32 = NULL;
00409 Elf64_Phdr ph64;
00410 Elf64_Nhdr *nh64 = NULL;
00411 size_t offset, nameoffset, noffset, reloffset;
00412 unsigned char c;
00413 int i, j;
00414 char nbuf[BUFSIZ];
00415 int nb;
00416 int os_style = -1;
00417
00418 if (size != ph_size) {
00419 error(EXIT_FAILURE, 0, "corrupted program header size.\n");
00420
00421 }
00422
00423
00424
00425
00426 for ( ; num; num--) {
00427 if (lseek(fm->fd, off, SEEK_SET) == -1) {
00428 error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
00429
00430 }
00431 if (read(fm->fd, ph_addr, size) == -1) {
00432 error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno));
00433
00434 }
00435 off += size;
00436 if (ph_type != PT_NOTE)
00437 continue;
00438
00439
00440
00441
00442
00443 if (lseek(fm->fd, (off_t) ph_offset, SEEK_SET) == -1) {
00444 error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
00445
00446 }
00447 nb = read(fm->fd, nbuf, BUFSIZ);
00448 if (nb == -1) {
00449 error(EXIT_FAILURE, 0, ": " "read failed (%s).\n", strerror(errno));
00450
00451 }
00452 offset = 0;
00453 for (;;) {
00454 if (offset >= nb)
00455 break;
00456 if (fm->cls == ELFCLASS32)
00457 nh32 = (Elf32_Nhdr *)&nbuf[offset];
00458 else
00459 nh64 = (Elf64_Nhdr *)&nbuf[offset];
00460 offset += 12;
00461
00462
00463
00464
00465
00466 if (offset + nh_namesz >= nb) {
00467
00468
00469
00470 break;
00471 }
00472
00473 nameoffset = offset;
00474 offset += nh_namesz;
00475 offset = ((offset + 3)/4)*4;
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491 if (os_style == -1) {
00492 if ((nh_namesz == 4 &&
00493 strncmp(&nbuf[nameoffset],
00494 "CORE", 4) == 0) ||
00495 (nh_namesz == 5 &&
00496 strcmp(&nbuf[nameoffset],
00497 "CORE") == 0)) {
00498 os_style = OS_STYLE_SVR4;
00499 } else
00500 if ((nh_namesz == 8 &&
00501 strcmp(&nbuf[nameoffset],
00502 "FreeBSD") == 0)) {
00503 os_style = OS_STYLE_FREEBSD;
00504 } else
00505 if ((nh_namesz >= 11 &&
00506 strncmp(&nbuf[nameoffset],
00507 "NetBSD-CORE", 11) == 0)) {
00508 os_style = OS_STYLE_NETBSD;
00509 } else
00510 continue;
00511 file_printf(fm, ", %s-style", os_style_names[os_style]);
00512 }
00513
00514 if (os_style == OS_STYLE_NETBSD &&
00515 nh_type == NT_NETBSD_CORE_PROCINFO) {
00516 uint32_t signo;
00517
00518
00519
00520
00521
00522
00523 file_printf(fm, ", from '%.31s'", &nbuf[offset + 0x7c]);
00524
00525
00526
00527
00528
00529 memcpy(&signo, &nbuf[offset + 0x08],
00530 sizeof(signo));
00531 file_printf(fm, " (signal %u)", getu32(fm, signo));
00532 } else
00533 if (os_style != OS_STYLE_NETBSD &&
00534 nh_type == NT_PRPSINFO) {
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545 for (i = 0; i < NOFFSETS; i++) {
00546 reloffset = prpsoffsets(i);
00547 noffset = offset + reloffset;
00548 for (j = 0; j < 16;
00549 j++, noffset++, reloffset++) {
00550
00551
00552
00553
00554
00555 if (noffset >= nb)
00556 goto tryanother;
00557
00558
00559
00560
00561
00562
00563
00564 if (reloffset >= nh_descsz)
00565 goto tryanother;
00566
00567 c = nbuf[noffset];
00568 if (c == '\0') {
00569
00570
00571
00572
00573
00574
00575
00576 if (j == 0)
00577 goto tryanother;
00578 else
00579 break;
00580 } else {
00581
00582
00583
00584
00585
00586 #define isquote(c) (strchr("'\"`", (c)) != NULL)
00587 if (!isprint(c) ||
00588 isquote(c))
00589 goto tryanother;
00590 }
00591 }
00592
00593
00594
00595
00596 file_printf(fm, ", from '%.16s'",
00597 &nbuf[offset + prpsoffsets(i)]);
00598 break;
00599
00600 tryanother:
00601 ;
00602 }
00603 break;
00604 }
00605 offset += nh_descsz;
00606 offset = ((offset + 3)/4)*4;
00607 }
00608 }
00609 }
00610
00611 #endif
00612
00613
00614 void
00615 fmagicE(fmagic fm)
00616 {
00617
00618 union {
00619 int32_t l;
00620 char c[sizeof (int32_t)];
00621 } u;
00622
00623
00624
00625
00626
00627 if((lseek(fm->fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
00628 fm->fd = file_pipe2file(fm->fd, fm->buf, fm->nb);
00629
00630
00631
00632
00633
00634
00635
00636 if (fm->buf[EI_MAG0] != ELFMAG0
00637 || (fm->buf[EI_MAG1] != ELFMAG1 && fm->buf[EI_MAG1] != OLFMAG1)
00638 || fm->buf[EI_MAG2] != ELFMAG2 || fm->buf[EI_MAG3] != ELFMAG3)
00639 return;
00640
00641 fm->cls = fm->buf[EI_CLASS];
00642
00643 if (fm->cls == ELFCLASS32) {
00644 Elf32_Ehdr elfhdr;
00645 if (fm->nb <= sizeof (elfhdr))
00646 return;
00647
00648
00649 u.l = 1;
00650 (void) memcpy(&elfhdr, fm->buf, sizeof elfhdr);
00651
00652 fm->swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
00653
00654
00655 if (getu16(fm, elfhdr.e_type) == ET_CORE)
00656 #ifdef ELFCORE
00657 dophn_core(fm,
00658 getu32(fm, elfhdr.e_phoff),
00659 getu16(fm, elfhdr.e_phnum),
00660 getu16(fm, elfhdr.e_phentsize));
00661 #else
00662 ;
00663 #endif
00664 else {
00665 if (getu16(fm, elfhdr.e_type) == ET_EXEC) {
00666 dophn_exec(fm,
00667 getu32(fm, elfhdr.e_phoff),
00668 getu16(fm, elfhdr.e_phnum),
00669 getu16(fm, elfhdr.e_phentsize));
00670 }
00671 doshn(fm,
00672 getu32(fm, elfhdr.e_shoff),
00673 getu16(fm, elfhdr.e_shnum),
00674 getu16(fm, elfhdr.e_shentsize));
00675 }
00676 return;
00677 }
00678
00679 if (fm->cls == ELFCLASS64) {
00680 Elf64_Ehdr elfhdr;
00681 if (fm->nb <= sizeof (elfhdr))
00682 return;
00683
00684 u.l = 1;
00685 (void) memcpy(&elfhdr, fm->buf, sizeof elfhdr);
00686
00687 fm->swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
00688
00689
00690 if (getu16(fm, elfhdr.e_type) == ET_CORE)
00691 #ifdef ELFCORE
00692 dophn_core(fm,
00693 #ifdef USE_ARRAY_FOR_64BIT_TYPES
00694 getu32(fm, elfhdr.e_phoff[1]),
00695 #else
00696 getu64(fm, elfhdr.e_phoff),
00697 #endif
00698 getu16(fm, elfhdr.e_phnum),
00699 getu16(fm, elfhdr.e_phentsize));
00700 #else
00701 ;
00702 #endif
00703 else
00704 {
00705 if (getu16(fm, elfhdr.e_type) == ET_EXEC) {
00706 dophn_exec(fm,
00707 #ifdef USE_ARRAY_FOR_64BIT_TYPES
00708 getu32(fm, elfhdr.e_phoff[1]),
00709 #else
00710 getu64(fm, elfhdr.e_phoff),
00711 #endif
00712 getu16(fm, elfhdr.e_phnum),
00713 getu16(fm, elfhdr.e_phentsize));
00714 }
00715 doshn(fm,
00716 #ifdef USE_ARRAY_FOR_64BIT_TYPES
00717 getu32(fm, elfhdr.e_shoff[1]),
00718 #else
00719 getu64(fm, elfhdr.e_shoff),
00720 #endif
00721 getu16(fm, elfhdr.e_shnum),
00722 getu16(fm, elfhdr.e_shentsize));
00723 }
00724 return;
00725 }
00726 }
00727
00728 #endif