Aaron Durbin (adurbin@google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5373
-gerrit
commit 6b57aee277b11e96876feb86b45145b811ceaf80 Author: Aaron Durbin adurbin@chromium.org Date: Wed Mar 5 13:09:55 2014 -0600
cbfstool: introduce struct parsed_elf and parse_elf()
In order to make the ELF parsing more flexible introduce a parse_elf() function which takes a struct parsed_elf parameter. In addition take a flags parameter which instructs the ELF parser as to what data within the ELF file should be parsed.
Change-Id: I3e30e84bf8043c3df96a6ab56cd077eef2632173 Signed-off-by: Aaron Durbin adurbin@chromium.org --- util/cbfstool/elfheaders.c | 112 ++++++++++++++++++++++++++++++++------------- util/cbfstool/elfparsing.h | 25 ++++++++++ 2 files changed, 106 insertions(+), 31 deletions(-)
diff --git a/util/cbfstool/elfheaders.c b/util/cbfstool/elfheaders.c index 03d8e7d..94c16b0 100644 --- a/util/cbfstool/elfheaders.c +++ b/util/cbfstool/elfheaders.c @@ -251,13 +251,16 @@ elf_shdr(struct buffer *pinput, Elf64_Shdr *shdr, buffer_seek(pinput, entsize); }
-static Elf64_Phdr * -phdr_read(const struct buffer *in, Elf64_Ehdr *ehdr, struct xdr *xdr, int bit64) +static int +phdr_read(const struct buffer *in, struct parsed_elf *pelf, + struct xdr *xdr, int bit64) { struct buffer b; Elf64_Phdr *phdr; + Elf64_Ehdr *ehdr; int i;
+ ehdr = &pelf->ehdr; /* cons up an input buffer for the headers. * Note that the program headers can be anywhere, * per the ELF spec, You'd be surprised how many ELF @@ -265,7 +268,7 @@ phdr_read(const struct buffer *in, Elf64_Ehdr *ehdr, struct xdr *xdr, int bit64) */ buffer_splice(&b, in, ehdr->e_phoff, ehdr->e_phentsize * ehdr->e_phnum); if (check_size(in, ehdr->e_phoff, buffer_size(&b), "program headers")) - return NULL; + return -1;
/* gather up all the phdrs. * We do them all at once because there is more @@ -279,19 +282,25 @@ phdr_read(const struct buffer *in, Elf64_Ehdr *ehdr, struct xdr *xdr, int bit64) /* Ensure the contents are valid within the elf file. */ if (check_size(in, phdr[i].p_offset, phdr[i].p_filesz, "segment contents")) - return NULL; + return -1; }
- return phdr; + pelf->phdr = phdr; + + return 0; }
-static Elf64_Shdr * -shdr_read(const struct buffer *in, Elf64_Ehdr *ehdr, struct xdr *xdr, int bit64) +static int +shdr_read(const struct buffer *in, struct parsed_elf *pelf, + struct xdr *xdr, int bit64) { struct buffer b; Elf64_Shdr *shdr; + Elf64_Ehdr *ehdr; int i;
+ ehdr = &pelf->ehdr; + /* cons up an input buffer for the section headers. * Note that the section headers can be anywhere, * per the ELF spec, You'd be surprised how many ELF @@ -299,7 +308,7 @@ shdr_read(const struct buffer *in, Elf64_Ehdr *ehdr, struct xdr *xdr, int bit64) */ buffer_splice(&b, in, ehdr->e_shoff, ehdr->e_shentsize * ehdr->e_shnum); if (check_size(in, ehdr->e_shoff, buffer_size(&b), "section headers")) - return NULL; + return -1;
/* gather up all the shdrs. */ shdr = calloc(ehdr->e_shnum, sizeof(*shdr)); @@ -308,34 +317,28 @@ shdr_read(const struct buffer *in, Elf64_Ehdr *ehdr, struct xdr *xdr, int bit64) elf_shdr(&b, &shdr[i], ehdr->e_shentsize, xdr, bit64); }
- return shdr; + pelf->shdr = shdr; + + return 0; }
-/* Get the headers from the buffer. - * Return -1 in the event of an error. - * The section headers are optional; if NULL - * is passed in for pshdr they won't be parsed. - * We don't (yet) make payload parsing optional - * because we've never seen a use case. - */ -int -elf_headers(const struct buffer *pinput, - uint32_t arch, - Elf64_Ehdr *ehdr, - Elf64_Phdr **pphdr, - Elf64_Shdr **pshdr) +int parse_elf(const struct buffer *pinput, struct parsed_elf *pelf, int flags) { struct xdr *xdr = &xdr_le; int bit64 = 0; struct buffer input; + Elf64_Ehdr *ehdr;
- buffer_clone(&input, pinput); + /* Zero out the parsed elf structure. */ + memset(pelf, 0, sizeof(*pelf));
if (!iself(buffer_get(pinput))) { ERROR("The stage file is not in ELF format!\n"); return -1; }
+ buffer_clone(&input, pinput); + ehdr = &pelf->ehdr; elf_eident(&input, ehdr); bit64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64; /* Assume LE unless we are sure otherwise. @@ -348,6 +351,54 @@ elf_headers(const struct buffer *pinput,
elf_ehdr(&input, ehdr, xdr, bit64);
+ if ((flags & ELF_PARSE_PHDR) && phdr_read(pinput, pelf, xdr, bit64)) + goto fail; + + if ((flags & ELF_PARSE_SHDR) && shdr_read(pinput, pelf, xdr, bit64)) + goto fail; + + return 0; + +fail: + parsed_elf_destroy(pelf); + return -1; +} + +void parsed_elf_destroy(struct parsed_elf *pelf) +{ + free(pelf->phdr); + free(pelf->shdr); +} + +/* Get the headers from the buffer. + * Return -1 in the event of an error. + * The section headers are optional; if NULL + * is passed in for pshdr they won't be parsed. + * We don't (yet) make payload parsing optional + * because we've never seen a use case. + */ +int +elf_headers(const struct buffer *pinput, + uint32_t arch, + Elf64_Ehdr *ehdr, + Elf64_Phdr **pphdr, + Elf64_Shdr **pshdr) +{ + + struct parsed_elf pelf; + int flags; + + flags = ELF_PARSE_PHDR; + + if (pshdr != NULL) + flags |= ELF_PARSE_SHDR; + + if (parse_elf(pinput, &pelf, flags)) + return -1; + + /* Copy out the parsed elf header. */ + memcpy(ehdr, &pelf.ehdr, sizeof(*ehdr)); + // The tool may work in architecture-independent way. if (arch != CBFS_ARCHITECTURE_UNKNOWN && !((ehdr->e_machine == EM_ARM) && (arch == CBFS_ARCHITECTURE_ARMV7)) && @@ -356,16 +407,15 @@ elf_headers(const struct buffer *pinput, return -1; }
- *pphdr = phdr_read(pinput, ehdr, xdr, bit64); - if (*pphdr == NULL) - return -1; + *pphdr = calloc(ehdr->e_phnum, sizeof(Elf64_Phdr)); + memcpy(*pphdr, pelf.phdr, ehdr->e_phnum * sizeof(Elf64_Phdr));
- if (!pshdr) - return 0; + if (pshdr != NULL) { + *pshdr = calloc(ehdr->e_shnum, sizeof(Elf64_Shdr)); + memcpy(*pshdr, pelf.shdr, ehdr->e_shnum * sizeof(Elf64_Shdr)); + }
- *pshdr = shdr_read(pinput, ehdr, xdr, bit64); - if (*pshdr == NULL) - return -1; + parsed_elf_destroy(&pelf);
return 0; } diff --git a/util/cbfstool/elfparsing.h b/util/cbfstool/elfparsing.h index 3cfa1cd..4ad46b3 100644 --- a/util/cbfstool/elfparsing.h +++ b/util/cbfstool/elfparsing.h @@ -22,6 +22,31 @@
struct buffer;
+struct parsed_elf { + Elf64_Ehdr ehdr; + Elf64_Phdr *phdr; + Elf64_Shdr *shdr; +}; + +#define ELF_PARSE_PHDR (1 << 0) +#define ELF_PARSE_SHDR (1 << 1) + +#define ELF_PARSE_ALL (-1) + +/* + * Parse an ELF file contained within provide struct buffer. The ELF header + * is always parsed while the flags value containing the ELF_PARSE_* values + * determine if other parts of the ELF file will be parsed as well. + * Returns 0 on success, < 0 error. + */ +int parse_elf(const struct buffer *pinput, struct parsed_elf *pelf, int flags); + +/* + * Clean up memory associated with parsed_elf. + */ +void parsed_elf_destroy(struct parsed_elf *pelf); + + int elf_headers(const struct buffer *pinput, uint32_t arch,