Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
29741d7
feat: add semantic printing for Rust &str values
swananan Jul 15, 2026
5faa44a
feat: add semantic printing for Rust String values
swananan Jul 16, 2026
098d46b
feat: add semantic printing for Rust Vec values
swananan Jul 17, 2026
1137dee
feat: add semantic printing for Rust slice values
swananan Jul 17, 2026
4363fe0
feat: add semantic printing for Rust Box<str>
swananan Jul 17, 2026
003d58b
feat: add semantic printing for Rust OsString values
swananan Jul 17, 2026
9432be0
feat: add semantic printing for Rust VecDeque values
swananan Jul 17, 2026
abdaf70
feat: add semantic printing for Rust NonZero values
swananan Jul 17, 2026
01ffd3a
feat: add semantic printing for Rust Cell values
swananan Jul 17, 2026
4f6ac13
feat: add semantic printing for Rust RefCell values
swananan Jul 17, 2026
d8aeada
feat: add semantic printing for Rust Ref guards
swananan Jul 17, 2026
40c5855
feat: add semantic printing for Rust Rc and Arc
swananan Jul 17, 2026
e326d7d
feat: add semantic printing for Rust hash collections
swananan Jul 17, 2026
c6004a5
feat: add semantic printing for Rust B-Tree collections
swananan Jul 17, 2026
008c71c
fix: support Rust value layouts across versions
swananan Jul 17, 2026
12e1690
feat: support Rust 1.35 hash collections
swananan Jul 17, 2026
d478d0a
feat: support Rust 1.35 B-Tree collections
swananan Jul 17, 2026
ac226ff
test: cover Rust 1.35 string layouts
swananan Jul 17, 2026
8c16e80
test: cover Rust 1.35 sequence layouts
swananan Jul 17, 2026
eb2de31
feat: display Rust Rc<str> and Arc<str> targets
swananan Jul 18, 2026
7cc4d10
feat: support Rust Path values
swananan Jul 18, 2026
53bb3de
docs: document Rust value support and limits
swananan Jul 19, 2026
b3ed06a
feat: support Rust enums from DWARF variants
swananan Jul 19, 2026
7e6603c
refactor: centralize Rust DWARF presentation logic
swananan Jul 19, 2026
6b71086
test: expand Rust compatibility coverage
swananan Jul 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ jobs:
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@1.88.0

- name: Install Rust compatibility toolchains
run: |
mapfile -t toolchains < <(
sed -e 's/[[:space:]]*#.*$//' \
-e '/^[[:space:]]*$/d' \
e2e-tests/rust-compat-toolchains.txt
)
rustup toolchain install --profile minimal "${toolchains[@]}"

- name: Cache cargo registry
uses: actions/cache@v4
with:
Expand Down Expand Up @@ -133,6 +142,7 @@ jobs:
- name: Run workspace tests
run: cargo test --all-features
env:
GHOSTSCOPE_REQUIRE_RUST_COMPAT_TOOLCHAINS: 1
RUST_BACKTRACE: 1

e2e:
Expand All @@ -156,6 +166,15 @@ jobs:
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@1.88.0

- name: Install Rust e2e compatibility toolchains
run: |
mapfile -t toolchains < <(
sed -e 's/[[:space:]]*#.*$//' \
-e '/^[[:space:]]*$/d' \
e2e-tests/rust-compat-toolchains.txt
)
rustup toolchain install --profile minimal "${toolchains[@]}"

