#include <u.h>
#include <libc.h>
#include <mach.h>
#include "elf.h"

/*
aggr Linkdebug
{
	'X' 0 version;
	'X' 4 map;
};

aggr Linkmap
{
	'X' 0 addr;
	'X' 4 name;
	'X' 8 dynsect;
	'X' 12 next;
	'X' 16 prev;
};
*/
enum
{
	DT_NULL = 0,
	DT_NEEDED,
	DT_PLTRRELSZ,
	DT_PLTGOT,
	DT_HASH,
	DT_STRTAB,
	DT_SYMTAB,
	DT_RELA,
	DT_RELASZ = 8,
	DT_RELAENT,
	DT_STSZ,
	DT_SYMENT,
	DT_INIT,
	DT_FINI,
	DT_SONAME,
	DT_RPATH,
	DT_SYMBOLIC = 16,
	DT_REL,
	DT_RELSZ,
	DT_RELENT,
	DT_PLTREL,
	DT_DEBUG,
	DT_TEXTREL,
	DT_JMPREL
};

static int
getstr(Map *map, ulong addr, char *buf, uint nbuf)
{
	int i;

	for(i=0; i<nbuf; i++){
		if(get1(map, addr+i, (uchar*)buf+i, 1) < 0)
			return -1;
		if(buf[i] == 0)
			return 0;
	}
	return -1;	/* no nul */
}

static ulong
dyninfo(Fhdr *hdr, int x)
{
	u32int addr, u;

	if(hdr == nil || (addr = ((Elf*)hdr->elf)->dynamic) == 0){
		fprint(2, "no hdr/dynamic %p\n", hdr);
		return 0;
	}
	addr += hdr->base;

	while(addr != 0){
		if(get4(cormap, addr, &u) < 0)
			return 0;
		if(u == x){
			if(get4(cormap, addr+4, &u) < 0)
				return 0;
			return u;
		}
		addr += 8;
	}
	return 0;
}

void
elfdl386mapdl(int verbose)
{
	int i;
	Fhdr *hdr;
	u32int linkdebug, linkmap, name, addr;
	char buf[1024];

	if((linkdebug = dyninfo(symhdr, DT_DEBUG)) == 0){
		fprint(2, "no dt_debug section\n");
		return;
	}
	if(get4(cormap, linkdebug+4, &linkmap) < 0){
		fprint(2, "get4 linkdebug+4 (0x%lux) failed\n", linkdebug);
		return;
	}

	for(i=0; i<100 && linkmap != 0; i++){
		if(get4(cormap, linkmap, &addr) < 0
		|| get4(cormap, linkmap+4, &name) < 0
		|| get4(cormap, linkmap+12, &linkmap) < 0)
			break;

		if(name == 0 || getstr(cormap, name, buf, sizeof buf) < 0 || buf[0] == 0)
			continue;
		if((hdr = crackhdr(buf, OREAD)) == nil){
			fprint(2, "crackhdr %s: %r\n", buf);
			continue;
		}
		hdr->base = addr;
		if(verbose)
			fprint(2, "%s: %s %s %s\n", buf, hdr->aname, hdr->mname, hdr->fname);
		if(mapfile(hdr, addr, symmap, nil) < 0)
			fprint(2, "mapping %s: %r\n", buf);
		if(corhdr){
			/*
			 * Need to map the text file under the core file.
			 */
			unmapfile(corhdr, cormap);
			mapfile(hdr, addr, cormap, nil);
			mapfile(corhdr, 0, cormap, nil);
		}
		if(symopen(hdr) < 0)
			fprint(2, "syminit %s: %r\n", buf);
	}
}