Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

Content

I have been asked countless times: how do you debug more efficiently in the terminal? Or how do you debug in Vim? Well, today I will answer this uniformly: I never debug in Vim because it is not mature enough. So, aside from running GDB in the command line, is there a more efficient method in the terminal? One that allows me to achieve more with less effort?

Of course, there is. Choosing the right tools and methods can significantly enhance GDB debugging efficiency without any issues. The prerequisite is that you at least know how to use the most basic GDB.

Bare-bones State: Basic GDB Command Line

Before putting on various outfits, you must at least learn to run bare, so find a simple GDB cheat sheet to refer to:

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

When a crash occurs in a production environment, since online servers generally do not have a development environment or accompanying source code, if you are too lazy to drag the core file back to the development machine for inspection, you can first use GDB on the online server to take a quick look.

GDB commands are numerous, but the commonly used ones are just a few from the cheat sheet. For example, after entering, the first step is to use bt to check the call stack, info local to view local variables, and then use up/down to navigate between different levels of the call stack to check the values of local variables, and print a certain expression. Even without code, you can check the symbols and disassembly, and generally, you can debug quite effectively.

When encountering more complex bugs, you must refer to the source code. You need to pull the core file to the development environment and use GDB to debug against the source code, using list [line number] to view the current running source code, and then use other methods for debugging.

At this point, if the complexity of debugging continues to rise, you will need to set breakpoints constantly. After each next/step, you will need to list the source code before and after, or use disassemble [function name/address] to view the instructions. Many people may feel overwhelmed, so we need to give our bare-bones GDB some underwear.

Putting on Underwear: TUI

This is the text user interface that comes with GDB, started with the command gdb -tui, for example:

gdb -tui hello

This opens our text interface:

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

The upper part is the source code window, and the lower part is the GDB terminal. The window management shortcuts mimic Emacs, using c-x o to switch windows. If you want to view the instruction window, you can enter:<span>layout split</span>

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

Then, when you step through, the upper source code window will scroll along, which is much more convenient than constantly listing. If you want to see the source code before and after, you can continue to switch windows with c-x o and scroll up and down.

Sometimes, after you switch stack frames with up/down, the upper code may not update in time. In that case, you can use the update command to let the upper code window locate your latest execution position, and sometimes you may need to use CTRL-L to redraw the entire interface.

In GDB’s built-in TUI mode, you can not only view code/instructions at any time but also check registers. Well, GDB, despite its simplicity, still comes with a pair of underwear; many people just forget to take it out and wear it.

Putting on Lingerie: gdbinit

If the information in the above text TUI is not rich enough, you might be interested in ~/.gdbinit, which is a GDB configuration script that can set up some plugins written in Python, such as PEDA:

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

After configuring PEDA in ~/.gdbinit, you will see the command prompt change from (gdb) to gdb-peda$. Each time you enter a step command, PEDA will display an abundance of information, and you can configure to add more. With highlighting, you can get an enhanced command line.

However, I don’t use this much because it affects the TUI mode interface, and I don’t like to clutter my GDB with too many things. Meanwhile, as our debugging needs become more complex, you will need to set breakpoints continuously and frequently step through. Inputting various commands in the traditional command line can be exhausting. Is it possible to view the source code directly in the interface and set breakpoints and step through with shortcuts?

Yes, you can try CGDB.

Putting on a Coat: cgdb

CGDB is similar to GDB TUI, consisting of a terminal window and a code window:

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

The upper code window is called CGDB mode, and the lower GDB window is called GDB mode. Debugging involves constantly switching between the two modes, with key operations mimicking Vim. Press ESC to switch back to CGDB mode and i to switch to GDB mode.

This looks similar to TUI GDB, right? Aside from syntax highlighting, how is it more efficient than GDB TUI? The answer is: most operations can be performed in CGDB mode (the source code window) using shortcut keys.

You can move the cursor with the arrow keys or hjkl, flip pages with page-down/up or c-f / c-b, and pressing o will list the source code files of the current executable, allowing you to switch to view other related code files. You can search the documentation with / or ?.

These shortcuts correspond closely to Vim, allowing you to browse the source code conveniently. In the code window, you can use the space bar to toggle breakpoints, along with other shortcuts:

  • F5 – Send a run command to GDB.
  • F6 – Send a continue command to GDB.
  • F7 – Send a finish command to GDB.
  • F8 – Send a next command to GDB.
  • F10 – Send a step command to GDB.

For more shortcuts, see here. Now stepping and setting breakpoints is much easier; you can basically stay in the source code window without needing to go back to the GDB command line to input next/step one by one.

Edit ~/.cgdb/cgdbrc to make it more convenient:

set ignorecase
set ts=4
set wso=vertical
set eld=shortarrow
set hls
map <F9> :until<cr>

This roughly sets case-insensitive search, tab size, split screen mode (default changed to left-right split), search highlighting, and adds an F9 shortcut for breaking out of loops (which does not have this shortcut by default):

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

