db_trace.c revision 276190
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 276190 2014-12-24 18:54:31Z ian $");
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
111252320Sandrew#define	INSN_POP_REGS		0xb1
112245549Sandrew#define	INSN_VSP_LARGE_INC	0xb2
113245549Sandrew
114245549Sandrew/* An item in the exception index table */
115245549Sandrewstruct unwind_idx {
116245549Sandrew	uint32_t offset;
117245549Sandrew	uint32_t insn;
118245549Sandrew};
119245549Sandrew
120245549Sandrew/* The state of the unwind process */
121245549Sandrewstruct unwind_state {
122245549Sandrew	uint32_t registers[16];
123245549Sandrew	uint32_t start_pc;
124245549Sandrew	uint32_t *insn;
125245549Sandrew	u_int entries;
126245549Sandrew	u_int byte;
127245549Sandrew	uint16_t update_mask;
128245549Sandrew};
129245549Sandrew
130245549Sandrew/* Expand a 31-bit signed value to a 32-bit signed value */
131245549Sandrewstatic __inline int32_t
132245549Sandrewdb_expand_prel31(uint32_t prel31)
133245549Sandrew{
134245549Sandrew
135245549Sandrew	return ((int32_t)(prel31 & 0x7fffffffu) << 1) / 2;
136245549Sandrew}
137245549Sandrew
138245549Sandrew/*
139245549Sandrew * Perform a binary search of the index table to find the function
140245549Sandrew * with the largest address that doesn't exceed addr.
141245549Sandrew */
142245549Sandrewstatic struct unwind_idx *
143245549Sandrewdb_find_index(uint32_t addr)
144245549Sandrew{
145245549Sandrew	unsigned int min, mid, max;
146245549Sandrew	struct unwind_idx *start;
147245549Sandrew	struct unwind_idx *item;
148245549Sandrew	int32_t prel31_addr;
149245549Sandrew	uint32_t func_addr;
150245549Sandrew
151245549Sandrew	start = (struct unwind_idx *)&exidx_start;
152245549Sandrew
153245549Sandrew	min = 0;
154245549Sandrew	max = (&exidx_end - &exidx_start) / 2;
155245549Sandrew
156245549Sandrew	while (min != max) {
157245549Sandrew		mid = min + (max - min + 1) / 2;
158245549Sandrew
159245549Sandrew		item = &start[mid];
160245549Sandrew
161245549Sandrew	 	prel31_addr = db_expand_prel31(item->offset);
162245549Sandrew		func_addr = (uint32_t)&item->offset + prel31_addr;
163245549Sandrew
164245549Sandrew		if (func_addr <= addr) {
165245549Sandrew			min = mid;
166245549Sandrew		} else {
167245549Sandrew			max = mid - 1;
168245549Sandrew		}
169245549Sandrew	}
170245549Sandrew
171245549Sandrew	return &start[min];
172245549Sandrew}
173245549Sandrew
174245549Sandrew/* Reads the next byte from the instruction list */
175245549Sandrewstatic uint8_t
176245549Sandrewdb_unwind_exec_read_byte(struct unwind_state *state)
177245549Sandrew{
178245549Sandrew	uint8_t insn;
179245549Sandrew
180245549Sandrew	/* Read the unwind instruction */
181245549Sandrew	insn = (*state->insn) >> (state->byte * 8);
182245549Sandrew
183245549Sandrew	/* Update the location of the next instruction */
184245549Sandrew	if (state->byte == 0) {
185245549Sandrew		state->byte = 3;
186245549Sandrew		state->insn++;
187245549Sandrew		state->entries--;
188245549Sandrew	} else
189245549Sandrew		state->byte--;
190245549Sandrew
191245549Sandrew	return insn;
192245549Sandrew}
193245549Sandrew
194245549Sandrew/* Executes the next instruction on the list */
195245549Sandrewstatic int
196245549Sandrewdb_unwind_exec_insn(struct unwind_state *state)
197245549Sandrew{
198245549Sandrew	unsigned int insn;
199245549Sandrew	uint32_t *vsp = (uint32_t *)state->registers[SP];
200245549Sandrew	int update_vsp = 0;
201245549Sandrew
202245549Sandrew	/* This should never happen */
203245549Sandrew	if (state->entries == 0)
204245549Sandrew		return 1;
205245549Sandrew
206245549Sandrew	/* Read the next instruction */
207245549Sandrew	insn = db_unwind_exec_read_byte(state);
208245549Sandrew
209245549Sandrew	if ((insn & INSN_VSP_MASK) == INSN_VSP_INC) {
210245549Sandrew		state->registers[SP] += ((insn & INSN_VSP_SIZE_MASK) << 2) + 4;
211245549Sandrew
212245549Sandrew	} else if ((insn & INSN_VSP_MASK) == INSN_VSP_DEC) {
213245549Sandrew		state->registers[SP] -= ((insn & INSN_VSP_SIZE_MASK) << 2) + 4;
214245549Sandrew
215245549Sandrew	} else if ((insn & INSN_STD_MASK) == INSN_POP_MASKED) {
216245549Sandrew		unsigned int mask, reg;
217245549Sandrew
218245549Sandrew		/* Load the mask */
219245549Sandrew		mask = db_unwind_exec_read_byte(state);
220245549Sandrew		mask |= (insn & INSN_STD_DATA_MASK) << 8;
221245549Sandrew
222245549Sandrew		/* We have a refuse to unwind instruction */
223245549Sandrew		if (mask == 0)
224245549Sandrew			return 1;
225245549Sandrew
226245549Sandrew		/* Update SP */
227245549Sandrew		update_vsp = 1;
228245549Sandrew
229245549Sandrew		/* Load the registers */
230245549Sandrew		for (reg = 4; mask && reg < 16; mask >>= 1, reg++) {
231245549Sandrew			if (mask & 1) {
232245549Sandrew				state->registers[reg] = *vsp++;
233245549Sandrew				state->update_mask |= 1 << reg;
234245549Sandrew
235245549Sandrew				/* If we have updated SP kep its value */
236245549Sandrew				if (reg == SP)
237245549Sandrew					update_vsp = 0;
238245549Sandrew			}
239245549Sandrew		}
240245549Sandrew
241245549Sandrew	} else if ((insn & INSN_STD_MASK) == INSN_VSP_REG &&
242245549Sandrew	    ((insn & INSN_STD_DATA_MASK) != 13) &&
243245549Sandrew	    ((insn & INSN_STD_DATA_MASK) != 15)) {
244245549Sandrew		/* sp = register */
245245549Sandrew		state->registers[SP] =
246245549Sandrew		    state->registers[insn & INSN_STD_DATA_MASK];
247245549Sandrew
248245549Sandrew	} else if ((insn & INSN_STD_MASK) == INSN_POP_COUNT) {
249245549Sandrew		unsigned int count, reg;
250245549Sandrew
251245549Sandrew		/* Read how many registers to load */
252245549Sandrew		count = insn & INSN_POP_COUNT_MASK;
253245549Sandrew
254245549Sandrew		/* Update sp */
255245549Sandrew		update_vsp = 1;
256245549Sandrew
257245549Sandrew		/* Pop the registers */
258245549Sandrew		for (reg = 4; reg <= 4 + count; reg++) {
259245549Sandrew			state->registers[reg] = *vsp++;
260245549Sandrew			state->update_mask |= 1 << reg;
261245549Sandrew		}
262245549Sandrew
263245549Sandrew		/* Check if we are in the pop r14 version */
264245549Sandrew		if ((insn & INSN_POP_TYPE_MASK) != 0) {
265245549Sandrew			state->registers[14] = *vsp++;
266245549Sandrew		}
267245549Sandrew
268245549Sandrew	} else if (insn == INSN_FINISH) {
269245549Sandrew		/* Stop processing */
270245549Sandrew		state->entries = 0;
271245549Sandrew
272261214Simp	} else if (insn == INSN_POP_REGS) {
273252320Sandrew		unsigned int mask, reg;
274252320Sandrew
275252320Sandrew		mask = db_unwind_exec_read_byte(state);
276252320Sandrew		if (mask == 0 || (mask & 0xf0) != 0)
277252320Sandrew			return 1;
278252320Sandrew
279252320Sandrew		/* Update SP */
280252320Sandrew		update_vsp = 1;
281252320Sandrew
282252320Sandrew		/* Load the registers */
283252320Sandrew		for (reg = 0; mask && reg < 4; mask >>= 1, reg++) {
284252320Sandrew			if (mask & 1) {
285252320Sandrew				state->registers[reg] = *vsp++;
286252320Sandrew				state->update_mask |= 1 << reg;
287252320Sandrew			}
288252320Sandrew		}
289252320Sandrew
290245549Sandrew	} else if ((insn & INSN_VSP_LARGE_INC_MASK) == INSN_VSP_LARGE_INC) {
291245549Sandrew		unsigned int uleb128;
292245549Sandrew
293245549Sandrew		/* Read the increment value */
294245549Sandrew		uleb128 = db_unwind_exec_read_byte(state);
295245549Sandrew
296245549Sandrew		state->registers[SP] += 0x204 + (uleb128 << 2);
297245549Sandrew
298245549Sandrew	} else {
299245549Sandrew		/* We hit a new instruction that needs to be implemented */
300245549Sandrew		db_printf("Unhandled instruction %.2x\n", insn);
301245549Sandrew		return 1;
302245549Sandrew	}
303245549Sandrew
304245549Sandrew	if (update_vsp) {
305245549Sandrew		state->registers[SP] = (uint32_t)vsp;
306245549Sandrew	}
307245549Sandrew
308245549Sandrew#if 0
309245549Sandrew	db_printf("fp = %08x, sp = %08x, lr = %08x, pc = %08x\n",
310245549Sandrew	    state->registers[FP], state->registers[SP], state->registers[LR],
311245549Sandrew	    state->registers[PC]);
312245549Sandrew#endif
313245549Sandrew
314245549Sandrew	return 0;
315245549Sandrew}
316245549Sandrew
317245549Sandrew/* Performs the unwind of a function */
318245549Sandrewstatic int
319245549Sandrewdb_unwind_tab(struct unwind_state *state)
320245549Sandrew{
321245549Sandrew	uint32_t entry;
322245549Sandrew
323245549Sandrew	/* Set PC to a known value */
324245549Sandrew	state->registers[PC] = 0;
325245549Sandrew
326245549Sandrew	/* Read the personality */
327245549Sandrew	entry = *state->insn & ENTRY_MASK;
328245549Sandrew
329245549Sandrew	if (entry == ENTRY_ARM_SU16) {
330245549Sandrew		state->byte = 2;
331245549Sandrew		state->entries = 1;
332245549Sandrew	} else if (entry == ENTRY_ARM_LU16) {
333245549Sandrew		state->byte = 1;
334245549Sandrew		state->entries = ((*state->insn >> 16) & 0xFF) + 1;
335245549Sandrew	} else {
336245549Sandrew		db_printf("Unknown entry: %x\n", entry);
337245549Sandrew		return 1;
338245549Sandrew	}
339245549Sandrew
340245549Sandrew	while (state->entries > 0) {
341245549Sandrew		if (db_unwind_exec_insn(state) != 0)
342245549Sandrew			return 1;
343245549Sandrew	}
344245549Sandrew
345245549Sandrew	/*
346245549Sandrew	 * The program counter was not updated, load it from the link register.
347245549Sandrew	 */
348276033Sandrew	if (state->registers[PC] == 0) {
349245549Sandrew		state->registers[PC] = state->registers[LR];
350245549Sandrew
351276033Sandrew		/*
352276033Sandrew		 * If the program counter changed, flag it in the update mask.
353276033Sandrew		 */
354276033Sandrew		if (state->start_pc != state->registers[PC])
355276033Sandrew			state->update_mask |= 1 << PC;
356276033Sandrew	}
357276033Sandrew
358245549Sandrew	return 0;
359245549Sandrew}
360245549Sandrew
361245549Sandrewstatic void
362245549Sandrewdb_stack_trace_cmd(struct unwind_state *state)
363245549Sandrew{
364245549Sandrew	struct unwind_idx *index;
365245549Sandrew	const char *name;
366245549Sandrew	db_expr_t value;
367245549Sandrew	db_expr_t offset;
368245549Sandrew	c_db_sym_t sym;
369245549Sandrew	u_int reg, i;
370245549Sandrew	char *sep;
371250252Sian	uint16_t upd_mask;
372250252Sian	bool finished;
373245549Sandrew
374250252Sian	finished = false;
375250252Sian	while (!finished) {
376245549Sandrew		/* Reset the mask of updated registers */
377245549Sandrew		state->update_mask = 0;
378245549Sandrew
379245549Sandrew		/* The pc value is correct and will be overwritten, save it */
380245549Sandrew		state->start_pc = state->registers[PC];
381245549Sandrew
382245549Sandrew		/* Find the item to run */
383245549Sandrew		index = db_find_index(state->start_pc);
384245549Sandrew
385250252Sian		if (index->insn != EXIDX_CANTUNWIND) {
386258780Seadler			if (index->insn & (1U << 31)) {
387250252Sian				/* The data is within the instruction */
388250252Sian				state->insn = &index->insn;
389250252Sian			} else {
390250252Sian				/* A prel31 offset to the unwind table */
391250252Sian				state->insn = (uint32_t *)
392273157Srpaulo				    ((uintptr_t)&index->insn +
393250252Sian				     db_expand_prel31(index->insn));
394250252Sian			}
395250252Sian			/* Run the unwind function */
396250252Sian			finished = db_unwind_tab(state);
397245549Sandrew		}
398245549Sandrew
399245549Sandrew		/* Print the frame details */
400245549Sandrew		sym = db_search_symbol(state->start_pc, DB_STGY_ANY, &offset);
401245549Sandrew		if (sym == C_DB_SYM_NULL) {
402245549Sandrew			value = 0;
403245549Sandrew			name = "(null)";
404245549Sandrew		} else
405245549Sandrew			db_symbol_values(sym, &name, &value);
406245549Sandrew		db_printf("%s() at ", name);
407245549Sandrew		db_printsym(state->start_pc, DB_STGY_PROC);
408245549Sandrew		db_printf("\n");
409245549Sandrew		db_printf("\t pc = 0x%08x  lr = 0x%08x (", state->start_pc,
410245549Sandrew		    state->registers[LR]);
411245549Sandrew		db_printsym(state->registers[LR], DB_STGY_PROC);
412245549Sandrew		db_printf(")\n");
413245549Sandrew		db_printf("\t sp = 0x%08x  fp = 0x%08x",
414245549Sandrew		    state->registers[SP], state->registers[FP]);
415245549Sandrew
416245549Sandrew		/* Don't print the registers we have already printed */
417273157Srpaulo		upd_mask = state->update_mask &
418250252Sian		    ~((1 << SP) | (1 << FP) | (1 << LR) | (1 << PC));
419245549Sandrew		sep = "\n\t";
420250252Sian		for (i = 0, reg = 0; upd_mask != 0; upd_mask >>= 1, reg++) {
421250252Sian			if ((upd_mask & 1) != 0) {
422245549Sandrew				db_printf("%s%sr%d = 0x%08x", sep,
423245549Sandrew				    (reg < 10) ? " " : "", reg,
424245549Sandrew				    state->registers[reg]);
425245549Sandrew				i++;
426245549Sandrew				if (i == 2) {
427245549Sandrew					sep = "\n\t";
428245549Sandrew					i = 0;
429245549Sandrew				} else
430245549Sandrew					sep = " ";
431273157Srpaulo
432245549Sandrew			}
433245549Sandrew		}
434245549Sandrew		db_printf("\n");
435250252Sian
436250254Sian		/*
437250254Sian		 * Stop if directed to do so, or if we've unwound back to the
438250252Sian		 * kernel entry point, or if the unwind function didn't change
439250252Sian		 * anything (to avoid getting stuck in this loop forever).
440250252Sian		 * If the latter happens, it's an indication that the unwind
441250252Sian		 * information is incorrect somehow for the function named in
442250252Sian		 * the last frame printed before you see the unwind failure
443250252Sian		 * message (maybe it needs a STOP_UNWINDING).
444250252Sian		 */
445250252Sian		if (index->insn == EXIDX_CANTUNWIND) {
446250252Sian			finished = true;
447250252Sian		} else if (state->registers[PC] < VM_MIN_KERNEL_ADDRESS) {
448250252Sian			db_printf("Unable to unwind into user mode\n");
449250252Sian			finished = true;
450250252Sian		} else if (state->update_mask == 0) {
451250252Sian			db_printf("Unwind failure (no registers changed)\n");
452250252Sian			finished = true;
453250252Sian		}
454245549Sandrew	}
455245549Sandrew}
456245549Sandrew#endif
457245549Sandrew
458245549Sandrew/*
459129198Scognet * APCS stack frames are awkward beasts, so I don't think even trying to use
460129198Scognet * a structure to represent them is a good idea.
461129198Scognet *
462129198Scognet * Here's the diagram from the APCS.  Increasing address is _up_ the page.
463236991Simp *
464129198Scognet *          save code pointer       [fp]        <- fp points to here
465129198Scognet *          return link value       [fp, #-4]
466129198Scognet *          return sp value         [fp, #-8]
467129198Scognet *          return fp value         [fp, #-12]
468129198Scognet *          [saved v7 value]
469129198Scognet *          [saved v6 value]
470129198Scognet *          [saved v5 value]
471129198Scognet *          [saved v4 value]
472129198Scognet *          [saved v3 value]
473129198Scognet *          [saved v2 value]
474129198Scognet *          [saved v1 value]
475129198Scognet *          [saved a4 value]
476129198Scognet *          [saved a3 value]
477129198Scognet *          [saved a2 value]
478129198Scognet *          [saved a1 value]
479129198Scognet *
480236991Simp * The save code pointer points twelve bytes beyond the start of the
481236991Simp * code sequence (usually a single STM) that created the stack frame.
482236991Simp * We have to disassemble it if we want to know which of the optional
483129198Scognet * fields are actually present.
484129198Scognet */
485129198Scognet
486245549Sandrew#ifndef __ARM_EABI__	/* The frame format is differend in AAPCS */
487132482Smarcelstatic void
488236308Sgberdb_stack_trace_cmd(db_expr_t addr, db_expr_t count, boolean_t kernel_only)
489129198Scognet{
490129198Scognet	u_int32_t	*frame, *lastframe;
491129198Scognet	c_db_sym_t sym;
492129198Scognet	const char *name;
493129198Scognet	db_expr_t value;
494129198Scognet	db_expr_t offset;
495160312Sjhb	int	scp_offset;
496129198Scognet
497137977Scognet	frame = (u_int32_t *)addr;
498129198Scognet	lastframe = NULL;
499129198Scognet	scp_offset = -(get_pc_str_offset() >> 2);
500129198Scognet
501160312Sjhb	while (count-- && frame != NULL && !db_pager_quit) {
502129198Scognet		db_addr_t	scp;
503129198Scognet		u_int32_t	savecode;
504129198Scognet		int		r;
505129198Scognet		u_int32_t	*rp;
506129198Scognet		const char	*sep;
507129198Scognet
508129198Scognet		/*
509129198Scognet		 * In theory, the SCP isn't guaranteed to be in the function
510129198Scognet		 * that generated the stack frame.  We hope for the best.
511129198Scognet		 */
512129198Scognet		scp = frame[FR_SCP];
513129198Scognet
514135647Scognet		sym = db_search_symbol(scp, DB_STGY_ANY, &offset);
515129198Scognet		if (sym == C_DB_SYM_NULL) {
516129198Scognet			value = 0;
517129198Scognet			name = "(null)";
518129198Scognet		} else
519129198Scognet			db_symbol_values(sym, &name, &value);
520129198Scognet		db_printf("%s() at ", name);
521135647Scognet		db_printsym(scp, DB_STGY_PROC);
522129198Scognet		db_printf("\n");
523129198Scognet#ifdef __PROG26
524253309Srpaulo		db_printf("\tscp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV] & R15_PC);
525129198Scognet		db_printsym(frame[FR_RLV] & R15_PC, DB_STGY_PROC);
526129198Scognet		db_printf(")\n");
527129198Scognet#else
528253309Srpaulo		db_printf("\tscp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV]);
529129198Scognet		db_printsym(frame[FR_RLV], DB_STGY_PROC);
530129198Scognet		db_printf(")\n");
531129198Scognet#endif
532129198Scognet		db_printf("\trsp=0x%08x rfp=0x%08x", frame[FR_RSP], frame[FR_RFP]);
533129198Scognet
534129198Scognet		savecode = ((u_int32_t *)scp)[scp_offset];
535129198Scognet		if ((savecode & 0x0e100000) == 0x08000000) {
536129198Scognet			/* Looks like an STM */
537129198Scognet			rp = frame - 4;
538129198Scognet			sep = "\n\t";
539129198Scognet			for (r = 10; r >= 0; r--) {
540129198Scognet				if (savecode & (1 << r)) {
541129198Scognet					db_printf("%sr%d=0x%08x",
542129198Scognet					    sep, r, *rp--);
543129198Scognet					sep = (frame - rp) % 4 == 2 ?
544129198Scognet					    "\n\t" : " ";
545129198Scognet				}
546129198Scognet			}
547129198Scognet		}
548129198Scognet
549129198Scognet		db_printf("\n");
550129198Scognet
551129198Scognet		/*
552129198Scognet		 * Switch to next frame up
553129198Scognet		 */
554129198Scognet		if (frame[FR_RFP] == 0)
555129198Scognet			break; /* Top of stack */
556129198Scognet
557129198Scognet		lastframe = frame;
558129198Scognet		frame = (u_int32_t *)(frame[FR_RFP]);
559129198Scognet
560129198Scognet		if (INKERNEL((int)frame)) {
561129198Scognet			/* staying in kernel */
562129198Scognet			if (frame <= lastframe) {
563129198Scognet				db_printf("Bad frame pointer: %p\n", frame);
564129198Scognet				break;
565129198Scognet			}
566129198Scognet		} else if (INKERNEL((int)lastframe)) {
567129198Scognet			/* switch from user to kernel */
568129198Scognet			if (kernel_only)
569129198Scognet				break;	/* kernel stack only */
570129198Scognet		} else {
571129198Scognet			/* in user */
572129198Scognet			if (frame <= lastframe) {
573129198Scognet				db_printf("Bad user frame pointer: %p\n",
574129198Scognet					  frame);
575129198Scognet				break;
576129198Scognet			}
577129198Scognet		}
578129198Scognet	}
579129198Scognet}
580245549Sandrew#endif
581129198Scognet
582129198Scognet/* XXX stubs */
583129198Scognetvoid
584129198Scognetdb_md_list_watchpoints()
585129198Scognet{
586129198Scognet}
587129198Scognet
588129198Scognetint
589129198Scognetdb_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
590129198Scognet{
591129198Scognet	return (0);
592129198Scognet}
593129198Scognet
594129198Scognetint
595129198Scognetdb_md_set_watchpoint(db_expr_t addr, db_expr_t size)
596129198Scognet{
597129198Scognet	return (0);
598129198Scognet}
599132482Smarcel
600132059Scognetint
601132059Scognetdb_trace_thread(struct thread *thr, int count)
602129198Scognet{
603245549Sandrew#ifdef __ARM_EABI__
604245549Sandrew	struct unwind_state state;
605245549Sandrew#endif
606198943Smarcel	struct pcb *ctx;
607129198Scognet
608236308Sgber	if (thr != curthread) {
609236308Sgber		ctx = kdb_thr_ctx(thr);
610245549Sandrew
611245549Sandrew#ifdef __ARM_EABI__
612276190Sian		state.registers[FP] = ctx->pcb_regs.sf_r11;
613276190Sian		state.registers[SP] = ctx->pcb_regs.sf_sp;
614276190Sian		state.registers[LR] = ctx->pcb_regs.sf_lr;
615276190Sian		state.registers[PC] = ctx->pcb_regs.sf_pc;
616245549Sandrew
617245549Sandrew		db_stack_trace_cmd(&state);
618245549Sandrew#else
619276190Sian		db_stack_trace_cmd(ctx->pcb_regs.sf_r11, -1, TRUE);
620245549Sandrew#endif
621236308Sgber	} else
622236308Sgber		db_trace_self();
623132059Scognet	return (0);
624129198Scognet}
625132059Scognet
626132059Scognetvoid
627132059Scognetdb_trace_self(void)
628132059Scognet{
629245549Sandrew#ifdef __ARM_EABI__
630245549Sandrew	struct unwind_state state;
631248124Sandrew	uint32_t sp;
632245549Sandrew
633248124Sandrew	/* Read the stack pointer */
634248124Sandrew	__asm __volatile("mov %0, sp" : "=&r" (sp));
635248124Sandrew
636245549Sandrew	state.registers[FP] = (uint32_t)__builtin_frame_address(0);
637248124Sandrew	state.registers[SP] = sp;
638245549Sandrew	state.registers[LR] = (uint32_t)__builtin_return_address(0);
639245549Sandrew	state.registers[PC] = (uint32_t)db_trace_self;
640245549Sandrew
641245549Sandrew	db_stack_trace_cmd(&state);
642245549Sandrew#else
643198942Smarcel	db_addr_t addr;
644198942Smarcel
645203171Smarcel	addr = (db_addr_t)__builtin_frame_address(0);
646236308Sgber	db_stack_trace_cmd(addr, -1, FALSE);
647245549Sandrew#endif
648132059Scognet}
649