summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/cbfstool/elfheaders.c87
-rw-r--r--util/cbfstool/elfparsing.h10
2 files changed, 97 insertions, 0 deletions
diff --git a/util/cbfstool/elfheaders.c b/util/cbfstool/elfheaders.c
index 94c16b0a1f..8e06f5e9d5 100644
--- a/util/cbfstool/elfheaders.c
+++ b/util/cbfstool/elfheaders.c
@@ -322,6 +322,79 @@ shdr_read(const struct buffer *in, struct parsed_elf *pelf,
return 0;
}
+static int
+reloc_read(const struct buffer *in, struct parsed_elf *pelf,
+ struct xdr *xdr, int bit64)
+{
+ struct buffer b;
+ Elf64_Word i;
+ Elf64_Ehdr *ehdr;
+
+ ehdr = &pelf->ehdr;
+ pelf->relocs = calloc(ehdr->e_shnum, sizeof(Elf64_Rela *));
+
+ /* Allocate array for each section that contains relocation entries. */
+ for (i = 0; i < ehdr->e_shnum; i++) {
+ Elf64_Shdr *shdr;
+ Elf64_Rela *rela;
+ Elf64_Xword j;
+ Elf64_Xword nrelocs;
+ int is_rela;
+
+ shdr = &pelf->shdr[i];
+
+ /* Only process REL and RELA sections. */
+ if (shdr->sh_type != SHT_REL && shdr->sh_type != SHT_RELA)
+ continue;
+
+ DEBUG("Checking relocation section %u\n", i);
+
+ /* Ensure the section that relocations apply is a valid. */
+ if (shdr->sh_info >= ehdr->e_shnum ||
+ shdr->sh_info == SHN_UNDEF) {
+ ERROR("Relocations apply to an invalid section: %u\n",
+ shdr[i].sh_info);
+ return -1;
+ }
+
+ is_rela = shdr->sh_type == SHT_RELA;
+
+ /* Determine the number relocations in this section. */
+ nrelocs = shdr->sh_size / shdr->sh_entsize;
+
+ pelf->relocs[i] = calloc(nrelocs, sizeof(Elf64_Rela));
+
+ buffer_splice(&b, in, shdr->sh_offset, shdr->sh_size);
+ if (check_size(in, shdr->sh_offset, buffer_size(&b),
+ "relocation section")) {
+ ERROR("Relocation section %u failed.\n", i);
+ return -1;
+ }
+
+ rela = pelf->relocs[i];
+ for (j = 0; j < nrelocs; j++) {
+ if (bit64) {
+ rela->r_offset = xdr->get64(&b);
+ rela->r_info = xdr->get64(&b);
+ if (is_rela)
+ rela->r_addend = xdr->get64(&b);
+ } else {
+ uint32_t r_info;
+
+ rela->r_offset = xdr->get32(&b);
+ r_info = xdr->get32(&b);
+ rela->r_info = ELF64_R_INFO(ELF32_R_SYM(r_info),
+ ELF32_R_TYPE(r_info));
+ if (is_rela)
+ rela->r_addend = xdr->get32(&b);
+ }
+ rela++;
+ }
+ }
+
+ return 0;
+}
+
int parse_elf(const struct buffer *pinput, struct parsed_elf *pelf, int flags)
{
struct xdr *xdr = &xdr_le;
@@ -351,12 +424,19 @@ int parse_elf(const struct buffer *pinput, struct parsed_elf *pelf, int flags)
elf_ehdr(&input, ehdr, xdr, bit64);
+ /* Relocation processing requires section header parsing. */
+ if (flags & ELF_PARSE_RELOC)
+ flags |= ELF_PARSE_SHDR;
+
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;
+ if ((flags & ELF_PARSE_RELOC) && reloc_read(pinput, pelf, xdr, bit64))
+ goto fail;
+
return 0;
fail:
@@ -368,6 +448,13 @@ void parsed_elf_destroy(struct parsed_elf *pelf)
{
free(pelf->phdr);
free(pelf->shdr);
+ if (pelf->relocs != NULL) {
+ Elf64_Half i;
+
+ for (i = 0; i < pelf->ehdr.e_shnum; i++)
+ free(pelf->relocs[i]);
+ }
+ free(pelf->relocs);
}
/* Get the headers from the buffer.
diff --git a/util/cbfstool/elfparsing.h b/util/cbfstool/elfparsing.h
index 4ad46b3928..2827748c06 100644
--- a/util/cbfstool/elfparsing.h
+++ b/util/cbfstool/elfparsing.h
@@ -26,10 +26,20 @@ struct parsed_elf {
Elf64_Ehdr ehdr;
Elf64_Phdr *phdr;
Elf64_Shdr *shdr;
+ /*
+ * The relocs array contains pointers to arrays of relocation
+ * structures. Each index into the relocs array corresponds to its
+ * corresponding section index. i.e. if a section i is of type SHT_REL
+ * or SHT_RELA then the corresponding index into the relocs array will
+ * contain the associated relocations. Otherwise thee entry will be
+ * NULL.
+ */
+ Elf64_Rela **relocs;
};
#define ELF_PARSE_PHDR (1 << 0)
#define ELF_PARSE_SHDR (1 << 1)
+#define ELF_PARSE_RELOC (1 << 2)
#define ELF_PARSE_ALL (-1)