64kramsystem / 64kramsystem/ghidra-vice-connector

Tracepoints: non-stopping checkpoints for call graph mapping

Abierto
#20 0 comentarios 0 reacciones 0 asignados Ver en GitHub
priority: high
Lenguaje dominante
Python
Estrellas
1
Forks
0
Métricas de merge de PR
Sin PR fusionados en 30 d

Descripción

## Summary

Add the ability to set tracepoints — checkpoints that log execution without pausing — so the game can run freely while address hits are collected. This lets you map which subroutines are called, how often, and in what order during a gameplay session without interactive stepping.

Source: IceBroLite tracepoint view; VICE BMP already supports `stop_on_hit=False` on checkpoints.

---

## How VICE supports this

`checkpoint_set()` in `util.py:480` already accepts `stop_on_hit: bool`. Setting it to `False` creates a tracepoint. VICE fires `RESP_CHECKPOINT_INFO` (0x11) events (with `currently_hit=True`) each time the tracepoint is hit, without stopping execution.

The missing piece is:
1. A `RESP_CHECKPOINT_INFO` **event** handler (currently only `RESP_STOPPED` and `RESP_RESUMED` are handled in `hooks.py`)
2. Ghidra methods to set/clear tracepoints and display the log

---

## Implementation plan

### 1. `util.py` — event handler for checkpoint hits

In `ViceBmpClient.connect()` (`util.py:159`), register a handler for `RESP_CHECKPOINT_INFO` (0x11) as an event:

```python
self.on_event(RESP_CHECKPOINT_INFO, self._on_checkpoint_hit)
```

```python
def _on_checkpoint_hit(self, resp_type, error, body):
cp = _parse_checkpoint_info(body) # util.py:98 — already parses all fields
if cp['currently_hit'] and not cp['stop_on_hit']:
self._tracepoint_hits.append({
'number': cp['number'],
'address': cp['start'],
'hit_count': cp['hit_count'],
})
```

`_tracepoint_hits` is a list (or `collections.deque(maxlen=10000)`) initialized in `__init__`.

### 2. `methods.py` — new methods

```python
@REGISTRY.method(display='Set Tracepoint')
def set_tracepoint(process: C64, address: Address):
"""Set a non-stopping execution tracepoint."""
vice = commands.STATE.require_vice()
vice.checkpoint_set(address.offset, address.offset,
stop_on_hit=False, cpu_op=CPU_OP_EXEC)
with commands.open_tracked_tx('Add tracepoint'):
commands.put_breakpoints()

@REGISTRY.method(display='Dump Tracepoint Log')
def dump_tracepoint_log(process: C64):
"""Print accumulated tracepoint hits to the Ghidra console."""
hits = commands.STATE.require_vice()._tracepoint_hits
for h in hits:
log.info(f" TP#{h['number']} addr=0x{h['address']:04X} hits={h['hit_count']}")
log.info(f"Total: {len(hits)} events")

@REGISTRY.method(display='Clear Tracepoint Log')
def clear_tracepoint_log(process: C64):
commands.STATE.require_vice()._tracepoint_hits.clear()
```

### 3. Schema / breakpoint display

Tracepoints and breakpoints both use VICE checkpoints. The existing `put_breakpoints()` (`commands.py:328`) and `ViceBreakpoint` schema already capture `stop_on_hit` implicitly via the `_kinds` display string. Consider adding a `_display` suffix `"[TRACE]"` vs `"[BREAK]"` to distinguish them in the Ghidra breakpoint panel.

---

## Files to change

- `src/main/py/src/vice/util.py` — `__init__`: add `_tracepoint_hits`; `connect()`: register `RESP_CHECKPOINT_INFO` event; add `_on_checkpoint_hit()`
- `src/main/py/src/vice/methods.py` — add `set_tracepoint`, `dump_tracepoint_log`, `clear_tracepoint_log`
- `src/main/py/src/vice/commands.py` — optionally update `put_breakpoints()` display to distinguish trace vs break

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.