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