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>
This commit is contained in:
parent
19a11d6fe9
commit
d0f6165923
|
@ -251,13 +251,16 @@ elf_shdr(struct buffer *pinput, Elf64_Shdr *shdr,
|
||||||
buffer_seek(pinput, entsize);
|
buffer_seek(pinput, entsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Elf64_Phdr *
|
static int
|
||||||
phdr_read(const struct buffer *in, Elf64_Ehdr *ehdr, struct xdr *xdr, int bit64)
|
phdr_read(const struct buffer *in, struct parsed_elf *pelf,
|
||||||
|
struct xdr *xdr, int bit64)
|
||||||
{
|
{
|
||||||
struct buffer b;
|
struct buffer b;
|
||||||
Elf64_Phdr *phdr;
|
Elf64_Phdr *phdr;
|
||||||
|
Elf64_Ehdr *ehdr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
ehdr = &pelf->ehdr;
|
||||||
/* cons up an input buffer for the headers.
|
/* cons up an input buffer for the headers.
|
||||||
* Note that the program headers can be anywhere,
|
* Note that the program headers can be anywhere,
|
||||||
* per the ELF spec, You'd be surprised how many ELF
|
* 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);
|
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"))
|
if (check_size(in, ehdr->e_phoff, buffer_size(&b), "program headers"))
|
||||||
return NULL;
|
return -1;
|
||||||
|
|
||||||
/* gather up all the phdrs.
|
/* gather up all the phdrs.
|
||||||
* We do them all at once because there is more
|
* 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. */
|
/* Ensure the contents are valid within the elf file. */
|
||||||
if (check_size(in, phdr[i].p_offset, phdr[i].p_filesz,
|
if (check_size(in, phdr[i].p_offset, phdr[i].p_filesz,
|
||||||
"segment contents"))
|
"segment contents"))
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return phdr;
|
pelf->phdr = phdr;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Elf64_Shdr *
|
static int
|
||||||
shdr_read(const struct buffer *in, Elf64_Ehdr *ehdr, struct xdr *xdr, int bit64)
|
shdr_read(const struct buffer *in, struct parsed_elf *pelf,
|
||||||
|
struct xdr *xdr, int bit64)
|
||||||
{
|
{
|
||||||
struct buffer b;
|
struct buffer b;
|
||||||
Elf64_Shdr *shdr;
|
Elf64_Shdr *shdr;
|
||||||
|
Elf64_Ehdr *ehdr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
ehdr = &pelf->ehdr;
|
||||||
|
|
||||||
/* cons up an input buffer for the section headers.
|
/* cons up an input buffer for the section headers.
|
||||||
* Note that the section headers can be anywhere,
|
* Note that the section headers can be anywhere,
|
||||||
* per the ELF spec, You'd be surprised how many ELF
|
* 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);
|
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"))
|
if (check_size(in, ehdr->e_shoff, buffer_size(&b), "section headers"))
|
||||||
return NULL;
|
return -1;
|
||||||
|
|
||||||
/* gather up all the shdrs. */
|
/* gather up all the shdrs. */
|
||||||
shdr = calloc(ehdr->e_shnum, sizeof(*shdr));
|
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);
|
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.
|
/* Get the headers from the buffer.
|
||||||
|
@ -325,28 +384,20 @@ elf_headers(const struct buffer *pinput,
|
||||||
Elf64_Phdr **pphdr,
|
Elf64_Phdr **pphdr,
|
||||||
Elf64_Shdr **pshdr)
|
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))) {
|
flags = ELF_PARSE_PHDR;
|
||||||
ERROR("The stage file is not in ELF format!\n");
|
|
||||||
|
if (pshdr != NULL)
|
||||||
|
flags |= ELF_PARSE_SHDR;
|
||||||
|
|
||||||
|
if (parse_elf(pinput, &pelf, flags))
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
elf_eident(&input, ehdr);
|
/* Copy out the parsed elf header. */
|
||||||
bit64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64;
|
memcpy(ehdr, &pelf.ehdr, sizeof(*ehdr));
|
||||||
/* 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);
|
|
||||||
|
|
||||||
// The tool may work in architecture-independent way.
|
// The tool may work in architecture-independent way.
|
||||||
if (arch != CBFS_ARCHITECTURE_UNKNOWN &&
|
if (arch != CBFS_ARCHITECTURE_UNKNOWN &&
|
||||||
|
@ -356,16 +407,15 @@ elf_headers(const struct buffer *pinput,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*pphdr = phdr_read(pinput, ehdr, xdr, bit64);
|
*pphdr = calloc(ehdr->e_phnum, sizeof(Elf64_Phdr));
|
||||||
if (*pphdr == NULL)
|
memcpy(*pphdr, pelf.phdr, ehdr->e_phnum * sizeof(Elf64_Phdr));
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (!pshdr)
|
if (pshdr != NULL) {
|
||||||
return 0;
|
*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);
|
parsed_elf_destroy(&pelf);
|
||||||
if (*pshdr == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,31 @@
|
||||||
|
|
||||||
struct buffer;
|
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
|
int
|
||||||
elf_headers(const struct buffer *pinput,
|
elf_headers(const struct buffer *pinput,
|
||||||
uint32_t arch,
|
uint32_t arch,
|
||||||
|
|
Loading…
Reference in New Issue