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