posts: gdb-scripting: Grammar correction

This commit is contained in:
Sanchayan Maity 2021-12-25 19:33:56 +05:30
parent 77ac78d6e8
commit 98a60c1fbc
1 changed files with 71 additions and 74 deletions

View File

@ -4,9 +4,9 @@ title: Automate debugging using GDB scripting
tags: linux, gdb, gdb scripting, gstreamer tags: linux, gdb, gdb scripting, gstreamer
--- ---
Recently I was working on a GStreamer For a while, have had the pleasure of working on a GStreamer
[plugin](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/572) [plugin](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/572)
in Rust. The plugin basically rounds the corners of an incoming video, in Rust at work. The plugin basically rounds the corners of an incoming video,
something akin to the `border-radius` property in CSS. Below is how it looks something akin to the `border-radius` property in CSS. Below is how it looks
like when running on a video. like when running on a video.
@ -15,47 +15,44 @@ like when running on a video.
The GStreamer pipeline for the same. The GStreamer pipeline for the same.
```bash ```bash
gst-launch-1.0 filesrc location=~/Downloads/bunny.mp4 ! decodebin ! videoconvert ! video/x-raw,format=I420 ! roundedcorners border-radius-px=100 ! video/x-raw,format=A420 ! videoconvert ! gtksink gst-launch-1.0 filesrc location=~/Downloads/bunny.mp4 ! decodebin ! videoconvert ! roundedcorners border-radius-px=100 ! videoconvert ! gtksink
``` ```
This was my first time working on a video plugin in GStreamer. Had a lot to This was the first time working on a video plugin in GStreamer. Had a lot to
learn on how to use the `BaseTransform` class from GStreamer, among other learn on how to use the `BaseTransform` class from GStreamer, among other
things. Without getting into the GStreamer specific details here, I basically things. Without getting into the GStreamer specific details here, basically ran
ran into a problem for which I needed to do some debugging for figuring out into a problem for which needed some debugging for figuring out what was going
what was going on in the internals of GStreamer. on in the internals of GStreamer.
Now, while I never had problems using GDB from the command line, but, the way I Now, while using GDB from the command line has never been a problem, but, the
was using it earlier was just not good enough. I would start the pipeline, then straight forward regular approach is time-consuming. Start the pipeline, then
attach gdb to a running process, place breakpoints by manually typing out the attach gdb to a running process, place breakpoints by manually typing out the
whole thing and then start. For one off debugging sessions, where may be you whole thing and then start. For one off debugging sessions, where perhaps you
just want to quickly inspect the backtrace from a crash or may be look into a just want to inspect the backtrace from a crash or may be look into a
deadlock condition where your code hanged, this could be fine. However, when deadlock condition where your code hung, this could be fine. However, when you
you have to repeat this multiple times, do a source code change, compile and have to repeat this multiple times do a source code change compile and then
then check again, it becomes frustrating. select again it becomes frustrating.
## GDB Dashboard ## GDB Dashboard
Looking for a better way, I first stumbled on Looking for a better way, [gdb-dashboard](https://github.com/cyrus-and/gdb-dashboard)
[gdb-dashboard](https://github.com/cyrus-and/gdb-dashboard). is what first came up as an option. This is quite useful since it can give the needed
This is quite useful since it can give the needed information without having to information without having to type anything. Using gdb
type anything. Using gdb
[hooks](https://git.sr.ht/~sanchayanmaity/dotfiles/tree/master/item/gdb/.gdbinit.d/hooks), [hooks](https://git.sr.ht/~sanchayanmaity/dotfiles/tree/master/item/gdb/.gdbinit.d/hooks),
the dashboard can be triggered when appropriate. See the rest of my the dashboard can be triggered when appropriate. See the rest of the [gdb
[gdb configuration](https://git.sr.ht/~sanchayanmaity/dotfiles/tree/master/item/gdb/.gdbinit.d) configuration](https://git.sr.ht/~sanchayanmaity/dotfiles/tree/master/item/gdb/.gdbinit.d)
to get an idea. I use this in scenarios like where code is stuck due to a to get an idea. This is useful in scenarios like where code is stuck due to a
deadlock, I need to look at the backtrace of a crash or any such one off simple deadlock and one needs to look at the backtrace of a crash or any such one off
investigation. simple investigation.
## Construct breakpoint command in neovim & copy to clipboard ## Construct breakpoint command in neovim & copy to clipboard
The next small improvement I did was more specific to my use of neovim. Am The next small improvement is more specific to neovim. Navigating source code
generally navigating source code using neovim, which would be opened in one with neovim opened in one kitty tab and gdb running in terminal in next tab or
kitty tab and gdb would be running in terminal in next tab or a split. Wanted a split is a preferred workflow personally. Being able to place a breakpoint
to be able to quickly place a breakpoint without having to type anything out on without having to type anything out on the gdb prompt would be convenient. The
the gdb prompt. Wrote a small piece of vimscript code which generates the gdb vimscript code below generates the gdb command, considering the current line
command, I would have to type on the gdb prompt to enable a breakpoint, and file on which the cursor is at in the source when opened in neovim.
considering the current line and file on which my cursor is at in the source
when opened in neovim.
```vimscript ```vimscript
function! CopyBpLocToClipboard() abort function! CopyBpLocToClipboard() abort
@ -68,8 +65,8 @@ endfunction
nnoremap <silent> <Leader>yb :<C-U>call CopyBpLocToClipboard()<CR> nnoremap <silent> <Leader>yb :<C-U>call CopyBpLocToClipboard()<CR>
``` ```
So I can hit the key binding above and a command like below will be copied to By using the preceding key binding, a command like below gets copied to the
the clipboard which I can paste on gdb prompt. clipboard which can be just pasted on gdb prompt.
```bash ```bash
break subprojects/gst-plugins-base/gst-libs/gst/video/video-frame.c:104 break subprojects/gst-plugins-base/gst-libs/gst/video/video-frame.c:104
@ -79,19 +76,19 @@ Nifty!!!
## GDB scripting ## GDB scripting
Now imagine a scenario where may be one wants to look at multiple places in the Now imagine a scenario where perhaps one wants to look at multiple places in the
source code and when the program is running, inspect certain variables or just source code and when the program is running, inspect certain variables or just
print out a back trace each time a specific code point is reached. print out a back trace each time a specific code point is reached.
The dumb way to do this and the way which I was also doing it earlier, was to The manual way to do this is to load the executable in gdb or attach to a
load the executable in gdb or attach to a running process, place a break point, running process, place a break point, run, inspect the local variables or print
run, inspect the local variables or print stack trace, place the next break stack trace, place the next break point and repeat this whole process. Just
point and repeat this whole process. Just time consuming and a waste of time. time-consuming.
GDB can completely automate the above process. Let's see how. GDB can completely automate the preceding process like below.
Below is the `.gdbinit` file I came up with for my problem. This is what is Below is the `.gdbinit` file applicable for the problem facing encountered at
called a command file by gdb. work. This is what's called a command file by gdb.
```bash ```bash
set confirm off set confirm off
@ -156,21 +153,20 @@ disable 6
run run
``` ```
The command I was using to debug my GStreamer plugin in this pipeline with gdb. Below is the command to debug the GStreamer plugin in this pipeline with gdb.
```bash ```bash
gdb --nx -x .gdbinit --args env RUST_BACKTRACE=1 GST_DEBUG=3,basetransform:6 GST_PLUGIN_PATH=$GST_PLUGIN_PATH:~/GitSources/gst-plugins-rs/target/debug gst-launch-1.0 filesrc location=~/Downloads/bunny.mp4 ! decodebin ! videoconvert ! video/x-raw,format=I420 ! roundedcorners border-radius-px=100 ! video/x-raw,format=A420 ! videoconvert ! gtksink gdb --nx -x .gdbinit --args env RUST_BACKTRACE=1 GST_DEBUG=3,basetransform:6 GST_PLUGIN_PATH=$GST_PLUGIN_PATH:~/GitSources/gst-plugins-rs/target/debug gst-launch-1.0 filesrc location=~/Downloads/bunny.mp4 ! decodebin ! videoconvert ! video/x-raw,format=I420 ! roundedcorners border-radius-px=100 ! video/x-raw,format=A420 ! videoconvert ! gtksink
``` ```
In the command above, the `-x` parameter tells gdb to use the command file. The In the preceding command, the `-x` parameter tells gdb to use the command file.
`--nx` flag tells gdb to not read any any `.gdbinit` files in any directory, as The `--nx` flag tells gdb to not read any `.gdbinit` files in any directory, as
I did not want to use `gdb-dashboard` for this. `--args` is how I tell gdb what `gdb-dashboard` isn't intended to be used for this. `--args` is how one tells
to run, which is my GStreamer pipeline. You can see `gdb --help` for details on gdb what to run, which is the GStreamer pipeline in this case. See `gdb --help`
the flags. for details on the flags.
Now, let's understand what the command file does. The ones below are just some Now, consider what the command file does. The ones below are just some
settings we want gdb to use. Note that we have turned on logging and pretty settings for gdb to use. Note that logging and pretty printing are enabled.
printing.
```bash ```bash
set confirm off set confirm off
@ -181,8 +177,8 @@ set print pretty on
set pagination off set pagination off
``` ```
Next we specify the breakpoints. We have six breakpoints. These are the Next, specify the breakpoints. There are six breakpoints. These are the source
locations which were of interest to me. code locations of interest.
```bash ```bash
break subprojects/gst-plugins-base/gst-libs/gst/video/video-frame.c:104 if meta->n_planes == 4 break subprojects/gst-plugins-base/gst-libs/gst/video/video-frame.c:104 if meta->n_planes == 4
@ -194,9 +190,10 @@ break subprojects/gst-plugins-base/gst-libs/gst/video/video-frame.c:136
``` ```
Breakpoints can be enabled conditionally. The `if meta->n_planes == 4` implies Breakpoints can be enabled conditionally. The `if meta->n_planes == 4` implies
to consider this breakpoint only when we get a video frame with 4 planes. to consider this breakpoint only when a video frame with 4 planes is received.
We can now tell gdb what should it do when each of the breakpoint above is hit. Next gdb has to be told what should be done when each of the preceding
breakpoints is hit.
```bash ```bash
commands 1 commands 1
@ -212,9 +209,9 @@ end
``` ```
`commands 1` implies these are the commands for gdb to execute when breakpoint `commands 1` implies these are the commands for gdb to execute when breakpoint
1 is hit. When breakpoint 1 is hit, it will print the value of `i` and `frame`. 1 is hit. When breakpoint 1 is hit, the value of `i` and `frame` gets printed.
The other breakpoints get enabled only after the first one is hit. This is The other breakpoints get enabled only after the first one is hit. This is
because at the end of command file, we have because at the end of command file, the following commands
```bash ```bash
disable 2 disable 2
@ -224,38 +221,38 @@ disable 5
disable 6 disable 6
``` ```
which tells gdb to start with these breakpoints disabled. They will get enabled instruct gdb to start with these breakpoints off. These get enabled only
only when we hit breakpoint 1. The `continue` just tells gdb to continue, as we when breakpoint 1 is hit. The `continue` just tells gdb to continue, as gdb
do not want to stop on hitting a breakpoint and only want to inspect in the end shouldn't stop on hitting a breakpoint and logs can be inspected in the
using gdb log. end using gdb log.
Similarly we have for other breakpoints. Other breakpoints are specified similarly.
The `run` at the end tells gdb to start running immediately. In normal usage The `run` at the end tells gdb to start executing immediately. In normal usage
one would have to explicitly type `run` on the gdb prompt to make gdb start one would have to explicitly type `run` on the gdb prompt to make gdb start
debugging. debugging.
If it is not clear so far, basically whatever gdb commands we would have used If it's not clear so far, basically whatever gdb commands would have been used
for debugging at the gdb prompt, we now use them in the command file. for debugging at the gdb prompt, is what gets specified in the command file as
well.
Now, since we turned on logging after running the below on the terminal After running the below on the terminal
```bash ```bash
gdb --nx -x .gdbinit --args env RUST_BACKTRACE=1 GST_DEBUG=3,basetransform:6 GST_PLUGIN_PATH=$GST_PLUGIN_PATH:~/GitSources/gst-plugins-rs/target/debug gst-launch-1.0 filesrc location=~/Downloads/bunny.mp4 ! decodebin ! videoconvert ! video/x-raw,format=I420 ! roundedcorners border-radius-px=100 ! video/x-raw,format=A420 ! videoconvert ! gtksink gdb --nx -x .gdbinit --args env RUST_BACKTRACE=1 GST_DEBUG=3,basetransform:6 GST_PLUGIN_PATH=$GST_PLUGIN_PATH:~/GitSources/gst-plugins-rs/target/debug gst-launch-1.0 filesrc location=~/Downloads/bunny.mp4 ! decodebin ! videoconvert ! video/x-raw,format=I420 ! roundedcorners border-radius-px=100 ! video/x-raw,format=A420 ! videoconvert ! gtksink
``` ```
gdb will run the pipeline, considering the command file it was passed and log The pipeline gets executed by gdb, considering the command file it was passed
whatever it was asked to log when each breakpoint is encountered. And now since and log whatever it was asked to log when each breakpoint is encountered. Since
we had turned on logging and pretty printing, gdb will nicely log everything in logging and pretty printing were enabled earlier, gdb logs everything in
default `gdb.txt` file. You can see the exact log text file default `gdb.txt` file. The exact log text file can be seen
[here](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/572#note_1107146), [here](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/572#note_1107146),
where I have attached the `gdbinit` and the other two log files. with `gdbinit` and the other two log files attached.
Now, one can comfortably look at this log and see what is going on. Once the Now, one can comfortably look at this log and see what's going on. Once the
command file is written, the whole debugging process is completely automated. command file is written, the whole debugging process is completely automated.
Run, sit back and then look at the logs. Run, sit back and then look at the logs.
Using gdb is now a breeze and hassle free experience. Being able to automate Using gdb is now a breeze and hassle-free experience. Being able to automate
and log the debugging process like this, also means you could share your and log the debugging process like this, also means you could share your
command file and someone else can replicate this. Wish I would have learned command file and someone else can replicate this.
this sooner.