1 /* $NetBSD: db_break.c,v 1.25 2007/02/22 04:38:04 matt Exp $ */
4 * Mach Operating System
5 * Copyright (c) 1991,1990 Carnegie Mellon University
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation.
14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 * Carnegie Mellon requests users of this software to return to
20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
25 * any improvements or extensions that they make and grant Carnegie the
26 * rights to redistribute these changes.
28 * Author: David B. Golub, Carnegie Mellon University
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: db_break.c,v 1.25 2007/02/22 04:38:04 matt Exp $");
39 #include <sys/param.h>
42 #include <machine/db_machdep.h> /* type definitions */
44 #include <ddb/db_lex.h>
45 #include <ddb/db_access.h>
46 #include <ddb/db_sym.h>
47 #include <ddb/db_break.h>
48 #include <ddb/db_output.h>
50 #define NBREAKPOINTS 100
51 static struct db_breakpoint db_break_table
[NBREAKPOINTS
];
52 static db_breakpoint_t db_next_free_breakpoint
= &db_break_table
[0];
53 static db_breakpoint_t db_free_breakpoints
= 0;
54 static db_breakpoint_t db_breakpoint_list
= 0;
56 static db_breakpoint_t
db_breakpoint_alloc(void);
57 static void db_breakpoint_free(db_breakpoint_t
);
58 static void db_delete_breakpoint(struct vm_map
*, db_addr_t
);
59 static db_breakpoint_t
db_find_breakpoint(struct vm_map
*, db_addr_t
);
60 static void db_list_breakpoints(void);
61 static void db_set_breakpoint(struct vm_map
*, db_addr_t
, int);
63 static db_breakpoint_t
64 db_breakpoint_alloc(void)
68 if ((bkpt
= db_free_breakpoints
) != 0) {
69 db_free_breakpoints
= bkpt
->link
;
72 if (db_next_free_breakpoint
== &db_break_table
[NBREAKPOINTS
]) {
73 db_printf("All breakpoints used.\n");
76 bkpt
= db_next_free_breakpoint
;
77 db_next_free_breakpoint
++;
83 db_breakpoint_free(db_breakpoint_t bkpt
)
85 bkpt
->link
= db_free_breakpoints
;
86 db_free_breakpoints
= bkpt
;
90 db_set_breakpoint(struct vm_map
*map
, db_addr_t addr
, int count
)
94 if (db_find_breakpoint(map
, addr
)) {
95 db_printf("Already set.\n");
99 bkpt
= db_breakpoint_alloc();
101 db_printf("Too many breakpoints.\n");
106 bkpt
->address
= BKPT_ADDR(addr
);
108 bkpt
->init_count
= count
;
111 bkpt
->link
= db_breakpoint_list
;
112 db_breakpoint_list
= bkpt
;
116 db_delete_breakpoint(struct vm_map
*map
, db_addr_t addr
)
118 db_breakpoint_t bkpt
;
119 db_breakpoint_t
*prev
;
121 for (prev
= &db_breakpoint_list
;
123 prev
= &bkpt
->link
) {
124 if (db_map_equal(bkpt
->map
, map
) &&
125 (bkpt
->address
== BKPT_ADDR(addr
))) {
131 db_printf("Not set.\n");
135 db_breakpoint_free(bkpt
);
139 db_find_breakpoint(struct vm_map
*map
, db_addr_t addr
)
141 db_breakpoint_t bkpt
;
143 for (bkpt
= db_breakpoint_list
;
146 if (db_map_equal(bkpt
->map
, map
) &&
147 (bkpt
->address
== BKPT_ADDR(addr
)))
154 db_find_breakpoint_here(db_addr_t addr
)
156 return db_find_breakpoint(db_map_addr(addr
), addr
);
159 static bool db_breakpoints_inserted
= true;
162 db_set_breakpoints(void)
164 db_breakpoint_t bkpt
;
166 if (!db_breakpoints_inserted
) {
168 for (bkpt
= db_breakpoint_list
;
171 if (db_map_current(bkpt
->map
)) {
172 bkpt
->bkpt_inst
= db_get_value(bkpt
->address
,
174 db_put_value(bkpt
->address
,
176 BKPT_SET(bkpt
->bkpt_inst
, bkpt
->address
));
178 db_breakpoints_inserted
= true;
183 db_clear_breakpoints(void)
185 db_breakpoint_t bkpt
;
187 if (db_breakpoints_inserted
) {
189 for (bkpt
= db_breakpoint_list
;
192 if (db_map_current(bkpt
->map
))
193 db_put_value(bkpt
->address
, BKPT_SIZE
,
195 db_breakpoints_inserted
= false;
203 db_list_breakpoints(void)
205 db_breakpoint_t bkpt
;
207 if (db_breakpoint_list
== 0) {
208 db_printf("No breakpoints set\n");
212 db_printf(" Map Count Address\n");
213 for (bkpt
= db_breakpoint_list
;
216 db_printf("%s%p %5d ",
217 db_map_current(bkpt
->map
) ? "*" : " ",
218 bkpt
->map
, bkpt
->init_count
);
219 db_printsym(bkpt
->address
, DB_STGY_PROC
, db_printf
);
224 /* Delete breakpoint */
227 db_delete_cmd(db_expr_t addr
, bool have_addr
, db_expr_t count
,
231 db_delete_breakpoint(db_map_addr(addr
), (db_addr_t
)addr
);
234 /* Set breakpoint with skip count */
237 db_breakpoint_cmd(db_expr_t addr
, bool have_addr
, db_expr_t count
,
244 db_set_breakpoint(db_map_addr(addr
), (db_addr_t
)addr
, count
);
247 /* list breakpoints */
250 db_listbreak_cmd(db_expr_t addr
, bool have_addr
,
251 db_expr_t count
, const char *modif
)
254 db_list_breakpoints();
257 #include <uvm/uvm_extern.h>
260 * We want ddb to be usable before most of the kernel has been
261 * initialized. In particular, current_thread() or kernel_map
262 * (or both) may be null.
266 db_map_equal(struct vm_map
*map1
, struct vm_map
*map2
)
269 return ((map1
== map2
) ||
270 ((map1
== NULL
) && (map2
== kernel_map
)) ||
271 ((map1
== kernel_map
) && (map2
== NULL
)));
275 db_map_current(struct vm_map
*map
)
280 return ((map
== NULL
) ||
281 (map
== kernel_map
) ||
282 (((thread
= current_thread()) != NULL
) &&
283 (map
== thread
->task
->map
)));
291 db_map_addr(vaddr_t addr
)
297 * We want to return kernel_map for all
298 * non-user addresses, even when debugging
299 * kernel tasks with their own maps.
302 if ((VM_MIN_ADDRESS
<= addr
) && (addr
< VM_MAX_ADDRESS
) &&
303 ((thread
= current_thread()) != NULL
))
304 return thread
->task
->map
;