- name: Cache cargo registry
uses: actions/cache@v4
with:
Expand Down Expand Up @@ -185,7 +204,7 @@ jobs:
uses: actions/cache@v4
with:
path: e2e-tests/.fixture-cache/fixture-binaries.tar
key: ${{ runner.os }}-${{ github.job }}-fixtures-${{ env.FIXTURE_COMPILER_CACHE_REV }}-${{ hashFiles('e2e-tests/cache-fixtures.sh', 'e2e-tests/compile-fixtures.sh', 'e2e-tests/tests/fixtures/**/*.c', 'e2e-tests/tests/fixtures/**/*.h', 'e2e-tests/tests/fixtures/**/*.cpp', 'e2e-tests/tests/fixtures/**/*.rs', 'e2e-tests/tests/fixtures/**/Makefile', 'e2e-tests/tests/fixtures/**/Cargo.toml', 'e2e-tests/tests/fixtures/**/Cargo.lock') }}
key: ${{ runner.os }}-${{ github.job }}-fixtures-${{ env.FIXTURE_COMPILER_CACHE_REV }}-${{ hashFiles('e2e-tests/cache-fixtures.sh', 'e2e-tests/compile-fixtures.sh', 'e2e-tests/compile-rust-compat-fixtures.sh', 'e2e-tests/rust-compat-toolchains.txt', 'e2e-tests/tests/fixtures/**/*.c', 'e2e-tests/tests/fixtures/**/*.h', 'e2e-tests/tests/fixtures/**/*.cpp', 'e2e-tests/tests/fixtures/**/*.rs', 'e2e-tests/tests/fixtures/**/Makefile', 'e2e-tests/tests/fixtures/**/Cargo.toml', 'e2e-tests/tests/fixtures/**/Cargo.lock') }}

- name: Restore fixture archive
if: steps.fixture-cache.outputs.cache-hit == 'true'
Expand All @@ -200,13 +219,22 @@ jobs:
"$FIXTURE_COMPILER_IMAGE" \
bash ./compile-fixtures.sh
sudo chown -R "$(id -u):$(id -g)" "${GITHUB_WORKSPACE}/e2e-tests/tests/fixtures"
bash ./e2e-tests/cache-fixtures.sh pack

- name: Compile Rust target-compiler matrix fixtures
if: steps.fixture-cache.outputs.cache-hit != 'true'
run: bash ./e2e-tests/compile-rust-compat-fixtures.sh

- name: Pack fixture archive
if: steps.fixture-cache.outputs.cache-hit != 'true'
run: bash ./e2e-tests/cache-fixtures.sh pack

- name: Build GhostScope CLI and dwarf-tool
run: cargo build -p ghostscope -p dwarf-tool --all-features

