diff --git a/drivers/ti3410.c b/drivers/ti3410.c index 85e3c2a..1bf8fbb 100644 --- a/drivers/ti3410.c +++ b/drivers/ti3410.c @@ -395,24 +395,23 @@ static FILE *find_firmware(void) return NULL; } -static int do_extract(void *user_data, address_t addr, - const uint8_t *data, int len) +static int do_extract(void *user_data, const struct binfile_chunk *ch) { struct firmware *f = (struct firmware *)user_data; - if (f->size != addr) { + if (f->size != ch->addr) { printc_err("ti3410: firmware gap at 0x%x (ends at 0x%0x)\n", - f->size, addr); + f->size, ch->addr); return -1; } - if (f->size + len > sizeof(f->buf)) { + if (f->size + ch->len > sizeof(f->buf)) { printc_err("ti3410: maximum firmware size exceeded\n"); return -1; } - memcpy(f->buf + f->size, data, len); - f->size += len; + memcpy(f->buf + f->size, ch->data, ch->len); + f->size += ch->len; return 0; } diff --git a/formats/binfile.h b/formats/binfile.h index ac84f85..81e009b 100644 --- a/formats/binfile.h +++ b/formats/binfile.h @@ -23,9 +23,16 @@ #include #include "stab.h" +struct binfile_chunk { + const char *name; + address_t addr; + const uint8_t *data; + int len; +}; + /* Callback for binary image data */ typedef int (*binfile_imgcb_t)(void *user_data, - address_t addr, const uint8_t *data, int len); + const struct binfile_chunk *ch); #define BINFILE_HAS_SYMS 0x01 #define BINFILE_HAS_TEXT 0x02 diff --git a/formats/coff.c b/formats/coff.c index 78dff67..fce037f 100644 --- a/formats/coff.c +++ b/formats/coff.c @@ -198,6 +198,7 @@ static int load_section(FILE *in, uint32_t addr, uint32_t offset, uint32_t size, binfile_imgcb_t cb, void *user_data) { + struct binfile_chunk ch = {0}; uint8_t *section; if (!size) @@ -217,7 +218,11 @@ static int load_section(FILE *in, uint32_t addr, uint32_t offset, return -1; } - if (cb(user_data, addr, section, size) < 0) { + ch.addr = addr; + ch.len = size; + ch.data = section; + + if (cb(user_data, &ch) < 0) { free(section); return -1; } diff --git a/formats/elf32.c b/formats/elf32.c index 5a2855c..b1259b5 100644 --- a/formats/elf32.c +++ b/formats/elf32.c @@ -134,27 +134,40 @@ static uint32_t file_to_phys(struct elf32_info *info, uint32_t v) } static int feed_section(struct elf32_info *info, - FILE *in, uint32_t offset, uint32_t size, + FILE *in, const Elf32_Shdr *sh, binfile_imgcb_t cb, void *user_data) { + uint32_t offset = sh->sh_offset; + uint32_t size = sh->sh_size; uint8_t buf[1024]; uint32_t addr = file_to_phys(info, offset); + const char *name = NULL; if (fseek(in, offset, SEEK_SET) < 0) { pr_error("elf32: can't seek to section"); return -1; } + if (info->string_tab && + sh->sh_name < info->string_len) + name = info->string_tab + sh->sh_name; + while (size) { int ask = size > sizeof(buf) ? sizeof(buf) : size; int len = fread(buf, 1, ask, in); + struct binfile_chunk ch = {0}; if (len < 0) { pr_error("elf32: can't read section"); return -1; } - if (cb(user_data, addr, buf, len) < 0) + ch.name = name; + ch.addr = addr; + ch.data = buf; + ch.len = len; + + if (cb(user_data, &ch) < 0) return -1; size -= len; @@ -184,53 +197,7 @@ static int read_all(struct elf32_info *info, FILE *in) return 0; } -int elf32_extract(FILE *in, binfile_imgcb_t cb, void *user_data) -{ - struct elf32_info info; - int i; - - if (read_all(&info, in) < 0) - return -1; - - for (i = 0; i < info.file_ehdr.e_shnum; i++) { - Elf32_Shdr *s = &info.file_shdrs[i]; - - if (s->sh_type == SHT_PROGBITS && s->sh_flags & SHF_ALLOC && - feed_section(&info, in, s->sh_offset, s->sh_size, - cb, user_data) < 0) - return -1; - } - - return 0; -} - -int elf32_check(FILE *in) -{ - int i; - - rewind(in); - for (i = 0; i < sizeof(elf32_id); i++) - if (fgetc(in) != elf32_id[i]) - return 0; - - return 1; -} - -static Elf32_Shdr *find_shdr(struct elf32_info *info, Elf32_Word type) -{ - int i; - - for (i = 0; i < info->file_ehdr.e_shnum; i++) { - Elf32_Shdr *s = &info->file_shdrs[i]; - - if (s->sh_type == type) - return s; - } - - return NULL; -} - -static int syms_load_strings(struct elf32_info *info, FILE *in, Elf32_Shdr *s) +static int load_strings(struct elf32_info *info, FILE *in, Elf32_Shdr *s) { int len = s->sh_size; @@ -264,6 +231,62 @@ static int syms_load_strings(struct elf32_info *info, FILE *in, Elf32_Shdr *s) return 0; } +int elf32_extract(FILE *in, binfile_imgcb_t cb, void *user_data) +{ + struct elf32_info info; + int i; + int ret = 0; + + if (read_all(&info, in) < 0) + return -1; + + if (load_strings(&info, in, + &info.file_shdrs[info.file_ehdr.e_shstrndx]) < 0) { + printc_err("elf32: warning: can't load section string " + "table\n"); + info.string_tab = NULL; + } + + for (i = 0; i < info.file_ehdr.e_shnum; i++) { + Elf32_Shdr *s = &info.file_shdrs[i]; + + if (s->sh_type == SHT_PROGBITS && s->sh_flags & SHF_ALLOC && + feed_section(&info, in, s, cb, user_data) < 0) + ret = -1; + } + + if (info.string_tab) + free(info.string_tab); + + return ret; +} + +int elf32_check(FILE *in) +{ + int i; + + rewind(in); + for (i = 0; i < sizeof(elf32_id); i++) + if (fgetc(in) != elf32_id[i]) + return 0; + + return 1; +} + +static Elf32_Shdr *find_shdr(struct elf32_info *info, Elf32_Word type) +{ + int i; + + for (i = 0; i < info->file_ehdr.e_shnum; i++) { + Elf32_Shdr *s = &info->file_shdrs[i]; + + if (s->sh_type == type) + return s; + } + + return NULL; +} + #define N_SYMS 128 #ifndef STT_COMMON @@ -342,7 +365,7 @@ int elf32_syms(FILE *in) return -1; } - if (syms_load_strings(&info, in, &info.file_shdrs[s->sh_link]) < 0 || + if (load_strings(&info, in, &info.file_shdrs[s->sh_link]) < 0 || syms_load_syms(&info, in, s) < 0) ret = -1; diff --git a/formats/ihex.c b/formats/ihex.c index 206fc33..dc2adec 100644 --- a/formats/ihex.c +++ b/formats/ihex.c @@ -37,6 +37,7 @@ static int feed_line(FILE *in, uint8_t *data, int nbytes, binfile_imgcb_t cb, uint8_t *payload; int data_len; int i; + struct binfile_chunk ch = {0}; if (nbytes < 5) return 0; @@ -60,8 +61,10 @@ static int feed_line(FILE *in, uint8_t *data, int nbytes, binfile_imgcb_t cb, switch (type) { case 0: - return cb(user_data, address + *segment_offset, - payload, data_len); + ch.addr = address + *segment_offset; + ch.data = payload; + ch.len = data_len; + return cb(user_data, &ch); case 1: case 3: diff --git a/formats/srec.c b/formats/srec.c index dac2d29..a3be0e3 100644 --- a/formats/srec.c +++ b/formats/srec.c @@ -110,6 +110,7 @@ int srec_extract(FILE *in, binfile_imgcb_t cb, void *user_data) if (buf[1] >= '1' && buf[1] <= '3') { int addrbytes = buf[1] - '1' + 2; address_t addr = 0; + struct binfile_chunk ch = {0}; for (i = 0; i < addrbytes; i++) addr = (addr << 8) | bytes[i + 1]; @@ -120,10 +121,12 @@ int srec_extract(FILE *in, binfile_imgcb_t cb, void *user_data) return -1; } - if (cb(user_data, addr, bytes + addrbytes + 1, - count - 2 - addrbytes) < 0) { - printc_err("srec: error on line %d\n", - lno); + ch.addr = addr; + ch.data = bytes + addrbytes + 1; + ch.len = count - 2 - addrbytes; + + if (cb(user_data, &ch) < 0) { + printc_err("srec: error on line %d\n", lno); return -1; } } diff --git a/formats/titext.c b/formats/titext.c index 560ae1a..5617af4 100644 --- a/formats/titext.c +++ b/formats/titext.c @@ -75,6 +75,7 @@ static int process_data_line(address_t address, const char *buf, int data_len = 0; int value = 0; int vc = 0; + struct binfile_chunk ch = {0}; while (*buf) { int c = *(buf++); @@ -118,7 +119,10 @@ static int process_data_line(address_t address, const char *buf, data[data_len++] = value; } - if (cb(user_data, address, data, data_len) < 0) + ch.addr = address; + ch.data = data; + ch.len = data_len; + if (cb(user_data, &ch) < 0) return -1; return data_len; diff --git a/ui/devcmd.c b/ui/devcmd.c index 1a0c95e..cc8fe52 100644 --- a/ui/devcmd.c +++ b/ui/devcmd.c @@ -490,10 +490,9 @@ fail: return -1; } -static int cmd_prog_feed(void *user_data, address_t addr, - const uint8_t *data, int len) +static int cmd_prog_feed(void *user_data, const struct binfile_chunk *ch) { - return prog_feed((struct prog_data *)user_data, addr, data, len); + return prog_feed((struct prog_data *)user_data, ch); } static int do_cmd_prog(char **arg, int prog_flags) diff --git a/util/prog.c b/util/prog.c index 67bae93..7aecdda 100644 --- a/util/prog.c +++ b/util/prog.c @@ -41,7 +41,11 @@ int prog_flush(struct prog_data *prog) prog->have_erased = 1; } - printc_dbg("Writing %4d bytes to %04x...\n", prog->len, prog->addr); + printc_dbg("Writing %4d bytes to %04x", prog->len, prog->addr); + if (prog->section[0]) + printc_dbg(" [section: %s]", prog->section); + printc_dbg("...\n"); + if (device_writemem(prog->addr, prog->buf, prog->len) < 0) return -1; @@ -50,16 +54,28 @@ int prog_flush(struct prog_data *prog) return 0; } -int prog_feed(struct prog_data *prog, address_t addr, - const uint8_t *data, int len) +int prog_feed(struct prog_data *prog, const struct binfile_chunk *ch) { - /* Flush if this section is discontiguous */ - if (prog->len && prog->addr + prog->len != addr && - prog_flush(prog) < 0) - return -1; + const char *section = ch->name ? ch->name : ""; + const uint8_t *data = ch->data; + int len = ch->len; - if (!prog->len) - prog->addr = addr; + /* Flush if this chunk is discontiguous, or in a different + * section. + */ + if (prog->len && + ((prog->addr + prog->len != ch->addr) || + strcmp(prog->section, section))) { + if (prog_flush(prog) < 0) + return -1; + } + + if (!prog->len) { + prog->addr = ch->addr; + + strncpy(prog->section, section, sizeof(prog->section)); + prog->section[sizeof(prog->section) - 1] = 0; + } /* Add the buffer in piece by piece, flushing when it gets * full. diff --git a/util/prog.h b/util/prog.h index a531f66..2ed48f8 100644 --- a/util/prog.h +++ b/util/prog.h @@ -19,9 +19,12 @@ #ifndef PROG_H_ #define PROG_H_ +#include "binfile.h" + #define PROG_BUFSIZE 4096 struct prog_data { + char section[64]; uint8_t buf[PROG_BUFSIZE]; address_t addr; int len; @@ -32,8 +35,7 @@ struct prog_data { #define PROG_WANT_ERASE 0x01 void prog_init(struct prog_data *data, int flags); -int prog_feed(struct prog_data *data, address_t addr, - const uint8_t *buffer, int count); +int prog_feed(struct prog_data *data, const struct binfile_chunk *ch); int prog_flush(struct prog_data *data); #endif