Added support for COFF file format.
This commit is contained in:
parent
31cfaf213b
commit
dae8f2dc61
4
Makefile
4
Makefile
|
@ -28,7 +28,7 @@ else
|
|||
endif
|
||||
|
||||
# Mac OS X/MacPorts stuff
|
||||
UNAME :=$(shell sh -c 'uname -s')
|
||||
UNAME := $(shell sh -c 'uname -s')
|
||||
ifeq ($(UNAME),Darwin)
|
||||
MACPORTS_CFLAGS = -I/opt/local/include
|
||||
MACPORTS_LDFLAGS = -L/opt/local/lib
|
||||
|
@ -56,7 +56,7 @@ install: mspdebug mspdebug.man
|
|||
mspdebug: main.o fet.o rf2500.o dis.o uif.o olimex.o ihex.o elf32.o stab.o \
|
||||
util.o bsl.o sim.o symmap.o gdb.o btree.o rtools.o sym.o devcmd.o \
|
||||
cproc.o vector.o cproc_util.o expr.o fet_error.o binfile.o fet_db.o \
|
||||
usbutil.o titext.o srec.o device.o
|
||||
usbutil.o titext.o srec.o device.o coff.o
|
||||
$(CC) $(LDFLAGS) $(MACPORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
|
||||
|
||||
.c.o:
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "symmap.h"
|
||||
#include "titext.h"
|
||||
#include "srec.h"
|
||||
#include "coff.h"
|
||||
|
||||
struct file_format {
|
||||
int (*check)(FILE *in);
|
||||
|
@ -51,6 +52,11 @@ static const struct file_format formats[] = {
|
|||
{
|
||||
.check = srec_check,
|
||||
.extract = srec_extract
|
||||
},
|
||||
{
|
||||
.check = coff_check,
|
||||
.extract = coff_extract,
|
||||
.syms = coff_syms
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,397 @@
|
|||
/* MSPDebug - debugging tool for MSP430 MCUs
|
||||
* Copyright (C) 2009, 2010 Daniel Beer
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "coff.h"
|
||||
#include "util.h"
|
||||
|
||||
struct coff_header {
|
||||
uint16_t version;
|
||||
int sec_count;
|
||||
uint32_t timestamp;
|
||||
int stab_start;
|
||||
int stab_count;
|
||||
int opt_bytes;
|
||||
uint16_t flags;
|
||||
uint16_t target_id;
|
||||
};
|
||||
|
||||
/* Header sizes */
|
||||
#define FILE_HEADER_SIZE 22
|
||||
#define OPT_HEADER_SIZE 28
|
||||
#define SHDR_SIZE 48
|
||||
#define STAB_ENTRY_SIZE 18
|
||||
|
||||
/* Bits in the flags field */
|
||||
#define F_RELFLG 0x0001
|
||||
#define F_EXEC 0x0002
|
||||
#define F_LSYMS 0x0008
|
||||
#define F_LITTLE 0x0100
|
||||
#define F_BIG 0x0200
|
||||
#define F_SYMMERGE 0x1000
|
||||
|
||||
/* Section header flags */
|
||||
#define STYP_REG 0x00000000
|
||||
#define STYP_DSECT 0x00000001
|
||||
#define STYP_NOLOAD 0x00000002
|
||||
#define STYP_GROUP 0x00000004
|
||||
#define STYP_PAD 0x00000008
|
||||
#define STYP_COPY 0x00000010
|
||||
#define STYP_TEXT 0x00000020
|
||||
#define STYP_DATA 0x00000040
|
||||
#define STYP_BSS 0x00000080
|
||||
#define STYP_BLOCK 0x00001000
|
||||
#define STYP_PASS 0x00002000
|
||||
#define STYP_CLINK 0x00004000
|
||||
#define STYP_VECTOR 0x00008000
|
||||
#define STYP_PADDED 0x00010000
|
||||
|
||||
/* Symbol storage classes */
|
||||
#define C_NULL 0
|
||||
#define C_AUTO 1
|
||||
#define C_EXT 2
|
||||
#define C_STAT 3
|
||||
#define C_REG 4
|
||||
#define C_EXTREF 5
|
||||
#define C_LABEL 6
|
||||
#define C_ULABEL 7
|
||||
#define C_MOS 8
|
||||
#define C_ARG 9
|
||||
#define C_STRTAG 10
|
||||
#define C_MOU 11
|
||||
#define C_UNTAG 12
|
||||
#define C_TPDEF 13
|
||||
#define C_USTATIC 14
|
||||
#define C_ENTAG 15
|
||||
#define C_MOE 16
|
||||
#define C_REGPARM 17
|
||||
#define C_FIELD 18
|
||||
#define C_UEXT 19
|
||||
#define C_STATLAB 20
|
||||
#define C_EXTLAB 21
|
||||
#define C_VARARG 22
|
||||
#define C_BLOCK 100
|
||||
#define C_FCN 101
|
||||
#define C_EOS 102
|
||||
#define C_FILE 103
|
||||
#define C_LINE 104
|
||||
|
||||
/* MSP430 magic number */
|
||||
#define MSP430_MAGIC 0x00a0
|
||||
|
||||
static int read_block(FILE *in, int offset, int size, void *buf)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (size < 0) {
|
||||
fprintf(stderr, "coff: invalid size: %d\n", size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fseek(in, offset, SEEK_SET) < 0) {
|
||||
fprintf(stderr, "coff: can't seek to offset %d: %s\n",
|
||||
offset, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = fread(buf, 1, size, in);
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "coff: can't read %d bytes from "
|
||||
"offset %d: %s\n",
|
||||
size, offset, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len < size) {
|
||||
fprintf(stderr, "coff: can't read %d bytes from "
|
||||
"offset %d: short read\n",
|
||||
size, offset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void parse_header(const uint8_t *data, struct coff_header *hdr)
|
||||
{
|
||||
hdr->version = LE_WORD(data, 0);
|
||||
hdr->sec_count = LE_WORD(data, 2);
|
||||
hdr->timestamp = LE_LONG(data, 4);
|
||||
hdr->stab_start = LE_LONG(data, 8);
|
||||
hdr->stab_count = LE_LONG(data, 12);
|
||||
hdr->opt_bytes = LE_WORD(data, 16);
|
||||
hdr->flags = LE_WORD(data, 18);
|
||||
hdr->target_id = LE_WORD(data, 20);
|
||||
}
|
||||
|
||||
static int read_header(FILE *in, struct coff_header *hdr)
|
||||
{
|
||||
uint8_t hdr_data[FILE_HEADER_SIZE];
|
||||
|
||||
if (read_block(in, 0, FILE_HEADER_SIZE, hdr_data) < 0) {
|
||||
fprintf(stderr, "coff: failed to extract COFF header\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
parse_header(hdr_data, hdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int coff_check(FILE *in)
|
||||
{
|
||||
uint8_t data[FILE_HEADER_SIZE];
|
||||
|
||||
rewind(in);
|
||||
if (fread(data, 1, FILE_HEADER_SIZE, in) != FILE_HEADER_SIZE)
|
||||
return 0;
|
||||
|
||||
return data[20] == 0xa0 && !data[21];
|
||||
}
|
||||
|
||||
static int read_sechdrs(FILE *in, const struct coff_header *hdr,
|
||||
uint8_t **ret_tab)
|
||||
{
|
||||
uint8_t *table;
|
||||
int alloc_size = SHDR_SIZE * hdr->sec_count;
|
||||
|
||||
if (!hdr->sec_count) {
|
||||
*ret_tab = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
table = malloc(alloc_size);
|
||||
if (!table) {
|
||||
perror("coff: can't allocate memory for section headers");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (read_block(in, hdr->opt_bytes + FILE_HEADER_SIZE,
|
||||
SHDR_SIZE * hdr->sec_count, table) < 0) {
|
||||
fprintf(stderr, "coff: can't read section headers\n");
|
||||
free(table);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ret_tab = table;
|
||||
return hdr->sec_count;
|
||||
}
|
||||
|
||||
static int load_section(FILE *in, uint32_t addr, uint32_t offset,
|
||||
uint32_t size,
|
||||
binfile_imgcb_t cb, void *user_data)
|
||||
{
|
||||
uint8_t *section;
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
section = malloc(size);
|
||||
if (!section) {
|
||||
fprintf(stderr, "coff: couldn't allocate memory for "
|
||||
"section at 0x%x: %s\n", offset, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (read_block(in, offset, size, section) < 0) {
|
||||
fprintf(stderr, "coff: couldn't read section at 0x%x\n",
|
||||
offset);
|
||||
free(section);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cb(user_data, addr, section, size) < 0) {
|
||||
free(section);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(section);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int coff_extract(FILE *in, binfile_imgcb_t cb, void *user_data)
|
||||
{
|
||||
struct coff_header hdr;
|
||||
uint8_t *shdrs;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
if (read_header(in, &hdr) < 0)
|
||||
return -1;
|
||||
|
||||
if (read_sechdrs(in, &hdr, &shdrs) < 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < hdr.sec_count; i++) {
|
||||
uint8_t *header = shdrs + SHDR_SIZE * i;
|
||||
uint32_t flags = LE_LONG(header, 40);
|
||||
|
||||
if (((flags & STYP_TEXT) || (flags & STYP_DATA)) &&
|
||||
!(flags & STYP_NOLOAD)) {
|
||||
uint32_t addr = LE_LONG(header, 8);
|
||||
uint32_t offset = LE_LONG(header, 20);
|
||||
uint32_t size = LE_LONG(header, 16);
|
||||
|
||||
if (load_section(in, addr, offset, size,
|
||||
cb, user_data) < 0) {
|
||||
fprintf(stderr, "coff: error while loading "
|
||||
"section %d\n", i);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shdrs)
|
||||
free(shdrs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_strtab(FILE *in, const struct coff_header *hdr,
|
||||
char **ret_tab)
|
||||
{
|
||||
char *strtab;
|
||||
int file_size;
|
||||
int alloc_size;
|
||||
int strtab_len;
|
||||
int strtab_start = hdr->stab_count * STAB_ENTRY_SIZE + hdr->stab_start;
|
||||
|
||||
if (fseek(in, 0, SEEK_END) < 0) {
|
||||
fprintf(stderr, "coff: can't seek to end\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
file_size = ftell(in);
|
||||
strtab_len = file_size - strtab_start;
|
||||
|
||||
if (strtab_len < 0) {
|
||||
fprintf(stderr, "coff: invalid string table size\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!strtab_len) {
|
||||
*ret_tab = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
alloc_size = strtab_len + 1;
|
||||
strtab = malloc(alloc_size);
|
||||
if (!strtab) {
|
||||
perror("coff: can't allocate memory for string table");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (read_block(in, strtab_start, strtab_len, strtab) < 0) {
|
||||
fprintf(stderr, "coff: failed to read string table\n");
|
||||
free(strtab);
|
||||
return -1;
|
||||
}
|
||||
|
||||
strtab[strtab_len] = 0;
|
||||
*ret_tab = strtab;
|
||||
return strtab_len;
|
||||
}
|
||||
|
||||
static int read_symtab(FILE *in, const struct coff_header *hdr,
|
||||
uint8_t **ret_tab)
|
||||
{
|
||||
uint8_t *table;
|
||||
int alloc_size = STAB_ENTRY_SIZE * hdr->stab_count;
|
||||
|
||||
if (!hdr->stab_count) {
|
||||
*ret_tab = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
table = malloc(alloc_size);
|
||||
if (!table) {
|
||||
perror("coff: failed to allocate memory for symbol table");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (read_block(in, hdr->stab_start,
|
||||
STAB_ENTRY_SIZE * hdr->stab_count, table) < 0) {
|
||||
fprintf(stderr, "coff: failed to read symbol table\n");
|
||||
free(table);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ret_tab = table;
|
||||
return hdr->stab_count;
|
||||
}
|
||||
|
||||
int coff_syms(FILE *in, stab_t stab)
|
||||
{
|
||||
struct coff_header hdr;
|
||||
char *strtab;
|
||||
uint8_t *symtab;
|
||||
int strtab_len;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
if (read_header(in, &hdr) < 0)
|
||||
return -1;
|
||||
|
||||
strtab_len = read_strtab(in, &hdr, &strtab);
|
||||
if (strtab_len < 0)
|
||||
return -1;
|
||||
|
||||
if (read_symtab(in, &hdr, &symtab) < 0) {
|
||||
if (strtab)
|
||||
free(strtab);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < hdr.stab_count; i++) {
|
||||
uint8_t *entry = symtab + i * STAB_ENTRY_SIZE;
|
||||
uint32_t value = LE_LONG(entry, 8);
|
||||
int storage_class = entry[16];
|
||||
char namebuf[9];
|
||||
const char *name = NULL;
|
||||
|
||||
if (LE_LONG(entry, 0)) {
|
||||
memcpy(namebuf, entry, 8);
|
||||
namebuf[8] = 0;
|
||||
name = namebuf;
|
||||
} else {
|
||||
uint32_t offset = LE_LONG(entry, 4);
|
||||
|
||||
if (offset >= 4 && offset < strtab_len)
|
||||
name = strtab + offset;
|
||||
}
|
||||
|
||||
if ((storage_class == C_EXT || storage_class == C_LABEL) &&
|
||||
stab_set(stab, name, value) < 0) {
|
||||
fprintf(stderr, "coff: failed to insert symbol\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Skip auxiliary entries */
|
||||
i += entry[17];
|
||||
}
|
||||
|
||||
if (symtab)
|
||||
free(symtab);
|
||||
if (strtab)
|
||||
free(strtab);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/* MSPDebug - debugging tool for MSP430 MCUs
|
||||
* Copyright (C) 2009, 2010 Daniel Beer
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef COFF_H_
|
||||
#define COFF_H_
|
||||
|
||||
#include "binfile.h"
|
||||
|
||||
int coff_check(FILE *in);
|
||||
int coff_extract(FILE *in, binfile_imgcb_t cb, void *user_data);
|
||||
int coff_syms(FILE *in, stab_t stab);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue