Subversion Repositories HelenOS

Rev

Rev 4101 | Go to most recent revision | 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>
3139 jermar 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>
45
 
4132 svoboda 46
#ifdef CONFIG_SYMTAB
47
#include <symtab.h>
48
#endif
49
 
614 palkovsky 50
bpinfo_t breakpoints[BKPOINTS_MAX];
623 jermar 51
SPINLOCK_INITIALIZE(bkpoint_lock);
614 palkovsky 52
 
3707 decky 53
#ifdef CONFIG_KCONSOLE
54
 
614 palkovsky 55
static int cmd_print_breakpoints(cmd_arg_t *argv);
673 jermar 56
static cmd_info_t bkpts_info = {
57
	.name = "bkpts",
614 palkovsky 58
	.description = "Print breakpoint table.",
59
	.func = cmd_print_breakpoints,
60
	.argc = 0,
61
};
62
 
63
static int cmd_del_breakpoint(cmd_arg_t *argv);
64
static cmd_arg_t del_argv = {
65
	.type = ARG_TYPE_INT
66
};
67
static cmd_info_t delbkpt_info = {
68
	.name = "delbkpt",
69
	.description = "delbkpt <number> - Delete breakpoint.",
70
	.func = cmd_del_breakpoint,
71
	.argc = 1,
72
	.argv = &del_argv
73
};
74
 
75
static int cmd_add_breakpoint(cmd_arg_t *argv);
76
static cmd_arg_t add_argv = {
77
	.type = ARG_TYPE_INT
78
};
79
static cmd_info_t addbkpt_info = {
80
	.name = "addbkpt",
3139 jermar 81
	.description = "addbkpt <&symbol> - new bkpoint. Break on J/Branch "
82
	    "insts unsupported.",
614 palkovsky 83
	.func = cmd_add_breakpoint,
84
	.argc = 1,
85
	.argv = &add_argv
86
};
87
 
635 palkovsky 88
static cmd_arg_t adde_argv[] = {
89
	{ .type = ARG_TYPE_INT },
90
	{ .type = ARG_TYPE_INT }
91
};
92
static cmd_info_t addbkpte_info = {
93
	.name = "addbkpte",
3139 jermar 94
	.description = "addebkpte <&symbol> <&func> - new bkpoint. Call "
95
	    "func(or Nothing if 0).",
635 palkovsky 96
	.func = cmd_add_breakpoint,
97
	.argc = 2,
98
	.argv = adde_argv
99
};
100
 
101
static struct {
1780 jermar 102
	uint32_t andmask;
103
	uint32_t value;
3139 jermar 104
} jmpinstr[] = {
635 palkovsky 105
	{0xf3ff0000, 0x41000000}, /* BCzF */
106
	{0xf3ff0000, 0x41020000}, /* BCzFL */
107
	{0xf3ff0000, 0x41010000}, /* BCzT */
108
	{0xf3ff0000, 0x41030000}, /* BCzTL */
109
	{0xfc000000, 0x10000000}, /* BEQ */
110
	{0xfc000000, 0x50000000}, /* BEQL */
111
	{0xfc1f0000, 0x04010000}, /* BEQL */
112
	{0xfc1f0000, 0x04110000}, /* BGEZAL */
113
	{0xfc1f0000, 0x04130000}, /* BGEZALL */
114
	{0xfc1f0000, 0x04030000}, /* BGEZL */
115
	{0xfc1f0000, 0x1c000000}, /* BGTZ */
116
	{0xfc1f0000, 0x5c000000}, /* BGTZL */
117
	{0xfc1f0000, 0x18000000}, /* BLEZ */
118
	{0xfc1f0000, 0x58000000}, /* BLEZL */
119
	{0xfc1f0000, 0x04000000}, /* BLTZ */
120
	{0xfc1f0000, 0x04100000}, /* BLTZAL */
121
	{0xfc1f0000, 0x04120000}, /* BLTZALL */
122
	{0xfc1f0000, 0x04020000}, /* BLTZL */
123
	{0xfc000000, 0x14000000}, /* BNE */
124
	{0xfc000000, 0x54000000}, /* BNEL */
125
	{0xfc000000, 0x08000000}, /* J */
126
	{0xfc000000, 0x0c000000}, /* JAL */
127
	{0xfc1f07ff, 0x00000009}, /* JALR */
3139 jermar 128
	{0, 0} /* EndOfTable */
635 palkovsky 129
};
130
 
3707 decky 131
 
635 palkovsky 132
/** Test, if the given instruction is a jump or branch instruction
133
 *
134
 * @param instr Instruction code
135
 * @return true - it is jump instruction, false otherwise
3707 decky 136
 *
635 palkovsky 137
 */
