1/* $OpenBSD: db_trace.c,v 1.16 2021/03/25 04:12:00 jsg Exp $ */ 2/* $NetBSD: db_trace.c,v 1.8 2003/01/17 22:28:48 thorpej Exp $ */ 3 4/* 5 * Copyright (c) 2000, 2001 Ben Harris 6 * Copyright (c) 1996 Scott K. Stevens 7 * 8 * Mach Operating System 9 * Copyright (c) 1991,1990 Carnegie Mellon University 10 * All Rights Reserved. 11 * 12 * Permission to use, copy, modify and distribute this software and its 13 * documentation is hereby granted, provided that both the copyright 14 * notice and this permission notice appear in all copies of the 15 * software, derivative works or modified versions, and any portions 16 * thereof, and that both notices appear in supporting documentation. 17 * 18 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 19 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 20 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 21 * 22 * Carnegie Mellon requests users of this software to return to 23 * 24 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 25 * School of Computer Science 26 * Carnegie Mellon University 27 * Pittsburgh PA 15213-3890 28 * 29 * any improvements or extensions that they make and grant Carnegie the 30 * rights to redistribute these changes. 31 */ 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/proc.h> 36#include <sys/user.h> 37#include <machine/db_machdep.h> 38 39#include <ddb/db_interface.h> 40#include <ddb/db_sym.h> 41#include <ddb/db_output.h> 42 43db_regs_t ddb_regs; 44 45#define INKERNEL(va) (((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS) 46 47/* 48 * return link value [fp, #+4] 49 * return fp value [fp] <- fp points to here 50 */ 51#define FR_RFP (0) 52#define FR_RLV (+1) 53 54void 55db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, 56 char *modif, int (*pr)(const char *, ...)) 57{ 58 u_int32_t *frame, *lastframe; 59 char c, *cp = modif; 60 int kernel_only = 1; 61 int trace_thread = 0; 62 vaddr_t scp; 63 64 while ((c = *cp++) != 0) { 65 if (c == 'u') 66 kernel_only = 0; 67 if (c == 't') 68 trace_thread = 1; 69 } 70 71 if (!have_addr) { 72 frame = (u_int32_t *)(ddb_regs.tf_r11); 73 scp = ddb_regs.tf_pc; 74 } else { 75 if (trace_thread) { 76 struct proc *p; 77 struct user *u; 78 (*pr) ("trace: pid %d ", (int)addr); 79 p = tfind(addr); 80 if (p == NULL) { 81 (*pr)("not found\n"); 82 return; 83 } 84 u = p->p_addr; 85 frame = (u_int32_t *)(u->u_pcb.pcb_un.un_32.pcb32_r11); 86 (*pr)("at %p\n", frame); 87 scp = u->u_pcb.pcb_un.un_32.pcb32_pc; 88 } else 89 frame = (u_int32_t *)(addr); 90 } 91 lastframe = NULL; 92 93 while (count-- && frame != NULL) { 94 db_printsym(scp, DB_STGY_PROC, pr); 95 (*pr)("\n\trlv=0x%08x rfp=0x%08x\n", frame[FR_RLV], frame[FR_RFP]); 96 scp = frame[FR_RLV]; 97 98 /* 99 * Switch to next frame up 100 */ 101 if (frame[FR_RFP] == 0) 102 break; /* Top of stack */ 103 104 lastframe = frame; 105 frame = (u_int32_t *)(frame[FR_RFP]); 106 107 if (INKERNEL((int)frame)) { 108 /* staying in kernel */ 109 if (frame <= lastframe) { 110 (*pr)("Bad frame pointer: %p\n", frame); 111 break; 112 } 113 } else if (INKERNEL((int)lastframe)) { 114 /* switch from user to kernel */ 115 if (kernel_only) 116 break; /* kernel stack only */ 117 } else { 118 /* in user */ 119 if (frame <= lastframe) { 120 (*pr)("Bad user frame pointer: %p\n", 121 frame); 122 break; 123 } 124 } 125 } 126} 127