or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Do you want to remove this version name and description?
Syncing
xxxxxxxxxx
Debugging tricks
33 useful ideas to make WebKit GStreamer debugging easier
Slides: https://hackmd.io/@eocanha/debugging-tricks
Table of contents (1/3)
Debugging tricks using GDB
Table of contents (2/3)
Debugging by instrumenting source code
Table of contents (3/3)
Debugging by using external tools
Share your own tricks
Debugging tricks using GDB
Breakpoints with command
You can break on a place, run some command and continue execution. Useful to get logs:
This idea can be combined with watchpoints and applied to trace reference counting in GObjects and know from which places the refcount is increased and decreased.
Force execution of an if branch
Just wait until the if chooses a branch and then jump to the other one:
Debug glib warnings
If you get a warning message like this:
the functions involved are:
g_return_if_fail_warning()
, which calls tog_log()
. It's good to set a breakpoint in any of the two:Another method is to
export G_DEBUG=fatal_criticals
, which will convert all the criticals in crashes, which will stop the debugger.Debug GObjects
If you want to inspect the contents of a GObjects that you have in a reference…
you can dereference it…
even if it's an untyped gpointer…
To find the type, you can use GType:
Instantiate C++ object from gdb
See: 1 and 2
Print corrupt stacktraces (1/3)
In some circumstances you may get stacktraces that eventually stop because of missing symbols or corruption (
??
entries).However, you can print the stack in a useful way that gives you leads about what was next in the stack:
x/256wa $esp
x/256ga $rsp
x/256wa $sp
You may want to enable asm-demangle:
set print asm-demangle
Example output, the 3 last lines give interesting info:
More info: 1
Print corrupt stacktraces (2/3)
Sometimes (eg: Arris box) the symbol names aren't printed in the stack memdump. You can do this trick to iterate the stack and print the symbols found there (take with a grain of salt!):
Print corrupt stacktraces (3/3)
/proc/<PID>/smaps
andinfo proc mappings
can help to locate the library providing the missing symbol. Then we can load it by hand.For instance, for this backtrace:
In a shell, we examine smaps and find out that the unknown piece of code comes from libgstomx:
Now we load the unstripped .so in gdb and we're able to see the new symbol afterwards:
Useful script to prepare the add-symbol-file:
More info: 1
Debugging a binary without debug symbols
Some useful keybindings in this mode:
Wake up an unresponsive gdb on ARM
Sometimes, when you continue ('c') execution on ARM there's no way to stop it again unless a breakpoint is hit. But there's a trick to retake the control: just send a harmless signal to the process.
Know which GStreamer thread id matches with each gdb thread
Sometimes you need to match threads in the GStreamer logs with threads in a running gdb session. The simplest way is to ask it to GThread for each gdb thread:
This will print a list of gdb threads and
GThread*
. We only need to find the one we're looking for.Generate a pipeline dump from gdb
If we have a pointer to the pipeline object, we can call the function that dumps the pipeline:
Debugging by instrumenting source code
Know all the env vars read by a program by using LD_PRELOAD to intercept libc calls
See the breakpoints with command example to know how to get the same using gdb. Check also Zan's libpine for more features.
Track lifetime of GObjects by LD_PRELOADing gobject-list
The gobject-list project, written by Thibault Saunier, is a simple LD_PRELOAD library for tracking the lifetime of GObjects. When loaded into an application, it prints a list of living GObjects on exiting the application (unless the application crashes), and also prints reference count data when it changes. SIGUSR1 or SIGUSR2 can be sent to the application to trigger printing of more information.
Overriding the behaviour of a debugging macro (1/2)
The usual debugging macros aren't printing messages? Redefine them to make what you want:
This can be done to enable asserts on demand in WebKit too:
Overriding the behaviour of a debugging macro (2/2)
It may be interesting to enable WebKit
LOG()
and GStreamerGST_DEBUG()
macros only on selected files:Note all the preprocessor trickery used here:
__VA_ARGS__
do while(false)
is a trick to avoid {braces} and make the code block work when used in if/then/else one-liners#channel
expandsLOG(MyChannel,....)
asprintf("%s: ", "MyChannel")
. It's called "stringification".## __VA_ARGS__
expands the variable argument list as a comma-separated list of items, but if the list is empty, it eats the comma after "msg", preventing syntax errorsPrint the compile-time type of an expression
Use
typeid(<expression>).name()
. Filter the ouput throughc++filt -t
:Abusing the compiler to know all the places where a function is called
If you want to know all the places from where the
GstClockTime toGstClockTime(float time)
function is called, you can convert it to a template function and usestatic_assert
on a wrong datatype like this (in the .h):Note that
T=float
is different tointeger
(is_integral
). It has nothing to do with thefloat time
parameter declaration.You will get compile-time errors like this on every place the function is used:
Use pragma message to print values at compile time
Sometimes is useful to know if a particular define is enabled:
The code above would generate this output:
Print current thread id
The thread id is generated by Linux and can take values higher than 1-9, just like PIDs. This thread number is useful to know which function calls are issued by the same thread, avoiding confusion between threads.
Debug GStreamer thread locks (1/2)
We redefine the
GST_OBJECT_LOCK
/UNLOCK
/TRYLOCK
macros to print the calls, compare locks against unlocks, and see who's not releasing its lock:Warning: The statement expression that allows the
TRYLOCK
macro to return a value will only work on GCC.Debug GStreamer thread locks (2/2)
There's a way to know which thread has taken a lock in glib/GStreamer using gdb. First locate the stalled thread:
Now get the process id (PID) and use the pthread_mutex_t structure to print the Linux thread id that has acquired the lock:
Trace function calls (poor developer version)
If you're using C++, you can define a tracer class. This is for webkit, but you get the idea:
And use it like this in all the functions you want to trace:
The constructor will log when the execution flow enters into the function and the destructor will log when the flow exits.
Setting breakpoints from C
In the C code, just call
raise(SIGINT)
(simulate CTRL+C, normally the program would finish).And then, in a previously attached gdb, after breaking and having debugging all you needed, just continue the execution by ignoring the signal or just plainly continuing:
There's a way to do the same but attaching gdb after the raise. Use
raise(SIGSTOP)
instead (simulate CTRL+Z). Then attach gdb, locate the thread calling raise and switch to it:Now, from a terminal, send a continuation signal:
kill -SIGCONT 1977
. Finally instruct gdb to single-step only the current thread (IMPORTANT!) and run some steps until all the raises have been processed:Know the name of a GStreamer function stored in a pointer at runtime
Just use this macro:
Detecting memory leaks in WebKit
RefCountedLeakCounter is a tool class that can help to debug reference leaks by printing this kind of messages when WebKit exits:
To use it you have to modify the particular class you want to debug:
wtf/RefCountedLeakCounter.h
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, myClassCounter, ("MyClass"));
myClassCounter.increment()
myClassCounter.decrement()
Finding memory leaks in a RefCounted subclass (1/2)
The code in the next slide must be placed in the .h where the class to be debugged is defined. It's written in a way that doesn't need to rebuild
RefCounted.h
, so it saves a lot of build time. It logs all refs, unrefs and adoptPtrs, so that any anomaly in the refcounting can be traced and investigated later. To use it, just make your class inherit fromLoggedRefCounted
instead ofRefCounted
.Example output:
Finding leaks in a RefCounted subclass (2/2)
Pause WebProcess on launch
WebProcessMainGtk and WebProcessMainWPE will sleep for 30 seconds if a special environment variable is defined:
It only works
#if ENABLE(DEVELOPER_MODE)
, so you might want to remove those ifdefs if you're building in Release mode.Log tracers
In big pipelines (e.g. playbin) it can be very hard to find what element is replying to a query or handling an event. Even using gdb can be extremely tedious due to the very high level of recursion. Using log tracers is more helpful in this case.
GST_TRACERS=log
enables additional GST_TRACE() calls all accross GStreamer. The following example logs entries and exits into the query function.The names of the logging categories are somewhat inconsistent:
The log tracer code is in
subprojects/gstreamer/plugins/tracers/gstlog.c
.Debugging by using external tools
Use strace to know which config/library files are used by a program
If you're becoming crazy supposing that the program should use some config and it seems to ignore it, just use strace to check what config files, libraries or other kind of files is the program actually using. Use the grep rules you need to refine the search:
Know which process is killing another one
First, try to
strace -e trace=signal -p 1234
the killed process.If that doesn't work (eg: because it's being killed with the uncatchable SIGKILL signal), then you can resort to modifying the kernel source code (signal.c) to log the calls to
kill()
:Wrap gcc/ld/make to tweak build parameters
If you ever find yourself with little time in front of a stubborn build system and, no matter what you try, you can't get the right flags to the compiler, think about putting something (a wrapper) between the build system and the compiler. Example for
g++
:Make sure that the wrappers appear earlier than the real commands in your PATH.
The
make
wrapper can also callremake
instead. Remake is fully compatible with make but has features to help debugging compilation and makefile errors.Analyze the structure of MP4 data
The ISOBMFF Box Structure Viewer online tool allows you to upload an MP4 file and explore its structure.
How to debug pkgconfig
When
pkg-config
finds thePKG_CONFIG_DEBUG_SPEW
env var, it explains all the steps used to resolve the packages:This is useful to know why a particular package isn't found and what are the default values for
PKG_CONFIG_PATH
when it's not defined. For example:If we have tuned
PKG_CONFIG_PATH
, maybe we also want to add the default paths. For example:Man in the middle proxy for WebKit
Sometimes it's useful to use our own modified/unminified files with a 3rd party service we don't control. Mitmproxy can be used as a man-in-the-middle proxy, but I haven't tried it personally yet. What I have tried (with WPE) is this:
/etc/hosts
entry to point the host serving the files we want to change to an IP address controlled by us.- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →Bandwidth control for a dependent device
If your computer has a "shared internet connection" enabled in Network Manager and provides access to a dependent device , you can control the bandwidth offered to that device. This is useful to trigger quality changes on adaptive streaming videos from services out of your control.
This can be done using
tc
, the Traffic Control tool from the Linux kernel. You can use this script to automate the process (edit it to suit to your needs).Useful scripts to process GStreamer logs
I use these scripts in my daily job to look for strange patterns in GStreamer logs that help me to find the cause of the bugs I'm debugging:
h
: Highlights each expression in the command line in a different color.mgrep
: Greps (only) for the lines with the expressions in the command line and highlights each expression in a different color.filter-time
: Gets a subset of the log lines between a start and (optionally) an end GStreamer log timestamp.highlight-threads
: Highlights each thread in a GStreamer log with a different color. That way it's easier to follow a thread with the naked eye.remove-ansi-colors
: Removes the color codes from a colored GStreamer log.aha
: ANSI-HTML-Adapter converts plain text with color codes to HTML, so you can share your GStreamer logs from a web server (eg: for bug discussion). Available in most distros.gstbuffer-leak-analyzer
: Analyzes a GStreamer log and shows unbalances in the creation/destruction of GstBuffer and GstMemory objects.Share your own tricks
Do you use similar tricks in your daily job?
Don't hold them to yourself. Go share them and make the life of your team mates easier.
Thank you!
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →