1#include <ctype.h>2#include <errno.h>3#include <limits.h>4#include <stdarg.h>5#include <stdio.h>6#include <stdlib.h>7#include <string.h>8#include <time.h>910#include <scc/ar.h>11#include <scc/arg.h>12#include <scc/scc.h>13#include <scc/mach.h>1415#include "objdump.h"1617struct binops {18 void (*dumpsyms)(Obj *);19 void (*dumpsecs)(Obj *);20 void (*dumpfhdr)(Obj *, unsigned long long *, Flags *);21 int (*hasrelloc)(Obj *, Section *);22};2324int tflag, fflag, hflag, pflag, aflag, rflag, sflag;25char *argv0;2627static int status, nsecs;28static char *filename, *membname, **secs;2930static struct binops *op, ops[NFORMATS] = {31 [COFF32] = {32 .dumpsyms = coff32syms,33 .dumpsecs = coff32scns,34 .dumpfhdr = coff32fhdr,35 .hasrelloc = coff32hasrelloc,36 },37 [ELF] = {38 .dumpsyms = elfsyms,39 .dumpsecs = elfscns,40 .dumpfhdr = elffhdr,41 .hasrelloc = elfhasrelloc,42 },43};4445void46error(char *fmt, ...)47{48 va_list va;4950 va_start(va, fmt);51 fprintf(stderr, "scc-objdump: %s: ", filename);52 if (membname)53 fprintf(stderr, "%s: ", membname);54 vfprintf(stderr, fmt, va);55 putc('\n', stderr);56 va_end(va);5758 status = EXIT_FAILURE;59}6061void62setflag(Flags *f, int cond, int flag)63{64 if (cond)65 f->flags |= 1 << flag;66}6768void69printflags(Flags *f)70{71 int i, first;72 unsigned long flags = f->flags;7374 first = 1;75 for (i = 0; i < f->nr; i++) {76 if (flags & 1) {77 if (!first)78 fputs(", ", stdout);79 first = 0;80 fputs(f->text[i], stdout);81 }82 flags >>= 1;83 }8485 putchar('\n');86}8788static void89dumpfhdr(Obj *obj, char *fmt)90{91 unsigned long long start = 0;92 static Flags f = {93 .nr = NR_FILE_FLAGS,94 .text = {95 [HAS_RELOC] = "HAS_RELOC",96 [EXEC_P] = "EXEC_P",97 [HAS_LINENO] = "HAS_LINENO",98 [HAS_DEBUG] = "HAS_DEBUG",99 [HAS_SYMS] = "HAS_SYMS",100 [HAS_LOCALS] = "HAS_LOCALS",101 [DYNAMIC] = "DYNAMIC",102 }103 };104105 printf("architecture: %s, flags: 0x%08x\n",106 strchr(fmt, '-') + 1,107 obj->type);108109 f.flags = 0;110111 (*op->dumpfhdr)(obj, &start, &f);112 printflags(&f);113 printf("start address 0x%08llx\n", start);114}115116static int117logb2(unsigned val)118{119 int n;120121 if (val == 0)122 return 0;123124 for (n = 0; (val & 1) == 0; n++)125 val >>= 1;126 return n;127}128129int130selected(char *secname)131{132 int i;133134 if (nsecs == 0)135 return 1;136137 for (i = 0; i < nsecs; i++) {138 if (strcmp(secname, secs[i]) == 0)139 return 1;140 }141142 return 0;143}144145static void146dumpscns(Obj *obj)147{148 int i, debug;149 unsigned flags;150 Section sec;151 static Flags f = {152 .nr = NR_SEC_FLAGS,153 .text = {154 [SEC_HAS_CONTENTS] = "CONTENTS",155 [SEC_ALLOC] = "ALLOC",156 [SEC_LOAD] = "LOAD",157 [SEC_RELOC] = "RELOC",158 [SEC_READONLY] = "READONLY",159 [SEC_CODE] = "CODE",160 [SEC_DATA] = "DATA",161 [SEC_DEBUGGING] = "DEBUGGING",162 }163 };164165 puts("Sections:");166 puts("Idx Name Size VMA LMA File off Algn");167 for (i = 0; getsec(obj, &i, &sec); i++) {168 if (!selected(sec.name))169 continue;170171 printf("%3d %-13s %08llx %08llx %08llx %08lx 2**%d\n",172 sec.index,173 sec.name,174 sec.size,175 sec.base,176 sec.load,177 sec.offset,178 logb2(sec.align));179180 f.flags = 0;181 flags = sec.flags;182 debug = sec.type == 'N';183 setflag(&f, flags & SALLOC, SEC_ALLOC);184 setflag(&f, flags & SLOAD, SEC_LOAD);185 setflag(&f, (*op->hasrelloc)(obj, &sec), SEC_RELOC);186 setflag(&f, (flags & SWRITE) == 0 && !debug, SEC_READONLY);187 setflag(&f, flags & SEXEC, SEC_CODE);188 setflag(&f, (flags & (SEXEC|SLOAD)) == SLOAD, SEC_DATA);189 setflag(&f, debug, SEC_DEBUGGING);190 setflag(&f, (flags & SALLOC) && sec.size > 0, SEC_HAS_CONTENTS);191 fputs(" ", stdout);192 printflags(&f);193 }194195 if (!pflag)196 return;197 (*op->dumpsecs)(obj);198}199200static void201dumpdata(Obj *obj, FILE *fp)202{203 int i, j, c;204 char buf[19];205 Section sec;206 unsigned long long n;207208 buf[0] = '|';209 buf[17] = '|';210 buf[18] = '\0';211212 for (i = 0; getsec(obj, &i, &sec); i++) {213 if (!selected(sec.name))214 continue;215 if ((sec.flags & SALLOC) == 0 || sec.size == 0)216 continue;217218 printf("Contents of section %s\n", sec.name);219220 if (!objpos(obj, fp, sec.offset))221 goto errno_error;222223 for (n = 0; n < sec.size; ) {224 memset(buf+1, '.', 16);225 printf(" %04llx ", sec.base + n);226 for (j = 0; j < 16 && n < sec.size; j++, n++) {227 if ((c = getc(fp)) == EOF) {228 if (ferror(fp))229 goto errno_error;230 error("section %s: end of file found before end of section",231 sec.name);232 goto next_section;233 }234235 if (c < CHAR_MAX && c > 0 && isprint(c))236 buf[j] = c;237238 printf("%02x ", (unsigned) c & 0xFF);239 }240241 for ( ; j < 16; j++)242 fputs(" ", stdout);243 puts(buf);244 }245246next_section:247 continue;248249errno_error:250 error("section %s: %s", sec.name, strerror(errno));251 }252}253254255static void256dumpobj(FILE *fp, int type, char *fmt)257{258 int id;259 Obj *obj;260261 printf("\n%s", filename);262 if (membname)263 printf("(%s)", membname);264 printf(":\tfile format %s\n", fmt);265266 if ((obj = newobj(type)) == NULL) {267 error("failed object allocation");268 return;269 }270271 if (readobj(obj, fp) < 0) {272 error("object file corrupted");273 goto err;274 }275276 id = objfmt(obj);277 if (id >= NFORMATS) {278 error("unknown symbol binary format");279 return;280 }281 op = &ops[id];282283 if (fflag)284 dumpfhdr(obj, fmt);285 if (hflag)286 dumpscns(obj);287 if (sflag)288 dumpdata(obj, fp);289 if (tflag)290 (*op->dumpsyms)(obj);291292err:293 delobj(obj);294}295296static void297dumprights(unsigned r)298{299 putchar((r & 4) ? 'r' : '-');300 putchar((r & 2) ? 'w' : '-');301 putchar((r & 1) ? 'x' : '-');302}303304static void305dumpar(char *fname, struct ar_hdr *hdr, char *fmt)306{307 time_t t;308 int n;309 struct tm *tm;310 char buf[60];311 unsigned long mode;312313 printf("%s: file format %s\n", fname, fmt);314315 mode = strtol(hdr->ar_mode, NULL, 8);316 dumprights((mode >> 6) & 7);317 dumprights((mode >> 3) & 7);318 dumprights(mode & 7);319320 t = fromepoch(atoll(hdr->ar_date));321 strftime(buf, sizeof(buf), "%c", gmtime(&t));322 printf(" %d/%d %lld %s %s\n\n",323 atoi(hdr->ar_uid),324 atoi(hdr->ar_gid),325 atoll(hdr->ar_size),326 buf,327 fname);328}329330static void331dumplib(FILE *fp)332{333 int t;334 char *fmt;335 long off, cur;336 struct ar_hdr hdr;337 char memb[SARNAM+1];338339 for (;;) {340 cur = ftell(fp);341342 off = armember(fp, memb, &hdr);343 switch (off) {344 case -1:345 error("library corrupted");346 if (ferror(fp))347 error(strerror(errno));348 case 0:349 return;350 default:351 membname = memb;352 if ((t = objprobe(fp, &fmt)) != -1) {353 if (aflag)354 dumpar(memb, &hdr, fmt);355 dumpobj(fp, t, fmt);356 }357 membname = NULL;358 fseek(fp, cur, SEEK_SET);359 fseek(fp, off, SEEK_CUR);360 break;361 }362 }363}364365static void366objdump(char *fname)367{368 int t;369 char *fmt;370 FILE *fp;371372 membname = NULL;373 filename = fname;374 if ((fp = fopen(fname, "rb")) == NULL) {375 error(strerror(errno));376 return;377 }378379 if ((t = objprobe(fp, &fmt)) != -1)380 dumpobj(fp, t, fmt);381 else if (archive(fp))382 dumplib(fp);383 else384 error("bad format");385386 fclose(fp);387}388389static void390usage(void)391{392 fputs("usage: scc-objdump [-afhpts][-j section] file...\n", stderr);393 exit(EXIT_FAILURE);394}395396int397main(int argc, char *argv[])398{399 char *s;400401 ARGBEGIN {402 case 'a':403 aflag = 1;404 break;405 case 'f':406 fflag = 1;407 break;408 case 'h':409 hflag = 1;410 break;411 case 'p':412 pflag = 1;413 break;414 case 's':415 sflag = 1;416 break;417 case 't':418 tflag = 1;419 break;420 case 'j':421 s = EARGF(usage());422 secs = xrealloc(secs, (nsecs + 1) * sizeof(char *));423 secs[nsecs++] = s;424 break;425 default:426 usage();427 } ARGEND428429 if (!aflag && !fflag && !hflag430 && !tflag && !sflag) {431 fputs("scc-objdump: At least one of [afhts] flags must be used\n",432 stderr);433 usage();434 }435436 if (argc == 0) {437 objdump("a.out");438 } else {439 for ( ; *argv; ++argv)440 objdump(*argv);441 }442443 if (fflush(stdout)) {444 fprintf(stderr,445 "size: error writing in output:%s\n",446 strerror(errno));447 status = 1;448 }449450 return status;451}