diff options
author | Aaron Durbin <adurbin@chromium.org> | 2014-03-05 13:09:55 -0600 |
---|---|---|
committer | Aaron Durbin <adurbin@google.com> | 2014-03-14 21:50:42 +0100 |
commit | d0f61659238c3ed79fecf841c58cabedbf936ac8 (patch) | |
tree | e828bd0807ffe8c6ab592e066283d1fb0e14a31b | |
parent | 19a11d6fe9593e585aff8a5787d25e38faa3d88c (diff) |
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>
Reviewed-on: http://review.coreboot.org/5373
Tested-by: build bot (Jenkins)
Reviewed-by: Marc Jones <marc.jones@se-eng.com>
-rw-r--r-- | util/cbfstool/elfheaders.c | 112 | ||||
-rw-r--r-- | 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 03d8e7d68c..94c16b0a1f 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 3cfa1cd6ba..4ad46b3928 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, |