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[17], _r16_offsets[17], _r8_offsets[8], _sp_offset, _ss_offset function test_x86_fs:long() %{ /* pure */ #if defined(STAPCONF_X86_XFS) || defined (STAPCONF_X86_FS) STAP_RETVALUE = 1; #else STAP_RETVALUE = 0; #endif %} function test_x86_gs:long() %{ /* pure */ #ifdef STAPCONF_X86_GS STAP_RETVALUE = 1; #else STAP_RETVALUE = 0; #endif %} probe init { /* Same order as pt_regs */ _offset = 0 _reg_offsets["ebx"] = _r16_offsets["bx"] = _r8_offsets["bl"] = _offset _r8_offsets["bh"] = _offset + 1 _reg_offsets["ecx"] = _r16_offsets["cx"] = _r8_offsets["cl"] = (_offset += 4) _r8_offsets["ch"] = _offset + 1 _reg_offsets["edx"] = _r16_offsets["dx"] = _r8_offsets["dl"] = (_offset += 4) _r8_offsets["dh"] = _offset + 1 _reg_offsets["esi"] = _r16_offsets["si"] = (_offset += 4) _reg_offsets["edi"] = _r16_offsets["di"] = (_offset += 4) _reg_offsets["ebp"] = _r16_offsets["bp"] = (_offset += 4) _reg_offsets["eax"] = _r16_offsets["ax"] = _r8_offsets["al"] = (_offset += 4) _r8_offsets["ah"] = _offset + 1 _reg_offsets["xds"] = _r16_offsets["ds"] = (_offset += 4) _reg_offsets["xes"] = _r16_offsets["es"] = (_offset += 4) if (test_x86_fs()) { _reg_offsets["xfs"] = _r16_offsets["fs"] = (_offset += 4) } if (test_x86_gs()) { _reg_offsets["xgs"] = _r16_offsets["gs"] = (_offset += 4) } _reg_offsets["orig_eax"] = _r16_offsets["orig_ax"] = (_offset += 4) _reg_offsets["eip"] = _r16_offsets["ip"] = (_offset += 4) _reg_offsets["xcs"] = _r16_offsets["cs"] = (_offset += 4) _reg_offsets["eflags"] = _r16_offsets["flags"] = (_offset += 4) _reg_offsets["esp"] = _r16_offsets["sp"] = _sp_offset = (_offset += 4) _reg_offsets["xss"] = _r16_offsets["ss"] = _ss_offset = (_offset += 4) } 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", 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 } /* * esp and ss aren't saved on a breakpoint in kernel mode, so * the pre-trap stack pointer is ®s->sp. * * Note that the idea of i386 trap regs is that pt_regs is the very * first thing saved on the stack. Neither sp nor ss are saved, but * pt_regs is aligned on the stack such that the place where sp would * be saved happens to be the top where the sp was when the trap * started. So ®s->sp is that original sp value. See * arch/x86/entry/entry_32.S in the kernel source for more details. */ function _stp_kernel_sp:long (sp_offset:long) %{ /* pure */ STAP_RETVALUE = ((long) CONTEXT->kregs) + STAP_ARG_sp_offset; %} /* Assume ss register hasn't changed since we took the trap. */ function _stp_kernel_ss:long () %{ /* pure */ unsigned short ss; asm volatile("movw %%ss, %0" : : "m" (ss)); STAP_RETVALUE = ss; %} /* * _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) { 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 = _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; } } if (_stp_probing_kernel()) { if (offset == _sp_offset) return _stp_kernel_sp(_sp_offset) else if (offset == _ss_offset) return _stp_kernel_ss() } value = _stp_get_register_by_offset(offset) 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 } else { if (sign_extend) value = _stp_sign_extend32(value) else value &= 0xffffffff } 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) as a signed value. */ function _stp_arg:long (argnum:long) %{ /* pure */ __label__ deref_fault; long val; int n, nr_regargs, result; struct pt_regs *regs; 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) nr_regargs = 0; else nr_regargs = 3; } else nr_regargs = (CONTEXT->regparm & _STP_REGPARM_MASK); result = _stp_get_arg32_by_number(n, nr_regargs, regs, &val); switch (result) { case 0: /* Arg is in register. */ STAP_RETVALUE = (int64_t) val; break; case 1: /* Arg is on kernel stack. */ STAP_RETVALUE = 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, sizeof(val)) != 0) { /* Stack page not resident. */ _stp_warn("cannot access arg(%d) " "at user stack address %p\n", n, vaddr); STAP_RETVALUE = 0; } else STAP_RETVALUE = (int64_t) val; break; } default: goto bad_argnum; } 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; %} /* 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) { /* * TODO: If argnum == nr_regarg, gcc puts the whole 64-bit arg * on the stack. */ 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() %{ CONTEXT->regparm = _STP_REGPARM | 0; %} function fastcall() %{ CONTEXT->regparm = _STP_REGPARM | 3; %} function regparm(n:long) %{ if (STAP_ARG_n < 0 || STAP_ARG_n > 3) { snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), "For i386, regparm value must be in the range 0-3."); CONTEXT->last_error = CONTEXT->error_buffer; } else CONTEXT->regparm = _STP_REGPARM | (int) STAP_ARG_n; %}