db_break.c revision 8876
1168404Spjd/*
2168404Spjd * Mach Operating System
3168404Spjd * Copyright (c) 1991,1990 Carnegie Mellon University
4168404Spjd * All Rights Reserved.
5168404Spjd *
6168404Spjd * Permission to use, copy, modify and distribute this software and its
7168404Spjd * documentation is hereby granted, provided that both the copyright
8168404Spjd * notice and this permission notice appear in all copies of the
9168404Spjd * software, derivative works or modified versions, and any portions
10168404Spjd * thereof, and that both notices appear in supporting documentation.
11168404Spjd *
12168404Spjd * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13168404Spjd * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14168404Spjd * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15168404Spjd *
16168404Spjd * Carnegie Mellon requests users of this software to return to
17168404Spjd *
18168404Spjd *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19168404Spjd *  School of Computer Science
20168404Spjd *  Carnegie Mellon University
21168404Spjd *  Pittsburgh PA 15213-3890
22208373Smm *
23168404Spjd * any improvements or extensions that they make and grant Carnegie the
24168404Spjd * rights to redistribute these changes.
25168404Spjd *
26168404Spjd *	$Id: db_break.c,v 1.5 1994/08/18 22:34:19 wollman Exp $
27168404Spjd */
28168404Spjd
29168404Spjd/*
30168404Spjd *	Author: David B. Golub, Carnegie Mellon University
31168404Spjd *	Date:	7/90
32168404Spjd */
33168404Spjd/*
34168404Spjd * Breakpoints.
35168404Spjd */
36168404Spjd#include <sys/param.h>
37168404Spjd#include <sys/systm.h>
38168404Spjd#include <sys/proc.h>
39168404Spjd#include <ddb/ddb.h>
40168404Spjd
41168404Spjd#include <ddb/db_lex.h>
42168404Spjd#include <ddb/db_break.h>
43168404Spjd#include <ddb/db_access.h>
44168404Spjd#include <ddb/db_sym.h>
45168404Spjd#include <ddb/db_break.h>
46168404Spjd
47168404Spjd#define	NBREAKPOINTS	100
48185029Spjdstruct db_breakpoint	db_break_table[NBREAKPOINTS];
49185029Spjddb_breakpoint_t		db_next_free_breakpoint = &db_break_table[0];
50168404Spjddb_breakpoint_t		db_free_breakpoints = 0;
51168404Spjddb_breakpoint_t		db_breakpoint_list = 0;
52168404Spjd
53168404Spjddb_breakpoint_t
54185029Spjddb_breakpoint_alloc()
55168404Spjd{
56168404Spjd	register db_breakpoint_t	bkpt;
57168404Spjd
58168404Spjd	if ((bkpt = db_free_breakpoints) != 0) {
59168404Spjd	    db_free_breakpoints = bkpt->link;
60168404Spjd	    return (bkpt);
61168404Spjd	}
62168404Spjd	if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
63168404Spjd	    db_printf("All breakpoints used.\n");
64168404Spjd	    return (0);
65168404Spjd	}
66168404Spjd	bkpt = db_next_free_breakpoint;
67168404Spjd	db_next_free_breakpoint++;
68168404Spjd
69168404Spjd	return (bkpt);
70168404Spjd}
71168404Spjd
72168404Spjdvoid
73168404Spjddb_breakpoint_free(bkpt)
74168404Spjd	register db_breakpoint_t	bkpt;
75168404Spjd{
76185029Spjd	bkpt->link = db_free_breakpoints;
77168404Spjd	db_free_breakpoints = bkpt;
78168404Spjd}
79168404Spjd
80168404Spjdvoid
81168404Spjddb_set_breakpoint(map, addr, count)
82168404Spjd	vm_map_t	map;
83168404Spjd	db_addr_t	addr;
84168404Spjd	int		count;
85168404Spjd{
86168404Spjd	register db_breakpoint_t	bkpt;
87168404Spjd
88168404Spjd	if (db_find_breakpoint(map, addr)) {
89168404Spjd	    db_printf("Already set.\n");
90168404Spjd	    return;
91168404Spjd	}
92168404Spjd
93168404Spjd	bkpt = db_breakpoint_alloc();
94168404Spjd	if (bkpt == 0) {
95168404Spjd	    db_printf("Too many breakpoints.\n");
96168404Spjd	    return;
97168404Spjd	}
98168404Spjd
99168404Spjd	bkpt->map = map;
100168404Spjd	bkpt->address = addr;
101168404Spjd	bkpt->flags = 0;
102168404Spjd	bkpt->init_count = count;
103168404Spjd	bkpt->count = count;
104168404Spjd
105168404Spjd	bkpt->link = db_breakpoint_list;
106168404Spjd	db_breakpoint_list = bkpt;
107168404Spjd}
108168404Spjd
109168404Spjdvoid
110185029Spjddb_delete_breakpoint(map, addr)
111185029Spjd	vm_map_t	map;
112185029Spjd	db_addr_t	addr;
113185029Spjd{
114185029Spjd	register db_breakpoint_t	bkpt;
115185029Spjd	register db_breakpoint_t	*prev;
116185029Spjd
117185029Spjd	for (prev = &db_breakpoint_list;
118168404Spjd	     (bkpt = *prev) != 0;
119168404Spjd	     prev = &bkpt->link) {
120168404Spjd	    if (db_map_equal(bkpt->map, map) &&
121168404Spjd		(bkpt->address == addr)) {
122168404Spjd		*prev = bkpt->link;
123168404Spjd		break;
124168404Spjd	    }
125168404Spjd	}
126185029Spjd	if (bkpt == 0) {
127168404Spjd	    db_printf("Not set.\n");
128168404Spjd	    return;
129168404Spjd	}
130168404Spjd
131168404Spjd	db_breakpoint_free(bkpt);
132168404Spjd}
133168404Spjd
134191902Skmacydb_breakpoint_t
135191902Skmacydb_find_breakpoint(map, addr)
136168404Spjd	vm_map_t	map;
137168404Spjd	db_addr_t	addr;
138168404Spjd{
139168404Spjd	register db_breakpoint_t	bkpt;
140185029Spjd
141185029Spjd	for (bkpt = db_breakpoint_list;
142185029Spjd	     bkpt != 0;
143185029Spjd	     bkpt = bkpt->link)
144168404Spjd	{
145168404Spjd	    if (db_map_equal(bkpt->map, map) &&
146168404Spjd		(bkpt->address == addr))
147168404Spjd		return (bkpt);
148168404Spjd	}
149168404Spjd	return (0);
150168404Spjd}
151168404Spjd
152168404Spjddb_breakpoint_t
153168404Spjddb_find_breakpoint_here(addr)
154168404Spjd	db_addr_t	addr;
155208373Smm{
156208373Smm    return db_find_breakpoint(db_map_addr(addr), addr);
157208373Smm}
158208373Smm
159208373Smmboolean_t	db_breakpoints_inserted = TRUE;
160208373Smm
161168404Spjdvoid
162168404Spjddb_set_breakpoints()
163168404Spjd{
164168404Spjd	register db_breakpoint_t	bkpt;
165168404Spjd
166168404Spjd	if (!db_breakpoints_inserted) {
167208373Smm
168194043Skmacy	    for (bkpt = db_breakpoint_list;
169168404Spjd	         bkpt != 0;
170168404Spjd	         bkpt = bkpt->link)
171185029Spjd		if (db_map_current(bkpt->map)) {
172185029Spjd		    bkpt->bkpt_inst = db_get_value(bkpt->address,
173185029Spjd						   BKPT_SIZE,
174185029Spjd						   FALSE);
175185029Spjd		    db_put_value(bkpt->address,
176168404Spjd				 BKPT_SIZE,
177168404Spjd				 BKPT_SET(bkpt->bkpt_inst));
178185029Spjd		}
179185029Spjd	    db_breakpoints_inserted = TRUE;
180185029Spjd	}
181185029Spjd}
182208373Smm
183208373Smmvoid
184208373Smmdb_clear_breakpoints()
185185029Spjd{
186185029Spjd	register db_breakpoint_t	bkpt;
187185029Spjd
188185029Spjd	if (db_breakpoints_inserted) {
189185029Spjd
190168473Spjd	    for (bkpt = db_breakpoint_list;
191185029Spjd	         bkpt != 0;
192168473Spjd		 bkpt = bkpt->link)
193185029Spjd		if (db_map_current(bkpt->map)) {
194168473Spjd		    db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
195185029Spjd		}
196185029Spjd	    db_breakpoints_inserted = FALSE;
197168404Spjd	}
198168404Spjd}
199185029Spjd
200168404Spjd/*
201168404Spjd * Set a temporary breakpoint.
202168404Spjd * The instruction is changed immediately,
203168404Spjd * so the breakpoint does not have to be on the breakpoint list.
204168404Spjd */
205185029Spjddb_breakpoint_t
206185029Spjddb_set_temp_breakpoint(addr)
207185029Spjd	db_addr_t	addr;
208185029Spjd{
209185029Spjd	register db_breakpoint_t	bkpt;
210185029Spjd
211185029Spjd	bkpt = db_breakpoint_alloc();
212185029Spjd	if (bkpt == 0) {
213168404Spjd	    db_printf("Too many breakpoints.\n");
214168404Spjd	    return 0;
215168404Spjd	}
216168404Spjd
217168404Spjd	bkpt->map = NULL;
218168404Spjd	bkpt->address = addr;
219168404Spjd	bkpt->flags = BKPT_TEMP;
220185029Spjd	bkpt->init_count = 1;
221185029Spjd	bkpt->count = 1;
222185029Spjd
223185029Spjd	bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
224185029Spjd	db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
225185029Spjd	return bkpt;
226185029Spjd}
227185029Spjd
228168404Spjdvoid
229168404Spjddb_delete_temp_breakpoint(bkpt)
230205264Skmacy	db_breakpoint_t	bkpt;
231205231Skmacy{
232205231Skmacy	db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
233205231Skmacy	db_breakpoint_free(bkpt);
234205231Skmacy}
235205231Skmacy
236205231Skmacy/*
237205231Skmacy * List breakpoints.
238205231Skmacy */
239205231Skmacyvoid
240205231Skmacydb_list_breakpoints()
241205231Skmacy{
242205231Skmacy	register db_breakpoint_t	bkpt;
243205231Skmacy
244206796Spjd	if (db_breakpoint_list == 0) {
245205231Skmacy	    db_printf("No breakpoints set\n");
246168404Spjd	    return;
247185029Spjd	}
248185029Spjd
249205231Skmacy	db_printf(" Map      Count    Address\n");
250205264Skmacy	for (bkpt = db_breakpoint_list;
251168404Spjd	     bkpt != 0;
252168404Spjd	     bkpt = bkpt->link)
253206796Spjd	{
254205231Skmacy	    db_printf("%s%8x %5d    ",
255185029Spjd		      db_map_current(bkpt->map) ? "*" : " ",
256168404Spjd		      bkpt->map, bkpt->init_count);
257168404Spjd	    db_printsym(bkpt->address, DB_STGY_PROC);
258168404Spjd	    db_printf("\n");
259168404Spjd	}
260168404Spjd}
261185029Spjd
262168404Spjd/* Delete breakpoint */
263168404Spjd/*ARGSUSED*/
264168404Spjdvoid
265168404Spjddb_delete_cmd(addr, have_addr, count, modif)
266168404Spjd	db_expr_t	addr;
267168404Spjd	int		have_addr;
268168404Spjd	db_expr_t	count;
269168404Spjd	char *		modif;
270168404Spjd{
271168404Spjd	db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr);
272168404Spjd}
273168404Spjd
274168404Spjd/* Set breakpoint with skip count */
275168404Spjd/*ARGSUSED*/
276168404Spjdvoid
277168404Spjddb_breakpoint_cmd(addr, have_addr, count, modif)
278205231Skmacy	db_expr_t	addr;
279168404Spjd	int		have_addr;
280205231Skmacy	db_expr_t	count;
281168404Spjd	char *		modif;
282168404Spjd{
283168404Spjd	if (count == -1)
284208373Smm	    count = 1;
285208373Smm
286208373Smm	db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count);
287168404Spjd}
288168404Spjd
289168404Spjd/* list breakpoints */
290168404Spjdvoid
291168404Spjddb_listbreak_cmd(db_expr_t dummy1, int dummy2, db_expr_t dummy3, char *dummy4)
292168404Spjd{
293168404Spjd	db_list_breakpoints();
294168404Spjd}
295168404Spjd
296168404Spjd#include <vm/vm_kern.h>
297185029Spjd
298208373Smm/*
299208373Smm *	We want ddb to be usable before most of the kernel has been
300185029Spjd *	initialized.  In particular, current_thread() or kernel_map
301185029Spjd *	(or both) may be null.
302185029Spjd */
303185029Spjd
304208373Smmboolean_t
305208373Smmdb_map_equal(map1, map2)
306185029Spjd	vm_map_t	map1, map2;
307185029Spjd{
308185029Spjd	return ((map1 == map2) ||
309185029Spjd		((map1 == NULL) && (map2 == kernel_map)) ||
310185029Spjd		((map1 == kernel_map) && (map2 == NULL)));
311185029Spjd}
312185029Spjd
313185029Spjdboolean_t
314185029Spjddb_map_current(map)
315185029Spjd	vm_map_t	map;
316185029Spjd{
317185029Spjd#if 0
318185029Spjd	thread_t	thread;
319205231Skmacy
320205231Skmacy	return ((map == NULL) ||
321205231Skmacy		(map == kernel_map) ||
322206796Spjd		(((thread = current_thread()) != NULL) &&
323205231Skmacy		 (map == thread->task->map)));
324205231Skmacy#else
325205231Skmacy	return (1);
326205231Skmacy#endif
327205231Skmacy}
328205231Skmacy
329205231Skmacyvm_map_t
330205231Skmacydb_map_addr(addr)
331168404Spjd	vm_offset_t addr;
332168404Spjd{
333168404Spjd#if 0
334168404Spjd	thread_t	thread;
335168404Spjd
336168404Spjd	/*
337168404Spjd	 *	We want to return kernel_map for all
338168404Spjd	 *	non-user addresses, even when debugging
339168404Spjd	 *	kernel tasks with their own maps.
340168404Spjd	 */
341168404Spjd
342168404Spjd	if ((VM_MIN_ADDRESS <= addr) &&
343168404Spjd	    (addr < VM_MAX_ADDRESS) &&
344168404Spjd	    ((thread = current_thread()) != NULL))
345168404Spjd	    return thread->task->map;
346168404Spjd	else
347168404Spjd#endif
348205231Skmacy	    return kernel_map;
349168404Spjd}
350205231Skmacy