db_trace.c revision 248124
1129198Scognet/*	$NetBSD: db_trace.c,v 1.8 2003/01/17 22:28:48 thorpej Exp $	*/
2129198Scognet
3139735Simp/*-
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.
10236991Simp *
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.
16236991Simp *
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.
20236991Simp *
21129198Scognet * Carnegie Mellon requests users of this software to return to
22236991Simp *
23129198Scognet *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
24129198Scognet *  School of Computer Science
25129198Scognet *  Carnegie Mellon University
26129198Scognet *  Pittsburgh PA 15213-3890
27236991Simp *
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 248124 2013-03-10 02:40:50Z andrew $");
34129198Scognet#include <sys/param.h>
35132402Scognet#include <sys/systm.h>
36129198Scognet
37129198Scognet
38129198Scognet#include <sys/proc.h>
39132059Scognet#include <sys/kdb.h>
40148666Sjeff#include <sys/stack.h>
41129198Scognet#include <machine/armreg.h>
42129198Scognet#include <machine/asm.h>
43129198Scognet#include <machine/cpufunc.h>
44129198Scognet#include <machine/db_machdep.h>
45138129Sdas#include <machine/pcb.h>
46174195Srwatson#include <machine/stack.h>
47129198Scognet#include <machine/vmparam.h>
48129198Scognet#include <ddb/ddb.h>
49129198Scognet#include <ddb/db_access.h>
50129198Scognet#include <ddb/db_sym.h>
51129198Scognet#include <ddb/db_output.h>
52129198Scognet
53245549Sandrew#ifdef __ARM_EABI__
54129198Scognet/*
55245549Sandrew * Definitions for the instruction interpreter.
56245549Sandrew *
57245549Sandrew * The ARM EABI specifies how to perform the frame unwinding in the
58245549Sandrew * Exception Handling ABI for the ARM Architecture document. To perform
59245549Sandrew * the unwind we need to know the initial frame pointer, stack pointer,
60245549Sandrew * link register and program counter. We then find the entry within the
61245549Sandrew * index table that points to the function the program counter is within.
62245549Sandrew * This gives us either a list of three instructions to process, a 31-bit
63245549Sandrew * relative offset to a table of instructions, or a value telling us
64245549Sandrew * we can't unwind any further.
65245549Sandrew *
66245549Sandrew * When we have the instructions to process we need to decode them
67245549Sandrew * following table 4 in section 9.3. This describes a collection of bit
68245549Sandrew * patterns to encode that steps to take to update the stack pointer and
69245549Sandrew * link register to the correct values at the start of the function.
70245549Sandrew */
71245549Sandrew
72245549Sandrew/* A special case when we are unable to unwind past this function */
73245549Sandrew#define	EXIDX_CANTUNWIND	1
74245549Sandrew
75245549Sandrew/* The register names */
76245549Sandrew#define	FP	11
77245549Sandrew#define	SP	13
78245549Sandrew#define	LR	14
79245549Sandrew#define	PC	15
80245549Sandrew
81245549Sandrew/*
82245549Sandrew * These are set in the linker script. Their addresses will be
83245549Sandrew * either the start or end of the exception table or index.
84245549Sandrew */
85245549Sandrewextern int extab_start, extab_end, exidx_start, exidx_end;
86245549Sandrew
87245549Sandrew/*
88245549Sandrew * Entry types.
89245549Sandrew * These are the only entry types that have been seen in the kernel.
90245549Sandrew */
91245549Sandrew#define	ENTRY_MASK	0xff000000
92245549Sandrew#define	ENTRY_ARM_SU16	0x80000000
93245549Sandrew#define	ENTRY_ARM_LU16	0x81000000
94245549Sandrew
95245549Sandrew/* Instruction masks. */
96245549Sandrew#define	INSN_VSP_MASK		0xc0
97245549Sandrew#define	INSN_VSP_SIZE_MASK	0x3f
98245549Sandrew#define	INSN_STD_MASK		0xf0
99245549Sandrew#define	INSN_STD_DATA_MASK	0x0f
100245549Sandrew#define	INSN_POP_TYPE_MASK	0x08
101245549Sandrew#define	INSN_POP_COUNT_MASK	0x07
102245549Sandrew#define	INSN_VSP_LARGE_INC_MASK	0xff
103245549Sandrew
104245549Sandrew/* Instruction definitions */
105245549Sandrew#define	INSN_VSP_INC		0x00
106245549Sandrew#define	INSN_VSP_DEC		0x40
107245549Sandrew#define	INSN_POP_MASKED		0x80
108245549Sandrew#define	INSN_VSP_REG		0x90
109245549Sandrew#define	INSN_POP_COUNT		0xa0
110245549Sandrew#define	INSN_FINISH		0xb0
111245549Sandrew#define	INSN_VSP_LARGE_INC	0xb2
112245549Sandrew
113245549Sandrew/* An item in the exception index table */
114245549Sandrewstruct unwind_idx {
115245549Sandrew	uint32_t offset;
116245549Sandrew	uint32_t insn;
117245549Sandrew};
118245549Sandrew
119245549Sandrew/* The state of the unwind process */
120245549Sandrewstruct unwind_state {
121245549Sandrew	uint32_t registers[16];
122245549Sandrew	uint32_t start_pc;
123245549Sandrew	uint32_t *insn;
124245549Sandrew	u_int entries;
125245549Sandrew	u_int byte;
126245549Sandrew	uint16_t update_mask;
127245549Sandrew};
128245549Sandrew
129245549Sandrew/* We need to provide these but never use them */
130245549Sandrewvoid __aeabi_unwind_cpp_pr0(void);
131245549Sandrewvoid __aeabi_unwind_cpp_pr1(void);
132245549Sandrewvoid __aeabi_unwind_cpp_pr2(void);
133245549Sandrew
134245549Sandrewvoid
135245549Sandrew__aeabi_unwind_cpp_pr0(void)
136245549Sandrew{
137245549Sandrew	panic("__aeabi_unwind_cpp_pr0");
138245549Sandrew}
139245549Sandrew
140245549Sandrewvoid
141245549Sandrew__aeabi_unwind_cpp_pr1(void)
142245549Sandrew{
143245549Sandrew	panic("__aeabi_unwind_cpp_pr1");
144245549Sandrew}
145245549Sandrew
146245549Sandrewvoid
147245549Sandrew__aeabi_unwind_cpp_pr2(void)
148245549Sandrew{
149245549Sandrew	panic("__aeabi_unwind_cpp_pr2");
150245549Sandrew}
151245549Sandrew
152245549Sandrew/* Expand a 31-bit signed value to a 32-bit signed value */
153245549Sandrewstatic __inline int32_t
154245549Sandrewdb_expand_prel31(uint32_t prel31)
155245549Sandrew{
156245549Sandrew
157245549Sandrew	return ((int32_t)(prel31 & 0x7fffffffu) << 1) / 2;
158245549Sandrew}
159245549Sandrew
160245549Sandrew/*
161245549Sandrew * Perform a binary search of the index table to find the function
162245549Sandrew * with the largest address that doesn't exceed addr.
163245549Sandrew */
164245549Sandrewstatic struct unwind_idx *
165245549Sandrewdb_find_index(uint32_t addr)
166245549Sandrew{
167245549Sandrew	unsigned int min, mid, max;
168245549Sandrew	struct unwind_idx *start;
169245549Sandrew	struct unwind_idx *item;
170245549Sandrew	int32_t prel31_addr;
171245549Sandrew	uint32_t func_addr;
172245549Sandrew
173245549Sandrew	start = (struct unwind_idx *)&exidx_start;
174245549Sandrew
175245549Sandrew	min = 0;
176245549Sandrew	max = (&exidx_end - &exidx_start) / 2;
177245549Sandrew
178245549Sandrew	while (min != max) {
179245549Sandrew		mid = min + (max - min + 1) / 2;
180245549Sandrew
181245549Sandrew		item = &start[mid];
182245549Sandrew
183245549Sandrew	 	prel31_addr = db_expand_prel31(item->offset);
184245549Sandrew		func_addr = (uint32_t)&item->offset + prel31_addr;
185245549Sandrew
186245549Sandrew		if (func_addr <= addr) {
187245549Sandrew			min = mid;
188245549Sandrew		} else {
189245549Sandrew			max = mid - 1;
190245549Sandrew		}
191245549Sandrew	}
192245549Sandrew
193245549Sandrew	return &start[min];
194245549Sandrew}
195245549Sandrew
196245549Sandrew/* Reads the next byte from the instruction list */
197245549Sandrewstatic uint8_t
198245549Sandrewdb_unwind_exec_read_byte(struct unwind_state *state)
199245549Sandrew{
200245549Sandrew	uint8_t insn;
201245549Sandrew
202245549Sandrew	/* Read the unwind instruction */
203245549Sandrew	insn = (*state->insn) >> (state->byte * 8);
204245549Sandrew
205245549Sandrew	/* Update the location of the next instruction */
206245549Sandrew	if (state->byte == 0) {
207245549Sandrew		state->byte = 3;
208245549Sandrew		state->insn++;
209245549Sandrew		state->entries--;
210245549Sandrew	} else
211245549Sandrew		state->byte--;
212245549Sandrew
213245549Sandrew	return insn;
214245549Sandrew}
215245549Sandrew
216245549Sandrew/* Executes the next instruction on the list */
217245549Sandrewstatic int
218245549Sandrewdb_unwind_exec_insn(struct unwind_state *state)
219245549Sandrew{
220245549Sandrew	unsigned int insn;
221245549Sandrew	uint32_t *vsp = (uint32_t *)state->registers[SP];
222245549Sandrew	int update_vsp = 0;
223245549Sandrew
224245549Sandrew	/* This should never happen */
225245549Sandrew	if (state->entries == 0)
226245549Sandrew		return 1;
227245549Sandrew
228245549Sandrew	/* Read the next instruction */
229245549Sandrew	insn = db_unwind_exec_read_byte(state);
230245549Sandrew
231245549Sandrew	if ((insn & INSN_VSP_MASK) == INSN_VSP_INC) {
232245549Sandrew		state->registers[SP] += ((insn & INSN_VSP_SIZE_MASK) << 2) + 4;
233245549Sandrew
234245549Sandrew	} else if ((insn & INSN_VSP_MASK) == INSN_VSP_DEC) {
235245549Sandrew		state->registers[SP] -= ((insn & INSN_VSP_SIZE_MASK) << 2) + 4;
236245549Sandrew
237245549Sandrew	} else if ((insn & INSN_STD_MASK) == INSN_POP_MASKED) {
238245549Sandrew		unsigned int mask, reg;
239245549Sandrew
240245549Sandrew		/* Load the mask */
241245549Sandrew		mask = db_unwind_exec_read_byte(state);
242245549Sandrew		mask |= (insn & INSN_STD_DATA_MASK) << 8;
243245549Sandrew
244245549Sandrew		/* We have a refuse to unwind instruction */
245245549Sandrew		if (mask == 0)
246245549Sandrew			return 1;
247245549Sandrew
248245549Sandrew		/* Update SP */
249245549Sandrew		update_vsp = 1;
250245549Sandrew
251245549Sandrew		/* Load the registers */
252245549Sandrew		for (reg = 4; mask && reg < 16; mask >>= 1, reg++) {
253245549Sandrew			if (mask & 1) {
254245549Sandrew				state->registers[reg] = *vsp++;
255245549Sandrew				state->update_mask |= 1 << reg;
256245549Sandrew
257245549Sandrew				/* If we have updated SP kep its value */
258245549Sandrew				if (reg == SP)
259245549Sandrew					update_vsp = 0;
260245549Sandrew			}
261245549Sandrew		}
262245549Sandrew
263245549Sandrew	} else if ((insn & INSN_STD_MASK) == INSN_VSP_REG &&
264245549Sandrew	    ((insn & INSN_STD_DATA_MASK) != 13) &&
265245549Sandrew	    ((insn & INSN_STD_DATA_MASK) != 15)) {
266245549Sandrew		/* sp = register */
267245549Sandrew		state->registers[SP] =
268245549Sandrew		    state->registers[insn & INSN_STD_DATA_MASK];
269245549Sandrew
270245549Sandrew	} else if ((insn & INSN_STD_MASK) == INSN_POP_COUNT) {
271245549Sandrew		unsigned int count, reg;
272245549Sandrew
273245549Sandrew		/* Read how many registers to load */
274245549Sandrew		count = insn & INSN_POP_COUNT_MASK;
275245549Sandrew
276245549Sandrew		/* Update sp */
277245549Sandrew		update_vsp = 1;
278245549Sandrew
279245549Sandrew		/* Pop the registers */
280245549Sandrew		for (reg = 4; reg <= 4 + count; reg++) {
281245549Sandrew			state->registers[reg] = *vsp++;
282245549Sandrew			state->update_mask |= 1 << reg;
283245549Sandrew		}
284245549Sandrew
285245549Sandrew		/* Check if we are in the pop r14 version */
286245549Sandrew		if ((insn & INSN_POP_TYPE_MASK) != 0) {
287245549Sandrew			state->registers[14] = *vsp++;
288245549Sandrew		}
289245549Sandrew
290245549Sandrew	} else if (insn == INSN_FINISH) {
291245549Sandrew		/* Stop processing */
292245549Sandrew		state->entries = 0;
293245549Sandrew
294245549Sandrew	} else if ((insn & INSN_VSP_LARGE_INC_MASK) == INSN_VSP_LARGE_INC) {
295245549Sandrew		unsigned int uleb128;
296245549Sandrew
297245549Sandrew		/* Read the increment value */
298245549Sandrew		uleb128 = db_unwind_exec_read_byte(state);
299245549Sandrew
300245549Sandrew		state->registers[SP] += 0x204 + (uleb128 << 2);
301245549Sandrew
302245549Sandrew	} else {
303245549Sandrew		/* We hit a new instruction that needs to be implemented */
304245549Sandrew		db_printf("Unhandled instruction %.2x\n", insn);
305245549Sandrew		return 1;
306245549Sandrew	}
307245549Sandrew
308245549Sandrew	if (update_vsp) {
309245549Sandrew		state->registers[SP] = (uint32_t)vsp;
310245549Sandrew	}
311245549Sandrew
312245549Sandrew#if 0
313245549Sandrew	db_printf("fp = %08x, sp = %08x, lr = %08x, pc = %08x\n",
314245549Sandrew	    state->registers[FP], state->registers[SP], state->registers[LR],
315245549Sandrew	    state->registers[PC]);
316245549Sandrew#endif
317245549Sandrew
318245549Sandrew	return 0;
319245549Sandrew}
320245549Sandrew
321245549Sandrew/* Performs the unwind of a function */
322245549Sandrewstatic int
323245549Sandrewdb_unwind_tab(struct unwind_state *state)
324245549Sandrew{
325245549Sandrew	uint32_t entry;
326245549Sandrew
327245549Sandrew	/* Set PC to a known value */
328245549Sandrew	state->registers[PC] = 0;
329245549Sandrew
330245549Sandrew	/* Read the personality */
331245549Sandrew	entry = *state->insn & ENTRY_MASK;
332245549Sandrew
333245549Sandrew	if (entry == ENTRY_ARM_SU16) {
334245549Sandrew		state->byte = 2;
335245549Sandrew		state->entries = 1;
336245549Sandrew	} else if (entry == ENTRY_ARM_LU16) {
337245549Sandrew		state->byte = 1;
338245549Sandrew		state->entries = ((*state->insn >> 16) & 0xFF) + 1;
339245549Sandrew	} else {
340245549Sandrew		db_printf("Unknown entry: %x\n", entry);
341245549Sandrew		return 1;
342245549Sandrew	}
343245549Sandrew
344245549Sandrew	while (state->entries > 0) {
345245549Sandrew		if (db_unwind_exec_insn(state) != 0)
346245549Sandrew			return 1;
347245549Sandrew	}
348245549Sandrew
349245549Sandrew	/*
350245549Sandrew	 * The program counter was not updated, load it from the link register.
351245549Sandrew	 */
352245549Sandrew	if (state->registers[PC] == 0)
353245549Sandrew		state->registers[PC] = state->registers[LR];
354245549Sandrew
355245549Sandrew	return 0;
356245549Sandrew}
357245549Sandrew
358245549Sandrewstatic void
359245549Sandrewdb_stack_trace_cmd(struct unwind_state *state)
360245549Sandrew{
361245549Sandrew	struct unwind_idx *index;
362245549Sandrew	const char *name;
363245549Sandrew	db_expr_t value;
364245549Sandrew	db_expr_t offset;
365245549Sandrew	c_db_sym_t sym;
366245549Sandrew	u_int reg, i;
367245549Sandrew	char *sep;
368245549Sandrew
369245549Sandrew	while (1) {
370245549Sandrew		/* Reset the mask of updated registers */
371245549Sandrew		state->update_mask = 0;
372245549Sandrew
373245549Sandrew		/* The pc value is correct and will be overwritten, save it */
374245549Sandrew		state->start_pc = state->registers[PC];
375245549Sandrew
376245549Sandrew		/* Find the item to run */
377245549Sandrew		index = db_find_index(state->start_pc);
378245549Sandrew
379245549Sandrew		if (index->insn == EXIDX_CANTUNWIND) {
380245549Sandrew			printf("Unable to unwind\n");
381245549Sandrew			break;
382245549Sandrew		} else if (index->insn & (1 << 31)) {
383245549Sandrew			/* The data is within the instruction */
384245549Sandrew			state->insn = &index->insn;
385245549Sandrew		} else {
386245549Sandrew			/* We have a prel31 offset to the unwind table */
387245549Sandrew			uint32_t prel31_tbl = db_expand_prel31(index->insn);
388245549Sandrew
389245549Sandrew			state->insn = (uint32_t *)((uintptr_t)&index->insn +
390245549Sandrew			    prel31_tbl);
391245549Sandrew		}
392245549Sandrew
393245549Sandrew		/* Run the unwind function */
394245549Sandrew		if (db_unwind_tab(state) != 0)
395245549Sandrew			break;
396245549Sandrew
397245549Sandrew		/* This is not a kernel address, stop processing */
398245549Sandrew		if (state->registers[PC] < VM_MIN_KERNEL_ADDRESS)
399245549Sandrew			break;
400245549Sandrew
401245549Sandrew		/* Print the frame details */
402245549Sandrew		sym = db_search_symbol(state->start_pc, DB_STGY_ANY, &offset);
403245549Sandrew		if (sym == C_DB_SYM_NULL) {
404245549Sandrew			value = 0;
405245549Sandrew			name = "(null)";
406245549Sandrew		} else
407245549Sandrew			db_symbol_values(sym, &name, &value);
408245549Sandrew		db_printf("%s() at ", name);
409245549Sandrew		db_printsym(state->start_pc, DB_STGY_PROC);
410245549Sandrew		db_printf("\n");
411245549Sandrew		db_printf("\t pc = 0x%08x  lr = 0x%08x (", state->start_pc,
412245549Sandrew		    state->registers[LR]);
413245549Sandrew		db_printsym(state->registers[LR], DB_STGY_PROC);
414245549Sandrew		db_printf(")\n");
415245549Sandrew		db_printf("\t sp = 0x%08x  fp = 0x%08x",
416245549Sandrew		    state->registers[SP], state->registers[FP]);
417245549Sandrew
418245549Sandrew		/* Don't print the registers we have already printed */
419245549Sandrew		state->update_mask &= ~((1 << SP) | (1 << FP) | (1 << LR) |
420245549Sandrew		    (1 << PC));
421245549Sandrew		sep = "\n\t";
422245549Sandrew		for (i = 0, reg = 0; state->update_mask != 0;
423245549Sandrew		    state->update_mask >>= 1, reg++) {
424245549Sandrew			if ((state->update_mask & 1) != 0) {
425245549Sandrew				db_printf("%s%sr%d = 0x%08x", sep,
426245549Sandrew				    (reg < 10) ? " " : "", reg,
427245549Sandrew				    state->registers[reg]);
428245549Sandrew				i++;
429245549Sandrew				if (i == 2) {
430245549Sandrew					sep = "\n\t";
431245549Sandrew					i = 0;
432245549Sandrew				} else
433245549Sandrew					sep = " ";
434245549Sandrew
435245549Sandrew			}
436245549Sandrew		}
437245549Sandrew		db_printf("\n");
438245549Sandrew	}
439245549Sandrew}
440245549Sandrew#endif
441245549Sandrew
442245549Sandrew/*
443129198Scognet * APCS stack frames are awkward beasts, so I don't think even trying to use
444129198Scognet * a structure to represent them is a good idea.
445129198Scognet *
446129198Scognet * Here's the diagram from the APCS.  Increasing address is _up_ the page.
447236991Simp *
448129198Scognet *          save code pointer       [fp]        <- fp points to here
449129198Scognet *          return link value       [fp, #-4]
450129198Scognet *          return sp value         [fp, #-8]
451129198Scognet *          return fp value         [fp, #-12]
452129198Scognet *          [saved v7 value]
453129198Scognet *          [saved v6 value]
454129198Scognet *          [saved v5 value]
455129198Scognet *          [saved v4 value]
456129198Scognet *          [saved v3 value]
457129198Scognet *          [saved v2 value]
458129198Scognet *          [saved v1 value]
459129198Scognet *          [saved a4 value]
460129198Scognet *          [saved a3 value]
461129198Scognet *          [saved a2 value]
462129198Scognet *          [saved a1 value]
463129198Scognet *
464236991Simp * The save code pointer points twelve bytes beyond the start of the
465236991Simp * code sequence (usually a single STM) that created the stack frame.
466236991Simp * We have to disassemble it if we want to know which of the optional
467129198Scognet * fields are actually present.
468129198Scognet */
469129198Scognet
470245549Sandrew#ifndef __ARM_EABI__	/* The frame format is differend in AAPCS */
471132482Smarcelstatic void
472236308Sgberdb_stack_trace_cmd(db_expr_t addr, db_expr_t count, boolean_t kernel_only)
473129198Scognet{
474129198Scognet	u_int32_t	*frame, *lastframe;
475129198Scognet	c_db_sym_t sym;
476129198Scognet	const char *name;
477129198Scognet	db_expr_t value;
478129198Scognet	db_expr_t offset;
479160312Sjhb	int	scp_offset;
480129198Scognet
481137977Scognet	frame = (u_int32_t *)addr;
482129198Scognet	lastframe = NULL;
483129198Scognet	scp_offset = -(get_pc_str_offset() >> 2);
484129198Scognet
485160312Sjhb	while (count-- && frame != NULL && !db_pager_quit) {
486129198Scognet		db_addr_t	scp;
487129198Scognet		u_int32_t	savecode;
488129198Scognet		int		r;
489129198Scognet		u_int32_t	*rp;
490129198Scognet		const char	*sep;
491129198Scognet
492129198Scognet		/*
493129198Scognet		 * In theory, the SCP isn't guaranteed to be in the function
494129198Scognet		 * that generated the stack frame.  We hope for the best.
495129198Scognet		 */
496129198Scognet		scp = frame[FR_SCP];
497129198Scognet
498135647Scognet		sym = db_search_symbol(scp, DB_STGY_ANY, &offset);
499129198Scognet		if (sym == C_DB_SYM_NULL) {
500129198Scognet			value = 0;
501129198Scognet			name = "(null)";
502129198Scognet		} else
503129198Scognet			db_symbol_values(sym, &name, &value);
504129198Scognet		db_printf("%s() at ", name);
505135647Scognet		db_printsym(scp, DB_STGY_PROC);
506129198Scognet		db_printf("\n");
507129198Scognet#ifdef __PROG26
508129198Scognet		db_printf("scp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV] & R15_PC);
509129198Scognet		db_printsym(frame[FR_RLV] & R15_PC, DB_STGY_PROC);
510129198Scognet		db_printf(")\n");
511129198Scognet#else
512129198Scognet		db_printf("scp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV]);
513129198Scognet		db_printsym(frame[FR_RLV], DB_STGY_PROC);
514129198Scognet		db_printf(")\n");
515129198Scognet#endif
516129198Scognet		db_printf("\trsp=0x%08x rfp=0x%08x", frame[FR_RSP], frame[FR_RFP]);
517129198Scognet
518129198Scognet		savecode = ((u_int32_t *)scp)[scp_offset];
519129198Scognet		if ((savecode & 0x0e100000) == 0x08000000) {
520129198Scognet			/* Looks like an STM */
521129198Scognet			rp = frame - 4;
522129198Scognet			sep = "\n\t";
523129198Scognet			for (r = 10; r >= 0; r--) {
524129198Scognet				if (savecode & (1 << r)) {
525129198Scognet					db_printf("%sr%d=0x%08x",
526129198Scognet					    sep, r, *rp--);
527129198Scognet					sep = (frame - rp) % 4 == 2 ?
528129198Scognet					    "\n\t" : " ";
529129198Scognet				}
530129198Scognet			}
531129198Scognet		}
532129198Scognet
533129198Scognet		db_printf("\n");
534129198Scognet
535129198Scognet		/*
536129198Scognet		 * Switch to next frame up
537129198Scognet		 */
538129198Scognet		if (frame[FR_RFP] == 0)
539129198Scognet			break; /* Top of stack */
540129198Scognet
541129198Scognet		lastframe = frame;
542129198Scognet		frame = (u_int32_t *)(frame[FR_RFP]);
543129198Scognet
544129198Scognet		if (INKERNEL((int)frame)) {
545129198Scognet			/* staying in kernel */
546129198Scognet			if (frame <= lastframe) {
547129198Scognet				db_printf("Bad frame pointer: %p\n", frame);
548129198Scognet				break;
549129198Scognet			}
550129198Scognet		} else if (INKERNEL((int)lastframe)) {
551129198Scognet			/* switch from user to kernel */
552129198Scognet			if (kernel_only)
553129198Scognet				break;	/* kernel stack only */
554129198Scognet		} else {
555129198Scognet			/* in user */
556129198Scognet			if (frame <= lastframe) {
557129198Scognet				db_printf("Bad user frame pointer: %p\n",
558129198Scognet					  frame);
559129198Scognet				break;
560129198Scognet			}
561129198Scognet		}
562129198Scognet	}
563129198Scognet}
564245549Sandrew#endif
565129198Scognet
566129198Scognet/* XXX stubs */
567129198Scognetvoid
568129198Scognetdb_md_list_watchpoints()
569129198Scognet{
570129198Scognet}
571129198Scognet
572129198Scognetint
573129198Scognetdb_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
574129198Scognet{
575129198Scognet	return (0);
576129198Scognet}
577129198Scognet
578129198Scognetint
579129198Scognetdb_md_set_watchpoint(db_expr_t addr, db_expr_t size)
580129198Scognet{
581129198Scognet	return (0);
582129198Scognet}
583132482Smarcel
584132059Scognetint
585132059Scognetdb_trace_thread(struct thread *thr, int count)
586129198Scognet{
587245549Sandrew#ifdef __ARM_EABI__
588245549Sandrew	struct unwind_state state;
589245549Sandrew#endif
590198943Smarcel	struct pcb *ctx;
591129198Scognet
592236308Sgber	if (thr != curthread) {
593236308Sgber		ctx = kdb_thr_ctx(thr);
594245549Sandrew
595245549Sandrew#ifdef __ARM_EABI__
596245549Sandrew		state.registers[FP] = ctx->un_32.pcb32_r11;
597245549Sandrew		state.registers[SP] = ctx->un_32.pcb32_sp;
598245549Sandrew		state.registers[LR] = ctx->un_32.pcb32_lr;
599245549Sandrew		state.registers[PC] = ctx->un_32.pcb32_pc;
600245549Sandrew
601245549Sandrew		db_stack_trace_cmd(&state);
602245549Sandrew#else
603236308Sgber		db_stack_trace_cmd(ctx->un_32.pcb32_r11, -1, TRUE);
604245549Sandrew#endif
605236308Sgber	} else
606236308Sgber		db_trace_self();
607132059Scognet	return (0);
608129198Scognet}
609132059Scognet
610132059Scognetvoid
611132059Scognetdb_trace_self(void)
612132059Scognet{
613245549Sandrew#ifdef __ARM_EABI__
614245549Sandrew	struct unwind_state state;
615248124Sandrew	uint32_t sp;
616245549Sandrew
617248124Sandrew	/* Read the stack pointer */
618248124Sandrew	__asm __volatile("mov %0, sp" : "=&r" (sp));
619248124Sandrew
620245549Sandrew	state.registers[FP] = (uint32_t)__builtin_frame_address(0);
621248124Sandrew	state.registers[SP] = sp;
622245549Sandrew	state.registers[LR] = (uint32_t)__builtin_return_address(0);
623245549Sandrew	state.registers[PC] = (uint32_t)db_trace_self;
624245549Sandrew
625245549Sandrew	db_stack_trace_cmd(&state);
626245549Sandrew#else
627198942Smarcel	db_addr_t addr;
628198942Smarcel
629203171Smarcel	addr = (db_addr_t)__builtin_frame_address(0);
630236308Sgber	db_stack_trace_cmd(addr, -1, FALSE);
631245549Sandrew#endif
632132059Scognet}
633