shithub: scc

ref: 75f3f829eaa2e72575b9e5c802b290a17d837e54
dir: /src/cmd/addr2line.c/

View raw version
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <scc/arg.h>
#include <scc/mach.h>

static int status;
static char *filename = "a.out";
char *argv0;

static void
error(char *fmt, ...)
{
	va_list va;

	va_start(va, fmt);
	fprintf(stderr, "strip: %s: ", filename);
	vfprintf(stderr, fmt, va);
	putc('\n', stderr);
	va_end(va);

	status = EXIT_FAILURE;
}

static void
addr2line(Obj *obj, char *s)
{
	int line;
	unsigned long long addr;
	char *end;
	char fname[FILENAME_MAX];

	addr = strtoull(s, &end, 16);
	if (*end  || addr == ULONG_MAX) {
		error("invalid address: '%s'", s);
		return;
	}

	if (pc2line(obj, addr, fname, &line) < 0) {
		error("not matching line");
		return;
	}

	printf("%s:%d\n", fname, line);
}

static char *
getln(void)
{
	size_t len;
	static char buf[BUFSIZ];

	for (;;) {
		if (!fgets(buf, sizeof(buf), stdin)) {
			error(strerror(errno));
			return NULL;
		}
		if ((len = strlen(buf)) == 0)
			continue;
		if (buf[len-1] != '\n') {
			error("too long address");
			continue;
		}
		buf[len-1] = '\0';

		return buf;
	}
}

static Obj *
loadexe(char *fname)
{
	int t;
	FILE *fp;
	Obj *obj;

	if ((fp = fopen(fname, "rb")) == NULL) {
		error(strerror(errno));
		return NULL;
	}

	if ((t = objtype(fp, NULL)) < 0) {
		error("file format not recognized");
		return NULL;
	}

	if ((obj = newobj(t)) == NULL) {
		error("out of memory");
		return NULL;
	}

	if (readobj(obj, fp) < 0) {
		error("file corrupted");
		return NULL;
	}

	return obj;
}

static void
usage(void)
{
	fputs("usage: addr2line [-e file] [addr ...]\n", stderr);
	exit(EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
	char *ln;
	Obj *obj;

	ARGBEGIN {
	case 'e':
		filename = EARGF(usage());
		break;
	default:
		usage();
	} ARGEND

	obj = loadexe(filename);
	if (!obj)
		return status;

	if (argc > 0) {
		for ( ; *argv; ++argv)
			addr2line(obj, *argv);
	} else {
		while ((ln = getln()) != NULL)
			addr2line(obj, ln);
	}

	fflush(stdout);
	if (ferror(stdout)) {
		filename = "stdout";
		error("error writing stdout: %s", strerror(errno));
	}

	return status;
}