|
|
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:48 wsanchez
29: * Import of Mac OS X kernel (~semeria)
30: *
31: * Revision 1.1.1.1 1998/03/07 02:26:09 wsanchez
32: * Import of OSF Mach kernel (~mburg)
33: *
34: * Revision 1.1.12.2 1995/01/06 19:11:06 devrcs
35: * mk6 CR668 - 1.3b26 merge
36: * * Revision 1.1.3.5 1994/05/06 18:40:29 tmt
37: * Merged osc1.3dec/shared with osc1.3b19
38: * Merge Alpha changes into osc1.312b source code.
39: * 64bit cleanup.
40: * * End1.3merge
41: * [1994/11/04 08:50:16 dwm]
42: *
43: * Revision 1.1.12.1 1994/09/23 01:22:53 ezf
44: * change marker to not FREE
45: * [1994/09/22 21:11:33 ezf]
46: *
47: * Revision 1.1.10.1 1994/01/05 19:28:22 bolinger
48: * Be sure to count kernel-loaded tasks as part of kernel address space
49: * in locating watchpoints.
50: * [1994/01/04 17:43:33 bolinger]
51: *
52: * Revision 1.1.3.3 1993/07/27 18:28:31 elliston
53: * Add ANSI prototypes. CR #9523.
54: * [1993/07/27 18:13:30 elliston]
55: *
56: * Revision 1.1.3.2 1993/06/02 23:13:14 jeffc
57: * Added to OSF/1 R1.3 from NMK15.0.
58: * [1993/06/02 20:57:54 jeffc]
59: *
60: * Revision 1.1 1992/09/30 02:01:33 robert
61: * Initial revision
62: *
63: * $EndLog$
64: */
65: /* CMU_HIST */
66: /*
67: * Revision 2.7 91/10/09 16:04:32 af
68: * Revision 2.6.3.1 91/10/05 13:08:50 jeffreyh
69: * Added user space watch point support including non current task.
70: * Changed "map" field of db_watchpoint structure to "task"
71: * for a user to easily understand the target space.
72: * [91/08/29 tak]
73: *
74: * Revision 2.6.3.1 91/10/05 13:08:50 jeffreyh
75: * Added user space watch point support including non current task.
76: * Changed "map" field of db_watchpoint structure to "task"
77: * for a user to easily understand the target space.
78: * [91/08/29 tak]
79: *
80: * Revision 2.6 91/05/14 15:37:30 mrt
81: * Correcting copyright
82: *
83: * Revision 2.5 91/02/05 17:07:27 mrt
84: * Changed to new Mach copyright
85: * [91/01/31 16:20:02 mrt]
86: *
87: * Revision 2.4 91/01/08 15:09:24 rpd
88: * Use db_map_equal, db_map_current, db_map_addr.
89: * [90/11/10 rpd]
90: *
91: * Revision 2.3 90/11/05 14:26:39 rpd
92: * Initialize db_watchpoints_inserted to TRUE.
93: * [90/11/04 rpd]
94: *
95: * Revision 2.2 90/10/25 14:44:16 rwd
96: * Made db_watchpoint_cmd parse a size argument.
97: * [90/10/17 rpd]
98: * Generalized the watchpoint support.
99: * [90/10/16 rwd]
100: * Created.
101: * [90/10/16 rpd]
102: *
103: */
104: /* CMU_ENDHIST */
105: /*
106: * Mach Operating System
107: * Copyright (c) 1991,1990 Carnegie Mellon University
108: * All Rights Reserved.
109: *
110: * Permission to use, copy, modify and distribute this software and its
111: * documentation is hereby granted, provided that both the copyright
112: * notice and this permission notice appear in all copies of the
113: * software, derivative works or modified versions, and any portions
114: * thereof, and that both notices appear in supporting documentation.
115: *
116: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
117: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
118: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
119: *
120: * Carnegie Mellon requests users of this software to return to
121: *
122: * Software Distribution Coordinator or [email protected]
123: * School of Computer Science
124: * Carnegie Mellon University
125: * Pittsburgh PA 15213-3890
126: *
127: * any improvements or extensions that they make and grant Carnegie Mellon
128: * the rights to redistribute these changes.
129: */
130: /*
131: */
132: /*
133: * Author: Richard P. Draves, Carnegie Mellon University
134: * Date: 10/90
135: */
136:
137: #include <mach/boolean.h>
138: #include <mach/vm_param.h>
139: #include <mach/machine/vm_types.h>
140: #include <mach/machine/vm_param.h>
141: #include <vm/vm_map.h>
142:
143: #include <machine/db_machdep.h>
144: #include <ddb/db_lex.h>
145: #include <ddb/db_watch.h>
146: #include <ddb/db_access.h>
147: #include <ddb/db_sym.h>
148: #include <ddb/db_task_thread.h>
149: #include <ddb/db_command.h>
150: #include <ddb/db_expr.h>
151: #include <ddb/db_output.h> /* For db_printf() */
152: #include <ddb/db_run.h> /* For db_single_step() */
153:
154: /*
155: * Watchpoints.
156: */
157:
158: boolean_t db_watchpoints_inserted = TRUE;
159:
160: #define NWATCHPOINTS 100
161: struct db_watchpoint db_watch_table[NWATCHPOINTS];
162: db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0];
163: db_watchpoint_t db_free_watchpoints = 0;
164: db_watchpoint_t db_watchpoint_list = 0;
165:
166: extern vm_map_t kernel_map;
167:
168:
169:
170: /* Prototypes for functions local to this file. XXX -- should be static.
171: */
172:
173: db_watchpoint_t db_watchpoint_alloc(void);
174:
175: void db_watchpoint_free(register db_watchpoint_t watch);
176:
177: void db_set_watchpoint(
178: task_t task,
179: db_addr_t addr,
180: vm_size_t size);
181:
182: void db_delete_watchpoint(
183: task_t task,
184: db_addr_t addr);
185:
186: static int db_get_task(
187: char *modif,
188: task_t *taskp,
189: db_addr_t addr);
190:
191: void db_list_watchpoints(void);
192:
193:
194:
195: db_watchpoint_t
196: db_watchpoint_alloc(void)
197: {
198: register db_watchpoint_t watch;
199:
200: if ((watch = db_free_watchpoints) != 0) {
201: db_free_watchpoints = watch->link;
202: return (watch);
203: }
204: if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
205: db_printf("All watchpoints used.\n");
206: return (0);
207: }
208: watch = db_next_free_watchpoint;
209: db_next_free_watchpoint++;
210:
211: return (watch);
212: }
213:
214: void
215: db_watchpoint_free(register db_watchpoint_t watch)
216: {
217: watch->link = db_free_watchpoints;
218: db_free_watchpoints = watch;
219: }
220:
221: void
222: db_set_watchpoint(
223: task_t task,
224: db_addr_t addr,
225: vm_size_t size)
226: {
227: register db_watchpoint_t watch;
228:
229: /*
230: * Should we do anything fancy with overlapping regions?
231: */
232:
233: for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
234: if (watch->task == task &&
235: (watch->loaddr == addr) &&
236: (watch->hiaddr == addr+size)) {
237: db_printf("Already set.\n");
238: return;
239: }
240: }
241:
242: watch = db_watchpoint_alloc();
243: if (watch == 0) {
244: db_printf("Too many watchpoints.\n");
245: return;
246: }
247:
248: watch->task = task;
249: watch->loaddr = addr;
250: watch->hiaddr = addr+size;
251:
252: watch->link = db_watchpoint_list;
253: db_watchpoint_list = watch;
254:
255: db_watchpoints_inserted = FALSE;
256: }
257:
258: void
259: db_delete_watchpoint(
260: task_t task,
261: db_addr_t addr)
262: {
263: register db_watchpoint_t watch;
264: register db_watchpoint_t *prev;
265:
266: for (prev = &db_watchpoint_list; (watch = *prev) != 0;
267: prev = &watch->link) {
268: if (watch->task == task &&
269: (watch->loaddr <= addr) &&
270: (addr < watch->hiaddr)) {
271: *prev = watch->link;
272: db_watchpoint_free(watch);
273: return;
274: }
275: }
276:
277: db_printf("Not set.\n");
278: }
279:
280: void
281: db_list_watchpoints(void)
282: {
283: register db_watchpoint_t watch;
284: int task_id;
285:
286: if (db_watchpoint_list == 0) {
287: db_printf("No watchpoints set\n");
288: return;
289: }
290:
291: db_printf("Space Address Size\n");
292: for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
293: if (watch->task == TASK_NULL)
294: db_printf("kernel ");
295: else {
296: task_id = db_lookup_task(watch->task);
297: if (task_id < 0)
298: db_printf("%*X", 2*sizeof(vm_offset_t), watch->task);
299: else
300: db_printf("task%-3d ", task_id);
301: }
302: db_printf(" %*X %X\n", 2*sizeof(vm_offset_t), watch->loaddr,
303: watch->hiaddr - watch->loaddr);
304: }
305: }
306:
307: static int
308: db_get_task(
309: char *modif,
310: task_t *taskp,
311: db_addr_t addr)
312: {
313: task_t task = TASK_NULL;
314: db_expr_t value;
315: boolean_t user_space;
316:
317: user_space = db_option(modif, 'T');
318: if (user_space) {
319: if (db_expression(&value)) {
320: task = (task_t)value;
321: if (db_lookup_task(task) < 0) {
322: db_printf("bad task address %X\n", task);
323: return(-1);
324: }
325: } else {
326: task = db_default_task;
327: if (task == TASK_NULL) {
328: if ((task = db_current_task()) == TASK_NULL) {
329: db_printf("no task\n");
330: return(-1);
331: }
332: }
333: }
334: }
335: if (!DB_VALID_ADDRESS(addr, user_space)) {
336: db_printf("Address %#X is not in %s space\n", addr,
337: (user_space)? "user": "kernel");
338: return(-1);
339: }
340: *taskp = task;
341: return(0);
342: }
343:
344: /* Delete watchpoint */
345: void
346: db_deletewatch_cmd(
347: db_expr_t addr,
348: int have_addr,
349: db_expr_t count,
350: char * modif)
351: {
352: task_t task;
353:
354: if (db_get_task(modif, &task, addr) < 0)
355: return;
356: db_delete_watchpoint(task, addr);
357: }
358:
359: /* Set watchpoint */
360: void
361: db_watchpoint_cmd(
362: db_expr_t addr,
363: int have_addr,
364: db_expr_t count,
365: char * modif)
366: {
367: vm_size_t size;
368: db_expr_t value;
369: task_t task;
370:
371: if (db_get_task(modif, &task, addr) < 0)
372: return;
373: if (db_expression(&value))
374: size = (vm_size_t) value;
375: else
376: size = sizeof(int);
377: db_set_watchpoint(task, addr, size);
378: }
379:
380: /* list watchpoints */
381: void
382: db_listwatch_cmd(void)
383: {
384: db_list_watchpoints();
385: }
386:
387: void
388: db_set_watchpoints(void)
389: {
390: register db_watchpoint_t watch;
391: vm_map_t map;
392:
393: if (!db_watchpoints_inserted) {
394: for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
395: map = (watch->task)? watch->task->map: kernel_map;
396: pmap_protect(map->pmap,
397: trunc_page(watch->loaddr),
398: round_page(watch->hiaddr),
399: VM_PROT_READ);
400: }
401: db_watchpoints_inserted = TRUE;
402: }
403: }
404:
405: void
406: db_clear_watchpoints(void)
407: {
408: db_watchpoints_inserted = FALSE;
409: }
410:
411: boolean_t
412: db_find_watchpoint(
413: vm_map_t map,
414: db_addr_t addr,
415: db_regs_t *regs)
416: {
417: register db_watchpoint_t watch;
418: db_watchpoint_t found = 0;
419: register task_t task_space;
420:
421: task_space = (vm_map_pmap(map) == kernel_pmap)?
422: TASK_NULL: db_current_space();
423: for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
424: if (watch->task == task_space) {
425: if ((watch->loaddr <= addr) && (addr < watch->hiaddr))
426: return (TRUE);
427: else if ((trunc_page(watch->loaddr) <= addr) &&
428: (addr < round_page(watch->hiaddr)))
429: found = watch;
430: }
431: }
432:
433: /*
434: * We didn't hit exactly on a watchpoint, but we are
435: * in a protected region. We want to single-step
436: * and then re-protect.
437: */
438:
439: if (found) {
440: db_watchpoints_inserted = FALSE;
441: db_single_step(regs, task_space);
442: }
443:
444: return (FALSE);
445: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.