xref: /openbsd/sys/ddb/db_break.c (revision 1ac7f822)
1 /*	$OpenBSD: db_break.c,v 1.24 2024/11/05 10:19:11 miod Exp $	*/
2 /*	$NetBSD: db_break.c,v 1.7 1996/03/30 22:30:03 christos Exp $	*/
3 
4 /*
5  * Mach Operating System
6  * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
7  * All Rights Reserved.
8  *
9  * Permission to use, copy, modify and distribute this software and its
10  * documentation is hereby granted, provided that both the copyright
11  * notice and this permission notice appear in all copies of the
12  * software, derivative works or modified versions, and any portions
13  * thereof, and that both notices appear in supporting documentation.
14  *
15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18  *
19  * Carnegie Mellon requests users of this software to return to
20  *
21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22  *  School of Computer Science
23  *  Carnegie Mellon University
24  *  Pittsburgh PA 15213-3890
25  *
26  * any improvements or extensions that they make and grant Carnegie Mellon
27  * the rights to redistribute these changes.
28  *
29  *	Author: David B. Golub, Carnegie Mellon University
30  *	Date:	7/90
31  */
32 
33 /*
34  * Breakpoints.
35  */
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 
39 #include <machine/db_machdep.h>		/* type definitions */
40 
41 #include <ddb/db_access.h>
42 #include <ddb/db_sym.h>
43 #include <ddb/db_break.h>
44 #include <ddb/db_output.h>
45 
46 #define	NBREAKPOINTS	100
47 struct db_breakpoint	db_break_table[NBREAKPOINTS];
48 db_breakpoint_t		db_next_free_breakpoint = &db_break_table[0];
49 db_breakpoint_t		db_free_breakpoints = 0;
50 db_breakpoint_t		db_breakpoint_list = 0;
51 
52 db_breakpoint_t db_breakpoint_alloc(void);
53 void db_breakpoint_free(db_breakpoint_t);
54 void db_set_breakpoint(vaddr_t, int);
55 void db_delete_breakpoint(vaddr_t);
56 void db_list_breakpoints(void);
57 
58 db_breakpoint_t
db_breakpoint_alloc(void)59 db_breakpoint_alloc(void)
60 {
61 	db_breakpoint_t	bkpt;
62 
63 	if ((bkpt = db_free_breakpoints) != 0) {
64 		db_free_breakpoints = bkpt->link;
65 		return (bkpt);
66 	}
67 	if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
68 		db_printf("All breakpoints used.\n");
69 		return (0);
70 	}
71 	bkpt = db_next_free_breakpoint;
72 	db_next_free_breakpoint++;
73 
74 	return (bkpt);
75 }
76 
77 void
db_breakpoint_free(db_breakpoint_t bkpt)78 db_breakpoint_free(db_breakpoint_t bkpt)
79 {
80 	bkpt->link = db_free_breakpoints;
81 	db_free_breakpoints = bkpt;
82 }
83 
84 void
db_set_breakpoint(vaddr_t addr,int count)85 db_set_breakpoint(vaddr_t addr, int count)
86 {
87 	db_breakpoint_t	bkpt;
88 
89 	if (db_find_breakpoint(addr)) {
90 		db_printf("Already set.\n");
91 		return;
92 	}
93 
94 #ifdef DB_VALID_BREAKPOINT
95 	if (!DB_VALID_BREAKPOINT(addr)) {
96 		db_printf("Not a valid address for a breakpoint.\n");
97 		return;
98 	}
99 #endif
100 
101 	bkpt = db_breakpoint_alloc();
102 	if (bkpt == 0) {
103 		db_printf("Too many breakpoints.\n");
104 		return;
105 	}
106 
107 	bkpt->address = addr;
108 	bkpt->flags = 0;
109 	bkpt->init_count = count;
110 	bkpt->count = count;
111 
112 	bkpt->link = db_breakpoint_list;
113 	db_breakpoint_list = bkpt;
114 }
115 
116 void
db_delete_breakpoint(vaddr_t addr)117 db_delete_breakpoint(vaddr_t addr)
118 {
119 	db_breakpoint_t	bkpt;
120 	db_breakpoint_t	*prev;
121 
122 	for (prev = &db_breakpoint_list; (bkpt = *prev) != 0;
123 	    prev = &bkpt->link) {
124 		if (bkpt->address == addr) {
125 			*prev = bkpt->link;
126 			break;
127 		}
128 	}
129 	if (bkpt == 0) {
130 		db_printf("Not set.\n");
131 		return;
132 	}
133 
134 	db_breakpoint_free(bkpt);
135 }
136 
137 db_breakpoint_t
db_find_breakpoint(vaddr_t addr)138 db_find_breakpoint(vaddr_t addr)
139 {
140 	db_breakpoint_t	bkpt;
141 
142 	for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link)
143 		if (bkpt->address == addr)
144 			return (bkpt);
145 
146 	return (0);
147 }
148 
149 int db_breakpoints_inserted = 1;
150 
151 void
db_set_breakpoints(void)152 db_set_breakpoints(void)
153 {
154 	db_breakpoint_t	bkpt;
155 
156 	if (!db_breakpoints_inserted) {
157 		for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
158 			bkpt->bkpt_inst =
159 			    db_get_value(bkpt->address, BKPT_SIZE, 0);
160 			db_put_value(bkpt->address, BKPT_SIZE,
161 			    BKPT_SET(bkpt->bkpt_inst));
162 		}
163 		db_breakpoints_inserted = 1;
164 	}
165 }
166 
167 void
db_clear_breakpoints(void)168 db_clear_breakpoints(void)
169 {
170 	db_breakpoint_t	bkpt;
171 
172 	if (db_breakpoints_inserted) {
173 		for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link)
174 			db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
175 		db_breakpoints_inserted = 0;
176 	}
177 }
178 
179 /*
180  * Set a temporary breakpoint.
181  * The instruction is changed immediately,
182  * so the breakpoint does not have to be on the breakpoint list.
183  */
184 db_breakpoint_t
db_set_temp_breakpoint(vaddr_t addr)185 db_set_temp_breakpoint(vaddr_t addr)
186 {
187 	db_breakpoint_t	bkpt;
188 
189 #ifdef DB_VALID_BREAKPOINT
190 	if (!DB_VALID_BREAKPOINT(addr)) {
191 		db_printf("Not a valid address for a breakpoint.\n");
192 		return (0);
193 	}
194 #endif
195 
196 	bkpt = db_breakpoint_alloc();
197 	if (bkpt == 0) {
198 		db_printf("Too many breakpoints.\n");
199 		return (0);
200 	}
201 
202 	bkpt->address = addr;
203 	bkpt->flags = BKPT_TEMP;
204 	bkpt->init_count = 1;
205 	bkpt->count = 1;
206 
207 	bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, 0);
208 	db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
209 	return bkpt;
210 }
211 
212 void
db_delete_temp_breakpoint(db_breakpoint_t bkpt)213 db_delete_temp_breakpoint(db_breakpoint_t bkpt)
214 {
215 	db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
216 	db_breakpoint_free(bkpt);
217 }
218 
219 /*
220  * List breakpoints.
221  */
222 void
db_list_breakpoints(void)223 db_list_breakpoints(void)
224 {
225 	db_breakpoint_t	bkpt;
226 
227 	if (db_breakpoint_list == NULL) {
228 		db_printf("No breakpoints set\n");
229 		return;
230 	}
231 
232 	db_printf(" Count    Address\n");
233 	for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
234 		db_printf(" %5d    ", bkpt->init_count);
235 		db_printsym(bkpt->address, DB_STGY_PROC, db_printf);
236 		db_printf("\n");
237 	}
238 }
239 
240 /* Delete breakpoint */
241 void
db_delete_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)242 db_delete_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
243 {
244 	db_delete_breakpoint((vaddr_t)addr);
245 }
246 
247 /* Set breakpoint with skip count */
248 void
db_breakpoint_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)249 db_breakpoint_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
250 {
251 	if (count < 1)
252 		count = 1;
253 
254 	db_set_breakpoint((vaddr_t)addr, count);
255 }
256 
257 /* list breakpoints */
258 void
db_listbreak_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)259 db_listbreak_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
260 {
261 	db_list_breakpoints();
262 }
263