Text Format - The Renacer Book - Pure Rust System Call Tracing
Description: A comprehensive guide to renacer: syscall tracing, DWARF correlation, and performance analysis

# Text Format Specification

Complete technical reference for Renacer's default text output format (strace-compatible).

## Overview

The text format provides human-readable syscall trace output optimized for terminal viewing and strace compatibility. It outputs formatted syscall entries to stdout with optional source correlation and timing information.

Format Identifier: `text` (default format)

Sprints: 3-4 (initial), 5-6 (DWARF), 9-10 (timing), 13 (function profiling), 20 (real-time anomaly)

## Quick Start

### Basic Usage

    # Default format (no flag needed)
    renacer -- ls

    # Explicitly specify text format
    renacer --format text -- ls

    # Pipe to grep/awk for filtering
    renacer -- ls | grep "openat"

    # Save to file
    renacer -- ls > trace.txt

    # Follow forks for multi-process tracing
    renacer -f -- make

## Output Format

### Basic Syscall Format

Pattern:

    syscall_name(arg1, arg2, arg3, ...) = result

Example:

    openat(AT_FDCWD, "/etc/passwd", O_RDONLY) = 3
    read(3, "root:x:0:0:root:/root:/bin/bash\n"..., 4096) = 1024
    close(3) = 0

Field Descriptions:

Component | Description | Example
--- | --- | ---
`syscall_name` | System call name | `openat`, `read`, `write`
`(args...)` | Comma-separated arguments | `3, "hello", 4096`
`result` | Return value | `0` (success), `-1` (error), `3` (fd)

### Argument Formatting

Arguments are formatted based on their type and semantic meaning:

#### File Descriptors

    read(3, ...) = 256
    close(5) = 0

Format: Decimal integer

#### File Paths (Strings)

    openat(AT_FDCWD, "/tmp/test.txt", O_RDONLY) = 3

Format: Double-quoted string (`"path"`)

Truncation: Long paths are truncated with `...`:

    openat(AT_FDCWD, "/very/long/path/to/file/that/ex"..., O_RDONLY) = 3

Truncation Threshold: 40 characters (configurable in implementation)

#### Flags and Bitmasks

    openat(AT_FDCWD, "/tmp/file", O_RDONLY|O_CLOEXEC) = 3
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f...

Format: Symbolic constant names joined with `|`

Common Flag Families:

- File: `O_RDONLY`, `O_WRONLY`, `O_RDWR`, `O_CREAT`, `O_APPEND`, `O_CLOEXEC`
- Memory: `PROT_READ`, `PROT_WRITE`, `PROT_EXEC`, `MAP_PRIVATE`, `MAP_SHARED`
- Access: `R_OK`, `W_OK`, `X_OK`, `F_OK`

#### Special Constants

    openat(AT_FDCWD, "file.txt", O_RDONLY) = 3
    fstatat(AT_FDCWD, ".", {...}, AT_SYMLINK_NOFOLLOW) = 0

Format: Symbolic constant name

Common Constants:

- `AT_FDCWD` (-100) - Use current working directory
- `NULL` - Null pointer
- `SEEK_SET`, `SEEK_CUR`, `SEEK_END` - lseek whence values

#### Buffers and Data

    read(3, "hello world\n", 4096) = 12
    write(1, "output\n", 7) = 7

Format:

- Read buffers: Contents in double quotes (if printable)
- Non-printable data: Hex escapes (`\x0a` for newline)
- Binary data: Truncated with byte count

Binary Data Example:

    read(3, "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00"..., 832) = 832

#### Pointers

    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffff7a00000
    brk(0x555555560000) = 0x555555560000

Format: Hexadecimal with `0x` prefix

NULL Pointer: `NULL` (not `0x0`)

#### Structures

    fstat(3, {st_mode=S_IFREG|0644, st_size=1234, ...}) = 0
    stat("/tmp/file", {st_dev=makedev(0x8, 0x1), ...}) = 0

Format: `{field=value, field=value, ...}`

Truncation: Large structures abbreviated with `...`

### Return Values

#### Success (Non-Negative)

    open("/tmp/file", O_RDONLY) = 3
    read(3, "hello", 5) = 5

Format: Decimal integer

Common Values:

- `0` - Success (for syscalls like `close`, `unlink`)
- `> 0` - Successful result (file descriptor, bytes read, etc.)

#### Errors (Negative)

    open("/nonexistent", O_RDONLY) = -1 ENOENT (No such file or directory)
    read(99, ..., 4096) = -1 EBADF (Bad file descriptor)

