diff options
-rw-r--r-- | ChangeLog | 47 | ||||
-rw-r--r-- | hash.cxx | 15 | ||||
-rw-r--r-- | main.cxx | 71 | ||||
-rw-r--r-- | runtime/regs.c | 154 | ||||
-rw-r--r-- | session.h | 6 | ||||
-rw-r--r-- | stap.1.in | 76 | ||||
-rw-r--r-- | stapfuncs.5.in | 104 | ||||
-rw-r--r-- | tapset/i686/registers.stp | 202 | ||||
-rw-r--r-- | tapset/nd_syscalls.stp | 2845 | ||||
-rw-r--r-- | tapset/x86_64/registers.stp | 243 | ||||
-rw-r--r-- | tapsets.cxx | 916 | ||||
-rwxr-xr-x | testsuite/semko/nodwf01.stp | 14 | ||||
-rwxr-xr-x | testsuite/semko/nodwf02.stp | 14 | ||||
-rwxr-xr-x | testsuite/semko/nodwf03.stp | 14 | ||||
-rwxr-xr-x | testsuite/semko/nodwf04.stp | 14 | ||||
-rwxr-xr-x | testsuite/semko/nodwf05.stp | 14 | ||||
-rwxr-xr-x | testsuite/semko/nodwf06.stp | 14 | ||||
-rwxr-xr-x | testsuite/semko/nodwf07.stp | 15 | ||||
-rwxr-xr-x | testsuite/semko/nodwf08.stp | 14 | ||||
-rwxr-xr-x | testsuite/semko/nodwf09.stp | 14 | ||||
-rwxr-xr-x | testsuite/semok/nodwf01.stp | 12 | ||||
-rwxr-xr-x | testsuite/semok/nodwf02.stp | 44 | ||||
-rwxr-xr-x | testsuite/semok/nodwf03.stp | 13 | ||||
-rwxr-xr-x | testsuite/semok/nodwf04.stp | 14 | ||||
-rwxr-xr-x | testsuite/semok/nodwf05.stp | 46 | ||||
-rwxr-xr-x | testsuite/semok/nodwf06.stp | 14 | ||||
-rwxr-xr-x | testsuite/semok/nodwf07.stp | 17 | ||||
-rw-r--r-- | translate.cxx | 1 |
28 files changed, 4830 insertions, 137 deletions
@@ -1,9 +1,54 @@ +2008-05-12 Jim Keniston <jkenisto@us.ibm.com> + + PR 4311 - Function boundary tracing without debuginfo: Phase II + Merged dwarfless branch into mainline. But first... + * runtime/regs.c: Removed register name:value lookup facility. + Moved basically all register-lookup code to the i686 and x86_64 + registers.stp tapsets. Args stuff shared between i386 and + x86_64 remains in regs.c. + * tapset/{i686,x86_64}/registers.stp: Moved register-lookup + code from runtime/regs.c to here. + +2008-05-12 Jim Keniston <jkenisto@us.ibm.com> + + (2008-05-06 in dwarfless branch) + PR 4311 - Function boundary tracing without debuginfo: Phase II + * stapfuncs.5.in: Added sections on CPU REGISTERS and + NUMBERED FUNCTION ARGUMENTS. + +2008-05-12 Jim Keniston <jkenisto@us.ibm.com> + + (2008-05-05 in dwarfless branch) + PR 4311 - Function boundary tracing without debuginfo: Phase II + * runtime/regs.c: Added register name:value lookup facility. + Added support for register and arg lookup for i386 and x86_64. + * tapset/{i686,x86_64}/registers.stp: New: support for register + and arg lookup. + * tapsets.cxx, translate.cxx: Added regparm field to struct + context. + * tapset/nd_syscall.stp: syscall.stp migrating toward numbered + args rather than named args. + +2008-05-12 Jim Keniston <jkenisto@us.ibm.com> + + (2008-04-18 in dwarfless branch) + PR 4311 - Function boundary tracing without debuginfo: Phase I + * tapsets.cxx: Major rework of dwflpp, dwarf_query, and related + code to make do with elf info if dwarf info is absent, or + (in the case of vmlinux) make do with a System.map-style + symbol table if even the elf file is absent. + * main.cxx: Use getopt_long instead of getopt. Added --kelf, + --kmap, --ignore-vmlinux, and --ignore-dwarf. + * hash.cxx, session.h, stap.1.in: Added --kelf, --kmap, + --ignore-vmlinux, and --ignore-dwarf. + * testsuite/{semok,semko}/nodwf*.stp + 2008-05-09 Frank Ch. Eigler <fche@elastic.org> PR 6487. * main.cxx (dwarf_query::build_blacklist): Add kernel/relay.c and kernel/timer.c to probing blacklist. - + 2008-05-07 Frank Ch. Eigler <fche@elastic.org> PR 6492. @@ -97,6 +97,21 @@ find_hash (systemtap_session& s, const string& script) h.add(s.merge); // '-M' h.add(s.timing); // '-t' h.add(s.prologue_searching); // '-P' + h.add(s.ignore_vmlinux); // --ignore-vmlinux + h.add(s.ignore_dwarf); // --ignore-dwarf + h.add(s.consult_symtab); // --kelf, --kmap + if (!s.kernel_symtab_path.empty()) // --kmap + { + h.add(s.kernel_symtab_path); + if (stat(s.kernel_symtab_path.c_str(), &st) == 0) + { + // NB: stat of /proc/kallsyms always returns size=0, mtime=now... + // which is a good reason to use the default /boot/System.map-2.6.xx + // instead. + h.add(st.st_size); + h.add(st.st_mtime); + } + } for (unsigned i = 0; i < s.macros.size(); i++) h.add(s.macros[i]); @@ -37,6 +37,7 @@ extern "C" { #include <sys/stat.h> #include <time.h> #include <elfutils/libdwfl.h> +#include <getopt.h> } using namespace std; @@ -106,8 +107,15 @@ usage (systemtap_session& s, int exitcode) << " -x PID sets target() to PID" << endl << " -t collect probe timing information" << endl #ifdef HAVE_LIBSQLITE3 - << " -q generate information on tapset coverage" + << " -q generate information on tapset coverage" << endl #endif /* HAVE_LIBSQLITE3 */ + << " --kelf make do with symbol table from vmlinux" << endl + << " --kmap[=FILE]" << endl + << " make do with symbol table from nm listing" << endl + << " --ignore-vmlinux" << endl + << " for testing, pretend vmlinux can't be found" << endl + << " --ignore-dwarf" << endl + << " for testing, pretend vmlinux and modules lack debug info" << endl ; // -d: dump safety-related external references @@ -295,6 +303,9 @@ main (int argc, char * const argv []) s.use_cache = true; s.tapset_compile_coverage = false; s.need_uprobes = false; + s.consult_symtab = false; + s.ignore_vmlinux = false; + s.ignore_dwarf = false; const char* s_p = getenv ("SYSTEMTAP_TAPSET"); if (s_p != NULL) @@ -345,8 +356,21 @@ main (int argc, char * const argv []) while (true) { + int long_opt; +#define LONG_OPT_KELF 1 +#define LONG_OPT_KMAP 2 +#define LONG_OPT_IGNORE_VMLINUX 3 +#define LONG_OPT_IGNORE_DWARF 4 // NB: also see find_hash(), usage(), switch stmt below, stap.1 man page - int grc = getopt (argc, argv, "hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:uqwl:"); + static struct option long_options[] = { + { "kelf", 0, &long_opt, LONG_OPT_KELF }, + { "kmap", 2, &long_opt, LONG_OPT_KMAP }, + { "ignore-vmlinux", 0, &long_opt, LONG_OPT_IGNORE_VMLINUX }, + { "ignore-dwarf", 0, &long_opt, LONG_OPT_IGNORE_DWARF }, + { NULL, 0, NULL, 0 } + }; + int grc = getopt_long (argc, argv, "hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:uqwl:", + long_options, NULL); if (grc < 0) break; switch (grc) @@ -523,6 +547,37 @@ main (int argc, char * const argv []) have_script = true; break; + case 0: + switch (long_opt) + { + case LONG_OPT_KELF: + s.consult_symtab = true; + break; + case LONG_OPT_KMAP: + // Leave s.consult_symtab unset for now, to ease error checking. + if (!s.kernel_symtab_path.empty()) + { + cerr << "You can't specify multiple --kmap options." << endl; + usage(s, 1); + } + if (optarg) + s.kernel_symtab_path = optarg; + else +#define PATH_TBD string("__TBD__") + s.kernel_symtab_path = PATH_TBD; + break; + case LONG_OPT_IGNORE_VMLINUX: + s.ignore_vmlinux = true; + break; + case LONG_OPT_IGNORE_DWARF: + s.ignore_dwarf = true; + break; + default: + cerr << "Internal error parsing command arguments." << endl; + usage(s, 1); + } + break; + default: usage (s, 1); break; @@ -547,6 +602,18 @@ main (int argc, char * const argv []) usage (s, 1); } + if (!s.kernel_symtab_path.empty()) + { + if (s.consult_symtab) + { + cerr << "You can't specify --kelf and --kmap together." << endl; + usage (s, 1); + } + s.consult_symtab = true; + if (s.kernel_symtab_path == PATH_TBD) + s.kernel_symtab_path = string("/boot/System.map-") + s.kernel_release; + } + if (s.last_pass > 4 && release_changed) { if (s.verbose) diff --git a/runtime/regs.c b/runtime/regs.c index 5e08e376..5821f7e7 100644 --- a/runtime/regs.c +++ b/runtime/regs.c @@ -383,5 +383,159 @@ void _stp_print_regs(struct pt_regs * regs) #endif + +/* Function arguments */ + +#define _STP_REGPARM 0x8000 +#define _STP_REGPARM_MASK ((_STP_REGPARM) - 1) + +/* + * x86_64 and i386 are especially ugly because: + * 1) the pt_reg member names changed as part of the x86 merge. We use + * either the pre-merge name or the post-merge name, as needed. + * 2) -m32 apps on x86_64 look like i386 apps, so we need to support + * those semantics on both i386 and x86_64. + */ + +#ifdef __i386__ +#ifdef STAPCONF_X86_UNIREGS +#define EREG(nm, regs) ((regs)->nm) +#else +#define EREG(nm, regs) ((regs)->e##nm) +#endif + +static long _stp_get_sp(struct pt_regs *regs) +{ + if (!user_mode(regs)) + return (long) &EREG(sp, regs); + return EREG(sp, regs); +} + +static int _stp_get_regparm(int regparm, struct pt_regs *regs) +{ + if (regparm == 0) { + /* Default */ + if (user_mode(regs)) + return 0; + else + // Kernel is built with -mregparm=3. + return 3; + } else + return (regparm & _STP_REGPARM_MASK); +} +#endif /* __i386__ */ + +#ifdef __x86_64__ +#ifdef STAPCONF_X86_UNIREGS +#define EREG(nm, regs) ((regs)->nm) +#define RREG(nm, regs) ((regs)->nm) +#else +#define EREG(nm, regs) ((regs)->r##nm) +#define RREG(nm, regs) ((regs)->r##nm) +#endif + +static long _stp_get_sp(struct pt_regs *regs) +{ + return RREG(sp, regs); +} + +static int _stp_probing_32bit_app(struct pt_regs *regs) +{ + if (!regs) + return 0; + return (user_mode(regs) && test_tsk_thread_flag(current, TIF_IA32)); +} + +/* Ensure that the upper 32 bits of val are a sign-extension of the lower 32. */ +static int64_t __stp_sign_extend32(int64_t val) +{ + int32_t *val_ptr32 = (int32_t*) &val; + return *val_ptr32; +} + +static int _stp_get_regparm(int regparm, struct pt_regs *regs) +{ + if (regparm == 0) { + /* Default */ + if (_stp_probing_32bit_app(regs)) + return 0; + else + return 6; + } else + return (regparm & _STP_REGPARM_MASK); +} +#endif /* __x86_64__ */ + +#if defined(__i386__) || defined(__x86_64__) +/* + * Use this for i386 kernel and apps, and for 32-bit apps running on x86_64. + * Does arch-specific work for fetching function arg #argnum (1 = first arg). + * nr_regargs is the number of arguments that reside in registers (e.g., + * 3 for fastcall functions). + * Returns: + * 0 if the arg resides in a register. *val contains its value. + * 1 if the arg resides on the kernel stack. *val contains its address. + * 2 if the arg resides on the user stack. *val contains its address. + * -1 if the arg number is invalid. + * We assume that the regs pointer is valid. + */ +static int _stp_get_arg32_by_number(int n, int nr_regargs, + struct pt_regs *regs, long *val) +{ + if (nr_regargs < 0) + return -1; + if (n > nr_regargs) { + /* + * The typical case: arg n is on the stack. + * stack[0] = return address + */ + int stack_index = n - nr_regargs; + int32_t *stack = (int32_t*) _stp_get_sp(regs); + *val = (long) &stack[stack_index]; + return (user_mode(regs) ? 2 : 1); + } else { + switch (n) { + case 1: *val = EREG(ax, regs); break; + case 2: *val = EREG(dx, regs); break; + case 3: *val = EREG(cx, regs); break; + default: + /* gcc rejects regparm values > 3. */ + return -1; + } + return 0; + } +} +#endif /* __i386__ || __x86_64__ */ + +#ifdef __x86_64__ +/* See _stp_get_arg32_by_number(). */ +static int _stp_get_arg64_by_number(int n, int nr_regargs, + struct pt_regs *regs, unsigned long *val) +{ + if (nr_regargs < 0) + return -1; + if (n > nr_regargs) { + /* arg n is on the stack. stack[0] = return address */ + int stack_index = n - nr_regargs; + unsigned long *stack = (unsigned long*) _stp_get_sp(regs); + *val = (unsigned long) &stack[stack_index]; + return (user_mode(regs) ? 2 : 1); + } else { + switch (n) { + case 1: *val = RREG(di, regs); break; + case 2: *val = RREG(si, regs); break; + case 3: *val = RREG(dx, regs); break; + case 4: *val = RREG(cx, regs); break; + case 5: *val = regs->r8; break; + case 6: *val = regs->r9; break; + default: + /* gcc rejects regparm values > 6. */ + return -1; + } + return 0; + } +} +#endif /* __x86_64__ */ + /** @} */ #endif /* _REGS_C_ */ @@ -107,6 +107,12 @@ struct systemtap_session std::string cache_path; std::string hash_path; + // dwarfless operation + bool consult_symtab; + std::string kernel_symtab_path; + bool ignore_vmlinux; + bool ignore_dwarf; + // temporary directory for module builds etc. // hazardous - it is "rm -rf"'d at exit std::string tmpdir; @@ -167,6 +167,41 @@ a specific process. Instead of running a probe script, just list all available probe points matching the given pattern. The pattern may include wildcards and aliases. +.TP +.B \-\-kelf +For names and addresses of functions to probe, +consult the symbol tables in the kernel and modules. +This can be useful if your kernel and/or modules were compiled +without debugging information, or the function you want to probe +is in an assembly-language file built without debugging information. +See the +.B "MAKING DO WITH SYMBOL TABLES" +section for more information. +.TP +.BI \-\-kmap [=FILE] +For names and addresses of kernel functions to probe, +consult the symbol table in the indicated text file. +The default is /boot/System.map-VERSION. +The contents of this file should be in the form of the default output from +.IR nm (1). +Only symbols of type T or t are used. +If you specify /proc/kallsyms or some other file in that format, +where lines for module symbols contain a fourth column, +reading of the symbol table stops with the first module symbol +(which should be right after the last kernel symbol). +As with +.BR \-\-kelf , +the symbol table in each module's .ko file will also be consulted. +See the +.B "MAKING DO WITH SYMBOL TABLES" +section for more information. +.TP +.B \-\-ignore\-vmlinux +For testing, act as though neither the uncompressed kernel (vmlinux) +nor the kernel debugging information can be found. +.TP +.B \-\-ignore\-dwarf +For testing, act as though vmlinux and modules lack debugging information. .SH ARGUMENTS @@ -930,6 +965,47 @@ have overloaded the system and an exit is triggered. By default, overload processing is turned on for all modules. If you would like to disable overload processing, define STP_NO_OVERLOAD. +.SH MAKING DO WITH SYMBOL TABLES +Systemtap performs best when it has access to the debugging information +associated with your kernel and modules. +However, if this information is not available, +systemtap can still support probing of function entries and returns +using symbols read from vmlinux and/or the modules in /lib/modules. +Systemtap can also read the kernel symbol table from a text file +such as /boot/System.map or /proc/kallsyms. +See the +.B \-\--kelf +and +.B \-\--kmap +options. +.PP +If systemtap finds relevant debugging information, +it will use it even if you specify +.B \-\--kelf +or +.BR \-\--kmap . +.PP +Without debugging information, systemtap cannot support the +following types of language constructs: +.IP \(bu 4 +probe specifications that refer to source files or line numbers +.IP \(bu 4 +probe specifications that refer to inline functions +.IP \(bu 4 +statements that refer to $target variables +.IP \(bu 4 +tapset-defined variables defined using any of the above constructs. +In particular, at this writing, +the prologue blocks for certain aliases in the syscall tapset +(e.g., syscall.open) contain "if" statements that refer to $target variables. +If your script refers to any such aliases, +systemtap must have access to the kernel's debugging information. +.PP +Most T and t symbols correspond to function entry points, but some do not. +Based only on the symbol table, systemtap cannot tell the difference. +Placing return probes on symbols that aren't entry points +will most likely lead to kernel stack corruption. + .SH FILES .\" consider autoconf-substituting these directories .TP diff --git a/stapfuncs.5.in b/stapfuncs.5.in index 9bca845d..994b8c06 100644 --- a/stapfuncs.5.in +++ b/stapfuncs.5.in @@ -343,6 +343,110 @@ Return the number of open file handles for the given task. task_max_file_handles:long(task:long) Return the maximum number of file handles for the given task. +.SS CPU REGISTERS +.TP +register:long (name:string) +Return the value of the named CPU register, +as it was saved when the current probe point was hit. +If the register is 32 bits, it is sign-extended to 64 bits. + +For the i386 architecture, the following names are recognized. +(name1/name2 indicates that name1 and name2 are alternative names +for the same register.) +eax/ax, ebp/bp, ebx/bx, ecx/cx, edi/di, edx/dx, eflags/flags, +eip/ip, esi/si, esp/sp, orig_eax/orig_ax, +xcs/cs, xds/ds, xes/es, xfs/fs, xss/ss. + +For the x86_64 architecture, the following names are recognized: +64-bit registers: +r8, r9, r10, r11, r12, r13, r14, r15, +rax/ax, rbp/bp, rbx/bx, rcx/cx, rdi/di, rdx/dx, +rip/ip, rsi/si, rsp/sp; +32-bit registers: +eax, ebp, ebx, ecx, edx, edi, edx, eip, esi, esp, flags/eflags, orig_eax; +segment registers: xcs/cs, xss/ss. +.TP +u_register:long (name:string) +Same as register(name), except that +if the register is 32 bits, it is zero-extended to 64 bits. + +.SS NUMBERED FUNCTION ARGUMENTS +The functions in this section provide the values of a probed function's +arguments. +They can be called when you have hit +a probe point at the entry to a function. +Arguments are referred to by number, starting at 1. +Ordinarily, you can access arguments by name as well, +but you may find these functions useful if the code you are probing +was built without debugging information. + +On 32-bit architectures +\(em and when probing 32-bit applications on 64-bit architectures \(em +a 64-bit argument occupies two "arg slots." +For example, if you are probing the following function + + void f(int a, long long b, char *c) + +you would refer to a, b, and c as int_arg(1), longlong_arg(2), and +pointer_arg(3), respectively, on a 64-bit architecture; +but on a 32-bit architecture, you would refer to c as pointer_arg(4) +(since b occupies slots 2 and 3). + +If the function you are probing doesn't follow the default rules +for argument passing, you need to call one of the following functions +(which see) in your handler before calling any *_arg function: +asmlinkage(), fastcall(), or regparm(). +(This isn't necessary when referring to arguments only by name.) +.TP +int_arg:long (n:long) +Return the value of argument n as a signed int +(i.e., a 32-bit integer sign-extended to 64 bits). +.TP +uint_arg:long (n:long) +Return the value of argument n as an unsigned int +(i.e., a 32-bit integer zero-extended to 64 bits). +.TP +long_arg:long (n:long) +Return the value of argument n as a signed long. +On architectures where a long is 32 bits, the value is sign-extended to 64 bits. +.TP +ulong_arg:long (n:long) +Return the value of argument n as an unsigned long. +On architectures where a long is 32 bits, the value is zero-extended to 64 bits. +.TP +longlong_arg:long (n:long) +Return the value of argument n as a 64-bit value. +.TP +ulonglong_arg:long (n:long) +Same as longlong_arg(n). +.TP +pointer_arg:long (n:long) +Same as ulong_arg(n). +Use with any type of pointer. +.TP +s32_arg:long (n:long) +Same as int_arg(n). +.TP +u32_arg:long (n:long) +Same as uint_arg(n). +.TP +s64_arg:long (n:long) +Same as longlong_arg(n). +.TP +u64_arg:long (n:long) +Same as [u]longlong_arg(n). +.TP +asmlinkage:unknown () +The probed kernel function is declared asmlinkage in the source. +.TP +fastcall:unknown () +The probed kernel function is declared fastcall in the source. +.TP +regparm:unknown (n:long) +The probed function was built with the gcc \-mregparm=n option. +(The i386 kernel is built with \-mregparm=3, so systemtap considers +regparm(3) the default for kernel functions on that architecture.) + .SS QUEUE_STATS .PP The queue_stats tapset provides functions that, given notifications of diff --git a/tapset/i686/registers.stp b/tapset/i686/registers.stp new file mode 100644 index 00000000..db532f7a --- /dev/null +++ b/tapset/i686/registers.stp @@ -0,0 +1,202 @@ +global _reg_offsets, _stp_regs_registered + +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 + _reg_offsets["orig_eax"] = 40 _reg_offsets["orig_ax"] = 40 + _reg_offsets["eip"] = 44 _reg_offsets["ip"] = 44 + _reg_offsets["xcs"] = 48 _reg_offsets["cs"] = 48 + _reg_offsets["eflags"] = 52 _reg_offsets["flags"] = 52 + _reg_offsets["esp"] = 56 _reg_offsets["sp"] = 56 sp_offset = 56 + _reg_offsets["xss"] = 60 _reg_offsets["ss"] = 60 ss_offset = 60 + + _stp_regs_registered = 1 +} + +function _stp_get_register_by_offset:long (offset:long) %{ + long value; + memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value)); + THIS->__retvalue = value; +%} + +function _stp_probing_kernel:long () %{ + 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) %{ + THIS->__retvalue = ((long) CONTEXT->regs) + THIS->sp_offset; +%} + +/* Assume ss register hasn't changed since we took the trap. */ +function _stp_kernel_ss:long () %{ + 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 (!_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) %{ + 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) %{ + 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) n; +%} diff --git a/tapset/nd_syscalls.stp b/tapset/nd_syscalls.stp new file mode 100644 index 00000000..eb5efda0 --- /dev/null +++ b/tapset/nd_syscalls.stp @@ -0,0 +1,2845 @@ +// syscalls tapset part 1 [A-M] +// Copyright (C) 2005 IBM Corp. +// Copyright (C) 2005-2007 Red Hat Inc. +// Copyright (C) 2007 Quentin Barnes. +// +// This file is part of systemtap, and is free software. You can +// redistribute it and/or modify it under the terms of the GNU General +// Public License (GPL); either version 2, or (at your option) any +// later version. + + +/* Each syscall returns the calls parameters. In addition, the following +* variables are set: +* +* name - generally the syscall name minus the "sys_". +* +* argstr - a string containing the decoded args in an easy-to-read format. +* It doesn't need to contain everything, but should have all the +* important args. Set in entry probes only. Values enclosed in +* square brackets are user-space pointers. Values in curly +* braces are decoded structs. +* +* retstr - a string containing the return value in an easy-to-read format. +* Set in return probes only. +*/ + + +# accept _____________________________________________________ +# long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, +# int __user *upeer_addrlen) +probe nd_syscall.accept = kernel.function("sys_accept") ? { + name = "accept" + // sockfd = $fd + // addr_uaddr = $upeer_sockaddr + // addrlen_uaddr = $upeer_addrlen + // argstr = sprintf("%d, %p, %p", $fd, $upeer_sockaddr, $upeer_addrlen) + asmlinkage() + sockfd = int_arg(1) + addr_uaddr = pointer_arg(2) + addrlen_uaddr = int_arg(3) + argstr = sprintf("%d, %p, %p", sockfd, addr_uaddr, addrlen_uaddr) +} +probe nd_syscall.accept.return = kernel.function("sys_accept").return ? { + name = "accept" + retstr = returnstr(1) +} + +# access _____________________________________________________ +# long sys_access(const char __user * filename, int mode) +probe nd_syscall.access = kernel.function("sys_access") { + name = "access" + // pathname = user_string($filename) + // mode = $mode + // mode_str = _access_mode_str($mode) + // argstr = sprintf("%s, %s", user_string_quoted($filename), mode_str) + asmlinkage() + pathname = user_string(pointer_arg(1)) + mode = int_arg(2) + mode_str = _access_mode_str(mode) + argstr = sprintf("%s, %s", user_string_quoted(pointer_arg(1)), mode_str) +} +probe nd_syscall.access.return = kernel.function("sys_access").return { + name = "access" + retstr = returnstr(1) +} + +# acct _______________________________________________________ +# long sys_acct(const char __user *name) +probe nd_syscall.acct = kernel.function("sys_acct") ? { + name = "acct" + // filename = user_string($name) + // argstr = user_string_quoted($name) + asmlinkage() + filename = user_string(pointer_arg(1)) + argstr = user_string_quoted(pointer_arg(1)) +} +probe nd_syscall.acct.return = kernel.function("sys_acct").return ? { + name = "acct" + retstr = returnstr(1) +} + +# add_key ____________________________________________________ +# long sys_add_key(const char __user *_type, +# const char __user *_description, +# const void __user *_payload, +# size_t plen, +# key_serial_t ringid) +# +probe nd_syscall.add_key = kernel.function("sys_add_key") ? { + name = "add_key" + type_uaddr = $_type + description_auddr = $_description + payload_uaddr = $_payload + plen = $plen + ringid = $ringid + argstr = sprintf("%s, %s, %s, %d, %d", + user_string_quoted($_type), + user_string_quoted($_description), + text_strn(user_string($_payload),syscall_string_trunc,1), + $plen, $ringid) +} +probe nd_syscall.add_key.return = kernel.function("sys_add_key").return ? { + name = "add_key" + retstr = returnstr(1) +} + +# adjtimex ___________________________________________________ +# long sys_adjtimex(struct timex __user *txc_p) +probe nd_syscall.adjtimex = kernel.function("sys_adjtimex") { + name = "adjtimex" + + /* + * buf_offset = __uget_timex_m($txc_p,1) + * buf_freq = __uget_timex_m($txc_p,2) + * buf_maxerror = __uget_timex_m($txc_p,3) + * buf_esterror = __uget_timex_m($txc_p,4) + * buf_status = __uget_timex_m($txc_p,5) + * buf_constant = __uget_timex_m($txc_p,6) + * buf_precision = __uget_timex_m($txc_p,7) + * buf_tolerance = __uget_timex_m($txc_p,8) + * buf_time_tv_sec = __uget_timex_m($txc_p,9) + * buf_time_tv_usec = __uget_timex_m($txc_p,10) + * buf_tick = __uget_timex_m($txc_p,11) + */ + argstr = sprintf("%p", $txc_p) +} +probe nd_syscall.adjtimex.return = kernel.function("sys_adjtimex").return { + name = "adjtimex" + retstr = _adjtimex_return_str($return) +} +# long compat_sys_adjtimex(struct compat_timex __user *utp) +probe nd_syscall.compat_adjtimex = kernel.function("compat_sys_adjtimex") ? { + name = "compat_adjtimex" + argstr = sprintf("%p", $utp) +} +probe nd_syscall.compat_adjtimex.return = kernel.function("compat_sys_adjtimex").return ? { + name = "compat_adjtimex" + retstr = returnstr(1) +} + +# alarm ______________________________________________________ +# unsigned long sys_alarm (unsigned int seconds) +# long sys32_alarm(unsigned int seconds) +# +probe nd_syscall.alarm = + kernel.function("sys_alarm") ?, + kernel.function("sys32_alarm") ? +{ + name = "alarm" + seconds = $seconds + argstr = sprint($seconds) +} +probe nd_syscall.alarm.return = + kernel.function("sys_alarm").return ?, + kernel.function("sys32_alarm").return ? +{ + name = "alarm" + retstr = returnstr(1) +} + +# bdflush ____________________________________________________ +# long sys_bdflush(int func,long data) +probe nd_syscall.bdflush = kernel.function("sys_bdflush") ? { + name = "bdflush" + func = $func + data = $data + if (($func>=2)&&($func%2==0)) + data_str = sprintf("%p", $data) + else + data_str = sprintf("%d", $data) + argstr = sprintf("%d, %s",func, data_str) +} +probe nd_syscall.bdflush.return = kernel.function("sys_bdflush").return ? { + name = "bdflush" + retstr = returnstr(1) +} + +# bind _______________________________________________________ +# long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) +probe nd_syscall.bind = kernel.function("sys_bind") ? { + name = "bind" + sockfd = $fd + my_addr_uaddr = $umyaddr + addrlen = $addrlen + argstr = sprintf("%d, %s, %d", $fd, _struct_sockaddr_u($umyaddr,$addrlen),$addrlen) +} +probe nd_syscall.bind.return = kernel.function("sys_bind").return ? { + name = "bind" + retstr = returnstr(1) +} + +# brk ________________________________________________________ +# unsigned long sys_brk(unsigned long brk) +probe nd_syscall.brk = + kernel.function("sys_brk"), + kernel.function("ia64_brk") ? +{ + name = "brk" + brk = $brk + argstr = sprintf("%p", brk) +} +probe nd_syscall.brk.return = + kernel.function("sys_brk").return, + kernel.function("ia64_brk").return ? +{ + name = "brk" + retstr = returnstr(1) +} + +# capget _____________________________________________________ +/* + * NOTE + * this is probably not a good function + * to probe. The structures are always + * changing. It also seems like it is + * not really used. Cscope produced no + * reference of this function in the + * kernel (returned no callers). Perhaps + * cap_get_proc / cap_set_proc are better + * functions to export. + */ +# long sys_capget(cap_user_header_t header, cap_user_data_t dataptr) +probe nd_syscall.capget = kernel.function("sys_capget") { + name = "capget" + header_uaddr = $header + data_uaddr = $dataptr + argstr = sprintf("%p, %p", $header, $dataptr) +} +probe nd_syscall.capget.return = kernel.function("sys_capget").return { + name = "capget" + retstr = returnstr(1) +} +# capset _____________________________________________________ +/* + * NOTE + * this is probably not a good function + * to probe. The structures are always + * changing. It also seems like it is + * not really used. Cscope produced no + * reference of this function in the + * kernel (returned no callers). Perhaps + * cap_get_proc / cap_set_proc are better + * functions to export. + */ +# long sys_capset(cap_user_header_t header, const cap_user_data_t data) +probe nd_syscall.capset = kernel.function("sys_capset") { + name = "capset" + header_uaddr = $header + data_uaddr = $data + argstr = sprintf("%p, %p", $header, $data) +} +probe nd_syscall.capset.return = kernel.function("sys_capset").return { + name = "capset" + retstr = returnstr(1) +} + +# chdir ______________________________________________________ +# long sys_chdir(const char __user * filename) +probe nd_syscall.chdir = kernel.function("sys_chdir") { + name = "chdir" + path = user_string($filename) + argstr = user_string_quoted($filename) +} +probe nd_syscall.chdir.return = kernel.function("sys_chdir").return { + name = "chdir" + retstr = returnstr(1) +} + +# chmod ______________________________________________________ +# long sys_chmod(const char __user * filename, mode_t mode) +probe nd_syscall.chmod = kernel.function("sys_chmod") { + name = "chmod" + path = user_string($filename) + mode = $mode + argstr = sprintf("%s, %#o", user_string_quoted($filename), mode) +} +probe nd_syscall.chmod.return = kernel.function("sys_chmod").return { + name = "chmod" + retstr = returnstr(1) +} + +# chown ______________________________________________________ +# long sys_chown(const char __user * filename, uid_t user, gid_t group) +probe nd_syscall.chown = kernel.function("sys_chown") { + name = "chown" + path = user_string($filename) + owner = __int32($user) + group = __int32($group) + argstr = sprintf("%s, %d, %d",user_string_quoted($filename), owner, group) +} +probe nd_syscall.chown.return = kernel.function("sys_chown").return { + name = "chown" + retstr = returnstr(1) +} +# chown16 ___________________________________________________ +# long sys_chown16(const char __user * filename, old_uid_t user, +# old_gid_t group) +# +probe nd_syscall.chown16 = kernel.function("sys_chown16") ? { + name = "chown16" + path = user_string($filename) + owner = __short($user) + group = __short($group) + argstr = sprintf("%s, %d, %d", user_string_quoted($filename), owner, group) +} +probe nd_syscall.chown16.return = kernel.function("sys_chown16").return ? { + name = "chown16" + retstr = returnstr(1) +} + +# chroot _____________________________________________________ +# long sys_chroot(const char __user * filename) +probe nd_syscall.chroot = kernel.function("sys_chroot") { + name = "chroot" + path = user_string($filename) + argstr = user_string_quoted($filename) +} +probe nd_syscall.chroot.return = kernel.function("sys_chroot").return { + name = "chroot" + retstr = returnstr(1) +} + +# clock_getres _______________________________________________ +# long sys_clock_getres(clockid_t which_clock, struct timespec __user *tp) +# long compat_clock_getres(clockid_t which_clock, struct compat_timespec __user *tp) +# +probe nd_syscall.clock_getres = + kernel.function("sys_clock_getres"), + kernel.function("compat_clock_getres") ? +{ + name = "clock_getres" + clk_id = $which_clock + clk_id_str = _get_wc_str($which_clock) + res_uaddr = $tp + argstr = sprintf("%s, %p", _get_wc_str($which_clock), $tp) +} +probe nd_syscall.clock_getres.return = + kernel.function("sys_clock_getres").return, + kernel.function("compat_clock_getres").return ? +{ + name = "clock_getres" + retstr = returnstr(1) +} + +# clock_gettime ______________________________________________ +# long sys_clock_gettime(clockid_t which_clock, struct timespec __user *tp) +# +probe nd_syscall.clock_gettime = + kernel.function("sys_clock_gettime") +{ + name = "clock_gettime" + clk_id = $which_clock + clk_id_str = _get_wc_str($which_clock) + argstr = sprintf("%s, %p", _get_wc_str($which_clock), $tp) +} +probe nd_syscall.clock_gettime.return = kernel.function("sys_clock_gettime").return +{ + name = "clock_gettime" + retstr = returnstr(1) +} + +# clock_nanosleep ____________________________________________ +# long sys_clock_nanosleep(clockid_t which_clock, +# int flags, +# const struct timespec __user *rqtp, +# struct timespec __user *rmtp) +# +probe nd_syscall.clock_nanosleep = kernel.function("sys_clock_nanosleep") { + name = "clock_nanosleep" + if ($flags == 1) + flag_str = "TIMER_ABSTIME" + else + flag_str = sprintf("0x%x", $flags) + argstr = sprintf("%s, %s, %s, %p", _get_wc_str($which_clock), flag_str, + _struct_timespec_u($rqtp,1), $rmtp) +} +probe nd_syscall.clock_nanosleep.return = kernel.function("sys_clock_nanosleep").return { + name = "clock_nanosleep" + retstr = returnstr(1) +} +# compat_clock_nanosleep ________________________________________ +# +# long compat_clock_nanosleep(clockid_t which_clock, int flags, +# struct compat_timespec __user *rqtp, +# struct compat_timespec __user *rmtp) +# +probe nd_syscall.compat_clock_nanosleep = + kernel.function("compat_clock_nanosleep") ?, + kernel.function("compat_sys_clock_nanosleep") ? +{ + name = "compat_clock_nanosleep" + if ($flags == 1) + flag_str = "TIMER_ABSTIME" + else + flag_str = sprintf("0x%x", $flags) + argstr = sprintf("%s, %s, %s, %p", _get_wc_str($which_clock), flag_str, + _struct_compat_timespec_u($rqtp,1), $rmtp) +} +probe nd_syscall.compat_clock_nanosleep.return = + kernel.function("compat_clock_nanosleep").return ?, + kernel.function("compat_sys_clock_nanosleep").return ? +{ + name = "compat_clock_nanosleep" + retstr = returnstr(1) +} + +# clock_settime ______________________________________________ +# long sys_clock_settime(clockid_t which_clock, +# const struct timespec __user *tp) +# +probe nd_syscall.clock_settime = kernel.function("sys_clock_settime") { + name = "clock_settime" + clk_id = $which_clock + clk_id_str = _get_wc_str($which_clock) + tp_uaddr = $tp + argstr = sprintf("%s, %s", clk_id_str, _struct_timespec_u($tp,1)) +} +probe nd_syscall.clock_settime.return = kernel.function("sys_clock_settime").return { + name = "clock_settime" + retstr = returnstr(1) +} + +# close ______________________________________________________ +# long sys_close(unsigned int fd) +probe nd_syscall.close = kernel.function("sys_close") { + name = "close" + // fd = $fd + asmlinkage() + fd = int_arg(1) + argstr = sprint(fd) +} +probe nd_syscall.close.return = kernel.function("sys_close").return { + name = "close" + retstr = returnstr(1) +} +# connect ____________________________________________________ +# long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen) +probe nd_syscall.connect = kernel.function("sys_connect") ? { + name = "connect" + sockfd = $fd + serv_addr_uaddr = $uservaddr + addrlen = $addrlen + argstr = sprintf("%d, %s, %d", $fd, _struct_sockaddr_u($uservaddr,$addrlen),$addrlen) +} +probe nd_syscall.connect.return = kernel.function("sys_connect").return ? { + name = "connect" + retstr = returnstr(1) +} + +# creat +# long sys_creat(const char __user * pathname, int mode) +probe nd_syscall.creat = kernel.function("sys_creat") ? +{ + name = "creat" + mode = $mode + pathname = user_string($pathname) + argstr = sprintf("%s, %#o", user_string_quoted($pathname), $mode) +} +probe nd_syscall.creat.return = kernel.function("sys_creat").return ? +{ + name = "creat" + retstr = returnstr(1) +} + +# delete_module ______________________________________________ +# long sys_delete_module(const char __user *name_user, unsigned int flags) +probe nd_syscall.delete_module = kernel.function("sys_delete_module") ? { + name = "delete_module" + name_user = user_string($name_user) + flags = $flags + argstr = sprintf("%s, %s", user_string_quoted($name_user), _module_flags_str($flags)) +} +probe nd_syscall.delete_module.return = kernel.function("sys_delete_module").return ? { + name = "delete_module" + retstr = returnstr(1) +} + +# dup ________________________________________________________ +# long sys_dup(unsigned int fildes) +probe nd_syscall.dup = kernel.function("sys_dup") { + name = "dup" + // oldfd = $fildes + // argstr = sprint($fildes) + asmlinkage() + old_fd = int_arg(1) + argstr = sprint(old_fd) +} +probe nd_syscall.dup.return = kernel.function("sys_dup").return { + name = "dup" + retstr = returnstr(1) +} + +# dup2 _______________________________________________________ +# long sys_dup2(unsigned int oldfd, unsigned int newfd) +probe nd_syscall.dup2 = kernel.function("sys_dup2") { + name = "dup2" + oldfd = $oldfd + newfd = $newfd + argstr = sprintf("%d, %d", $oldfd, $newfd) +} +probe nd_syscall.dup2.return = kernel.function("sys_dup2").return { + name = "dup2" + retstr = returnstr(1) +} + +# epoll_create _______________________________________________ +# long sys_epoll_create(int size) +probe nd_syscall.epoll_create = kernel.function("sys_epoll_create") ? { + name = "epoll_create" + size = $size + argstr = sprint($size) +} +probe nd_syscall.epoll_create.return = kernel.function("sys_epoll_create").return ? { + name = "epoll_create" + retstr = returnstr(1) +} + +# epoll_ctl __________________________________________________ +# +# long sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event) +# long compat_sys_epoll_ctl(int epfd, int op, int fd, +# struct compat_epoll_event __user *event) +# +probe nd_syscall.epoll_ctl = + kernel.function("sys_epoll_ctl") ?, + kernel.function("compat_sys_epoll_ctl") ? +{ + name = "epoll_ctl" + epfd = $epfd + op = $op + op_str = _opoll_op_str($op) + fd = $fd + event_uaddr = $event + argstr = sprintf("%d, %s, %d, %p", $epfd, _opoll_op_str($op), $fd, $event) +} +probe nd_syscall.epoll_ctl.return = + kernel.function("sys_epoll_ctl").return ?, + kernel.function("compat_sys_epoll_ctl").return ? +{ + name = "epoll_ctl" + retstr = returnstr(1) +} + +# epoll_pwait _________________________________________________ +# +# long sys_epoll_pwait(int epfd, struct epoll_event __user *events, +# int maxevents, int timeout, const sigset_t __user *sigmask, +# size_t sigsetsize) +# long compat_sys_epoll_pwait(int epfd, +# struct compat_epoll_event __user *events, +# int maxevents, int timeout, +# const compat_sigset_t __user *sigmask, +# compat_size_t sigsetsize) +# +probe nd_syscall.epoll_pwait = + kernel.function("sys_epoll_pwait") ?, + kernel.function("compat_sys_epoll_pwait") ? +{ + name = "epoll_pwait" + argstr = sprintf("%d, %p, %d, %d, %p, %d", + $epfd, $events, $maxevents, $timeout, $sigmask, $sigsetsize) +} +probe nd_syscall.epoll_pwait.return = + kernel.function("sys_epoll_pwait").return ?, + kernel.function("compat_sys_epoll_pwait").return ? +{ + name = "epoll_pwait" + retstr = returnstr(1) +} + +# epoll_wait _________________________________________________ +# +# long sys_epoll_wait(int epfd, struct epoll_event __user *events, +# int maxevents, int timeout) +# long compat_sys_epoll_wait(int epfd, +# struct compat_epoll_event __user *events, +# int maxevents, int timeout) +# +probe nd_syscall.epoll_wait = + kernel.function("sys_epoll_wait") ?, + kernel.function("compat_sys_epoll_wait") ? +{ + name = "epoll_wait" + epfd = $epfd + events_uaddr = $events + maxevents = $maxevents + timeout = $timeout + argstr = sprintf("%d, %p, %d, %d", $epfd, $events, $maxevents, $timeout) +} +probe nd_syscall.epoll_wait.return = + kernel.function("sys_epoll_wait").return ?, + kernel.function("compat_sys_epoll_wait").return ? +{ + name = "epoll_wait" + retstr = returnstr(1) +} + +# eventfd _____________________________________________________ +# long sys_eventfd(unsigned int count) +# +probe nd_syscall.eventfd = kernel.function("sys_eventfd") ? { + name = "eventfd" + argstr = sprint($count) +} +probe nd_syscall.eventfd.return = kernel.function("sys_eventfd").return ? { + name = "eventfd" + retstr = returnstr(1) +} + +# execve _____________________________________________________ +# int sys_execve(struct pt_regs regs) +# which breaks out the args and immediately calls +# int do_execve(char * filename, +# char __user *__user *argv, +# char __user *__user *envp, +# struct pt_regs * regs) +probe nd_syscall.execve = kernel.function("do_execve") { + name = "execve" + // filename = kernel_string($filename) + // args = __get_argv($argv, 0) + // argstr = sprintf("%s %s", filename, __get_argv($argv, 1)) + filename = kernel_string(pointer_arg(1)) + args = __get_argv(pointer_arg(2), 0) + argstr = sprintf("%s %s", filename, __get_argv(pointer_arg(2), 1)) +} +# v2.6.15-rc2 or earlier has problems with sys_execve return probes +# another reason to probe on do_execve +probe nd_syscall.execve.return = kernel.function("do_execve").return { + name = "execve" + retstr = returnstr(1) +} +# int compat_do_execve(char * filename, +# compat_uptr_t __user *argv, +# compat_uptr_t __user *envp, +# struct pt_regs * regs) +probe nd_syscall.compat_execve = kernel.function("compat_do_execve") ? { + name = "compat_execve" + filename = kernel_string($filename) + args = __get_compat_argv($argv, 0) + argstr = sprintf("%s %s", filename, __get_compat_argv($argv, 1)) +} +probe nd_syscall.compat_execve.return = kernel.function("compat_do_execve").return ? { + name = "compat_execve" + retstr = returnstr(1) +} + +# exit _______________________________________________________ +# long sys_exit(int error_code) +probe nd_syscall.exit = kernel.function("do_exit") { + name = "exit" + status = $code + argstr = sprint($code) +} +probe nd_syscall.exit.return = end {} + +# exit_group _________________________________________________ +# void sys_exit_group(int error_code) +# +probe nd_syscall.exit_group = kernel.function("sys_exit_group") { + name = "exit_group" + status = $error_code + argstr = sprint($error_code) +} + +probe nd_syscall.exit_group.return = end {} + +%(arch != "x86_64" %? +# fadvise64 __________________________________________________ +# long sys_fadvise64(int fd, loff_t offset, size_t len, int advice) +# +probe nd_syscall.fadvise64 = kernel.function("sys_fadvise64") ? { + name = "fadvise64" + fs = $fd + offset = $offset + len = $len + advice = $advice + argstr = sprintf("%d, %d, %d, %s", $fd, $offset, $len, _fadvice_advice_str($advice)) +} +probe nd_syscall.fadvise64.return = kernel.function("sys_fadvise64").return ? { + name = "fadvise64" + retstr = returnstr(1) +} + +# fadvise64_64 _______________________________________________ +# long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) +# +probe nd_syscall.fadvise64_64 = kernel.function("sys_fadvise64_64") { + name = "fadvise64_64" + fs = $fd + offset = $offset + len = $len + advice = $advice + argstr = sprintf("%d, %d, %d, %s", $fd, $offset, $len, _fadvice_advice_str($advice)) +} +probe nd_syscall.fadvise64_64.return = kernel.function("sys_fadvise64_64").return { + name = "fadvise64_64" + retstr = returnstr(1) +} +%: +# FIXME x86_64 has problems resolving parameters + +# fadvise64 __________________________________________________ +# long sys_fadvise64(int fd, loff_t offset, size_t len, int advice) +# +probe nd_syscall.fadvise64 = kernel.function("sys_fadvise64") { + name = "fadvise64" + fs = 0 + offset = 0 + len = 0 + advice = 0 + argstr = "" +} +probe nd_syscall.fadvise64.return = kernel.function("sys_fadvise64").return { + name = "fadvise64" + retstr = returnstr(1) +} + +# fadvise64_64 _______________________________________________ +# long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) +# +probe nd_syscall.fadvise64_64 = kernel.function("sys_fadvise64_64") { + name = "fadvise64_64" + fs = 0 + offset = 0 + len = 0 + advice = 0 + argstr = "" +} +probe nd_syscall.fadvise64_64.return = kernel.function("sys_fadvise64_64").return { + name = "fadvise64_64" + retstr = returnstr(1) +} +%) + +# fchdir _____________________________________________________ +# long sys_fchdir(unsigned int fd) +probe nd_syscall.fchdir = kernel.function("sys_fchdir") { + name = "fchdir" + fd = $fd + argstr = sprint($fd) +} +probe nd_syscall.fchdir.return = kernel.function("sys_fchdir").return { + name = "fchdir" + retstr = returnstr(1) +} + +# fchmod _____________________________________________________ +# long sys_fchmod(unsigned int fd, mode_t mode) +probe nd_syscall.fchmod = kernel.function("sys_fchmod") { + name = "fchmod" + fildes = $fd + mode = $mode + argstr = sprintf("%d, %#o", $fd, $mode) +} +probe nd_syscall.fchmod.return = kernel.function("sys_fchmod").return { + name = "fchmod" + retstr = returnstr(1) +} + +# fchown _____________________________________________________ +# long sys_fchown(unsigned int fd, uid_t user, gid_t group) +probe nd_syscall.fchown = kernel.function("sys_fchown") { + name = "fchown" + fd = $fd + owner = __int32($user) + group = __int32($group) + argstr = sprintf("%d, %d, %d", $fd, owner, group) +} +probe nd_syscall.fchown.return = kernel.function("sys_fchown").return { + name = "fchown" + retstr = returnstr(1) +} + +# fchown16 ___________________________________________________ +# long sys_fchown16(unsigned int fd, old_uid_t user, old_gid_t group) +probe nd_syscall.fchown16 = kernel.function("sys_fchown16") ? { + name = "fchown16" + fd = $fd + owner = __short($user) + group = __short($group) + argstr = sprintf("%d, %d, %d", $fd, owner, group) +} +probe nd_syscall.fchown16.return = kernel.function("sys_fchown16").return ? { + name = "fchown16" + retstr = returnstr(1) +} + +# fcntl ______________________________________________________ +# long sys_fcntl(int fd, unsigned int cmd, unsigned long arg) +# long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) +# long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) +# long compat_sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) +# +probe nd_syscall.fcntl = + kernel.function("sys_fcntl") ?, + kernel.function("sys_fcntl64") ?, + kernel.function("compat_sys_fcntl") ?, + kernel.function("compat_sys_fcntl64") ? +{ + name = "fcntl" + fd = $fd + cmd = $cmd + cmd_str = _fcntl_cmd_str($cmd) + arg = $arg + argstr = sprintf("%d, %s, %p", $fd, _fcntl_cmd_str($cmd), $arg) +} +probe nd_syscall.fcntl.return = + kernel.function("sys_fcntl").return ?, + kernel.function("sys_fcntl64").return ?, + kernel.function("compat_sys_fcntl").return ?, + kernel.function("compat_sys_fcntl64").return ? +{ + name = "fcntl" + retstr = returnstr(1) +} + +# fdatasync __________________________________________________ +# long sys_fdatasync(unsigned int fd) +probe nd_syscall.fdatasync = kernel.function("sys_fdatasync") { + name = "fdatasync" + fd = $fd + argstr = sprint(fd) +} +probe nd_syscall.fdatasync.return = kernel.function("sys_fdatasync").return { + name = "fdatasync" + retstr = returnstr(1) +} + +# fgetxattr __________________________________________________ +# ssize_t sys_fgetxattr(int fd, char __user *name, +# void __user *value, size_t size) +probe nd_syscall.fgetxattr = kernel.function("sys_fgetxattr") { + name = "fgetxattr" + filedes = $fd +#FIXME + name2 = user_string($name) + value_uaddr = $value + size = $size + argstr = sprintf("%d, %s, %p, %d", filedes, user_string_quoted($name), value_uaddr, size) +} +probe nd_syscall.fgetxattr.return = kernel.function("sys_fgetxattr").return { + name = "fgetxattr" + retstr = returnstr(1) +} +# flistxattr _________________________________________________ +# ssize_t sys_flistxattr(int fd, char __user *list, size_t size) +probe nd_syscall.flistxattr = kernel.function("sys_flistxattr") { + name = "flistxattr" + filedes = $fd + list_uaddr = $list + size = $size + argstr = sprintf("%d, %p, %d", filedes, list_uaddr, size) +} +probe nd_syscall.flistxattr.return = kernel.function("sys_flistxattr").return { + name = "flistxattr" + retstr = returnstr(1) +} + +# flock ______________________________________________________ +# long sys_flock(unsigned int fd, unsigned int cmd) +probe nd_syscall.flock = kernel.function("sys_flock") { + name = "flock" + fd = $fd + operation = $cmd + argstr = sprintf("%d, %s", fd, _flock_cmd_str(operation)) +} +probe nd_syscall.flock.return = kernel.function("sys_flock").return { + name = "flock" + retstr = returnstr(1) +} + +function __is_user_regs:long (regs:long) %{ /* pure */ + struct pt_regs * regs = (void *)((unsigned long)THIS->regs); +/* copied from asm/ptrace.h */ +#if defined(__i386__) +#ifdef STAPCONF_X86_UNIREGS + int cs = kread(®s->cs); +#else + int cs = kread(®s->xcs); +#endif + THIS->__retvalue = (!!((cs & 3))); +#elif defined(__x86_64__) + unsigned long cs = kread(®s->cs); + THIS->__retvalue = (!!((cs & 3))); +#elif defined(__ia64__) + unsigned long psr = kread(®s->cr_ipsr); + THIS->__retvalue = (((struct ia64_psr *) &psr)->cpl != 0); +#elif defined(__powerpc64__) + unsigned long msr = kread(®s->msr); + THIS->__retvalue = ((msr >> MSR_PR_LG) & 0x1); +#elif defined(__arm__) + long cpsr = kread(®s->ARM_cpsr); + THIS->__retvalue = ((cpsr & 0xf) == 0); +#elif defined(__s390__) || defined(__s390x__) + unsigned long mask = kread(®s->psw.mask); + THIS->__retvalue = ((mask & PSW_MASK_PSTATE) != 0); +#else +#error "Unimplemented architecture" +#endif +CATCH_DEREF_FAULT(); +%} + +# fork _______________________________________________________ +# long do_fork(unsigned long clone_flags, +# unsigned long stack_start, +# struct pt_regs *regs, +# unsigned long stack_size, +# int __user *parent_tidptr, +# int __user *child_tidptr) +probe nd_syscall.fork = kernel.function("do_fork") { + // clone_flags = $clone_flags + // stack_start = $stack_start + // regs = $regs + // stack_size = $stack_size + // parent_tid_uaddr = $parent_tidptr + // child_tid_uaddr = $child_tidptr + clone_flags = ulong_arg(1) + stack_start = ulong_arg(2) + regs = pointer_arg(3) + stack_size = ulong_arg(4) + parent_tid_uaddr = pointer_arg(5) + child_tid_uaddr = pointer_arg(6) + + if (!__is_user_regs(regs)) { + name = "fork_kernel_thread" + argstr = __fork_flags(clone_flags) + } else if (clone_flags == 17) + name = "fork" + else if (clone_flags & 0x4000) + name = "vfork" + else { + name = "clone" + argstr = __fork_flags(clone_flags) + } +} +probe nd_syscall.fork.return = kernel.function("do_fork").return { + name = "fork" + retstr = returnstr(1) +} +# fremovexattr _______________________________________________ +# long sys_fremovexattr(int fd, char __user *name) +probe nd_syscall.fremovexattr = kernel.function("sys_fremovexattr") { + name = "fremovexattr" + filedes = $fd + name_uaddr = $name + argstr = sprintf("FIXME PLEASE") +} +probe nd_syscall.fremovexattr.return = kernel.function("sys_fremovexattr").return { + name = "fremovexattr" + retstr = returnstr(1) +} + +# fsetxattr __________________________________________________ +/* + * asmlinkage long + * sys_fsetxattr(int fd, + * char __user *name, + * void __user *value, + * size_t size, + * int flags) + */ +probe nd_syscall.fsetxattr = kernel.function("sys_fsetxattr") { + name = "fsetxattr" + filedes = $fd +# FIXME + name2 = user_string($name) + value_uaddr = $value + size = $size + flags = $flags + argstr = sprintf("%d, %s, %p, %d, %p", filedes, user_string_quoted($name), value_uaddr, size, flags) +} +probe nd_syscall.fsetxattr.return = kernel.function("sys_fsetxattr").return { + name = "fsetxattr" + retstr = returnstr(1) +} + +# fstat ______________________________________________________ +# long sys_fstat(unsigned int fd, struct __old_kernel_stat __user * statbuf) +# long sys_fstat64(unsigned long fd, struct stat64 __user * statbuf) +# long sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf) +# long sys_newfstat(unsigned int fd, struct stat __user * statbuf) +# long sys_oabi_fstat64(char __user * filename, +# struct oldabi_stat64 __user * statbuf) +# long compat_sys_newfstat(unsigned int fd, struct compat_stat __user * statbuf) +# +probe nd_syscall.fstat = + kernel.function("sys_fstat") ?, + kernel.function("sys_fstat64") ?, + kernel.function("sys32_fstat64") ?, + kernel.function("sys_newfstat") ?, + kernel.function("sys_oabi_fstat64") ?, + kernel.function("compat_sys_newfstat") ? +{ + name = "fstat" + filedes = $fd + buf_uaddr = $statbuf + argstr = sprintf("%d, %p", $fd, $statbuf) +} +probe nd_syscall.fstat.return = + kernel.function("sys_fstat").return ?, + kernel.function("sys_fstat64").return ?, + kernel.function("sys32_fstat64").return ?, + kernel.function("sys_newfstat").return ?, + kernel.function("sys_oabi_fstat64").return ?, + kernel.function("compat_sys_newfstat").return ? +{ + name = "fstat" + retstr = returnstr(1) +} + +# fstatat ____________________________________________________ +# sys32_fstatat64(unsigned int dfd, char __user *filename, struct stat64_emu31 __user* statbuf, int flag) +# long sys_newfstatat(int dfd, char __user *filename, struct stat __user *statbuf, int flag) +# long sys_fstatat64(int dfd, char __user *filename, struct stat64 __user *statbuf, int flag) +# long compat_sys_newfstatat(unsigned int dfd, char __user *filename, struct compat_stat __user *statbuf, int flag) +probe nd_syscall.fstatat = + kernel.function("sys_fstatat64") ?, + kernel.function("sys_newfstatat") ?, + kernel.function("compat_sys_newfstatat") ?, + kernel.function("sys32_fstatat64") ? +{ + name = "fstatat" + dirfd = $dfd + path = user_string($filename) + buf_uaddr = $statbuf + argstr = sprintf("%s, %s, %p, %s", _dfd_str($dfd), user_string_quoted($filename), $statbuf, _at_flag_str($flag)) +} +probe nd_syscall.fstatat.return = + kernel.function("sys_fstatat64").return ?, + kernel.function("sys_newfstatat").return ?, + kernel.function("compat_sys_newfstatat").return ?, + kernel.function("sys32_fstatat64").return ? +{ + name = "fstatat" + retstr = returnstr(1) +} + +# fstatfs ____________________________________________________ +# long sys_fstatfs(unsigned int fd, struct statfs __user * buf) +# long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf) +# +probe nd_syscall.fstatfs = + kernel.function("sys_fstatfs"), + kernel.function("compat_sys_fstatfs") ? +{ + name = "fstatfs" + fd = $fd + buf_uaddr = $buf + argstr = sprintf("%d, %p", $fd, $buf) +} +probe nd_syscall.fstatfs.return = + kernel.function("sys_fstatfs").return, + kernel.function("compat_sys_fstatfs").return ? +{ + name = "fstatfs" + retstr = returnstr(1) +} + +# fstatfs64 __________________________________________________ +# long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user *buf) +# long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user *buf) +# +probe nd_syscall.fstatfs64 = + kernel.function("sys_fstatfs64") ?, + kernel.function("compat_sys_fstatfs64") ? +{ + name = "fstatfs" + fd = $fd + sz = $sz + buf_uaddr = $buf + argstr = sprintf("%d, %d, %p", $fd, $sz, $buf) +} +probe nd_syscall.fstatfs64.return = + kernel.function("sys_fstatfs64").return ?, + kernel.function("compat_sys_fstatfs64").return ? +{ + name = "fstatfs" + retstr = returnstr(1) +} + +# fsync ______________________________________________________ +# long sys_fsync(unsigned int fd) +probe nd_syscall.fsync = kernel.function("sys_fsync") { + name = "fsync" + fd = $fd + argstr = sprint(fd) +} +probe nd_syscall.fsync.return = kernel.function("sys_fsync").return { + name = "fsync" + retstr = returnstr(1) +} +# ftruncate __________________________________________________ +# long sys_ftruncate(unsigned int fd, unsigned long length) +probe nd_syscall.ftruncate = kernel.function("sys_ftruncate") { + name = "ftruncate" + fd = $fd + length = $length + argstr = sprintf("%d, %d", fd, length) +} +probe nd_syscall.ftruncate.return = kernel.function("sys_ftruncate").return { + name = "ftruncate" + retstr = returnstr(1) +} + +# ftruncate64 ________________________________________________ +# long sys_ftruncate64(unsigned int fd, loff_t length) +probe nd_syscall.ftruncate64 = kernel.function("sys_ftruncate64") ? { + name = "ftruncate" + fd = $fd + length = $length + argstr = sprintf("%d, %d", fd, length) +} +probe nd_syscall.ftruncate64.return = kernel.function("sys_ftruncate64").return ? { + name = "ftruncate" + retstr = returnstr(1) +} + +# futex ______________________________________________________ +# long sys_futex(u32 __user *uaddr, +# int op, +# int val, +# struct timespec __user *utime, +# u32 __user *uaddr2, +# int val3) +# long compat_sys_futex(u32 __user *uaddr, int op, u32 val, +# struct compat_timespec __user *utime, u32 __user *uaddr2, +# u32 val3) +# +probe nd_syscall.futex = kernel.function("sys_futex") ? { + name = "futex" + futex_uaddr = $uaddr + op = $op + val = $val + utime_uaddr = $utime + uaddr2_uaddr = $uaddr2 + val3 = $val3 + if (op == 0) + argstr = sprintf("%p, %s, %d, %s", $uaddr, _futex_op_str($op), + $val, _struct_timespec_u($utime,1)) + else + argstr = sprintf("%p, %s, %d", $uaddr, _futex_op_str($op), + $val) +} +probe nd_syscall.futex.return = kernel.function("sys_futex").return ? { + name = "futex" + retstr = returnstr(1) +} +probe nd_syscall.compat_futex = kernel.function("compat_sys_futex") ? { + name = "futex" + futex_uaddr = $uaddr + op = $op + val = $val + utime_uaddr = $utime + uaddr2_uaddr = $uaddr2 + val3 = $val3 + if (op == 0) + argstr = sprintf("%p, %s, %d, %s", $uaddr, _futex_op_str($op), + $val, _struct_compat_timespec_u($utime,1)) + else + argstr = sprintf("%p, %s, %d", $uaddr, _futex_op_str($op), + $val) +} +probe nd_syscall.compat_futex.return = kernel.function("compat_sys_futex").return ? { + name = "futex" + retstr = returnstr(1) +} + +# futimesat _____________________________________________________ +# +# long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes) +# long compat_sys_futimesat(unsigned int dfd, char __user *filename, struct compat_timeval __user *t) +# + +probe nd_syscall.futimesat = kernel.function("sys_futimesat") ? { + name = "futimesat" + dirfd = $dfd + filename_uaddr = $filename + filename = user_string($filename) + tvp_uaddr = $utimes + argstr = sprintf("%s, %s, %s", _dfd_str($dfd), user_string_quoted($filename), + _struct_timeval_u($utimes, 2)) +} +probe nd_syscall.compat_futimesat = kernel.function("compat_sys_futimesat") ? { + name = "futimesat" + dirfd = $dfd + filename_uaddr = $filename + filename = user_string($filename) + tvp_uaddr = $t + argstr = sprintf("%s, %s, %s", _dfd_str($dfd), user_string_quoted($filename), + _struct_compat_timeval_u($t, 2)) +} +probe nd_syscall.futimesat.return = kernel.function("sys_futimesat").return ? { + name = "futimesat" + retstr = returnstr(1) +} +probe nd_syscall.compat_futimesat.return = kernel.function("compat_sys_futimesat").return ? { + name = "futimesat" + retstr = returnstr(1) +} + +# getcwd _____________________________________________________ +# long sys_getcwd(char __user *buf, unsigned long size) +probe nd_syscall.getcwd = kernel.function("sys_getcwd") { + name = "getcwd" + buf_uaddr = $buf + size = $size + argstr = sprintf("%p, %d", buf_uaddr, size) +} +probe nd_syscall.getcwd.return = kernel.function("sys_getcwd").return { + name = "getcwd" + retstr = returnstr(1) +} + +# getdents ___________________________________________________ +# long sys_getdents(unsigned int fd, struct linux_dirent __user * dirent, unsigned int count) +# long compat_sys_getdents(unsigned int fd,struct compat_linux_dirent __user *dirent, unsigned int count) +# long sys_getdents64(unsigned int fd, struct linux_dirent64 __user * dirent, unsigned int count) +# long compat_sys_getdents64(unsigned int fd, struct linux_dirent64 __user * dirent, unsigned int count) +# +probe nd_syscall.getdents = + kernel.function("sys_getdents") ?, + kernel.function("sys_getdents64") ?, + kernel.function("compat_sys_getdents") ?, + kernel.function("compat_sys_getdents64") ? +{ + name = "getdents" + fd = $fd + dirp_uaddr = $dirent + count = $count + argstr = sprintf("%d, %p, %d", $fd, $dirent, $count) +} +probe nd_syscall.getdents.return = + kernel.function("sys_getdents").return ?, + kernel.function("sys_getdents64").return ?, + kernel.function("compat_sys_getdents").return ?, + kernel.function("compat_sys_getdents64").return ? +{ + name = "getdents" + retstr = returnstr(1) +} + +# getegid ____________________________________________________ +# long sys_getegid(void) +# long sys_getegid16(void) +# long sys32_getegid16(void) +# +probe nd_syscall.getegid = + kernel.function("sys_getegid16") ?, + kernel.function("sys32_getegid16") ?, + kernel.function("sys_getegid") +{ + name = "getegid" + argstr = "" +} +probe nd_syscall.getegid.return = + kernel.function("sys_getegid16").return ?, + kernel.function("sys32_getegid16").return ?, + kernel.function("sys_getegid").return +{ + name = "getegid" + retstr = returnstr(1) +} + +# geteuid ____________________________________________________ +# long sys_geteuid(void) +# long sys32_geteuid16(void) +# +probe nd_syscall.geteuid = + kernel.function("sys_geteuid16") ?, + kernel.function("sys32_geteuid16") ?, + kernel.function("sys_geteuid") +{ + name = "geteuid" + argstr = "" +} +probe nd_syscall.geteuid.return = + kernel.function("sys_geteuid16").return ?, + kernel.function("sys32_geteuid16").return ?, + kernel.function("sys_geteuid").return +{ + name = "geteuid" + retstr = returnstr(1) +} + +# getgid _____________________________________________________ +# long sys_getgid(void) +# long sys32_getgid16(void) +# +probe nd_syscall.getgid = + kernel.function("sys_getgid16") ?, + kernel.function("sys32_getgid16") ?, + kernel.function("sys_getgid") +{ + name = "getgid" + argstr = "" +} +probe nd_syscall.getgid.return = + kernel.function("sys_getgid16").return ?, + kernel.function("sys32_getgid16").return ?, + kernel.function("sys_getgid").return +{ + name = "getgid" + retstr = returnstr(1) +} + +# getgroups __________________________________________________ +# long sys_getgroups(int gidsetsize, gid_t __user *grouplist) +# long sys_getgroups16(int gidsetsize, old_gid_t __user *grouplist) +# long sys32_getgroups16(int gidsetsize, u16 __user *grouplist) +# +probe nd_syscall.getgroups = + kernel.function("sys_getgroups") ?, + kernel.function("sys_getgroups16") ?, + kernel.function("sys32_getgroups16") ? +{ + name = "getgroups" + size = $gidsetsize + list_uaddr = $grouplist + argstr = sprintf("%d, %p", $gidsetsize, $grouplist) +} +probe nd_syscall.getgroups.return = + kernel.function("sys_getgroups").return ?, + kernel.function("sys_getgroups16").return ?, + kernel.function("sys32_getgroups16").return ? +{ + name = "getgroups" + retstr = returnstr(1) +} + +# gethostname ________________________________________________ +# long sys_gethostname(char __user *name, int len) +probe nd_syscall.gethostname = kernel.function("sys_gethostname") ? { + name = "gethostname" + name_uaddr = $name + len = $len + argstr = sprintf ("%p, %d", name_uaddr, len) +} +probe nd_syscall.gethostname.return = kernel.function("sys_gethostname").return ? { + name = "gethostname" + retstr = returnstr(1) +} + +# getitimer __________________________________________________ +# sys_getitimer(int which, struct itimerval __user *value) +# +probe nd_syscall.getitimer = kernel.function("sys_getitimer") { + name = "getitimer" + which = $which + value_uaddr = $value + argstr = sprintf("%s, %p", _itimer_which_str($which), $value) +} +probe nd_syscall.getitimer.return = kernel.function("sys_getitimer").return { + name = "getitimer" + retstr = returnstr(1) +} +# long compat_sys_getitimer(int which, struct compat_itimerval __user *it +probe nd_syscall.compat_getitimer = kernel.function("compat_sys_getitimer") ? { + name = "getitimer" + which = $which + value_uaddr = $it + argstr = sprintf("%s, %p", _itimer_which_str($which), $it) +} +probe nd_syscall.compat_getitimer.return = kernel.function("compat_sys_getitimer").return ? { + name = "getitimer" + retstr = returnstr(1) +} + +# get_mempolicy ______________________________________________ +# long sys_get_mempolicy(int __user *policy, +# unsigned long __user *nmask, +# unsigned long maxnode, +# unsigned long addr, +# unsigned long flags) +# long compat_sys_get_mempolicy(int __user *policy, +# compat_ulong_t __user *nmask, +# compat_ulong_t maxnode, +# compat_ulong_t addr, compat_ulong_t flags) +# +probe nd_syscall.get_mempolicy = + kernel.function("sys_get_mempolicy") ?, + kernel.function("compat_sys_get_mempolicy") ? +{ + name = "get_mempolicy" + policy_uaddr = $policy + nmask_uaddr = $nmask + maxnode = $maxnode + addr = $addr + flags = $flags + argstr = sprintf("%p, %p, %d, %p, 0x%x", $policy, + $nmask, $maxnode, $addr, $flags) +} +probe nd_syscall.get_mempolicy.return = + kernel.function("sys_get_mempolicy").return ?, + kernel.function("compat_sys_get_mempolicy").return ? +{ + name = "get_mempolicy" + retstr = returnstr(1) +} + +# getpeername ________________________________________________ +# long sys_getpeername(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len) +# +probe nd_syscall.getpeername = kernel.function("sys_getpeername") ? { + name = "getpeername" + s = $fd + name_uaddr = $usockaddr + namelen_uaddr = $usockaddr_len + argstr = sprintf("%d, %p, %p", $fd, $usockaddr, $usockaddr_len) +} +probe nd_syscall.getpeername.return = kernel.function("sys_getpeername").return ? { + name = "getpeername" + retstr = returnstr(1) +} + +# getpgid ____________________________________________________ +# long sys_getpgid(pid_t pid) +probe nd_syscall.getpgid = kernel.function("sys_getpgid") { + name = "getpgid" + pid = $pid + argstr = sprintf("%d", $pid) +} +probe nd_syscall.getpgid.return = kernel.function("sys_getpgid").return { + name = "getpgid" + retstr = returnstr(1) +} + +# getpgrp ____________________________________________________ +# long sys_getpgrp(void) +probe nd_syscall.getpgrp = kernel.function("sys_getpgrp") ? { + name = "getpgrp" + argstr = "" +} +probe nd_syscall.getpgrp.return = kernel.function("sys_getpgrp").return ? { + name = "getpgrp" + retstr = returnstr(1) +} + +# getpid _____________________________________________________ +# long sys_getpid(void) +probe nd_syscall.getpid = kernel.function("sys_getpid") { + name = "getpid" + argstr = "" +} +probe nd_syscall.getpid.return = kernel.function("sys_getpid").return { + name = "getpid" + retstr = returnstr(1) +} + +# getppid ____________________________________________________ +# long sys_getppid(void) +probe nd_syscall.getppid = kernel.function("sys_getppid") { + name = "getppid" + argstr = "" +} +probe nd_syscall.getppid.return = kernel.function("sys_getppid").return { + name = "getppid" + retstr = returnstr(1) +} + +# getpriority ________________________________________________ +# long sys_getpriority(int which, int who) +probe nd_syscall.getpriority = kernel.function("sys_getpriority") { + name = "getpriority" + which = $which + who = $who + argstr = sprintf("%s, %d", _priority_which_str(which), who) +} +probe nd_syscall.getpriority.return = kernel.function("sys_getpriority").return { + name = "getpriority" + retstr = returnstr(1) +} + +# getresgid __________________________________________________ +# long sys_getresgid(gid_t __user *rgid, +# gid_t __user *egid, +# gid_t __user *sgid) +# long sys_getresgid16(old_uid_t __user *rgid, +# old_uid_t __user *egid, +# old_uid_t __user *sgid) +probe nd_syscall.getresgid = + kernel.function("sys_getresgid16") ?, + kernel.function("sys_getresgid") +{ + name = "getresgid" + rgid_uaddr = $rgid + egid_uaddr = $egid + sgid_uaddr = $sgid + argstr = sprintf("%p, %p, %p", $rgid, $egid, $sgid) +} +probe nd_syscall.getresgid.return = + kernel.function("sys_getresgid16").return ?, + kernel.function("sys_getresgid").return +{ + name = "getresgid" + retstr = returnstr(1) +} + +# getresuid __________________________________________________ +# long sys_getresuid(uid_t __user *ruid, +# uid_t __user *euid, +# uid_t __user *suid) +probe nd_syscall.getresuid = + kernel.function("sys_getresuid16") ?, + kernel.function("sys_getresuid") +{ + name = "getresuid" + ruid_uaddr = $ruid + euid_uaddr = $euid + suid_uaddr = $suid + argstr = sprintf("%p, %p, %p", $ruid, $euid, $suid) +} +probe nd_syscall.getresuid.return = + kernel.function("sys_getresuid16").return ?, + kernel.function("sys_getresuid").return +{ + name = "getresuid" + retstr = returnstr(1) +} + +# getrlimit __________________________________________________ +# long sys_getrlimit(unsigned int resource, struct rlimit __user *rlim) +# long sys_old_getrlimit(unsigned int resource, struct rlimit __user *rlim) +# long compat_sys_getrlimit (unsigned int resource, struct compat_rlimit __user *rlim) +probe nd_syscall.getrlimit = kernel.function("sys_getrlimit"), + kernel.function("sys_old_getrlimit") ?, + kernel.function("compat_sys_getrlimit") ? +{ + name = "getrlimit" + resource = $resource + rlim_uaddr = $rlim + argstr = sprintf("%s, %p", _rlimit_resource_str($resource), $rlim) +} +probe nd_syscall.getrlimit.return = kernel.function("sys_getrlimit").return, + kernel.function("sys_old_getrlimit").return ?, + kernel.function("compat_sys_getrlimit").return ? +{ + name = "getrlimit" + retstr = returnstr(1) +} + +# getrusage __________________________________________________ +# long sys_getrusage(int who, struct rusage __user *ru) +probe nd_syscall.getrusage = kernel.function("sys_getrusage") { + name = "getrusage" + who = $who + if($who==-2) + { + # RUSAGE_BOTH is not valid argument for sys_getrusage + who_str = sprintf("UNKNOWN VALUE: %d", $who) + } + else + { + who_str = _rusage_who_str($who) + } + usage_uaddr = $ru + argstr = sprintf("%s, %p", who_str, usage_uaddr) +} +probe nd_syscall.getrusage.return = kernel.function("sys_getrusage").return { + name = "getrusage" + retstr = returnstr(1) +} + +# getsid _____________________________________________________ +# long sys_getsid(pid_t pid) +probe nd_syscall.getsid = kernel.function("sys_getsid") { + name = "getsid" + pid = $pid + argstr = sprint(pid) +} +probe nd_syscall.getsid.return = kernel.function("sys_getsid").return { + name = "getsid" + retstr = returnstr(1) +} + +# getsockname ________________________________________________ +# long sys_getsockname(int fd, +# struct sockaddr __user *usockaddr, +# int __user *usockaddr_len) +probe nd_syscall.getsockname = kernel.function("sys_getsockname") ? { + name = "getsockname" + s = $fd + name_uaddr = $usockaddr + namelen_uaddr = $usockaddr_len + argstr = sprintf("%d, %p, %p", $fd, $usockaddr, $usockaddr_len) +} +probe nd_syscall.getsockname.return = kernel.function("sys_getsockname").return ? { + name = "getsockname" + retstr = returnstr(1) +} + +# getsockopt _________________________________________________ +# long sys_getsockopt(int fd, +# int level, +# int optname, +# char __user *optval, +# int __user *optlen) +# +probe nd_syscall.getsockopt = + kernel.function("sys_getsockopt") ?, + kernel.function("compat_sys_getsockopt") ? +{ + name = "getsockopt" + fd = $fd + level = $level + level_str = _sockopt_level_str($level) + optname = $optname + optname_str = _sockopt_optname_str($optname) + optval_uaddr = $optval + optlen_uaddr = $optlen + argstr = sprintf("%d, %s, %s, %p, %p", $fd, _sockopt_level_str($level), + _sockopt_optname_str($optname), $optval, $optlen) +} +probe nd_syscall.getsockopt.return = + kernel.function("sys_getsockopt").return ?, + kernel.function("compat_sys_getsockopt").return ? +{ + name = "getsockopt" + retstr = returnstr(1) +} + +# gettid _____________________________________________________ +# long sys_gettid(void) +probe nd_syscall.gettid = kernel.function("sys_gettid") { + name = "gettid" + argstr = "" +} +probe nd_syscall.gettid.return = kernel.function("sys_gettid").return { + name = "gettid" + retstr = returnstr(1) +} + +# gettimeofday _______________________________________________ +# long sys_gettimeofday(struct timeval __user *tv, +# struct timezone __user *tz) +# long sys32_gettimeofday(struct compat_timeval __user *tv, +# struct timezone __user *tz) +# long compat_sys_gettimeofday(struct compat_timeval __user *tv, +# struct timezone __user *tz) +probe nd_syscall.gettimeofday = + kernel.function("sys_gettimeofday"), + kernel.function("sys32_gettimeofday") ?, + kernel.function("compat_sys_gettimeofday") ? +{ + name = "gettimeofday" + tv_uaddr = $tv + tz_uaddr = $tz + argstr = sprintf("%p, %p", $tv, $tz) +} + +probe nd_syscall.gettimeofday.return = + kernel.function("sys_gettimeofday").return, + kernel.function("sys32_gettimeofday").return ?, + kernel.function("compat_sys_gettimeofday").return ? +{ + name = "gettimeofday" + retstr = returnstr(1) +} + +# getuid _____________________________________________________ +# long sys_getuid(void +# long sys_getuid16(void) +# long sys32_getuid16(void) +# +probe nd_syscall.getuid = + kernel.function("sys_getuid16") ?, + kernel.function("sys32_getuid16") ?, + kernel.function("sys_getuid") +{ + name = "getuid" + argstr = "" +} +probe nd_syscall.getuid.return = + kernel.function("sys_getuid16").return ?, + kernel.function("sys32_getuid16").return ?, + kernel.function("sys_getuid").return +{ + name = "getuid" + retstr = returnstr(1) +} + +# getxattr ___________________________________________________ +# ssize_t sys_getxattr(char __user *path, char __user *name, +# void __user *value, size_t size) +probe nd_syscall.getxattr = kernel.function("sys_getxattr") { + name = "getxattr" + path = user_string($path) + # FIXME + name2 = user_string($name) + value_uaddr = $value + size = $size + argstr = sprintf("%s, %s, %p, %d", + user_string_quoted($path), + user_string_quoted($name), + value_uaddr, size) +} +probe nd_syscall.getxattr.return = kernel.function("sys_getxattr").return { + name = "getxattr" + retstr = returnstr(1) +} + +# init_module ________________________________________________ +# long sys_init_module(void __user *umod, +# unsigned long len, +# const char __user *uargs) +# +probe nd_syscall.init_module = kernel.function("sys_init_module") ? { + name = "init_module" + umod_uaddr = $umod + len = $len + uargs = user_string($uargs) + argstr = sprintf("%p, %d, %s", $umod, $len, user_string_quoted($uargs)) +} +probe nd_syscall.init_module.return = kernel.function("sys_init_module").return ? { + name = "init_module" + retstr = returnstr(1) +} + +# inotify_add_watch __________________________________________ +# +# long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) +# +probe nd_syscall.inotify_add_watch = kernel.function("sys_inotify_add_watch") ? { + name = "inotify_add_watch" + fd = $fd + path_uaddr = $path + path = user_string($path) + mask = $mask + argstr = sprintf("%d, %s, %d", $fd, user_string_quoted($path), $mask) +} +probe nd_syscall.inotify_add_watch.return = kernel.function("sys_inotify_add_watch").return ? { + name = "inotify_add_watch" + retstr = returnstr(1) +} + +# inotify_init _______________________________________________ +# +# long sys_inotify_init(void) +# +probe nd_syscall.inotify_init = kernel.function("sys_inotify_init") ? { + name = "inotify_init" + argstr = "" +} +probe nd_syscall.inotify_init.return = kernel.function("sys_inotify_init").return ? { + name = "inotify_init" + retstr = returnstr(1) +} + +# inotify_rm_watch ___________________________________________ +# +# long sys_inotify_rm_watch(int fd, u32 wd) +# +probe nd_syscall.inotify_rm_watch = kernel.function("sys_inotify_rm_watch") ? { + name = "inotify_rm_watch" + fd = $fd + wd = $wd + argstr = sprintf("%d, %d", $fd, $wd) +} +probe nd_syscall.inotify_rm_watch.return = kernel.function("sys_inotify_rm_watch").return ? { + name = "inotify_rm_watch" + retstr = returnstr(1) +} + +# io_cancel __________________________________________________ +# long sys_io_cancel(aio_context_t ctx_id, +# struct iocb __user *iocb, +# struct io_event __user *result) +probe nd_syscall.io_cancel = kernel.function("sys_io_cancel") { + name = "io_cancel" + ctx_id = $ctx_id + iocb_uaddr = $iocb + result_uaddr = $result + argstr = sprintf("%d, %p, %p", ctx_id, iocb_uaddr, result_uaddr) +} +probe nd_syscall.io_cancel.return = kernel.function("sys_io_cancel").return { + name = "io_cancel" + retstr = returnstr(1) +} + +# ioctl ______________________________________________________ +# long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +# long compat_sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +# +probe nd_syscall.ioctl = + kernel.function("sys_ioctl") ?, + kernel.function("compat_sys_ioctl") ? +{ + name = "ioctl" + fd = $fd + request = $cmd + argp = $arg + argstr = sprintf("%d, %d, %p", $fd, $cmd, $arg) +} +probe nd_syscall.ioctl.return = + kernel.function("sys_ioctl").return ?, + kernel.function("compat_sys_ioctl").return ? +{ + name = "ioctl" + retstr = returnstr(1) +} + +# io_destroy _________________________________________________ +# long sys_io_destroy(aio_context_t ctx) +probe nd_syscall.io_destroy = kernel.function("sys_io_destroy") { + name = "io_destroy" + ctx = $ctx + argstr = sprintf("%d", ctx) +} +probe nd_syscall.io_destroy.return = kernel.function("sys_io_destroy").return { + name = "io_destroy" + retstr = returnstr(1) +} + +# io_getevents _______________________________________________ +# long sys_io_getevents(aio_context_t ctx_id, +# long min_nr, +# long nr, +# struct io_event __user *events, +# struct timespec __user *timeout) +# long compat_sys_io_getevents(aio_context_t ctx_id, +# unsigned long min_nr, +# unsigned long nr, +# struct io_event __user *events, +# struct compat_timespec __user *timeout) +# +probe nd_syscall.io_getevents = + kernel.function("sys_io_getevents") ?, + kernel.function("compat_sys_io_getevents") ? +{ + name = "io_getevents" + ctx_id = $ctx_id + min_nr = $min_nr + nr = $nr + events_uaddr = $events + timeout_uaddr = $timeout + timestr = _struct_timespec_u($timeout,1) + argstr = sprintf("%d, %d, %d, %p, %p, %s", $ctx_id, $min_nr, + $nr, $events, $timeout, timestr) +} +probe nd_syscall.io_getevents.return = + kernel.function("sys_io_getevents").return ?, + kernel.function("compat_sys_io_getevents").return ? +{ + name = "io_getevents" + retstr = returnstr(1) +} + +# ioperm _____________________________________________________ +# long sys_ioperm(unsigned long from, unsigned long num, int turn_on) +# +probe nd_syscall.ioperm = kernel.function("sys_ioperm") ? { + name = "ioperm" + from = $from + num = $num + turn_on = $turn_on + argstr = sprintf("%d, %d, %d", $from, $num, $turn_on) +} +probe nd_syscall.ioperm.return = kernel.function("sys_ioperm").return ? { + name = "ioperm" + retstr = returnstr(1) +} + +# io_setup ___________________________________________________ +# long sys_io_setup(unsigned nr_events, aio_context_t __user *ctxp) +# +probe nd_syscall.io_setup = kernel.function("sys_io_setup") { + name = "io_setup" + maxevents = $nr_events + ctxp_uaddr = $ctxp + argstr = sprintf("%d, %p", $nr_events, $ctxp) +} + +probe nd_syscall.io_setup.return = kernel.function("sys_io_setup").return { + name = "io_setup" + retstr = returnstr(1) +} +# long compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p) +# +probe nd_syscall.compat_io_setup = kernel.function("compat_sys_io_setup") ? { + name = "io_setup" + maxevents = $nr_reqs + ctxp_uaddr = $ctx32p + argstr = sprintf("%d, %p", $nr_reqs, $ctx32p) +} + +probe nd_syscall.compat_io_setup.return = kernel.function("compat_sys_io_setup").return ? { + name = "io_setup" + retstr = returnstr(1) +} + +# io_submit __________________________________________________ +# long sys_io_submit(aio_context_t ctx_id, long nr, struct iocb __user * __user *iocbpp) +# +probe nd_syscall.io_submit = kernel.function("sys_io_submit") { + name = "io_submit" + ctx_id = $ctx_id + nr = $nr + iocbpp_uaddr = $iocbpp + argstr = sprintf("%d, %d, %p", $ctx_id, $nr, $iocbpp) +} +probe nd_syscall.io_submit.return = kernel.function("sys_io_submit").return { + name = "io_submit" + retstr = returnstr(1) +} +# long compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb) +# +probe nd_syscall.compat_io_submit = kernel.function("compat_sys_io_submit") ? { + name = "io_submit" + ctx_id = $ctx_id + nr = $nr + iocbpp_uaddr = $iocb + argstr = sprintf("%d, %d, %p", $ctx_id, $nr, $iocb) +} +probe nd_syscall.compat_io_submit.return = kernel.function("compat_sys_io_submit").return ? { + name = "io_submit" + retstr = returnstr(1) +} + +# ioprio_get _________________________________________________ +# long sys_ioprio_get(int which, int who) +# +probe nd_syscall.ioprio_get = kernel.function("sys_ioprio_get") ? { + name = "ioprio_get" + which = $which + who = $who + argstr = sprintf("%d, %d", $which, $who) +} +probe nd_syscall.ioprio_get.return = kernel.function("sys_ioprio_get").return ? { + name = "ioprio_get" + retstr = returnstr(1) +} + +# ioprio_set _________________________________________________ +# long sys_ioprio_set(int which, int who, int ioprio) +# +probe nd_syscall.ioprio_set = kernel.function("sys_ioprio_set") ? { + name = "ioprio_set" + which = $which + who = $who + ioprio = $ioprio + argstr = sprintf("%d, %d, %d", $which, $who, $ioprio) +} +probe nd_syscall.ioprio_set.return = kernel.function("sys_ioprio_set").return ? { + name = "ioprio_set" + retstr = returnstr(1) +} + +# kexec_load _________________________________________________ +# long sys_kexec_load(unsigned long entry, +# unsigned long nr_segments, +# struct kexec_segment __user *segments, +# unsigned long flags) +# long compat_sys_kexec_load(unsigned long entry, +# unsigned long nr_segments, +# struct compat_kexec_segment __user *segments, +# unsigned long flags) +# +probe nd_syscall.kexec_load = + kernel.function("sys_kexec_load") ?, + kernel.function("compat_sys_kexec_load") ? +{ + name = "kexec_load" + entry = $entry + nr_segments = $nr_segments + segments_uaddr = $segments + flags = $flags + argstr = sprintf("%p, %d, %p, %d", $entry, $nr_segments, $segments, $flags) +} +probe nd_syscall.kexec_load.return = + kernel.function("sys_kexec_load").return ?, + kernel.function("compat_sys_kexec_load").return ? +{ + name = "kexec_load" + retstr = returnstr(1) +} + +# keyctl _____________________________________________________ +# long sys_keyctl(int option, +# unsigned long arg2, +# unsigned long arg3, +# unsigned long arg4, +# unsigned long arg5) +# long compat_sys_keyctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5) +# +probe nd_syscall.keyctl = + kernel.function("sys_keyctl") ?, + kernel.function("compat_sys_keyctl") ? +{ + name = "keyctl" + argstr = sprintf("%d, ...", $option) + +} +probe nd_syscall.keyctl.return = + kernel.function("sys_keyctl").return ?, + kernel.function("compat_sys_keyctl").return ? +{ + name = "keyctl" + retstr = returnstr(1) +} + +# kill _______________________________________________________ +# long sys_kill(int pid, int sig) +probe nd_syscall.kill = kernel.function("sys_kill") { + name = "kill" + pid = $pid + sig = $sig + argstr = sprintf("%d, %s", $pid, _signal_name($sig)) +} +probe nd_syscall.kill.return = kernel.function("sys_kill").return { + name = "kill" + retstr = returnstr(1) +} + +# lchown _____________________________________________________ +# long sys_lchown(const char __user * filename, uid_t user, gid_t group) +# +probe nd_syscall.lchown = kernel.function("sys_lchown") { + name = "lchown" + path = user_string($filename) + owner = __int32($user) + group = __int32($group) + argstr = sprintf("%s, %d, %d",user_string_quoted($filename), owner, group) +} +probe nd_syscall.lchown.return = kernel.function("sys_lchown").return { + name = "lchown" + retstr = returnstr(1) +} + +# lchown16 ___________________________________________________ +# long sys_lchown16(const char __user * filename, old_uid_t user, +# old_gid_t group) +# +probe nd_syscall.lchown16 = kernel.function("sys_lchown16") ? { + name = "lchown16" + path = user_string($filename) + owner = __short($user) + group = __short($group) + argstr = sprintf("%s, %d, %d", user_string_quoted($filename), owner, group) +} +probe nd_syscall.lchown16.return = kernel.function("sys_lchown16").return ? { + name = "lchown16" + retstr = returnstr(1) +} +# lgetxattr __________________________________________________ +# ssize_t sys_lgetxattr(char __user *path, +# char __user *name, +# void __user *value, +# size_t size) +# +probe nd_syscall.lgetxattr = kernel.function("sys_lgetxattr") { + name = "lgetxattr" + path = user_string($path) + # FIXME + name2 = user_string($name) + value_uaddr = $value + size = $size + argstr = sprintf("%s, %s, %p, %d", + user_string_quoted($path), + user_string_quoted($name), + value_uaddr, size) +} +probe nd_syscall.lgetxattr.return = kernel.function("sys_lgetxattr").return { + name = "lgetxattr" + retstr = returnstr(1) +} +# link _______________________________________________________ +# long sys_link(const char __user * oldname, +# const char __user * newname) +probe nd_syscall.link = kernel.function("sys_link") { + name = "link" + oldpath = user_string($oldname) + newpath = user_string($newname) + argstr = sprintf("%s, %s", + user_string_quoted($oldname), + user_string_quoted($newname)) +} +probe nd_syscall.link.return = kernel.function("sys_link").return { + name = "link" + retstr = returnstr(1) +} + +# listen _____________________________________________________ +# long sys_listen(int fd, int backlog) +probe nd_syscall.listen = kernel.function("sys_listen") ? { + name = "listen" + sockfd = $fd + backlog = $backlog + argstr = sprintf("%d, %d", $fd, $backlog) +} +probe nd_syscall.listen.return = kernel.function("sys_listen").return ? { + name = "listen" + retstr = returnstr(1) +} + +# listxattr __________________________________________________ +# ssize_t sys_listxattr(char __user *path, char __user *list, size_t size) +# +probe nd_syscall.listxattr = kernel.function("sys_listxattr") { + name = "listxattr" + path_uaddr = $path + path = user_string($path) + list_uaddr = $list + size = $size + argstr = sprintf("%s, %p, %d", user_string_quoted($path), $list, $size) +} +probe nd_syscall.listxattr.return = kernel.function("sys_listxattr").return { + name = "listxattr" + retstr = returnstr(1) +} + +# llistxattr _________________________________________________ +# ssize_t sys_llistxattr(char __user *path, char __user *list, size_t size) +# +probe nd_syscall.llistxattr = kernel.function("sys_llistxattr") { + name = "llistxattr" + path_uaddr = $path + path = user_string($path) + list_uaddr = $list + size = $size + argstr = sprintf("%s, %p, %d", user_string_quoted($path), $list, $size) +} +probe nd_syscall.llistxattr.return = kernel.function("sys_llistxattr").return { + name = "llistxattr" + retstr = returnstr(1) +} + +# llseek _____________________________________________________ +# long sys_llseek(unsigned int fd, +# unsigned long offset_high, +# unsigned long offset_low, +# loff_t __user * result, +# unsigned int origin) +probe nd_syscall.llseek = kernel.function("sys_llseek") ? { + name = "llseek" + fd = $fd + offset_high = $offset_high + offset_low = $offset_low + result_uaddr = $result + whence = $origin + whence_str = _seek_whence_str($origin) + argstr = sprintf("%d, 0x%x, 0x%x, %p, %s", $fd, $offset_high, + $offset_low, $result, whence_str) +} +probe nd_syscall.llseek.return = kernel.function("sys_llseek").return ? { + name = "llseek" + retstr = returnstr(1) +} + +# lookup_dcookie _____________________________________________ +# long sys_lookup_dcookie(u64 cookie64, char __user * buf, size_t len) +# +probe nd_syscall.lookup_dcookie = kernel.function("sys_lookup_dcookie") ? { + name = "lookup_dcookie" + cookie = $cookie64 + buffer_uaddr = $buf + len = $len + argstr = sprintf("%d, %p, %d", $cookie64, $buf, $len) +} +probe nd_syscall.lookup_dcookie.return = kernel.function("sys_lookup_dcookie").return ? { + name = "lookup_dcookie" + retstr = returnstr(1) +} + +# lremovexattr _______________________________________________ +# long sys_lremovexattr(char __user *path, char __user *name) +# +probe nd_syscall.lremovexattr = kernel.function("sys_lremovexattr") { + name = "lremovexattr" + path_uaddr = $path + path = user_string($path) + name_uaddr = $name + name2 = user_string($name) + argstr = sprintf("%s, %s", user_string_quoted($path), user_string_quoted($name)) +} +probe nd_syscall.lremovexattr.return = kernel.function("sys_lremovexattr").return { + name = "lremovexattr" + retstr = returnstr(1) +} + +# lseek ______________________________________________________ +# off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin) +probe nd_syscall.lseek = kernel.function("sys_lseek") { + name = "lseek" + fildes = $fd +# offset = __int32($offset) + offset = $offset + whence = $origin + whence_str = _seek_whence_str($origin) + argstr = sprintf("%d, %d, %s", $fd, offset, whence_str) +} +probe nd_syscall.lseek.return = kernel.function("sys_lseek").return { + name = "lseek" + retstr = returnstr(1) +} + +# lsetxattr __________________________________________________ +# long sys_lsetxattr(char __user *path, +# char __user *name, +# void __user *value, +# size_t size, +# int flags) +# +probe nd_syscall.lsetxattr = kernel.function("sys_lsetxattr") { + name = "lsetxattr" + path_uaddr = $path + path = user_string($path) + name_uaddr = $name + name_str = user_string($name) + value_uaddr = $value + size = $size + flags = $flags + argstr = sprintf("%s, %s, %p, %d, %d", + user_string_quoted($path), + user_string_quoted($name), + value_uaddr, $size, $flags) +} +probe nd_syscall.lsetxattr.return = kernel.function("sys_lsetxattr").return { + name = "lsetxattr" + retstr = returnstr(1) +} + +# lstat ______________________________________________________ +# long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf) +# long sys_newlstat(char __user * filename, struct stat __user * statbuf) +# long compat_sys_newlstat(char __user * filename, struct compat_stat __user *statbuf) +# long sys32_lstat64(char * filename, struct stat64 __user *statbuf) +# long sys_lstat64(char __user * filename, struct stat64 __user * statbuf) +# long sys_oabi_lstat64(char __user * filename, +# struct oldabi_stat64 __user * statbuf) +# +probe nd_syscall.lstat = + kernel.function("sys_lstat") ?, + kernel.function("sys_newlstat") ?, + kernel.function("compat_sys_newlstat") ?, + kernel.function("sys32_lstat64") ?, + kernel.function("sys_lstat64") ?, + kernel.function("sys_oabi_lstat64") ? +{ + name = "lstat" + path = user_string($filename) + buf_uaddr = $statbuf + argstr = sprintf("%s, %p", user_string_quoted($filename), $statbuf) +} +probe nd_syscall.lstat.return = + kernel.function("sys_lstat").return ?, + kernel.function("sys_newlstat").return ?, + kernel.function("compat_sys_newlstat").return ?, + kernel.function("sys32_lstat64").return ?, + kernel.function("sys_lstat64").return ?, + kernel.function("sys_oabi_lstat64").return ? +{ + name = "lstat" + retstr = returnstr(1) +} + +# madvise ____________________________________________________ +# long sys_madvise(unsigned long start, size_t len_in, int behavior) +# +probe nd_syscall.madvise = kernel.function("sys_madvise") ? { + name = "madvise" + start = $start + length = $len_in + advice = $behavior + advice_str = _madvice_advice_str($behavior) + argstr = sprintf("%p, %d, %s", $start, $len_in, _madvice_advice_str($behavior)) +} +probe nd_syscall.madvise.return = kernel.function("sys_madvise").return ? { + name = "madvise" + retstr = returnstr(1) +} + +# mbind ______________________________________________________ +# long sys_mbind(unsigned long start, +# unsigned long len, +# unsigned long mode, +# unsigned long __user *nmask, +# unsigned long maxnode, +# unsigned flags) +# +# long compat_sys_mbind(compat_ulong_t start, +# compat_ulong_t len, +# compat_ulong_t mode, +# compat_ulong_t __user *nmask, +# compat_ulong_t maxnode, +# compat_ulong_t flags) +# +probe nd_syscall.mbind = + kernel.function("sys_mbind") ?, + kernel.function("compat_sys_mbind") ? +{ + name = "mbind" + start = $start + len = $len + mode = $mode + nmask_uaddr = $nmask + maxnode = $maxnode + flags = $flags + argstr = sprintf("%d, %d, %d, %p, %d, 0x%x", $start, $len, $mode, + $nmask, $maxnode, $flags) +} +probe nd_syscall.mbind.return = + kernel.function("sys_mbind").return ?, + kernel.function("compat_sys_mbind").return ? +{ + name = "mbind" + retstr = returnstr(1) +} + +# migrate_pages ____________________________________________________ +# long sys_migrate_pages(pid_t pid, unsigned long maxnode, +# const unsigned long __user *old_nodes, +# const unsigned long __user *new_nodes) +probe nd_syscall.migrate_pages = kernel.function("sys_migrate_pages") ? { + name = "migrate_pages" + argstr = sprintf("%d, %d, %p, %p", $pid, $maxnode, $old_nodes, $new_nodes) +} +probe nd_syscall.migrate_pages.return = kernel.function("sys_migrate_pages").return ? { + name = "migrate_pages" + retstr = returnstr(1) +} + +# mincore ____________________________________________________ +# long sys_mincore(unsigned long start, size_t len, unsigned char __user * vec) +# +probe nd_syscall.mincore = kernel.function("sys_mincore") ? { + name = "mincore" + start = $start + length = $len + vec_uaddr = $vec + argstr = sprintf("%p, %d, %p", $start, $len, $vec) +} +probe nd_syscall.mincore.return = kernel.function("sys_mincore").return ? { + name = "mincore" + retstr = returnstr(1) +} + +# mkdir ______________________________________________________ +# long sys_mkdir(const char __user * pathname, int mode) +probe nd_syscall.mkdir = kernel.function("sys_mkdir") { + name = "mkdir" + pathname_uaddr = $pathname + pathname = user_string($pathname) + mode = $mode + argstr = sprintf("%s, %#o", user_string_quoted($pathname), $mode) +} +probe nd_syscall.mkdir.return = kernel.function("sys_mkdir").return { + name = "mkdir" + retstr = returnstr(1) +} + +# mkdirat ____________________________________________________ +# new function with 2.6.16 +# long sys_mkdirat(int dfd, const char __user *pathname, int mode) +probe nd_syscall.mkdirat = kernel.function("sys_mkdirat") ? { + name = "mkdirat" + dirfd = $dfd + pathname = user_string($pathname) + mode = $mode + argstr = sprintf("%d, %s, %#o", $dfd, user_string_quoted($pathname), $mode) +} +probe nd_syscall.mkdirat.return = kernel.function("sys_mkdirat").return ? { + name = "mkdirat" + retstr = returnstr(1) +} + +# mknod +# long sys_mknod(const char __user * filename, int mode, unsigned dev) +probe nd_syscall.mknod = kernel.function("sys_mknod") { + name = "mknod" + pathname = user_string($filename) + mode = $mode + dev = $dev + argstr = sprintf("%s, %s, %p", user_string_quoted($filename), _mknod_mode_str($mode), dev) +} + +probe nd_syscall.mknod.return = kernel.function("sys_mknod").return { + name = "mknod" + retstr = returnstr(1) +} + +# mlock ______________________________________________________ +# +# long sys_mlock(unsigned long start, size_t len) +# +probe nd_syscall.mlock = kernel.function("sys_mlock") ? { + name = "mlock" + addr = $start + len = $len + argstr = sprintf("%p, %d", $start, $len) +} +probe nd_syscall.mlock.return = kernel.function("sys_mlock").return ? { + name = "mlock" + retstr = returnstr(1) +} +# mlockall ___________________________________________________ +# +# long sys_mlockall(int flags) +# +probe nd_syscall.mlockall = kernel.function("sys_mlockall") ? { + name = "mlockall" + flags = $flags + argstr = _mlockall_flags_str($flags) +} +probe nd_syscall.mlockall.return = kernel.function("sys_mlockall").return ? { + name = "mlockall" + retstr = returnstr(1) +} + +# modify_ldt _________________________________________________ +# int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) +# +probe nd_syscall.modify_ldt = kernel.function("sys_modify_ldt") ? { + name = "modify_ldt" + func = $func + ptr_uaddr = $ptr + bytecount = $bytecount + argstr = sprintf("%d, %p, %d", $func, $ptr, $bytecount) +} +probe nd_syscall.modify_ldt.return = kernel.function("sys_modify_ldt").return ? { + name = "modify_ldt" + retstr = returnstr(1) +} + +# move_pages ____________________________________________________ +# long sys_move_pages(pid_t pid, unsigned long nr_pages, +# const void __user * __user *pages, +# const int __user *nodes, +# int __user *status, +# int flags) +# +# long compat_sys_move_pages(pid_t pid, unsigned long nr_pages, +# compat_uptr_t __user *pages32, +# const int __user *nodes, +# int __user *status, +# int flags) +# +probe nd_syscall.move_pages = + kernel.function("sys_move_pages") ?, + kernel.function("compat_sys_move_pages") ? +{ + name = "move_pages" + argstr = sprintf("%d, %d, %p, %p, 0x%x", $pid, $nr_pages, $nodes, $status, $flags) +} +probe nd_syscall.move_pages.return = + kernel.function("sys_move_pages").return ?, + kernel.function("compat_sys_move_pages").return ? +{ + name = "move_pages" + retstr = returnstr(1) +} + +# mount ______________________________________________________ +# long sys_mount(char __user * dev_name, +# char __user * dir_name, +# char __user * type, +# unsigned long flags, +# void __user * data) +# long compat_sys_mount(char __user * dev_name, +# char __user * dir_name, +# char __user * type, +# unsigned long flags, +# void __user * data) +probe nd_syscall.mount = + kernel.function("sys_mount"), + kernel.function("compat_sys_mount") ? +{ + name = "mount" + source = user_string($dev_name) + target = user_string($dir_name) + filesystemtype = user_string($type) + mountflags = $flags + mountflags_str = _mountflags_str($flags) + data = text_strn(user_string($data),syscall_string_trunc,1) + argstr = sprintf("%s, %s, %s, %s, %s", + user_string_quoted($dev_name), + user_string_quoted($dir_name), + user_string_quoted($type), + mountflags_str, data) +} +probe nd_syscall.mount.return = + kernel.function("sys_mount").return, + kernel.function("compat_sys_mount").return ? +{ + name = "mount" + retstr = returnstr(1) +} + +# mprotect ___________________________________________________ +# long sys_mprotect(unsigned long start, size_t len, unsigned long prot) +# +probe nd_syscall.mprotect = kernel.function("sys_mprotect") ? { + name = "mprotect" + addr = $start + len = $len + prot = $prot + prot_str = _mprotect_prot_str($prot) + argstr = sprintf("%p, %d, %s", $start, $len, _mprotect_prot_str($prot)) +} +probe nd_syscall.mprotect.return = kernel.function("sys_mprotect").return ? { + name = "mprotect" + retstr = returnstr(1) +} + +# mq_getsetattr ______________________________________________ +# long sys_mq_getsetattr(mqd_t mqdes, +# const struct mq_attr __user *u_mqstat, +# struct mq_attr __user *u_omqstat) +# long compat_sys_mq_getsetattr(mqd_t mqdes, +# const struct compat_mq_attr __user *u_mqstat, +# struct compat_mq_attr __user *u_omqstat) +# +probe nd_syscall.mq_getsetattr = + kernel.function("sys_mq_getsetattr") ?, + kernel.function("compat_sys_mq_getsetattr") ? +{ + name = "mq_getsetattr" + mqdes = $mqdes + u_mqstat_uaddr = $u_mqstat + u_omqstat_uaddr = $u_omqstat + argstr = sprintf("%d, %p, %p", $mqdes, $u_mqstat, $u_omqstat) +} +probe nd_syscall.mq_getsetattr.return = + kernel.function("sys_mq_getsetattr").return ?, + kernel.function("compat_sys_mq_getsetattr").return ? +{ + name = "mq_getsetattr" + retstr = returnstr(1) +} + +# mq_notify __________________________________________________ +# long sys_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification) +# long compat_sys_mq_notify(mqd_t mqdes, const struct compat_sigevent __user *u_notification) +# +probe nd_syscall.mq_notify = + kernel.function("sys_mq_notify") ?, + kernel.function("compat_sys_mq_notify") ? +{ + name = "mq_notify" + mqdes = $mqdes + notification_uaddr = $u_notification + argstr = sprintf("%d, %p", $mqdes, $u_notification) +} +probe nd_syscall.mq_notify.return = + kernel.function("sys_mq_notify").return ?, + kernel.function("compat_sys_mq_notify").return ? +{ + name = "mq_notify" + retstr = returnstr(1) +} + +# mq_open ____________________________________________________ +# long sys_mq_open(const char __user *u_name, +# int oflag, +# mode_t mode, +# struct mq_attr __user *u_attr) +# long compat_sys_mq_open(const char __user *u_name, +# int oflag, compat_mode_t mode, +# struct compat_mq_attr __user *u_attr) +# +probe nd_syscall.mq_open = + kernel.function("sys_mq_open") ?, + kernel.function("compat_sys_mq_open") ? +{ + name = "mq_open" + name_uaddr = $u_name + filename = user_string($u_name) + mode = $mode + u_attr_uaddr = $u_attr + oflag = $oflag + if (oflag & 64) + argstr = sprintf("%s, %s, %#o, %p", user_string_quoted($u_name), + _sys_open_flag_str($oflag), $mode, $u_attr) + else + argstr = sprintf("%s, %s", user_string_quoted($u_name), _sys_open_flag_str($oflag)) +} +probe nd_syscall.mq_open.return = + kernel.function("sys_mq_open").return ?, + kernel.function("compat_sys_mq_open").return ? +{ + name = "mq_open" + retstr = returnstr(1) +} + +# mq_timedreceive ____________________________________________ +# ssize_t sys_mq_timedreceive(mqd_t mqdes, +# char __user *u_msg_ptr, +# size_t msg_len, +# unsigned int __user *u_msg_prio, +# const struct timespec __user *u_abs_timeout) +# ssize_t compat_sys_mq_timedreceive(mqd_t mqdes, +# char __user *u_msg_ptr, +# size_t msg_len, unsigned int __user *u_msg_prio, +# const struct compat_timespec __user *u_abs_timeout) +# +probe nd_syscall.mq_timedreceive = + kernel.function("sys_mq_timedreceive") ?, + kernel.function("compat_sys_mq_timedreceive") ? +{ + name = "mq_timedreceive" + mqdes = $mqdes + msg_ptr_uaddr = $u_msg_ptr + msg_len = $msg_len + msg_prio_uaddr = $u_msg_prio + abs_timout_uaddr = $u_abs_timeout + argstr = sprintf("%d, %p, %d, %p, %p", $mqdes, $u_msg_ptr, $msg_len, + $u_msg_prio, $u_abs_timeout) +} +probe nd_syscall.mq_timedreceive.return = + kernel.function("sys_mq_timedreceive").return ?, + kernel.function("compat_sys_mq_timedreceive").return ? +{ + name = "mq_timedreceive" + retstr = returnstr(1) +} + +# mq_timedsend _______________________________________________ +# long sys_mq_timedsend(mqd_t mqdes, +# const char __user *u_msg_ptr, +# size_t msg_len, +# unsigned int msg_prio, +# const struct timespec __user *u_abs_timeout) +# long compat_sys_mq_timedsend(mqd_t mqdes, +# const char __user *u_msg_ptr, +# size_t msg_len, unsigned int msg_prio, +# const struct compat_timespec __user *u_abs_timeout) +# +probe nd_syscall.mq_timedsend = + kernel.function("sys_mq_timedsend") ?, + kernel.function("compat_sys_mq_timedsend") ? +{ + name = "mq_timedsend" + mqdes = $mqdes + msg_ptr_uaddr = $u_msg_ptr + msg_len = $msg_len + msg_prio = $msg_prio + abs_timeout_uaddr = $u_abs_timeout + argstr = sprintf("%d, %p, %d, %d, %p", $mqdes, $u_msg_ptr, $msg_len, + $msg_prio, $u_abs_timeout) +} +probe nd_syscall.mq_timedsend.return = + kernel.function("sys_mq_timedsend").return ?, + kernel.function("compat_sys_mq_timedsend").return ? +{ + name = "mq_timedsend" + retstr = returnstr(1) +} + +# mq_unlink __________________________________________________ +# long sys_mq_unlink(const char __user *u_name) +# +probe nd_syscall.mq_unlink = kernel.function("sys_mq_unlink") ? { + name = "mq_unlink" + u_name_uaddr = $u_name + u_name = user_string($u_name) + argstr = user_string_quoted($u_name) +} +probe nd_syscall.mq_unlink.return = kernel.function("sys_mq_unlink").return ? { + name = "mq_unlink" + retstr = returnstr(1) +} + +# mremap _____________________________________________________ +# unsigned long sys_mremap(unsigned long addr, +# unsigned long old_len, +# unsigned long new_len, +# unsigned long flags, +# unsigned long new_addr) +# +probe nd_syscall.mremap = + kernel.function("sys_mremap") ?, + kernel.function("ia64_mremap") ? +{ + name = "mremap" + old_address = $addr + old_size = $old_len + new_size = $new_len + flags = $flags + new_address = $new_addr + argstr = sprintf("%p, %d, %d, %s, %p", $addr, $old_len, $new_len, + _mremap_flags($flags), $new_addr) +} +probe nd_syscall.mremap.return = + kernel.function("sys_mremap").return ?, + kernel.function("ia64_mremap").return ? +{ + name = "mremap" + retstr = returnstr(2) +} + +# msgctl _____________________________________________________ +# long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf) +# +probe nd_syscall.msgctl = kernel.function("sys_msgctl") ? { + name = "msgctl" + msqid = $msqid + cmd = $cmd + buf_uaddr = $buf + argstr = sprintf("%d, %d, %p", $msqid, $cmd, $buf) +} +probe nd_syscall.msgctl.return = kernel.function("sys_msgctl").return ? { + name = "msgctl" + retstr = returnstr(1) +} +# compat_sys_msgctl ________________________________________ +# +# long compat_sys_msgctl(int first, int second, void __user *uptr) +# +probe nd_syscall.compat_sys_msgctl = kernel.function("compat_sys_msgctl") ? { + name = "compat_sys_msgctl" + argstr = sprintf("%d, %d, %p", $first, $second, $uptr) +} +probe nd_syscall.compat_sys_msgctl.return = kernel.function("compat_sys_msgctl").return ? { + name = "compat_sys_msgctl" + retstr = returnstr(1) +} + +# msgget _____________________________________________________ +# long sys_msgget (key_t key, int msgflg) +# +probe nd_syscall.msgget = kernel.function("sys_msgget") ? { + name = "msgget" + key = $key + msgflg = $msgflg + msgflg_str = _sys_open_flag_str($msgflg) + argstr = sprintf("%d, %s", $key, _sys_open_flag_str($msgflg)) +} +probe nd_syscall.msgget.return = kernel.function("sys_msgget").return ? { + name = "msgget" + retstr = returnstr(1) +} + +# msgrcv _____________________________________________________ +# long sys_msgrcv (int msqid, +# struct msgbuf __user *msgp, +# size_t msgsz, +# long msgtyp, +# int msgflg) +# +probe nd_syscall.msgrcv = kernel.function("sys_msgrcv") ? { + name = "msgrcv" + msqid = $msqid + msgp_uaddr = $msgp + msgsz = $msgsz + msgtyp = $msgtyp + msgflg = $msgflg + argstr = sprintf("%d, %p, %d, %d, %d", $msqid, $msgp, $msgsz, $msgtyp, $msgflg) +} +probe nd_syscall.msgrcv.return = kernel.function("sys_msgrcv").return ? { + name = "msgrcv" + retstr = returnstr(1) +} +# compat_sys_msgrcv ________________________________________ +# +# long compat_sys_msgrcv(int first, int second, int msgtyp, int third, +# int version, void __user *uptr) +# +probe nd_syscall.compat_sys_msgrcv = kernel.function("compat_sys_msgrcv") ? { + name = "compat_sys_msgrcv" + argstr = sprintf("%d, %d, %d, %p", $first, $second, $third, $uptr) +} +probe nd_syscall.compat_sys_msgrcv.return = kernel.function("compat_sys_msgrcv").return ? { + name = "compat_sys_msgrcv" + retstr = returnstr(1) +} + +# msgsnd _____________________________________________________ +# long sys_msgsnd (int msqid, +# struct msgbuf __user *msgp, +# size_t msgsz, +# int msgflg) +# +probe nd_syscall.msgsnd = kernel.function("sys_msgsnd") ? { + name = "msgsnd" + msqid = $msqid + msgp_uaddr = $msgp + msgsz = $msgsz + msgflg = $msgflg + argstr = sprintf("%d, %p, %d, %d", $msqid, $msgp, $msgsz, $msgflg) +} +probe nd_syscall.msgsnd.return = kernel.function("sys_msgsnd").return ? { + name = "msgsnd" + retstr = returnstr(1) +} +# compat_sys_msgsnd ________________________________________ +# +# long compat_sys_msgsnd(int first, int second, int third, void __user *uptr) +# +probe nd_syscall.compat_sys_msgsnd = kernel.function("compat_sys_msgsnd") ? { + name = "compat_sys_msgsnd" + argstr = sprintf("%d, %d, %d, %p", $first, $second, $third, $uptr) +} +probe nd_syscall.compat_sys_msgsnd.return = kernel.function("compat_sys_msgsnd").return ? { + name = "compat_sys_msgsnd" + retstr = returnstr(1) +} + +# msync ______________________________________________________ +# long sys_msync(unsigned long start, size_t len, int flags) +probe nd_syscall.msync = kernel.function("sys_msync") ? { + name = "msync" + start = $start + length = $len + flags = $flags + argstr = sprintf("%p, %d, %s",start, length, _msync_flag_str(flags)) +} +probe nd_syscall.msync.return = kernel.function("sys_msync").return ? { + name = "msync" + retstr = returnstr(1) +} + +# munlock ____________________________________________________ +# long sys_munlock(unsigned long start, size_t len) +probe nd_syscall.munlock = kernel.function("sys_munlock") ? { + name = "munlock" + addr = $start + len = $len + argstr = sprintf("%p, %d", addr, len) +} +probe nd_syscall.munlock.return = kernel.function("sys_munlock").return ? { + name = "munlock" + retstr = returnstr(1) +} + +# munlockall _________________________________________________ +# long sys_munlockall(void) +probe nd_syscall.munlockall = kernel.function("sys_munlockall") ? { + name = "munlockall" + argstr = "" +} +probe nd_syscall.munlockall.return = kernel.function("sys_munlockall").return ? { + name = "munlockall" + retstr = returnstr(1) +} + +# munmap _____________________________________________________ +# long sys_munmap(unsigned long addr, size_t len) +probe nd_syscall.munmap = kernel.function("sys_munmap") { + name = "munmap" + start = $addr + length = $len + argstr = sprintf("%p, %d", start, length) +} +probe nd_syscall.munmap.return = kernel.function("sys_munmap").return { + name = "munmap" + retstr = returnstr(1) +} diff --git a/tapset/x86_64/registers.stp b/tapset/x86_64/registers.stp new file mode 100644 index 00000000..a5aba55a --- /dev/null +++ b/tapset/x86_64/registers.stp @@ -0,0 +1,243 @@ +global _reg_offsets, _r32_offsets, _stp_regs_registered + +function _stp_register_regs() { + /* 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["bp"] = 32 + _reg_offsets["rbx"] = 40 _reg_offsets["bx"] = 40 + _reg_offsets["r11"] = 48 + _reg_offsets["r10"] = 56 + _reg_offsets["r9"] = 64 + _reg_offsets["r8"] = 72 + _reg_offsets["rax"] = 80 _reg_offsets["ax"] = 80 + _reg_offsets["rcx"] = 88 _reg_offsets["cx"] = 88 + _reg_offsets["rdx"] = 96 _reg_offsets["dx"] = 96 + _reg_offsets["rsi"] = 104 _reg_offsets["si"] = 104 + _reg_offsets["rdi"] = 112 _reg_offsets["di"] = 112 + _reg_offsets["orig_rax"] = 120 _reg_offsets["orig_ax"] = 120 + _reg_offsets["rip"] = 128 _reg_offsets["ip"] = 128 + _reg_offsets["xcs"] = 136 _reg_offsets["cs"] = 136 + _reg_offsets["eflags"] = 144 _reg_offsets["flags"] = 144 + _reg_offsets["rsp"] = 152 _reg_offsets["sp"] = 152 + _reg_offsets["xss"] = 160 _reg_offsets["ss"] = 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 + + _stp_regs_registered = 1 +} + +function _stp_get_register_by_offset:long (offset:long) %{ + long value; + memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value)); + THIS->__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) %{ + THIS->__retvalue = __stp_sign_extend32(THIS->value); +%} + +function _stp_register:long (name:string, sign_extend:long) { + reg32 = 0 + if (!_stp_regs_registered) + _stp_register_regs() + offset = _reg_offsets[name] + if (offset == 0 && !(name in _reg_offsets)) { + offset = _r32_offsets[name] + if (offset == 0 && !(name in _r32_offsets)) { + error("Unknown register: " . name) + return 0 + } + reg32 = 1 + } + value = _stp_get_register_by_offset(offset) + if (reg32) { + 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). + * 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. + */ +function _stp_arg:long (argnum:long, sign_extend:long, truncate:long) %{ + long val; + int result, n, nr_regargs; + size_t argsz = sizeof(long); + + 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); + if (_stp_probing_32bit_app(CONTEXT->regs)) { + argsz = sizeof(int); + result = _stp_get_arg32_by_number(n, nr_regargs, CONTEXT->regs, + &val); + } else + result = _stp_get_arg64_by_number(n, nr_regargs, CONTEXT->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); + THIS->__retvalue = 0; + return; + } + break; + } + default: + goto bad_argnum; + } + if (THIS->truncate || argsz == sizeof(int)) { + if (THIS->sign_extend) + THIS->__retvalue = (int64_t) __stp_sign_extend32(val); + else + /* High bits may be garbage. */ + THIS->__retvalue = (int64_t) (val & 0xffffffff); + } else + THIS->__retvalue = (int64_t) val; + 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; + } +%} + +function probing_32bit_app() %{ + THIS->__retvalue = _stp_probing_32bit_app(CONTEXT->regs); +%} + +/* Return the value of function arg #argnum (1=first arg) as a signed int. */ +function int_arg:long (argnum:long) { + return _stp_arg(argnum, 1, 1) +} + +/* Return the value of function arg #argnum (1=first arg) as an unsigned int. */ +function uint_arg:long (argnum:long) { + return _stp_arg(argnum, 0, 1) +} + +function long_arg:long (argnum:long) { + return _stp_arg(argnum, 1, 0) +} + +function ulong_arg:long (argnum:long) { + return _stp_arg(argnum, 0, 0) +} + +function longlong_arg:long (argnum:long) { + if (probing_32bit_app()) { + lowbits = _stp_arg(argnum, 0, 1) + highbits = _stp_arg(argnum+1, 0, 1) + return ((highbits << 32) | lowbits) + } else + return _stp_arg(argnum, 0, 0) +} + +function ulonglong_arg:long (argnum:long) { + return longlong_arg(argnum) +} + +function pointer_arg:long (argnum:long) { + return _stp_arg(argnum, 0, 0) +} + +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() { +} + +function fastcall() { +} + +function regparm(n) %{ + if (_stp_probing_32bit_app(CONTEXT->regs) && + (THIS->n < 0 || THIS->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 (THIS->n < 0 || THIS->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) n; +%} diff --git a/tapsets.cxx b/tapsets.cxx index 67412396..ef9cf0c6 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -40,6 +40,7 @@ extern "C" { #include <regex.h> #include <glob.h> #include <fnmatch.h> +#include <stdio.h> #include "loc2c.h" #define __STDC_FORMAT_MACROS @@ -208,6 +209,7 @@ common_probe_entryfn_prologue (translator_output* o, string statestr, o->newline() << "c->unwaddr = 0;"; // reset unwound address cache o->newline() << "c->pi = 0;"; + o->newline() << "c->regparm = 0;"; o->newline() << "c->probe_point = 0;"; if (! interruptible) o->newline() << "c->actionremaining = MAXACTION;"; @@ -444,12 +446,27 @@ static string TOK_STATEMENT("statement"); static string TOK_ABSOLUTE("absolute"); static string TOK_PROCESS("process"); +// Can we handle this query with just symbol-table info? +enum dbinfo_reqt +{ + dbr_unknown, + dbr_none, // kernel.statement(NUM).absolute + dbr_need_symtab, // can get by with symbol table if there's no dwarf + dbr_need_dwarf +}; + +enum info_status +{ + info_unknown, + info_present, + info_absent +}; struct func_info { func_info() - : decl_file(NULL), decl_line(-1), prologue_end(0) + : decl_file(NULL), decl_line(-1), addr(0), prologue_end(0) { memset(&die, 0, sizeof(die)); } @@ -457,6 +474,7 @@ func_info char const * decl_file; int decl_line; Dwarf_Die die; + Dwarf_Addr addr; Dwarf_Addr prologue_end; }; @@ -475,6 +493,78 @@ inline_instance_info }; +struct dwarf_query; // forward decls +struct dwflpp; +struct symbol_table; + +struct +module_info +{ + Dwfl_Module* mod; + const char* name; + string elf_path; + Dwarf_Addr addr; + Dwarf_Addr bias; + symbol_table *sym_table; + info_status dwarf_status; // module has dwarf info? + info_status symtab_status; // symbol table cached? + + void get_symtab(dwarf_query *q); + + module_info(const char *name) : + mod(NULL), + name(name), + addr(0), + bias(0), + sym_table(NULL), + dwarf_status(info_unknown), + symtab_status(info_unknown) + {} + + ~module_info(); +}; + +struct +module_cache +{ + map<string, module_info*> cache; + bool paths_collected; + bool dwarf_collected; + + module_cache() : paths_collected(false), dwarf_collected(false) {} +}; +typedef struct module_cache module_cache_t; + +typedef map<string, vector<Dwarf_Die>*> cu_function_cache_t; + +struct +symbol_table +{ + module_info *mod_info; // associated module + map<string, func_info*> map_by_name; + vector<func_info*> list_by_addr; + + void add_symbol(const char *name, Dwarf_Addr addr, Dwarf_Addr *high_addr); + enum info_status read_symbols(FILE *f, const string& path); + enum info_status read_from_elf_file(const string& path); + enum info_status read_from_text_file(const string& path); + enum info_status get_from_elf(); + void mark_dwarf_redundancies(dwflpp *dw); + func_info *lookup_symbol(const string& name); + Dwarf_Addr lookup_symbol_address(const string& name); + func_info *get_func_containing_address(Dwarf_Addr addr); + int get_index_for_address(Dwarf_Addr addr); + + symbol_table(module_info *mi) : mod_info(mi) {} + ~symbol_table(); +}; + +static bool null_die(Dwarf_Die *die) +{ + static Dwarf_Die null = { 0 }; + return (!die || !memcmp(die, &null, sizeof(null))); +} + static int query_cu (Dwarf_Die * cudie, void * arg); @@ -489,9 +579,6 @@ dwarf_diename_integrate (Dwarf_Die *die) return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem)); } - -struct dwarf_query; // forward decl - struct dwflpp { systemtap_session & sess; @@ -501,6 +588,7 @@ struct dwflpp Dwfl_Module * module; Dwarf * module_dwarf; Dwarf_Addr module_bias; + module_info * mod_info; // These describe the current module's PC address range Dwarf_Addr module_start; @@ -522,40 +610,55 @@ struct dwflpp } - void get_module_dwarf(bool required = false) + void get_module_dwarf(bool required = false, bool report = true) { - if (!module_dwarf) - module_dwarf = dwfl_module_getdwarf(module, &module_bias); - - if (!module_dwarf) + if (!module_dwarf && mod_info->dwarf_status != info_absent) { - string msg = "cannot find "; - if (module_name == "") - msg += "kernel"; - else - msg += string("module ") + module_name; - msg += " debuginfo"; - - int i = dwfl_errno(); - if (i) - msg += string(": ") + dwfl_errmsg (i); + if (!sess.ignore_dwarf) + module_dwarf = dwfl_module_getdwarf(module, &module_bias); + mod_info->dwarf_status = (module_dwarf ? info_present : info_absent); + } - if (required) - throw semantic_error (msg); - else - cerr << "WARNING: " << msg << "\n"; + if (!module_dwarf && report) + { + string msg = "cannot find "; + if (module_name == "") + msg += "kernel"; + else + msg += string("module ") + module_name; + msg += " debuginfo"; + + int i = dwfl_errno(); + if (i) + msg += string(": ") + dwfl_errmsg (i); + + if (required) + throw semantic_error (msg); + else + cerr << "WARNING: " << msg << "\n"; } } - void focus_on_module(Dwfl_Module * m) + void focus_on_module(Dwfl_Module * m, module_info * mi) { - assert(m); module = m; - module_name = default_name(dwfl_module_info(module, NULL, + mod_info = mi; + if (m) + { + module_name = default_name(dwfl_module_info(module, NULL, &module_start, &module_end, NULL, NULL, NULL, NULL), "module"); + } + else + { + assert(mi && mi->name && mi->name == TOK_KERNEL); + module_name = mi->name; + module_start = 0; + module_end = 0; + module_bias = mi->bias; + } // Reset existing pointers and names @@ -601,7 +704,7 @@ struct dwflpp cu = NULL; Dwfl_Module* mod = dwfl_addrmodule(dwfl, a); if (mod) // address could be wildly out of range - focus_on_module(mod); + focus_on_module(mod, NULL); } @@ -644,7 +747,6 @@ struct dwflpp bool module_name_matches(string pattern) { - assert(module); bool t = (fnmatch(pattern.c_str(), module_name.c_str(), 0) == 0); if (t && sess.verbose>3) clog << "pattern '" << pattern << "' " @@ -652,27 +754,35 @@ struct dwflpp << "module '" << module_name << "'" << "\n"; return t; } + bool name_has_wildcard(string pattern) + { + return (pattern.find('*') != string::npos || + pattern.find('?') != string::npos || + pattern.find('[') != string::npos); + } bool module_name_final_match(string pattern) { // Assume module_name_matches(). Can there be any more matches? // Not unless the pattern is a wildcard, since module names are // presumed unique. - return (pattern.find('*') == string::npos && - pattern.find('?') == string::npos && - pattern.find('[') == string::npos); + return !name_has_wildcard(pattern); } - bool function_name_matches(string pattern) + bool function_name_matches_pattern(string name, string pattern) { - assert(function); - bool t = (fnmatch(pattern.c_str(), function_name.c_str(), 0) == 0); + bool t = (fnmatch(pattern.c_str(), name.c_str(), 0) == 0); if (t && sess.verbose>3) clog << "pattern '" << pattern << "' " << "matches " - << "function '" << function_name << "'" << "\n"; + << "function '" << name << "'" << "\n"; return t; } + bool function_name_matches(string pattern) + { + assert(function); + return function_name_matches_pattern(function_name, pattern); + } bool function_name_final_match(string pattern) { return module_name_final_match (pattern); @@ -714,20 +824,57 @@ struct dwflpp throw semantic_error (msg); } + // static so pathname_caching_callback() can access them + static module_cache_t module_cache; + static bool ignore_vmlinux; + - dwflpp(systemtap_session & sess) + dwflpp(systemtap_session & session) : - sess(sess), + sess(session), dwfl(NULL), module(NULL), module_dwarf(NULL), module_bias(0), + mod_info(NULL), module_start(0), module_end(0), cu(NULL), function(NULL) - {} + { + ignore_vmlinux = sess.ignore_vmlinux; + } + + // Called by dwfl_linux_kernel_report_offline(). We may not have + // dwarf info for the kernel and/or modules, so remember this + // module's pathname in case we need to extract elf info from it. + // (Currently, we get all the elf info we need via elfutils -- if the + // elf file exists -- so remembering the pathname isn't strictly needed. + // But we still need to handle the case where there's no vmlinux.) + static int pathname_caching_callback(const char *name, const char *path) + { + module_info *mi = new module_info(name); + module_cache.cache[name] = mi; + if (ignore_vmlinux && path && name == TOK_KERNEL) + { + // report_kernel() in elfutils found vmlinux, but pretend it didn't. + // Given a non-null path, returning 1 means keep reporting modules. + mi->dwarf_status = info_absent; + return 1; + } + else if (path) + { + mi->elf_path = path; + return 1; + } + + // No vmlinux. Here returning 0 to report_kernel() means go ahead + // and keep reporting modules. + assert(name == TOK_KERNEL); + mi->dwarf_status = info_absent; + return 0; + } void setup(bool kernel, bool debuginfo_needed = true) { @@ -761,10 +908,18 @@ struct dwflpp throw semantic_error ("cannot open dwfl"); dwfl_report_begin (dwfl); + int (*callback)(const char *name, const char *path); + if (sess.consult_symtab && !module_cache.paths_collected) + { + callback = pathname_caching_callback; + module_cache.paths_collected = true; + } + else + callback = NULL; int rc = dwfl_linux_kernel_report_offline (dwfl, sess.kernel_release.c_str(), /* selection predicate */ - NULL); + callback); if (debuginfo_needed) dwfl_assert (string("missing kernel ") + sess.kernel_release + @@ -806,36 +961,34 @@ struct dwflpp // ----------------------------------------------------------------- - struct module_cache_entry { - Dwfl_Module* mod; - const char* name; - Dwarf_Addr addr; - }; - typedef vector<module_cache_entry> module_cache_t; - module_cache_t module_cache; - static int module_caching_callback(Dwfl_Module * mod, void **, const char *name, Dwarf_Addr addr, void *param) { - module_cache_t* cache = static_cast<module_cache_t*>(param); - module_cache_entry it; - it.mod = mod; - it.name = name; - it.addr = addr; - cache->push_back (it); + module_cache_t *cache = static_cast<module_cache_t*>(param); + module_info *mi = NULL; + + if (ignore_vmlinux && name == TOK_KERNEL) + // This wouldn't be called for vmlinux if vmlinux weren't there. + return DWARF_CB_OK; + + if (cache->paths_collected) + mi = cache->cache[name]; + if (!mi) + { + mi = new module_info(name); + cache->cache[name] = mi; + } + mi->mod = mod; + mi->addr = addr; return DWARF_CB_OK; } - - void iterate_over_modules(int (* callback)(Dwfl_Module *, void **, - const char *, Dwarf_Addr, - void *), - void * data) + void cache_modules_dwarf() { - if (module_cache.empty()) + if (!module_cache.dwarf_collected) { ptrdiff_t off = 0; do @@ -846,18 +999,29 @@ struct dwflpp } while (off > 0); dwfl_assert("dwfl_getmodules", off); + module_cache.dwarf_collected = true; } + } - // Traverse the cache. - for (unsigned i = 0; i < module_cache.size(); i++) + void iterate_over_modules(int (* callback)(Dwfl_Module *, module_info *, + const char *, Dwarf_Addr, + void *), + void * data) + { + cache_modules_dwarf(); + + map<string, module_info*>::iterator i; + for (i = module_cache.cache.begin(); i != module_cache.cache.end(); i++) { if (pending_interrupts) return; - module_cache_entry& it = module_cache[i]; - int rc = callback (it.mod, 0, it.name, it.addr, data); + module_info *mi = i->second; + int rc = callback (mi->mod, mi, mi->name, mi->addr, data); if (rc != DWARF_CB_OK) break; } } + // Defined after dwarf_query + void query_modules(dwarf_query *q); // ----------------------------------------------------------------- @@ -947,7 +1111,6 @@ struct dwflpp // ----------------------------------------------------------------- - typedef map<string, vector<Dwarf_Die>*> cu_function_cache_t; cu_function_cache_t cu_function_cache; static int cu_function_caching_callback (Dwarf_Die* func, void *arg) @@ -957,9 +1120,10 @@ struct dwflpp return DWARF_CB_OK; } - void iterate_over_functions (int (* callback)(Dwarf_Die * func, void * arg), + int iterate_over_functions (int (* callback)(Dwarf_Die * func, void * arg), void * data) { + int rc = DWARF_CB_OK; assert (module); assert (cu); @@ -975,9 +1139,10 @@ struct dwflpp for (unsigned i=0; i<v->size(); i++) { Dwarf_Die die = v->at(i); - int rc = (*callback)(& die, data); + rc = (*callback)(& die, data); if (rc != DWARF_CB_OK) break; } + return rc; } @@ -2018,6 +2183,9 @@ struct dwflpp } }; +module_cache_t dwflpp::module_cache; +bool dwflpp::ignore_vmlinux = false; + enum function_spec_type @@ -2029,7 +2197,6 @@ function_spec_type struct dwarf_builder; -struct dwarf_query; // XXX: This class is a candidate for subclassing to separate @@ -2187,6 +2354,8 @@ struct dwarf_query : public base_query vector<derived_probe *> & results); virtual void handle_query_module(); + void query_module_dwarf(); + void query_module_symtab(); void add_probe_point(string const & funcname, char const * filename, @@ -2234,11 +2403,15 @@ struct dwarf_query : public base_query bool has_absolute; + enum dbinfo_reqt dbinfo_reqt; + enum dbinfo_reqt assess_dbinfo_reqt(); + function_spec_type parse_function_spec(string & spec); function_spec_type spec_type; string function; string file; int line; + bool query_done; // Found exact match set<char const *> filtered_srcfiles; @@ -2375,11 +2548,13 @@ dwarf_query::dwarf_query(systemtap_session & sess, spec_type = parse_function_spec(statement_str_val); build_blacklist(); // XXX: why not reuse amongst dwarf_query instances? + dbinfo_reqt = assess_dbinfo_reqt(); + query_done = false; } void -dwarf_query::handle_query_module() +dwarf_query::query_module_dwarf() { if (has_function_num || has_statement_num) { @@ -2408,6 +2583,110 @@ dwarf_query::handle_query_module() } } +static void query_func_info (Dwarf_Addr entrypc, func_info & fi, + dwarf_query * q); + +void +dwarf_query::query_module_symtab() +{ + // Get the symbol table if it's necessary, sufficient, and not already got. + if (dbinfo_reqt == dbr_need_dwarf) + return; + + module_info *mi = dw.mod_info; + if (dbinfo_reqt == dbr_need_symtab) + { + if (mi->symtab_status == info_unknown) + mi->get_symtab(this); + if (mi->symtab_status == info_absent) + return; + } + + func_info *fi = NULL; + symbol_table *sym_table = mi->sym_table; + + if (has_function_str) + { + // Per dwarf_query::assess_dbinfo_reqt()... + assert(spec_type == function_alone); + if (dw.name_has_wildcard(function_str_val)) + { + // Until we augment the blacklist sufficently... + if (function_str_val.find_first_not_of("*?") == string::npos) + { + // e.g., kernel.function("*") + cerr << "Error: Pattern '" + << function_str_val + << "' matches every instruction address in the symbol table," + << endl + << "some of which aren't even functions." + << " Please be more precise." + << endl; + return; + } + + size_t i; + size_t nsyms = sym_table->list_by_addr.size(); + for (i = 0; i < nsyms; i++) + { + fi = sym_table->list_by_addr.at(i); + if (!null_die(&fi->die)) + continue; // already handled in query_module_dwarf() + if (dw.function_name_matches_pattern(fi->name, function_str_val)) + query_func_info(fi->addr, *fi, this); + } + } + else + { + fi = sym_table->lookup_symbol(function_str_val); + if (fi && null_die(&fi->die)) + query_func_info(fi->addr, *fi, this); + } + } + else + { + assert(has_function_num || has_statement_num); + // Find the "function" in which the indicated address resides. + Dwarf_Addr addr = + (has_function_num ? function_num_val : statement_num_val); + fi = sym_table->get_func_containing_address(addr); + if (!fi) + { + cerr << "Warning: address " + << hex << addr << dec + << " out of range for module " + << dw.module_name; + return; + } + if (!null_die(&fi->die)) + { + // addr looks like it's in the compilation unit containing + // the indicated function, but query_module_dwarf() didn't + // match addr to any compilation unit, so addr must be + // above that cu's address range. + cerr << "Warning: address " + << hex << addr << dec + << " maps to no known compilation unit in module " + << dw.module_name; + return; + } + query_func_info(fi->addr, *fi, this); + } +} + +void +dwarf_query::handle_query_module() +{ + dw.get_module_dwarf(false, + (dbinfo_reqt == dbr_need_dwarf || !sess.consult_symtab)); + if (dw.mod_info->dwarf_status == info_present) + query_module_dwarf(); + // Consult the symbol table if we haven't found all we're looking for. + // asm functions can show up in the symbol table but not in dwarf. + if (sess.consult_symtab && !query_done) + query_module_symtab(); +} + void dwarf_query::build_blacklist() @@ -2604,7 +2883,7 @@ dwarf_query::parse_function_spec(string & spec) // Forward declaration. -static int query_kernel_module (Dwfl_Module *, void **, const char *, +static int query_kernel_module (Dwfl_Module *, module_info *, const char *, Dwarf_Addr, void *); @@ -2728,7 +3007,13 @@ dwarf_query::add_probe_point(const string& funcname, assert (! has_absolute); // already handled in dwarf_builder::build() - if (dwfl_module_relocations (dw.module) > 0) + if (!dw.module) + { + assert(module == TOK_KERNEL); + reloc_section = ""; + blacklist_section = ""; + } + else if (dwfl_module_relocations (dw.module) > 0) { // This is arelocatable module; libdwfl already knows its // sections, so we can relativize addr. @@ -2778,6 +3063,44 @@ dwarf_query::add_probe_point(const string& funcname, } } +enum dbinfo_reqt +dwarf_query::assess_dbinfo_reqt() +{ + if (has_absolute) + { + // kernel.statement(NUM).absolute + return dbr_none; + } + if (has_inline) + { + // kernel.function("f").inline or module("m").function("f").inline + return dbr_need_dwarf; + } + if (has_function_str && spec_type == function_alone) + { + // kernel.function("f") or module("m").function("f") + return dbr_need_symtab; + } + if (has_statement_num) + { + // kernel.statement(NUM) or module("m").statement(NUM) + // Technically, all we need is the module offset (or _stext, for + // the kernel). But for that we need either the ELF file or (for + // _stext) the symbol table. In either case, the symbol table + // is available, and that allows us to map the NUM (address) + // to a function, which is goodness. + return dbr_need_symtab; + } + if (has_function_num) + { + // kernel.function(NUM) or module("m").function(NUM) + // Need the symbol table so we can back up from NUM to the + // start of the function. + return dbr_need_symtab; + } + // Symbol table tells us nothing about source files or line numbers. + return dbr_need_dwarf; +} @@ -3110,7 +3433,9 @@ query_cu (Dwarf_Die * cudie, void * arg) // Pick up [entrypc, name, DIE] tuples for all the functions // matching the query, and fill in the prologue endings of them // all in a single pass. - q->dw.iterate_over_functions (query_dwarf_func, q); + int rc = q->dw.iterate_over_functions (query_dwarf_func, q); + if (rc != DWARF_CB_OK) + q->query_done = true; if (q->sess.prologue_searching && !q->has_statement_str && !q->has_statement_num) // PR 2608 @@ -3171,7 +3496,7 @@ query_cu (Dwarf_Die * cudie, void * arg) static int query_kernel_module (Dwfl_Module *mod, - void **, + module_info *, const char *name, Dwarf_Addr, void *arg) @@ -3186,10 +3511,74 @@ query_kernel_module (Dwfl_Module *mod, return DWARF_CB_OK; } +static void +validate_module_elf (Dwfl_Module *mod, const char *name, base_query *q) +{ + // Validate the machine code in this elf file against the + // session machine. This is important, in case the wrong kind + // of debuginfo is being automagically processed by elfutils. + // While we can tell i686 apart from x86-64, unfortunately + // we can't help confusing i586 vs i686 (both EM_386). + + Dwarf_Addr bias; + // We prefer dwfl_module_getdwarf to dwfl_module_getelf here, + // because dwfl_module_getelf can force costly section relocations + // we don't really need, while either will do for this purpose. + Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (mod, &bias)) + ?: dwfl_module_getelf (mod, &bias)); + + GElf_Ehdr ehdr_mem; + GElf_Ehdr* em = gelf_getehdr (elf, &ehdr_mem); + if (em == 0) { q->dw.dwfl_assert ("dwfl_getehdr", dwfl_errno()); } + int elf_machine = em->e_machine; + const char* debug_filename = ""; + const char* main_filename = ""; + (void) dwfl_module_info (mod, NULL, NULL, + NULL, NULL, NULL, + & main_filename, + & debug_filename); + const string& sess_machine = q->sess.architecture; + string expect_machine; + + switch (elf_machine) + { + case EM_386: expect_machine = "i?86"; break; // accept e.g. i586 + case EM_X86_64: expect_machine = "x86_64"; break; + case EM_PPC: expect_machine = "ppc"; break; + case EM_PPC64: expect_machine = "ppc64"; break; + case EM_S390: expect_machine = "s390x"; break; + case EM_IA_64: expect_machine = "ia64"; break; + case EM_ARM: expect_machine = "armv*"; break; + // XXX: fill in some more of these + default: expect_machine = "?"; break; + } + + if (! debug_filename) debug_filename = main_filename; + if (! debug_filename) debug_filename = name; + + if (fnmatch (expect_machine.c_str(), sess_machine.c_str(), 0) != 0) + { + stringstream msg; + msg << "ELF machine " << expect_machine << " (code " << elf_machine + << ") mismatch with target " << sess_machine + << " in '" << debug_filename << "'"; + throw semantic_error(msg.str ()); + } + + if (q->sess.verbose>2) + clog << "focused on module '" << q->dw.module_name + << " = [0x" << hex << q->dw.module_start + << "-0x" << q->dw.module_end + << ", bias 0x" << q->dw.module_bias << "]" << dec + << " file " << debug_filename + << " ELF machine " << expect_machine + << " (code " << elf_machine << ")" + << "\n"; +} static int query_module (Dwfl_Module *mod, - void **, + module_info *mi, const char *name, Dwarf_Addr, void *arg) @@ -3198,7 +3587,7 @@ query_module (Dwfl_Module *mod, try { - q->dw.focus_on_module(mod); + q->dw.focus_on_module(mod, mi); // If we have enough information in the pattern to skip a module and // the module does not match that information, return early. @@ -3211,67 +3600,15 @@ query_module (Dwfl_Module *mod, if (q->dw.module_name == TOK_KERNEL && ! q->has_kernel) return DWARF_CB_OK; - // Validate the machine code in this elf file against the - // session machine. This is important, in case the wrong kind - // of debuginfo is being automagically processed by elfutils. - // While we can tell i686 apart from x86-64, unfortunately - // we can't help confusing i586 vs i686 (both EM_386). - - Dwarf_Addr bias; - // We prefer dwfl_module_getdwarf to dwfl_module_getelf here, - // because dwfl_module_getelf can force costly section relocations - // we don't really need, while either will do for this purpose. - Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (mod, &bias)) - ?: dwfl_module_getelf (mod, &bias)); - - GElf_Ehdr ehdr_mem; - GElf_Ehdr* em = gelf_getehdr (elf, &ehdr_mem); - if (em == 0) { q->dw.dwfl_assert ("dwfl_getehdr", dwfl_errno()); } - int elf_machine = em->e_machine; - const char* debug_filename = ""; - const char* main_filename = ""; - (void) dwfl_module_info (mod, NULL, NULL, - NULL, NULL, NULL, - & main_filename, - & debug_filename); - const string& sess_machine = q->sess.architecture; - string expect_machine; - - switch (elf_machine) - { - case EM_386: expect_machine = "i?86"; break; // accept e.g. i586 - case EM_X86_64: expect_machine = "x86_64"; break; - case EM_PPC: expect_machine = "ppc"; break; - case EM_PPC64: expect_machine = "ppc64"; break; - case EM_S390: expect_machine = "s390x"; break; - case EM_IA_64: expect_machine = "ia64"; break; - case EM_ARM: expect_machine = "armv*"; break; - // XXX: fill in some more of these - default: expect_machine = "?"; break; - } - - if (! debug_filename) debug_filename = main_filename; - if (! debug_filename) debug_filename = name; - - if (fnmatch (expect_machine.c_str(), sess_machine.c_str(), 0) != 0) + if (mod) + validate_module_elf(mod, name, q); + else { - stringstream msg; - msg << "ELF machine " << expect_machine << " (code " << elf_machine - << ") mismatch with target " << sess_machine - << " in '" << debug_filename << "'"; - throw semantic_error(msg.str ()); + assert(q->has_kernel); // and no vmlinux to examine + if (q->sess.verbose>2) + cerr << "focused on module '" << q->dw.module_name << "'\n"; } - if (q->sess.verbose>2) - clog << "focused on module '" << q->dw.module_name - << " = [0x" << hex << q->dw.module_start - << "-0x" << q->dw.module_end - << ", bias 0x" << q->dw.module_bias << "]" << dec - << " file " << debug_filename - << " ELF machine " << expect_machine - << " (code " << elf_machine << ")" - << "\n"; - q->handle_query_module(); // If we know that there will be no more matches, abort early. @@ -3287,6 +3624,24 @@ query_module (Dwfl_Module *mod, } } +void +dwflpp::query_modules(dwarf_query *q) +{ + string name = q->module_val; + if (name_has_wildcard(name)) + iterate_over_modules(&query_module, q); + else + { + cache_modules_dwarf(); + + map<string, module_info*>::iterator i = module_cache.cache.find(name); + if (i != module_cache.cache.end()) + { + module_info *mi = i->second; + query_module(mi->mod, mi, name.c_str(), mi->addr, q); + } + } +} struct var_expanding_copy_visitor: public deep_copy_visitor { @@ -3818,7 +4173,7 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, q.base_loc->tok); // Make a target-variable-expanded copy of the probe body - if (scope_die) + if (!null_die(scope_die)) { dwarf_var_expanding_copy_visitor v (q, scope_die, dwfl_addr); require <statement*> (&v, &(this->body), this->body); @@ -4274,7 +4629,300 @@ dwarf_builder::build(systemtap_session & sess, return; } - dw->iterate_over_modules(&query_module, &q); + // dw->iterate_over_modules(&query_module, &q); + dw->query_modules(&q); +} + +symbol_table::~symbol_table() +{ + // map::clear() and vector::clear() don't call destructors for + // pointers, only for objects. + int i; + int nsym = (int) list_by_addr.size(); + for (i = 0; i < nsym; i++) + delete list_by_addr.at(i); + list_by_addr.clear(); + map_by_name.clear(); +} + +void +symbol_table::add_symbol(const char *name, Dwarf_Addr addr, + Dwarf_Addr *high_addr) +{ + func_info *fi = new func_info(); + fi->addr = addr; + fi->name = name; + map_by_name[fi->name] = fi; + // TODO: Use a multimap in case there are multiple static + // functions with the same name? + if (addr >= *high_addr) + { + list_by_addr.push_back(fi); + *high_addr = addr; + } + else + { + // Symbols aren't in numerical order. FWIW, sort(1) doesn't + // handle hex numbers without the leading 0x. + int index = get_index_for_address(fi->addr); + list_by_addr.insert(list_by_addr.begin()+(index+1), fi); + } +} + +enum info_status +symbol_table::read_symbols(FILE *f, const string& path) +{ + // Based on do_kernel_symbols() in runtime/staprun/symbols.c + int ret; + char *name, *mod; + char type; + unsigned long long addr; + Dwarf_Addr high_addr = 0; + int line = 0; + + // %as (non-POSIX) mallocs space for the string and stores its address. + while ((ret = fscanf(f, "%llx %c %as [%as", &addr, &type, &name, &mod)) > 0) + { + line++; + if (ret < 3) + { + cerr << "Symbol table error: Line " + << line + << " of symbol list from " + << path + << " is not in correct format: address type name [module]"; + // Caller should delete symbol_table object. + return info_absent; + } + if (ret > 3) + { + // Modules are loaded above the kernel, so if we're getting + // modules, we're done. + free(name); + free(mod); + goto done; + } + if (type == 'T' || type == 't') + add_symbol(name, (Dwarf_Addr) addr, &high_addr); + free(name); + } + +done: + if (list_by_addr.size() < 1) + { + cerr << "Symbol table error: " + << path << " contains no function symbols." << endl; + return info_absent; + } + return info_present; +} + +// NB: This currently unused. We use get_from_elf() instead because +// that gives us raw addresses -- which we need for modules -- whereas +// nm provides the address relative to the beginning of the section. +enum info_status +symbol_table::read_from_elf_file(const string &path) +{ + FILE *f; + string cmd = string("/usr/bin/nm -n --defined-only ") + path; + f = popen(cmd.c_str(), "r"); + if (!f) + { + // nm failures are detected by pclose, not popen. + cerr << "Internal error reading symbol table from " + << path << " -- " << strerror (errno); + return info_absent; + } + enum info_status status = read_symbols(f, path); + if (pclose(f) != 0) + { + if (status == info_present) + cerr << "Warning: nm cannot read symbol table from " << path; + return info_absent; + } + return status; +} + +enum info_status +symbol_table::read_from_text_file(const string& path) +{ + FILE *f = fopen(path.c_str(), "r"); + if (!f) + { + cerr << "Warning: cannot read symbol table from " + << path << " -- " << strerror (errno); + return info_absent; + } + enum info_status status = read_symbols(f, path); + (void) fclose(f); + return status; +} + +enum info_status +symbol_table::get_from_elf() +{ + Dwarf_Addr high_addr = 0; + Dwfl_Module *mod = mod_info->mod; + int syments = dwfl_module_getsymtab(mod); + assert(syments); + for (int i = 1; i < syments; ++i) + { + GElf_Sym sym; + const char *name = dwfl_module_getsym(mod, i, &sym, NULL); + if (name && GELF_ST_TYPE(sym.st_info) == STT_FUNC) + add_symbol(name, sym.st_value, &high_addr); + } + return info_present; +} + +void +symbol_table::mark_dwarf_redundancies(dwflpp *dw) +{ + // dwflpp.cu_function_cache maps each module_name:cu_name to a + // vector of Dwarf_Dies, one per function. + string module_prefix = string(mod_info->name) + ":"; + + cu_function_cache_t::iterator cu; + for (cu = dw->cu_function_cache.begin(); + cu != dw->cu_function_cache.end(); cu++) + { + string key = cu->first; + if (key.find(module_prefix) == 0) + { + // Found a compilation unit in the module of interest. + // Mark all its functions in the symbol table. + vector<Dwarf_Die>* v = cu->second; + assert(v); + for (unsigned f=0; f < v->size(); f++) + { + Dwarf_Die func = v->at(f); + string func_name = dwarf_diename(&func); + // map_by_name[func_name]->die = func; + map<string, func_info*>::iterator i = map_by_name.find(func_name); + // Func names can show up in the dwarf but not the symtab (!). + if (i != map_by_name.end()) + { + func_info *fi = i->second; + fi->die = func; + } + } + } + } +} + +func_info * +symbol_table::get_func_containing_address(Dwarf_Addr addr) +{ + int index = get_index_for_address(addr); + if (index < 0) + return NULL; + return list_by_addr.at(index); +} + +// Find the index in list_by_addr of the last element whose address +// is <= addr. Returns -1 if addr is less than the first address in +// list_by_addr. +int +symbol_table::get_index_for_address(Dwarf_Addr addr) +{ + // binary search from runtime/sym.c + int begin = 0; + int mid; + int end = list_by_addr.size(); + + if (end == 0 || addr < list_by_addr.at(0)->addr) + return -1; + do + { + mid = (begin + end) / 2; + if (addr < list_by_addr.at(mid)->addr) + end = mid; + else + begin = mid; + } + while (begin + 1 < end); + return begin; +} + +func_info * +symbol_table::lookup_symbol(const string& name) +{ + map<string, func_info*>::iterator i = map_by_name.find(name); + if (i == map_by_name.end()) + return NULL; + return i->second; +} + +Dwarf_Addr +symbol_table::lookup_symbol_address(const string& name) +{ + func_info *fi = lookup_symbol(name); + if (fi) + return fi->addr; + return 0; +} + +void +module_info::get_symtab(dwarf_query *q) +{ + systemtap_session &sess = q->sess; + + sym_table = new symbol_table(this); + if (!elf_path.empty()) + { + if (name == TOK_KERNEL && !sess.kernel_symtab_path.empty()) + cerr << "Warning: reading symbol table from " + << elf_path + << " -- ignoring " + << sess.kernel_symtab_path + << endl ;; + symtab_status = sym_table->get_from_elf(); + } + else + { + assert(name == TOK_KERNEL); + if (sess.kernel_symtab_path.empty()) + { + symtab_status = info_absent; + cerr << "Error: Cannot find vmlinux." + << " Consider using --kmap instead of --kelf." + << endl;; + } + else + { + symtab_status = + sym_table->read_from_text_file(sess.kernel_symtab_path); + if (symtab_status == info_present) + { + sess.sym_kprobes_text_start = + sym_table->lookup_symbol_address("__kprobes_text_start"); + sess.sym_kprobes_text_end = + sym_table->lookup_symbol_address("__kprobes_text_end"); + sess.sym_stext = sym_table->lookup_symbol_address("_stext"); + bias = sym_table->lookup_symbol_address("_text"); + } + } + } + if (symtab_status == info_absent) + { + delete sym_table; + sym_table = NULL; + return; + } + + // If we have dwarf for the same module, mark the redundant symtab + // entries. + // + // In dwarf_query::handle_query_module(), the call to query_module_dwarf() + // precedes the call to query_module_symtab(). So we should never read + // a module's symbol table without first having tried to get its dwarf. + sym_table->mark_dwarf_redundancies(&q->dw); +} + +module_info::~module_info() +{ + if (sym_table) + delete sym_table; } diff --git a/testsuite/semko/nodwf01.stp b/testsuite/semko/nodwf01.stp new file mode 100755 index 00000000..25217bac --- /dev/null +++ b/testsuite/semko/nodwf01.stp @@ -0,0 +1,14 @@ +#!/bin/sh +# +# Verify that --ignore-vmlinux "hides" vmlinux. + +stap -p2 --ignore-vmlinux -e ' +probe kernel.function("printk") { + printf("%s called\n", probefunc()) + exit() +} + +probe timer.sec(30) { + exit() +} +' diff --git a/testsuite/semko/nodwf02.stp b/testsuite/semko/nodwf02.stp new file mode 100755 index 00000000..8f82d54b --- /dev/null +++ b/testsuite/semko/nodwf02.stp @@ -0,0 +1,14 @@ +#!/bin/sh +# +# Verify that --ignore-dwarf "hides" dwarf info. + +stap -p2 --ignore-dwarf -e ' +probe kernel.function("printk") { + printf("%s called\n", probefunc()) + exit() +} + +probe timer.sec(30) { + exit() +} +' diff --git a/testsuite/semko/nodwf03.stp b/testsuite/semko/nodwf03.stp new file mode 100755 index 00000000..6b66f2e9 --- /dev/null +++ b/testsuite/semko/nodwf03.stp @@ -0,0 +1,14 @@ +#!/bin/sh +# +# --kelf doesn't work if vmlinux can't be found. + +stap -p2 --ignore-vmlinux --kelf -e ' +probe kernel.function("printk") { + printf("%s called\n", probefunc()) + exit() +} + +probe timer.sec(30) { + exit() +} +' diff --git a/testsuite/semko/nodwf04.stp b/testsuite/semko/nodwf04.stp new file mode 100755 index 00000000..c20dec4f --- /dev/null +++ b/testsuite/semko/nodwf04.stp @@ -0,0 +1,14 @@ +#!/bin/sh +# +# The symbol table doesn't give us enough info to probe inline functions. + +stap -p2 --ignore-vmlinux --kmap=/proc/kallsyms -e ' +probe kernel.function("list_empty").inline { + printf("%s called\n", probefunc()) + exit() +} + +probe timer.sec(15) { + exit() +} +' diff --git a/testsuite/semko/nodwf05.stp b/testsuite/semko/nodwf05.stp new file mode 100755 index 00000000..83fcfa3d --- /dev/null +++ b/testsuite/semko/nodwf05.stp @@ -0,0 +1,14 @@ +#!/bin/sh +# +# The symbol table doesn't give us enough info to map source files to functions. + +stap -p2 --ignore-vmlinux --kmap=/proc/kallsyms -e ' +probe kernel.function("*@kernel/printk.c") { + printf("%s called\n", probefunc()) + exit() +} + +probe timer.sec(15) { + exit() +} +' diff --git a/testsuite/semko/nodwf06.stp b/testsuite/semko/nodwf06.stp new file mode 100755 index 00000000..7318cbec --- /dev/null +++ b/testsuite/semko/nodwf06.stp @@ -0,0 +1,14 @@ +#!/bin/sh +# +# The symbol table doesn't give us enough info to probe statements. + +stap -p2 --ignore-vmlinux --kmap=/proc/kallsyms -e ' +probe kernel.statement("*@kernel/printk.c:639") { + printf("probe hit: %s\n", pp()) + exit() +} + +probe timer.sec(15) { + exit() +} +' diff --git a/testsuite/semko/nodwf07.stp b/testsuite/semko/nodwf07.stp new file mode 100755 index 00000000..4a2cf4a5 --- /dev/null +++ b/testsuite/semko/nodwf07.stp @@ -0,0 +1,15 @@ +#!/bin/sh +# +# This should fail until/unless we expand our blacklist to cover symbols +# in the symbol table that don't show up in dwarf. + +stap -p2 --ignore-vmlinux --kmap=/proc/kallsyms -e ' +probe kernel.function("*") { + printf("%s called\n", probefunc()) + exit() +} + +probe timer.sec(15) { + exit() +} +' diff --git a/testsuite/semko/nodwf08.stp b/testsuite/semko/nodwf08.stp new file mode 100755 index 00000000..4b6d9da5 --- /dev/null +++ b/testsuite/semko/nodwf08.stp @@ -0,0 +1,14 @@ +#!/bin/sh +# +# The regular blacklist should thwart this. + +stap -p2 --ignore-vmlinux --kmap=/proc/kallsyms -e ' +probe kernel.function("register_kprobe") { + printf("%s called\n", probefunc()) + exit() +} + +probe timer.sec(30) { + exit() +} +' diff --git a/testsuite/semko/nodwf09.stp b/testsuite/semko/nodwf09.stp new file mode 100755 index 00000000..e103833f --- /dev/null +++ b/testsuite/semko/nodwf09.stp @@ -0,0 +1,14 @@ +#!/bin/sh +# +# The symbol table doesn't give us enough info to evaluate target variables. + +stap -p2 --ignore-vmlinux --kmap=/proc/kallsyms -e ' +probe kernel.function("printk") { + printf("%s called; fmt = \"%s\"\n", probefunc(), kernel_string($fmt)) + exit() +} + +probe timer.sec(15) { + exit() +} +' diff --git a/testsuite/semok/nodwf01.stp b/testsuite/semok/nodwf01.stp new file mode 100755 index 00000000..c7a08f2a --- /dev/null +++ b/testsuite/semok/nodwf01.stp @@ -0,0 +1,12 @@ +#!/bin/sh + +stap -p2 --ignore-vmlinux --kmap=/proc/kallsyms -e ' +global nret + +probe syscall.*.return { + /* NB: $return does NOT currently work here. */ + printf("%s returns %s\n", name, returnstr(2)); + if (nret++ > 50) + exit() +} +' diff --git a/testsuite/semok/nodwf02.stp b/testsuite/semok/nodwf02.stp new file mode 100755 index 00000000..545f6154 --- /dev/null +++ b/testsuite/semok/nodwf02.stp @@ -0,0 +1,44 @@ +#!/bin/sh + +stap -p2 --ignore-vmlinux --kmap=/proc/kallsyms -e ' +global ncall + +/* + * We want + * probe syscall.* + * but in the syscall tapset, the prologue blocks for the following system + * calls contain "if" statements that cause target variables to be read... + * and we cannot evaluate target variables without dwarf. + * bdflush, clock_nanosleep, fork, futex, getrusage, mq_open, open, sysfs + */ +probe + syscall.a*, + /* skip b */ + /* skip c */ + syscall.d*, + syscall.e*, + /* skip f */ + /* skip g */ + /* no h */ + syscall.i*, + /* no j */ + syscall.k*, + syscall.l*, + /* skip m */ + syscall.n*, + /* skip o */ + syscall.p*, + syscall.q*, + syscall.r*, + /* skip s */ + syscall.t*, + syscall.u*, + syscall.v*, + syscall.w* + /* no xyz */ +{ + printf("%s called\n", name) + if (ncall++ > 50) + exit() +} +' diff --git a/testsuite/semok/nodwf03.stp b/testsuite/semok/nodwf03.stp new file mode 100755 index 00000000..6f8b3629 --- /dev/null +++ b/testsuite/semok/nodwf03.stp @@ -0,0 +1,13 @@ +#!/bin/sh +# +# Test function-name wildcard. + +stap -p2 --ignore-vmlinux --kmap=/proc/kallsyms -e ' +global ncall + +probe kernel.function("sys_*") { + printf("%s called\n", probefunc()) + if (ncall++ > 50) + exit() +} +' diff --git a/testsuite/semok/nodwf04.stp b/testsuite/semok/nodwf04.stp new file mode 100755 index 00000000..84438fda --- /dev/null +++ b/testsuite/semok/nodwf04.stp @@ -0,0 +1,14 @@ +#!/bin/sh +# +# Like nodwf01.stp, but extract the symbol table from vmlinux. + +stap -p2 --ignore-dwarf --kelf -e ' +global nret + +probe syscall.*.return { + /* NB: $return does NOT currently work here. */ + printf("%s returns %s\n", name, returnstr(2)); + if (nret++ > 50) + exit() +} +' diff --git a/testsuite/semok/nodwf05.stp b/testsuite/semok/nodwf05.stp new file mode 100755 index 00000000..d0043eab --- /dev/null +++ b/testsuite/semok/nodwf05.stp @@ -0,0 +1,46 @@ +#!/bin/sh +# +# Like nodwf02.stp, but extract the symbol table from vmlinux. + +stap -p2 --ignore-dwarf --kelf -e ' +global ncall + +/* + * We want + * probe syscall.* + * but in the syscall tapset, the prologue blocks for the following system + * calls contain "if" statements that cause target variables to be read... + * and we cannot evaluate target variables without dwarf. + * bdflush, clock_nanosleep, fork, futex, getrusage, mq_open, open, sysfs + */ +probe + syscall.a*, + /* skip b */ + /* skip c */ + syscall.d*, + syscall.e*, + /* skip f */ + /* skip g */ + /* no h */ + syscall.i*, + /* no j */ + syscall.k*, + syscall.l*, + /* skip m */ + syscall.n*, + /* skip o */ + syscall.p*, + syscall.q*, + syscall.r*, + /* skip s */ + syscall.t*, + syscall.u*, + syscall.v*, + syscall.w* + /* no xyz */ +{ + printf("%s called\n", name) + if (ncall++ > 50) + exit() +} +' diff --git a/testsuite/semok/nodwf06.stp b/testsuite/semok/nodwf06.stp new file mode 100755 index 00000000..d27e3f84 --- /dev/null +++ b/testsuite/semok/nodwf06.stp @@ -0,0 +1,14 @@ +#!/bin/sh +# +# Test function-name wildcard. +# Like nodwf03.stp, but extract the symbol table from vmlinux. + +stap -p2 --ignore-dwarf --kelf -e ' +global ncall + +probe kernel.function("sys_*") { + printf("%s called\n", probefunc()) + if (ncall++ > 50) + exit() +} +' diff --git a/testsuite/semok/nodwf07.stp b/testsuite/semok/nodwf07.stp new file mode 100755 index 00000000..d886ac79 --- /dev/null +++ b/testsuite/semok/nodwf07.stp @@ -0,0 +1,17 @@ +#!/bin/sh +# +# Test module-name and function-name wildcards. + +stap -p2 --ignore-dwarf --kelf -e ' +global ncall + +probe module("*").function("*_probe") { + printf("%s called\n", probefunc()) + if (ncall++ > 50) + exit() +} + +probe timer.sec(5) { + exit() +} +' diff --git a/translate.cxx b/translate.cxx index 3821e9cd..1782abd1 100644 --- a/translate.cxx +++ b/translate.cxx @@ -878,6 +878,7 @@ c_unparser::emit_common_header () o->newline() << "unsigned long *unwaddr;"; // unwaddr is caching unwound address in each probe handler on ia64. o->newline() << "struct kretprobe_instance *pi;"; + o->newline() << "int regparm;"; o->newline() << "va_list *mark_va_list;"; o->newline() << "void *data;"; o->newline() << "#ifdef STP_TIMING"; |