From eb2748e7b5d4f40c45e85118766b93cf78ba467a Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Mon, 20 Feb 2023 20:04:07 +0100 Subject: [PATCH] [tools] Add ability to coredump from GDB directly By using GDB you can dump all volatile memories including heap and backup memories. This works even without an ELF file in case it is not at hand right away. To find the right ELF file later, the GNU build ID can also be extracted from the firmware. --- ext/adamgreen/catcher.lb | 13 ++++ src/modm/platform/core/cortex/linker.macros | 13 ++-- src/modm/platform/core/cortex/module.lb | 4 +- .../platform/fault/crashcatcher/module.md | 12 ++++ .../resources/ModmConfiguration.cmake.in | 8 +-- tools/build_script_generator/gdbinit | 6 -- tools/build_script_generator/gdbinit.in | 68 +++++++++++++++++++ tools/build_script_generator/make/module.md | 23 +++++++ .../make/resources/Makefile.in | 23 +++++-- tools/build_script_generator/module.lb | 17 +++-- tools/build_script_generator/scons/module.md | 41 +++++++++-- .../scons/resources/build_target.py.in | 4 ++ .../scons/site_tools/bmp.py | 14 ++++ .../scons/site_tools/crashdebug.py | 4 +- .../scons/site_tools/openocd.py | 18 +++++ tools/modm_tools/crashdebug.py | 16 ++--- tools/modm_tools/gdb.md | 32 +++++++-- tools/modm_tools/gdb.py | 2 +- 18 files changed, 262 insertions(+), 56 deletions(-) delete mode 100644 tools/build_script_generator/gdbinit create mode 100644 tools/build_script_generator/gdbinit.in diff --git a/ext/adamgreen/catcher.lb b/ext/adamgreen/catcher.lb index 17dd2c8043..69a6e495d4 100644 --- a/ext/adamgreen/catcher.lb +++ b/ext/adamgreen/catcher.lb @@ -17,9 +17,22 @@ def init(module): CrashCatcher hooks into the ARM Cortex-M HardFault handler and generates a coredump that can be used with CrashDebug for post-mortem debugging. +You must place the `CrashDebug` binary in your path or alternatively set the +environment variable `MODM_CRASHDEBUG_PATH` to point to the enclosing folder: + +```sh +export MODM_CRASHDEBUG_PATH=/path/to/crashdebug/bin +``` - https://github.com/adamgreen/CrashCatcher - https://github.com/adamgreen/CrashDebug + +!!! tip "The debugger can generate coredumps too" + In case you encounter a hardfault while debugging or you simply want to + store the current system state for later analysis or to share with other + developers, you can simply call the `modm_coredump` function in GDB and it + will generate a `coredump.txt` file. Consult your chosen build system module + for additional integration. """ def prepare(module, options): diff --git a/src/modm/platform/core/cortex/linker.macros b/src/modm/platform/core/cortex/linker.macros index 13389a6830..d8ecf7ad8e 100644 --- a/src/modm/platform/core/cortex/linker.macros +++ b/src/modm/platform/core/cortex/linker.macros @@ -193,6 +193,13 @@ MAIN_STACK_SIZE = {{ options[":platform:cortex-m:main_stack_size"] }}; %% macro section_rom(memory) + /* build id directly after vector table */ + .build_id : + { + __build_id = .; + KEEP(*(.note.gnu.build-id)) + } >{{memory}} + /* Read-only sections in {{memory}} */ .text : { @@ -223,12 +230,6 @@ MAIN_STACK_SIZE = {{ options[":platform:cortex-m:main_stack_size"] }}; __assertion_table_end = .; } >{{memory}} - .build_id : - { - __build_id = .; - KEEP(*(.note.gnu.build-id)) - } >{{memory}} - /* We do not call static destructors ever */ /DISCARD/ : { diff --git a/src/modm/platform/core/cortex/module.lb b/src/modm/platform/core/cortex/module.lb index 910e720c27..59c27724df 100644 --- a/src/modm/platform/core/cortex/module.lb +++ b/src/modm/platform/core/cortex/module.lb @@ -56,11 +56,13 @@ def common_vector_table(env): for vector in driver["vector"]: interrupts[int(vector["position"])] = vector["name"] + "_IRQHandler" + highest_irq = max(interrupts.keys()) + 1 properties = { "core": core, + "highest_irq": highest_irq, "vector_table_location": common_vector_table_location(env), "vector_table": interrupts, - "highest_irq": max(interrupts.keys()) + 1, + "vector_table_size": (16 + highest_irq) * 4, } return properties diff --git a/src/modm/platform/fault/crashcatcher/module.md b/src/modm/platform/fault/crashcatcher/module.md index dd9677b5b3..004a5d8048 100644 --- a/src/modm/platform/fault/crashcatcher/module.md +++ b/src/modm/platform/fault/crashcatcher/module.md @@ -121,6 +121,18 @@ int main() ``` +## Coredump via GDB + +In case you encounter a HardFault while debugging and you did not include this +module or if you simply want to store the current system state for later +analysis or to share with other developers, you can simply call the +`modm_coredump` function inside GDB and it will generate a `coredump.txt` file. +Note that this coredump file contains all volatile memories including the heap, +so this method is strongly recommended if you can attach a debugger. + +Consult your chosen build system module for additional integrations. + + ## Using the Fault Report The fault report contains a core dump generated by CrashCatcher and is supposed diff --git a/tools/build_script_generator/cmake/resources/ModmConfiguration.cmake.in b/tools/build_script_generator/cmake/resources/ModmConfiguration.cmake.in index 60e1b4fde2..b1645fefd3 100644 --- a/tools/build_script_generator/cmake/resources/ModmConfiguration.cmake.in +++ b/tools/build_script_generator/cmake/resources/ModmConfiguration.cmake.in @@ -207,21 +207,21 @@ function(modm_targets_create project_name) add_custom_command(TARGET debug USES_TERMINAL COMMAND ${PYTHON3_EXECUTABLE} modm/modm_tools/gdb.py -x modm/gdbinit -x modm/openocd_gdbinit - ${PROJECT_BINARY_DIR}/src/${project_name}.elf --ui=${MODM_DBG_UI} openocd -f modm/openocd.cfg + --elf ${PROJECT_BINARY_DIR}/src/${project_name}.elf --ui=${MODM_DBG_UI} openocd -f modm/openocd.cfg WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) add_custom_target(debug-bmp DEPENDS ${project_name}.elf) add_custom_command(TARGET debug-bmp USES_TERMINAL - COMMAND ${PYTHON3_EXECUTABLE} modm/modm_tools/gdb.py -x modm/gdbinit ${PROJECT_BINARY_DIR}/src/${project_name}.elf + COMMAND ${PYTHON3_EXECUTABLE} modm/modm_tools/gdb.py -x modm/gdbinit --elf ${PROJECT_BINARY_DIR}/src/${project_name}.elf --ui=${MODM_DBG_UI} bmp -p ${MODM_BMP_PORT} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) add_custom_target(debug-coredump DEPENDS ${project_name}.elf) add_custom_command(TARGET debug-coredump USES_TERMINAL - COMMAND ${PYTHON3_EXECUTABLE} modm/modm_tools/gdb.py -x modm/gdbinit ${PROJECT_BINARY_DIR}/src/${project_name}.elf - --ui=${MODM_DBG_UI} crashdebug --binary-path modm/ext/crashcatcher/bins + COMMAND ${PYTHON3_EXECUTABLE} modm/modm_tools/gdb.py -x modm/gdbinit --elf ${PROJECT_BINARY_DIR}/src/${project_name}.elf + --ui=${MODM_DBG_UI} crashdebug WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) add_custom_target(log-itm DEPENDS ${project_name}.elf) diff --git a/tools/build_script_generator/gdbinit b/tools/build_script_generator/gdbinit deleted file mode 100644 index 12e5481ead..0000000000 --- a/tools/build_script_generator/gdbinit +++ /dev/null @@ -1,6 +0,0 @@ -set print pretty -set print asm-demangle on -set mem inaccessible-by-default off -set pagination off -compare-sections -b main diff --git a/tools/build_script_generator/gdbinit.in b/tools/build_script_generator/gdbinit.in new file mode 100644 index 0000000000..1f4d8db302 --- /dev/null +++ b/tools/build_script_generator/gdbinit.in @@ -0,0 +1,68 @@ +# Copyright (c) 2023, Niklas Hauser +# +# This file is part of the modm project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# ----------------------------------------------------------------------------- + +# Do not ask for confirmation when using Ctrl-D or the quit command +define hook-quit + set confirm off +end + +# Create a coredump.txt file in CrashDebug format +define modm_coredump + set pagination off + set style enabled off + set logging file coredump.txt + set logging overwrite on + set logging enabled on + + # Dump all volatile memories +%% for ram in all_rams + set var $ptr = 0x{{ "%08x" % ram.start }} + while $ptr < 0x{{ "%08x" % (ram.start + ram.size) }} + x/4wx $ptr + set var $ptr += 16 + end + +%% endfor + + # Dump all CPU/FPU registers + info all-registers + + set logging enabled off + set logging overwrite off + set logging file gdb.txt + set style enabled on + set pagination on +end + +# Print the modm::build_id() content only from the firmware +define print_build_id + # We want to do a coredump without an ELF file, since you may not have it at + # hand, so we locate it manually: it is the first entry after the vector table + set var $__build_id = 0x08000000 + {{ vector_table_size }} + + # We want to do `__build_id.data[__build_id.namesz]` but `ElfNoteSection_t` + # may not even be in the ELF file, so we need to do this manually + set var $start = (const unsigned char*)$__build_id + 12 + *(const unsigned int*)$__build_id + set var $end = $start + 20 + + # Print the 20 bytes of the signatures as hexadecimal + printf "build_id = " + while $start < $end + printf "%02X", *$start + set var $start += 1 + end + printf "\n" +end + + +set print pretty +set print asm-demangle on +set mem inaccessible-by-default off +compare-sections +b main diff --git a/tools/build_script_generator/make/module.md b/tools/build_script_generator/make/module.md index d52fd83597..ce05573521 100644 --- a/tools/build_script_generator/make/module.md +++ b/tools/build_script_generator/make/module.md @@ -309,6 +309,29 @@ from the `coredump={filepath}` argument. See the `modm:platform:fault` module for details how to receive the coredump data. +#### make coredump + +``` +make coredump +``` + +Launches GDB via OpenOCD and creates a `coredump.txt` file containing all +volatile memories and prints the GNU build ID of the firmware under debug. +Note that this command does not require an ELF file, so it can be used to +coredump any firmware whose ELF file is currently unavailable. +(\* *only ARM Cortex-M targets*) + + +#### make coredump-bmp + +``` +make coredump-bmp +``` + +Creates a coredump via Black Magic Probe. +(\* *only ARM Cortex-M targets*) + + #### make reset ``` diff --git a/tools/build_script_generator/make/resources/Makefile.in b/tools/build_script_generator/make/resources/Makefile.in index 2126321852..161a5eabdf 100644 --- a/tools/build_script_generator/make/resources/Makefile.in +++ b/tools/build_script_generator/make/resources/Makefile.in @@ -139,22 +139,35 @@ ui?=tui debug: build @python3 $(MODM_PATH)/modm_tools/gdb.py $(addprefix -x ,$(MODM_GDBINIT)) \ $(addprefix -x ,$(MODM_OPENOCD_GDBINIT)) \ - $(ELF_FILE) --ui=$(ui) \ + --elf $(ELF_FILE) --ui=$(ui) \ openocd $(addprefix -f ,$(MODM_OPENOCD_CONFIGFILES)) .PHONY: debug-bmp debug-bmp: build @python3 $(MODM_PATH)/modm_tools/gdb.py $(addprefix -x ,$(MODM_GDBINIT)) \ - $(ELF_FILE) --ui=$(ui) \ + --elf $(ELF_FILE) --ui=$(ui) \ bmp -p $(port) coredump?=coredump.txt .PHONY: debug-coredump debug-coredump: build @python3 $(MODM_PATH)/modm_tools/gdb.py $(addprefix -x ,$(MODM_GDBINIT)) \ - $(ELF_FILE) --ui=$(ui) \ - crashdebug --binary-path $(MODM_PATH)/ext/crashcatcher/bins \ - --dump $(coredump) + --elf $(ELF_FILE) --ui=$(ui) \ + crashdebug --dump $(coredump) + +.PHONY: coredump +coredump: + python3 $(MODM_PATH)/modm_tools/gdb.py $(addprefix -x ,$(MODM_GDBINIT)) \ + $(addprefix -x ,$(MODM_OPENOCD_GDBINIT)) \ + -ex "modm_coredump" -ex "print_build_id" -ex "quit" \ + openocd $(addprefix -f ,$(MODM_OPENOCD_CONFIGFILES)) + +.PHONY: coredump-bmp +coredump-bmp: + python3 $(MODM_PATH)/modm_tools/gdb.py $(addprefix -x ,$(MODM_GDBINIT)) \ + $(addprefix -x ,$(MODM_OPENOCD_GDBINIT)) \ + -ex "modm_coredump" -ex "print_build_id" -ex "quit" \ + bmp -p $(port) fcpu?=0 .PHONY: log-itm diff --git a/tools/build_script_generator/module.lb b/tools/build_script_generator/module.lb index 428349a2fe..4153d7387a 100644 --- a/tools/build_script_generator/module.lb +++ b/tools/build_script_generator/module.lb @@ -178,11 +178,6 @@ def build(env): env.collect("gitignore", "modm/src/info_build.c") env.copy("info_build.h") - # Copy crashcatcher binaries - if env.has_module(":crashcatcher"): - env.outbasepath = "modm/ext/crashcatcher" - env.copy(repopath("ext/adamgreen/crashcatcher/CrashDebug/bins/"), "bins/") - # Append common search paths to metadata if env.has_collector(":build:path.openocd"): env.collect(":build:path.openocd", "modm/openocd") @@ -247,16 +242,20 @@ def post_build(env): [env.relcwdoutpath(path) for path in env.collector_values("path.openocd")] env.substitutions["openocd_sources"] = env.collector_values("openocd.source") + linkerscript = env.query(":platform:cortex-m:linkerscript", {}) + all_rams = [m for m in linkerscript.get("memories") if "w" in m["access"]] + env.substitutions["all_rams"] = all_rams + vector_table = env.query(":platform:cortex-m:vector_table", {"vector_table_size": 16*4}) + env.substitutions["vector_table_size"] = vector_table["vector_table_size"] + env.template("gdbinit.in") + has_rtt = env.has_module(":platform:rtt") env.substitutions["has_rtt"] = has_rtt if has_rtt: - main_ram = env.query(":platform:cortex-m:linkerscript", {}) - main_ram = main_ram.get("cont_ram_regions", [{"start": 0x20000000, "size": 4096}])[0] - env.substitutions["main_ram"] = main_ram + env.substitutions["main_ram"] = linkerscript.get("cont_ram_regions", [{"start": 0x20000000, "size": 4096}])[0] env.substitutions["rtt_channels"] = len(env.get(":platform:rtt:buffer.tx", [])) env.template("openocd.cfg.in") env.template("openocd_gdbinit.in") - env.template("gdbinit") # ============================ Option Descriptions ============================ diff --git a/tools/build_script_generator/scons/module.md b/tools/build_script_generator/scons/module.md index 63550794a6..c433e7511f 100644 --- a/tools/build_script_generator/scons/module.md +++ b/tools/build_script_generator/scons/module.md @@ -328,6 +328,17 @@ This is just a convenience wrapper for the debug functionality defined in the program profile=debug` and try `scons debug profile=debug` again. +#### scons debug-remote + +``` +scons debug-remote profile={debug|release} ui={tui|web} [host={ip or hostname}] [firmware={hash or file}] +``` + +Debugs the executable via a remote OpenOCD process running on your own computer +(localhost is default) or somewhere else. +(\* *only ARM Cortex-M targets*) + + #### scons debug-bmp ``` @@ -348,20 +359,38 @@ scons debug-coredump profile={debug|release} ui={tui|web} \ Launches GDB for post-mortem debugging with the firmware identified by the (optional) `firmware={hash or filepath}` argument using the data from the -`coredump={filepath}` argument. +`coredump={filepath}` argument. Note that CrashDebug must be in your path, see +the `modm:crashcatcher` module for details. (\* *only ARM Cortex-M targets*) -See the `modm:platform:fault` module for details how to receive the coredump data. +Use the `scons coredump` method to generate a coredump with a debugger attached, +otherwise see the `modm:platform:fault` module for details how to generate and +receive the coredump data from the device itself. +(\* *only ARM Cortex-M targets*) -#### scons debug-remote +#### scons coredump ``` -scons debug-remote profile={debug|release} ui={tui|web} [host={ip or hostname}] [firmware={hash or file}] +scons coredump ``` -Debugs the executable via a remote OpenOCD process running on your own computer -(localhost is default) or somewhere else. +Launches GDB via OpenOCD and creates a `coredump.txt` file containing all +volatile memories and prints the GNU build ID of the firmware under debug. +Note that this command does not require an ELF file, so it can be used to +coredump any firmware whose ELF file is currently unavailable. +You can use the GNU build ID to find the corresponding ELF file in your +artifact store (see `scons artifact`). +(\* *only ARM Cortex-M targets*) + + +#### scons coredump-bmp + +``` +scons coredump-bmp +``` + +Creates a coredump via Black Magic Probe. (\* *only ARM Cortex-M targets*) diff --git a/tools/build_script_generator/scons/resources/build_target.py.in b/tools/build_script_generator/scons/resources/build_target.py.in index e0425673a2..d08bb6c8cf 100644 --- a/tools/build_script_generator/scons/resources/build_target.py.in +++ b/tools/build_script_generator/scons/resources/build_target.py.in @@ -70,10 +70,14 @@ def build_target(env, sources): # Start only OpenOCD to attach a external (remote) debugger env.Alias("openocd", env.OpenOcd()) + env.Alias("coredump-openocd", env.CoredumpOpenOcd()) + env.Alias("coredump-bmp", env.CoredumpBMP()) + # Default to OpenOCD env.Alias("program", "program-openocd") env.Alias("reset", "reset-openocd") env.Alias("debug", "debug-openocd") + env.Alias("coredump", "coredump-openocd") %% elif core.startswith("avr") env.Alias("program-avrdude", env.ProgramAvrdude(chosen_program)) diff --git a/tools/build_script_generator/scons/site_tools/bmp.py b/tools/build_script_generator/scons/site_tools/bmp.py index c0b459a089..f68f93311f 100644 --- a/tools/build_script_generator/scons/site_tools/bmp.py +++ b/tools/build_script_generator/scons/site_tools/bmp.py @@ -34,6 +34,19 @@ def call_bmp_debug(target, source, env): action = Action(call_bmp_debug, cmdstr="$BMP_DEBUG_COMSTR") return env.AlwaysBuild(env.Alias(alias, source, action)) +# ----------------------------------------------------------------------------- +def black_magic_probe_coredump(env, alias='black_magic_probe_coredump'): + def call_bmp_coredump(target, source, env): + backend = bmp.BlackMagicProbeBackend(port=ARGUMENTS.get("port", "auto")) + commands = map(env.subst, env.Listify(env.get("MODM_GDB_COMMANDS", []))) + commands += ["modm_coredump", "print_build_id", "quit"] + gdb.call(backend=backend, + config=map(env.subst, env.Listify(env.get("MODM_GDBINIT", []))), + commands=commands) + + action = Action(call_bmp_coredump, cmdstr="$BMP_DEBUG_COMSTR") + return env.AlwaysBuild(env.Alias(alias, '', action)) + # ----------------------------------------------------------------------------- def black_magic_probe_reset(env, alias='black_magic_probe_reset'): def call_bmp_reset(target, source, env): @@ -47,6 +60,7 @@ def generate(env, **kw): env.AddMethod(black_magic_probe_program, 'ProgramBMP') env.AddMethod(black_magic_probe_debug, 'DebugBMP') env.AddMethod(black_magic_probe_reset, 'ResetBMP') + env.AddMethod(black_magic_probe_coredump, 'CoredumpBMP') def exists(env): return True diff --git a/tools/build_script_generator/scons/site_tools/crashdebug.py b/tools/build_script_generator/scons/site_tools/crashdebug.py index 8295690881..cf0f697f65 100644 --- a/tools/build_script_generator/scons/site_tools/crashdebug.py +++ b/tools/build_script_generator/scons/site_tools/crashdebug.py @@ -29,9 +29,7 @@ def run_post_mortem_gdb(target, source, env): .format(env["COREDUMP_FILE"])) return 1 - backend = crashdebug.CrashDebugBackend( - binary_path=env.subst("$BASEPATH/modm/ext/crashcatcher/bins"), - coredump=env["COREDUMP_FILE"]) + backend = crashdebug.CrashDebugBackend(coredump=env["COREDUMP_FILE"]) gdb.call(source=source[0].path, backend=backend, ui=ARGUMENTS.get("ui", "tui"), config=map(env.subst, env.Listify(env.get("MODM_GDBINIT", []))), commands=map(env.subst, env.Listify(env.get("MODM_GDB_COMMANDS", [])))) diff --git a/tools/build_script_generator/scons/site_tools/openocd.py b/tools/build_script_generator/scons/site_tools/openocd.py index b68241b8f5..d78f4ae9f7 100644 --- a/tools/build_script_generator/scons/site_tools/openocd.py +++ b/tools/build_script_generator/scons/site_tools/openocd.py @@ -39,6 +39,23 @@ def call_debug_openocd(target, source, env): action = Action(call_debug_openocd, cmdstr="$DEBUG_OPENOCD_COMSTR") return env.AlwaysBuild(env.Alias(alias, source, action)) +# ----------------------------------------------------------------------------- +def coredump_openocd(env, alias="coredump_openocd"): + def call_coredump_openocd(target, source, env): + config_openocd = env.Listify(env.get("MODM_OPENOCD_CONFIGFILES", [])) + config_searchdirs = env.Listify(env.get("MODM_OPENOCD_SEARCHDIRS", [])) + backend = OpenOcdBackend(config=map(env.subst, config_openocd), + search=map(env.subst, config_searchdirs)) + config = env.Listify(env.get("MODM_OPENOCD_GDBINIT", [])) + config += env.Listify(env.get("MODM_GDBINIT", [])) + commands = env.Listify(env.get("MODM_GDB_COMMANDS", [])) + commands += ["modm_coredump", "print_build_id", "quit"] + gdb.call(backend=backend, config=map(env.subst, config), + commands=map(env.subst, commands)) + + action = Action(call_coredump_openocd, cmdstr="$COREDUMP_OPENOCD_COMSTR") + return env.AlwaysBuild(env.Alias(alias, '', action)) + # ----------------------------------------------------------------------------- def program_openocd(env, source, alias="program_openocd"): def call_program_openocd(target, source, env): @@ -77,6 +94,7 @@ def call_run_openocd(target, source, env): def generate(env, **kw): env.AddMethod(program_openocd, "ProgramOpenOcd") env.AddMethod(debug_openocd, "DebugOpenOcd") + env.AddMethod(coredump_openocd, "CoredumpOpenOcd") env.AddMethod(reset_openocd, "ResetOpenOcd") env.AddMethod(run_openocd, "OpenOcd") diff --git a/tools/modm_tools/crashdebug.py b/tools/modm_tools/crashdebug.py index 04a252b4bf..d0844b4c6f 100644 --- a/tools/modm_tools/crashdebug.py +++ b/tools/modm_tools/crashdebug.py @@ -13,15 +13,16 @@ import os, platform class CrashDebugBackend: - def __init__(self, binary_path, coredump): + def __init__(self, coredump, binary_path=None): self.coredump = coredump + if binary_path is None: + binary_path = os.environ.get("MODM_CRASHDEBUG_PATH") - crashdebug = "lin64/CrashDebug" + self.binary = "CrashDebug" if "Windows" in platform.platform(): - crashdebug = "win32/CrashDebug.exe" - elif "Darwin" in platform.system(): - crashdebug = "osx64/CrashDebug" - self.binary = os.path.join(binary_path, crashdebug) + self.binary = "CrashDebug.exe" + if binary_path is not None: + self.binary = os.path.join(binary_path, self.binary) def init(self, elf): init = ["set target-charset ASCII", @@ -41,7 +42,6 @@ def add_subparser(subparser): parser.add_argument( "--binary-path", dest="binary_path", - required=True, help="Folder of CrashDebug Binaries.") parser.add_argument( "--dump", @@ -49,7 +49,7 @@ def add_subparser(subparser): default="coredump.txt", help="Path to coredump file.") def build_backend(args): - return CrashDebugBackend(args.binary_path, args.coredump) + return CrashDebugBackend(args.coredump, args.binary_path) parser.set_defaults(backend=build_backend) return parser diff --git a/tools/modm_tools/gdb.md b/tools/modm_tools/gdb.md index 447447d973..0d2f5f1b7f 100644 --- a/tools/modm_tools/gdb.md +++ b/tools/modm_tools/gdb.md @@ -8,7 +8,7 @@ The tool can be called from the command line. Here is a typical use-case using the openocd backend with the common configuration files: ```sh -python3 modm/modm_tools/gdb.py path/to/project.elf --ui=tui \ +python3 --elf modm/modm_tools/gdb.py path/to/project.elf --ui=tui \ -x modm/gdbinit -x modm/openocd_gdbinit \ openocd -f modm/openocd.cfg ``` @@ -32,20 +32,26 @@ remote backend with the `--host={ip or hostname}` via the command line: ```sh # Extended-Remote running remotely -python3 modm/modm_tools/gdb.py path/to/project.elf -x modm/gdbinit --ui=tui \ +python3 --elf modm/modm_tools/gdb.py path/to/project.elf -x modm/gdbinit --ui=tui \ remote --host 123.45.67.89 ``` -Note that you can use different programmer backends to GDB: +Note that you can use different programmer backends to GDB, for example the +Black Magic Probe: ```sh # Black Magic Probe -python3 modm/modm_tools/gdb.py path/to/project.elf -x modm/gdbinit --ui=tui \ +python3 --elf modm/modm_tools/gdb.py path/to/project.elf -x modm/gdbinit --ui=tui \ bmp --port /dev/tty.usbserial-123 +``` + +To analyze a core dump, you can use the `CrashDebug` GDB backend. +See the `modm:crashcatcher` module for details. -# CrashDebug for Post-Mortem debugging -python3 modm/modm_tools/gdb.py path/to/project.elf -x modm/gdbinit --ui=tui \ - crashdebug --binary-path modm/ext/crashcatcher/bins --dump coredump.txt +```sh +# Using CrashDebug for Post-Mortem debugging +python3 --elf modm/modm_tools/gdb.py path/to/project.elf -x modm/gdbinit --ui=tui \ + crashdebug --dump coredump.txt ``` (\* *only ARM Cortex-M targets*) @@ -98,3 +104,15 @@ IDE-independent debugging solution. ![](https://github.com/cs01/gdbgui/raw/master/screenshots/gdbgui_animation.gif) [gdbgui]: https://www.gdbgui.com + + +#### Configuration + +modm configures GDB using the generated `modm/gdbinit` file which provides +these convenience methods: + +- `restart`: Resets the device and halts. +- `rerun`: Resets the device and continues. +- `modm_coredump`: Dumps all volatile memories into a `coredump.txt` file. + See the `modm:platform:fault` module for details. +- `print_build_id`: Finds and prints the GNU build id of the firmware. diff --git a/tools/modm_tools/gdb.py b/tools/modm_tools/gdb.py index acbf28875a..1a15c767bc 100644 --- a/tools/modm_tools/gdb.py +++ b/tools/modm_tools/gdb.py @@ -85,8 +85,8 @@ def build_backend(args): parser = argparse.ArgumentParser(description='Run GDB in TUI or GUI mode') parser.add_argument( + "--elf", dest="source", - metavar="ELF", help="The ELF files to use for debugging.") parser.add_argument( "--ui",