aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/libelf
diff options
context:
space:
mode:
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>2007-08-01 15:47:54 +0100
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>2007-08-01 15:47:54 +0100
commit71b66d78933833d09538c903ded167636acf8a59 (patch)
tree4114759089eb13090e3d155c04b7ff1a10d65fc0 /xen/common/libelf
parentb1757490f0d13d1525e9d6a589188ddf4acafbbf (diff)
downloadxen-71b66d78933833d09538c903ded167636acf8a59.tar.gz
xen-71b66d78933833d09538c903ded167636acf8a59.tar.bz2
xen-71b66d78933833d09538c903ded167636acf8a59.zip
[ELF] Load elf symbols when BSD_SYMTAB=yes.
When a guest kernel specifies BSD_SYMTAB=yes, then Xen loads the ELF symbols for it. This works with Xen 3.0.4, but not with Xen 3.1. During the libelf work between Xen 3.0.4 and Xen 3.1 the loading got broken in the way, that BSD_SYMTAB gets parsed but not handled. Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
Diffstat (limited to 'xen/common/libelf')
-rw-r--r--xen/common/libelf/libelf-dominfo.c101
-rw-r--r--xen/common/libelf/libelf-loader.c42
-rw-r--r--xen/common/libelf/libelf-tools.c30
3 files changed, 167 insertions, 6 deletions
diff --git a/xen/common/libelf/libelf-dominfo.c b/xen/common/libelf/libelf-dominfo.c
index eedf970753..cff6710749 100644
--- a/xen/common/libelf/libelf-dominfo.c
+++ b/xen/common/libelf/libelf-dominfo.c
@@ -333,6 +333,99 @@ static int elf_xen_note_check(struct elf_binary *elf,
return 0;
}
+
+static void elf_xen_loadsymtab(struct elf_binary *elf,
+ struct elf_dom_parms *parms)
+{
+ unsigned long maxva, len;
+
+ if ( !parms->bsd_symtab )
+ return;
+
+ /* Calculate the required additional kernel space for the elf image */
+
+ /* The absolute base address of the elf image */
+ maxva = elf_round_up(elf, parms->virt_kend);
+ maxva += sizeof(long); /* Space to store the size of the elf image */
+ /* Space for the elf and elf section headers */
+ maxva += (elf_uval(elf, elf->ehdr, e_ehsize) +
+ elf_shdr_count(elf) * elf_uval(elf, elf->ehdr, e_shentsize));
+ maxva = elf_round_up(elf, maxva);
+
+ /* Space for the symbol and string tabs */
+ len = (unsigned long)elf->send - (unsigned long)elf->sstart;
+ maxva = elf_round_up(elf, maxva + len);
+
+ /* The address the kernel must expanded to */
+ parms->virt_end = maxva;
+}
+
+int elf_xen_dom_load_binary(struct elf_binary *elf,
+ struct elf_dom_parms *parms)
+{
+ elf_ehdr *sym_ehdr;
+ unsigned long shdr, symtab_addr;
+ unsigned long maxva, symbase;
+ uint8_t i;
+ char *p;
+
+ elf_load_binary(elf);
+
+ if ( !parms->bsd_symtab )
+ return 0;
+
+#define elf_hdr_elm(_elf, _hdr, _elm, _val) \
+do { \
+ if ( elf_64bit(_elf) ) \
+ (_hdr)->e64._elm = _val; \
+ else \
+ (_hdr)->e32._elm = _val; \
+} while ( 0 )
+
+ /* ehdr right after the kernel image (4 byte aligned) */
+ symbase = elf_round_up(elf, parms->virt_kend);
+ symtab_addr = maxva = symbase + sizeof(long);
+
+ /* Set up Elf header. */
+ sym_ehdr = (elf_ehdr *)symtab_addr;
+ maxva = elf_copy_ehdr(elf, sym_ehdr);
+
+ 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 = maxva;
+ maxva = elf_copy_shdr(elf, (elf_shdr *)shdr);
+
+ for ( i = 0; i < elf_shdr_count(elf); i++ )
+ {
+ uint8_t type;
+ unsigned long tmp;
+ type = elf_uval(elf, (elf_shdr *)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, (elf_shdr *)shdr), (void *)maxva);
+ tmp = elf_copy_section(elf, (elf_shdr *)shdr, (void *)maxva);
+ /* Mangled to be based on ELF header location. */
+ elf_hdr_elm(elf, (elf_shdr *)shdr, sh_offset,
+ maxva - symtab_addr);
+ maxva = tmp;
+ }
+ shdr += elf_uval(elf, elf->ehdr, e_shentsize);
+ }
+
+ /* Write down the actual sym size. */
+ p = (char *)symbase;
+ *(long *)p = maxva - symtab_addr; /* sym size */
+
+#undef elf_ehdr_elm
+
+ return 0;
+}
+
static int elf_xen_addr_calc_check(struct elf_binary *elf,
struct elf_dom_parms *parms)
{
@@ -374,22 +467,28 @@ static int elf_xen_addr_calc_check(struct elf_binary *elf,
parms->virt_offset = parms->virt_base - parms->elf_paddr_offset;
parms->virt_kstart = elf->pstart + parms->virt_offset;
parms->virt_kend = elf->pend + parms->virt_offset;
+ parms->virt_end = parms->virt_kend;
if ( parms->virt_entry == UNSET_ADDR )
parms->virt_entry = elf_uval(elf, elf->ehdr, e_entry);
+ if ( parms->bsd_symtab )
+ elf_xen_loadsymtab(elf, parms);
+
elf_msg(elf, "%s: addresses:\n", __FUNCTION__);
elf_msg(elf, " virt_base = 0x%" PRIx64 "\n", parms->virt_base);
elf_msg(elf, " elf_paddr_offset = 0x%" PRIx64 "\n", parms->elf_paddr_offset);
elf_msg(elf, " virt_offset = 0x%" PRIx64 "\n", parms->virt_offset);
elf_msg(elf, " virt_kstart = 0x%" PRIx64 "\n", parms->virt_kstart);
elf_msg(elf, " virt_kend = 0x%" PRIx64 "\n", parms->virt_kend);
+ elf_msg(elf, " virt_end = 0x%" PRIx64 "\n", parms->virt_end);
elf_msg(elf, " virt_entry = 0x%" PRIx64 "\n", parms->virt_entry);
if ( (parms->virt_kstart > parms->virt_kend) ||
(parms->virt_entry < parms->virt_kstart) ||
(parms->virt_entry > parms->virt_kend) ||
- (parms->virt_base > parms->virt_kstart) )
+ (parms->virt_base > parms->virt_kstart) ||
+ (parms->virt_kend > parms->virt_end) )
{
elf_err(elf, "%s: ERROR: ELF start or entries are out of bounds.\n",
__FUNCTION__);
diff --git a/xen/common/libelf/libelf-loader.c b/xen/common/libelf/libelf-loader.c
index e0f8dba913..bfb3cab57b 100644
--- a/xen/common/libelf/libelf-loader.c
+++ b/xen/common/libelf/libelf-loader.c
@@ -10,6 +10,8 @@ int elf_init(struct elf_binary *elf, const char *image, size_t size)
{
const elf_shdr *shdr;
uint64_t i, count, section, offset;
+ uint64_t low = -1;
+ uint64_t high = 0;
if ( !elf_is_elfbinary(image) )
{
@@ -24,7 +26,11 @@ int elf_init(struct elf_binary *elf, const char *image, size_t size)
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 +40,7 @@ int elf_init(struct elf_binary *elf, const char *image, size_t size)
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,29 +50,55 @@ int elf_init(struct elf_binary *elf, const char *image, size_t size)
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++ )
{
+ const char *sh_symend, *sh_strend;
+
shdr = elf_shdr_by_index(elf, i);
if ( elf_uval(elf, shdr, sh_type) != SHT_SYMTAB )
continue;
elf->sym_tab = shdr;
+ sh_symend = (const char *)elf_section_end(elf, shdr);
shdr = elf_shdr_by_index(elf, elf_uval(elf, shdr, sh_link));
if ( shdr == NULL )
{
elf->sym_tab = NULL;
+ sh_symend = 0;
continue;
}
elf->sym_strtab = elf_section_start(elf, shdr);
- break;
+ sh_strend = (const char *)elf_section_end(elf, shdr);
+
+ if ( low > (unsigned long)elf->sym_tab )
+ low = (unsigned long)elf->sym_tab;
+ if ( low > (unsigned long)shdr )
+ low = (unsigned long)shdr;
+
+ if ( high < ((unsigned long)sh_symend) )
+ high = (unsigned long)sh_symend;
+ if ( high < ((unsigned long)sh_strend) )
+ high = (unsigned long)sh_strend;
+
+ elf_msg(elf, "%s: shdr: sym_tab=%p size=0x%" PRIx64 "\n",
+ __FUNCTION__, elf->sym_tab,
+ elf_uval(elf, elf->sym_tab, sh_size));
+ elf_msg(elf, "%s: shdr: str_tab=%p size=0x%" PRIx64 "\n",
+ __FUNCTION__, elf->sym_strtab, elf_uval(elf, shdr, sh_size));
+
+ elf->sstart = low;
+ elf->send = high;
+ elf_msg(elf, "%s: symbol map: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
+ __FUNCTION__, elf->sstart, elf->send);
}
+
return 0;
}
diff --git a/xen/common/libelf/libelf-tools.c b/xen/common/libelf/libelf-tools.c
index 99a0a91576..c383a03111 100644
--- a/xen/common/libelf/libelf-tools.c
+++ b/xen/common/libelf/libelf-tools.c
@@ -238,6 +238,36 @@ int elf_phdr_is_loadable(struct elf_binary *elf, const elf_phdr * phdr)
return ((p_type == PT_LOAD) && (p_flags & (PF_W | PF_X)) != 0);
}
+unsigned long
+elf_copy_ehdr(struct elf_binary *elf, void *dest)
+{
+ uint64_t size;
+
+ size = elf_uval(elf, elf->ehdr, e_ehsize);
+ memcpy(dest, elf->ehdr, size);
+ return elf_round_up(elf, (unsigned long)(dest) + size);
+}
+
+unsigned long
+elf_copy_shdr(struct elf_binary *elf, void *dest)
+{
+ uint64_t size;
+
+ size = elf_shdr_count(elf) * elf_uval(elf, elf->ehdr, e_shentsize);
+ memcpy(dest, elf->image + elf_uval(elf, elf->ehdr, e_shoff), size);
+ return elf_round_up(elf, (unsigned long)(dest) + size);
+}
+
+unsigned long
+elf_copy_section(struct elf_binary *elf, const elf_shdr *shdr, void *dest)
+{
+ uint64_t size;
+
+ size = elf_uval(elf, shdr, sh_size);
+ memcpy(dest, elf_section_start(elf, shdr), size);
+ return elf_round_up(elf, (unsigned long)(dest) + size);
+}
+
/*
* Local variables:
* mode: C