debugger-core.c (10413B)
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 26 #include <pthread.h> 27 #include <sys/socket.h> 28 29 #include <fw/types.h> 30 #include <protocol/rswdp.h> 31 #include "debugger.h" 32 #include "rswdp.h" 33 34 #define DHCSR_C_DEBUGEN (1 << 0) 35 #define DHCSR_C_HALT (1 << 1) 36 #define DHCSR_C_STEP (1 << 2) 37 #define DHCSR_C_MASKINTS (1 << 3) 38 #define DHCSR_C_SNAPSTALL (1 << 5) 39 #define DHCSR_S_REGRDY (1 << 16) 40 #define DHCSR_S_HALT (1 << 17) 41 #define DHCSR_S_SLEEP (1 << 18) 42 #define DHCSR_S_LOCKUP (1 << 19) 43 #define DHCSR_S_RETIRE_ST (1 << 24) 44 #define DHCSR_S_RESET_ST (1 << 25) 45 46 #define DFSR 0xE000ED30 47 #define DFSR_HALTED (1 << 0) 48 #define DFSR_BKPT (1 << 1) 49 #define DFSR_DWTTRAP (1 << 2) 50 #define DFSR_VCATCH (1 << 3) 51 #define DFSR_EXTERNAL (1 << 4) 52 #define DFSR_MASK 0x1F 53 54 extern int swd_verbose; 55 56 static void m_event(const char *evt) { 57 xprintf(XCORE, "DEBUG EVENT: %s\n", evt); 58 } 59 60 static void monitor(void) { 61 u32 v; 62 if (swdp_clear_error()) return; 63 if (swdp_ahb_read(DFSR, &v) == 0) { 64 if (v & DFSR_MASK) { 65 swdp_ahb_write(DFSR, DFSR_MASK); 66 } 67 if (v & DFSR_HALTED) m_event("HALTED"); 68 if (v & DFSR_BKPT) m_event("BKPT"); 69 if (v & DFSR_DWTTRAP) m_event("DWTTRAP"); 70 if (v & DFSR_VCATCH) m_event("VCATCH"); 71 if (v & DFSR_EXTERNAL) m_event("EXTERNAL"); 72 } 73 } 74 75 static pthread_mutex_t _dbg_lock = PTHREAD_MUTEX_INITIALIZER; 76 static pthread_t _dbg_thread; 77 78 void debugger_lock() { 79 pthread_mutex_lock(&_dbg_lock); 80 if (swdp_clear_error()) { 81 #if 0 82 // way too noisy if the link goes down 83 xprintf("SWD ERROR persists. Attempting link reset.\n"); 84 #endif 85 swdp_reset(); 86 } 87 swd_verbose = 1; 88 } 89 90 void debugger_unlock() { 91 #if 0 92 if (swdp_error()) { 93 xprintf(XCORE, "SWD ERROR\n"); 94 } 95 #endif 96 swd_verbose = 0; 97 pthread_mutex_unlock(&_dbg_lock); 98 } 99 100 void *debugger_monitor(void *arg) { 101 for (;;) { 102 pthread_mutex_lock(&_dbg_lock); 103 monitor(); 104 pthread_mutex_unlock(&_dbg_lock); 105 usleep(250000); 106 } 107 } 108 109 void gdb_server(int fd); 110 int socket_listen_tcp(unsigned port); 111 112 static pthread_t _listen_master; 113 void *gdb_listener(void *arg) { 114 int fd; 115 if ((fd = socket_listen_tcp(5555)) < 0) { 116 xprintf(XGDB, "gdb_listener() cannot bind to 5555\n"); 117 return NULL; 118 } 119 for (;;) { 120 int s = accept(fd, NULL, NULL); 121 if (s >= 0) { 122 gdb_server(s); 123 close(s); 124 } 125 } 126 return NULL; 127 } 128 129 void debugger_init() { 130 pthread_create(&_dbg_thread, NULL, debugger_monitor, NULL); 131 pthread_create(&_listen_master, NULL, gdb_listener, NULL); 132 } 133 134 135 static struct varinfo *all_variables = 0; 136 static struct funcinfo *allfuncs = 0; 137 138 static int frame_argc = 0; 139 static param *frame_argv = 0; 140 141 static void variable_set(const char *name, u32 value) { 142 struct varinfo *vi; 143 int len; 144 for (vi = all_variables; vi; vi = vi->next) { 145 if (!strcmp(name, vi->name)) { 146 vi->value = value; 147 return; 148 } 149 } 150 len = strlen(name) + 1; 151 vi = malloc(sizeof(*vi) + len); 152 memcpy(vi->name, name, len); 153 vi->value = value; 154 vi->next = all_variables; 155 all_variables = vi; 156 } 157 158 static int variable_get(const char *name, u32 *value) { 159 struct varinfo *vi; 160 for (vi = all_variables; vi; vi = vi->next) { 161 if (!strcmp(name, vi->name)) { 162 *value = vi->value; 163 return 0; 164 } 165 } 166 return -1; 167 } 168 169 int debugger_variable(const char *name, u32 *value) { 170 return variable_get(name, value); 171 } 172 173 static int do_script(int argc, param *argv) { 174 FILE *fp; 175 char *line,linebuf[256]; 176 struct funcinfo *newfunc = 0; 177 struct funcline *lastline = 0; 178 const char *fname = argv[0].s; 179 180 if (argc != 1) 181 return -1; 182 183 if (!strcmp(fname, "-")) { 184 fp = stdin; 185 } else { 186 if (!(fp = fopen(argv[0].s, "r"))) { 187 xprintf(XCORE, "error: cannot open '%s'\n", argv[0].s); 188 return -1; 189 } 190 } 191 192 while (fgets(linebuf, sizeof(linebuf), fp)) { 193 line = linebuf; 194 while (isspace(*line)) 195 line++; 196 if (iscntrl(line[0]) || line[0] == '#') 197 continue; 198 if (!strncmp(line, "function", 8) && isspace(line[8])) { 199 char *name, *x; 200 name = line + 9; 201 if (newfunc) { 202 xprintf(XCORE, "error: nested functions not allowed\n"); 203 break; 204 } 205 while (isspace(*name)) 206 name++; 207 x = name; 208 while (!isspace(*x) && *x) 209 x++; 210 *x = 0; 211 if (*name == 0) { 212 xprintf(XCORE, "error: functions must have names\n"); 213 break; 214 } 215 newfunc = malloc(sizeof(*newfunc) + strlen(name) + 1); 216 if (newfunc == 0) { 217 xprintf(XCORE, "error: out of memory\n"); 218 break; 219 } 220 strcpy(newfunc->name, name); 221 newfunc->next = 0; 222 newfunc->lines = 0; 223 continue; 224 } 225 if (newfunc) { 226 struct funcline *fl; 227 if (!strncmp(line, "end", 3) && isspace(line[3])) { 228 newfunc->next = allfuncs; 229 allfuncs = newfunc; 230 newfunc = 0; 231 lastline = 0; 232 continue; 233 } 234 fl = malloc(sizeof(*fl) + strlen(line) + 1); 235 if (fl == 0) { 236 xprintf(XCORE, "out of memory"); 237 newfunc = 0; 238 if (fp != stdin) 239 fclose(fp); 240 return -1; 241 } 242 strcpy(fl->text, line); 243 fl->next = 0; 244 if (lastline) { 245 lastline->next = fl; 246 } else { 247 newfunc->lines = fl; 248 } 249 lastline = fl; 250 } else { 251 xprintf(XCORE, "script> %s", line); 252 if (debugger_command(line)) 253 return -1; 254 } 255 } 256 if (fp != stdin) 257 fclose(fp); 258 259 if (newfunc) 260 newfunc = 0; 261 return 0; 262 } 263 264 static int do_set(int argc, param *argv) { 265 const char *name; 266 if ((argc != 2) && (argc != 4)) { 267 xprintf(XCORE, "error: set requires two or four arguments\n"); 268 return -1; 269 } 270 name = argv[0].s; 271 if (*name == '$') 272 name++; 273 if (*name == 0) { 274 xprintf(XCORE, "error: empty name?!\n"); 275 return -1; 276 } 277 if (!isalpha(*name)) { 278 xprintf(XCORE, "error: variable name must begin with a letter\n"); 279 return -1; 280 } 281 282 if (argc == 4) { 283 u32 a, b, n; 284 const char *op; 285 a = argv[1].n; 286 op = argv[2].s; 287 b = argv[3].n; 288 if (!strcmp(op,"+")) { 289 n = a + b; 290 } else if (!strcmp(op, "-")) { 291 n = a - b; 292 } else if (!strcmp(op, "<<")) { 293 n = a << b; 294 } else if (!strcmp(op, ">>")) { 295 n = a >> b; 296 } else if (!strcmp(op, "*")) { 297 n = a * b; 298 } else if (!strcmp(op, "/")) { 299 if (b == 0) { 300 n = 0; 301 } else { 302 n = a / b; 303 } 304 } else { 305 xprintf(XCORE, "error: set <var> <a> <op> <b> requires op: + - * / << >>\n"); 306 return -1; 307 } 308 variable_set(name, n); 309 } else { 310 variable_set(name, argv[1].n); 311 } 312 return 0; 313 } 314 315 static int parse_number(const char *in, unsigned *out) { 316 u32 value; 317 char text[64]; 318 char *obrack; 319 int r; 320 321 strncpy(text, in, sizeof(text)); 322 text[sizeof(text)-1] = 0; 323 324 /* handle dereference forms */ 325 obrack = strchr(text, '['); 326 if (obrack) { 327 unsigned base, index; 328 char *cbrack; 329 *obrack++ = 0; 330 cbrack = strchr(obrack, ']'); 331 if (!cbrack) 332 return -1; 333 *cbrack = 0; 334 if (parse_number(text, &base)) 335 return -1; 336 if (parse_number(obrack, &index)) 337 return -1; 338 if (read_memory_word(base + index, &value)) 339 return -1; 340 *out = value; 341 return 0; 342 } 343 344 /* handle local $[0..9] and global $... variables */ 345 if (text[0] == '$') { 346 if (isdigit(text[1]) && (text[2] == 0)) { 347 r = atoi(text + 1); 348 if (r > 0) { 349 if (r <= frame_argc) { 350 *out = frame_argv[r - 1].n; 351 return 0; 352 } 353 } 354 xprintf(XCORE, "no local variable %s\n", text); 355 *out = 0; 356 return 0; 357 } 358 if (variable_get(text + 1, &value) == 0) { 359 *out = value; 360 } else { 361 xprintf(XCORE, "undefined variable '%s'\n", text + 1); 362 *out = 0; 363 } 364 return 0; 365 } 366 367 /* handle registers */ 368 r = read_register(text, &value); 369 if (r != ERROR_UNKNOWN) { 370 *out = value; 371 return r; 372 } 373 374 /* otherwise decimal or hex constants */ 375 if (text[0] == '.') { 376 *out = strtoul(text + 1, 0, 10); 377 } else { 378 *out = strtoul(text, 0, 16); 379 } 380 return 0; 381 } 382 383 static int exec_function(struct funcinfo *f, int argc, param *argv) { 384 param *saved_argv; 385 int saved_argc; 386 struct funcline *line; 387 char text[256]; 388 int r, n; 389 390 saved_argv = frame_argv; 391 saved_argc = frame_argc; 392 frame_argv = argv; 393 frame_argc = argc; 394 395 for (line = f->lines, n = 1; line; line = line->next, n++) { 396 strcpy(text, line->text); 397 r = debugger_command(text); 398 if (r) { 399 xprintf(XCORE, "error: %s: line %d\n", f->name, n); 400 goto done; 401 } 402 } 403 r = 0; 404 done: 405 frame_argc = saved_argc; 406 frame_argv = saved_argv; 407 return r; 408 } 409 410 static int _debugger_exec(const char *cmd, unsigned argc, param *argv) { 411 struct funcinfo *f; 412 struct debugger_command *c; 413 414 /* core built-ins */ 415 if (!strcasecmp(cmd, "set")) 416 return do_set(argc, argv); 417 if (!strcasecmp(cmd, "script")) 418 return do_script(argc, argv); 419 420 for (c = debugger_commands; c->name; c++) { 421 if (!strcasecmp(cmd, c->name)) { 422 int n; 423 debugger_lock(); 424 n = c->func(argc, argv); 425 debugger_unlock(); 426 return n; 427 } 428 } 429 for (f = allfuncs; f; f = f->next) { 430 if (!strcasecmp(cmd, f->name)) { 431 return exec_function(f, argc, argv); 432 } 433 } 434 return ERROR_UNKNOWN; 435 } 436 437 int debugger_invoke(const char *cmd, unsigned argc, ...) { 438 param arg[32]; 439 unsigned n; 440 va_list ap; 441 442 if (argc > 31) 443 return -1; 444 445 va_start(ap, argc); 446 for (n = 0; n < argc; n++) { 447 arg[n].s = ""; 448 arg[n].n = va_arg(ap, unsigned); 449 } 450 return _debugger_exec(cmd, argc, arg); 451 } 452 453 int debugger_command(char *line) { 454 param arg[32]; 455 unsigned c, n = 0; 456 int r; 457 458 while (*line && (*line == ' ')) line++; 459 460 if (*line == '/') { 461 arg[0].s = line + 1; 462 return _debugger_exec("wconsole", 1, arg); 463 } 464 465 while ((c = *line)) { 466 if (c <= ' ') { 467 line++; 468 continue; 469 } 470 arg[n].s = line; 471 for (;;) { 472 if (c == 0) { 473 n++; 474 break; 475 } else if (c == '#') { 476 *line = 0; 477 break; 478 } else if (c <= ' ') { 479 *line++ = 0; 480 n++; 481 break; 482 } 483 c = *++line; 484 } 485 } 486 487 if (n == 0) 488 return 0; 489 490 for (c = 0; c < n; c++) { 491 if (parse_number(arg[c].s, &(arg[c].n))) { 492 xprintf(XCORE, "error: bad number: %s\n", arg[c].s); 493 return -1; 494 } 495 } 496 497 r = _debugger_exec(arg[0].s, n - 1, arg + 1); 498 if (r == ERROR_UNKNOWN) { 499 xprintf(XCORE, "unknown command: %s\n", arg[0].s); 500 } 501 return r; 502 } 503