source: mainline/kernel/arch/amd64/src/debugger.c@ 89c57b6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 89c57b6 was 96b02eb9, checked in by Martin Decky <martin@…>, 15 years ago

more unification of basic types

  • use sysarg_t and native_t (unsigned and signed variant) in both kernel and uspace
  • remove ipcarg_t in favour of sysarg_t

(no change in functionality)

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