|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * HISTORY
27: *
28: * Revision 1.1.1.1 1998/09/22 21:05:47 wsanchez
29: * Import of Mac OS X kernel (~semeria)
30: *
31: * Revision 1.2 1998/04/29 17:35:26 mburg
32: * MK7.3 merger
33: *
34: * Revision 1.2.47.1 1998/02/03 09:23:57 gdt
35: * Merge up to MK7.3
36: * [1998/02/03 09:10:14 gdt]
37: *
38: * Revision 1.2.45.1 1997/03/27 18:46:16 barbou
39: * ri-osc CR1557: re-enable thread-specific breakpoints.
40: * [1995/09/20 15:23:46 bolinger]
41: * [97/02/25 barbou]
42: *
43: * Revision 1.2.21.6 1996/01/09 19:15:21 devrcs
44: * Changed declarations of 'register foo' to 'register int foo'
45: * Fixed printfs which print addresses.
46: * [1995/12/01 21:41:51 jfraser]
47: *
48: * Merged '64-bit safe' changes from DEC alpha port.
49: * [1995/11/21 18:02:40 jfraser]
50: *
51: * Revision 1.2.21.5 1995/04/07 18:52:54 barbou
52: * Allow breakpoints on non-resident pages. The breakpoint will
53: * actually be set when the page is paged in.
54: * [93/09/23 barbou]
55: * [95/03/08 barbou]
56: *
57: * Revision 1.2.21.4 1995/02/23 21:43:19 alanl
58: * Merged with DIPC2_SHARED.
59: * [1995/01/04 20:15:04 alanl]
60: *
61: * Revision 1.2.28.1 1994/11/04 09:52:15 dwm
62: * mk6 CR668 - 1.3b26 merge
63: * * Revision 1.2.4.5 1994/05/06 18:38:52 tmt
64: * Merged osc1.3dec/shared with osc1.3b19
65: * Moved struct db_breakpoint from here to db_break.h.
66: * Merge Alpha changes into osc1.312b source code.
67: * 64bit cleanup.
68: * * End1.3merge
69: * [1994/11/04 08:49:10 dwm]
70: *
71: * Revision 1.2.21.2 1994/09/23 01:17:57 ezf
72: * change marker to not FREE
73: * [1994/09/22 21:09:19 ezf]
74: *
75: * Revision 1.2.21.1 1994/06/11 21:11:24 bolinger
76: * Merge up to NMK17.2.
77: * [1994/06/11 20:01:06 bolinger]
78: *
79: * Revision 1.2.25.2 1994/10/28 18:56:21 rwd
80: * Delint.
81: * [94/10/28 rwd]
82: *
83: * Revision 1.2.25.1 1994/08/04 01:42:15 mmp
84: * 23-Jun-94 Stan Smith ([email protected])
85: * Let d * delete all breakpoints.
86: * [1994/06/28 13:54:00 sjs]
87: *
88: * Revision 1.2.19.2 1994/04/11 09:34:22 bernadat
89: * Moved db_breakpoint struct declaration to db_break.h
90: * [94/03/16 bernadat]
91: *
92: * Revision 1.2.19.1 1994/02/08 10:57:22 bernadat
93: * When setting a breakpoint, force user_space if breakpoint is
94: * outside kernel_space (like in the case of an emulator).
95: * [93/09/27 paire]
96: *
97: * Changed silly decimal display to hex (to match input conventions).
98: * Change from NORMA_MK14.6 [93/01/09 sjs]
99: * [93/07/16 bernadat]
100: * [94/02/07 bernadat]
101: *
102: * Revision 1.2.4.3 1993/07/27 18:26:48 elliston
103: * Add ANSI prototypes. CR #9523.
104: * [1993/07/27 18:10:54 elliston]
105: *
106: * Revision 1.2.4.2 1993/06/09 02:19:39 gm
107: * Added to OSF/1 R1.3 from NMK15.0.
108: * [1993/06/02 20:55:42 jeffc]
109: *
110: * Revision 1.2 1993/04/19 16:01:31 devrcs
111: * Changes from MK78:
112: * Removed unused variable from db_delete_cmd().
113: * Added declaration for arg 'count' of db_add_thread_breakpoint().
114: * [92/05/18 jfriedl]
115: * Fixed b/tu to b/Tu work if the specified address is valid in the
116: * target address space but not the current user space. Explicit
117: * user space breakpoints (b/u, b/Tu, etc) will no longer get
118: * inserted into the kernel if the specified address is invalid.
119: * [92/04/18 danner]
120: * [92/12/18 bruel]
121: *
122: * Revision 1.1 1992/09/30 02:00:52 robert
123: * Initial revision
124: *
125: * $EndLog$
126: */
127: /* CMU_HIST */
128: /*
129: * Revision 2.11.3.1 92/03/03 16:13:20 jeffreyh
130: * Pick up changes from TRUNK
131: * [92/02/26 10:58:37 jeffreyh]
132: *
133: * Revision 2.12 92/02/19 16:46:24 elf
134: * Removed one of the many user-unfriendlinesses.
135: * [92/02/10 17:48:25 af]
136: *
137: * Revision 2.11 91/11/12 11:50:24 rvb
138: * Fixed db_delete_cmd so that just "d" works in user space.
139: * [91/10/31 rpd]
140: * Fixed db_delete_thread_breakpoint for zero task_thd.
141: * [91/10/30 rpd]
142: *
143: * Revision 2.10 91/10/09 15:57:41 af
144: * Supported thread-oriented break points.
145: * [91/08/29 tak]
146: *
147: * Revision 2.9 91/07/09 23:15:39 danner
148: * Conditionalized db_map_addr to work right on the luna. Used a
149: * ifdef luna88k. This is evil, and needs to be fixed.
150: * [91/07/08 danner]
151: *
152: * Revision 2.2 91/04/10 22:54:50 mbj
153: * Grabbed 3.0 copyright/disclaimer since ddb comes from 3.0.
154: * [91/04/09 rvb]
155: *
156: * Revision 2.7 91/02/05 17:06:00 mrt
157: * Changed to new Mach copyright
158: * [91/01/31 16:17:01 mrt]
159: *
160: * Revision 2.6 91/01/08 15:09:03 rpd
161: * Added db_map_equal, db_map_current, db_map_addr.
162: * [90/11/10 rpd]
163: *
164: * Revision 2.5 90/11/05 14:26:32 rpd
165: * Initialize db_breakpoints_inserted to TRUE.
166: * [90/11/04 rpd]
167: *
168: * Revision 2.4 90/10/25 14:43:33 rwd
169: * Added map field to breakpoints.
170: * Added map argument to db_set_breakpoint, db_delete_breakpoint,
171: * db_find_breakpoint. Added db_find_breakpoint_here.
172: * [90/10/18 rpd]
173: *
174: * Revision 2.3 90/09/28 16:57:07 jsb
175: * Fixed db_breakpoint_free.
176: * [90/09/18 rpd]
177: *
178: * Revision 2.2 90/08/27 21:49:53 dbg
179: * Reflected changes in db_printsym()'s calling seq.
180: * [90/08/20 af]
181: * Clear breakpoints only if inserted.
182: * Reduce lint.
183: * [90/08/07 dbg]
184: * Created.
185: * [90/07/25 dbg]
186: *
187: */
188: /* CMU_ENDHIST */
189: /*
190: * Mach Operating System
191: * Copyright (c) 1991,1990 Carnegie Mellon University
192: * All Rights Reserved.
193: *
194: * Permission to use, copy, modify and distribute this software and its
195: * documentation is hereby granted, provided that both the copyright
196: * notice and this permission notice appear in all copies of the
197: * software, derivative works or modified versions, and any portions
198: * thereof, and that both notices appear in supporting documentation.
199: *
200: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
201: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
202: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
203: *
204: * Carnegie Mellon requests users of this software to return to
205: *
206: * Software Distribution Coordinator or [email protected]
207: * School of Computer Science
208: * Carnegie Mellon University
209: * Pittsburgh PA 15213-3890
210: *
211: * any improvements or extensions that they make and grant Carnegie Mellon
212: * the rights to redistribute these changes.
213: */
214: /*
215: */
216: /*
217: * Author: David B. Golub, Carnegie Mellon University
218: * Date: 7/90
219: */
220:
221: /*
222: * Breakpoints.
223: */
224: #include <mach/boolean.h>
225: #include <machine/db_machdep.h>
226: #include <ddb/db_lex.h>
227: #include <ddb/db_break.h>
228: #include <ddb/db_access.h>
229: #include <ddb/db_sym.h>
230: #include <ddb/db_variables.h>
231: #include <ddb/db_command.h>
232: #include <ddb/db_cond.h>
233: #include <ddb/db_expr.h>
234: #include <ddb/db_output.h> /* For db_printf() */
235: #include <ddb/db_task_thread.h>
236:
237:
238: #define NBREAKPOINTS 100
239: #define NTHREAD_LIST (NBREAKPOINTS*3)
240:
241: struct db_breakpoint db_break_table[NBREAKPOINTS];
242: db_breakpoint_t db_next_free_breakpoint = &db_break_table[0];
243: db_breakpoint_t db_free_breakpoints = 0;
244: db_breakpoint_t db_breakpoint_list = 0;
245:
246: static struct db_thread_breakpoint db_thread_break_list[NTHREAD_LIST];
247: static db_thread_breakpoint_t db_free_thread_break_list = 0;
248: static boolean_t db_thread_break_init = FALSE;
249: static int db_breakpoint_number = 0;
250:
251: /* Prototypes for functions local to this file. XXX -- should be static!
252: */
253: static int db_add_thread_breakpoint(
254: register db_breakpoint_t bkpt,
255: vm_offset_t task_thd,
256: int count,
257: boolean_t task_bpt);
258:
259: static int db_delete_thread_breakpoint(
260: register db_breakpoint_t bkpt,
261: vm_offset_t task_thd);
262:
263: static db_thread_breakpoint_t db_find_thread_breakpoint(
264: db_breakpoint_t bkpt,
265: thread_act_t thr_act);
266:
267: static void db_force_delete_breakpoint(
268: db_breakpoint_t bkpt,
269: vm_offset_t task_thd,
270: boolean_t is_task);
271:
272: db_breakpoint_t db_breakpoint_alloc(void);
273:
274: void db_breakpoint_free(register db_breakpoint_t bkpt);
275:
276: void db_delete_breakpoint(
277: task_t task,
278: db_addr_t addr,
279: vm_offset_t task_thd);
280:
281: void
282: db_delete_all_breakpoints(
283: task_t task);
284:
285: void db_list_breakpoints(void);
286:
287:
288:
289: db_breakpoint_t
290: db_breakpoint_alloc(void)
291: {
292: register db_breakpoint_t bkpt;
293:
294: if ((bkpt = db_free_breakpoints) != 0) {
295: db_free_breakpoints = bkpt->link;
296: return (bkpt);
297: }
298: if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
299: db_printf("All breakpoints used.\n");
300: return (0);
301: }
302: bkpt = db_next_free_breakpoint;
303: db_next_free_breakpoint++;
304:
305: return (bkpt);
306: }
307:
308: void
309: db_breakpoint_free(register db_breakpoint_t bkpt)
310: {
311: bkpt->link = db_free_breakpoints;
312: db_free_breakpoints = bkpt;
313: }
314:
315: static int
316: db_add_thread_breakpoint(
317: register db_breakpoint_t bkpt,
318: vm_offset_t task_thd,
319: int count,
320: boolean_t task_bpt)
321: {
322: register db_thread_breakpoint_t tp;
323:
324: if (db_thread_break_init == FALSE) {
325: for (tp = db_thread_break_list;
326: tp < &db_thread_break_list[NTHREAD_LIST-1]; tp++)
327: tp->tb_next = tp+1;
328: tp->tb_next = 0;
329: db_free_thread_break_list = db_thread_break_list;
330: db_thread_break_init = TRUE;
331: }
332: if (db_free_thread_break_list == 0)
333: return (-1);
334: tp = db_free_thread_break_list;
335: db_free_thread_break_list = tp->tb_next;
336: tp->tb_is_task = task_bpt;
337: tp->tb_task_thd = task_thd;
338: tp->tb_count = count;
339: tp->tb_init_count = count;
340: tp->tb_cond = 0;
341: tp->tb_number = ++db_breakpoint_number;
342: tp->tb_next = bkpt->threads;
343: bkpt->threads = tp;
344: return(0);
345: }
346:
347: static int
348: db_delete_thread_breakpoint(
349: register db_breakpoint_t bkpt,
350: vm_offset_t task_thd)
351: {
352: register db_thread_breakpoint_t tp;
353: register db_thread_breakpoint_t *tpp;
354:
355: if (task_thd == 0) {
356: /* delete all the thread-breakpoints */
357:
358: for (tpp = &bkpt->threads; (tp = *tpp) != 0; tpp = &tp->tb_next)
359: db_cond_free(tp);
360:
361: *tpp = db_free_thread_break_list;
362: db_free_thread_break_list = bkpt->threads;
363: bkpt->threads = 0;
364: return 0;
365: } else {
366: /* delete the specified thread-breakpoint */
367:
368: for (tpp = &bkpt->threads; (tp = *tpp) != 0; tpp = &tp->tb_next)
369: if (tp->tb_task_thd == task_thd) {
370: db_cond_free(tp);
371: *tpp = tp->tb_next;
372: tp->tb_next = db_free_thread_break_list;
373: db_free_thread_break_list = tp;
374: return 0;
375: }
376:
377: return -1; /* not found */
378: }
379: }
380:
381: static db_thread_breakpoint_t
382: db_find_thread_breakpoint(
383: db_breakpoint_t bkpt,
384: thread_act_t thr_act)
385: {
386: register db_thread_breakpoint_t tp;
387: register task_t task =
388: (thr_act == THR_ACT_NULL || thr_act->kernel_loaded)
389: ? TASK_NULL : thr_act->task;
390:
391: for (tp = bkpt->threads; tp; tp = tp->tb_next) {
392: if (tp->tb_is_task) {
393: if (tp->tb_task_thd == (vm_offset_t)task)
394: break;
395: continue;
396: }
397: if (tp->tb_task_thd == (vm_offset_t)thr_act || tp->tb_task_thd == 0)
398: break;
399: }
400: return(tp);
401: }
402:
403: db_thread_breakpoint_t
404: db_find_thread_breakpoint_here(
405: task_t task,
406: db_addr_t addr)
407: {
408: db_breakpoint_t bkpt;
409:
410: bkpt = db_find_breakpoint(task, (db_addr_t)addr);
411: if (bkpt == 0)
412: return(0);
413: return(db_find_thread_breakpoint(bkpt, current_act()));
414: }
415:
416: db_thread_breakpoint_t
417: db_find_breakpoint_number(
418: int num,
419: db_breakpoint_t *bkptp)
420: {
421: register db_thread_breakpoint_t tp;
422: register db_breakpoint_t bkpt;
423:
424: for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
425: for (tp = bkpt->threads; tp; tp = tp->tb_next) {
426: if (tp->tb_number == num) {
427: if (bkptp)
428: *bkptp = bkpt;
429: return(tp);
430: }
431: }
432: }
433: return(0);
434: }
435:
436: static void
437: db_force_delete_breakpoint(
438: db_breakpoint_t bkpt,
439: vm_offset_t task_thd,
440: boolean_t is_task)
441: {
442: db_printf("deleted a stale breakpoint at ");
443: if (bkpt->task == TASK_NULL || db_lookup_task(bkpt->task) >= 0)
444: db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
445: else
446: db_printf("%#X", bkpt->address);
447: if (bkpt->task)
448: db_printf(" in task %X", bkpt->task);
449: if (task_thd)
450: db_printf(" for %s %X", (is_task)? "task": "thr_act", task_thd);
451: db_printf("\n");
452: db_delete_thread_breakpoint(bkpt, task_thd);
453: }
454:
455: void
456: db_check_breakpoint_valid(void)
457: {
458: register db_thread_breakpoint_t tbp, tbp_next;
459: register db_breakpoint_t bkpt, *bkptp;
460:
461: bkptp = &db_breakpoint_list;
462: for (bkpt = *bkptp; bkpt; bkpt = *bkptp) {
463: if (bkpt->task != TASK_NULL) {
464: if (db_lookup_task(bkpt->task) < 0) {
465: db_force_delete_breakpoint(bkpt, 0, FALSE);
466: *bkptp = bkpt->link;
467: db_breakpoint_free(bkpt);
468: continue;
469: }
470: } else {
471: for (tbp = bkpt->threads; tbp; tbp = tbp_next) {
472: tbp_next = tbp->tb_next;
473: if (tbp->tb_task_thd == 0)
474: continue;
475: if ((tbp->tb_is_task &&
476: db_lookup_task((task_t)(tbp->tb_task_thd)) < 0) ||
477: (!tbp->tb_is_task &&
478: db_lookup_act((thread_act_t)(tbp->tb_task_thd)) < 0)) {
479: db_force_delete_breakpoint(bkpt,
480: tbp->tb_task_thd, tbp->tb_is_task);
481: }
482: }
483: if (bkpt->threads == 0) {
484: db_put_task_value(bkpt->address, BKPT_SIZE,
485: bkpt->bkpt_inst, bkpt->task);
486: *bkptp = bkpt->link;
487: db_breakpoint_free(bkpt);
488: continue;
489: }
490: }
491: bkptp = &bkpt->link;
492: }
493: }
494:
495: void
496: db_set_breakpoint(
497: task_t task,
498: db_addr_t addr,
499: int count,
500: thread_act_t thr_act,
501: boolean_t task_bpt)
502: {
503: register db_breakpoint_t bkpt;
504: db_breakpoint_t alloc_bkpt = 0;
505: vm_offset_t task_thd;
506:
507: bkpt = db_find_breakpoint(task, addr);
508: if (bkpt) {
509: if (thr_act == THR_ACT_NULL
510: || db_find_thread_breakpoint(bkpt, thr_act)) {
511: db_printf("Already set.\n");
512: return;
513: }
514: } else {
515: if (!DB_CHECK_ACCESS(addr, BKPT_SIZE, task)) {
516: if (task) {
517: db_printf("Warning: non-resident page for breakpoint at %lX",
518: addr);
519: db_printf(" in task %lX.\n", task);
520: } else {
521: db_printf("Cannot set breakpoint at %lX in kernel space.\n",
522: addr);
523: return;
524: }
525: }
526: alloc_bkpt = bkpt = db_breakpoint_alloc();
527: if (bkpt == 0) {
528: db_printf("Too many breakpoints.\n");
529: return;
530: }
531: bkpt->task = task;
532: bkpt->flags = (task && thr_act == THR_ACT_NULL)?
533: (BKPT_USR_GLOBAL|BKPT_1ST_SET): 0;
534: bkpt->address = addr;
535: bkpt->threads = 0;
536: }
537: if (db_breakpoint_list == 0)
538: db_breakpoint_number = 0;
539: task_thd = (task_bpt) ? (vm_offset_t)(thr_act->task)
540: : (vm_offset_t)thr_act;
541: if (db_add_thread_breakpoint(bkpt, task_thd, count, task_bpt) < 0) {
542: if (alloc_bkpt)
543: db_breakpoint_free(alloc_bkpt);
544: db_printf("Too many thread_breakpoints.\n");
545: } else {
546: db_printf("set breakpoint #%x\n", db_breakpoint_number);
547: if (alloc_bkpt) {
548: bkpt->link = db_breakpoint_list;
549: db_breakpoint_list = bkpt;
550: }
551: }
552: }
553:
554: void
555: db_delete_breakpoint(
556: task_t task,
557: db_addr_t addr,
558: vm_offset_t task_thd)
559: {
560: register db_breakpoint_t bkpt;
561: register db_breakpoint_t *prev;
562:
563: for (prev = &db_breakpoint_list; (bkpt = *prev) != 0;
564: prev = &bkpt->link) {
565: if ((bkpt->task == task
566: || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
567: && bkpt->address == addr)
568: break;
569: }
570: if (bkpt && (bkpt->flags & BKPT_SET_IN_MEM)) {
571: db_printf("cannot delete it now.\n");
572: return;
573: }
574: if (bkpt == 0
575: || db_delete_thread_breakpoint(bkpt, task_thd) < 0) {
576: db_printf("Not set.\n");
577: return;
578: }
579: if (bkpt->threads == 0) {
580: *prev = bkpt->link;
581: db_breakpoint_free(bkpt);
582: }
583: }
584:
585: db_breakpoint_t
586: db_find_breakpoint(
587: task_t task,
588: db_addr_t addr)
589: {
590: register db_breakpoint_t bkpt;
591:
592: for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
593: if ((bkpt->task == task
594: || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
595: && bkpt->address == addr)
596: return (bkpt);
597: }
598: return (0);
599: }
600:
601: boolean_t
602: db_find_breakpoint_here(
603: task_t task,
604: db_addr_t addr)
605: {
606: register db_breakpoint_t bkpt;
607:
608: for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
609: if ((bkpt->task == task
610: || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
611: && bkpt->address == addr)
612: return(TRUE);
613: if ((bkpt->flags & BKPT_USR_GLOBAL) == 0 &&
614: DB_PHYS_EQ(task, addr, bkpt->task, bkpt->address))
615: return (TRUE);
616: }
617: return(FALSE);
618: }
619:
620: boolean_t db_breakpoints_inserted = TRUE;
621:
622: void
623: db_set_breakpoints(void)
624: {
625: register db_breakpoint_t bkpt;
626: register task_t task;
627: db_expr_t inst;
628: thread_act_t cur_act = current_act();
629: task_t cur_task =
630: (cur_act && !cur_act->kernel_loaded) ?
631: cur_act->task : TASK_NULL;
632: boolean_t inserted = TRUE;
633:
634: if (!db_breakpoints_inserted) {
635: for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
636: if (bkpt->flags & BKPT_SET_IN_MEM)
637: continue;
638: task = bkpt->task;
639: if (bkpt->flags & BKPT_USR_GLOBAL) {
640: if ((bkpt->flags & BKPT_1ST_SET) == 0) {
641: if (cur_task == TASK_NULL)
642: continue;
643: task = cur_task;
644: } else
645: bkpt->flags &= ~BKPT_1ST_SET;
646: }
647: if (DB_CHECK_ACCESS(bkpt->address, BKPT_SIZE, task)) {
648: inst = db_get_task_value(bkpt->address, BKPT_SIZE, FALSE,
649: task);
650: if (inst == BKPT_SET(inst))
651: continue;
652: bkpt->bkpt_inst = inst;
653: db_put_task_value(bkpt->address,
654: BKPT_SIZE,
655: BKPT_SET(bkpt->bkpt_inst), task);
656: bkpt->flags |= BKPT_SET_IN_MEM;
657: } else {
658: inserted = FALSE;
659: }
660: }
661: db_breakpoints_inserted = inserted;
662: }
663: }
664:
665: void
666: db_clear_breakpoints(void)
667: {
668: register db_breakpoint_t bkpt, *bkptp;
669: register task_t task;
670: db_expr_t inst;
671: thread_act_t cur_act = current_act();
672: task_t cur_task = (cur_act && !cur_act->kernel_loaded) ?
673: cur_act->task: TASK_NULL;
674:
675: if (db_breakpoints_inserted) {
676: bkptp = &db_breakpoint_list;
677: for (bkpt = *bkptp; bkpt; bkpt = *bkptp) {
678: task = bkpt->task;
679: if (bkpt->flags & BKPT_USR_GLOBAL) {
680: if (cur_task == TASK_NULL) {
681: bkptp = &bkpt->link;
682: continue;
683: }
684: task = cur_task;
685: }
686: if ((bkpt->flags & BKPT_SET_IN_MEM)
687: && DB_CHECK_ACCESS(bkpt->address, BKPT_SIZE, task)) {
688: inst = db_get_task_value(bkpt->address, BKPT_SIZE, FALSE,
689: task);
690: if (inst != BKPT_SET(inst)) {
691: if (bkpt->flags & BKPT_USR_GLOBAL) {
692: bkptp = &bkpt->link;
693: continue;
694: }
695: db_force_delete_breakpoint(bkpt, 0, FALSE);
696: *bkptp = bkpt->link;
697: db_breakpoint_free(bkpt);
698: continue;
699: }
700: db_put_task_value(bkpt->address, BKPT_SIZE,
701: bkpt->bkpt_inst, task);
702: bkpt->flags &= ~BKPT_SET_IN_MEM;
703: }
704: bkptp = &bkpt->link;
705: }
706: db_breakpoints_inserted = FALSE;
707: }
708: }
709:
710: /*
711: * Set a temporary breakpoint.
712: * The instruction is changed immediately,
713: * so the breakpoint does not have to be on the breakpoint list.
714: */
715: db_breakpoint_t
716: db_set_temp_breakpoint(
717: task_t task,
718: db_addr_t addr)
719: {
720: register db_breakpoint_t bkpt;
721:
722: bkpt = db_breakpoint_alloc();
723: if (bkpt == 0) {
724: db_printf("Too many breakpoints.\n");
725: return 0;
726: }
727: bkpt->task = task;
728: bkpt->address = addr;
729: bkpt->flags = BKPT_TEMP;
730: bkpt->threads = 0;
731: if (db_add_thread_breakpoint(bkpt, 0, 1, FALSE) < 0) {
732: if (bkpt)
733: db_breakpoint_free(bkpt);
734: db_printf("Too many thread_breakpoints.\n");
735: return 0;
736: }
737: bkpt->bkpt_inst = db_get_task_value(bkpt->address, BKPT_SIZE,
738: FALSE, task);
739: db_put_task_value(bkpt->address, BKPT_SIZE,
740: BKPT_SET(bkpt->bkpt_inst), task);
741: return bkpt;
742: }
743:
744: void
745: db_delete_temp_breakpoint(
746: task_t task,
747: db_breakpoint_t bkpt)
748: {
749: db_put_task_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst, task);
750: db_delete_thread_breakpoint(bkpt, 0);
751: db_breakpoint_free(bkpt);
752: }
753:
754: /*
755: * List breakpoints.
756: */
757: void
758: db_list_breakpoints(void)
759: {
760: register db_breakpoint_t bkpt;
761:
762: if (db_breakpoint_list == 0) {
763: db_printf("No breakpoints set\n");
764: return;
765: }
766:
767: db_printf(" No Space Task.Act Cnt Address(Cond)\n");
768: for (bkpt = db_breakpoint_list;
769: bkpt != 0;
770: bkpt = bkpt->link)
771: {
772: register db_thread_breakpoint_t tp;
773: int task_id;
774: int act_id;
775:
776: if (bkpt->threads) {
777: for (tp = bkpt->threads; tp; tp = tp->tb_next) {
778: db_printf("%3d ", tp->tb_number);
779: if (bkpt->flags & BKPT_USR_GLOBAL)
780: db_printf("user ");
781: else if (bkpt->task == TASK_NULL)
782: db_printf("kernel ");
783: else if ((task_id = db_lookup_task(bkpt->task)) < 0)
784: db_printf("%0*X ", 2*sizeof(vm_offset_t), bkpt->task);
785: else
786: db_printf("task%-3d ", task_id);
787: if (tp->tb_task_thd == 0) {
788: db_printf("all ");
789: } else {
790: if (tp->tb_is_task) {
791: task_id = db_lookup_task((task_t)(tp->tb_task_thd));
792: if (task_id < 0)
793: db_printf("%0*X ", 2*sizeof(vm_offset_t),
794: tp->tb_task_thd);
795: else
796: db_printf("task%03d ", task_id);
797: } else {
798: thread_act_t thd = (thread_act_t)(tp->tb_task_thd);
799: task_id = db_lookup_task(thd->task);
800: act_id = db_lookup_task_act(thd->task, thd);
801: if (task_id < 0 || act_id < 0)
802: db_printf("%0*X ", 2*sizeof(vm_offset_t),
803: tp->tb_task_thd);
804: else
805: db_printf("task%03d.%-3d ", task_id, act_id);
806: }
807: }
808: db_printf("%3d ", tp->tb_init_count);
809: db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
810: if (tp->tb_cond > 0) {
811: db_printf("(");
812: db_cond_print(tp);
813: db_printf(")");
814: }
815: db_printf("\n");
816: }
817: } else {
818: if (bkpt->task == TASK_NULL)
819: db_printf(" ? kernel ");
820: else
821: db_printf("%*X ", 2*sizeof(vm_offset_t), bkpt->task);
822: db_printf("(?) ");
823: db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
824: db_printf("\n");
825: }
826: }
827: }
828:
829: void
830: db_delete_all_breakpoints(
831: task_t task)
832: {
833: register db_breakpoint_t bkpt;
834:
835: bkpt = db_breakpoint_list;
836: while ( bkpt != 0 ) {
837: if (bkpt->task == task ||
838: (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL))) {
839: db_delete_breakpoint(task, bkpt->address, 0);
840: bkpt = db_breakpoint_list;
841: }
842: else
843: bkpt = bkpt->link;
844:
845: }
846: }
847:
848: /* Delete breakpoint */
849: void
850: db_delete_cmd(void)
851: {
852: register int n;
853: thread_act_t thr_act;
854: vm_offset_t task_thd;
855: boolean_t user_global = FALSE;
856: boolean_t task_bpt = FALSE;
857: boolean_t user_space = FALSE;
858: boolean_t thd_bpt = FALSE;
859: db_expr_t addr;
860: int t;
861:
862: t = db_read_token();
863: if (t == tSLASH) {
864: t = db_read_token();
865: if (t != tIDENT) {
866: db_printf("Bad modifier \"%s\"\n", db_tok_string);
867: db_error(0);
868: }
869: user_global = db_option(db_tok_string, 'U');
870: user_space = (user_global)? TRUE: db_option(db_tok_string, 'u');
871: task_bpt = db_option(db_tok_string, 'T');
872: thd_bpt = db_option(db_tok_string, 't');
873: if (task_bpt && user_global)
874: db_error("Cannot specify both 'T' and 'U' option\n");
875: t = db_read_token();
876: }
877:
878: if ( t == tSTAR ) {
879: db_printf("Delete ALL breakpoints\n");
880: db_delete_all_breakpoints( (task_t)task_bpt );
881: return;
882: }
883:
884: if (t == tHASH) {
885: db_thread_breakpoint_t tbp;
886: db_breakpoint_t bkpt;
887:
888: if (db_read_token() != tNUMBER) {
889: db_printf("Bad break point number #%s\n", db_tok_string);
890: db_error(0);
891: }
892: if ((tbp = db_find_breakpoint_number(db_tok_number, &bkpt)) == 0) {
893: db_printf("No such break point #%d\n", db_tok_number);
894: db_error(0);
895: }
896: db_delete_breakpoint(bkpt->task, bkpt->address, tbp->tb_task_thd);
897: return;
898: }
899: db_unread_token(t);
900: if (!db_expression(&addr)) {
901: /*
902: * We attempt to pick up the user_space indication from db_dot,
903: * so that a plain "d" always works.
904: */
905: addr = (db_expr_t)db_dot;
906: if (!user_space && !DB_VALID_ADDRESS(addr, FALSE))
907: user_space = TRUE;
908: }
909: if (!DB_VALID_ADDRESS(addr, user_space)) {
910: db_printf("Address %#X is not in %s space\n", addr,
911: (user_space)? "user": "kernel");
912: db_error(0);
913: }
914: if (thd_bpt || task_bpt) {
915: for (n = 0; db_get_next_act(&thr_act, n); n++) {
916: if (thr_act == THR_ACT_NULL)
917: db_error("No active thr_act\n");
918: if (task_bpt) {
919: if (thr_act->task == TASK_NULL)
920: db_error("No task\n");
921: task_thd = (vm_offset_t) (thr_act->task);
922: } else
923: task_thd = (user_global)? 0: (vm_offset_t) thr_act;
924: db_delete_breakpoint(db_target_space(thr_act, user_space),
925: (db_addr_t)addr, task_thd);
926: }
927: } else {
928: db_delete_breakpoint(db_target_space(THR_ACT_NULL, user_space),
929: (db_addr_t)addr, 0);
930: }
931: }
932:
933: /* Set breakpoint with skip count */
934: #include <mach/machine/vm_param.h>
935:
936: void
937: db_breakpoint_cmd(
938: db_expr_t addr,
939: int have_addr,
940: db_expr_t count,
941: char * modif)
942: {
943: register int n;
944: thread_act_t thr_act;
945: boolean_t user_global = db_option(modif, 'U');
946: boolean_t task_bpt = db_option(modif, 'T');
947: boolean_t user_space;
948:
949: if (count == -1)
950: count = 1;
951: #if 0 /* CHECKME */
952: if (!task_bpt && db_option(modif,'t'))
953: task_bpt = TRUE;
954: #endif
955:
956: if (task_bpt && user_global)
957: db_error("Cannot specify both 'T' and 'U'\n");
958: user_space = (user_global)? TRUE: db_option(modif, 'u');
959: if (user_space && db_access_level < DB_ACCESS_CURRENT)
960: db_error("User space break point is not supported\n");
961: if ((!task_bpt || !user_space) &&
962: !DB_VALID_ADDRESS(addr, user_space)) {
963: /* if the user has explicitly specified user space,
964: do not insert a breakpoint into the kernel */
965: if (user_space)
966: db_error("Invalid user space address\n");
967: user_space = TRUE;
968: db_printf("%#X is in user space\n", addr);
969: db_printf("kernel is from %#X to %#x\n", VM_MIN_KERNEL_ADDRESS, VM_MAX_KERNEL_ADDRESS);
970: }
971: if (db_option(modif, 't') || task_bpt) {
972: for (n = 0; db_get_next_act(&thr_act, n); n++) {
973: if (thr_act == THR_ACT_NULL)
974: db_error("No active thr_act\n");
975: if (task_bpt && thr_act->task == TASK_NULL)
976: db_error("No task\n");
977: if (db_access_level <= DB_ACCESS_CURRENT && user_space
978: && thr_act->task != db_current_space())
979: db_error("Cannot set break point in inactive user space\n");
980: db_set_breakpoint(db_target_space(thr_act, user_space),
981: (db_addr_t)addr, count,
982: (user_global)? THR_ACT_NULL: thr_act,
983: task_bpt);
984: }
985: } else {
986: db_set_breakpoint(db_target_space(THR_ACT_NULL, user_space),
987: (db_addr_t)addr,
988: count, THR_ACT_NULL, FALSE);
989: }
990: }
991:
992: /* list breakpoints */
993: void
994: db_listbreak_cmd(void)
995: {
996: db_list_breakpoints();
997: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.