summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude <[email protected]>2026-06-05 07:27:50 +0000
committerClaude <[email protected]>2026-06-05 07:27:50 +0000
commitde756315ec43bdca54599a7d0ba772fa7fbf7cf6 (patch)
treeee1488d54cf8cf721bc5efc545715f8c2b60c3bf
parentddc065dc9fd929fcc94b0993c3af4b56877b1cd6 (diff)
Add pvs skill to run PVS-Studio analysis for a board
Bundle a run_pvs.sh helper (takes BOARD as its first argument) that follows the PVS-Studio static-analysis flow from AGENTS.md: build all examples with an exported compile_commands.json, run pvs-studio-analyzer against .PVS-Studio/.pvsconfig, then emit errorfile + SARIF reports. https://claude.ai/code/session_015inWmFhRYSq17CxMukdoqX
-rw-r--r--.claude/skills/pvs/SKILL.md74
-rwxr-xr-x.claude/skills/pvs/run_pvs.sh82
2 files changed, 156 insertions, 0 deletions
diff --git a/.claude/skills/pvs/SKILL.md b/.claude/skills/pvs/SKILL.md
new file mode 100644
index 000000000..cde453d9a
--- /dev/null
+++ b/.claude/skills/pvs/SKILL.md
@@ -0,0 +1,74 @@
+---
+name: pvs
+description: Use when running PVS-Studio static analysis (SAST + MISRA C:2023 / C++:2008) on TinyUSB for a given board. Wraps building the examples with an exported compile_commands.json and running pvs-studio-analyzer against .PVS-Studio/.pvsconfig, then converts the log to readable + SARIF output.
+---
+
+# PVS-Studio Static Analysis
+
+Run PVS-Studio on TinyUSB for one board. The skill bundles `run_pvs.sh`, which
+follows the "Static Analysis (PVS-Studio)" section of AGENTS.md / CLAUDE.md:
+build all examples for the board with `compile_commands.json` exported, run
+`pvs-studio-analyzer` against it using `.PVS-Studio/.pvsconfig`, then convert the
+log to an `errorfile` view and a SARIF report.
+
+## Quick start
+
+```bash
+# Whole project for a board:
+.claude/skills/pvs/run_pvs.sh raspberry_pi_pico
+
+# Specific files only — -S takes a plaintext list (one path per line), NOT a
+# source file directly (the AGENTS.md "-S src/foo.c" snippet is inaccurate):
+printf 'src/tusb.c\nsrc/class/cdc/cdc_device.c\n' > /tmp/files.txt
+.claude/skills/pvs/run_pvs.sh stm32f407disco -S /tmp/files.txt
+```
+
+The first positional argument is **BOARD** (required). Everything after it is
+forwarded verbatim to `pvs-studio-analyzer analyze`.
+
+## What the script does
+
+1. **License** — if no license file is registered, materializes one from the
+ `PVS_STUDIO_CREDENTIALS` env var (`<name> <key>`, same secret CI uses).
+2. **Build** — `cmake examples -B examples/cmake-build-<board> -G Ninja
+ -DBOARD=<board> -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_EXPORT_COMPILE_COMMANDS=ON`
+ then `cmake --build`. The exported `compile_commands.json` is what PVS reads.
+3. **Analyze** — `pvs-studio-analyzer analyze -f <compile_db>
+ -R .PVS-Studio/.pvsconfig -o pvs-<board>.log -j<nproc>
+ --misra-c-version 2023 --misra-cpp-version 2008 --use-old-parser`.
+ (AGENTS.md shows `--dump-files`; it's omitted because it scatters
+ `.PVS-Studio.i/.cfg` dumps across the tree — only useful for debugging FPs.)
+4. **Report** — `plog-converter -a GA:1,2 -t errorfile` (printed) and
+ `-t sarif` → `pvs-<board>.sarif`.
+
+`.PVS-Studio/.pvsconfig` already excludes vendored code (`lib/`, `hw/mcu/`,
+`pico-sdk/`, `esp-idf/`, IAR runtime) and suppresses the project's accepted
+MISRA deviations — don't duplicate those excludes on the command line.
+
+## Choosing a board
+
+Match the build prerequisites (same as the rest of the repo):
+
+- `raspberry_pi_pico` — what CI's PVS-Studio job uses (needs Pico SDK deps).
+- `stm32f407disco` — no external SDK; fastest to get a clean compile DB.
+- Anything under `hw/bsp/<family>/boards/` works if its deps are fetched
+ (`python3 tools/get_deps.py -b <board>`).
+
+## Outputs
+
+- `pvs-<board>.log` — raw analyzer log (input to plog-converter).
+- `pvs-<board>.sarif` — SARIF report (same format CI uploads).
+- errorfile findings are printed to stdout for a quick read.
+
+## Timing
+
+Dominated by the example build (tens of seconds to a few minutes depending on
+board/deps). The analysis pass itself is ~10-30 s. Use a timeout ≥ 10 minutes
+for boards whose deps must be fetched/built first.
+
+## Reporting results
+
+After a run, summarize the findings by rule/severity from the errorfile output
+and point the user at `pvs-<board>.sarif`. Cross-check anything flagged in
+`src/` against `.pvsconfig` — if it's an already-accepted deviation it will have
+been suppressed, so surviving findings are genuinely new.
diff --git a/.claude/skills/pvs/run_pvs.sh b/.claude/skills/pvs/run_pvs.sh
new file mode 100755
index 000000000..3a829327d
--- /dev/null
+++ b/.claude/skills/pvs/run_pvs.sh
@@ -0,0 +1,82 @@
+#!/usr/bin/env bash
+# Run PVS-Studio static analysis on TinyUSB for a given BOARD.
+#
+# Mirrors the "Static Analysis (PVS-Studio)" section in AGENTS.md / CLAUDE.md:
+# - build all examples for BOARD with compile_commands.json exported
+# - run pvs-studio-analyzer against that compile DB using .PVS-Studio/.pvsconfig
+# - convert the log to human-readable (errorfile) and SARIF output
+#
+# Usage:
+# .claude/skills/pvs/run_pvs.sh <BOARD> [extra pvs-studio-analyzer args...]
+#
+# Examples:
+# .claude/skills/pvs/run_pvs.sh raspberry_pi_pico
+# # Scope to specific files via a plaintext list (one path per line):
+# printf 'src/tusb.c\nsrc/class/cdc/cdc_device.c\n' > /tmp/files.txt
+# .claude/skills/pvs/run_pvs.sh stm32f407disco -S /tmp/files.txt
+set -euo pipefail
+
+BOARD="${1:-}"
+if [ -z "$BOARD" ]; then
+ echo "Usage: $0 <BOARD> [extra pvs-studio-analyzer args...]" >&2
+ echo "Example: $0 raspberry_pi_pico" >&2
+ exit 2
+fi
+shift
+
+REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
+cd "$REPO_ROOT"
+
+BUILD_DIR="examples/cmake-build-${BOARD}"
+COMPILE_DB="${BUILD_DIR}/compile_commands.json"
+REPORT_LOG="pvs-${BOARD}.log"
+SARIF_OUT="pvs-${BOARD}.sarif"
+JOBS="$(nproc 2>/dev/null || echo 4)"
+
+# --- License ---------------------------------------------------------------
+# Use an existing license file, else materialize one from PVS_STUDIO_CREDENTIALS
+# (format: "<name> <key>", as supplied by the CI secret of the same name).
+if ! pvs-studio-analyzer lic-info >/dev/null 2>&1; then
+ if [ -n "${PVS_STUDIO_CREDENTIALS:-}" ]; then
+ echo ">>> Registering PVS-Studio license from PVS_STUDIO_CREDENTIALS"
+ # shellcheck disable=SC2086 # credentials expects two whitespace-separated args
+ pvs-studio-analyzer credentials $PVS_STUDIO_CREDENTIALS
+ else
+ echo "ERROR: no PVS-Studio license found and PVS_STUDIO_CREDENTIALS is unset." >&2
+ exit 1
+ fi
+fi
+
+# --- Build (exports compile_commands.json) ---------------------------------
+echo ">>> Building all examples for ${BOARD} (this also fetches the compile DB)"
+cmake examples -B "${BUILD_DIR}" -G Ninja \
+ -DBOARD="${BOARD}" \
+ -DCMAKE_BUILD_TYPE=MinSizeRel \
+ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
+cmake --build "${BUILD_DIR}"
+
+if [ ! -f "${COMPILE_DB}" ]; then
+ echo "ERROR: ${COMPILE_DB} was not produced by the build." >&2
+ exit 1
+fi
+
+# --- Analyze ---------------------------------------------------------------
+echo ">>> Running PVS-Studio analyzer (-j${JOBS})"
+# Note: AGENTS.md shows --dump-files, but that scatters .PVS-Studio.i/.cfg dump
+# files across the source tree (only useful for debugging false positives). It is
+# omitted here to keep the working tree clean; add it back via "$@" if needed.
+pvs-studio-analyzer analyze \
+ -f "${COMPILE_DB}" \
+ -R .PVS-Studio/.pvsconfig \
+ -o "${REPORT_LOG}" -j"${JOBS}" \
+ --misra-c-version 2023 --misra-cpp-version 2008 --use-old-parser \
+ "$@"
+
+# --- Report ----------------------------------------------------------------
+echo ">>> General-analysis + MISRA findings (errorfile):"
+plog-converter -a GA:1,2 -t errorfile "${REPORT_LOG}" || true
+plog-converter -t sarif -o "${SARIF_OUT}" "${REPORT_LOG}" >/dev/null
+
+echo ">>> Done."
+echo " Raw log : ${REPORT_LOG}"
+echo " SARIF : ${SARIF_OUT}"