Format: `-1 ERRNAME (Error description)`

Common Errors:

- `ENOENT` - No such file or directory
- `EACCES` - Permission denied
- `EBADF` - Bad file descriptor
- `EINVAL` - Invalid argument
- `ENOMEM` - Out of memory

Error Highlighting: Errors are typically displayed in red when output is to a terminal that supports color.

#### Unfinished Syscalls

    exit_group(0) = ?

Format: `?` (question mark)

Meaning: Syscall did not return (process terminated during call)

### Source Correlation (Sprint 5-6)

When `--source` flag is used and DWARF debug info is available:

    src/main.rs:42 read_config openat(AT_FDCWD, "/etc/config", O_RDONLY) = 3
    src/main.rs:45 read_config read(3, "key=value\n", 4096) = 10

Format:

    <file>:<line> <function> <syscall>

Field Descriptions:

Component | Description | Example
--- | --- | ---
`<file>` | Source file path | `src/main.rs`
`<line>` | Line number (1-indexed) | `42`
`<function>` | Function name | `read_config`
`<syscall>` | Standard syscall format | `openat(...) = 3`

Requirements:

1. `--source` flag enabled
2. Binary compiled with debug info (`-g` or `RUSTFLAGS="-C debuginfo=2"`)
3. DWARF sections present in binary

### Timing Mode (Sprint 9-10)

When `--timing` (or `-T`) flag is used:

    openat(AT_FDCWD, "/etc/passwd", O_RDONLY) = 3 <0.000234>
    read(3, "root:x:0:0:root:/root:/bin/bash\n"..., 4096) = 1024 <0.000089>
    close(3) = 0 <0.000012>

Format:

    syscall(...) = result <seconds>

Timing Format:

- Unit: Seconds (with microsecond precision)
- Precision: 6 decimal places (`0.000234` = 234 μs)
- Delimiters: Angle brackets `<...>`

Combined with Source:

    src/main.rs:42 read_config openat(AT_FDCWD, "/etc/config", O_RDONLY) = 3 <0.000145>

### Statistics Mode (Sprint 9-10)

When `-c` flag is used, syscall details are suppressed and only a summary is printed:

    $ renacer -c -- ls
    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
     45.23    0.000234          12        20           openat
     23.45    0.000121          15         8           read
     12.34    0.000064          16         4           fstat
      8.90    0.000046          23         2           write
      5.67    0.000029          14         2           close
      4.41    0.000023          23         1           execve
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.000517                    37         2 total

Column Descriptions:

Column | Description | Example
--- | --- | ---
`% time` | Percentage of total time | `45.23`
`seconds` | Total time in seconds | `0.000234`
`usecs/call` | Average time per call (μs) | `12`
`calls` | Number of calls | `20`
`errors` | Number of failed calls | `2`
`syscall` | Syscall name | `openat`

Sorting: By descending `% time` (slowest syscalls first)

See Also: Statistics Mode for complete details

### Real-Time Anomaly Detection (Sprint 20)

When `--anomaly-realtime` flag is used, anomalies are printed to stderr:

    $ renacer --anomaly-realtime -- ./myapp
    openat(AT_FDCWD, "/etc/config", O_RDONLY) = 3
    read(3, "key=value\n", 4096) = 10
    ⚠️  ANOMALY: read took 12456 μs (3.2σ from baseline 234.5 μs) - 🟡 Medium
    close(3) = 0

Anomaly Format (stderr):

    ⚠️  ANOMALY: <syscall> took <duration> μs (<z-score>σ from baseline <baseline> μs) - <severity>

Severity Levels:

- 🟢 Low - 2σ to 3σ deviation
- 🟡 Medium - 3σ to 4σ deviation
- 🔴 High - >4σ deviation

Output Streams:

- stdout: Normal syscall trace
- stderr: Anomaly warnings

See Also: Real-Time Anomaly Detection

## Output Streams

### stdout (Standard Output)

Contains:

- Syscall trace entries
- Statistics summary (if `-c` flag)
- Function profiling (if `--function-time` flag)
- HPU analysis (if `--hpu-analysis` flag)

Example:

    renacer -- ls > trace.txt
    # All syscall entries written to trace.txt

### stderr (Standard Error)

Contains:

- Renacer diagnostic messages
- DWARF loading status
- Real-time anomaly warnings
- Error messages

