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