GDB Guide Part 7 - Custom Commands
GDB Guides Series:
1. Introduction
Today’s lesson will focus primarily on creating custom commands in GDB. If you are a long term user of the vanilla GDB, you may find yourself wanting more features to support your research needs. To fulfill those needs, the open-source project, GEF (GDB Enhanced Features) provides many QoL features that aid dynamic analysis.
However, GEF is not what I want to talk about today. Instead of using GEF, we will be writing our user-defined commands using native GDB syntax first, then extending them further with python to enhance GDB’s capabilities.
2. GDB Syntax
For example, if you needed to do a set of repetitive commands over and over again, you can just define them under a user-defined command.
The following example shows how you can define a new command called “test_command”, where it takes one step-into, examine the current instruction and then printing information on the RDI register.
(gdb) define test_command
> si
> x/i $pc
> info registers rdi
> end
Demo - Using User-Defined Commands
3. Python
To create a new custom command in python, all you need to do is create a new class that inherits from the gdb.Command class. Let’s break this down step by step!
3.1 Setting New Class
Preferably, we want to name our python class based on the command that we are creating. For example, if we want the custom command to be “get_base_addr”, then the class should be called GetBaseAddr.
The snippet below shows the overall layout of what your class should look like as a start:
class TestCommand(gdb.Command):
def __init__(self):
self.__command_name = "test_command"
super(TestCommand, self).__init__(self.__command_name, gdb.COMMAND_USER)
return
TestCommand()
3.2 Defining Invoke Function
Still within the same class, we will also need to define our invoke() function which contains all the logic of our user-defined command.
The snippet below replicates what we did previously.
def invoke(self, args: str, from_tty: bool = False) -> None:
gdb.execute("si")
gdb.execute("x/i $pc")
gdb.execute("info registers rdi")
return
- You can pass arguments to invoke which will be taken in as a full string. You will need to parse it yourself.
- You can redirect the output to a variable to do further processing.
# Example to put the mappings into a list mappings = gdb.execute("info proc mappings", to_string=True).split("\n")[4:]
3.3 Importing Command & Running
Once the above 2 steps are done correctly, you will be able to import your new command in by doing the following command:
(gdb) source test_command.py
If there are any syntax errors, go back and fix the python code and import it in again. When GDB doesn’t complain, it means your custom command has been
successfully imported! The name of your command will follow what you have defined previously in self.__command_name.
4. Conclusion
Now that you have reached this stage of the tutorial, great job making it this far!
If you are interested in more useful python extensions for GDB, you may check out some of the commands I wrote to help researchers debug their targets faster.