Skip to content

feat(debug): opcode decoding, call-stack walking and range reads - #56

Merged
NullSablex merged 5 commits into
masterfrom
feat/debug-tooling
Sep 1, 2026
Merged

feat(debug): opcode decoding, call-stack walking and range reads#56
NullSablex merged 5 commits into
masterfrom
feat/debug-tooling

Conversation

@NullSablex

@NullSablex NullSablex commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Moves into the SDK the AMX facts a debugger had to reimplement on top of it. Every piece here was extracted from the PawnPro Debugger, where it already ran against live SA-MP and open.mp servers (compilers 3.10.10 and 3.10.11).

AmxDbg::function_address (#55, now merged) had no CHANGELOG entry, and neither did Amx::hlw (#54) — both are recorded in this release section, along with the CI and dependency work since the v3.4.0 tag.

Added

  • samp::debug::opcode — opcode numbering (the order of the opcode enum in amx.c, identical on SA-MP and open.mp), OP_NUM_OPCODES, the VM's STK_MARGIN, and operand_cells(op) for instruction sizes. Returns None on a variable-length instruction (casetbl) or an out-of-range opcode — the signal for a scanner to stop rather than guess.
  • OpcodeMap and Amx::opcode_map() — inverts the VM dispatch table (label address → opcode) to undo the computed-goto rewrite the loader applies on GCC/Clang builds. is_identity() reports a non-relocated image. This replaces the hand-rolled HashMap that docs/vm-debugging.md used to show consumers writing themselves.
  • samp::debug::stack::walk and Amx::call_stack(top_cip) — walks the frame chain ([frm] = caller's FRM, [frm + CELL] = return address) into (cip, frm) per frame, top first. The cell reader is injected, so it is unit-testable against a fake memory map and usable host-side; MAX_DEPTH keeps a corrupted stack from spinning a debug hook.
  • Amx::read_cells / Amx::read_bytes — range reads with the same amx_GetAddr bounds checking as read_cell. They stop early at the first inaccessible address and return what they read (the natural case at the end of the data segment), returning None only when the start itself is inaccessible; read_bytes needs no alignment. The get_ref-based Buffer/AmxString path needs a function table and cannot serve a debug hook, which is why only single cells were reachable there before.
  • Amx::data_only(ptr) — wraps a raw *mut AMX for data-side access only, stating the intent instead of passing a bare 0 as the function table (the usual situation while a VM is paused).

Changelog completeness

The v3.5.0 section covers all 20 commits since the v3.4.0 tag, not just this branch:

Validation

  • 284 tests + 14 doctests on i686-unknown-linux-gnu; cargo clippy --all-targets -D warnings clean; cargo fmt clean.
  • Checked that the new code adds no clippy::pedantic warnings — the project's existing pedantic baseline is untouched.

Docs

  • VM Debugging rewritten around the new API, with new sections on opcode numbers/instruction sizes and on walking the call stack.
  • API reference updated; README's debug feature description widened and its badge row extended (crates.io version and downloads, docs.rs, MSRV, stars).

Crate versions

Per the project's independent-versioning policy:

  • rust-samp (lib samp): 3.3.0 → 3.4.0 — re-exports the widened surface; requires rust-samp-sdk 3.4.0.
  • rust-samp-sdk (lib samp_sdk): 3.3.0 → 3.4.0 — additive public API.
  • rust-samp-codegen: 1.4.0, unchanged.

Downstream

The debugger already consumes this branch and dropped ~250 lines: its local stack.rs, the 44 OP_* constants, the OP_PARAMS table, its own OpcodeMap, and the manual alignment in its memory reads.

Contraparte de lookup_function: resolve o nome de uma função no endereço da
primeira linha quebrável do corpo (ou codestart), para o PawnPro-Debugger
implementar breakpoints de função (parar ao entrar numa função por nome).
Adds the AMX facts a debugger had to reimplement on top of the SDK:

- samp::debug::opcode — opcode numbering, STK_MARGIN, OP_NUM_OPCODES and
  operand_cells(op) for instruction sizes (None on variable-length or
  out-of-range: the signal to stop scanning).
- OpcodeMap — inverts the VM dispatch table to undo the computed-goto rewrite,
  with Amx::opcode_map() building one from a VM. Replaces the hand-rolled
  HashMap the docs used to show.
- samp::debug::stack::walk — frame-chain walking with an injected cell reader,
  plus Amx::call_stack(top_cip). MAX_DEPTH guards a corrupted stack.
- Amx::read_cells / read_bytes — range reads with amx_GetAddr bounds checking,
  stopping early at the first inaccessible address; read_bytes is alignment
  free. The get_ref path needs a function table and cannot serve a debug hook.
- Amx::data_only(ptr) — states data-side-only intent instead of a bare 0 as
  the function table.

Extracted from the PawnPro Debugger, where each piece already ran against live
SA-MP and open.mp servers.

Docs and CHANGELOG updated; crate versions bumped per the project policy
(samp-sdk and samp 3.3.0 -> 3.4.0, codegen unchanged).
Adds crates.io version and downloads, docs.rs, MSRV and stars to the badge
row, alongside the CI, license, Scorecard and dependency badges already there.

The debug feature description no longer says 'parser': it now also covers the
opcode helpers and call-stack walking added in this release.
@NullSablex NullSablex added feat New feature docs Documentation labels Sep 1, 2026
The v3.5.0 section only had the three commits of this branch. It now covers all
20 commits since the tag: Amx::hlw (#54), which was public API and had no entry
at all, plus a Changed section for the CI work (CodeQL advanced setup #52, the
ci-status gate #51, grouped Dependabot #44) and the dependency bumps, following
how earlier releases record them.
@NullSablex
NullSablex merged commit df66c77 into master Sep 1, 2026
9 checks passed
@NullSablex
NullSablex deleted the feat/debug-tooling branch September 1, 2026 04:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation feat New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant