feat(handlers): add callstack_resolve and section_write (Phase 5C)#164
feat(handlers): add callstack_resolve and section_write (Phase 5C)#164BANANASJIM merged 3 commits intomasterfrom
Conversation
Add two new daemon handlers and CLI commands for Phase 5C: - `callstack_resolve`: resolves CPU callstacks for events via InitResolver/GetResolve API. Returns frames with function/file/line. Guards for missing callstacks, symbol unavailability, and EID range. - `section_write`: writes custom sections to capture files with base64 wire format. Protects built-in sections (FrameCapture, ResolveDatabase, etc.) from overwrite. CLI additions: - `rdc callstacks [--eid N] [--json]` with 60s timeout for symbol load - `rdc section <name> --write <file>` with stdin support via `-` - `call()` helper gains optional `timeout` parameter 35 handler tests + 25 CLI tests + 5 E2E tests covering all error paths.
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdded a new Changes
Sequence Diagram(s)mermaid Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PR Compliance Guide 🔍Below is a summary of compliance checks for this PR:
Compliance status legend🟢 - Fully Compliant🟡 - Partial Compliant 🔴 - Not Compliant ⚪ - Requires Further Human Verification 🏷️ - Compliance label |
|||||||||||||||||||||||||
PR Code Suggestions ✨Explore these optional code suggestions:
|
||||||||||||||||||
There was a problem hiding this comment.
🧹 Nitpick comments (3)
src/rdc/commands/_helpers.py (1)
125-142: Consider addingtimeoutparameter totry_callfor consistency.
try_callcurrently doesn't support thetimeoutparameter whilecalldoes. If callers need longer timeouts for optional features, they'd be unable to configure it.♻️ Optional: Add timeout to try_call
-def try_call(method: str, params: dict[str, Any]) -> dict[str, Any] | None: +def try_call(method: str, params: dict[str, Any], *, timeout: float = 30.0) -> dict[str, Any] | None: """Send a JSON-RPC request, returning None on failure. Unlike call(), this never exits -- failures are silent. Use for optional features where partial success is acceptable. """ try: host, port, token = require_session() except SystemExit: return None payload = _request(method, 1, {"_token": token, **params}).to_dict() try: - response = send_request(host, port, payload) + response = send_request(host, port, payload, timeout=timeout) except (OSError, ValueError): return None🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/rdc/commands/_helpers.py` around lines 125 - 142, The try_call function lacks a timeout parameter while call supports one; add an optional timeout: float | None = None to try_call's signature and docstring (mirror call's default), pass it through to send_request(host, port, payload, timeout=timeout), and update the return/typing accordingly; ensure require_session(), _request(method, 1, ...), and any callers of try_call are compatible with the new optional parameter (update usages if they need to set a timeout).tests/unit/test_capturefile_handlers.py (1)
302-321: Thorough multi-frame test with minor style suggestion.The test correctly validates frame ordering and content parsing. Minor suggestion: line 311's
[i for i in range(5)]can be simplified tolist(range(5)).♻️ Suggested simplification
resolve = [f"func{i} file{i}.c:{i * 10}" for i in range(5)] state = _make_callstack_state( tmp_path, monkeypatch, - callstack_addrs=[i for i in range(5)], + callstack_addrs=list(range(5)), resolve_strings=resolve, )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/unit/test_capturefile_handlers.py` around lines 302 - 321, In test_callstack_resolve_multi_frame replace the explicit comprehension used for callstack_addrs with the simpler built-in conversion: change the argument callstack_addrs=[i for i in range(5)] to callstack_addrs=list(range(5)) in the test_callstack_resolve_multi_frame function to improve readability and style.tests/unit/test_capturefile_commands.py (1)
162-176: Consider using the top-leveljsonimport.The test imports
json as _jsonlocally, butjsonis already imported at the module level insrc/rdc/commands/capturefile.py. If this test file needs JSON parsing, consider addingimport jsonto the top-level imports instead of the local alias.♻️ Suggested refactor
Add to top-level imports:
import jsonThen in the test:
def test_section_write_json(monkeypatch, tmp_path: Path) -> None: """T-5C-28: --json on write emits JSON.""" - import json as _json - f = tmp_path / "notes.txt" f.write_bytes(b"hello") patch_cli_session(monkeypatch, {"name": "MyNotes", "bytes": 5}) result = CliRunner().invoke(section_cmd, ["MyNotes", "--write", str(f), "--json"]) assert result.exit_code == 0 # stdout has confirmation on stderr + JSON; extract JSON line json_lines = [ln for ln in result.output.splitlines() if ln.startswith("{")] assert json_lines, "no JSON line in output" - data = _json.loads(json_lines[0]) + data = json.loads(json_lines[0]) assert data["name"] == "MyNotes" assert data["bytes"] == 5🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/unit/test_capturefile_commands.py` around lines 162 - 176, The test test_section_write_json is locally importing json as _json; instead add a top-level import json to the test module and switch the test to use that top-level json (remove the local `import json as _json`), so data = json.loads(...) and other json references use the module-level import; this keeps imports consistent with the rest of the codebase and avoids the local alias.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/rdc/commands/_helpers.py`:
- Around line 125-142: The try_call function lacks a timeout parameter while
call supports one; add an optional timeout: float | None = None to try_call's
signature and docstring (mirror call's default), pass it through to
send_request(host, port, payload, timeout=timeout), and update the return/typing
accordingly; ensure require_session(), _request(method, 1, ...), and any callers
of try_call are compatible with the new optional parameter (update usages if
they need to set a timeout).
In `@tests/unit/test_capturefile_commands.py`:
- Around line 162-176: The test test_section_write_json is locally importing
json as _json; instead add a top-level import json to the test module and switch
the test to use that top-level json (remove the local `import json as _json`),
so data = json.loads(...) and other json references use the module-level import;
this keeps imports consistent with the rest of the codebase and avoids the local
alias.
In `@tests/unit/test_capturefile_handlers.py`:
- Around line 302-321: In test_callstack_resolve_multi_frame replace the
explicit comprehension used for callstack_addrs with the simpler built-in
conversion: change the argument callstack_addrs=[i for i in range(5)] to
callstack_addrs=list(range(5)) in the test_callstack_resolve_multi_frame
function to improve readability and style.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (21)
src/rdc/_skills/references/commands-quick-ref.mdsrc/rdc/cli.pysrc/rdc/commands/_helpers.pysrc/rdc/commands/capturefile.pysrc/rdc/handlers/capturefile.pytests/e2e/test_capturefile.pytests/mocks/mock_renderdoc.pytests/unit/conftest.pytests/unit/test_capturefile_commands.pytests/unit/test_capturefile_handlers.pytests/unit/test_debug_commands.pytests/unit/test_info_commands.pytests/unit/test_pipeline_cli_phase27.pytests/unit/test_pipeline_commands.pytests/unit/test_pipeline_shader.pytests/unit/test_resources_commands.pytests/unit/test_resources_filter.pytests/unit/test_script_command.pytests/unit/test_search.pytests/unit/test_shader_preload.pytests/unit/test_unix_helpers_commands.py
The actual RenderDoc system section is named "renderdoc/internal/framecapture", not "FrameCapture". The E2E test was creating a custom section instead of testing the protection against overwriting real system sections.
Greptile SummaryThis PR successfully implements Phase 5C by adding CPU callstack resolution and custom section writing capabilities to the RenderDoc CLI. The implementation is well-designed with proper error handling, input validation, and security protections. Key Changes:
Code Quality Highlights:
Confidence Score: 5/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant CLI as CLI Command
participant Helper as call() helper
participant Daemon as Daemon Handler
participant RDC as RenderDoc API
Note over CLI,RDC: Callstack Resolution Flow
CLI->>Helper: callstacks_cmd(eid, json)<br/>timeout=60s
Helper->>Daemon: callstack_resolve(eid)
Daemon->>RDC: HasCallstacks()
RDC-->>Daemon: true
Daemon->>RDC: InitResolver(interactive=False)
RDC-->>Daemon: ok
Daemon->>RDC: controller.GetCallstack(eid)
RDC-->>Daemon: [addresses]
Daemon->>RDC: GetResolve(addresses)
RDC-->>Daemon: ["func file.c:line"]
Daemon->>Daemon: _parse_resolve_string()
Daemon-->>Helper: {eid, frames}
Helper-->>CLI: formatted output
Note over CLI,RDC: Section Write Flow
CLI->>Helper: section_cmd(name, write_file)
CLI->>CLI: read file or stdin
CLI->>CLI: base64.encode(data)
Helper->>Daemon: section_write(name, data_b64)
Daemon->>RDC: FindSectionByName(name)
RDC-->>Daemon: idx
alt section exists
Daemon->>RDC: GetSectionProperties(idx)
RDC-->>Daemon: props
Daemon->>Daemon: check if type in PROTECTED_SECTION_TYPES
alt protected
Daemon-->>Helper: error: cannot overwrite
end
end
Daemon->>Daemon: base64.decode(data_b64)
Daemon->>RDC: WriteSection(props, bytes)
RDC-->>Daemon: success
Daemon-->>Helper: {name, bytes}
Helper-->>CLI: confirmation message
Last reviewed commit: a3e3bfa |
- Wrap WriteSection in try/except to return JSON-RPC error instead of crashing - Remove raw exception details from callstack_resolve error responses - Log exception details at DEBUG level for troubleshooting
User description
Summary
callstack_resolvedaemon handler: resolves CPU callstacks viaInitResolver()+GetResolve(), with proper guards for missing callstacks and unavailable symbolssection_writedaemon handler: writes custom sections into .rdc files via base64-encoded data, with protection against overwriting system sections (FrameCapture, ResolveDatabase, etc.)rdc callstacks [--eid N] [--json]CLI command with 60s timeout for symbol loading latencyrdc section <name> --write <file>CLI command supporting file and stdin (-) inputtimeoutparameter tocall()helper for per-command timeout controlTest plan
pixi run lint— zero errorspixi run test— 2488 passed, 93.80% coveragepixi run test-e2e— GPU e2e tests passrdc open fixture.rdc→rdc callstacks→ exits 1 "no callstacks"rdc section MyNote --write /tmp/note.txt→ write + readbackPR Type
Enhancement
Description
Add
callstack_resolvedaemon handler resolving CPU callstacks via InitResolver/GetResolveAdd
section_writedaemon handler writing custom sections with built-in section protectionAdd
rdc callstacks [--eid N] [--json]CLI command with 60s timeoutExtend
rdc section <name> --write <file>supporting file and stdin inputAdd
timeoutparameter tocall()helper for per-command timeout control44 handler tests + 17 CLI tests + 5 E2E tests covering all error paths
Diagram Walkthrough
File Walkthrough
4 files
Register callstacks_cmd in main CLIAdd timeout parameter to call() helperAdd callstacks_cmd and section_write supportImplement callstack_resolve and section_write handlers16 files
Add E2E tests for callstacks and section writeAdd mock support for callstack and section APIsUpdate send_request mock to accept timeout kwargAdd 17 CLI tests for callstacks and section writeAdd 44 handler tests for callstack and section logicUpdate send_request mock signature for timeoutUpdate send_request mock signature for timeoutUpdate send_request mock signature for timeoutUpdate send_request mock signature for timeoutUpdate send_request mock signature for timeoutUpdate send_request mock signature for timeoutUpdate send_request mock signature for timeoutUpdate send_request mock signature for timeoutUpdate send_request mock signature for timeoutUpdate send_request mock signature for timeoutUpdate send_request mock signature for timeout1 files
Document callstacks command and section --write optionSummary by CodeRabbit
New Features
Improvements
Quality
Documentation