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