summaryrefslogtreecommitdiffstats
path: root/tapset/i386
diff options
context:
space:
mode:
Diffstat (limited to 'tapset/i386')
-rw-r--r--tapset/i386/nd_syscalls.stp205
-rw-r--r--tapset/i386/registers.stp232
-rw-r--r--tapset/i386/syscalls.stp174
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 &regs->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)
+}
+