banner



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 variables_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

Tyler Hoffman has worked on the embedded software teams at Pebble and Fitbit. He is now a founder at Memfault.

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

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel