概述
mysql是一个单进程多线程的架构数据库,空闲情况下线程已经有二十个了,如何在有多个会话的情况下,通过会话的ID找到对应的线程ID,对于gdb调试来讲,是很有必要的。gdb 可以通过python 扩展实现这个功能。
查看GDB是否支持Python
使用 help命令提示查看,如果不支持python,需要重新编译带有python扩展的版本。
(gdb) help python
python, py
Evaluate a Python command.
The command can be given as an argument, for instance:
python print (23)
If no argument is given, the following lines are read and used
as the Python commands. Type a line containing "end" to indicate
the end of the command.
查看当前会话的ID
mysql> select connection_id();
+-----------------+
| connection_id() |
+-----------------+
| 18 |
+-----------------+
1 row in set (0.00 sec)
如何找到对应的线程ID?

mysql 每个会话线程都会创建一个THD类对象,这个对象有一个函数thread_id可以返回线程ID,该ID就是会话ID。
my_thread_id thread_id() const { return m_thread_id; }
通过轮询找到对应的ID是个很简单的方法。
编写python函数实现
通过引入gdb模块,实现灵活的操作gdb变量
import gdb
class FindGDBThread(gdb.Command):
def __init__(self):
super(FindGDBThread, self).__init__("find_gdb_thread", gdb.COMMAND_USER)
def invoke(self, arg, from_tty):
# 解析参数
args = gdb.string_to_argv(arg)
if len(args) != 1:
print("Usage: find_gdb_thread <user_thread_id>")
return
target_user_id = int(args[0])
print(f"Searching for GDB thread with User Thread ID: {target_user_id}")
threads = gdb.selected_inferior().threads()
found = False
for thread in threads:
thread.switch() # 切换到当前线程
# 查找do_command frame
current_frame = gdb.newest_frame()
found_do_command_frame = False
while current_frame is not None:
if current_frame.name() == "do_command":
current_frame.select() # 切换到do_command frame
found_do_command_frame = True
break
current_frame = current_frame.older()
if not found_do_command_frame:
continue # 未找到do_command frame,跳过此线程
try:
# 获取thd变量
thd = gdb.parse_and_eval("thd")
if thd == 0: # 检查是否为空指针
continue
# 获取线程ID
thread_id_value = gdb.parse_and_eval(f"((THD*){thd})->thread_id()")
# 处理不同类型的返回值
if thread_id_value.type.code == gdb.TYPE_CODE_INT:
thread_id = int(thread_id_value)
elif thread_id_value.type.code == gdb.TYPE_CODE_PTR:
thread_id = int(thread_id_value.dereference())
else:
thread_id = int(thread_id_value)
# 检查是否匹配目标用户线程ID
if thread_id == target_user_id:
print(f"Found match!")
print(f"GDB Thread ID: {thread.num}")
print(f"User Thread ID: {thread_id}")
found = True
except (gdb.error, ValueError):
continue # 忽略错误,继续处理下一个线程
if not found:
print(f"No thread found with User Thread ID: {target_user_id}")
FindGDBThread()
脚本使用
加载到gdb后,可以直接通过注册的函数名调用。
(gdb) source /home/mysql/test/find_gdb_thread.py
(gdb) find_gdb_thread 18
Searching for GDB thread with User Thread ID: 18
Found match!
GDB Thread ID: 29
User Thread ID: 18
(gdb) thread 29
[Switching to thread 29 (Thread 0x7f2b0c3a46c0 (LWP 306385))]
#0 0x00007f2b2c8a7b96 in ?? () from /usr/lib64/libc.so.6
小结
通过gdb的python扩展,可以很灵活的使用gdb,提高debug效率。