db_break.c revision 1.1.1.1 1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie the
24 * rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: db_break.c,v $
29 * Revision 1.1.1.1 1993/03/21 09:45:37 cgd
30 * initial import of 386bsd-0.1 sources
31 *
32 * Revision 1.1 1992/03/25 21:44:57 pace
33 * Initial revision
34 *
35 * Revision 2.7 91/02/05 17:06:00 mrt
36 * Changed to new Mach copyright
37 * [91/01/31 16:17:01 mrt]
38 *
39 * Revision 2.6 91/01/08 15:09:03 rpd
40 * Added db_map_equal, db_map_current, db_map_addr.
41 * [90/11/10 rpd]
42 *
43 * Revision 2.5 90/11/05 14:26:32 rpd
44 * Initialize db_breakpoints_inserted to TRUE.
45 * [90/11/04 rpd]
46 *
47 * Revision 2.4 90/10/25 14:43:33 rwd
48 * Added map field to breakpoints.
49 * Added map argument to db_set_breakpoint, db_delete_breakpoint,
50 * db_find_breakpoint. Added db_find_breakpoint_here.
51 * [90/10/18 rpd]
52 *
53 * Revision 2.3 90/09/28 16:57:07 jsb
54 * Fixed db_breakpoint_free.
55 * [90/09/18 rpd]
56 *
57 * Revision 2.2 90/08/27 21:49:53 dbg
58 * Reflected changes in db_printsym()'s calling seq.
59 * [90/08/20 af]
60 * Clear breakpoints only if inserted.
61 * Reduce lint.
62 * [90/08/07 dbg]
63 * Created.
64 * [90/07/25 dbg]
65 *
66 */
67 /*
68 * Author: David B. Golub, Carnegie Mellon University
69 * Date: 7/90
70 */
71 /*
72 * Breakpoints.
73 */
74 #include "param.h"
75 #include "proc.h"
76 #include <machine/db_machdep.h> /* type definitions */
77
78 #include <ddb/db_lex.h>
79 #include <ddb/db_break.h>
80 #include <ddb/db_access.h>
81 #include <ddb/db_sym.h>
82 #include <ddb/db_break.h>
83
84 extern boolean_t db_map_equal();
85 extern boolean_t db_map_current();
86 extern vm_map_t db_map_addr();
87
88 #define NBREAKPOINTS 100
89 struct db_breakpoint db_break_table[NBREAKPOINTS];
90 db_breakpoint_t db_next_free_breakpoint = &db_break_table[0];
91 db_breakpoint_t db_free_breakpoints = 0;
92 db_breakpoint_t db_breakpoint_list = 0;
93
94 db_breakpoint_t
95 db_breakpoint_alloc()
96 {
97 register db_breakpoint_t bkpt;
98
99 if ((bkpt = db_free_breakpoints) != 0) {
100 db_free_breakpoints = bkpt->link;
101 return (bkpt);
102 }
103 if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
104 db_printf("All breakpoints used.\n");
105 return (0);
106 }
107 bkpt = db_next_free_breakpoint;
108 db_next_free_breakpoint++;
109
110 return (bkpt);
111 }
112
113 void
114 db_breakpoint_free(bkpt)
115 register db_breakpoint_t bkpt;
116 {
117 bkpt->link = db_free_breakpoints;
118 db_free_breakpoints = bkpt;
119 }
120
121 void
122 db_set_breakpoint(map, addr, count)
123 vm_map_t map;
124 db_addr_t addr;
125 int count;
126 {
127 register db_breakpoint_t bkpt;
128
129 if (db_find_breakpoint(map, addr)) {
130 db_printf("Already set.\n");
131 return;
132 }
133
134 bkpt = db_breakpoint_alloc();
135 if (bkpt == 0) {
136 db_printf("Too many breakpoints.\n");
137 return;
138 }
139
140 bkpt->map = map;
141 bkpt->address = addr;
142 bkpt->flags = 0;
143 bkpt->init_count = count;
144 bkpt->count = count;
145
146 bkpt->link = db_breakpoint_list;
147 db_breakpoint_list = bkpt;
148 }
149
150 void
151 db_delete_breakpoint(map, addr)
152 vm_map_t map;
153 db_addr_t addr;
154 {
155 register db_breakpoint_t bkpt;
156 register db_breakpoint_t *prev;
157
158 for (prev = &db_breakpoint_list;
159 (bkpt = *prev) != 0;
160 prev = &bkpt->link) {
161 if (db_map_equal(bkpt->map, map) &&
162 (bkpt->address == addr)) {
163 *prev = bkpt->link;
164 break;
165 }
166 }
167 if (bkpt == 0) {
168 db_printf("Not set.\n");
169 return;
170 }
171
172 db_breakpoint_free(bkpt);
173 }
174
175 db_breakpoint_t
176 db_find_breakpoint(map, addr)
177 vm_map_t map;
178 db_addr_t addr;
179 {
180 register db_breakpoint_t bkpt;
181
182 for (bkpt = db_breakpoint_list;
183 bkpt != 0;
184 bkpt = bkpt->link)
185 {
186 if (db_map_equal(bkpt->map, map) &&
187 (bkpt->address == addr))
188 return (bkpt);
189 }
190 return (0);
191 }
192
193 db_breakpoint_t
194 db_find_breakpoint_here(addr)
195 db_addr_t addr;
196 {
197 return db_find_breakpoint(db_map_addr(addr), addr);
198 }
199
200 boolean_t db_breakpoints_inserted = TRUE;
201
202 void
203 db_set_breakpoints()
204 {
205 register db_breakpoint_t bkpt;
206
207 if (!db_breakpoints_inserted) {
208
209 for (bkpt = db_breakpoint_list;
210 bkpt != 0;
211 bkpt = bkpt->link)
212 if (db_map_current(bkpt->map)) {
213 bkpt->bkpt_inst = db_get_value(bkpt->address,
214 BKPT_SIZE,
215 FALSE);
216 db_put_value(bkpt->address,
217 BKPT_SIZE,
218 BKPT_SET(bkpt->bkpt_inst));
219 }
220 db_breakpoints_inserted = TRUE;
221 }
222 }
223
224 void
225 db_clear_breakpoints()
226 {
227 register db_breakpoint_t bkpt;
228
229 if (db_breakpoints_inserted) {
230
231 for (bkpt = db_breakpoint_list;
232 bkpt != 0;
233 bkpt = bkpt->link)
234 if (db_map_current(bkpt->map)) {
235 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
236 }
237 db_breakpoints_inserted = FALSE;
238 }
239 }
240
241 /*
242 * Set a temporary breakpoint.
243 * The instruction is changed immediately,
244 * so the breakpoint does not have to be on the breakpoint list.
245 */
246 db_breakpoint_t
247 db_set_temp_breakpoint(addr)
248 db_addr_t addr;
249 {
250 register db_breakpoint_t bkpt;
251
252 bkpt = db_breakpoint_alloc();
253 if (bkpt == 0) {
254 db_printf("Too many breakpoints.\n");
255 return 0;
256 }
257
258 bkpt->map = NULL;
259 bkpt->address = addr;
260 bkpt->flags = BKPT_TEMP;
261 bkpt->init_count = 1;
262 bkpt->count = 1;
263
264 bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
265 db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
266 return bkpt;
267 }
268
269 void
270 db_delete_temp_breakpoint(bkpt)
271 db_breakpoint_t bkpt;
272 {
273 db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
274 db_breakpoint_free(bkpt);
275 }
276
277 /*
278 * List breakpoints.
279 */
280 void
281 db_list_breakpoints()
282 {
283 register db_breakpoint_t bkpt;
284
285 if (db_breakpoint_list == 0) {
286 db_printf("No breakpoints set\n");
287 return;
288 }
289
290 db_printf(" Map Count Address\n");
291 for (bkpt = db_breakpoint_list;
292 bkpt != 0;
293 bkpt = bkpt->link)
294 {
295 db_printf("%s%8x %5d ",
296 db_map_current(bkpt->map) ? "*" : " ",
297 bkpt->map, bkpt->init_count);
298 db_printsym(bkpt->address, DB_STGY_PROC);
299 db_printf("\n");
300 }
301 }
302
303 /* Delete breakpoint */
304 /*ARGSUSED*/
305 void
306 db_delete_cmd(addr, have_addr, count, modif)
307 db_expr_t addr;
308 int have_addr;
309 db_expr_t count;
310 char * modif;
311 {
312 db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr);
313 }
314
315 /* Set breakpoint with skip count */
316 /*ARGSUSED*/
317 void
318 db_breakpoint_cmd(addr, have_addr, count, modif)
319 db_expr_t addr;
320 int have_addr;
321 db_expr_t count;
322 char * modif;
323 {
324 if (count == -1)
325 count = 1;
326
327 db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count);
328 }
329
330 /* list breakpoints */
331 void
332 db_listbreak_cmd()
333 {
334 db_list_breakpoints();
335 }
336
337 #include <vm/vm_kern.h>
338
339 /*
340 * We want ddb to be usable before most of the kernel has been
341 * initialized. In particular, current_thread() or kernel_map
342 * (or both) may be null.
343 */
344
345 boolean_t
346 db_map_equal(map1, map2)
347 vm_map_t map1, map2;
348 {
349 return ((map1 == map2) ||
350 ((map1 == NULL) && (map2 == kernel_map)) ||
351 ((map1 == kernel_map) && (map2 == NULL)));
352 }
353
354 boolean_t
355 db_map_current(map)
356 vm_map_t map;
357 {
358 #if 0
359 thread_t thread;
360
361 return ((map == NULL) ||
362 (map == kernel_map) ||
363 (((thread = current_thread()) != NULL) &&
364 (map == thread->task->map)));
365 #else
366 return (1);
367 #endif
368 }
369
370 vm_map_t
371 db_map_addr(addr)
372 vm_offset_t addr;
373 {
374 #if 0
375 thread_t thread;
376
377 /*
378 * We want to return kernel_map for all
379 * non-user addresses, even when debugging
380 * kernel tasks with their own maps.
381 */
382
383 if ((VM_MIN_ADDRESS <= addr) &&
384 (addr < VM_MAX_ADDRESS) &&
385 ((thread = current_thread()) != NULL))
386 return thread->task->map;
387 else
388 #endif
389 return kernel_map;
390 }
391