shithub: scc

ref: 16ac0a93b39ea62401f2d2edb5f203ffe2e746b0
dir: /nm/myro.c/

View raw version
static char sccsid[] = "@(#) ./nm/myro.c";

#include <ctype.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../inc/scc.h"
#include "../inc/myro.h"
#include "nm.h"

static char *strings;

static int
typeof(struct myrosym *sym)
{
	int t, flags = sym->flags;

	switch (sym->section) {
	case MYRO_TEXT:
		t = 't';
		break;
	case MYRO_DATA:
		t = 'd';
		break;
	case MYRO_BSS:
		t = (flags & MYROSYM_COMMON) ? 'c' : 'b';
		break;
	case MYRO_ABS:
		t = 'a';
		break;
	default:
		t = (flags & MYROSYM_UNDEF) ? 'u' : '?';
		break;
	}
	if (flags & MYROSYM_ABS)
		t = 'a';
	if (flags & MYROSYM_EXTERN)
		t = tolower(t);
	return t;
}

static int
cmp(const void *p1, const void *p2)
{
	const struct myrosym *s1 = p1, *s2 = p2;

	if (vflag)
		return s1->offset - s2->offset;
	else
		return strcmp(strings + s1->name, strings + s2->name);
}

void
nm(char *fname, char *member, FILE *fp)
{
	struct myrohdr hdr;
	struct myrosym *syms = NULL, *sym;
	struct symbol symbol;
	size_t n, i;
	long off;

	strings = NULL;
	if (rdmyrohdr(fp, &hdr) < 0) {
		fprintf(stderr, "nm: %s: incorrect header\n", member);
		return;
	}

	n = hdr.symsize / MYROSYM_SIZ;
	if (n == 0) {
		fprintf(stderr, "nm: %s: no name list\n", member);
		return;
	}
	if (n > SIZE_MAX / sizeof(struct myrosym) ||
	    hdr.symsize / MYROSYM_SIZ > SIZE_MAX ||
	    hdr.strsize > SIZE_MAX) {
		goto offset_overflow;
	}

	syms = xmalloc(n * sizeof(struct myrosym));
	strings = xmalloc(hdr.strsize);
	fread(strings, hdr.strsize, 1, fp);
	if (feof(fp))
		goto free_arrays;
	if ((off = ftell(fp)) < 0)
		return;
	if (off > LONG_MAX - hdr.secsize)
		goto offset_overflow;
	off += hdr.secsize;

	if (fseek(fp, off, SEEK_SET) < 0)
		goto free_arrays;

	for (i = 0; i < n; ++i) {
		if (rdmyrosym(fp, &syms[i]) < 0)
			goto symbol_error;
		if (syms[i].name >= hdr.strsize)
			goto offset_overflow;
	}
	qsort(syms, n, sizeof(*syms), cmp);
	for (i = 0; i < n; ++i) {
		sym = &syms[i];
		symbol.name = strings + sym->name;
		symbol.type = typeof(sym);
		symbol.off = sym->offset;
		symbol.size = sym->len;
		print(fname, member, &symbol);
	}

free_arrays:
	free(syms);
	free(strings);
	return;

symbol_error:
	fprintf(stderr, "nm: %s: error reading symbols\n", fname);
	goto free_arrays;

offset_overflow:
	fprintf(stderr, "nm: %s: overflow in headers of archive\n",
		fname);
	goto free_arrays;
}

int
object(char *fname, FILE *fp)
{
	char magic[MYROMAGIC_SIZ];
	fpos_t pos;

	fgetpos(fp, &pos);
	fread(magic, sizeof(magic), 1, fp);
	fsetpos(fp, &pos);

	if (!ferror(fp) && !strncmp(magic, MYROMAGIC, MYROMAGIC_SIZ))
		return 1;
	return 0;
}