/* $OpenBSD: db_trace.c,v 1.5 2022/02/22 07:46:04 visa Exp $ */ /* * Copyright (c) 2000, 2001 Ben Harris * Copyright (c) 1996 Scott K. Stevens * * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ #include #include #include #include #include #include #include #include #include #include #include extern unsigned char cpu_exception_handler_supervisor[]; extern unsigned char cpu_exception_handler_user[]; db_regs_t ddb_regs; #define INKERNEL(va) (((vaddr_t)(va)) & (1ULL << 63)) void db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, char *modif, int (*pr)(const char *, ...)) { vaddr_t frame, lastframe, ra, subr; char c, *cp = modif; db_expr_t offset; Elf_Sym * sym; char *name; int kernel_only = 1; while ((c = *cp++) != 0) { if (c == 'u') kernel_only = 0; if (c == 't') { db_printf("tracing threads not yet supported\n"); return; } } if (!have_addr) { ra = ddb_regs.tf_ra; frame = ddb_regs.tf_s[0]; } else { db_read_bytes(addr - 16, sizeof(vaddr_t), (char *)&frame); db_read_bytes(addr - 8, sizeof(vaddr_t), (char *)&ra); } while (count != 0 && frame != 0) { if (INKERNEL(frame)) { sym = db_search_symbol(ra, DB_STGY_ANY, &offset); db_symbol_values(sym, &name, NULL); } else { sym = NULL; name = NULL; } if (name == NULL || strcmp(name, "end") == 0) { (*pr)("%llx() at 0x%lx", ra, ra); } else { (*pr)("%s() at ", name); db_printsym(ra, DB_STGY_PROC, pr); } (*pr)("\n"); if ((frame & 0x7) != 0) { (*pr)("bad frame pointer: 0x%lx\n", frame); break; } subr = 0; if (sym != NULL) subr = ra - (vaddr_t)offset; lastframe = frame; if (subr == (vaddr_t)cpu_exception_handler_supervisor || subr == (vaddr_t)cpu_exception_handler_user) { struct trapframe *tf = (struct trapframe *)frame; db_read_bytes((vaddr_t)&tf->tf_ra, sizeof(ra), (char *)&ra); db_read_bytes((vaddr_t)&tf->tf_s[0], sizeof(frame), (char *)&frame); } else { db_read_bytes(frame - 16, sizeof(frame), (char *)&frame); if (frame == 0) break; if ((frame & 0x7) != 0) { (*pr)("bad frame pointer: 0x%lx\n", frame); break; } db_read_bytes(frame - 8, sizeof(ra), (char *)&ra); } if (INKERNEL(frame)) { if (frame <= lastframe) { (*pr)("bad frame pointer: 0x%lx\n", frame); break; } } else { if (kernel_only) { (*pr)("end of kernel\n"); break; } } --count; } (*pr)("end trace frame: 0x%lx, count: %d\n", frame, count); }