From ddd260eb620d65f58913e23152a6cc0c67564444 Mon Sep 17 00:00:00 2001 From: Johann Date: Wed, 23 Feb 2011 17:07:35 -0500 Subject: [PATCH] 64bit elf support enable parsing 64bit elf files Change-Id: I7981f4769cf1b822f288fe2e32166254e4394bab --- build/make/obj_int_extract.c | 509 ++++++++++++++++++++++++++++++------------- 1 file changed, 358 insertions(+), 151 deletions(-) diff --git a/build/make/obj_int_extract.c b/build/make/obj_int_extract.c index 3c54b24..5f11e40 100644 --- a/build/make/obj_int_extract.c +++ b/build/make/obj_int_extract.c @@ -218,7 +218,7 @@ bail: return EXIT_FAILURE; } -#else +#elif defined(__ELF__) #include "elf.h" #define COPY_STRUCT(dst, buf, ofst, sz) do {\ @@ -237,212 +237,420 @@ bail: typedef struct { - uint8_t *buf; /* Buffer containing ELF data */ - size_t sz; /* Buffer size */ - int le_data; /* Data is little-endian */ - Elf32_Ehdr hdr; + uint8_t *buf; /* Buffer containing ELF data */ + size_t sz; /* Buffer size */ + int le_data; /* Data is little-endian */ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + int bits; /* 32 or 64 */ + Elf32_Ehdr hdr32; + Elf64_Ehdr hdr64; } elf_obj_t; -int parse_elf32_header(elf_obj_t *elf) +int parse_elf_header(elf_obj_t *elf) { int res; - /* Verify ELF32 header */ - COPY_STRUCT(&elf->hdr, elf->buf, 0, elf->sz); - res = elf->hdr.e_ident[EI_MAG0] == ELFMAG0; - res &= elf->hdr.e_ident[EI_MAG1] == ELFMAG1; - res &= elf->hdr.e_ident[EI_MAG2] == ELFMAG2; - res &= elf->hdr.e_ident[EI_MAG3] == ELFMAG3; - res &= elf->hdr.e_ident[EI_CLASS] == ELFCLASS32; - res &= elf->hdr.e_ident[EI_DATA] == ELFDATA2LSB - || elf->hdr.e_ident[EI_DATA] == ELFDATA2MSB; + /* Verify ELF Magic numbers */ + COPY_STRUCT(&elf->e_ident, elf->buf, 0, elf->sz); + res = elf->e_ident[EI_MAG0] == ELFMAG0; + res &= elf->e_ident[EI_MAG1] == ELFMAG1; + res &= elf->e_ident[EI_MAG2] == ELFMAG2; + res &= elf->e_ident[EI_MAG3] == ELFMAG3; + res &= elf->e_ident[EI_CLASS] == ELFCLASS32 + || elf->e_ident[EI_CLASS] == ELFCLASS64; + res &= elf->e_ident[EI_DATA] == ELFDATA2LSB; if (!res) goto bail; - elf->le_data = elf->hdr.e_ident[EI_DATA] == ELFDATA2LSB; - - ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_type); - ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_machine); - ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_version); - ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_entry); - ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_phoff); - ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_shoff); - ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_flags); - ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_ehsize); - ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_phentsize); - ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_phnum); - ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_shentsize); - ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_shnum); - ENDIAN_ASSIGN_IN_PLACE(elf->hdr.e_shstrndx); + elf->le_data = elf->e_ident[EI_DATA] == ELFDATA2LSB; + + /* Read in relevant values */ + if (elf->e_ident[EI_CLASS] == ELFCLASS32) + { + elf->bits = 32; + COPY_STRUCT(&elf->hdr32, elf->buf, 0, elf->sz); + + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_type); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_machine); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_version); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_entry); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phoff); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shoff); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_flags); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_ehsize); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phentsize); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phnum); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shentsize); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shnum); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shstrndx); + } + else /* if (elf->e_ident[EI_CLASS] == ELFCLASS64) */ + { + elf->bits = 64; + COPY_STRUCT(&elf->hdr64, elf->buf, 0, elf->sz); + + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_type); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_machine); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_version); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_entry); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phoff); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shoff); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_flags); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_ehsize); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phentsize); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phnum); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shentsize); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shnum); + ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shstrndx); + } + return 0; bail: + log_msg("Failed to parse ELF file header"); return 1; } -int parse_elf32_section(elf_obj_t *elf, int idx, Elf32_Shdr *hdr) +int parse_elf_section(elf_obj_t *elf, int idx, Elf32_Shdr *hdr32, Elf64_Shdr *hdr64) { - if (idx >= elf->hdr.e_shnum) - goto bail; + if (hdr32) + { + if (idx >= elf->hdr32.e_shnum) + goto bail; + + COPY_STRUCT(hdr32, elf->buf, elf->hdr32.e_shoff + idx * elf->hdr32.e_shentsize, + elf->sz); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_name); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_type); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_flags); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_addr); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_offset); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_size); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_link); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_info); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_addralign); + ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_entsize); + } + else /* if (hdr64) */ + { + if (idx >= elf->hdr64.e_shnum) + goto bail; + + COPY_STRUCT(hdr64, elf->buf, elf->hdr64.e_shoff + idx * elf->hdr64.e_shentsize, + elf->sz); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_name); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_type); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_flags); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_addr); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_offset); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_size); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_link); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_info); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_addralign); + ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_entsize); + } - COPY_STRUCT(hdr, elf->buf, elf->hdr.e_shoff + idx * elf->hdr.e_shentsize, - elf->sz); - ENDIAN_ASSIGN_IN_PLACE(hdr->sh_name); - ENDIAN_ASSIGN_IN_PLACE(hdr->sh_type); - ENDIAN_ASSIGN_IN_PLACE(hdr->sh_flags); - ENDIAN_ASSIGN_IN_PLACE(hdr->sh_addr); - ENDIAN_ASSIGN_IN_PLACE(hdr->sh_offset); - ENDIAN_ASSIGN_IN_PLACE(hdr->sh_size); - ENDIAN_ASSIGN_IN_PLACE(hdr->sh_link); - ENDIAN_ASSIGN_IN_PLACE(hdr->sh_info); - ENDIAN_ASSIGN_IN_PLACE(hdr->sh_addralign); - ENDIAN_ASSIGN_IN_PLACE(hdr->sh_entsize); return 0; bail: return 1; } -char *parse_elf32_string_table(elf_obj_t *elf, int s_idx, int idx) +char *parse_elf_string_table(elf_obj_t *elf, int s_idx, int idx) { - Elf32_Shdr shdr; - - if (parse_elf32_section(elf, s_idx, &shdr)) + if (elf->bits == 32) { - log_msg("Failed to parse ELF string table: section %d, index %d\n", - s_idx, idx); - return ""; + Elf32_Shdr shdr; + + if (parse_elf_section(elf, s_idx, &shdr, NULL)) + { + log_msg("Failed to parse ELF string table: section %d, index %d\n", + s_idx, idx); + return ""; + } + + return (char *)(elf->buf + shdr.sh_offset + idx); } + else /* if (elf->bits == 64) */ + { + Elf64_Shdr shdr; + + if (parse_elf_section(elf, s_idx, NULL, &shdr)) + { + log_msg("Failed to parse ELF string table: section %d, index %d\n", + s_idx, idx); + return ""; + } - return (char *)(elf->buf + shdr.sh_offset + idx); + return (char *)(elf->buf + shdr.sh_offset + idx); + } } -int parse_elf32_symbol(elf_obj_t *elf, unsigned int ofst, Elf32_Sym *sym) +int parse_elf_symbol(elf_obj_t *elf, unsigned int ofst, Elf32_Sym *sym32, Elf64_Sym *sym64) { - COPY_STRUCT(sym, elf->buf, ofst, elf->sz); - ENDIAN_ASSIGN_IN_PLACE(sym->st_name); - ENDIAN_ASSIGN_IN_PLACE(sym->st_value); - ENDIAN_ASSIGN_IN_PLACE(sym->st_size); - ENDIAN_ASSIGN_IN_PLACE(sym->st_info); - ENDIAN_ASSIGN_IN_PLACE(sym->st_other); - ENDIAN_ASSIGN_IN_PLACE(sym->st_shndx); + if (sym32) + { + COPY_STRUCT(sym32, elf->buf, ofst, elf->sz); + ENDIAN_ASSIGN_IN_PLACE(sym32->st_name); + ENDIAN_ASSIGN_IN_PLACE(sym32->st_value); + ENDIAN_ASSIGN_IN_PLACE(sym32->st_size); + ENDIAN_ASSIGN_IN_PLACE(sym32->st_info); + ENDIAN_ASSIGN_IN_PLACE(sym32->st_other); + ENDIAN_ASSIGN_IN_PLACE(sym32->st_shndx); + } + else /* if (sym64) */ + { + COPY_STRUCT(sym64, elf->buf, ofst, elf->sz); + ENDIAN_ASSIGN_IN_PLACE(sym64->st_name); + ENDIAN_ASSIGN_IN_PLACE(sym64->st_value); + ENDIAN_ASSIGN_IN_PLACE(sym64->st_size); + ENDIAN_ASSIGN_IN_PLACE(sym64->st_info); + ENDIAN_ASSIGN_IN_PLACE(sym64->st_other); + ENDIAN_ASSIGN_IN_PLACE(sym64->st_shndx); + } return 0; bail: return 1; } -int parse_elf32(uint8_t *buf, size_t sz, output_fmt_t mode) +int parse_elf(uint8_t *buf, size_t sz, output_fmt_t mode) { - elf_obj_t elf; - Elf32_Shdr shdr; + elf_obj_t elf; unsigned int ofst; - int i; - Elf32_Off strtab_off; /* save String Table offset for later use */ + int i; + Elf32_Off strtab_off32; + Elf64_Off strtab_off64; /* save String Table offset for later use */ memset(&elf, 0, sizeof(elf)); elf.buf = buf; elf.sz = sz; /* Parse Header */ - if (parse_elf32_header(&elf)) - { - log_msg("Parse error: File does not appear to be valid ELF32\n"); - return 1; - } + if (parse_elf_header(&elf)) + goto bail; - for (i = 0; i < elf.hdr.e_shnum; i++) + if (elf.bits == 32) { - parse_elf32_section(&elf, i, &shdr); - - if (shdr.sh_type == SHT_STRTAB) + Elf32_Shdr shdr; + for (i = 0; i < elf.hdr32.e_shnum; i++) { - char strtsb_name[128]; - - strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name)); + parse_elf_section(&elf, i, &shdr, NULL); - if (!(strcmp(strtsb_name, ".shstrtab"))) + if (shdr.sh_type == SHT_STRTAB) { - log_msg("found section: %s\n", strtsb_name); - strtab_off = shdr.sh_offset; - break; + char strtsb_name[128]; + + strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name)); + + if (!(strcmp(strtsb_name, ".shstrtab"))) + { + /* log_msg("found section: %s\n", strtsb_name); */ + strtab_off32 = shdr.sh_offset; + break; + } } } } - - /* Parse all Symbol Tables */ - for (i = 0; i < elf.hdr.e_shnum; i++) + else /* if (elf.bits == 64) */ { - - parse_elf32_section(&elf, i, &shdr); - - if (shdr.sh_type == SHT_SYMTAB) + Elf64_Shdr shdr; + for (i = 0; i < elf.hdr64.e_shnum; i++) { - for (ofst = shdr.sh_offset; - ofst < shdr.sh_offset + shdr.sh_size; - ofst += shdr.sh_entsize) - { - Elf32_Sym sym; + parse_elf_section(&elf, i, NULL, &shdr); - parse_elf32_symbol(&elf, ofst, &sym); + if (shdr.sh_type == SHT_STRTAB) + { + char strtsb_name[128]; - /* For all OBJECTS (data objects), extract the value from the - * proper data segment. - */ - if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name) - log_msg("found data object %s\n", - parse_elf32_string_table(&elf, - shdr.sh_link, - sym.st_name)); + strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name)); - if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT - && sym.st_size == 4) + if (!(strcmp(strtsb_name, ".shstrtab"))) { - Elf32_Shdr dhdr; - int32_t val; - char section_name[128]; - - parse_elf32_section(&elf, sym.st_shndx, &dhdr); + /* log_msg("found section: %s\n", strtsb_name); */ + strtab_off64 = shdr.sh_offset; + break; + } + } + } + } - /* For explanition - refer to _MSC_VER version of code */ - strcpy(section_name, (char *)(elf.buf + strtab_off + dhdr.sh_name)); - log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); + /* Parse all Symbol Tables */ + if (elf.bits == 32) + { + Elf32_Shdr shdr; + for (i = 0; i < elf.hdr32.e_shnum; i++) + { + parse_elf_section(&elf, i, &shdr, NULL); - if (!(strcmp(section_name, ".bss"))) - { - val = 0; - } - else + if (shdr.sh_type == SHT_SYMTAB) + { + for (ofst = shdr.sh_offset; + ofst < shdr.sh_offset + shdr.sh_size; + ofst += shdr.sh_entsize) + { + Elf32_Sym sym; + + parse_elf_symbol(&elf, ofst, &sym, NULL); + + /* For all OBJECTS (data objects), extract the value from the + * proper data segment. + */ + /* if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name) + log_msg("found data object %s\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name)); + */ + + if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT + && sym.st_size == 4) { - memcpy(&val, - elf.buf + dhdr.sh_offset + sym.st_value, - sizeof(val)); + Elf32_Shdr dhdr; + int val = 0; + char section_name[128]; + + parse_elf_section(&elf, sym.st_shndx, &dhdr, NULL); + + /* For explanition - refer to _MSC_VER version of code */ + strcpy(section_name, (char *)(elf.buf + strtab_off32 + dhdr.sh_name)); + /* log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); */ + + if (strcmp(section_name, ".bss")) + { + if (sizeof(val) != sym.st_size) + { + /* The target value is declared as an int in + * asm_*_offsets.c, which is 4 bytes on all + * targets we currently use. Complain loudly if + * this is not true. + */ + log_msg("Symbol size is wrong\n"); + goto bail; + } + + memcpy(&val, + elf.buf + dhdr.sh_offset + sym.st_value, + sym.st_size); + } + + if (!elf.le_data) + { + log_msg("Big Endian data not supported yet!\n"); + goto bail; + } + + switch (mode) + { + case OUTPUT_FMT_RVDS: + printf("%-40s EQU %5d\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name), + val); + break; + case OUTPUT_FMT_GAS: + printf(".equ %-40s, %5d\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name), + val); + break; + default: + printf("%s = %d\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name), + val); + } } + } + } + } + } + else /* if (elf.bits == 64) */ + { + Elf64_Shdr shdr; + for (i = 0; i < elf.hdr64.e_shnum; i++) + { + parse_elf_section(&elf, i, NULL, &shdr); - if (!elf.le_data) - { - log_msg("Big Endian data not supported yet!\n"); - goto bail; - }\ - - switch (mode) + if (shdr.sh_type == SHT_SYMTAB) + { + for (ofst = shdr.sh_offset; + ofst < shdr.sh_offset + shdr.sh_size; + ofst += shdr.sh_entsize) + { + Elf64_Sym sym; + + parse_elf_symbol(&elf, ofst, NULL, &sym); + + /* For all OBJECTS (data objects), extract the value from the + * proper data segment. + */ + /* if (ELF64_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name) + log_msg("found data object %s\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name)); + */ + + if (ELF64_ST_TYPE(sym.st_info) == STT_OBJECT + && sym.st_size == 4) { - case OUTPUT_FMT_RVDS: - printf("%-40s EQU %5d\n", - parse_elf32_string_table(&elf, - shdr.sh_link, - sym.st_name), - val); - break; - case OUTPUT_FMT_GAS: - printf(".equ %-40s, %5d\n", - parse_elf32_string_table(&elf, - shdr.sh_link, - sym.st_name), - val); - break; - default: - printf("%s = %d\n", - parse_elf32_string_table(&elf, - shdr.sh_link, - sym.st_name), - val); + Elf64_Shdr dhdr; + int val = 0; + char section_name[128]; + + parse_elf_section(&elf, sym.st_shndx, NULL, &dhdr); + + /* For explanition - refer to _MSC_VER version of code */ + strcpy(section_name, (char *)(elf.buf + strtab_off64 + dhdr.sh_name)); + /* log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); */ + + if ((strcmp(section_name, ".bss"))) + { + if (sizeof(val) != sym.st_size) + { + /* The target value is declared as an int in + * asm_*_offsets.c, which is 4 bytes on all + * targets we currently use. Complain loudly if + * this is not true. + */ + log_msg("Symbol size is wrong\n"); + goto bail; + } + + memcpy(&val, + elf.buf + dhdr.sh_offset + sym.st_value, + sym.st_size); + } + + if (!elf.le_data) + { + log_msg("Big Endian data not supported yet!\n"); + goto bail; + } + + switch (mode) + { + case OUTPUT_FMT_RVDS: + printf("%-40s EQU %5d\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name), + val); + break; + case OUTPUT_FMT_GAS: + printf(".equ %-40s, %5d\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name), + val); + break; + default: + printf("%s = %d\n", + parse_elf_string_table(&elf, + shdr.sh_link, + sym.st_name), + val); + } } } } @@ -454,7 +662,7 @@ int parse_elf32(uint8_t *buf, size_t sz, output_fmt_t mode) return 0; bail: - log_msg("Parse error: File does not appear to be valid ELF32\n"); + log_msg("Parse error: File does not appear to be valid ELF32 or ELF64\n"); return 1; } @@ -521,8 +729,7 @@ int main(int argc, char **argv) goto bail; } - res = parse_elf32(file_buf, stat_buf.st_size, mode); - //res = parse_coff(file_buf, stat_buf.st_size); + res = parse_elf(file_buf, stat_buf.st_size, mode); free(file_buf); if (!res) -- 2.7.4