Tapsets & translators
We already discussed problem with probe stability. Some issues may be related to changing data structures in kernel, or several variants may exist in kernel, for example for 32- and 64-bit calls. Let's see how access to fields of that structure may be unified.
DTrace has a translators for doing that:
struct stat_info { long long st_size; }; translator struct stat_info < uintptr_t s > { st_size = * ((long long*) copyin(s + offsetof(struct stat64_32, st_size), sizeof (long long))); }; syscall::fstatat64:entry { self->filename = copyinstr(arg1); self->statptr = arg2; } syscall::fstatat64:return { printf("STAT %s size: %d\n", self->filename, xlate < struct stat_info* > (self->statptr)->st_size); }
stat64_32
to a structure with known format defined in DTrace stat_info
. After that, xlate
operator is called which receives pointer to stat64_32
structure to a stat_info
. Note that our translator also responsible for copying data from userspace to kernel. Built-in DTrace translators are located in /usr/lib/dtrace
.
SystemTap doesn't have translators, but you can create prologue or epilogue alias which performs necessary conversions before (or after, respectively) probe is called. These aliases are grouped into script libraries called tapsets and put into /usr/share/systemtap/tapset
directory. Many probes that we will use in following modules are implemented in such tapsets.
Linux has several variants for stat
structure in stat()
system call, some of them deprecated, some are intended to support 64-bit sizes for 32-bit callers. By using following tapset we will remove such differences and make them universally available through filename
and size
variables:
probe lstat = kernel.function("sys_lstat64").return ? , kernel.function("sys32_lstat64").return ? { filename = user_string($filename); size = user_uint64(& @cast($statbuf, "struct stat64")->st_size); } probe lstat = kernel.function("sys_newlstat").return ? { filename = user_string($filename); %( arch == "x86_64" %? size = user_uint64(& @cast($statbuf, "struct stat")->st_size); %: size = user_uint32(& @cast($statbuf, "struct stat")->st_size); %) }
vfs_lstat
function which has universal representation of stat
structure and doesn't involve copying from userspace. Summarizing the syntax of creating aliases:
probe alias-name {=|+=} probe-name-1 [?] [,probe-name-2 [?] ...] probe-bodyHere
=
is used for creating prologue aliases and +=
is for epilogue aliases. Question mark ?
suffix is optional and used if some functions are not present in kernel –- it allows to choose probe from multiple possibilities.
Warning
Note that this tapset only checks for 64-bit Intel architecture. You will need additional checks for PowerPC, AArch64 and S/390 architectures.
After we created this tapset, it can be used very easy:
probe lstat { printf("%s %d\n", filename, size); }
inline
keyword:
inline int TS_RUN = 2;You may use initializer for global variable to do that in SystemTap:
global TASK_RUNNING = 0;If you have enabled preprocessor with
-C
option, you may use #define
to create macro as well.
References