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 <wangmingrong1@xiaomi.com>
This commit is contained in:
wangmingrong1 2024-08-29 19:30:33 +08:00 committed by Xiang Xiao
parent bdac8c116a
commit b5c5e4b850
2 changed files with 147 additions and 11 deletions

View file

@ -86,7 +86,7 @@ To halt the board:
.. code-block:: .. code-block::
(gdb) mon halt (gdb) mon halt
To set a breakpoint: To set a breakpoint:
.. code-block:: .. code-block::
@ -104,7 +104,7 @@ and to finally start nuttx:
208 sched_getparam(0, &param); 208 sched_getparam(0, &param);
(gdb) continue (gdb) continue
Continuing. Continuing.
.. tip:: .. tip::
You can abbreviate ``gdb`` commands: ``info b`` is a shortcut for 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_DISABLE_MQUEUE=y``
* ``CONFIG_LEGACY_PAGING=n`` * ``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. change the corresponding settings and then rebuild it.
Finally, to enable NuttX integration, you need to supply an additional ``openocd`` argument: 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 .. code-block:: console
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c '$_TARGETNAME configure -rtos nuttx' $ 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`` 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: 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.state_offset %d", &((struct tcb_s *)(0))->task_state
eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name
eval "monitor nuttx.name_size %d", sizeof(((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: One way to do this is to define a gdb `hook` function that will be called when running ``file`` command:
.. code-block:: .. 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_offset %d", &((struct tcb_s *)(0))->name
eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name) eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name)
end end
You will see that ``openocd`` has received the memory offsets in its output: You will see that ``openocd`` has received the memory offsets in its output:
.. code-block:: .. code-block::
@ -196,10 +196,10 @@ You will see that ``openocd`` has received the memory offsets in its output:
Info : state_offset: 26 Info : state_offset: 26
Info : name_offset: 208 Info : name_offset: 208
Info : name_size: 32 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 xPSR: 0x01000000 pc: 0x000000dc msp: 0x20000cf0
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 .. 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. 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:: .. code-block::
(gdb) info threads (gdb) info threads
Id Target Id Frame Id Target Id Frame
* 1 Remote target nx_start_application () at init/nx_bringup.c:261 * 1 Remote target nx_start_application () at init/nx_bringup.c:261
(gdb) info registers (gdb) info registers
r0 0x0 0 r0 0x0 0
r1 0x2f 47 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 *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 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 <id>`` , The python script has extended many commands like ``thread <id>`` ,
``thread apply <all|id list> cmd``, ``nxsetargs`` etc. ``thread apply <all|id list> cmd``, ``nxsetargs`` etc.
You can use ``help <command>`` to get help. You can use ``help <command>`` to get help.

129
tools/gdb/gcore.py Normal file
View file

@ -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: <start>,<end>,<flags>,....\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()