Example Messages:

    [renacer: DWARF debug info loaded from ./target/debug/myapp]
    [renacer: Attached to process 12345]
    [renacer: Warning - failed to load DWARF: No debug sections found]

Filtering stderr:

    # Suppress Renacer diagnostics
    renacer -- ls 2>/dev/null > trace.txt

    # Show only errors
    renacer -- ls > trace.txt

## Color Support

### Terminal Detection

Renacer automatically enables color output when:

1. stdout is a TTY (interactive terminal)
2. `TERM` environment variable is set
3. `NO_COLOR` environment variable is not set

Disable Color:

    # Via environment variable
    NO_COLOR=1 renacer -- ls

    # Via redirection (auto-disables)
    renacer -- ls > trace.txt

### Color Scheme

Element | Color | Example
--- | --- | ---
Syscall name | Cyan | `openat`
Error result | Red | `-1 ENOENT`
File path | Green | `"/etc/passwd"`
Return value (success) | Default | `3`
Source location | Blue | `src/main.rs:42`
Function name | Yellow | `read_config`

Implementation Note: Colors use ANSI escape codes (e.g., `\x1b[36m` for cyan).

## Compatibility

### strace Compatibility

Renacer text output is designed to be mostly compatible with strace format:

Compatible Features:

- `syscall(args...) = result` format
- Error format: `-1 ERRNO (Description)`
- Argument formatting (strings, flags, structures)
- `-c` statistics output
- `-T` timing suffix `<seconds>`

Differences from strace:

- Source correlation: Renacer adds `file:line function` prefix (strace: requires `-k` stack trace)
- Timing precision: Renacer uses 6 decimal places (strace: variable)
- Statistics columns: Slightly different column widths
- Multi-process: Renacer uses process tracking without PIDs in output (strace: adds `[pid XXXX]` prefix with `-f`)

Migration Tip: Most strace workflows work with Renacer text output:

    # Works with both strace and renacer
    renacer -- ls | grep "openat.*ENOENT"

## Filtering and Processing

### With grep

    # Find file operations
    renacer -- ls | grep "openat"

    # Find errors
    renacer -- ls | grep "ENOENT"

    # Find specific files
    renacer -- ls | grep '"/etc/'

### With awk

    # Extract syscall names
    renacer -- ls | awk -F'(' '{print $1}'

    # Filter by return value
    renacer -- ls | awk '/ = -1/'

    # Count syscalls
    renacer -- ls | awk -F'(' '{print $1}' | sort | uniq -c

### With sed

    # Remove source location
    renacer --source -- ls | sed 's/^[^ ]* [^ ]* //'

    # Extract only successful calls
    renacer -- ls | sed -n '/ = [0-9]/p'

## Performance Characteristics

### Overhead

Feature | Overhead | Notes
--- | --- | ---
Basic tracing | ~0% | Direct stdout write
Source correlation | +5-10% | DWARF lookup per syscall
Timing | +2-3% | gettimeofday per syscall
Color | +1% | ANSI escape insertion

Recommendation: Text format has the lowest overhead of all output formats.

### Output Size

Typical Sizes:

- Simple trace (100 syscalls): ~5-10 KB
- With source (100 syscalls): ~8-15 KB
- Statistics only (`-c`): ~1-2 KB (regardless of syscall count)

Comparison:

- Text: Smallest (baseline)
- JSON: +50-100% (structured overhead)
- CSV: +30-50% (delimiter overhead)
- HTML: +200-400% (template overhead)

## Line-by-Line Format Examples

### Basic File Operations

    openat(AT_FDCWD, "/tmp/test.txt", O_WRONLY|O_CREAT|O_TRUNC, 0644) = 3
    write(3, "hello world\n", 12) = 12
    fsync(3) = 0
    close(3) = 0

### Error Handling

    openat(AT_FDCWD, "/nonexistent", O_RDONLY) = -1 ENOENT (No such file or directory)
    access("/etc/shadow", R_OK) = -1 EACCES (Permission denied)
    read(99, ..., 4096) = -1 EBADF (Bad file descriptor)

