How To Print 100 Register Values Gdb
Almost vi years agone, when I was in my first few months at Pebble as a firmware engineer, I decided to take an unabridged workday to read through the bulk of the GDB manual. Information technology was past far one of my all-time decisions every bit an early professional person engineer. After that day, I felt like I was 10x faster at debugging the Pebble firmware and our suite of unit of measurement tests. I even had a new .gdbinit
script with a few macros and configuration flags to kick, which I proceed to amend to this day.
Over the years, I've learned from many firmware developers and am here writing this postal service to share what I've learned along the way. If you take whatever comments or suggestions about this post, I would love to hear from you in Interrupt's Slack aqueduct.
In this reference-style post, we hash out some of the more avant-garde and powerful commands of the GNU debugger, GDB, as well every bit cover some of the best practices and hacks I've establish over the years that help make GDB more than pleasant to employ.
Although there might be debuggers and interfaces out there that provide meliorate experiences than using GDB directly, many of them are built on top of GDB and provide raw access to the GDB trounce, where you can build and use automation through the Python scripting API.
At the cease of nigh of the sections, there are links to either subpages with the GDB manual or to the original content to acquire more about the topic discussed.
Essentials
First, we need to cover the items which I experience are most of import for any developer or team to work efficiently within GDB.
There'south no improve identify to start learning GDB than to start acquire how to search the help menus. Surprisingly, or maybe unsurprisingly, GDB has over 1500+ commands!
# Count number of GDB commands in the master assist list $ gdb --batch -ex 'help all' | grep '\-\-' | wc 1512 16248 117306
With this in listen, the most useful command within GDB is concerning
, which searches all the "assistance" menus of each command. To use it, simply type apropos <regex>
.
(gdb) apropos symbol add-symbol-file -- Load symbols from FILE, assuming FILE has been dynamically loaded. add-symbol-file-from-retentiveness -- Load the symbols out of memory from a dynamically loaded object file. adhere -- Attach to a process or file exterior of GDB. ...
To go the individual assistance menu of whatever control in GDB, but type help <command>
, and GDB will output everything it knows almost the command or subcommand.
(gdb) help apropos Search for commands matching a REGEXP
If aid is used on a collection of commands:
(gdb) help info Generic command for showing things about the program being debugged. List of info subcommands: info address -- Depict where symbol SYM is stored. info all-registers -- List of all registers and their contents, for selected stack frame. info args -- All argument variables of current stack frame or those matching REGEXPs. ...
Reference
GDB History
Next, we demand to ensure that command history is enabled.
By default GDB does not save any history of the commands that were run during each session. This is especially annoying because GDB supports CTRL+R
for history search just like your shell!
To fix this, nosotros tin can place the following in our .gdbinit
.
set history salve on set history size 10000 set history filename ~/.gdb_history
With this in place, GDB volition now keep the last 10,000 commands in a file ~/.gdb_history.
Reference
Sharing .gdbinit
Files
I'm a huge believer in developer productivity, and I attempt my best to share my all-time-practices with co-workers and the greater customs. In the past, I've made it a point to take per-project GDB configuration files that are automatically loaded for everyone by default.
This could be in a fustigate script debug.sh
which developers use instead of typing gdb
and all the arguments past paw:
#!/bin/sh gdb build/symbols.elf \ -ix=./gdb/project.gdbinit \ --ex='source ./gdb/extra_gdb.py' \ "$@"
Better yet, y'all tin build a Projection CLI using Invoke which wraps the GDB invocation into an invoke debug
command.
This ensures that anybody working on the project has the latest set of configuration flags and GDB Python scripts to accelerate their debugging.
Source Files
With the essentials out of the mode, allow's dive into learning GDB! The start thing to talk almost is how best to view and navigate the source code while debugging.
Directory Search Paths
Many times, the CI system builds with absolute paths instead of paths relative to the project root, which causes GDB not to be able to find the source files.
It volition produce an mistake similar below:
(gdb) f one #2 cli_state_collect (p_cli=0x3ad00 <m_cli>) at ../nrf5_sdk/components/libraries/cli/nrf_cli.c:1952 1952 ../nrf5_sdk/components/libraries/cli/nrf_cli.c: No such file or directory.
If yous are proactive and desire to fix this permanently in the build pace, y'all tin can follow the steps in Interrupt's post about Reproducible Firmware Builds to brand the paths relative.
If you want to patch information technology up now in GDB, you tin apply a combination of the set up substitute-path
and directory
commands in GDB, depending on how the paths are built.
To fix the above consequence, all I needed to practice was to add a local directory. Later on calculation it, GDB tin find the source lawmaking of the line in the frame.
(gdb) directory sdk/embedded/platforms/nrf5/nrf5_sdk/ Source directories searched: /[...]/sdk/embedded/platforms/nrf5/nrf5_sdk:$cdir:$cwd (gdb) f one #i 0x000292a2 in cli_execute (p_cli=0x3ad00 <m_cli>) at ../nrf5_sdk/components/libraries/cli/nrf_cli.c:2554 2554 p_cli->p_ctx->p_current_stcmd->handler(p_cli,
Reference
Source Context with listing
Sometimes, yous just want to quickly add a few lines higher up and below the current line. To quickly view ten lines of source-code context inside GDB, you can use the list
command.
(gdb) list 2549 &p_static_entry, 2550 &static_entry); 2551 2552 p_cli->p_ctx->p_current_stcmd = p_static_entry; 2553 2554 p_cli->p_ctx->p_current_stcmd->handler(p_cli, 2555 argc - cmd_handler_lvl, 2556 &argv[cmd_handler_lvl]); 2557 } 2558 else if (handler_cmd_lvl_0 != Goose egg)
If you lot desire to set a larger or smaller default number of lines shown with this command, you can change the setting:
Reference
Viewing Associates With disassemble
It'southward oft useful to dive into the assembly of a specific function. GDB has this capability born and tin can even interleave the source code with the assembly (past using the /s
pick).
(gdb) detach /s nrf_cli_cmd_echo_on Dump of assembler code for function nrf_cli_cmd_echo_on: nrf_cli.c: 3511 { 3512 if (nrf_cli_build_in_cmd_common_executed(p_cli, (argc != ane), Zip, 0)) 0x0002969c <+0>: ldr r3, [r0, #eight] 0x0002969e <+2>: ldr.w r2, [r3, #316] ; 0x13c nrf_cli.h: 604 render p_cli->p_ctx->internal.flag.show_help; 0x000296a2 <+6>: lsls r2, r2, #xxx 0x000296a4 <+eight>: bmi.n 0x296b8 <nrf_cli_cmd_echo_on+28> nrf_cli.c: 3391 if (arg_cnt_nok) 0x000296a6 <+10>: cmp r1, #1 0x000296a8 <+12>: bne.north 0x296bc <nrf_cli_cmd_echo_on+32>
If you want something more powerful than detach
, you can use objdump
itself. Interrupt'southward post on GNU Binutils is a slap-up reference for this.
Reference
GDB Visual Interfaces
There are many visual interfaces that are built into or on top of GDB. Let'south become through a few of the most popular ones.
GDB TUI
GDB has a built-in graphical interface for viewing source code, registers, assembly, and other diverse items, and it'due south quite elementary to use!
You can start the TUI interface by running:
This should give you the source code viewer. You lot are now able to type next
, stride
, continue
, etc. and the TUI interface will update and follow along.
If you want to view the assembly as well, y'all can run:
To show the registers at the top of the window, you can type:
Alternate GDB Interfaces
Although TUI is nice, I don't know many people who use it and run across information technology more as a gimmick. It's neat for quick observations and exploration, just I would propose spending the fifteen-30 minutes to get something fix that is more powerful and permanent.
I would suggest looking into using gdb-dashboard or Conque-GDB if you lot'd like to stick with using GDB itself.
For a full list of GUI enhancements to GDB, you can check out the list of plugins from my previous mail on GDBundle.
gdbgui
gdbgui is a browser-based frontend to GDB, built past Chad Smith, who besides happens to be the author of another one of my favorite tools, pipx.
gdbgui is great tool if you don't desire to employ a vendor-provided debugger but still want to have a visual way to interface with GDB.
VSCode
VSCode has pretty good support for GDB baked in. If you are just using GDB to debug C/C++ lawmaking locally on your motorcar, you should be able to follow the official instructions.
If y'all are looking to do remote debugging on devices connected with OpenOCD, PyOCD, or JLink, you'll desire to expect into the Platform.io or Cortex-Debug extensions.
Registers
The side by side topic to cover is interacting with registers through GDB.
Printing Registers
Y'all can print the register values within GDB using info registers
.
(gdb) info registers r0 0x2 2 r1 0x7530 30000 r2 0x10000194 268435860 r3 0x1 i r4 0x8001dd9 134225369 r5 0xa5a5a5a5 -1515870811 r6 0xa5a5a5a5 -1515870811 r7 0x20002ad8 536881880 r8 0xa5a5a5a5 -1515870811 r9 0xa5a5a5a5 -1515870811 r10 0xa5a5a5a5 -1515870811 r11 0xa5a5a5a5 -1515870811 r12 0xffffffff -one sp 0x20002ad8 0x20002ad8 <ucHeap1.14288+7812> lr 0x8026563 134374755 pc 0x802f03c 0x802f03c <vPortEnterCritical+32> xpsr 0x10d0000 17629184 fpscr 0x0 0 msp 0x20017fe0 0x20017fe0 psp 0x20002ad8 0x20002ad8 <ucHeap1.14288+7812> primask 0x0 0 control 0x6 6
You can also use info registers all
if there are more registers on your system that aren't printed by default, merely do note they may or may not be valid values (depending on your system and gdbserver).
Annals Variables
GDB provides you lot access to the values of the system registers in the class of variables, such as $pc
or $sp
for the program counter or stack pointer.
When nosotros want to reference these registers directly, we tin merely use $<register_name>
!
(gdb) p $sp $2 = (void *) 0x20002ad8 <ucHeap1.14288+7812> (gdb) p $pc $3 = (void (*)()) 0x802f03c <vPortEnterCritical+32>
Notice these are the same values equally above when nosotros used info registers
.
If your gdbserver supports it, you can also set these annals values! This is really useful for when you are trying to debug a difficult mistake and all you lot have are the sp
, lr
, and pc
registers.
(gdb) set $pc = <pc from fault handler> (gdb) set $lr = <lr from fault handler> (gdb) ready $sp = <sp from fault handler> # Hopefully now a real backtrace! (gdb) bt
Memory
Listing Memory Regions
Information technology's possible to list the memory regions of the binary currently existence debugged past running the info files
command.
(gdb) info files Symbols from "symbols/zephyr.elf". Local exec file: `symbols/zephyr.elf', file type elf32-littlearm. Entry point: 0x8009e94 0x08000000 - 0x080001c4 is text 0x080001d0 - 0x0802cb6e is _TEXT_SECTION_NAME_2 0x0802cb70 - 0x0802cb78 is .ARM.exidx 0x0802cb78 - 0x0802ce08 is sw_isr_table 0x0802ce08 - 0x0802cfac is devconfig 0x0802cfac - 0x0802cfb8 is net_socket_register 0x0802cfb8 - 0x0802d098 is log_const_sections 0x0802d098 - 0x0802d0a8 is log_backends_sections 0x0802d0a8 - 0x0802d0e8 is shell_root_cmds_sections 0x0802d0e8 - 0x08036e98 is rodata 0x20000000 - 0x2000a1f5 is bss 0x2000a200 - 0x2001112b is noinit 0x2001112c - 0x200113f1 is datas ... 0x200117c0 - 0x200117e0 is net_if_dev
This is specially helpful when you are trying to effigy out exactly where a variable exists in memory.
Examine Memory using x
Many developers know how to utilise GDB's print
, but less know about the more powerful x
(for "etenamine") command. The ten
command is used to examine retentivity using several formats.
My nigh common employ of ten
is looking at the stack memory of a system that doesn't have a valid backtrace in GDB. If we know the stack area proper name and size, we can chop-chop print the entire contents and run across if there are valid function references.
I'one thousand looking at a Zephyr RTOS based system and one of the stack regions is chosen my_stack_area
. Let's dump the unabridged contents.
Start nosotros discover the size of the stack:
(gdb) p sizeof(my_stack_area) $1 = 2980
It's 2980 bytes, so nosotros want to print 2980/4 = 745 words. That should exist x/745a
then.
(gdb) x/745a my_stack_area 0x2000a3c0 <my_stack_area>: 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa 0x2000a3d0 <my_stack_area+xvi>: 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa ... A lot more 0xaaaaaaaa 0x2000a8d0 <my_stack_area+1296>: 0xaaaaaaaa 0xaaaaaaaa 0x190 0x2000a900 <my_stack_area+1344> 0x2000a8e0 <my_stack_area+1312>: 0x18f 0x0 0x2000a298 <my_stack_area2+152> 0x18f 0x2000a8f0 <my_stack_area+1328>: 0x20000434 <my_work_q> 0x8021063 <process_accel_data_worker_task> 0x0 0x802108d <process_accel_data_worker_task+42> 0x2000a900 <my_stack_area+1344>: 0x1 0x20002 0x40002 0x60002 0x2000a910 <my_stack_area+1360>: 0x80002 0xc0004 0x100004 0x160006 0x2000a920 <my_stack_area+1376>: 0x1c0006 0x240008 0x2c0008 0x38000c ... A lot of accel int32_t readings 0x2000af30 <my_stack_area+2928>: 0x92f5648a 0xf83c6547 0x5d9a654f 0xc39f6605 0x2000af40 <my_stack_area+2944>: 0x0 0x8021505 <z_work_q_main+68> 0x0 0x80214c1 <z_work_q_main> 0x2000af50 <my_stack_area+2960>: 0x0 0x80214b9 <z_thread_entry+12> 0x0 0xaaaaaaaa 0x2000af60 <my_stack_area+2976>: 0xaaaaaaaa
We tin can easily see some references to functions in this stack, such every bit process_accel_data_worker_task
, z_work_q_main
, and z_thread_entry
. This stack dump technique is especially useful if your GDB provides yous with no backtrace information, such as:
(gdb) bt #0 0x00015f5a in ?? ()
Reference
Searching Retentiveness using notice
Sometimes you know a blueprint that you lot are looking for in retentiveness, and you want to quickly find out if it exists in memory on the system. Maybe it's a magic cord or a specific four-byte design, similar 0xdeadbeef
.
Let's search for the string shell_uart
, which is the job proper noun of a thread in my Zephyr system. I'll search the entire writeable RAM space, which tin can be found by running the info files
command mentioned previously.
(gdb) find 0x20000000, 0x200117e0, "shell_uart" 0x2000121c <shell_uart_thread+104> 1 pattern found.
If we use 10/s
to examine that retention, we can see that it is indeed shell_uart
.
(gdb) x/south 0x2000121c 0x2000121c <shell_uart_thread+104>: "shell_uart"
The find
command can besides be useful for finding pointers pointing to arbitrary structs. For example, I want to observe all the pointers that incorporate a reference to the variable mgmt_thread_data
.
(gdb) observe 0x20000000, 0x200117e0, &mgmt_thread_data 0x20002a18 <tx_classes+120> 0x2000d068 <mgmt_stack+648> 0x2000d074 <mgmt_stack+660> 0x2000d088 <mgmt_stack+680> 0x2001169c <network_event> 0x200116a0 <network_event+4> vi patterns found.
It looks similar there are some references on the mgmt_stack
, and a few other references, which are actually pointers from linked lists.
Using detect
tin assistance rail downwards memory leaks, retention abuse, and possible difficult faults by seeing what pieces of the system are continuing to reference retentiveness or values when they shouldn't.
Reference
Hex Dump with xxd
I dear xxd
for press files in hexdump format in the beat out, but GDB doesn't take anything similar built-in Below is a bit of a hack to bring xxd
into GDB only information technology works perfectly.
define xxd dump binary memory /tmp/dump.bin $arg0 ((char *)$arg0)+$arg1 crush xxd /tmp/dump.bin cease document xxd Runs xxd on a memory ADDR and LENGTH xxd ADDR LENTH stop
If I place the to a higher place in my .gdbinit
, I should now have a command xxd
in GDB that I can use to hexdump an address and length.
(gdb) xxd &shell_uart_out_buffer sizeof(shell_uart_out_buffer) 00000000: 6d66 6c74 3e68 656c 700a 6372 6173 680a mflt>assist.crash. 00000010: 6163 6365 6c65 726f 6d65 7465 720a 7761 accelerometer.wa 00000020: 7463 6864 6f67 0a74 696d 6572 730a 6578 tchdog.timers.ex 00000030: 6974 0a it.
I find this near useful when dumping the contents of log buffers, simply it is a slap-up compliment to using the x
command to see if a binary buffer contains ASCII information.
Reference
Variables
Adjacent up, let's acquire to find and print out any variable on the system.
Searching for Variables
To print the local and argument variables, we can use info locals
and info args
.
(gdb) info locals i = 400 tmp = {1, 222, 7, 84} (gdb) info args raw_samples = 0x3128115f dft_out = 0x2000a900 <my_stack_area+1344> num_samples = 536912536
You can also print all static and global variables in the system past using info variables
, but that will print a lot of variables out to your screen. It'southward better to filter through them!
The command info variables
can optionally take a regular expression that will perform a search confronting the proper noun of the variable.
(gdb) info variables coredump* All variables matching regular expression "coredump": File components/core/src/memfault_data_packetizer.c: twoscore: const sMemfaultDataSourceImpl g_memfault_coredump_data_source; File components/panics/src/memfault_coredump.c: 392: const sMemfaultDataSourceImpl g_memfault_coredump_data_source; File ports/panics/src/memfault_platform_ram_backed_coredump.c: 48: static uint8_t s_ram_backed_coredump_region[700]; ...
It's too possible to have the regular expression apply to the type every bit well! Merely add -t
before the regex.
(gdb) info variables -t k_spinlock All divers variables with type matching regular expression "k_spinlock" : File zephyr/drivers/timer/cortex_m_systick.c: 41: static struct k_spinlock lock; File zephyr/kernel/mem_slab.c: 17: static struct k_spinlock lock; File zephyr/kernel/mempool.c: 16: static struct k_spinlock lock; ...
Reference
Referencing Specific Variables
If you lot work on a large project with many modules, yous'll likely have static and global variables with the same name.
(gdb) info variables lock File zephyr/zephyr/kernel/mempool.c: 16: static struct k_spinlock lock; File zephyr/zephyr/kernel/mutex.c: 46: static struct k_spinlock lock; File zephyr/zephyr/kernel/poll.c: 36: static struct k_spinlock lock; ...
You can reference specific variables from specific files using the following syntax:
(gdb) p &'mempool.c'::lock $four = (struct k_spinlock *) 0x20002370 <lock> (gdb) p &('mutex.c'::lock) $eight = (struct k_spinlock *) 0x2000a0c4 <lock>
Yous can besides reference specific variables from functions using a similar syntax. This is almost helpful for referencing static
variables inside functions from the global context.
For case, in the Memfault Firmware SDK, we accept a function ``memfault_platform_coredump_get_regionswhich contains a static variable
s_coredump_regions`. Source
In GDB, we are unable to print that variable directly:
(gdb) p s_coredump_regions No symbol "s_coredump_regions" in current context.
Merely, if we reference the function directly, we can print the value:
(gdb) p memfault_platform_coredump_get_regions::s_coredump_regions $3 = {{ blazon = kMfltCoredumpRegionType_Memory, region_start = 0x0, region_size = 0 }}
Reference
Value History Variables
Every fourth dimension you print an expression in GDB, it will print the value, but in the format of$<integre> = <value>
.
(gdb) p "hello" $ane = "hi"
The $1
is a variable, which you tin can employ at whatsoever indicate in the debugging session in other expressions and functions. Every new print statement will get its ain variable and the numbers will continuously increase.
Can't recall exactly which variable existed in the past? Just use show values
to print the most recent x.
(gdb) show values $1 = 800 $2 = 2980 $3 = (uint32_t *) 0x3128115f $4 = (uint32_t *) 0x2000a900 <my_stack_area+1344> $five = 536912536 $six = 400
Reference
Convenience Variables
GDB likewise allows you to create and recall any number of variables inside a debugging session. All you demand to do is use set $<name>
and then you can print these out or use them in expressions.
(gdb) set $examination = 5 (gdb) p $test $4 = five
These are useful when you are using complex expressions, possibly involving casts and nested structs, that you want to call up later.
(gdb) fix $wifi = mgmt_thread_data.next_thread.next_thread (gdb) p $wifi $11 = (struct k_thread *) 0x200022ac <eswifi_spi0+20>
You tin can too use convenience variables to help yous print fields inside an assortment of structs.
(gdb) p &shell_wifi_commands $37 = (const struct shell_static_entry (*)[v]) 0x8031650 <shell_wifi_commands>
The above assortment is a list of shell_static_entry
structs, each of which has many fields. Browsing through lists of structs is sometimes cumbersome, particularly if I'1000 only trying to expect at a single field.
Convenience variables can help with this.
Let'due south print the help
element from struct in the array. I'll gear up $i = 0
as my index counter and utilise $i++
in each command then that it increments.
(gdb) fix $i = 0 (gdb) print shell_wifi_commands[$i++]->assistance $1 = 0x80314e0 "\"<SSID>\"\n<SSID length>\n<channel number (optional), 0 ways all>\n<PSK (optional: valid just for secured SSIDs)>" (gdb) <enter> $2 = 0x803155c "Disconnect from Wifi AP" ...
Each time I press enter, the previous control is executed and i
increments, printing me the data in the side by side struct in the assortment.
Reference
The $
Variable
In GDB, the value of $
is the value returned from the previous control.
(gdb) p "hullo" $63 = "hi" (gdb) p $ $64 = "hello"
This is useful in its own correct, but it is particularly useful for helping me with one of my least favorite tasks in GDB: iterating over linked lists.
You may take done something like to the following:
(gdb) p mgmt_thread_data.next_thread $65 = (struct k_thread *) 0x2000188c <eswifi0+48> (gdb) p mgmt_thread_data.next_thread.next_thread $66 = (struct k_thread *) 0x200022ac <eswifi_spi0+20>
Instead of adding .next_thread
onto the end of the list each iteration, you can use the value of $
and just keep pressing <enter>
.
(gdb) p mgmt_thread_data.next_thread $67 = (struct k_thread *) 0x2000188c <eswifi0+48> (gdb) p $.next_thread $68 = (struct k_thread *) 0x200022ac <eswifi_spi0+twenty> (gdb) <enter> $69 = (struct k_thread *) 0x2000a120 <k_sys_work_q+20>
Reference
Artificial Arrays
It is frequently useful to impress a contiguous region of retentiveness as if information technology were an array. A common occurrence of this is when using malloc
to allocate a buffer for a listing of integers.
int num_elements = 100 ; int * elements = malloc ( num_elements * sizeof ( int ));
In GDB, if you endeavor to print this, information technology volition only impress the arrow value, since it doesn't know it'due south an array.
(gdb) p num_elements $1 = 100 (gdb) p elements $ii = (int *) 0x5575e51f6260
We tin can print this entire assortment using one of two ways. Outset, we can bandage it to a int[100]
array and print that.
(gdb) p (int[100])*elements $10 = {0, one, ii, iii, four, v, ...
Or nosotros can use GDB'south bogus arrays! An bogus array is denoted by using the binary operator @
. The left operand of @
should be the first element in thee assortment. The right operand should be the desired length of the array.
(gdb) p *elements@100 $xi = {0, 1, 2, three, 4, five, ...
Reference
Conditional Breakpoints and Watchpoints
A conditional breakpoint in GDB follows the format break WHERE if CONDITION
. It will but bubble up a breakpoint to the user if CONDITION
is truthful.
Allow's imagine we are trying to triage a reproducible retentiveness corruption problems. You lot don't exactly know when or how a num_samples
statement is being corrupted with the value of 0xdeadbeef
when the function compute_fft
is called. We tin ameliorate our investigation using provisional breakpoints.
(gdb) break compute_fft if num_samples == 0xdeadbeef
You tin can use register values ($sp
, $pc
, etc.) in the conditional expressions as well.
Notation that the expressions are evaluated host side within GDB, and then the organization halts every time, but GDB will just prompt the user when the expression is truthful. Therefore, system functioning might be impacted.
Y'all can as well exercise the aforementioned with watchpoints, which volition only prompt the user in GDB if the provisional is true.
(gdb) lookout man i if i == 100 (gdb) info watchpoints Num Type Disp Enb Address What one hw watchpoint continue y i end only if i == 100
Reference
Backtrace for All Threads
To quickly gain an understanding of all of the threads, you can print the backtrace of all threads using the following:
(gdb) thread apply all bt # Shortcut (gdb) taa bt
In my personal .gdbinit
, I have the post-obit alias fix to btall
.
# Print backtrace of all threads define btall thread apply all backtrace end
Reference Bonus Reference for Backtrace Formatting
Pretty Printers
GDB Pretty Printers are essentially printing plugins that you tin can register with GDB. Every fourth dimension a value is printed in GDB, GDB volition check to see if at that place are any registered pretty printers for that blazon, and will use it to impress instead.
For instance, imagine nosotros have a struct Uuid
type in our codebase. `
typedef struct Uuid { uint8_t bytes [ 16 ]; } Uuid ;
If we print this, we'll get the following:
(gdb) p *(Uuid *)uuid $half dozen = { bytes = "\235]D@\213Z#^\251\357\354?\221\234zA" }
That's pretty useless to us every bit we can't read it like a UUID should be written. It would be great if information technology was printed in the course of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
. Pretty printers to the rescue!
After writing a custom pretty printer using GDB's Python API, our UUID'south volition exist printed in a human-readable format.
(gdb) p *(Uuid *)uuid $6 = { bytes = 9d5d4440-8b5a-235e-a9ef-ec3f919c7a41 }
Reference
Struct Operations
sizeof
Y'all tin can easily get the size of any type using sizeof
inside GDB, as you would in C.
(gdb) p sizeof(struct k_thread) $v = 160
offsetof
This isn't a built-in command, simply it's like shooting fish in a barrel enough to add a small macro for it.
(gdb) macro define offsetof(t, f) &((t *) 0)->f
This macro can besides be placed directly within a .gdbinit
file.
With this in place, we tin can now print the offset of whatever struct members.
(gdb) p/d offsetof(struct k_thread, next_thread) $3 = 100
Reference
Interactions Outside of GDB
Run Make within GDB
Executing the command make
directly in GDB will trigger Make from the current working directory.
(gdb) pwd Working directory /Users/tyler/nrf5/apps/memfault_demo_app. (gdb) make Compiling file: arch_arm_cortex_m.c Compiling file: memfault_batched_events.c ...
Reference
Running Shell Commands
You can also run arbitrary beat out commands within GDB. This is particularly useful to me when I'm working on my firmware projects because I always wrap Make with an Invoke-based CLI for building and debugging my projects.
(gdb) beat invoke build Compiling file: arch_arm_cortex_m.c Compiling file: memfault_batched_events.c
Reference
Outputting to File
You lot can output GDB's stdout to a file by using GDB's born logging functionality.
(gdb) prepare logging on Copying output to gdb.txt. Copying debug output to gdb.txt.
Now, whatever command yous run during this session will accept its output written to this file too.
(gdb) p "hi" $1 = "hullo" (gdb) quit $ true cat gdb.txt $1 = "hi" quit
This is most useful when you have a GDB script or Python command that outputs structured data, such as JSON, which you want to so utilize exterior of the GDB session.
Reference
Embedded Specific Enhancements
Thread Sensation
If you lot are using PyOCD, OpenOCD, or JLink, ensure yous are using a gdbserver that is compatible with your RTOS so that you can go the backtraces for all threads.
For OpenOCD and PyOCD, you lot tin view their supported RTOS's and source code for them in Github (OpenOCD, PyOCD)
To integrate an RTOS with Jlink, yous'll have to either use ChibiOS or FreeRTOS, which they support by default, or write your ain JLink RTOS plugin. You can reference Github to gain an understanding of how to write one.
SVD Files and Peripheral Registers
With the help of PyCortexMDebug, you can parse SVD files and read peripheral register values more easily. To get started, first acquire the .svd file from your vendor or wait at the cmsis-svd repo on Github.
Once yous have the file, clone the PyCortexMDebug repo.
$ git clone https://github.com/bnahill/PyCortexMDebug
Next, in GDB, source the svd_gdb.py
within the project.
(gdb) source <path/to/PyCortexMDebug>/cmdebug/svd_gdb.py
Finally, load your .svd file and showtime perusing!
(gdb) svd <path/to/svd>/nrf52840.svd Loading SVD file ... Done! (gdb) svd Available Peripherals: FICR: Manufacturing plant information configuration registers UICR: User information configuration registers CLOCK: Clock control ...
Conclusion
I accept only scratched the surface of what GDB is capable of and the commands and tools mentioned hither are generally built into the awarding itself. The real fun begins when you start extending GDB using it's Python API.
What are your favorite commands in GDB or Python extensions that you've written? I would love to hear from you in Interrupt's Slack channel.
Run across annihilation you'd similar to change? Submit a pull asking or open an issue at GitHub
Farther Reading
- GDBundle: GDB's Missing Bundle managing director
- Automate Debugging with GDB Python API
- GDB Manual
- 8 gdb tricks you should know
How To Print 100 Register Values Gdb,
Source: https://interrupt.memfault.com/blog/advanced-gdb
Posted by: henrydonve1960.blogspot.com
0 Response to "How To Print 100 Register Values Gdb"
Post a Comment