From 1583b1cd53282efda61ab00da64e627667d9cda9 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Wed, 1 Dec 2010 16:17:11 +0000 Subject: [PATCH] sbinfo: first try at creating an elf file out of the .sb mess git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28717 a1c6a512-1295-4272-9138-f99709370657 --- utils/sbinfo/Makefile | 4 +- utils/sbinfo/elf.c | 169 ++++++++++++++++++++++++++++++++++++++++++ utils/sbinfo/elf.h | 140 ++++++++++++++++++++++++++++++++++ utils/sbinfo/sbinfo.c | 52 ++++++++++++- 4 files changed, 361 insertions(+), 4 deletions(-) create mode 100644 utils/sbinfo/elf.c create mode 100644 utils/sbinfo/elf.h diff --git a/utils/sbinfo/Makefile b/utils/sbinfo/Makefile index 8b2cd2649d..9427eaf875 100644 --- a/utils/sbinfo/Makefile +++ b/utils/sbinfo/Makefile @@ -2,8 +2,8 @@ TGT = sbinfo all: $(TGT) -$(TGT): sbinfo.c crc.c crypto.h aes128.c sha1.c - $(CC) -g -std=c99 -o $(TGT) -W -Wall sbinfo.c aes128.c crc.c sha1.c +$(TGT): sbinfo.c crc.c crypto.h aes128.c sha1.c elf.c + $(CC) -g -std=c99 -o $(TGT) -W -Wall sbinfo.c aes128.c crc.c sha1.c elf.c clean: rm -fr $(TGT) diff --git a/utils/sbinfo/elf.c b/utils/sbinfo/elf.c new file mode 100644 index 0000000000..0fe6792e1d --- /dev/null +++ b/utils/sbinfo/elf.c @@ -0,0 +1,169 @@ +#include "elf.h" + +void elf_init(struct elf_params_t *params) +{ + params->has_start_addr = false; + params->start_addr = 0; + params->first_section = NULL; + params->last_section = NULL; +} + +extern void *xmalloc(size_t s); + +static struct elf_section_t *elf_add_section(struct elf_params_t *params) +{ + struct elf_section_t *sec = xmalloc(sizeof(struct elf_section_t)); + if(params->first_section == NULL) + params->first_section = params->last_section = sec; + else + { + params->last_section->next = sec; + params->last_section = sec; + } + sec->next = NULL; + + return sec; +} + +void elf_add_load_section(struct elf_params_t *params, + uint32_t load_addr, uint32_t size, const void *section) +{ + struct elf_section_t *sec = elf_add_section(params); + + sec->type = EST_LOAD; + sec->addr = load_addr; + sec->size = size; + sec->section = xmalloc(size); + memcpy(sec->section, section, size); +} + +void elf_add_fill_section(struct elf_params_t *params, + uint32_t fill_addr, uint32_t size, uint32_t pattern) +{ + if(pattern != 0x00) + { + printf("oops, non-zero filling, ignore fill section\n"); + return; + } + + struct elf_section_t *sec = elf_add_section(params); + + sec->type = EST_FILL; + sec->addr = fill_addr; + sec->size = size; + sec->pattern = pattern; +} + +void elf_output(struct elf_params_t *params, elf_write_fn_t write, void *user) +{ + Elf32_Ehdr ehdr; + uint32_t phoff = sizeof(Elf32_Ehdr); + uint32_t phentsize = sizeof(Elf32_Phdr); + uint32_t phnum = 0; + uint32_t shstrndx = SHN_UNDEF; + struct elf_section_t *sec = params->first_section; + uint32_t offset = 0; + Elf32_Phdr phdr; + + while(sec) + { + if(sec->type == EST_LOAD) + { + sec->offset = offset; + offset += sec->size; + } + + phnum++; + sec = sec->next; + } + + memset(&ehdr, 0, EI_NIDENT); + ehdr.e_ident[EI_MAG0] = ELFMAG0; + ehdr.e_ident[EI_MAG1] = ELFMAG1; + ehdr.e_ident[EI_MAG2] = ELFMAG2; + ehdr.e_ident[EI_MAG3] = ELFMAG3; + ehdr.e_ident[EI_CLASS] = ELFCLASS32; + ehdr.e_ident[EI_DATA] = ELFDATA2LSB; + ehdr.e_ident[EI_VERSION] = EV_CURRENT; + ehdr.e_ident[EI_OSABI] = ELFOSABI_NONE; + ehdr.e_ident[EI_ABIVERSION] = 0; + ehdr.e_type = ET_EXEC; + ehdr.e_machine = EM_ARM; + ehdr.e_version = EV_CURRENT; + ehdr.e_entry = params->start_addr; + ehdr.e_phoff = phoff; + ehdr.e_shoff = 0; + ehdr.e_flags = 0; + if(params->has_start_addr) + ehdr.e_flags |= EF_ARM_HASENTRY; + ehdr.e_ehsize = sizeof ehdr; + ehdr.e_phentsize = phentsize; + ehdr.e_phnum = phnum; + ehdr.e_shentsize = 0; + ehdr.e_shnum = 0; + ehdr.e_shstrndx = shstrndx; + + write(user, 0, &ehdr, sizeof ehdr); + + sec = params->first_section; + offset = phoff; + while(sec) + { + sec->offset += phoff + phnum * phentsize; + + phdr.p_type = PT_LOAD; + if(sec->type == EST_LOAD) + phdr.p_offset = sec->offset; + else + phdr.p_offset = 0; + phdr.p_paddr = sec->addr; + phdr.p_vaddr = phdr.p_paddr; /* assume identity map ? */ + phdr.p_memsz = sec->size; + if(sec->type == EST_LOAD) + phdr.p_filesz = phdr.p_memsz; + else + phdr.p_filesz = 0; + phdr.p_flags = PF_X | PF_W | PF_R; + phdr.p_align = 0; + + write(user, offset, &phdr, sizeof phdr); + + offset += sizeof(Elf32_Phdr); + sec = sec->next; + } + + sec = params->first_section; + while(sec) + { + if(sec->type == EST_LOAD) + write(user, sec->offset, sec->section, sec->size); + sec = sec->next; + } +} + +bool elf_is_empty(struct elf_params_t *params) +{ + return params->first_section == NULL; +} + +void elf_set_start_addr(struct elf_params_t *params, uint32_t addr) +{ + params->has_start_addr = true; + params->start_addr = addr; +} + +void elf_release(struct elf_params_t *params) +{ + struct elf_section_t *sec, *next_sec; + sec = params->first_section; + while(sec) + { + next_sec = sec->next; + if(sec->type == EST_LOAD) + free(sec->section); + free(sec); + sec = next_sec; + } + params->first_section = NULL; + params->last_section = NULL; +} diff --git a/utils/sbinfo/elf.h b/utils/sbinfo/elf.h new file mode 100644 index 0000000000..6835178289 --- /dev/null +++ b/utils/sbinfo/elf.h @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include + +/** + * Definitions + * taken from elf.h linux header + * based on ELF specification + * based on ARM ELF specification + */ +typedef uint16_t Elf32_Half; + +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint16_t Elf32_Section; + +#define EI_NIDENT 16 + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +}Elf32_Ehdr; + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASS32 1 /* 32-bit objects */ + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ + +#define EI_VERSION 6 /* File version byte index, Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ +#define ELFOSABI_ARM 97 /* ARM */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +#define ET_EXEC 2 /* Executable file */ + +#define EM_ARM 40 /* ARM */ + +#define EV_CURRENT 1 /* Current version */ + +#define EF_ARM_HASENTRY 0x0 + +#define SHN_UNDEF 0 /* Undefined section */ + +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +}Elf32_Phdr; + +#define PT_LOAD 1 /* Loadable program segment */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ + +/** + * API + */ +enum elf_section_type_t +{ + EST_LOAD, + EST_FILL +}; + +struct elf_section_t +{ + uint32_t addr; + uint32_t size; + enum elf_section_type_t type; + /* */ + void *section; + uint32_t pattern; + /* */ + struct elf_section_t *next; + /* Internal to elf_output */ + uint32_t offset; +}; + +struct elf_params_t +{ + bool has_start_addr; + uint32_t start_addr; + struct elf_section_t *first_section; + struct elf_section_t *last_section; +}; + +typedef void (*elf_write_fn_t)(void *user, uint32_t addr, const void *buf, size_t count); + +void elf_init(struct elf_params_t *params); +void elf_add_load_section(struct elf_params_t *params, + uint32_t load_addr, uint32_t size, const void *section); +void elf_add_fill_section(struct elf_params_t *params, + uint32_t fill_addr, uint32_t size, uint32_t pattern); +void elf_output(struct elf_params_t *params, elf_write_fn_t write, void *user); +bool elf_is_empty(struct elf_params_t *params); +void elf_set_start_addr(struct elf_params_t *params, uint32_t addr); +void elf_release(struct elf_params_t *params); diff --git a/utils/sbinfo/sbinfo.c b/utils/sbinfo/sbinfo.c index 74b5a0b7be..361764310f 100644 --- a/utils/sbinfo/sbinfo.c +++ b/utils/sbinfo/sbinfo.c @@ -38,7 +38,9 @@ #include #include #include + #include "crypto.h" +#include "elf.h" #if 1 /* ANSI colors */ @@ -117,7 +119,7 @@ struct sb_instruction_call_t uint32_t arg; } __attribute__((packed)); -static void *xmalloc(size_t s) /* malloc helper */ +void *xmalloc(size_t s) /* malloc helper, used in elf.c */ { void * r = malloc(s); if(!r) bugp("malloc"); @@ -259,9 +261,31 @@ static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr) return sum; } +static void elf_write(void *user, uint32_t addr, const void *buf, size_t count) +{ + FILE *f = user; + fseek(f, addr, SEEK_SET); + fwrite(buf, count, 1, f); +} + +static void extract_elf_section(struct elf_params_t *elf, int count, const char *prefix) +{ + char *filename = xmalloc(strlen(prefix) + 32); + sprintf(filename, "%s.%d.elf", prefix, count); + printf("write %s\n", filename); + + FILE *fd = fopen(filename, "wb"); + free(filename); + + if(fd == NULL) + return ; + elf_output(elf, elf_write, fd); + fclose(fd); +} + static void extract_section(int data_sec, char name[5], byte *buf, int size, const char *indent) { - char filename[PREFIX_SIZE + 16]; + char filename[PREFIX_SIZE + 32]; snprintf(filename, sizeof filename, "%s%s.bin", out_prefix, name); FILE *fd = fopen(filename, "wb"); if (fd != NULL) { @@ -270,6 +294,13 @@ static void extract_section(int data_sec, char name[5], byte *buf, int size, con } if(data_sec) return; + + snprintf(filename, sizeof filename, "%s%s", out_prefix, name); + + /* elf construction */ + struct elf_params_t elf; + elf_init(&elf); + int elf_count = 0; /* Pretty print the content */ int pos = 0; while(pos < size) @@ -306,6 +337,10 @@ static void extract_section(int data_sec, char name[5], byte *buf, int size, con else printf(" Failed (crc=0x%08x)\n", computed_crc); + /* elf construction */ + elf_add_load_section(&elf, load->addr, load->len, + &buf[pos + sizeof(struct sb_instruction_load_t)]); + pos += load->len + sizeof(struct sb_instruction_load_t); // unsure about rounding pos = ROUND_UP(pos, 16); @@ -326,6 +361,9 @@ static void extract_section(int data_sec, char name[5], byte *buf, int size, con printf("pattern=0x%08x\n", fill->pattern); color(OFF); + /* elf construction */ + elf_add_fill_section(&elf, fill->addr, fill->len, fill->pattern); + pos += sizeof(struct sb_instruction_fill_t); // fixme: useless as pos is a multiple of 16 and fill struct is 4-bytes wide ? pos = ROUND_UP(pos, 16); @@ -348,6 +386,12 @@ static void extract_section(int data_sec, char name[5], byte *buf, int size, con printf("arg=0x%08x\n", call->arg); color(OFF); + /* elf construction */ + elf_set_start_addr(&elf, call->addr); + extract_elf_section(&elf, elf_count++, filename); + elf_release(&elf); + elf_init(&elf); + pos += sizeof(struct sb_instruction_call_t); // fixme: useless as pos is a multiple of 16 and call struct is 4-bytes wide ? pos = ROUND_UP(pos, 16); @@ -359,6 +403,10 @@ static void extract_section(int data_sec, char name[5], byte *buf, int size, con break; } } + + if(elf_is_empty(&elf)) + extract_elf_section(&elf, elf_count++, filename); + elf_release(&elf); } static void extract(unsigned long filesize)