Subversion Repositories HelenOS

Rev

Rev 3424 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
614 palkovsky 1
/*
2071 jermar 2
 * Copyright (c) 2005 Ondrej Palkovsky
614 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
 
1888 jermar 29
/** @addtogroup mips32debug
1702 cejka 30
 * @{
31
 */
32
/** @file
33
 */
34
 
614 palkovsky 35
#include <arch/debugger.h>
3424 svoboda 36
#include <arch/barrier.h>
614 palkovsky 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>
4377 svoboda 45
#include <symtab.h>
614 palkovsky 46
 
47
bpinfo_t breakpoints[BKPOINTS_MAX];
623 jermar 48
SPINLOCK_INITIALIZE(bkpoint_lock);
614 palkovsky 49
 
4377 svoboda 50
#ifdef CONFIG_KCONSOLE
51
 
614 palkovsky 52
static int cmd_print_breakpoints(cmd_arg_t *argv);
673 jermar 53
static cmd_info_t bkpts_info = {
54
    .name = "bkpts",
614 palkovsky 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",
3424 svoboda 78
    .description = "addbkpt <&symbol> - new bkpoint. Break on J/Branch "
79
        "insts unsupported.",
614 palkovsky 80
    .func = cmd_add_breakpoint,
81
    .argc = 1,
82
    .argv = &add_argv
83
};
84
 
635 palkovsky 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",
3424 svoboda 91
    .description = "addebkpte <&symbol> <&func> - new bkpoint. Call "
92
        "func(or Nothing if 0).",
635 palkovsky 93
    .func = cmd_add_breakpoint,
94
    .argc = 2,
95
    .argv = adde_argv
96
};
97
 
98
static struct {
1780 jermar 99
    uint32_t andmask;
100
    uint32_t value;
3424 svoboda 101
} jmpinstr[] = {
635 palkovsky 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 */
3424 svoboda 125
    {0, 0} /* EndOfTable */
635 palkovsky 126
};
127
 
4377 svoboda 128
 
635 palkovsky 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
4377 svoboda 133
 *
635 palkovsky 134
 */
1780 jermar 135
static bool is_jump(unative_t instr)
635 palkovsky 136
{
137
    int i;
138
 
3424 svoboda 139
    for (i = 0; jmpinstr[i].andmask; i++) {
635 palkovsky 140
        if ((instr & jmpinstr[i].andmask) == jmpinstr[i].value)
141
            return true;
142
    }
143
 
144
    return false;
145
}
146
 
614 palkovsky 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 */
3424 svoboda 162
    for (i = 0; i < BKPOINTS_MAX; i++) {
1780 jermar 163
        if (breakpoints[i].address == (uintptr_t)argv->intval) {
614 palkovsky 164
            printf("Duplicate breakpoint %d.\n", i);
4377 svoboda 165
            spinlock_unlock(&bkpoint_lock);
614 palkovsky 166
            return 0;
3424 svoboda 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);
4377 svoboda 172
            spinlock_unlock(&bkpoint_lock);
614 palkovsky 173
            return 0;
174
        }
4377 svoboda 175
 
614 palkovsky 176
    }
177
 
3424 svoboda 178
    for (i = 0; i < BKPOINTS_MAX; i++)
614 palkovsky 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
    }
1780 jermar 189
    cur->address = (uintptr_t) argv->intval;
614 palkovsky 190
    printf("Adding breakpoint on address: %p\n", argv->intval);
1780 jermar 191
    cur->instruction = ((unative_t *)cur->address)[0];
192
    cur->nextinstruction = ((unative_t *)cur->address)[1];
635 palkovsky 193
    if (argv == &add_argv) {
194
        cur->flags = 0;
195
    } else { /* We are add extended */
196
        cur->flags = BKPOINT_FUNCCALL;
3424 svoboda 197
        cur->bkfunc = (void (*)(void *, istate_t *)) argv[1].intval;
635 palkovsky 198
    }
199
    if (is_jump(cur->instruction))
200
        cur->flags |= BKPOINT_ONESHOT;
201
    cur->counter = 0;
614 palkovsky 202
 
203
    /* Set breakpoint */
1780 jermar 204
    *((unative_t *)cur->address) = 0x0d;
3424 svoboda 205
    smc_coherence(cur->address);
614 palkovsky 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
 
2745 decky 219
    if (argv->intval > BKPOINTS_MAX) {
614 palkovsky 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
    }
635 palkovsky 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
    }
1780 jermar 239
    ((uint32_t *)cur->address)[0] = cur->instruction;
3424 svoboda 240
    smc_coherence(((uint32_t *)cur->address)[0]);
1780 jermar 241
    ((uint32_t *)cur->address)[1] = cur->nextinstruction;
3424 svoboda 242
    smc_coherence(((uint32_t *)cur->address)[1]);
614 palkovsky 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
{
2719 decky 254
    unsigned int i;
614 palkovsky 255
    char *symbol;
2719 decky 256
 
257
    printf("#  Count Address    INPROG ONESHOT FUNCCALL In symbol\n");
258
    printf("-- ----- ---------- ------ ------- -------- ---------\n");
259
 
260
    for (i = 0; i < BKPOINTS_MAX; i++)
614 palkovsky 261
        if (breakpoints[i].address) {
4377 svoboda 262
            symbol = symtab_fmt_name_lookup(
263
                breakpoints[i].address);
264
 
2719 decky 265
            printf("%-2u %-5d %#10zx %-6s %-7s %-8s %s\n", i,
3424 svoboda 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);
614 palkovsky 271
        }
272
    return 1;
273
}
274
 
4377 svoboda 275
#endif
276
 