### Network Operations

    socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
    connect(3, {sa_family=AF_INET, sin_port=htons(443), sin_addr=inet_addr("93.184.216.34")}, 16) = 0
    send(3, "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n", 38) = 38
    recv(3, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"..., 4096) = 1256
    close(3) = 0

### Memory Management

    brk(NULL) = 0x555555560000
    brk(0x555555581000) = 0x555555581000
    mmap(NULL, 4194304, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffff7a00000
    mprotect(0x7ffff7a00000, 4096, PROT_READ) = 0
    munmap(0x7ffff7a00000, 4194304) = 0

### Multi-Process (Fork/Exec)

    clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD) = 12345
    execve("/usr/bin/ls", ["ls", "-la"], ...) = 0
    wait4(12345, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 12345

Note: Use `-f` flag to trace forked processes. See Multi-Process Tracing.

### With Source Correlation

    src/config.rs:127 load_config openat(AT_FDCWD, "/etc/myapp.conf", O_RDONLY) = 3
    src/config.rs:128 load_config fstat(3, {st_mode=S_IFREG|0644, st_size=256, ...}) = 0
    src/config.rs:129 load_config read(3, "debug=true\nport=8080\n", 256) = 21
    src/config.rs:130 load_config close(3) = 0
    src/main.rs:45 main write(1, "Config loaded\n", 14) = 14

### With Timing

    openat(AT_FDCWD, "/etc/passwd", O_RDONLY) = 3 <0.000145>
    fstat(3, {...}) = 0 <0.000023>
    read(3, "root:x:0:0:root:/root:/bin/bash\n"..., 4096) = 1024 <0.000067>
    close(3) = 0 <0.000009>

### Complete Example (All Features)

Command:

    renacer --source --timing -- cat /etc/hostname

Output:

    /usr/lib/x86_64-linux-gnu/ld-2.31.so:? _dl_start execve("/usr/bin/cat", ["cat", "/etc/hostname"], ...) = 0 <0.000234>
    /usr/lib/x86_64-linux-gnu/ld-2.31.so:? _dl_init brk(NULL) = 0x555555560000 <0.000012>
    /usr/lib/x86_64-linux-gnu/ld-2.31.so:? _dl_map_object access("/etc/ld.so.cache", R_OK) = 0 <0.000034>
    /usr/lib/x86_64-linux-gnu/ld-2.31.so:? _dl_map_object openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 <0.000056>
    src/cat.c:234 main openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3 <0.000123>
    src/cat.c:245 cat_file fstat(3, {st_mode=S_IFREG|0644, st_size=8, ...}) = 0 <0.000045>
    src/cat.c:267 cat_file read(3, "myhost\n", 131072) = 7 <0.000078>
    src/cat.c:271 cat_file write(1, "myhost\n", 7) = 7 <0.000034>
    src/cat.c:267 cat_file read(3, "", 131072) = 0 <0.000012>
    src/cat.c:285 cat_file close(3) = 0 <0.000008>
    src/cat.c:312 main close(1) = 0 <0.000007>
    src/cat.c:315 main exit_group(0) = ?

## Edge Cases

### Unknown Syscalls

For syscalls not in Renacer's syscall table:

    syscall_999(0x1, 0x2, 0x3) = -1 ENOSYS (Function not implemented)

Format: `syscall_<number>(args...) = result`

### Incomplete Syscalls (Process Death)

    read(3, ...

Meaning: Process terminated before syscall entry was complete (rare edge case).

### Very Long Arguments

    openat(AT_FDCWD, "/very/long/path/that/gets/truncated/because/it/exceeds/the/maximum/length"..., O_RDONLY) = 3

Truncation Indicator: `...` (ellipsis)

### Non-Printable Characters

    write(1, "Hello\nWorld\t!\x00\x01\x02", 14) = 14

Escaping:

- Newline: `\n`
- Tab: `\t`
- Null: `\x00`
- Other: `\xXX` (hex)

## Combining with Other Flags

### Filtering + Text

    # Trace only file operations (text output is default)
    renacer -e trace=file -- ls

### Statistics + Timing

    # Statistics summary with timing information
    renacer -c -T -- ./myapp

Output includes `seconds` and `usecs/call` columns

### Multi-Process + Source

    # Follow forks with source correlation
    renacer -f --source -- make

All processes show source locations (if debug info available)

### Function Profiling (Sprint 13)

    # Function-level profiling with text output
    renacer --function-time -- ./myapp

Output:

    Function Profiling Report:
    ==========================================
    Function                    | Time (μs) | Calls | Avg (μs)
    ---------------------------------------------------------
    read_config                 |      234  |     1 |      234
    process_data                |     5678  |   100 |       56
    write_output                |      123  |     1 |      123

See Also: Function Profiling

## Related

- Output Formats Overview - Format selection guide
- JSON Format - Machine-parseable JSON output
- CSV Format - Spreadsheet-compatible output
- CLI Reference - Complete command-line options
- Statistics Mode - Statistics mode details