~galfy/helenos/bird-port-mainline

« back to all changes in this revision

Viewing changes to kernel/arch/mips32/src/debugger.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2005 Ondrej Palkovsky
 
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
 *
 
9
 * - Redistributions of source code must retain the above copyright
 
10
 *   notice, this list of conditions and the following disclaimer.
 
11
 * - Redistributions in binary form must reproduce the above copyright
 
12
 *   notice, this list of conditions and the following disclaimer in the
 
13
 *   documentation and/or other materials provided with the distribution.
 
14
 * - The name of the author may not be used to endorse or promote products
 
15
 *   derived from this software without specific prior written permission.
 
16
 *
 
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
27
 */
 
28
 
 
29
/** @addtogroup mips32debug
 
30
 * @{
 
31
 */
 
32
/** @file
 
33
 */
 
34
 
 
35
#include <arch/debugger.h>
 
36
#include <arch/barrier.h>
 
37
#include <memstr.h>
 
38
#include <console/kconsole.h>
 
39
#include <console/cmd.h>
 
40
#include <print.h>
 
41
#include <panic.h>
 
42
#include <arch.h>
 
43
#include <arch/cp0.h>
 
44
#include <func.h>
 
45
#include <symtab.h>
 
46
 
 
47
bpinfo_t breakpoints[BKPOINTS_MAX];
 
48
SPINLOCK_INITIALIZE(bkpoint_lock);
 
49
 
 
50
#ifdef CONFIG_KCONSOLE
 
51
 
 
52
static int cmd_print_breakpoints(cmd_arg_t *argv);
 
53
static cmd_info_t bkpts_info = {
 
54
        .name = "bkpts",
 
55
        .description = "Print breakpoint table.",
 
56
        .func = cmd_print_breakpoints,
 
57
        .argc = 0,
 
58
};
 
59
 
 
60
static int cmd_del_breakpoint(cmd_arg_t *argv);
 
61
static cmd_arg_t del_argv = {
 
62
        .type = ARG_TYPE_INT
 
63
};
 
64
static cmd_info_t delbkpt_info = {
 
65
        .name = "delbkpt",
 
66
        .description = "delbkpt <number> - Delete breakpoint.",
 
67
        .func = cmd_del_breakpoint,
 
68
        .argc = 1,
 
69
        .argv = &del_argv
 
70
};
 
71
 
 
72
static int cmd_add_breakpoint(cmd_arg_t *argv);
 
73
static cmd_arg_t add_argv = {
 
74
        .type = ARG_TYPE_INT
 
75
};
 
76
static cmd_info_t addbkpt_info = {
 
77
        .name = "addbkpt",
 
78
        .description = "addbkpt <&symbol> - new bkpoint. Break on J/Branch "
 
79
            "insts unsupported.",
 
80
        .func = cmd_add_breakpoint,
 
81
        .argc = 1,
 
82
        .argv = &add_argv
 
83
};
 
84
 
 
85
static cmd_arg_t adde_argv[] = {
 
86
        { .type = ARG_TYPE_INT },
 
87
        { .type = ARG_TYPE_INT }
 
88
};
 
89
static cmd_info_t addbkpte_info = {
 
90
        .name = "addbkpte",
 
91
        .description = "addebkpte <&symbol> <&func> - new bkpoint. Call "
 
92
            "func(or Nothing if 0).",
 
93
        .func = cmd_add_breakpoint,
 
94
        .argc = 2,
 
95
        .argv = adde_argv
 
96
};
 
97
 
 
98
static struct {
 
99
        uint32_t andmask;
 
100
        uint32_t value;
 
101
} jmpinstr[] = {
 
102
        {0xf3ff0000, 0x41000000}, /* BCzF */
 
103
        {0xf3ff0000, 0x41020000}, /* BCzFL */
 
104
        {0xf3ff0000, 0x41010000}, /* BCzT */
 
105
        {0xf3ff0000, 0x41030000}, /* BCzTL */
 
106
        {0xfc000000, 0x10000000}, /* BEQ */
 
107
        {0xfc000000, 0x50000000}, /* BEQL */
 
108
        {0xfc1f0000, 0x04010000}, /* BEQL */
 
109
        {0xfc1f0000, 0x04110000}, /* BGEZAL */
 
110
        {0xfc1f0000, 0x04130000}, /* BGEZALL */
 
111
        {0xfc1f0000, 0x04030000}, /* BGEZL */
 
112
        {0xfc1f0000, 0x1c000000}, /* BGTZ */
 
113
        {0xfc1f0000, 0x5c000000}, /* BGTZL */
 
114
        {0xfc1f0000, 0x18000000}, /* BLEZ */
 
115
        {0xfc1f0000, 0x58000000}, /* BLEZL */
 
116
        {0xfc1f0000, 0x04000000}, /* BLTZ */
 
117
        {0xfc1f0000, 0x04100000}, /* BLTZAL */
 
118
        {0xfc1f0000, 0x04120000}, /* BLTZALL */
 
119
        {0xfc1f0000, 0x04020000}, /* BLTZL */
 
120
        {0xfc000000, 0x14000000}, /* BNE */
 
121
        {0xfc000000, 0x54000000}, /* BNEL */
 
122
        {0xfc000000, 0x08000000}, /* J */
 
123
        {0xfc000000, 0x0c000000}, /* JAL */
 
124
        {0xfc1f07ff, 0x00000009}, /* JALR */
 
125
        {0, 0} /* EndOfTable */
 
126
};
 
