diff options
author | Frank Ch. Eigler <fche@elastic.org> | 2009-08-24 19:38:51 -0400 |
---|---|---|
committer | Frank Ch. Eigler <fche@elastic.org> | 2009-08-24 19:38:51 -0400 |
commit | edef3e8e82546c0b2bdbb110da7e4a02480761d6 (patch) | |
tree | 2eafa571262c1340da3a36d64f109093488beaf1 /tapset/i386 | |
parent | e0ccd368149d63108042c97150012ad4a2e7593c (diff) | |
download | systemtap-steved-edef3e8e82546c0b2bdbb110da7e4a02480761d6.tar.gz systemtap-steved-edef3e8e82546c0b2bdbb110da7e4a02480761d6.tar.xz systemtap-steved-edef3e8e82546c0b2bdbb110da7e4a02480761d6.zip |
PR4186 cont'd: move tapset/i686 -> tapset/i386
Diffstat (limited to 'tapset/i386')
-rw-r--r-- | tapset/i386/nd_syscalls.stp | 205 | ||||
-rw-r--r-- | tapset/i386/registers.stp | 232 | ||||
-rw-r--r-- | tapset/i386/syscalls.stp | 174 |
3 files changed, 611 insertions, 0 deletions
diff --git a/tapset/i386/nd_syscalls.stp b/tapset/i386/nd_syscalls.stp new file mode 100644 index 00000000..f19e54a9 --- /dev/null +++ b/tapset/i386/nd_syscalls.stp @@ -0,0 +1,205 @@ +# 32-bit x86-specific system calls +# These are typically defined in arch/i386 +# + +# get_thread_area ____________________________________________ +/* + * asmlinkage int + * sys_get_thread_area(struct user_desc __user *u_info) + */ +probe nd_syscall.get_thread_area = kprobe.function("sys_get_thread_area") +{ + name = "get_thread_area" + // u_info_uaddr = $u_info + asmlinkage() + u_info_uaddr = pointer_arg(1) + argstr = sprintf("%p", u_info_uaddr) +} +probe nd_syscall.get_thread_area.return = kprobe.function("sys_get_thread_area").return +{ + name = "get_thread_area" + retstr = returnstr(1) +} + +# iopl _______________________________________________________ +# long sys_iopl(unsigned long unused) +# NOTE. This function is only in i386 and x86_64 and its args vary +# between those two archs. +# +probe nd_syscall.iopl = kprobe.function("sys_iopl") +{ + name = "iopl" + argstr = "" +} +probe nd_syscall.iopl.return = kprobe.function("sys_iopl").return +{ + name = "iopl" + retstr = returnstr(1) +} + +# ipc ________________________________________________________ +# int sys_ipc (uint call, int first, int second, int third, void __user *ptr, long fifth) +# +probe nd_syscall.ipc = kprobe.function("sys_ipc") ? +{ + name = "ipc" + // call = $call + // first = $first + // second = $second + // third = $third + // ptr_uaddr = $ptr + // fifth = $fifth + // argstr = sprintf("%d, %d, %d, %d, %p, %d", $call, $first, + // $second, $third, $ptr, $fifth) + asmlinkage() + call = uint_arg(1) + first = int_arg(2) + second = int_arg(3) + third = int_arg(4) + ptr_uaddr = pointer_arg(5) + fifth = long_arg(6) + argstr = sprintf("%d, %d, %d, %d, %p, %d", call, first, + second, third, ptr_uaddr, fifth) +} +probe nd_syscall.ipc.return = kprobe.function("sys_ipc").return ? +{ + name = "ipc" + retstr = returnstr(1) +} + +# mmap2 ____________________________________________ +# sys_mmap2(unsigned long addr, unsigned long len, +# unsigned long prot, unsigned long flags, +# unsigned long fd, unsigned long pgoff) +# +probe nd_syscall.mmap2 = kprobe.function("sys_mmap2") ? +{ + name = "mmap2" + // start = $addr + // length = $len + // prot = $prot + // flags = $flags + // fd = $fd + // pgoffset = $pgoff + // argstr = sprintf("%p, %d, %s, %s, %d, %d", $addr, + // $len, _mprotect_prot_str($prot), _mmap_flags($flags), + // $fd, $pgoff) + asmlinkage() + start = ulong_arg(1) + length = ulong_arg(2) + prot = ulong_arg(3) + flags = ulong_arg(4) + fd = ulong_arg(5) + pgoffset = ulong_arg(6) + argstr = sprintf("%p, %d, %s, %s, %d, %d", start, + length, _mprotect_prot_str(prot), _mmap_flags(flags), + fd, pgoffset) +} +probe nd_syscall.mmap2.return = kprobe.function("sys_mmap2").return ? +{ + name = "mmap2" + retstr = returnstr(2) +} + +# set_thread_area ____________________________________________ +/* + * asmlinkage int + * sys_set_thread_area(struct user_desc __user *u_info) + */ +probe nd_syscall.set_thread_area = kprobe.function("sys_set_thread_area") +{ + name = "set_thread_area" + // u_info_uaddr = $u_info + asmlinkage() + u_info_uaddr = pointer_arg(1) + argstr = sprintf("%p", u_info_uaddr) +} +probe nd_syscall.set_thread_area.return = kprobe.function("sys_set_thread_area").return +{ + name = "set_thread_area" + retstr = returnstr(1) +} + +# set_zone_reclaim ___________________________________________ +/* + * asmlinkage long + * sys_set_zone_reclaim(unsigned int node, + * unsigned int zone, + * unsigned int state) + */ +probe nd_syscall.set_zone_reclaim = kprobe.function("sys_set_zone_reclaim") ? +{ + name = "set_zone_reclaim" + // node = $node + // zone = $zone + // state = $state + // argstr = sprintf("%d, %d, %d", $node, $zone, $state) + asmlinkage() + node = uint_arg(1) + zone = uint_arg(2) + state = uint_arg(3) + argstr = sprintf("%d, %d, %d", node, zone, state) +} +probe nd_syscall.set_zone_reclaim.return = kprobe.function("sys_set_zone_reclaim").return ? +{ + name = "set_zone_reclaim" + retstr = returnstr(1) +} + +# sigaltstack ________________________________________________ +# int sys_sigaltstack(unsigned long ebx) +# +# NOTE: args vary between archs. +# +probe nd_syscall.sigaltstack = kprobe.function("sys_sigaltstack") +{ + name = "sigaltstack" + // ussp = %( kernel_vr < "2.6.25" %? $ebx %: %( kernel_vr < "2.6.29" %? $bx %: $regs->bx %) %) + // NB: no asmlinkage() + ussp = %( kernel_vr < "2.6.29" %? ulong_arg(1) %: @cast(ulong_arg(1), "pt_regs")->bx %) + argstr = sprintf("%p", ussp) +} +probe nd_syscall.sigaltstack.return = kprobe.function("sys_sigaltstack").return +{ + name = "sigaltstack" + retstr = returnstr(1) +} + +# vm86 _______________________________________________________ +# +# int sys_vm86(struct pt_regs regs) +# +probe nd_syscall.vm86 = kprobe.function("sys_vm86") ? +{ + name = "vm86" + /* + * unsupported type identifier '$regs' + * regs = $regs + */ + argstr = "" +} +probe nd_syscall.vm86.return = kprobe.function("sys_vm86").return ? +{ + name = "vm86" + retstr = returnstr(1) +} + +# vm86old ____________________________________________________ +# +# int sys_vm86old(struct pt_regs regs) +# +probe nd_syscall.vm86old = kprobe.function("sys_vm86old") ? +{ + name = "vm86old" + /* + * unsupported type identifier '$regs' + * regs = $regs + */ + argstr = "" +} +probe nd_syscall.vm86old.return = kprobe.function("sys_vm86old").return ? +{ + name = "vm86old" + retstr = returnstr(1) +} + diff --git a/tapset/i386/registers.stp b/tapset/i386/registers.stp new file mode 100644 index 00000000..997376dc --- /dev/null +++ b/tapset/i386/registers.stp @@ -0,0 +1,232 @@ +global _reg_offsets, _stp_regs_registered, _sp_offset, _ss_offset + +function test_x86_gs:long() %{ /* pure */ +#ifdef STAPCONF_X86_GS + THIS->__retvalue = 1; +#else + THIS->__retvalue = 0; +#endif +%} + +function _stp_register_regs() { + + /* Same order as pt_regs */ + _reg_offsets["ebx"] = 0 _reg_offsets["bx"] = 0 + _reg_offsets["ecx"] = 4 _reg_offsets["cx"] = 4 + _reg_offsets["edx"] = 8 _reg_offsets["dx"] = 8 + _reg_offsets["esi"] = 12 _reg_offsets["si"] = 12 + _reg_offsets["edi"] = 16 _reg_offsets["di"] = 16 + _reg_offsets["ebp"] = 20 _reg_offsets["bp"] = 20 + _reg_offsets["eax"] = 24 _reg_offsets["ax"] = 24 + _reg_offsets["xds"] = 28 _reg_offsets["ds"] = 28 + _reg_offsets["xes"] = 32 _reg_offsets["es"] = 32 + _reg_offsets["xfs"] = 36 _reg_offsets["fs"] = 36 + gs_incr = 0 +if (test_x86_gs()) { + gs_incr = 4 + _reg_offsets["xgs"] = 40 _reg_offsets["gs"] = 40 +} + _reg_offsets["orig_eax"] = 40 + gs_incr _reg_offsets["orig_ax"] = 40 + gs_incr + _reg_offsets["eip"] = 44 + gs_incr _reg_offsets["ip"] = 44 + gs_incr + _reg_offsets["xcs"] = 48 + gs_incr _reg_offsets["cs"] = 48 + gs_incr + _reg_offsets["eflags"] = 52 + gs_incr _reg_offsets["flags"] = 52 + gs_incr + _reg_offsets["esp"] = 56 + gs_incr _reg_offsets["sp"] = 56 + gs_incr + _reg_offsets["xss"] = 60 + gs_incr _reg_offsets["ss"] = 60 + gs_incr + _sp_offset = 56 + gs_incr + _ss_offset = 60 + gs_incr + + _stp_regs_registered = 1 +} + +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", THIS->offset); + CONTEXT->last_error = CONTEXT->error_buffer; + return; + } + memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value)); + THIS->__retvalue = value; +%} + +function _stp_probing_kernel:long () %{ /* pure */ + THIS->__retvalue = !user_mode(CONTEXT->regs); +%} + +/* + * esp and ss aren't saved on a breakpoint in kernel mode, so + * the pre-trap stack pointer is ®s->sp. + */ +function _stp_kernel_sp:long (sp_offset:long) %{ /* pure */ + THIS->__retvalue = ((long) CONTEXT->regs) + THIS->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)); + THIS->__retvalue = ss; +%} + +/* Return the named register value as a signed value. */ +function register:long (name:string) { + 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 + } + if (_stp_probing_kernel()) { + if (offset == _sp_offset) + return _stp_kernel_sp(_sp_offset) + else if (offset == _ss_offset) + return _stp_kernel_ss() + } + 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; +} + +/* Return the value of function arg #argnum (1=first arg) as a signed value. */ +function _stp_arg:long (argnum:long) %{ /* pure */ + long val; + int n, nr_regargs, result; + + THIS->__retvalue = 0; + if (!CONTEXT->regs) { + snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "cannot access function args in this context"); + CONTEXT->last_error = CONTEXT->error_buffer; + return; + } + if (THIS->argnum < 1) + goto bad_argnum; + n = (int) THIS->argnum; + nr_regargs = _stp_get_regparm(CONTEXT->regparm, CONTEXT->regs); + result = _stp_get_arg32_by_number(n, nr_regargs, CONTEXT->regs, &val); + switch (result) { + case 0: + /* Arg is in register. */ + THIS->__retvalue = (int64_t) val; + break; + case 1: + /* Arg is on kernel stack. */ + THIS->__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); + THIS->__retvalue = 0; + } else + THIS->__retvalue = (int64_t) val; + break; + } + default: + goto bad_argnum; + } + return; + +bad_argnum: + snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "cannot access arg(%lld)", THIS->argnum); + CONTEXT->last_error = CONTEXT->error_buffer; + return; + + if (0) { +deref_fault: /* branched to from deref() */ + snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), + "kernel fault at %#lx accessing arg(%lld)", val, + THIS->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 (THIS->n < 0 || THIS->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) THIS->n; +%} diff --git a/tapset/i386/syscalls.stp b/tapset/i386/syscalls.stp new file mode 100644 index 00000000..dec0aa97 --- /dev/null +++ b/tapset/i386/syscalls.stp @@ -0,0 +1,174 @@ +# 32-bit x86-specific system calls +# These are typically defined in arch/i386 +# + +# get_thread_area ____________________________________________ +/* + * asmlinkage int + * sys_get_thread_area(struct user_desc __user *u_info) + */ +probe syscall.get_thread_area = kernel.function("sys_get_thread_area") +{ + name = "get_thread_area" + u_info_uaddr = $u_info + argstr = sprintf("%p", u_info_uaddr) +} +probe syscall.get_thread_area.return = kernel.function("sys_get_thread_area").return +{ + name = "get_thread_area" + retstr = returnstr(1) +} +# iopl _______________________________________________________ +# long sys_iopl(unsigned long unused) +# NOTE. This function is only in i386 and x86_64 and its args vary +# between those two archs. +# +probe syscall.iopl = kernel.function("sys_iopl") +{ + name = "iopl" + argstr = "" +} +probe syscall.iopl.return = kernel.function("sys_iopl").return +{ + name = "iopl" + retstr = returnstr(1) +} + +# ipc ________________________________________________________ +# int sys_ipc (uint call, int first, int second, int third, void __user *ptr, long fifth) +# +probe syscall.ipc = kernel.function("sys_ipc") ? +{ + name = "ipc" + call = $call + first = $first + second = $second + third = $third + ptr_uaddr = $ptr + fifth = $fifth + argstr = sprintf("%d, %d, %d, %d, %p, %d", $call, $first, + $second, $third, $ptr, $fifth) +} +probe syscall.ipc.return = kernel.function("sys_ipc").return ? +{ + name = "ipc" + retstr = returnstr(1) +} + + +# mmap2 ____________________________________________ +# sys_mmap2(unsigned long addr, unsigned long len, +# unsigned long prot, unsigned long flags, +# unsigned long fd, unsigned long pgoff) +# +probe syscall.mmap2 = kernel.function("sys_mmap2") ? +{ + name = "mmap2" + start = $addr + length = $len + prot = $prot + flags = $flags + fd = $fd + pgoffset = $pgoff + argstr = sprintf("%p, %d, %s, %s, %d, %d", $addr, + $len, _mprotect_prot_str($prot), _mmap_flags($flags), + $fd, $pgoff) +} +probe syscall.mmap2.return = kernel.function("sys_mmap2").return ? +{ + name = "mmap2" + retstr = returnstr(2) +} + +# set_thread_area ____________________________________________ +/* + * asmlinkage int + * sys_set_thread_area(struct user_desc __user *u_info) + */ +probe syscall.set_thread_area = kernel.function("sys_set_thread_area") +{ + name = "set_thread_area" + u_info_uaddr = $u_info + argstr = sprintf("%p", u_info_uaddr) +} +probe syscall.set_thread_area.return = kernel.function("sys_set_thread_area").return +{ + name = "set_thread_area" + retstr = returnstr(1) +} +# set_zone_reclaim ___________________________________________ +/* + * asmlinkage long + * sys_set_zone_reclaim(unsigned int node, + * unsigned int zone, + * unsigned int state) + */ +probe syscall.set_zone_reclaim = kernel.function("sys_set_zone_reclaim") ? +{ + name = "set_zone_reclaim" + node = $node + zone = $zone + state = $state + argstr = sprintf("%d, %d, %d", $node, $zone, $state) +} +probe syscall.set_zone_reclaim.return = kernel.function("sys_set_zone_reclaim").return ? +{ + name = "set_zone_reclaim" + retstr = returnstr(1) +} + +# sigaltstack ________________________________________________ +# int sys_sigaltstack(unsigned long ebx) +# +# NOTE: args vary between archs. +# +probe syscall.sigaltstack = kernel.function("sys_sigaltstack") +{ + name = "sigaltstack" + ussp = %( kernel_vr < "2.6.25" %? $ebx %: %( kernel_vr < "2.6.29" %? $bx %: $regs->bx %) %) + argstr = sprintf("%p", ussp) +} +probe syscall.sigaltstack.return = kernel.function("sys_sigaltstack").return +{ + name = "sigaltstack" + retstr = returnstr(1) +} + +# vm86 _______________________________________________________ +# +# int sys_vm86(struct pt_regs regs) +# +probe syscall.vm86 = kernel.function("sys_vm86") ? +{ + name = "vm86" + /* + * unsupported type identifier '$regs' + * regs = $regs + */ + argstr = "" +} +probe syscall.vm86.return = kernel.function("sys_vm86").return ? +{ + name = "vm86" + retstr = returnstr(1) +} + +# vm86old ____________________________________________________ +# +# int sys_vm86old(struct pt_regs regs) +# +probe syscall.vm86old = kernel.function("sys_vm86old") ? +{ + name = "vm86old" + /* + * unsupported type identifier '$regs' + * regs = $regs + */ + argstr = "" +} +probe syscall.vm86old.return = kernel.function("sys_vm86old").return ? +{ + name = "vm86old" + retstr = returnstr(1) +} + |