Now that everyone has wide-screen monitors, changing the default to a left-right split (requires CGDB 7.0) is much more comfortable.

CGDB has more features, such as viewing assembly when there are no source files, or cross-referencing source code and assembly, setting marks, etc. For specifics, refer to its official documentation.

This small tool can liberate you from a lot of GDB command line work, and the configuration file allows you to bind various commands to shortcuts according to your preferences.

Fully Dressed: Emacs GDB

Although most operations in CGDB can be performed with shortcuts, there are still many times when you need to switch back to the right GDB mode to type commands, such as when you need to use info local to check local variables or print a global variable’s value after each step. Frequent switching can be exhausting.

When debugging relatively complex issues, the above tools may not hold up. For those who usually write code in Vim, I do not hesitate to use Emacs’s GDB mode to debug complex issues. Undoubtedly, Emacs is currently the strongest GDB frontend in the terminal.

If you have never used Emacs, it doesn’t matter; just install Emacs and remember the following commands to debug:

  • Switch files: c-x c-f (press ctrl_x then ctrl_f), you can use tab for completion when entering the file name.
  • Move the cursor: arrow keys, or c-f, c-b, c-p, c-n; page up/down or c-v / m-v.
  • Switch buffers: c-x b to switch the current window’s buffer, c-x c-b to open a new window and switch buffers.
  • Window operations: c-x o to switch windows, c-x 2 / c-x 3 for vertical/horizontal splits, c-x 0 / c-x 1 to close/exclusive.
  • Input commands: m-x (press ALT_x) to input commands with tab completion, c-g to exit command input.

Of course, don’t forget that the exit command is c-x c-c. That’s enough; first, we start Emacs:

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

Press m-x (alt+x), and it will prompt you to input a command (if the terminal software’s alt key doesn’t work, you can set it up, or press ESC then x within a second, which is equivalent in xterm), type “gdb” and press enter:

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

It will then ask how to run GDB; input the shell command to start GDB and press enter to begin GDB mode:

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

You may wonder if this is any different from running GDB directly in the command line. Hold on, continue with m-x to input the command:

gdb-many-windows

And it will immediately satisfy you:

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

These commands starting with gud- are universal debugging commands in Emacs GDB mode, corresponding one-to-one with GDB commands. You can input these commands with m-x or operate them directly with shortcut keys.

If you want to replace a window with disassembly or register monitoring, you can use m-x to input:

gdb-display-disassembly-buffer

Then one of the windows will switch to the disassembly window:

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

The upper left GDB terminal has been switched to the disassembly window. After viewing, remember to use c-x b to switch back to the GDB console. If you want to prevent a window from being switched, you can search for Emacs’s dedicated window feature. Furthermore, we can use window management shortcuts to split the layout according to our preferences:

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

For example, I split it again, moving the GDB terminal to the right, placing the output window below, and displaying the disassembly in the area that originally showed the GDB terminal. Basically, all debugging methods you see in an IDE can be operated in Emacs, and Emacs can also debug Mingw programs under Windows using GDB.

You might complain that operating in Emacs is too cumbersome; no worries, just a little tuning will do.

Tuning Emacs GDB Mode

Open ~/.emacs (or ~/_emacs under Windows) and enter the following content:

