Project

General

Profile

Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / bsp / drv / dev / base / kd.c @ 03e9c04a

History | View | Annotate | Download (13.9 KB)

1 03e9c04a Brad Neuman
/*-
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
}