1780 jermar 138
static bool is_jump(unative_t instr)
635 palkovsky 139
{
140
	int i;
141
 
3139 jermar 142
	for (i = 0; jmpinstr[i].andmask; i++) {
635 palkovsky 143
		if ((instr & jmpinstr[i].andmask) == jmpinstr[i].value)
144
			return true;
145
	}
146
 
147
	return false;
148
}
149
 
614 palkovsky 150
/** Add new breakpoint to table */
151
int cmd_add_breakpoint(cmd_arg_t *argv)
152
{
153
	bpinfo_t *cur = NULL;
154
	ipl_t ipl;
155
	int i;
156
 
157
	if (argv->intval & 0x3) {
158
		printf("Not aligned instruction, forgot to use &symbol?\n");
159
		return 1;
160
	}
161
	ipl = interrupts_disable();
162
	spinlock_lock(&bkpoint_lock);
163
 
164
	/* Check, that the breakpoints do not conflict */
3071 decky 165
	for (i = 0; i < BKPOINTS_MAX; i++) {
1780 jermar 166
		if (breakpoints[i].address == (uintptr_t)argv->intval) {
614 palkovsky 167
			printf("Duplicate breakpoint %d.\n", i);
3913 decky 168
			spinlock_unlock(&bkpoint_lock);
614 palkovsky 169
			return 0;
3139 jermar 170
		} else if (breakpoints[i].address == (uintptr_t)argv->intval +
171
		    sizeof(unative_t) || breakpoints[i].address ==
172
		    (uintptr_t)argv->intval - sizeof(unative_t)) {
173
			printf("Adjacent breakpoints not supported, conflict "
174
			    "with %d.\n", i);
3913 decky 175
			spinlock_unlock(&bkpoint_lock);
614 palkovsky 176
			return 0;
177
		}
3913 decky 178
 
614 palkovsky 179
	}
180
 
3139 jermar 181
	for (i = 0; i < BKPOINTS_MAX; i++)
614 palkovsky 182
		if (!breakpoints[i].address) {
183
			cur = &breakpoints[i];
184
			break;
185
		}
186
	if (!cur) {
187
		printf("Too many breakpoints.\n");
188
		spinlock_unlock(&bkpoint_lock);
189
		interrupts_restore(ipl);
190
		return 0;
191
	}
1780 jermar 192
	cur->address = (uintptr_t) argv->intval;
614 palkovsky 193
	printf("Adding breakpoint on address: %p\n", argv->intval);
1780 jermar 194
	cur->instruction = ((unative_t *)cur->address)[0];
195
	cur->nextinstruction = ((unative_t *)cur->address)[1];
635 palkovsky 196
	if (argv == &add_argv) {
197
		cur->flags = 0;
198
	} else { /* We are add extended */
199
		cur->flags = BKPOINT_FUNCCALL;
3139 jermar 200
		cur->bkfunc = (void (*)(void *, istate_t *)) argv[1].intval;
635 palkovsky 201
	}
202
	if (is_jump(cur->instruction))
203
		cur->flags |= BKPOINT_ONESHOT;
204
	cur->counter = 0;
614 palkovsky 205
 
206
	/* Set breakpoint */
1780 jermar 207
	*((unative_t *)cur->address) = 0x0d;
3139 jermar 208
	smc_coherence(cur->address);
614 palkovsky 209
 
210
	spinlock_unlock(&bkpoint_lock);
211
	interrupts_restore(ipl);
212
 
213
	return 1;
214
}
215
 
216
/** Remove breakpoint from table */
217
int cmd_del_breakpoint(cmd_arg_t *argv)
218
{
219
	bpinfo_t *cur;
220
	ipl_t ipl;
221
 
2745 decky 222
	if (argv->intval > BKPOINTS_MAX) {
614 palkovsky 223
		printf("Invalid breakpoint number.\n");
224
		return 0;
225
	}
226
	ipl = interrupts_disable();
227
	spinlock_lock(&bkpoint_lock);
228
 
229
	cur = &breakpoints[argv->intval];
230
	if (!cur->address) {
231
		printf("Breakpoint does not exist.\n");
232
		spinlock_unlock(&bkpoint_lock);
233
		interrupts_restore(ipl);
234
		return 0;
235
	}
635 palkovsky 236
	if ((cur->flags & BKPOINT_INPROG) && (cur->flags & BKPOINT_ONESHOT)) {
237
		printf("Cannot remove one-shot breakpoint in-progress\n");
238
		spinlock_unlock(&bkpoint_lock);
239
		interrupts_restore(ipl);
240
		return 0;
241
	}
1780 jermar 242
	((uint32_t *)cur->address)[0] = cur->instruction;
3139 jermar 243
	smc_coherence(((uint32_t *)cur->address)[0]);
1780 jermar 244
	((uint32_t *)cur->address)[1] = cur->nextinstruction;
3139 jermar 245
	smc_coherence(((uint32_t *)cur->address)[1]);
614 palkovsky 246
 
247
	cur->address = NULL;
248
 
249
	spinlock_unlock(&bkpoint_lock);
250
	interrupts_restore(ipl);
251
	return 1;
252
}
253
 
