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,7 +317,57 @@ 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; +} + +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; + + /* 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. + * We're not going to take on the task of + * fully validating the ELF file. That way + * lies madness. + */ + if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + xdr = &xdr_be; + + 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. @@ -325,28 +384,20 @@ elf_headers(const struct buffer *pinput, Elf64_Phdr **pphdr, Elf64_Shdr **pshdr) { - struct xdr *xdr = &xdr_le; - int bit64 = 0; - struct buffer input; - buffer_clone(&input, pinput); + struct parsed_elf pelf; + int flags; - if (!iself(buffer_get(pinput))) { - ERROR("The stage file is not in ELF format!\n"); + flags = ELF_PARSE_PHDR; + + if (pshdr != NULL) + flags |= ELF_PARSE_SHDR; + + if (parse_elf(pinput, &pelf, flags)) return -1; - } - elf_eident(&input, ehdr); - bit64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64; - /* Assume LE unless we are sure otherwise. - * We're not going to take on the task of - * fully validating the ELF file. That way - * lies madness. - */ - if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) - xdr = &xdr_be; - - elf_ehdr(&input, ehdr, xdr, bit64); + /* 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 && @@ -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,