summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2013-03-10 00:43:01 +0000
committerian <ian@FreeBSD.org>2013-03-10 00:43:01 +0000
commit84fe418fcb138d0ad2fe6b181a17c4eee59e2a0e (patch)
tree57af97b3bf14dc2635ddddc2bef0199b60539a72
parent5e403de75ee05384c91cbd144df91148207fc551 (diff)
downloadFreeBSD-src-84fe418fcb138d0ad2fe6b181a17c4eee59e2a0e.zip
FreeBSD-src-84fe418fcb138d0ad2fe6b181a17c4eee59e2a0e.tar.gz
Attach the elf section headers to the loaded kernel as metadata, so
they can easily be used by later post-processing. When searching for a compiled-in fdt blob, use the section headers to get the size and location of the .dynsym section to do a symbol search. This fixes a problem where the search could overshoot the symbol table and wander into the string table. Sometimes that was harmless and sometimes it lead to spurious panic messages about an offset bigger than the module size.
-rw-r--r--sys/boot/common/load_elf.c2
-rw-r--r--sys/boot/fdt/fdt_loader_cmd.c49
2 files changed, 19 insertions, 32 deletions
diff --git a/sys/boot/common/load_elf.c b/sys/boot/common/load_elf.c
index 4a1896e..8990d90 100644
--- a/sys/boot/common/load_elf.c
+++ b/sys/boot/common/load_elf.c
@@ -397,6 +397,8 @@ __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
"_loadimage: failed to read section headers");
goto nosyms;
}
+ file_addmetadata(fp, MODINFOMD_SHDR, chunk, shdr);
+
symtabindex = -1;
symstrindex = -1;
for (i = 0; i < ehdr->e_shnum; i++) {
diff --git a/sys/boot/fdt/fdt_loader_cmd.c b/sys/boot/fdt/fdt_loader_cmd.c
index 1d65fe7..b32fddf 100644
--- a/sys/boot/fdt/fdt_loader_cmd.c
+++ b/sys/boot/fdt/fdt_loader_cmd.c
@@ -118,16 +118,17 @@ static char cwd[FDT_CWD_LEN] = "/";
static vm_offset_t
fdt_find_static_dtb()
{
- Elf_Dyn dyn;
+ Elf_Ehdr *ehdr;
+ Elf_Shdr *shdr;
Elf_Sym sym;
- vm_offset_t dyntab, esym, strtab, symtab, fdt_start;
+ vm_offset_t strtab, symtab, fdt_start;
uint64_t offs;
struct preloaded_file *kfp;
struct file_metadata *md;
char *strp;
- int sym_count;
+ int i, sym_count;
- symtab = strtab = dyntab = esym = 0;
+ symtab = strtab = 0;
strp = NULL;
offs = __elfN(relocation_offset);
@@ -136,42 +137,26 @@ fdt_find_static_dtb()
if (kfp == NULL)
return (0);
- md = file_findmetadata(kfp, MODINFOMD_ESYM);
+ /* Locate the dynamic symbols and strtab. */
+ md = file_findmetadata(kfp, MODINFOMD_ELFHDR);
if (md == NULL)
return (0);
- bcopy(md->md_data, &esym, sizeof(esym));
- /* esym is already offset */
+ ehdr = (Elf_Ehdr *)md->md_data;
- md = file_findmetadata(kfp, MODINFOMD_DYNAMIC);
+ md = file_findmetadata(kfp, MODINFOMD_SHDR);
if (md == NULL)
return (0);
- bcopy(md->md_data, &dyntab, sizeof(dyntab));
- dyntab += offs;
-
- /* Locate STRTAB and DYNTAB */
- for (;;) {
- COPYOUT(dyntab, &dyn, sizeof(dyn));
- if (dyn.d_tag == DT_STRTAB) {
- strtab = (vm_offset_t)(dyn.d_un.d_ptr) + offs;
- } else if (dyn.d_tag == DT_SYMTAB) {
- symtab = (vm_offset_t)(dyn.d_un.d_ptr) + offs;
- } else if (dyn.d_tag == DT_NULL) {
- break;
+ shdr = (Elf_Shdr *)md->md_data;
+
+ for (i = 0; i < ehdr->e_shnum; ++i) {
+ if (shdr[i].sh_type == SHT_DYNSYM && symtab == 0) {
+ symtab = shdr[i].sh_addr + offs;
+ sym_count = shdr[i].sh_size / sizeof(Elf_Sym);
+ } else if (shdr[i].sh_type == SHT_STRTAB && strtab == 0) {
+ strtab = shdr[i].sh_addr + offs;
}
- dyntab += sizeof(dyn);
}
- if (symtab == 0 || strtab == 0) {
- /*
- * No symtab? No strtab? That should not happen here,
- * and should have been verified during __elfN(loadimage).
- * This must be some kind of a bug.
- */
- return (0);
- }
-
- sym_count = (int)(esym - symtab) / sizeof(Elf_Sym);
-
/*
* The most efficent way to find a symbol would be to calculate a
* hash, find proper bucket and chain, and thus find a symbol.
OpenPOWER on IntegriCloud