toos/gdb/thread:Support thread command on nuttx

support arch:
  sim x86
  sim x86_64
  arm32 all series

  If we need to support more architectures in the future,
  just add the 'g_tcbinfo' of the corresponding architecture

support thread command:
  1. thread <id>
    switch thread
  2. info thread
    list all thread info
  3. thread apply [all | id list] command
    like this:
      thread apply all bt
      thread apply all bt full
      thread apply 1 2 4 bt
      thread apply all info r
  4. nxsetregs
      Set registers to the specified values.
      Usage: nxsetregs [regs]

      Etc: nxsetregs
           nxsetregs g_current_regs[0]
           nxsetregs tcb->xcp.regs
           Nxsetregs g_pidhash[0].tcb->xcp.regs

      Default regs is g_current_regs[0],if regs is NULL,
      it will not set registers.

    Because NuttX enters exception_common during a crash,
    this assembly function manipulates the stack pointer (sp),
    causing GDB to be unable to trace back to the first context of the crash.
    Instead, it shows the context of the interrupt stack. By using nxsetregs,
    it is possible to forcefully set the first context to
    the one before the interrupt occurred.

Notice:
  Switching threads is achieved by setting registers,
  so registers need to be restored before continue,
  please use 'c' to continue instead of 'continue'

Signed-off-by: anjiahao <anjiahao@xiaomi.com>
This commit is contained in:
anjiahao 2023-07-20 11:25:16 +08:00 committed by Xiang Xiao
parent eadfdab9a7
commit d63a36e0f3
4 changed files with 307 additions and 460 deletions

View File

@ -37,3 +37,6 @@ gdb.write("set pagination off\n")
for py_file in py_files:
gdb.execute("source %s" % py_file)
gdb.write("source %s\n" % py_file)
gdb.execute('handle SIGUSR1 "nostop" "pass" "noprint"')
gdb.write('"handle SIGUSR1 "nostop" "pass" "noprint"\n')

295
tools/gdb/thread.py Normal file
View File

