Skip to content

Commit 19fe604

Browse files
mathieuchopstmfabiobaltieri
authored andcommitted
scripts: west_commands: runners: add ST-LINK GDB server
Add the ST-Link GDB server (part of the STM32CubeCLT) as west runner. The STM32CubeCLT is an all-in-one multi-OS command-line toolset, which is part of the STM32Cube ecosystem, and notably includes a GDB server for debugging using ST-Link probes. This runner supports the "attach", "debug" and "debugserver" commands. Documentation: https://www.st.com/en/development-tools/stm32cubeclt.html Signed-off-by: Mathieu Choplain <mathieu.choplain@st.com>
1 parent 0829c2b commit 19fe604

File tree

6 files changed

+265
-26
lines changed

6 files changed

+265
-26
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
board_set_debugger_ifnset(stlink_gdbserver)
4+
board_finalize_runner_args(stlink_gdbserver)

doc/develop/flash_debug/host-tools.rst

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,50 @@ to ``rfp-cli`` when flashing:
525525
526526
west flash --rfp-cli ~/Downloads/RFP_CLI_Linux_V31800_x64/linux-x64/rfp-cli
527527
528+
.. _stm32cubeclt-host-tools:
529+
.. _runner_stlink_gdbserver:
530+
531+
STM32CubeCLT Flash & Debug Host Tools
532+
*************************************
533+
534+
STMicroelectronics provides `STM32CubeCLT`_ as an official all-in-one toolset compatible with
535+
Linux |reg|, macOS |reg| and Windows |reg|, allowing the use of STMicroelectronics proprietary
536+
tools within third-party development environments.
537+
538+
It notably provides a GDB debugging server (the *ST-LINK GDB Server*) that can be used to debug
539+
applications on STM32 boards thanks to on-board or external ST-LINK debug probes.
540+
541+
It is compatible with the following debug probes:
542+
543+
- :ref:`stlink-v21-onboard-debug-probe`
544+
- Standalone `ST-LINK-V2`_, `ST-LINK-V3`_, and `STLINK-V3PWR`_ probes
545+
546+
Install STM32CubeCLT
547+
--------------------
548+
549+
The easiest way to get the ST-LINK GDB Server is to install `STM32CubeCLT`_ from STMicroelectronics' website.
550+
A valid email address is needed to receive the downloading link.
551+
552+
Basic usage
553+
-----------
554+
555+
The ST-Link GDB Server can be used through the ``west attach``, ``west debug`` or ``west debugserver`` commands
556+
to debug Zephyr applications.
557+
558+
.. code-block:: console
559+
560+
west debug --runner stlink_gdbserver
561+
562+
.. note::
563+
564+
The `STM32CubeProgrammer`_ version contained in the `STM32CubeCLT`_ installation can also be used to flash
565+
applications. To do so, the dedicated :ref:`STM32CubeProgrammer runner <runner_stm32cubeprogrammer>` should
566+
be used instead of ``stlink_gdbserver``, as done in the following example:
567+
568+
.. code-block:: console
569+
570+
west flash --runner stm32cubeprogrammer
571+
528572
.. _stm32cubeprog-flash-host-tools:
529573
.. _runner_stm32cubeprogrammer:
530574

@@ -650,12 +694,12 @@ For more about the UF2 format and its tooling, see `USB Flashing Format (UF2)`_.
650694
.. _probe-rs Supported Devices:
651695
https://probe.rs/targets/
652696

653-
.. _STM32CubeProgrammer:
654-
https://www.st.com/en/development-tools/stm32cubeprog.html
655-
656697
.. _STM32CubeCLT:
657698
https://www.st.com/en/development-tools/stm32cubeclt.html
658699

700+
.. _STM32CubeProgrammer:
701+
https://www.st.com/en/development-tools/stm32cubeprog.html
702+
659703
.. _STM32CubeProgrammer User Manual:
660704
https://www.st.com/resource/en/user_manual/um2237-stm32cubeprogrammer-software-description-stmicroelectronics.pdf
661705