- name: Run e2e
env:
GHOSTSCOPE_REQUIRE_RUST_135_E2E: 1
GHOSTSCOPE_REQUIRE_RUST_E2E_TOOLCHAINS: 1
GHOSTSCOPE_PRESERVE_PRECOMPILED_FIXTURES: 1
RUST_BACKTRACE: 1
run: sudo -E "$(which cargo)" test -p ghostscope-e2e-tests --tests --all-features -- --nocapture
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ test_*
# Keep fixture compiler entrypoint tracked
!e2e-tests/compile-fixtures.sh
!e2e-tests/cache-fixtures.sh
!e2e-tests/compile-rust-compat-fixtures.sh
# Keep other C files in test fixtures but exclude random C files in root
/*.c
e2e-tests/tests/fixtures/complex_types_program/complex_types_program
Expand All @@ -69,6 +70,7 @@ e2e-tests/tests/fixtures/member_pointer_program/member_pointer_program
e2e-tests/tests/fixtures/member_pointer_program/member_pointer_program_o*
e2e-tests/tests/fixtures/partitioned_ranges_program/partitioned_ranges_program
e2e-tests/tests/fixtures/rust_global_program/target/
e2e-tests/tests/fixtures/rust_compat_program/bin/
e2e-tests/tests/fixtures/scalar_types_program/scalar_types_program
e2e-tests/tests/fixtures/sample_program/sample_lib.o
e2e-tests/tests/fixtures/sample_program/sample_program
Expand Down
8 changes: 5 additions & 3 deletions docs/design-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ does not permit known unsupported paths to return plausible but unproven data.
traced. Embedded DWARF is read from that module. For separate debug files,
available `.gnu_debuglink` CRC and Build ID evidence is checked strictly by
default.
- C has the strongest end-to-end coverage. C++ and Rust currently use a more
limited, DWARF-layout-oriented model. Language coverage is documented in
[limitations](limitations.md).
- C has the strongest end-to-end coverage. C++ remains primarily
DWARF-layout-oriented, while Rust adds targeted standard-library semantic
adapters selected from validated target DWARF. See
[Source Language Support](scripting.md#source-language-support) for current
coverage and [limitations](limitations.md) for its boundaries.
- The kernel must provide the required eBPF, uprobe, and event transport
facilities, and GhostScope must have permission to use them.

Expand Down
24 changes: 21 additions & 3 deletions docs/limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,27 @@ Official builds and correctness testing currently support **Linux x86_64 (AMD64)
## Soft Limitations

### 1. Language Support
Primary focus is on **C language**, which currently has the best end-to-end support. **C++** and **Rust** are supported in a more limited, DWARF-layout-oriented way: GhostScope can automatically demangle function names and global/static symbols, but most language-specific features are not modeled yet. In practice, simple C-like layouts work best, while advanced Rust and C++ features still require substantial future work.

For interpreted languages (Lua, Python, Ruby, etc.), only the interpreter itself can be traced (since interpreters are typically implemented in compiled languages). Tracing script code is technically feasible but requires substantial development time. JIT language support is an even more distant goal.
Primary focus is on **C**, which has the best end-to-end coverage. Inline C
structs, arrays, unions, enums, typedefs, and qualifiers are formatted
recursively from DWARF. Pointer members are shown as addresses unless the DSL
or a read plan explicitly follows them; GhostScope does not automatically walk
arbitrary C pointer graphs or linked data structures. Recursive inline
formatting has a maximum depth of 32.

**Rust** has targeted semantic support for common standard-library value
families. It is selected from the concrete target DWARF rather than from a
promised Rust ABI. Nested semantic adapters do not yet compose automatically.
See [Rust Value Presentation](scripting.md#rust-value-presentation) for the
current type list, formatting behavior, and nesting boundary.

**C++** remains primarily DWARF-layout-oriented. Simple C-like layouts work
best; broader standard-library and language-specific semantics are not modeled
yet.

For interpreted languages (Lua, Python, Ruby, etc.), only the interpreter
itself can be traced because interpreters are typically implemented in compiled
languages. Tracing script code is technically feasible but requires substantial
development time. JIT language support is an even more distant goal.

### 2. User-Memory Reads via `bpf_probe_read_user`
In traditional non-sleepable probe paths, helpers such as `bpf_probe_read_user` cannot resolve user-space page faults, so reads from a target virtual address may still fail if the page is not resident or otherwise faults on access.
Expand Down
119 changes: 115 additions & 4 deletions docs/scripting.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,123 @@ GhostScope's script syntax is source-language agnostic, but real-world support d
| --- | --- | --- |
| C | Best | This is the primary target. Plain locals, globals, x86_64 executable static thread-local variables, pointers, arrays, structs, enums, and C strings map most directly to the current DWARF readers and script operators. |
| C++ | Limited | Automatic demangling is supported for function names in `trace ...` patterns and for global/static variable lookup. Beyond name resolution, most C++-specific language features are not modeled yet, so the best results come from simple, C-like layouts and scalar fields. |
| Rust | Limited | Automatic demangling is supported for function names in `trace ...` patterns and for global/static variable lookup. Numeric tuple fields such as `value.0` are supported for tuples and tuple structs when Rust DWARF type identity is available. Most other Rust-specific features are not modeled yet. |
| Rust | Targeted | See [Rust value details](#rust-value-presentation). |

Practical guidance:
- Prefer C targets when you need the highest success rate for complex DWARF expressions.
- GhostScope recognizes `DW_OP_form_tls_address`, which is used for both static and dynamic TLS. Runtime address resolution currently supports only x86_64 executable static TLS; dynamic/shared-library TLS is not modeled yet.
- C++ remains primarily DWARF-layout aware. Rust tuple fields are the first language-aware projection, but broader Rust semantics are not modeled yet.
- In C++ and Rust, start from demangled function/global names, then probe simple fields first. If name lookup is ambiguous, fall back to line- or address-based trace patterns.
- C++ remains primarily DWARF-layout aware.
- Rust support is determined from each target type's language, identity, and
validated DWARF layout. A rustc release parsed from `DW_AT_producer` is only
advisory metadata; it never establishes a private layout by itself.
- If name lookup is ambiguous, fall back to line- or address-based trace
patterns.

### Rust Value Presentation

Rust value support does not add Rust-specific syntax to the DSL. After the DSL
resolves an expression, the DWARF layer may select a bounded semantic read plan
for its root type. If the concrete type identity or layout does not validate,
GhostScope keeps the native DWARF presentation instead of guessing an ABI.

GhostScope's own Rust 1.88 build toolchain does not constrain the rustc used to
build a traced target. CI compiles representative target binaries with the
releases in the [compatibility matrix](../e2e-tests/rust-compat-toolchains.txt).
That matrix records audited DWARF layouts rather than version gates: coverage is
adapter-specific, so not every value family is validated on every listed
release, and unmatched older layouts fall back to native DWARF presentation.

The currently supported value families are:

- UTF-8 strings: `&str`, `&mut str`, `String`, and `Box<str>`;
- platform byte strings: `OsString`, `PathBuf`, and supported `&Path` layouts;
- sequences: `Vec<T>`, `&[T]`, `&mut [T]`, and `VecDeque<T>`;
- transparent and state wrappers: `NonZero*`, `Cell<T>`, and `RefCell<T>`;
- borrow guards: `Ref<T>` and `RefMut<T>`;
- reference counting: `Rc<T>` and `Arc<T>`;
- collections: `HashMap`, `HashSet`, `BTreeMap`, and `BTreeSet`;
- enums: fieldless, unit, tuple, and struct variants, including DWARF default
branches used by niche-optimized types such as `Option<NonZero*>`; and
- tuple and tuple-struct projections such as `value.0`.

`Rc<str>` and `Arc<str>` are displayed as their target address plus public
strong and weak counts. GhostScope does not read the dynamically sized string
contents through these owners.

Rust enum formatting follows the target DWARF rather than a rustc ABI table.
For payload enums, GhostScope reads `DW_TAG_variant_part`, follows its
`DW_AT_discr` member, and handles exact values, discriminant ranges, and default
branches before recursively formatting the active inline payload. Fieldless
enums use `DW_TAG_enumeration_type` and `DW_AT_enum_class`. The DSL does not yet
provide Rust pattern matching or direct active-variant payload projection, and
semantic adapters nested inside an enum payload still use native DWARF
formatting.

Semantic values use the existing format placeholders:

```ghostscope
trace do_stuff {
print "text={} ascii={:s} bytes={:x}", text, text, text;
print "items={}", values;
}
```

- `{}` uses the selected semantic presentation.
- When a semantic value supports no-length `{:s}` or `{:x}`, the formatter uses
its logical captured payload rather than exposing internal protocol metadata.
- Length forms such as `{:s.16}`, `{:x.*}`, and `{:s.n$}` retain their generic
explicit memory-read behavior.
- `ebpf.mem_dump_cap` bounds each indirect argument and defaults to 256 bytes.
A semantic value whose logical length exceeds the captured prefix is marked
`<truncated>`.

For example, with `mem_dump_cap = 3`, an `&str` containing
`"hello from rust"` is rendered as:

```text
"hel" <truncated>
```

The value can also be read explicitly when its target DWARF exposes known
members:

```ghostscope
trace do_stuff {
print "manual={:s.*}", text.length, text.data_ptr;
print "manual_hex={:x.*}", text.length, text.data_ptr;
}
```

This explicit form depends on the target's physical member paths. The semantic
form validates and hides those paths.

#### Nested Rust Values

Inline DWARF structure formatting is recursive, with a maximum depth of 32.
This also applies to inline Rust values after an outer adapter captures them:

```text
Outer { inner: Pair } inline Pair uses recursive DWARF formatting
Vec<Pair> Vec captures elements; Pair formats structurally
Rc<Pair> Rc projects Pair and counters; Pair formats inline
Cell<(i32, u16)> Cell projects and formats the inline tuple value
```

Semantic adapter selection currently occurs once for the root expression type.
Nested semantic containers are not recursively recaptured:

```text
Rc<Vec<i32>> inner Vec elements are not captured recursively
Cell<String> inner String bytes are not captured recursively
Vec<String> String elements retain physical DWARF formatting
HashMap<String, Vec<i32>> keys and values do not run nested adapters
```

Known nested fields remain accessible explicitly through the DSL. The
limitation applies to automatic whole-value presentation. Recursive semantic
capture requires bounded depth, byte, element, and dereference budgets; cycle
detection; deterministic event reservation; and per-child read-error and
truncation status.

## Variables

Expand Down Expand Up @@ -854,7 +964,8 @@ trace foo {
4. Limited string operations (CString equality and built‑ins only)
5. Integer-only arithmetic/bitwise operators; floating-point arithmetic is not supported
6. No dynamic memory allocation in eBPF
7. Uneven source-language coverage: C works best; C++ and Rust currently rely mostly on automatic demangling plus DWARF-layout-based access, with most language-specific features unsupported
7. Source-language coverage remains type- and DWARF-layout-specific; see
[Source Language Support](#source-language-support)

## Best Practices

Expand Down
5 changes: 4 additions & 1 deletion docs/zh/design-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ GhostScope 把运行中程序的机器状态转换为源码感知的观测结果

- 官方发布产物和正确性测试面向 Linux x86_64。运行时构建会拒绝其他构建目标,trace setup 也会拒绝不是 64 位小端 x86_64 ELF 的目标文件。
- 源码级值依赖与目标模块对应的 DWARF。内嵌 DWARF 直接来自目标模块;独立调试文件默认严格检查可用的 `.gnu_debuglink` CRC 和 Build ID 证据。
- C 语言的端到端覆盖最完整。C++ 和 Rust 目前主要采用能力更有限的“按 DWARF 布局访问”模型。具体语言覆盖见[使用限制](limitations.md)。
- C 语言的端到端覆盖最完整。C++ 仍主要按 DWARF 布局访问;Rust 则在
验证目标 DWARF 后,为部分标准库类型提供语义适配。当前覆盖范围见
[源语言支持现状](scripting.md#源语言支持现状),能力边界见
[使用限制](limitations.md)。
- 内核必须提供所需的 eBPF、uprobe 和事件传输能力,GhostScope 也必须具备使用这些设施的权限。

`--allow-loose-debug-match` 会显式退出独立调试文件的严格匹配。启用后 GhostScope 会对不匹配发出警告,但用户同时也削弱了源码语义解释所依赖的证据。如果一个显式指定的调试文件既没有可用 CRC,也没有可比较的 Build ID,系统同样无法证明它与目标模块一致;相应 warning 表示这成为用户提供的信任假设,不属于严格证据范围。
Expand Down
14 changes: 13 additions & 1 deletion docs/zh/limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,19 @@ GhostScope 的脚本和编译器能力面只用于观测,不提供主动修改
## 软性限制

### 1. 语言支持
目前主要支持 **C 语言**,对 C 的端到端支持最完善。**C++** 和 **Rust** 目前属于更偏“按 DWARF 布局访问”的有限支持:GhostScope 支持对函数名以及全局/静态符号做自动 demangle,但大多数语言特性还没有建模。实际使用中,越接近 C 风格的数据布局越容易成功;Rust 和 C++ 的高级特性仍需要后续大量补强。
目前以 **C 语言** 为主要目标,对 C 的端到端支持最完善。内联 C
结构体、数组、联合体、枚举、typedef 和限定类型会根据 DWARF 递归格式化。
除非 DSL 或读取计划显式跟随指针,否则指针成员只显示地址;GhostScope
不会自动遍历任意 C 指针图或链式数据结构。内联递归格式化的最大深度为
32。

**Rust** 已针对常见标准库类型提供定向语义支持。这些适配器根据具体目标
的 DWARF 选择,而不是假设一个稳定的 Rust ABI。嵌套语义适配器目前不会
自动递归组合。当前类型列表、格式化行为和嵌套边界见
[Rust 值展示](scripting.md#rust-值展示)。

**C++** 仍主要按 DWARF 布局访问。简单、接近 C 的数据布局效果最好;
更广泛的标准库和语言特定语义尚未建模。

对于解释型语言(Lua、Python、Ruby 等),目前只能追踪解释器本身(因为解释器通常用编译型语言实现)。追踪脚本代码在技术上可行,但需要大量开发时间,JIT 语言支持计划就更远了。

Expand Down
Loading
Loading