{"id":582,"date":"2021-05-04T07:00:00","date_gmt":"2021-05-04T06:00:00","guid":{"rendered":"https:\/\/eocanha.org\/blog\/?p=582"},"modified":"2021-05-04T18:31:23","modified_gmt":"2021-05-04T17:31:23","slug":"gstreamer-webkit-debugging-by-instrumenting-source-code-2-3","status":"publish","type":"post","link":"https:\/\/eocanha.org\/blog\/2021\/05\/04\/gstreamer-webkit-debugging-by-instrumenting-source-code-2-3\/","title":{"rendered":"GStreamer WebKit debugging by instrumenting source code (2\/3)"},"content":{"rendered":"\n<p>In this post I show some more useful debugging tricks. Check also the other posts of the series:<\/p>\n\n\n\n<ul id=\"block-b42f86ed-cff9-42e2-b084-bd3cfb76f92c\"><li><a href=\"https:\/\/eocanha.org\/blog\/2021\/04\/13\/gstreamer-webkit-debugging-tricks-using-gdb-1-2\/\">GStreamer WebKit debugging tricks using GDB (1\/2)<\/a><\/li><li><a href=\"https:\/\/eocanha.org\/blog\/2021\/04\/20\/gstreamer-webkit-debugging-tricks-using-gdb-2-2\/\">GStreamer WebKit debugging tricks using GDB (2\/2)<\/a><\/li><li><a href=\"https:\/\/eocanha.org\/blog\/2021\/04\/27\/gstreamer-webkit-debugging-by-instrumenting-source-code-1-3\/\">GStreamer WebKit debugging by instrumenting source code (1\/3)<\/a><\/li><\/ul>\n\n\n\n<h2>Print current thread id<\/h2>\n\n\n\n<p>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.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;stdio.h>\n#include &lt;unistd.h>\n#include &lt;sys\/syscall.h>\n\nprintf(\"%s [%d]\\n\", __PRETTY_FUNCTION__, syscall(SYS_gettid));\nfflush(stdout);<\/pre>\n\n\n\n<h2>Debug GStreamer thread locks<\/h2>\n\n\n\n<p>We redefine the <code>GST_OBJECT_LOCK<\/code>\/<code>UNLOCK<\/code>\/<code>TRYLOCK<\/code> macros to print the calls, compare locks against unlocks, and see who&#8217;s not releasing its lock:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include \"wtf\/Threading.h\"\n#define GST_OBJECT_LOCK(obj) do { \\\n  printf(\"### [LOCK] %s [%p]\\n\", __PRETTY_FUNCTION__, &amp;Thread::current()); fflush(stdout); \\\n  g_mutex_lock(GST_OBJECT_GET_LOCK(obj)); \\\n} while (0)\n#define GST_OBJECT_UNLOCK(obj) do { \\\n  printf(\"### [UNLOCK] %s [%p]\\n\", __PRETTY_FUNCTION__, &amp;Thread::current()); fflush(stdout); \\\n  g_mutex_unlock(GST_OBJECT_GET_LOCK(obj)); \\\n} while (0)\n#define GST_OBJECT_TRYLOCK(obj) ({ \\\n  gboolean result = g_mutex_trylock(GST_OBJECT_GET_LOCK(obj)); \\\n  if (result) { \\\n   printf(\"### [LOCK] %s [%p]\\n\", __PRETTY_FUNCTION__, &amp;Thread::current()); fflush(stdout); \\\n  } \\\n  result; \\\n})<\/pre>\n\n\n\n<p>Warning: The <a href=\"https:\/\/gcc.gnu.org\/onlinedocs\/gcc\/Statement-Exprs.html\">statement expression<\/a> that allows the <code>TRYLOCK<\/code> macro to return a value will only work on GCC.<\/p>\n\n\n\n<p>There&#8217;s a way to know which thread has taken a lock in glib\/GStreamer using gdb. First locate the stalled thread:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">(gdb) thread \n(gdb) bt\n#2  0x74f07416 in pthread_mutex_lock ()\n#3  0x7488aec6 in gst_pad_query ()\n#4  0x6debebf2 in autoplug_query_allocation ()\n\n(gdb) frame 3\n#3  0x7488aec6 in gst_pad_query (pad=pad@entry=0x54a9b8, ...)\n4058        GST_PAD_STREAM_LOCK (pad);<\/pre>\n\n\n\n<p>Now get the process id (PID) and use the pthread_mutex_t structure to print the Linux thread id that has acquired the lock:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">(gdb) call getpid()\n$30 = 6321\n(gdb) p ((pthread_mutex_t*)pad.stream_rec_lock.p)->__data.__owner\n$31 = 6368\n(gdb) thread find 6321.6368\nThread 21 has target id 'Thread 6321.6368'<\/pre>\n\n\n\n<h2>Trace function calls (poor developer version)<\/h2>\n\n\n\n<p>If you&#8217;re using C++, you can define a tracer class. This is for webkit, but you get the idea:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#define MYTRACER() MyTracer(__PRETTY_FUNCTION__);\nclass MyTracer {\npublic:\n    MyTracer(const gchar* functionName)\n      : m_functionName(functionName) {\n      printf(\"### %s : begin %d\\n\", m_functionName.utf8().data(), currentThread()); fflush(stdout);\n    }\n    virtual ~MyTracer() {\n        printf(\"### %s : end %d\\n\", m_functionName.utf8().data(), currentThread()); fflush(stdout);\n    }\nprivate:\n    String m_functionName;\n};<\/pre>\n\n\n\n<p>And use it like this in all the functions you want to trace:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">void somefunction() {\n  MYTRACER();\n  \/\/ Some other code...\n}<\/pre>\n\n\n\n<p>The constructor will log when the execution flow enters into the function and the destructor will log when the flow exits.<\/p>\n\n\n\n<h2>Setting breakpoints from C<\/h2>\n\n\n\n<p>In the C code, just call <code>raise(SIGINT)<\/code> (simulate CTRL+C, normally the program would finish).<\/p>\n\n\n\n<p>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:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">(gdb) signal 0\n(gdb) continue<\/pre>\n\n\n\n<p>There&#8217;s a way to do the same but attaching gdb after the raise. Use <code>raise(SIGSTOP)<\/code> instead (simulate CTRL+Z). Then attach gdb, locate the thread calling raise and switch to it:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">(gdb) thread apply all bt\n[now search for \"raise\" in the terminal log]\nThread 36 (Thread 1977.2033): #1 0x74f5b3f2 in raise () from \/home\/enrique\/buildroot\/output2\/staging\/lib\/libpthread.so.0\n(gdb) thread 36<\/pre>\n\n\n\n<p>Now, from a terminal, send a continuation signal: <code>kill -SIGCONT 1977<\/code>. Finally instruct gdb to single-step only the current thread (IMPORTANT!) and run some steps until all the raises have been processed:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">(gdb) set scheduler-locking on\n(gdb) next    \/\/ Repeat several times...<\/pre>\n\n\n\n<h2>Know the name of a GStreamer function stored in a pointer at runtime<\/h2>\n\n\n\n<p>Just use this macro:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">GST_DEBUG_FUNCPTR_NAME(func)<\/pre>\n\n\n\n<h2>Detecting memory leaks in WebKit<\/h2>\n\n\n\n<p><a href=\"https:\/\/github.com\/WebKit\/WebKit\/blob\/main\/Source\/WTF\/wtf\/RefCountedLeakCounter.h\">RefCountedLeakCounter<\/a> is a tool class that can help to debug reference leaks by printing this kind of messages when WebKit exits:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">  LEAK: 2 XMLHttpRequest\n  LEAK: 25 CachedResource\n  LEAK: 3820 WebCoreNode<\/pre>\n\n\n\n<p>To use it you have to modify the particular class you want to debug:<\/p>\n\n\n\n<ul><li>Include <code>wtf\/RefCountedLeakCounter.h<\/code><\/li><li><code>DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, myClassCounter, (\"MyClass\"));<\/code><\/li><li>In the constructor: <code>myClassCounter.increment()<\/code><\/li><li>In the destructor: <code>myClassCounter.decrement()<\/code><\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>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 &hellip; <a href=\"https:\/\/eocanha.org\/blog\/2021\/05\/04\/gstreamer-webkit-debugging-by-instrumenting-source-code-2-3\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">GStreamer WebKit debugging by instrumenting source code (2\/3)<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[11,13,2,1,7,12],"tags":[20],"_links":{"self":[{"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/posts\/582"}],"collection":[{"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/comments?post=582"}],"version-history":[{"count":6,"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/posts\/582\/revisions"}],"predecessor-version":[{"id":611,"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/posts\/582\/revisions\/611"}],"wp:attachment":[{"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/media?parent=582"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/categories?post=582"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/tags?post=582"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}