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