1/* $NetBSD: db_trace.c,v 1.24 2024/02/07 04:20:26 msaitoh Exp $ */
2
3/*
4 * Copyright (c) 2017 Ryo Shimizu
5 * All rights reserved.
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 ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30
31__KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.24 2024/02/07 04:20:26 msaitoh Exp $");
32
33#include <sys/param.h>
34#include <sys/bitops.h>
35#include <sys/proc.h>
36
37#include <aarch64/db_machdep.h>
38#include <aarch64/machdep.h>
39#include <aarch64/armreg.h>
40#include <aarch64/vmparam.h>
41
42#include <arm/cpufunc.h>
43
44#include <uvm/uvm_extern.h>
45
46#include <ddb/db_access.h>
47#include <ddb/db_command.h>
48#include <ddb/db_output.h>
49#include <ddb/db_variables.h>
50#include <ddb/db_sym.h>
51#include <ddb/db_proc.h>
52#include <ddb/db_lwp.h>
53#include <ddb/db_extern.h>
54#include <ddb/db_interface.h>
55
56#ifdef _KERNEL
57extern char el0_trap[];
58extern char el1_trap[];
59#else
60/* see also usr.sbin/crash/arch/aarch64.c */
61extern vaddr_t el0_trap;
62extern vaddr_t el1_trap;
63#endif
64
65#define MAXBACKTRACE	128	/* against infinite loop */
66
67
68__CTASSERT(VM_MIN_ADDRESS == 0);
69#define IN_USER_VM_ADDRESS(addr)	\
70	((addr) < VM_MAX_ADDRESS)
71#define IN_KERNEL_VM_ADDRESS(addr)	\
72	((VM_MIN_KERNEL_ADDRESS <= (addr)) && ((addr) < VM_MAX_KERNEL_ADDRESS))
73
74static void
75pr_frame(struct trapframe *tf, void (*pr)(const char *, ...) __printflike(1, 2))
76{
77	struct trapframe tf_buf;
78
79	db_read_bytes((db_addr_t)tf, sizeof(tf_buf), (char *)&tf_buf);
80
81	if (tf_buf.tf_sp == 0) {
82		(*pr)("---- switchframe %p (%zu bytes) ----\n",
83		    tf, sizeof(*tf));
84		dump_switchframe(tf, pr);
85	} else {
86#ifdef _KERNEL
87		(*pr)("---- %s: trapframe %p (%zu bytes) ----\n",
88		    (tf_buf.tf_esr == (uint64_t)-1) ? "Interrupt" :
89		    eclass_trapname(__SHIFTOUT(tf_buf.tf_esr, ESR_EC)),
90		    tf, sizeof(*tf));
91#else
92		(*pr)("---- trapframe %p (%zu bytes) ----\n", tf, sizeof(*tf));
93#endif
94		dump_trapframe(tf, pr);
95	}
96	(*pr)("------------------------"
97	      "------------------------\n");
98}
99
100static bool __unused
101is_lwp(void *p)
102{
103	lwp_t *lwp;
104
105	for (lwp = db_lwp_first(); lwp != NULL; lwp = db_lwp_next(lwp)) {
106		if (lwp == p)
107			return true;
108	}
109	return false;
110}
111
112static vaddr_t
113db_lwp_getuarea(lwp_t *l)
114{
115	void *laddr;
116	db_read_bytes((db_addr_t)&l->l_addr, sizeof(laddr), (char *)&laddr);
117	if (laddr == 0)
118		return 0;
119	return (vaddr_t)((char *)laddr - UAREA_PCB_OFFSET);
120}
121
122static const char *
123getlwpnamebysp(uint64_t sp)
124{
125	static char c_name[MAXCOMLEN];
126	lwp_t *lwp;
127	struct proc *pp;
128	char *lname;
129
130	for (lwp = db_lwp_first(); lwp != NULL; lwp = db_lwp_next(lwp)) {
131		uint64_t uarea = db_lwp_getuarea(lwp);
132		if ((uarea <= sp) && (sp < (uarea + USPACE))) {
133			db_read_bytes((db_addr_t)&lwp->l_name, sizeof(lname),
134			    (char *)&lname);
135			if (lname != NULL) {
136				db_read_bytes((db_addr_t)lname, sizeof(c_name),
137			    c_name);
138				return c_name;
139			}
140			db_read_bytes((db_addr_t)&lwp->l_proc, sizeof(pp),
141			    (char *)&pp);
142			if (pp != NULL) {
143				db_read_bytes((db_addr_t)&pp->p_comm,
144				    sizeof(c_name), c_name);
145				return c_name;
146			}
147			break;
148		}
149	}
150	return "unknown";
151}
152
153#define TRACEFLAG_LOOKUPLWP	0x00000001
154#define TRACEFLAG_USERSPACE	0x00000002
155
156static void
157pr_traceaddr(const char *prefix, uint64_t frame, uint64_t pc, int flags,
158    void (*pr)(const char *, ...) __printflike(1, 2))
159{
160	db_expr_t offset;
161	db_sym_t sym;
162	const char *name;
163
164	sym = db_search_symbol(pc, DB_STGY_ANY, &offset);
165	if (sym != DB_SYM_NULL) {
166		db_symbol_values(sym, &name, NULL);
167
168		if (flags & TRACEFLAG_LOOKUPLWP) {
169			(*pr)("%s %016lx %s %s() at %016lx ",
170			    prefix, frame, getlwpnamebysp(frame), name, pc);
171		} else {
172			(*pr)("%s %016lx %s() at %016lx ",
173			    prefix, frame, name, pc);
174		}
175		db_printsym(pc, DB_STGY_PROC, pr);
176		(*pr)("\n");
177	} else {
178		if (flags & TRACEFLAG_LOOKUPLWP) {
179			(*pr)("%s %016lx %s ?() at %016lx\n",
180			    prefix, frame, getlwpnamebysp(frame), pc);
181		} else {
182			(*pr)("%s %016lx ?() at %016lx\n", prefix, frame, pc);
183		}
184	}
185}
186
187static __inline uint64_t
188SignExtend(int bitwidth, uint64_t imm, unsigned int multiply)
189{
190	const uint64_t signbit = ((uint64_t)1 << (bitwidth - 1));
191	const uint64_t immmax = signbit << 1;
192
193	if (imm & signbit)
194		imm -= immmax;
195	return imm * multiply;
196}
197
198static __inline uint64_t
199ZeroExtend(int bitwidth, uint64_t imm, unsigned int multiply)
200{
201	return imm * multiply;
202}
203
204/* rotate right. if n < 0, rotate left. */
205static __inline uint64_t
206rotate(int bitwidth, uint64_t v, int n)
207{
208	uint64_t result;
209
210	n &= (bitwidth - 1);
211	result = (((v << (bitwidth - n)) | (v >> n)));
212	if (bitwidth < 64)
213		result &= ((1ULL << bitwidth) - 1);
214	return result;
215}
216
217static __inline uint64_t
218DecodeBitMasks(uint64_t sf, uint64_t n, uint64_t imms, uint64_t immr)
219{
220	const int bitwidth = (sf == 0) ? 32 : 64;
221	uint64_t result;
222	int esize, len;
223
224	len = fls64((n << 6) + (~imms & 0x3f)) - 1;
225	esize = (1 << len);
226	imms &= (esize - 1);
227	immr &= (esize - 1);
228	result = rotate(esize, (1ULL << (imms + 1)) - 1, immr);
229	while (esize < bitwidth) {
230		result |= (result << esize);
231		esize <<= 1;
232	}
233	if (sf == 0)
234		result &= ((1ULL << bitwidth) - 1);
235	return result;
236}
237
238static int
239analyze_func(db_addr_t func_entry, db_addr_t pc, db_addr_t sp,
240    db_addr_t *lrp, vsize_t *stacksizep,
241    void (*pr)(const char *, ...) __printflike(1, 2))
242{
243	vsize_t ssize = 0, lr_off = 0;
244	db_addr_t lr = 0;
245	uint64_t alloc_by_Xn_kvalue = 0;
246	uint64_t alloc_by_Xn_kmask = 0;
247	int alloc_by_Xn_reg = -1;
248	bool found_lr_off = false;
249	bool func_entry_autodetect = false;
250
251#define MAX_BACKTRACK_ANALYZE_INSN	(1024 * 4)
252	if (func_entry == 0) {
253		if (pc > MAX_BACKTRACK_ANALYZE_INSN)
254			func_entry = pc - MAX_BACKTRACK_ANALYZE_INSN;
255		else
256			func_entry = 4;
257		func_entry_autodetect = true;
258	};
259
260
261	/*
262	 * Locate the following instructions that allocates a stackframe.
263	 * Only the following patterns are supported:
264	 *
265	 *  sub sp, sp, #ALLOCSIZE		-> ssize += ALLOCSIZE
266	 *  sub sp, sp, #ALLOCSIZE, lsl #12	-> ssize += (ALLOCSIZE << 12)
267	 *
268	 *  mov xN, #ALLOCSIZE1
269	 *  (movk xN, #ALLOCSIZE2, lsl #xx)
270	 *  sub sp, sp, xN			-> ssize += ALLOCSIZE
271	 *
272	 *  stp x30, x??, [sp, #-ALLOCSIZE]!	-> ssize =+ ALLOCSIZE, lr_off=0
273	 *  stp x??, x30, [sp, #-ALLOCSIZE]!	-> ssize =+ ALLOCSIZE, lr_off=8
274	 *  stp x??, x??, [sp, #-ALLOCSIZE]!	-> ssize =+ ALLOCSIZE
275	 *
276	 *  str x30, [sp, #-ALLOCSIZE]!		-> ssize =+ ALLOCSIZE, lr_off=0
277	 *
278	 *  stp x30, x??, [sp, #LR_OFF]		-> lr_off = LR_OFF
279	 *  stp x??, x30, [sp, #LR_OFF]		-> lr_off = LR_OFF+8
280	 *  str x30, [sp, #LR_OFF]		-> lr_off = LR_OFF
281	 */
282
283/* #define BACKTRACE_ANALYZE_DEBUG */
284#ifdef BACKTRACE_ANALYZE_DEBUG
285#define TRACE_DEBUG(fmt, args...)	pr("BACKTRACE: " fmt, ## args)
286#else
287#define TRACE_DEBUG(args...)		__nothing
288#endif
289
290	TRACE_DEBUG("func_entry=%016lx\n", func_entry);
291	TRACE_DEBUG("        pc=%016lx (+%#lx)\n", pc, pc - func_entry);
292	TRACE_DEBUG("        sp=%016lx\n", sp);
293
294	for (pc -= 4; pc >= func_entry; pc -= 4) {
295		uint32_t insn;
296
297		db_read_bytes(pc, sizeof(insn), (char *)&insn);
298		if (insn == 0)
299			break;
300		LE32TOH(insn);
301
302		TRACE_DEBUG("INSN: %016lx: %04x\n", pc, insn);
303
304		/* "ret", "eret", or "paciasp" to detect function entry */
305		if (func_entry_autodetect && (
306		    insn == 0xd65f03e0 ||	/* "ret" */
307		    insn == 0xd69f03e0 ||	/* "eret" */
308		    insn == 0xd503233f))	/* "paciasp" */
309			break;
310
311		/* "sub sp,sp,#imm" or "sub sp,sp,#imm,lsl #12" */
312		if ((insn & 0xff8003ff) == 0xd10003ff) {
313			unsigned int sh = (insn >> 22) & 1;
314			uint64_t imm12 =
315			    ZeroExtend(12, (insn >> 10) & 0xfff, 1);
316			if (sh)
317				imm12 <<= 12;
318			ssize += imm12;
319			TRACE_DEBUG("sub sp,sp,#%lu\n", imm12);
320			continue;
321		}
322
323		/* sub sp,sp,Xn */
324		if ((insn & 0xffe0ffff) == 0xcb2063ff) {
325			alloc_by_Xn_reg = (insn >> 16) & 0x1f;
326			alloc_by_Xn_kvalue = 0;
327			alloc_by_Xn_kmask = 0;
328			TRACE_DEBUG("sub sp,sp,x%d\n", alloc_by_Xn_reg);
329			continue;
330		}
331		if (alloc_by_Xn_reg >= 0) {
332			/* movk xN,#ALLOCSIZE2,lsl #xx */
333			if ((insn & 0xff80001f) ==
334			    (0xf2800000 | alloc_by_Xn_reg)) {
335				int hw = (insn >> 21) & 3;
336				alloc_by_Xn_kvalue = ZeroExtend(16,
337				    (insn >> 5) & 0xffff, 1) << (hw * 16);
338				alloc_by_Xn_kmask = (0xffffULL << (hw * 16));
339				TRACE_DEBUG("movk x%d,#%#lx,lsl #%d\n",
340				    alloc_by_Xn_reg, alloc_by_Xn_kvalue,
341				    hw * 16);
342				continue;
343			}
344
345			/* (orr) mov xN,#ALLOCSIZE1 */
346			if ((insn & 0xff8003ff) ==
347			    (0xb20003e0 | alloc_by_Xn_reg)) {
348				uint64_t n = (insn >> 22) & 1;
349				uint64_t immr = (insn >> 16) & 0x3f;
350				uint64_t imms = (insn >> 10) & 0x3f;
351				uint64_t v = DecodeBitMasks(1, n, imms, immr);
352				TRACE_DEBUG("(orr) mov x%d,#%#lx\n",
353				    alloc_by_Xn_reg, v);
354				ssize += v;
355				alloc_by_Xn_reg = -1;
356				continue;
357			}
358
359			/* (movz) mov xN,#ALLOCSIZE1 */
360			if ((insn & 0xffe0001f) ==
361			    (0xd2800000 | alloc_by_Xn_reg)) {
362				uint64_t v =
363				    ZeroExtend(16, (insn >> 5) & 0xffff, 1);
364				TRACE_DEBUG("(movz) mov x%d,#%#lx\n",
365				    alloc_by_Xn_reg, v);
366				v &= ~alloc_by_Xn_kmask;
367				v |= alloc_by_Xn_kvalue;
368				ssize += v;
369				alloc_by_Xn_reg = -1;
370				continue;
371			}
372			/* (movn) mov xN,#ALLOCSIZE1 */
373			if ((insn & 0xffe0001f) ==
374			    (0x92800000 | alloc_by_Xn_reg)) {
375				uint64_t v =
376				    ~ZeroExtend(16, (insn >> 5) & 0xffff, 1);
377				TRACE_DEBUG("(movn) mov x%d,#%#lx\n",
378				    alloc_by_Xn_reg, v);
379				v &= ~alloc_by_Xn_kmask;
380				v |= alloc_by_Xn_kvalue;
381				ssize += v;
382				alloc_by_Xn_reg = -1;
383				continue;
384			}
385		}
386
387		/* stp x??,x??,[sp,#-imm7]! */
388		if ((insn & 0xffe003e0) == 0xa9a003e0) {
389			int64_t imm7 = SignExtend(7, (insn >> 15) & 0x7f, 8);
390			uint64_t Rt2 = (insn >> 10) & 0x1f;
391			uint64_t Rt1 = insn & 0x1f;
392			if (Rt1 == 30) {
393				TRACE_DEBUG("stp x30,Xn[sp,#%ld]!\n", imm7);
394				lr_off = ssize;
395				ssize += -imm7;
396				found_lr_off = true;
397			} else if (Rt2 == 30) {
398				TRACE_DEBUG("stp Xn,x30,[sp,#%ld]!\n", imm7);
399				lr_off = ssize + 8;
400				ssize += -imm7;
401				found_lr_off = true;
402			} else {
403				ssize += -imm7;
404				TRACE_DEBUG("stp Xn,Xn,[sp,#%ld]!\n", imm7);
405			}
406
407			/*
408			 * "stp x29,x30,[sp,#-n]!" is the code to create
409			 * a frame pointer at the beginning of the function.
410			 */
411			if (func_entry_autodetect && Rt1 == 29 && Rt2 == 30)
412				break;
413
414			continue;
415		}
416
417		/* stp x??,x??,[sp,#imm7] */
418		if ((insn & 0xffc003e0) == 0xa90003e0) {
419			int64_t imm7 = SignExtend(7, (insn >> 15) & 0x7f, 8);
420			uint64_t Rt2 = (insn >> 10) & 0x1f;
421			uint64_t Rt1 = insn & 0x1f;
422			if (Rt1 == 30) {
423				lr_off = ssize + imm7;
424				found_lr_off = true;
425				TRACE_DEBUG("stp x30,X%lu[sp,#%ld]\n",
426				    Rt2, imm7);
427				TRACE_DEBUG("lr off = %lu = %#lx\n",
428				    lr_off, lr_off);
429			} else if (Rt2 == 30) {
430				lr_off = ssize + imm7 + 8;
431				found_lr_off = true;
432				TRACE_DEBUG("stp X%lu,x30,[sp,#%ld]\n",
433				    Rt1, imm7);
434				TRACE_DEBUG("lr off = %lu = %#lx\n",
435				    lr_off, lr_off);
436			}
437			continue;
438		}
439
440		/* str x30,[sp,#imm12] */
441		if ((insn & 0xffc003ff) == 0xf90003fe) {
442			uint64_t imm12 =
443			    ZeroExtend(12, (insn >> 10) & 0xfff, 8);
444			lr_off = ssize + imm12;
445			found_lr_off = true;
446			TRACE_DEBUG("str x30,[sp,#%lu]\n", imm12);
447			TRACE_DEBUG("lr off = %lu = %#lx\n", lr_off, lr_off);
448			continue;
449		}
450
451		/* str x30,[sp,#-imm9]! */
452		if ((insn & 0xfff00fff) == 0xf8100ffe) {
453			int64_t imm9 = SignExtend(9, (insn >> 12) & 0x1ff, 1);
454			lr_off = ssize;
455			ssize += -imm9;
456			found_lr_off = true;
457			TRACE_DEBUG("str x30,[sp,#%ld]!\n", imm9);
458			TRACE_DEBUG("lr off = %lu = %#lx\n", lr_off, lr_off);
459			continue;
460		}
461	}
462
463	if (found_lr_off) {
464		if (lr_off >= ssize) {
465			pr("cannot locate return address\n");
466			return -1;
467		}
468		db_read_bytes((db_addr_t)sp + lr_off, sizeof(lr), (char *)&lr);
469		lr = aarch64_strip_pac(lr);
470	}
471	*stacksizep = ssize;
472	*lrp = lr;
473
474	TRACE_DEBUG("-----------\n");
475	TRACE_DEBUG("       sp: %#lx\n", sp);
476	TRACE_DEBUG("stacksize: %#06lx = %lu\n", ssize, ssize);
477	TRACE_DEBUG("lr offset: %#06lx = %lu\n", lr_off, lr_off);
478	TRACE_DEBUG("   new lr: %#lx\n", lr);
479	TRACE_DEBUG("===========\n\n");
480
481	return 0;
482}
483
484/*
485 * Backtrace without framepointer ($fp).
486 *
487 * Examines the contents of a function and returns the stack size allocated
488 * by the function and the stored $lr.
489 *
490 * This works well for code compiled with -fomit-frame-pointer.
491 */
492static void
493db_sp_trace(struct trapframe *tf, db_addr_t fp, db_expr_t count, int flags,
494    void (*pr)(const char *, ...) __printflike(1, 2))
495{
496	struct trapframe tf_buf;
497	db_addr_t pc, sp, lr0;
498	bool allow_leaf_function = false;
499
500	if (tf == NULL) {
501		/*
502		 * In the case of "trace/s <frame-address>",
503		 * the specified frame pointer address is considered
504		 * a trapframe (or a switchframe) address.
505		 */
506		tf = (struct trapframe *)fp;
507	}
508
509	pr_frame(tf, pr);
510
511	db_read_bytes((db_addr_t)tf, sizeof(tf_buf), (char *)&tf_buf);
512	if (tf_buf.tf_sp == 0) {
513		/* switchframe */
514		lr0 = 0;
515		pc = aarch64_strip_pac(tf_buf.tf_lr) - 4;
516		sp = (uint64_t)(tf + 1);
517	} else {
518		/* trapframe */
519		lr0 = aarch64_strip_pac(tf_buf.tf_lr);
520		pc = tf_buf.tf_pc;
521		sp = tf_buf.tf_sp;
522		allow_leaf_function = true;
523	}
524
525	TRACE_DEBUG("pc =%016lx\n", pc);
526	TRACE_DEBUG("sp =%016lx\n", sp);
527	TRACE_DEBUG("lr0=%016lx\n", lr0);
528
529	for (; (count > 0) && (sp != 0); count--) {
530		if ((pc == (db_addr_t)el0_trap) ||
531		    (pc == (db_addr_t)el1_trap)) {
532
533			pr_traceaddr("tf", sp, pc, flags, pr);
534
535			db_read_bytes((db_addr_t)sp, sizeof(tf_buf),
536			    (char *)&tf_buf);
537			if (tf_buf.tf_lr == 0)
538				break;
539			pr_frame((struct trapframe *)sp, pr);
540
541			sp = tf_buf.tf_sp;
542			pc = tf_buf.tf_pc;
543			if (pc == 0)
544				pc = aarch64_strip_pac(tf_buf.tf_lr) - 4;
545			if (pc == 0)
546				break;
547			lr0 = aarch64_strip_pac(tf_buf.tf_lr);
548			allow_leaf_function = true;
549
550		} else {
551			db_sym_t sym;
552			db_addr_t func_entry, lr;
553			db_expr_t func_offset;
554			vsize_t stacksize;
555
556			pr_traceaddr("sp", sp, pc, flags, pr);
557
558			if ((flags & TRACEFLAG_USERSPACE) == 0 &&
559			    !IN_KERNEL_VM_ADDRESS(pc))
560				break;
561
562			sym = db_search_symbol(pc, DB_STGY_ANY, &func_offset);
563			if (sym != 0) {
564				func_entry = pc - func_offset;
565				if (func_entry ==
566				    (db_addr_t)cpu_switchto_softint) {
567					/*
568					 * In cpu_switchto_softint(), backtrace
569					 * information for DDB is pushed onto
570					 * the stack.
571					 */
572					db_read_bytes((db_addr_t)sp + 8,
573					    sizeof(pc), (char *)&pc);
574					db_read_bytes((db_addr_t)sp,
575					    sizeof(sp), (char *)&sp);
576					continue;
577				}
578			} else {
579				func_entry = 0;	/* autodetect mode */
580			}
581
582			if (analyze_func(func_entry, pc, sp, &lr, &stacksize,
583			    pr) != 0)
584				break;
585
586			if (allow_leaf_function) {
587				if (lr == 0)
588					lr = lr0;
589				allow_leaf_function = false;
590			} else {
591				if (lr == 0)
592					break;
593			}
594
595			sp += stacksize;
596			pc = lr - 4;
597		}
598	}
599}
600
601static void
602db_fp_trace(struct trapframe *tf, db_addr_t fp, db_expr_t count, int flags,
603    void (*pr)(const char *, ...) __printflike(1, 2))
604{
605	uint64_t lr;
606	uint64_t lastlr, lastfp;
607
608	if (tf != NULL) {
609		pr_frame(tf, pr);
610		lastfp = lastlr = lr = fp = 0;
611
612		db_read_bytes((db_addr_t)&tf->tf_pc, sizeof(lr), (char *)&lr);
613		db_read_bytes((db_addr_t)&tf->tf_reg[29], sizeof(fp), (char *)&fp);
614		lr = aarch64_strip_pac(lr);
615
616		pr_traceaddr("fp", fp, lr - 4, flags, pr);
617	}
618
619	for (; (count > 0) && (fp != 0); count--) {
620
621		lastfp = fp;
622		fp = lr = 0;
623		/*
624		 * normal stack frame
625		 *  fp[0]  saved fp(x29) value
626		 *  fp[1]  saved lr(x30) value
627		 */
628		db_read_bytes(lastfp + 0, sizeof(fp), (char *)&fp);
629		db_read_bytes(lastfp + 8, sizeof(lr), (char *)&lr);
630		lr = aarch64_strip_pac(lr);
631
632		if (lr == 0 || ((flags & TRACEFLAG_USERSPACE) == 0 &&
633		    IN_USER_VM_ADDRESS(lr)))
634			break;
635
636		if (((char *)(lr - 4) == (char *)el0_trap) ||
637		    ((char *)(lr - 4) == (char *)el1_trap)) {
638
639			tf = (struct trapframe *)fp;
640
641			lastfp = (uint64_t)tf;
642			lastlr = lr;
643			lr = fp = 0;
644			db_read_bytes((db_addr_t)&tf->tf_pc, sizeof(lr),
645			    (char *)&lr);
646			if (lr == 0) {
647				/*
648				 * The exception may have been from a
649				 * jump to null, so the null pc we
650				 * would return to is useless.  Try
651				 * x[30] instead -- that will be the
652				 * return address for the jump.
653				 */
654				db_read_bytes((db_addr_t)&tf->tf_reg[30],
655				    sizeof(lr), (char *)&lr);
656			}
657			db_read_bytes((db_addr_t)&tf->tf_reg[29], sizeof(fp),
658			    (char *)&fp);
659			lr = aarch64_strip_pac(lr);
660
661			pr_traceaddr("tf", (db_addr_t)tf, lastlr - 4, flags, pr);
662
663			if (lr == 0)
664				break;
665
666			pr_frame(tf, pr);
667			tf = NULL;
668
669			if ((flags & TRACEFLAG_USERSPACE) == 0 &&
670			    IN_USER_VM_ADDRESS(lr))
671				break;
672
673			pr_traceaddr("fp", fp, lr, flags, pr);
674		} else {
675			pr_traceaddr("fp", fp, lr - 4, flags, pr);
676		}
677	}
678}
679
680void
681db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count,
682    const char *modif, void (*pr)(const char *, ...) __printflike(1, 2))
683{
684	uint64_t fp;
685	struct trapframe *tf = NULL;
686	int flags = 0;
687	bool trace_thread = false;
688	bool trace_lwp = false;
689	bool trace_sp = false;
690
691	for (; *modif != '\0'; modif++) {
692		switch (*modif) {
693		case 'a':
694			trace_lwp = true;
695			trace_thread = false;
696			break;
697		case 'l':
698			break;
699		case 't':
700			trace_thread = true;
701			trace_lwp = false;
702			break;
703		case 's':
704			trace_sp = true;
705			break;
706		case 'u':
707			flags |= TRACEFLAG_USERSPACE;
708			break;
709		case 'x':
710			flags |= TRACEFLAG_LOOKUPLWP;
711			break;
712		default:
713			pr("usage: bt[/ulsx] [frame-address][,count]\n");
714			pr("       bt/t[ulsx] [pid][,count]\n");
715			pr("       bt/a[ulsx] [lwpaddr][,count]\n");
716			pr("\n");
717			pr("       /s      trace without framepointer\n");
718			pr("       /x      reverse lookup lwp name from sp\n");
719			return;
720		}
721	}
722
723#if defined(_KERNEL)
724	if (!have_addr) {
725		if (trace_lwp) {
726			addr = (db_expr_t)curlwp;
727		} else if (trace_thread) {
728			addr = curlwp->l_proc->p_pid;
729		} else {
730			tf = DDB_REGS;
731		}
732	}
733#endif
734
735	if (trace_thread) {
736		proc_t *pp;
737
738		if ((pp = db_proc_find((pid_t)addr)) == 0) {
739			(*pr)("trace: pid %d: not found\n", (int)addr);
740			return;
741		}
742		db_read_bytes((db_addr_t)pp + offsetof(proc_t, p_lwps.lh_first),
743		    sizeof(addr), (char *)&addr);
744		trace_thread = false;
745		trace_lwp = true;
746	}
747
748#if 0
749	/* "/a" is abbreviated? */
750	if (!trace_lwp && is_lwp(addr))
751		trace_lwp = true;
752#endif
753
754	if (trace_lwp) {
755		struct lwp l;
756		pid_t pid;
757
758		db_read_bytes(addr, sizeof(l), (char *)&l);
759		db_read_bytes((db_addr_t)l.l_proc + offsetof(proc_t, p_pid),
760		    sizeof(pid), (char *)&pid);
761
762#if defined(_KERNEL)
763		if (addr == (db_expr_t)curlwp) {
764			fp = (uint64_t)&DDB_REGS->tf_reg[29];	/* &reg[29]={fp,lr} */
765			tf = DDB_REGS;
766			(*pr)("trace: pid %d lid %d (curlwp) at tf %p\n",
767			    pid, l.l_lid, tf);
768		} else
769#endif
770		{
771			struct pcb *pcb = lwp_getpcb(&l);
772
773			db_read_bytes((db_addr_t)pcb +
774			    offsetof(struct pcb, pcb_tf),
775			    sizeof(tf), (char *)&tf);
776			if (tf != 0) {
777				db_read_bytes((db_addr_t)&tf->tf_reg[29],
778				    sizeof(fp), (char *)&fp);
779				(*pr)("trace: pid %d lid %d at tf %p (in pcb)\n",
780				    pid, l.l_lid, tf);
781			}
782#if defined(MULTIPROCESSOR) && defined(_KERNEL)
783			else if (l.l_stat == LSONPROC ||
784			    (l.l_pflag & LP_RUNNING) != 0) {
785
786				/* running lwp on other cpus */
787				extern struct trapframe *db_readytoswitch[];
788				u_int index;
789
790				db_read_bytes((db_addr_t)l.l_cpu +
791				    offsetof(struct cpu_info, ci_index),
792				    sizeof(index), (char *)&index);
793				tf = db_readytoswitch[index];
794
795				(*pr)("trace: pid %d lid %d at tf %p (in kdb_trap)\n",
796				    pid, l.l_lid, tf);
797			}
798#endif
799			else {
800				(*pr)("trace: no trapframe found for lwp: %p\n", (void *)addr);
801			}
802		}
803	} else if (tf == NULL) {
804		fp = addr;
805		pr("trace fp %016lx\n", fp);
806	} else {
807		pr("trace tf %p\n", tf);
808	}
809
810	if (count > MAXBACKTRACE)
811		count = MAXBACKTRACE;
812
813	if (trace_sp) {
814		/* trace $lr pushed to sp */
815		db_sp_trace(tf, fp, count, flags, pr);
816	} else {
817		/* trace $fp linked list */
818		db_fp_trace(tf, fp, count, flags, pr);
819	}
820}
821