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/f45f3ceba177
branches:  trunk
changeset: 744744:f45f3ceba177
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 554473a9d2f8 -r f45f3ceba177 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