Using GDB with ROS 1, a reference

Keywords: #ros #gdb #emacs #debugging

I wanted to write this to act as a quick lookup for anyone who needs it (Mostly me). Almost all of the guides I found mention inserting a launch-prefix into a launch file to launch gdb with the node, but I don’t like doing that. I don’t want to have start gdb from scratch and manually insert the break-points each time I want to debug. That’s goofy. Also, I’d like to use my editor’s built-in debugging tools.

Therefore, there aren’t any instructions for launching gdb through a launchfile on this page. I figure that if you were searching for “gdb ros”, you scrolled through countless examples of those instructions before you arrived here. Go annoy the people who wrote those guides if that’s what you’re looking for.

Step 1: Compile with debug flags

$ catkin build [Package_1] -DCMAKE_BUILD_TYPE=Debug.

You don’t need to build your whole workspace with debug flags, just the package you want to debug.

Step 2: Debug

Open GDB, select one of the cases below.

Case 1: Node
(gdb) exec-file devel/lib/[ros_package_name]/[node_name]
(gdb) start
Case 2: Nodelet
(gdb) exec file /opt/ros/[ros version]/lib/nodelet/nodelet 
(gdb) set args standalone [Package]/[NodeletName] __name:=[NodeletName]
(gdb) start

You may notice the usage of standalone, instead of the usual load, I haven’t been able to get gdb to read the memory tables when loading through a nodelet manager, and thus use standalone as a workaround for this.

Step 3: Panic (It isn’t working)

Potential cause 1: The node/nodelet is failing to launch (Can’t be found)

This most often occurs to me when I’ve just written a new node. The fix is almost always to simply $ source {workspace}/install/setup.bash from the terminal you’re running gdb from.

Potential cause 2: Not able to read any debugging symbols (No breakpoints, memory inspection, etc)

If it’s a nodelet, make sure you’re running it with the standalone flag, as opposed to loading it to a nodelet manager. If that doesn’t do it, double check that you have actually compiled the package with debug flags. Sounds silly, but you’d be surprised how easy it is to miss this when you’re in the zone.

Step 4: Realise that you don’t know how to use gdb

As far as I’m concerned, the best introduction to gdb is Beej’s Quick Guide to GDB. If you have time to spare, I cannot recommend going through Beej’s website enough. It’s an absolute treasure, and I enjoy it immensely. Fantastic stuff.

Step 5: Make some additions to your .bashrc to streamline your workflow.

debug_nodelet()
{
    # Usage: debug_nodelet {nodelet_name}
    local full_name="$(rosrun nodelet declared_nodelets | grep -i $*)"
    local nodelet_name=$(echo "$full_name" | cut -d'/' -f2)
    if [ -z "$nodelet_name" ]
    then
        echo "Could not find nodelet: $*, possible options:"
        rosrun nodelet declared_nodelets
    else
        gdb --args /opt/ros/$ROS_DISTRO/lib/nodelet/nodelet standalone $full_name __name:=$nodelet_name
    fi
}

debug_controller()
{
    # Usage: debug_controller {controller_name}
    gdb --args /opt/ros/$ROS_DISTRO/lib/controller_manager/controller_manager standalone $full_name __name:=$nodelet_name
}

Fin

I’ll be writing up another one of these for ROS2 when I get around to it.