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 %{ /* Set to include regparm field in probe context in translate.cxx. */ #ifndef STAP_NEED_REGPARM #define STAP_NEED_REGPARM 1 #endif %} @__private30 global _reg_offsets[21], _r32_offsets[10], _r16_offsets[13], _r8_offsets[8] probe init { /* Same order as pt_regs */ _reg_offsets["r15"] = 0 _reg_offsets["r14"] = 8 _reg_offsets["r13"] = 16 _reg_offsets["r12"] = 24 _reg_offsets["rbp"] = 32 _reg_offsets["rbx"] = 40 _reg_offsets["r11"] = 48 _reg_offsets["r10"] = 56 _reg_offsets["r9"] = 64 _reg_offsets["r8"] = 72 _reg_offsets["rax"] = 80 _reg_offsets["rcx"] = 88 _reg_offsets["rdx"] = 96 _reg_offsets["rsi"] = 104 _reg_offsets["rdi"] = 112 _reg_offsets["orig_rax"] = 120 _reg_offsets["rip"] = 128 _reg_offsets["xcs"] = 136 _reg_offsets["eflags"] = 144 _reg_offsets["rsp"] = 152 _reg_offsets["xss"] = 160 _r32_offsets["ebp"] = 32 _r32_offsets["ebx"] = 40 _r32_offsets["eax"] = 80 _r32_offsets["ecx"] = 88 _r32_offsets["edx"] = 96 _r32_offsets["esi"] = 104 _r32_offsets["edi"] = 112 _r32_offsets["orig_eax"] = 120 _r32_offsets["eip"] = 128 _r32_offsets["esp"] = 152 _r16_offsets["bp"] = 32 _r16_offsets["bx"] = 40 _r16_offsets["ax"] = 80 _r16_offsets["cx"] = 88 _r16_offsets["dx"] = 96 _r16_offsets["si"] = 104 _r16_offsets["di"] = 112 _r16_offsets["orig_ax"] = 120 _r16_offsets["ip"] = 128 _r16_offsets["cs"] = 136 _r16_offsets["flags"] = 144 _r16_offsets["sp"] = 152 _r16_offsets["ss"] = 160 _r8_offsets["al"] = 80 _r8_offsets["ah"] = 81 _r8_offsets["bl"] = 40 _r8_offsets["bh"] = 41 _r8_offsets["cl"] = 88 _r8_offsets["ch"] = 89 _r8_offsets["dl"] = 96 _r8_offsets["dh"] = 97 } function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ long value; struct pt_regs *regs; regs = (CONTEXT->user_mode_p ? CONTEXT->uregs : 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", (long long) STAP_ARG_offset); CONTEXT->last_error = CONTEXT->error_buffer; return; } memcpy(&value, ((char *)regs) + STAP_ARG_offset, sizeof(value)); STAP_RETVALUE = value; %} /* * _stp_sign_extend32() is callable from a script function. * __stp_sign_extend32() (in regs.c) is callable from a C function. */ function _stp_sign_extend32:long (value:long) %{ /* pure */ STAP_RETVALUE = __stp_sign_extend32(STAP_ARG_value); %} /* * _stp_sign_extend16() is callable from a script function. * __stp_sign_extend16() (in regs.c) is callable from a C function. */ function _stp_sign_extend16:long (value:long) %{ /* pure */ STAP_RETVALUE = __stp_sign_extend16(STAP_ARG_value); %} /* * _stp_sign_extend8() is callable from a script function. * __stp_sign_extend8() (in regs.c) is callable from a C function. */ function _stp_sign_extend8:long (value:long) %{ /* pure */ STAP_RETVALUE = __stp_sign_extend8(STAP_ARG_value); %} function _stp_register:long (name:string, sign_extend:long) { reg32 = 0 reg16 = 0 reg8 = 0 assert(registers_valid(), "cannot access CPU registers in this context") offset = _reg_offsets[name] if (offset == 0 && !(name in _reg_offsets)) { offset = _r32_offsets[name] if (offset == 0 && !(name in _r32_offsets)) { offset = _r16_offsets[name] if (offset == 0 && !(name in _r16_offsets)) { offset = _r8_offsets[name] if (offset == 0 && !(name in _r8_offsets)) { assert(0, "Unknown register: " . name) } else { reg8 = 1; } } else { reg16 = 1; } } else { reg32 = 1 } } value = _stp_get_register_by_offset(offset) if (reg32) { if (sign_extend) value = _stp_sign_extend32(value) else value &= 0xffffffff } else if (reg16) { if (sign_extend) value = _stp_sign_extend16(value) else value &= 0xffff } else if (reg8) { if (sign_extend) value = _stp_sign_extend8(value) else value &= 0xff } 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. * If force64=1, return a 64-bit value even if we're in a 32-bit app. */ function _stp_arg:long (argnum:long, sign_extend:long, truncate:long) { return _stp_arg2(argnum, sign_extend, truncate, 0) } function _stp_arg2:long (argnum:long, sign_extend:long, truncate:long, force64:long) %{ /* pure */ __label__ deref_fault; long val; struct pt_regs *regs; int result, n, nr_regargs; size_t argsz = sizeof(long); if (CONTEXT->sregs) { /* syscall-in-pt_regs mode: kernel 4.17+ or similar */ void* valptr; int is_32bit = _stp_is_compat_task(); regs = CONTEXT->sregs; /* NB: kread() is probably unnecessary paranoia w.r.t. the sregs pointer. */ if (is_32bit) switch (STAP_ARG_argnum) { /* SC_IA32_REGS_TO_ARGS / SC_X86_64_REGS_TO_ARGS */ case 1: valptr = &(RREG(bx, regs)); break; case 2: valptr = &(RREG(cx, regs)); break; case 3: valptr = &(RREG(dx, regs)); break; case 4: valptr = &(RREG(si, regs)); break; case 5: valptr = &(RREG(di, regs)); break; case 6: valptr = &(RREG(bp, regs)); break; default: goto bad_argnum; } else switch (STAP_ARG_argnum) { /* SC_IA32_REGS_TO_ARGS / SC_X86_64_REGS_TO_ARGS */ case 1: valptr = &(RREG(di, regs)); break; case 2: valptr = &(RREG(si, regs)); break; case 3: valptr = &(RREG(dx, regs)); break; case 4: valptr = &(regs->r10); break; case 5: valptr = &(regs->r8); break; case 6: valptr = &(regs->r9); break; default: goto bad_argnum; } val = kread((long *)valptr); /* Here, we do sign extension / truncation, ignoring CONTEXT->user_mode_p. */ if ((STAP_ARG_truncate || _stp_is_compat_task()) && !STAP_ARG_force64) { if (STAP_ARG_sign_extend) STAP_RETVALUE = (int64_t) __stp_sign_extend32(val); else /* High bits may be garbage. */ STAP_RETVALUE = (int64_t) (val & 0xffffffff); } else STAP_RETVALUE = (int64_t) val; return; } // fall through in the non-sycall-mode case regs = (CONTEXT->user_mode_p ? CONTEXT->uregs : CONTEXT->kregs); STAP_RETVALUE = 0; if (!regs) { snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "cannot access function args in this context"); CONTEXT->last_error = CONTEXT->error_buffer; return; } if (STAP_ARG_argnum < 1) goto bad_argnum; n = (int) STAP_ARG_argnum; if (CONTEXT->regparm == 0) { /* Default */ if (CONTEXT->user_mode_p && _stp_is_compat_task()) nr_regargs = 0; else nr_regargs = 6; } else nr_regargs = (CONTEXT->regparm & _STP_REGPARM_MASK); if (!STAP_ARG_force64 && CONTEXT->user_mode_p && _stp_is_compat_task()) { argsz = sizeof(int); result = _stp_get_arg32_by_number(n, nr_regargs, regs, &val); } else { result = _stp_get_arg64_by_number(n, nr_regargs, regs, &val); } switch (result) { case 0: /* Arg is in register. */ break; case 1: /* Arg is on kernel stack. */ val = kread((long *) val); break; case 2: { /* Arg is on user stack. */ const char __user *vaddr = (const char __user*) val; if (_stp_copy_from_user((char*)&val, vaddr, argsz) != 0) { /* Stack page not resident. */ _stp_warn("cannot access arg(%d) " "at user stack address %p\n", n, vaddr); STAP_RETVALUE = 0; return; } break; } default: goto bad_argnum; } /* Sign-extend etc. as needed, depending on process 32-bitness. */ if ((STAP_ARG_truncate || (CONTEXT->user_mode_p && _stp_is_compat_task())) && !STAP_ARG_force64) { if (STAP_ARG_sign_extend) STAP_RETVALUE = (int64_t) __stp_sign_extend32(val); else /* High bits may be garbage. */ STAP_RETVALUE = (int64_t) (val & 0xffffffff); } else STAP_RETVALUE = (int64_t) val; return; bad_argnum: snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "cannot access arg(%lld)", STAP_ARG_argnum); CONTEXT->last_error = CONTEXT->error_buffer; return; deref_fault: /* branched to from kread() */ snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "kernel fault at %#lx accessing arg(%lld)", val, STAP_ARG_argnum); CONTEXT->last_error = CONTEXT->error_buffer; %} /* For use with syscall-in-pt_regs mode: kernel 4.17+ or similar */ function _stp_get_arg_ptr:long (argnum:long) %{ void* regptr; struct pt_regs *regs; int is_32bit = _stp_is_compat_task(); if (!CONTEXT->sregs) { snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "cannot access function args in this context"); CONTEXT->last_error = CONTEXT->error_buffer; return; } regs = CONTEXT->sregs; if (is_32bit) switch (STAP_ARG_argnum) { case 1: regptr = &(RREG(bx, regs)); break; case 2: regptr = &(RREG(cx, regs)); break; case 3: regptr = &(RREG(dx, regs)); break; case 4: regptr = &(RREG(si, regs)); break; case 5: regptr = &(RREG(di, regs)); break; case 6: regptr = &(RREG(bp, regs)); break; default: goto bad_argnum; } else switch (STAP_ARG_argnum) { case 1: regptr = &(RREG(di, regs)); break; case 2: regptr = &(RREG(si, regs)); break; case 3: regptr = &(RREG(dx, regs)); break; case 4: regptr = &(regs->r10); break; case 5: regptr = &(regs->r8); break; case 6: regptr = &(regs->r9); break; default: goto bad_argnum; } STAP_RETVALUE = (unsigned long) regptr; return; bad_argnum: snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "cannot access arg(%lld)", STAP_ARG_argnum); CONTEXT->last_error = CONTEXT->error_buffer; return; %} function probing_32bit_app:long() %{ /* pure */ STAP_RETVALUE = (CONTEXT->user_mode_p && _stp_is_compat_task()); %} function arch_bytes:long() %{ /* pure */ STAP_RETVALUE = sizeof(long); %} function uarch_bytes:long() { assert(user_mode(), "requires user mode") return probing_32bit_app() ? 4 : 8 } /* Set the #value of function arg #argnum (1=first arg) as a signed int. */ function set_int_arg (argnum:long, value:long) { set_kernel_int(_stp_get_arg_ptr(argnum), value); return } /* Return the value of function arg #argnum (1=first arg) as a signed int. */ function int_arg:long (argnum:long) { return _stp_arg2(argnum, 1, 1, 0) } /* Set the #value of function arg #argnum (1=first arg) as an unsigned int. */ function set_uint_arg (argnum:long, value:long) { set_int_arg(argnum, value); return } /* Return the value of function arg #argnum (1=first arg) as an unsigned int. */ function uint_arg:long (argnum:long) { return _stp_arg2(argnum, 0, 1, 0) } function set_long_arg (argnum:long, value:long) { set_kernel_long(_stp_get_arg_ptr(argnum), value); return } function long_arg:long (argnum:long) { return _stp_arg2(argnum, 1, 0, 0) } function set_ulong_arg (argnum:long, value:long) { set_kernel_long(_stp_get_arg_ptr(argnum), value); return } function ulong_arg:long (argnum:long) { return _stp_arg2(argnum, 0, 0, 0) } function set_longlong_arg (argnum:long, value:long) { if (probing_32bit_app()) { highbits = value >> 32 lowbits = value & 0xffffffff set_u32_arg(argnum, lowbits) set_u32_arg(argnum+1, highbits) } else set_long_arg(argnum, value) } function longlong_arg:long (argnum:long) { if (probing_32bit_app()) { lowbits = _stp_arg2(argnum, 0, 1, 0) highbits = _stp_arg2(argnum+1, 0, 1, 0) return ((highbits << 32) | lowbits) } else return _stp_arg2(argnum, 0, 0, 1) } function set_ulonglong_arg (argnum:long, value:long) { set_longlong_arg(argnum, value) return } function ulonglong_arg:long (argnum:long) { return longlong_arg(argnum) } function set_pointer_arg (argnum:long, value:long) { set_kernel_pointer(_stp_get_arg_ptr(argnum), value); return } function pointer_arg:long (argnum:long) { return _stp_arg2(argnum, 0, 0, 0) } function set_s32_arg:long (argnum:long, value:long) { set_int_arg(argnum, value); return } function s32_arg:long (argnum:long) { return int_arg(argnum) } function set_u32_arg (argnum:long, value:long) { set_uint_arg(argnum, value); return } function u32_arg:long (argnum:long) { return uint_arg(argnum) } function set_s64_arg (argnum:long, value:long) { set_longlong_arg(argnum, value); return } function s64_arg:long (argnum:long) { return longlong_arg(argnum) } function set_u64_arg (argnum:long, value:long) { set_ulonglong_arg(argnum, value); return } function u64_arg:long (argnum:long) { return ulonglong_arg(argnum) } function asmlinkage() %{ /* pure */ %} function fastcall() %{ /* pure */ %} function regparm(n:long) %{ if (CONTEXT->user_mode_p && _stp_is_compat_task() && (STAP_ARG_n < 0 || STAP_ARG_n > 3)) { snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "For -m32 programs, " "regparm value must be in the range 0-3."); CONTEXT->last_error = CONTEXT->error_buffer; } else if (STAP_ARG_n < 0 || STAP_ARG_n > 6) { snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "For x86_64, regparm value must be in the range 0-6."); CONTEXT->last_error = CONTEXT->error_buffer; } else CONTEXT->regparm = _STP_REGPARM | (int) STAP_ARG_n; %}