Scripting with GDB

debug
 
gdb
 

A lesser known but nevertheless powerful feature of GDB is its support for macro scripting. This expands on GDB’s capability for customizing the debugger, automating project based setups, setting up advance conditions and routines and more.

Source Files

The user defined GDB scripts are executed

  1. before gdb is called, as in ~/.gdbinit or local .gdbinit or
  2. calling source gdb_script from within an GDB instance or other GDB script files.

Gdbinit are special GDB script files containing macros to be sourced right before GDB startup:

  • ~/.gdbinit is the first file executed and it traditionally contains user-specific system-wide set up. Notable examples are interface customizations, system-wide configurations, etc;
  • .gdbinit refers to the named file from the directory that GDB is run. Generally, project specific setups, such as initializations and frequently-used routines, are defined in it. It is also a good place to add advance conditions for debugging. Note that it is not run by default
    warning: File ".gdbinit" auto-loading has been declined by your `auto-load safe-path'
    

    and the directory needs to be added in ~/.gdbinit for it to run

    set auto-load safe-path dir1\:dir2\:dirN
    

Basics

GDB scripts files share the same syntaxes as the commands for a running GDB instance. Basically, GDB scripts consist of

  • Basic statements, i.e. variable set up, control flow, etc;
  • Definitions, i.e. user-defined commands, hooks and document, etc.
  • GDB commands, i.e. GDB built-in commands or user-defined commands;
  • Shell commands. Shell commands can be executed with shell cmd. shell does not take arguments, so if we need to pass variables to a shell commands, it needs eval "shell echo %d", $var.

GDB Variables

GDB variables (not to be confused with program variables as these are specific to the host GDB instance and not the guest program), a.k.a. Convenience Variables, are denoted with a preceding-$. GDB variables are globally scoped, i.e. changing them anywhere have the same effect. These variables can be set and used

set $var1 = 16 
set $var2 = $var1+1

Control Flow

If and while loops are supported:

If-else:

if $var2%2 == 0
  echo Odd number!\n
else
  printf "Var is 0x%0x\n", $var2
end

While loop:

# count number of instructions executed
set $count = 0
while $pc != 0x7c00
  set $count = $count+1
  x $pc
  si
end
printf "%d insts executed.\n", %count
# Additionally, 'loop_break' and 'loop_continue' can be used in while loops

Functions and Hooks

GDB supports commands, GDB equivalent of functions, and hooks. All elements listed on basics for GDB scripts can be used for defining them.

Commands can be user-defined as

define func
  echo $argc passed in
  if $argc > 0
	# '\ ' for a whitespace
    echo \ and the first one is $arg0 
  end
  echo \n
end

and an optional help message can be included with

document func
'func' prints out its args.
end

Notice that GDB commands accept arguments with $argc for a count and $argN for the Nth element. Hooks are commands intended to run before or after the actual command. They can be defined similarly to commands, with the only exception that they aren’t aware of the arguments:

# Hooks can be defined as 'hook[post]-command_name', where 'command_name' must match an existing
# command name, either a built-in (e.g. stop, run, etc) or a user-defined one (e.g. func).
define hook-func
echo Before the command.\n
end
define hookpost-func
echo After the command.\n
end

One special built-in command that is stop is particular useful for hooks:

(gdb) help stop
There is no `stop' command, but you can set a hook on `stop'. This allows you to set a list of commands to be run each time execution of the program stops.

Commands, including built-in commands, and hooks can be redefined or overwritten. However, GDB issues the user a warning when it detects such definitions:

Redefine command "func"? (y or n) [answered Y; input not from terminal]
Really redefine built-in command "break"? (y or n) [answered Y; input not from terminal]

Output

Finally, a few items to organize the outputs.

When the script generates output and GDB detects that the output is too much to fill in the display, it will

---Type <return> to continue, or q <return> to quit---

. To prevent needing to confirm every time the display is full, simply add

# Set both height to unlimited. Alternatively, set [height|width] 0 has the same effect.
set height unlimited
set width unlimited
# Or simply turn off pagination to achive the same effect
set pagination off

Alternatively, outputs can be redirected to a file as well:

set logging file filename
set logging overwrite on
set logging redirect on
# The line below must be the last for all above to take effect!
set logging on
set pagination off

There are several commands that can be used to generated output, and GDB documents each one of them with help [command]. One might be preferred over others depending on the specific scenario:

  • echo: generally used to print helper messages. It takes constant strings and does not evaluate expressions or variables;
  • print: one of the most used commands in GDB. It evaluates variables and expressions, widely using in the interactive interface;
  • output: similar to print, with a few differences to make it more suitable for user-defined commands (no automatic new lines, not recorded in command history, etc);
  • printf: similar to C printf() function. It formats the string before outputting, with the first parameter as the format string and the following ones as the variables.