Extend GDB with python
.gdbinit
Implement the custom command in the file. mv
The code is as follows
define mv
if $argc == 2
delete $arg0
# 注意新创建的断点编号和被删除断点的编号不同
break $arg1
else
print "输入参数数目不对,help mv 以获得用法"
end
end
# (gdb) help mv 会输出以下帮助文档
document mv
Move breakpoint.
Usage: mv old_breakpoint_num new_breakpoint
Example:
(gdb) mv 1 binary_search -- move breakpoint 1 to `b binary_search`
end
Use python
to implement the code as follows
# move.py
# 1. 导入 gdb 模块来访问 gdb 提供的 python 接口
import gdb
# 2. 用户自定义命令需要继承自 gdb.Command 类
class Move(gdb.Command):
# 3. docstring 里面的文本是不是很眼熟?gdb 会提取该类的__doc__属性作为对应命令的文档
"""Move breakpoint
Usage: mv old_breakpoint_num new_breakpoint
Example:
(gdb) mv 1 binary_search -- move breakpoint 1 to `b binary_search`
"""
def __init__(self):
# 4. 在构造函数中注册该命令的名字
super(self.__class__, self).__init__("mv", gdb.COMMAND_USER)
# 5. 在 invoke 方法中实现该自定义命令具体的功能
# args 表示该命令后面所衔接的参数,这里通过 string_to_argv 转换成数组
def invoke(self, args, from_tty):
argv = gdb.string_to_argv(args)
if len(argv) != 2:
raise gdb.GdbError('输入参数数目不对,help mv 以获得用法')
# 6. 使用 gdb.execute 来执行具体的命令
gdb.execute('delete' + argv[0])
gdb.execute('break' + argv[1])
# 7. 向 gdb 会话注册该自定义命令
Move()
.gdbinit
import python
file within file
layout src
# 导入 python 文件
source test.py
...
...
In this way, gdb will source it for us every time it starts.
python interface of gdb
gdb provides many python interfaces through the gdb module. The most commonly used ones are gdb.execute
and gdb.parse_and_eval
.
-
gdb.execute can be used to execute a gdb command. By default, results are output to the gdb interface. If you want to dump the output results into a string, set to_string to True: gdb.execute(cmd, to_string=True).
-
gdb.parse_and_eval accepts a string as an expression and returns the result of expression evaluation in the form of gdb.Value. For example, there is a variable i in the current context of gdb, and i is equal to 3. Then the result of gdb.parse_and_eval('i + 1') is an instance of gdb.Value, whose value attribute has a value of 4. This is equivalent to (gdb) i + 1.
What is gdb.Value? In a gdb session, we can access C/C++ type values. When we deal with these values through the python interface, gdb will wrap them into a gdb.Value object.
For example, struct Point has two members: x and y. Now assume that there is a variable point of type Point and a Point pointer p pointing to the variable in the current context, which means:
point = gdb.parse_and_eval('point')
point['x'] # 等价于point.x
point['y'] # 等价于point.y
point.referenced_value() # 等价于&point
p = gdb.parse_and_eval('p')
point2 = p.dereference() # 等价于*p
point2['x'] # 等价于(*p).x,也即p->x
Example
C code
#include <stdio.h>
typedef struct
{
int x;
int y;
} point_t;
int binary_search(int *ary, unsigned int ceiling, int target)
{
unsigned int floor = 0;
while (ceiling > floor)
{
unsigned int pivot = (ceiling + floor) / 2;
if (ary[pivot] < target)
floor = pivot + 1;
else if (ary[pivot] > target)
ceiling = pivot;
else
return pivot;
}
return -1;
}
void set_point_data(point_t *point_in, point_t *p_point_in, int x, int y)
{
point_in->x = x;
point_in->y = y;
return;
}
int main(int argc, char *argv)
{
int a[] = {
1, 2, 4, 5, 6};
point_t point1;
point_t *p_point;
printf("%d\r\n", binary_search(a, 5, 7)); /* -1 */
printf("%d\r\n", binary_search(a, 5, 6)); /* 4 */
printf("%d\r\n", binary_search(a, 5, 5)); /* 3 */
p_point = &point1;
point1.x = 78;
point1.y = 78;
set_point_data(&point1, p_point, 1, 2);
printf("%d %d\r\n", point1.x, point1.y);
printf("%d %d\r\n", p_point->x, p_point->y);
return 0;
}
.gdbinit code
layout src
# 导入 python 文件
source test.py
b main
b binary_search if target == 5
b set_point_data
# set_point_data 触发的命令
comm
# 向命令 print_point 传递的参数是 *point_in 和 p_point_in
print_point *point_in p_point_in
end
# 断点 1 触发执行的命令
command 1
i locals
i args
end
# 断点 2 触发执行的命令
comm 2
i locals
i args
end
python code
# 1. 导入gdb模块来访问gdb提供的python接口
import gdb
# 2. 用户自定义命令需要继承自gdb.Command类
class Move(gdb.Command):
# 3. docstring里面的文本是不是很眼熟?gdb会提取该类的__doc__属性作为对应命令的文档
"""Move breakpoint
Usage: mv old_breakpoint_num new_breapkpoint
Example:
(gdb) mv 1 binary_search -- move breakpoint 1 to `b binary_search`
"""
def __init__(self):
# 4. 在构造函数中注册该命令的名字
super(self.__class__, self).__init__("mv", gdb.COMMAND_USER)
# 5. 在invoke方法中实现该自定义命令具体的功能
# args表示该命令后面所衔接的参数,这里通过string_to_argv转换成数组
def invoke(self, args, from_tty):
argv = gdb.string_to_argv(args)
if len(argv) != 2:
raise gdb.GdbError('输入参数数目不对,help mv以获得用法')
# 6. 使用gdb.execute来执行具体的命令
gdb.execute('delete ' + argv[0])
gdb.execute('break ' + argv[1])
# 7. 向gdb会话注册该自定义命令
Move()
class print_point(gdb.Command):
def __init__(self):
super(self.__class__, self).__init__("print_point", gdb.COMMAND_USER)
def invoke(self, args, from_tty):
point = gdb.parse_and_eval('point_in')
print(point['x']) # 等价于 point.x
print(point['y']) # 等价于 point.y
point.referenced_value() # 等价于 &point
p = gdb.parse_and_eval('p_point_in')
point2 = p.dereference() # 等价于 *p
print(point2['x']) # 等价于 (*p).x,也即 p->x
print(point2['y']) # 等价于 (*p).y,也即 p->y
print_point()
Effect
reference
https://github.com/kfggww/algorithms-in-c/tree/main
https://segmentfault.com/a/1190000005718889