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; +%}