posts: gdb-scripting: Grammar correction
This commit is contained in:
parent
77ac78d6e8
commit
98a60c1fbc
|
@ -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.
|
|
||||||
|
|
Loading…
Reference in New Issue