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 * $FreeBSD: releng/5.1/sys/amd64/amd64/db_trace.c 115403 2003-05-30 01:01:07Z peter $
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/proc.h>
32 #include <sys/sysent.h>
33
34 #include <machine/cpu.h>
35 #include <machine/md_var.h>
36 #include <machine/pcb.h>
37 #include <machine/reg.h>
38
39 #include <vm/vm.h>
40 #include <vm/vm_param.h>
41 #include <vm/pmap.h>
42
43 #include <ddb/ddb.h>
44 #include <ddb/db_access.h>
45 #include <ddb/db_sym.h>
46 #include <ddb/db_variables.h>
47
48 #if 0
49 db_varfcn_t db_dr0;
50 db_varfcn_t db_dr1;
51 db_varfcn_t db_dr2;
52 db_varfcn_t db_dr3;
53 db_varfcn_t db_dr4;
54 db_varfcn_t db_dr5;
55 db_varfcn_t db_dr6;
56 db_varfcn_t db_dr7;
57 #endif
58
59 /*
60 * Machine register set.
61 */
62 struct db_variable db_regs[] = {
63 { "cs", &ddb_regs.tf_cs, FCN_NULL },
64 #if 0
65 { "ds", &ddb_regs.tf_ds, FCN_NULL },
66 { "es", &ddb_regs.tf_es, FCN_NULL },
67 { "fs", &ddb_regs.tf_fs, FCN_NULL },
68 { "gs", &ddb_regs.tf_gs, FCN_NULL },
69 #endif
70 { "ss", &ddb_regs.tf_ss, FCN_NULL },
71 { "rax", &ddb_regs.tf_rax, FCN_NULL },
72 { "rcx", &ddb_regs.tf_rcx, FCN_NULL },
73 { "rdx", &ddb_regs.tf_rdx, FCN_NULL },
74 { "rbx", &ddb_regs.tf_rbx, FCN_NULL },
75 { "rsp", &ddb_regs.tf_rsp, FCN_NULL },
76 { "rbp", &ddb_regs.tf_rbp, FCN_NULL },
77 { "rsi", &ddb_regs.tf_rsi, FCN_NULL },
78 { "rdi", &ddb_regs.tf_rdi, FCN_NULL },
79 { "r8", &ddb_regs.tf_r8, FCN_NULL },
80 { "r9", &ddb_regs.tf_r9, FCN_NULL },
81 { "r10", &ddb_regs.tf_r10, FCN_NULL },
82 { "r11", &ddb_regs.tf_r11, FCN_NULL },
83 { "r12", &ddb_regs.tf_r12, FCN_NULL },
84 { "r13", &ddb_regs.tf_r13, FCN_NULL },
85 { "r14", &ddb_regs.tf_r14, FCN_NULL },
86 { "r15", &ddb_regs.tf_r15, FCN_NULL },
87 { "rip", &ddb_regs.tf_rip, FCN_NULL },
88 { "rflags", &ddb_regs.tf_rflags, FCN_NULL },
89 #if 0
90 { "dr0", NULL, db_dr0 },
91 { "dr1", NULL, db_dr1 },
92 { "dr2", NULL, db_dr2 },
93 { "dr3", NULL, db_dr3 },
94 { "dr4", NULL, db_dr4 },
95 { "dr5", NULL, db_dr5 },
96 { "dr6", NULL, db_dr6 },
97 { "dr7", NULL, db_dr7 },
98 #endif
99 };
100 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
101
102 /*
103 * Stack trace.
104 */
105 #define INKERNEL(va) (((vm_offset_t)(va)) >= USRSTACK)
106
107 struct amd64_frame {
108 struct amd64_frame *f_frame;
109 long f_retaddr;
110 long f_arg0;
111 };
112
113 #define NORMAL 0
114 #define TRAP 1
115 #define INTERRUPT 2
116 #define SYSCALL 3
117
118 static void db_nextframe(struct amd64_frame **, db_addr_t *, struct proc *);
119 static int db_numargs(struct amd64_frame *);
120 static void db_print_stack_entry(const char *, int, char **, long *, db_addr_t);
121 static void decode_syscall(int, struct proc *);
122 static void db_trace_one_stack(int count, boolean_t have_addr,
123 struct proc *p, struct amd64_frame *frame, db_addr_t callpc);
124
125
126 #if 0
127 static char * watchtype_str(int type);
128 int amd64_set_watch(int watchnum, unsigned int watchaddr, int size, int access,
129 struct dbreg * d);
130 int amd64_clr_watch(int watchnum, struct dbreg * d);
131 #endif
132 int db_md_set_watchpoint(db_expr_t addr, db_expr_t size);
133 int db_md_clr_watchpoint(db_expr_t addr, db_expr_t size);
134 void db_md_list_watchpoints(void);
135
136
137 /*
138 * Figure out how many arguments were passed into the frame at "fp".
139 */
140 static int
141 db_numargs(fp)
142 struct amd64_frame *fp;
143 {
144 #if 1
145 return (0); /* regparm, needs dwarf2 info */
146 #else
147 long *argp;
148 int inst;
149 int args;
150
151 argp = (long *)db_get_value((long)&fp->f_retaddr, 8, FALSE);
152 /*
153 * XXX etext is wrong for LKMs. We should attempt to interpret
154 * the instruction at the return address in all cases. This
155 * may require better fault handling.
156 */
157 if (argp < (long *)btext || argp >= (long *)etext) {
158 args = 5;
159 } else {
160 inst = db_get_value((long)argp, 4, FALSE);
161 if ((inst & 0xff) == 0x59) /* popl %ecx */
162 args = 1;
163 else if ((inst & 0xffff) == 0xc483) /* addl $Ibs, %esp */
164 args = ((inst >> 16) & 0xff) / 4;
165 else
166 args = 5;
167 }
168 return (args);
169 #endif
170 }
171
172 static void
173 db_print_stack_entry(name, narg, argnp, argp, callpc)
174 const char *name;
175 int narg;
176 char **argnp;
177 long *argp;
178 db_addr_t callpc;
179 {
180 db_printf("%s(", name);
181 #if 0
182 while (narg) {
183 if (argnp)
184 db_printf("%s=", *argnp++);
185 db_printf("%lr", (long)db_get_value((long)argp, 8, FALSE));
186 argp++;
187 if (--narg != 0)
188 db_printf(",");
189 }
190 #endif
191 db_printf(") at ");
192 db_printsym(callpc, DB_STGY_PROC);
193 db_printf("\n");
194 }
195
196 static void
197 decode_syscall(number, p)
198 int number;
199 struct proc *p;
200 {
201 c_db_sym_t sym;
202 db_expr_t diff;
203 sy_call_t *f;
204 const char *symname;
205
206 db_printf(" (%d", number);
207 if (p != NULL && 0 <= number && number < p->p_sysent->sv_size) {
208 f = p->p_sysent->sv_table[number].sy_call;
209 sym = db_search_symbol((db_addr_t)f, DB_STGY_ANY, &diff);
210 if (sym != DB_SYM_NULL && diff == 0) {
211 db_symbol_values(sym, &symname, NULL);
212 db_printf(", %s, %s", p->p_sysent->sv_name, symname);
213 }
214 }
215 db_printf(")");
216 }
217
218 /*
219 * Figure out the next frame up in the call stack.
220 */
221 static void
222 db_nextframe(fp, ip, p)
223 struct amd64_frame **fp; /* in/out */
224 db_addr_t *ip; /* out */
225 struct proc *p; /* in */
226 {
227 struct trapframe *tf;
228 int frame_type;
229 long rip, rsp, rbp;
230 db_expr_t offset;
231 c_db_sym_t sym;
232 const char *name;
233
234 rip = db_get_value((long) &(*fp)->f_retaddr, 8, FALSE);
235 rbp = db_get_value((long) &(*fp)->f_frame, 8, FALSE);
236
237 /*
238 * Figure out frame type.
239 */
240 frame_type = NORMAL;
241 sym = db_search_symbol(rip, DB_STGY_ANY, &offset);
242 db_symbol_values(sym, &name, NULL);
243 if (name != NULL) {
244 if (strcmp(name, "calltrap") == 0 ||
245 strcmp(name, "fork_trampoline") == 0)
246 frame_type = TRAP;
247 else if (strncmp(name, "Xintr", 5) == 0 ||
248 strncmp(name, "Xfastintr", 9) == 0)
249 frame_type = INTERRUPT;
250 else if (strcmp(name, "Xfast_syscall") == 0)
251 frame_type = SYSCALL;
252 }
253
254 /*
255 * Normal frames need no special processing.
256 */
257 if (frame_type == NORMAL) {
258 *ip = (db_addr_t) rip;
259 *fp = (struct amd64_frame *) rbp;
260 return;
261 }
262
263 db_print_stack_entry(name, 0, 0, 0, rip);
264
265 /*
266 * Point to base of trapframe which is just above the
267 * current frame.
268 */
269 tf = (struct trapframe *)((long)*fp + 16);
270
271 if (INKERNEL((long) tf)) {
272 rsp = (ISPL(tf->tf_cs) == SEL_UPL) ?
273 tf->tf_rsp : (long)&tf->tf_rsp;
274 rip = tf->tf_rip;
275 rbp = tf->tf_rbp;
276 switch (frame_type) {
277 case TRAP:
278 db_printf("--- trap %#lr", tf->tf_trapno);
279 break;
280 case SYSCALL:
281 db_printf("--- syscall");
282 decode_syscall(tf->tf_rax, p);
283 break;
284 case INTERRUPT:
285 db_printf("--- interrupt");
286 break;
287 default:
288 panic("The moon has moved again.");
289 }
290 db_printf(", rip = %#lr, rsp = %#lr, rbp = %#lr ---\n", rip,
291 rsp, rbp);
292 }
293
294 *ip = (db_addr_t) rip;
295 *fp = (struct amd64_frame *) rbp;
296 }
297
298 void
299 db_stack_trace_cmd(addr, have_addr, count, modif)
300 db_expr_t addr;
301 boolean_t have_addr;
302 db_expr_t count;
303 char *modif;
304 {
305 struct amd64_frame *frame;
306 struct proc *p;
307 struct pcb *pcb;
308 struct thread *td;
309 db_addr_t callpc;
310 pid_t pid;
311
312 if (count == -1)
313 count = 1024;
314
315 if (!have_addr) {
316 td = curthread;
317 p = td->td_proc;
318 frame = (struct amd64_frame *)ddb_regs.tf_rbp;
319 if (frame == NULL)
320 frame = (struct amd64_frame *)(ddb_regs.tf_rsp - 8);
321 callpc = (db_addr_t)ddb_regs.tf_rip;
322 } else if (!INKERNEL(addr)) {
323 pid = (addr % 16) + ((addr >> 4) % 16) * 10 +
324 ((addr >> 8) % 16) * 100 + ((addr >> 12) % 16) * 1000 +
325 ((addr >> 16) % 16) * 10000;
326 /*
327 * The pcb for curproc is not valid at this point,
328 * so fall back to the default case.
329 */
330 if (pid == curthread->td_proc->p_pid) {
331 td = curthread;
332 p = td->td_proc;
333 frame = (struct amd64_frame *)ddb_regs.tf_rbp;
334 if (frame == NULL)
335 frame = (struct amd64_frame *)
336 (ddb_regs.tf_rsp - 8);
337 callpc = (db_addr_t)ddb_regs.tf_rip;
338 } else {
339
340 /* sx_slock(&allproc_lock); */
341 LIST_FOREACH(p, &allproc, p_list) {
342 if (p->p_pid == pid)
343 break;
344 }
345 /* sx_sunlock(&allproc_lock); */
346 if (p == NULL) {
347 db_printf("pid %d not found\n", pid);
348 return;
349 }
350 if ((p->p_sflag & PS_INMEM) == 0) {
351 db_printf("pid %d swapped out\n", pid);
352 return;
353 }
354 pcb = FIRST_THREAD_IN_PROC(p)->td_pcb; /* XXXKSE */
355 frame = (struct amd64_frame *)pcb->pcb_rbp;
356 if (frame == NULL)
357 frame = (struct amd64_frame *)
358 (pcb->pcb_rsp - 8);
359 callpc = (db_addr_t)pcb->pcb_rip;
360 }
361 } else {
362 p = NULL;
363 frame = (struct amd64_frame *)addr;
364 callpc = (db_addr_t)db_get_value((long)&frame->f_retaddr, 8, FALSE);
365 frame = frame->f_frame;
366 }
367 db_trace_one_stack(count, have_addr, p, frame, callpc);
368 }
369
370 void
371 db_stack_thread(db_expr_t addr, boolean_t have_addr,
372 db_expr_t count, char *modif)
373 {
374 struct amd64_frame *frame;
375 struct thread *td;
376 struct proc *p;
377 struct pcb *pcb;
378 db_addr_t callpc;
379
380 if (!have_addr)
381 return;
382 if (!INKERNEL(addr)) {
383 printf("bad thread address");
384 return;
385 }
386 td = (struct thread *)addr;
387 /* quick sanity check */
388 if ((p = td->td_proc) != td->td_ksegrp->kg_proc)
389 return;
390 if (TD_IS_SWAPPED(td)) {
391 db_printf("thread at %p swapped out\n", td);
392 return;
393 }
394 if (td == curthread) {
395 frame = (struct amd64_frame *)ddb_regs.tf_rbp;
396 if (frame == NULL)
397 frame = (struct amd64_frame *)(ddb_regs.tf_rsp - 8);
398 callpc = (db_addr_t)ddb_regs.tf_rip;
399 } else {
400 pcb = td->td_pcb;
401 frame = (struct amd64_frame *)pcb->pcb_rbp;
402 if (frame == NULL)
403 frame = (struct amd64_frame *) (pcb->pcb_rsp - 8);
404 callpc = (db_addr_t)pcb->pcb_rip;
405 }
406 db_trace_one_stack(count, have_addr, p, frame, callpc);
407 }
408
409 static void
410 db_trace_one_stack(int count, boolean_t have_addr,
411 struct proc *p, struct amd64_frame *frame, db_addr_t callpc)
412 {
413 long *argp;
414 boolean_t first;
415
416 first = TRUE;
417 while (count--) {
418 struct amd64_frame *actframe;
419 int narg;
420 const char * name;
421 db_expr_t offset;
422 c_db_sym_t sym;
423 #define MAXNARG 16
424 char *argnames[MAXNARG], **argnp = NULL;
425
426 sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
427 db_symbol_values(sym, &name, NULL);
428
429 /*
430 * Attempt to determine a (possibly fake) frame that gives
431 * the caller's pc. It may differ from `frame' if the
432 * current function never sets up a standard frame or hasn't
433 * set one up yet or has just discarded one. The last two
434 * cases can be guessed fairly reliably for code generated
435 * by gcc. The first case is too much trouble to handle in
436 * general because the amount of junk on the stack depends
437 * on the pc (the special handling of "calltrap", etc. in
438 * db_nextframe() works because the `next' pc is special).
439 */
440 actframe = frame;
441 if (first) {
442 if (!have_addr) {
443 int instr;
444
445 instr = db_get_value(callpc, 4, FALSE);
446 if ((instr & 0xffffffff) == 0xe5894855) {
447 /* pushq %rbp; movq %rsp, %rbp */
448 actframe = (struct amd64_frame *)
449 (ddb_regs.tf_rsp - 8);
450 } else if ((instr & 0x00ffffff) == 0x00e58948) {
451 /* movq %rsp, %rbp */
452 actframe = (struct amd64_frame *)
453 ddb_regs.tf_rsp;
454 if (ddb_regs.tf_rbp == 0) {
455 /* Fake caller's frame better. */
456 frame = actframe;
457 }
458 } else if ((instr & 0x000000ff) == 0x000000c3) {
459 /* ret */
460 actframe = (struct amd64_frame *)
461 (ddb_regs.tf_rsp - 8);
462 } else if (offset == 0) {
463 /* Probably a symbol in assembler code. */
464 actframe = (struct amd64_frame *)
465 (ddb_regs.tf_rsp - 8);
466 }
467 } else if (strcmp(name, "fork_trampoline") == 0) {
468 /*
469 * Don't try to walk back on a stack for a
470 * process that hasn't actually been run yet.
471 */
472 db_print_stack_entry(name, 0, 0, 0, callpc);
473 break;
474 }
475 first = FALSE;
476 }
477
478 argp = &actframe->f_arg0;
479 narg = MAXNARG;
480 if (sym != NULL && db_sym_numargs(sym, &narg, argnames)) {
481 argnp = argnames;
482 } else {
483 narg = db_numargs(frame);
484 }
485
486 db_print_stack_entry(name, narg, argnp, argp, callpc);
487
488 if (actframe != frame) {
489 /* `frame' belongs to caller. */
490 callpc = (db_addr_t)
491 db_get_value((long)&actframe->f_retaddr, 8, FALSE);
492 continue;
493 }
494
495 db_nextframe(&frame, &callpc, p);
496
497 if (INKERNEL((long) callpc) && !INKERNEL((long) frame)) {
498 sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
499 db_symbol_values(sym, &name, NULL);
500 db_print_stack_entry(name, 0, 0, 0, callpc);
501 break;
502 }
503 if (!INKERNEL((long) frame)) {
504 break;
505 }
506 }
507 }
508
509 void
510 db_print_backtrace(void)
511 {
512 register_t ebp;
513
514 __asm __volatile("movq %%rbp,%0" : "=r" (ebp));
515 db_stack_trace_cmd(ebp, 1, -1, NULL);
516 }
517
518 #if 0
519 #define DB_DRX_FUNC(reg) \
520 int \
521 db_ ## reg (vp, valuep, op) \
522 struct db_variable *vp; \
523 db_expr_t * valuep; \
524 int op; \
525 { \
526 if (op == DB_VAR_GET) \
527 *valuep = r ## reg (); \
528 else \
529 load_ ## reg (*valuep); \
530 return (0); \
531 }
532
533 DB_DRX_FUNC(dr0)
534 DB_DRX_FUNC(dr1)
535 DB_DRX_FUNC(dr2)
536 DB_DRX_FUNC(dr3)
537 DB_DRX_FUNC(dr4)
538 DB_DRX_FUNC(dr5)
539 DB_DRX_FUNC(dr6)
540 DB_DRX_FUNC(dr7)
541
542 int
543 amd64_set_watch(watchnum, watchaddr, size, access, d)
544 int watchnum;
545 unsigned int watchaddr;
546 int size;
547 int access;
548 struct dbreg * d;
549 {
550 int i;
551 unsigned int mask;
552
553 if (watchnum == -1) {
554 for (i = 0, mask = 0x3; i < 4; i++, mask <<= 2)
555 if ((d->dr[7] & mask) == 0)
556 break;
557 if (i < 4)
558 watchnum = i;
559 else
560 return (-1);
561 }
562
563 switch (access) {
564 case DBREG_DR7_EXEC:
565 size = 1; /* size must be 1 for an execution breakpoint */
566 /* fall through */
567 case DBREG_DR7_WRONLY:
568 case DBREG_DR7_RDWR:
569 break;
570 default : return (-1); break;
571 }
572
573 /*
574 * we can watch a 1, 2, or 4 byte sized location
575 */
576 switch (size) {
577 case 1 : mask = 0x00; break;
578 case 2 : mask = 0x01 << 2; break;
579 case 4 : mask = 0x03 << 2; break;
580 default : return (-1); break;
581 }
582
583 mask |= access;
584
585 /* clear the bits we are about to affect */
586 d->dr[7] &= ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16)));
587
588 /* set drN register to the address, N=watchnum */
589 DBREG_DRX(d,watchnum) = watchaddr;
590
591 /* enable the watchpoint */
592 d->dr[7] |= (0x2 << (watchnum*2)) | (mask << (watchnum*4+16));
593
594 return (watchnum);
595 }
596
597
598 int
599 amd64_clr_watch(watchnum, d)
600 int watchnum;
601 struct dbreg * d;
602 {
603
604 if (watchnum < 0 || watchnum >= 4)
605 return (-1);
606
607 d->dr[7] = d->dr[7] & ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16)));
608 DBREG_DRX(d,watchnum) = 0;
609
610 return (0);
611 }
612
613
614 int
615 db_md_set_watchpoint(addr, size)
616 db_expr_t addr;
617 db_expr_t size;
618 {
619 int avail, wsize;
620 int i;
621 struct dbreg d;
622
623 fill_dbregs(NULL, &d);
624
625 avail = 0;
626 for(i=0; i<4; i++) {
627 if ((d.dr[7] & (3 << (i*2))) == 0)
628 avail++;
629 }
630
631 if (avail*4 < size)
632 return (-1);
633
634 for (i=0; i<4 && (size != 0); i++) {
635 if ((d.dr[7] & (3<<(i*2))) == 0) {
636 if (size > 4)
637 wsize = 4;
638 else
639 wsize = size;
640 if (wsize == 3)
641 wsize++;
642 amd64_set_watch(i, addr, wsize,
643 DBREG_DR7_WRONLY, &d);
644 addr += wsize;
645 size -= wsize;
646 }
647 }
648
649 set_dbregs(NULL, &d);
650
651 return(0);
652 }
653
654
655 int
656 db_md_clr_watchpoint(addr, size)
657 db_expr_t addr;
658 db_expr_t size;
659 {
660 int i;
661 struct dbreg d;
662
663 fill_dbregs(NULL, &d);
664
665 for(i=0; i<4; i++) {
666 if (d.dr[7] & (3 << (i*2))) {
667 if ((DBREG_DRX((&d), i) >= addr) &&
668 (DBREG_DRX((&d), i) < addr+size))
669 amd64_clr_watch(i, &d);
670
671 }
672 }
673
674 set_dbregs(NULL, &d);
675
676 return(0);
677 }
678
679
680 static
681 char *
682 watchtype_str(type)
683 int type;
684 {
685 switch (type) {
686 case DBREG_DR7_EXEC : return "execute"; break;
687 case DBREG_DR7_RDWR : return "read/write"; break;
688 case DBREG_DR7_WRONLY : return "write"; break;
689 default : return "invalid"; break;
690 }
691 }
692
693
694 void
695 db_md_list_watchpoints()
696 {
697 int i;
698 struct dbreg d;
699
700 fill_dbregs(NULL, &d);
701
702 db_printf("\nhardware watchpoints:\n");
703 db_printf(" watch status type len address\n");
704 db_printf(" ----- -------- ---------- --- ----------\n");
705 for (i=0; i<4; i++) {
706 if (d.dr[7] & (0x03 << (i*2))) {
707 unsigned type, len;
708 type = (d.dr[7] >> (16+(i*4))) & 3;
709 len = (d.dr[7] >> (16+(i*4)+2)) & 3;
710 db_printf(" %-5d %-8s %10s %3d 0x%08x\n",
711 i, "enabled", watchtype_str(type),
712 len+1, DBREG_DRX((&d),i));
713 }
714 else {
715 db_printf(" %-5d disabled\n", i);
716 }
717 }
718
719 db_printf("\ndebug register values:\n");
720 for (i=0; i<8; i++) {
721 db_printf(" dr%d 0x%08x\n", i, DBREG_DRX((&d),i));
722 }
723 db_printf("\n");
724 }
725
726 #else
727 int
728 db_md_set_watchpoint(addr, size)
729 db_expr_t addr;
730 db_expr_t size;
731 {
732 return (-1);
733 }
734
735 int
736 db_md_clr_watchpoint(addr, size)
737 db_expr_t addr;
738 db_expr_t size;
739 {
740 return (-1);
741 }
742
743 void
744 db_md_list_watchpoints()
745 {
746 }
747 #endif
Cache object: f85115c88e42faeb86882a1673908a9e
|