$NetBSD: patch-bc,v 1.1 2007/08/17 17:26:05 bouyer Exp $ --- xen/common/libelf/libelf-loader.c.orig 2007-05-18 16:45:21.000000000 +0200 +++ xen/common/libelf/libelf-loader.c 2007-08-16 21:43:18.000000000 +0200 @@ -20,11 +20,15 @@ memset(elf, 0, sizeof(*elf)); elf->image = image; elf->size = size; - elf->ehdr = (elf_ehdr *) image; + elf->ehdr = (elf_ehdr *)image; elf->class = elf->ehdr->e32.e_ident[EI_CLASS]; elf->data = elf->ehdr->e32.e_ident[EI_DATA]; - /* sanity check phdr */ +#ifdef VERBOSE + elf_set_verbose(elf); +#endif + + /* Sanity check phdr. */ offset = elf_uval(elf, elf->ehdr, e_phoff) + elf_uval(elf, elf->ehdr, e_phentsize) * elf_phdr_count(elf); if ( offset > elf->size ) @@ -34,7 +38,7 @@ return -1; } - /* sanity check shdr */ + /* Sanity check shdr. */ offset = elf_uval(elf, elf->ehdr, e_shoff) + elf_uval(elf, elf->ehdr, e_shentsize) * elf_shdr_count(elf); if ( offset > elf->size ) @@ -44,13 +48,13 @@ return -1; } - /* find section string table */ + /* Find section string table. */ section = elf_uval(elf, elf->ehdr, e_shstrndx); shdr = elf_shdr_by_index(elf, section); if ( shdr != NULL ) elf->sec_strtab = elf_section_start(elf, shdr); - /* find symbol table, symbol string table */ + /* Find symbol table and symbol string table. */ count = elf_shdr_count(elf); for ( i = 0; i < count; i++ ) { @@ -67,6 +71,7 @@ elf->sym_strtab = elf_section_start(elf, shdr); break; } + return 0; } @@ -83,6 +88,101 @@ } #endif +/* Calculate the required additional kernel space for the elf image */ +void elf_parse_bsdsyms(struct elf_binary *elf, uint64_t pstart) +{ + uint64_t sz; + const elf_shdr *shdr; + int i, type; + + if ( !elf->sym_tab ) + return; + + pstart = elf_round_up(elf, pstart); + + /* Space to store the size of the elf image */ + sz = sizeof(uint32_t); + + /* Space for the elf and elf section headers */ + sz += (elf_uval(elf, elf->ehdr, e_ehsize) + + elf_shdr_count(elf) * elf_uval(elf, elf->ehdr, e_shentsize)); + sz = elf_round_up(elf, sz); + + /* Space for the symbol and string tables. */ + for ( i = 0; i < elf_shdr_count(elf); i++ ) + { + shdr = elf_shdr_by_index(elf, i); + type = elf_uval(elf, (elf_shdr *)shdr, sh_type); + if ( (type == SHT_STRTAB) || (type == SHT_SYMTAB) ) + sz = elf_round_up(elf, sz + elf_uval(elf, shdr, sh_size)); + } + + elf->bsd_symtab_pstart = pstart; + elf->bsd_symtab_pend = pstart + sz; +} + +static void elf_load_bsdsyms(struct elf_binary *elf) +{ + elf_ehdr *sym_ehdr; + unsigned long sz; + char *maxva, *symbase, *symtab_addr; + elf_shdr *shdr; + int i, type; + + if ( !elf->bsd_symtab_pstart ) + return; + +#define elf_hdr_elm(_elf, _hdr, _elm, _val) \ +do { \ + if ( elf_64bit(_elf) ) \ + (_hdr)->e64._elm = _val; \ + else \ + (_hdr)->e32._elm = _val; \ +} while ( 0 ) + + symbase = elf_get_ptr(elf, elf->bsd_symtab_pstart); + symtab_addr = maxva = symbase + sizeof(uint32_t); + + /* Set up Elf header. */ + sym_ehdr = (elf_ehdr *)symtab_addr; + sz = elf_uval(elf, elf->ehdr, e_ehsize); + memcpy(sym_ehdr, elf->ehdr, sz); + maxva += sz; /* no round up */ + + elf_hdr_elm(elf, sym_ehdr, e_phoff, 0); + elf_hdr_elm(elf, sym_ehdr, e_shoff, elf_uval(elf, elf->ehdr, e_ehsize)); + elf_hdr_elm(elf, sym_ehdr, e_phentsize, 0); + elf_hdr_elm(elf, sym_ehdr, e_phnum, 0); + + /* Copy Elf section headers. */ + shdr = (elf_shdr *)maxva; + sz = elf_shdr_count(elf) * elf_uval(elf, elf->ehdr, e_shentsize); + memcpy(shdr, elf->image + elf_uval(elf, elf->ehdr, e_shoff), sz); + maxva = (char *)(long)elf_round_up(elf, (long)maxva + sz); + + for ( i = 0; i < elf_shdr_count(elf); i++ ) + { + type = elf_uval(elf, shdr, sh_type); + if ( (type == SHT_STRTAB) || (type == SHT_SYMTAB) ) + { + elf_msg(elf, "%s: shdr %i at 0x%p -> 0x%p\n", __func__, i, + elf_section_start(elf, shdr), maxva); + sz = elf_uval(elf, shdr, sh_size); + memcpy(maxva, elf_section_start(elf, shdr), sz); + /* Mangled to be based on ELF header location. */ + elf_hdr_elm(elf, shdr, sh_offset, maxva - symtab_addr); + maxva = (char *)(long)elf_round_up(elf, (long)maxva + sz); + } + shdr = (elf_shdr *)((long)shdr + + (long)elf_uval(elf, elf->ehdr, e_shentsize)); + } + + /* Write down the actual sym size. */ + *(uint32_t *)symbase = maxva - symtab_addr; + +#undef elf_ehdr_elm +} + void elf_parse_binary(struct elf_binary *elf) { const elf_phdr *phdr; @@ -133,6 +233,8 @@ memcpy(dest, elf->image + offset, filesz); memset(dest + filesz, 0, memsz - filesz); } + + elf_load_bsdsyms(elf); } void *elf_get_ptr(struct elf_binary *elf, unsigned long addr)