mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-27 23:41:18 +01:00
dist/tools/PyCortexMDebug: Integrate GDB extension into RIOT
When running
make RIOT_USE_PYCORTEXMDEBUG=1 debug
RIOT will now fetch PyCortexMDebug and instruct GDB to load that
extension on start. If additionally RIOT provides `SVD_VENDOR` and
`SVD_MODEL` to identify the SVD file to load, an
`svd_load $(SVD_VENDOR) $(SVD_CLIENT)` is also passed to GDB.
Co-authored-by: crasbe <crasbe@gmail.com>
Co-authored-by: Ann🐸 <git@annsann.eu>
This commit is contained in:
parent
6ad9cf1ec7
commit
7b474698a8
1
dist/tools/PyCortexMDebug/.gitignore
vendored
Normal file
1
dist/tools/PyCortexMDebug/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/checkout
|
||||
16
dist/tools/PyCortexMDebug/Makefile
vendored
Normal file
16
dist/tools/PyCortexMDebug/Makefile
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
PKG_NAME = PyCortexMDebug
|
||||
PKG_URL = https://github.com/bnahill/PyCortexMDebug
|
||||
PKG_VERSION = ce371500500a9168729f04b9dcad5f84440deadd
|
||||
PKG_LICENSE = GPL-3.0-only
|
||||
|
||||
# manually set some RIOT env vars, so this Makefile can be called stand-alone
|
||||
RIOTBASE ?= $(CURDIR)/../../..
|
||||
RIOTTOOLS ?= $(CURDIR)/..
|
||||
|
||||
PKG_SOURCE_DIR = $(CURDIR)/checkout
|
||||
PKG_BUILD_OUT_OF_SOURCE := 0
|
||||
|
||||
include $(RIOTBASE)/pkg/pkg.mk
|
||||
|
||||
.PHONY: all
|
||||
all: prepare
|
||||
25
dist/tools/PyCortexMDebug/README.md
vendored
Normal file
25
dist/tools/PyCortexMDebug/README.md
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
PyCortexMDebug
|
||||
==============
|
||||
|
||||
This is the RIOT integration of [PyCortexMDebug][], a GDB extension that allows
|
||||
inspecting and interpreting memory of MCUs based on the info provided in SVD
|
||||
files.
|
||||
|
||||
This integration adds PRs 58 and 59 on top of the upstream code. To get the
|
||||
CMSIS database, run:
|
||||
|
||||
```sh
|
||||
wget -O ~/.cache/cmdebug/cmsis-svd-data.zip https://github.com/cmsis-svd/cmsis-svd-data/archive/refs/heads/main.zip
|
||||
```
|
||||
|
||||
Automating Loading of Correct SVD File
|
||||
---------------------------------------
|
||||
|
||||
If `SVD_MODEL` and `SVD_VENDOR` are declared, the build system will inject
|
||||
an `svd_load $(SVD_MODEL) $(SVD_VENDOR)` command into GDB, so that users don't
|
||||
need to call that themselves.
|
||||
|
||||
Ideally, those variables are provided in `cpu/$(CPU)/Makefile.include`
|
||||
by inferring it from the `$(CPU_MODEL)` variable each board already provides.
|
||||
|
||||
[PyCortexMDebug]: https://github.com/bnahill/PyCortexMDebug
|
||||
41
dist/tools/PyCortexMDebug/patches/0001-cmdebug-LoadSVD-Fix-exception-in-complete.patch
vendored
Normal file
41
dist/tools/PyCortexMDebug/patches/0001-cmdebug-LoadSVD-Fix-exception-in-complete.patch
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
From 597434eab992cd3f9495434ed6b990c8c491d66b Mon Sep 17 00:00:00 2001
|
||||
From: Marian Buschsieweke <marian.buschsieweke@posteo.net>
|
||||
Date: Mon, 3 Nov 2025 23:11:09 +0100
|
||||
Subject: [PATCH] cmdebug: LoadSVD(): Fix exception in complete()
|
||||
|
||||
The parameter `word` may actually be `None`, as shown by this
|
||||
exception:
|
||||
|
||||
(gdb) svd_load STraceback (most recent call last):
|
||||
File "/usr/lib/python3.12/site-packages/cmdebug/svd_gdb.py", line 65, in complete
|
||||
prefix = word.lower()
|
||||
^^^^^^^^^^
|
||||
AttributeError: 'NoneType' object has no attribute 'lower'
|
||||
|
||||
This lets prefix fall back to `""` in case word is `None` to fix the
|
||||
issue.
|
||||
---
|
||||
cmdebug/svd_gdb.py | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/cmdebug/svd_gdb.py b/cmdebug/svd_gdb.py
|
||||
index 4fb993b..c6e1e9c 100644
|
||||
--- a/cmdebug/svd_gdb.py
|
||||
+++ b/cmdebug/svd_gdb.py
|
||||
@@ -62,11 +62,11 @@ class LoadSVD(gdb.Command):
|
||||
|
||||
# "svd_load <tab>" or "svd_load ST<tab>"
|
||||
if num_args == 1:
|
||||
- prefix = word.lower()
|
||||
+ prefix = "" if word is None else word.lower()
|
||||
return [vendor for vendor in self.vendors if vendor.lower().startswith(prefix)]
|
||||
# "svd_load STMicro<tab>" or "svd_load STMicro STM32F1<tab>"
|
||||
elif num_args == 2 and args[0] in self.vendors:
|
||||
- prefix = word.lower()
|
||||
+ prefix = "" if word is None else word.lower()
|
||||
filenames = self.vendors[args[0]]
|
||||
return [fname for fname in filenames if fname.lower().startswith(prefix)]
|
||||
return gdb.COMPLETE_NONE
|
||||
--
|
||||
2.51.2
|
||||
|
||||
115
dist/tools/PyCortexMDebug/patches/0002-LoadSVD-Load-SVD-from-ZIP-file-instead-of-pkg_resour.patch
vendored
Normal file
115
dist/tools/PyCortexMDebug/patches/0002-LoadSVD-Load-SVD-from-ZIP-file-instead-of-pkg_resour.patch
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
From 568ef712d68eb70574fbce5808fea63963aa908f Mon Sep 17 00:00:00 2001
|
||||
From: Marian Buschsieweke <marian.buschsieweke@posteo.net>
|
||||
Date: Sun, 9 Nov 2025 12:25:11 +0100
|
||||
Subject: [PATCH] LoadSVD: Load SVD from ZIP file instead of pkg_resources
|
||||
|
||||
This changes the logic with `svd_load <VENDOR> <MODEL>` to not search in
|
||||
the pkg_resources of Python module `cmsis_svd.data` but instead search
|
||||
in a ZIP file at `$CMSIS_SVD_ZIPFILE` if that environment variable is
|
||||
defined, otherwise it looks `$XDG_CACHE_HOME/cmdebug/cmsis-svd-data.zip`
|
||||
with `$XDG_CACHE_HOME` falling back to `~/.cache` if not found in the
|
||||
environment.
|
||||
|
||||
As of 2025-11-09, the `HEAD` of https://github.com/cmsis-svd/cmsis-svd-data
|
||||
is 5.8 GiB in size uncompressed, or 254 MiB when zipped. Personally, I
|
||||
do not perceive any additional latency by having to unzip the chosen
|
||||
SVD file first.
|
||||
---
|
||||
cmdebug/svd_gdb.py | 52 +++++++++++++++++++++++++++++++++++++---------
|
||||
1 file changed, 42 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/cmdebug/svd_gdb.py b/cmdebug/svd_gdb.py
|
||||
index 4fb993b..33c7bec 100644
|
||||
--- a/cmdebug/svd_gdb.py
|
||||
+++ b/cmdebug/svd_gdb.py
|
||||
@@ -16,11 +16,15 @@ along with PyCortexMDebug. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import gdb
|
||||
-import re
|
||||
import math
|
||||
-import sys
|
||||
+import pathlib
|
||||
+import re
|
||||
import struct
|
||||
-import pkg_resources
|
||||
+import sys
|
||||
+import tempfile
|
||||
+import zipfile
|
||||
+
|
||||
+from os import environ
|
||||
|
||||
sys.path.append('.')
|
||||
from cmdebug.svd import SVDFile
|
||||
@@ -31,6 +35,16 @@ BITS_TO_UNPACK_FORMAT = {
|
||||
32: "I",
|
||||
}
|
||||
|
||||
+if "XDG_CACHE_HOME" in environ and environ["XDG_CACHE_HOME"] != "":
|
||||
+ CACHE_DIR = pathlib.Path.joinpath(environ["XDG_CACHE_HOME"], "cmdebug")
|
||||
+else:
|
||||
+ CACHE_DIR = pathlib.Path.joinpath(pathlib.Path.home(), ".cache", "cmdebug")
|
||||
+
|
||||
+if "CMSIS_SVD_ZIPFILE" in environ and environ["CMSIS_SVD_ZIPFILE"] != "":
|
||||
+ CMSIS_SVD_ZIPFILE = pathlib.Path(environ("CMSIS_SVD_ZIPFILE"))
|
||||
+else:
|
||||
+ CMSIS_SVD_ZIPFILE = pathlib.Path.joinpath(CACHE_DIR, "cmsis-svd-data.zip")
|
||||
+
|
||||
|
||||
class LoadSVD(gdb.Command):
|
||||
""" A command to load an SVD file and to create the command for inspecting
|
||||
@@ -40,11 +54,16 @@ class LoadSVD(gdb.Command):
|
||||
def __init__(self):
|
||||
self.vendors = {}
|
||||
try:
|
||||
- vendor_names = pkg_resources.resource_listdir("cmsis_svd", "data")
|
||||
- for vendor in vendor_names:
|
||||
- fnames = pkg_resources.resource_listdir("cmsis_svd", "data/{}".format(vendor))
|
||||
- self.vendors[vendor] = [fname for fname in fnames if fname.lower().endswith(".svd")]
|
||||
- except:
|
||||
+ with zipfile.ZipFile(CMSIS_SVD_ZIPFILE, mode='r') as svdzip:
|
||||
+ for entry in svdzip.namelist():
|
||||
+ if entry.lower().endswith(".svd"):
|
||||
+ p = pathlib.Path(entry)
|
||||
+ vendor = p.parent.name
|
||||
+ model = p.name[:-4]
|
||||
+ if vendor not in self.vendors:
|
||||
+ self.vendors[vendor] = list()
|
||||
+ self.vendors[vendor].append(model)
|
||||
+ except FileNotFoundError:
|
||||
pass
|
||||
|
||||
if len(self.vendors) > 0:
|
||||
@@ -75,14 +94,27 @@ class LoadSVD(gdb.Command):
|
||||
def invoke(args, from_tty):
|
||||
args = gdb.string_to_argv(args)
|
||||
argc = len(args)
|
||||
+ f = None
|
||||
if argc == 1:
|
||||
gdb.write("Loading SVD file {}...\n".format(args[0]))
|
||||
f = args[0]
|
||||
elif argc == 2:
|
||||
gdb.write("Loading SVD file {}/{}...\n".format(args[0], args[1]))
|
||||
- f = pkg_resources.resource_filename("cmsis_svd", "data/{}/{}".format(args[0], args[1]))
|
||||
+ name = args[0].lower() + "/" + args[1].lower() + ".svd"
|
||||
+ try:
|
||||
+ with zipfile.ZipFile(CMSIS_SVD_ZIPFILE, mode='r') as svdzip:
|
||||
+ for entry in svdzip.namelist():
|
||||
+ lower = entry.lower()
|
||||
+ if lower == name or lower.endswith("/" + name):
|
||||
+ f = svdzip.extract(entry, path=tempfile.TemporaryDirectory().name)
|
||||
+ break
|
||||
+ except FileNotFoundError:
|
||||
+ raise gdb.GdbError(f"Could not open \"{CMSIS_SVD_ZIPFILE}\"")
|
||||
+
|
||||
+ if f is None:
|
||||
+ raise gdb.GdbError(f"Could not find SVD for \"{args[0]}/{args[1]}\" in \"{CMSIS_SVD_ZIPFILE}\": No case-insensitive match for \"**/{name}\"")
|
||||
else:
|
||||
- raise gdb.GdbError("Usage: svd_load <vendor> <device.svd> or svd_load <path/to/filename.svd>\n")
|
||||
+ raise gdb.GdbError("Usage: svd_load <vendor> <device> or svd_load <path/to/filename.svd>\n")
|
||||
try:
|
||||
SVD(SVDFile(f))
|
||||
except Exception as e:
|
||||
--
|
||||
2.51.2
|
||||
|
||||
11
makefiles/tools/dbg_common.inc.mk
Normal file
11
makefiles/tools/dbg_common.inc.mk
Normal file
@ -0,0 +1,11 @@
|
||||
# Control whether to use PyCortexMDebug
|
||||
USE_PYCORTEXMDEBUG ?= 0
|
||||
|
||||
ifeq (1,$(USE_PYCORTEXMDEBUG))
|
||||
DEBUGDEPS += $(RIOTTOOLS)/PyCortexMDebug/checkout
|
||||
DBG_EXTRA_FLAGS += --init-command='$(RIOTTOOLS)/PyCortexMDebug/checkout/scripts/gdb.py'
|
||||
|
||||
ifneq (,$(SVD_MODEL))
|
||||
DBG_EXTRA_FLAGS += --eval-command='svd_load $(SVD_VENDOR) $(SVD_MODEL)'
|
||||
endif
|
||||
endif
|
||||
@ -1,3 +1,5 @@
|
||||
include $(RIOTMAKE)/tools/dbg_common.inc.mk
|
||||
|
||||
FLASHER ?= $(RIOTTOOLS)/jlink/jlink.sh
|
||||
DEBUGGER ?= $(RIOTTOOLS)/jlink/jlink.sh
|
||||
DEBUGSERVER ?= $(RIOTTOOLS)/jlink/jlink.sh
|
||||
@ -18,7 +20,8 @@ JLINK_PRE_FLASH ?=
|
||||
JLINK_POST_FLASH ?=
|
||||
|
||||
JLINK_FLASH_TARGETS = flash flash%
|
||||
JLINK_TARGETS = debug% $(JLINK_FLASH_TARGETS) reset term-rtt
|
||||
JLINK_DEBUG_TARGETS = debug debug-server
|
||||
JLINK_TARGETS = $(JLINK_DEBUG_TARGETS) $(JLINK_FLASH_TARGETS) reset term-rtt
|
||||
|
||||
# Export JLINK_SERIAL to required targets
|
||||
$(call target-export-variables,$(JLINK_TARGETS),JLINK_SERIAL)
|
||||
@ -50,3 +53,8 @@ endif
|
||||
ifneq (,$(JLINK_POST_FLASH))
|
||||
$(call target-export-variables,JLINK_FLASH_TARGETS,JLINK_POST_FLASH)
|
||||
endif
|
||||
|
||||
ifneq (,$(DBG_EXTRA_FLAGS))
|
||||
# Export OPENOCD_DBG_EXTRA_CMD only to the flash/flash-only target
|
||||
$(call target-export-variables,$(JLINK_DEBUG_TARGETS),DBG_EXTRA_FLAGS)
|
||||
endif
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
include $(RIOTMAKE)/tools/dbg_common.inc.mk
|
||||
|
||||
FLASHER ?= $(RIOTTOOLS)/openocd/openocd.sh
|
||||
DEBUGGER ?= $(RIOTTOOLS)/openocd/openocd.sh
|
||||
DEBUGSERVER ?= $(RIOTTOOLS)/openocd/openocd.sh
|
||||
@ -78,6 +80,11 @@ ifneq (,$(OPENOCD_DBG_EXTRA_CMD))
|
||||
$(call target-export-variables,$(OPENOCD_DEBUG_TARGETS),OPENOCD_DBG_EXTRA_CMD)
|
||||
endif
|
||||
|
||||
ifneq (,$(DBG_EXTRA_FLAGS))
|
||||
# Export OPENOCD_DBG_EXTRA_CMD only to the flash/flash-only target
|
||||
$(call target-export-variables,$(OPENOCD_DEBUG_TARGETS),DBG_EXTRA_FLAGS)
|
||||
endif
|
||||
|
||||
OPENOCD_FLASH_TARGETS = flash flash-only flashr
|
||||
|
||||
ifneq (,$(IMAGE_OFFSET))
|
||||
|
||||
@ -75,3 +75,8 @@ $(RIOTTOOLS)/pioasm/pioasm: $(RIOTTOOLS)/pioasm/Makefile
|
||||
@echo "[INFO] pioasm not found - fetching it from GitHub now"
|
||||
CC= CFLAGS= $(MAKE) -C $(RIOTTOOLS)/pioasm
|
||||
@echo "[INFO] pioasm successfully fetched!"
|
||||
|
||||
$(RIOTTOOLS)/PyCortexMDebug/checkout: $(RIOTTOOLS)/PyCortexMDebug/Makefile
|
||||
@echo "[INFO] PyCortexMDebug not found - fetching it from GitHub now"
|
||||
CC= CFLAGS= $(MAKE) -C $(RIOTTOOLS)/PyCortexMDebug
|
||||
@echo "[INFO] PyCortexMDebug successfully fetched!"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user