Subversion Repositories HelenOS

Rev

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