From b5c5e4b850d431707167f31423ac5a320c3719b1 Mon Sep 17 00:00:00 2001 From: wangmingrong1 Date: Thu, 29 Aug 2024 19:30:33 +0800 Subject: [PATCH] gdb plugin: Encapsulate the gdb native command gcore as nxgcore Modify elf with nxgcore and call gcore: (gdb) nxgcore --help usage: [-h] [-o OUTPUT] [-t OBJCOPY] [-r MEMRANGE] options: -h, --help show this help message and exit -o OUTPUT, --output OUTPUT Gcore output file -t OBJCOPY, --objcopy OBJCOPY Select the appropriate architecture for the objcopy tool -r MEMRANGE, --memrange MEMRANGE examples: (gdb) nxgcore -t arm-none-eabi-objcopy -r 0x40200000,0x48000000,0x07 Signed-off-by: wangmingrong1 --- Documentation/quickstart/debugging.rst | 29 +++--- tools/gdb/gcore.py | 129 +++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 11 deletions(-) create mode 100644 tools/gdb/gcore.py diff --git a/Documentation/quickstart/debugging.rst b/Documentation/quickstart/debugging.rst index d9bc13d3a8..53444449c9 100644 --- a/Documentation/quickstart/debugging.rst +++ b/Documentation/quickstart/debugging.rst @@ -86,7 +86,7 @@ To halt the board: .. code-block:: (gdb) mon halt - + To set a breakpoint: .. code-block:: @@ -104,7 +104,7 @@ and to finally start nuttx: 208 sched_getparam(0, ¶m); (gdb) continue Continuing. - + .. tip:: You can abbreviate ``gdb`` commands: ``info b`` is a shortcut for @@ -130,8 +130,8 @@ opencd. By default, it assumes: * ``CONFIG_DISABLE_MQUEUE=y`` * ``CONFIG_LEGACY_PAGING=n`` - -If you need these options to be set differently, you will have to edit ``./src/rtos/nuttx_header.h`` from ``openocd``, + +If you need these options to be set differently, you will have to edit ``./src/rtos/nuttx_header.h`` from ``openocd``, change the corresponding settings and then rebuild it. Finally, to enable NuttX integration, you need to supply an additional ``openocd`` argument: @@ -139,7 +139,7 @@ Finally, to enable NuttX integration, you need to supply an additional ``openocd .. code-block:: console $ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c '$_TARGETNAME configure -rtos nuttx' - + Since ``openocd`` also needs to know the memory layout of certain datastructures, you need to have ``gdb`` run the following commands once the ``nuttx`` binary is loaded: @@ -150,7 +150,7 @@ run the following commands once the ``nuttx`` binary is loaded: eval "monitor nuttx.state_offset %d", &((struct tcb_s *)(0))->task_state eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name) - + One way to do this is to define a gdb `hook` function that will be called when running ``file`` command: .. code-block:: @@ -162,7 +162,7 @@ One way to do this is to define a gdb `hook` function that will be called when r eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name) end - + You will see that ``openocd`` has received the memory offsets in its output: .. code-block:: @@ -196,10 +196,10 @@ You will see that ``openocd`` has received the memory offsets in its output: Info : state_offset: 26 Info : name_offset: 208 Info : name_size: 32 - target halted due to debug-request, current mode: Thread + target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x000000dc msp: 0x20000cf0 target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x000000dc msp: 0x20000cf0 - + .. note:: You will probably see the ``Error: No symbols for NuttX`` error appear once at startup. This is OK unless you see it every time you step the debugger. In this case, it would mean you did not enable debug symbols. @@ -208,8 +208,8 @@ Now, You can now inspect threads: .. code-block:: (gdb) info threads - Id Target Id Frame - * 1 Remote target nx_start_application () at init/nx_bringup.c:261 + Id Target Id Frame + * 1 Remote target nx_start_application () at init/nx_bringup.c:261 (gdb) info registers r0 0x0 0 r1 0x2f 47 @@ -261,6 +261,13 @@ the prefix is arm-ebai-none-. *0 Thread 0x20000398 (Name: Idle Task, State: Running, Priority: 0, Stack: 1000) 0x80001ac __start() at chip/stm32_start.c:111 1 Thread 0x10000188 (Name: nsh_main, State: Waiting,Semaphore, Priority: 100, Stack: 2000) 0x800aa06 sys_call2() at /home/ajh/work/vela_all/nuttx/include/arch/syscall.h:187 +.. code-block:: + + (gdb) (gdb) nxgcore -r 0x40200000,0x48000000,0x07 + Saved corefile nuttx.core + Please run gdbserver.py to parse nuttx.core + + The python script has extended many commands like ``thread `` , ``thread apply cmd``, ``nxsetargs`` etc. You can use ``help `` to get help. diff --git a/tools/gdb/gcore.py b/tools/gdb/gcore.py new file mode 100644 index 0000000000..a83f2e760e --- /dev/null +++ b/tools/gdb/gcore.py @@ -0,0 +1,129 @@ +############################################################################ +# tools/gdb/gcore.py +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you 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 +# +# http://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. +# +############################################################################ + +import argparse +import os +import shutil +import tempfile + +import gdb +import utils + + +def create_file_with_size(filename, size): + with open(filename, "wb") as f: + f.write(b"\0" * size) + + +def parse_args(args): + parser = argparse.ArgumentParser() + parser.add_argument("-o", "--output", help="Gcore output file") + parser.add_argument( + "-t", + "--objcopy", + help="Select the appropriate architecture for the objcopy tool", + type=str, + ) + parser.add_argument( + "-r", + "--memrange", + type=str, + ) + return parser.parse_args(args) + + +class NXGcore(gdb.Command): + def __init__(self): + super(NXGcore, self).__init__("nxgcore", gdb.COMMAND_USER) + + def invoke(self, args, from_tty): + try: + args = parse_args(gdb.string_to_argv(args)) + except SystemExit: + return + + objfile = gdb.current_progspace().objfiles()[0] + elffile = objfile.filename + tmpfile = tempfile.NamedTemporaryFile(suffix=".elf") + + # Create temporary ELF file with sections for each memory region + + shutil.copy(elffile, tmpfile.name) + + # If no parameters are passed in + + if args.output: + corefile = args.output + else: + corefile = elffile + ".core" + + # Obtain memory range from macros or parameters + + if args.memrange: + memregion = args.memrange + else: + memregion = str(utils.get_symbol_value("CONFIG_BOARD_MEMORY_RANGE")) + if len(memregion) < 3: + print( + "Please set CONFIG_BOARD_MEMORY_RANGE.\n" + "Memory range of board. format: ,,,....\n" + "start: start address of memory range\n" + "end: end address of memory range\n" + "flags: Readable 0x1, writable 0x2, executable 0x4\n" + "example:0x1000,0x2000,0x1,0x2000,0x3000,0x3,0x3000,0x4000,0x7" + ) + return + + # Resolve memory range and shell run commands + + values = memregion.replace('"', "").split(",") + + for i in range(0, len(values), 3): + start = int(values[i], 16) + end = int(values[i + 1], 16) + + # Create a random section name + + section = tmpfile.name + f"{i // 3}" + + # Add objcopy insertion segment command and modify segment start address command + + create_file_with_size(section, end - start) + + os.system( + f"{args.objcopy} --add-section {section}={section} " + f"--set-section-flags {section}=noload,alloc {tmpfile.name}" + ) + os.system( + f"{args.objcopy} --change-section-address " + f"{section}={hex(start)} {tmpfile.name}" + ) + + os.remove(section) + + gdb.execute(f"file {tmpfile.name}") + gdb.execute(f"gcore {corefile}") + gdb.execute(f"file {elffile}") + tmpfile.close() + + print(f"Please run gdbserver.py to parse {corefile}") + + +NXGcore()