diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-19 10:44:49 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-19 10:44:49 +0200 |
| commit | 7c33a6b86127e7a69f57f89913639926aa652a9e (patch) | |
| tree | fe7e6a77a489ce99c8c5e07b87c910cee9924afe | |
| parent | 59ddf9fbf4b4cfa379ec57e6479a24b8b3400aea (diff) | |
fix: resolve dirfd-relative capture paths (task 462)
| -rw-r--r-- | AGENTS.md | 218 | ||||
| -rw-r--r-- | scripts/syscall_matrix.c | 248 | ||||
| -rw-r--r-- | systemtap/src/ioriot.stp | 101 | ||||
| -rw-r--r-- | systemtap/src/javaioriot.stp | 101 | ||||
| -rw-r--r-- | systemtap/src/targetedioriot.stp | 101 |
5 files changed, 724 insertions, 45 deletions
diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..3ab36b5 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,218 @@ +# Agent Notes + +## Syscall Matrix End-to-End Test + +Use this procedure when you need a reproducible end-to-end test that exercises +the supported capture/generate/replay syscall surface with a controlled +workload. + +### Preconditions + +- Run from the repository root: `/home/paul/git/ioriot`. +- Use a base directory under `/home`, not `/tmp`. This project filters some + file systems during replay generation, and `/tmp` may be `tmpfs`. +- The helper below is intentionally dirfd-heavy so it catches path-resolution + bugs in `*at` syscalls as well as normal file I/O. +- `readdir` is intentionally excluded. Generation handles it, but replay does + not currently have a `READDIR` implementation. + +### 1. Rebuild, test, and install + +```bash +make clean all test +sudo make install +``` + +### 2. Prepare a unique run directory and compile the helper + +```bash +stamp=$(date +%Y%m%d_%H%M%S) +run_root=/tmp/ioriot-syscall-e2e-$stamp +user_name=${SUDO_USER:-$USER} +base_dir=/home/$user_name/ioriot-syscall-matrix-src-$stamp +helper_bin=$run_root/syscall_matrix + +mkdir -p "$run_root" +cc -Wall -Wextra -O2 -o "$helper_bin" scripts/syscall_matrix.c + +pid_file=$run_root/syscall_matrix.pid +go_file=$run_root/syscall_matrix.go +capture_file=$run_root/syscall_matrix.capture +replay_file=$run_root/syscall_matrix.replay +stats_file=$run_root/syscall_matrix.stats +strace_file=$run_root/replay.strace +test_name=e2e_syscall_matrix_$stamp +``` + +### 3. Start the helper in a paused state + +Run this in terminal A: + +```bash +sudo "$helper_bin" "$pid_file" "$go_file" "$base_dir" "$user_name" +``` + +The helper writes its real PID into `"$pid_file"` and then waits until +`"$go_file"` exists. + +### 4. Attach targeted capture before releasing the helper + +Run this in terminal B after `"$pid_file"` exists: + +```bash +helper_pid=$(cat "$pid_file") +sudo /opt/ioriot/bin/ioriot -c "$capture_file" -x "$helper_pid" +``` + +Wait until `staprun` reports that `targetedioriot.ko` has been inserted. + +### 5. Release the helper and stop capture after it exits + +Back in terminal A, release the workload: + +```bash +touch "$go_file" +``` + +When the helper exits, stop capture in terminal B with `Ctrl+C`. + +### 6. Generate the replay file + +```bash +sudo /opt/ioriot/bin/ioriot \ + -c "$capture_file" \ + -r "$replay_file" \ + -u "$user_name" \ + -n "$test_name" \ + -w /home/$user_name/.ioriot-wd +``` + +### 7. Sanity-check capture and replay contents + +List the captured syscall names: + +```bash +python - "$capture_file" <<'PY' +import re +import sys +ops=set() +for line in open(sys.argv[1]): + m=re.search(r';:,o=([^;]+);:,', line) + if m: + ops.add(m.group(1)) +for op in sorted(ops): + print(op) +PY +``` + +List the replay operation names: + +```bash +python - "$replay_file" <<'PY' +import re +import sys +ops=set() +for line in open(sys.argv[1]): + m=re.search(r'\|([a-z0-9_]+)@[0-9]+\|\s*$', line) + if m: + ops.add(m.group(1)) +for op in sorted(ops): + print(op) +PY +``` + +Verify the replay file contains expected workload paths: + +```bash +rg -n 'head-renamed|openat|creat|link-open|emptydir' "$replay_file" +``` + +Architecture note: + +- On modern x86_64 systems, some operations may surface as modern entry points + rather than legacy ones. For example, `open` may appear as `openat`, and + `stat` / `lstat` may appear as `newfstatat` in `strace`. +- Some replay entries are intentionally no-ops today: `statfs`, `fstatfs`, + `readahead`, `readlink`, `readlinkat`, `sync`, `syncfs`, and + `sync_file_range`. + +### 8. Initialize the replay tree + +```bash +sudo /opt/ioriot/bin/ioriot \ + -i "$replay_file" \ + -w /home/$user_name/.ioriot-wd +``` + +### 9. Replay single-threaded under strace + +```bash +sudo strace -f -o "$strace_file" \ + /opt/ioriot/bin/ioriot \ + -D \ + -r "$replay_file" \ + -p 1 \ + -t 1 \ + -S "$stats_file" +``` + +### 10. Verify replay activity and resulting state + +Check stats: + +```bash +cat "$stats_file" +``` + +Inspect replay syscalls touching the target tree: + +```bash +rg -n "/home/\\.ioriot/$test_name/" "$strace_file" +``` + +Useful follow-up checks: + +```bash +find "/home/.ioriot/$test_name" -maxdepth 6 \ + \( -name 'head-renamed.bin' -o -name 'open*.txt' -o -name 'creat*.txt' \ + -o -name 'link-open.txt' -o -name 'emptydir' \) | sort +``` + +```bash +python - "$test_name" "$user_name" "$stamp" <<'PY' +from pathlib import Path +import sys + +test_name, user_name, stamp = sys.argv[1:] +root = Path(f"/home/.ioriot/{test_name}/{user_name}") +base = root / f"ioriot-syscall-matrix-src-{stamp}" + +paths = [ + base / "open-renamed.txt", + base / "emptydir", + base / "dirA" / "openat-renamed.txt", +] +for p in paths: + print(f"{p}: exists={p.exists()} is_dir={p.is_dir()}") +PY +``` + +### Expected coverage + +The helper in [scripts/syscall_matrix.c](/home/paul/git/ioriot/scripts/syscall_matrix.c) +attempts to exercise these operations: + +- `creat`, `openat`, `close` +- `read`, `readv`, `write`, `writev` +- `fstat`, `fstatat`, `statfs`, `fstatfs` +- `fcntl`, `readahead`, `sync`, `syncfs`, `sync_file_range` +- `getdents`, `lseek`, `llseek` when available +- `mkdir`, `mkdirat`, `rename`, `renameat`, `renameat2` +- `unlink`, `unlinkat`, `rmdir` +- `readlink`, `readlinkat` +- `chmod`, `fchmod`, `fchmodat` +- `chown`, `fchown`, `fchownat`, `lchown` + +If the generated replay only contains the header and `#INIT`, or the replay +paths escape the intended test tree, investigate capture tokenization and +dirfd-relative path handling first. diff --git a/scripts/syscall_matrix.c b/scripts/syscall_matrix.c new file mode 100644 index 0000000..df7311a --- /dev/null +++ b/scripts/syscall_matrix.c @@ -0,0 +1,248 @@ +#define _GNU_SOURCE + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <pwd.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <sys/uio.h> +#include <unistd.h> + +static void +die(const char *msg) +{ + perror(msg); + exit(1); +} + +static void +must(bool ok, const char *msg) +{ + if (!ok) + die(msg); +} + +static void +must_eq(long rc, const char *msg) +{ + if (rc == -1) + die(msg); +} + +static void +write_pid_file(const char *path) +{ + FILE *fp = fopen(path, "w"); + + must(fp != NULL, "fopen pid file"); + fprintf(fp, "%ld\n", (long)getpid()); + fclose(fp); +} + +static void +wait_for_go(const char *path) +{ + while (access(path, F_OK) != 0) + usleep(10000); +} + +static void +write_full(int fd, const char *buf, size_t len) +{ + while (len > 0) { + ssize_t written = write(fd, buf, len); + + must_eq(written, "write"); + buf += written; + len -= (size_t)written; + } +} + +int +main(int argc, char **argv) +{ + if (argc != 5) { + fprintf(stderr, "usage: %s PID_FILE GO_FILE BASE_DIR USER\n", argv[0]); + return 2; + } + + const char *pid_file = argv[1]; + const char *go_file = argv[2]; + const char *base = argv[3]; + const char *user = argv[4]; + + struct passwd *pw = getpwnam(user); + + must(pw != NULL, "getpwnam"); + + write_pid_file(pid_file); + wait_for_go(go_file); + + char path_open[1024]; + char path_renamed[1024]; + char path_creat[1024]; + char path_link[1024]; + char path_emptydir[1024]; + + snprintf(path_open, sizeof(path_open), "%s/open.txt", base); + snprintf(path_renamed, sizeof(path_renamed), "%s/open-renamed.txt", base); + snprintf(path_creat, sizeof(path_creat), "%s/creat.txt", base); + snprintf(path_link, sizeof(path_link), "%s/link-open.txt", base); + snprintf(path_emptydir, sizeof(path_emptydir), "%s/emptydir", base); + + must_eq(mkdir(base, 0777), "mkdir base"); + + int basefd = open(base, O_RDONLY | O_DIRECTORY); + + must_eq(basefd, "open base dir"); + must_eq(mkdirat(basefd, "dirA", 0777), "mkdirat dirA"); + must_eq(mkdirat(basefd, "emptydir", 0777), "mkdirat emptydir"); + + int dirfd = openat(basefd, "dirA", O_RDONLY | O_DIRECTORY); + + must_eq(dirfd, "openat dirA"); + must_eq(mkdirat(dirfd, "nested", 0777), "mkdirat nested"); + + int fd_open = open(path_open, O_CREAT | O_RDWR | O_TRUNC, 0644); + + must_eq(fd_open, "open open.txt"); + write_full(fd_open, "alpha", 5); + must_eq(fsync(fd_open), "fsync open.txt"); + must_eq(fdatasync(fd_open), "fdatasync open.txt"); + must_eq(lseek(fd_open, 0, SEEK_SET), "lseek open.txt"); + + char read_buf[64]; + + must_eq(read(fd_open, read_buf, 5), "read open.txt"); + + struct iovec write_iov[2] = { + {.iov_base = "beta", .iov_len = 4}, + {.iov_base = "gamma", .iov_len = 5}, + }; + + must_eq(writev(fd_open, write_iov, 2), "writev open.txt"); + must_eq(lseek(fd_open, 0, SEEK_SET), "lseek open.txt again"); + + char readv_a[5] = {0}; + char readv_b[10] = {0}; + struct iovec read_iov[2] = { + {.iov_base = readv_a, .iov_len = sizeof(readv_a) - 1}, + {.iov_base = readv_b, .iov_len = sizeof(readv_b) - 1}, + }; + + must_eq(readv(fd_open, read_iov, 2), "readv open.txt"); + + struct stat st; + + must_eq(fstat(fd_open, &st), "fstat open.txt"); + must_eq(stat(path_open, &st), "stat open.txt"); + must_eq(fstatat(basefd, "open.txt", &st, 0), "fstatat open.txt"); + + struct statfs sfs; + + must_eq(statfs(base, &sfs), "statfs base"); + must_eq(fstatfs(fd_open, &sfs), "fstatfs open.txt"); + + int flags = fcntl(fd_open, F_GETFL); + + must_eq(flags, "fcntl getfl"); + must_eq(fcntl(fd_open, F_SETFL, flags | O_APPEND), "fcntl setfl"); + +#ifdef SYS_readahead + syscall(SYS_readahead, fd_open, 0, 8); +#endif + +#ifdef SYS_sync_file_range + syscall(SYS_sync_file_range, fd_open, 0, 8, 0); +#endif + +#if defined(SYS_llseek) + long long llseek_result = 0; + syscall(SYS_llseek, fd_open, 0UL, 0UL, &llseek_result, SEEK_END); +#elif defined(SYS__llseek) + long long llseek_result = 0; + syscall(SYS__llseek, fd_open, 0UL, 0UL, &llseek_result, SEEK_END); +#endif + + must_eq(syncfs(fd_open), "syncfs"); + sync(); + + int fd_openat = openat(dirfd, "openat.txt", O_CREAT | O_RDWR | O_TRUNC, + 0640); + + must_eq(fd_openat, "openat openat.txt"); + write_full(fd_openat, "openat-data", 11); + must_eq(lseek(fd_openat, 0, SEEK_SET), "lseek openat.txt"); + must_eq(read(fd_openat, read_buf, 4), "read openat.txt"); + + int fd_creat = creat(path_creat, 0644); + + must_eq(fd_creat, "creat creat.txt"); + write_full(fd_creat, "creat", 5); + must_eq(close(fd_creat), "close creat.txt"); + + int fd_nested = openat(dirfd, "nested", O_RDONLY | O_DIRECTORY); + + must_eq(fd_nested, "open nested dir"); + + int fd_nested_file = openat(fd_nested, "head.bin", + O_CREAT | O_RDWR | O_TRUNC, 0644); + + must_eq(fd_nested_file, "open nested file"); + write_full(fd_nested_file, "head-data", 9); + must_eq(close(fd_nested_file), "close nested file"); + +#ifdef SYS_getdents + char dents_buf[4096]; + syscall(SYS_getdents, dirfd, dents_buf, sizeof(dents_buf)); +#endif + + must_eq(symlink(path_open, path_link), "symlink"); + must_eq(lstat(path_link, &st), "lstat link"); + must_eq(readlink(path_link, read_buf, sizeof(read_buf)), "readlink"); + must_eq(readlinkat(basefd, "link-open.txt", read_buf, sizeof(read_buf)), + "readlinkat"); + + must_eq(chmod(path_open, 0640), "chmod"); + must_eq(fchmod(fd_open, 0600), "fchmod"); + must_eq(fchmodat(basefd, "open.txt", 0644, 0), "fchmodat"); + + must_eq(chown(path_open, pw->pw_uid, pw->pw_gid), "chown"); + must_eq(fchown(fd_open, pw->pw_uid, pw->pw_gid), "fchown"); + must_eq(fchownat(basefd, "open.txt", pw->pw_uid, pw->pw_gid, 0), + "fchownat"); + must_eq(lchown(path_link, pw->pw_uid, pw->pw_gid), "lchown"); + + must_eq(rename(path_open, path_renamed), "rename"); + must_eq(renameat(dirfd, "openat.txt", dirfd, "openat-renamed.txt"), + "renameat"); + +#ifdef SYS_renameat2 + must_eq(syscall(SYS_renameat2, basefd, "creat.txt", basefd, + "creat-renamed.txt", 0), "renameat2"); +#endif + + must_eq(unlink(path_renamed), "unlink"); + must_eq(unlinkat(dirfd, "openat-renamed.txt", 0), "unlinkat"); + must_eq(unlinkat(basefd, "creat-renamed.txt", 0), "unlinkat creat"); + + must_eq(renameat(fd_nested, "head.bin", dirfd, "head-renamed.bin"), + "renameat nested"); + + must_eq(close(fd_nested), "close nested dir"); + must_eq(rmdir(path_emptydir), "rmdir emptydir"); + + must_eq(close(fd_openat), "close openat"); + must_eq(close(fd_open), "close open"); + must_eq(close(dirfd), "close dirA"); + must_eq(close(basefd), "close base"); + + return 0; +} diff --git a/systemtap/src/ioriot.stp b/systemtap/src/ioriot.stp index 1e12574..9bdf440 100644 --- a/systemtap/src/ioriot.stp +++ b/systemtap/src/ioriot.stp @@ -30,6 +30,7 @@ global PROBE_ENTRY_TIMES%[8096] global ENTRY_PATH%[8096] global ENTRY_PATH2%[8096] global ENTRY_FD%[8096] +global ENTRY_FD2%[8096] global ENTRY_FLAGS%[8096] global ENTRY_MODE%[8096] global ENTRY_OFFSET%[8096] @@ -64,6 +65,34 @@ function absolute_path:string (path:string) { return task_dentry_path(tc, pwd_dentry, pwd_mnt) . "/" . path; } +function task_file_handle_d_path:string (task:long, fd:long) { + path = "" + + try { + file = task_fd_lookup(task, fd) + if (file) + path = fullpath_struct_file(task, file) + } catch { + } + + return path +} + +function absolute_path_at:string (path:string, dirfd:long) { + if (substr(path,0,1) == "/") + return path; + + if (dirfd == @const("AT_FDCWD")) + return absolute_path(path); + + tc = task_current(); + dir_path = task_file_handle_d_path(tc, dirfd); + if (strlen(dir_path) > 0) + return dir_path . "/" . path; + + return absolute_path(path); +} + # Stop probing after 1h (for safety) probe timer.s(3600) { exit(); @@ -73,9 +102,9 @@ probe begin { printf("#|capture_version=%d|\n", 3); } -# --- open/openat --- +# --- open --- # Tapset entry vars: filename_unquoted, flags, mode -probe syscall.open, syscall.openat { +probe syscall.open { if (execname() != "stapio") { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() ENTRY_PATH[tid(),name] = filename_unquoted @@ -84,7 +113,7 @@ probe syscall.open, syscall.openat { } } -probe syscall.open.return, syscall.openat.return { +probe syscall.open.return { if (execname() != "stapio") { ns = gettimeofday_ns() printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,d=%d;:,p=%s;:,f=%d;:,m=%d;:,\n", @@ -101,6 +130,36 @@ probe syscall.open.return, syscall.openat.return { } } +# --- openat --- +# Tapset entry vars: dfd, filename_unquoted, flags, mode +probe syscall.openat { + if (execname() != "stapio") { + PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = dfd + ENTRY_PATH[tid(),name] = filename_unquoted + ENTRY_FLAGS[tid(),name] = flags + ENTRY_MODE[tid(),name] = mode + } +} + +probe syscall.openat.return { + if (execname() != "stapio") { + ns = gettimeofday_ns() + printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,d=%d;:,p=%s;:,f=%d;:,m=%d;:,\n", + ns, ns-PROBE_ENTRY_TIMES[tid(),name], + pid(), tid(), name, + retval, + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), + ENTRY_FLAGS[tid(),name], + ENTRY_MODE[tid(),name]); + delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] + delete ENTRY_PATH[tid(),name] + delete ENTRY_FLAGS[tid(),name] + delete ENTRY_MODE[tid(),name] + } +} + # --- lseek --- # Tapset entry vars: fildes, offset, whence probe syscall.lseek { @@ -272,7 +331,7 @@ probe syscall.unlinkat.return { ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, ENTRY_FD[tid(),name], - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_FLAGS[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] @@ -308,10 +367,12 @@ probe syscall.rename.return { } # --- renameat/renameat2 --- -# Tapset entry vars: oldname_str_unquoted, newname_str_unquoted +# Tapset entry vars: olddfd, oldname_str_unquoted, newdfd, newname_str_unquoted probe syscall.renameat, syscall.renameat2 { if (execname() != "stapio") { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = olddfd + ENTRY_FD2[tid(),name] = newdfd ENTRY_PATH[tid(),name] = oldname_str_unquoted ENTRY_PATH2[tid(),name] = newname_str_unquoted } @@ -323,10 +384,14 @@ probe syscall.renameat.return, syscall.renameat2.return { printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,p=%s;:,P=%s;:,s=%d;:,\n", ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, - absolute_path(ENTRY_PATH[tid(),name]), - absolute_path(ENTRY_PATH2[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], + ENTRY_FD[tid(),name]), + absolute_path_at(ENTRY_PATH2[tid(),name], + ENTRY_FD2[tid(),name]), retval); delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] + delete ENTRY_FD2[tid(),name] delete ENTRY_PATH[tid(),name] delete ENTRY_PATH2[tid(),name] } @@ -427,10 +492,11 @@ probe syscall.readlink.return { } # --- readlinkat --- -# Tapset entry vars: path_unquoted +# Tapset entry vars: dfd, path_unquoted probe syscall.readlinkat { if (execname() != "stapio") { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = dfd ENTRY_PATH[tid(),name] = path_unquoted } } @@ -441,9 +507,10 @@ probe syscall.readlinkat.return { printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,p=%s;:,s=%d;:,\n", ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), retval); delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] delete ENTRY_PATH[tid(),name] } } @@ -650,7 +717,7 @@ probe syscall.mkdirat.return { ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, ENTRY_FD[tid(),name], - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_MODE[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] @@ -788,7 +855,7 @@ probe syscall.fstatat.return { ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, ENTRY_FD[tid(),name], - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_FLAGS[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] @@ -824,10 +891,11 @@ probe syscall.chmod.return { } # --- fchmodat --- -# Tapset entry vars: pathname_unquoted, mode +# Tapset entry vars: dirfd, pathname_unquoted, mode probe syscall.fchmodat { if (execname() != "stapio") { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = dirfd ENTRY_PATH[tid(),name] = pathname_unquoted ENTRY_MODE[tid(),name] = mode } @@ -839,10 +907,11 @@ probe syscall.fchmodat.return { printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,p=%s;:,m=%d;:,s=%d;:,\n", ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_MODE[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] delete ENTRY_PATH[tid(),name] delete ENTRY_MODE[tid(),name] } @@ -934,10 +1003,11 @@ probe syscall.fchown.return { } # --- fchownat --- -# Tapset entry vars: pathname_unquoted, owner, group, flags +# Tapset entry vars: dirfd, pathname_unquoted, owner, group, flags probe syscall.fchownat { if (execname() != "stapio") { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = dirfd ENTRY_PATH[tid(),name] = pathname_unquoted ENTRY_OWNER[tid(),name] = owner ENTRY_GROUP[tid(),name] = group @@ -951,12 +1021,13 @@ probe syscall.fchownat.return { printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,p=%s;:,O=%d;:,G=%d;:,f=%d;:,s=%d;:,\n", ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_OWNER[tid(),name], ENTRY_GROUP[tid(),name], ENTRY_FLAGS[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] delete ENTRY_PATH[tid(),name] delete ENTRY_OWNER[tid(),name] delete ENTRY_GROUP[tid(),name] diff --git a/systemtap/src/javaioriot.stp b/systemtap/src/javaioriot.stp index 3d54b19..cf7e797 100644 --- a/systemtap/src/javaioriot.stp +++ b/systemtap/src/javaioriot.stp @@ -30,6 +30,7 @@ global PROBE_ENTRY_TIMES%[8096] global ENTRY_PATH%[8096] global ENTRY_PATH2%[8096] global ENTRY_FD%[8096] +global ENTRY_FD2%[8096] global ENTRY_FLAGS%[8096] global ENTRY_MODE%[8096] global ENTRY_OFFSET%[8096] @@ -64,6 +65,34 @@ function absolute_path:string (path:string) { return task_dentry_path(tc, pwd_dentry, pwd_mnt) . "/" . path; } +function task_file_handle_d_path:string (task:long, fd:long) { + path = "" + + try { + file = task_fd_lookup(task, fd) + if (file) + path = fullpath_struct_file(task, file) + } catch { + } + + return path +} + +function absolute_path_at:string (path:string, dirfd:long) { + if (substr(path,0,1) == "/") + return path; + + if (dirfd == @const("AT_FDCWD")) + return absolute_path(path); + + tc = task_current(); + dir_path = task_file_handle_d_path(tc, dirfd); + if (strlen(dir_path) > 0) + return dir_path . "/" . path; + + return absolute_path(path); +} + # Stop probing after 1h (for safety) probe timer.s(3600) { exit(); @@ -73,9 +102,9 @@ probe begin { printf("#|capture_version=%d|\n", 3); } -# --- open/openat --- +# --- open --- # Tapset entry vars: filename_unquoted, flags, mode -probe syscall.open, syscall.openat { +probe syscall.open { if (execname() == "java") { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() ENTRY_PATH[tid(),name] = filename_unquoted @@ -84,7 +113,7 @@ probe syscall.open, syscall.openat { } } -probe syscall.open.return, syscall.openat.return { +probe syscall.open.return { if (execname() == "java") { ns = gettimeofday_ns() printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,d=%d;:,p=%s;:,f=%d;:,m=%d;:,\n", @@ -101,6 +130,36 @@ probe syscall.open.return, syscall.openat.return { } } +# --- openat --- +# Tapset entry vars: dfd, filename_unquoted, flags, mode +probe syscall.openat { + if (execname() == "java") { + PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = dfd + ENTRY_PATH[tid(),name] = filename_unquoted + ENTRY_FLAGS[tid(),name] = flags + ENTRY_MODE[tid(),name] = mode + } +} + +probe syscall.openat.return { + if (execname() == "java") { + ns = gettimeofday_ns() + printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,d=%d;:,p=%s;:,f=%d;:,m=%d;:,\n", + ns, ns-PROBE_ENTRY_TIMES[tid(),name], + pid(), tid(), name, + retval, + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), + ENTRY_FLAGS[tid(),name], + ENTRY_MODE[tid(),name]); + delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] + delete ENTRY_PATH[tid(),name] + delete ENTRY_FLAGS[tid(),name] + delete ENTRY_MODE[tid(),name] + } +} + # --- lseek --- # Tapset entry vars: fildes, offset, whence probe syscall.lseek { @@ -272,7 +331,7 @@ probe syscall.unlinkat.return { ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, ENTRY_FD[tid(),name], - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_FLAGS[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] @@ -308,10 +367,12 @@ probe syscall.rename.return { } # --- renameat/renameat2 --- -# Tapset entry vars: oldname_str_unquoted, newname_str_unquoted +# Tapset entry vars: olddfd, oldname_str_unquoted, newdfd, newname_str_unquoted probe syscall.renameat, syscall.renameat2 { if (execname() == "java") { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = olddfd + ENTRY_FD2[tid(),name] = newdfd ENTRY_PATH[tid(),name] = oldname_str_unquoted ENTRY_PATH2[tid(),name] = newname_str_unquoted } @@ -323,10 +384,14 @@ probe syscall.renameat.return, syscall.renameat2.return { printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,p=%s;:,P=%s;:,s=%d;:,\n", ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, - absolute_path(ENTRY_PATH[tid(),name]), - absolute_path(ENTRY_PATH2[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], + ENTRY_FD[tid(),name]), + absolute_path_at(ENTRY_PATH2[tid(),name], + ENTRY_FD2[tid(),name]), retval); delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] + delete ENTRY_FD2[tid(),name] delete ENTRY_PATH[tid(),name] delete ENTRY_PATH2[tid(),name] } @@ -427,10 +492,11 @@ probe syscall.readlink.return { } # --- readlinkat --- -# Tapset entry vars: path_unquoted +# Tapset entry vars: dfd, path_unquoted probe syscall.readlinkat { if (execname() == "java") { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = dfd ENTRY_PATH[tid(),name] = path_unquoted } } @@ -441,9 +507,10 @@ probe syscall.readlinkat.return { printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,p=%s;:,s=%d;:,\n", ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), retval); delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] delete ENTRY_PATH[tid(),name] } } @@ -650,7 +717,7 @@ probe syscall.mkdirat.return { ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, ENTRY_FD[tid(),name], - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_MODE[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] @@ -788,7 +855,7 @@ probe syscall.fstatat.return { ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, ENTRY_FD[tid(),name], - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_FLAGS[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] @@ -824,10 +891,11 @@ probe syscall.chmod.return { } # --- fchmodat --- -# Tapset entry vars: pathname_unquoted, mode +# Tapset entry vars: dirfd, pathname_unquoted, mode probe syscall.fchmodat { if (execname() == "java") { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = dirfd ENTRY_PATH[tid(),name] = pathname_unquoted ENTRY_MODE[tid(),name] = mode } @@ -839,10 +907,11 @@ probe syscall.fchmodat.return { printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,p=%s;:,m=%d;:,s=%d;:,\n", ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_MODE[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] delete ENTRY_PATH[tid(),name] delete ENTRY_MODE[tid(),name] } @@ -934,10 +1003,11 @@ probe syscall.fchown.return { } # --- fchownat --- -# Tapset entry vars: pathname_unquoted, owner, group, flags +# Tapset entry vars: dirfd, pathname_unquoted, owner, group, flags probe syscall.fchownat { if (execname() == "java") { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = dirfd ENTRY_PATH[tid(),name] = pathname_unquoted ENTRY_OWNER[tid(),name] = owner ENTRY_GROUP[tid(),name] = group @@ -951,12 +1021,13 @@ probe syscall.fchownat.return { printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,p=%s;:,O=%d;:,G=%d;:,f=%d;:,s=%d;:,\n", ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_OWNER[tid(),name], ENTRY_GROUP[tid(),name], ENTRY_FLAGS[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] delete ENTRY_PATH[tid(),name] delete ENTRY_OWNER[tid(),name] delete ENTRY_GROUP[tid(),name] diff --git a/systemtap/src/targetedioriot.stp b/systemtap/src/targetedioriot.stp index b93b21c..dccfe4c 100644 --- a/systemtap/src/targetedioriot.stp +++ b/systemtap/src/targetedioriot.stp @@ -30,6 +30,7 @@ global PROBE_ENTRY_TIMES%[8096] global ENTRY_PATH%[8096] global ENTRY_PATH2%[8096] global ENTRY_FD%[8096] +global ENTRY_FD2%[8096] global ENTRY_FLAGS%[8096] global ENTRY_MODE%[8096] global ENTRY_OFFSET%[8096] @@ -64,6 +65,34 @@ function absolute_path:string (path:string) { return task_dentry_path(tc, pwd_dentry, pwd_mnt) . "/" . path; } +function task_file_handle_d_path:string (task:long, fd:long) { + path = "" + + try { + file = task_fd_lookup(task, fd) + if (file) + path = fullpath_struct_file(task, file) + } catch { + } + + return path +} + +function absolute_path_at:string (path:string, dirfd:long) { + if (substr(path,0,1) == "/") + return path; + + if (dirfd == @const("AT_FDCWD")) + return absolute_path(path); + + tc = task_current(); + dir_path = task_file_handle_d_path(tc, dirfd); + if (strlen(dir_path) > 0) + return dir_path . "/" . path; + + return absolute_path(path); +} + # Stop probing after 1h (for safety) probe timer.s(3600) { exit(); @@ -73,9 +102,9 @@ probe begin { printf("#|capture_version=%d|\n", 3); } -# --- open/openat --- +# --- open --- # Tapset entry vars: filename_unquoted, flags, mode -probe syscall.open, syscall.openat { +probe syscall.open { if (pid() == target()) { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() ENTRY_PATH[tid(),name] = filename_unquoted @@ -84,7 +113,7 @@ probe syscall.open, syscall.openat { } } -probe syscall.open.return, syscall.openat.return { +probe syscall.open.return { if (pid() == target()) { ns = gettimeofday_ns() printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,d=%d;:,p=%s;:,f=%d;:,m=%d;:,\n", @@ -101,6 +130,36 @@ probe syscall.open.return, syscall.openat.return { } } +# --- openat --- +# Tapset entry vars: dfd, filename_unquoted, flags, mode +probe syscall.openat { + if (pid() == target()) { + PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = dfd + ENTRY_PATH[tid(),name] = filename_unquoted + ENTRY_FLAGS[tid(),name] = flags + ENTRY_MODE[tid(),name] = mode + } +} + +probe syscall.openat.return { + if (pid() == target()) { + ns = gettimeofday_ns() + printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,d=%d;:,p=%s;:,f=%d;:,m=%d;:,\n", + ns, ns-PROBE_ENTRY_TIMES[tid(),name], + pid(), tid(), name, + retval, + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), + ENTRY_FLAGS[tid(),name], + ENTRY_MODE[tid(),name]); + delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] + delete ENTRY_PATH[tid(),name] + delete ENTRY_FLAGS[tid(),name] + delete ENTRY_MODE[tid(),name] + } +} + # --- lseek --- # Tapset entry vars: fildes, offset, whence probe syscall.lseek { @@ -272,7 +331,7 @@ probe syscall.unlinkat.return { ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, ENTRY_FD[tid(),name], - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_FLAGS[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] @@ -308,10 +367,12 @@ probe syscall.rename.return { } # --- renameat/renameat2 --- -# Tapset entry vars: oldname_str_unquoted, newname_str_unquoted +# Tapset entry vars: olddfd, oldname_str_unquoted, newdfd, newname_str_unquoted probe syscall.renameat, syscall.renameat2 { if (pid() == target()) { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = olddfd + ENTRY_FD2[tid(),name] = newdfd ENTRY_PATH[tid(),name] = oldname_str_unquoted ENTRY_PATH2[tid(),name] = newname_str_unquoted } @@ -323,10 +384,14 @@ probe syscall.renameat.return, syscall.renameat2.return { printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,p=%s;:,P=%s;:,s=%d;:,\n", ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, - absolute_path(ENTRY_PATH[tid(),name]), - absolute_path(ENTRY_PATH2[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], + ENTRY_FD[tid(),name]), + absolute_path_at(ENTRY_PATH2[tid(),name], + ENTRY_FD2[tid(),name]), retval); delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] + delete ENTRY_FD2[tid(),name] delete ENTRY_PATH[tid(),name] delete ENTRY_PATH2[tid(),name] } @@ -427,10 +492,11 @@ probe syscall.readlink.return { } # --- readlinkat --- -# Tapset entry vars: path_unquoted +# Tapset entry vars: dfd, path_unquoted probe syscall.readlinkat { if (pid() == target()) { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = dfd ENTRY_PATH[tid(),name] = path_unquoted } } @@ -441,9 +507,10 @@ probe syscall.readlinkat.return { printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,p=%s;:,s=%d;:,\n", ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), retval); delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] delete ENTRY_PATH[tid(),name] } } @@ -650,7 +717,7 @@ probe syscall.mkdirat.return { ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, ENTRY_FD[tid(),name], - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_MODE[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] @@ -788,7 +855,7 @@ probe syscall.fstatat.return { ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, ENTRY_FD[tid(),name], - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_FLAGS[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] @@ -824,10 +891,11 @@ probe syscall.chmod.return { } # --- fchmodat --- -# Tapset entry vars: pathname_unquoted, mode +# Tapset entry vars: dirfd, pathname_unquoted, mode probe syscall.fchmodat { if (pid() == target()) { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = dirfd ENTRY_PATH[tid(),name] = pathname_unquoted ENTRY_MODE[tid(),name] = mode } @@ -839,10 +907,11 @@ probe syscall.fchmodat.return { printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,p=%s;:,m=%d;:,s=%d;:,\n", ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_MODE[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] delete ENTRY_PATH[tid(),name] delete ENTRY_MODE[tid(),name] } @@ -934,10 +1003,11 @@ probe syscall.fchown.return { } # --- fchownat --- -# Tapset entry vars: pathname_unquoted, owner, group, flags +# Tapset entry vars: dirfd, pathname_unquoted, owner, group, flags probe syscall.fchownat { if (pid() == target()) { PROBE_ENTRY_TIMES[tid(),name] = gettimeofday_ns() + ENTRY_FD[tid(),name] = dirfd ENTRY_PATH[tid(),name] = pathname_unquoted ENTRY_OWNER[tid(),name] = owner ENTRY_GROUP[tid(),name] = group @@ -951,12 +1021,13 @@ probe syscall.fchownat.return { printf("t=%ld;:,D=%ld;:,i=%d:%d;:,o=%s;:,p=%s;:,O=%d;:,G=%d;:,f=%d;:,s=%d;:,\n", ns, ns-PROBE_ENTRY_TIMES[tid(),name], pid(), tid(), name, - absolute_path(ENTRY_PATH[tid(),name]), + absolute_path_at(ENTRY_PATH[tid(),name], ENTRY_FD[tid(),name]), ENTRY_OWNER[tid(),name], ENTRY_GROUP[tid(),name], ENTRY_FLAGS[tid(),name], retval); delete PROBE_ENTRY_TIMES[tid(),name] + delete ENTRY_FD[tid(),name] delete ENTRY_PATH[tid(),name] delete ENTRY_OWNER[tid(),name] delete ENTRY_GROUP[tid(),name] |