@ -0,0 +1,295 @@
############################################################################
# tools/gdb/thread.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 gdb
import utils
UINT16_MAX = 0xFFFF
saved_regs = None
def save_regs():
global saved_regs
tcbinfo = gdb.parse_and_eval("g_tcbinfo")
if saved_regs is not None:
return
arch = gdb.selected_frame().architecture()
saved_regs = []
i = 0
for reg in arch.registers():
if i >= tcbinfo["basic_num"]:
break
saved_regs.append(gdb.parse_and_eval("$%s" % reg.name))
i += 1
def restore_regs():
tcbinfo = gdb.parse_and_eval("g_tcbinfo")
global saved_regs
if saved_regs is None:
return
arch = gdb.selected_frame().architecture()
i = 0
for reg in arch.registers():
if i >= tcbinfo["basic_num"]:
break
gdb.execute("set $%s=%d" % (reg.name, int(saved_regs[i])))
i += 1
saved_regs = None
class Nxsetregs(gdb.Command):
"""
Set registers to the specified values.
Usage: nxsetregs [regs]
Etc: nxsetregs
nxsetregs g_current_regs[0]
nxsetregs tcb->xcp.regs
Nxsetregs g_pidhash[0].tcb->xcp.regs
Default regs is g_current_regs[0],if regs is NULL, it will not set registers.
"""
def __init__(self):
super(Nxsetregs, self).__init__("nxsetregs", gdb.COMMAND_USER)
def invoke(self, args, from_tty):
current_regs = gdb.parse_and_eval("g_current_regs")
tcbinfo = gdb.parse_and_eval("g_tcbinfo")
arg = args.split(" ")
if arg[0] != "":
regs = gdb.parse_and_eval("%s" % arg[0]).cast(
gdb.lookup_type("char").pointer()
)
else:
if utils.is_target_smp():
gdb.execute("set $_index=up_cpu_index()")
index = gdb.parse_and_eval("$_index")
else:
index = 0
if current_regs[index] == 0:
return
regs = current_regs[index].cast(gdb.lookup_type("char").pointer())
if regs == 0:
gdb.write("regs is NULL\n")
return
save_regs()
arch = gdb.selected_frame().architecture()
i = 0
for reg in arch.registers():
if i >= tcbinfo["basic_num"]:
return
if tcbinfo["reg_off"]["p"][i] != UINT16_MAX:
value = gdb.Value(regs + tcbinfo["reg_off"]["p"][i]).cast(
gdb.lookup_type("uintptr_t").pointer()
)[0]
gdb.execute("set $%s = 0x%x" % (reg.name, value))
i += 1
def get_pc_value(tcb):
arch = gdb.selected_frame().architecture()
tcbinfo = gdb.parse_and_eval("g_tcbinfo")
i = 0
for reg in arch.registers():
if reg.name == "pc" or reg.name == "rip" or reg.name == "eip":
break
i += 1
regs = tcb["xcp"]["regs"].cast(gdb.lookup_type("char").pointer())
value = gdb.Value(regs + tcbinfo["reg_off"]["p"][i]).cast(
gdb.lookup_type("uintptr_t").pointer()
)[0]
return int(value)
class Nxinfothreads(gdb.Command):
def __init__(self):
super(Nxinfothreads, self).__init__("info threads", gdb.COMMAND_USER)
def invoke(self, args, from_tty):
npidhash = gdb.parse_and_eval("g_npidhash")
pidhash = gdb.parse_and_eval("g_pidhash")
statenames = gdb.parse_and_eval("g_statenames")
if utils.is_target_smp():
gdb.write(
"%-4s %-4s %-21s %-80s %-30s\n"
% ("Id", "Cpu", "Thread", "Info", "Frame")
)
else:
gdb.write("%-4s %-21s %-80s %-30s\n" % ("Id", "Thread", "Info", "Frame"))
for i in range(0, npidhash):
if pidhash[i] == 0:
continue
if pidhash[i]["task_state"] == gdb.parse_and_eval("TSTATE_TASK_RUNNING"):
id = "*%s" % i
pc = int(gdb.parse_and_eval("$pc"))
else:
id = "%s" % i
pc = get_pc_value(pidhash[i])
thread = "Thread 0x%x" % pidhash[i]
try:
"""Maybe tcb not have name member, or name is not utf-8"""
info = "(Name: %s, State: %s, Priority: %d, Stack: %d)" % (
pidhash[i]["name"].string(),
statenames[pidhash[i]["task_state"]].string(),
pidhash[i]["sched_priority"],
pidhash[i]["adj_stack_size"],
)
except gdb.error and UnicodeDecodeError:
info = "(Name: Not utf-8, State: %s, Priority: %d, Stack: %d)" % (
statenames[pidhash[i]["task_state"]].string(),
pidhash[i]["sched_priority"],
pidhash[i]["adj_stack_size"],
)
line = gdb.find_pc_line(pc)
if line.symtab:
func = gdb.execute("info symbol %d " % pc, to_string=True)
frame = "0x%x %s at %s:%d" % (
pc,
func.split()[0] + "()",
line.symtab,
line.line,
)
else:
frame = "No symbol with pc"
if utils.is_target_smp():
cpu = "%d" % pidhash[i]["cpu"]
gdb.write(
"%-4s %-4s %-21s %-80s %-30s\n" % (id, cpu, thread, info, frame)
)
else:
gdb.write("%-4s %-21s %-80s %-30s\n" % (id, thread, info, frame))
class Nxthread(gdb.Command):
def __init__(self):
super(Nxthread, self).__init__("thread", gdb.COMMAND_USER)
def invoke(self, args, from_tty):
npidhash = gdb.parse_and_eval("g_npidhash")
pidhash = gdb.parse_and_eval("g_pidhash")
arg = args.split(" ")
arglen = len(arg)
if arg[0] == "":
pass
elif arg[0] == "apply":
if arglen <= 1:
gdb.write("Please specify a thread ID list\n")
elif arglen <= 2:
gdb.write("Please specify a command following the thread ID list\n")
elif arg[1] == "all":
for i in range(0, npidhash):
if pidhash[i] == 0:
continue
try:
gdb.write("Thread %d %s\n" % (i, pidhash[i]["name"].string()))
except gdb.error and UnicodeDecodeError:
gdb.write("Thread %d\n" % (i))
gdb.execute("nxsetregs g_pidhash[%d]->xcp.regs" % i)
cmd_arg = ""
for cmd in arg[2:]:
cmd_arg += cmd + " "
gdb.execute("%s\n" % cmd_arg)
restore_regs()
else:
threadlist = []
i = 0
cmd = ""
for i in range(1, arglen):
if arg[i].isnumeric():
threadlist.append(int(arg[i]))
else:
cmd += arg[i] + " "
if len(threadlist) == 0 or cmd == "":
gdb.write("Please specify a thread ID list and command\n")
else:
for i in threadlist:
if i >= npidhash:
break
if pidhash[i] == 0:
continue
try:
gdb.write(
"Thread %d %s\n" % (i, pidhash[i]["name"].string())
)
except gdb.error and UnicodeDecodeError:
gdb.write("Thread %d\n" % (i))
gdb.execute("nxsetregs g_pidhash[%d]->xcp.regs" % i)
gdb.execute("%s\n" % cmd)
restore_regs()
else:
if arg[0].isnumeric() and pidhash[int(arg[0])] != 0:
gdb.execute("nxsetregs g_pidhash[%s]->xcp.regs" % arg[0])
else:
gdb.write("Invalid thread id %s\n" % arg[0])
class Nxcontinue(gdb.Command):
def __init__(self):
super(Nxcontinue, self).__init__("nxcontinue", gdb.COMMAND_USER)
def invoke(self, args, from_tty):
restore_regs()
gdb.execute("continue")
# We can't use a user command to rename continue it will recursion
gdb.execute("define c\n nxcontinue \n end\n")
gdb.write("\nif use thread command, plase don't use 'continue', use 'c' inside !!!\n")
Nxsetregs()
Nxinfothreads()
Nxthread()
Nxcontinue()

