64kramsystem / 64kramsystem/ghidra-vice-connector

Memory access heatmap: runtime code-vs-data classification

未关闭
#18 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
priority: high
主要语言
Python
星标
1
派生
0
PR 合并指标
30 天内没有已合并 PR

描述

## Summary

The fundamental challenge in C64 game disassembly is distinguishing code from data in a flat 64KB address space (sprite frames, music data, lookup tables, level maps all live alongside executable code). Using VICE tracepoints (non-stopping checkpoints) to record which addresses are executed vs. read as data vs. written, then annotating the Ghidra listing accordingly, can solve this automatically at runtime.

Inspired by RetroDebugger's memory access layers and IceBroLite's memory visualization.

---

## How VICE supports this

Checkpoints with `stop_on_hit=False` fire without pausing execution. VICE still sends `RESP_CHECKPOINT_INFO` (0x11) events when these tracepoints are hit — with `currently_hit=True` and the `cpu_op` flag (EXEC/LOAD/STORE) identifying the access type.

`checkpoint_set()` in `util.py:480` already accepts `stop_on_hit` — it just needs to be `False`. The event handler in `hooks.py` currently only handles `RESP_STOPPED` (0x62) and `RESP_RESUMED` (0x63); a handler for `RESP_CHECKPOINT_INFO` (0x11) needs to be registered.

---

## Implementation plan

### Phase 1 — Collect access data

1. **`util.py`**: Register a `RESP_CHECKPOINT_INFO` (0x11) event handler in `ViceBmpClient` that accumulates `(address, cpu_op)` hits into a dict without blocking. The address is already in the checkpoint info struct at `start` field (`util.py:98-116`).

2. **`methods.py`**: Add three new remote methods:
- `start_heatmap(process: C64, start: Address, end: Address)` — calls `checkpoint_set()` three times (EXEC, LOAD, STORE) with `stop_on_hit=False` over the given range.
- `stop_heatmap(process: C64)` — deletes the heatmap checkpoints.
- `apply_heatmap(process: C64)` — applies collected data to the program (Phase 2).

### Phase 2 — Annotate the Ghidra listing

`apply_heatmap()` iterates the accumulated access dict and for each address:
- EXEC hits → set Ghidra bookmark type `"Code"` (or call `trace.disassemble()` at those addresses)
- LOAD-only (never EXEC) → set bookmark type `"Data"`, add plate comment `"Read as data (heatmap)"`
- STORE hits → add plate comment `"Written at runtime"`

Bookmarks are written via the trace: `trace.proxy_object_path(...).set_value(...)` or via a post-analysis Ghidra script that reads from a persisted set.

### Alternative: CPU History bulk approach

If tracepoints prove too noisy (too many RESP_CHECKPOINT_INFO events flooding the socket), use `CMD_CPU_HISTORY` (0x86) on each stop instead: retrieve the last N instructions, extract their PCs, and accumulate them. This gives executed addresses only, not data reads.

---

## BMP commands involved

| Command | Hex | Already in util.py? |
|---------|-----|-------------------|
| `CMD_CHECKPOINT_SET` | 0x12 | Yes (`util.py:480`) |
| `CMD_CHECKPOINT_DELETE` | 0x13 | Yes (`util.py:512`) |
| `RESP_CHECKPOINT_INFO` event | 0x11 | Not handled as event |

---

## Files to change

- `src/main/py/src/vice/util.py` — add `RESP_CHECKPOINT_INFO` event handling
- `src/main/py/src/vice/methods.py` — add `start_heatmap`, `stop_heatmap`, `apply_heatmap` methods
- `src/main/py/src/vice/commands.py` — add accumulated access state and annotation logic

贡献指南

这个仓库没有索引到贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。