{"id":578,"date":"2021-04-27T07:00:00","date_gmt":"2021-04-27T06:00:00","guid":{"rendered":"https:\/\/eocanha.org\/blog\/?p=578"},"modified":"2021-05-04T18:32:04","modified_gmt":"2021-05-04T17:32:04","slug":"gstreamer-webkit-debugging-by-instrumenting-source-code-1-3","status":"publish","type":"post","link":"https:\/\/eocanha.org\/blog\/2021\/04\/27\/gstreamer-webkit-debugging-by-instrumenting-source-code-1-3\/","title":{"rendered":"GStreamer WebKit debugging by instrumenting source code (1\/3)"},"content":{"rendered":"\n<p>This is the continuation of the GStreamer WebKit debugging tricks post series. In the next three posts, I&#8217;ll focus on what we can get by doing some little changes to the source code for debugging purposes (known as &#8220;instrumenting&#8221;), but before, you might want to check the previous posts of the series:<\/p>\n\n\n\n<ul><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><\/ul>\n\n\n\n<h2>Know all the env vars read by a program by using LD_PRELOAD to intercept libc calls<\/h2>\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=\"\">\/\/ File getenv.c\n\/\/ To compile: gcc -shared -Wall -fPIC -o getenv.so getenv.c -ldl\n\/\/ To use: export LD_PRELOAD=\".\/getenv.so\", then run any program you want\n\/\/ See http:\/\/www.catonmat.net\/blog\/simple-ld-preload-tutorial-part-2\/\n\n#define _GNU_SOURCE\n\n#include &lt;stdio.h>\n#include &lt;dlfcn.h>\n\n\/\/ This function will take the place of the original getenv() in libc\nchar *getenv(const char *name) {\n printf(\"Calling getenv(\\\"%s\\\")\\n\", name);\n\n char *(*original_getenv)(const char*);\n original_getenv = dlsym(RTLD_NEXT, \"getenv\");\n\n return (*original_getenv)(name);\n}<\/pre>\n\n\n\n<p>See the breakpoints with command example to know how to get the same using gdb. Check also Zan&#8217;s <a href=\"https:\/\/github.com\/zdobersek\/libpine\">libpine<\/a> for more features.<\/p>\n\n\n\n<h2>Track lifetime of GObjects by LD_PRELOADing gobject-list<\/h2>\n\n\n\n<p>The <a href=\"https:\/\/github.com\/thiblahute\/gobject-list\/tree\/meson\">gobject-list project<\/a>, 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.<\/p>\n\n\n\n<h2>Overriding the behaviour of a debugging macro<\/h2>\n\n\n\n<p>The usual debugging macros aren&#8217;t printing messages? Redefine them to make what you want:<\/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=\"\">#undef LOG_MEDIA_MESSAGE\n#define LOG_MEDIA_MESSAGE(...) do { \\\n  printf(\"LOG %s: \", __PRETTY_FUNCTION__); \\\n  printf(__VA_ARGS__); \\\n  printf(\"\\n\"); \\\n  fflush(stdout); \\\n} while(0)<\/pre>\n\n\n\n<p>This can be done to enable asserts on demand in WebKit too:<\/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=\"\">#undef ASSERT\n#define ASSERT(assertion) \\\n  (!(assertion) ? \\\n      (WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion), \\\n       CRASH()) : \\\n      (void)0)\n\n#undef ASSERT_NOT_REACHED\n#define ASSERT_NOT_REACHED() do { \\\n  WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, 0); \\\n  CRASH(); \\\n} while (0)<\/pre>\n\n\n\n<p>It may be interesting to enable WebKit <code>LOG()<\/code> and GStreamer <code>GST_DEBUG()<\/code> macros only on selected files:<\/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 LOG(channel, msg, ...) do { \\\n  printf(\"%s: \", #channel); \\\n  printf(msg, ## __VA_ARGS__); \\\n  printf(\"\\n\"); \\\n  fflush(stdout); \\\n} while (false)\n\n#define _GST_DEBUG(msg, ...) do { \\\n  printf(\"### %s: \", __PRETTY_FUNCTION__); \\\n  printf(msg, ## __VA_ARGS__); \\\n  printf(\"\\n\"); \\\n  fflush(stdout); \\\n} while (false)<\/pre>\n\n\n\n<p>Note all the preprocessor trickery used here:<\/p>\n\n\n\n<ul><li>First arguments (channel, msg) are captured intependently<\/li><li>The remaining args are captured in <code>__VA_ARGS__<\/code><\/li><li><code>do while(false)<\/code> is a trick to avoid {braces} and make the code block work when used in if\/then\/else one-liners<\/li><li><code>#channel<\/code> expands <code>LOG(MyChannel,....)<\/code> as <code>printf(\"%s: \", \"MyChannel\")<\/code>. It&#8217;s called &#8220;stringification&#8221;.<\/li><li><code>## __VA_ARGS__<\/code> expands the variable argument list as a comma-separated list of items, but if the list is empty, it eats the comma after &#8220;msg&#8221;, preventing syntax errors<\/li><\/ul>\n\n\n\n<h2>Print the compile-time type of an expression<\/h2>\n\n\n\n<p>Use <code>typeid(&lt;expression&gt;).name()<\/code>. Filter the ouput through <code>c++filt -t<\/code>:<\/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=\"\">std::vector&lt;char *> v; \nprintf(\"Type: %s\\n\", typeid(v.begin()).name());<\/pre>\n\n\n\n<h2>Abusing the compiler to know all the places where a function is called<\/h2>\n\n\n\n<p>If you want to know all the places from where the <code>GstClockTime toGstClockTime(float time)<\/code> function is called, you can convert it to a template function and use <code>static_assert<\/code> on a wrong datatype like this (in the .h):<\/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=\"\">template &lt;typename T = float> GstClockTime toGstClockTime(float time) { \n  static_assert(std::is_integral&lt;T>::value,\n    \"Don't call toGstClockTime(float)!\");\n  return 0;\n}<\/pre>\n\n\n\n<p>Note that <code>T=float<\/code> is different to <code>integer<\/code> (<code>is_integral<\/code>). It has nothing to do with the <code>float time<\/code> parameter declaration.<\/p>\n\n\n\n<p>You will get compile-time errors like this on every place the function is used:<\/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=\"\">WebKitMediaSourceGStreamer.cpp:474:87:   required from here\nGStreamerUtilities.h:84:43: error: static assertion failed: Don't call toGstClockTime(float)!<\/pre>\n\n\n\n<h2>Use pragma message to print values at compile time<\/h2>\n\n\n\n<p>Sometimes is useful to know if a particular define is enabled:<\/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;limits.h>\n\n#define _STR(x) #x\n#define STR(x) _STR(x)\n\n#pragma message \"Int max is \" STR(INT_MAX)\n\n#ifdef WHATEVER\n#pragma message \"Compilation goes by here\"\n#else\n#pragma message \"Compilation goes by there\"\n#endif\n\n...<\/pre>\n\n\n\n<p>The code above would generate this output:<\/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=\"\">test.c:6:9: note: #pragma message: Int max is 0x7fffffff\n #pragma message \"Int max is \" STR(INT_MAX)\n         ^~~~~~~\ntest.c:11:9: note: #pragma message: Compilation goes by there\n #pragma message \"Compilation goes by there\"\n         ^~~~~~~<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>This is the continuation of the GStreamer WebKit debugging tricks post series. In the next three posts, I&#8217;ll focus on what we can get by doing some little changes to the source code for debugging purposes (known as &#8220;instrumenting&#8221;), but before, you might want to check the previous posts of the series: GStreamer WebKit debugging &hellip; <a href=\"https:\/\/eocanha.org\/blog\/2021\/04\/27\/gstreamer-webkit-debugging-by-instrumenting-source-code-1-3\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">GStreamer WebKit debugging by instrumenting source code (1\/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\/578"}],"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=578"}],"version-history":[{"count":4,"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/posts\/578\/revisions"}],"predecessor-version":[{"id":612,"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/posts\/578\/revisions\/612"}],"wp:attachment":[{"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/media?parent=578"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/categories?post=578"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eocanha.org\/blog\/wp-json\/wp\/v2\/tags?post=578"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}