In this post I show some more useful debugging tricks. Check also the other posts of the series:
- GStreamer WebKit debugging tricks using GDB (1/2)
- GStreamer WebKit debugging tricks using GDB (2/2)
- GStreamer WebKit debugging by instrumenting source code (1/3)
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.
#include <stdio.h> #include <unistd.h> #include <sys/syscall.h> printf("%s [%d]\n", __PRETTY_FUNCTION__, syscall(SYS_gettid)); fflush(stdout);
Debug GStreamer thread locks
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:
#include "wtf/Threading.h" #define GST_OBJECT_LOCK(obj) do { \ printf("### [LOCK] %s [%p]\n", __PRETTY_FUNCTION__, &Thread::current()); fflush(stdout); \ g_mutex_lock(GST_OBJECT_GET_LOCK(obj)); \ } while (0) #define GST_OBJECT_UNLOCK(obj) do { \ printf("### [UNLOCK] %s [%p]\n", __PRETTY_FUNCTION__, &Thread::current()); fflush(stdout); \ g_mutex_unlock(GST_OBJECT_GET_LOCK(obj)); \ } while (0) #define GST_OBJECT_TRYLOCK(obj) ({ \ gboolean result = g_mutex_trylock(GST_OBJECT_GET_LOCK(obj)); \ if (result) { \ printf("### [LOCK] %s [%p]\n", __PRETTY_FUNCTION__, &Thread::current()); fflush(stdout); \ } \ result; \ })
Warning: The statement expression that allows the TRYLOCK
macro to return a value will only work on GCC.
There’s a way to know which thread has taken a lock in glib/GStreamer using gdb. First locate the stalled thread:
(gdb) thread (gdb) bt #2 0x74f07416 in pthread_mutex_lock () #3 0x7488aec6 in gst_pad_query () #4 0x6debebf2 in autoplug_query_allocation () (gdb) frame 3 #3 0x7488aec6 in gst_pad_query (pad=pad@entry=0x54a9b8, ...) 4058 GST_PAD_STREAM_LOCK (pad);
Now get the process id (PID) and use the pthread_mutex_t structure to print the Linux thread id that has acquired the lock:
(gdb) call getpid() $30 = 6321 (gdb) p ((pthread_mutex_t*)pad.stream_rec_lock.p)->__data.__owner $31 = 6368 (gdb) thread find 6321.6368 Thread 21 has target id 'Thread 6321.6368'
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:
#define MYTRACER() MyTracer(__PRETTY_FUNCTION__); class MyTracer { public: MyTracer(const gchar* functionName) : m_functionName(functionName) { printf("### %s : begin %d\n", m_functionName.utf8().data(), currentThread()); fflush(stdout); } virtual ~MyTracer() { printf("### %s : end %d\n", m_functionName.utf8().data(), currentThread()); fflush(stdout); } private: String m_functionName; };
And use it like this in all the functions you want to trace:
void somefunction() { MYTRACER(); // Some other code... }
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:
(gdb) signal 0 (gdb) continue
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:
(gdb) thread apply all bt [now search for "raise" in the terminal log] Thread 36 (Thread 1977.2033): #1 0x74f5b3f2 in raise () from /home/enrique/buildroot/output2/staging/lib/libpthread.so.0 (gdb) thread 36
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:
(gdb) set scheduler-locking on (gdb) next // Repeat several times...
Know the name of a GStreamer function stored in a pointer at runtime
Just use this macro:
GST_DEBUG_FUNCPTR_NAME(func)
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:
LEAK: 2 XMLHttpRequest LEAK: 25 CachedResource LEAK: 3820 WebCoreNode
To use it you have to modify the particular class you want to debug:
- Include
wtf/RefCountedLeakCounter.h
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, myClassCounter, ("MyClass"));
- In the constructor:
myClassCounter.increment()
- In the destructor:
myClassCounter.decrement()