From 18e3fbac7486791503e6579aff89fa8b35137334 Mon Sep 17 00:00:00 2001 From: Daniel Beer Date: Wed, 12 Oct 2011 13:52:56 +1300 Subject: [PATCH] Display section names when programming. The binfile extraction and programming code is now aware of section names when dealing with ELF32 files. The names are displayed when programming, and chunks in different sections aren't combined, even if they're contiguous. --- drivers/ti3410.c | 13 +++-- formats/binfile.h | 9 +++- formats/coff.c | 7 ++- formats/elf32.c | 123 +++++++++++++++++++++++++++------------------- formats/ihex.c | 7 ++- formats/srec.c | 11 +++-- formats/titext.c | 6 ++- ui/devcmd.c | 5 +- util/prog.c | 34 +++++++++---- util/prog.h | 6 ++- 10 files changed, 141 insertions(+), 80 deletions(-) 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