doc/develop/flash_debug/probes.rst

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,29 +36,29 @@ with pyOCD or OpenOCD debug host tools, or with J-Link firmware to communicate
3636
with J-Link debug host tools.
3737

3838

39-
+------------------------------------------+---------------------------------------------------------------------------------------------------------+
40-
|| *Debug Probes & Host Tools* | Host Tools |
41-
+| *Compatibility Chart* +--------------------+--------------------+---------------------+--------------------+--------------------+
42-
| | **J-Link Debug** | **OpenOCD** | **pyOCD** | **NXP S32DS** | **NXP LinkServer** |
43-
+----------------+-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+
44-
| | **J-Link External** ||| | | |
45-
| +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+
46-
| | **LPC-Link2 CMSIS-DAP** | | | | ||
47-
| +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+
48-
| | **LPC-Link2 J-Link** || | | | |
49-
| +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+
50-
| | **MCU-Link CMSIS-DAP** | | | | ||
51-
| Debug Probes +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+
52-
| | **MCU-Link J-Link** || | | | |
53-
| +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+
54-
| | **NXP S32 Debug Probe** | | | || |
55-
| +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+
56-
| | **OpenSDA DAPLink** | ||| ||
57-
| +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+
58-
| | **OpenSDA J-Link** || | | | |
59-
| +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+
60-
| | **ST-LINK/V2-1** ||| *some STM32 boards* | | |
61-
+----------------+-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+
39+
+------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------+
40+
|| *Debug Probes & Host Tools* | Host Tools |
41+
+| *Compatibility Chart* +--------------------+--------------------+---------------------+--------------------+--------------------+------------------------+
42+
| | **J-Link Debug** | **OpenOCD** | **pyOCD** | **NXP S32DS** | **NXP LinkServer** | **ST-LINK GDB Server** |
43+
+----------------+-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+------------------------+
44+
| | **J-Link External** ||| | | | |
45+
| +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+------------------------+
46+
| | **LPC-Link2 CMSIS-DAP** | | | | || |
47+
| +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+------------------------+
48+
| | **LPC-Link2 J-Link** || | | | | |
49+
| +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+------------------------+
50+
| | **MCU-Link CMSIS-DAP** | | | | || |
51+
| Debug Probes +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+------------------------+
52+
| | **MCU-Link J-Link** || | | | | |
53+
| +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+------------------------+
54+
| | **NXP S32 Debug Probe** | | | || | |
55+
| +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+------------------------+
56+
| | **OpenSDA DAPLink** | ||| || |
57+
| +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+------------------------+
58+
| | **OpenSDA J-Link** || | | | | |
59+
| +-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+------------------------+
60+
| | **ST-LINK/V2-1** ||| *some STM32 boards* | | ||
61+
+----------------+-------------------------+--------------------+--------------------+---------------------+--------------------+--------------------+------------------------+
6262

6363

6464
Some supported boards in Zephyr do not include an onboard debug probe and
@@ -374,6 +374,7 @@ It is compatible with the following host debug tools:
374374

375375
- :ref:`openocd-debug-host-tools`
376376
- :ref:`jlink-debug-host-tools`
377+
- :ref:`stm32cubeclt-host-tools`
377378

378379
For some STM32 based boards, it is also compatible with:
379380

