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