127
 
 
128
 
 
129
/** Test, if the given instruction is a jump or branch instruction
 
130
 *
 
131
 * @param instr Instruction code
 
132
 * @return true - it is jump instruction, false otherwise
 
133
 *
 
134
 */
 
135
static bool is_jump(unative_t instr)
 
136
{
 
137
        int i;
 
138
 
 
139
        for (i = 0; jmpinstr[i].andmask; i++) {
 
140
                if ((instr & jmpinstr[i].andmask) == jmpinstr[i].value)
 
141
                        return true;
 
142
        }
 
143
 
 
144
        return false;
 
145
}
 
146
 
 
147
/** Add new breakpoint to table */
 
148
int cmd_add_breakpoint(cmd_arg_t *argv)
 
149
{
 
150
        bpinfo_t *cur = NULL;
 
151
        ipl_t ipl;
 
152
        int i;
 
153
 
 
154
        if (argv->intval & 0x3) {
 
155
                printf("Not aligned instruction, forgot to use &symbol?\n");
 
156
                return 1;
 
157
        }
 
158
        ipl = interrupts_disable();
 
159
        spinlock_lock(&bkpoint_lock);
 
160
 
 
161
        /* Check, that the breakpoints do not conflict */
 
162
        for (i = 0; i < BKPOINTS_MAX; i++) {
 
163
                if (breakpoints[i].address == (uintptr_t)argv->intval) {
 
164
                        printf("Duplicate breakpoint %d.\n", i);
 
165
                        spinlock_unlock(&bkpoint_lock);
 
166
                        return 0;
 
167
                } else if (breakpoints[i].address == (uintptr_t)argv->intval +
 
168
                    sizeof(unative_t) || breakpoints[i].address ==
 
169
                    (uintptr_t)argv->intval - sizeof(unative_t)) {
 
170
                        printf("Adjacent breakpoints not supported, conflict "
 
171
                            "with %d.\n", i);
 
172
                        spinlock_unlock(&bkpoint_lock);
 
173
                        return 0;
 
174
                }
 
175
                
 
176
        }
 
177
 
 
178
        for (i = 0; i < BKPOINTS_MAX; i++)
 
179
                if (!breakpoints[i].address) {
 
180
                        cur = &breakpoints[i];
 
181
                        break;
 
182
                }
 
183
        if (!cur) {
 
184
                printf("Too many breakpoints.\n");
 
185
                spinlock_unlock(&bkpoint_lock);
 
186
                interrupts_restore(ipl);
 
187
                return 0;
 
188
        }
 
189
        cur->address = (uintptr_t) argv->intval;
 
190
        printf("Adding breakpoint on address: %p\n", argv->intval);
 
191
        cur->instruction = ((unative_t *)cur->address)[0];
 
192
        cur->nextinstruction = ((unative_t *)cur->address)[1];
 
193
        if (argv == &add_argv) {
 
194
                cur->flags = 0;
 
195
        } else { /* We are add extended */
 
196
                cur->flags = BKPOINT_FUNCCALL;
 
197
                cur->bkfunc = (void (*)(void *, istate_t *)) argv[1].intval;
 
198
        }
 
199
        if (is_jump(cur->instruction))
 
200
                cur->flags |= BKPOINT_ONESHOT;
 
201
        cur->counter = 0;
 
202
 
 
203
        /* Set breakpoint */
 
204
        *((unative_t *)cur->address) = 0x0d;
 
205
        smc_coherence(cur->address);
 
206
 
 
207
        spinlock_unlock(&bkpoint_lock);
 
208
        interrupts_restore(ipl);
 
209
 
 
210
        return 1;
 
211
}
 
212
 
 
213
/** Remove breakpoint from table */
 
