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