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::
(gdb) mon halt
To set a breakpoint:
.. code-block::
@ -104,7 +104,7 @@ and to finally start nuttx:
208 sched_getparam(0, &param);
(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 <id>`` ,
``thread apply <all|id list> cmd``, ``nxsetargs`` etc.
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()