mirror of
https://github.com/apache/nuttx.git
synced 2026-05-31 14:27:37 +08:00
tools/gdb: add deadlock detect tool
Signed-off-by: xuxingliang <xuxingliang@xiaomi.com>
This commit is contained in:
+49
-2
@@ -548,13 +548,60 @@ class Ps(gdb.Command):
|
|||||||
self.parse_and_show_info(tcb)
|
self.parse_and_show_info(tcb)
|
||||||
|
|
||||||
|
|
||||||
|
class DeadLock(gdb.Command):
|
||||||
|
def __init__(self):
|
||||||
|
super(DeadLock, self).__init__("deadlock", gdb.COMMAND_USER)
|
||||||
|
|
||||||
|
def has_deadlock(self, pid):
|
||||||
|
"""Check if the thread has a deadlock"""
|
||||||
|
tcb = utils.get_tcb(pid)
|
||||||
|
if not tcb or not tcb["waitobj"]:
|
||||||
|
return False
|
||||||
|
|
||||||
|
sem = tcb["waitobj"].cast(utils.lookup_type("sem_t").pointer())
|
||||||
|
if not sem["flags"] & SEM_TYPE_MUTEX:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# It's waiting on a mutex
|
||||||
|
mutex = tcb["waitobj"].cast(utils.lookup_type("mutex_t").pointer())
|
||||||
|
holder = mutex["holder"]
|
||||||
|
if holder in self.holders:
|
||||||
|
return True
|
||||||
|
|
||||||
|
self.holders.append(holder)
|
||||||
|
return self.has_deadlock(holder)
|
||||||
|
|
||||||
|
def invoke(self, args, from_tty):
|
||||||
|
detected = []
|
||||||
|
for tcb in utils.get_tcbs():
|
||||||
|
self.holders = [] # Holders for this tcb
|
||||||
|
pid = tcb["pid"]
|
||||||
|
if pid in detected or not self.has_deadlock(tcb["pid"]):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Deadlock detected
|
||||||
|
detected.append(pid)
|
||||||
|
detected.extend(self.holders)
|
||||||
|
gdb.write(f'Thread {pid} "{utils.get_task_name(tcb)}" has deadlocked!\n')
|
||||||
|
|
||||||
|
gdb.write(f" holders: {pid}->")
|
||||||
|
gdb.write("->".join(str(pid) for pid in self.holders))
|
||||||
|
gdb.write("\n")
|
||||||
|
|
||||||
|
if not detected:
|
||||||
|
gdb.write("No deadlock detected.")
|
||||||
|
|
||||||
|
gdb.write("\n")
|
||||||
|
|
||||||
|
|
||||||
def register_commands():
|
def register_commands():
|
||||||
|
DeadLock()
|
||||||
SetRegs()
|
SetRegs()
|
||||||
Ps()
|
Ps()
|
||||||
Nxinfothreads()
|
|
||||||
Nxthread()
|
|
||||||
Nxcontinue()
|
Nxcontinue()
|
||||||
|
Nxinfothreads()
|
||||||
Nxstep()
|
Nxstep()
|
||||||
|
Nxthread()
|
||||||
|
|
||||||
# Use custom command for thread if current target does not support it.
|
# Use custom command for thread if current target does not support it.
|
||||||
# The recognized threads count is less than or equal to the number of CPUs in this case.
|
# The recognized threads count is less than or equal to the number of CPUs in this case.
|
||||||
|
|||||||
+19
-1
@@ -24,7 +24,6 @@ import re
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
import gdb
|
import gdb
|
||||||
|
|
||||||
from macros import fetch_macro_info, try_expand
|
from macros import fetch_macro_info, try_expand
|
||||||
|
|
||||||
g_symbol_cache = {}
|
g_symbol_cache = {}
|
||||||
@@ -543,3 +542,22 @@ def get_tcbs():
|
|||||||
npidhash = gdb.parse_and_eval("g_npidhash")
|
npidhash = gdb.parse_and_eval("g_npidhash")
|
||||||
|
|
||||||
return [pidhash[i] for i in range(0, npidhash) if pidhash[i]]
|
return [pidhash[i] for i in range(0, npidhash) if pidhash[i]]
|
||||||
|
|
||||||
|
|
||||||
|
def get_tcb(pid):
|
||||||
|
"""get tcb from pid"""
|
||||||
|
g_pidhash = gdb.parse_and_eval("g_pidhash")
|
||||||
|
g_npidhash = gdb.parse_and_eval("g_npidhash")
|
||||||
|
tcb = g_pidhash[pid & (g_npidhash - 1)]
|
||||||
|
if not tcb or pid != tcb["pid"]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return tcb
|
||||||
|
|
||||||
|
|
||||||
|
def get_task_name(tcb):
|
||||||
|
try:
|
||||||
|
name = tcb["name"].cast(gdb.lookup_type("char").pointer())
|
||||||
|
return name.string()
|
||||||
|
except gdb.error:
|
||||||
|
return ""
|
||||||
|
|||||||
Reference in New Issue
Block a user