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
--- /dev/null
+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
--- /dev/null
+.\"
+.\" 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
--- /dev/null
+/*
+ * 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);
+}
#include <unistd.h>
#include <getopt.h>
#include <string.h>
+#include <stdbool.h>
#include "stlink-common.h"
#include "ao-elf.h"
#include "ccdbg.h"
#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)
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' },
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) {
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
*/
#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;
ao-hex.c \
ao-hex.h \
ao-elf.c \
- ao-elf.h
+ ao-elf.h \
+ ao-verbose.c \
+ ao-verbose.h
#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;
}
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
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;
/* 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) {
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);
*/
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;
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) {
#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_ */
#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;
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;
}
input->line++;
switch (state) {
case read_marker:
+ if (c == EOF)
+ return NULL;
if (c != ':') {
ao_hex_error(input, "Missing ':'");
goto bail;
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,
hex = newhex;
}
hex->records[hex->nrecord++] = record;
- if (record->type == AO_HEX_RECORD_EOF)
- done = 1;
}
return hex;
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)
{
int length;
+ /* Find the address bounds of the file
+ */
base = 0xffffffff;
bound = 0x0;
extended_addr = 0;
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)
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);
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;
}
}
}
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;
+}
#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
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);
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_ */
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
])