pyGdbToolkit 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyGdbToolkit/__init__.py +55 -0
- pyGdbToolkit/arch/__init__.py +79 -0
- pyGdbToolkit/arch/arm/__init__.py +17 -0
- pyGdbToolkit/arch/arm/coresight.py +427 -0
- pyGdbToolkit/arch/arm/cortex_m.py +504 -0
- pyGdbToolkit/arch/arm/fault.py +629 -0
- pyGdbToolkit/arch/arm/models.py +60 -0
- pyGdbToolkit/arch/arm/mpu.py +556 -0
- pyGdbToolkit/arch/arm/probe.py +10 -0
- pyGdbToolkit/arch/arm/providers/__init__.py +16 -0
- pyGdbToolkit/arch/arm/providers/base.py +77 -0
- pyGdbToolkit/arch/arm/providers/manufacturers/__init__.py +4 -0
- pyGdbToolkit/arch/arm/providers/manufacturers/stm32.py +680 -0
- pyGdbToolkit/arch/arm/sau.py +253 -0
- pyGdbToolkit/arch/arm/security.py +816 -0
- pyGdbToolkit/arch/arm/session_state.py +96 -0
- pyGdbToolkit/arch/arm/target.py +32 -0
- pyGdbToolkit/arch/base.py +143 -0
- pyGdbToolkit/arch/diagnostics.py +300 -0
- pyGdbToolkit/arch/registry.py +43 -0
- pyGdbToolkit/cmd_faultinfo.py +99 -0
- pyGdbToolkit/cmd_lscpu.py +116 -0
- pyGdbToolkit/cmd_profile.py +1402 -0
- pyGdbToolkit/cmd_rtos.py +298 -0
- pyGdbToolkit/cmd_secscan.py +466 -0
- pyGdbToolkit/cmd_svd.py +1208 -0
- pyGdbToolkit/diagnostic_runtime.py +52 -0
- pyGdbToolkit/rtos/__init__.py +8 -0
- pyGdbToolkit/rtos/camelot.py +513 -0
- pyGdbToolkit/session.py +233 -0
- pyGdbToolkit/svd.py +1194 -0
- pyGdbToolkit/target_memory.py +190 -0
- pygdbtoolkit-0.1.0.dist-info/METADATA +586 -0
- pygdbtoolkit-0.1.0.dist-info/RECORD +36 -0
- pygdbtoolkit-0.1.0.dist-info/WHEEL +5 -0
- pygdbtoolkit-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 H2Lab Development Team
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
"""The architecture-neutral ``fault_info`` GDB command entry point."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import gdb
|
|
9
|
+
from rich import box
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.panel import Panel
|
|
12
|
+
from rich.table import Table
|
|
13
|
+
|
|
14
|
+
from .arch import (
|
|
15
|
+
DiagnosticPanel,
|
|
16
|
+
DiagnosticReport,
|
|
17
|
+
DiagnosticServiceName,
|
|
18
|
+
DiagnosticTable,
|
|
19
|
+
)
|
|
20
|
+
from .diagnostic_runtime import gdb_diagnostic_access
|
|
21
|
+
from .session import SESSION, ToolkitSession
|
|
22
|
+
from .target_memory import TargetReadError
|
|
23
|
+
|
|
24
|
+
CONSOLE = Console(force_terminal=True)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def run_fault_analysis(
|
|
28
|
+
session: ToolkitSession = SESSION,
|
|
29
|
+
) -> DiagnosticReport:
|
|
30
|
+
"""Run the registered fault-analysis service against the selected target.
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
session : ToolkitSession
|
|
35
|
+
Unified session providing target access and the portable diagnostic runtime.
|
|
36
|
+
|
|
37
|
+
Returns
|
|
38
|
+
-------
|
|
39
|
+
DiagnosticReport
|
|
40
|
+
Renderer-independent diagnostic report returned by the selected service.
|
|
41
|
+
|
|
42
|
+
Raises
|
|
43
|
+
------
|
|
44
|
+
gdb.GdbError
|
|
45
|
+
If target access fails or no service supports the selected target.
|
|
46
|
+
"""
|
|
47
|
+
try:
|
|
48
|
+
result = session.diagnose(
|
|
49
|
+
DiagnosticServiceName.FAULT_ANALYSIS,
|
|
50
|
+
gdb_diagnostic_access(),
|
|
51
|
+
)
|
|
52
|
+
except TargetReadError as error:
|
|
53
|
+
raise gdb.GdbError(str(error)) from error
|
|
54
|
+
if result.report is not None:
|
|
55
|
+
return result.report
|
|
56
|
+
if result.access_error:
|
|
57
|
+
raise gdb.GdbError(result.unavailable_reason or "target unavailable")
|
|
58
|
+
raise gdb.GdbError("fault_info only supports ARM Cortex-M targets")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def render_report(report: DiagnosticReport) -> None:
|
|
62
|
+
"""Render a generic diagnostic report through the shared Rich console."""
|
|
63
|
+
blocks = report.blocks or (*report.tables, *report.panels)
|
|
64
|
+
for block in blocks:
|
|
65
|
+
if isinstance(block, DiagnosticTable):
|
|
66
|
+
table = Table(
|
|
67
|
+
title=block.title,
|
|
68
|
+
box=box.SIMPLE_HEAVY,
|
|
69
|
+
header_style="bold cyan",
|
|
70
|
+
show_header=True,
|
|
71
|
+
)
|
|
72
|
+
for column in block.columns:
|
|
73
|
+
table.add_column(column, style="bold" if column in {"Property", "Register"} else "")
|
|
74
|
+
for row in block.rows:
|
|
75
|
+
table.add_row(*("" if value is None else str(value) for value in row.values))
|
|
76
|
+
CONSOLE.print(table)
|
|
77
|
+
elif isinstance(block, DiagnosticPanel):
|
|
78
|
+
CONSOLE.print(
|
|
79
|
+
Panel(
|
|
80
|
+
"\n".join(block.lines),
|
|
81
|
+
title=f"[bold yellow]{block.title}[/bold yellow]",
|
|
82
|
+
box=box.SIMPLE_HEAVY,
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class FaultInfoCmd(gdb.Command):
|
|
88
|
+
"""Run portable fault analysis and render the returned diagnostic report."""
|
|
89
|
+
|
|
90
|
+
def __init__(self) -> None:
|
|
91
|
+
"""Register the command with GDB."""
|
|
92
|
+
super().__init__("fault_info", gdb.COMMAND_USER)
|
|
93
|
+
|
|
94
|
+
def invoke(self, arg: str, from_tty: bool) -> None:
|
|
95
|
+
"""Execute ``fault_info`` without command-line arguments."""
|
|
96
|
+
del from_tty
|
|
97
|
+
if arg.strip():
|
|
98
|
+
raise gdb.GdbError("fault_info does not accept arguments")
|
|
99
|
+
render_report(run_fault_analysis())
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 H2Lab Development Team
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
"""The ``lscpu`` GDB command for Cortex-M targets."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import gdb
|
|
9
|
+
from rich import box
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.table import Table
|
|
12
|
+
from rich.text import Text
|
|
13
|
+
|
|
14
|
+
from .arch.arm.coresight import RomTableDiscovery
|
|
15
|
+
from .arch.arm.models import DeviceReport, FieldValue
|
|
16
|
+
from .arch.arm.session_state import device_report
|
|
17
|
+
from .target_memory import TargetReadError
|
|
18
|
+
|
|
19
|
+
CONSOLE = Console(force_terminal=True)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class LscpuCmd(gdb.Command):
|
|
23
|
+
"""Display CPU and electronic-signature information for a Cortex-M target."""
|
|
24
|
+
|
|
25
|
+
def __init__(self) -> None:
|
|
26
|
+
"""Register the command with GDB."""
|
|
27
|
+
super().__init__("lscpu", gdb.COMMAND_USER)
|
|
28
|
+
|
|
29
|
+
def invoke(self, arg: str, from_tty: bool) -> None:
|
|
30
|
+
"""Run the command.
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
arg
|
|
35
|
+
The user-supplied argument string. This command accepts no arguments.
|
|
36
|
+
from_tty
|
|
37
|
+
Whether GDB invoked the command from its terminal.
|
|
38
|
+
|
|
39
|
+
Raises
|
|
40
|
+
------
|
|
41
|
+
gdb.GdbError
|
|
42
|
+
If arguments are supplied or the target CPUID cannot be read.
|
|
43
|
+
"""
|
|
44
|
+
del from_tty
|
|
45
|
+
if arg.strip():
|
|
46
|
+
raise gdb.GdbError("lscpu does not accept arguments")
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
report = device_report()
|
|
50
|
+
except TargetReadError as error:
|
|
51
|
+
raise gdb.GdbError(str(error)) from error
|
|
52
|
+
|
|
53
|
+
render_report(report)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def render_report(report: DeviceReport) -> None:
|
|
57
|
+
"""Render a stable device report through the shared Rich console.
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
report
|
|
62
|
+
Decoded CPU and device information.
|
|
63
|
+
"""
|
|
64
|
+
table = Table(
|
|
65
|
+
title="Cortex-M CPU report",
|
|
66
|
+
box=box.SIMPLE_HEAVY,
|
|
67
|
+
header_style="bold cyan",
|
|
68
|
+
show_header=True,
|
|
69
|
+
)
|
|
70
|
+
table.add_column("Property", style="bold", no_wrap=True)
|
|
71
|
+
table.add_column("Value")
|
|
72
|
+
table.add_row("Core type", report.target.core_name)
|
|
73
|
+
table.add_row("Core revision", report.target.rnp_revision)
|
|
74
|
+
table.add_row("Implementer", report.target.implementer_name)
|
|
75
|
+
table.add_row(
|
|
76
|
+
"MCU ROM JEP106 identity",
|
|
77
|
+
_field_text(_rom_jep106_field(report.discovery.mcu_rom)),
|
|
78
|
+
)
|
|
79
|
+
table.add_row("Vendor", report.vendor)
|
|
80
|
+
table.add_row("Product line", _field_text(report.product_line))
|
|
81
|
+
table.add_row("Part number", _field_text(report.part_number))
|
|
82
|
+
table.add_row("RAM", _field_text(report.ram))
|
|
83
|
+
table.add_row("Flash", _field_text(report.flash))
|
|
84
|
+
table.add_row("Package type", _field_text(report.package))
|
|
85
|
+
table.add_row("Serial number", _field_text(report.serial_number))
|
|
86
|
+
CONSOLE.print(table)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _field_text(field: FieldValue) -> Text:
|
|
90
|
+
"""Create a Rich value cell with a visible unavailable-state reason.
|
|
91
|
+
|
|
92
|
+
Parameters
|
|
93
|
+
----------
|
|
94
|
+
field
|
|
95
|
+
A ``FieldValue`` supplied by the report model.
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
Text
|
|
100
|
+
The formatted field cell.
|
|
101
|
+
"""
|
|
102
|
+
display = field.display()
|
|
103
|
+
if field.is_available:
|
|
104
|
+
return Text(display)
|
|
105
|
+
return Text.assemble(("Unavailable: ", "yellow"), display.removeprefix("Unavailable: "))
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _rom_jep106_field(discovery: RomTableDiscovery) -> FieldValue:
|
|
109
|
+
"""Format a table root's validated JEP106 identity when it is available."""
|
|
110
|
+
if discovery.table is None:
|
|
111
|
+
assert discovery.unavailable_reason is not None
|
|
112
|
+
return FieldValue.unavailable(discovery.unavailable_reason)
|
|
113
|
+
identity = discovery.table.identity.peripheral_id.jep106
|
|
114
|
+
if identity is None:
|
|
115
|
+
return FieldValue.unavailable("ROM-table root does not advertise a JEDEC manufacturer")
|
|
116
|
+
return FieldValue.known(identity.display())
|