(global-set-key [M-left] 'windmove-left)
(global-set-key [M-right] 'windmove-right)
(global-set-key [M-up] 'windmove-up)
(global-set-key [M-down] 'windmove-down)

(global-set-key [f5] 'gud-run)
(global-set-key [S-f5] 'gud-cont)
(global-set-key [f6] 'gud-jump)
(global-set-key [S-f6] 'gud-print)
(global-set-key [f7] 'gud-step)
(global-set-key [f8] 'gud-next)
(global-set-key [S-f7] 'gud-stepi)
(global-set-key [S-f8] 'gud-nexti)
(global-set-key [f9] 'gud-break)
(global-set-key [S-f9] 'gud-remove)
(global-set-key [f10] 'gud-until)
(global-set-key [S-f10] 'gud-finish)

(global-set-key [f4] 'gud-up)
(global-set-key [S-f4] 'gud-down)

(setq gdb-many-windows t)

This sets ALT + arrow keys to jump between windows. If your terminal’s alt + arrow keys don’t work, you can change it to C-left, C-right, etc., to move windows with ctrl + arrow keys. The rest sets shortcuts for commonly used commands.

Finally, set gdb-many-windows to open by default, and it’s best to add the following segment to allow mouse operations:

(require 'xt-mouse)
(xterm-mouse-mode)
(require 'mouse)
(xterm-mouse-mode t)
(defun track-mouse (e))

(setq mouse-wheel-follow-mouse 't)

(defvar alternating-scroll-down-next t)
(defvar alternating-scroll-up-next t)

(defun alternating-scroll-down-line ()
  (interactive "@")
    (when alternating-scroll-down-next
      (scroll-down-line))
    (setq alternating-scroll-down-next (not alternating-scroll-down-next)))

(defun alternating-scroll-up-line ()
  (interactive "@")
    (when alternating-scroll-up-next
      (scroll-up-line))
    (setq alternating-scroll-up-next (not alternating-scroll-up-next)))

(global-set-key (kbd "<mouse-4>") 'alternating-scroll-down-line)
(global-set-key (kbd "<mouse-5>") 'alternating-scroll-up-line)

Now in xterm, you can use the mouse to click to switch windows, click buttons, and use the scroll wheel to view the source code:

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

This gives you more freedom; with ALT + arrow or mouse clicks, you can directly jump between windows and operate with the commands below:

  • F5 – Run, Shift + F5 – Continue
  • F7/F8 for code-level stepping, and Shift-F7/F8 for instruction-level stepping
  • F9 – Set breakpoint, Shift-F9 – Remove breakpoint
  • F10 – Break out of loop, Shift-F10 – Break out of function
  • F4 – Move to the previous call stack frame, Shift-F4 – Move to the next

The upper right local variable window has two buttons that can be clicked to switch between displaying local variables or registers. The lower right also has two buttons to switch between displaying breakpoints or threads. The buttons in the green area at the top can also be clicked directly with the mouse.

Finally, this is much better than our initial version. If you enjoy tinkering, you can also customize the initial layout of gdb-many-windows to be more complex:

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

This can thoroughly satisfy your various complex debugging needs; I won’t elaborate here, but if you’re interested, see this article.

Finally, is it cumbersome to open Emacs every time you debug, input m-x and then the file name? Let’s tune .bashrc:

gdbtool () { emacs --eval "(gdb \"gdb --annotate=3 -i=mi $*\")";}

Now, in the terminal, to debug the program, you just need to input:

$ gdbtool hello

And it will automatically open Emacs and switch to GDB mode, expanding our multi-window setup to start debugging. Isn’t that delightful?

I usually start with GDB TUI to take a look when I don’t have an environment, and if the environment is available or the problem is complex, I will open Emacs for debugging. Later, after being introduced to CGDB, GDB TUI has been retired. I first use CGDB to get a rough idea, and when encountering complex issues, I open Emacs. After some tuning, it becomes very handy.

Making GDB More Attractive

Actually, by the time we reach Emacs, we are almost there. But if you really can’t remember these limited shortcuts or GDB commands, you can also try GDB GUI:

Enhancing GDB Debugging Efficiency on Microcontrollers and LinuxA browser-based GDB frontend developed in Python, just install it via pip, and when using:

gdbgui --host 0.0.0.0 hello

It will listen on local port 5000, and we can open the server address in a browser to debug entirely with the mouse.

The middle shows the program code, the bottom shows the GDB terminal, and the top can switch source code, control run/continue/step, etc. The right side can view local variables, call stack frames, memory addresses, breakpoints, threads, etc. in real-time.

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

For example, the above shows the call stack and thread view, as well as the custom structure query below:

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

It can also visualize data structure queries:

Clicking on the left side of the code allows you to set/remove breakpoints, and clicking the buttons above can switch to display assembly code. Basically, it presents the main functions of GDB in a visual way, showcasing a modern web interface without needing to remember any shortcuts; just point and click.

Additionally, this GDB GUI also supports GDB debugging under Windows. Currently, GDB GUI is still under active development, and as the most attractive GDB frontend, it is expected to become more powerful.

Conclusion

We have experienced the journey from the initial bare command line state of GDB to the most complete debugging environment in the terminal, Emacs GDB mode, and finally to the attractive GDB GUI. The advantage of GDB lies in its ability to incorporate various plugins internally and provide various interfaces externally, allowing you to handle debugging tasks well while leaving the frontend interface to other programs, whether local or remote. This is why there are so many rich GDB frontends and various remote GDB tools.

It does not limit you to say that you can only debug this way or that you only have one UI to operate. Therefore, the combinations of GDB are countless. You don’t have to think that GDB only has the primitive command input method. With the many methods above, just pick a couple, and in less than half an hour, you can significantly speed up your debugging work in the terminal.

Original link: https://zhuanlan.zhihu.com/p/32843449 Copyright belongs to the original author. If there is any infringement, please contact the author for deletion.

Materials sourced from the internet, for academic research only. If there is any infringement, please contact for deletion. Thank you~

Finally

That’s all for today. If you found this helpful, be sure to give alike~

The only, permanent, free platform for sharing embedded technology knowledge~

Recommended Albums Click the blue text to jump

MCU Advanced Album Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

Embedded C Language Advanced Album Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

“Bug Talk” Album Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

Album | Comprehensive Programming for Linux Applications

Album | Learn Some Networking Knowledge

Album | Handwritten C Language

Album | Handwritten C++ Language

Album | Experience Sharing

Album | Power Control Technology

Album | From Microcontrollers to Linux

Enhancing GDB Debugging Efficiency on Microcontrollers and Linux

Leave a Comment