ao-tools: Add ao-elftohex and .ihx symbol support
authorKeith Packard <keithp@keithp.com>
Thu, 28 Nov 2013 17:31:02 +0000 (09:31 -0800)
committerKeith Packard <keithp@keithp.com>
Thu, 28 Nov 2013 17:31:02 +0000 (09:31 -0800)
ao-elftohex converts an elf file into a hex file so that we can load
it with java.

Signed-off-by: Keith Packard <keithp@keithp.com>
12 files changed:
ao-tools/Makefile.am
ao-tools/ao-elftohex/Makefile.am [new file with mode: 0644]
ao-tools/ao-elftohex/ao-elftohex.1 [new file with mode: 0644]
ao-tools/ao-elftohex/ao-elftohex.c [new file with mode: 0644]
ao-tools/ao-stmload/ao-stmload.c
ao-tools/ao-stmload/ao-stmload.h
ao-tools/lib/Makefile.am
ao-tools/lib/ao-elf.c
ao-tools/lib/ao-elf.h
ao-tools/lib/ao-hex.c
ao-tools/lib/ao-hex.h
configure.ac

index 4600f1d62221bf73ffe348ce532b6423d99aa4a4..9c38273955236d36a1f2a4f260c2254d8f0762e0 100644 (file)
@@ -1,3 +1,3 @@
 SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list \
        ao-load ao-telem ao-stmload ao-send-telem ao-sky-flash \
