/*
 * 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;
}