614 palkovsky 277
/** Initialize debugger */
278
void debugger_init()
279
{
280
    int i;
281
 
3424 svoboda 282
    for (i = 0; i < BKPOINTS_MAX; i++)
614 palkovsky 283
        breakpoints[i].address = NULL;
4377 svoboda 284
 
285
#ifdef CONFIG_KCONSOLE
673 jermar 286
    cmd_initialize(&bkpts_info);
287
    if (!cmd_register(&bkpts_info))
4377 svoboda 288
        printf("Cannot register command %s\n", bkpts_info.name);
614 palkovsky 289
 
290
    cmd_initialize(&delbkpt_info);
291
    if (!cmd_register(&delbkpt_info))
4377 svoboda 292
        printf("Cannot register command %s\n", delbkpt_info.name);
614 palkovsky 293
 
294
    cmd_initialize(&addbkpt_info);
295
    if (!cmd_register(&addbkpt_info))
4377 svoboda 296
        printf("Cannot register command %s\n", addbkpt_info.name);
635 palkovsky 297
 
298
    cmd_initialize(&addbkpte_info);
299
    if (!cmd_register(&addbkpte_info))
4377 svoboda 300
        printf("Cannot register command %s\n", addbkpte_info.name);
301
#endif
614 palkovsky 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
 */
958 jermar 312
void debugger_bpoint(istate_t *istate)
614 palkovsky 313
{
314
    bpinfo_t *cur = NULL;
1780 jermar 315
    uintptr_t fireaddr = istate->epc;
614 palkovsky 316
    int i;
317
 
318
    /* test branch delay slot */
319
    if (cp0_cause_read() & 0x80000000)
4377 svoboda 320
        panic("Breakpoint in branch delay slot not supported.");
614 palkovsky 321
 
322
    spinlock_lock(&bkpoint_lock);
3424 svoboda 323
    for (i = 0; i < BKPOINTS_MAX; i++) {
635 palkovsky 324
        /* Normal breakpoint */
3424 svoboda 325
        if (fireaddr == breakpoints[i].address &&
326
            !(breakpoints[i].flags & BKPOINT_REINST)) {
614 palkovsky 327
            cur = &breakpoints[i];
635 palkovsky 328
            break;
329
        }
330
        /* Reinst only breakpoint */
3424 svoboda 331
        if ((breakpoints[i].flags & BKPOINT_REINST) &&
332
            (fireaddr == breakpoints[i].address + sizeof(unative_t))) {
635 palkovsky 333
            cur = &breakpoints[i];
334
            break;
335
        }
614 palkovsky 336
    }
337
    if (cur) {
635 palkovsky 338
        if (cur->flags & BKPOINT_REINST) {
614 palkovsky 339
            /* Set breakpoint on first instruction */
1780 jermar 340
            ((uint32_t *)cur->address)[0] = 0x0d;
3424 svoboda 341
            smc_coherence(((uint32_t *)cur->address)[0]);
614 palkovsky 342
            /* Return back the second */
1780 jermar 343
            ((uint32_t *)cur->address)[1] = cur->nextinstruction;
3424 svoboda 344
            smc_coherence(((uint32_t *)cur->address)[1]);
635 palkovsky 345
            cur->flags &= ~BKPOINT_REINST;
614 palkovsky 346
            spinlock_unlock(&bkpoint_lock);
347
            return;
635 palkovsky 348
        }
349
        if (cur->flags & BKPOINT_INPROG)
350
            printf("Warning: breakpoint recursion\n");
351
 
4377 svoboda 352
        if (!(cur->flags & BKPOINT_FUNCCALL)) {
3424 svoboda 353
            printf("***Breakpoint %d: %p in %s.\n", i, fireaddr,
4377 svoboda 354
                symtab_fmt_name_lookup(istate->epc));
355
        }
635 palkovsky 356
 
357
        /* Return first instruction back */
1780 jermar 358
        ((uint32_t *)cur->address)[0] = cur->instruction;
3424 svoboda 359
        smc_coherence(cur->address);
635 palkovsky 360
 
361
        if (! (cur->flags & BKPOINT_ONESHOT)) {
362
            /* Set Breakpoint on next instruction */
1780 jermar 363
            ((uint32_t *)cur->address)[1] = 0x0d;
635 palkovsky 364
            cur->flags |= BKPOINT_REINST;
365
        }
366
        cur->flags |= BKPOINT_INPROG;
614 palkovsky 367
    } else {
4377 svoboda 368
        printf("***Breakpoint %d: %p in %s.\n", i, fireaddr,
369
            symtab_fmt_name_lookup(fireaddr));
370
 
614 palkovsky 371
        /* Move on to next instruction */
958 jermar 372
        istate->epc += 4;
614 palkovsky 373
    }
850 palkovsky 374
    if (cur)
375
        cur->counter++;
635 palkovsky 376
    if (cur && (cur->flags & BKPOINT_FUNCCALL)) {
377
        /* Allow zero bkfunc, just for counting */
378
        if (cur->bkfunc)
958 jermar 379
            cur->bkfunc(cur, istate);
635 palkovsky 380
    } else {
4377 svoboda 381
#ifdef CONFIG_KCONSOLE
635 palkovsky 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
         */
4377 svoboda 387
        atomic_set(&haltstate, 1);
635 palkovsky 388
        spinlock_unlock(&bkpoint_lock);
4377 svoboda 389
 
390
        kconsole("debug", "Debug console ready.\n", false);
391
 
635 palkovsky 392
        spinlock_lock(&bkpoint_lock);
4377 svoboda 393
        atomic_set(&haltstate, 0);
394
#endif
635 palkovsky 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
    }
614 palkovsky 403
    spinlock_unlock(&bkpoint_lock);
404
}
1702 cejka 405
 
1888 jermar 406
/** @}
1702 cejka 407
 */