1/*	$NetBSD: db_trace.c,v 1.6 2023/10/06 11:45:16 skrll Exp $	*/
2
3/* Inspired by reading alpha/db_trace.c */
4
5/*-
6 * Copyright (c) 2006 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * Author: Cherry G. Mathew
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33
34#include "opt_ddb.h"
35
36#include <sys/param.h>
37#include <sys/proc.h>
38#include <sys/systm.h>
39
40#include <machine/cpufunc.h>
41#include <machine/md_var.h>
42#include <machine/db_machdep.h>
43
44#include <ddb/db_sym.h>
45#include <ddb/db_access.h>
46#include <ddb/db_output.h>
47#include <ddb/db_variables.h>
48#include <ddb/db_interface.h>
49
50#include <ia64/unwind/decode.h>
51#include <ia64/unwind/stackframe.h>
52
53#if 0
54#define UNWIND_DIAGNOSTIC
55#endif
56
57#define debug_frame_dump_XXX(uwf) \
58	printf("Frame Dump: \n bsp = 0x%lx \n pfs = 0x%lx, SOL(pfs) = %lu \n rp = 0x%lx \n",  \
59	       uwf->bsp, uwf->pfs, IA64_CFM_SOL(uwf->pfs), uwf->rp);	\
60
61void
62initunwindframe(struct unwind_frame *uwf, struct trapframe *tf);
63void
64rewindframe(struct unwind_frame *uwf, db_addr_t ip);
65
66void
67db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count,
68		     const char *modif, void (*pr)(const char *, ...))
69{
70	char c;
71	const char *cp = modif;
72	bool trace_thread = false;
73	bool trace_user = false;
74	struct trapframe *tf;
75	struct unwind_frame current_frame;
76	db_addr_t ip;
77	const char *name;
78	db_sym_t sym;
79	db_expr_t offset;
80
81	while ((c = *cp++) != 0) {
82		trace_thread |= c == 't';
83		trace_user |= c == 'u';
84	}
85
86	if (trace_user) {
87		(*pr)("User-space stack tracing not implemented yet. \n");
88		return;
89	}
90	if (!have_addr) {
91		(*pr)("--Kernel Call Trace-- \n");
92
93		tf = DDB_REGS;
94		ip = tf->tf_special.iip + ((tf->tf_special.psr >> 41) & 3);
95
96		initunwindframe(&current_frame, tf);
97
98#ifdef UNWIND_DIAGNOSTIC
99		struct unwind_frame *uwf = &current_frame;
100		debug_frame_dump_XXX(uwf);
101#endif
102		KASSERT(ip >= kernstart);
103		patchunwindframe(&current_frame, ip - kernstart, kernstart);
104#ifdef UNWIND_DIAGNOSTIC
105		debug_frame_dump_XXX(uwf);
106#endif
107		/* Get into unwind loop. */
108
109		while(ip) {
110			sym = db_search_symbol(ip, DB_STGY_ANY, &offset);
111			db_symbol_values(sym, &name, NULL);
112			(*pr)("%s(...)\n", name);
113
114			ip = current_frame.rp;
115
116			if(!ip) break;
117
118			rewindframe(&current_frame, ip);
119		}
120
121		return;
122
123
124	} else (*pr) ("Unwind from arbitrary addresses unimplemented. \n");
125
126
127		if (trace_thread) {
128			(*pr)("trace by pid unimplemented. \n");
129			return;
130		}
131		else {
132			(*pr)("trace from arbitrary trap frame address unimplemented. \n");
133		}
134
135}
136
137extern db_addr_t ia64_unwindtab;
138extern vsize_t ia64_unwindtablen;
139
140
141/* Generates initial unwind frame context based on the contents
142 * of the trap frame, by consulting the Unwind library
143 * staterecord. If a register is of type enum UNSAVED, we fetch
144 * the live value of the register from the trapframe.
145 */
146
147void
148initunwindframe(struct unwind_frame *uwf, struct trapframe *tf)
149
150{
151
152	uwf->rp = tf->tf_special.rp;
153
154	/* ndirty = bsp - bspstore: , not the same as the definition in the spec.
155	 * Gave me hell for a day!
156	 * see: ia64/exception.S: exception_save_restore: */
157
158	uwf->bsp = tf->tf_special.bspstore + tf->tf_special.ndirty;
159	uwf->bsp = ia64_bsp_adjust_ret(uwf->bsp, IA64_CFM_SOF(tf->tf_special.cfm));
160#ifdef UNWIND_DIAGNOSTIC
161	printf("inituwframe(): SOF(cfm) = %lu \n", IA64_CFM_SOF(tf->tf_special.cfm));
162#endif
163	uwf->pfs = tf->tf_special.pfs;
164	uwf->sp = uwf->psp = tf->tf_special.sp;
165
166
167}
168
169
170
171/* Single step the frame backward.
172 * Assumes unwind_frame is setup already.
173 */
174
175void
176rewindframe(struct unwind_frame *uwf, db_addr_t ip)
177{
178/* XXX: Check for a stack switch */
179
180	uwf->bsp = ia64_bsp_adjust_ret(uwf->bsp, IA64_CFM_SOL(uwf->pfs));
181	uwf->sp = uwf->psp;
182
183	/* Pre-stomp frame dump */
184#ifdef UNWIND_DIAGNOSTIC
185	debug_frame_dump_XXX(uwf);
186#endif
187
188	/* Stomp on rp and pfs
189	 */
190	KASSERT(ip >= kernstart);
191	patchunwindframe(uwf, ip - kernstart, kernstart);
192
193#ifdef UNWIND_DIAGNOSTIC
194	debug_frame_dump_XXX(uwf);
195#endif
196
197}
198