summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Keniston <jkenisto@us.ibm.com>2008-05-12 12:17:20 -0700
committerJim Keniston <jkenisto@us.ibm.com>2008-05-12 12:17:20 -0700
commitc7fe0041d2132e801f72e158854d54da50fc651d (patch)
tree258d955ef4a1ead4ba1102812d962c9c981d873b
parent8dd6b23de4dd099aa244402192cb3d7be2bda739 (diff)
parentda3fe5fe9641e7c4cc6ae5c4a289ddbc020aca1a (diff)
downloadsystemtap-steved-c7fe0041d2132e801f72e158854d54da50fc651d.tar.gz
systemtap-steved-c7fe0041d2132e801f72e158854d54da50fc651d.tar.xz
systemtap-steved-c7fe0041d2132e801f72e158854d54da50fc651d.zip
Merge commit 'origin/dwarfless'
PR 4311 - Function boundary tracing without debuginfo: Phases 1 and 2
-rw-r--r--ChangeLog45
-rw-r--r--hash.cxx15
-rw-r--r--main.cxx71
-rw-r--r--runtime/regs.c154
-rw-r--r--session.h6
-rw-r--r--stap.1.in76
-rw-r--r--stapfuncs.5.in104
-rw-r--r--tapset/i686/registers.stp202
-rw-r--r--tapset/nd_syscalls.stp2845
-rw-r--r--tapset/x86_64/registers.stp243
-rw-r--r--tapsets.cxx916
-rwxr-xr-xtestsuite/semko/nodwf01.stp14
-rwxr-xr-xtestsuite/semko/nodwf02.stp14
-rwxr-xr-xtestsuite/semko/nodwf03.stp14
-rwxr-xr-xtestsuite/semko/nodwf04.stp14
-rwxr-xr-xtestsuite/semko/nodwf05.stp14
-rwxr-xr-xtestsuite/semko/nodwf06.stp14
-rwxr-xr-xtestsuite/semko/nodwf07.stp15
-rwxr-xr-xtestsuite/semko/nodwf08.stp14
-rwxr-xr-xtestsuite/semko/nodwf09.stp14
-rwxr-xr-xtestsuite/semok/nodwf01.stp12
-rwxr-xr-xtestsuite/semok/nodwf02.stp44
-rwxr-xr-xtestsuite/semok/nodwf03.stp13
-rwxr-xr-xtestsuite/semok/nodwf04.stp14
-rwxr-xr-xtestsuite/semok/nodwf05.stp46
-rwxr-xr-xtestsuite/semok/nodwf06.stp14
-rwxr-xr-xtestsuite/semok/nodwf07.stp17
-rw-r--r--translate.cxx1
28 files changed, 4829 insertions, 136 deletions
diff --git a/ChangeLog b/ChangeLog
index 1054e468..e913e76b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,48 @@
+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-07 Frank Ch. Eigler <fche@elastic.org>
PR 6492.
diff --git a/hash.cxx b/hash.cxx
index d05be268..c41600d2 100644
--- a/hash.cxx
+++ b/hash.cxx
@@ -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]);
diff --git a/main.cxx b/main.cxx
index 53c8b51f..2a1c0dfb 100644
--- a/main.cxx
+++ b/main.cxx
@@ -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_ */
diff --git a/session.h b/session.h
index 6fa05a2f..646b9154 100644
--- a/session.h
+++ b/session.h
@@ -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;
diff --git a/stap.1.in b/stap.1.in
index db64748f..d4458850 100644
--- a/stap.1.in
+++ b/stap.1.in
@@ -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 &regs->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(&regs->cs);
+#else
+ int cs = kread(&regs->xcs);
+#endif
+ THIS->__retvalue = (!!((cs & 3)));
+#elif defined(__x86_64__)
+ unsigned long cs = kread(&regs->cs);
+ THIS->__retvalue = (!!((cs & 3)));
+#elif defined(__ia64__)
+ unsigned long psr = kread(&regs->cr_ipsr);
+ THIS->__retvalue = (((struct ia64_psr *) &psr)->cpl != 0);
+#elif defined(__powerpc64__)
+ unsigned long msr = kread(&regs->msr);
+ THIS->__retvalue = ((msr >> MSR_PR_LG) & 0x1);
+#elif defined(__arm__)
+ long cpsr = kread(&regs->ARM_cpsr);
+ THIS->__retvalue = ((cpsr & 0xf) == 0);
+#elif defined(__s390__) || defined(__s390x__)
+ unsigned long mask = kread(&regs->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 7cdf3c32..9528066f 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()
@@ -2596,7 +2875,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 *);
@@ -2720,7 +2999,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.
@@ -2770,6 +3055,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;
+}
@@ -3102,7 +3425,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
@@ -3163,7 +3488,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)
@@ -3178,10 +3503,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)
@@ -3190,7 +3579,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.
@@ -3203,67 +3592,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.
@@ -3279,6 +3616,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
{
@@ -3810,7 +4165,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);
@@ -4266,7 +4621,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";