on amd64 and i386.
With guenther@
-/* $OpenBSD: db_trace.c,v 1.25 2017/02/06 09:13:41 mpi Exp $ */
+/* $OpenBSD: db_trace.c,v 1.26 2017/04/20 12:41:43 visa Exp $ */
/* $NetBSD: db_trace.c,v 1.1 2003/04/26 18:39:27 fvdl Exp $ */
/*
}
}
+static inline int
+db_is_trap(const char *name)
+{
+ if (name != NULL) {
+ if (!strcmp(name, "trap"))
+ return TRAP;
+ if (!strcmp(name, "ast"))
+ return AST;
+ if (!strcmp(name, "syscall"))
+ return SYSCALL;
+ if (name[0] == 'X') {
+ if (!strncmp(name, "Xintr", 5) ||
+ !strncmp(name, "Xresume", 7) ||
+ !strncmp(name, "Xrecurse", 8) ||
+ !strcmp(name, "Xdoreti") ||
+ !strncmp(name, "Xsoft", 5))
+ return INTERRUPT;
+ }
+ }
+ return NONE;
+}
+
void
db_stack_trace_print(db_expr_t addr, boolean_t have_addr, db_expr_t count,
char *modif, int (*pr)(const char *, ...))
offset = 0;
}
}
- if (INKERNEL(callpc) && name) {
- if (!strcmp(name, "trap")) {
- is_trap = TRAP;
- } else if (!strcmp(name, "ast")) {
- is_trap = AST;
- } else if (!strcmp(name, "syscall")) {
- is_trap = SYSCALL;
- } else if (name[0] == 'X') {
- if (!strncmp(name, "Xintr", 5) ||
- !strncmp(name, "Xresume", 7) ||
- !strncmp(name, "Xrecurse", 8) ||
- !strcmp(name, "Xdoreti") ||
- !strncmp(name, "Xsoft", 5)) {
- is_trap = INTERRUPT;
- } else
- goto normal;
- } else
- goto normal;
+ if (INKERNEL(callpc) && (is_trap = db_is_trap(name)) != NONE)
narg = 0;
- } else {
- normal:
+ else {
is_trap = NONE;
narg = db_numargs(frame, name);
}
}
}
+void
+db_save_stack_trace(struct db_stack_trace *st)
+{
+ struct callframe *frame, *lastframe;
+ db_addr_t callpc;
+ unsigned int i;
+
+ frame = __builtin_frame_address(0);
+
+ callpc = db_get_value((db_addr_t)&frame->f_retaddr, 8, FALSE);
+ frame = frame->f_frame;
+
+ lastframe = NULL;
+ for (i = 0; i < DB_STACK_TRACE_MAX && frame != NULL; i++) {
+ struct trapframe *tf;
+ char *name;
+ db_expr_t offset;
+ db_sym_t sym;
+ int is_trap;
+
+ st->st_pc[st->st_count++] = callpc;
+ sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
+ db_symbol_values(sym, &name, NULL);
+
+ if (INKERNEL(callpc))
+ is_trap = db_is_trap(name);
+ else
+ is_trap = NONE;
+
+ if (is_trap == NONE) {
+ lastframe = frame;
+ callpc = frame->f_retaddr;
+ frame = frame->f_frame;
+ } else {
+ if (is_trap == INTERRUPT) {
+ /*
+ * Interrupt routines don't update %rbp,
+ * so it still points to the frame that
+ * was interrupted. Pull back to just
+ * above lastframe so we can find the
+ * trapframe as with syscalls and traps.
+ */
+ if (lastframe == NULL)
+ break;
+
+ frame =
+ (struct callframe *)&lastframe->f_retaddr;
+ }
+ lastframe = frame;
+
+ tf = (struct trapframe *)&frame->f_arg0;
+ callpc = (db_addr_t)tf->tf_rip;
+ frame = (struct callframe *)tf->tf_rbp;
+ }
+
+ if (!INKERNEL(frame))
+ break;
+ if (frame <= lastframe)
+ break;
+ }
+}
+
vaddr_t
db_get_pc(struct trapframe *tf)
{
-/* $OpenBSD: db_trace.c,v 1.24 2017/02/06 09:13:41 mpi Exp $ */
+/* $OpenBSD: db_trace.c,v 1.25 2017/04/20 12:41:43 visa Exp $ */
/* $NetBSD: db_trace.c,v 1.18 1996/05/03 19:42:01 christos Exp $ */
/*
}
}
+static inline int
+db_is_trap(const char *name)
+{
+ if (name != NULL) {
+ if (!strcmp(name, "trap"))
+ return TRAP;
+ if (!strcmp(name, "ast"))
+ return AST;
+ if (!strcmp(name, "syscall"))
+ return SYSCALL;
+ if (name[0] == 'X') {
+ if (!strncmp(name, "Xintr", 5) ||
+ !strncmp(name, "Xresume", 7) ||
+ !strncmp(name, "Xstray", 6) ||
+ !strncmp(name, "Xhold", 5) ||
+ !strncmp(name, "Xrecurse", 8) ||
+ !strcmp(name, "Xdoreti") ||
+ !strncmp(name, "Xsoft", 5))
+ return INTERRUPT;
+ }
+ }
+ return NONE;
+}
+
void
db_stack_trace_print(db_expr_t addr, boolean_t have_addr, db_expr_t count,
char *modif, int (*pr)(const char *, ...))
offset = 0;
}
}
- if (INKERNEL(callpc) && name) {
- if (!strcmp(name, "trap")) {
- is_trap = TRAP;
- } else if (!strcmp(name, "ast")) {
- is_trap = AST;
- } else if (!strcmp(name, "syscall")) {
- is_trap = SYSCALL;
- } else if (!strncmp(name, "Xintr", 5) ||
- !strncmp(name, "Xresume", 7) ||
- !strncmp(name, "Xstray", 6) ||
- !strncmp(name, "Xhold", 5) ||
- !strncmp(name, "Xrecurse", 8) ||
- !strcmp(name, "Xdoreti") ||
- !strncmp(name, "Xsoft", 5)) {
- is_trap = INTERRUPT;
- } else
- goto normal;
+ if (INKERNEL(callpc) && (is_trap = db_is_trap(name)) != NONE)
narg = 0;
- } else {
- normal:
+ else {
is_trap = NONE;
narg = db_numargs(frame, name);
}
/* end of chain */
break;
}
- if (INKERNEL((int)frame)) {
+ if (INKERNEL(frame)) {
/* staying in kernel */
if (frame <= lastframe) {
(*pr)("Bad frame pointer: %p\n", frame);
break;
}
- } else if (INKERNEL((int)lastframe)) {
+ } else if (INKERNEL(lastframe)) {
/* switch from user to kernel */
if (kernel_only)
break; /* kernel stack only */
}
}
+void
+db_save_stack_trace(struct db_stack_trace *st)
+{
+ struct callframe *frame, *lastframe;
+ db_addr_t callpc;
+ unsigned int i;
+
+ frame = __builtin_frame_address(0);
+ callpc = db_get_value((int)&frame->f_retaddr, 4, FALSE);
+
+ lastframe = NULL;
+ for (i = 0; i < DB_STACK_TRACE_MAX && frame != NULL; i++) {
+ char *name;
+ db_expr_t offset;
+ db_sym_t sym;
+ int is_trap = 0;
+
+ st->st_pc[st->st_count++] = callpc;
+ sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
+ db_symbol_values(sym, &name, NULL);
+
+ if (INKERNEL(callpc))
+ is_trap = db_is_trap(name);
+ else
+ is_trap = NONE;
+
+ lastframe = frame;
+ if (is_trap == NONE) {
+ callpc = frame->f_retaddr;
+ frame = frame->f_frame;
+ } else {
+ struct trapframe *tf;
+
+ tf = (struct trapframe *)&frame->f_arg0;
+ callpc = (db_addr_t)tf->tf_eip;
+ frame = (struct callframe *)tf->tf_ebp;
+ }
+
+ if (!INKERNEL(frame))
+ break;
+ if (frame <= lastframe)
+ break;
+ }
+}
+
vaddr_t
db_get_pc(struct trapframe *tf)
{
-/* $OpenBSD: db_access.h,v 1.7 2016/04/19 10:24:42 mpi Exp $ */
+/* $OpenBSD: db_access.h,v 1.8 2017/04/20 12:41:43 visa Exp $ */
/* $NetBSD: db_access.h,v 1.6 1994/10/09 08:29:57 mycroft Exp $ */
/*
void db_read_bytes(db_addr_t, size_t, char *);
void db_write_bytes(db_addr_t, size_t, char *);
+
+#define DB_STACK_TRACE_MAX 19
+
+struct db_stack_trace {
+ unsigned int st_count;
+ db_addr_t st_pc[DB_STACK_TRACE_MAX];
+};
+
+void db_print_stack_trace(struct db_stack_trace *);
+void db_save_stack_trace(struct db_stack_trace *);
-/* $OpenBSD: db_output.c,v 1.30 2016/09/03 21:43:46 jasper Exp $ */
+/* $OpenBSD: db_output.c,v 1.31 2017/04/20 12:41:43 visa Exp $ */
/* $NetBSD: db_output.c,v 1.13 1996/04/01 17:27:14 christos Exp $ */
/*
#include <ddb/db_command.h>
#include <ddb/db_output.h>
+#include <ddb/db_access.h>
#include <ddb/db_interface.h>
#include <ddb/db_sym.h>
#include <ddb/db_var.h>
printf("End of stack trace.\n");
intrace = 0;
}
+
+void
+db_print_stack_trace(struct db_stack_trace *st)
+{
+ unsigned int i;
+
+ for (i = 0; i < st->st_count; i++) {
+ printf("#%-2u ", i);
+ db_printsym(st->st_pc[i], DB_STGY_PROC, printf);
+ printf("\n");
+ }
+}