Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/external/cddl/osnet/dev/dtrace/aarch64 Teach dtrace about el...
details: https://anonhg.NetBSD.org/src/rev/0de8e0d7328c
branches: trunk
changeset: 1007245:0de8e0d7328c
user: riastradh <riastradh%NetBSD.org@localhost>
date: Wed Feb 12 01:10:16 2020 +0000
description:
Teach dtrace about el1_trap_exit frames on aarch64.
Implement dtrace_getarg and dtrace_getreg while here.
diffstat:
external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c | 170 ++++++++++++-------
1 files changed, 104 insertions(+), 66 deletions(-)
diffs (209 lines):
diff -r a6082611b809 -r 0de8e0d7328c external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c
--- a/external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c Wed Feb 12 01:10:08 2020 +0000
+++ b/external/cddl/osnet/dev/dtrace/aarch64/dtrace_isa.c Wed Feb 12 01:10:16 2020 +0000
@@ -89,52 +89,60 @@
dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes,
uint32_t *intrpc)
{
- struct unwind_state state;
- int scp_offset;
- register_t sp, fp;
- int depth;
+ extern const char el1_trap_exit[];
+ const register_t *fp;
+ int i = 0;
- depth = 0;
-
- if (intrpc != 0) {
- pcstack[depth++] = (pc_t) intrpc;
+ if (intrpc) {
+ if (i < pcstack_limit)
+ pcstack[i++] = (pc_t)intrpc;
}
- aframes++;
-
- __asm __volatile("mov %0, sp" : "=&r" (sp));
-
- state.fp = (uint64_t)__builtin_frame_address(0);
- state.sp = sp;
- state.pc = (uint64_t)dtrace_getpcstack;
-
- while (depth < pcstack_limit) {
- if (!INKERNEL(state.pc) || !INKERNEL(state.fp))
- break;
+ /*
+ * fp[0] = x29 (saved frame pointer)
+ * fp[1] = x30 (saved link register == return address)
+ */
+ fp = __builtin_frame_address(0);
+ while (i < pcstack_limit && INKERNEL(fp[0]) && INKERNEL(fp[1])) {
+ /* Skip the specified number of artificial frames. */
+ if (aframes > 0)
+ aframes--;
+ else
+ pcstack[i++] = fp[1];
- fp = state.fp;
- state.sp = fp + 0x10;
- /* FP to previous frame (X29) */
- state.fp = *(register_t *)(fp);
- /* LR (X30) */
- state.pc = *(register_t *)(fp + 8) - 4;
-
- /*
- * NB: Unlike some other architectures, we don't need to
- * explicitly insert cpu_dtrace_caller as it appears in the
- * normal kernel stack trace rather than a special trap frame.
- */
- if (aframes > 0) {
- aframes--;
+ /* Check whether this frame is handling a trap. */
+ if (fp[1] == (register_t)el1_trap_exit) {
+ /*
+ * Trap from kernel. The trapframe is the
+ * saved frame pointer of the call to the trap
+ * handler whose return address is
+ * el1_trap_exit. The frame pointer of the
+ * interrupted code is in x29 stashed in the
+ * trapframe, alongside its pc.
+ */
+ const struct trapframe *tf = (const void *)fp[0];
+ /* x29 = frame pointer */
+ fp = (const void *)tf->tf_regs.r_reg[29];
+ if (INKERNEL(tf->tf_pc)) {
+ if (i >= pcstack_limit)
+ break;
+ if (aframes > 0)
+ aframes--;
+ else
+ pcstack[i++] = tf->tf_pc;
+ }
} else {
- pcstack[depth++] = state.pc;
+ /*
+ * Not a trap. Keep going with fp[0] as the
+ * parent frame pointer.
+ */
+ fp = (const void *)fp[0];
}
-
}
- for (; depth < pcstack_limit; depth++) {
- pcstack[depth] = 0;
- }
+ /* Zero the rest of the return address stack. (Paranoia?) */
+ while (i < pcstack_limit)
+ pcstack[i++] = 0;
}
static int
@@ -282,48 +290,78 @@
uint64_t
dtrace_getarg(int arg, int aframes)
{
+ extern const char el1_trap_exit[];
+ const register_t *fp;
+ const struct trapframe *tf = NULL;
+ int i = 0;
- printf("IMPLEMENT ME: %s\n", __func__);
+ /*
+ * The first arguments are passed in x0,...,x7. The rest are
+ * on the stack, too much trouble to figure out.
+ *
+ * XXX Shouldn't we ask ctf or dwarf or something to figure
+ * this stuff out for us?
+ */
+ KASSERT(arg >= 0);
+ if (arg >= 8)
+ return 0;
- return (0);
+ fp = __builtin_frame_address(0);
+ while (i < 1000 && INKERNEL(fp[0]) && INKERNEL(fp[1])) {
+ if (aframes > 0)
+ aframes--;
+ else
+ i++;
+ if (fp[1] == (register_t)el1_trap_exit) {
+ tf = (const void *)fp[0];
+ break;
+ } else {
+ fp = (const void *)fp[0];
+ }
+ }
+
+ /* If we didn't find a trap frame, give up. */
+ if (tf == NULL)
+ return 0;
+
+ /* Arg0, arg1, ..., arg7 are in registers x0, x1, ..., x7. */
+ return tf->tf_regs.r_reg[arg];
}
int
dtrace_getstackdepth(int aframes)
{
- struct unwind_state state;
- int scp_offset;
- register_t sp;
- int depth;
- int done;
-
- depth = 1;
- done = 0;
-
- __asm __volatile("mov %0, sp" : "=&r" (sp));
+ extern const char el1_trap_exit[];
+ const register_t *fp;
+ int i = 0;
- state.fp = (uint64_t)__builtin_frame_address(0);
- state.sp = sp;
- state.pc = (uint64_t)dtrace_getstackdepth;
+ fp = __builtin_frame_address(0);
+ while (i < 1000 && INKERNEL(fp[0]) && INKERNEL(fp[1])) {
+ if (aframes > 0)
+ aframes--;
+ else
+ i++;
+ if (fp[1] == (register_t)el1_trap_exit) {
+ const struct trapframe *tf = (const void *)fp[0];
+ fp = (const void *)tf->tf_regs.r_reg[29];
+ if (aframes > 0)
+ aframes--;
+ else
+ i++;
+ } else {
+ fp = (const void *)fp[0];
+ }
+ }
- do {
- done = unwind_frame(&state);
- if (!INKERNEL(state.pc) || !INKERNEL(state.fp))
- break;
- depth++;
- } while (!done);
-
- if (depth < aframes)
- return (0);
- else
- return (depth - aframes);
+ return i;
}
ulong_t
-dtrace_getreg(struct trapframe *rp, uint_t reg)
+dtrace_getreg(struct trapframe *tf, uint_t reg)
{
- printf("IMPLEMENT ME: %s\n", __func__);
+ if (reg < 32)
+ return tf->tf_regs.r_reg[reg];
return (0);
}
Home |
Main Index |
Thread Index |
Old Index