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