posts: gdb-scripting: Grammar correction
This commit is contained in:
parent
77ac78d6e8
commit
98a60c1fbc
1 changed files with 71 additions and 74 deletions
|
@ -4,9 +4,9 @@ title: Automate debugging using GDB scripting
|
|||
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)
|
||||
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
|
||||
like when running on a video.
|
||||
|
||||
|
@ -15,47 +15,44 @@ like when running on a video.
|
|||
The GStreamer pipeline for the same.
|
||||
|
||||
```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
|
||||
things. Without getting into the GStreamer specific details here, I basically
|
||||
ran into a problem for which I needed to do some debugging for figuring out
|
||||
what was going on in the internals of GStreamer.
|
||||
things. Without getting into the GStreamer specific details here, basically ran
|
||||
into a problem for which needed some debugging for figuring out what was going
|
||||
on in the internals of GStreamer.
|
||||
|
||||
Now, while I never had problems using GDB from the command line, but, the way I
|
||||
was using it earlier was just not good enough. I would start the pipeline, then
|
||||
Now, while using GDB from the command line has never been a problem, but, the
|
||||
straight forward regular approach is time-consuming. Start the pipeline, then
|
||||
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
|
||||
just want to quickly inspect the backtrace from a crash or may be look into a
|
||||
deadlock condition where your code hanged, this could be fine. However, when
|
||||
you have to repeat this multiple times, do a source code change, compile and
|
||||
then check again, it becomes frustrating.
|
||||
whole thing and then start. For one off debugging sessions, where perhaps you
|
||||
just want to inspect the backtrace from a crash or may be look into a
|
||||
deadlock condition where your code hung, this could be fine. However, when you
|
||||
have to repeat this multiple times do a source code change compile and then
|
||||
select again it becomes frustrating.
|
||||
|
||||
## GDB Dashboard
|
||||
|
||||
Looking for a better way, I first stumbled on
|
||||
[gdb-dashboard](https://github.com/cyrus-and/gdb-dashboard).
|
||||
This is quite useful since it can give the needed information without having to
|
||||
type anything. Using gdb
|
||||
Looking for a better way, [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
|
||||
information without having to type anything. Using gdb
|
||||
[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
|
||||
[gdb 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
|
||||
deadlock, I need to look at the backtrace of a crash or any such one off simple
|
||||
investigation.
|
||||
the dashboard can be triggered when appropriate. See the rest of the [gdb
|
||||
configuration](https://git.sr.ht/~sanchayanmaity/dotfiles/tree/master/item/gdb/.gdbinit.d)
|
||||
to get an idea. This is useful in scenarios like where code is stuck due to a
|
||||
deadlock and one needs to look at the backtrace of a crash or any such one off
|
||||
simple investigation.
|
||||
|
||||
## Construct breakpoint command in neovim & copy to clipboard
|
||||
|
||||
The next small improvement I did was more specific to my use of neovim. Am
|
||||
generally navigating source code using neovim, which would be opened in one
|
||||
kitty tab and gdb would be running in terminal in next tab or a split. Wanted
|
||||
to be able to quickly place a breakpoint without having to type anything out on
|
||||
the gdb prompt. Wrote a small piece of vimscript code which generates the gdb
|
||||
command, I would have to type on the gdb prompt to enable a breakpoint,
|
||||
considering the current line and file on which my cursor is at in the source
|
||||
when opened in neovim.
|
||||
The next small improvement is more specific to neovim. Navigating source code
|
||||
with neovim opened in one kitty tab and gdb running in terminal in next tab or
|
||||
a split is a preferred workflow personally. Being able to place a breakpoint
|
||||
without having to type anything out on the gdb prompt would be convenient. The
|
||||
vimscript code below generates the gdb command, considering the current line
|
||||
and file on which the cursor is at in the source when opened in neovim.
|
||||
|
||||
```vimscript
|
||||
function! CopyBpLocToClipboard() abort
|
||||
|
@ -68,8 +65,8 @@ endfunction
|
|||
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
|
||||
the clipboard which I can paste on gdb prompt.
|
||||
By using the preceding key binding, a command like below gets copied to the
|
||||
clipboard which can be just pasted on gdb prompt.
|
||||
|
||||
```bash
|
||||
break subprojects/gst-plugins-base/gst-libs/gst/video/video-frame.c:104
|
||||
|
@ -79,19 +76,19 @@ Nifty!!!
|
|||
|
||||
## 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
|
||||
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
|
||||
load the executable in gdb or attach to a running process, place a break point,
|
||||
run, inspect the local variables or print stack trace, place the next break
|
||||
point and repeat this whole process. Just time consuming and a waste of time.
|
||||
The manual way to do this is to load the executable in gdb or attach to a
|
||||
running process, place a break point, run, inspect the local variables or print
|
||||
stack trace, place the next break point and repeat this whole process. Just
|
||||
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
|
||||
called a command file by gdb.
|
||||
Below is the `.gdbinit` file applicable for the problem facing encountered at
|
||||
work. This is what's called a command file by gdb.
|
||||
|
||||
```bash
|
||||
set confirm off
|
||||
|
@ -156,21 +153,20 @@ disable 6
|
|||
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
|
||||
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
|
||||
`--nx` flag tells gdb to not read any any `.gdbinit` files in any directory, as
|
||||
I did not want to use `gdb-dashboard` for this. `--args` is how I tell gdb what
|
||||
to run, which is my GStreamer pipeline. You can see `gdb --help` for details on
|
||||
the flags.
|
||||
In the preceding command, the `-x` parameter tells gdb to use the command file.
|
||||
The `--nx` flag tells gdb to not read any `.gdbinit` files in any directory, as
|
||||
`gdb-dashboard` isn't intended to be used for this. `--args` is how one tells
|
||||
gdb what to run, which is the GStreamer pipeline in this case. See `gdb --help`
|
||||
for details on the flags.
|
||||
|
||||
Now, let's understand 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
|
||||
printing.
|
||||
Now, consider what the command file does. The ones below are just some
|
||||
settings for gdb to use. Note that logging and pretty printing are enabled.
|
||||
|
||||
```bash
|
||||
set confirm off
|
||||
|
@ -181,8 +177,8 @@ set print pretty on
|
|||
set pagination off
|
||||
```
|
||||
|
||||
Next we specify the breakpoints. We have six breakpoints. These are the
|
||||
locations which were of interest to me.
|
||||
Next, specify the breakpoints. There are six breakpoints. These are the source
|
||||
code locations of interest.
|
||||
|
||||
```bash
|
||||
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
|
||||
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
|
||||
commands 1
|
||||
|
@ -212,9 +209,9 @@ end
|
|||
```
|
||||
|
||||
`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
|
||||
because at the end of command file, we have
|
||||
because at the end of command file, the following commands
|
||||
|
||||
```bash
|
||||
disable 2
|
||||
|
@ -224,38 +221,38 @@ disable 5
|
|||
disable 6
|
||||
```
|
||||
|
||||
which tells gdb to start with these breakpoints disabled. They will get enabled
|
||||
only when we hit breakpoint 1. The `continue` just tells gdb to continue, as we
|
||||
do not want to stop on hitting a breakpoint and only want to inspect in the end
|
||||
using gdb log.
|
||||
instruct gdb to start with these breakpoints off. These get enabled only
|
||||
when breakpoint 1 is hit. The `continue` just tells gdb to continue, as gdb
|
||||
shouldn't stop on hitting a breakpoint and logs can be inspected in the
|
||||
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
|
||||
debugging.
|
||||
|
||||
If it is not clear so far, basically whatever gdb commands we would have used
|
||||
for debugging at the gdb prompt, we now use them in the command file.
|
||||
If it's not clear so far, basically whatever gdb commands would have been used
|
||||
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
|
||||
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
|
||||
whatever it was asked to log when each breakpoint is encountered. And now since
|
||||
we had turned on logging and pretty printing, gdb will nicely log everything in
|
||||
default `gdb.txt` file. You can see the exact log text file
|
||||
The pipeline gets executed by gdb, considering the command file it was passed
|
||||
and log whatever it was asked to log when each breakpoint is encountered. Since
|
||||
logging and pretty printing were enabled earlier, gdb logs everything in
|
||||
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),
|
||||
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.
|
||||
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
|
||||
command file and someone else can replicate this. Wish I would have learned
|
||||
this sooner.
|
||||
command file and someone else can replicate this.
|
||||
|
|
Loading…
Reference in a new issue