254
/** Print table of active breakpoints */
255
int cmd_print_breakpoints(cmd_arg_t *argv)
256
{
2719 decky 257
	unsigned int i;
614 palkovsky 258
	char *symbol;
2719 decky 259
 
260
	printf("#  Count Address    INPROG ONESHOT FUNCCALL In symbol\n");
261
	printf("-- ----- ---------- ------ ------- -------- ---------\n");
262
 
263
	for (i = 0; i < BKPOINTS_MAX; i++)
614 palkovsky 264
		if (breakpoints[i].address) {
4132 svoboda 265
#ifdef CONFIG_SYMTAB
614 palkovsky 266
			symbol = get_symtab_entry(breakpoints[i].address);
4132 svoboda 267
#else
268
			symbol = "n/a";
269
#endif
2719 decky 270
 
271
			printf("%-2u %-5d %#10zx %-6s %-7s %-8s %s\n", i,
3139 jermar 272
			    breakpoints[i].counter, breakpoints[i].address,
273
			    ((breakpoints[i].flags & BKPOINT_INPROG) ? "true" :
274
			    "false"), ((breakpoints[i].flags & BKPOINT_ONESHOT)
275
			    ? "true" : "false"), ((breakpoints[i].flags &
276
			    BKPOINT_FUNCCALL) ? "true" : "false"), symbol);
614 palkovsky 277
		}
278
	return 1;
279
}
280
 
3707 decky 281
#endif
282
 
614 palkovsky 283
/** Initialize debugger */
284
void debugger_init()
285
{
286
	int i;
287
 
3139 jermar 288
	for (i = 0; i < BKPOINTS_MAX; i++)
614 palkovsky 289
		breakpoints[i].address = NULL;
3707 decky 290
 
291
#ifdef CONFIG_KCONSOLE
673 jermar 292
	cmd_initialize(&bkpts_info);
293
	if (!cmd_register(&bkpts_info))
3707 decky 294
		printf("Cannot register command %s\n", bkpts_info.name);
614 palkovsky 295
 
296
	cmd_initialize(&delbkpt_info);
297
	if (!cmd_register(&delbkpt_info))
3707 decky 298
		printf("Cannot register command %s\n", delbkpt_info.name);
614 palkovsky 299
 
300
	cmd_initialize(&addbkpt_info);
301
	if (!cmd_register(&addbkpt_info))
3707 decky 302
		printf("Cannot register command %s\n", addbkpt_info.name);
635 palkovsky 303
 
304
	cmd_initialize(&addbkpte_info);
305
	if (!cmd_register(&addbkpte_info))
3707 decky 306
		printf("Cannot register command %s\n", addbkpte_info.name);
307
#endif
614 palkovsky 308
}
309
 
310
/** Handle breakpoint
311
 *
312
 * Find breakpoint in breakpoint table. 
313
 * If found, call kconsole, set break on next instruction and reexecute.
314
 * If we are on "next instruction", set it back on the first and reexecute.
315
 * If breakpoint not found in breakpoint table, call kconsole and start
316
 * next instruction.
317
 */
