diff --git a/.agents/skills/add-trace-board/SKILL.md b/.agents/skills/add-trace-board/SKILL.md index 367ecb3..9ff2341 100644 --- a/.agents/skills/add-trace-board/SKILL.md +++ b/.agents/skills/add-trace-board/SKILL.md @@ -98,8 +98,9 @@ selection. Each set references the same `TraceDemo.Debug` image. Configure SWD and SWO clocks from the verified hardware and probe capabilities; keep solution transport clocks and profile timestamps consistent. Existing profiles are a starting point, not evidence that an unknown board supports those -rates. Obtain the Pack's `.dbgconf` defaults and retain their base files when -CMSIS generates them. +rates. Obtain the Pack's `.dbgconf` defaults and keep the active configuration. +Generated `.base@*` and `.update@*` comparison files are ignored; do not add them +to version control. Create `.cmsis/Trace+@.ctrace.yml` for each named set, following TRACE_APP.md. Use `g_trace_sine` and `g_trace_noise` symbol names, ITM channel 1, diff --git a/.agents/skills/trace-stack-magic-corruption-test/SKILL.md b/.agents/skills/trace-stack-magic-corruption-test/SKILL.md deleted file mode 100644 index d1aaef8..0000000 --- a/.agents/skills/trace-stack-magic-corruption-test/SKILL.md +++ /dev/null @@ -1,192 +0,0 @@ ---- -name: trace-stack-magic-corruption-test -description: Capture the stack-magic write trace for this project's active CMSIS target set, resolve recorded PCs with arm-none-eabi-addr2line, and create a separate Markdown report with source text, project-relative locations and source-based explanations, one section per CSV record. Keep the CSV unchanged and open the completed report in VS Code. Use to automate the existing StackCorruption experiment; it does not add targets or invent a missing trace watch. ---- - -# Trace Stack Magic corruption test - -Run this repository's existing stack-corruption experiment for the **currently -selected target and set**. Deliver the original SWO CSV and a separate Markdown -report with one section per CSV record, including legitimate initialization writes -and records without a PC. Never add columns to or rewrite the CSV. - -The repository root contains `Trace.csolution.yml`. Read the -[stack experiment](../../../docs/TRACE_APP.md#stack-corruption-watch-nucleo-l552ze-q) -and its [validation limits](../../../docs/VALIDATION.md#nucleo-l552ze-q-stackcorruption--2026-10-05) -when preparing a capture. Do not encode the board, probe ID, ELF address or source -line number from a previous run into the workflow. - -## Bind the active target and verify its trace - -Use `cmsis-debug-live` for hardware operations and the CMSIS Developer Assistant -MCP tools for build/load/debug. Select this repository's VS Code window with -`list_debug_windows` / `select_debug_window`; leave other projects' sessions alone. -Apply the user's physical probe-selection rules. Allow up to **10 attempts** -per failing CMSIS operation, correcting the cause between attempts. After ten -failures, call `get_session_status` and `get_recent_problems`, then stop and -explain the required VS Code action; do not substitute shell board access. -Shell helpers below operate on local files only. This workflow intentionally -uses the user-requested `arm-none-eabi-addr2line` for offline PC resolution. - -1. Read `.vscode/cmsis.json` (`activeSolution`, `activeTarget`) and - `Trace.cbuild-idx.yml` (`build-idx.target`, `cbuild-run`). The selected target - includes `@` for a named set. Build **that selection** with - `cmsis_action build`, using `check-cmsis-environment` when a build environment - check is needed. If this project already has a debug session, check its state - and end it before rebuilding/starting a fresh capture. Do not switch to the - example L552 set merely because another selected set has no magic watch. -2. From the indexed `.cbuild-run.yml`, read `solution`, `target-type`, `target-set`, - `output` and `debugger.trace`. Require agreement with the active selection. - Resolve the one symbol-bearing ELF from its `output` entry, relative to the - run file. For multiple images/cores, require an unambiguous association with - the watch before continuing. Require SWO file capture. -3. Form the profile stem from the solution name, target and optional set: - `Trace+[@]`. Read `.cmsis/.ctrace.yml`. It must contain a data - watch for `g_stack_corruption_stack` (or its first element), with a write access, - **four-byte size** and **PC output**. Check this against the workload's actual - RTX stack storage, not a similarly named spare canary. If missing or incompatible, - report the exact active set and deficiency; do not enable a different demo. -4. Regenerate with the installed CMSIS Debugger's pyTS against the indexed run - file. Check its missing-symbol list and `.trace/.ctrace-run.yml`: the - magic watch resolves to the first stack word, has size four and PC output, and - its `symbol-file` is the selected ELF. Resolve the corresponding DWT index for - later CSV checks. Retain protocol synchronization; this experiment needs - `sync-on-run` to decode its short capture. Other demo sources should remain - disabled in the StackCorruption profile. Do not change Pack/pyOCD sources. -5. Find `arm-none-eabi-addr2line` beside the selected GCC compiler (the active - `compile_commands.json` records its path), from the tools environment, or on - the activated PATH. Do not install a compiler. Missing tools are a setup issue. - -## Prepare and record - -The helpers require Python 3 and only its standard library. Use arguments, not -shell interpolation of untrusted YAML/CSV contents. Quote paths containing spaces. - -Run `scripts/capture_manifest.py prepare` with the resolved values: - -```sh -python3 .agents/skills/trace-stack-magic-corruption-test/scripts/capture_manifest.py prepare \ - --workspace "$trace_workspace" --target "$trace_target" \ - --elf "$trace_elf" --compile-commands "$trace_compile_commands" \ - --run-description "$trace_run" --source-profile "$trace_profile" \ - --runtime-profile "$trace_runtime_profile" \ - --raw "$trace_raw" --csv "$trace_csv" -``` - -The returned manifest is in a unique `.trace/captures/stack-magic-*` directory. -It records the exact ELF snapshot, profile hashes, compilation-source hashes and -capture start time. Keep this manifest path for verification and the report. -Prepare again after any build, profile or target change. - -- Check `get_session_status` and `list_breakpoints`. A clean capture must pass the - corruption store without breakpoints or single stepping. Remove only this - workflow's own breakpoints; if user breakpoints interrupt the path, arrange for - them to be disabled/restored rather than silently clearing all breakpoints. -- Use `cmsis_action load_and_debug` with the exact active target/set. Confirm the - image/probe match. From the initial halt at `main`, use `continue_execution` - with a **4500 ms** wait for the current two-second workload. A `running` result - is expected. If the workload delay changes, use its delay plus sufficient drain - time instead. If execution stops early, investigate before calling it a capture. -- Pause after the uninterrupted run, then **end the debug session** with - `stop_debugging`. The pause lets the existing IDE workflow convert the drained - RAW; ending the session fixes the final input for the report. - This experiment normally ends in `osRtxErrorNotify` after the deliberate error. -- Run `capture_manifest.py verify --manifest "$trace_manifest"`. It waits up to - 15 seconds for a fresh, nonempty, stable RAW/CSV pair and saves the unannotated - capture beside the manifest. Do not accept a previous CSV because it exists. - Inspect decoder diagnostics. If automatic conversion is missing or stale, - run the installed `ctrace` offline on this exact stem and final RAW/profile, - then verify again; report that manual fallback was used. - -## Resolve PCs and write the Markdown report - -After the session and final conversion have ended, run: - -```sh -python3 .agents/skills/trace-stack-magic-corruption-test/scripts/report_trace.py \ - --csv "$trace_csv" --elf "$trace_snapshot_elf" \ - --addr2line "$trace_addr2line" --source-root "$trace_workspace" \ - --source-manifest "$trace_manifest" --output "$trace_report" -``` - -Set `trace_report` to `.trace/.SWO.md`; by default the helper replaces the -input CSV's `.csv` suffix with `.md`. Take `trace_snapshot_elf` from the manifest's -`elf`, not whichever build is now newest. The helper checks ELF and captured CSV -hashes, batches distinct PCs through `addr2line`, and writes only the Markdown -file atomically. **Leave CSV bytes, columns, cells and row order unchanged.** -Use trace PCs exactly as recorded; do not subtract a Thumb or return-address -offset. If an old capture was enriched by the previous skill version, use its -archived original CSV and matching manifest, without rewriting the current CSV. - -Create exactly one `## Entry N` section per CSV data record, in original order, -including duplicates, decoder diagnostics and records without a PC. The header -is not an entry. For a resolved PC, show the source code first and the location -next, for example: - -````markdown -## Entry 2 - -```c -*bad_destination = 0xDEADC0DEU; -``` - -Location: `Common/Workloads/stack_corruption.c:39` -```` - -Follow this with the record's trace fields, including its PC and any original -notes. Make all source paths project-relative, including `../` for external -Pack files. Pair each inline frame's source and location within the same entry. -For missing/invalid PCs or unavailable/changed source text, state the actual -status and retain the original CSV information; never invent a source line. -Verify source text against the captured compilation inputs; an uncaptured inline -header can have a valid DWARF location without verified source text. Repeating -the helper with unchanged inputs must produce identical base Markdown. - -After the helper finishes, **explain what happened** in the report. Use its -`addr2line` results (or call that tool again with the captured ELF) to locate the -actual functions, then read the surrounding source, relevant callers and symbol -or constant definitions. Check available source hashes against the capture. -Add a compact context excerpt when needed to explain the resolved store, retaining -the exact recorded source line and its location. Use the matching code-fence -language, including `asm` for assembly. Add one to three explanatory sentences to -each entry and a brief overall interpretation before the entries. Preserve the -entry count/order and original trace fields; leave the CSV untouched. - -Distinguish normal startup/RTX initialization from deliberate corruption using -the source context, never fixed PC addresses, row numbers or a matching literal -alone. Separate recorded evidence from source-based interpretation: PC-only -trace identifies writes but does not directly record their stored values or -elapsed time. Explain subsequent stack checking from its actual code; claim an -observed error-handler stop only when this run has corresponding debugger -inspection. Mark missing evidence or unresolved entries explicitly. Do not -rerun the helper after adding explanations, because it replaces the report; -archive and open the explained report as the final artifact. - -Check that the report section count equals the CSV record count, and that the -CSV hash is unchanged. The magic-watch DWT index must contain a PC resolving to -the corruption store. An initialization write is expected and remains a separate -entry; it is not evidence of corruption by itself. A missing corruption PC, -decoder errors or unresolved corruption location prevents a successful end-to-end -result. Do not treat cycle fields as elapsed time when timestamps are disabled. - -Copy the Markdown report beside the manifest; retain original RAW/CSV and ELF -there. **Automatically open the newly generated report in VS Code before the -final response**, including reports that document unresolved entries. Use a -workspace-targeted editor tool if available; otherwise use the installed VS Code -CLI with both absolute paths: - -```sh -code "$trace_workspace" "$trace_report" -``` - -Passing the project folder lets VS Code select its existing workspace window. -Respect its Markdown editor/preview association. Do not force a new/reused window -or use `--wait`, which would block until the user closes the report. Open only the -report generated and verified by this run, never a stale file after generation -failed. If no GUI/editor is available (for example in CI), keep the report and -state that it could not be opened; do not rerun the capture for this reason. - -Finish with the active target/set, capture/report result, resolved store location, -and links to the report, original CSV and capture directory. Include material -decoder/capture limitations. Do not restart debugging after reporting; a later -capture replaces current files but the archived report remains available. diff --git a/.agents/skills/trace-stack-magic-corruption-test/agents/openai.yaml b/.agents/skills/trace-stack-magic-corruption-test/agents/openai.yaml deleted file mode 100644 index 678f246..0000000 --- a/.agents/skills/trace-stack-magic-corruption-test/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Trace Stack Magic corruption test" - short_description: "Capture stack writes and open a Markdown report" - default_prompt: "Use $trace-stack-magic-corruption-test to capture the active target's stack-magic writes and create and explain a Markdown report with one section per CSV record, leaving the CSV unchanged, then open the report in VS Code." diff --git a/.agents/skills/trace-stack-magic-corruption-test/scripts/capture_manifest.py b/.agents/skills/trace-stack-magic-corruption-test/scripts/capture_manifest.py deleted file mode 100644 index 7498234..0000000 --- a/.agents/skills/trace-stack-magic-corruption-test/scripts/capture_manifest.py +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env python3 -"""Bind one CMSIS trace capture to its ELF, profiles, sources and fresh CSV.""" - -import argparse -import csv -import hashlib -import json -from pathlib import Path -import shutil -import sys -import tempfile -import time - - -def digest(path): - return hashlib.sha256(Path(path).read_bytes()).hexdigest() - - -def prepare(args): - paths = {key: Path(getattr(args, key)).resolve() for key in ( - "elf", "csv", "raw", "source_profile", "runtime_profile", - "run_description", "compile_commands", "workspace")} - for key in ("elf", "source_profile", "runtime_profile", "run_description", - "compile_commands"): - if not paths[key].is_file(): - raise ValueError(f"Missing {key}: {paths[key]}") - if paths["elf"].read_bytes()[:4] != b"\x7fELF": - raise ValueError("Selected image is not an ELF file") - active_file = paths["workspace"] / ".vscode/cmsis.json" - if active_file.is_file(): - active = json.loads(active_file.read_text()).get("activeTarget") - if active and active != args.target: - raise ValueError(f"Selected target is {active!r}, not {args.target!r}") - sources = {} - for entry in json.loads(paths["compile_commands"].read_text()): - source = Path(entry["file"]) - if not source.is_absolute(): - source = Path(entry["directory"]) / source - source = source.resolve() - sources[str(source)] = digest(source) - if not sources: - raise ValueError("The compilation database has no sources") - - parent = paths["csv"].parent / "captures" - parent.mkdir(parents=True, exist_ok=True) - capture_dir = Path(tempfile.mkdtemp(prefix="stack-magic-", dir=parent)) - snapshot_elf = capture_dir / paths["elf"].name - shutil.copy2(paths["elf"], snapshot_elf) - for key in ("source_profile", "runtime_profile"): - shutil.copy2(paths[key], capture_dir / paths[key].name) - # Avoid *.cbuild-run.yml: CMSIS build tools would discover a duplicate context. - shutil.copy2(paths["run_description"], capture_dir / "run-description.snapshot.yml") - manifest = { - "version": 1, - "target": args.target, - "workspace": str(paths["workspace"]), - "elf": str(snapshot_elf), - "elf_original": str(paths["elf"]), - "elf_sha256": digest(snapshot_elf), - "csv": str(paths["csv"]), - "raw": str(paths["raw"]), - "sources": sources, - "inputs": {str(paths[key]): digest(paths[key]) for key in ( - "source_profile", "runtime_profile", "run_description")}, - "capture_started_ns": time.time_ns(), - } - output = capture_dir / "manifest.json" - output.write_text(json.dumps(manifest, indent=2) + "\n") - print(json.dumps({"manifest": str(output), **manifest}, indent=2)) - - -def verify_inputs(manifest): - for key in ("elf", "elf_original"): - if digest(manifest[key]) != manifest["elf_sha256"]: - raise ValueError("ELF changed; build, regenerate and prepare a new capture") - for source, expected in manifest["inputs"].items(): - if digest(source) != expected: - raise ValueError(f"Capture input changed: {source}") - active_file = Path(manifest["workspace"]) / ".vscode/cmsis.json" - if active_file.is_file(): - active = json.loads(active_file.read_text()).get("activeTarget") - if active and active != manifest["target"]: - raise ValueError("Active target changed since capture preparation") - - -def verify(args): - path = Path(args.manifest).resolve() - manifest = json.loads(path.read_text()) - verify_inputs(manifest) - files = [Path(manifest[key]) for key in ("raw", "csv")] - deadline = time.monotonic() + args.timeout - previous = None - stable_since = time.monotonic() - while time.monotonic() < deadline: - try: - state = [(p.stat().st_size, p.stat().st_mtime_ns) for p in files] - except FileNotFoundError: - state = None - fresh = state is not None and all( - size > 0 and modified >= manifest["capture_started_ns"] - for size, modified in state) - # The final CSV must have been decoded after the last RAW write. - fresh = fresh and state[1][1] >= state[0][1] - if not fresh or state != previous: - stable_since = time.monotonic() - elif time.monotonic() - stable_since >= 1.0: - break - previous = state - time.sleep(0.2) - else: - raise ValueError("No fresh, stable RAW/CSV pair; await conversion or decode the final RAW with ctrace") - with files[1].open(newline="", encoding="utf-8-sig") as handle: - reader = csv.DictReader(handle) - if not reader.fieldnames or "pc" not in reader.fieldnames: - raise ValueError("CSV has no pc column") - rows = list(reader) - if any(None in row or None in row.values() for row in rows): - raise ValueError("CSV row length differs from its header") - pc_rows = sum(bool(row.get("pc", "").strip()) for row in rows) - if not pc_rows: - raise ValueError("CSV contains no PC records; do not claim a successful magic-word capture") - # The selected context may change while waiting for asynchronous conversion. - verify_inputs(manifest) - for key, source in zip(("raw", "csv"), files): - shutil.copy2(source, path.parent / source.name) - manifest[f"{key}_sha256"] = digest(source) - manifest["verified_ns"] = time.time_ns() - path.write_text(json.dumps(manifest, indent=2) + "\n") - print(json.dumps({"target": manifest["target"], "raw_bytes": files[0].stat().st_size, - "rows": len(rows), "pc_rows": pc_rows, - "manifest": str(path), "elf": manifest["elf"], - "csv": manifest["csv"]}, indent=2)) - - -def main(): - parser = argparse.ArgumentParser(description=__doc__) - commands = parser.add_subparsers(dest="command", required=True) - prepare_parser = commands.add_parser("prepare", help="Snapshot capture inputs before starting debug") - for name in ("target", "workspace", "elf", "csv", "raw", "source-profile", - "runtime-profile", "run-description", "compile-commands"): - prepare_parser.add_argument("--" + name, required=True) - verify_parser = commands.add_parser("verify", help="Wait for final conversion after debug has ended") - verify_parser.add_argument("--manifest", required=True) - verify_parser.add_argument("--timeout", type=float, default=15.0) - args = parser.parse_args() - try: - (prepare if args.command == "prepare" else verify)(args) - except (OSError, ValueError, KeyError, csv.Error) as error: - print(f"error: {error}", file=sys.stderr) - return 1 - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/.agents/skills/trace-stack-magic-corruption-test/scripts/report_trace.py b/.agents/skills/trace-stack-magic-corruption-test/scripts/report_trace.py deleted file mode 100644 index 9f36d46..0000000 --- a/.agents/skills/trace-stack-magic-corruption-test/scripts/report_trace.py +++ /dev/null @@ -1,286 +0,0 @@ -#!/usr/bin/env python3 -"""Write a Markdown source report for a completed ctrace CSV; keep inputs intact.""" - -import argparse -import csv -import hashlib -import io -import json -import os -from pathlib import Path -import re -import stat -import subprocess -import sys -import tempfile - - -ADDRESS = re.compile(r"^(?:0[xX])?[0-9a-fA-F]+$") -LOCATION = re.compile(r"^(.*):(\d+|\?)(?: \(discriminator \d+\))?$") -HASH = re.compile(r"[0-9a-fA-F]{64}") - - -def sha256(data): - return hashlib.sha256(data).hexdigest() - - -def file_hash(path): - digest = hashlib.sha256() - with path.open("rb") as source: - for chunk in iter(lambda: source.read(1024 * 1024), b""): - digest.update(chunk) - return digest.hexdigest() - - -def local_path(name, root): - path = Path(name) - return (path if path.is_absolute() else root / path).resolve() - - -def relative_name(path, root): - return Path(os.path.relpath(path, root)).as_posix() - - -def read_manifest(path, root): - if path is None: - return {}, {}, set(), None - original = path.read_bytes() - manifest = json.loads(original) - if not isinstance(manifest, dict) or not isinstance(manifest.get("sources"), dict): - raise ValueError("Manifest requires a sources path/hash object") - if not isinstance(manifest.get("elf_sha256"), str) or not HASH.fullmatch(manifest["elf_sha256"]): - raise ValueError("Manifest requires a valid elf_sha256") - sources = {} - for name, digest in manifest["sources"].items(): - if not isinstance(digest, str) or not HASH.fullmatch(digest): - raise ValueError(f"Invalid source SHA-256 in manifest: {name}") - sources[local_path(name, root)] = digest.lower() - protected = set(sources) - protected.update(local_path(name, root) for name in manifest.get("inputs", {})) - for key, value in manifest.items(): - if isinstance(value, str) and (Path(value).is_absolute() or key in ("elf", "elf_original", "csv", "raw", "profile")): - protected.add(local_path(value, root)) - return manifest, sources, protected, original - - -def check_output(output, protected): - if output.suffix.casefold() != ".md": - raise ValueError("Report output must have a .md extension") - resolved = output.resolve() - for path in protected: - if resolved == path.resolve() or (output.exists() and path.exists() and output.samefile(path)): - raise ValueError(f"Report output aliases an input: {path}") - - -def inline_code(value): - # Escape embedded newlines in names; multiline values use fenced blocks below. - value = str(value).replace("\r", "\\r").replace("\n", "\\n") - length = max((len(match) for match in re.findall(r"`+", value)), default=0) + 1 - fence = "`" * length - padding = " " if value.startswith(("`", " ")) or value.endswith(("`", " ")) else "" - return fence + padding + value + padding + fence - - -def fenced(value, language="text"): - length = max(3, max((len(match) for match in re.findall(r"`+", value)), default=0) + 1) - fence = "`" * length - return f"{fence}{language}\n{value}\n{fence}" - - -def resolve_addresses(tool, elf, addresses): - """Parse address/function/location pairs, preserving all inline frames.""" - if not addresses: - return {} - result = subprocess.run( - [str(tool), "-a", "-f", "-C", "-i", "-e", str(elf)], - input="".join(f"0x{address:x}\n" for address in addresses), - text=True, encoding="utf-8", errors="replace", capture_output=True, - check=False, timeout=60, - ) - if result.returncode: - raise ValueError(f"addr2line failed ({result.returncode}): {result.stderr.strip()}") - blocks, seen, current = {}, [], None - for line in result.stdout.splitlines(): - if re.fullmatch(r"0[xX][0-9a-fA-F]+", line): - current = int(line, 16) - if current in blocks: - raise ValueError("addr2line returned a duplicate address block") - blocks[current] = [] - seen.append(current) - elif current is None: - raise ValueError("addr2line output has no initial address marker") - else: - blocks[current].append(line) - if seen != addresses: - raise ValueError("addr2line did not return the requested addresses in order") - for address, lines in blocks.items(): - if not lines or len(lines) % 2: - raise ValueError(f"Incomplete addr2line frames for 0x{address:x}") - blocks[address] = list(zip(lines[0::2], lines[1::2])) - return blocks - - -def source_details(location, root, hashes, cache, warnings): - match = LOCATION.fullmatch(location) - if not match or match[1] == "??" or match[2] in ("?", "0"): - return None, None, "Source location unresolved." - path = local_path(match[1], root) - number = int(match[2]) - label = f"{relative_name(path, root)}:{number}" - if path not in cache: - if path not in hashes: - cache[path] = (None, "Source hash unavailable in capture manifest; text omitted.") - else: - try: - raw = path.read_bytes() - if sha256(raw) != hashes[path]: - cache[path] = (None, "Source changed since capture; text omitted.") - else: - cache[path] = (raw.decode("utf-8").splitlines(), None) - except (OSError, UnicodeError): - cache[path] = (None, "Source unavailable; text omitted.") - lines, error = cache[path] - if not error and number > len(lines): - error = "Source line outside file; text omitted." - if error: - warnings.append(f"{label}: {error}") - return label, None, error - return label, lines[number - 1].strip(), None - - -def trace_fields(header, row, pc_index): - """Retain original nonempty values, including decoder notes and extra columns.""" - fields = [(header[i] if i < len(header) else f"column {i + 1}", value) - for i, value in enumerate(row) if value != "" and i != pc_index] - if pc_index is not None and pc_index < len(row) and row[pc_index] != "": - fields.insert(0, (header[pc_index], row[pc_index])) - compact, multiline = [], [] - for name, value in fields: - label = inline_code(name) - if "\n" in value or "\r" in value: - multiline.extend([f"CSV {label}:", fenced(value)]) - else: - compact.append(f"{label}: {inline_code(value)}") - return ([" · ".join(compact)] if compact else []) + multiline - - -def report(args): - csv_path = args.csv.resolve() - elf = args.elf.resolve() - root = args.source_root.resolve() - output = (args.output or args.csv.with_suffix(".md")).absolute() - manifest, hashes, protected, manifest_bytes = read_manifest(args.source_manifest, root) - protected.update((csv_path, elf, args.addr2line.resolve())) - if args.source_manifest: - protected.add(args.source_manifest.resolve()) - check_output(output, protected) - - manifest_elf = manifest.get("elf_sha256", "").lower() or None - expected = args.elf_sha256.lower() if args.elf_sha256 else manifest_elf - if expected is not None and not HASH.fullmatch(expected): - raise ValueError("ELF SHA-256 must contain 64 hexadecimal characters") - if manifest_elf is not None and expected != manifest_elf: - raise ValueError("--elf-sha256 disagrees with capture manifest") - elf_hash = file_hash(elf) - if expected is not None and elf_hash != expected: - raise ValueError("ELF differs from capture SHA-256; report left unchanged") - csv_bytes = csv_path.read_bytes() - csv_hash = sha256(csv_bytes) - if manifest.get("csv_sha256") is not None and csv_hash != manifest["csv_sha256"]: - raise ValueError("CSV differs from capture SHA-256; use the archived original CSV") - rows = list(csv.reader(io.StringIO(csv_bytes.decode("utf-8-sig"), newline=""), strict=True)) - if not rows or not rows[0]: - raise ValueError("CSV has no header") - header, records = rows[0], rows[1:] - pc_columns = [i for i, name in enumerate(header) if name.casefold() == "pc"] - if len(pc_columns) > 1: - raise ValueError("CSV has multiple PC columns") - pc_index = pc_columns[0] if pc_columns else None - raw_pcs = [row[pc_index].strip() if pc_index is not None and pc_index < len(row) else "" for row in records] - parsed = [int(raw, 16) if raw and ADDRESS.fullmatch(raw) else None for raw in raw_pcs] - addresses = list(dict.fromkeys(address for address in parsed if address is not None)) - resolved = resolve_addresses(args.addr2line, elf, addresses) - - parts = ["# Stack magic trace", f"CSV: {inline_code(relative_name(csv_path, root))}"] - if isinstance(manifest.get("target"), str): - parts.append(f"Target: {inline_code(manifest['target'])}") - cache, warnings, unresolved = {}, [], 0 - for index, (row, raw_pc, address) in enumerate(zip(records, raw_pcs, parsed), start=1): - parts.append(f"## Entry {index}") - located = False - if not raw_pc: - parts.append("Status: No PC recorded; source lookup not applicable.") - elif address is None: - parts.append("Status: Invalid PC; source unresolved.") - else: - frames = resolved[address] - for frame_index, (function, location) in enumerate(frames): - if frame_index: - parts.append(f"**Inline caller {frame_index}** ({inline_code(function)})") - label, source, error = source_details(location, root, hashes, cache, warnings) - located = located or label is not None - if source is not None: - parts.append(fenced(source, "c")) - else: - parts.append(f"Status: {error}") - if label is not None: - parts.append(f"Location: {inline_code(label)}") - if raw_pc and not located: - unresolved += 1 - parts.extend(trace_fields(header, row, pc_index)) - updated = ("\n\n".join(parts) + "\n").encode("utf-8") - - def recheck_inputs(): - check_output(output, protected) - if csv_path.read_bytes() != csv_bytes: - raise ValueError("CSV changed during reporting; stop capture/conversion first") - if file_hash(elf) != elf_hash: - raise ValueError("ELF changed during reporting; report left unchanged") - if args.source_manifest and args.source_manifest.read_bytes() != manifest_bytes: - raise ValueError("Capture manifest changed during reporting; report left unchanged") - - recheck_inputs() - changed = not output.exists() or output.read_bytes() != updated - if changed: - temporary = None - try: - with tempfile.NamedTemporaryFile(dir=output.parent, delete=False) as handle: - temporary = Path(handle.name) - handle.write(updated) - handle.flush() - os.fsync(handle.fileno()) - if output.exists(): - temporary.chmod(stat.S_IMODE(output.stat().st_mode)) - recheck_inputs() - os.replace(temporary, output) - finally: - if temporary is not None and temporary.exists(): - temporary.unlink() - print(json.dumps({ - "rows": len(records), "sections": len(records), - "pc_rows": sum(bool(raw) for raw in raw_pcs), "unique_pcs": len(addresses), - "unresolved_rows": unresolved, "source_warnings": list(dict.fromkeys(warnings)), - "report": str(output), "csv_sha256": csv_hash, "elf_sha256": elf_hash, - "changed": changed, - }, ensure_ascii=False, indent=2)) - - -def main(): - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--csv", type=Path, required=True) - parser.add_argument("--elf", type=Path, required=True) - parser.add_argument("--addr2line", type=Path, required=True) - parser.add_argument("--source-root", type=Path, required=True) - parser.add_argument("--source-manifest", type=Path) - parser.add_argument("--elf-sha256") - parser.add_argument("--output", type=Path) - try: - report(parser.parse_args()) - except (OSError, ValueError, csv.Error, subprocess.SubprocessError) as error: - print(f"report_trace: {error}", file=sys.stderr) - return 1 - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/.cmsis/Trace+MCBSTM32F400.dbgconf.base@0.0.0 b/.cmsis/Trace+MCBSTM32F400.dbgconf.base@0.0.0 deleted file mode 100644 index 1df0a1b..0000000 --- a/.cmsis/Trace+MCBSTM32F400.dbgconf.base@0.0.0 +++ /dev/null @@ -1,48 +0,0 @@ -// File: STM32F405_415_407_417_427_437_429_439.dbgconf -// Version: 1.0.0 -// Note: refer to STM32F405/415 STM32F407/417 STM32F427/437 STM32F429/439 reference manual (RM0090) -// refer to STM32F40x STM32F41x datasheets -// refer to STM32F42x STM32F43x datasheets - -// <<< Use Configuration Wizard in Context Menu >>> - -// Debug MCU configuration register (DBGMCU_CR) -// DBG_STANDBY Debug Standby Mode -// DBG_STOP Debug Stop Mode -// DBG_SLEEP Debug Sleep Mode -// -DbgMCU_CR = 0x00000007; - -// Debug MCU APB1 freeze register (DBGMCU_APB1_FZ) -// Reserved bits must be kept at reset value -// DBG_CAN2_STOP CAN2 stopped when core is halted -// DBG_CAN1_STOP CAN2 stopped when core is halted -// DBG_I2C3_SMBUS_TIMEOUT I2C3 SMBUS timeout mode stopped when core is halted -// DBG_I2C2_SMBUS_TIMEOUT I2C2 SMBUS timeout mode stopped when core is halted -// DBG_I2C1_SMBUS_TIMEOUT I2C1 SMBUS timeout mode stopped when core is halted -// DBG_IWDG_STOP Independent watchdog stopped when core is halted -// DBG_WWDG_STOP Window watchdog stopped when core is halted -// DBG_RTC_STOP RTC stopped when core is halted -// DBG_TIM14_STOP TIM14 counter stopped when core is halted -// DBG_TIM13_STOP TIM13 counter stopped when core is halted -// DBG_TIM12_STOP TIM12 counter stopped when core is halted -// DBG_TIM7_STOP TIM7 counter stopped when core is halted -// DBG_TIM6_STOP TIM6 counter stopped when core is halted -// DBG_TIM5_STOP TIM5 counter stopped when core is halted -// DBG_TIM4_STOP TIM4 counter stopped when core is halted -// DBG_TIM3_STOP TIM3 counter stopped when core is halted -// DBG_TIM2_STOP TIM2 counter stopped when core is halted -// -DbgMCU_APB1_Fz = 0x00000000; - -// Debug MCU APB2 freeze register (DBGMCU_APB2_FZ) -// Reserved bits must be kept at reset value -// DBG_TIM11_STOP TIM11 counter stopped when core is halted -// DBG_TIM10_STOP TIM10 counter stopped when core is halted -// DBG_TIM9_STOP TIM9 counter stopped when core is halted -// DBG_TIM8_STOP TIM8 counter stopped when core is halted -// DBG_TIM1_STOP TIM1 counter stopped when core is halted -// -DbgMCU_APB2_Fz = 0x00000000; - -// <<< end of configuration section >>> \ No newline at end of file diff --git a/.cmsis/Trace+NUCLEO-F401RE.dbgconf.base@0.0.0 b/.cmsis/Trace+NUCLEO-F401RE.dbgconf.base@0.0.0 deleted file mode 100644 index de9f9b9..0000000 --- a/.cmsis/Trace+NUCLEO-F401RE.dbgconf.base@0.0.0 +++ /dev/null @@ -1,41 +0,0 @@ -// File: STM32F401xBCDE_411xCE.dbgconf -// Version: 1.0.0 -// Note: refer to STM32F401xB/C STM32F401xD/E reference manual (RM0368) -// refer to STM32F401xB/C STM32F401xD/E datasheet -// refer to STM32F411xC/E reference manual (RM0383) -// refer to STM32F411xC/E datasheet - -// <<< Use Configuration Wizard in Context Menu >>> - -// Debug MCU configuration register (DBGMCU_CR) -// DBG_STANDBY Debug Standby Mode -// DBG_STOP Debug Stop Mode -// DBG_SLEEP Debug Sleep Mode -// -DbgMCU_CR = 0x00000007; - -// Debug MCU APB1 freeze register (DBGMCU_APB1_FZ) -// Reserved bits must be kept at reset value -// DBG_I2C3_SMBUS_TIMEOUT I2C3 SMBUS timeout mode stopped when core is halted -// DBG_I2C2_SMBUS_TIMEOUT I2C2 SMBUS timeout mode stopped when core is halted -// DBG_I2C1_SMBUS_TIMEOUT I2C1 SMBUS timeout mode stopped when core is halted -// DBG_IWDG_STOP Independent watchdog stopped when core is halted -// DBG_WWDG_STOP Window watchdog stopped when core is halted -// DBG_RTC_STOP RTC stopped when core is halted -// DBG_TIM5_STOP TIM5 counter stopped when core is halted -// DBG_TIM4_STOP TIM4 counter stopped when core is halted -// DBG_TIM3_STOP TIM3 counter stopped when core is halted -// DBG_TIM2_STOP TIM2 counter stopped when core is halted -// -DbgMCU_APB1_Fz = 0x00000000; - -// Debug MCU APB2 freeze register (DBGMCU_APB2_FZ) -// Reserved bits must be kept at reset value -// DBG_TIM11_STOP TIM11 counter stopped when core is halted -// DBG_TIM10_STOP TIM10 counter stopped when core is halted -// DBG_TIM9_STOP TIM9 counter stopped when core is halted -// DBG_TIM1_STOP TIM1 counter stopped when core is halted -// -DbgMCU_APB2_Fz = 0x00000000; - -// <<< end of configuration section >>> \ No newline at end of file diff --git a/.cmsis/Trace+NUCLEO-F446RE.dbgconf.base@0.0.0 b/.cmsis/Trace+NUCLEO-F446RE.dbgconf.base@0.0.0 deleted file mode 100644 index 4694254..0000000 --- a/.cmsis/Trace+NUCLEO-F446RE.dbgconf.base@0.0.0 +++ /dev/null @@ -1,73 +0,0 @@ -// File: STM32F446.dbgconf -// Version: 1.0.0 -// Note: refer to STM32F446xx reference manual (RM0390) -// refer to STM32F446xx datasheets - -// <<< Use Configuration Wizard in Context Menu >>> - -// Debug MCU configuration register (DBGMCU_CR) -// DBG_STANDBY Debug Standby Mode -// DBG_STOP Debug Stop Mode -// DBG_SLEEP Debug Sleep Mode -// -DbgMCU_CR = 0x00000007; - -// Debug MCU APB1 freeze register (DBGMCU_APB1_FZ) -// Reserved bits must be kept at reset value -// DBG_CAN2_STOP CAN2 stopped when core is halted -// DBG_CAN1_STOP CAN2 stopped when core is halted -// DBG_I2CFMP_SMBUS_TIMEOUT I2CFMP SMBUS timeout mode stopped when core is halted -// DBG_I2C3_SMBUS_TIMEOUT I2C3 SMBUS timeout mode stopped when core is halted -// DBG_I2C2_SMBUS_TIMEOUT I2C2 SMBUS timeout mode stopped when core is halted -// DBG_I2C1_SMBUS_TIMEOUT I2C1 SMBUS timeout mode stopped when core is halted -// DBG_IWDG_STOP Independent watchdog stopped when core is halted -// DBG_WWDG_STOP Window watchdog stopped when core is halted -// DBG_RTC_STOP RTC stopped when core is halted -// DBG_TIM14_STOP TIM14 counter stopped when core is halted -// DBG_TIM13_STOP TIM13 counter stopped when core is halted -// DBG_TIM12_STOP TIM12 counter stopped when core is halted -// DBG_TIM7_STOP TIM7 counter stopped when core is halted -// DBG_TIM6_STOP TIM6 counter stopped when core is halted -// DBG_TIM5_STOP TIM5 counter stopped when core is halted -// DBG_TIM4_STOP TIM4 counter stopped when core is halted -// DBG_TIM3_STOP TIM3 counter stopped when core is halted -// DBG_TIM2_STOP TIM2 counter stopped when core is halted -// -DbgMCU_APB1_Fz = 0x00000000; - -// Debug MCU APB2 freeze register (DBGMCU_APB2_FZ) -// Reserved bits must be kept at reset value -// DBG_TIM11_STOP TIM11 counter stopped when core is halted -// DBG_TIM10_STOP TIM10 counter stopped when core is halted -// DBG_TIM9_STOP TIM9 counter stopped when core is halted -// DBG_TIM8_STOP TIM8 counter stopped when core is halted -// DBG_TIM1_STOP TIM1 counter stopped when core is halted -// -DbgMCU_APB2_Fz = 0x00000000; - -// TPIU Pin Routing (TRACECLK fixed on Pin PE2) -// TRACECLK: Pin PE2 -// TRACED0 -// ETM Trace Data 0 -// <0x00040003=> Pin PE3 -// <0x00020008=> Pin PC8 -// TRACED1 -// ETM Trace Data 1 -// <0x00040004=> Pin PE4 -// <0x00030003=> Pin PD3 -// TRACED2 -// ETM Trace Data 2 -// <0x00040005=> Pin PE5 -// <0x0006000D=> Pin PG13 -// TRACED3 -// ETM Trace Data 3 -// <0x00040006=> Pin PE6 -// <0x0006000E=> Pin PG14 -// -TraceClk_Pin = 0x00040002; -TraceD0_Pin = 0x00040003; -TraceD1_Pin = 0x00040004; -TraceD2_Pin = 0x00040005; -TraceD3_Pin = 0x00040006; - -// <<< end of configuration section >>> \ No newline at end of file diff --git a/.cmsis/Trace+NUCLEO-F756ZG.dbgconf.base@2.0.1 b/.cmsis/Trace+NUCLEO-F756ZG.dbgconf.base@2.0.1 deleted file mode 100644 index 8af7d02..0000000 --- a/.cmsis/Trace+NUCLEO-F756ZG.dbgconf.base@2.0.1 +++ /dev/null @@ -1,76 +0,0 @@ -// File: STM32F74x_75x.dbgconf -// Version: 2.0.1 -// Note: refer to STM32F75xxx STM32F74xxx reference manual (RM0385) -// refer to STM32F75xxx STM32F74xxx datasheets - -// <<< Use Configuration Wizard in Context Menu >>> - -// Debug MCU configuration register (DBGMCU_CR) -// DBG_STANDBY Debug standby mode -// DBG_STOP Debug stop mode -// DBG_SLEEP Debug sleep mode -// -DbgMCU_CR = 0x00000007; - -// Debug MCU APB1 freeze register (DBGMCU_APB1_FZ) -// Reserved bits must be kept at reset value -// DBG_CAN2_STOP Debug CAN2 stopped when core is halted -// DBG_CAN1_STOP Debug CAN1 stopped when core is halted -// DBG_I2C4_SMBUS_TIMEOUT SMBUS timeout mode stopped when core is halted -// DBG_I2C3_SMBUS_TIMEOUT SMBUS timeout mode stopped when core is halted -// DBG_I2C2_SMBUS_TIMEOUT SMBUS timeout mode stopped when core is halted -// DBG_I2C1_SMBUS_TIMEOUT SMBUS timeout mode stopped when core is halted -// DBG_IWDG_STOP Debug independent watchdog stopped when core is halted -// DBG_WWDG_STOP Debug window watchdog stopped when core is halted -// DBG_RTC_STOP RTC stopped when core is halted -// DBG_LPTIM1_STOP LPTMI1 counter stopped when core is halted -// DBG_TIM14_STOP TIM14 counter stopped when core is halted -// DBG_TIM13_STOP TIM13 counter stopped when core is halted -// DBG_TIM12_STOP TIM12 counter stopped when core is halted -// DBG_TIM7_STOP TIM7 counter stopped when core is halted -// DBG_TIM6_STOP TIM6 counter stopped when core is halted -// DBG_TIM5_STOP TIM5 counter stopped when core is halted -// DBG_TIM4_STOP TIM4 counter stopped when core is halted -// DBG_TIM3_STOP TIM3 counter stopped when core is halted -// DBG_TIM2_STOP TIM2 counter stopped when core is halted -// -DbgMCU_APB1_Fz = 0x07E01BFF; - -// Debug MCU APB2 freeze register (DBGMCU_APB2_FZ) -// Reserved bits must be kept at reset value -// DBG_TIM11_STOP TIM11 counter stopped when core is halted -// DBG_TIM10_STOP TIM10 counter stopped when core is halted -// DBG_TIM9_STOP TIM9 counter stopped when core is halted -// DBG_TIM8_STOP TIM8 counter stopped when core is halted -// DBG_TIM1_STOP TIM1 counter stopped when core is halted -// -DbgMCU_APB2_Fz = 0x00070003; - -// TPIU Pin Routing (TRACECLK fixed on Pin PE2) -// TRACECLK: Pin PE2 -// TRACED0 -// ETM Trace Data 0 -// <0x00040003=> Pin PE3 -// <0x00020001=> Pin PC1 -// <0x0006000D=> Pin PG13 -// TRACED1 -// ETM Trace Data 1 -// <0x00040004=> Pin PE4 -// <0x00020008=> Pin PC8 -// <0x0006000E=> Pin PG14 -// TRACED2 -// ETM Trace Data 2 -// <0x00040005=> Pin PE5 -// <0x00030002=> Pin PD2 -// TRACED3 -// ETM Trace Data 3 -// <0x00040006=> Pin PE6 -// <0x0002000C=> Pin PC12 -// -TraceClk_Pin = 0x00040002; -TraceD0_Pin = 0x00040003; -TraceD1_Pin = 0x00040004; -TraceD2_Pin = 0x00040005; -TraceD3_Pin = 0x00040006; - -// <<< end of configuration section >>> diff --git a/.cmsis/Trace+NUCLEO-G474RE.dbgconf.base@0.0.0 b/.cmsis/Trace+NUCLEO-G474RE.dbgconf.base@0.0.0 deleted file mode 100644 index 08d5314..0000000 --- a/.cmsis/Trace+NUCLEO-G474RE.dbgconf.base@0.0.0 +++ /dev/null @@ -1,64 +0,0 @@ -// File: STM32G4xx.dbgconf -// Version: 1.0.1 -// Note: refer to STM32G4xx Reference manual (RM0440) -// refer to STM32G4xx datasheets - -// <<< Use Configuration Wizard in Context Menu >>> - -// Debug MCU configuration register (DBGMCU_CR) -// DBG_STANDBY Debug Standby mode -// DBG_STOP Debug Stop mode -// DBG_SLEEP Debug Sleep mode -// -DbgMCU_CR = 0x00000007; - -// Debug MCU APB1 freeze register1 (DBGMCU_APB1FZR1) -// Reserved bits must be kept at reset value -// DBG_LPTIM1_STOP LPTIM1 counter stopped when core is halted -// DBG_I2C3_STOP I2C3 SMBUS timeout counter stopped when core is halted -// DBG_I2C2_STOP I2C2 SMBUS timeout counter stopped when core is halted -// DBG_I2C1_STOP I2C1 SMBUS timeout counter stopped when core is halted -// DBG_IWDG_STOP Independent watchdog counter stopped when core is halted -// DBG_WWDG_STOP Window watchdog counter stopped when core is halted -// DBG_RTC_STOP RTC counter stopped when core is halted -// DBG_TIM7_STOP TIM7 counter stopped when core is halted -// DBG_TIM6_STOP TIM6 counter stopped when core is halted -// DBG_TIM5_STOP TIM5 counter stopped when core is halted -// DBG_TIM4_STOP TIM4 counter stopped when core is halted -// DBG_TIM3_STOP TIM3 counter stopped when core is halted -// DBG_TIM2_STOP TIM2 counter stopped when core is halted -// -DbgMCU_APB1_Fz1 = 0x00000000; - -// Debug MCU APB1 freeze register 2 (DBGMCU_APB1FZR2) -// Reserved bits must be kept at reset value -// DBG_I2C4_STOP I2C4 SMBUS timeout counter stopped when core is halted -// -DbgMCU_APB1_Fz2 = 0x00000000; - -// Debug MCU APB2 freeze register (DBGMCU_APB2FZR) -// Reserved bits must be kept at reset value -// DBG_HRTIM_STOP HRTIM counter stopped when core is halted -// DBG_TIM20_STOP TIM20 counter stopped when core is halted -// DBG_TIM17_STOP TIM17 counter stopped when core is halted -// DBG_TIM16_STOP TIM16 counter stopped when core is halted -// DBG_TIM15_STOP TIM15 counter stopped when core is halted -// DBG_TIM8_STOP TIM8 counter stopped when core is halted -// DBG_TIM1_STOP TIM1 counter stopped when core is halted -// -DbgMCU_APB2_Fz = 0x00000000; - -// TPIU Pin Routing -// TRACECLK: Pin PE2 -// TRACED[0]: Pin PE3 -// TRACED[1]: Pin PE4 -// TRACED[2]: Pin PE5 -// TRACED[3]: Pin PE6 -// - -// Flash Download Options -// Option Byte Loading Launch the Option Byte Loading after a Flash Download by setting the OBL_LAUNCH bit (causes a reset) -// -DoOptionByteLoading = 0x00000000; - -// <<< end of configuration section >>> diff --git a/.cmsis/Trace+NUCLEO-L552ZE-Q.dbgconf.base@1.0.0 b/.cmsis/Trace+NUCLEO-L552ZE-Q.dbgconf.base@1.0.0 deleted file mode 100644 index 2712d11..0000000 --- a/.cmsis/Trace+NUCLEO-L552ZE-Q.dbgconf.base@1.0.0 +++ /dev/null @@ -1,81 +0,0 @@ -// File: STM32F552xx_562xx.dbgconf -// Version: 1.0.1 -// Note: refer to STM32L552xx STM32L562xx reference manual (RM0410) -// refer to STM32L552xx STM32L562xx datasheets - -// <<< Use Configuration Wizard in Context Menu >>> - -// Debug MCU configuration register (DBGMCU_CR) -// DBG_STANDBY Debug standby mode -// DBG_STOP Debug stop mode -// -DbgMCU_CR = 0x00000006; - -// Debug MCU APB1L freeze register (DBGMCU_APB1LFZR) -// Reserved bits must be kept at reset value -// DBG_LPTIM1_STOP LPTMI1 counter stopped when core is halted -// DBG_I2C3_STOP SMBUS timeout mode stopped when core is halted -// DBG_I2C2_STOP SMBUS timeout mode stopped when core is halted -// DBG_I2C1_STOP SMBUS timeout mode stopped when core is halted -// DBG_IWDG_STOP Debug independent watchdog stopped when core is halted -// DBG_WWDG_STOP Debug window watchdog stopped when core is halted -// DBG_RTC_STOP RTC stopped when core is halted -// DBG_TIM7_STOP TIM7 counter stopped when core is halted -// DBG_TIM6_STOP TIM6 counter stopped when core is halted -// DBG_TIM5_STOP TIM5 counter stopped when core is halted -// DBG_TIM4_STOP TIM4 counter stopped when core is halted -// DBG_TIM3_STOP TIM3 counter stopped when core is halted -// DBG_TIM2_STOP TIM2 counter stopped when core is halted -// -DbgMCU_APB1L_Fz = 0x00000000; - -// Debug MCU APB1H freeze register (DBGMCU_APB1HFZR) -// Reserved bits must be kept at reset value -// DBG_LPTIM3_STOP LPTIM3 counter stopped when core is halted -// DBG_LPTIM2_STOP LPTIM2 counter stopped when core is halted -// DBG_I2C4_STOP SMBUS timeout mode stopped when core is halted -// -DbgMCU_APB1H_Fz = 0x00000000; - -// Debug MCU APB2 freeze register (DBGMCU_APB2FZR) -// Reserved bits must be kept at reset value -// DBG_TIM17_STOP TIM17 counter stopped when core is halted -// DBG_TIM16_STOP TIM16 counter stopped when core is halted -// DBG_TIM15_STOP TIM15 counter stopped when core is halted -// DBG_TIM8_STOP TIM8 counter stopped when core is halted -// DBG_TIM1_STOP TIM1 counter stopped when core is halted -// -DbgMCU_APB2_Fz = 0x00000000; - -// TPIU Pin Routing (TRACECLK fixed on Pin PE2) -// TRACECLK: Pin PE2 -// TRACED0 -// ETM Trace Data 0 -// <0x00020009=> Pin PC9 -// <0x00040003=> Pin PE3 -// <0x00020001=> Pin PC1 -// TRACED1 -// ETM Trace Data 1 -// <0x0002000A=> Pin PC10 -// <0x00040004=> Pin PE4 -// TRACED2 -// ETM Trace Data 2 -// <0x00040005=> Pin PE5 -// <0x00030002=> Pin PD2 -// TRACED3 -// ETM Trace Data 3 -// <0x0002000C=> Pin PC12 -// <0x00040006=> Pin PE6 -// -TraceClk_Pin = 0x00040002; -TraceD0_Pin = 0x00020009; -TraceD1_Pin = 0x0002000A; -TraceD2_Pin = 0x00040005; -TraceD3_Pin = 0x0002000C; - -// Flash Download Options -// Option Byte Loading Launch the Option Byte Loading after a Flash Download by setting the OBL_LAUNCH bit (causes a reset) -// -DoOptionByteLoading = 0x00000000; - -// <<< end of configuration section >>> diff --git a/.cmsis/Trace+NUCLEO-L552ZE-Q@ULINKplus StackCorruption.ctrace.yml b/.cmsis/Trace+NUCLEO-L552ZE-Q@ULINKplus StackCorruption.ctrace.yml deleted file mode 100644 index 2ae192b..0000000 --- a/.cmsis/Trace+NUCLEO-L552ZE-Q@ULINKplus StackCorruption.ctrace.yml +++ /dev/null @@ -1,21 +0,0 @@ -# Watch only the first word of this thread's stack: RTX writes its magic here. -# Resolve the address from the selected ELF; size: 4 excludes the rest of the stack. -ctrace: - setup: - - core: Cortex-M33 - data: - - location: g_stack_corruption_stack - label: StackMagic - access: W - size: 4 - output: PC - itm: - enable: 0x00000000 - pcsampling: - period: 0 - synchronization: - DWT: 16M - sync-on-run: true -# No timestamps, exception events, or other trace sources. pyTS clears the -# previous ITM/DWT configuration before enabling this single data watch. -# Protocol synchronization lets ctrace decode even this very short capture. diff --git a/.cmsis/Trace+STM32F4-DISCO.dbgconf.base@0.0.0 b/.cmsis/Trace+STM32F4-DISCO.dbgconf.base@0.0.0 deleted file mode 100644 index 1df0a1b..0000000 --- a/.cmsis/Trace+STM32F4-DISCO.dbgconf.base@0.0.0 +++ /dev/null @@ -1,48 +0,0 @@ -// File: STM32F405_415_407_417_427_437_429_439.dbgconf -// Version: 1.0.0 -// Note: refer to STM32F405/415 STM32F407/417 STM32F427/437 STM32F429/439 reference manual (RM0090) -// refer to STM32F40x STM32F41x datasheets -// refer to STM32F42x STM32F43x datasheets - -// <<< Use Configuration Wizard in Context Menu >>> - -// Debug MCU configuration register (DBGMCU_CR) -// DBG_STANDBY Debug Standby Mode -// DBG_STOP Debug Stop Mode -// DBG_SLEEP Debug Sleep Mode -// -DbgMCU_CR = 0x00000007; - -// Debug MCU APB1 freeze register (DBGMCU_APB1_FZ) -// Reserved bits must be kept at reset value -// DBG_CAN2_STOP CAN2 stopped when core is halted -// DBG_CAN1_STOP CAN2 stopped when core is halted -// DBG_I2C3_SMBUS_TIMEOUT I2C3 SMBUS timeout mode stopped when core is halted -// DBG_I2C2_SMBUS_TIMEOUT I2C2 SMBUS timeout mode stopped when core is halted -// DBG_I2C1_SMBUS_TIMEOUT I2C1 SMBUS timeout mode stopped when core is halted -// DBG_IWDG_STOP Independent watchdog stopped when core is halted -// DBG_WWDG_STOP Window watchdog stopped when core is halted -// DBG_RTC_STOP RTC stopped when core is halted -// DBG_TIM14_STOP TIM14 counter stopped when core is halted -// DBG_TIM13_STOP TIM13 counter stopped when core is halted -// DBG_TIM12_STOP TIM12 counter stopped when core is halted -// DBG_TIM7_STOP TIM7 counter stopped when core is halted -// DBG_TIM6_STOP TIM6 counter stopped when core is halted -// DBG_TIM5_STOP TIM5 counter stopped when core is halted -// DBG_TIM4_STOP TIM4 counter stopped when core is halted -// DBG_TIM3_STOP TIM3 counter stopped when core is halted -// DBG_TIM2_STOP TIM2 counter stopped when core is halted -// -DbgMCU_APB1_Fz = 0x00000000; - -// Debug MCU APB2 freeze register (DBGMCU_APB2_FZ) -// Reserved bits must be kept at reset value -// DBG_TIM11_STOP TIM11 counter stopped when core is halted -// DBG_TIM10_STOP TIM10 counter stopped when core is halted -// DBG_TIM9_STOP TIM9 counter stopped when core is halted -// DBG_TIM8_STOP TIM8 counter stopped when core is halted -// DBG_TIM1_STOP TIM1 counter stopped when core is halted -// -DbgMCU_APB2_Fz = 0x00000000; - -// <<< end of configuration section >>> \ No newline at end of file diff --git a/.cmsis/Trace+STM32F429I-DISCO.dbgconf.base@0.0.0 b/.cmsis/Trace+STM32F429I-DISCO.dbgconf.base@0.0.0 deleted file mode 100644 index 1df0a1b..0000000 --- a/.cmsis/Trace+STM32F429I-DISCO.dbgconf.base@0.0.0 +++ /dev/null @@ -1,48 +0,0 @@ -// File: STM32F405_415_407_417_427_437_429_439.dbgconf -// Version: 1.0.0 -// Note: refer to STM32F405/415 STM32F407/417 STM32F427/437 STM32F429/439 reference manual (RM0090) -// refer to STM32F40x STM32F41x datasheets -// refer to STM32F42x STM32F43x datasheets - -// <<< Use Configuration Wizard in Context Menu >>> - -// Debug MCU configuration register (DBGMCU_CR) -// DBG_STANDBY Debug Standby Mode -// DBG_STOP Debug Stop Mode -// DBG_SLEEP Debug Sleep Mode -// -DbgMCU_CR = 0x00000007; - -// Debug MCU APB1 freeze register (DBGMCU_APB1_FZ) -// Reserved bits must be kept at reset value -// DBG_CAN2_STOP CAN2 stopped when core is halted -// DBG_CAN1_STOP CAN2 stopped when core is halted -// DBG_I2C3_SMBUS_TIMEOUT I2C3 SMBUS timeout mode stopped when core is halted -// DBG_I2C2_SMBUS_TIMEOUT I2C2 SMBUS timeout mode stopped when core is halted -// DBG_I2C1_SMBUS_TIMEOUT I2C1 SMBUS timeout mode stopped when core is halted -// DBG_IWDG_STOP Independent watchdog stopped when core is halted -// DBG_WWDG_STOP Window watchdog stopped when core is halted -// DBG_RTC_STOP RTC stopped when core is halted -// DBG_TIM14_STOP TIM14 counter stopped when core is halted -// DBG_TIM13_STOP TIM13 counter stopped when core is halted -// DBG_TIM12_STOP TIM12 counter stopped when core is halted -// DBG_TIM7_STOP TIM7 counter stopped when core is halted -// DBG_TIM6_STOP TIM6 counter stopped when core is halted -// DBG_TIM5_STOP TIM5 counter stopped when core is halted -// DBG_TIM4_STOP TIM4 counter stopped when core is halted -// DBG_TIM3_STOP TIM3 counter stopped when core is halted -// DBG_TIM2_STOP TIM2 counter stopped when core is halted -// -DbgMCU_APB1_Fz = 0x00000000; - -// Debug MCU APB2 freeze register (DBGMCU_APB2_FZ) -// Reserved bits must be kept at reset value -// DBG_TIM11_STOP TIM11 counter stopped when core is halted -// DBG_TIM10_STOP TIM10 counter stopped when core is halted -// DBG_TIM9_STOP TIM9 counter stopped when core is halted -// DBG_TIM8_STOP TIM8 counter stopped when core is halted -// DBG_TIM1_STOP TIM1 counter stopped when core is halted -// -DbgMCU_APB2_Fz = 0x00000000; - -// <<< end of configuration section >>> \ No newline at end of file diff --git a/.cmsis/Trace+STM32H7B3I-DK.dbgconf.base@1.1.1 b/.cmsis/Trace+STM32H7B3I-DK.dbgconf.base@1.1.1 deleted file mode 100644 index e30e498..0000000 --- a/.cmsis/Trace+STM32H7B3I-DK.dbgconf.base@1.1.1 +++ /dev/null @@ -1,89 +0,0 @@ -// File: STM32H7A3_7B3_7B0.dbgconf -// Version: 1.1.1 -// Note: refer to STM32H7A3/B3 and STM32H7B0 Value line reference manual (RM0455) -// refer to STM32H753xI STM32H743xI datasheets - -// <<< Use Configuration Wizard in Context Menu >>> - -// DBGMCU configuration register (DBGMCU_CR) -// TRGOEN External trigger output enable -// DBGSTBY_SRD Allow debug in SmartRun domain Standby mode -// DBGSTOP_SRD Allow debug in SmartRun domain Stop mode -// DBGSTBY_CD Allow CPU domain debug in Standby mode -// DBGSTOP_CD Allow CPU domain debug in Stop mode -// DBGSLEEP_CD Allow CPU domain debug in Sleep mode -// -DbgMCU_CR = 0x00000007; - -// DBGMCU APB3 peripheral freeze register (DBGMCU_APB3FZ1) -// Reserved bits must be kept at reset value -// WWDG1 WWDG1 stop in debug -// -DbgMCU_APB3_Fz1 = 0x00000040; - -// DBGMCU APB1L peripheral freeze register (DBGMCU_APB1LFZ1) -// Reserved bits must be kept at reset value -// DBG_I2C3 I2C3 SMBUS timeout stop in debug -// DBG_I2C2 I2C2 SMBUS timeout stop in debug -// DBG_I2C1 I2C1 SMBUS timeout stop in debug -// DBG_LPTIM1 LPTIM1 stop in debug -// DBG_TIM14 TIM14 stop in debug -// DBG_TIM13 TIM13 stop in debug -// DBG_TIM12 TIM12 stop in debug -// DBG_TIM7 TIM7 stop in debug -// DBG_TIM6 TIM6 stop in debug -// DBG_TIM5 TIM5 stop in debug -// DBG_TIM4 TIM4 stop in debug -// DBG_TIM3 TIM3 stop in debug -// DBG_TIM2 TIM2 stop in debug -// -DbgMCU_APB1L_Fz1 = 0x00E003FF; - -// DBGMCU APB2 peripheral freeze register (DBGMCU_APB2FZ1) -// Reserved bits must be kept at reset value -// DBG_TIM17 TIM17 stop in debug -// DBG_TIM16 TIM16 stop in debug -// DBG_TIM15 TIM15 stop in debug -// DBG_TIM8 TIM8 stop in debug -// DBG_TIM1 TIM1 stop in debug -// -DbgMCU_APB2_Fz1 = 0x00070003; - -// DBGMCU APB4 peripheral freeze register (DBGMCU_APB4FZ1) -// Reserved bits must be kept at reset value -// DBG_WDGLSCD LS watchdog for CPU domain stop in debug -// DBG_RTC RTC stop in debug -// DBG_LPTIM3 LPTIM2 stop in debug -// DBG_LPTIM2 LPTIM2 stop in debug -// DBG_I2C4 I2C4 SMBUS timeout stop in debug -// -DbgMCU_APB4_Fz1 = 0x00040680; - -// TPIU Pin Routing (TRACECLK fixed on Pin PE2) -// TRACECLK: Pin PE2 -// TRACED0 -// ETM Trace Data 0 -// <0x00040003=> Pin PE3 -// <0x00020001=> Pin PC1 -// <0x0006000D=> Pin PG13 -// TRACED1 -// ETM Trace Data 1 -// <0x00040004=> Pin PE4 -// <0x00020008=> Pin PC8 -// <0x0006000E=> Pin PG14 -// TRACED2 -// ETM Trace Data 2 -// <0x00040005=> Pin PE5 -// <0x00030002=> Pin PD2 -// TRACED3 -// ETM Trace Data 3 -// <0x00040006=> Pin PE6 -// <0x0002000C=> Pin PC12 -// -TraceClk_Pin = 0x00040002; -TraceD0_Pin = 0x00040003; -TraceD1_Pin = 0x00040004; -TraceD2_Pin = 0x00040005; -TraceD3_Pin = 0x00040006; - -// <<< end of configuration section >>> diff --git a/.gitignore b/.gitignore index 8d17582..4215716 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,8 @@ compile_commands.json # Context headers are regenerated; component configuration is versioned. **/RTE/_*/ +# CMSIS-generated configuration baselines and update copies. +*.base@* *.update@* .vscode/cmsis.json .DS_Store diff --git a/Board/NUCLEO-L552ZE-Q/README.md b/Board/NUCLEO-L552ZE-Q/README.md index e3b43fd..a2a0ca0 100644 --- a/Board/NUCLEO-L552ZE-Q/README.md +++ b/Board/NUCLEO-L552ZE-Q/README.md @@ -11,7 +11,7 @@ with `trustzone: off`. | Linked SRAM | 256 KiB at `0x20000000` | | Main stack | 4 KiB | | Nominal reset clock | 4 MHz MSI | -| Debugger sets | `ULINKplus`, `STLink` (shared `Debug` image); `ULINKplus StackCorruption` (separate build); SWD / 1 Mbaud SWO | +| Debugger sets | `ULINKplus`, `STLink`; same firmware, SWD / 1 Mbaud SWO | The layer follows the [shared board design](../../docs/BOARD_SUPPORT.md#shared-layer-design). DFP sequences provide the PB3 SWO pin/clock setup; no local override is used. @@ -24,11 +24,3 @@ MB1361 uses different connector/jumper names from F756; follow the [L552 wiring table](../../docs/ST_BOARD_BRINGUP.md#nucleo-l552ze-q--mb1361). See [Validation](../../docs/VALIDATION.md) for hardware results and recording limits, and [debugger profiles](../../docs/DEBUG_PROBES.md) for capture setup. - -`ULINKplus StackCorruption` adds a `StackCorruption` thread with a 256-byte stack. -After two seconds it deliberately overwrites the first stack word, RTX's -`0xE25A2EA5` magic, with `0xDEADC0DE`. Its trace profile watches only writes to -that word and emits the writing PC; the normal demo trace sources are disabled. -RTX stack checking then enters its stack-overflow error handler. Select this set, -build and regenerate its trace profile before capture; see the -[stack-corruption workflow](../../docs/TRACE_APP.md#stack-corruption-watch-nucleo-l552ze-q). diff --git a/Common/App/app_main.c b/Common/App/app_main.c index 5ba9db5..57824c1 100644 --- a/Common/App/app_main.c +++ b/Common/App/app_main.c @@ -4,9 +4,6 @@ #include "target.h" #include "dwt_workload.h" #include "trace.h" -#if defined(TRACE_STACK_CORRUPTION) -#include "stack_corruption.h" -#endif enum app_state { APP_STARTING, @@ -119,13 +116,6 @@ int app_main(void) return -1; } -#if defined(TRACE_STACK_CORRUPTION) - if (!stack_corruption_start(2U * tick_hz)) { - g_app_state = APP_ERROR; - return -1; - } -#endif - g_app_state = APP_RUNNING; (void)osKernelStart(); g_app_state = APP_ERROR; diff --git a/Common/Include/stack_corruption.h b/Common/Include/stack_corruption.h deleted file mode 100644 index a4dddc6..0000000 --- a/Common/Include/stack_corruption.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ -#ifndef TRACE_STACK_CORRUPTION_H -#define TRACE_STACK_CORRUPTION_H - -#include -#include - -/* Create the fault-injection thread before starting the RTX kernel. */ -bool stack_corruption_start(uint32_t delay_ticks); - -#endif diff --git a/Common/Workloads/stack_corruption.c b/Common/Workloads/stack_corruption.c deleted file mode 100644 index 1523bb7..0000000 --- a/Common/Workloads/stack_corruption.c +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ -#include "cmsis_compiler.h" -#include "cmsis_os2.h" -#include "rtx_os.h" -#include "stack_corruption.h" - -/* RTX initializes word 0 to osRtxStackMagicWord (0xE25A2EA5). The trace watch - * resolves this symbol to the actual thread stack, not a separate test canary. - */ -__ALIGNED(8) uint32_t g_stack_corruption_stack[64]; - -static osRtxThread_t thread_control_block; -static uint32_t corruption_delay_ticks; - -static void stack_corruption_thread(void *argument) -{ - volatile uint32_t local_words[8]; - (void)argument; - - /* Leave time to inspect the intact RTX stack before the deliberate fault. */ - if (osDelay(corruption_delay_ticks) != osOK) { - osThreadExit(); - } - for (uint32_t i = 0U; i < 8U; ++i) { - local_words[i] = i; - } - - /* Inject an array-underflow write with a deliberately invalid byte offset. - * Integer address arithmetic confines the injected error to the magic word: - * no intermediate writes damage the live frame, saved registers or returns. - * PSP stays within the 256-byte stack, so Cortex-M33 PSPLIM does not fault - * before the watched STR instruction can emit its PC through DWT/SWO. - */ - const uintptr_t local_address = (uintptr_t)&local_words[0]; - const uintptr_t invalid_offset = - local_address - (uintptr_t)&g_stack_corruption_stack[0]; - volatile uint32_t *bad_destination = - (volatile uint32_t *)(local_address - invalid_offset); - *bad_destination = 0xDEADC0DEU; - - /* Keep RTX stack checking enabled. This switch detects the overwritten - * magic and enters the standard osRtxErrorNotify stack-overflow handler. - */ - (void)osDelay(1U); - osThreadExit(); -} - -bool stack_corruption_start(uint32_t delay_ticks) -{ - static const osThreadAttr_t attributes = { - .name = "StackCorruption", - .cb_mem = &thread_control_block, - .cb_size = sizeof(thread_control_block), - .stack_mem = g_stack_corruption_stack, - .stack_size = sizeof(g_stack_corruption_stack), - .priority = osPriorityNormal - }; - - corruption_delay_ticks = delay_ticks; - return osThreadNew(stack_corruption_thread, NULL, &attributes) != NULL; -} diff --git a/Projects/TraceDemo/RTE/CMSIS/RTX_Config.c.base@5.2.0 b/Projects/TraceDemo/RTE/CMSIS/RTX_Config.c.base@5.2.0 deleted file mode 100644 index d21fa0a..0000000 --- a/Projects/TraceDemo/RTE/CMSIS/RTX_Config.c.base@5.2.0 +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2013-2023 Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ----------------------------------------------------------------------------- - * - * $Revision: V5.2.0 - * - * Project: CMSIS-RTOS RTX - * Title: RTX Configuration - * - * ----------------------------------------------------------------------------- - */ - -#include "cmsis_compiler.h" -#include "rtx_os.h" - -// OS Idle Thread -__WEAK __NO_RETURN void osRtxIdleThread (void *argument) { - (void)argument; - - for (;;) {} -} - -// OS Error Callback function -__WEAK uint32_t osRtxErrorNotify (uint32_t code, void *object_id) { - (void)object_id; - - switch (code) { - case osRtxErrorStackOverflow: - // Stack overflow detected for thread (thread_id=object_id) - break; - case osRtxErrorISRQueueOverflow: - // ISR Queue overflow detected when inserting object (object_id) - break; - case osRtxErrorTimerQueueOverflow: - // User Timer Callback Queue overflow detected for timer (timer_id=object_id) - break; - case osRtxErrorClibSpace: - // Standard C/C++ library libspace not available: increase OS_THREAD_LIBSPACE_NUM - break; - case osRtxErrorClibMutex: - // Standard C/C++ library mutex initialization failed - break; - case osRtxErrorSVC: - // Invalid SVC function called (function=object_id) - break; - default: - // Reserved - break; - } - for (;;) {} -//return 0U; -} diff --git a/Projects/TraceDemo/RTE/CMSIS/RTX_Config.h.base@5.6.0 b/Projects/TraceDemo/RTE/CMSIS/RTX_Config.h.base@5.6.0 deleted file mode 100644 index fe0c57b..0000000 --- a/Projects/TraceDemo/RTE/CMSIS/RTX_Config.h.base@5.6.0 +++ /dev/null @@ -1,663 +0,0 @@ -/* - * Copyright (c) 2013-2023 Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ----------------------------------------------------------------------------- - * - * $Revision: V5.6.0 - * - * Project: CMSIS-RTOS RTX - * Title: RTX Configuration definitions - * - * ----------------------------------------------------------------------------- - */ - -#ifndef RTX_CONFIG_H_ -#define RTX_CONFIG_H_ - -#ifdef _RTE_ -#include "RTE_Components.h" -#ifdef RTE_RTX_CONFIG_H -#include RTE_RTX_CONFIG_H -#endif -#endif - -//-------- <<< Use Configuration Wizard in Context Menu >>> -------------------- - -// System Configuration -// ======================= - -// Global Dynamic Memory size [bytes] <0-1073741824:8> -// Defines the combined global dynamic memory size. -// Default: 32768 -#ifndef OS_DYNAMIC_MEM_SIZE -#define OS_DYNAMIC_MEM_SIZE 32768 -#endif - -// Kernel Tick Frequency [Hz] <1-1000000> -// Defines base time unit for delays and timeouts. -// Default: 1000 (1ms tick) -#ifndef OS_TICK_FREQ -#define OS_TICK_FREQ 1000 -#endif - -// Round-Robin Thread switching -// Enables Round-Robin Thread switching. -#ifndef OS_ROBIN_ENABLE -#define OS_ROBIN_ENABLE 1 -#endif - -// Round-Robin Timeout <1-1000> -// Defines how many ticks a thread will execute before a thread switch. -// Default: 5 -#ifndef OS_ROBIN_TIMEOUT -#define OS_ROBIN_TIMEOUT 5 -#endif - -// - -// Safety features (Source variant only) -// Enables FuSa related features. -// Requires RTX Source variant. -// Enables: -// - selected features from this group -// - Thread functions: osThreadProtectPrivileged -#ifndef OS_SAFETY_FEATURES -#define OS_SAFETY_FEATURES 0 -#endif - -// Safety Class -// Threads assigned to lower classes cannot modify higher class threads. -// Enables: -// - Object attributes: osSafetyClass -// - Kernel functions: osKernelProtect, osKernelDestroyClass -// - Thread functions: osThreadGetClass, osThreadSuspendClass, osThreadResumeClass -#ifndef OS_SAFETY_CLASS -#define OS_SAFETY_CLASS 1 -#endif - -// MPU Protected Zone -// Access protection via MPU (Spatial isolation). -// Enables: -// - Thread attributes: osThreadZone -// - Thread functions: osThreadGetZone, osThreadTerminateZone -// - Zone Management: osZoneSetup_Callback -#ifndef OS_EXECUTION_ZONE -#define OS_EXECUTION_ZONE 1 -#endif - -// Thread Watchdog -// Watchdog alerts ensure timing for critical threads (Temporal isolation). -// Enables: -// - Thread functions: osThreadFeedWatchdog -// - Handler functions: osWatchdogAlarm_Handler -#ifndef OS_THREAD_WATCHDOG -#define OS_THREAD_WATCHDOG 1 -#endif - -// Object Pointer checking -// Check object pointer alignment and memory region. -#ifndef OS_OBJ_PTR_CHECK -#define OS_OBJ_PTR_CHECK 0 -#endif - -// SVC Function Pointer checking -// Check SVC function pointer alignment and memory region. -// User needs to define a linker execution region RTX_SVC_VENEERS -// containing input sections: rtx_*.o (.text.os.svc.veneer.*) -#ifndef OS_SVC_PTR_CHECK -#define OS_SVC_PTR_CHECK 0 -#endif - -// - -// ISR FIFO Queue -// <4=> 4 entries <8=> 8 entries <12=> 12 entries <16=> 16 entries -// <24=> 24 entries <32=> 32 entries <48=> 48 entries <64=> 64 entries -// <96=> 96 entries <128=> 128 entries <196=> 196 entries <256=> 256 entries -// RTOS Functions called from ISR store requests to this buffer. -// Default: 16 entries -#ifndef OS_ISR_FIFO_QUEUE -#define OS_ISR_FIFO_QUEUE 16 -#endif - -// Object Memory usage counters -// Enables object memory usage counters (requires RTX source variant). -#ifndef OS_OBJ_MEM_USAGE -#define OS_OBJ_MEM_USAGE 0 -#endif - -// - -// Thread Configuration -// ======================= - -// Object specific Memory allocation -// Enables object specific memory allocation. -#ifndef OS_THREAD_OBJ_MEM -#define OS_THREAD_OBJ_MEM 0 -#endif - -// Number of user Threads <1-1000> -// Defines maximum number of user threads that can be active at the same time. -// Applies to user threads with system provided memory for control blocks. -#ifndef OS_THREAD_NUM -#define OS_THREAD_NUM 1 -#endif - -// Number of user Threads with default Stack size <0-1000> -// Defines maximum number of user threads with default stack size. -// Applies to user threads with zero stack size specified. -#ifndef OS_THREAD_DEF_STACK_NUM -#define OS_THREAD_DEF_STACK_NUM 0 -#endif - -// Total Stack size [bytes] for user Threads with user-provided Stack size <0-1073741824:8> -// Defines the combined stack size for user threads with user-provided stack size. -// Applies to user threads with user-provided stack size and system provided memory for stack. -// Default: 0 -#ifndef OS_THREAD_USER_STACK_SIZE -#define OS_THREAD_USER_STACK_SIZE 0 -#endif - -// - -// Default Thread Stack size [bytes] <96-1073741824:8> -// Defines stack size for threads with zero stack size specified. -// Default: 3072 -#ifndef OS_STACK_SIZE -#define OS_STACK_SIZE 3072 -#endif - -// Idle Thread Stack size [bytes] <72-1073741824:8> -// Defines stack size for Idle thread. -// Default: 512 -#ifndef OS_IDLE_THREAD_STACK_SIZE -#define OS_IDLE_THREAD_STACK_SIZE 512 -#endif - -// Idle Thread TrustZone Module Identifier -// Defines TrustZone Thread Context Management Identifier. -// Applies only to cores with TrustZone technology. -// Default: 0 (not used) -#ifndef OS_IDLE_THREAD_TZ_MOD_ID -#define OS_IDLE_THREAD_TZ_MOD_ID 0 -#endif - -// Idle Thread Safety Class <0-15> -// Defines the Safety Class number. -// Default: 0 -#ifndef OS_IDLE_THREAD_CLASS -#define OS_IDLE_THREAD_CLASS 0 -#endif - -// Idle Thread Zone <0-127> -// Defines Thread Zone. -// Default: 0 -#ifndef OS_IDLE_THREAD_ZONE -#define OS_IDLE_THREAD_ZONE 0 -#endif - -// Stack overrun checking -// Enables stack overrun check at thread switch (requires RTX source variant). -// Enabling this option increases slightly the execution time of a thread switch. -#ifndef OS_STACK_CHECK -#define OS_STACK_CHECK 1 -#endif - -// Stack usage watermark -// Initializes thread stack with watermark pattern for analyzing stack usage. -// Enabling this option increases significantly the execution time of thread creation. -#ifndef OS_STACK_WATERMARK -#define OS_STACK_WATERMARK 0 -#endif - -// Default Processor mode for Thread execution -// <0=> Unprivileged mode -// <1=> Privileged mode -// Default: Unprivileged mode -#ifndef OS_PRIVILEGE_MODE -#define OS_PRIVILEGE_MODE 0 -#endif - -// - -// Timer Configuration -// ====================== - -// Object specific Memory allocation -// Enables object specific memory allocation. -#ifndef OS_TIMER_OBJ_MEM -#define OS_TIMER_OBJ_MEM 0 -#endif - -// Number of Timer objects <1-1000> -// Defines maximum number of objects that can be active at the same time. -// Applies to objects with system provided memory for control blocks. -#ifndef OS_TIMER_NUM -#define OS_TIMER_NUM 1 -#endif - -// - -// Timer Thread Priority -// <8=> Low -// <16=> Below Normal <24=> Normal <32=> Above Normal -// <40=> High -// <48=> Realtime -// Defines priority for timer thread -// Default: High -#ifndef OS_TIMER_THREAD_PRIO -#define OS_TIMER_THREAD_PRIO 40 -#endif - -// Timer Thread Stack size [bytes] <0-1073741824:8> -// Defines stack size for Timer thread. -// May be set to 0 when timers are not used. -// Default: 512 -#ifndef OS_TIMER_THREAD_STACK_SIZE -#define OS_TIMER_THREAD_STACK_SIZE 512 -#endif - -// Timer Thread TrustZone Module Identifier -// Defines TrustZone Thread Context Management Identifier. -// Applies only to cores with TrustZone technology. -// Default: 0 (not used) -#ifndef OS_TIMER_THREAD_TZ_MOD_ID -#define OS_TIMER_THREAD_TZ_MOD_ID 0 -#endif - -// Timer Thread Safety Class <0-15> -// Defines the Safety Class number. -// Default: 0 -#ifndef OS_TIMER_THREAD_CLASS -#define OS_TIMER_THREAD_CLASS 0 -#endif - -// Timer Thread Zone <0-127> -// Defines Thread Zone. -// Default: 0 -#ifndef OS_TIMER_THREAD_ZONE -#define OS_TIMER_THREAD_ZONE 0 -#endif - -// Timer Callback Queue entries <0-256> -// Number of concurrent active timer callback functions. -// May be set to 0 when timers are not used. -// Default: 4 -#ifndef OS_TIMER_CB_QUEUE -#define OS_TIMER_CB_QUEUE 4 -#endif - -// - -// Event Flags Configuration -// ============================ - -// Object specific Memory allocation -// Enables object specific memory allocation. -#ifndef OS_EVFLAGS_OBJ_MEM -#define OS_EVFLAGS_OBJ_MEM 0 -#endif - -// Number of Event Flags objects <1-1000> -// Defines maximum number of objects that can be active at the same time. -// Applies to objects with system provided memory for control blocks. -#ifndef OS_EVFLAGS_NUM -#define OS_EVFLAGS_NUM 1 -#endif - -// - -// - -// Mutex Configuration -// ====================== - -// Object specific Memory allocation -// Enables object specific memory allocation. -#ifndef OS_MUTEX_OBJ_MEM -#define OS_MUTEX_OBJ_MEM 0 -#endif - -// Number of Mutex objects <1-1000> -// Defines maximum number of objects that can be active at the same time. -// Applies to objects with system provided memory for control blocks. -#ifndef OS_MUTEX_NUM -#define OS_MUTEX_NUM 1 -#endif - -// - -// - -// Semaphore Configuration -// ========================== - -// Object specific Memory allocation -// Enables object specific memory allocation. -#ifndef OS_SEMAPHORE_OBJ_MEM -#define OS_SEMAPHORE_OBJ_MEM 0 -#endif - -// Number of Semaphore objects <1-1000> -// Defines maximum number of objects that can be active at the same time. -// Applies to objects with system provided memory for control blocks. -#ifndef OS_SEMAPHORE_NUM -#define OS_SEMAPHORE_NUM 1 -#endif - -// - -// - -// Memory Pool Configuration -// ============================ - -// Object specific Memory allocation -// Enables object specific memory allocation. -#ifndef OS_MEMPOOL_OBJ_MEM -#define OS_MEMPOOL_OBJ_MEM 0 -#endif - -// Number of Memory Pool objects <1-1000> -// Defines maximum number of objects that can be active at the same time. -// Applies to objects with system provided memory for control blocks. -#ifndef OS_MEMPOOL_NUM -#define OS_MEMPOOL_NUM 1 -#endif - -// Data Storage Memory size [bytes] <0-1073741824:8> -// Defines the combined data storage memory size. -// Applies to objects with system provided memory for data storage. -// Default: 0 -#ifndef OS_MEMPOOL_DATA_SIZE -#define OS_MEMPOOL_DATA_SIZE 0 -#endif - -// - -// - -// Message Queue Configuration -// ============================== - -// Object specific Memory allocation -// Enables object specific memory allocation. -#ifndef OS_MSGQUEUE_OBJ_MEM -#define OS_MSGQUEUE_OBJ_MEM 0 -#endif - -// Number of Message Queue objects <1-1000> -// Defines maximum number of objects that can be active at the same time. -// Applies to objects with system provided memory for control blocks. -#ifndef OS_MSGQUEUE_NUM -#define OS_MSGQUEUE_NUM 1 -#endif - -// Data Storage Memory size [bytes] <0-1073741824:8> -// Defines the combined data storage memory size. -// Applies to objects with system provided memory for data storage. -// Default: 0 -#ifndef OS_MSGQUEUE_DATA_SIZE -#define OS_MSGQUEUE_DATA_SIZE 0 -#endif - -// - -// - -// Event Recorder Configuration -// =============================== - -// Global Initialization -// Initialize Event Recorder during 'osKernelInitialize'. -#ifndef OS_EVR_INIT -#define OS_EVR_INIT 0 -#endif - -// Start recording -// Start event recording after initialization. -#ifndef OS_EVR_START -#define OS_EVR_START 1 -#endif - -// Global Event Filter Setup -// Initial recording level applied to all components. -// Error events -// API function call events -// Operation events -// Detailed operation events -// -#ifndef OS_EVR_LEVEL -#define OS_EVR_LEVEL 0x00U -#endif - -// RTOS Event Filter Setup -// Recording levels for RTX components. -// Only applicable if events for the respective component are generated. - -// Memory Management -// Recording level for Memory Management events. -// Error events -// API function call events -// Operation events -// Detailed operation events -// -#ifndef OS_EVR_MEMORY_LEVEL -#define OS_EVR_MEMORY_LEVEL 0x81U -#endif - -// Kernel -// Recording level for Kernel events. -// Error events -// API function call events -// Operation events -// Detailed operation events -// -#ifndef OS_EVR_KERNEL_LEVEL -#define OS_EVR_KERNEL_LEVEL 0x81U -#endif - -// Thread -// Recording level for Thread events. -// Error events -// API function call events -// Operation events -// Detailed operation events -// -#ifndef OS_EVR_THREAD_LEVEL -#define OS_EVR_THREAD_LEVEL 0x85U -#endif - -// Generic Wait -// Recording level for Generic Wait events. -// Error events -// API function call events -// Operation events -// Detailed operation events -// -#ifndef OS_EVR_WAIT_LEVEL -#define OS_EVR_WAIT_LEVEL 0x81U -#endif - -// Thread Flags -// Recording level for Thread Flags events. -// Error events -// API function call events -// Operation events -// Detailed operation events -// -#ifndef OS_EVR_THFLAGS_LEVEL -#define OS_EVR_THFLAGS_LEVEL 0x81U -#endif - -// Event Flags -// Recording level for Event Flags events. -// Error events -// API function call events -// Operation events -// Detailed operation events -// -#ifndef OS_EVR_EVFLAGS_LEVEL -#define OS_EVR_EVFLAGS_LEVEL 0x81U -#endif - -// Timer -// Recording level for Timer events. -// Error events -// API function call events -// Operation events -// Detailed operation events -// -#ifndef OS_EVR_TIMER_LEVEL -#define OS_EVR_TIMER_LEVEL 0x81U -#endif - -// Mutex -// Recording level for Mutex events. -// Error events -// API function call events -// Operation events -// Detailed operation events -// -#ifndef OS_EVR_MUTEX_LEVEL -#define OS_EVR_MUTEX_LEVEL 0x81U -#endif - -// Semaphore -// Recording level for Semaphore events. -// Error events -// API function call events -// Operation events -// Detailed operation events -// -#ifndef OS_EVR_SEMAPHORE_LEVEL -#define OS_EVR_SEMAPHORE_LEVEL 0x81U -#endif - -// Memory Pool -// Recording level for Memory Pool events. -// Error events -// API function call events -// Operation events -// Detailed operation events -// -#ifndef OS_EVR_MEMPOOL_LEVEL -#define OS_EVR_MEMPOOL_LEVEL 0x81U -#endif - -// Message Queue -// Recording level for Message Queue events. -// Error events -// API function call events -// Operation events -// Detailed operation events -// -#ifndef OS_EVR_MSGQUEUE_LEVEL -#define OS_EVR_MSGQUEUE_LEVEL 0x81U -#endif - -// - -// - -// RTOS Event Generation -// Enables event generation for RTX components (requires RTX source variant). - -// Memory Management -// Enables Memory Management event generation. -#ifndef OS_EVR_MEMORY -#define OS_EVR_MEMORY 1 -#endif - -// Kernel -// Enables Kernel event generation. -#ifndef OS_EVR_KERNEL -#define OS_EVR_KERNEL 1 -#endif - -// Thread -// Enables Thread event generation. -#ifndef OS_EVR_THREAD -#define OS_EVR_THREAD 1 -#endif - -// Generic Wait -// Enables Generic Wait event generation. -#ifndef OS_EVR_WAIT -#define OS_EVR_WAIT 1 -#endif - -// Thread Flags -// Enables Thread Flags event generation. -#ifndef OS_EVR_THFLAGS -#define OS_EVR_THFLAGS 1 -#endif - -// Event Flags -// Enables Event Flags event generation. -#ifndef OS_EVR_EVFLAGS -#define OS_EVR_EVFLAGS 1 -#endif - -// Timer -// Enables Timer event generation. -#ifndef OS_EVR_TIMER -#define OS_EVR_TIMER 1 -#endif - -// Mutex -// Enables Mutex event generation. -#ifndef OS_EVR_MUTEX -#define OS_EVR_MUTEX 1 -#endif - -// Semaphore -// Enables Semaphore event generation. -#ifndef OS_EVR_SEMAPHORE -#define OS_EVR_SEMAPHORE 1 -#endif - -// Memory Pool -// Enables Memory Pool event generation. -#ifndef OS_EVR_MEMPOOL -#define OS_EVR_MEMPOOL 1 -#endif - -// Message Queue -// Enables Message Queue event generation. -#ifndef OS_EVR_MSGQUEUE -#define OS_EVR_MSGQUEUE 1 -#endif - -// - -// - -// Number of Threads which use standard C/C++ library libspace -// (when thread specific memory allocation is not used). -#if (OS_THREAD_OBJ_MEM == 0) -#ifndef OS_THREAD_LIBSPACE_NUM -#define OS_THREAD_LIBSPACE_NUM 4 -#endif -#else -#define OS_THREAD_LIBSPACE_NUM OS_THREAD_NUM -#endif - -//------------- <<< end of configuration section >>> --------------------------- - -#endif // RTX_CONFIG_H_ diff --git a/Projects/TraceDemo/TraceDemo.cproject.yml b/Projects/TraceDemo/TraceDemo.cproject.yml index 8563561..5b2d2f0 100644 --- a/Projects/TraceDemo/TraceDemo.cproject.yml +++ b/Projects/TraceDemo/TraceDemo.cproject.yml @@ -26,12 +26,6 @@ project: - file: ../../Common/Workloads/dwt_workload.c - file: ../../Common/Include/dwt_workload.h - - group: Stack Corruption - for-context: .StackCorruption+NUCLEO-L552ZE-Q - files: - - file: ../../Common/Workloads/stack_corruption.c - - file: ../../Common/Include/stack_corruption.h - - group: Trace Output files: - file: ../../Common/Trace/itm_output.c diff --git a/README.md b/README.md index 6b2c7f6..43d5c75 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,6 @@ local board layers, covering Cortex-M4, Cortex-M7 and Cortex-M33. The workload updates sine and deterministic-noise variables every 100 ms for DWT and emits an ITM channel 1 counter every 200 ms. Debugger profiles add PC sampling and timestamps. pyOCD captures SWO; ctrace converts recordings to CSV. -NUCLEO-L552ZE-Q also provides `ULINKplus StackCorruption`: a fourth thread -deliberately overwrites its RTX stack magic word, and a single DWT watch reports -the writing PC over SWO. See the [stack-corruption workflow](docs/TRACE_APP.md#stack-corruption-watch-nucleo-l552ze-q). **Status: experimental SWO demo.** Trace Generation and automatic CSV conversion require the [listed development tool versions](docs/BUILD.md#trace-toolchain). @@ -51,9 +48,8 @@ Missing CMSIS packs are installed by `cbuild --packs` using the pinned dependenc 1. Open this folder in VS Code and activate the build environment described in the [build guide](docs/BUILD.md). 2. Select `Trace.csolution.yml` as the active solution. Open **CMSIS: Manage Solution - Settings**, choose a board and its target set (`ULINKplus`, `STLink`, or the - L552-only `ULINKplus StackCorruption`). Sets use automatic probe selection; - select the intended probe locally when several are connected. Check the + Settings**, choose a board and, where available, the `ULINKplus` or `STLink` set. + Both use automatic probe selection. Check the board README linked above and the [ST board wiring notes](docs/ST_BOARD_BRINGUP.md). 3. Build the selected target. Enable `vscode-cmsis-debugger.enableTraceGenerationView` in local VS Code settings. In the CMSIS Debugger **Trace Generation** view, @@ -64,22 +60,14 @@ Missing CMSIS packs are installed by `cbuild --packs` using the pinned dependenc trigger CSV conversion when new trace data is available. Inspect decoder errors as well as the CSV. See the [trace workflow](docs/TRACE_APP.md). -For an agent-driven stack-magic capture, invoke `Use $trace-stack-magic-corruption-test` with the -intended target set active. The project -[trace-stack-magic-corruption-test skill](.agents/skills/trace-stack-magic-corruption-test/SKILL.md) checks its -trace watch, runs and ends debugging, then creates a Markdown report with one -section per CSV entry, source text and project-relative locations. The CSV remains -unchanged. See the [workflow](docs/TRACE_APP.md#stack-magic-agent-workflow). - Command-line build from an activated tool environment: ```sh cbuild Trace.csolution.yml --active 'STM32F429I-DISCO@STLink' --packs --frozen-packs --update-rte ``` -The regular `ULINKplus` and `STLink` sets share the board's `Debug` image. -`ULINKplus StackCorruption` selects the separate `StackCorruption` build. -Changing boards selects another local board layer. Firmware produces the signals; Pack +Changing the debugger set keeps the same application image for that board. Changing +boards selects another local board layer. Firmware produces the signals; Pack sequences, pyOCD and ctrace configuration own trace initialization. ## Add a board diff --git a/Trace.csolution.yml b/Trace.csolution.yml index 581ed65..356df42 100644 --- a/Trace.csolution.yml +++ b/Trace.csolution.yml @@ -12,11 +12,6 @@ solution: - type: Debug debug: on optimize: none - - type: StackCorruption - debug: on - optimize: none - define: - - TRACE_STACK_CORRUPTION: 1 target-types: - type: MCBSTM32F400 @@ -55,20 +50,6 @@ solution: mode: file input-clock: 4000000 output-clock: 1000000 - - set: ULINKplus StackCorruption - images: - - project-context: TraceDemo.StackCorruption - debugger: - name: ULINKplus@pyOCD - protocol: swd - clock: 10000000 - gdbserver: - - port: 43333 - trace: - - swo-uart: - mode: file - input-clock: 4000000 - output-clock: 1000000 - set: STLink images: - project-context: TraceDemo.Debug @@ -270,6 +251,3 @@ solution: projects: - project: Projects/TraceDemo/TraceDemo.cproject.yml - for-context: - - .Debug - - .StackCorruption+NUCLEO-L552ZE-Q diff --git a/docs/BUILD.md b/docs/BUILD.md index e7cb21b..79c35cd 100644 --- a/docs/BUILD.md +++ b/docs/BUILD.md @@ -44,13 +44,6 @@ The debugger and pyOCD links identify source revisions; pyTS and ctrace link to releases. Together they describe the reference toolchain, not a stable debugger release. -The L552 `StackCorruption` profile was built and tested on hardware with the -installed validation tools: CMSIS Debugger `1.8.1-64-g28c1601`, pyOCD -`0.45.2.dev36+g74e3290d8`, pyTS `0.6.1` and ctrace `0.4.0`. Its short capture -requires `sync-on-run` support in trace generation and runtime setup; compatibility -with the reference versions above has not been established for this profile. -The capture results and remaining limitations are recorded in [Validation](VALIDATION.md#nucleo-l552ze-q-stackcorruption--2026-10-05). - ## Build and select a target ```sh @@ -60,9 +53,6 @@ cbuild Trace.csolution.yml --active MCBSTM32F400 --packs --frozen-packs --update # Select a board and named debugger set. cbuild Trace.csolution.yml --active 'NUCLEO-F756ZG@STLink' --packs --frozen-packs -# Build the L552-only stack-corruption experiment. -cbuild Trace.csolution.yml --active 'NUCLEO-L552ZE-Q@ULINKplus StackCorruption' --packs --frozen-packs - # Build all Debug contexts. cbuild Trace.csolution.yml --context 'TraceDemo.Debug+*' --packs --frozen-packs ``` @@ -70,10 +60,7 @@ cbuild Trace.csolution.yml --context 'TraceDemo.Debug+*' --packs --frozen-packs `--active ` selects an unnamed target set; `--active '@'` selects a named debugger set. It also generates `out/Trace+.cbuild-run.yml` for that selection. `--context` selects the project/build/target context matrix. -The regular `ULINKplus` and `STLink` sets reuse the board's `Debug` image. -`NUCLEO-L552ZE-Q@ULINKplus StackCorruption` selects `TraceDemo.StackCorruption`, -which defines `TRACE_STACK_CORRUPTION=1` and includes the additional thread. -This build context is restricted to L552; see [debugger selection](DEBUG_PROBES.md). +Named sets reuse the same application image; see [debugger selection](DEBUG_PROBES.md). In VS Code, select `Trace.csolution.yml` as the active solution and choose the target/set in **CMSIS: Manage Solution Settings**. The `Board-Layer` variable @@ -81,12 +68,12 @@ selects the matching local layer automatically. ## Generated files and editor setup -ELF, HEX and BIN outputs are in `out/TraceDemo///` -(`Debug` or the L552-only `StackCorruption`); intermediates and +ELF, HEX and BIN outputs are in `out/TraceDemo//Debug/`; intermediates and link maps are under `tmp/`. Build/run descriptions, context-specific RTE headers and `.trace/` runtime profiles are generated. Keep the solution, CProject, layers, -pack lock, `RTX_Config.*` and their `.base@...` originals, `.cmsis/*.dbgconf*` and -source `.cmsis/*.ctrace.yml` profiles under version control. +pack lock, active `RTX_Config.c`/`RTX_Config.h`, `.cmsis/*.dbgconf` and source +`.cmsis/*.ctrace.yml` profiles under version control. Generated `.base@*` and +`.update@*` comparison files are ignored and are not kept in the repository. After a build or trace-profile edit, regenerate the trace runtime configuration from the current ELF as described in the [trace workflow](TRACE_APP.md#configure-and-generate-trace). diff --git a/docs/DEBUG_PROBES.md b/docs/DEBUG_PROBES.md index 11fa4e8..697eec5 100644 --- a/docs/DEBUG_PROBES.md +++ b/docs/DEBUG_PROBES.md @@ -1,10 +1,8 @@ # Debugger selection Debugger target sets in [`Trace.csolution.yml`](../Trace.csolution.yml) select the -probe and, where configured, trace profile. The regular `ULINKplus` and `STLink` -sets use the same board layer and `Debug` application image. L552's -`ULINKplus StackCorruption` selects a separate build and watch-only profile. -Build commands are in [BUILD.md](BUILD.md); measured results are in +probe and trace profile. Both probes use the same board layer and application +image. Build commands are in [BUILD.md](BUILD.md); measured results are in [Validation](VALIDATION.md). ## Configured probes and profiles @@ -14,7 +12,6 @@ All sets use SWD and SWO UART/NRZ file capture at **1 Mbaud**. | Probe | Debugger name | Selection | SWD clock | PC period | | --- | --- | --- | --- | --- | | ULINK+ | `ULINKplus@pyOCD` | Automatic | 10 MHz; MCB uses the tool default | 8192 cycles | -| ULINK+ (L552 StackCorruption) | `ULINKplus@pyOCD` | Automatic | 10 MHz | Disabled | | ST-LINK | `ST-Link@pyOCD` | Automatic | 4 MHz | 16384 cycles | Both probe types use automatic selection without a fixed `probe-id`. @@ -24,7 +21,7 @@ type are connected, select the intended probe before loading an image. | Target | Available target sets | Core / timestamp clock | | --- | --- | --- | | MCBSTM32F400 | `ULINKplus` (unnamed set) | 16 MHz | -| NUCLEO-L552ZE-Q | `ULINKplus`, `STLink`, `ULINKplus StackCorruption` | 4 MHz (no timestamps in StackCorruption) | +| NUCLEO-L552ZE-Q | `ULINKplus`, `STLink` | 4 MHz | | NUCLEO-F756ZG | `ULINKplus`, `STLink` | 16 MHz | | NUCLEO-G474RE | `ULINKplus`, `STLink` | 16 MHz | | STM32F429I-DISCO | `ULINKplus`, `STLink` | 16 MHz | @@ -37,12 +34,9 @@ For the two unnamed sets, select `--active MCBSTM32F400` or `--active STM32H7B3I-DK`, without an `@ULINKplus` suffix. The other boards use named sets, for example `--active NUCLEO-F756ZG@ULINKplus`. -For the regular STM32 `ULINKplus` and `STLink` profiles, only the PC-sampling period differs; +Only the PC-sampling period differs between a board's two trace profiles; ST-LINK uses half the PC sample rate. The common sources and timestamp/sync settings are described in [Trace application](TRACE_APP.md#configuration-ownership). -The L552 `ULINKplus StackCorruption` profile instead enables one write watch on -the additional thread's stack magic word, with `output: PC`; see the -[experiment workflow](TRACE_APP.md#stack-corruption-watch-nucleo-l552ze-q). ## Switch sets diff --git a/docs/DESIGN.md b/docs/DESIGN.md index bdf4796..fbcd12f 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -17,10 +17,6 @@ hardware results and capture limitations are in [Validation](VALIDATION.md). - Run separate sine and deterministic-noise threads at 100 ms and an ITM channel 1 counter thread at 200 ms. Configure two DWT sources, PC sampling and timestamps through the Trace Generation view and `.ctrace.yml`. -- Provide an L552-only `ULINKplus StackCorruption` target set with a fourth, - 256-byte-stack thread that deliberately corrupts its RTX stack magic. Capture - the writing PC through a single DWT watch over SWO, with other trace sources - disabled. - Keep trace initialization in the debugger. Firmware writes the watched variables and makes nonblocking ITM writes; it does not enable or configure the trace path. - Use ULINK+ through pyOCD as the baseline. Provide ST-LINK profiles with a lower @@ -42,8 +38,8 @@ then NUCLEO-F446RE. | Element | Responsibility | | --- | --- | -| `Trace.csolution.yml` | Device-based targets, Debug and L552-only StackCorruption builds, layer selection and debugger sets | -| `Projects/TraceDemo/TraceDemo.cproject.yml` | One application image per selected context; shared sources and CMSIS/RTX components | +| `Trace.csolution.yml` | Device-based targets, Debug build, layer selection and debugger sets | +| `Projects/TraceDemo/TraceDemo.cproject.yml` | One application image per selected board; shared sources and CMSIS/RTX components | | `Board//Board.clayer.yml` | Device header/startup/system selection, board `main()`, target adaptation and linker regions | | `Common/App`, `Common/Workloads`, `Common/Trace` | RTX startup, periodic signal generation and nonblocking ITM output | | `Projects/TraceDemo/RTE/CMSIS` | Shared RTX5 component configuration | @@ -66,11 +62,6 @@ Reset → device SystemInit / C runtime → board main() → target_init() → shared app_main() → RTX5 and the three signal threads ``` -The L552 `StackCorruption` context additionally creates its fault-injection thread. -The normal `Debug` contexts exclude that source and thread. See the -[stack-corruption workflow](TRACE_APP.md#stack-corruption-watch-nucleo-l552ze-q) -for the injected store and watch-only trace profile. - `target_init()` retains the vendor clock baseline and updates `SystemCoreClock`. RTX5/CMSIS OS Tick supply SVC, PendSV and SysTick handling. The Trace application is currently a CProject, not an application clayer. Explicit layer selection and diff --git a/docs/TRACE_APP.md b/docs/TRACE_APP.md index 5346830..c218496 100644 --- a/docs/TRACE_APP.md +++ b/docs/TRACE_APP.md @@ -1,8 +1,6 @@ # Trace application and workflow -All targets use the shared RTX5 workload. L552's `ULINKplus StackCorruption` -adds one fault-injection thread and selects a dedicated trace profile. -See [Validation](VALIDATION.md) +All targets use the shared RTX5 workload. See [Validation](VALIDATION.md) for measured results and remaining limits; [BUILD.md](BUILD.md) covers build and board prerequisites, and [DEBUG_PROBES.md](DEBUG_PROBES.md) covers probe selection. @@ -30,84 +28,13 @@ not console text; `g_app_state` and `g_app_core_clock_hz` support runtime inspec The RTX idle thread spins without `WFE`/`WFI`, so most PC samples can be in idle. PC sampling observes locations periodically; it need not catch each short update function. -## Stack-corruption watch (NUCLEO-L552ZE-Q) - -The `ULINKplus StackCorruption` set selects the `StackCorruption` build with -`TRACE_STACK_CORRUPTION=1`. Only this context includes and creates the fourth -thread, `StackCorruption`, from -[`stack_corruption.c`](../Common/Workloads/stack_corruption.c). -Its 256-byte stack is the aligned `g_stack_corruption_stack[64]` array; RTX writes -its `0xE25A2EA5` magic to the first word at the lowest stack address. - -After a two-second delay the thread fills a small local array, then uses a -deliberately invalid offset from that array to write `0xDEADC0DE` into the magic -word. The injected store uses integer address arithmetic and a volatile pointer -to target that one word while keeping the live stack pointer within its limits. -The next RTX context switch detects the changed magic and enters the existing -`osRtxErrorNotify` stack-overflow loop. This is an intentional terminal error; -restart the session to repeat it. - -The matching -[`ULINKplus StackCorruption` profile](<../.cmsis/Trace+NUCLEO-L552ZE-Q@ULINKplus StackCorruption.ctrace.yml>) -configures a single watch at `g_stack_corruption_stack`, `access: W`, `size: 4`, -`output: PC`. It disables ITM channels and periodic PC sampling, and requests no -timestamps or exception events. DWT synchronization (`16M`, `sync-on-run: true`) -provides the protocol framing needed to decode the short capture. The three -normal workload threads remain present, but their outputs are not selected for -capture. - -1. Select `NUCLEO-L552ZE-Q` / `ULINKplus StackCorruption`, build, and regenerate - the matching trace runtime profile against the `StackCorruption` ELF. -2. Check that the watch resolves to the first stack word and retains `output: PC`. - Start debugging with ULINK+ and run continuously from `main` for at least - three seconds, through the two-second injection delay and into the error - handler. Avoid breakpoints around the store: short breakpoint-to-breakpoint - runs have lost its PC packet at the capture boundary. -3. Pause to convert the pyOCD SWO recording with ctrace. Inspect - `.trace/Trace+NUCLEO-L552ZE-Q@ULINKplus StackCorruption.SWO.csv` for the PC of - the store in `stack_corruption_thread`. - -The watch reports every write to that address. A capture from reset can also -contain PCs from BSS initialization and RTX stack initialization; these are not -corruption events. The profile reports writing PCs rather than stored values; -without timestamps, CSV cycle fields do not measure elapsed time. -The verified continuous run captured both the RTX initialization PC and the -corruption-store PC. See [Validation](VALIDATION.md#nucleo-l552ze-q-stackcorruption--2026-10-05) -for the measured result and remaining pause-boundary limitation. - -## Stack-magic agent workflow - -Invoke `Use $trace-stack-magic-corruption-test` to use the project -[trace-stack-magic-corruption-test skill](../.agents/skills/trace-stack-magic-corruption-test/SKILL.md). -It derives the profile and ELF from the active target set and keeps that -selection. Before running, it checks that the stack-magic watch uses `access: W`, -`size: 4` and `output: PC` and resolves to the intended stack word. - -The skill starts debugging, lets the application run, ends the debug session and -waits for final CSV conversion. Its `report_trace.py` helper uses `addr2line` -with the matching ELF to create `.trace/.SWO.md`, leaving the CSV unchanged. -Every CSV entry gets a section, including entries without a PC. Resolved source -code appears first, followed by `project-relative/file:line`, the original trace -fields and any resolution diagnostics. External Pack paths use `../` relative -to the project root. The agent then reads the surrounding source at the resolved -locations and adds a short explanation per entry, with relevant code context. -It distinguishes initialization from corruption and separates recorded PCs from -values or behavior inferred from the source. - -Original RAW/CSV, an ELF snapshot, a manifest and the Markdown report are retained -under `.trace/captures/stack-magic-*`. At the end, the skill automatically opens -the completed report in VS Code. In a headless environment it keeps the report -and reports that opening was unavailable. Later captures replace the current `.trace/` -CSV, so keep the archived result for comparison. The capture-boundary limitations -above still apply. - ## Configuration ownership In filenames below, `[@]` is omitted for an unnamed target set. | Owner / file | Responsibility | | --- | --- | -| Shared firmware | Periodic variable updates, nonblocking ITM writes and the optional stack-corruption thread. | +| Shared firmware | Periodic variable updates and nonblocking ITM writes. | | `Trace.csolution.yml` | Target set, probe, SWD and SWO transport, input/output clocks. | | `.cmsis/Trace+[@].ctrace.yml` | Editable DWT symbols, ITM channels, PC sampling, timestamps and synchronization. | | `out/Trace+.cbuild-run.yml` | Generated active-set description: image, debugger and Pack sequences. | @@ -119,7 +46,7 @@ clocks, pyOCD supplies standard ITM/TPIU setup in legacy mode, and the generated profile configures sources. Firmware does not configure comparators, enable ITM, or initialize trace pins/path. -The regular demo profiles select both DWT variables with `access: W`, `size: 4`, and +Current profiles select both DWT variables with `access: W`, `size: 4`, and `output: value`; ITM mask `0x00000002`; timestamp prescaler 1; and DWT sync `16M`. Board clocks, SWO rate and per-probe PC periods are listed in [Debugger profiles](DEBUG_PROBES.md#configured-probes-and-profiles). A clock change @@ -130,8 +57,7 @@ requires matching solution transport and profile timestamp settings, then regene This workflow uses the [reference trace-tool versions](BUILD.md#trace-toolchain). Their development status and source/release links are recorded there. -1. Select the target and available set (`ULINKplus`, `STLink`, or L552's - `ULINKplus StackCorruption`) in CMSIS +1. Select the target and, where available, `ULINKplus` or `STLink` in CMSIS **Manage Solution**; [build](BUILD.md) the selected image. 2. Enable `vscode-cmsis-debugger.enableTraceGenerationView` in local VS Code settings. Open **Trace Generation** and review the matching source `.ctrace.yml`. @@ -139,10 +65,8 @@ Their development status and source/release links are recorded there. 3. Run **CMSIS Debugger: Convert *.ctrace.yml to *.ctrace-run.yml** after every build and source-profile change. pyTS uses the active `.cbuild-run.yml` and current ELF; relinking can move variables without changing their names. -4. For the regular demo, check the generated profile resolves both symbols as - signed 32-bit values and includes the intended DWT, ITM, PC, timestamp and - synchronization settings. For StackCorruption, check the single stack-word - watch and its writing-PC output as described above. +4. Check the generated profile resolves both symbols as signed 32-bit values and + includes the intended DWT, ITM, PC, timestamp and synchronization settings. Start the matching debugger configuration and inspect the resulting capture. Equivalent offline generation with the bundled pyTS executable, for example: @@ -167,9 +91,8 @@ is not automatic. Manual decoding uses the matching profile beside the RAW: ``` Inspect decoder errors as well as the CSV; apply the checks in -[Validation](VALIDATION.md#stm32-capture-test-scope). Keep RAW/CSV together for diagnosis. -The [stack-magic agent workflow](#stack-magic-agent-workflow) provides a reusable -capture and Markdown source-report workflow for stack-word PC watches. +[Validation](VALIDATION.md#test-scope). Keep RAW/CSV together for diagnosis. +The project currently has no reusable automated capture/check runner. ## Temporary run-description overrides diff --git a/docs/VALIDATION.md b/docs/VALIDATION.md index 7b51c62..8e666f6 100644 --- a/docs/VALIDATION.md +++ b/docs/VALIDATION.md @@ -3,12 +3,10 @@ Status: **2026-10-08**. Build, Flash loading/readback and RTX5 execution passed on all eight boards: the original six on 2026-09-28, STM32F4-DISCO on 2026-09-29, and NUCLEO-F446RE on 2026-10-01. -The regular demo uses the same image with both debuggers where tested. Board prerequisites +Both debuggers use the same image where tested. Board prerequisites and configuration are in [Board support](BOARD_SUPPORT.md); capture settings and commands are in [Debugger profiles](DEBUG_PROBES.md) and [Trace workflow](TRACE_APP.md). An additional L552 board passed the ST-LINK retest below after TrustZone/RDP recovery. -L552's separate StackCorruption build and its watch-only SWO capture passed the -specific checks recorded below. ## Results @@ -16,7 +14,6 @@ specific checks recorded below. PC range checks, and decoder error/overflow checks. **FAIL** means a capture check failed; **OPEN** means a finding remains unresolved; **—** means untested. A PASS does not establish complete capture from reset or repeatable start/pause/end behavior. -This table covers the regular demo; the StackCorruption experiment has its own scope below. | Board | Controlled SWO: ULINK+ | Controlled SWO: ST-LINK | IDE pause / debug end | | --- | --- | --- | --- | @@ -41,7 +38,7 @@ or decoder exit 0 alone is insufficient. On F429, opening the RAW file before tr setup passes a diagnostic ULINK+ capture; this is not an installed IDE fix. The same ordering still fails initial synchronization on MCB and H7. -## STM32 capture test scope +## Test scope - Controlled captures run for 30 s, then halt the core and drain for 50 ms before stopping. A fixed drain delay does not prove an empty probe queue. @@ -53,106 +50,6 @@ same ordering still fails initial synchronization on MCB and H7. - L552 was tested with hardware TrustZone disabled. Tests use the internal-memory and reset-clock baseline; they do not qualify external memory or other clock setups. -## NUCLEO-L552ZE-Q StackCorruption — 2026-10-05 - -**Build, load/debug, deliberate stack corruption and uninterrupted SWO capture: -PASS.** The dedicated `ULINKplus StackCorruption` set was tested on L552 with -ULINK+ `L39352482A`, a 4 MHz core clock and 1 Mbaud SWO, using the installed -[validation tools](BUILD.md#trace-toolchain). The set uses GDB server port -`43333`; the generated launch configuration left the other board's session on -port `3333` untouched. Installed pyOCD and Pack sources were unchanged. - -pyTS `0.6.1` resolved `g_stack_corruption_stack` to `0x200000F8` and configured -its first four bytes as the sole DWT write watch with PC output -(`COMP0=0x200000F8`, `FUNCTION0=0x835`). ITM channels, periodic PC sampling, -timestamps and exception events were disabled. Protocol synchronization and -`sync-on-run` remained enabled; an offline synthetic test demonstrated that ctrace -otherwise discarded these short PC captures before synchronization. - -Runtime inspection found four application threads plus RTX idle and timer -threads. Before the injected store, the first stack word held RTX's `0xE25A2EA5` -magic and `bad_destination` equalled the stack base. After the store it held -`0xDEADC0DE`. `PSP=0x200001A8` remained 176 bytes above the stack base. The next -context switch reached `osRtxErrorNotify` with stack-overflow code `1` and thread -object `0x200001F8`, matching `thread_control_block`; `CFSR=HFSR=0`. - -Running continuously from `main` for 4.5 seconds and then pausing produced a -34-byte RAW capture and automatic CSV with exactly two DWT PC records: -`0x08003388` from RTX stack initialization and `0x080005B2` from the corruption -store. Symbol lookup placed the latter at `stack_corruption_thread+82`; target -instruction readback confirmed opcode `0x601A` (`STR r2, [r3]`). Independent -decoding with ctrace `0.4.0` exited successfully and reproduced both PCs, with no -other trace records, decoder warnings/errors or overflow records. With timestamps -disabled, CSV cycle fields do not establish timing. - -**Pause-boundary limitation:** an earlier run with breakpoints immediately before -the store and in the error handler omitted the store's PC packet, although the -overwrite and RTX error were confirmed. The installed pyOCD capture path has a -3 ms flush interval and can discard bytes arriving after the RAW file closes; -this is a plausible explanation, not a proven cause of that missing packet. -For this experiment, run continuously through the two-second injection delay and -pause after at least three seconds; avoid breakpoints around the store when -checking trace delivery. Repeatable breakpoint/pause/end capture remains open. - -Local evidence (ignored by Git) is under -`.trace/captures/L552-StackCorruption-20261005/uninterrupted/`, including the -RAW/CSV, profile and independent decoder logs; the earlier breakpoint-driven run -is under the adjacent `stepped/` directory. The regular `ULINKplus`/`Debug` image -also rebuilt successfully after the shared-source changes; symbol lookup found -no `stack_corruption` symbols. Switching back to `StackCorruption` and rebuilding -retained the verified addresses above. A second uninterrupted load/debug run after -that switch reproduced the 34-byte capture and the same two PCs; its automatic -CSV and check results are saved in the adjacent `repeat/` directory. - -The [`trace-stack-magic-corruption-test` skill](../.agents/skills/trace-stack-magic-corruption-test/SKILL.md) -subsequently passed the complete build, trace-generation, load/run/end and CSV -annotation workflow on the same active set. This capture contained 69 RAW bytes -and three DWT writes: BSS clearing at `Reset_Handler` (`0x080006A0`, -`startup_stm32l552xx.s:88`), RTX initialization (`0x08003388`, -`rtx_thread.c:1039`) and corruption (`0x080005B2`, `stack_corruption.c:39`). -`arm-none-eabi-addr2line` resolved all three against the captured ELF. The final -annotation format then put matching, hash-verified source text in `note` and the -project-relative location in `info`. All other CSV cells were preserved, and a -repeated annotation was byte-identical. Original decoder notes are archived. - -The automatic CSV matched an independent ctrace decode with no decoder warnings, -errors or overflows. Original RAW/CSV, ELF, profiles, the capture manifest, -annotated CSV and check results are saved locally under -`.trace/captures/stack-magic-9nrr48yr/`. Isolated helper checks also passed for -stale CSVs, target/input changes, unresolved PCs, changed source text, CSV quoting -and failed symbolization without CSV modification. The debugger separately -reported failed evaluate responses and an adapter read error at session shutdown; -these diagnostics are not a decoder failure and were not investigated further. - -**Skill retest after capture cleanup: PASS.** After the previous `.trace` -captures were deleted, the skill regenerated the runtime profile, built and -loaded the active set, ran through the corruption without breakpoints, and ended -the debug session. Automatic conversion produced a fresh 46-byte RAW and two PC -records (RTX initialization and corruption); no manual conversion fallback was -needed. Independent decoding matched with no decoder warnings/errors. Both PCs -resolved into separate `note` (source text) and `info` (project-relative location) -fields, and repeating annotation was byte-identical. Current evidence is under -`.trace/captures/stack-magic-wbxrgwwb/`; the earlier local capture directories -listed above were removed by that cleanup. The debugger diagnostics above -recurred; the capture and annotation checks passed. - -**Markdown report: PASS (offline).** The revised skill leaves the CSV unchanged -and writes one Markdown section per CSV record. Against the archived original -capture in `stack-magic-wbxrgwwb`, both records produced sections with verified -source text, project-relative locations and original trace fields. The input CSV, -current CSV, ELF and manifest hashes stayed unchanged; a repeated report was -byte-identical. The report and `report-validation.json` are archived beside the -capture. Separate checks covered records without PCs, invalid PCs, inline frames, -decoder notes, Markdown escaping and failure without input/report replacement. -This output-format change did not require another hardware capture. - -A subsequent complete hardware run of the Markdown skill also passed: a fresh -69-byte RAW and automatic CSV contained BSS initialization, RTX initialization -and corruption. All three PCs resolved into three report sections; the CSV hash -remained unchanged after report generation. Independent decoding matched without -warnings/errors, and the debug session ended. Evidence and the archived report -are under `.trace/captures/stack-magic-yk0r6ae8/`. - ## NUCLEO-L552ZE-Q recovery and ST-LINK retest — 2026-09-30 **Build, Flash readback, RTX5 execution and controlled SWO: PASS.** This retest