source: mainline/arch/amd64/src/debugger.c@ 280a27e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 280a27e was 280a27e, checked in by Josef Cejka <malyzelenyhnus@…>, 19 years ago

Printf ported back from uspace to kernel.
Printf calls changed to match new conventions.

  • Property mode set to 100644
File size: 8.8 KB
Line 
1/*
2 * Copyright (C) 2006 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#include <arch/debugger.h>
30#include <console/kconsole.h>
31#include <console/cmd.h>
32#include <symtab.h>
33#include <print.h>
34#include <panic.h>
35#include <interrupt.h>
36#include <arch/asm.h>
37#include <arch/cpu.h>
38#include <debug.h>
39#include <func.h>
40#include <smp/ipi.h>
41
42typedef struct {
43 __address address; /**< Breakpoint address */
44 int flags; /**< Flags regarding breakpoint */
45 int counter; /**< How many times the exception occured */
46} bpinfo_t;
47
48static bpinfo_t breakpoints[BKPOINTS_MAX];
49SPINLOCK_INITIALIZE(bkpoint_lock);
50
51static int cmd_print_breakpoints(cmd_arg_t *argv);
52static cmd_info_t bkpts_info = {
53 .name = "bkpts",
54 .description = "Print breakpoint table.",
55 .func = cmd_print_breakpoints,
56 .argc = 0,
57};
58
59#ifndef CONFIG_DEBUG_AS_WATCHPOINT
60
61static int cmd_del_breakpoint(cmd_arg_t *argv);
62static cmd_arg_t del_argv = {
63 .type = ARG_TYPE_INT
64};
65static cmd_info_t delbkpt_info = {
66 .name = "delbkpt",
67 .description = "delbkpt <number> - Delete breakpoint.",
68 .func = cmd_del_breakpoint,
69 .argc = 1,
70 .argv = &del_argv
71};
72
73static int cmd_add_breakpoint(cmd_arg_t *argv);
74static cmd_arg_t add_argv = {
75 .type = ARG_TYPE_INT
76};
77static cmd_info_t addbkpt_info = {
78 .name = "addbkpt",
79 .description = "addbkpt <&symbol> - new breakpoint.",
80 .func = cmd_add_breakpoint,
81 .argc = 1,
82 .argv = &add_argv
83};
84
85static cmd_arg_t addw_argv = {
86 .type = ARG_TYPE_INT
87};
88static cmd_info_t addwatchp_info = {
89 .name = "addwatchp",
90 .description = "addbwatchp <&symbol> - new write watchpoint.",
91 .func = cmd_add_breakpoint,
92 .argc = 1,
93 .argv = &addw_argv
94};
95
96#endif
97
98/** Print table of active breakpoints */
99int cmd_print_breakpoints(cmd_arg_t *argv)
100{
101 int i;
102 char *symbol;
103
104 printf("Breakpoint table.\n");
105 for (i=0; i < BKPOINTS_MAX; i++)
106 if (breakpoints[i].address) {
107 symbol = get_symtab_entry(breakpoints[i].address);
108 printf("%d. %p in %s\n",i,
109 breakpoints[i].address, symbol);
110 printf(" Count(%d) ", breakpoints[i].counter);
111 printf("\n");
112 }
113 return 1;
114}
115
116/* Setup DR register according to table */
117static void setup_dr(int curidx)
118{
119 __native dr7;
120 bpinfo_t *cur = &breakpoints[curidx];
121 int flags = breakpoints[curidx].flags;
122
123 /* Disable breakpoint in DR7 */
124 dr7 = read_dr7();
125 dr7 &= ~(0x2 << (curidx*2));
126
127 if (cur->address) { /* Setup DR register */
128 /* Set breakpoint to debug registers */
129 switch (curidx) {
130 case 0:
131 write_dr0(cur->address);
132 break;
133 case 1:
134 write_dr1(cur->address);
135 break;
136 case 2:
137 write_dr2(cur->address);
138 break;
139 case 3:
140 write_dr3(cur->address);
141 break;
142 }
143 /* Set type to requested breakpoint & length*/
144 dr7 &= ~ (0x3 << (16 + 4*curidx));
145 dr7 &= ~ (0x3 << (18 + 4*curidx));
146 if ((flags & BKPOINT_INSTR)) {
147 ;
148 } else {
149 if (sizeof(int) == 4)
150 dr7 |= ((__native) 0x3) << (18 + 4*curidx);
151 else /* 8 */
152 dr7 |= ((__native) 0x2) << (18 + 4*curidx);
153
154 if ((flags & BKPOINT_WRITE))
155 dr7 |= ((__native) 0x1) << (16 + 4*curidx);
156 else if ((flags & BKPOINT_READ_WRITE))
157 dr7 |= ((__native) 0x3) << (16 + 4*curidx);
158 }
159
160 /* Enable global breakpoint */
161 dr7 |= 0x2 << (curidx*2);
162
163 write_dr7(dr7);
164
165 }
166}
167
168/** Enable hardware breakpoint
169 *
170 *
171 * @param where Address of HW breakpoint
172 * @param flags Type of breakpoint (EXECUTE, WRITE)
173 * @return Debug slot on success, -1 - no available HW breakpoint
174 */
175int breakpoint_add(void * where, int flags, int curidx)
176{
177 ipl_t ipl;
178 int i;
179 bpinfo_t *cur;
180
181 ASSERT( flags & (BKPOINT_INSTR | BKPOINT_WRITE | BKPOINT_READ_WRITE));
182
183 ipl = interrupts_disable();
184 spinlock_lock(&bkpoint_lock);
185
186 if (curidx == -1) {
187 /* Find free space in slots */
188 for (i=0; i<BKPOINTS_MAX; i++)
189 if (!breakpoints[i].address) {
190 curidx = i;
191 break;
192 }
193 if (curidx == -1) {
194 /* Too many breakpoints */
195 spinlock_unlock(&bkpoint_lock);
196 interrupts_restore(ipl);
197 return -1;
198 }
199 }
200 cur = &breakpoints[curidx];
201
202 cur->address = (__address) where;
203 cur->flags = flags;
204 cur->counter = 0;
205
206 setup_dr(curidx);
207
208 spinlock_unlock(&bkpoint_lock);
209 interrupts_restore(ipl);
210
211 /* Send IPI */
212#ifdef CONFIG_SMP
213// ipi_broadcast(VECTOR_DEBUG_IPI);
214#endif
215
216 return curidx;
217}
218
219#ifdef amd64
220# define getip(x) ((x)->rip)
221#else
222# define getip(x) ((x)->eip)
223#endif
224
225static void handle_exception(int slot, istate_t *istate)
226{
227 ASSERT(breakpoints[slot].address);
228
229 /* Handle zero checker */
230 if (! (breakpoints[slot].flags & BKPOINT_INSTR)) {
231 if ((breakpoints[slot].flags & BKPOINT_CHECK_ZERO)) {
232 if (*((__native *) breakpoints[slot].address) != 0)
233 return;
234 printf("**** Found ZERO on address %P ****\n",
235 slot, breakpoints[slot].address);
236 } else {
237 printf("Data watchpoint - new data: %P\n",
238 *((__native *) breakpoints[slot].address));
239 }
240 }
241 printf("Reached breakpoint %d:%P(%s)\n", slot, getip(istate),
242 get_symtab_entry(getip(istate)));
243 printf("***Type 'exit' to exit kconsole.\n");
244 atomic_set(&haltstate,1);
245 kconsole("debug");
246 atomic_set(&haltstate,0);
247}
248
249void breakpoint_del(int slot)
250{
251 bpinfo_t *cur;
252 ipl_t ipl;
253
254 ipl = interrupts_disable();
255 spinlock_lock(&bkpoint_lock);
256
257 cur = &breakpoints[slot];
258 if (!cur->address) {
259 spinlock_unlock(&bkpoint_lock);
260 interrupts_restore(ipl);
261 return;
262 }
263
264 cur->address = NULL;
265
266 setup_dr(slot);
267
268 spinlock_unlock(&bkpoint_lock);
269 interrupts_restore(ipl);
270#ifdef CONFIG_SMP
271// ipi_broadcast(VECTOR_DEBUG_IPI);
272#endif
273}
274
275#ifndef CONFIG_DEBUG_AS_WATCHPOINT
276
277/** Remove breakpoint from table */
278int cmd_del_breakpoint(cmd_arg_t *argv)
279{
280 if (argv->intval < 0 || argv->intval > BKPOINTS_MAX) {
281 printf("Invalid breakpoint number.\n");
282 return 0;
283 }
284 breakpoint_del(argv->intval);
285 return 1;
286}
287
288/** Add new breakpoint to table */
289static int cmd_add_breakpoint(cmd_arg_t *argv)
290{
291 int flags;
292 int id;
293
294 if (argv == &add_argv) {
295 flags = BKPOINT_INSTR;
296 } else { /* addwatchp */
297 flags = BKPOINT_WRITE;
298 }
299 printf("Adding breakpoint on address: %p\n", argv->intval);
300 id = breakpoint_add((void *)argv->intval, flags, -1);
301 if (id < 0)
302 printf("Add breakpoint failed.\n");
303 else
304 printf("Added breakpoint %d.\n", id);
305
306 return 1;
307}
308#endif
309
310static void debug_exception(int n, istate_t *istate)
311{
312 __native dr6;
313 int i;
314
315 /* Set RF to restart the instruction */
316#ifdef amd64
317 istate->rflags |= RFLAGS_RF;
318#else
319 istate->eflags |= EFLAGS_RF;
320#endif
321
322 dr6 = read_dr6();
323 for (i=0; i < BKPOINTS_MAX; i++) {
324 if (dr6 & (1 << i)) {
325 dr6 &= ~ (1 << i);
326 write_dr6(dr6);
327
328 handle_exception(i, istate);
329 }
330 }
331}
332
333#ifdef CONFIG_SMP
334static void debug_ipi(int n, istate_t *istate)
335{
336 int i;
337
338 spinlock_lock(&bkpoint_lock);
339 for (i=0; i < BKPOINTS_MAX; i++)
340 setup_dr(i);
341 spinlock_unlock(&bkpoint_lock);
342}
343#endif
344
345/** Initialize debugger */
346void debugger_init()
347{
348 int i;
349
350 for (i=0; i<BKPOINTS_MAX; i++)
351 breakpoints[i].address = NULL;
352
353 cmd_initialize(&bkpts_info);
354 if (!cmd_register(&bkpts_info))
355 panic("could not register command %s\n", bkpts_info.name);
356
357#ifndef CONFIG_DEBUG_AS_WATCHPOINT
358 cmd_initialize(&delbkpt_info);
359 if (!cmd_register(&delbkpt_info))
360 panic("could not register command %s\n", delbkpt_info.name);
361
362 cmd_initialize(&addbkpt_info);
363 if (!cmd_register(&addbkpt_info))
364 panic("could not register command %s\n", addbkpt_info.name);
365
366 cmd_initialize(&addwatchp_info);
367 if (!cmd_register(&addwatchp_info))
368 panic("could not register command %s\n", addwatchp_info.name);
369#endif
370
371 exc_register(VECTOR_DEBUG, "debugger",
372 debug_exception);
373#ifdef CONFIG_SMP
374 exc_register(VECTOR_DEBUG_IPI, "debugger_smp",
375 debug_ipi);
376#endif
377}
Note: See TracBrowser for help on using the repository browser.