214
int cmd_del_breakpoint(cmd_arg_t *argv)
 
215
{
 
216
        bpinfo_t *cur;
 
217
        ipl_t ipl;
 
218
 
 
219
        if (argv->intval > BKPOINTS_MAX) {
 
220
                printf("Invalid breakpoint number.\n");
 
221
                return 0;
 
222
        }
 
223
        ipl = interrupts_disable();
 
224
        spinlock_lock(&bkpoint_lock);
 
225
 
 
226
        cur = &breakpoints[argv->intval];
 
227
        if (!cur->address) {
 
228
                printf("Breakpoint does not exist.\n");
 
229
                spinlock_unlock(&bkpoint_lock);
 
230
                interrupts_restore(ipl);
 
231
                return 0;
 
232
        }
 
233
        if ((cur->flags & BKPOINT_INPROG) && (cur->flags & BKPOINT_ONESHOT)) {
 
234
                printf("Cannot remove one-shot breakpoint in-progress\n");
 
235
                spinlock_unlock(&bkpoint_lock);
 
236
                interrupts_restore(ipl);
 
237
                return 0;
 
238
        }
 
239
        ((uint32_t *)cur->address)[0] = cur->instruction;
 
240
        smc_coherence(((uint32_t *)cur->address)[0]);
 
241
        ((uint32_t *)cur->address)[1] = cur->nextinstruction;
 
242
        smc_coherence(((uint32_t *)cur->address)[1]);
 
243
 
 
244
        cur->address = NULL;
 
245
 
 
246
        spinlock_unlock(&bkpoint_lock);
 
247
        interrupts_restore(ipl);
 
248
        return 1;
 
249
}
 
250
 
 
251
/** Print table of active breakpoints */
 
252
int cmd_print_breakpoints(cmd_arg_t *argv)
 
253
{
 
254
        unsigned int i;
 
255
        char *symbol;
 
256
        
 
257
        printf("#  Count Address    INPROG ONESHOT FUNCCALL In symbol\n");
 
258
        printf("-- ----- ---------- ------ ------- -------- ---------\n");
 
259
        
 
260
        for (i = 0; i < BKPOINTS_MAX; i++)
 
261
                if (breakpoints[i].address) {
 
262
                        symbol = symtab_fmt_name_lookup(
 
263
                            breakpoints[i].address);
 
264
 
 
265
                        printf("%-2u %-5d %#10zx %-6s %-7s %-8s %s\n", i,
 
266
                            breakpoints[i].counter, breakpoints[i].address,
 
267
                            ((breakpoints[i].flags & BKPOINT_INPROG) ? "true" :
 
268
                            "false"), ((breakpoints[i].flags & BKPOINT_ONESHOT)
 
269
                            ? "true" : "false"), ((breakpoints[i].flags &
 
270
                            BKPOINT_FUNCCALL) ? "true" : "false"), symbol);
 
271
                }
 
272
        return 1;
 
273
}
 
274
 
 
275
#endif
 
276
 
 
277
/** Initialize debugger */
 
278
void debugger_init()
 
279
{
 
280
        int i;
 
281
 
 
282
        for (i = 0; i < BKPOINTS_MAX; i++)
 
283
                breakpoints[i].address = NULL;
 
284
 
 
285
#ifdef CONFIG_KCONSOLE
 
286
        cmd_initialize(&bkpts_info);
 
287
        if (!cmd_register(&bkpts_info))
 
288
                printf("Cannot register command %s\n", bkpts_info.name);
 
289
 
 
290
        cmd_initialize(&delbkpt_info);
 
291
        if (!cmd_register(&delbkpt_info))
 
292
                printf("Cannot register command %s\n", delbkpt_info.name);
 
293
 
 
294
        cmd_initialize(&addbkpt_info);
 
295
        if (!cmd_register(&addbkpt_info))
 
296
                printf("Cannot register command %s\n", addbkpt_info.name);
 
297
 
 
298
        cmd_initialize(&addbkpte_info);
 
299
        if (!cmd_register(&addbkpte_info))
 
300
                printf("Cannot register command %s\n", addbkpte_info.name);
 
301
#endif
 
302
}
 
303
 
 
304
/** Handle breakpoint
 
305
 *
 
306
 * Find breakpoint in breakpoint table. 
 
307
 * If found, call kconsole, set break on next instruction and reexecute.
 
308
 * If we are on "next instruction", set it back on the first and reexecute.
 
309
 * If breakpoint not found in breakpoint table, call kconsole and start
 
310
 * next instruction.
 
311
 */
 
312
void debugger_bpoint(istate_t *istate)
 
313
{
 
314
        bpinfo_t *cur = NULL;
 
315
        uintptr_t fireaddr = istate->epc;
 
316
        int i;
 
317
 
 
318
        /* test branch delay slot */
 
319
        if (cp0_cause_read() & 0x80000000)
 
320
                panic("Breakpoint in branch delay slot not supported.");
 
321
 
 
322
        spinlock_lock(&bkpoint_lock);
 
323
        for (i = 0; i < BKPOINTS_MAX; i++) {
 
324
                /* Normal breakpoint */
 
325
                if (fireaddr == breakpoints[i].address &&
 
326
                    !(breakpoints[i].flags & BKPOINT_REINST)) {
 
327
                        cur = &breakpoints[i];
 
328
                        break;
 
329
                }
 
330
                /* Reinst only breakpoint */
 
331
                if ((breakpoints[i].flags & BKPOINT_REINST) &&
 
332
                    (fireaddr == breakpoints[i].address + sizeof(unative_t))) {
 
333
                        cur = &breakpoints[i];
 
334
                        break;
 
335
                }
 
336
        }
 
337
        if (cur) {
 
338
                if (cur->flags & BKPOINT_REINST) {
 
339
                        /* Set breakpoint on first instruction */
 
340
                        ((uint32_t *)cur->address)[0] = 0x0d;
 
341
                        smc_coherence(((uint32_t *)cur->address)[0]);
 
342
                        /* Return back the second */
 
343
                        ((uint32_t *)cur->address)[1] = cur->nextinstruction;
 
344
                        smc_coherence(((uint32_t *)cur->address)[1]);
 
345
                        cur->flags &= ~BKPOINT_REINST;
 
346
                        spinlock_unlock(&bkpoint_lock);
 
347
                        return;
 
348
                } 
 
349
                if (cur->flags & BKPOINT_INPROG)
 
350
                        printf("Warning: breakpoint recursion\n");
 
351
                
 
352
                if (!(cur->flags & BKPOINT_FUNCCALL)) {
 
353
                        printf("***Breakpoint %d: %p in %s.\n", i, fireaddr,
 
354
                            symtab_fmt_name_lookup(istate->epc));
 
355
                }
 
356
 
 
357
                /* Return first instruction back */
 
358
                ((uint32_t *)cur->address)[0] = cur->instruction;
 
359
                smc_coherence(cur->address);
 
360
 
 
361
                if (! (cur->flags & BKPOINT_ONESHOT)) {
 
362
                        /* Set Breakpoint on next instruction */
 
363
                        ((uint32_t *)cur->address)[1] = 0x0d;
 
364
                        cur->flags |= BKPOINT_REINST;
 
365
                } 
 
366
                cur->flags |= BKPOINT_INPROG;
 
367
        } else {
 
368
                printf("***Breakpoint %d: %p in %s.\n", i, fireaddr,
 
369
                    symtab_fmt_name_lookup(fireaddr));
 
370
 
 
371
                /* Move on to next instruction */
 
372
                istate->epc += 4;
 
373
        }
 
374
        if (cur)
 
375
                cur->counter++;
 
376
        if (cur && (cur->flags & BKPOINT_FUNCCALL)) {
 
377
                /* Allow zero bkfunc, just for counting */
 
378
                if (cur->bkfunc)
 
379
                        cur->bkfunc(cur, istate);
 
380
        } else {
 
381
#ifdef CONFIG_KCONSOLE
 
382
                /* This disables all other processors - we are not SMP,
 
383
                 * actually this gets us to cpu_halt, if scheduler() is run
 
384
                 * - we generally do not want scheduler to be run from debug,
 
385
                 *   so this is a good idea
 
386
                 */     
 
387
                atomic_set(&haltstate, 1);
 
388
                spinlock_unlock(&bkpoint_lock);
 
389
                
 
390
                kconsole("debug", "Debug console ready.\n", false);
 
391
                
 
392
                spinlock_lock(&bkpoint_lock);
 
393
                atomic_set(&haltstate, 0);
 
394
#endif
 
395
        }
 
396
        if (cur && cur->address == fireaddr && (cur->flags & BKPOINT_INPROG)) {
 
397
                /* Remove one-shot breakpoint */
 
398
                if ((cur->flags & BKPOINT_ONESHOT))
 
399
                        cur->address = NULL;
 
400
                /* Remove in-progress flag */
 
401
                cur->flags &= ~BKPOINT_INPROG;
 
402
        } 
 
403
        spinlock_unlock(&bkpoint_lock);
 
404
}
 
405
 
 
406
/** @}
 
407
 */