Print Complex Data in GDB with Python Pretty Printer
GDB Python pretty printers let you display complex C/C++ data structures in a readable format, making debugging easier and clearer. In this post, we will write simple plugins to print in_addr and linked list structs.
In this section, we will write a plugin to print IP address
(struct in_addr
).
// Header: /usr/include/netinet/in.h
/* Internet address. */
typedef uint32_t in_addr_t;
struct in_addr
{
;
in_addr_t s_addr};
#include <arpa/inet.h>
int main() {
struct in_addr address;
(AF_INET, "192.168.1.1", &address);
inet_pton
while (1) {} // pause for debug
}
$ gcc -g -o main main.c
import gdb
class InAddrPrinter:
def __init__(self, val):
self.val = val
def to_string(self):
= self.val.bytes
octets = ""
s for x in octets:
+= str(x) + "."
s return "IP address: " + s
def in_addr_lookup(val):
= val.type.name
typename if typename == "in_addr":
return InAddrPrinter(val)
return None
gdb.printing.register_pretty_printer(=None, printer=in_addr_lookup, replace=True)
obj
$ gdb main
(gdb) source in_addr_printer.py
(gdb) info pretty-printer
global pretty-printers:
builtin
mpx_bound128
in_addr_lookup
(gdb) run
^C
Program received signal SIGINT, Interrupt.
main () at main.c:8
8 while (1) {}
gdb) print address
$3 = IP address: 192.168.1.1.
In this section, we will write a plugin to print a linked list.
struct Node {
int data;
struct Node* next;
};
int main() {
struct Node* first = (struct Node*)malloc(sizeof(struct Node));
struct Node* second = (struct Node*)malloc(sizeof(struct Node));
struct Node* third = (struct Node*)malloc(sizeof(struct Node));
->data = 1;
first->next = second;
first
->data = 2;
second->next = third;
second
->data = 3;
third->next = NULL;
third
while (1) {} // pause for debug
}
$ gcc -g -o main main.c
import gdb
class NodePrinter:
def __init__(self, val):
self.val = val
def to_string(self):
= "\n"
s = self.val
node
while node != 0:
= node["data"]
data
= node.const_value()
current_address
next = node["next"]
= "null" if next == 0 else next.const_value()
next_address
+= f"Node {current_address} [data={data}, next={next_address}]\n"
s
= next
node # end while
return s
def linked_list_lookup(val):
if str(val.type) == "struct Node *":
return NodePrinter(val)
return None
gdb.printing.register_pretty_printer(=None, printer=linked_list_lookup, replace=True)
obj
$ gdb main
(gdb) source linked_list_printer.py
(gdb) info pretty-printer
global pretty-printers:
builtin
mpx_bound128
linked_list_lookup
(gdb) run
Starting program: /root/demo/main
^C
Program received signal SIGINT, Interrupt.
main () at main.c:23
23 while (1) {} // pause for debug
(gdb) print third
$1 =
Node 0x5555555592e0 [data=3, next=null]
(gdb) print second
$2 =
Node 0x5555555592c0 [data=2, next=0x5555555592e0]
Node 0x5555555592e0 [data=3, next=null]
(gdb) print first
$3 =
Node 0x5555555592a0 [data=1, next=0x5555555592c0]
Node 0x5555555592c0 [data=2, next=0x5555555592e0]
Node 0x5555555592e0 [data=3, next=null]