cbfstool: add symbol table parsing to the ELF parser

Optionally parse the symbol table contained within an ELF
file. It currently assumes there is only one symbol table present,
and it errors out if more than one is found.

Change-Id: I4ac4ad03184a319562576d8ab24fa620e701672a
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/5376
Tested-by: build bot (Jenkins)
Reviewed-by: Marc Jones <marc.jones@se-eng.com>
This commit is contained in:
Aaron Durbin 2014-03-05 16:41:27 -06:00 committed by Aaron Durbin
parent c3e6e14a12
commit c078094f39
2 changed files with 74 additions and 0 deletions

View File

@ -430,6 +430,69 @@ static int strtab_read(const struct buffer *in, struct parsed_elf *pelf)
return 0; return 0;
} }
static int
symtab_read(const struct buffer *in, struct parsed_elf *pelf,
struct xdr *xdr, int bit64)
{
Elf64_Ehdr *ehdr;
Elf64_Shdr *shdr;
Elf64_Half i;
Elf64_Xword nsyms;
Elf64_Sym *sym;
struct buffer b;
ehdr = &pelf->ehdr;
shdr = NULL;
for (i = 0; i < ehdr->e_shnum; i++) {
if (pelf->shdr[i].sh_type != SHT_SYMTAB)
continue;
if (shdr != NULL) {
ERROR("Multiple symbol sections found. %u and %u\n",
(unsigned int)(shdr - pelf->shdr), i);
return -1;
}
shdr = &pelf->shdr[i];
}
if (shdr == NULL) {
ERROR("No symbol table found.\n");
return -1;
}
buffer_splice(&b, in, shdr->sh_offset, shdr->sh_size);
if (check_size(in, shdr->sh_offset, buffer_size(&b), "symtab"))
return -1;
nsyms = shdr->sh_size / shdr->sh_entsize;
pelf->syms = calloc(nsyms, sizeof(Elf64_Sym));
for (i = 0; i < nsyms; i++) {
sym = &pelf->syms[i];
if (bit64) {
sym->st_name = xdr->get32(&b);
sym->st_info = xdr->get8(&b);
sym->st_other = xdr->get8(&b);
sym->st_shndx = xdr->get16(&b);
sym->st_value = xdr->get64(&b);
sym->st_size = xdr->get64(&b);
} else {
sym->st_name = xdr->get32(&b);
sym->st_value = xdr->get32(&b);
sym->st_size = xdr->get32(&b);
sym->st_info = xdr->get8(&b);
sym->st_other = xdr->get8(&b);
sym->st_shndx = xdr->get16(&b);
}
}
return 0;
}
int parse_elf(const struct buffer *pinput, struct parsed_elf *pelf, int flags) int parse_elf(const struct buffer *pinput, struct parsed_elf *pelf, int flags)
{ {
struct xdr *xdr = &xdr_le; struct xdr *xdr = &xdr_le;
@ -467,6 +530,10 @@ int parse_elf(const struct buffer *pinput, struct parsed_elf *pelf, int flags)
if (flags & ELF_PARSE_STRTAB) if (flags & ELF_PARSE_STRTAB)
flags |= ELF_PARSE_SHDR; flags |= ELF_PARSE_SHDR;
/* Symbole table processing requires section header parsing. */
if (flags & ELF_PARSE_SYMTAB)
flags |= ELF_PARSE_SHDR;
if ((flags & ELF_PARSE_PHDR) && phdr_read(pinput, pelf, xdr, bit64)) if ((flags & ELF_PARSE_PHDR) && phdr_read(pinput, pelf, xdr, bit64))
goto fail; goto fail;
@ -479,6 +546,9 @@ int parse_elf(const struct buffer *pinput, struct parsed_elf *pelf, int flags)
if ((flags & ELF_PARSE_STRTAB) && strtab_read(pinput, pelf)) if ((flags & ELF_PARSE_STRTAB) && strtab_read(pinput, pelf))
goto fail; goto fail;
if ((flags & ELF_PARSE_SYMTAB) && symtab_read(pinput, pelf, xdr, bit64))
goto fail;
return 0; return 0;
fail: fail:
@ -503,6 +573,7 @@ void parsed_elf_destroy(struct parsed_elf *pelf)
free(pelf->strtabs[i]); free(pelf->strtabs[i]);
} }
free(pelf->strtabs); free(pelf->strtabs);
free(pelf->syms);
} }
/* Get the headers from the buffer. /* Get the headers from the buffer.

View File

@ -41,12 +41,15 @@ struct parsed_elf {
* entry. * entry.
*/ */
struct buffer **strtabs; struct buffer **strtabs;
/* Parsed symbols. */
Elf64_Sym *syms;
}; };
#define ELF_PARSE_PHDR (1 << 0) #define ELF_PARSE_PHDR (1 << 0)
#define ELF_PARSE_SHDR (1 << 1) #define ELF_PARSE_SHDR (1 << 1)
#define ELF_PARSE_RELOC (1 << 2) #define ELF_PARSE_RELOC (1 << 2)
#define ELF_PARSE_STRTAB (1 << 3) #define ELF_PARSE_STRTAB (1 << 3)
#define ELF_PARSE_SYMTAB (1 << 4)
#define ELF_PARSE_ALL (-1) #define ELF_PARSE_ALL (-1)