summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorAmaury Pouly <pamaury@rockbox.org>2011-07-02 02:12:01 +0000
committerAmaury Pouly <pamaury@rockbox.org>2011-07-02 02:12:01 +0000
commitfed77808c5b3efa1a8e6ac10647845da6847f48a (patch)
treea3ebe987b86806d270032937eb1a9eb563174d9d /utils
parent337e922685d11f80fa9e7b164511e043044b6302 (diff)
downloadrockbox-fed77808c5b3efa1a8e6ac10647845da6847f48a.tar.gz
rockbox-fed77808c5b3efa1a8e6ac10647845da6847f48a.tar.bz2
rockbox-fed77808c5b3efa1a8e6ac10647845da6847f48a.zip
elftosb: support 'strings' in section id, support load binary at address, support call/jump at address
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30110 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'utils')
-rw-r--r--utils/sbtools/elftosb.c211
1 files changed, 182 insertions, 29 deletions
diff --git a/utils/sbtools/elftosb.c b/utils/sbtools/elftosb.c
index 58665da16d..38ac0ae32a 100644
--- a/utils/sbtools/elftosb.c
+++ b/utils/sbtools/elftosb.c
@@ -164,28 +164,48 @@ static key_array_t read_keys(const char *key_file, int *num_keys)
* Command file parsing
*/
+enum cmd_source_type_t
+{
+ CMD_SRC_UNK,
+ CMD_SRC_ELF,
+ CMD_SRC_BIN
+};
+
+struct bin_param_t
+{
+ uint32_t size;
+ void *data;
+};
+
struct cmd_source_t
{
char *identifier;
char *filename;
struct cmd_source_t *next;
/* for later use */
+ enum cmd_source_type_t type;
+ bool bin_loaded;
bool elf_loaded;
struct elf_params_t elf;
+ struct bin_param_t bin;
};
enum cmd_inst_type_t
{
- CMD_LOAD,
- CMD_JUMP,
- CMD_CALL
+ CMD_LOAD, /* load image */
+ CMD_JUMP, /* jump at image */
+ CMD_CALL, /* call image */
+ CMD_LOAD_AT, /* load binary at */
+ CMD_CALL_AT, /* call at address */
+ CMD_JUMP_AT, /* jump at address */
};
struct cmd_inst_t
{
enum cmd_inst_type_t type;
char *identifier;
- uint32_t argument;
+ uint32_t argument; // for jump, call
+ uint32_t addr; // for 'at'
struct cmd_inst_t *next;
};
@@ -213,6 +233,7 @@ enum lexem_type_t
LEX_SEMICOLON,
LEX_LBRACE,
LEX_RBRACE,
+ LEX_RANGLE,
LEX_EOF
};
@@ -276,6 +297,34 @@ static void parse_string(char **ptr, char *end, struct lexem_t *lexem)
__parse_string(ptr, end, (void *)&pstr, __parse_string_emit);
}
+static void parse_ascii_number(char **ptr, char *end, struct lexem_t *lexem)
+{
+ /* skip ' */
+ (*ptr)++;
+ /* we expect 4 character and then ' */
+ int len = 0;
+ uint32_t value = 0;
+ while(*ptr != end)
+ {
+ if(**ptr != '\'')
+ {
+ value = value << 8 | **ptr;
+ len++;
+ (*ptr)++;
+ }
+ else
+ break;
+ }
+ if(*ptr == end || **ptr != '\'')
+ bug("Unterminated ascii number literal");
+ if(len != 1 && len != 2 && len != 4)
+ bug("Invalid ascii number literal length: only 1, 2 or 4 are valid");
+ /* skip ' */
+ (*ptr)++;
+ lexem->type = LEX_NUMBER;
+ lexem->num = value;
+}
+
static void parse_number(char **ptr, char *end, struct lexem_t *lexem)
{
int base = 10;
@@ -337,9 +386,11 @@ static void next_lexem(char **ptr, char *end, struct lexem_t *lexem)
if(**ptr == ')') ret_simple(LEX_RPAREN, 1);
if(**ptr == '{') ret_simple(LEX_LBRACE, 1);
if(**ptr == '}') ret_simple(LEX_RBRACE, 1);
+ if(**ptr == '>') ret_simple(LEX_RANGLE, 1);
if(**ptr == '=') ret_simple(LEX_EQUAL, 1);
if(**ptr == ';') ret_simple(LEX_SEMICOLON, 1);
if(**ptr == '"') return parse_string(ptr, end, lexem);
+ if(**ptr == '\'') return parse_ascii_number(ptr, end, lexem);
if(isdigit(**ptr)) return parse_number(ptr, end, lexem);
if(isalpha(**ptr) || **ptr == '_') return parse_identifier(ptr, end, lexem);
bug("Unexpected character '%c' in command file\n", **ptr);
@@ -433,6 +484,8 @@ static struct cmd_file_t *read_command_file(const char *file)
bug("invalid command file: ';' expected after string");
if(find_source_by_id(cmd_file, src->identifier) != NULL)
bug("invalid command file: duplicated source identifier");
+ /* type filled later */
+ src->type = CMD_SRC_UNK;
cmd_file->source_list = src;
}
@@ -452,9 +505,14 @@ static struct cmd_file_t *read_command_file(const char *file)
if(lexem.type != LEX_LPAREN)
bug("invalid command file: '(' expected after 'section'");
next();
- if(lexem.type != LEX_NUMBER)
+ /* can be a number or a 4 character long string */
+ if(lexem.type == LEX_NUMBER)
+ {
+ sec->identifier = lexem.num;
+ }
+ else
bug("invalid command file: number expected as section identifier");
- sec->identifier = lexem.num;
+
next();
if(lexem.type != LEX_RPAREN)
bug("invalid command file: ')' expected after section identifier");
@@ -480,26 +538,62 @@ static struct cmd_file_t *read_command_file(const char *file)
else
bug("invalid command file: instruction expected in section");
next();
- if(lexem.type != LEX_IDENTIFIER)
- bug("invalid command file: identifier expected after instruction");
- inst->identifier = lexem.str;
- if(find_source_by_id(cmd_file, inst->identifier) == NULL)
- bug("invalid command file: undefined reference to source '%s'", inst->identifier);
- next();
- if((inst->type == CMD_CALL || inst->type == CMD_JUMP) && lexem.type == LEX_LPAREN)
+
+ if(inst->type == CMD_LOAD)
{
+ if(lexem.type != LEX_IDENTIFIER)
+ bug("invalid command file: identifier expected after instruction");
+ inst->identifier = lexem.str;
+ if(find_source_by_id(cmd_file, inst->identifier) == NULL)
+ bug("invalid command file: undefined reference to source '%s'", inst->identifier);
next();
- if(lexem.type != LEX_NUMBER)
- bug("invalid command file: expected numeral expression after (");
- inst->argument = lexem.num;
- next();
- if(lexem.type != LEX_RPAREN)
- bug("invalid command file: expected closing brace");
- next();
+ if(lexem.type == LEX_RANGLE)
+ {
+ // load at
+ inst->type = CMD_LOAD_AT;
+ next();
+ if(lexem.type != LEX_NUMBER)
+ bug("invalid command file: number expected for loading address");
+ inst->addr = lexem.num;
+ next();
+ }
+ if(lexem.type != LEX_SEMICOLON)
+ bug("invalid command file: expected ';' after command");
}
- if(lexem.type != LEX_SEMICOLON)
- bug("invalid command file: expected ';' after command");
-
+ else if(inst->type == CMD_CALL || inst->type == CMD_JUMP)
+ {
+ if(lexem.type == LEX_IDENTIFIER)
+ {
+ inst->identifier = lexem.str;
+ if(find_source_by_id(cmd_file, inst->identifier) == NULL)
+ bug("invalid command file: undefined reference to source '%s'", inst->identifier);
+ next();
+ }
+ else if(lexem.type == LEX_NUMBER)
+ {
+ inst->type = (inst->type == CMD_CALL) ? CMD_CALL_AT : CMD_JUMP_AT;
+ inst->addr = lexem.num;
+ next();
+ }
+ else
+ bug("invalid command file: identifier or number expected after jump/load");
+
+ if(lexem.type == LEX_LPAREN)
+ {
+ next();
+ if(lexem.type != LEX_NUMBER)
+ bug("invalid command file: expected numeral expression after (");
+ inst->argument = lexem.num;
+ next();
+ if(lexem.type != LEX_RPAREN)
+ bug("invalid command file: expected closing brace");
+ next();
+ }
+ if(lexem.type != LEX_SEMICOLON)
+ bug("invalid command file: expected ';' after command");
+ }
+ else
+ bug("die");
if(end_list == NULL)
{
sec->inst_list = inst;
@@ -589,8 +683,11 @@ static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id)
if(src == NULL)
bug("undefined reference to source '%s'\n", id);
/* avoid reloading */
- if(src->elf_loaded)
+ if(src->type == CMD_SRC_ELF && src->elf_loaded)
return;
+ if(src->type != CMD_SRC_UNK)
+ bug("source '%s' seen both as elf and binary file", id);
+ src->type = CMD_SRC_ELF;
int fd = open(src->filename, O_RDONLY);
if(fd < 0)
bug("cannot open '%s' (id '%s')\n", src->filename, id);
@@ -603,6 +700,32 @@ static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id)
bug("error loading elf file '%s' (id '%s')\n", src->filename, id);
}
+static void load_bin_by_id(struct cmd_file_t *cmd_file, const char *id)
+{
+ struct cmd_source_t *src = find_source_by_id(cmd_file, id);
+ if(src == NULL)
+ bug("undefined reference to source '%s'\n", id);
+ if(src == NULL)
+ bug("undefined reference to source '%s'\n", id);
+ /* avoid reloading */
+ if(src->type == CMD_SRC_BIN && src->bin_loaded)
+ return;
+ if(src->type != CMD_SRC_UNK)
+ bug("source '%s' seen both as elf and binary file", id);
+ src->type = CMD_SRC_BIN;
+ int fd = open(src->filename, O_RDONLY);
+ if(fd < 0)
+ bug("cannot open '%s' (id '%s')\n", src->filename, id);
+ if(g_debug)
+ printf("Loading BIN file '%s'...\n", src->filename);
+ src->bin.size = lseek(fd, 0, SEEK_END);
+ lseek(fd, 0, SEEK_SET);
+ src->bin.data = xmalloc(src->bin.size);
+ read(fd, src->bin.data, src->bin.size);
+ close(fd);
+ src->bin_loaded = true;
+}
+
static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
{
struct sb_file_t *sb = xmalloc(sizeof(struct sb_file_t));
@@ -630,17 +753,31 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
struct cmd_inst_t *cinst = csec->inst_list;
while(cinst)
{
- load_elf_by_id(cmd_file, cinst->identifier);
- struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf;
-
if(cinst->type == CMD_LOAD)
+ {
+ load_elf_by_id(cmd_file, cinst->identifier);
+ struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf;
sec->nr_insts += elf_get_nr_sections(elf);
+ }
else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL)
{
+ load_elf_by_id(cmd_file, cinst->identifier);
+ struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf;
if(!elf_get_start_addr(elf, NULL))
bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier);
sec->nr_insts++;
}
+ else if(cinst->type == CMD_CALL_AT || cinst->type == CMD_JUMP_AT)
+ {
+ sec->nr_insts++;
+ }
+ else if(cinst->type == CMD_LOAD_AT)
+ {
+ load_bin_by_id(cmd_file, cinst->identifier);
+ sec->nr_insts++;
+ }
+ else
+ bug("die");
cinst = cinst->next;
}
@@ -652,10 +789,9 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
cinst = csec->inst_list;
while(cinst)
{
- struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf;
-
if(cinst->type == CMD_LOAD)
{
+ struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf;
struct elf_section_t *esec = elf->first_section;
while(esec)
{
@@ -678,10 +814,27 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
}
else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL)
{
+ struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf;
sec->insts[idx].argument = cinst->argument;
sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL;
sec->insts[idx++].addr = elf->start_addr;
}
+ else if(cinst->type == CMD_JUMP_AT || cinst->type == CMD_CALL_AT)
+ {
+ sec->insts[idx].argument = cinst->argument;
+ sec->insts[idx].inst = (cinst->type == CMD_JUMP_AT) ? SB_INST_JUMP : SB_INST_CALL;
+ sec->insts[idx++].addr = cinst->addr;
+ }
+ else if(cinst->type == CMD_LOAD_AT)
+ {
+ struct bin_param_t *bin = &find_source_by_id(cmd_file, cinst->identifier)->bin;
+ sec->insts[idx].inst = SB_INST_LOAD;
+ sec->insts[idx].addr = cinst->addr;
+ sec->insts[idx].data = bin->data;
+ sec->insts[idx++].size = bin->size;
+ }
+ else
+ bug("die");
cinst = cinst->next;
}