Regex Patterns
Regex patterns provide powerful pattern matching for syscall filtering. Instead of listing individual syscalls or using predefined classes, you can use regular expressions to match syscall names flexibly.
Why Use Regex?
Without Regex
# Manually list all *at variants
renacer -e 'trace=openat,fstatat,renameat,linkat,symlinkat,readlinkat,unlinkat' -- ls
Problem: Tedious, error-prone, easy to miss some syscalls.
With Regex
# Match all syscalls ending with "at"
renacer -e 'trace=/.*at$/' -- ls
Result: Automatically matches all *at syscalls.
Regex Syntax
Pattern Delimiters
Regex patterns must be enclosed in forward slashes: /pattern/
renacer -e 'trace=/pattern/' -- command
Valid:
renacer -e 'trace=/^open.*/' -- ls
Invalid:
renacer -e 'trace=^open.*' -- ls # Missing slashes
Supported Regex Features
Renacer uses the Rust regex crate (Perl-compatible):
- Anchors:
^(start),$(end) - Wildcards:
.(any char),.*(any chars) - Character classes:
[abc],[0-9],[a-z] - Quantifiers:
*(0+),+(1+),?(0-1),{n},{n,m} - Groups:
(...),(?:...)(non-capturing) - Alternation:
|(OR) - Case-insensitive:
(?i)pattern
Basic Patterns
Prefix Matching
Match syscalls starting with a pattern:
$ renacer -e 'trace=/^open.*/' -- ls
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
# Matches: open, openat, open_by_handle_at
Regex: /^open.*/
^- Start of stringopen- Literal "open".*- Any characters (0 or more)
Suffix Matching
Match syscalls ending with a pattern:
$ renacer -e 'trace=/.*at$/' -- ls
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
fstatat(AT_FDCWD, "file.txt", {...}, 0) = 0
renameat(AT_FDCWD, "old.txt", AT_FDCWD, "new.txt") = 0
# Matches: openat, fstatat, renameat, linkat, etc.
Regex: /.*at$/
.*- Any characters (0 or more)at- Literal "at"$- End of string
Exact Match
Match syscalls exactly:
$ renacer -e 'trace=/^read$/' -- cat file.txt
read(3, "contents...\n", 131072) = 13
# Matches only "read", not "readv", "pread64", etc.
Regex: /^read$/
^- Startread- Literal "read"$- End
Substring Match
Match syscalls containing a pattern:
$ renacer -e 'trace=/stat/' -- ls
fstat(3, {...}) = 0
fstatat(AT_FDCWD, "file.txt", {...}, 0) = 0
# Matches any syscall with "stat" anywhere: stat, fstat, lstat, fstatat, etc.
OR Patterns
Multiple Alternatives
$ renacer -e 'trace=/read|write/' -- cat file.txt > output.txt
read(3, "contents...\n", 131072) = 13
write(4, "contents...\n", 13) = 13
# Matches: read, readv, pread64, write, writev, pwrite64, etc.
Regex: /read|write/
read- First alternative|- OR operatorwrite- Second alternative
Specific Alternatives
$ renacer -e 'trace=/^(read|write|close)$/' -- ./app
read(3, ...) = 42
write(4, ...) = 42
close(3) = 0
# Matches ONLY: read, write, close (exact matches)
Regex: /^(read|write|close)$/
^- Start(read|write|close)- Exact alternatives$- End
Advanced Patterns
Case-Insensitive
$ renacer -e 'trace=/(?i)OPEN/' -- ls
open("/etc/ld.so.cache", ...) = 3
openat(AT_FDCWD, ".", ...) = 3
# Matches: open, OPEN, Open, oPeN, etc.
Regex: /(?i)OPEN/
(?i)- Case-insensitive flagOPEN- Pattern (matches any case)
Character Classes
$ renacer -e 'trace=/^[rw].*/' -- cat file.txt > output.txt
read(3, ...) = 42
write(4, ...) = 42
# Matches syscalls starting with 'r' or 'w'
Regex: /^[rw].*/
^- Start[rw]- 'r' OR 'w'.*- Any characters
Quantifiers
$ renacer -e 'trace=/^.{4,6}$/' -- ./app
read(3, ...) = 42 # 4 chars
write(4, ...) = 42 # 5 chars
close(3) = 0 # 5 chars
# Matches syscalls with 4-6 character names
Regex: /^.{4,6}$/
^- Start.{4,6}- Any 4-6 characters$- End
Combining Regex with Other Filters
Regex + Classes
$ renacer -e 'trace=file,/^recv.*/' -- wget https://example.com
# Matches all file operations + recv-related syscalls
openat(...) = 3 # From 'file' class
read(...) = 1024 # From 'file' class
recvfrom(...) = 512 # From regex /^recv.*/
Regex + Literals
$ renacer -e 'trace=/^open.*/,close,read' -- ./app
# Matches: open*, close (exact), read (exact)
openat(...) = 3 # From regex
open(...) = 4 # From regex
close(3) = 0 # Literal
read(4, ...) = 42 # Literal
Regex + Negation
$ renacer -e 'trace=/^open.*/,!/openat/' -- ls
open("/etc/ld.so.cache", ...) = 3
# Matches open* EXCEPT openat
Process:
/^open.*/- Include all syscalls starting with "open"!/openat/- Exclude "openat" specifically
Common Use Cases
1. All Variants of a Syscall
Problem: Want all read variants (read, readv, pread64, etc.)
$ renacer -e 'trace=/^read/' -- ./app
read(3, ...) = 1024
readv(4, ...) = 2048
pread64(5, ..., 0) = 512
2. Modern *at Syscalls
Problem: Focus on *at syscalls (modern POSIX API)
$ renacer -e 'trace=/.*at$/' -- ./app
openat(AT_FDCWD, "/etc/passwd", O_RDONLY) = 3
fstatat(AT_FDCWD, "file.txt", {...}, 0) = 0
renameat(AT_FDCWD, "old", AT_FDCWD, "new") = 0
3. Short Syscall Names
Problem: Filter to simple syscalls (short names)
$ renacer -e 'trace=/^.{1,5}$/' -- ./app
open(...) = 3 # 4 chars
read(...) = 42 # 4 chars
write(...) = 42 # 5 chars
close(...) = 0 # 5 chars
# Excludes: openat (6), fstatat (7), etc.
4. Network Send/Receive
Problem: All network send and receive operations
$ renacer -e 'trace=/send|recv/' -- curl https://api.example.com
sendto(...) = 120
recvfrom(...) = 1024
sendmsg(...) = 256
recvmsg(...) = 512
Troubleshooting
Issue: Regex Not Matching
Symptoms:
$ renacer -e 'trace=^open.*' -- ls
# No output or error
Cause: Missing slashes around regex pattern.
Fix:
$ renacer -e 'trace=/^open.*/' -- ls
Issue: Too Many Matches
Symptoms:
$ renacer -e 'trace=/stat/' -- ls
# Matches stat, fstat, lstat, fstatat, newfstatat, statfs, etc.
Cause: Pattern too broad.
Fix: Be more specific:
$ renacer -e 'trace=/^stat$/' -- ls
# Matches ONLY "stat" (exact)
Issue: Invalid Regex Error
Symptoms:
$ renacer -e 'trace=/[/' -- ls
Error: Invalid regex pattern: unclosed character class
Cause: Malformed regex syntax.
Fix: Check regex syntax:
$ renacer -e 'trace=/\[/' -- ls # Escape special chars
Performance Considerations
Regex Compilation Cost
Renacer compiles regex patterns once at startup. No per-syscall regex cost.
# Fast: Regex compiled once
renacer -e 'trace=/^open.*/' -- ./app
Specific vs. Broad Patterns
# Faster: Specific pattern
renacer -e 'trace=/^openat$/' -- ./app
# Slower: Broad pattern matching many syscalls
renacer -e 'trace=/.*/' -- ./app # Matches everything
Tip: Use specific patterns when possible.
Best Practices
1. Start Simple
# Start with simple substring match
renacer -e 'trace=/read/' -- ./app
# Refine to prefix if needed
renacer -e 'trace=/^read/' -- ./app
# Make exact if too broad
renacer -e 'trace=/^read$/' -- ./app
2. Test Regex Separately
# Test your regex pattern
$ echo "openat" | grep -E '^open.*'
openat
$ echo "read" | grep -E '^open.*'
# No match
3. Quote Your Patterns
# Always quote filter expressions
renacer -e 'trace=/^open.*/' -- ./app
Why: Prevents shell from interpreting regex special characters.
4. Use Negation for Exclusion
# Include broad pattern, exclude specific
renacer -e 'trace=/^open.*/,!/openat/' -- ./app
Why: More maintainable than complex negative lookaheads.
Examples Gallery
Match All File Descriptors Operations
$ renacer -e 'trace=/^(dup|fcntl|ioctl)/' -- ./app
dup2(3, 4) = 4
fcntl(5, F_GETFD) = 0
ioctl(6, TIOCGWINSZ, {...}) = 0
Match Memory Operations
$ renacer -e 'trace=/^m(map|unmap|protect|advise)/' -- ./app
mmap(NULL, 262144, PROT_READ|PROT_WRITE, ...) = 0x7f...
munmap(0x7f..., 262144) = 0
mprotect(0x7f..., 4096, PROT_READ) = 0
Match Asynchronous I/O
$ renacer -e 'trace=/^(poll|select|epoll)/' -- ./app
poll([{fd=3, events=POLLIN}], 1, 1000) = 1
epoll_wait(4, [{...}], 128, -1) = 1
Summary
Regex patterns enable flexible syscall filtering:
- Syntax:
/pattern/(slashes required) - Anchors:
^(start),$(end) - Wildcards:
.(any),.*(any sequence) - OR:
|for alternatives - Case-insensitive:
(?i)pattern
Common Patterns:
- Prefix:
/^open.*/- Matches open, openat, etc. - Suffix:
/.*at$/- Matches *at syscalls - OR:
/read|write/- Matches read OR write - Exact:
/^read$/- Matches only "read"
Combine with:
- Classes:
trace=file,/^recv.*/ - Literals:
trace=/^open.*/,close - Negation:
trace=/^open.*/,!/openat/
Next Steps:
- Negation Operator - Exclude patterns
- Syscall Classes - Predefined groups
- Filtering Syscalls - Main filtering guide