958 jermar 318
void debugger_bpoint(istate_t *istate)
614 palkovsky 319
{
320
	bpinfo_t *cur = NULL;
1780 jermar 321
	uintptr_t fireaddr = istate->epc;
614 palkovsky 322
	int i;
323
 
324
	/* test branch delay slot */
325
	if (cp0_cause_read() & 0x80000000)
3790 svoboda 326
		panic("Breakpoint in branch delay slot not supported.");
614 palkovsky 327
 
328
	spinlock_lock(&bkpoint_lock);
3139 jermar 329
	for (i = 0; i < BKPOINTS_MAX; i++) {
635 palkovsky 330
		/* Normal breakpoint */
3139 jermar 331
		if (fireaddr == breakpoints[i].address &&
332
		    !(breakpoints[i].flags & BKPOINT_REINST)) {
614 palkovsky 333
			cur = &breakpoints[i];
635 palkovsky 334
			break;
335
		}
336
		/* Reinst only breakpoint */
3139 jermar 337
		if ((breakpoints[i].flags & BKPOINT_REINST) &&
338
		    (fireaddr == breakpoints[i].address + sizeof(unative_t))) {
635 palkovsky 339
			cur = &breakpoints[i];
340
			break;
341
		}
614 palkovsky 342
	}
343
	if (cur) {
635 palkovsky 344
		if (cur->flags & BKPOINT_REINST) {
614 palkovsky 345
			/* Set breakpoint on first instruction */
1780 jermar 346
			((uint32_t *)cur->address)[0] = 0x0d;
3139 jermar 347
			smc_coherence(((uint32_t *)cur->address)[0]);
614 palkovsky 348
			/* Return back the second */
1780 jermar 349
			((uint32_t *)cur->address)[1] = cur->nextinstruction;
3139 jermar 350
			smc_coherence(((uint32_t *)cur->address)[1]);
635 palkovsky 351
			cur->flags &= ~BKPOINT_REINST;
614 palkovsky 352
			spinlock_unlock(&bkpoint_lock);
353
			return;
635 palkovsky 354
		} 
355
		if (cur->flags & BKPOINT_INPROG)
356
			printf("Warning: breakpoint recursion\n");
357
 
4132 svoboda 358
		if (!(cur->flags & BKPOINT_FUNCCALL)) {
359
#ifdef CONFIG_SYMTAB
3139 jermar 360
			printf("***Breakpoint %d: %p in %s.\n", i, fireaddr,
361
			    get_symtab_entry(istate->epc));
4132 svoboda 362
#else
363
			printf("***Breakpoint %d: %p.\n", i, fireaddr);
364
#endif
365
		}
635 palkovsky 366
 
367
		/* Return first instruction back */
1780 jermar 368
		((uint32_t *)cur->address)[0] = cur->instruction;
3139 jermar 369
		smc_coherence(cur->address);
635 palkovsky 370
 
371
		if (! (cur->flags & BKPOINT_ONESHOT)) {
372
			/* Set Breakpoint on next instruction */
1780 jermar 373
			((uint32_t *)cur->address)[1] = 0x0d;
635 palkovsky 374
			cur->flags |= BKPOINT_REINST;
375
		} 
376
		cur->flags |= BKPOINT_INPROG;
614 palkovsky 377
	} else {
4132 svoboda 378
#ifdef CONFIG_SYMTAB
379
		printf("***Breakpoint %p in %s.\n", fireaddr,
635 palkovsky 380
		       get_symtab_entry(fireaddr));
4132 svoboda 381
#else
382
		printf("***Breakpoint %p.\n", fireaddr);	
383
#endif
614 palkovsky 384
		/* Move on to next instruction */
958 jermar 385
		istate->epc += 4;
614 palkovsky 386
	}
850 palkovsky 387
	if (cur)
388
		cur->counter++;
635 palkovsky 389
	if (cur && (cur->flags & BKPOINT_FUNCCALL)) {
390
		/* Allow zero bkfunc, just for counting */
391
		if (cur->bkfunc)
958 jermar 392
			cur->bkfunc(cur, istate);
635 palkovsky 393
	} else {
3707 decky 394
#ifdef CONFIG_KCONSOLE
635 palkovsky 395
		/* This disables all other processors - we are not SMP,
396
		 * actually this gets us to cpu_halt, if scheduler() is run
397
		 * - we generally do not want scheduler to be run from debug,
398
		 *   so this is a good idea
399
		 */	
3707 decky 400
		atomic_set(&haltstate, 1);
635 palkovsky 401
		spinlock_unlock(&bkpoint_lock);
3707 decky 402
 
4101 decky 403
		kconsole("debug", "Debug console ready.\n", false);
3707 decky 404
 
635 palkovsky 405
		spinlock_lock(&bkpoint_lock);
3707 decky 406
		atomic_set(&haltstate, 0);
407
#endif
635 palkovsky 408
	}
409
	if (cur && cur->address == fireaddr && (cur->flags & BKPOINT_INPROG)) {
410
		/* Remove one-shot breakpoint */
411
		if ((cur->flags & BKPOINT_ONESHOT))
412
			cur->address = NULL;
413
		/* Remove in-progress flag */
414
		cur->flags &= ~BKPOINT_INPROG;
415
	} 
614 palkovsky 416
	spinlock_unlock(&bkpoint_lock);
417
}
1702 cejka 418
 
1888 jermar 419
/** @}
1702 cejka 420
 */