diff --git a/src/disasm.c b/src/disasm.c
index a404032b..a01c8f3b 100644
--- a/src/disasm.c
+++ b/src/disasm.c
@@ -130,108 +130,125 @@ static void add_symbol(int address, int type, int subtype, int count, const char
cx->dis_symbols[N].count = count;
cx->dis_symbols[N].used = 0;
cx->dis_symbols[N].printed = 0;
- cx->dis_symbols[N].name = name? cleanup(mmt_strdup(name)): NULL;
- cx->dis_symbols[N].comment = comment? mmt_strdup(comment): NULL;
+ cx->dis_symbols[N].name = name? cleanup(str_rtrim(mmt_strdup(str_ltrim(name)))): NULL;
+ cx->dis_symbols[N].comment = comment? str_rtrim(mmt_strdup(str_ltrim(comment))): NULL;
}
-static int line_error(const char *token, const char *message, int lineno) {
- if((token == NULL) || (strlen(token) == 0)) {
- pmsg_error("%s in tagfile, line %d\n", message, lineno);
- return 1;
+/*
+ * Tokenising of a tagfile line returning (argc, argv); parsing ends when
+ * - A token starts with a comment character #
+ * - The comment field after the name of the symbol is encountered
+ * - The end of the string is encountered
+ *
+ * Argv is allocated once, so the caller only needs to mmt_free argv.
+ * On error NULL is returned (when input line was too long).
+ *
+ */
+static int tagfile_tokenize(char *s, int *argcp, const char ***argvp) {
+ size_t slen;
+ int n, nargs;
+ const char **argv;
+ char *buf, *q, *r;
+
+ // Upper estimate of the number of arguments
+ for(nargs=0, q=s; *q; nargs++) {
+ while(*q && !isspace((unsigned char) *q))
+ q++;
+ while(*q && isspace((unsigned char) *q))
+ q++;
}
- return 0;
-}
+ slen = q - s;
-static int tagfile_readline(char *line, int lineno, const char * const *isrnames, int ni) {
- char *token, type, subtype, *name;
- int vn, address, count;
- const char *errptr;
-
- if(line[0] == '#' || strlen(line) <= 1)
+ // Limit input line to some 186 Megabytes as max nargs is (slen+1)/2
+ if(slen > 2*((INT_MAX - 2*sizeof(char *))/(sizeof(char *)+3)))
return 0;
- token = strtok(line, " \t\n");
- if(line_error(token, "nonempty line", lineno))
- return -1;
- address = str_int(token, STR_INT32, &errptr);
- if(errptr) {
- pmsg_error("address %s: %s\n", token, errptr);
- return -1;
+ // Allocate once for pointers and contents, so caller only needs to mmt_free(argv)
+ argv = mmt_malloc((nargs+2)*sizeof(char *) + slen + nargs);
+ buf = (char *) (argv+nargs+1);
+
+ for(n=0, r=s; *r; ) {
+ q = str_nexttok(r, " \t\n\r\v\f", &r);
+ size_t len = strlen(q);
+
+ if(*q == '#') { // Inline comment: ignore rest of line
+ r = q+len;
+ break;
+ }
+ strcpy(buf, q);
+ if(*buf) // Don't record empty arguments
+ argv[n++] = buf;
+
+ if(n > 1 && n == (str_eq(argv[1], "L")? 3: 5)) { // Stop parsing after symbol name
+ if(*r)
+ argv[n] = r; // Comment, if any
+ break;
+ }
+
+ buf += len + 1;
}
- token = strtok(NULL, " \t\n");
- if(line_error(token, "no second argument", lineno))
- return -1;
- if(strlen(token) != 1) {
- line_error(NULL, "second argument should be a type (L, P or M)", lineno);
- return -1;
- }
- type = token[0];
+ *argcp = n;
+ *argvp = argv;
+ return 1;
+}
- token = strtok(NULL, " \t\n");
- if(line_error(token, "no third argument", lineno))
- return -1;
+#define Return(fmt, ...) do { \
+ pmsg_error("tagfile line %d " fmt, lineno, __VA_ARGS__); msg_error("\n"); \
+ return -1; \
+} while (0)
+
+static int tagfile_readline(char *line, int lineno, const char * const *isrnames, int ni) {
+ int type, subtype, vn, address, count, argc = 0;
+ const char *errptr, **argv = NULL;
+
+ if(!tagfile_tokenize(line, &argc, &argv))
+ Return("%s", "is too long");
+ if(argc == 0)
+ return 0;
+ if(argc < 3)
+ Return("%s", "needs at least address, symbol type (L/P/M) and name");
+
+ address = str_int(argv[0], STR_INT32, &errptr);
+ if(errptr)
+ Return("address %s: %s", argv[0], errptr);
+
+ if(strlen(argv[1]) != 1 || !strchr("LPM", *argv[1]))
+ Return("%s", "2nd argument must be L, P or M");
+ type = *argv[1];
if(type == 'L') {
- name = token; // Name, comment is optional
-
+ const char *name = argv[2];
if(str_starts(name, "__vector_") && looks_like_number(name + 9))
if((vn = strtol(name+9, NULL, 0)) > 0 && vn < ni) // Don't replace __vectors_0
name = str_lc((char *) str_ccprintf("__vector_%s", isrnames[vn]));
-
- add_symbol(address, 'L', TYPE_BYTE, 1, name, strtok(NULL, "\t\n"));
+ add_symbol(address, 'L', TYPE_BYTE, 1, name, argv[3]);
return 0;
}
- if(line_error(token, "no fourth argument", lineno))
- return -1;
- if(strlen(token) != 1) {
- line_error(NULL, "fourth argument should be a subtype (B, W, A or S)", lineno);
- return -1;
- }
- subtype = token[0];
+ if(argc < 5 || strlen(argv[2]) != 1 || !strchr("BWAS", *argv[2]))
+ Return("needs to be
%c [%s] ", type, type == 'M'? "BW": "BWAS");
- switch(subtype) {
- case 'B':
- subtype = TYPE_BYTE;
- break;
- case 'W':
- subtype = TYPE_WORD;
- break;
- case 'A':
- subtype = TYPE_ASTRING;
- break;
- case 'S':
- subtype = TYPE_STRING;
- break;
- default:
- line_error(NULL, "invalid subtype (expected one of B, W, A or S)", lineno);
+ switch(*argv[2]) {
+ default: subtype = TYPE_BYTE; break;
+ case 'W': subtype = TYPE_WORD; break;
+ case 'A': subtype = TYPE_ASTRING; break;
+ case 'S': subtype = TYPE_STRING;
+ }
+
+ if(type == 'M' && subtype != TYPE_BYTE && subtype != TYPE_WORD) {
+ pmsg_error("memory label type can only be B(yte) or W(ord)");
return -1;
}
- if((type == 'M') && ((subtype != TYPE_BYTE) && (subtype != TYPE_WORD))) {
- line_error(NULL, "memory labels can only be of type B or W", lineno);
- return -1;
- }
+ count = str_int(argv[3], STR_INT32, &errptr);
+ if(errptr)
+ Return("count %s: %s\n", argv[3], errptr);
+ if(count < 1)
+ Return("tagfile line %d has invalid count %d", lineno, count);
- token = strtok(NULL, " \t\n");
- count = str_int(token, STR_INT32, &errptr);
- if(errptr) {
- pmsg_error("count %s: %s\n", token, errptr);
- return -1;
- }
- if(count < 1) {
- line_error(NULL, str_ccprintf("invalid count %d given", count), lineno);
- return -1;
- }
-
- name = strtok(NULL, " \t\n");
- if(type != 'P' && type != 'M') {
- pmsg_error("invalid tag type %c (must be L, P or M)\n", type);
- return -1;
- }
-
- add_symbol(address, type, subtype, count, name, NULL);
+ add_symbol(address, type, subtype, count, argv[4], argv[5]);
+ mmt_free(argv);
return 0;
}
@@ -386,8 +403,8 @@ typedef struct {
char label[LINE_N], code[LINE_N], comment[LINE_N];
} Disasm_line;
-// Column where opcode starts
-static int codecol() {
+// Comments start in commentcol() + 1
+static int commentcol() {
int ret = 0;
if(cx->dis_opts.addresses)
ret += 3 + cx->dis_addrwidth;
@@ -398,7 +415,7 @@ static int codecol() {
if(cx->dis_opts.opcode_bytes)
ret += 12;
- return ret? ret+1: 2;
+ return (ret? ret+1: 2) + cx->dis_codewidth;
}
static int is_jumpable(int address) {
@@ -413,7 +430,7 @@ static int is_jumpable(int address) {
static void lineout(const char *code, const char *comment,
int mnemo, int oplen, const char *buf, int pos, int addr, int showlabel) {
- int here = disasm_wrap(pos + addr), codewidth = 27;
+ int here = disasm_wrap(pos + addr);
if(cx->dis_opts.labels && showlabel) {
int match = 0;
@@ -430,7 +447,7 @@ static void lineout(const char *code, const char *comment,
if(match && (name = get_label_name(here, &comment))) {
if(comment)
- disasm_out("%-*s ; %s\n", codecol() + codewidth, str_ccprintf("%s:", name), comment);
+ disasm_out("%-*s ; %s\n", commentcol(), str_ccprintf("%s:", name), comment);
else
disasm_out("%s:\n", name);
}
@@ -445,11 +462,11 @@ static void lineout(const char *code, const char *comment,
if(cx->dis_opts.opcode_bytes)
for(int i = 0; i < 4; i++)
disasm_out(i < oplen? "%02x ": " ", buf[pos + i] & 0xff);
- disasm_out(codecol() > 2? " ": " ");
+ disasm_out(commentcol() > 2 + cx->dis_codewidth? " ": " ");
if(!comment || !*comment || !cx->dis_opts.comments)
disasm_out("%s\n", code);
else
- disasm_out("%-*s ; %s\n", codewidth, code, comment);
+ disasm_out("%-*s ; %s\n", cx->dis_codewidth, code, comment);
if(mnemo == MNEMO_ret || mnemo == MNEMO_u_ret || mnemo == MNEMO_reti || mnemo == MNEMO_u_reti)
cx->dis_para = 1;
}
@@ -559,14 +576,19 @@ static void emit_used_symbols() {
int len, maxlen = 0;
for(int i = 0; i < cx->dis_symbolN; i++)
- if(s[i].used && !s[i].printed)
+ if(s[i].used && !s[i].printed && s[i].name)
if((len = strlen(s[i].name)) > maxlen)
maxlen = len;
for(int i = 0; i < cx->dis_symbolN; i++)
- if(s[i].used && !s[i].printed)
- disasm_out(".equ %s,%*s 0x%02x\n", s[i].name,
- (int) (maxlen-strlen(s[i].name)), "", s[i].address);
+ if(s[i].used && !s[i].printed && s[i].name) {
+ const char *equ = str_ccprintf(".equ %s,%*s 0x%02x", s[i].name,
+ (int) (maxlen-strlen(s[i].name)), "", s[i].address);
+ if(s[i].comment)
+ disasm_out("%-*s ; %s\n", commentcol(), equ, s[i].comment);
+ else
+ disasm_out("%s\n", equ);
+ }
}
void disasm_zap_jumpcalls() {
@@ -1085,6 +1107,7 @@ int disasm_init(const AVRPART *p) {
cx->dis_flashsz2 = 0; // Flash size rounded up to next power of two
cx->dis_addrwidth = 4; // Number of hex digits needed for flash addresses
cx->dis_sramwidth = 4; // Number of hex digits needed for sram addresses
+ cx->dis_codewidth = 27; // Width of the code column (ldi r17, 0x32)
if((mem = avr_locate_flash(p)) && mem->size > 1) {
int nbits = intlog2(mem->size - 1) + 1;
diff --git a/src/libavrdude.h b/src/libavrdude.h
index 3a44c2ae..7f085136 100644
--- a/src/libavrdude.h
+++ b/src/libavrdude.h
@@ -1824,7 +1824,7 @@ typedef struct {
// Static variables from disasm.c
int dis_initopts, dis_flashsz, dis_flashsz2, dis_addrwidth, dis_sramwidth;
- int dis_pass, dis_para, dis_cycle_index, dis_io_offset;
+ int dis_pass, dis_para, dis_cycle_index, dis_io_offset, dis_codewidth;
Disasm_options dis_opts;
int dis_jumpcallN, dis_symbolN, *dis_jumpable, dis_start, dis_end;
Disasm_jumpcall *dis_jumpcalls;