This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
[RFC 04/13] mips: runtime and tapset code from cisco
- From: Crestez Dan Leonard <cdleonard at gmail dot com>
- To: systemtap at sourceware dot org
- Date: Thu, 31 Jul 2014 23:21:09 +0300
- Subject: [RFC 04/13] mips: runtime and tapset code from cisco
- Authentication-results: sourceware.org; auth=none
- References: <cover dot 1406837921 dot git dot cdleonard at gmail dot com>
- References: <cover dot 1406837921 dot git dot cdleonard at gmail dot com>
Signed-off-by: Crestez Dan Leonard <cdleonard@gmail.com>
---
runtime/linux/arith.c | 25 +++-
runtime/regs.c | 117 ++++++++++++++++++
runtime/stack-mips.c | 7 ++
runtime/stack.c | 2 +
runtime/syscall.h | 49 ++++++++
tapset/errno.stp | 2 +
tapset/linux/aux_syscalls.stp | 5 +-
tapset/linux/scheduler.stp | 2 +-
tapset/linux/syscalls2.stp | 8 ++
tapset/mips/aux_syscalls.stp | 44 +++++++
tapset/mips/registers.stp | 276 ++++++++++++++++++++++++++++++++++++++++++
11 files changed, 533 insertions(+), 4 deletions(-)
create mode 100644 runtime/stack-mips.c
create mode 100644 tapset/mips/aux_syscalls.stp
create mode 100644 tapset/mips/registers.stp
diff --git a/runtime/linux/arith.c b/runtime/linux/arith.c
index b64984a..9f65711 100644
--- a/runtime/linux/arith.c
+++ b/runtime/linux/arith.c
@@ -21,7 +21,8 @@
/* Other 32-bit cpus will need to modify this file. */
#if defined (__i386__) || defined(__arm__) || \
- (defined(__powerpc__) && !defined(__powerpc64__))
+ (defined(__powerpc__) && !defined(__powerpc64__)) || \
+ (defined(__mips__) && !defined(__mips64))
static long long _div64 (long long u, long long v);
static long long _mod64 (long long u, long long v);
#endif
@@ -116,7 +117,8 @@ static int _stp_random_pm (unsigned n)
#if defined (__i386__) || defined (__arm__) || \
- (defined(__powerpc__) && !defined(__powerpc64__))
+ (defined(__powerpc__) && !defined(__powerpc64__)) || \
+ (defined(__mips__) && !defined(__mips64))
/* 64-bit division functions extracted from libgcc */
typedef long long DWtype;
@@ -248,6 +250,25 @@ typedef union
: "r" ((USItype) (a)), \
"r" ((USItype) (b)) __CLOBBER_CC );}
+#elif defined (__mips__)
+
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("multu %2,%3" \
+ : "=l" ((USItype) (w0)), \
+ "=h" ((USItype) (w1)) \
+ : "d" ((USItype) (u)), \
+ "d" ((USItype) (v)))
+
+#if !defined (sub_ddmmss)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ do { \
+ UWtype __x; \
+ __x = (al) - (bl); \
+ (sh) = (ah) - (bh) - (__x > (al)); \
+ (sl) = __x; \
+ } while (0)
+#endif
+
#endif
#define __udiv_qrnnd_c(q, r, n1, n0, d) \
diff --git a/runtime/regs.c b/runtime/regs.c
index ade3ad9..8a3f365 100644
--- a/runtime/regs.c
+++ b/runtime/regs.c
@@ -3,6 +3,7 @@
* Copyright (C) 2005, 2007 Red Hat Inc.
* Copyright (C) 2005 Intel Corporation.
* Copyright (C) 2007 Quentin Barnes.
+ * Copyright (C) 2009 Sony Corporation.
*
* This file is part of systemtap, and is free software. You can
* redistribute it and/or modify it under the terms of the GNU General
@@ -23,6 +24,122 @@
#include "dyninst/regs.c"
+#elif defined (__mips__)
+/*
+ * Only o32 application has 32bit registers. N32 and N64 both
+ * should use 64bit registers regardless of pointer size
+ */
+static int _stp_probing_app_with_32bit_regs(struct pt_regs *regs)
+{
+ if (!regs)
+ return 0;
+ return (user_mode(regs) &&
+ test_tsk_thread_flag(current, TIF_32BIT_REGS));
+}
+
+void _stp_print_regs(struct pt_regs * regs)
+{
+#ifdef MIPS_PRINT_REGS_SHOW_SYMBOLS
+ /* it is too much stack to do symbol translation by default */
+ char symbol_name[KSYM_SYMBOL_LEN];
+#endif /* MIPS_PRINT_REGS_SHOW_SYMBOLS */
+ const int field = 2 * sizeof(unsigned long);
+ unsigned int cause = regs->cp0_cause;
+ int i;
+
+ _stp_printf("Cpu %d\n", smp_processor_id());
+
+ /*
+ * Saved main processor registers
+ */
+ for (i = 0; i < 32;) {
+ if ((i % 4) == 0)
+ _stp_printf("$%2d :", i);
+ if (i == 0)
+ _stp_printf(" %0*lx", field, 0UL);
+ else if (i == 26 || i == 27)
+ _stp_printf(" %*s", field, "");
+ else
+ _stp_printf(" %0*lx", field, regs->regs[i]);
+
+ i++;
+ if ((i % 4) == 0)
+ _stp_printf("\n");
+ }
+
+ _stp_printf("Hi : %0*lx\n", field, regs->hi);
+ _stp_printf("Lo : %0*lx\n", field, regs->lo);
+
+ /*
+ * Saved cp0 registers
+ */
+ _stp_printf("epc : %0*lx ", field, regs->cp0_epc);
+#ifdef MIPS_PRINT_REGS_SHOW_SYMBOLSx
+ sprint_symbol(symbol_name, regs->cp0_epc);
+ _stp_printf("%s ", symbol_name);
+#endif /* MIPS_PRINT_REGS_SHOW_SYMBOLS */
+
+ _stp_printf("ra : %0*lx ", field, regs->regs[31]);
+#ifdef MIPS_PRINT_REGS_SHOW_SYMBOLS
+ sprint_symbol(symbol_name, regs->regs[31]);
+ _stp_printf("%s", symbol_name);
+#endif /* MIPS_PRINT_REGS_SHOW_SYMBOLS */
+ _stp_printf("\n");
+
+ _stp_printf("Status: %08x ", (uint32_t) regs->cp0_status);
+
+ if (current_cpu_data.isa_level == MIPS_CPU_ISA_I) {
+ if (regs->cp0_status & ST0_KUO)
+ _stp_printf("KUo ");
+ if (regs->cp0_status & ST0_IEO)
+ _stp_printf("IEo ");
+ if (regs->cp0_status & ST0_KUP)
+ _stp_printf("KUp ");
+ if (regs->cp0_status & ST0_IEP)
+ _stp_printf("IEp ");
+ if (regs->cp0_status & ST0_KUC)
+ _stp_printf("KUc ");
+ if (regs->cp0_status & ST0_IEC)
+ _stp_printf("IEc ");
+ } else {
+ if (regs->cp0_status & ST0_KX)
+ _stp_printf("KX ");
+ if (regs->cp0_status & ST0_SX)
+ _stp_printf("SX ");
+ if (regs->cp0_status & ST0_UX)
+ _stp_printf("UX ");
+ switch (regs->cp0_status & ST0_KSU) {
+ case KSU_USER:
+ _stp_printf("USER ");
+ break;
+ case KSU_SUPERVISOR:
+ _stp_printf("SUPERVISOR ");
+ break;
+ case KSU_KERNEL:
+ _stp_printf("KERNEL ");
+ break;
+ default:
+ _stp_printf("BAD_MODE ");
+ break;
+ }
+ if (regs->cp0_status & ST0_ERL)
+ _stp_printf("ERL ");
+ if (regs->cp0_status & ST0_EXL)
+ _stp_printf("EXL ");
+ if (regs->cp0_status & ST0_IE)
+ _stp_printf("IE ");
+ }
+
+ _stp_printf("\n");
+
+ _stp_printf("Cause : %08x\n", cause);
+
+ cause = (((cause) & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE);
+ if (1 <= cause && cause <= 5)
+ _stp_printf("BadVA : %0*lx\n", field, regs->cp0_badvaddr);
+
+ _stp_printf("PrId : %08x\n", read_c0_prid());
+}
#endif
diff --git a/runtime/stack-mips.c b/runtime/stack-mips.c
new file mode 100644
index 0000000..e1eb995
--- /dev/null
+++ b/runtime/stack-mips.c
@@ -0,0 +1,7 @@
+static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk,
+ struct unwind_context *context,
+ struct uretprobe_instance *ri, int uregs_valid)
+{
+ /* TODO: fix, it is just stub for now */
+}
diff --git a/runtime/stack.c b/runtime/stack.c
index 769f7bc..ba47f37 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -78,6 +78,8 @@ static int _stp_valid_pc_addr(unsigned long addr, struct task_struct *tsk)
#include "stack-ia64.c"
#elif defined (__arm__)
#include "stack-arm.c"
+#elif defined (__mips__)
+#include "stack-mips.c"
#elif defined (__s390__)
#include "stack-s390.c"
#else
diff --git a/runtime/syscall.h b/runtime/syscall.h
index 32af78c..447adb1 100644
--- a/runtime/syscall.h
+++ b/runtime/syscall.h
@@ -77,6 +77,55 @@
#define MREMAP_SYSCALL_NO(tsk) 1156
#endif
+#if defined(__mips__)
+/* n64 values: scall64-64.S */
+#define MMAP_SYSCALL_NO_MIPS_N64 5009
+#define MMAP2_SYSCALL_NO_MIPS_N64 ((unsigned long)-1) /* does not exits */
+#define MPROTECT_SYSCALL_NO_MIPS_N64 5010
+#define MUNMAP_SYSCALL_NO_MIPS_N64 5011
+#define MREMAP_SYSCALL_NO_MIPS_N64 5024
+
+/* n32 values: scall64-n32.S */
+#define MMAP_SYSCALL_NO_MIPS_N32 6009
+#define MMAP2_SYSCALL_NO_MIPS_N32 ((unsigned long)-1) /* does not exits */
+#define MPROTECT_SYSCALL_NO_MIPS_N32 6010
+#define MUNMAP_SYSCALL_NO_MIPS_N32 6011
+#define MREMAP_SYSCALL_NO_MIPS_N32 6024
+
+/* o32 values: scall32-o32.S */
+#define MMAP_SYSCALL_NO_MIPS_O32 4090
+#define MMAP2_SYSCALL_NO_MIPS_O32 4210
+#define MPROTECT_SYSCALL_NO_MIPS_O32 4125
+#define MUNMAP_SYSCALL_NO_MIPS_O32 4091
+#define MREMAP_SYSCALL_NO_MIPS_O32 4167
+
+#define MMAP_SYSCALL_NO(tsk) ((test_tsk_thread_flag((tsk), TIF_32BIT_ADDR)) ? \
+ ((test_tsk_thread_flag((tsk), TIF_32BIT_REGS)) ? \
+ (MMAP_SYSCALL_NO_MIPS_O32) : \
+ (MMAP_SYSCALL_NO_MIPS_N32)) : \
+ (MMAP_SYSCALL_NO_MIPS_N64))
+#define MMAP2_SYSCALL_NO(tsk) ((test_tsk_thread_flag((tsk), TIF_32BIT_ADDR)) ? \
+ ((test_tsk_thread_flag((tsk), TIF_32BIT_REGS)) ? \
+ (MMAP2_SYSCALL_NO_MIPS_O32) : \
+ (MMAP2_SYSCALL_NO_MIPS_N32)) : \
+ (MMAP2_SYSCALL_NO_MIPS_N64))
+#define MPROTECT_SYSCALL_NO(tsk) ((test_tsk_thread_flag((tsk), TIF_32BIT_ADDR)) ? \
+ ((test_tsk_thread_flag((tsk), TIF_32BIT_REGS)) ? \
+ (MPROTECT_SYSCALL_NO_MIPS_O32) : \
+ (MPROTECT_SYSCALL_NO_MIPS_N32)) : \
+ (MPROTECT_SYSCALL_NO_MIPS_N64))
+#define MUNMAP_SYSCALL_NO(tsk) ((test_tsk_thread_flag((tsk), TIF_32BIT_ADDR)) ? \
+ ((test_tsk_thread_flag((tsk), TIF_32BIT_REGS)) ? \
+ (MUNMAP_SYSCALL_NO_MIPS_O32) : \
+ (MUNMAP_SYSCALL_NO_MIPS_N32)) : \
+ (MUNMAP_SYSCALL_NO_MIPS_N64))
+#define MREMAP_SYSCALL_NO(tsk) ((test_tsk_thread_flag((tsk), TIF_32BIT_ADDR)) ? \
+ ((test_tsk_thread_flag((tsk), TIF_32BIT_REGS)) ? \
+ (MREMAP_SYSCALL_NO_MIPS_O32) : \
+ (MREMAP_SYSCALL_NO_MIPS_N32)) : \
+ (MREMAP_SYSCALL_NO_MIPS_N64))
+#endif
+
#if defined(__s390__) || defined(__s390x__)
#define MMAP_SYSCALL_NO(tsk) 90
#define MMAP2_SYSCALL_NO(tsk) 192
diff --git a/tapset/errno.stp b/tapset/errno.stp
index df1ccbd..7e1d2f4 100644
--- a/tapset/errno.stp
+++ b/tapset/errno.stp
@@ -390,6 +390,8 @@ static long _stp_returnval(struct pt_regs *regs) {
return regs->regs[0];
#elif defined (__arm__)
return regs->ARM_r0;
+#elif defined (__mips__)
+ return regs->regs[2];
#else
_stp_error("returnval() not defined for this architecture");
return 0;
diff --git a/tapset/linux/aux_syscalls.stp b/tapset/linux/aux_syscalls.stp
index 53e73f8..a5e7b56 100644
--- a/tapset/linux/aux_syscalls.stp
+++ b/tapset/linux/aux_syscalls.stp
@@ -2745,7 +2745,7 @@ static void _stp_sigaction_str(struct sigaction *act, char *ptr, int len)
strlcat (ptr, ", ", len);
_stp_lookup_or_str(_stp_sa_flags_list, act->sa_flags, ptr, len);
strlcat (ptr, ", ", len);
-#if !defined (__ia64__)
+#if !defined (__ia64__) && !defined (__mips__)
slen = strlen(ptr);
_stp_snprintf(ptr + slen, len - slen,
"0x%lx, [", (long)act->sa_restorer);
@@ -3085,6 +3085,9 @@ function __is_user_regs:long (regs:long)
#elif defined(__arm__)
long cpsr = kread(®s->ARM_cpsr);
STAP_RETVALUE = ((cpsr & 0xf) == 0);
+#elif defined(__mips__) /* TODO kamensky: need to test */
+ unsigned long cp0 = kread(®s->cp0_status);
+ THIS->__retvalue = ((cp0 & 0x08) == 8);
#elif defined(__s390__) || defined(__s390x__)
unsigned long mask = kread(®s->psw.mask);
STAP_RETVALUE = ((mask & PSW_MASK_PSTATE) != 0);
diff --git a/tapset/linux/scheduler.stp b/tapset/linux/scheduler.stp
index 7596a46..d45116b 100644
--- a/tapset/linux/scheduler.stp
+++ b/tapset/linux/scheduler.stp
@@ -117,7 +117,7 @@ probe scheduler.balance = kernel.function("idle_balance") ?
*/
probe scheduler.ctxswitch = kernel.trace("sched_switch") !,
-%( arch != "x86_64" && arch != "ia64" && arch != "arm" %?
+%( arch != "x86_64" && arch != "ia64" && arch != "arm" && arch != "mips" %?
kernel.function("__switch_to")
%:
kernel.function("context_switch")
diff --git a/tapset/linux/syscalls2.stp b/tapset/linux/syscalls2.stp
index 08d4e36..7832dd4 100644
--- a/tapset/linux/syscalls2.stp
+++ b/tapset/linux/syscalls2.stp
@@ -1553,7 +1553,11 @@ probe syscall.rt_sigreturn.return =
kernel.function("sys32_rt_sigreturn").return ?
{
name = "rt_sigreturn"
+%( arch == "mips" %?
+ retstr = "void"
+%:
retstr = return_str(1, $return)
+%)
}
# rt_sigsuspend ______________________________________________
@@ -3143,7 +3147,11 @@ probe syscall.sigreturn.return = kernel.function("sys_sigreturn").return ?,
kernel.function("sys32_sigreturn").return ?
{
name = "sigreturn"
+%( arch == "mips" %?
+ retstr = "void"
+%:
retstr = return_str(1, $return)
+%)
}
# sigsuspend _________________________________________________
diff --git a/tapset/mips/aux_syscalls.stp b/tapset/mips/aux_syscalls.stp
new file mode 100644
index 0000000..5de5485
--- /dev/null
+++ b/tapset/mips/aux_syscalls.stp
@@ -0,0 +1,44 @@
+# arch-specific requests of ptrace ___________________________
+#
+function _arch_ptrace_argstr(request, pid, addr, data)
+{
+ if (request == %{ PTRACE_GETREGS %})
+ // TODO: Retrieve *data in .return
+ return sprintf ("PTRACE_GETREGS, %d, data=%p", pid, data)
+ if (request == %{ PTRACE_SETREGS %})
+ // TODO: Retrieve *data here
+ return sprintf ("PTRACE_SETREGS, %d, data=%p", pid, data)
+ if (request == %{ PTRACE_GETFPREGS %})
+ // TODO: Retrieve *data in .return
+ return sprintf ("PTRACE_GETFPREGS, %d, data=%p", pid, data)
+ if (request == %{ PTRACE_SETFPREGS %})
+ // TODO: Retrieve *data here
+ return sprintf ("PTRACE_SETFPREGS, %d, data=%p", pid, data)
+ if (request == %{ PTRACE_PEEKTEXT_3264 %})
+ // TODO: Retrieve *data in .return
+ return sprintf ("PTRACE_PEEKTEXT_3264, %d, *addr=%p, data=%p", pid, user_long(addr), data)
+ if (request == %{ PTRACE_PEEKDATA_3264 %})
+ // TODO: Retrieve *data in .return
+ return sprintf ("PTRACE_PEEKDATA_3264, %d, *addr=%p, data=%p", pid, user_long(addr), data)
+ if (request == %{ PTRACE_POKETEXT_3264 %})
+ return sprintf ("PTRACE_POKETEXT_3264, %d, *addr=%p, data=%p", pid, user_long(addr), data)
+ if (request == %{ PTRACE_POKEDATA_3264 %})
+ return sprintf ("PTRACE_POKEDATA_3264, %d, *addr=%p, data=%p", pid, user_long(addr), data)
+ if (request == %{ PTRACE_GET_THREAD_AREA %})
+ // TODO: Retrieve *data in .return
+ return sprintf ("PTRACE_GET_THREAD_AREA, %d, index=%d, data=%p", pid, addr, data)
+ if (request == %{ PTRACE_GET_THREAD_AREA_3264 %})
+ // TODO: Retrieve *data in .return
+ return sprintf ("PTRACE_GET_THREAD_AREA_3264, %d, index=%d, data=%p", pid, addr, data)
+ if (request == %{ PTRACE_GET_WATCH_REGS %})
+ // TODO: Retrieve *data in .return
+ return sprintf ("PTRACE_GET_WATCH_REGS, %d, data=%p", pid, data)
+ if (request == %{ PTRACE_SET_WATCH_REGS %})
+ // TODO: Retrieve *data here
+ return sprintf ("PTRACE_SET_WATCH_REGS, %d, data=%p", pid, data)
+}
+
+function _ptrace_return_arch_prctl_addr:long(request:long, addr:long, data:long)
+{
+ return 0
+}
diff --git a/tapset/mips/registers.stp b/tapset/mips/registers.stp
new file mode 100644
index 0000000..be50f76
--- /dev/null
+++ b/tapset/mips/registers.stp
@@ -0,0 +1,276 @@
+/* Dwarfless register access for mips */
+
+global _reg_offsets, _stp_regs_registered
+
+function _stp_register_regs() {
+%( CONFIG_64BIT == "y" %?
+ /* n32/n64 registers naming scheme */
+ /* Same order as struct pt_regs */
+ _reg_offsets["zero"] = 0
+ _reg_offsets["at"] = 8
+ _reg_offsets["v0"] = 16
+ _reg_offsets["v1"] = 24
+ _reg_offsets["a0"] = 32
+ _reg_offsets["a1"] = 40
+ _reg_offsets["a2"] = 48
+ _reg_offsets["a3"] = 56
+ _reg_offsets["a4"] = 64
+ _reg_offsets["a5"] = 72
+ _reg_offsets["a6"] = 80
+ _reg_offsets["a7"] = 88
+ _reg_offsets["t0"] = 96
+ _reg_offsets["t1"] = 104
+ _reg_offsets["t2"] = 112
+ _reg_offsets["t3"] = 120
+ _reg_offsets["s0"] = 128
+ _reg_offsets["s1"] = 136
+ _reg_offsets["s2"] = 144
+ _reg_offsets["s3"] = 152
+ _reg_offsets["s4"] = 160
+ _reg_offsets["s5"] = 168
+ _reg_offsets["s6"] = 176
+ _reg_offsets["s7"] = 184
+ _reg_offsets["t8"] = 192
+ _reg_offsets["t9"] = 200
+ _reg_offsets["k0"] = 208
+ _reg_offsets["k1"] = 216
+ _reg_offsets["gp"] = 224
+ _reg_offsets["sp"] = 232
+ _reg_offsets["s8"] = 240 _reg_offsets["fp"] = 240
+ _reg_offsets["ra"] = 248
+
+ _reg_offsets["status"] = 256
+ _reg_offsets["hi"] = 264
+ _reg_offsets["lo"] = 272
+
+ /*
+ * no CONFIG_CPU_HAS_SMARTMIPS support for now, if it is
+ * enabled below values will be wrong
+ */
+
+ _reg_offsets["badvaddr"] = 280
+ _reg_offsets["cause"] = 288
+ _reg_offsets["epc"] = 296
+
+ /* no cp0_tcstatus register for now */
+ /* no mpl and mtp registers for now */
+%:
+ /* o32 registers naming scheme */
+ /* Same order as struct pt_regs */
+ _reg_offsets["zero"] = 24
+ _reg_offsets["at"] = 28
+ _reg_offsets["v0"] = 32
+ _reg_offsets["v1"] = 36
+ _reg_offsets["a0"] = 40
+ _reg_offsets["a1"] = 44
+ _reg_offsets["a2"] = 48
+ _reg_offsets["a3"] = 52
+ _reg_offsets["t0"] = 56
+ _reg_offsets["t1"] = 60
+ _reg_offsets["t2"] = 64
+ _reg_offsets["t3"] = 68
+ _reg_offsets["t4"] = 72
+ _reg_offsets["t5"] = 76
+ _reg_offsets["t6"] = 80
+ _reg_offsets["t7"] = 84
+ _reg_offsets["s0"] = 88
+ _reg_offsets["s1"] = 92
+ _reg_offsets["s2"] = 96
+ _reg_offsets["s3"] = 100
+ _reg_offsets["s4"] = 104
+ _reg_offsets["s5"] = 108
+ _reg_offsets["s6"] = 112
+ _reg_offsets["s7"] = 116
+ _reg_offsets["t8"] = 120
+ _reg_offsets["t9"] = 124
+ _reg_offsets["k0"] = 128
+ _reg_offsets["k1"] = 132
+ _reg_offsets["gp"] = 136
+ _reg_offsets["sp"] = 140
+ _reg_offsets["s8"] = 144 _reg_offsets["fp"] = 144
+ _reg_offsets["ra"] = 148
+
+ _reg_offsets["status"] = 152
+ _reg_offsets["hi"] = 156
+ _reg_offsets["lo"] = 160
+
+ /*
+ * no CONFIG_CPU_HAS_SMARTMIPS support for now, if it is
+ * enabled below values will be wrong
+ */
+ _reg_offsets["badvaddr"] = 164
+ _reg_offsets["cause"] = 168
+ _reg_offsets["epc"] = 172
+
+ /* no cp0_tcstatus register for now */
+ /* no mpl and mtp registers for now */
+%)
+ _stp_regs_registered = 1
+}
+
+function probing_app_with_32bit_regs() %{ /* pure */
+ THIS->__retvalue = _stp_probing_app_with_32bit_regs(CONTEXT->regs);
+%}
+
+function _stp_get_register_by_offset:long (offset:long) %{ /* pure */
+ long value;
+ if (!CONTEXT->regs) {
+ CONTEXT->last_error = "No registers available in this context";
+ return;
+ }
+ if (THIS->offset < 0 || THIS->offset > sizeof(struct pt_regs) - sizeof(long)) {
+ snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer),
+ "Bad register offset: %lld",
+ (long long)THIS->offset);
+ CONTEXT->last_error = CONTEXT->error_buffer;
+ return;
+ }
+ memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value));
+ THIS->__retvalue = value;
+%}
+
+function _stp_sign_extend32:long (value:long) {
+ if (value & 0x80000000)
+ value |= (0xffffffff << 32)
+ return value
+}
+
+function _stp_register:long (name:string, sign_extend:long) {
+ if (!registers_valid()) {
+ error("cannot access CPU registers in this context")
+ return 0
+ }
+ if (!_stp_regs_registered)
+ _stp_register_regs()
+ offset = _reg_offsets[name]
+ if (offset == 0 && !(name in _reg_offsets)) {
+ error("Unknown register: " . name)
+ return 0
+ }
+ value = _stp_get_register_by_offset(offset)
+%( CONFIG_64BIT == "y" %?
+ if (probing_app_with_32bit_regs()) {
+%)
+ if (sign_extend)
+ value = _stp_sign_extend32(value)
+ else
+ value &= 0xffffffff
+%( CONFIG_64BIT == "y" %?
+ }
+%)
+ return value
+}
+
+/* Return the named register value as a signed value. */
+function register:long (name:string) {
+ return _stp_register(name, 1)
+}
+
+/*
+ * Return the named register value as an unsigned value. Specifically,
+ * don't sign-extend the register value when promoting it to 64 bits.
+ */
+function u_register:long (name:string) {
+ return _stp_register(name, 0)
+}
+
+/*
+ * Return the value of function arg #argnum (1=first arg).
+ * If truncate=1, mask off the top 32 bits.
+ * If sign_extend=1 and (truncate=1 or the probepoint we've hit is in a
+ * 32-bit app), sign-extend the 32-bit value.
+ */
+function _stp_arg:long (argnum:long, sign_extend:long, truncate:long) {
+ val = 0
+ if (argnum < 1 || argnum > 8) {
+ error(sprintf("Cannot access arg(%d)", argnum))
+ return 0
+ }
+
+ if (argnum == 1)
+ val = u_register("a0")
+ else if (argnum == 2)
+ val = u_register("a1")
+ else if (argnum == 3)
+ val = u_register("a2")
+ else if (argnum == 4)
+ val = u_register("a3")
+ else if (argnum == 5)
+ val = u_register("a4")
+ else if (argnum == 6)
+ val = u_register("a5")
+ else if (argnum == 7)
+ val = u_register("a6")
+ else if (argnum == 8)
+ val = u_register("a7")
+
+ if (truncate) {
+ if (sign_extend)
+ val = _stp_sign_extend32(val)
+ else
+ /* High bits may be garbage. */
+ val = (val & 0xffffffff);
+ }
+ return val;
+}
+
+/* Return the value of function arg #argnum (1=first arg) as a signed int. */
+function int_arg:long (argnum:long) {
+ return _stp_arg(argnum, 1, 1)
+}
+
+/* Return the value of function arg #argnum (1=first arg) as an unsigned int. */
+function uint_arg:long (argnum:long) {
+ return _stp_arg(argnum, 0, 1)
+}
+
+function long_arg:long (argnum:long) {
+ return _stp_arg(argnum, 1, 0)
+}
+
+function ulong_arg:long (argnum:long) {
+ return _stp_arg(argnum, 0, 0)
+}
+
+function longlong_arg:long (argnum:long) {
+ if (probing_app_with_32bit_regs()) {
+ lowbits = _stp_arg(argnum, 0, 1)
+ highbits = _stp_arg(argnum+1, 0, 1)
+ return ((highbits << 32) | lowbits)
+ } else
+ return _stp_arg(argnum, 0, 0)
+}
+
+function ulonglong_arg:long (argnum:long) {
+ return longlong_arg(argnum)
+}
+
+function pointer_arg:long (argnum:long) {
+ return _stp_arg(argnum, 0, 0)
+}
+
+function s32_arg:long (argnum:long) {
+ return int_arg(argnum)
+}
+
+function u32_arg:long (argnum:long) {
+ return uint_arg(argnum)
+}
+
+function s64_arg:long (argnum:long) {
+ return longlong_arg(argnum)
+}
+
+function u64_arg:long (argnum:long) {
+ return ulonglong_arg(argnum)
+}
+
+function asmlinkage() %{ /* pure */ %}
+
+function fastcall() %{ /* pure */ %}
+
+function regparm() %{
+ snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer),
+ "regparm is invalid on mips.");
+ CONTEXT->last_error = CONTEXT->error_buffer;
+%}