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 */
31294740Szbb#include "opt_ddb.h"
32129198Scognet
33129198Scognet#include <sys/cdefs.h>
34129198Scognet__FBSDID("$FreeBSD: stable/11/sys/arm/arm/db_trace.c 314506 2017-03-01 19:55:04Z ian $");
35129198Scognet#include <sys/param.h>
36132402Scognet#include <sys/systm.h>
37129198Scognet
38129198Scognet
39129198Scognet#include <sys/proc.h>
40132059Scognet#include <sys/kdb.h>
41148666Sjeff#include <sys/stack.h>
42278895Sandrew
43129198Scognet#include <machine/armreg.h>
44129198Scognet#include <machine/asm.h>
45129198Scognet#include <machine/cpufunc.h>
46129198Scognet#include <machine/db_machdep.h>
47294740Szbb#include <machine/debug_monitor.h>
48138129Sdas#include <machine/pcb.h>
49174195Srwatson#include <machine/stack.h>
50129198Scognet#include <machine/vmparam.h>
51278895Sandrew
52129198Scognet#include <ddb/ddb.h>
53129198Scognet#include <ddb/db_access.h>
54129198Scognet#include <ddb/db_sym.h>
55129198Scognet#include <ddb/db_output.h>
56129198Scognet
57245549Sandrewstatic void
58245549Sandrewdb_stack_trace_cmd(struct unwind_state *state)
59245549Sandrew{
60245549Sandrew	const char *name;
61245549Sandrew	db_expr_t value;
62245549Sandrew	db_expr_t offset;
63245549Sandrew	c_db_sym_t sym;
64245549Sandrew	u_int reg, i;
65245549Sandrew	char *sep;
66250252Sian	uint16_t upd_mask;
67250252Sian	bool finished;
68245549Sandrew
69250252Sian	finished = false;
70250252Sian	while (!finished) {
71279667Sandrew		finished = unwind_stack_one(state, 1);
72245549Sandrew
73245549Sandrew		/* Print the frame details */
74245549Sandrew		sym = db_search_symbol(state->start_pc, DB_STGY_ANY, &offset);
75245549Sandrew		if (sym == C_DB_SYM_NULL) {
76245549Sandrew			value = 0;
77245549Sandrew			name = "(null)";
78245549Sandrew		} else
79245549Sandrew			db_symbol_values(sym, &name, &value);
80245549Sandrew		db_printf("%s() at ", name);
81245549Sandrew		db_printsym(state->start_pc, DB_STGY_PROC);
82245549Sandrew		db_printf("\n");
83245549Sandrew		db_printf("\t pc = 0x%08x  lr = 0x%08x (", state->start_pc,
84245549Sandrew		    state->registers[LR]);
85245549Sandrew		db_printsym(state->registers[LR], DB_STGY_PROC);
86245549Sandrew		db_printf(")\n");
87245549Sandrew		db_printf("\t sp = 0x%08x  fp = 0x%08x",
88245549Sandrew		    state->registers[SP], state->registers[FP]);
89245549Sandrew
90245549Sandrew		/* Don't print the registers we have already printed */
91273157Srpaulo		upd_mask = state->update_mask &
92250252Sian		    ~((1 << SP) | (1 << FP) | (1 << LR) | (1 << PC));
93245549Sandrew		sep = "\n\t";
94250252Sian		for (i = 0, reg = 0; upd_mask != 0; upd_mask >>= 1, reg++) {
95250252Sian			if ((upd_mask & 1) != 0) {
96245549Sandrew				db_printf("%s%sr%d = 0x%08x", sep,
97245549Sandrew				    (reg < 10) ? " " : "", reg,
98245549Sandrew				    state->registers[reg]);
99245549Sandrew				i++;
100245549Sandrew				if (i == 2) {
101245549Sandrew					sep = "\n\t";
102245549Sandrew					i = 0;
103245549Sandrew				} else
104245549Sandrew					sep = " ";
105273157Srpaulo
106245549Sandrew			}
107245549Sandrew		}
108245549Sandrew		db_printf("\n");
109250252Sian
110278895Sandrew		if (finished)
111278895Sandrew			break;
112278895Sandrew
113250254Sian		/*
114250254Sian		 * Stop if directed to do so, or if we've unwound back to the
115250252Sian		 * kernel entry point, or if the unwind function didn't change
116250252Sian		 * anything (to avoid getting stuck in this loop forever).
117250252Sian		 * If the latter happens, it's an indication that the unwind
118250252Sian		 * information is incorrect somehow for the function named in
119250252Sian		 * the last frame printed before you see the unwind failure
120250252Sian		 * message (maybe it needs a STOP_UNWINDING).
121250252Sian		 */
122278895Sandrew		if (state->registers[PC] < VM_MIN_KERNEL_ADDRESS) {
123250252Sian			db_printf("Unable to unwind into user mode\n");
124250252Sian			finished = true;
125250252Sian		} else if (state->update_mask == 0) {
126250252Sian			db_printf("Unwind failure (no registers changed)\n");
127250252Sian			finished = true;
128250252Sian		}
129245549Sandrew	}
130245549Sandrew}
131245549Sandrew
132129198Scognetvoid
133314506Siandb_md_list_watchpoints(void)
134129198Scognet{
135294740Szbb
136294740Szbb	dbg_show_watchpoint();
137129198Scognet}
138129198Scognet
139129198Scognetint
140129198Scognetdb_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
141129198Scognet{
142294740Szbb
143294740Szbb	return (dbg_remove_watchpoint(addr, size));
144129198Scognet}
145129198Scognet
146129198Scognetint
147129198Scognetdb_md_set_watchpoint(db_expr_t addr, db_expr_t size)
148129198Scognet{
149294740Szbb
150294740Szbb	return (dbg_setup_watchpoint(addr, size, HW_WATCHPOINT_RW));
151129198Scognet}
152132482Smarcel
153132059Scognetint
154132059Scognetdb_trace_thread(struct thread *thr, int count)
155129198Scognet{
156245549Sandrew	struct unwind_state state;
157198943Smarcel	struct pcb *ctx;
158129198Scognet
159236308Sgber	if (thr != curthread) {
160236308Sgber		ctx = kdb_thr_ctx(thr);
161245549Sandrew
162276190Sian		state.registers[FP] = ctx->pcb_regs.sf_r11;
163276190Sian		state.registers[SP] = ctx->pcb_regs.sf_sp;
164276190Sian		state.registers[LR] = ctx->pcb_regs.sf_lr;
165276190Sian		state.registers[PC] = ctx->pcb_regs.sf_pc;
166245549Sandrew
167245549Sandrew		db_stack_trace_cmd(&state);
168236308Sgber	} else
169236308Sgber		db_trace_self();
170132059Scognet	return (0);
171129198Scognet}
172132059Scognet
173132059Scognetvoid
174132059Scognetdb_trace_self(void)
175132059Scognet{
176245549Sandrew	struct unwind_state state;
177248124Sandrew	uint32_t sp;
178245549Sandrew
179248124Sandrew	/* Read the stack pointer */
180248124Sandrew	__asm __volatile("mov %0, sp" : "=&r" (sp));
181248124Sandrew
182245549Sandrew	state.registers[FP] = (uint32_t)__builtin_frame_address(0);
183248124Sandrew	state.registers[SP] = sp;
184245549Sandrew	state.registers[LR] = (uint32_t)__builtin_return_address(0);
185245549Sandrew	state.registers[PC] = (uint32_t)db_trace_self;
186245549Sandrew
187245549Sandrew	db_stack_trace_cmd(&state);
188132059Scognet}
189