10e6594a8SSascha Wildner /*
20e6594a8SSascha Wildner * Copyright (c) 2008 The DragonFly Project. All rights reserved.
30e6594a8SSascha Wildner *
40e6594a8SSascha Wildner * Redistribution and use in source and binary forms, with or without
50e6594a8SSascha Wildner * modification, are permitted provided that the following conditions
60e6594a8SSascha Wildner * are met:
70e6594a8SSascha Wildner *
80e6594a8SSascha Wildner * 1. Redistributions of source code must retain the above copyright
90e6594a8SSascha Wildner * notice, this list of conditions and the following disclaimer.
100e6594a8SSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
110e6594a8SSascha Wildner * notice, this list of conditions and the following disclaimer in
120e6594a8SSascha Wildner * the documentation and/or other materials provided with the
130e6594a8SSascha Wildner * distribution.
140e6594a8SSascha Wildner * 3. Neither the name of The DragonFly Project nor the names of its
150e6594a8SSascha Wildner * contributors may be used to endorse or promote products derived
160e6594a8SSascha Wildner * from this software without specific, prior written permission.
170e6594a8SSascha Wildner *
180e6594a8SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
190e6594a8SSascha Wildner * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
200e6594a8SSascha Wildner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
210e6594a8SSascha Wildner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
220e6594a8SSascha Wildner * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
230e6594a8SSascha Wildner * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
240e6594a8SSascha Wildner * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
250e6594a8SSascha Wildner * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
260e6594a8SSascha Wildner * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
270e6594a8SSascha Wildner * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
280e6594a8SSascha Wildner * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
290e6594a8SSascha Wildner * SUCH DAMAGE.
300e6594a8SSascha Wildner *
310e6594a8SSascha Wildner * --
320e6594a8SSascha Wildner *
330e6594a8SSascha Wildner * Mach Operating System
340e6594a8SSascha Wildner * Copyright (c) 1991,1990 Carnegie Mellon University
350e6594a8SSascha Wildner * All Rights Reserved.
360e6594a8SSascha Wildner *
370e6594a8SSascha Wildner * Permission to use, copy, modify and distribute this software and its
380e6594a8SSascha Wildner * documentation is hereby granted, provided that both the copyright
390e6594a8SSascha Wildner * notice and this permission notice appear in all copies of the
400e6594a8SSascha Wildner * software, derivative works or modified versions, and any portions
410e6594a8SSascha Wildner * thereof, and that both notices appear in supporting documentation.
420e6594a8SSascha Wildner *
430e6594a8SSascha Wildner * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
440e6594a8SSascha Wildner * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
450e6594a8SSascha Wildner * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
460e6594a8SSascha Wildner *
470e6594a8SSascha Wildner * Carnegie Mellon requests users of this software to return to
480e6594a8SSascha Wildner *
490e6594a8SSascha Wildner * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
500e6594a8SSascha Wildner * School of Computer Science
510e6594a8SSascha Wildner * Carnegie Mellon University
520e6594a8SSascha Wildner * Pittsburgh PA 15213-3890
530e6594a8SSascha Wildner *
540e6594a8SSascha Wildner * any improvements or extensions that they make and grant Carnegie the
550e6594a8SSascha Wildner * rights to redistribute these changes.
560e6594a8SSascha Wildner *
570e6594a8SSascha Wildner * $FreeBSD: src/sys/i386/i386/db_trace.c,v 1.35.2.3 2002/02/21 22:31:25 silby Exp $
580e6594a8SSascha Wildner */
590e6594a8SSascha Wildner
600e6594a8SSascha Wildner #include <sys/param.h>
610e6594a8SSascha Wildner #include <sys/systm.h>
620e6594a8SSascha Wildner #include <sys/linker_set.h>
630e6594a8SSascha Wildner #include <sys/lock.h>
640e6594a8SSascha Wildner #include <sys/proc.h>
650e6594a8SSascha Wildner #include <sys/reg.h>
660e6594a8SSascha Wildner
670e6594a8SSascha Wildner #include <machine/cpu.h>
680e6594a8SSascha Wildner #include <machine/md_var.h>
690e6594a8SSascha Wildner
700e6594a8SSascha Wildner #include <vm/vm.h>
710e6594a8SSascha Wildner #include <vm/vm_param.h>
720e6594a8SSascha Wildner #include <vm/pmap.h>
730e6594a8SSascha Wildner #include <vm/vm_map.h>
740e6594a8SSascha Wildner #include <ddb/ddb.h>
750e6594a8SSascha Wildner #include <dlfcn.h> /* DLL */
760e6594a8SSascha Wildner
770e6594a8SSascha Wildner #include <ddb/db_access.h>
780e6594a8SSascha Wildner #include <ddb/db_sym.h>
790e6594a8SSascha Wildner #include <ddb/db_variables.h>
800e6594a8SSascha Wildner
810e6594a8SSascha Wildner db_varfcn_t db_dr0;
820e6594a8SSascha Wildner db_varfcn_t db_dr1;
830e6594a8SSascha Wildner db_varfcn_t db_dr2;
840e6594a8SSascha Wildner db_varfcn_t db_dr3;
850e6594a8SSascha Wildner db_varfcn_t db_dr4;
860e6594a8SSascha Wildner db_varfcn_t db_dr5;
870e6594a8SSascha Wildner db_varfcn_t db_dr6;
880e6594a8SSascha Wildner db_varfcn_t db_dr7;
890e6594a8SSascha Wildner
900e6594a8SSascha Wildner /*
910e6594a8SSascha Wildner * Machine register set.
920e6594a8SSascha Wildner */
930e6594a8SSascha Wildner struct db_variable db_regs[] = {
940e6594a8SSascha Wildner { "cs", &ddb_regs.tf_cs, NULL },
950e6594a8SSascha Wildner /* { "ds", &ddb_regs.tf_ds, NULL },
960e6594a8SSascha Wildner { "es", &ddb_regs.tf_es, NULL },
970e6594a8SSascha Wildner { "fs", &ddb_regs.tf_fs, NULL },
980e6594a8SSascha Wildner { "gs", &ddb_regs.tf_gs, NULL }, */
990e6594a8SSascha Wildner { "ss", &ddb_regs.tf_ss, NULL },
1000e6594a8SSascha Wildner { "rax", &ddb_regs.tf_rax, NULL },
1010e6594a8SSascha Wildner { "rcx", &ddb_regs.tf_rcx, NULL },
1020e6594a8SSascha Wildner { "rdx", &ddb_regs.tf_rdx, NULL },
1030e6594a8SSascha Wildner { "rbx", &ddb_regs.tf_rbx, NULL },
1040e6594a8SSascha Wildner { "rsp", &ddb_regs.tf_rsp, NULL },
1050e6594a8SSascha Wildner { "rbp", &ddb_regs.tf_rbp, NULL },
1060e6594a8SSascha Wildner { "rsi", &ddb_regs.tf_rsi, NULL },
1070e6594a8SSascha Wildner { "rdi", &ddb_regs.tf_rdi, NULL },
1080e6594a8SSascha Wildner { "rip", &ddb_regs.tf_rip, NULL },
1090e6594a8SSascha Wildner { "rfl", &ddb_regs.tf_rflags, NULL },
1100e6594a8SSascha Wildner { "r8", &ddb_regs.tf_r8, NULL },
1110e6594a8SSascha Wildner { "r9", &ddb_regs.tf_r9, NULL },
1120e6594a8SSascha Wildner { "r10", &ddb_regs.tf_r10, NULL },
1130e6594a8SSascha Wildner { "r11", &ddb_regs.tf_r11, NULL },
1140e6594a8SSascha Wildner { "r12", &ddb_regs.tf_r12, NULL },
1150e6594a8SSascha Wildner { "r13", &ddb_regs.tf_r13, NULL },
1160e6594a8SSascha Wildner { "r14", &ddb_regs.tf_r14, NULL },
1170e6594a8SSascha Wildner { "r15", &ddb_regs.tf_r15, NULL },
1180e6594a8SSascha Wildner { "dr0", NULL, db_dr0 },
1190e6594a8SSascha Wildner { "dr1", NULL, db_dr1 },
1200e6594a8SSascha Wildner { "dr2", NULL, db_dr2 },
1210e6594a8SSascha Wildner { "dr3", NULL, db_dr3 },
1220e6594a8SSascha Wildner { "dr4", NULL, db_dr4 },
1230e6594a8SSascha Wildner { "dr5", NULL, db_dr5 },
1240e6594a8SSascha Wildner { "dr6", NULL, db_dr6 },
1250e6594a8SSascha Wildner { "dr7", NULL, db_dr7 },
1260e6594a8SSascha Wildner };
127c157ff7aSSascha Wildner struct db_variable *db_eregs = db_regs + NELEM(db_regs);
1280e6594a8SSascha Wildner
1290e6594a8SSascha Wildner /*
1300e6594a8SSascha Wildner * Stack trace.
1310e6594a8SSascha Wildner */
1320e6594a8SSascha Wildner #define INKERNEL(va) (((vm_offset_t)(va)) >= USRSTACK)
1330e6594a8SSascha Wildner
134a76ca9b9SSascha Wildner struct x86_64_frame {
135a76ca9b9SSascha Wildner struct x86_64_frame *f_frame;
1360e6594a8SSascha Wildner long f_retaddr;
1370e6594a8SSascha Wildner long f_arg0;
1380e6594a8SSascha Wildner };
1390e6594a8SSascha Wildner
1400e6594a8SSascha Wildner #define NORMAL 0
1410e6594a8SSascha Wildner #define TRAP 1
1420e6594a8SSascha Wildner #define INTERRUPT 2
1430e6594a8SSascha Wildner #define SYSCALL 3
1440e6594a8SSascha Wildner
145a76ca9b9SSascha Wildner static void db_nextframe(struct x86_64_frame **, db_addr_t *);
146a76ca9b9SSascha Wildner static int db_numargs(struct x86_64_frame *);
1470e6594a8SSascha Wildner static void db_print_stack_entry(const char *, int, char **, long *, db_addr_t);
1480e6594a8SSascha Wildner static void dl_symbol_values(long callpc, const char **name);
1490e6594a8SSascha Wildner
1500e6594a8SSascha Wildner
1510e6594a8SSascha Wildner static char *watchtype_str(int type);
152a76ca9b9SSascha Wildner static int kx86_64_set_watch(int watchnum, unsigned int watchaddr,
1530e6594a8SSascha Wildner int size, int access, struct dbreg * d);
154a76ca9b9SSascha Wildner static int kx86_64_clr_watch(int watchnum, struct dbreg * d);
1550e6594a8SSascha Wildner int db_md_set_watchpoint(db_expr_t addr, db_expr_t size);
1560e6594a8SSascha Wildner int db_md_clr_watchpoint(db_expr_t addr, db_expr_t size);
1570e6594a8SSascha Wildner void db_md_list_watchpoints(void);
1580e6594a8SSascha Wildner
1590e6594a8SSascha Wildner
1600e6594a8SSascha Wildner /*
1610e6594a8SSascha Wildner * Figure out how many arguments were passed into the frame at "fp".
1620e6594a8SSascha Wildner */
1630e6594a8SSascha Wildner static int
db_numargs(struct x86_64_frame * fp)164a76ca9b9SSascha Wildner db_numargs(struct x86_64_frame *fp)
1650e6594a8SSascha Wildner {
1660e6594a8SSascha Wildner #if 1
1670e6594a8SSascha Wildner return (0); /* regparm, needs dwarf2 info */
1680e6594a8SSascha Wildner #else
1690e6594a8SSascha Wildner int args;
1700e6594a8SSascha Wildner #if 0
1710e6594a8SSascha Wildner int *argp;
1720e6594a8SSascha Wildner int inst;
1730e6594a8SSascha Wildner
1740e6594a8SSascha Wildner argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
1750e6594a8SSascha Wildner /*
1760e6594a8SSascha Wildner * XXX etext is wrong for LKMs. We should attempt to interpret
1770e6594a8SSascha Wildner * the instruction at the return address in all cases. This
1780e6594a8SSascha Wildner * may require better fault handling.
1790e6594a8SSascha Wildner */
1800e6594a8SSascha Wildner if (argp < (int *)btext || argp >= (int *)etext) {
1810e6594a8SSascha Wildner args = 5;
1820e6594a8SSascha Wildner } else {
1830e6594a8SSascha Wildner inst = db_get_value((int)argp, 4, FALSE);
1840e6594a8SSascha Wildner if ((inst & 0xff) == 0x59) /* popl %ecx */
1850e6594a8SSascha Wildner args = 1;
1860e6594a8SSascha Wildner else if ((inst & 0xffff) == 0xc483) /* addl $Ibs, %esp */
1870e6594a8SSascha Wildner args = ((inst >> 16) & 0xff) / 4;
1880e6594a8SSascha Wildner else
1890e6594a8SSascha Wildner args = 5;
1900e6594a8SSascha Wildner }
1910e6594a8SSascha Wildner #endif
1920e6594a8SSascha Wildner args = 5;
1930e6594a8SSascha Wildner return(args);
1940e6594a8SSascha Wildner #endif
1950e6594a8SSascha Wildner }
1960e6594a8SSascha Wildner
1970e6594a8SSascha Wildner static void
db_print_stack_entry(const char * name,int narg,char ** argnp,long * argp,db_addr_t callpc)1980e6594a8SSascha Wildner db_print_stack_entry(const char *name, int narg, char **argnp, long *argp,
1990e6594a8SSascha Wildner db_addr_t callpc)
2000e6594a8SSascha Wildner {
2010e6594a8SSascha Wildner db_printf("%s(", name);
2020e6594a8SSascha Wildner while (narg) {
2030e6594a8SSascha Wildner if (argnp)
2040e6594a8SSascha Wildner db_printf("%s=", *argnp++);
2050e6594a8SSascha Wildner db_printf("%ld", (long)db_get_value((long)argp, 8, FALSE));
2060e6594a8SSascha Wildner argp++;
2070e6594a8SSascha Wildner if (--narg != 0)
2080e6594a8SSascha Wildner db_printf(",");
2090e6594a8SSascha Wildner }
2100e6594a8SSascha Wildner db_printf(") at ");
2110e6594a8SSascha Wildner db_printsym(callpc, DB_STGY_PROC);
2120e6594a8SSascha Wildner db_printf("\n");
2130e6594a8SSascha Wildner }
2140e6594a8SSascha Wildner
2150e6594a8SSascha Wildner /*
2160e6594a8SSascha Wildner * Figure out the next frame up in the call stack.
2170e6594a8SSascha Wildner */
2180e6594a8SSascha Wildner static void
db_nextframe(struct x86_64_frame ** fp,db_addr_t * ip)219a76ca9b9SSascha Wildner db_nextframe(struct x86_64_frame **fp, db_addr_t *ip)
2200e6594a8SSascha Wildner {
2210e6594a8SSascha Wildner struct trapframe *tf;
2220e6594a8SSascha Wildner int frame_type;
2230e6594a8SSascha Wildner long rip, rsp, rbp;
2240e6594a8SSascha Wildner db_expr_t offset;
2250e6594a8SSascha Wildner const char *sym, *name;
2260e6594a8SSascha Wildner
2270e6594a8SSascha Wildner if ((unsigned long)*fp < PAGE_SIZE) {
2280e6594a8SSascha Wildner *fp = NULL;
2290e6594a8SSascha Wildner return;
2300e6594a8SSascha Wildner }
2310e6594a8SSascha Wildner rip = db_get_value((long) &(*fp)->f_retaddr, 8, FALSE);
2320e6594a8SSascha Wildner rbp = db_get_value((long) &(*fp)->f_frame, 8, FALSE);
2330e6594a8SSascha Wildner
2340e6594a8SSascha Wildner /*
2350e6594a8SSascha Wildner * Figure out frame type.
2360e6594a8SSascha Wildner */
2370e6594a8SSascha Wildner
2380e6594a8SSascha Wildner frame_type = NORMAL;
2390e6594a8SSascha Wildner
2400e6594a8SSascha Wildner sym = db_search_symbol(rip, DB_STGY_ANY, &offset);
2410e6594a8SSascha Wildner db_symbol_values(sym, &name, NULL);
2420e6594a8SSascha Wildner dl_symbol_values(rip, &name);
2430e6594a8SSascha Wildner if (name != NULL) {
2440e6594a8SSascha Wildner if (!strcmp(name, "calltrap")) {
2450e6594a8SSascha Wildner frame_type = TRAP;
2460e6594a8SSascha Wildner } else if (!strncmp(name, "Xresume", 7)) {
2470e6594a8SSascha Wildner frame_type = INTERRUPT;
2480e6594a8SSascha Wildner } else if (!strcmp(name, "_Xsyscall")) {
2490e6594a8SSascha Wildner frame_type = SYSCALL;
2500e6594a8SSascha Wildner }
2510e6594a8SSascha Wildner }
2520e6594a8SSascha Wildner
2530e6594a8SSascha Wildner /*
2540e6594a8SSascha Wildner * Normal frames need no special processing.
2550e6594a8SSascha Wildner */
2560e6594a8SSascha Wildner if (frame_type == NORMAL) {
2570e6594a8SSascha Wildner *ip = (db_addr_t) rip;
258a76ca9b9SSascha Wildner *fp = (struct x86_64_frame *) rbp;
2590e6594a8SSascha Wildner return;
2600e6594a8SSascha Wildner }
2610e6594a8SSascha Wildner
2620e6594a8SSascha Wildner db_print_stack_entry(name, 0, 0, 0, rip);
2630e6594a8SSascha Wildner
2640e6594a8SSascha Wildner /*
2650e6594a8SSascha Wildner * Point to base of trapframe which is just above the
2660e6594a8SSascha Wildner * current frame.
2670e6594a8SSascha Wildner */
2680e6594a8SSascha Wildner tf = (struct trapframe *)((long)*fp + 16);
2690e6594a8SSascha Wildner
2700e6594a8SSascha Wildner #if 0
2710e6594a8SSascha Wildner rsp = (ISPL(tf->tf_cs) == SEL_UPL) ? tf->tf_rsp : (long)&tf->tf_rsp;
2720e6594a8SSascha Wildner #endif
2730e6594a8SSascha Wildner rsp = (long)&tf->tf_rsp;
2740e6594a8SSascha Wildner
2750e6594a8SSascha Wildner switch (frame_type) {
2760e6594a8SSascha Wildner case TRAP:
2770e6594a8SSascha Wildner {
2780e6594a8SSascha Wildner rip = tf->tf_rip;
2790e6594a8SSascha Wildner rbp = tf->tf_rbp;
2800e6594a8SSascha Wildner db_printf(
2810e6594a8SSascha Wildner "--- trap %016lx, rip = %016lx, rsp = %016lx, rbp = %016lx ---\n",
2820e6594a8SSascha Wildner tf->tf_trapno, rip, rsp, rbp);
2830e6594a8SSascha Wildner }
2840e6594a8SSascha Wildner break;
2850e6594a8SSascha Wildner case SYSCALL:
2860e6594a8SSascha Wildner {
2870e6594a8SSascha Wildner rip = tf->tf_rip;
2880e6594a8SSascha Wildner rbp = tf->tf_rbp;
2890e6594a8SSascha Wildner db_printf(
2900e6594a8SSascha Wildner "--- syscall %016lx, rip = %016lx, rsp = %016lx, rbp = %016lx ---\n",
2910e6594a8SSascha Wildner tf->tf_rax, rip, rsp, rbp);
2920e6594a8SSascha Wildner }
2930e6594a8SSascha Wildner break;
2940e6594a8SSascha Wildner case INTERRUPT:
2950e6594a8SSascha Wildner tf = (struct trapframe *)((long)*fp + 16);
2960e6594a8SSascha Wildner {
2970e6594a8SSascha Wildner rip = tf->tf_rip;
2980e6594a8SSascha Wildner rbp = tf->tf_rbp;
2990e6594a8SSascha Wildner db_printf(
3000e6594a8SSascha Wildner "--- interrupt, rip = %016lx, rsp = %016lx, rbp = %016lx ---\n",
3010e6594a8SSascha Wildner rip, rsp, rbp);
3020e6594a8SSascha Wildner }
3030e6594a8SSascha Wildner break;
3040e6594a8SSascha Wildner default:
3050e6594a8SSascha Wildner break;
3060e6594a8SSascha Wildner }
3070e6594a8SSascha Wildner
3080e6594a8SSascha Wildner *ip = (db_addr_t) rip;
309a76ca9b9SSascha Wildner *fp = (struct x86_64_frame *) rbp;
3100e6594a8SSascha Wildner }
3110e6594a8SSascha Wildner
3120e6594a8SSascha Wildner void
db_stack_trace_cmd(db_expr_t addr,boolean_t have_addr,db_expr_t count,char * modif)3130e6594a8SSascha Wildner db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
3140e6594a8SSascha Wildner char *modif)
3150e6594a8SSascha Wildner {
316a76ca9b9SSascha Wildner struct x86_64_frame *frame;
3170e6594a8SSascha Wildner long *argp;
3180e6594a8SSascha Wildner db_addr_t callpc;
3190e6594a8SSascha Wildner boolean_t first;
3200e6594a8SSascha Wildner int i;
3210e6594a8SSascha Wildner
3220e6594a8SSascha Wildner if (count == -1)
3230e6594a8SSascha Wildner count = 1024;
3240e6594a8SSascha Wildner
3250e6594a8SSascha Wildner if (!have_addr) {
326a76ca9b9SSascha Wildner frame = (struct x86_64_frame *)BP_REGS(&ddb_regs);
3270e6594a8SSascha Wildner if (frame == NULL)
328a76ca9b9SSascha Wildner frame = (struct x86_64_frame *)(SP_REGS(&ddb_regs) - 8);
3290e6594a8SSascha Wildner callpc = PC_REGS(&ddb_regs);
3300e6594a8SSascha Wildner } else {
3310e6594a8SSascha Wildner /*
3320e6594a8SSascha Wildner * Look for something that might be a frame pointer, just as
3330e6594a8SSascha Wildner * a convenience.
3340e6594a8SSascha Wildner */
335a76ca9b9SSascha Wildner frame = (struct x86_64_frame *)addr;
3360e6594a8SSascha Wildner for (i = 0; i < 4096; i += 8) {
337a76ca9b9SSascha Wildner struct x86_64_frame *check;
3380e6594a8SSascha Wildner
339a76ca9b9SSascha Wildner check = (struct x86_64_frame *)db_get_value((long)((char *)&frame->f_frame + i), 8, FALSE);
3400e6594a8SSascha Wildner if ((char *)check - (char *)frame >= 0 &&
3410e6594a8SSascha Wildner (char *)check - (char *)frame < 4096
3420e6594a8SSascha Wildner ) {
3430e6594a8SSascha Wildner break;
3440e6594a8SSascha Wildner }
3450e6594a8SSascha Wildner db_printf("%p does not look like a stack frame, skipping\n", (char *)&frame->f_frame + i);
3460e6594a8SSascha Wildner }
3470e6594a8SSascha Wildner if (i == 4096) {
3480e6594a8SSascha Wildner db_printf("Unable to find anything that looks like a stack frame\n");
3490e6594a8SSascha Wildner return;
3500e6594a8SSascha Wildner }
3510e6594a8SSascha Wildner frame = (void *)((char *)frame + i);
3520e6594a8SSascha Wildner db_printf("Trace beginning at frame %p\n", frame);
3530e6594a8SSascha Wildner callpc = (db_addr_t)db_get_value((long)&frame->f_retaddr, 8, FALSE);
3540e6594a8SSascha Wildner }
3550e6594a8SSascha Wildner
3560e6594a8SSascha Wildner first = TRUE;
3570e6594a8SSascha Wildner while (count--) {
358a76ca9b9SSascha Wildner struct x86_64_frame *actframe;
3590e6594a8SSascha Wildner int narg;
3600e6594a8SSascha Wildner const char * name;
3610e6594a8SSascha Wildner db_expr_t offset;
3620e6594a8SSascha Wildner c_db_sym_t sym;
3630e6594a8SSascha Wildner #define MAXNARG 16
3640e6594a8SSascha Wildner char *argnames[MAXNARG], **argnp = NULL;
3650e6594a8SSascha Wildner
3660e6594a8SSascha Wildner sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
3670e6594a8SSascha Wildner db_symbol_values(sym, &name, NULL);
3680e6594a8SSascha Wildner dl_symbol_values(callpc, &name);
3690e6594a8SSascha Wildner
3700e6594a8SSascha Wildner /*
3710e6594a8SSascha Wildner * Attempt to determine a (possibly fake) frame that gives
3720e6594a8SSascha Wildner * the caller's pc. It may differ from `frame' if the
3730e6594a8SSascha Wildner * current function never sets up a standard frame or hasn't
3740e6594a8SSascha Wildner * set one up yet or has just discarded one. The last two
3750e6594a8SSascha Wildner * cases can be guessed fairly reliably for code generated
3760e6594a8SSascha Wildner * by gcc. The first case is too much trouble to handle in
3770e6594a8SSascha Wildner * general because the amount of junk on the stack depends
3780e6594a8SSascha Wildner * on the pc (the special handling of "calltrap", etc. in
3790e6594a8SSascha Wildner * db_nextframe() works because the `next' pc is special).
3800e6594a8SSascha Wildner */
3810e6594a8SSascha Wildner actframe = frame;
3820e6594a8SSascha Wildner if (first) {
3830e6594a8SSascha Wildner if (!have_addr) {
3840e6594a8SSascha Wildner int instr;
3850e6594a8SSascha Wildner
3860e6594a8SSascha Wildner instr = db_get_value(callpc, 4, FALSE);
3870e6594a8SSascha Wildner if ((instr & 0xffffffff) == 0xe5894855) {
3880e6594a8SSascha Wildner /* pushq %rbp; movq %rsp, %rbp */
389a76ca9b9SSascha Wildner actframe = (struct x86_64_frame *)
3900e6594a8SSascha Wildner (SP_REGS(&ddb_regs) - 8);
3910e6594a8SSascha Wildner } else if ((instr & 0xffffff) == 0xe58948) {
3920e6594a8SSascha Wildner /* movq %rsp, %rbp */
393a76ca9b9SSascha Wildner actframe = (struct x86_64_frame *)
3940e6594a8SSascha Wildner SP_REGS(&ddb_regs);
3950e6594a8SSascha Wildner if (ddb_regs.tf_rbp == 0) {
3960e6594a8SSascha Wildner /* Fake caller's frame better. */
3970e6594a8SSascha Wildner frame = actframe;
3980e6594a8SSascha Wildner }
3990e6594a8SSascha Wildner } else if ((instr & 0xff) == 0xc3) {
4000e6594a8SSascha Wildner /* ret */
401a76ca9b9SSascha Wildner actframe = (struct x86_64_frame *)
4020e6594a8SSascha Wildner (SP_REGS(&ddb_regs) - 8);
4030e6594a8SSascha Wildner } else if (offset == 0) {
4040e6594a8SSascha Wildner /* Probably a symbol in assembler code. */
405a76ca9b9SSascha Wildner actframe = (struct x86_64_frame *)
4060e6594a8SSascha Wildner (SP_REGS(&ddb_regs) - 8);
4070e6594a8SSascha Wildner }
4080e6594a8SSascha Wildner } else if (name != NULL &&
4090e6594a8SSascha Wildner strcmp(name, "fork_trampoline") == 0) {
4100e6594a8SSascha Wildner /*
4110e6594a8SSascha Wildner * Don't try to walk back on a stack for a
4120e6594a8SSascha Wildner * process that hasn't actually been run yet.
4130e6594a8SSascha Wildner */
4140e6594a8SSascha Wildner db_print_stack_entry(name, 0, 0, 0, callpc);
4150e6594a8SSascha Wildner break;
4160e6594a8SSascha Wildner }
4170e6594a8SSascha Wildner first = FALSE;
4180e6594a8SSascha Wildner }
4190e6594a8SSascha Wildner
4200e6594a8SSascha Wildner argp = &actframe->f_arg0;
4210e6594a8SSascha Wildner narg = MAXNARG;
4220e6594a8SSascha Wildner if (sym != NULL && db_sym_numargs(sym, &narg, argnames)) {
4230e6594a8SSascha Wildner argnp = argnames;
4240e6594a8SSascha Wildner } else {
4250e6594a8SSascha Wildner narg = db_numargs(frame);
4260e6594a8SSascha Wildner }
4270e6594a8SSascha Wildner
4280e6594a8SSascha Wildner db_print_stack_entry(name, narg, argnp, argp, callpc);
4290e6594a8SSascha Wildner
4300e6594a8SSascha Wildner if (actframe != frame) {
4310e6594a8SSascha Wildner /* `frame' belongs to caller. */
4320e6594a8SSascha Wildner callpc = (db_addr_t)
4330e6594a8SSascha Wildner db_get_value((long)&actframe->f_retaddr, 8, FALSE);
4340e6594a8SSascha Wildner continue;
4350e6594a8SSascha Wildner }
4360e6594a8SSascha Wildner
4370e6594a8SSascha Wildner db_nextframe(&frame, &callpc);
438*4090d6ffSSascha Wildner if (frame == NULL)
4390e6594a8SSascha Wildner break;
4400e6594a8SSascha Wildner }
4410e6594a8SSascha Wildner }
4420e6594a8SSascha Wildner
4430e6594a8SSascha Wildner void
print_backtrace(int count)4447ce2998eSAlex Hornung print_backtrace(int count)
4450e6594a8SSascha Wildner {
4460e6594a8SSascha Wildner register_t rbp;
4470e6594a8SSascha Wildner
4480e6594a8SSascha Wildner __asm __volatile("movq %%rbp, %0" : "=r" (rbp));
4497ce2998eSAlex Hornung db_stack_trace_cmd(rbp, 1, count, NULL);
4500e6594a8SSascha Wildner }
4510e6594a8SSascha Wildner
4520e6594a8SSascha Wildner #define DB_DRX_FUNC(reg) \
4530e6594a8SSascha Wildner int \
4540e6594a8SSascha Wildner db_ ## reg (struct db_variable *vp, db_expr_t *valuep, int op) \
4550e6594a8SSascha Wildner { \
4560e6594a8SSascha Wildner if (op == DB_VAR_GET) \
4570e6594a8SSascha Wildner *valuep = r ## reg (); \
4580e6594a8SSascha Wildner else \
4590e6594a8SSascha Wildner load_ ## reg (*valuep); \
4600e6594a8SSascha Wildner \
4610e6594a8SSascha Wildner return(0); \
4620e6594a8SSascha Wildner }
4630e6594a8SSascha Wildner
4640e6594a8SSascha Wildner DB_DRX_FUNC(dr0)
DB_DRX_FUNC(dr1)4650e6594a8SSascha Wildner DB_DRX_FUNC(dr1)
4660e6594a8SSascha Wildner DB_DRX_FUNC(dr2)
4670e6594a8SSascha Wildner DB_DRX_FUNC(dr3)
4680e6594a8SSascha Wildner DB_DRX_FUNC(dr4)
4690e6594a8SSascha Wildner DB_DRX_FUNC(dr5)
4700e6594a8SSascha Wildner DB_DRX_FUNC(dr6)
4710e6594a8SSascha Wildner DB_DRX_FUNC(dr7)
4720e6594a8SSascha Wildner
4730e6594a8SSascha Wildner static int
474a76ca9b9SSascha Wildner kx86_64_set_watch(int watchnum, unsigned int watchaddr, int size, int access,
4750e6594a8SSascha Wildner struct dbreg *d)
4760e6594a8SSascha Wildner {
4770e6594a8SSascha Wildner int i;
4780e6594a8SSascha Wildner unsigned int mask;
4790e6594a8SSascha Wildner
4800e6594a8SSascha Wildner if (watchnum == -1) {
4810e6594a8SSascha Wildner for (i = 0, mask = 0x3; i < 4; i++, mask <<= 2)
4820e6594a8SSascha Wildner if ((d->dr[7] & mask) == 0)
4830e6594a8SSascha Wildner break;
4840e6594a8SSascha Wildner if (i < 4)
4850e6594a8SSascha Wildner watchnum = i;
4860e6594a8SSascha Wildner else
4870e6594a8SSascha Wildner return(-1);
4880e6594a8SSascha Wildner }
4890e6594a8SSascha Wildner
4900e6594a8SSascha Wildner switch (access) {
4910e6594a8SSascha Wildner case DBREG_DR7_EXEC:
4920e6594a8SSascha Wildner size = 1; /* size must be 1 for an execution breakpoint */
4930e6594a8SSascha Wildner /* fall through */
4940e6594a8SSascha Wildner case DBREG_DR7_WRONLY:
4950e6594a8SSascha Wildner case DBREG_DR7_RDWR:
4960e6594a8SSascha Wildner break;
4970e6594a8SSascha Wildner default:
4980e6594a8SSascha Wildner return(-1);
4990e6594a8SSascha Wildner }
5000e6594a8SSascha Wildner
5010e6594a8SSascha Wildner /*
5020e6594a8SSascha Wildner * we can watch a 1, 2, 4, or 8 byte sized location
5030e6594a8SSascha Wildner */
5040e6594a8SSascha Wildner switch (size) {
5050e6594a8SSascha Wildner case 1:
5060e6594a8SSascha Wildner mask = 0x00;
5070e6594a8SSascha Wildner break;
5080e6594a8SSascha Wildner case 2:
5090e6594a8SSascha Wildner mask = 0x01 << 2;
5100e6594a8SSascha Wildner break;
5110e6594a8SSascha Wildner case 4:
5120e6594a8SSascha Wildner mask = 0x03 << 2;
5130da449fcSSascha Wildner break;
5140e6594a8SSascha Wildner case 8:
5150e6594a8SSascha Wildner mask = 0x02 << 2;
5160e6594a8SSascha Wildner break;
5170e6594a8SSascha Wildner default:
5180e6594a8SSascha Wildner return(-1);
5190e6594a8SSascha Wildner }
5200e6594a8SSascha Wildner
5210e6594a8SSascha Wildner mask |= access;
5220e6594a8SSascha Wildner
5230e6594a8SSascha Wildner /* clear the bits we are about to affect */
5240e6594a8SSascha Wildner d->dr[7] &= ~((0x3 << (watchnum * 2)) | (0x0f << (watchnum * 4 + 16)));
5250e6594a8SSascha Wildner
5260e6594a8SSascha Wildner /* set drN register to the address, N=watchnum */
5270e6594a8SSascha Wildner DBREG_DRX(d, watchnum) = watchaddr;
5280e6594a8SSascha Wildner
5290e6594a8SSascha Wildner /* enable the watchpoint */
5300e6594a8SSascha Wildner d->dr[7] |= (0x2 << (watchnum * 2)) | (mask << (watchnum * 4 + 16));
5310e6594a8SSascha Wildner
5320e6594a8SSascha Wildner return(watchnum);
5330e6594a8SSascha Wildner }
5340e6594a8SSascha Wildner
5350e6594a8SSascha Wildner
5360e6594a8SSascha Wildner int
kx86_64_clr_watch(int watchnum,struct dbreg * d)537a76ca9b9SSascha Wildner kx86_64_clr_watch(int watchnum, struct dbreg *d)
5380e6594a8SSascha Wildner {
5390e6594a8SSascha Wildner if (watchnum < 0 || watchnum >= 4)
5400e6594a8SSascha Wildner return(-1);
5410e6594a8SSascha Wildner
5420e6594a8SSascha Wildner d->dr[7] &= ~((0x3 << (watchnum * 2)) | (0x0f << (watchnum * 4 + 16)));
5430e6594a8SSascha Wildner DBREG_DRX(d, watchnum) = 0;
5440e6594a8SSascha Wildner
5450e6594a8SSascha Wildner return(0);
5460e6594a8SSascha Wildner }
5470e6594a8SSascha Wildner
5480e6594a8SSascha Wildner
5490e6594a8SSascha Wildner int
db_md_set_watchpoint(db_expr_t addr,db_expr_t size)5500e6594a8SSascha Wildner db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
5510e6594a8SSascha Wildner {
5520e6594a8SSascha Wildner int avail, wsize;
5530e6594a8SSascha Wildner int i;
5540e6594a8SSascha Wildner struct dbreg d;
5550e6594a8SSascha Wildner
5560e6594a8SSascha Wildner fill_dbregs(NULL, &d);
5570e6594a8SSascha Wildner
5580e6594a8SSascha Wildner avail = 0;
5590e6594a8SSascha Wildner for (i = 0; i < 4; i++) {
5600e6594a8SSascha Wildner if ((d.dr[7] & (3 << (i * 2))) == 0)
5610e6594a8SSascha Wildner avail++;
5620e6594a8SSascha Wildner }
5630e6594a8SSascha Wildner
5640e6594a8SSascha Wildner if (avail * 8 < size)
5650e6594a8SSascha Wildner return(-1);
5660e6594a8SSascha Wildner
5670e6594a8SSascha Wildner for (i=0; i < 4 && (size != 0); i++) {
5680e6594a8SSascha Wildner if ((d.dr[7] & (3 << (i * 2))) == 0) {
5690e6594a8SSascha Wildner if (size >= 8 || (avail == 1 && size > 4))
5700e6594a8SSascha Wildner wsize = 8;
5710e6594a8SSascha Wildner else if (size > 2)
5720e6594a8SSascha Wildner wsize = 4;
5730e6594a8SSascha Wildner else
5740e6594a8SSascha Wildner wsize = size;
5750e6594a8SSascha Wildner if (wsize == 3)
5760e6594a8SSascha Wildner wsize++;
577a76ca9b9SSascha Wildner kx86_64_set_watch(i, addr, wsize, DBREG_DR7_WRONLY, &d);
5780e6594a8SSascha Wildner addr += wsize;
5790e6594a8SSascha Wildner size -= wsize;
5800e6594a8SSascha Wildner }
5810e6594a8SSascha Wildner }
5820e6594a8SSascha Wildner
5830e6594a8SSascha Wildner set_dbregs(NULL, &d);
5840e6594a8SSascha Wildner
5850e6594a8SSascha Wildner return(0);
5860e6594a8SSascha Wildner }
5870e6594a8SSascha Wildner
5880e6594a8SSascha Wildner int
db_md_clr_watchpoint(db_expr_t addr,db_expr_t size)5890e6594a8SSascha Wildner db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
5900e6594a8SSascha Wildner {
5910e6594a8SSascha Wildner struct dbreg d;
5920e6594a8SSascha Wildner int i;
5930e6594a8SSascha Wildner
5940e6594a8SSascha Wildner fill_dbregs(NULL, &d);
5950e6594a8SSascha Wildner
5960e6594a8SSascha Wildner for(i = 0; i < 4; i++) {
5970e6594a8SSascha Wildner if (d.dr[7] & (3 << (i * 2))) {
5980e6594a8SSascha Wildner if ((DBREG_DRX((&d), i) >= addr) &&
5990e6594a8SSascha Wildner (DBREG_DRX((&d), i) < addr + size))
600a76ca9b9SSascha Wildner kx86_64_clr_watch(i, &d);
6010e6594a8SSascha Wildner }
6020e6594a8SSascha Wildner }
6030e6594a8SSascha Wildner
6040e6594a8SSascha Wildner set_dbregs(NULL, &d);
6050e6594a8SSascha Wildner
6060e6594a8SSascha Wildner return(0);
6070e6594a8SSascha Wildner }
6080e6594a8SSascha Wildner
6090e6594a8SSascha Wildner static char *
watchtype_str(int type)6100e6594a8SSascha Wildner watchtype_str(int type)
6110e6594a8SSascha Wildner {
6120e6594a8SSascha Wildner switch (type) {
6130e6594a8SSascha Wildner case DBREG_DR7_EXEC:
6140e6594a8SSascha Wildner return "execute";
6150e6594a8SSascha Wildner case DBREG_DR7_RDWR:
6160e6594a8SSascha Wildner return "read/write";
6170e6594a8SSascha Wildner case DBREG_DR7_WRONLY:
6180e6594a8SSascha Wildner return "write";
6190e6594a8SSascha Wildner default:
6200e6594a8SSascha Wildner return "invalid";
6210e6594a8SSascha Wildner }
6220e6594a8SSascha Wildner }
6230e6594a8SSascha Wildner
6240e6594a8SSascha Wildner void
db_md_list_watchpoints(void)6250e6594a8SSascha Wildner db_md_list_watchpoints(void)
6260e6594a8SSascha Wildner {
6270e6594a8SSascha Wildner int i;
6280e6594a8SSascha Wildner struct dbreg d;
6290e6594a8SSascha Wildner
6300e6594a8SSascha Wildner fill_dbregs(NULL, &d);
6310e6594a8SSascha Wildner
6320e6594a8SSascha Wildner db_printf("\nhardware watchpoints:\n");
6330e6594a8SSascha Wildner db_printf(" watch status type len address\n"
6340e6594a8SSascha Wildner " ----- -------- ---------- --- ----------\n");
6350e6594a8SSascha Wildner for (i = 0; i < 4; i++) {
6360e6594a8SSascha Wildner if (d.dr[7] & (0x03 << (i * 2))) {
6370e6594a8SSascha Wildner unsigned type, len;
6380e6594a8SSascha Wildner type = (d.dr[7] >> (16 + (i * 4))) & 3;
6390e6594a8SSascha Wildner len = (d.dr[7] >> (16 + (i * 4) + 2)) & 3;
6400e6594a8SSascha Wildner db_printf(" %-5d %-8s %10s %3d 0x%08lx\n",
6410e6594a8SSascha Wildner i, "enabled", watchtype_str(type),
6420e6594a8SSascha Wildner len + 1, DBREG_DRX((&d), i));
6430e6594a8SSascha Wildner } else {
6440e6594a8SSascha Wildner db_printf(" %-5d disabled\n", i);
6450e6594a8SSascha Wildner }
6460e6594a8SSascha Wildner }
6470e6594a8SSascha Wildner
6480e6594a8SSascha Wildner db_printf("\ndebug register values:\n");
6490e6594a8SSascha Wildner for (i = 0; i < 8; i++)
6500e6594a8SSascha Wildner db_printf(" dr%d 0x%08lx\n", i, DBREG_DRX((&d),i));
6510e6594a8SSascha Wildner db_printf("\n");
6520e6594a8SSascha Wildner }
6530e6594a8SSascha Wildner
6540e6594a8SSascha Wildner /*
6550e6594a8SSascha Wildner * See if dladdr() can get the symbol name via the standard dynamic loader.
6560e6594a8SSascha Wildner */
6570e6594a8SSascha Wildner static
6580e6594a8SSascha Wildner void
dl_symbol_values(long callpc,const char ** name)6590e6594a8SSascha Wildner dl_symbol_values(long callpc, const char **name)
6600e6594a8SSascha Wildner {
6610e6594a8SSascha Wildner Dl_info info;
6620e6594a8SSascha Wildner
6630e6594a8SSascha Wildner if (*name == NULL) {
6640e6594a8SSascha Wildner if (dladdr((const void *)callpc, &info) != 0) {
6650e6594a8SSascha Wildner if (info.dli_saddr <= (const void *)callpc)
6660e6594a8SSascha Wildner *name = info.dli_sname;
6670e6594a8SSascha Wildner }
6680e6594a8SSascha Wildner }
6690e6594a8SSascha Wildner }
670