asda?‰PNG  IHDR ? f ??C1 sRGB ??é gAMA ±? üa pHYs ? ??o¨d GIDATx^íüL”÷e÷Y?a?("Bh?_ò???¢§?q5k?*:t0A-o??¥]VkJ¢M??f?±8\k2íll£1]q?ù???T /* Dwarfless register access for arm */ %{ // These functions are largely lifted from arch/arm/kernel/ptrace.c. static inline unsigned long _stp_kernel_stack_pointer(struct pt_regs *regs) { return regs->ARM_sp; } /* * _stp_regs_within_kernel_stack() - check the address in the stack * @regs: pt_regs which contains kernel stack pointer. * @addr: address which is checked. * * _stp_regs_within_kernel_stack() checks @addr is within the kernel * stack page(s). If @addr is within the kernel stack, it returns * true. If not, returns false. */ bool _stp_regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) { return ((addr & ~(THREAD_SIZE - 1)) == (_stp_kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); } /* * _stp_regs_get_kernel_stack_nth_addr() - get address of the Nth entry of the stack * @regs: pt_regs which contains kernel stack pointer. * @n: stack entry number. * * _stp_regs_get_kernel_stack_nth_addr() returns the address of the @n * th entry of the kernel stack which is specified by @regs. If the @n * th entry is NOT in the kernel stack, this returns 0. */ long * _stp_regs_get_kernel_stack_nth_addr(struct pt_regs *regs, unsigned int n) { long *addr = (unsigned long *)_stp_kernel_stack_pointer(regs); addr += n; if (_stp_regs_within_kernel_stack(regs, (unsigned long)addr)) return addr; else return 0; } %} @__private30 global _reg_offsets[30] probe init { /* Same order as pt_regs */ _reg_offsets["r0"] = 0 _reg_offsets["a1"] = 0 _reg_offsets["r1"] = 4 _reg_offsets["a2"] = 4 _reg_offsets["r2"] = 8 _reg_offsets["a3"] = 8 _reg_offsets["r3"] = 12 _reg_offsets["a4"] = 12 _reg_offsets["r4"] = 16 _reg_offsets["v1"] = 16 _reg_offsets["r5"] = 20 _reg_offsets["v2"] = 20 _reg_offsets["r6"] = 24 _reg_offsets["v3"] = 24 _reg_offsets["r7"] = 28 _reg_offsets["v4"] = 28 _reg_offsets["r8"] = 32 _reg_offsets["v5"] = 32 _reg_offsets["r9"] = 36 _reg_offsets["v6"] = 36 _reg_offsets["r10"] = 40 _reg_offsets["v7"] = 40 _reg_offsets["fp"] = 44 _reg_offsets["v8"] = 44 _reg_offsets["ip"] = 48 _reg_offsets["sp"] = 52 _reg_offsets["lr"] = 56 _reg_offsets["pc"] = 60 _reg_offsets["cpsr"] = 64 _reg_offsets["orig_r0"] = 68 } function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ long value; struct pt_regs *regs; if (CONTEXT->user_mode_p) { regs = CONTEXT->uregs; } else { regs = CONTEXT->kregs; } if (!regs) { CONTEXT->last_error = "No registers available in this context"; return; } if (STAP_ARG_offset < 0 || STAP_ARG_offset > sizeof(struct pt_regs) - sizeof(long)) { snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "Bad register offset: %lld", STAP_ARG_offset); CONTEXT->last_error = CONTEXT->error_buffer; return; } memcpy(&value, ((char *)regs) + STAP_ARG_offset, sizeof(value)); STAP_RETVALUE = value; %} function _stp_probing_kernel:long () { return !user_mode(); } function arch_bytes:long() %{ /* pure */ STAP_RETVALUE = sizeof(long); %} function uarch_bytes:long() { assert(user_mode(), "requires user mode") return 4 } /* Return the named register value as a signed value. */ function register:long (name:string) { assert(registers_valid(), "cannot access CPU registers in this context") offset = _reg_offsets[name] assert(offset != 0 || (name in _reg_offsets), "Unknown register: " . name) return _stp_get_register_by_offset(offset) } /* * 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 register(name) & 0xffffffff; } function _stp_get_stack_nth:long (n:long) %{ /* pure */ __label__ deref_fault; unsigned int n = (unsigned int)STAP_ARG_n; struct pt_regs *regs; long *addr; STAP_RETVALUE = 0; if (CONTEXT->user_mode_p) { // This function only handles kernel arguments off the stack. snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "cannot access function args in this context"); CONTEXT->last_error = CONTEXT->error_buffer; return; } regs = CONTEXT->kregs; if (!regs) { snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "cannot access function args in this context"); CONTEXT->last_error = CONTEXT->error_buffer; return; } /* Get the address of the nth item on the stack. */ addr = _stp_regs_get_kernel_stack_nth_addr(regs, n); if (addr == NULL) { snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "cannot access stack arg(%d)", n); CONTEXT->last_error = CONTEXT->error_buffer; return; } STAP_RETVALUE = kread(addr); return; deref_fault: /* branched to from kread() */ snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "kernel fault at %#lx accessing stack arg(%d)", (unsigned long)addr, n); CONTEXT->last_error = CONTEXT->error_buffer; %} /* Return the value of function arg #argnum (1=first arg) as a signed value. * * We don't yet support extracting arg #5 and beyond, which are passed * on stack */ function _stp_arg:long (argnum:long) { val = 0 assert(!(argnum < 1 || argnum > 7), sprintf("Cannot access arg(%d)", argnum)) if (argnum == 1) val = register("r0") else if (argnum == 2) val = register("r1") else if (argnum == 3) val = register("r2") else if (argnum == 4) val = register("r3") else val = _stp_get_stack_nth(argnum - 5) return val; } /* Return the value of function arg #argnum as a signed int. */ function int_arg:long (argnum:long) { return _stp_arg(argnum) } /* Return the value of function arg #argnum as an unsigned int. */ function uint_arg:long (argnum:long) { return _stp_arg(argnum) & 0xffffffff; } function long_arg:long (argnum:long) { return int_arg(argnum) } function ulong_arg:long (argnum:long) { return uint_arg(argnum) } function longlong_arg:long (argnum:long) { /* * gcc has a few odd rules: * 1) If argnum == 2, the 64-bit arg will start with arg 3. * 2) If argnum == nr_regarg (4), gcc puts the whole 64-bit * arg on the stack. * * Note that following argument numbers will need to be * adjusted. */ if (argnum == 2 || argnum == 4) argnum++ lowbits = uint_arg(argnum) highbits = uint_arg(argnum+1) return ((highbits << 32) | lowbits) } function ulonglong_arg:long (argnum:long) { return longlong_arg(argnum) } function pointer_arg:long (argnum:long) { return ulong_arg(argnum) } 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(n:long) %{ snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "regparm is invalid on arm."); CONTEXT->last_error = CONTEXT->error_buffer; %}