db_trace.c revision 129198
1129198Scognet/*	$NetBSD: db_trace.c,v 1.8 2003/01/17 22:28:48 thorpej Exp $	*/
2129198Scognet
3129198Scognet/*
4129198Scognet * Copyright (c) 2000, 2001 Ben Harris
5129198Scognet * Copyright (c) 1996 Scott K. Stevens
6129198Scognet *
7129198Scognet * Mach Operating System
8129198Scognet * Copyright (c) 1991,1990 Carnegie Mellon University
9129198Scognet * All Rights Reserved.
10129198Scognet *
11129198Scognet * Permission to use, copy, modify and distribute this software and its
12129198Scognet * documentation is hereby granted, provided that both the copyright
13129198Scognet * notice and this permission notice appear in all copies of the
14129198Scognet * software, derivative works or modified versions, and any portions
15129198Scognet * thereof, and that both notices appear in supporting documentation.
16129198Scognet *
17129198Scognet * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
18129198Scognet * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
19129198Scognet * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
20129198Scognet *
21129198Scognet * Carnegie Mellon requests users of this software to return to
22129198Scognet *
23129198Scognet *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
24129198Scognet *  School of Computer Science
25129198Scognet *  Carnegie Mellon University
26129198Scognet *  Pittsburgh PA 15213-3890
27129198Scognet *
28129198Scognet * any improvements or extensions that they make and grant Carnegie the
29129198Scognet * rights to redistribute these changes.
30129198Scognet */
31129198Scognet
32129198Scognet#include <sys/cdefs.h>
33129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/db_trace.c 129198 2004-05-14 11:46:45Z cognet $");
34129198Scognet#include <sys/param.h>
35129198Scognet
36129198Scognet
37129198Scognet#include <sys/proc.h>
38129198Scognet#include <sys/user.h>
39129198Scognet#include <machine/armreg.h>
40129198Scognet#include <machine/asm.h>
41129198Scognet#include <machine/cpufunc.h>
42129198Scognet#include <machine/db_machdep.h>
43129198Scognet#include <machine/vmparam.h>
44129198Scognet#include <ddb/ddb.h>
45129198Scognet#include <ddb/db_access.h>
46129198Scognet#include <ddb/db_sym.h>
47129198Scognet#include <ddb/db_output.h>
48129198Scognet
49129198Scognet#define INKERNEL(va)	(((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
50129198Scognet
51129198Scognetint  db_md_set_watchpoint(db_expr_t addr, db_expr_t size);
52129198Scognetint  db_md_clr_watchpoint(db_expr_t addr, db_expr_t size);
53129198Scognetvoid db_md_list_watchpoints(void);
54129198Scognet/*
55129198Scognet * APCS stack frames are awkward beasts, so I don't think even trying to use
56129198Scognet * a structure to represent them is a good idea.
57129198Scognet *
58129198Scognet * Here's the diagram from the APCS.  Increasing address is _up_ the page.
59129198Scognet *
60129198Scognet *          save code pointer       [fp]        <- fp points to here
61129198Scognet *          return link value       [fp, #-4]
62129198Scognet *          return sp value         [fp, #-8]
63129198Scognet *          return fp value         [fp, #-12]
64129198Scognet *          [saved v7 value]
65129198Scognet *          [saved v6 value]
66129198Scognet *          [saved v5 value]
67129198Scognet *          [saved v4 value]
68129198Scognet *          [saved v3 value]
69129198Scognet *          [saved v2 value]
70129198Scognet *          [saved v1 value]
71129198Scognet *          [saved a4 value]
72129198Scognet *          [saved a3 value]
73129198Scognet *          [saved a2 value]
74129198Scognet *          [saved a1 value]
75129198Scognet *
76129198Scognet * The save code pointer points twelve bytes beyond the start of the
77129198Scognet * code sequence (usually a single STM) that created the stack frame.
78129198Scognet * We have to disassemble it if we want to know which of the optional
79129198Scognet * fields are actually present.
80129198Scognet */
81129198Scognet
82129198Scognet#define FR_SCP	(0)
83129198Scognet#define FR_RLV	(-1)
84129198Scognet#define FR_RSP	(-2)
85129198Scognet#define FR_RFP	(-3)
86129198Scognet
87129198Scognetvoid
88129198Scognetdb_stack_trace_cmd(addr, have_addr, count, modif)
89129198Scognet	db_expr_t       addr;
90129198Scognet	int             have_addr;
91129198Scognet	db_expr_t       count;
92129198Scognet	char            *modif;
93129198Scognet{
94129198Scognet	u_int32_t	*frame, *lastframe;
95129198Scognet	c_db_sym_t sym;
96129198Scognet	db_expr_t pc;
97129198Scognet	char c, *cp = modif;
98129198Scognet	const char *name;
99129198Scognet	db_expr_t value;
100129198Scognet	db_expr_t offset;
101129198Scognet	boolean_t	kernel_only = TRUE;
102129198Scognet	boolean_t	trace_thread = FALSE;
103129198Scognet	int	scp_offset;
104129198Scognet
105129198Scognet	while ((c = *cp++) != 0) {
106129198Scognet		if (c == 'u')
107129198Scognet			kernel_only = FALSE;
108129198Scognet		if (c == 't')
109129198Scognet			trace_thread = TRUE;
110129198Scognet	}
111129198Scognet
112129198Scognet	if (!have_addr)
113129198Scognet		frame = (u_int32_t *)(DDB_REGS->tf_r11);
114129198Scognet	else {
115129198Scognet		if (trace_thread) {
116129198Scognet			struct proc *p;
117129198Scognet			struct thread *td;
118129198Scognet			pid_t pid = (pid_t)addr;
119129198Scognet			LIST_FOREACH(p, &allproc, p_list) {
120129198Scognet				if (p->p_pid == pid)
121129198Scognet					break;
122129198Scognet			}
123129198Scognet
124129198Scognet			if (p == NULL) {
125129198Scognet				db_printf("not found\n");
126129198Scognet				return;
127129198Scognet			}
128129198Scognet			if (!(p->p_sflag & PS_INMEM)) {
129129198Scognet				db_printf("swapped out\n");
130129198Scognet				return;
131129198Scognet			}
132129198Scognet			td = FIRST_THREAD_IN_PROC(p);
133129198Scognet			frame = (u_int32_t *)(td->td_pcb->un_32.pcb32_r11);
134129198Scognet			db_printf("at %p\n", frame);
135129198Scognet		} else
136129198Scognet			frame = (u_int32_t *)(addr);
137129198Scognet	}
138129198Scognet	lastframe = NULL;
139129198Scognet	scp_offset = -(get_pc_str_offset() >> 2);
140129198Scognet
141129198Scognet	while (count-- && frame != NULL) {
142129198Scognet		db_addr_t	scp;
143129198Scognet		u_int32_t	savecode;
144129198Scognet		int		r;
145129198Scognet		u_int32_t	*rp;
146129198Scognet		const char	*sep;
147129198Scognet
148129198Scognet		/*
149129198Scognet		 * In theory, the SCP isn't guaranteed to be in the function
150129198Scognet		 * that generated the stack frame.  We hope for the best.
151129198Scognet		 */
152129198Scognet#ifdef __PROG26
153129198Scognet		scp = frame[FR_SCP] & R15_PC;
154129198Scognet#else
155129198Scognet		scp = frame[FR_SCP];
156129198Scognet#endif
157129198Scognet
158129198Scognet		db_printsym(scp, DB_STGY_PROC);
159129198Scognet		db_printf("\n\t");
160129198Scognet		pc = ddb_regs.tf_pc;
161129198Scognet		sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
162129198Scognet		if (sym == C_DB_SYM_NULL) {
163129198Scognet			value = 0;
164129198Scognet			name = "(null)";
165129198Scognet		} else
166129198Scognet			db_symbol_values(sym, &name, &value);
167129198Scognet		db_printf("%s() at ", name);
168129198Scognet		db_printsym(pc, DB_STGY_PROC);
169129198Scognet		db_printf("\n");
170129198Scognet#ifdef __PROG26
171129198Scognet		db_printf("scp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV] & R15_PC);
172129198Scognet		db_printsym(frame[FR_RLV] & R15_PC, DB_STGY_PROC);
173129198Scognet		db_printf(")\n");
174129198Scognet#else
175129198Scognet		db_printf("scp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV]);
176129198Scognet		db_printsym(frame[FR_RLV], DB_STGY_PROC);
177129198Scognet		db_printf(")\n");
178129198Scognet#endif
179129198Scognet		db_printf("\trsp=0x%08x rfp=0x%08x", frame[FR_RSP], frame[FR_RFP]);
180129198Scognet
181129198Scognet		savecode = ((u_int32_t *)scp)[scp_offset];
182129198Scognet		if ((savecode & 0x0e100000) == 0x08000000) {
183129198Scognet			/* Looks like an STM */
184129198Scognet			rp = frame - 4;
185129198Scognet			sep = "\n\t";
186129198Scognet			for (r = 10; r >= 0; r--) {
187129198Scognet				if (savecode & (1 << r)) {
188129198Scognet					db_printf("%sr%d=0x%08x",
189129198Scognet					    sep, r, *rp--);
190129198Scognet					sep = (frame - rp) % 4 == 2 ?
191129198Scognet					    "\n\t" : " ";
192129198Scognet				}
193129198Scognet			}
194129198Scognet		}
195129198Scognet
196129198Scognet		db_printf("\n");
197129198Scognet
198129198Scognet		/*
199129198Scognet		 * Switch to next frame up
200129198Scognet		 */
201129198Scognet		if (frame[FR_RFP] == 0)
202129198Scognet			break; /* Top of stack */
203129198Scognet
204129198Scognet		lastframe = frame;
205129198Scognet		frame = (u_int32_t *)(frame[FR_RFP]);
206129198Scognet
207129198Scognet		if (INKERNEL((int)frame)) {
208129198Scognet			/* staying in kernel */
209129198Scognet			if (frame <= lastframe) {
210129198Scognet				db_printf("Bad frame pointer: %p\n", frame);
211129198Scognet				break;
212129198Scognet			}
213129198Scognet		} else if (INKERNEL((int)lastframe)) {
214129198Scognet			/* switch from user to kernel */
215129198Scognet			if (kernel_only)
216129198Scognet				break;	/* kernel stack only */
217129198Scognet		} else {
218129198Scognet			/* in user */
219129198Scognet			if (frame <= lastframe) {
220129198Scognet				db_printf("Bad user frame pointer: %p\n",
221129198Scognet					  frame);
222129198Scognet				break;
223129198Scognet			}
224129198Scognet		}
225129198Scognet	}
226129198Scognet}
227129198Scognet
228129198Scognet/* XXX stubs */
229129198Scognetvoid
230129198Scognetdb_md_list_watchpoints()
231129198Scognet{
232129198Scognet}
233129198Scognet
234129198Scognetint
235129198Scognetdb_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
236129198Scognet{
237129198Scognet	return (0);
238129198Scognet}
239129198Scognet
240129198Scognetint
241129198Scognetdb_md_set_watchpoint(db_expr_t addr, db_expr_t size)
242129198Scognet{
243129198Scognet	return (0);
244129198Scognet}
245129198Scognetvoid
246129198Scognetdb_print_backtrace(void)
247129198Scognet{
248129198Scognet
249129198Scognet	db_stack_trace_cmd((db_expr_t)__builtin_frame_address(0), 1, -1, NULL);
250129198Scognet}
251