/*
 * Dwarf pc to source line conversion.
 * 
 * Maybe should do the reverse here, but what should the interface look like?
 * One possibility is to use the Plan 9 line2addr interface:
 *
 *	long line2addr(ulong line, ulong basepc)
 *
 * which returns the smallest pc > basepc with line number line (ignoring file name).
 *
 * The encoding may be small, but it sure isn't simple!
 */

#include <u.h>
#include <libc.h>
#include <bio.h>
#include "elf.h"
#include "dwarf.h"

#define trace 0

enum
{
	Isstmt = 1<<0,
	BasicDwarfBlock = 1<<1,
	EndSequence = 1<<2,
	PrologueEnd = 1<<3,
	EpilogueBegin = 1<<4
};

typedef struct State State;
struct State
{
	ulong addr;
	ulong file;
	ulong line;
	ulong column;
	ulong flags;
	ulong isa;
};

int
dwarfpctoline(Dwarf *d, ulong pc, char **cdir, char **dir, char **file, ulong *line, ulong *mtime, ulong *length)
{
	uchar *prog, *opcount, *end;
	ulong off, unit, len, vers, x, start;
	int i, first, op, a, l, quantum, isstmt, linebase, linerange, opcodebase, nf;
	char *files, *dirs, *s;
	DwarfBuf b;
	DwarfSym sym;
	State emit, cur, reset;
	uchar **f, **newf;

	f = nil;

	if(dwarfaddrtounit(d, pc, &unit) < 0
	|| dwarflookuptag(d, unit, TagCompileUnit, &sym) < 0)
		return -1;

	if(!sym.attrs.have.stmtlist){
		werrstr("no line mapping information for 0x%lux", pc);
		return -1;
	}
	off = sym.attrs.stmtlist;
	if(off >= d->line.len){
		fprint(2, "bad stmtlist\n");
		goto bad;
	}

	if(trace) fprint(2, "unit 0x%lux stmtlist 0x%lux\n", unit, sym.attrs.stmtlist);

	memset(&b, 0, sizeof b);
	b.d = d;
	b.p = d->line.data + off;
	b.ep = b.p + d->line.len;
	b.addrsize = sym.b.addrsize;	/* should i get this from somewhere else? */

	len = dwarfget4(&b);
	if(b.p==nil || b.p+len > b.ep || b.p+len < b.p){
		fprint(2, "bad len\n");
		goto bad;
	}

	b.ep = b.p+len;
	vers = dwarfget2(&b);
	if(vers != 2){
		werrstr("bad dwarf version 0x%lux", vers);
		return -1;
	}

	len = dwarfget4(&b);
	if(b.p==nil || b.p+len > b.ep || b.p+len < b.p){
		fprint(2, "another bad len\n");
		goto bad;
	}
	prog = b.p+len;

	quantum = dwarfget1(&b);
	isstmt = dwarfget1(&b);
	linebase = (schar)dwarfget1(&b);
	linerange = (schar)dwarfget1(&b);
	opcodebase = dwarfget1(&b);

	opcount = b.p-1;
	dwarfgetnref(&b, opcodebase-1);
	if(b.p == nil){
		fprint(2, "bad opcode chart\n");
		goto bad;
	}

	/* just skip the files and dirs for now; we'll come back */
	dirs = (char*)b.p;
	while(b.p!=nil && *b.p!=0)
		dwarfgetstring(&b);
	dwarfget1(&b);

	files = (char*)b.p;
	while(b.p!=nil && *b.p!=0){
		dwarfgetstring(&b);
		dwarfget128(&b);
		dwarfget128(&b);
		dwarfget128(&b);
	}
	dwarfget1(&b);

	/* move on to the program */
	if(b.p == nil || b.p > prog){
		fprint(2, "bad header\n");
		goto bad;
	}
	b.p = prog;

	reset.addr = 0;
	reset.file = 1;
	reset.line = 1;
	reset.column = 0;
	reset.flags = isstmt ? Isstmt : 0;
	reset.isa = 0;

	cur = reset;
	emit = reset;
	nf = 0;
	start = 0;
	if(trace) fprint(2, "program @ %lud ... %.*H opbase = %d\n", b.p - d->line.data, b.ep-b.p, b.p, opcodebase);
	first = 1;
	while(b.p != nil){
		op = dwarfget1(&b);
		if(trace) fprint(2, "\tline %lud, addr 0x%lux, op %d %.10H", cur.line, cur.addr, op, b.p);
		if(op >= opcodebase){
			a = (op - opcodebase) / linerange;
			l = (op - opcodebase) % linerange + linebase;
			cur.line += l;
			cur.addr += a * quantum;
			if(trace) fprint(2, " +%d,%d\n", a, l);
		emit:
			if(first){
				if(cur.addr > pc){
					werrstr("found wrong line mapping 0x%lux for pc 0x%lux", cur.addr, pc);
					goto out;
				}
				first = 0;
				start = cur.addr;
			}
			if(cur.addr > pc)
				break;
			if(b.p == nil){
				werrstr("buffer underflow in line mapping");
				goto out;
			}
			emit = cur;
			if(emit.flags & EndSequence){
				werrstr("found wrong line mapping 0x%lux-0x%lux for pc 0x%lux", start, cur.addr, pc);
				goto out;
			}
			cur.flags &= ~(BasicDwarfBlock|PrologueEnd|EpilogueBegin);
		}else{
			switch(op){
			case 0:	/* extended op code */
				if(trace) fprint(2, " ext");
				len = dwarfget128(&b);
				end = b.p+len;
				if(b.p == nil || end > b.ep || end < b.p || len < 1)
					goto bad;
				switch(dwarfget1(&b)){
				case 1:	/* end sequence */
					if(trace) fprint(2, " end\n");
					cur.flags |= EndSequence;
					goto emit;
				case 2:	/* set address */
					cur.addr = dwarfgetaddr(&b);
					if(trace) fprint(2, " set pc 0x%lux\n", cur.addr);
					break;
				case 3:	/* define file */
					newf = realloc(f, (nf+1)*sizeof(f[0]));
					if(newf == nil)
						goto out;
					f = newf;
					f[nf++] = b.p;
					s = dwarfgetstring(&b);
					dwarfget128(&b);
					dwarfget128(&b);
					dwarfget128(&b);
					if(trace) fprint(2, " def file %s\n", s);
					break;
				}
				if(b.p == nil || b.p > end)
					goto bad;
				b.p = end;
				break;
			case 1:	/* emit */
				if(trace) fprint(2, " emit\n");
				goto emit;
			case 2:	/* advance pc */
				a = dwarfget128(&b);
				if(trace) fprint(2, " advance pc + %lud\n", a*quantum);
				cur.addr += a * quantum;
				break;
			case 3:	/* advance line */
				l = dwarfget128s(&b);
				if(trace) fprint(2, " advance line + %ld\n", l);
				cur.line += l;
				break;
			case 4:	/* set file */
				if(trace) fprint(2, " set file\n");
				cur.file = dwarfget128s(&b);
				break;
			case 5:	/* set column */
				if(trace) fprint(2, " set column\n");
				cur.column = dwarfget128(&b);
				break;
			case 6:	/* negate stmt */
				if(trace) fprint(2, " negate stmt\n");
				cur.flags ^= Isstmt;
				break;
			case 7:	/* set basic block */
				if(trace) fprint(2, " set basic block\n");
				cur.flags |= BasicDwarfBlock;
				break;
			case 8:	/* const add pc */
				a = (255 - opcodebase) / linerange * quantum;
				if(trace) fprint(2, " const add pc + %d\n", a);
				cur.addr += a;
				break;
			case 9:	/* fixed advance pc */
				a = dwarfget2(&b);
				if(trace) fprint(2, " fixed advance pc + %d\n", a);
				cur.addr += a;
				break;
			case 10:	/* set prologue end */
				if(trace) fprint(2, " set prologue end\n");
				cur.flags |= PrologueEnd;
				break;
			case 11:	/* set epilogue begin */
				if(trace) fprint(2, " set epilogue begin\n");
				cur.flags |= EpilogueBegin;
				break;
			case 12:	/* set isa */
				if(trace) fprint(2, " set isa\n");
				cur.isa = dwarfget128(&b);
				break;
			default:	/* something new - skip it */
				if(trace) fprint(2, " unknown %d\n", opcount[op]);
				for(i=0; i<opcount[op]; i++)
					dwarfget128(&b);
				break;
			}
		}
	}
	if(b.p == nil)
		goto bad;

	/* finally!  the data we seek is in "emit" */

	if(emit.file == 0){
		werrstr("invalid file index in mapping data");
		goto out;
	}
	if(line)
		*line = emit.line;

	/* skip over first emit.file-2 guys */
	b.p = (uchar*)files;
	for(i=emit.file-1; i > 0 && b.p!=nil && *b.p!=0; i--){
		dwarfgetstring(&b);
		dwarfget128(&b);
		dwarfget128(&b);
		dwarfget128(&b);
	}
	if(b.p == nil){
		werrstr("problem parsing file data second time (cannot happen)");
		goto bad;
	}
	if(*b.p == 0){
		if(i >= nf){
			werrstr("bad file index in mapping data");
			goto bad;
		}
		b.p = f[i];
	}
	s = dwarfgetstring(&b);
	if(file)
		*file = s;
	i = dwarfget128(&b);		/* directory */
	x = dwarfget128(&b);
	if(mtime)
		*mtime = x;
	x = dwarfget128(&b);
	if(length)
		*length = x;

	/* fetch dir name */
	if(cdir)
		*cdir = sym.attrs.compdir;

	if(dir){
		if(i == 0)
			*dir = nil;
		else{
			b.p = (uchar*)dirs;
			for(i--; i>0 && b.p!=nil && *b.p!=0; i--)
				dwarfgetstring(&b);
			if(b.p==nil || *b.p==0){
				werrstr("bad directory reference in line mapping");
				goto out;		/* can only happen with bad dir index */
			}
			*dir = dwarfgetstring(&b);
		}
	}

	/* free at last, free at last */
	free(f);
	return 0;

bad:
	werrstr("corrupted line mapping for 0x%lux", pc);
out:
	free(f);
	return -1;
}
