mdebug

cortex m series debugger
git clone http://frotz.net/git/mdebug.git
Log | Files | Refs | README | LICENSE

debugger-core.c (12953B)


      1 /* debugger-core.c
      2  *
      3  * Copyright 2011 Brian Swetland <swetland@frotz.net>
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 
     19 #include <stdio.h>
     20 #include <stdlib.h>
     21 #include <unistd.h>
     22 #include <string.h>
     23 #include <ctype.h>
     24 #include <stdarg.h>
     25 #include <errno.h>
     26 
     27 #include <pthread.h>
     28 #include <sys/socket.h>
     29 
     30 #include <fw/types.h>
     31 #include <protocol/rswdp.h>
     32 #include "debugger.h"
     33 #include "rswdp.h"
     34 
     35 #include "websocket.h"
     36 
     37 #define DHCSR_C_DEBUGEN		(1 << 0)
     38 #define DHCSR_C_HALT		(1 << 1)
     39 #define DHCSR_C_STEP		(1 << 2)
     40 #define DHCSR_C_MASKINTS	(1 << 3)
     41 #define DHCSR_C_SNAPSTALL	(1 << 5)
     42 #define DHCSR_S_REGRDY		(1 << 16)
     43 #define DHCSR_S_HALT		(1 << 17)
     44 #define DHCSR_S_SLEEP		(1 << 18)
     45 #define DHCSR_S_LOCKUP		(1 << 19)
     46 #define DHCSR_S_RETIRE_ST	(1 << 24)
     47 #define DHCSR_S_RESET_ST	(1 << 25)
     48 
     49 #define DFSR			0xE000ED30
     50 #define DFSR_HALTED		(1 << 0)
     51 #define DFSR_BKPT		(1 << 1)
     52 #define DFSR_DWTTRAP		(1 << 2)
     53 #define DFSR_VCATCH		(1 << 3)
     54 #define DFSR_EXTERNAL		(1 << 4)
     55 #define DFSR_MASK		0x1F
     56 
     57 extern int swd_verbose;
     58 
     59 #define GDB_SOCKET	5555
     60 #define SWO_SOCKET	2332
     61 #define WEB_SOCKET	5557
     62 
     63 static void m_event(const char *evt) {
     64 	xprintf(XCORE, "DEBUG EVENT: %s\n", evt);
     65 }
     66 
     67 static void monitor(void) {
     68 	u32 v;
     69 	if (swdp_clear_error()) return;
     70 	if (swdp_ahb_read(DFSR, &v) == 0) {
     71 		if (v & DFSR_MASK) {
     72 			swdp_ahb_write(DFSR, DFSR_MASK);
     73 		}
     74 		if (v & DFSR_HALTED) m_event("HALTED");
     75 		if (v & DFSR_BKPT) m_event("BKPT");
     76 		if (v & DFSR_DWTTRAP) m_event("DWTTRAP");
     77 		if (v & DFSR_VCATCH) m_event("VCATCH");
     78 		if (v & DFSR_EXTERNAL) m_event("EXTERNAL");
     79 	}
     80 }
     81 
     82 static pthread_mutex_t _dbg_lock = PTHREAD_MUTEX_INITIALIZER;
     83 static pthread_t _dbg_thread;
     84 static pthread_t _gdb_thread;
     85 
     86 static pthread_mutex_t _swo_lock = PTHREAD_MUTEX_INITIALIZER;
     87 static pthread_t _swo_thread;
     88 static pthread_t _ws_thread;
     89 static int swo_fd = -1;
     90 static ws_server_t *_ws = NULL;
     91 
     92 void debugger_lock() {
     93 	pthread_mutex_lock(&_dbg_lock);
     94 	if (swdp_clear_error()) {
     95 #if 0
     96 		// way too noisy if the link goes down
     97 		xprintf("SWD ERROR persists. Attempting link reset.\n");
     98 #endif
     99 		swdp_reset();
    100 	}
    101 	swd_verbose = 1;
    102 }
    103 
    104 void debugger_unlock() {
    105 #if 0
    106 	if (swdp_error()) {
    107 		xprintf(XCORE, "SWD ERROR\n");
    108 	}
    109 #endif
    110 	swd_verbose = 0;
    111 	pthread_mutex_unlock(&_dbg_lock);
    112 }
    113 
    114 void *debugger_monitor(void *arg) {
    115 	for (;;) {
    116 		pthread_mutex_lock(&_dbg_lock);
    117 		monitor();
    118 		pthread_mutex_unlock(&_dbg_lock);
    119 		usleep(250000);
    120 	}
    121 }
    122 
    123 void gdb_server(int fd);
    124 int socket_listen_tcp(unsigned port);
    125 
    126 void *gdb_listener(void *arg) {
    127 	int fd;
    128 	if ((fd = socket_listen_tcp(GDB_SOCKET)) < 0) {
    129 		xprintf(XGDB, "gdb_listener() cannot bind to %d\n", GDB_SOCKET);
    130 		return NULL;
    131 	}
    132 	for (;;) {
    133 		int s = accept(fd, NULL, NULL);
    134 		if (s >= 0) {
    135 			gdb_server(s);
    136 			close(s);
    137 		}
    138 	}
    139 	return NULL;
    140 }
    141 
    142 void transmit_swo_data(void *data, unsigned len) {
    143 	pthread_mutex_lock(&_swo_lock);
    144 	if (swo_fd >= 0) {
    145 		if (write(swo_fd, data, len)) ;
    146 	}
    147 	if (_ws != NULL) {
    148 		unsigned char *x = data;
    149 		x--;
    150 		*x = 3; // SWO DATA MARKER
    151 		ws_send_binary(_ws, x, len + 1);
    152 	}
    153 	pthread_mutex_unlock(&_swo_lock);
    154 }
    155 
    156 void *swo_listener(void *arg) {
    157 	char buf[1024];
    158 	int fd;
    159 	if ((fd = socket_listen_tcp(SWO_SOCKET)) < 0) {
    160 		xprintf(XCORE, "swo_listener() cannot bind to %d\n", SWO_SOCKET);
    161 		return NULL;
    162 	}
    163 	for (;;) {
    164 		int s = accept(fd, NULL, NULL);
    165 		if (s >= 0) {
    166 			xprintf(XCORE, "[ swo listener connected ]\n");
    167 			pthread_mutex_lock(&_swo_lock);
    168 			swo_fd = s;
    169 			pthread_mutex_unlock(&_swo_lock);
    170 			for (;;) {
    171 				int r = read(s, buf, 1024);
    172 				if (r < 0) {
    173 					if (errno != EINTR) break;
    174 				}
    175 				if (r == 0) break;
    176 			}
    177 			pthread_mutex_lock(&_swo_lock);
    178 			swo_fd = -1;
    179 			pthread_mutex_unlock(&_swo_lock);
    180 			close(s);
    181 			xprintf(XCORE, "[ swo listener disconnected ]\n");
    182 		}
    183 	}
    184 	return NULL;
    185 }
    186 
    187 static void ws_message(unsigned op, void *msg, size_t len, void *cookie) {
    188 }
    189 
    190 void *ws_listener(void *arg) {
    191 	ws_server_t *ws;
    192 	int fd;
    193 	if ((fd = socket_listen_tcp(WEB_SOCKET)) < 0) {
    194 		xprintf(XCORE, "websocket cannot bind to %d\n", WEB_SOCKET);
    195 		return NULL;
    196 	}
    197 	for (;;) {
    198 		int s = accept(fd, NULL, NULL);
    199 		if (s >= 0) {
    200 			ws = ws_handshake(s, ws_message, NULL);
    201 			if (ws) {
    202 				xprintf(XCORE, "[ websocket connected ]\n");
    203 			} else {
    204 				xprintf(XCORE, "[ websocket handshake failed ]\n");
    205 				continue;
    206 			}
    207 			pthread_mutex_lock(&_swo_lock);
    208 			_ws = ws;
    209 			pthread_mutex_unlock(&_swo_lock);
    210 			ws_process_messages(ws);
    211 			pthread_mutex_lock(&_swo_lock);
    212 			_ws = NULL;
    213 			pthread_mutex_unlock(&_swo_lock);
    214 			ws_close(ws);
    215 			xprintf(XCORE, "[ websocket disconnected ]\n");
    216 		}
    217 	}
    218 	return NULL;
    219 }
    220 
    221 void debugger_init() {
    222 	pthread_create(&_dbg_thread, NULL, debugger_monitor, NULL);
    223 	pthread_create(&_gdb_thread, NULL, gdb_listener, NULL);
    224 	pthread_create(&_swo_thread, NULL, swo_listener, NULL);
    225 	pthread_create(&_ws_thread, NULL, ws_listener, NULL);
    226 }
    227 
    228 
    229 static struct varinfo *all_variables = 0;
    230 static struct funcinfo *allfuncs = 0;
    231 
    232 static int frame_argc = 0;
    233 static param *frame_argv = 0;
    234 
    235 static void variable_set(const char *name, u32 value) {
    236 	struct varinfo *vi;
    237 	int len;
    238 	for (vi = all_variables; vi; vi = vi->next) {
    239 		if (!strcmp(name, vi->name)) {
    240 			vi->value = value;
    241 			return;
    242 		}
    243 	}
    244 	len = strlen(name) + 1;
    245 	vi = malloc(sizeof(*vi) + len);
    246 	memcpy(vi->name, name, len);
    247 	vi->value = value;
    248 	vi->next = all_variables;
    249 	all_variables = vi;
    250 }
    251 
    252 static int variable_get(const char *name, u32 *value) {
    253 	struct varinfo *vi;
    254 	for (vi = all_variables; vi; vi = vi->next) {
    255 		if (!strcmp(name, vi->name)) {
    256 			*value = vi->value;
    257 			return 0;
    258 		}
    259 	}
    260 	return -1;
    261 }
    262 
    263 int debugger_variable(const char *name, u32 *value) {
    264 	return variable_get(name, value);
    265 }
    266 
    267 static int do_script(int argc, param *argv) {
    268 	FILE *fp;
    269 	char *line,linebuf[256];
    270 	struct funcinfo *newfunc = 0;
    271 	struct funcline *lastline = 0;
    272 	const char *fname = argv[0].s;
    273 
    274 	if (argc != 1)
    275 		return -1;
    276 
    277 	if (!strcmp(fname, "-")) {
    278 		fp = stdin;
    279 	} else {
    280 		if (!(fp = fopen(argv[0].s, "r"))) {
    281 			xprintf(XCORE, "error: cannot open '%s'\n", argv[0].s);
    282 			return -1;
    283 		}
    284 	}
    285 
    286 	while (fgets(linebuf, sizeof(linebuf), fp)) {
    287 		line = linebuf;
    288 		while (isspace(*line))
    289 			line++;
    290 		if (iscntrl(line[0]) || line[0] == '#')
    291 			continue;
    292 		if (!strncmp(line, "function", 8) && isspace(line[8])) {
    293 			char *name, *x;
    294 			name = line + 9;
    295 			if (newfunc) {
    296 				xprintf(XCORE, "error: nested functions not allowed\n");
    297 				break;
    298 			}
    299 			while (isspace(*name))
    300 				name++;
    301 			x = name;
    302 			while (!isspace(*x) && *x)
    303 				x++;
    304 			*x = 0;
    305 			if (*name == 0) {
    306 				xprintf(XCORE, "error: functions must have names\n");
    307 				break;
    308 			}
    309 			newfunc = malloc(sizeof(*newfunc) + strlen(name) + 1);
    310 			if (newfunc == 0) {
    311 				xprintf(XCORE, "error: out of memory\n");
    312 				break;
    313 			}
    314 			strcpy(newfunc->name, name);
    315 			newfunc->next = 0;
    316 			newfunc->lines = 0;
    317 			continue;
    318 		}
    319 		if (newfunc) {
    320 			struct funcline *fl;
    321 			if (!strncmp(line, "end", 3) && isspace(line[3])) {
    322 				newfunc->next = allfuncs;
    323 				allfuncs = newfunc;
    324 				newfunc = 0;
    325 				lastline = 0;
    326 				continue;
    327 			}
    328 			fl = malloc(sizeof(*fl) + strlen(line) + 1);
    329 			if (fl == 0) {
    330 				xprintf(XCORE, "out of memory");
    331 				newfunc = 0;
    332 				if (fp != stdin)
    333 					fclose(fp);
    334 				return -1;
    335 			}
    336 			strcpy(fl->text, line);
    337 			fl->next = 0;
    338 			if (lastline) {
    339 				lastline->next = fl;
    340 			} else {
    341 				newfunc->lines = fl;
    342 			}
    343 			lastline = fl;
    344 		} else {
    345 			xprintf(XCORE, "script> %s", line);
    346 			if (debugger_command(line))
    347 				return -1;
    348 		}
    349 	}
    350 	if (fp != stdin)
    351 		fclose(fp);
    352 
    353 	if (newfunc)
    354 		newfunc = 0;
    355 	return 0;
    356 }
    357 
    358 static int do_set(int argc, param *argv) {
    359 	const char *name;
    360 	if ((argc != 2) && (argc != 4)) {
    361 		xprintf(XCORE, "error: set requires two or four arguments\n");
    362 		return -1;
    363 	}
    364 	name = argv[0].s;
    365 	if (*name == '$')
    366 		name++;
    367 	if (*name == 0) {
    368 		xprintf(XCORE, "error: empty name?!\n");
    369 		return -1;
    370 	}
    371 	if (!isalpha(*name)) {
    372 		xprintf(XCORE, "error: variable name must begin with a letter\n");
    373 		return -1;
    374 	}
    375 
    376 	if (argc == 4) {
    377 		u32 a, b, n;
    378 		const char *op;
    379 		a = argv[1].n;
    380  		op = argv[2].s;
    381 		b = argv[3].n;
    382 		if (!strcmp(op,"+")) {
    383 			n = a + b;
    384 		} else if (!strcmp(op, "-")) {
    385 			n = a - b;
    386 		} else if (!strcmp(op, "<<")) {
    387 			n = a << b;
    388 		} else if (!strcmp(op, ">>")) {
    389 			n = a >> b;
    390 		} else if (!strcmp(op, "*")) {
    391 			n = a * b;
    392 		} else if (!strcmp(op, "/")) {
    393 			if (b == 0) {
    394 				n = 0;
    395 			} else {
    396 				n = a / b;
    397 			}
    398 		} else {
    399 			xprintf(XCORE, "error: set <var> <a> <op> <b> requires op: + - * / << >>\n");
    400 			return -1;
    401 		}
    402 		variable_set(name, n);
    403 	} else {
    404 		variable_set(name, argv[1].n);
    405 	}
    406 	return 0;
    407 }
    408 
    409 static int parse_number(const char *in, unsigned *out) {
    410 	u32 value;
    411 	char text[64];
    412 	char *obrack;
    413 	int r;
    414 
    415 	strncpy(text, in, sizeof(text));
    416 	text[sizeof(text)-1] = 0;
    417 
    418 	/* handle dereference forms */
    419 	obrack = strchr(text, '[');
    420 	if (obrack) {
    421 		unsigned base, index;
    422 		char *cbrack;
    423 		*obrack++ = 0;
    424 		cbrack = strchr(obrack, ']');
    425 		if (!cbrack)
    426 			return -1;
    427 		*cbrack = 0;
    428 		if (parse_number(text, &base))
    429 			return -1;
    430 		if (parse_number(obrack, &index))
    431 			return -1;
    432 		if (read_memory_word(base + index, &value))
    433 			return -1;
    434 		*out = value;
    435 		return 0;
    436 	}
    437 
    438 	/* handle local $[0..9] and global $... variables */
    439 	if (text[0] == '$') {
    440 		if (isdigit(text[1]) && (text[2] == 0)) {
    441 			r = atoi(text + 1);
    442 			if (r > 0) {
    443 				if (r <= frame_argc) {
    444 					*out = frame_argv[r - 1].n;
    445 					return 0;
    446 				}
    447 			}
    448 			xprintf(XCORE, "no local variable %s\n", text);
    449 			*out = 0;
    450 			return 0;
    451 		}
    452 		if (variable_get(text + 1, &value) == 0) {
    453 			*out = value;
    454 		} else {
    455 			xprintf(XCORE, "undefined variable '%s'\n", text + 1);
    456 			*out = 0;
    457 		}
    458 		return 0;
    459 	}
    460 
    461 	/* handle registers */
    462 	r = read_register(text, &value);
    463 	if (r != ERROR_UNKNOWN) {
    464 		*out = value;
    465 		return r;
    466 	}
    467 
    468 	/* otherwise decimal or hex constants */
    469 	if (text[0] == '.') {
    470 		*out = strtoul(text + 1, 0, 10);
    471 	} else {
    472 		*out = strtoul(text, 0, 16);
    473 	}
    474 	return 0;
    475 }
    476 
    477 static int exec_function(struct funcinfo *f, int argc, param *argv) {
    478 	param *saved_argv;
    479 	int saved_argc;
    480 	struct funcline *line;
    481 	char text[256];
    482 	int r, n;
    483 
    484 	saved_argv = frame_argv;
    485 	saved_argc = frame_argc;
    486 	frame_argv = argv;
    487 	frame_argc = argc;
    488 
    489 	for (line = f->lines, n = 1; line; line = line->next, n++) {
    490 		strcpy(text, line->text);
    491 		r = debugger_command(text);
    492 		if (r) {
    493 			xprintf(XCORE, "error: %s: line %d\n", f->name, n);
    494 			goto done;
    495 		}
    496 	}
    497 	r = 0;
    498 done:
    499 	frame_argc = saved_argc;
    500 	frame_argv = saved_argv;
    501 	return r;
    502 }
    503 
    504 static int _debugger_exec(const char *cmd, unsigned argc, param *argv) {
    505 	struct funcinfo *f;
    506 	struct debugger_command *c;
    507 
    508 	/* core built-ins */
    509 	if (!strcasecmp(cmd, "set"))
    510 		return do_set(argc, argv);
    511 	if (!strcasecmp(cmd, "script"))
    512 		return do_script(argc, argv);
    513 
    514 	for (c = debugger_commands; c->name; c++) {
    515 		if (!strcasecmp(cmd, c->name)) {
    516 			int n;
    517 			debugger_lock();
    518 			n = c->func(argc, argv);
    519 			debugger_unlock();
    520 			return n;
    521 		}
    522 	}
    523 	for (f = allfuncs; f; f = f->next) {
    524 		if (!strcasecmp(cmd, f->name)) {
    525 			return exec_function(f, argc, argv);
    526 		}
    527 	}
    528 	return ERROR_UNKNOWN;
    529 }
    530 
    531 int debugger_invoke(const char *cmd, unsigned argc, ...) {
    532 	param arg[32];
    533 	unsigned n;
    534 	va_list ap;
    535 
    536 	if (argc > 31)
    537 		return -1;
    538 
    539 	va_start(ap, argc);
    540 	for (n = 0; n < argc; n++) {
    541 		arg[n].s = "";
    542 		arg[n].n = va_arg(ap, unsigned);
    543 	}
    544 	return _debugger_exec(cmd, argc, arg);
    545 }
    546 
    547 int debugger_command(char *line) {
    548 	param arg[32];
    549 	unsigned c, n = 0;
    550 	int r;
    551 
    552 	while (*line && (*line == ' ')) line++;
    553 
    554 	if (*line == '/') {
    555 		arg[0].s = line + 1;
    556 		return _debugger_exec("wconsole", 1, arg);
    557 	}
    558 
    559 	while ((c = *line)) {
    560 		if (c <= ' ') {
    561 			line++;
    562 			continue;
    563 		}
    564 		arg[n].s = line;
    565 		for (;;) {
    566 			if (c == 0) {
    567 				n++;
    568 				break;
    569 			} else if (c == '#') {
    570 				*line = 0;
    571 				break;
    572 			} else if (c <= ' ') {
    573 				*line++ = 0;
    574 				n++;
    575 				break;
    576 			}
    577 			c = *++line;
    578 		}
    579 	}
    580 
    581 	if (n == 0)
    582 		return 0;
    583 
    584 	for (c = 0; c < n; c++) {
    585 		if (parse_number(arg[c].s, &(arg[c].n))) {
    586 			xprintf(XCORE, "error: bad number: %s\n", arg[c].s);
    587 			return -1;
    588 		}
    589 	}
    590 
    591 	r = _debugger_exec(arg[0].s, n - 1, arg + 1);
    592 	if (r == ERROR_UNKNOWN) {
    593 		xprintf(XCORE, "unknown command: %s\n", arg[0].s);
    594 	}
    595 	return r;
    596 }
    597 
    598 static int _fail(void) {
    599 	return -1;
    600 }
    601 
    602 debug_transport DUMMY_TRANSPORT = {
    603 	.attach = (void*) _fail,
    604 	.clear_error = (void*) _fail,
    605 	.mem_rd_32 = (void*) _fail,
    606 	.mem_wr_32 = (void*) _fail,
    607 	.mem_rd_32_c = (void*) _fail,
    608 	.mem_wr_32_c = (void*) _fail,
    609 };
    610 
    611 debug_transport *ACTIVE_TRANSPORT = &SWDP_TRANSPORT;
    612