1/*-
2 * Copyright (c) 2015 The FreeBSD Foundation
3 *
4 * This software was developed by Semihalf under
5 * the sponsorship of the FreeBSD Foundation.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include "opt_ddb.h"
30
31#include <sys/param.h>
32#include <sys/proc.h>
33#include <sys/kdb.h>
34
35#include <machine/pcb.h>
36#include <ddb/ddb.h>
37#include <ddb/db_sym.h>
38
39#include <machine/armreg.h>
40#include <machine/debug_monitor.h>
41#include <machine/stack.h>
42#include <machine/vmparam.h>
43
44#define	FRAME_NORMAL	0
45#define	FRAME_SYNC	1
46#define	FRAME_IRQ	2
47#define	FRAME_SERROR	3
48#define	FRAME_UNHANDLED	4
49
50void
51db_md_list_breakpoints(void)
52{
53
54	dbg_show_breakpoint();
55}
56
57void
58db_md_list_watchpoints(void)
59{
60
61	dbg_show_watchpoint();
62}
63
64static void __nosanitizeaddress
65db_stack_trace_cmd(struct thread *td, struct unwind_state *frame)
66{
67	c_db_sym_t sym;
68	const char *name;
69	db_expr_t value;
70	db_expr_t offset;
71	int frame_type;
72
73	while (1) {
74		sym = db_search_symbol(frame->pc, DB_STGY_ANY, &offset);
75		if (sym == C_DB_SYM_NULL) {
76			value = 0;
77			name = "(null)";
78		} else
79			db_symbol_values(sym, &name, &value);
80
81		db_printf("%s() at ", name);
82		db_printsym(frame->pc, DB_STGY_PROC);
83		db_printf("\n");
84
85		if (strcmp(name, "handle_el0_sync") == 0 ||
86		    strcmp(name, "handle_el1h_sync") == 0)
87			frame_type = FRAME_SYNC;
88		else if (strcmp(name, "handle_el0_irq") == 0 ||
89		     strcmp(name, "handle_el1h_irq") == 0)
90			frame_type = FRAME_IRQ;
91		else if (strcmp(name, "handle_serror") == 0)
92			frame_type = FRAME_SERROR;
93		else if (strcmp(name, "handle_empty_exception") == 0)
94			frame_type = FRAME_UNHANDLED;
95		else
96			frame_type = FRAME_NORMAL;
97
98		if (frame_type != FRAME_NORMAL) {
99			struct trapframe *tf;
100
101			tf = (struct trapframe *)(uintptr_t)frame->fp - 1;
102			if (!__is_aligned(tf, _Alignof(struct trapframe)) ||
103			    !kstack_contains(td, (vm_offset_t)tf,
104			    sizeof(*tf))) {
105				db_printf("--- invalid trapframe %p\n", tf);
106				break;
107			}
108
109			switch (frame_type) {
110			case FRAME_SYNC:
111				db_printf("--- exception, esr %#lx\n",
112				    tf->tf_esr);
113				break;
114			case FRAME_IRQ:
115				db_printf("--- interrupt\n");
116				break;
117			case FRAME_SERROR:
118				db_printf("--- system error, esr %#lx\n",
119				    tf->tf_esr);
120				break;
121			case FRAME_UNHANDLED:
122				db_printf("--- unhandled exception, esr %#lx\n",
123				    tf->tf_esr);
124				break;
125			default:
126				__assert_unreachable();
127				break;
128			}
129
130			frame->fp = tf->tf_x[29];
131			frame->pc = ADDR_MAKE_CANONICAL(tf->tf_elr);
132			if (!INKERNEL(frame->fp))
133				break;
134		} else {
135			if (strcmp(name, "fork_trampoline") == 0)
136				break;
137
138			if (!unwind_frame(td, frame))
139				break;
140		}
141	}
142}
143
144int __nosanitizeaddress
145db_trace_thread(struct thread *thr, int count)
146{
147	struct unwind_state frame;
148	struct pcb *ctx;
149
150	if (thr != curthread) {
151		ctx = kdb_thr_ctx(thr);
152
153		frame.fp = (uintptr_t)ctx->pcb_x[PCB_FP];
154		frame.pc = (uintptr_t)ctx->pcb_x[PCB_LR];
155		db_stack_trace_cmd(thr, &frame);
156	} else
157		db_trace_self();
158	return (0);
159}
160
161void __nosanitizeaddress
162db_trace_self(void)
163{
164	struct unwind_state frame;
165
166	frame.fp = (uintptr_t)__builtin_frame_address(0);
167	frame.pc = (uintptr_t)db_trace_self;
168	db_stack_trace_cmd(curthread, &frame);
169}
170