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
RevLine 
[4e49572]1/*
[df4ed85]2 * Copyright (c) 2006 Ondrej Palkovsky
[4e49572]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
[06e1e95]29/** @addtogroup amd64debug
[b45c443]30 * @{
31 */
32/** @file
33 */
34
[4e49572]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>
[6c6a19e6]45#include <smp/ipi.h>
[e2b762ec]46#include <symtab.h>
47
[da1bafb]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
[4e49572]56typedef struct {
[da1bafb]57 uintptr_t address; /**< Breakpoint address */
58 unsigned int flags; /**< Flags regarding breakpoint */
59 size_t counter; /**< How many times the exception occured */
[4e49572]60} bpinfo_t;
61
62static bpinfo_t breakpoints[BKPOINTS_MAX];
[da1bafb]63IRQ_SPINLOCK_STATIC_INITIALIZE(bkpoint_lock);
[4e49572]64
[76fca31]65#ifdef CONFIG_KCONSOLE
66
[da1bafb]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
[4e49572]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};
[da1bafb]81
[4e49572]82static cmd_info_t delbkpt_info = {
83 .name = "delbkpt",
[da1bafb]84 .description = "Delete breakpoint.",
[4e49572]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};
[da1bafb]93
[4e49572]94static cmd_info_t addbkpt_info = {
95 .name = "addbkpt",
[da1bafb]96 .description = "Add breakpoint.",
[4e49572]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};
[da1bafb]105
[4e49572]106static cmd_info_t addwatchp_info = {
107 .name = "addwatchp",
[da1bafb]108 .description = "Add write watchpoint.",
[4e49572]109 .func = cmd_add_breakpoint,
110 .argc = 1,
111 .argv = &addw_argv
112};
113
[76fca31]114#endif /* CONFIG_KCONSOLE */
[4e49572]115
[da1bafb]116/** Setup DR register according to table
117 *
118 */
[6c6a19e6]119static void setup_dr(int curidx)
120{
[da1bafb]121 ASSERT(curidx >= 0);
122
[6c6a19e6]123 bpinfo_t *cur = &breakpoints[curidx];
[da1bafb]124 unsigned int flags = breakpoints[curidx].flags;
125
[6c6a19e6]126 /* Disable breakpoint in DR7 */
[96b02eb9]127 sysarg_t dr7 = read_dr7();
[dc0b964]128 dr7 &= ~(0x02U << (curidx * 2));
[da1bafb]129
130 /* Setup DR register */
131 if (cur->address) {
[6c6a19e6]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 }
[da1bafb]147
[6c6a19e6]148 /* Set type to requested breakpoint & length*/
[dc0b964]149 dr7 &= ~(0x03U << (16 + 4 * curidx));
150 dr7 &= ~(0x03U << (18 + 4 * curidx));
[f4c2b6a]151
[da1bafb]152 if (!(flags & BKPOINT_INSTR)) {
[f4c2b6a]153#ifdef __32_BITS__
[96b02eb9]154 dr7 |= ((sysarg_t) 0x03U) << (18 + 4 * curidx);
[f4c2b6a]155#endif
[da1bafb]156
[f4c2b6a]157#ifdef __64_BITS__
[96b02eb9]158 dr7 |= ((sysarg_t) 0x02U) << (18 + 4 * curidx);
[f4c2b6a]159#endif
[6c6a19e6]160
161 if ((flags & BKPOINT_WRITE))
[96b02eb9]162 dr7 |= ((sysarg_t) 0x01U) << (16 + 4 * curidx);
[6c6a19e6]163 else if ((flags & BKPOINT_READ_WRITE))
[96b02eb9]164 dr7 |= ((sysarg_t) 0x03U) << (16 + 4 * curidx);
[6c6a19e6]165 }
[da1bafb]166
[6c6a19e6]167 /* Enable global breakpoint */
[dc0b964]168 dr7 |= 0x02U << (curidx * 2);
[6c6a19e6]169
[da1bafb]170 write_dr7(dr7);
171 }
[6c6a19e6]172}
[da1bafb]173
[4e49572]174/** Enable hardware breakpoint
175 *
176 * @param where Address of HW breakpoint
177 * @param flags Type of breakpoint (EXECUTE, WRITE)
[da1bafb]178 *
[4e49572]179 * @return Debug slot on success, -1 - no available HW breakpoint
[da1bafb]180 *
[4e49572]181 */
[da1bafb]182int breakpoint_add(const void *where, const unsigned int flags, int curidx)
[4e49572]183{
[7f043c0]184 ASSERT(flags & (BKPOINT_INSTR | BKPOINT_WRITE | BKPOINT_READ_WRITE));
[da1bafb]185
186 irq_spinlock_lock(&bkpoint_lock, true);
[4e49572]187
[6c6a19e6]188 if (curidx == -1) {
189 /* Find free space in slots */
[da1bafb]190 unsigned int i;
191 for (i = 0; i < BKPOINTS_MAX; i++) {
[6c6a19e6]192 if (!breakpoints[i].address) {
193 curidx = i;
194 break;
195 }
[da1bafb]196 }
197
[6c6a19e6]198 if (curidx == -1) {
199 /* Too many breakpoints */
[da1bafb]200 irq_spinlock_unlock(&bkpoint_lock, true);
[6c6a19e6]201 return -1;
[4e49572]202 }
203 }
[da1bafb]204
205 bpinfo_t *cur = &breakpoints[curidx];
206
[7f1c620]207 cur->address = (uintptr_t) where;
[4e49572]208 cur->flags = flags;
209 cur->counter = 0;
[da1bafb]210
[6c6a19e6]211 setup_dr(curidx);
[da1bafb]212
213 irq_spinlock_unlock(&bkpoint_lock, true);
214
[6c6a19e6]215 /* Send IPI */
[6da1013f]216// ipi_broadcast(VECTOR_DEBUG_IPI);
[da1bafb]217
[4e49572]218 return curidx;
219}
220
221static void handle_exception(int slot, istate_t *istate)
222{
[da1bafb]223 ASSERT(slot >= 0);
[4e49572]224 ASSERT(breakpoints[slot].address);
[da1bafb]225
[4e49572]226 /* Handle zero checker */
[da1bafb]227 if (!(breakpoints[slot].flags & BKPOINT_INSTR)) {
[4e49572]228 if ((breakpoints[slot].flags & BKPOINT_CHECK_ZERO)) {
[96b02eb9]229 if (*((sysarg_t *) breakpoints[slot].address) != 0)
[4e49572]230 return;
[da1bafb]231
[7e752b2]232 printf("*** Found ZERO on address %p (slot %d) ***\n",
233 (void *) breakpoints[slot].address, slot);
[4e49572]234 } else {
[7e752b2]235 printf("Data watchpoint - new data: %#" PRIxn "\n",
[96b02eb9]236 *((sysarg_t *) breakpoints[slot].address));
[4e49572]237 }
238 }
[da1bafb]239
[7e752b2]240 printf("Reached breakpoint %d:%p (%s)\n", slot,
241 (void *) getip(istate), symtab_fmt_name_lookup(getip(istate)));
[da1bafb]242
[76fca31]243#ifdef CONFIG_KCONSOLE
244 atomic_set(&haltstate, 1);
[0b6eba5]245 kconsole("debug", "Debug console ready.\n", false);
[76fca31]246 atomic_set(&haltstate, 0);
247#endif
[4e49572]248}
249
250void breakpoint_del(int slot)
251{
[da1bafb]252 ASSERT(slot >= 0);
253
254 irq_spinlock_lock(&bkpoint_lock, true);
255
256 bpinfo_t *cur = &breakpoints[slot];
[4e49572]257 if (!cur->address) {
[da1bafb]258 irq_spinlock_unlock(&bkpoint_lock, true);
[4e49572]259 return;
260 }
[da1bafb]261
[0b4a67a]262 cur->address = (uintptr_t) NULL;
[da1bafb]263
[6c6a19e6]264 setup_dr(slot);
[da1bafb]265
266 irq_spinlock_unlock(&bkpoint_lock, true);
[26d3ae2]267// ipi_broadcast(VECTOR_DEBUG_IPI);
[4e49572]268}
269
[214ec25c]270static void debug_exception(unsigned int n __attribute__((unused)), istate_t *istate)
[6c6a19e6]271{
272 /* Set RF to restart the instruction */
[6da1013f]273#ifdef __64_BITS__
[6c6a19e6]274 istate->rflags |= RFLAGS_RF;
[da1bafb]275#endif
276
277#ifdef __32_BITS__
[6c6a19e6]278 istate->eflags |= EFLAGS_RF;
279#endif
[da1bafb]280
[96b02eb9]281 sysarg_t dr6 = read_dr6();
[da1bafb]282
283 unsigned int i;
284 for (i = 0; i < BKPOINTS_MAX; i++) {
[6c6a19e6]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
[214ec25c]295static void debug_ipi(unsigned int n __attribute__((unused)),
[d7c9fcb]296 istate_t *istate __attribute__((unused)))
[6c6a19e6]297{
[da1bafb]298 irq_spinlock_lock(&bkpoint_lock, false);
299
300 unsigned int i;
[7f043c0]301 for (i = 0; i < BKPOINTS_MAX; i++)
[6c6a19e6]302 setup_dr(i);
[da1bafb]303
304 irq_spinlock_unlock(&bkpoint_lock, false);
[6c6a19e6]305}
[da1bafb]306#endif /* CONFIG_SMP */
[4e49572]307
[da1bafb]308/** Initialize debugger
309 *
310 */
[4e49572]311void debugger_init()
312{
[da1bafb]313 unsigned int i;
[d7c9fcb]314 for (i = 0; i < BKPOINTS_MAX; i++)
[0b4a67a]315 breakpoints[i].address = (uintptr_t) NULL;
[da1bafb]316
[76fca31]317#ifdef CONFIG_KCONSOLE
[4e49572]318 cmd_initialize(&bkpts_info);
319 if (!cmd_register(&bkpts_info))
[76fca31]320 printf("Cannot register command %s\n", bkpts_info.name);
[da1bafb]321
[4e49572]322 cmd_initialize(&delbkpt_info);
323 if (!cmd_register(&delbkpt_info))
[76fca31]324 printf("Cannot register command %s\n", delbkpt_info.name);
[da1bafb]325
[4e49572]326 cmd_initialize(&addbkpt_info);
327 if (!cmd_register(&addbkpt_info))
[76fca31]328 printf("Cannot register command %s\n", addbkpt_info.name);
[da1bafb]329
[4e49572]330 cmd_initialize(&addwatchp_info);
331 if (!cmd_register(&addwatchp_info))
[76fca31]332 printf("Cannot register command %s\n", addwatchp_info.name);
333#endif /* CONFIG_KCONSOLE */
[4e49572]334
[b3b7e14a]335 exc_register(VECTOR_DEBUG, "debugger", true,
336 debug_exception);
337
[6c6a19e6]338#ifdef CONFIG_SMP
[b3b7e14a]339 exc_register(VECTOR_DEBUG_IPI, "debugger_smp", true,
340 debug_ipi);
[da1bafb]341#endif /* CONFIG_SMP */
[4e49572]342}
[b45c443]343
[76fca31]344#ifdef CONFIG_KCONSOLE
[da1bafb]345/** Print table of active breakpoints
346 *
347 */
[76fca31]348int cmd_print_breakpoints(cmd_arg_t *argv __attribute__((unused)))
349{
[6da1013f]350#ifdef __32_BITS__
[ccb426c]351 printf("[nr] [count] [address ] [in symbol\n");
[76fca31]352#endif
[da1bafb]353
[76fca31]354#ifdef __64_BITS__
[ccb426c]355 printf("[nr] [count] [address ] [in symbol\n");
[76fca31]356#endif
357
[da1bafb]358 unsigned int i;
359 for (i = 0; i < BKPOINTS_MAX; i++) {
[76fca31]360 if (breakpoints[i].address) {
[a000878c]361 const char *symbol = symtab_fmt_name_lookup(
[e16e0d59]362 breakpoints[i].address);
[da1bafb]363
[76fca31]364#ifdef __32_BITS__
[7e752b2]365 printf("%-4u %7zu %p %s\n", i,
366 breakpoints[i].counter, (void *) breakpoints[i].address,
[76fca31]367 symbol);
368#endif
[da1bafb]369
[76fca31]370#ifdef __64_BITS__
[7e752b2]371 printf("%-4u %7zu %p %s\n", i,
372 breakpoints[i].counter, (void *) breakpoints[i].address,
[76fca31]373 symbol);
374#endif
375 }
[da1bafb]376 }
377
[76fca31]378 return 1;
379}
380
[da1bafb]381/** Remove breakpoint from table
382 *
383 */
[76fca31]384int cmd_del_breakpoint(cmd_arg_t *argv)
385{
[96b02eb9]386 sysarg_t bpno = argv->intval;
[76fca31]387 if (bpno > BKPOINTS_MAX) {
388 printf("Invalid breakpoint number.\n");
389 return 0;
390 }
[da1bafb]391
[76fca31]392 breakpoint_del(argv->intval);
393 return 1;
394}
395
[da1bafb]396/** Add new breakpoint to table
397 *
398 */
[76fca31]399static int cmd_add_breakpoint(cmd_arg_t *argv)
400{
[da1bafb]401 unsigned int flags;
402 if (argv == &add_argv)
[76fca31]403 flags = BKPOINT_INSTR;
[da1bafb]404 else
[76fca31]405 flags = BKPOINT_WRITE;
[da1bafb]406
[7e752b2]407 printf("Adding breakpoint on address: %p\n",
408 (void *) argv->intval);
[da1bafb]409
[7e752b2]410 int id = breakpoint_add((void *) argv->intval, flags, -1);
[76fca31]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
[06e1e95]420/** @}
[b45c443]421 */
Note: See TracBrowser for help on using the repository browser.