Skip to content

Commit 7f3cc1e

Browse files
authored
feat: recursos do debugger (call stack, data breakpoints, erros de runtime, inspeção de arrays/strings) (#17)
* ci: migrate CodeQL to advanced setup and add CODEOWNERS (#16) The CodeQL default setup only analysed a pull request when it touched files relevant to the configured languages, so a docs-only PR produced no analysis while master still carried one per language, leaving the code_scanning branch rule unable to diff the two sides. Also add the CODEOWNERS file this repository was missing, so the branch ruleset can require code owner review like the sibling repositories do. * chore: re-pin rust-samp SDK to 51ba519 (v3.4.0) Traz o lookup_function do bloco de debug (base para a pilha de chamadas), Amx::exec_public_scope e o hardening de buffer/stack no FFI. Eventos do SDK (#[event]) são x86-only e viram no-op no check aarch64. * feat(debugger): call stack multi-frame Caminha a cadeia de frames do AMX (FRM anterior + endereço de retorno, parando no público de entrada) e expõe N frames ao editor. Cada frame traz nome da função (lookup_function), linha e variáveis em escopo — reaproveitando inspect::collect por frame. - protocolo: Event::Paused passa a carregar frames: Vec<Frame>; Command:: SetVariable ganha o índice do frame. - plugin: novo módulo stack (walker puro e testável) + build_frames no on_pause; PAUSE_CTX guarda o contexto de todos os frames para editar no frame certo. - adaptador: stackTrace com N frames + source; scopes/variables/evaluate/ setVariable operam por frame (frameId/variablesReference). Cobertura: 6 testes do walker + 2 do plumbing do adaptador. aarch64 ok. * feat(debugger): data breakpoints (pausar quando variável muda) Observa variáveis (globais e locais) e pausa na primeira linha após o valor mudar. Reusa o hook por linha; watches de locais expiram quando o frame dono retorna (via stack::walk), evitando observar slot de pilha reusado. - protocolo: Command::SetDataBreakpoints { watches: Vec<DataWatch{frame,name}> }. - plugin: control::DataWatch + check_data_watches (puro, com expiração por frame vivo); hook resolve frame+nome → endereço/classe/valor inicial e checa a cada linha, pausando com reason "data breakpoint". - adaptador: capability supportsDataBreakpoints; dataBreakpointInfo (dataId "frame:name") e setDataBreakpoints encaminhando ao plugin. Cobertura: 5 testes do controlador (mudança/expiração/global) + 3 do adaptador (parse_data_id, encaminhamento, capability). aarch64 ok. * chore: re-pin rust-samp SDK to 6c8b528 (Amx::hlw accessor) Traz o accessor hlw() (fundo do heap) necessário para detectar heap underflow. Aponta para a branch do PR NullSablex/rust-samp#54; re-pinar no master estável quando o PR mergear, antes de fechar este. * feat(debugger): detect STACKERR, HEAPLOW e MEMACCESS Estende o simulador de linha (runtime_error) para rastrear stk/hea/hlw/stp e detectar, antes do abort da VM e com as MESMAS condições do amx.c: - STACKERR: colisão pilha/heap (CHKMARGIN, hea+STKMARGIN>stk), inclusive antecipando o PROC do chamado num call (recursão infinita). - HEAPLOW: underflow de heap (CHKHEAP, hea<hlw). - MEMACCESS: endereço na lacuna [hea,stk) ou >=stp (VERIFYADDRESS). Conservador por construção: as checagens só rodam enquanto stk/hea (e o registrador de endereço) são rastreados exatamente; qualquer desvio/opcode não modelado (call, jump, sysreq, sctrl, aritmética) as desliga — nunca um falso-positivo. Números de opcode e condições conferidos no amx.c do omp-compiler. Mensagens localizadas nos 5 idiomas. Cobertura: +6 testes (colisão em stack/call, heaplow, memaccess na lacuna, endereço desconhecido não acusa, barreira pós-call). aarch64 ok. * chore: re-pin rust-samp SDK to stable master (336f8de, #54 merged) O PR NullSablex/rust-samp#54 (Amx::hlw) foi mergeado; sai da branch do PR e aponta para o master estável do fork. * docs: marcar call stack, data breakpoints e erros de runtime como concluídos Alinha docs/features.md e docs/runtime-errors.md ao que o PR entrega (estavam como 'planejado'/'em avaliação'). Adiciona STACKERR/HEAPLOW/MEMACCESS à tabela de erros com as condições fiéis ao amx.c. * feat(debugger): inspeção rica de arrays e strings Arrays viram expansíveis na árvore de variáveis (elementos como filhos com variablesReference próprio) e arrays de char são mostrados como string; editar um elemento (arr[i]) passa a ser suportado. - protocolo: Var ganha children (elementos); Command::SetVariable ganha index opcional (elemento do array). - plugin: inspect::build_array lê os elementos (até 256) e detecta string (imprimível até terminador 0, Latin-1); hook::set_variable escreve arr[index]. - adaptador: variablesReference codifica (frame, var) para expandir arrays e editar elementos; dataBreakpointInfo passa a recusar arrays por terem filhos. Cobertura: as_string (detecção/conservadorismo), encode/decode de ref de array, parse de índice. 77 testes; clippy pedantic, fmt, aarch64 ok. * feat(dap-adapter): watch/hover com expressões evaluate passa a avaliar expressões, não só o nome exato: literais, variáveis, elementos de array (arr[i], índice pode ser subexpressão) e A OP B com + - * / % (aritmética inteira estilo Pawn, ou float) e == != < > <= >= (comparação). Um operador por expressão, conservador — o que não avalia vira falha (o editor mostra 'não disponível'). Novo módulo expr no adaptador, puro e testável (11 testes). * feat(debugger): filtro de exceção (ligar/desligar erros de runtime) O editor passa a controlar a pausa em erros de runtime via exceptionBreakpoint Filters/setExceptionBreakpoints. Desligado, a VM aborta normalmente sem pausar. - protocolo: Command::SetExceptionFilter { runtime }. - plugin: flag atômica RUNTIME_ERRORS (ligada por padrão) que porteia o detect_runtime_error no on_break. - adaptador: capability exceptionBreakpointFilters + handler setExceptionBreakpoints. Cobertura: encaminhamento liga/desliga + capability. 85 testes. * chore: re-pin rust-samp SDK to 3d15a19 (AmxDbg::function_address) Traz function_address (nome->endereço de entrada) para os breakpoints de função. Aponta para a branch do PR NullSablex/rust-samp#55; re-pinar no master quando mergear, antes de fechar este. * feat(dap-adapter): breakpoints de função setFunctionBreakpoints resolve cada nome no endereço de entrada da função (AmxDbg::function_address) e o une aos breakpoints de linha no conjunto único do plugin. Capability supportsFunctionBreakpoints. Útil para callbacks (OnPlayerConnect etc.) sem procurar a linha. Cobertura: resolução + união linha/função + capability. 87 testes. * chore: re-pin rust-samp to 900ebd0 (rustfmt do #55) * feat(dap-adapter): localizar mensagens do adaptador (5 idiomas) As mensagens voltadas ao editor (valor/elemento inválido, editar array, expressão vazia/não avaliável, rótulo do filtro de exceção) passam a seguir o idioma — antes eram só pt-BR, enquanto os erros de runtime já eram localizados. O locale vem do argumento 'locale' do initialize (o cliente informa). Novo módulo l10n (Locale + Msg) espelhando pt-BR/en/es/ru/ro. 89 testes. * feat(dap-adapter): autocomplete no watch/console (completions) Responde ao completions do DAP sugerindo as variáveis em escopo cujo nome começa com o identificador antes do cursor. Capability supportsCompletionsRequest. Cobertura: word_prefix (extração do prefixo). 90 testes. * refactor(i18n): centralizar traduções em protocol/messages (5 idiomas) Unifica a localização num só lugar (crates/protocol/src/messages), com Locale, MsgKey (11 chaves) e um módulo por idioma em langs/<code>.rs (get -> &str, templates com {}). Plugin e adaptador passam a usar essa fonte única: - plugin: runtime_error re-exporta o Locale e delega message() a messages::msg. - adaptador: remove l10n.rs; usa messages::format/msg (from_tag no initialize). O match por MsgKey em cada idioma é exaustivo — falta chave = não compila. Cobertura documentada em docs/i18n.md (en, pt-BR, es, ru, ro: 11/11). 90 testes. * docs(i18n): roadmap de 50 idiomas + entrada no nav Espelha a meta de cobertura: 5 implementados (✅) e 45 no roadmap (⬜). Adiciona a página de localização ao nav do mkdocs. * feat(debugger): data breakpoint em elemento de array Arrays deixam de ser inobserváveis: dá para observar arr[i]. dataBreakpointInfo oferece o elemento (dataId frame:name:index) quando o variablesReference é de um array; o plugin resolve o endereço do elemento (base + index*4) e observa. - protocolo: DataWatch ganha index opcional. - adaptador: dataBreakpointInfo/parse_data_id tratam o índice. - plugin: resolve_data_watches lê o elemento e nomeia o watch 'arr[i]'. 90 testes; clippy pedantic, fmt, aarch64 ok. * feat(dap-adapter): setExpression (editar lvalue no watch/console) Edita um lvalue (name ou arr[i], índice podendo ser subexpressão) digitado no watch/console, encaminhando como SetVariable ao plugin. Capability supportsSetExpression. Cobertura: parse_lvalue + encaminhamento de elemento. 92 testes; aarch64 ok. * feat(debugger): readMemory (ver memória de dados crua) Adiciona um canal request/response ao protocolo (Command::ReadMemory ↔ Event::MemoryData, correlacionados por id) — o primeiro caminho em que o plugin responde a uma consulta. Variáveis expõem memoryReference (frame:name[:index]); o plugin resolve o endereço e lê count bytes; o adaptador responde em base64. - protocolo: ReadMemory/MemoryData. - plugin: hook::read_memory (resolve endereço, lê cells, responde via evento). - adaptador: plugin_client.read_memory (envia e espera com timeout, via canal); variables com memoryReference; on_read_memory + Outgoing::ReadMemory resolvido no main (base64_encode próprio, sem dependência). Capability supportsReadMemoryRequest. Cobertura: base64 (RFC), parse do memoryReference. 94 testes; aarch64 ok. * refactor: enxugar comentários redundantes nas capabilities O bloco de capabilities do initialize tinha um comentário por flag, traduzindo o nome dela. Mantidos só os que carregam informação não-óbvia (filtro de exceção e o motivo de não declarar supportsRestartRequest). Traduz também o único comentário em inglês do plugin, no hook. * docs: atualizar README e documentação para os recursos atuais README com badges (CI, CodeQL, docs, release, licença), navegação para a documentação e tabela de recursos alinhada ao que a branch entrega. docs/features.md ganha as seções de breakpoints de função, expressões do watch/console, data breakpoints e leitura de memória; architecture.md descreve o canal request/response (ReadMemory/MemoryData); index.md e getting-started.md atualizados; CHANGELOG com a seção Não lançado. * refactor: traduzir e enxugar os comentários do plugin hook.rs estava inteiramente comentado em inglês, destoando do resto do repo; plugin_client.rs, inspect.rs e langs/en.rs tinham pontos isolados. Todos traduzidos. Na passagem, corta o que repetia a assinatura ou já estava dito noutro lugar: as notas '&mut self porque...' no control.rs, a lista de parâmetros no doc de scan_line e a terceira repetição do argumento conservador. Corrige também o doc de resolve_data_watches, que ainda dizia que arrays não são observáveis — elementos de array passaram a ser em ed5a737. * docs: completar os opcodes de STACKERR e MEMACCESS A tabela omitia OP_CALL_PRI no STACKERR e OP_LODB_I/OP_STRB_I/OP_LIDX_B no MEMACCESS, todos checados em runtime_error.rs. * docs: badges de downloads, stars e OpenSSF Scorecard no README Adiciona também .github/workflows/scorecard.yml: sem ele o badge do Scorecard não tem o que exibir, porque a API pública do OpenSSF só conhece repositórios que publicam resultados (publish_results, em push no branch padrão). O workflow segue o padrão dos outros: actions pinadas por SHA, permissões mínimas por job e execução semanal além do push no master. O SARIF também vai para o code scanning. * docs(i18n): site em pt-BR e en-US com mkdocs-static-i18n Adiciona o plugin mkdocs-static-i18n (docs_structure: suffix), com pt-BR como idioma padrão na raiz e en-US em /en-US/. As seis páginas foram traduzidas, e o nav tem nav_translations; fallback_to_default cobre páginas futuras que ainda não tenham versão traduzida. O tema do locale en-US aponta para 'en': o Material só traz tabela de interface para 'en', e 'en-US' quebra o build (TemplateNotFound em partials/languages/en-US.html). requirements.in/txt recompilados com hashes. Validado como no CI: venv limpo, pip install --require-hashes e mkdocs build --strict. * docs: registrar docs, i18n do site e Scorecard no changelog A seção Não lançado parou nos recursos; faltavam o README com badges, o site bilíngue, a padronização dos comentários, as duas correções de documentação e o workflow do OpenSSF Scorecard. * chore(release): 0.2.0 Fecha o ciclo desde a v0.1.0: call stack multi-frame, data breakpoints, breakpoints de função, três novos erros de runtime, inspeção de arrays/strings, setExpression, readMemory, expressões no watch, autocomplete e a documentação em inglês. Sobe a versão do workspace e o marcador embutido no plugin (a extensão casa apenas o prefixo PAWNPRO_DEBUG_MARKER, então a versão dentro dele é livre; o tamanho segue 26 bytes). O changelog passa a cobrir todas as mudanças desde o último release, incluindo os re-pins do SDK e a infraestrutura do repositório. * docs: mover a data do release 0.2.0 para 01/09/2026 * refactor: usar as primitivas de VM do SDK (rust-samp-sdk 3.4.0) A numeração de opcodes, o tamanho das instruções, o OpcodeMap, a caminhada da pilha e a leitura de faixa de memória eram fatos genéricos da VM AMX que viviam no plugin. Passaram para o SDK e voltam como API: - samp::debug::opcode substitui as 44 constantes locais, a tabela OP_PARAMS e STK_MARGIN; operand_cells troca o índice cru por uma consulta checada. - samp::debug::stack substitui crates/debug-plugin/src/stack.rs, removido com seus 6 testes (reescritos no SDK). - Amx::read_bytes substitui o alinhamento e o fatiamento manuais do readMemory. - Amx::data_only substitui Amx::new(ptr, 0) nos três pontos da pausa. - Amx::opcode_map substitui OpcodeMap::new(amx.opcode_table(OP_NUM_OPCODES)). O plugin perde ~250 linhas sem mudança de comportamento: 88 testes (os 6 que saíram vivem agora no SDK), clippy pedantic e fmt verdes. * chore(deps): consumir rust-samp 3.4.0 do crates.io A dependência git + rev existia porque o debugger precisava de API do SDK que ainda não estava publicada. Com o lançamento da 3.4.0 (rust-samp e rust-samp-sdk), passa a ser dependência de versão: acaba o re-pin por SHA a cada mudança no SDK e o build deixa de resolver nada pelo GitHub — não há mais nenhuma dependência git no Cargo.lock. * docs(changelog): completar a 0.2.0 com tudo desde a v0.1.0 Faltavam a fileira de badges do README, o marcador do plugin subindo para 0.2.0, a correção da tabela de opcodes em runtime-errors.md e as atualizações de dependência do Dependabot nos três ecossistemas. Conferido item a item contra os 50 commits desde a tag.
1 parent a8bb944 commit 7f3cc1e

40 files changed

Lines changed: 3694 additions & 532 deletions

.github/workflows/scorecard.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# OpenSSF Scorecard.
2+
#
3+
# Scores the repository's supply-chain practices (branch protection, pinned
4+
# actions, token permissions, dependency update tooling, …) and uploads the
5+
# result twice: as SARIF to code scanning, and — via `publish_results` — to the
6+
# public OpenSSF API, which is what backs the Scorecard badge in the README.
7+
#
8+
# `publish_results` only works on a push to the default branch of a public
9+
# repository; on a pull request the workflow still runs and reports to code
10+
# scanning, without publishing.
11+
name: Scorecard
12+
13+
on:
14+
push:
15+
branches: [ "master" ]
16+
# Weekly, so the score keeps up with the checks Scorecard adds over time.
17+
schedule:
18+
- cron: '31 4 * * 1'
19+
workflow_dispatch:
20+
21+
permissions: read-all
22+
23+
jobs:
24+
analysis:
25+
name: Scorecard analysis
26+
runs-on: ubuntu-latest
27+
permissions:
28+
security-events: write # upload the SARIF results
29+
id-token: write # OIDC token, required to publish the results
30+
contents: read
31+
actions: read
32+
33+
steps:
34+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
35+
with:
36+
persist-credentials: false
37+
38+
- name: Run analysis
39+
uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
40+
with:
41+
results_file: results.sarif
42+
results_format: sarif
43+
publish_results: true
44+
45+
# Kept for 5 days so a failed upload can still be inspected.
46+
- name: Upload artifact
47+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
48+
with:
49+
name: SARIF file
50+
path: results.sarif
51+
retention-days: 5
52+
53+
- name: Upload to code scanning
54+
uses: github/codeql-action/upload-sarif@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
55+
with:
56+
sarif_file: results.sarif

CHANGELOG.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,46 @@ Podem existir falhas ou itens não declarados, causados por falha humana ou por
88

99
---
1010

11+
## [0.2.0] - 01/09/2026
12+
13+
Segundo pré-lançamento. Amplia o conjunto DAP suportado: a depuração deixa de ser
14+
"breakpoint e inspeção" e passa a cobrir call stack, data breakpoints, edição por
15+
expressão, leitura de memória e mais três classes de erro de runtime.
16+
17+
### Adicionado
18+
- **Call stack multi-frame** — caminha a cadeia de frames do AMX (FRM → endereço de retorno) e entrega nome da função, linha e variáveis de cada frame. O editor navega entre os frames e a inspeção segue o frame selecionado.
19+
- **Data breakpoints** — pausar quando um valor muda, em globais, locais e **elementos de array** (`arr[3]`). Watches de locais expiram quando o frame dono retorna, para não dispararem com o conteúdo de outro frame no mesmo slot.
20+
- **Breakpoints de função** — parar ao entrar numa função pelo nome; um nome que não resolve volta ao editor como não verificado, sem quebrar a sessão.
21+
- **Três novos erros de runtime**`STACKERR` (colisão pilha/heap), `HEAPLOW` (underflow de heap) e `MEMACCESS` (acesso inválido à memória), somando-se à divisão por zero e ao índice fora do limite. A simulação é fiel ao `amx.c` e conservadora: o rastreio dos registradores perde a confiança ao primeiro opcode não modelado, então não há falso-positivo.
22+
- **Filtro de exceção** — o editor liga e desliga a pausa em erros de runtime pelo painel de breakpoints.
23+
- **Inspeção de arrays e strings** — arrays são expansíveis (cada elemento vira um filho) e arrays de char são mostrados como **string** quando o conteúdo é texto terminado em zero.
24+
- **Edição por expressão** (`setExpression`) — `x = 1` ou `arr[i] = 10` direto no watch ou no console, com o índice podendo ser uma subexpressão. O array inteiro não é editável, só os elementos.
25+
- **Leitura de memória** (`readMemory`) — hex view da memória de dados crua a partir de qualquer variável, que agora expõe um `memoryReference`.
26+
- **Expressões no watch e no hover** — um operador de topo com `+ - * / %` (seguindo o truncamento do Pawn) e `== != < > <= >=`, sobre literais, variáveis e `arr[i]`.
27+
- **Autocomplete** — sugestão de variáveis em escopo no watch e no console.
28+
- **Documentação em inglês** — o site passa a ter **pt-BR** na raiz e **en-US** em `/en-US/`, com todas as páginas traduzidas e o menu localizado.
29+
30+
### Alterado
31+
- **Mensagens do adaptador agora são localizadas** — antes só os erros de runtime seguiam o idioma do editor. As mensagens dos dois lados foram unificadas em `crates/protocol/src/messages`, com 11 chaves em pt-BR, en, es, ro e ru; a tabela de cada idioma é exaustiva, então um idioma incompleto não compila.
32+
- **O protocolo ganhou um canal request/response**`ReadMemory``MemoryData`, correlacionados por `id` e com timeout, para a sessão não ficar presa se o plugin não responder. O restante do protocolo continua assíncrono nos dois sentidos.
33+
- **README e documentação reescritos** — recursos, arquitetura e a página de localização atualizados para o que esta versão entrega. O README ganhou a fileira de badges (CI, CodeQL, docs, OpenSSF Scorecard, release, downloads, estrelas e licença) e uma linha de navegação para a documentação, os releases e a extensão.
34+
- **Marcador do plugin atualizado para `PAWNPRO_DEBUG_MARKER:0.2.0`** — a extensão casa apenas o prefixo `PAWNPRO_DEBUG_MARKER`, então o reconhecimento do plugin oficial não muda; o tamanho segue 26 bytes.
35+
36+
### Corrigido
37+
- Tabela de erros em [Como funciona a pausa no erro](docs/runtime-errors.md): faltavam `OP_CALL_PRI` no STACKERR e `OP_LODB_I`/`OP_STRB_I`/`OP_LIDX_B` no MEMACCESS, todos já checados pelo plugin.
38+
39+
### Dependências
40+
- **SDK `rust-samp` agora vem do crates.io** (`3.4.0`), no lugar da dependência `git` + `rev` que o projeto carregava desde o início — ela existia porque o debugger precisava de API ainda não publicada. O build deixa de depender do GitHub para resolver dependências.
41+
- Ao longo do ciclo o SDK acompanhou o que cada versão liberou: `v3.3.1` (correção), `v3.4.0`, o acessor `Amx::hlw` (exigido pelo HEAPLOW) e `AmxDbg::function_address` (exigido pelos breakpoints de função).
42+
- Atualizações do **Dependabot** nos três ecossistemas, agrupadas por ecossistema a partir de #13: `cargo` (`serde` 1.0.228 → 1.0.229 e o grupo cargo com 2 atualizações), `github-actions` (`checkout`, `upload-artifact`, `download-artifact`, `setup-python`, `rust-cache`, `action-gh-release`) e `pip` (`mkdocs-material`, `pymdown-extensions`). Nenhuma altera comportamento do debugger.
43+
- **Lógica genérica de VM devolvida ao SDK** (`rust-samp-sdk` 3.4.0) — a numeração dos opcodes, o tamanho das instruções, o decodificador da relocação por computed-goto (`OpcodeMap`), a caminhada da cadeia de frames e a leitura de faixas de memória eram fatos da VM AMX que viviam aqui. Agora vêm de `samp::debug::opcode`, `samp::debug::stack` e `Amx::read_bytes`/`call_stack`/`data_only`, e o plugin ficou ~250 linhas menor sem perder comportamento.
44+
- Atualizações de `serde` (1.0.229), `serde_json` (1.0.151), das GitHub Actions e das dependências da documentação.
45+
46+
### Infraestrutura
47+
- **CodeQL** migrado para advanced setup, garantindo as duas análises (`actions`, `rust`) em todo pull request, com `CODEOWNERS`.
48+
- **OpenSSF Scorecard** — análise semanal e em push no `master`, publicando o resultado na API pública do OpenSSF e o SARIF no code scanning.
49+
- **Dependabot** para `github-actions`, `cargo` e `pip`, agrupado em um PR por ecossistema.
50+
1151
## [0.1.0] - 04/07/2026
1252

1353
Primeiro pré-lançamento (pre-release).

0 commit comments

Comments
 (0)