libmach
diff --git a/src/libmach/dwarfaranges.c b/src/libmach/dwarfaranges.c
new file mode 100644
index 0000000..2129958
--- /dev/null
+++ b/src/libmach/dwarfaranges.c
@@ -0,0 +1,63 @@
+/*
+ * Dwarf address ranges parsing code.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "elf.h"
+#include "dwarf.h"
+
+int
+dwarfaddrtounit(Dwarf *d, ulong addr, ulong *unit)
+{
+	DwarfBuf b;
+	int segsize, i;
+	ulong len, id, off, base, size;
+	uchar *start, *end;
+
+	memset(&b, 0, sizeof b);
+	b.d = d;
+	b.p = d->aranges.data;
+	b.ep = b.p + d->aranges.len;
+
+	while(b.p < b.ep){
+		start = b.p;
+		len = dwarfget4(&b);
+		if((id = dwarfget2(&b)) != 2){
+			if(b.p == nil){
+			underflow:
+				werrstr("buffer underflow reading address ranges header");
+			}else
+				werrstr("bad dwarf version 0x%lux in address ranges header", id);
+			return -1;
+		}
+		off = dwarfget4(&b);
+		b.addrsize = dwarfget1(&b);
+		if(d->addrsize == 0)
+			d->addrsize = b.addrsize;
+		segsize = dwarfget1(&b);
+		USED(segsize);	/* what am i supposed to do with this? */
+		if(b.p == nil)
+			goto underflow;
+		if((i = (b.p-start) % (2*b.addrsize)) != 0)
+			b.p += 2*b.addrsize - i;
+		end = start+4+len;
+		while(b.p!=nil && b.p<end){
+			base = dwarfgetaddr(&b);
+			size = dwarfgetaddr(&b);
+			if(b.p == nil)
+				goto underflow;
+			if(base <= addr && addr < base+size){
+				*unit = off;
+				return 0;
+			}
+		}
+		if(b.p == nil)
+			goto underflow;
+		b.p = end;
+	}
+	werrstr("address 0x%lux is not listed in dwarf debugging symbols", addr);
+	return -1;
+}
+