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()