|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/bsp/drv/dev/base/kd.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
1 /*- 2 * Copyright (c) 2008-2009, Kohsuke Ohtani 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * kd.c - kernel debugger. 32 */ 33 34 #include <driver.h> 35 #include <sys/sysinfo.h> 36 #include <sys/power.h> 37 #include <sys/dbgctl.h> 38 #include <sys/endian.h> 39 40 #include <devctl.h> 41 #include <cons.h> 42 #include <pm.h> 43 44 #define ARGMAX 32 45 46 static void kd_abort(void); 47 48 static int kd_null(int, char **); 49 static int kd_help(int, char **); 50 static int kd_continue(int, char **); 51 static int kd_reboot(int, char **); 52 static int kd_mstat(int, char **); 53 static int kd_thread(int, char **); 54 static int kd_task(int, char **); 55 static int kd_vm(int, char **); 56 static int kd_device(int, char **); 57 static int kd_driver(int, char **); 58 static int kd_irq(int, char **); 59 static int kd_trap(int, char **); 60 static int kd_devstat(int, char **); 61 static int kd_trace(int, char **); 62 static int kd_examine(int, char **); 63 static int kd_write(int, char **); 64 65 struct cmd_entry { 66 const char *cmd; 67 int (*func)(int, char **); 68 const char *usage; 69 }; 70 71 static const struct cmd_entry cmd_table[] = { 72 { "help" ,kd_help ,"This help" }, 73 { "continue" ,kd_continue ,"Continue execution [c]" }, 74 { "reboot" ,kd_reboot ,"Reboot system" }, 75 { "mstat" ,kd_mstat ,"Display memory usage" }, 76 { "thread" ,kd_thread ,"Display thread information" }, 77 { "task" ,kd_task ,"Display task information" }, 78 { "vm" ,kd_vm ,"Dump all VM segments" }, 79 { "device" ,kd_device ,"Display list of devices" }, 80 { "driver" ,kd_driver ,"Display list of drivers" }, 81 { "irq" ,kd_irq ,"Display interrupt information" }, 82 { "trap" ,kd_trap ,"Dump current trap frame" }, 83 { "devstat" ,kd_devstat ,"Dump all device state" }, 84 { "trace" ,kd_trace ,"Set trace flag for task" }, 85 { "examine" ,kd_examine ,"Examine data (x [/fmt] [addr])" }, 86 { "write" ,kd_write ,"Write data (w [/size] addr val)" }, 87 /* command alias section */ 88 { "?" ,kd_help ,NULL }, 89 { "x" ,kd_examine ,NULL }, 90 { "w" ,kd_write ,NULL }, 91 { "c" ,kd_continue ,NULL }, 92 { NULL ,kd_null ,NULL }, 93 }; 94 95 /* 96 * Errors 97 */ 98 #define KERR_SYNTAX 1 99 #define KERR_TOOMANY 2 100 #define KERR_INVAL 3 101 #define KERR_BADADDR 4 102 #define KERR_NOFUNC 5 103 #define KERR_NOMEM 6 104 105 static const char *kd_errname[] = { 106 "", 107 "Syntax error", 108 "Too many arguments", 109 "Invalid argument", 110 "No physical memory", 111 "Function not supported", 112 "Out of memory", 113 }; 114 115 #define KERR_MAX (int)(sizeof(kd_errname) / sizeof(char *)) 116 117 118 static dpc_t kd_dpc; /* dpc for debugger */ 119 120 static struct abort_ops kd_abort_ops = { 121 /* abort */ kd_abort, 122 }; 123 124 static int 125 kd_null(int argc, char **argv) 126 { 127 return 0; 128 } 129 130 static void 131 kd_error(int id) 132 { 133 134 if (id < KERR_MAX) 135 printf("%s\n", kd_errname[id]); 136 } 137 138 /* 139 * Get taks id from its name. 140 */ 141 static task_t 142 kd_lookup_task(char *name) 143 { 144 struct taskinfo ti; 145 task_t task = TASK_NULL; 146 int rc; 147 148 rc = 0; 149 ti.cookie = 0; 150 do { 151 rc = sysinfo(INFO_TASK, &ti); 152 if (!rc && !strncmp(ti.taskname, name, MAXTASKNAME)) { 153 task = ti.id; 154 } 155 } while (rc == 0); 156 return task; 157 } 158 159 160 static int 161 kd_help(int argc, char **argv) 162 { 163 int i = 0; 164 165 while (cmd_table[i].cmd != NULL) { 166 if (cmd_table[i].usage) 167 printf(" %10s -- %s.\n", cmd_table[i].cmd, 168 cmd_table[i].usage); 169 i++; 170 } 171 printf("\nuse `-?` to find out more about each command.\n"); 172 return 0; 173 } 174 175 static int 176 kd_continue(int argc, char **argv) 177 { 178 179 return -1; 180 } 181 182 static int 183 kd_reboot(int argc, char **argv) 184 { 185 186 #ifdef CONFIG_PM 187 pm_set_power(PWR_REBOOT); 188 #else 189 machine_powerdown(PWR_REBOOT); 190 #endif 191 return 0; 192 } 193 194 static int 195 kd_mstat(int argc, char **argv) 196 { 197 struct meminfo info; 198 199 /* Get memory information from kernel. */ 200 sysinfo(INFO_MEMORY, &info); 201 202 printf("Memory usage:\n"); 203 printf(" Used :%8ld KB\n", (info.total - info.free) / 1024); 204 printf(" Free :%8ld KB\n", info.free / 1024); 205 printf(" Total :%8ld KB\n", info.total / 1024); 206 printf(" Bootdisk :%8ld KB\n", info.bootdisk / 1024); 207 return 0; 208 } 209 210 static int 211 kd_thread(int argc, char **argv) 212 { 213 const char state[][4] = \ 214 { "RUN", "SLP", "SUS", "S&S", "EXT" }; 215 const char pol[][5] = { "FIFO", "RR " }; 216 struct threadinfo ti; 217 int rc; 218 219 printf("Thread list:\n"); 220 printf(" thread task stat pol pri base time " 221 "suscnt sleep event\n"); 222 printf(" -------- ------------ ---- ---- --- ---- -------- " 223 "------ ------------\n"); 224 225 rc = 0; 226 ti.cookie = 0; 227 do { 228 /* Get thread information from kernel. */ 229 rc = sysinfo(INFO_THREAD, &ti); 230 if (!rc) { 231 printf(" %08lx %12s %s%c %s %3d %3d %8d %6d %s\n", 232 ti.id, ti.taskname, state[ti.state], 233 ti.active ? '*' : ' ', 234 pol[ti.policy], ti.priority, ti.basepri, 235 ti.time, ti.suscnt, ti.slpevt); 236 } 237 } while (rc == 0); 238 239 return 0; 240 } 241 242 static int 243 kd_task(int argc, char **argv) 244 { 245 struct taskinfo ti; 246 int rc; 247 248 printf("Task list:\n"); 249 printf(" task name nthreads flags suscnt capability vmsize\n"); 250 printf(" --------- -------- -------- -------- ------ ---------- --------\n"); 251 252 rc = 0; 253 ti.cookie = 0; 254 do { 255 /* Get task information from kernel. */ 256 rc = sysinfo(INFO_TASK, &ti); 257 if (!rc) { 258 printf(" %08lx%c %8s %8d %08x %6d %08x %8d\n", 259 ti.id, ti.active ? '*' : ' ', ti.taskname, 260 ti.nthreads, ti.flags, ti.suscnt, 261 ti.capability, ti.vmsize); 262 } 263 } while (rc == 0); 264 265 return 0; 266 } 267 268 static void 269 kd_vm_region(task_t task) 270 { 271 struct vminfo vi; 272 char flags[6]; 273 int rc; 274 275 printf(" virtual physical size flags\n"); 276 printf(" -------- -------- -------- -----\n"); 277 278 rc = 0; 279 vi.cookie = 0; 280 do { 281 /* Get task information from kernel. */ 282 vi.task = task; 283 rc = sysinfo(INFO_VM, &vi); 284 if (!rc) { 285 if (vi.flags != VF_FREE) { 286 strlcpy(flags, "-----", sizeof(flags)); 287 if (vi.flags & VF_READ) 288 flags[0] = 'R'; 289 if (vi.flags & VF_WRITE) 290 flags[1] = 'W'; 291 if (vi.flags & VF_EXEC) 292 flags[2] = 'E'; 293 if (vi.flags & VF_SHARED) 294 flags[3] = 'S'; 295 if (vi.flags & VF_MAPPED) 296 flags[4] = 'M'; 297 printf(" %08lx %08lx %8x %s\n", 298 (long)vi.virt, (long)vi.phys, 299 vi.size, flags); 300 } 301 } 302 } while (rc == 0); 303 } 304 305 static int 306 kd_vm(int argc, char **argv) 307 { 308 struct taskinfo ti; 309 int rc; 310 311 printf("VM information:\n"); 312 313 rc = 0; 314 ti.cookie = 0; 315 do { 316 /* Get task information from kernel. */ 317 rc = sysinfo(INFO_TASK, &ti); 318 if (!rc) { 319 if (ti.vmsize != 0) { 320 printf("\ntask=%08lx name=%s total=%dK bytes\n", 321 ti.id, ti.taskname, ti.vmsize / 1024); 322 kd_vm_region(ti.id); 323 } 324 } 325 } while (rc == 0); 326 327 return 0; 328 } 329 330 static int 331 kd_device(int argc, char **argv) 332 { 333 struct devinfo di; 334 char flags[6]; 335 int rc; 336 337 printf("Device list:\n"); 338 printf(" device name flags\n"); 339 printf(" -------- ------------ -----\n"); 340 341 rc = 0; 342 di.cookie = 0; 343 do { 344 /* Get device information from kernel. */ 345 rc = sysinfo(INFO_DEVICE, &di); 346 if (!rc) { 347 strlcpy(flags, "-----", sizeof(flags)); 348 if (di.flags & D_CHR) 349 flags[0] = 'C'; 350 if (di.flags & D_BLK) 351 flags[1] = 'B'; 352 if (di.flags & D_REM) 353 flags[2] = 'R'; 354 if (di.flags & D_PROT) 355 flags[3] = 'P'; 356 if (di.flags & D_TTY) 357 flags[4] = 'T'; 358 359 printf(" %08lx %12s %s\n", di.id, di.name, flags); 360 } 361 } while (rc == 0); 362 363 return 0; 364 } 365 366 static int 367 kd_driver(int argc, char **argv) 368 { 369 370 driver_dump(); 371 return 0; 372 } 373 374 static int 375 kd_irq(int argc, char **argv) 376 { 377 struct irqinfo ii; 378 int rc; 379 380 printf("Interrupt table:\n"); 381 printf(" vector count pending IST pri thread\n"); 382 printf(" ------ -------- ----------- --- --------\n"); 383 384 rc = 0; 385 ii.cookie = 0; 386 do { 387 rc = sysinfo(INFO_IRQ, &ii); 388 if (!rc) { 389 printf(" %4d %8d %8d %3d %08lx\n", 390 ii.vector, ii.count, ii.istreq, 391 ii.priority, (long)ii.thread); 392 } 393 } while (rc == 0); 394 395 return 0; 396 } 397 398 static int 399 kd_trap(int argc, char **argv) 400 { 401 402 printf("Trap frame:\n"); 403 404 dbgctl(DBGC_DUMPTRAP, NULL); 405 return 0; 406 } 407 408 static int 409 kd_devstat(int argc, char **argv) 410 { 411 412 printf("Device state:\n"); 413 414 device_broadcast(DEVCTL_DBG_DEVSTAT, NULL, 1); 415 return 0; 416 } 417 418 static int 419 kd_trace(int argc, char **argv) 420 { 421 task_t task; 422 423 if (argc != 2 || !strncmp(argv[1], "-?", 2)) { 424 printf("usage: trace taskname\n"); 425 return 0; 426 } 427 428 task = kd_lookup_task(argv[1]); 429 if (task == TASK_NULL) 430 return KERR_INVAL; 431 432 printf("Toggle trace flag: %s (%08lx)\n", argv[1], (long)task); 433 dbgctl(DBGC_TRACE, (void *)task); 434 435 return 0; 436 } 437 438 static int 439 kd_examine(int argc, char **argv) 440 { 441 char *p; 442 u_char *kp; 443 static u_long len = 16; 444 static u_long cnt; 445 static vaddr_t addr; 446 static int size = 4; 447 static char fmt = '*'; 448 449 p = argv[1]; 450 switch (argc) { 451 case 1: 452 /* Use previous address and format */ 453 p = NULL; 454 break; 455 case 2: 456 p = argv[1]; 457 len = 16; 458 break; 459 case 3: 460 if (*p != '/') 461 return KERR_INVAL; 462 p++; 463 switch (*p) { 464 case 'c': 465 case 'b': 466 case 'h': 467 case 'w': 468 fmt = *p; 469 p++; 470 break; 471 } 472 len = strtoul(p, NULL, 16); 473 if (len == ULONG_MAX) 474 return KERR_INVAL; 475 p = argv[2]; 476 break; 477 default: 478 return KERR_SYNTAX; 479 } 480 if (p != NULL) { 481 addr = strtoul(p, NULL, 16); 482 if (addr == ULONG_MAX) 483 return KERR_INVAL; 484 } 485 486 if ((kp = kmem_map((void *)addr, (size_t)len)) == NULL) 487 return KERR_BADADDR; 488 489 for (cnt = 0; cnt < len;) { 490 if ((cnt % 16) == 0) 491 printf("\n%08lx: ", (long)addr); 492 493 switch (fmt) { 494 case 'c': 495 printf("%c", *kp); 496 size = 1; 497 break; 498 case 'b': 499 printf("%02x ", *kp); 500 size = 1; 501 break; 502 case 'h': 503 printf("%04x ", *(u_short *)kp); 504 size = 2; 505 break; 506 case 'w': 507 default: 508 printf("%08lx ", *(u_long *)kp); 509 size = 4; 510 break; 511 } 512 addr += size; 513 kp += size; 514 cnt += size; 515 } 516 return 0; 517 } 518 519 static int 520 kd_write(int argc, char **argv) 521 { 522 vaddr_t addr; 523 int size = 4; 524 u_char *kp; 525 char *p, *pa, *pv; 526 u_long val; 527 int i; 528 529 if (argc < 3) 530 return KERR_INVAL; 531 532 pa = argv[1]; 533 pv = argv[2]; 534 535 if (argc == 4) { 536 p = argv[1]; 537 if (*p != '/') 538 return KERR_INVAL; 539 p++; 540 switch (*p) { 541 case 'b': 542 size = 1; 543 break; 544 case 'h': 545 size = 2; 546 break; 547 case 'w': 548 size = 4; 549 break; 550 default: 551 return KERR_INVAL; 552 } 553 pa = argv[2]; 554 pv = argv[3]; 555 } 556 addr = strtoul(pa, NULL, 16); 557 if (addr == ULONG_MAX) 558 return KERR_INVAL; 559 560 val = strtoul(pv, NULL, 16); 561 if (val == ULONG_MAX) 562 return KERR_INVAL; 563 564 if ((kp = kmem_map((void *)addr, (size_t)size)) == NULL) 565 return KERR_BADADDR; 566 567 #if BYTE_ORDER == LITTLE_ENDIAN 568 for (i = 0; i < size; i++) { 569 #else /* BYTE_ORDER == BIG_ENDIAN */ 570 for (i = size; i-- > 0;) { 571 #endif /* BYTE_ORDER */ 572 /* FIXME: need to check alignment... */ 573 *(char *)((char *)addr + i) = (char)(val & 0xff); 574 val >>= 8; 575 } 576 577 return 0; 578 } 579 580 static int 581 kd_dispatch(int argc, char **argv) 582 { 583 int i = 0; 584 int error = 0; 585 586 while (cmd_table[i].cmd != NULL) { 587 if (!strncmp(argv[0], cmd_table[i].cmd, LINE_MAX)) { 588 error = (cmd_table[i].func)(argc, argv); 589 break; 590 } 591 i++; 592 } 593 if (cmd_table[i].cmd == NULL) 594 error = KERR_SYNTAX; 595 596 if (error > 0 && error <= KERR_MAX) 597 kd_error(error); 598 599 if (error == -1) 600 return -1; 601 return 0; 602 } 603 604 static int 605 kd_parse_line(char *line) 606 { 607 static char *args[ARGMAX]; 608 char *p, *word = NULL; 609 int argc = 0; 610 int rc = 0; 611 612 if (line[0] != ' ' && line[0] != '\t') 613 word = line; 614 615 p = line; 616 while (*p) { 617 if (word == NULL) { 618 /* Skip white space. */ 619 if (*p != ' ' && *p != '\t') 620 word = p; 621 } else { 622 if (*p == ' ' || *p == '\t') { 623 *p = '\0'; 624 args[argc++] = word; 625 word = NULL; 626 if (argc >= ARGMAX - 1) { 627 kd_error(KERR_TOOMANY); 628 return 0; 629 } 630 } 631 } 632 p++; 633 } 634 if (word) 635 args[argc++] = word; 636 args[argc] = NULL; 637 638 if (argc) { 639 if (kd_dispatch(argc, args)) 640 rc = 1; 641 } 642 return rc; 643 } 644 645 static void 646 kd_read_line(char *line) 647 { 648 int c, pos = 0; 649 char *p = line; 650 651 for (;;) { 652 c = cons_getc(); 653 654 switch(c) { 655 case '\n': 656 case '\r': 657 *p = '\0'; 658 printf("\n"); 659 return; 660 case '\b': 661 case 127: 662 if (pos > 0) { 663 *p = '\0'; 664 p--; 665 pos--; 666 printf("\b"); 667 printf(" "); 668 printf("\b"); 669 } 670 break; 671 default: 672 *p = (char)c; 673 p++; 674 pos++; 675 if (pos > LINE_MAX) { 676 *p = '\0'; 677 return; 678 } 679 printf("%c", c); 680 break; 681 } 682 } 683 } 684 685 void 686 kd_invoke(void *arg) 687 { 688 static char line[LINE_MAX]; 689 int s; 690 691 printf("\n-------------------------------\n"); 692 printf(" Entering debugger.\n"); 693 printf(" Type 'help' to list commands.\n"); 694 printf("-------------------------------\n"); 695 696 s = spl0(); 697 698 /* Set input device to polling mode. */ 699 cons_pollc(1); 700 701 for (;;) { 702 printf("\n[kd] "); 703 kd_read_line(line); 704 if (kd_parse_line(line)) 705 break; 706 } 707 cons_pollc(0); 708 splx(s); 709 } 710 711 /* 712 * User can enter kd by pressing ctrl+k key at any time. 713 */ 714 void 715 kd_enter(void) 716 { 717 718 /* Call back in DPC level */ 719 sched_dpc(&kd_dpc, &kd_invoke, NULL); 720 } 721 722 /* 723 * Callback handler for abort. 724 */ 725 void 726 kd_abort(void) 727 { 728 729 kd_invoke(NULL); 730 } 731 732 void 733 kd_init(void) 734 { 735 736 /* 737 * Install abort handler to catch assert & panic events. 738 */ 739 dbgctl(DBGC_SETABORT, &kd_abort_ops); 740 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |