C++ gdb user defined commands
Table of contents
Introduction
Often it is tedious to debug complex data structures. Debugging a linked list often requires printing a node by dereferencing the pointer to its struct, then accessing the next node and doing the same to it. This can become tedious and messy, resulting in commands like:
(gdb) print *(curr)
(gdb) print *(curr->next)
(gdb) print *(curr->next->next)
...
However, a command to print out a linked list can be created and
placed inside the .gdbinit
file.
Define a command
You can create a user defined command in the .gdbinit file:
define <command>
<code>
end
Document a command
You can document a command in the .gdbinit file:
document <command>
<information about the command>
end
This information appears when the help feature is used:
(gdb) help <command>
<information about the command>
Command parameters
When a user defined command is called in GBD, arguments can be passed in:
(gdb) <command> <arg0> <arg1> <arg2> ...
The number of arguments, and the arguments themselves can be referenced inside the command definition using the following variables:
$argc
$arg0
$arg1
$arg2
...
Example of user-defined command
To create a user-defined command, we use the GDB command define
, and
give it a command name, which in our example is bugreport
followed
by a set of GDB commands that you want to execute or capture the
output from.
(gdb) define bugreport
> set pagination off
> thread apply all backtrace full
> shell uname -a
> end
(gdb)
To save the output to a file:
(gdb) define bugreport
> set pagination off
> set logging file /tmp/bugreport.txt
> set logging on
> thread apply all backtrace full
> shell uname -a
> set logging off
> end
(gdb)
Run it and display the file contents.
(gdb) bugreport
(gdb) shell cat /tmp/bugreport.txt
struct node {
int data;
struct node *next;
};
struct node *create_node( int data );
struct node *create_list( int length );
void print_list( struct node *list );
int main( void )
{
struct node *list1 = create_list( 7 );
print_list( list1 );
return 0;
}
struct node *create_node( int data )
{
struct node *newNode = (struct node *)malloc( sizeof( struct node ) );
assert( newNode != NULL );
newNode->data = data;
newNode->next = NULL;
return newNode;
}
struct node *create_list( int length )
{
struct node *head = NULL;
if( length > 0 ) {
head = create_node( 0 );
int i = 1;
struct node *curr = head;
while( i < length ) {
curr->next = create_node( i );
curr = curr->next;
i++;
}
}
return head;
}
void print_list( struct node *list )
{
struct node *curr = list;
while( curr != NULL ) {
printf( "%d->", curr->data );
curr = curr->next;
}
printf( "X\n" );
}
GDB commands
set verbose off
set pagination off
define p_generic_list
set var $n = $arg0
while $n
print *($n)
set var $n = $n->next
end
end
document p_generic_list
p_generic_list LIST_HEAD_POINTER
Print all the fields of the nodes in the linked list pointed to by LIST_HEAD_POINTER. Assumes there is a next field in the struct.
end
define indentby
printf "\n"
set $i_$arg0 = $arg0
while $i_$arg0 > 10
set $i_$arg0 = $i_$arg0 - 1
printf "%c", ' '
end
end
start
set logging file output/gdb_user_defined_commands.gdb
set logging overwrite on
set logging on
# struct node *list1 = create_list( 7 );
next
p_generic_list list1
# See document p_generic_list
help p_generic_list
# print_list( list1 );
next
continue
quit
# vim: ft=gdb
GDB output
142 print_list( list1 );
$1 = {
data = 0,
next = 0x555555b02230
}
$2 = {
data = 1,
next = 0x555555b00090
}
$3 = {
data = 2,
next = 0x555555b000b0
}
$4 = {
data = 3,
next = 0x555555b000d0
}
$5 = {
data = 4,
next = 0x555555b000f0
}
$6 = {
data = 5,
next = 0x555555b00110
}
$7 = {
data = 6,
next = 0x0
}
p_generic_list LIST_HEAD_POINTER
Print all the fields of the nodes in the linked list pointed to by LIST_HEAD_POINTER. Assumes there is a next field in the struct.
144 return 0;
[Inferior 1 (process 330150) exited normally]
References
- [How to Work with User-Defined Commands in GDB?(https://undo.io/resources/gdb-watchpoint/how-work-user-defined-commands-gdb/
- GDB - Init File
- title