[GDB] Extend gdb with python

Extend GDB with python

.gdbinitImplement the custom command in the file. mvThe 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 pythonto 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()

.gdbinitimport pythonfile 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.executeand 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

Insert image description here

reference

https://github.com/kfggww/algorithms-in-c/tree/main
https://segmentfault.com/a/1190000005718889

Guess you like

Origin blog.csdn.net/tyustli/article/details/133420265