scripts/west_commands/runners/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def _import_runner_module(runner_name):
5959
'silabs_commander',
6060
'spi_burn',
6161
'spsdk',
62+
'stlink_gdbserver',
6263
'stm32cubeprogrammer',
6364
'stm32flash',
6465
'sy1xx',
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
# Copyright (c) 2025 STMicroelectronics
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
"""
6+
Runner for debugging applications using the ST-LINK GDB server
7+
from STMicroelectronics, provided as part of the STM32CubeCLT.
8+
"""
9+
10+
import argparse
11+
import platform
12+
import re
13+
import shutil
14+
from pathlib import Path
15+
16+
from runners.core import MissingProgram, RunnerCaps, RunnerConfig, ZephyrBinaryRunner
17+
18+
STLINK_GDB_SERVER_DEFAULT_PORT = 61234
19+
20+
21+
class STLinkGDBServerRunner(ZephyrBinaryRunner):
22+
@classmethod
23+
def _get_stm32cubeclt_paths(cls) -> tuple[Path, Path]:
24+
"""
25+
Returns a tuple of two elements of class pathlib.Path:
26+
[0]: path to the ST-LINK_gdbserver executable
27+
[1]: path to the "STM32CubeProgrammer/bin" folder
28+
"""
29+
30+
def find_highest_clt_version(tools_folder: Path) -> Path | None:
31+
if not tools_folder.is_dir():
32+
return None
33+
34+
# List all CubeCLT installations present in tools folder
35+
CUBECLT_FLDR_RE = re.compile(r"stm32cubeclt_([1-9]).(\d+).(\d+)", re.IGNORECASE)
36+
installations: list[tuple[int, Path]] = []
37+
for f in tools_folder.iterdir():
38+
m = CUBECLT_FLDR_RE.match(f.name)
39+
if m is not None:
40+
# Compute a number that can be easily compared
41+
# from the STM32CubeCLT version number
42+
major, minor, revis = int(m[1]), int(m[2]), int(m[3])
43+
ver_num = major * 1000000 + minor * 1000 + revis
44+
installations.append((ver_num, f))
45+
46+
if len(installations) == 0:
47+
return None
48+
49+
# Sort candidates and return the path to the most recent version
50+
most_recent_install = sorted(installations, key=lambda e: e[0], reverse=True)[0]
51+
return most_recent_install[1]
52+
53+
cur_platform = platform.system()
54+
55+
# Attempt to find via shutil.which()
56+
if cur_platform in ["Linux", "Windows"]:
57+
gdbserv = shutil.which("ST-LINK_gdbserver")
58+
cubeprg = shutil.which("STM32_Programmer_CLI")
59+
if gdbserv and cubeprg:
60+
# Return the parent of cubeprg as [1] should be the path
61+
# to the folder containing STM32_Programmer_CLI, not the
62+
# path to the executable itself
63+
return (Path(gdbserv), Path(cubeprg).parent)
64+
65+
# Search in OS-specific paths
66+
search_path: str
67+
tool_suffix = ""
68+
if cur_platform == "Linux":
69+
search_path = "/opt/st/"
70+
elif cur_platform == "Windows":
71+
search_path = "C:\\ST\\"
72+
tool_suffix = ".exe"
73+
elif cur_platform == "Darwin":
74+
search_path = "/opt/ST/"
75+
else:
76+
raise RuntimeError("Unsupported OS")
77+
78+
clt = find_highest_clt_version(Path(search_path))
79+
if clt is None:
80+
raise MissingProgram("ST-LINK_gdbserver (from STM32CubeCLT)")
81+
82+
gdbserver_path = clt / "STLink-gdb-server" / "bin" / f"ST-LINK_gdbserver{tool_suffix}"
83+
cubeprg_bin_path = clt / "STM32CubeProgrammer" / "bin"
84+
85+
return (gdbserver_path, cubeprg_bin_path)
86+
87+
@classmethod
88+
def name(cls) -> str:
89+
return "stlink_gdbserver"
90+
91+
@classmethod
92+
def capabilities(cls) -> RunnerCaps:
93+
return RunnerCaps(commands={"attach", "debug", "debugserver"}, dev_id=True, extload=True)
94+
95+
@classmethod
96+
def extload_help(cls) -> str:
97+
return "External Loader for ST-Link GDB server"
98+
99+
@classmethod
100+
def do_add_parser(cls, parser: argparse.ArgumentParser):
101+
# Expose a subset of the ST-LINK GDB server arguments
102+
parser.add_argument(
103+
"--swd", action='store_true', default=True, help="Enable SWD debug mode"
104+
)
105+
parser.add_argument("--apid", type=int, default=0, help="Target DAP ID")
106+
parser.add_argument(
107+
"--port-number",
108+
type=int,
109+
default=STLINK_GDB_SERVER_DEFAULT_PORT,
110+
help="Port number for GDB client",
111+
)
112+
113+
@classmethod
114+
def do_create(cls, cfg: RunnerConfig, args: argparse.Namespace) -> "STLinkGDBServerRunner":
115+
return STLinkGDBServerRunner(
116+
cfg, args.swd, args.apid, args.dev_id, args.port_number, args.extload
117+
)
118+
119+
def __init__(
120+
self,
121+
cfg: RunnerConfig,
122+
swd: bool,
123+
ap_id: int | None,
124+
stlink_serial: str | None,
125+
gdb_port: int,
126+
external_loader: str | None,
127+
):
128+
super().__init__(cfg)
129+
self.ensure_output('elf')
130+
131+
self._swd = swd
132+
self._gdb_port = gdb_port
133+
self._stlink_serial = stlink_serial
134+
self._ap_id = ap_id
135+
self._external_loader = external_loader
136+
137+
def do_run(self, command: str, **kwargs):
138+
if command in ["attach", "debug", "debugserver"]:
139+
self.do_attach_debug_debugserver(command)
140+
else:
141+
raise ValueError(f"{command} not supported")
142+
143+
def do_attach_debug_debugserver(self, command: str):
144+
# self.ensure_output('elf') is called in constructor
145+
# and validated that self.cfg.elf_file is non-null.
146+
# This assertion is required for the test framework,
147+
# which doesn't have this insight - it should never
148+
# trigger in real-world scenarios.
149+
assert self.cfg.elf_file is not None
150+
elf_path = Path(self.cfg.elf_file).as_posix()
151+
152+
gdb_args = ["-ex", f"target remote :{self._gdb_port}", elf_path]
153+
154+
(gdbserver_path, cubeprg_path) = STLinkGDBServerRunner._get_stm32cubeclt_paths()
155+
gdbserver_cmd = [gdbserver_path.as_posix()]
156+
gdbserver_cmd += ["--stm32cubeprogrammer-path", str(cubeprg_path.absolute())]
157+
gdbserver_cmd += ["--port-number", str(self._gdb_port)]
158+
gdbserver_cmd += ["--apid", str(self._ap_id)]
159+
gdbserver_cmd += ["--halt"]
160+
161+
if self._swd:
162+
gdbserver_cmd.append("--swd")
163+
164+
if command == "attach":
165+
gdbserver_cmd += ["--attach"]
166+
else: # debug/debugserver
167+
gdbserver_cmd += ["--initialize-reset"]
168+
gdb_args += ["-ex", f"load {elf_path}"]
169+
170+
if self._stlink_serial:
171+
gdbserver_cmd += ["--serial-number", self._stlink_serial]
172+
173+
if self._external_loader:
174+
extldr_path = cubeprg_path / "ExternalLoader" / self._external_loader
175+
if not extldr_path.exists():
176+
raise RuntimeError(f"External loader {self._external_loader} does not exist")
177+
gdbserver_cmd += ["--extload", str(extldr_path)]
178+
179+
self.require(gdbserver_cmd[0])
180+
181+
if command == "debugserver":
182+
self.check_call(gdbserver_cmd)
183+
elif self.cfg.gdb is None: # attach/debug
184+
raise RuntimeError("GDB is required for attach/debug")
185+
else: # attach/debug
186+
gdb_cmd = [self.cfg.gdb] + gdb_args
187+
self.require(gdb_cmd[0])
188+
self.run_server_and_client(gdbserver_cmd, gdb_cmd)

scripts/west_commands/tests/test_imports.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def test_runner_imports():
5050
'silabs_commander',
5151
'spi_burn',
5252
'spsdk',
53+
'stlink_gdbserver',
5354
'stm32cubeprogrammer',
5455
'stm32flash',
5556
'sy1xx',

0 commit comments

Comments
 (0)