Prex Home / Browse Source - Prex Version: 0.9.0

root/bsp/drv/dev/base/kd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. kd_null
  2. kd_error
  3. kd_lookup_task
  4. kd_help
  5. kd_continue
  6. kd_reboot
  7. kd_mstat
  8. kd_thread
  9. kd_task
  10. kd_vm_region
  11. kd_vm
  12. kd_device
  13. kd_driver
  14. kd_irq
  15. kd_trap
  16. kd_devstat
  17. kd_trace
  18. kd_examine
  19. kd_write
  20. kd_dispatch
  21. kd_parse_line
  22. kd_read_line
  23. kd_invoke
  24. kd_enter
  25. kd_abort
  26. kd_init

   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] */