libmach
diff --git a/src/libmach/elfdump.c b/src/libmach/elfdump.c
new file mode 100644
index 0000000..e96f818
--- /dev/null
+++ b/src/libmach/elfdump.c
@@ -0,0 +1,133 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "elf.h"
+#include "stabs.h"
+
+void
+usage(void)
+{
+	fprint(2, "usage: elf file list\n");
+	fprint(2, "	elf file syms\n");
+	fprint(2, "	elf file prog n\n");
+	fprint(2, "	elf file sect n\n");
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	int i, n, nn;
+	char buf[512];
+	ulong off, len;
+	Elf *elf;
+	ElfProg *p;
+	ElfSect *s;
+
+	ARGBEGIN{
+	default:
+		usage();
+	}ARGEND
+
+	if(argc < 2)
+		usage();
+
+	if((elf = elfopen(argv[0])) == nil)
+		sysfatal("elfopen %s: %r", argv[0]);
+
+	if(strcmp(argv[1], "syms") == 0){
+		ElfSym sym;
+		for(i=0; elfsym(elf, i, &sym) >= 0; i++){
+			print("%s 0x%lux +%lud bind %d type %d other %d shndx 0x%ux\n",
+				sym.name, (ulong)sym.value, (ulong)sym.size,
+				sym.bind, sym.type, sym.other, (uint)sym.shndx);
+		}
+	}
+	else if(strcmp(argv[1], "stabs") == 0){
+		ElfSect *s1, *s2;
+		Stab stabs;
+		StabSym sym;
+
+		if((s1 = elfsection(elf, ".stab")) == nil)
+			sysfatal("no stabs");
+		if(s1->link==0 || s1->link >= elf->nsect)
+			sysfatal("bad stabstr %d", s1->link);
+		s2 = &elf->sect[s1->link];
+		if(elfmap(elf, s1) < 0 || elfmap(elf, s2) < 0)
+			sysfatal("elfmap");
+		stabs.stabbase = s1->base;
+		stabs.stabsize = s1->size;
+		stabs.strbase = s2->base;
+		stabs.strsize = s2->size;
+		stabs.e2 = elf->hdr.e2;
+		stabs.e4 = elf->hdr.e4;
+		print("%ud %ud\n", stabs.stabsize, stabs.strsize);
+		for(i=0; stabsym(&stabs, i, &sym) >= 0; i++)
+			print("%s type 0x%x other %d desc %d value 0x%lux\n",
+				sym.name, sym.type, sym.other, (int)sym.desc, (ulong)sym.value);
+		fprint(2, "err at %d: %r\n", i);
+	}
+	else if(strcmp(argv[1], "list") == 0){
+		if(argc != 2)
+			usage();
+		print("elf %s %s v%d entry 0x%08lux phoff 0x%lux shoff 0x%lux flags 0x%lux\n",
+			elftype(elf->hdr.type), elfmachine(elf->hdr.machine),
+			elf->hdr.version, elf->hdr.entry, elf->hdr.phoff, elf->hdr.shoff,
+			elf->hdr.flags);
+		print("\tehsize %d phentsize %d phnum %d shentsize %d shnum %d shstrndx %d\n",
+			elf->hdr.ehsize, elf->hdr.phentsize, elf->hdr.phnum, elf->hdr.shentsize,
+			elf->hdr.shnum, elf->hdr.shstrndx);
+		for(i=0; i<elf->nprog; i++){
+			p = &elf->prog[i];
+			print("prog %d type %d offset 0x%08lux vaddr 0x%08lux paddr 0x%08lux filesz 0x%08lux memsz 0x%08lux flags 0x%08lux align 0x%08lux\n",
+				i, p->type, p->offset, p->vaddr, p->paddr,
+				p->filesz, p->memsz, p->flags, p->align);
+		}
+		for(i=0; i<elf->nsect; i++){
+			s = &elf->sect[i];
+			print("sect %d %s type %d flags 0x%lux addr 0x%08lux offset 0x%08lux size 0x%08lux link 0x%lux info 0x%lux align 0x%lux entsize 0x%lux\n",
+				i, s->name, s->type, s->flags, s->addr, s->offset, s->size, s->link, s->info,
+				s->align, s->entsize);
+		}
+	}
+	else if(strcmp(argv[1], "prog") == 0){
+		if(argc != 3)
+			usage();
+		i = atoi(argv[2]);
+		if(i < 0 || i >= elf->nprog)
+			sysfatal("bad prog number");
+		off = elf->prog[i].offset;
+		len = elf->prog[i].filesz;
+		fprint(2, "prog %d offset 0x%lux size 0x%lux\n", i, off, len);
+	copy:
+		seek(elf->fd, off, 0);
+		for(n=0; n<len; n+=nn){
+			nn = sizeof buf;
+			if(nn > len-n)
+				nn = len-n;
+			nn = read(elf->fd, buf, nn);
+			if(nn == 0)
+				break;
+			if(nn < 0)
+				sysfatal("read error");
+			write(1, buf, nn);
+		}
+		if(n < len)
+			fprint(2, "early eof\n");
+	}
+	else if(strcmp(argv[1], "sect") == 0){
+		if(argc != 3)
+			usage();
+		i = atoi(argv[2]);
+		if(i < 0 || i >= elf->nsect)
+			sysfatal("bad section number");
+		off = elf->sect[i].offset;
+		len = elf->sect[i].size;
+		fprint(2, "section %d offset 0x%lux size 0x%lux\n", i, off, len);
+		goto copy;
+	}
+	else
+		usage();
+	exits(0);
+}