-       ao-dumpflash ao-edit-telem ao-dump-up
+       ao-dumpflash ao-edit-telem ao-dump-up ao-elftohex
diff --git a/ao-tools/ao-elftohex/Makefile.am b/ao-tools/ao-elftohex/Makefile.am
new file mode 100644 (file)
index 0000000..33c9923
--- /dev/null
@@ -0,0 +1,18 @@
+if LIBSTLINK
+
+bin_PROGRAMS=ao-elftohex
+
+LIBSTLINKDIR=/local/src/stlink
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBSTLINK_CFLAGS) $(LIBUSB_CFLAGS)
+AO_STMLOAD_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_elftohex_DEPENDENCIES = $(AO_STMLOAD_LIBS)
+
+ao_elftohex_LDADD=$(AO_STMLOAD_LIBS) $(LIBSTLINK_LIBS) $(LIBUSB_LIBS) -lelf
+
+ao_elftohex_SOURCES=ao-elftohex.c
+
+man_MANS = ao-elftohex.1
+
+endif
diff --git a/ao-tools/ao-elftohex/ao-elftohex.1 b/ao-tools/ao-elftohex/ao-elftohex.1
new file mode 100644 (file)
index 0000000..e52e6f5
--- /dev/null
@@ -0,0 +1,38 @@
+.\"
+.\" Copyright © 2013 Keith Packard <keithp@keithp.com>
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License along
+.\" with this program; if not, write to the Free Software Foundation, Inc.,
+.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+.\"
+.\"
+.TH AO-LOAD 1 "ao-elftohex" ""
+.SH NAME
+ao-elftohex \- convert a program to IHX format
+.SH SYNOPSIS
+.B "ao-elftohex"
+[\--output-\fIoutput.ihx\fP]
+[\--verbose]
+\fIinput.elf\fP
+.SH DESCRIPTION
+.I ao-elftohex
+reads the specified .elf file and writes out a .ihx version.
+.SH OPTIONS
+.TP
+\--output=\fIoutput.ihx\fP
+This specifies the output file (default is stdout)
+.TP
+\--verbose
+Dumps some debug information.
+.SH AUTHOR
+Keith Packard
diff --git a/ao-tools/ao-elftohex/ao-elftohex.c b/ao-tools/ao-elftohex/ao-elftohex.c
new file mode 100644 (file)
index 0000000..db8f86f
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ao-hex.h"
+#include "ao-elf.h"
+#include "ao-verbose.h"
+
+static const struct option options[] = {
+       { .name = "verbose", .has_arg = 1, .val = 'v' },
+       { .name = "output", .has_arg = 1, .val = 'o' },
+       { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+       fprintf(stderr, "usage: %s [--verbose=<level>] [--output=<output.ihx>] <input.elf>\n", program);
+       exit(1);
+}
+
+static int
+ends_with(char *whole, char *suffix)
+{
+       int whole_len = strlen(whole);
+       int suffix_len = strlen(suffix);
+
+       if (suffix_len > whole_len)
+               return 0;
+       return strcmp(whole + whole_len - suffix_len, suffix) == 0;
+}
+
+int
+main (int argc, char **argv)
+{
+       char                    *input = NULL;
+       char                    *output = NULL;
+       struct ao_hex_image     *image;
+       struct ao_sym           *file_symbols;
+       int                     num_file_symbols;
+       FILE                    *file;
+       int                     c;
+
+       while ((c = getopt_long(argc, argv, "v:o:", options, NULL)) != -1) {
+               switch (c) {
+               case 'o':
+                       output = optarg;
+                       break;
+               case 'v':
+                       ao_verbose = (int) strtol(optarg, NULL, 0);
+                       break;
+               default:
+                       usage(argv[0]);
+                       break;
+               }
+       }
+
+       input = argv[optind];
+       if (input == NULL)
+               usage(argv[0]);
+
+       if (ends_with (input, ".ihx"))
+               image = ao_hex_load(input, &file_symbols, &num_file_symbols);
+       else
+               image = ao_load_elf(input, &file_symbols, &num_file_symbols);
+
+       if (!image)
+               usage(argv[0]);
+
+       if (!output)
+               file = stdout;
+       else {
+               file = fopen(output, "w");
+               if (!file) {
+                       perror(output);
+                       exit(1);
+               }
+       }
+
+       if (!ao_hex_save(file, image, file_symbols, num_file_symbols)) {
+               fprintf(stderr, "%s: failed to write hex file\n", output ? output : "<stdout>");
+               if (output)
+                       unlink(output);
+               exit(1);
+       }
+       exit(0);
+}
index 6e3906fd691a1f40f10e29ffdddd4a02254c58db..a11d93de68974c1c0e417f8f69c44cd412536e00 100644 (file)
@@ -25,6 +25,7 @@
 #include <unistd.h>
 #include <getopt.h>
 #include <string.h>
+#include <stdbool.h>
 #include "stlink-common.h"
 #include "ao-elf.h"
 #include "ccdbg.h"
@@ -34,7 +35,7 @@
 
 #define AO_USB_DESC_STRING             3
 
-struct ao_elf_sym ao_symbols[] = {
+struct ao_sym ao_symbols[] = {
 
        { 0, AO_BOOT_APPLICATION_BASE + 0x100,  "ao_romconfig_version", 1 },
 #define AO_ROMCONFIG_VERSION   (ao_symbols[0].addr)
@@ -218,6 +219,30 @@ check_flashed(stlink_t *sl, struct cc_usb *cc)
        return 1;
 }
 
+/*
+ * Find the symbols needed to correctly load the program
+ */
+
+static bool
+find_symbols(struct ao_sym *file_symbols, int num_file_symbols,
+            struct ao_sym *symbols, int num_symbols)
+{
+       int     f, s;
+
+       for (f = 0; f < num_file_symbols; f++) {
+               for (s = 0; s < num_symbols; s++) {
+                       if (strcmp(symbols[s].name, file_symbols[f].name) == 0) {
+                               symbols[s].addr = file_symbols[f].addr;
+                               symbols[s].found = true;
+                       }
+               }
+       }
+       for (s = 0; s < num_symbols; s++)
+               if (!symbols[s].found && symbols[s].required)
+                       return false;
+       return true;
+}
+
 static const struct option options[] = {
        { .name = "stlink", .has_arg = 0, .val = 'S' },
        { .name = "tty", .has_arg = 1, .val = 'T' },
@@ -288,6 +313,8 @@ main (int argc, char **argv)
        char                    *tty = NULL;
        int                     success;
        int                     verbose = 0;
+       struct ao_sym           *file_symbols;
+       int                     num_file_symbols;
 
        while ((c = getopt_long(argc, argv, "T:D:c:s:Sv", options, NULL)) != -1) {
                switch (c) {
@@ -329,15 +356,15 @@ main (int argc, char **argv)
                usage(argv[0]);
 
        if (ends_with (filename, ".elf")) {
-               load = ao_load_elf(filename, ao_symbols, ao_num_symbols);
+               load = ao_load_elf(filename, &file_symbols, &num_file_symbols);
        } else if (ends_with (filename, ".ihx")) {
-               int     i;
-               load = ao_hex_load(filename);
-               for (i = 0; i < ao_num_symbols; i++)
-                       ao_symbols[i].addr = ao_symbols[i].default_addr;
+               load = ao_hex_load(filename, &file_symbols, &num_file_symbols);
        } else
                usage(argv[0]);
 
+       if (!find_symbols(file_symbols, num_file_symbols, ao_symbols, ao_num_symbols))
+               fprintf(stderr, "Cannot find required symbols\n");
+
        if (use_stlink) {
                /* Connect to the programming dongle
                 */
index 28c2dda47a46100346f45acc6a693292ddde3b7c..744dfa75cac04e243fe2e71c05462dba6deacef5 100644 (file)
@@ -22,7 +22,7 @@
 
 #define AO_BOOT_APPLICATION_BASE       0x08001000
 
-extern struct ao_elf_sym ao_symbols[];
+extern struct ao_sym ao_symbols[];
 
 extern int ao_num_symbols;
 extern int ao_num_required_symbols;
index 868b64f157de882a14f253d9e3966367ab7bf5d4..ca32e121826224373c2125c4c5e10d7948d47246 100644 (file)
@@ -43,4 +43,6 @@ libao_tools_a_SOURCES = \
        ao-hex.c \
        ao-hex.h \
        ao-elf.c \
-       ao-elf.h
+       ao-elf.h \
+       ao-verbose.c \
+       ao-verbose.h
index 932dc85371b355a1e006f60c4011208c009e1cc2..99b37210781e553094f2e9aa52407392b7da2486 100644 (file)
 #include <fcntl.h>
 #include "ao-elf.h"
 #include "ao-hex.h"
+#include "ao-verbose.h"
 
 /*
  * Look through the Elf file for symbols that can be adjusted before
  * the image is written to the device
  */
-static bool
-find_symbols (Elf *e, struct ao_elf_sym *symbols, int num_symbols)
+static struct ao_sym *
+load_symbols (Elf *e, int *num_symbolsp)
 {
        Elf_Scn         *scn;
        Elf_Data        *symbol_data = NULL;
        GElf_Shdr       shdr;
        GElf_Sym        sym;
-       int             i, symbol_count, s;
+       int             i, symbol_count;
        char            *symbol_name;
        size_t          shstrndx;
+       struct ao_sym   *symbols = NULL;
+       struct ao_sym   *symbol;
+       int             num_symbols = 0;
+       int             size_symbols = 0;
 
        if (elf_getshdrstrndx(e, &shstrndx) < 0)
                return false;
@@ -64,23 +69,46 @@ find_symbols (Elf *e, struct ao_elf_sym *symbols, int num_symbols)
        }
 
        if (!symbol_data)
-               return false;
+               return NULL;
 
        for (i = 0; i < symbol_count; i++) {
                gelf_getsym(symbol_data, i, &sym);
 
                symbol_name = elf_strptr(e, shdr.sh_link, sym.st_name);
+               if (!symbol_name[0])
+                       continue;
 
-               for (s = 0; s < num_symbols; s++)
-                       if (!strcmp (symbols[s].name, symbol_name)) {
-                               symbols[s].addr = sym.st_value;
-                               symbols[s].found = true;
-                       }
+               if (num_symbols == size_symbols) {
+                       struct ao_sym   *new_symbols;
+                       int             new_size;
+
+                       if (!size_symbols)
+                               new_size = 16;
+                       else
+                               new_size = size_symbols * 2;
+                       new_symbols = realloc(symbols, new_size * sizeof (struct ao_sym));
+                       if (!new_symbols)
+                               goto bail;
+
+                       symbols = new_symbols;
+                       size_symbols = new_size;
+               }
+               symbol = &symbols[num_symbols];
+               memset(symbol, 0, sizeof (struct ao_sym));
+               symbol->name = strdup(symbol_name);
+               if (!symbol->name)
+                       goto bail;
+               symbol->addr = sym.st_value;
+               ao_printf(AO_VERBOSE_EXE, "Add symbol %s: %08x\n", symbol->name, symbol->addr);
+               num_symbols++;
        }
-       for (s = 0; s < num_symbols; s++)
-               if (symbols[s].required && !symbols[s].found)
-                       return false;
-       return true;
+       *num_symbolsp = num_symbols;
+       return symbols;
+bail:
+       for (i = 0; i < num_symbols; i++)
+               free(symbols[i].name);
+       free(symbols);
+       return NULL;
 }
 
 static uint32_t
@@ -173,7 +201,9 @@ get_load(Elf *e)
        GElf_Phdr       phdr;
        GElf_Addr       sh_paddr;
        struct ao_hex_image     *load = NULL;
+#if 0
        char            *section_name;
+#endif
        size_t          nshdr;
        size_t          s;
        
@@ -201,27 +231,29 @@ get_load(Elf *e)
                /* Get the associated file section */
 
 #if 0
-               printf ("offset %08x vaddr %08x paddr %08x filesz %08x memsz %08x\n",
-                       (uint32_t) phdr.p_offset,
-                       (uint32_t) phdr.p_vaddr,
-                       (uint32_t) phdr.p_paddr,
-                       (uint32_t) phdr.p_filesz,
-                       (uint32_t) phdr.p_memsz);
+               fprintf (stderr, "offset %08x vaddr %08x paddr %08x filesz %08x memsz %08x\n",
+                        (uint32_t) phdr.p_offset,
+                        (uint32_t) phdr.p_vaddr,
+                        (uint32_t) phdr.p_paddr,
+                        (uint32_t) phdr.p_filesz,
+                        (uint32_t) phdr.p_memsz);
 #endif
                
                for (s = 0; s < nshdr; s++) {
                        scn = elf_getscn(e, s);
 
                        if (!scn) {
-                               printf ("getscn failed\n");
+                               fprintf (stderr, "getscn failed\n");
                                abort();
                        }
                        if (gelf_getshdr(scn, &shdr) != &shdr) {
-                               printf ("gelf_getshdr failed\n");
+                               fprintf (stderr, "gelf_getshdr failed\n");
                                abort();
                        }
 
+#if 0
                        section_name = elf_strptr(e, shstrndx, shdr.sh_name);
+#endif
 
                        if (phdr.p_offset <= shdr.sh_offset && shdr.sh_offset < phdr.p_offset + phdr.p_filesz) {
                                        
@@ -230,11 +262,13 @@ get_load(Elf *e)
 
                                sh_paddr = phdr.p_paddr + shdr.sh_offset - phdr.p_offset;
 
-                               printf ("\tsize %08x rom %08x exec %08x %s\n",
-                                       (uint32_t) shdr.sh_size,
-                                       (uint32_t) sh_paddr,
-                                       (uint32_t) shdr.sh_addr,
-                                       section_name);
+#if 0
+                               fprintf (stderr, "\tsize %08x rom %08x exec %08x %s\n",
+                                        (uint32_t) shdr.sh_size,
+                                        (uint32_t) sh_paddr,
+                                        (uint32_t) shdr.sh_addr,
+                                        section_name);
+#endif
 
                                data = elf_getdata(scn, NULL);
 
@@ -252,7 +286,7 @@ get_load(Elf *e)
  */
 
 struct ao_hex_image *
-ao_load_elf(char *name, struct ao_elf_sym *symbols, int num_symbols)
+ao_load_elf(char *name, struct ao_sym **symbols, int *num_symbols)
 {
        int             fd;
        Elf             *e;
@@ -278,10 +312,8 @@ ao_load_elf(char *name, struct ao_elf_sym *symbols, int num_symbols)
        if (elf_getshdrstrndx(e, &shstrndx) != 0)
                return NULL;
 
-       if (!find_symbols(e, symbols, num_symbols)) {
-               fprintf (stderr, "Cannot find required symbols\n");
-               return NULL;
-       }
+       if (symbols)
+               *symbols = load_symbols(e, num_symbols);
 
        image = get_load(e);
        if (!image) {
index f3a2358c7004e5024601609aeca3a39fbdbff215..0f79d1425cad04226244ee3968d70ab69ea2812a 100644 (file)
 #include <gelf.h>
 #include "ao-hex.h"
 
-struct ao_elf_sym {
-       unsigned        addr;
-       unsigned        default_addr;
-       char            *name;
-       bool            required;
-       bool            found;
-};
-
 struct ao_hex_image *
-ao_load_elf(char *name, struct ao_elf_sym *symbols, int num_symbols);
-
-int
-ao_elf_find_symbols (Elf *e, struct ao_elf_sym *symbols, int num_symbols);
+ao_load_elf(char *name, struct ao_sym **symbols, int *num_symbols);
 
 #endif /* _AO_ELF_H_ */
index 85acc07f59537c1e624d6b0000fd1146cc190ce5..5cfc63c1347e999e70b7dd2da2e4c497b33925f1 100644 (file)
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <string.h>
 #include "ao-hex.h"
+#include "ao-verbose.h"
 
 struct ao_hex_input {
        FILE    *file;
@@ -118,7 +120,7 @@ ao_hex_read_record(struct ao_hex_input *input)
 
        while (state != read_done) {
                c = getc(input->file);
-               if (c == EOF && state != read_white) {
+               if (c == EOF && state != read_white && state != read_marker) {
                        ao_hex_error(input, "Unexpected EOF");
                        goto bail;
                }
@@ -128,6 +130,8 @@ ao_hex_read_record(struct ao_hex_input *input)
                        input->line++;
                switch (state) {
                case read_marker:
+                       if (c == EOF)
+                               return NULL;
                        if (c != ':') {
                                ao_hex_error(input, "Missing ':'");
                                goto bail;
@@ -246,13 +250,20 @@ ao_hex_file_read(FILE *file, char *name)
        int done = 0;
 
        hex = calloc(sizeof (struct ao_hex_file) + sizeof (struct ao_hex_record *), 1);
+       if (!hex)
+               return NULL;
        input.name = name;
        input.line = 1;
        input.file = file;
        while (!done) {
                record = ao_hex_read_record(&input);
-               if (!record)
-                       goto bail;
+               if (!record) {
+                       if (feof(input.file)) {
+                               done = 1;
+                               break;
+                       } else
+                               goto bail;
+               }
                if (hex->nrecord == srecord) {
                        srecord *= 2;
                        newhex = realloc(hex,
@@ -263,8 +274,6 @@ ao_hex_file_read(FILE *file, char *name)
                        hex = newhex;
                }
                hex->records[hex->nrecord++] = record;
-               if (record->type == AO_HEX_RECORD_EOF)
-                       done = 1;
        }
        return hex;
 
@@ -273,6 +282,92 @@ bail:
        return NULL;
 }
 
+static struct ao_sym *
+load_symbols(struct ao_hex_file *hex,
+            int *num_symbolsp)
+{
+       uint32_t                extended_addr;
+       uint32_t                addr;
+       int                     i;
+       struct ao_hex_record    *record;
+       struct ao_sym           *symbols = NULL;
+       struct ao_sym           *symbol;
+       int                     num_symbols = 0;
+       int                     size_symbols = 0;
+       
+       extended_addr = 0;
+       for (i = 0; i < hex->nrecord; i++) {
+               record = hex->records[i];
+               switch (record->type) {
+               case AO_HEX_RECORD_NORMAL:
+                       addr = extended_addr + record->address;
+                       break;
+               case AO_HEX_RECORD_EOF:
+                       break;
+               case AO_HEX_RECORD_EXTENDED_ADDRESS_4:
+                       if (record->length != 2)
+                               goto bail;
+                       extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
+                       break;
+               case AO_HEX_RECORD_EXTENDED_ADDRESS_8:
+                       if (record->length != 2)
+                               goto bail;
+                       extended_addr = (record->data[0] << 24) | (record->data[1] << 16);
+                       break;
+               case AO_HEX_RECORD_SYMBOL:
+                       addr = extended_addr + record->address;
+                       if (num_symbols == size_symbols) {
+                               struct ao_sym   *new_symbols;
+                               int             new_size;
+
+                               if (!size_symbols)
+                                       new_size = 16;
+                               else
+                                       new_size = size_symbols * 2;
+                               new_symbols = realloc(symbols, new_size * sizeof (struct ao_sym));
+                               if (!new_symbols)
+                                       goto bail;
+
+                               symbols = new_symbols;
+                               size_symbols = new_size;
+                       }
+                       symbol = &symbols[num_symbols];
+                       memset(symbol, 0, sizeof (struct ao_sym));
+                       symbol->name = calloc(record->length + 1, 1);
+                       if (!symbol->name)
+                               goto bail;
+                       memcpy(symbol->name, record->data, record->length);
+                       symbol->addr = addr;
+                       ao_printf(AO_VERBOSE_EXE, "Add symbol %s: %08x\n", symbol->name, symbol->addr);
+                       num_symbols++;
+                       break;
+               }
+       }
+       *num_symbolsp = num_symbols;
+       return symbols;
+bail:
+       for (i = 0; i < num_symbols; i++)
+               free(symbols[i].name);
+       free(symbols);
+       return NULL;
+}
+
+static void
+ao_hex_record_set_checksum(struct ao_hex_record *record)
+{
+       uint8_t cksum = 0;
+       int i;
+
+       cksum += record->length;
+       cksum += record->address >> 8;
+       cksum += record->address;
+       cksum += record->type;
+       for (i = 0; i < record->length; i++)
+               cksum += record->data[i];
+
+       record->checksum = -cksum;
+}
+
 struct ao_hex_image *
 ao_hex_image_create(struct ao_hex_file *hex)
 {
@@ -286,6 +381,8 @@ ao_hex_image_create(struct ao_hex_file *hex)
 
        int length;
 
+       /* Find the address bounds of the file
+        */
        base = 0xffffffff;
        bound = 0x0;
        extended_addr = 0;
@@ -293,7 +390,7 @@ ao_hex_image_create(struct ao_hex_file *hex)
                uint32_t r_bound;
                record = hex->records[i];
                switch (record->type) {
-               case 0:
+               case AO_HEX_RECORD_NORMAL:
                        addr = extended_addr + record->address;
                        r_bound = addr + record->length;
                        if (addr < base)
@@ -301,20 +398,21 @@ ao_hex_image_create(struct ao_hex_file *hex)
                        if (r_bound > bound)
                                bound = r_bound;
                        break;
-               case 1:
+               case AO_HEX_RECORD_EOF:
                        break;
-               case 2:
+               case AO_HEX_RECORD_EXTENDED_ADDRESS_4:
                        if (record->length != 2)
                                return NULL;
                        extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
                        break;
-               case 4:
+               case AO_HEX_RECORD_EXTENDED_ADDRESS_8:
                        if (record->length != 2)
                                return NULL;
-                       extended_addr = ((record->data[0] << 8) | record->data[1]) << 16;
+                       extended_addr = (record->data[0] << 24) | (record->data[1] << 16);
+                       break;
+               case AO_HEX_RECORD_SYMBOL:
                        break;
                }
-
        }
        length = bound - base;
        image = calloc(sizeof(struct ao_hex_image) + length, 1);
@@ -327,18 +425,20 @@ ao_hex_image_create(struct ao_hex_file *hex)
        for (i = 0; i < hex->nrecord; i++) {
                record = hex->records[i];
                switch (record->type) {
-               case 0:
+               case AO_HEX_RECORD_NORMAL:
                        addr = extended_addr + record->address;
                        offset = addr - base;
                        memcpy(image->data + offset, record->data, record->length);
                        break;
-               case 1:
+               case AO_HEX_RECORD_EOF:
                        break;
-               case 2:
+               case AO_HEX_RECORD_EXTENDED_ADDRESS_4:
                        extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
                        break;
-               case 4:
-                       extended_addr = ((record->data[0] << 8) | record->data[1]) << 16;
+               case AO_HEX_RECORD_EXTENDED_ADDRESS_8:
+                       extended_addr = (record->data[0] << 24) | (record->data[1] << 16);
+                       break;
+               case AO_HEX_RECORD_SYMBOL:
                        break;
                }
        }
@@ -362,23 +462,165 @@ ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b)
 }
 
 struct ao_hex_image *
-ao_hex_load(char *filename)
+ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbolsp)
 {
-       FILE *file;
+       FILE                    *file;
        struct ao_hex_file      *hex_file;
-       struct ao_hex_image *hex_image;
+       struct ao_hex_image     *hex_image;
 
        file = fopen (filename, "r");
        if (!file)
-               return 0;
+               return NULL;
        
        hex_file = ao_hex_file_read(file, filename);
        fclose(file);
        if (!hex_file)
-               return 0;
+               return NULL;
        hex_image = ao_hex_image_create(hex_file);
        if (!hex_image)
-               return 0;
+               return NULL;
+
+       if (symbols)
+               *symbols = load_symbols(hex_file, num_symbolsp);
+
        ao_hex_file_free(hex_file);
        return hex_image;
 }
+
+#define BYTES_PER_RECORD       32
+
+static struct ao_hex_file *
+ao_hex_file_create(struct ao_hex_image *image, struct ao_sym *symbols, int num_symbols)
+{
+       /* split data into n-byte-sized chunks */
+       uint32_t                data_records = (image->length + BYTES_PER_RECORD-1) / BYTES_PER_RECORD;
+       /* extended address and data for each block, EOF, address and data for each symbol */
+       uint32_t                total_records = data_records * 2 + 1 + num_symbols * 2;
+       uint32_t                offset;
+       uint32_t                address;
+       uint32_t                length;
+       char                    *name;
+       struct ao_hex_file      *hex_file;
+       int                     nrecord = 0;
+       int                     s;
+       struct ao_hex_record    *record;
+
+       hex_file = calloc(sizeof (struct ao_hex_file) + sizeof (struct ao_hex_record *) * total_records, 1);
+       if (!hex_file)
+               return NULL;
+
+       /* Add the data
+        */
+       for (offset = 0; offset < image->length; offset += BYTES_PER_RECORD) {
+               uint32_t                address = image->address + offset;
+               uint32_t                length = image->length - offset;
+
+               if (length > BYTES_PER_RECORD)
+                       length = BYTES_PER_RECORD;
+
+               record = calloc(sizeof (struct ao_hex_record) + 2, 1);
+               record->type = AO_HEX_RECORD_EXTENDED_ADDRESS_8;
+               record->address = 0;
+               record->length = 2;
+               record->data[0] = address >> 24;
+               record->data[1] = address >> 16;
+               ao_hex_record_set_checksum(record);
+
+               hex_file->records[nrecord++] = record;
+
+               record = calloc(sizeof (struct ao_hex_record) + length, 1);
+               record->type = AO_HEX_RECORD_NORMAL;
+               record->address = address;
+               record->length = length;
+               memcpy(record->data, image->data + offset, length);
+               ao_hex_record_set_checksum(record);
+
+               hex_file->records[nrecord++] = record;
+       }
+
+       /* Stick an EOF after the data
+        */
+       record = calloc(sizeof (struct ao_hex_record), 1);
+       record->type = AO_HEX_RECORD_EOF;
+       record->address = 0;
+       record->length = 0;
+       record->data[0] = 0;
+       record->data[1] = 0;
+       ao_hex_record_set_checksum(record);
+
+       hex_file->records[nrecord++] = record;
+       
+       /* Add the symbols
+        */
+
+       for (s = 0; s < num_symbols; s++) {
+
+               name = symbols[s].name;
+               address = symbols[s].addr;
+               length = strlen (name);
+
+               record = calloc(sizeof (struct ao_hex_record) + 2, 1);
+               record->type = AO_HEX_RECORD_EXTENDED_ADDRESS_8;
+               record->address = 0;
+               record->length = 2;
+               record->data[0] = address >> 24;
+               record->data[1] = address >> 16;
+               ao_hex_record_set_checksum(record);
+
+               hex_file->records[nrecord++] = record;
+
+               record = calloc(sizeof (struct ao_hex_record) + length, 1);
+               record->type = AO_HEX_RECORD_SYMBOL;
+               record->address = address;
+               record->length = length;
+               memcpy(record->data, name, length);
+               ao_hex_record_set_checksum(record);
+
+               hex_file->records[nrecord++] = record;
+       }
+
+       hex_file->nrecord = nrecord;
+       return hex_file;
+}
+
+static bool
+ao_hex_write_record(FILE *file, struct ao_hex_record *record)
+{
+       int     i;
+
+       fputc(':', file);
+       fprintf(file, "%02x", record->length);
+       fprintf(file, "%04x", record->address);
+       fprintf(file, "%02x", record->type);
+       for (i = 0; i < record->length; i++)
+               fprintf(file, "%02x", record->data[i]);
+       fprintf(file, "%02x", record->checksum);
+       fputc('\n', file);
+       return true;
+}
+
+bool
+ao_hex_save(FILE *file, struct ao_hex_image *image,
+           struct ao_sym *symbols, int num_symbols)
+{
+       struct ao_hex_file      *hex_file;
+       int                     i;
+       bool                    ret = false;
+
+       hex_file = ao_hex_file_create(image, symbols, num_symbols);
+       if (!hex_file)
+               goto create_failed;
+
+       for (i = 0; i < hex_file->nrecord; i++) {
+               if (!ao_hex_write_record(file, hex_file->records[i]))
+                       goto write_failed;
+       }
+       ret = true;
+       
+       if (fflush(file) != 0)
+               ret = false;
+write_failed:
+       ao_hex_file_free(hex_file);
+create_failed:
+       return ret;
+}
index 8528eb458689b2ebc615d18a3dd11d0534eca289..9849746091f7c1c866d01992fbc15b2a51c5bc9e 100644 (file)
@@ -19,6 +19,8 @@
 #define _AO_HEX_H_
 
 #include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
 
 #define AO_HEX_RECORD_NORMAL                   0x00
 #define AO_HEX_RECORD_EOF                      0x01
@@ -47,6 +49,14 @@ struct ao_hex_image {
        uint8_t         data[0];
 };
 
+struct ao_sym {
+       unsigned        addr;
+       unsigned        default_addr;
+       char            *name;
+       bool            required;
+       bool            found;
+};
+
 struct ao_hex_file *
 ao_hex_file_read(FILE *file, char *name);
 
@@ -60,9 +70,13 @@ void
 ao_hex_image_free(struct ao_hex_image *image);
 
 struct ao_hex_image *
-ao_hex_load(char *filename);
+ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbols);
 
 int
 ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b);
 
+bool
+ao_hex_save(FILE *file, struct ao_hex_image *image,
+           struct ao_sym *symbols, int num_symbols);
+
 #endif /* _AO_HEX_H_ */
index d1de21e6eae3920df4b6cb968af011519844466d..bf801744271dafe94aa2f73780de70c08a572456 100644 (file)
@@ -406,6 +406,7 @@ ao-tools/ao-sky-flash/Makefile
 ao-tools/ao-dumpflash/Makefile
 ao-tools/ao-edit-telem/Makefile
 ao-tools/ao-dump-up/Makefile
+ao-tools/ao-elftohex/Makefile
 ao-utils/Makefile
 src/Version
 ])