1 /* MSPDebug - debugging tool for MSP430 MCUs
2 * Copyright (C) 2009, 2010 Daniel Beer
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <stdio.h>
20 #include <assert.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <ctype.h>
24
25 #include "dis.h"
26 #include "output_util.h"
27 #include "stab.h"
28 #include "util.h"
29 #include "demangle.h"
30 #include "opdb.h"
31
copy_string(int lowercase_dis,char * dst,const char * const end,const char * src)32 static char* copy_string(int lowercase_dis, char *dst, const char *const end,
33 const char *src)
34 {
35 int c;
36
37 if (src != NULL) {
38 while (dst < end && (c = *src++) != '\0') {
39 if (lowercase_dis && isupper(c))
40 c = tolower(c);
41 *dst++ = c;
42 }
43 }
44 *dst = '\0';
45 return dst;
46 }
47
opcode_name_with_size(const struct msp430_instruction * insn)48 static const char *opcode_name_with_size(const struct msp430_instruction *insn)
49 {
50 static char buf[10];
51 const char *const end = buf + sizeof(buf) - 1;
52 const char *opname = dis_opcode_name(insn->op);
53 const int lowercase_dis = opdb_get_boolean("lowercase_dis");
54 const char *suffix = NULL;
55 char *dst;
56
57 if (!opname)
58 opname = "???";
59
60 if (insn->dsize == MSP430_DSIZE_BYTE)
61 suffix = ".B";
62 else if (insn->dsize == MSP430_DSIZE_AWORD)
63 suffix = ".A";
64 else if (insn->dsize == MSP430_DSIZE_UNKNOWN)
65 suffix = ".?";
66
67 /* Don't show the .A suffix for these instructions */
68 if (insn->op == MSP430_OP_MOVA || insn->op == MSP430_OP_CMPA ||
69 insn->op == MSP430_OP_SUBA || insn->op == MSP430_OP_ADDA ||
70 insn->op == MSP430_OP_BRA || insn->op == MSP430_OP_RETA)
71 suffix = NULL;
72
73 dst = copy_string(lowercase_dis, buf, end, opname);
74 dst = copy_string(lowercase_dis, dst, end, suffix);
75 return buf;
76 }
77
reg_name(const msp430_reg_t reg)78 static const char *reg_name(const msp430_reg_t reg)
79 {
80 static char buf[4];
81 const char *const end = buf + sizeof(buf) - 1;
82 const int lowercase_dis = opdb_get_boolean("lowercase_dis");
83 const char *name = dis_reg_name(reg);
84
85 if (!name)
86 return "???";
87 if (lowercase_dis == 0)
88 return name;
89 copy_string(lowercase_dis, buf, end, name);
90 return buf;
91 }
92
format_addr(msp430_amode_t amode,address_t addr,msp430_dsize_t dsize)93 static int format_addr(msp430_amode_t amode, address_t addr,
94 msp430_dsize_t dsize)
95 {
96 char name[MAX_SYMBOL_LENGTH];
97 const char *prefix = "";
98 int print_flags = PRINT_ADDRESS_EXACT;
99
100 switch (amode) {
101 case MSP430_AMODE_REGISTER:
102 case MSP430_AMODE_INDIRECT:
103 case MSP430_AMODE_INDIRECT_INC:
104 return 0;
105
106 case MSP430_AMODE_IMMEDIATE:
107 prefix = "#";
108 if (dsize == MSP430_DSIZE_BYTE)
109 print_flags |= PRINT_BYTE_DATA;
110 case MSP430_AMODE_INDEXED:
111 break;
112
113 case MSP430_AMODE_ABSOLUTE:
114 prefix = "&";
115 break;
116
117 case MSP430_AMODE_SYMBOLIC:
118 break;
119 }
120
121 print_address(addr, name, sizeof(name), print_flags);
122 return printc("%s\x1b[1m%s\x1b[0m", prefix, name);
123 }
124
format_reg(msp430_amode_t amode,msp430_reg_t reg)125 static int format_reg(msp430_amode_t amode, msp430_reg_t reg)
126 {
127 const char *prefix = "";
128 const char *suffix = "";
129
130 switch (amode) {
131 case MSP430_AMODE_REGISTER:
132 break;
133
134 case MSP430_AMODE_INDEXED:
135 prefix = "(";
136 suffix = ")";
137 break;
138
139 case MSP430_AMODE_IMMEDIATE:
140 case MSP430_AMODE_SYMBOLIC:
141 case MSP430_AMODE_ABSOLUTE:
142 return 0;
143
144 case MSP430_AMODE_INDIRECT_INC:
145 suffix = "+";
146 case MSP430_AMODE_INDIRECT:
147 prefix = "@";
148 break;
149 }
150
151 return printc("%s\x1b[33m%s\x1b[0m%s", prefix, reg_name(reg), suffix);
152 }
153
154 /* Given an operands addressing mode, value and associated register,
155 * print the canonical representation of it to stdout.
156 *
157 * Returns the number of characters printed.
158 */
format_operand(msp430_amode_t amode,address_t addr,msp430_reg_t reg,msp430_dsize_t dsize)159 static int format_operand(msp430_amode_t amode, address_t addr,
160 msp430_reg_t reg, msp430_dsize_t dsize)
161 {
162 int len = 0;
163
164 len += format_addr(amode, addr, dsize);
165 len += format_reg(amode, reg);
166
167 return len;
168 }
169
170 /* Write assembly language for the instruction to this buffer */
dis_format(const struct msp430_instruction * insn)171 static int dis_format(const struct msp430_instruction *insn)
172 {
173 int len = 0;
174
175 len += printc("\x1b[36m%s\x1b[0m", opcode_name_with_size(insn));
176 while (len < 8)
177 len += printc(" ");
178
179 /* Source operand */
180 if (insn->itype == MSP430_ITYPE_DOUBLE) {
181 len += format_operand(insn->src_mode,
182 insn->src_addr,
183 insn->src_reg,
184 insn->dsize);
185
186 len += printc(",");
187 while (len < 15)
188 len += printc(" ");
189 len += printc(" ");
190 }
191
192 /* Destination operand */
193 if (insn->itype != MSP430_ITYPE_NOARG)
194 len += format_operand(insn->dst_mode,
195 insn->dst_addr,
196 insn->dst_reg,
197 insn->dsize);
198
199 /* Repetition count */
200 if (insn->rep_register)
201 len += printc(" [repeat %s]", reg_name(insn->rep_index));
202 else if (insn->rep_index)
203 len += printc(" [repeat %d]", insn->rep_index + 1);
204
205 return len;
206 }
207
disassemble(address_t offset,const uint8_t * data,int length,powerbuf_t power)208 address_t disassemble(address_t offset, const uint8_t *data, int length,
209 powerbuf_t power)
210 {
211 int first_line = 1;
212 unsigned long long ua_total = 0;
213 int samples_total = 0;
214 address_t next_offset = offset;
215
216 while (length) {
217 struct msp430_instruction insn = {0};
218 int retval;
219 int count;
220 int i;
221 address_t oboff;
222 char obname[MAX_SYMBOL_LENGTH];
223
224 if (first_line ||
225 (!stab_nearest(offset, obname, sizeof(obname), &oboff) &&
226 !oboff)) {
227 char buffer[MAX_SYMBOL_LENGTH];
228
229 print_address(offset, buffer, sizeof(buffer), 0);
230 printc("\x1b[m%s\x1b[0m:\n", buffer);
231 }
232 first_line = 0;
233
234 retval = dis_decode(data, offset, length, &insn);
235 if (retval > 0)
236 next_offset = offset + retval;
237 count = retval > 0 ? retval : 2;
238 if (count > length)
239 count = length;
240
241 printc(" \x1b[36m%05x\x1b[0m:", offset);
242
243 for (i = 0; i < count; i++)
244 printc(" %02x", data[i]);
245
246 while (i < 9) {
247 printc(" ");
248 i++;
249 }
250
251 if (retval >= 0)
252 i = dis_format(&insn);
253
254 if (power) {
255 unsigned long long ua;
256 int samples;
257
258 while (i < 40) {
259 printc(" ");
260 i++;
261 }
262
263 samples = powerbuf_get_by_mab(power, offset, &ua);
264 if (samples) {
265 printc(" ;; %.01f uA",
266 (double)ua / (double)samples);
267 ua_total += ua;
268 samples_total += samples;
269 }
270 }
271
272 printc("\n");
273
274 offset += count;
275 length -= count;
276 data += count;
277 }
278
279 if (power && samples_total)
280 printc(";; Total over this block: "
281 "%.01f uAs in %.01f ms (%.01f uA avg)\n",
282 (double)(ua_total * power->interval_us) / 1000000.0,
283 (double)(samples_total * power->interval_us) / 1000.0,
284 (double)ua_total / (double)samples_total);
285
286 return next_offset;
287 }
288
hexdump(address_t addr,const uint8_t * data,int data_len)289 void hexdump(address_t addr, const uint8_t *data, int data_len)
290 {
291 int offset = 0;
292
293 while (offset < data_len) {
294 int i, j;
295
296 /* Address label */
297 printc(" \x1b[36m%05x:\x1b[0m", offset + addr);
298
299 /* Hex portion */
300 for (i = 0; i < 16 && offset + i < data_len; i++)
301 printc(" %02x", data[offset + i]);
302 for (j = i; j < 16; j++)
303 printc(" ");
304
305 /* Printable characters */
306 printc(" \x1b[32m|");
307 for (j = 0; j < i; j++) {
308 int c = data[offset + j];
309
310 printc("%c", (c >= 32 && c <= 126) ? c : '.');
311 }
312 for (; j < 16; j++)
313 printc(" ");
314 printc("|\x1b[0m\n");
315
316 offset += i;
317 }
318 }
319
show_regs(const address_t * regs)320 void show_regs(const address_t *regs)
321 {
322 int i;
323
324 for (i = 0; i < 4; i++) {
325 int j;
326
327 printc(" ");
328 for (j = 0; j < 4; j++) {
329 int k = j * 4 + i;
330
331 printc("(\x1b[1m%3s:\x1b[0m %05x) ",
332 reg_name(k), regs[k]);
333 }
334
335 printc("\n");
336 }
337 }
338
print_address(address_t addr,char * out,int max_len,print_address_flags_t f)339 int print_address(address_t addr, char *out, int max_len,
340 print_address_flags_t f)
341 {
342 char name[MAX_SYMBOL_LENGTH];
343 address_t offset;
344
345 if (!stab_nearest(addr, name, sizeof(name), &offset)) {
346 char demangled[MAX_SYMBOL_LENGTH];
347 int len;
348
349 if (offset) {
350 if (f & PRINT_ADDRESS_EXACT) {
351 snprintf(out, max_len, "0x%04x", addr);
352 return 0;
353 }
354
355 len = snprintf(out, max_len, "%s+0x%x", name, offset);
356 } else {
357 len = snprintf(out, max_len, "%s", name);
358 }
359
360 if (demangle(name, demangled, sizeof(demangled)) > 0)
361 snprintf(out + len, max_len - len, " (%s)", demangled);
362
363 return 1;
364 }
365
366 snprintf(out, max_len, (f & PRINT_BYTE_DATA) ? "0x%02x" : "0x%04x", addr);
367 return 0;
368 }
369
370 /************************************************************************
371 * Name lists
372 */
373
namelist_cmp(const void * a,const void * b)374 static int namelist_cmp(const void *a, const void *b)
375 {
376 return strcasecmp(*(const char **)a, *(const char **)b);
377 }
378
namelist_print(struct vector * v)379 void namelist_print(struct vector *v)
380 {
381 int i;
382 int max_len = 0;
383 int rows, cols;
384
385 qsort(v->ptr, v->size, v->elemsize, namelist_cmp);
386
387 for (i = 0; i < v->size; i++) {
388 const char *text = VECTOR_AT(*v, i, const char *);
389 int len = strlen(text);
390
391 if (len > max_len)
392 max_len = len;
393 }
394
395 max_len += 2;
396 cols = 72 / max_len;
397 rows = (v->size + cols - 1) / cols;
398
399 for (i = 0; i < rows; i++) {
400 int j;
401
402 printc(" ");
403 for (j = 0; j < cols; j++) {
404 int k = j * rows + i;
405 const char *text;
406
407 if (k >= v->size)
408 break;
409
410 text = VECTOR_AT(*v, k, const char *);
411 printc("%s", text);
412 for (k = strlen(text); k < max_len; k++)
413 printc(" ");
414 }
415
416 printc("\n");
417 }
418 }
419