scc

A fork of https://git.simple-cc.org/scc/ for Qute

git clone https://git.8pit.net/scc.git

  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>
  9
 10#include <scc/ar.h>
 11#include <scc/arg.h>
 12#include <scc/scc.h>
 13#include <scc/mach.h>
 14
 15#include "objdump.h"
 16
 17struct binops {
 18	void (*dumpsyms)(Obj *);
 19	void (*dumpsecs)(Obj *);
 20	void (*dumpfhdr)(Obj *, unsigned long long *, Flags *);
 21	int (*hasrelloc)(Obj *, Section *);
 22};
 23
 24int tflag, fflag, hflag, pflag, aflag, rflag, sflag;
 25char *argv0;
 26
 27static int status, nsecs;
 28static char *filename, *membname, **secs;
 29
 30static 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};
 44
 45void
 46error(char *fmt, ...)
 47{
 48	va_list va;
 49
 50	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);
 57
 58	status = EXIT_FAILURE;
 59}
 60
 61void
 62setflag(Flags *f, int cond, int flag)
 63{
 64	if (cond)
 65		f->flags |= 1 << flag;
 66}
 67
 68void
 69printflags(Flags *f)
 70{
 71	int i, first;
 72	unsigned long flags = f->flags;
 73
 74	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	}
 84
 85	putchar('\n');
 86}
 87
 88static void
 89dumpfhdr(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	};
104
105	printf("architecture: %s, flags: 0x%08x\n",
106	       strchr(fmt, '-') + 1,
107	       obj->type);
108
109	f.flags = 0;
110
111	(*op->dumpfhdr)(obj, &start, &f);
112	printflags(&f);
113	printf("start address 0x%08llx\n", start);
114}
115
116static int
117logb2(unsigned val)
118{
119	int n;
120
121	if (val == 0)
122		return 0;
123
124	for (n = 0; (val & 1) == 0; n++)
125		val >>= 1;
126	return n;
127}
128
129int
130selected(char *secname)
131{
132	int i;
133
134	if (nsecs == 0)
135		return 1;
136
137	for (i = 0; i < nsecs; i++) {
138		if (strcmp(secname, secs[i]) == 0)
139			return 1;
140	}
141
142	return 0;
143}
144
145static void
146dumpscns(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	};
164
165	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;
170
171		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));
179
180		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	}
194
195	if (!pflag)
196		return;
197	(*op->dumpsecs)(obj);
198}
199
200static void
201dumpdata(Obj *obj, FILE *fp)
202{
203	int i, j, c;
204	char buf[19];
205	Section sec;
206	unsigned long long n;
207
208	buf[0] = '|';
209	buf[17] = '|';
210	buf[18] = '\0';
211
212	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;
217
218		printf("Contents of section %s\n", sec.name);
219
220		if (!objpos(obj, fp, sec.offset))
221			goto errno_error;
222
223		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				}
234
235				if (c < CHAR_MAX && c > 0 && isprint(c))
236					buf[j] = c;
237
238				printf("%02x ", (unsigned) c & 0xFF);
239			}
240
241			for ( ; j < 16; j++)
242				fputs("   ", stdout);
243			puts(buf);
244		}
245
246next_section:
247		continue;
248
249errno_error:
250		error("section %s: %s", sec.name, strerror(errno));
251	}
252}
253
254
255static void
256dumpobj(FILE *fp, int type, char *fmt)
257{
258	int id;
259	Obj *obj;
260
261	printf("\n%s", filename);
262	if (membname)
263		printf("(%s)", membname);
264	printf(":\tfile format %s\n", fmt);
265
266	if ((obj = newobj(type)) == NULL) {
267		error("failed object allocation");
268		return;
269	}
270
271	if (readobj(obj, fp) < 0) {
272		error("object file corrupted");
273		goto err;
274	}
275
276	id = objfmt(obj);
277	if (id >= NFORMATS) {
278		error("unknown symbol binary format");
279		return;
280	}
281	op = &ops[id];
282
283	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);
291
292err:
293	delobj(obj);
294}
295
296static void
297dumprights(unsigned r)
298{
299	putchar((r & 4) ? 'r' : '-');
300	putchar((r & 2) ? 'w' : '-');
301	putchar((r & 1) ? 'x' : '-');
302}
303
304static void
305dumpar(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;
312
313	printf("%s:     file format %s\n", fname, fmt);
314
315	mode = strtol(hdr->ar_mode, NULL, 8);
316	dumprights((mode >> 6) & 7);
317	dumprights((mode >> 3) & 7);
318	dumprights(mode & 7);
319
320	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}
329
330static void
331dumplib(FILE *fp)
332{
333	int t;
334	char *fmt;
335	long off, cur;
336	struct ar_hdr hdr;
337	char memb[SARNAM+1];
338
339	for (;;) {
340		cur = ftell(fp);
341
342		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}
364
365static void
366objdump(char *fname)
367{
368	int t;
369	char *fmt;
370	FILE *fp;
371
372	membname = NULL;
373	filename = fname;
374	if ((fp = fopen(fname, "rb")) == NULL) {
375		error(strerror(errno));
376		return;
377	}
378
379	if ((t = objprobe(fp, &fmt)) != -1)
380		dumpobj(fp, t, fmt);
381	else if (archive(fp))
382		dumplib(fp);
383	else
384		error("bad format");
385			
386	fclose(fp);
387}
388
389static void
390usage(void)
391{
392	fputs("usage: scc-objdump [-afhpts][-j section] file...\n", stderr);
393	exit(EXIT_FAILURE);
394}
395
396int
397main(int argc, char *argv[])
398{
399	char *s;
400
401	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	} ARGEND
428
429	if (!aflag && !fflag && !hflag
430	&& !tflag && !sflag) {
431		fputs("scc-objdump: At least one of [afhts] flags must be used\n",
432		      stderr);
433		usage();
434	}
435
436	if (argc == 0) {
437		objdump("a.out");
438	} else {
439		for ( ; *argv; ++argv)
440			objdump(*argv);
441	}
442
443	if (fflush(stdout)) {
444		fprintf(stderr,
445		        "size: error writing in output:%s\n",
446		        strerror(errno));
447		status = 1;
448	}
449
450	return status;
451}