db_trace.c revision 620
155714Skris/*
255714Skris * Mach Operating System
355714Skris * Copyright (c) 1991,1990 Carnegie Mellon University
455714Skris * All Rights Reserved.
555714Skris *
655714Skris * Permission to use, copy, modify and distribute this software and its
755714Skris * documentation is hereby granted, provided that both the copyright
8296341Sdelphij * notice and this permission notice appear in all copies of the
955714Skris * software, derivative works or modified versions, and any portions
1055714Skris * thereof, and that both notices appear in supporting documentation.
1155714Skris *
1255714Skris * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
1355714Skris * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
1455714Skris * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15296341Sdelphij *
1655714Skris * Carnegie Mellon requests users of this software to return to
1755714Skris *
1855714Skris *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
1955714Skris *  School of Computer Science
2055714Skris *  Carnegie Mellon University
2155714Skris *  Pittsburgh PA 15213-3890
22296341Sdelphij *
2355714Skris * any improvements or extensions that they make and grant Carnegie the
2455714Skris * rights to redistribute these changes.
2555714Skris *
2655714Skris *	$Id$
2755714Skris */
2855714Skris
2955714Skris#include "param.h"
3055714Skris#include "proc.h"
3155714Skris#include <machine/db_machdep.h>
3255714Skris
3355714Skris#include <ddb/db_access.h>
3455714Skris#include <ddb/db_sym.h>
3555714Skris#include <ddb/db_variables.h>
3655714Skris
37296341Sdelphij/*
3855714Skris * Machine register set.
3955714Skris */
40296341Sdelphijstruct db_variable db_regs[] = {
4155714Skris	"cs",	(int *)&ddb_regs.tf_cs,  FCN_NULL,
4255714Skris	"ds",	(int *)&ddb_regs.tf_ds,  FCN_NULL,
4355714Skris	"es",	(int *)&ddb_regs.tf_es,  FCN_NULL,
4455714Skris#if 0
4555714Skris	"fs",	(int *)&ddb_regs.tf_fs,  FCN_NULL,
4655714Skris	"gs",	(int *)&ddb_regs.tf_gs,  FCN_NULL,
4755714Skris#endif
4855714Skris	"ss",	(int *)&ddb_regs.tf_ss,  FCN_NULL,
4955714Skris	"eax",	(int *)&ddb_regs.tf_eax, FCN_NULL,
5055714Skris	"ecx",	(int *)&ddb_regs.tf_ecx, FCN_NULL,
5155714Skris	"edx",	(int *)&ddb_regs.tf_edx, FCN_NULL,
52296341Sdelphij	"ebx",	(int *)&ddb_regs.tf_ebx, FCN_NULL,
5355714Skris	"esp",	(int *)&ddb_regs.tf_esp,FCN_NULL,
5455714Skris	"ebp",	(int *)&ddb_regs.tf_ebp, FCN_NULL,
5555714Skris	"esi",	(int *)&ddb_regs.tf_esi, FCN_NULL,
5655714Skris	"edi",	(int *)&ddb_regs.tf_edi, FCN_NULL,
5755714Skris	"eip",	(int *)&ddb_regs.tf_eip, FCN_NULL,
5855714Skris	"efl",	(int *)&ddb_regs.tf_eflags, FCN_NULL,
5955714Skris};
6055714Skrisstruct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
6155714Skris
6255714Skris/*
6355714Skris * Stack trace.
6455714Skris */
6555714Skris#define	INKERNEL(va)	(((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
6655714Skris
6755714Skrisstruct i386_frame {
6855714Skris	struct i386_frame	*f_frame;
69296341Sdelphij	int			f_retaddr;
7055714Skris	int			f_arg0;
7159191Skris};
7259191Skris
7355714Skris#define	TRAP		1
74296341Sdelphij#define	INTERRUPT	2
75296341Sdelphij
76296341Sdelphijdb_addr_t	db_trap_symbol_value = 0;
77296341Sdelphijdb_addr_t	db_kdintr_symbol_value = 0;
7855714Skrisboolean_t	db_trace_symbols_found = FALSE;
79296341Sdelphij
8055714Skrisvoid
81296341Sdelphijdb_find_trace_symbols()
82296341Sdelphij{
83296341Sdelphij	db_expr_t	value;
8455714Skris	if (db_value_of_name("_trap", &value))
85296341Sdelphij	    db_trap_symbol_value = (db_addr_t) value;
8655714Skris	if (db_value_of_name("_kdintr", &value))
87296341Sdelphij	    db_kdintr_symbol_value = (db_addr_t) value;
88296341Sdelphij	db_trace_symbols_found = TRUE;
8955714Skris}
90296341Sdelphij
91296341Sdelphij/*
92109998Smarkm * Figure out how many arguments were passed into the frame at "fp".
93296341Sdelphij */
94296341Sdelphijint
95296341Sdelphijdb_numargs(fp)
96296341Sdelphij	struct i386_frame *fp;
9768651Skris{
98296341Sdelphij	int	*argp;
99296341Sdelphij	int	inst;
100296341Sdelphij	int	args;
101296341Sdelphij	extern char	etext[];
102296341Sdelphij
103296341Sdelphij	argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
104296341Sdelphij	if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext)
105296341Sdelphij	    args = 5;
106296341Sdelphij	else {
107296341Sdelphij	    inst = db_get_value((int)argp, 4, FALSE);
10855714Skris	    if ((inst & 0xff) == 0x59)	/* popl %ecx */
109296341Sdelphij		args = 1;
110296341Sdelphij	    else if ((inst & 0xffff) == 0xc483)	/* addl %n, %esp */
111296341Sdelphij		args = ((inst >> 16) & 0xff) / 4;
112296341Sdelphij	    else
113296341Sdelphij		args = 5;
114296341Sdelphij	}
115296341Sdelphij	return (args);
116296341Sdelphij}
117296341Sdelphij
118296341Sdelphij/*
119296341Sdelphij * Figure out the next frame up in the call stack.
120296341Sdelphij * For trap(), we print the address of the faulting instruction and
121296341Sdelphij *   proceed with the calling frame.  We return the ip that faulted.
122 *   If the trap was caused by jumping through a bogus pointer, then
123 *   the next line in the backtrace will list some random function as
124 *   being called.  It should get the argument list correct, though.
125 *   It might be possible to dig out from the next frame up the name
126 *   of the function that faulted, but that could get hairy.
127 */
128void
129db_nextframe(fp, ip, argp, is_trap)
130	struct i386_frame **fp;		/* in/out */
131	db_addr_t	*ip;		/* out */
132	int *argp;			/* in */
133	int is_trap;			/* in */
134{
135	struct i386_saved_state *saved_regs;
136
137	if (is_trap == 0) {
138	    *ip = (db_addr_t)
139			db_get_value((int) &(*fp)->f_retaddr, 4, FALSE);
140	    *fp = (struct i386_frame *)
141			db_get_value((int) &(*fp)->f_frame, 4, FALSE);
142	} else {
143	    /*
144	     * We know that trap() has 1 argument and we know that
145	     * it is an (int *).
146	     */
147	    saved_regs = (struct i386_saved_state *)
148			db_get_value((int)argp, 4, FALSE);
149	    db_printf("--- trap (number %d) ---\n",
150		      saved_regs->tf_trapno & 0xffff);
151	    db_printsym(saved_regs->tf_eip, DB_STGY_XTRN);
152	    db_printf(":\n");
153	    *fp = (struct i386_frame *)saved_regs->tf_ebp;
154	    *ip = (db_addr_t)saved_regs->tf_eip;
155	}
156
157}
158
159void
160db_stack_trace_cmd(addr, have_addr, count, modif)
161	db_expr_t	addr;
162	boolean_t	have_addr;
163	db_expr_t	count;
164	char		*modif;
165{
166	struct i386_frame *frame, *lastframe;
167	int		*argp;
168	db_addr_t	callpc;
169	int		is_trap;
170	boolean_t	kernel_only = TRUE;
171	boolean_t	trace_thread = FALSE;
172
173	if (!db_trace_symbols_found)
174	    db_find_trace_symbols();
175
176	{
177	    register char *cp = modif;
178	    register char c;
179
180	    while ((c = *cp++) != 0) {
181		if (c == 't')
182		    trace_thread = TRUE;
183		if (c == 'u')
184		    kernel_only = FALSE;
185	    }
186	}
187
188	if (count == -1)
189	    count = 65535;
190
191	if (!have_addr) {
192	    frame = (struct i386_frame *)ddb_regs.tf_ebp;
193	    callpc = (db_addr_t)ddb_regs.tf_eip;
194	}
195	else if (trace_thread) {
196		printf ("db_trace.c: can't trace thread\n");
197	}
198	else {
199	    frame = (struct i386_frame *)addr;
200	    callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
201	}
202
203	lastframe = 0;
204	while (count-- && frame != 0) {
205	    register int narg;
206	    char *	name;
207	    db_expr_t	offset;
208
209	    if (INKERNEL((int)frame) && callpc == db_trap_symbol_value) {
210		narg = 1;
211		is_trap = TRAP;
212	    }
213	    else
214	    if (INKERNEL((int)frame) && callpc == db_kdintr_symbol_value) {
215		is_trap = INTERRUPT;
216		narg = 0;
217	    }
218	    else {
219		is_trap = 0;
220		narg = db_numargs(frame);
221	    }
222
223	    db_find_sym_and_offset(callpc, &name, &offset);
224	    db_printf("%s(", name);
225
226	    argp = &frame->f_arg0;
227	    while (narg) {
228		db_printf("%x", db_get_value((int)argp, 4, FALSE));
229		argp++;
230		if (--narg != 0)
231		    db_printf(",");
232	    }
233	    db_printf(") at ");
234	    db_printsym(callpc, DB_STGY_XTRN);
235	    db_printf("\n");
236
237	    lastframe = frame;
238	    db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap);
239
240	    if (frame == 0) {
241		/* end of chain */
242		break;
243	    }
244	    if (INKERNEL((int)frame)) {
245		/* staying in kernel */
246		if (frame <= lastframe) {
247		    db_printf("Bad frame pointer: 0x%x\n", frame);
248		    break;
249		}
250	    }
251	    else if (INKERNEL((int)lastframe)) {
252		/* switch from user to kernel */
253		if (kernel_only)
254		    break;	/* kernel stack only */
255	    }
256	    else {
257		/* in user */
258		if (frame <= lastframe) {
259		    db_printf("Bad frame pointer: 0x%x\n", frame);
260		    break;
261		}
262	    }
263	}
264}
265