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;
+}
+