View File

@ -170,3 +170,12 @@ def gdb_eval_or_none(expresssion):
return gdb.parse_and_eval(expresssion)
except gdb.error:
return None
def is_target_smp():
"""Return Ture if the target use smp"""
if gdb.lookup_global_symbol("g_assignedtasks"):
return True
else:
return False

View File

@ -1,460 +0,0 @@
############################################################################
# tools/nuttx-gdbinit
#
# 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.
#
############################################################################
# NOTE: you need to use gdb configured '--with-python'
# usage: gdb -ix=./tools/nuttx-gdbinit nuttx
# new commands: nxthread pid, nxthread_all_bt
# Do not stop with SIGUSR1 which is used for the NuttX sim SMP
handle SIGUSR1 "nostop" "pass" "noprint"
set $_current_tcb = 0x0
set $_target_examined = 0x0
define _examine_arch
python _target_frame = gdb.selected_frame()
python _target_arch = _target_frame.architecture()
python if (_target_arch.name() == 'armv7e-m') : \
gdb.execute("set $_target_arch = \"armv7e-m\"")
python if (_target_arch.name() == 'armv7') : \
gdb.execute("set $_target_arch = \"armv7e-m\"")
# TODO: need more smart way to detect armv7-a
python if (type(gdb.lookup_global_symbol("arm_decodeirq")) is gdb.Symbol) : \
gdb.execute("set $_target_arch = \"armv7-a\"")
python if (_target_arch.name() == 'i386:x86-64') : \
gdb.execute("set $_target_arch = \"i386:x86-64\"")
# NOTE: we assume that sim has sim_bringup function
python if (type(gdb.lookup_static_symbol("sim_start")) is gdb.Symbol \
and _target_arch.name() == 'i386') : \
gdb.execute("set $_target_arch=\"sim:x86\"")
python if (type(gdb.lookup_static_symbol("sim_start")) is gdb.Symbol \
and _target_arch.name() == 'i386:x86-64') : \
gdb.execute("set $_target_arch=\"sim:x86-64\"")
end
define _examine_target
if ($_target_examined == 0x0)
_examine_arch
set $_xcp_nregs = sizeof(g_last_regs) / sizeof(void *)
set $_target_has_fpu = 0
set $_target_regs_offset = 0
if ($_streq($_target_arch, "armv7e-m") == 1)
if ($_xcp_nregs != 19)
set $_target_has_fpu = 1
end
end
if ($_streq($_target_arch, "armv7-a") == 1)
if ($_xcp_nregs != 17)
set $_target_has_fpu = 1
set $_target_regs_offset = $_xcp_nregs - 17
end
end
python gdb.execute("set $_target_has_smp = 0")
python if (type(gdb.lookup_global_symbol("g_assignedtasks")) is gdb.Symbol) : \
gdb.execute("set $_target_has_smp = 1")
set $_target_examined = 1
end
end
define _running_task
if ($_target_has_smp == 0)
set $rtcb = (struct tcb_s *)g_readytorun->head
else
set $rtcb = (struct tcb_s *)g_assignedtasks[up_cpu_index()]->head
end
end
define _print_thread
set $tcb = (struct tcb_s *)$arg0
_running_task
if ($tcb == $rtcb)
printf "* "
else
printf " "
end
printf "%d Thread 0x%x (Name: %s, State: %s, Priority: %d, Stack: %d) PC: 0x%x in ", \
$tcb->pid, $tcb, $tcb->name, g_statenames[$tcb->task_state], $tcb->sched_priority, \
$tcb->adj_stack_size, $tcb->xcp.regs[$_pc_reg_idx]
python _symbol = gdb.execute("info symbol $tcb->xcp.regs[$_pc_reg_idx]", to_string=True); \
print(_symbol.split()[0] + "()")
end
define _save_tcb
_examine_target
set $tcb = $arg0
if ($_streq($_target_arch, "armv7-a") == 1)
_save_tcb_armv7-a $tcb
end
if ($_streq($_target_arch, "armv7e-m") == 1)
if ($_target_has_fpu == 0)
_save_tcb_armv7e-m $tcb
else
_save_tcb_armv7e-mf $tcb
end
end
if ($_streq($_target_arch, "i386:x86-64") == 1)
_save_tcb_i386x86-64 $tcb
end
if ($_streq($_target_arch, "sim:x86-64") == 1)
_save_tcb_simx86-64 $tcb
end
if ($_streq($_target_arch, "sim:x86") == 1)
_save_tcb_simx86 $tcb
end
end
define _save_current_tcb
_examine_target
if ($_current_tcb == 0)
_running_task
_save_tcb $rtcb
set $_current_tcb = $rtcb
end
end
define _switch_tcb
_save_current_tcb
# set the current frame to the newest before switching
python if (gdb.selected_frame() != gdb.newest_frame()) : \
gdb.newest_frame().select()
set $tcb = $arg0
if ($_streq($_target_arch, "armv7-a") == 1)
_switch_tcb_armv7-a $tcb
end
if ($_streq($_target_arch, "armv7e-m") == 1)
if ($_target_has_fpu == 0)
_switch_tcb_armv7e-m $tcb
else
_switch_tcb_armv7e-mf $tcb
end
end
if ($_streq($_target_arch, "i386:x86-64") == 1)
_switch_tcb_i386x86-64 $tcb
end
if ($_streq($_target_arch, "sim:x86-64") == 1)
_switch_tcb_simx86-64 $tcb
end
if ($_streq($_target_arch, "sim:x86") == 1)
_switch_tcb_simx86 $tcb
end
# update _current_tcb
set $_current_tcb = $tcb
end
# see nuttx/arch/arm/include/armv7-a/irq.h
define _save_tcb_armv7-a
set $tcb = (struct tcb_s *)$arg0
set $tcb.xcp.regs[0 + $_target_regs_offset] = $r13
set $tcb.xcp.regs[1 + $_target_regs_offset] = $r14
set $tcb.xcp.regs[2 + $_target_regs_offset] = $r0
set $tcb.xcp.regs[3 + $_target_regs_offset] = $r1
set $tcb.xcp.regs[4 + $_target_regs_offset] = $r2
set $tcb.xcp.regs[5 + $_target_regs_offset] = $r3
set $tcb.xcp.regs[6 + $_target_regs_offset] = $r4
set $tcb.xcp.regs[7 + $_target_regs_offset] = $r5
set $tcb.xcp.regs[8 + $_target_regs_offset] = $r6
set $tcb.xcp.regs[9 + $_target_regs_offset] = $r7
set $tcb.xcp.regs[10 + $_target_regs_offset] = $r8
set $tcb.xcp.regs[11 + $_target_regs_offset] = $r9
set $tcb.xcp.regs[12 + $_target_regs_offset] = $r10
set $tcb.xcp.regs[13 + $_target_regs_offset] = $r11
set $tcb.xcp.regs[14 + $_target_regs_offset] = $r12
set $tcb.xcp.regs[15 + $_target_regs_offset] = $r15
set $tcb.xcp.regs[16 + $_target_regs_offset] = $cpsr
set $_pc_reg_idx = $_target_regs_offset + 15
end
define _switch_tcb_armv7-a
set $tcb = (struct tcb_s *)$arg0
set $r13 = $tcb.xcp.regs[0 + $_target_regs_offset]
set $r14 = $tcb.xcp.regs[1 + $_target_regs_offset]
set $r0 = $tcb.xcp.regs[2 + $_target_regs_offset]
set $r1 = $tcb.xcp.regs[3 + $_target_regs_offset]
set $r2 = $tcb.xcp.regs[4 + $_target_regs_offset]
set $r3 = $tcb.xcp.regs[5 + $_target_regs_offset]
set $r4 = $tcb.xcp.regs[6 + $_target_regs_offset]
set $r5 = $tcb.xcp.regs[7 + $_target_regs_offset]
set $r6 = $tcb.xcp.regs[8 + $_target_regs_offset]
set $r7 = $tcb.xcp.regs[9 + $_target_regs_offset]
set $r8 = $tcb.xcp.regs[10 + $_target_regs_offset]
set $r9 = $tcb.xcp.regs[11 + $_target_regs_offset]
set $r10 = $tcb.xcp.regs[12 + $_target_regs_offset]
set $r11 = $tcb.xcp.regs[13 + $_target_regs_offset]
set $r12 = $tcb.xcp.regs[14 + $_target_regs_offset]
set $r15 = $tcb.xcp.regs[15 + $_target_regs_offset]
set $cpsr = $tcb.xcp.regs[16 + $_target_regs_offset]
end
# see nuttx/arch/arm/include/armv7-m/irq_cmnvector.h
define _save_tcb_armv7e-m
set $tcb = (struct tcb_s *)$arg0
set $tcb.xcp.regs[0] = $sp
# TODO: basepri/primask
set $tcb.xcp.regs[2] = $r4
set $tcb.xcp.regs[3] = $r5
set $tcb.xcp.regs[4] = $r6
set $tcb.xcp.regs[5] = $r7
set $tcb.xcp.regs[6] = $r8
set $tcb.xcp.regs[7] = $r9
set $tcb.xcp.regs[8] = $r10
set $tcb.xcp.regs[9] = $r11
# TODO: EXC_RETURN (protected)
set $tcb.xcp.regs[11] = $r0
set $tcb.xcp.regs[12] = $r1
set $tcb.xcp.regs[13] = $r2
set $tcb.xcp.regs[14] = $r3
set $tcb.xcp.regs[15] = $r12
set $tcb.xcp.regs[16] = $lr
set $tcb.xcp.regs[17] = $pc
# TODO: xPSR
set $_pc_reg_idx = 17
end
define _switch_tcb_armv7e-m
set $tcb = (struct tcb_s *)$arg0
set $sp = $tcb.xcp.regs[0]
# TODO: basepri/primask
set $r4 = $tcb.xcp.regs[2]
set $r5 = $tcb.xcp.regs[3]
set $r6 = $tcb.xcp.regs[4]
set $r7 = $tcb.xcp.regs[5]
set $r8 = $tcb.xcp.regs[6]
set $r9 = $tcb.xcp.regs[7]
set $r10 = $tcb.xcp.regs[8]
set $r11 = $tcb.xcp.regs[9]
# TODO: EXC_RETURN (protected)
set $r0 = $tcb.xcp.regs[11]
set $r1 = $tcb.xcp.regs[12]
set $r2 = $tcb.xcp.regs[13]
set $r3 = $tcb.xcp.regs[14]
set $r12 = $tcb.xcp.regs[15]
set $lr = $tcb.xcp.regs[16]
set $pc = $tcb.xcp.regs[17]
# TODO: xPSR
end
# see nuttx/arch/arm/include/armv7-m/irq_cmnvector.h
define _save_tcb_armv7e-mf
set $tcb = (struct tcb_s *)$arg0
set $tcb.xcp.regs[0] = $sp
# TODO: basepri/primask
set $tcb.xcp.regs[2] = $r4
set $tcb.xcp.regs[3] = $r5
set $tcb.xcp.regs[4] = $r6
set $tcb.xcp.regs[5] = $r7
set $tcb.xcp.regs[6] = $r8
set $tcb.xcp.regs[7] = $r9
set $tcb.xcp.regs[8] = $r10
set $tcb.xcp.regs[9] = $r11
# TODO: EXC_RETURN (protected)
# TODO: FPU
set $tcb.xcp.regs[27] = $r0
set $tcb.xcp.regs[28] = $r1
set $tcb.xcp.regs[29] = $r2
set $tcb.xcp.regs[30] = $r3
set $tcb.xcp.regs[31] = $r12
set $tcb.xcp.regs[32] = $lr
set $tcb.xcp.regs[33] = $pc
# TODO: xPSR
set $_pc_reg_idx = 33
end
define _switch_tcb_armv7e-mf
set $tcb = (struct tcb_s *)$arg0
set $sp = $tcb.xcp.regs[0]
# TODO: basepri/primask
set $r4 = $tcb.xcp.regs[2]
set $r5 = $tcb.xcp.regs[3]
set $r6 = $tcb.xcp.regs[4]
set $r7 = $tcb.xcp.regs[5]
set $r8 = $tcb.xcp.regs[6]
set $r9 = $tcb.xcp.regs[7]
set $r10 = $tcb.xcp.regs[8]
set $r11 = $tcb.xcp.regs[9]
# TODO: EXC_RETURN (protected)
# TODO: FPU
set $r0 = $tcb.xcp.regs[27]
set $r1 = $tcb.xcp.regs[28]
set $r2 = $tcb.xcp.regs[29]
set $r3 = $tcb.xcp.regs[30]
set $r12 = $tcb.xcp.regs[31]
set $lr = $tcb.xcp.regs[32]
set $pc = $tcb.xcp.regs[33]
# TODO: xPSR
end
# see nuttx/arch/x86_64/include/intel64/irq.h
define _save_tcb_i386x86-64
set $tcb = (struct tcb_s *)$arg0
set $tcb.xcp.regs[6 + 64] = $rbx
set $tcb.xcp.regs[7 + 64] = $rbp
set $tcb.xcp.regs[10 + 64] = $r12
set $tcb.xcp.regs[11 + 64] = $r13
set $tcb.xcp.regs[12 + 64] = $r14
set $tcb.xcp.regs[13 + 64] = $r15
set $tcb.xcp.regs[21 + 64] = $rip
set $tcb.xcp.regs[24 + 64] = $rsp
set $_pc_reg_idx = (21 + 64)
end
define _switch_tcb_i386x86-64
set $tcb = (struct tcb_s *)$arg0
set $rbx = $tcb.xcp.regs[6 + 64]
set $rbp = $tcb.xcp.regs[7 + 64]
set $r12 = $tcb.xcp.regs[10 + 64]
set $r13 = $tcb.xcp.regs[11 + 64]
set $r14 = $tcb.xcp.regs[12 + 64]
set $r15 = $tcb.xcp.regs[13 + 64]
set $rip = $tcb.xcp.regs[21 + 64]
set $rsp = $tcb.xcp.regs[24 + 64]
end
# see nuttx/arch/sim/src/sim/up_internal.h
define _save_tcb_simx86-64
set $tcb = (struct tcb_s *)$arg0
set $tcb.xcp.regs[0] = $rbx
set $tcb.xcp.regs[1] = $rsp
set $tcb.xcp.regs[2] = $rbp
set $tcb.xcp.regs[3] = $r12
set $tcb.xcp.regs[4] = $r13
set $tcb.xcp.regs[5] = $r14
set $tcb.xcp.regs[6] = $r15
set $tcb.xcp.regs[7] = $rip
set $_pc_reg_idx = 7
end
define _switch_tcb_simx86-64
set $tcb = (struct tcb_s *)$arg0
set $rbx = $tcb.xcp.regs[0]
set $rsp = $tcb.xcp.regs[1]
set $rbp = $tcb.xcp.regs[2]
set $r12 = $tcb.xcp.regs[3]
set $r13 = $tcb.xcp.regs[4]
set $r14 = $tcb.xcp.regs[5]
set $r15 = $tcb.xcp.regs[6]
set $rip = $tcb.xcp.regs[7]
end
# see nuttx/arch/sim/src/sim/up_internal.h
define _save_tcb_simx86
set $tcb = (struct tcb_s *)$arg0
set $tcb.xcp.regs[0] = $ebx
set $tcb.xcp.regs[1] = $esi
set $tcb.xcp.regs[2] = $edi
set $tcb.xcp.regs[3] = $ebp
set $tcb.xcp.regs[4] = $sp
set $tcb.xcp.regs[5] = $pc
set $_pc_reg_idx = 5
end
define _switch_tcb_simx86
set $tcb = (struct tcb_s *)$arg0
set $ebx = $tcb.xcp.regs[0]
set $esi = $tcb.xcp.regs[1]
set $edi = $tcb.xcp.regs[2]
set $ebp = $tcb.xcp.regs[3]
set $sp = $tcb.xcp.regs[4]
set $pc = $tcb.xcp.regs[5]
end
define _restore_current_tcb
_examine_target
_running_task
_switch_tcb $rtcb
set $_current_tcb = 0x0
end
define nxthread
set $hash = ($arg0 & (g_npidhash - 1))
set $tcb = g_pidhash[$hash]
if ($tcb != 0x0)
_switch_tcb $tcb
_print_thread $tcb
if ($argc == 2)
if ($arg1 == 1)
_switch_tcb $tcb
where
end
end
end
end
define nxthread_all_bt
_save_current_tcb
set $i = 0
while ($i < g_npidhash)
# 1: backtrace
nxthread $i 1
set $i = $i + 1
end
_restore_current_tcb
end
define info threads
_save_current_tcb
set $i = 0
while ($i < g_npidhash)
# dummy : 0 0
nxthread $i 0 0
set $i = $i + 1
end
_restore_current_tcb
end
define c
_restore_current_tcb
continue
end
define thread
_save_current_tcb
if ($argc == 0)
_running_task
set $pid = $rtcb->pid
else
set $pid = $arg0
end
nxthread $pid
end