1/* ide-debug.h.in
2 *
3 * Copyright (C) 2015 Christian Hergert <christian@hergert.me>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef IDE_DEBUG_H
20#define IDE_DEBUG_H
21
22#include <execinfo.h>
23#include <glib.h>
24
25#include "ide-version-macros.h"
26
27G_BEGIN_DECLS
28
29/**
30 * SECTION:ide-debug
31 * @title: Debug logging and tracing
32 * @short_description: tracing and debug facilities for Builder and plugins
33 *
34 * The debug macros such as %IDE_ENTRY, %IDE_EXIT, and %IDE_RETURN provide
35 * helpers for tracing Builder and plugins at runtime.
36 *
37 * These tracing macros will compile out when Builder is configured for a
38 * release build. Otherwise, running Builder with the "-vvvv" command line
39 * argument will show tracing output.
40 *
41 * Since: 3.18
42 */
43
44/**
45 * IDE_ENTRY: (skip)
46 *
47 * Traces the entry into a function. Place this at the beginning of your
48 * function above pre-condition checks.
49 *
50 * Since: 3.18
51 */
52
53/**
54 * IDE_EXIT: (skip)
55 *
56 * Traces the exit from a function. Use this instead of "return" to return
57 * and log the function exiting.
58 *
59 * Since: 3.18
60 */
61
62/**
63 * IDE_RETURN: (skip)
64 *
65 * Similar to %IDE_EXIT but allows providing a return value.
66 *
67 * Since: 3.18
68 */
69
70/**
71 * IDE_GOTO: (skip)
72 * @_l: the label to jump to
73 *
74 * Appends to the jump to label to the tracing log and then jumps
75 * to the label @_l.
76 *
77 * Since: 3.18
78 */
79
80/**
81 * IDE_TODO: (skip)
82 * @_msg: the message to append to the trace log
83 *
84 * Appends to the tracing log that unsupported code has been
85 * reached.
86 *
87 * Since: 3.18
88 */
89
90/**
91 * IDE_PROBE: (skip)
92 *
93 * Appends to the tracing log that a line of code was reached.
94 *
95 * Since: 3.18
96 */
97
98/**
99 * IDE_TRACE_MSG: (skip)
100 *
101 * Similar to %IDE_PROBE but allows specifying a log message.
102 *
103 * Since: 3.18
104 */
105
106#ifndef IDE_ENABLE_TRACE
107# define IDE_ENABLE_TRACE @ENABLE_TRACING@
108#endif
109#if IDE_ENABLE_TRACE != 1
110# undef IDE_ENABLE_TRACE
111#endif
112
113/**
114 * IDE_LOG_LEVEL_TRACE: (skip)
115 */
116#ifndef IDE_LOG_LEVEL_TRACE
117# define IDE_LOG_LEVEL_TRACE ((GLogLevelFlags)(1 << G_LOG_LEVEL_USER_SHIFT))
118#endif
119
120#ifdef IDE_ENABLE_TRACE
121_IDE_EXTERN
122void ide_trace_function (const gchar *strfunc,
123                         gint64       begin_time_usec,
124                         gint64       end_time_usec);
125# define IDE_TRACE_MSG(fmt, ...)                                         \
126   g_log(G_LOG_DOMAIN, IDE_LOG_LEVEL_TRACE, "  MSG: %s():%d: " fmt,      \
127         G_STRFUNC, __LINE__, ##__VA_ARGS__)
128# define IDE_PROBE                                                       \
129   g_log(G_LOG_DOMAIN, IDE_LOG_LEVEL_TRACE, "PROBE: %s():%d",            \
130         G_STRFUNC, __LINE__)
131# define IDE_TODO(_msg)                                                  \
132   g_log(G_LOG_DOMAIN, IDE_LOG_LEVEL_TRACE, " TODO: %s():%d: %s",        \
133         G_STRFUNC, __LINE__, _msg)
134# define IDE_ENTRY                                                       \
135   gint64 __trace_begin_time = g_get_monotonic_time ();                  \
136   g_log(G_LOG_DOMAIN, IDE_LOG_LEVEL_TRACE, "ENTRY: %s():%d",            \
137           G_STRFUNC, __LINE__)
138# define IDE_EXIT                                                        \
139   G_STMT_START {                                                        \
140      ide_trace_function (G_STRFUNC,                                     \
141                          __trace_begin_time,                            \
142                          g_get_monotonic_time ());                      \
143      g_log(G_LOG_DOMAIN, IDE_LOG_LEVEL_TRACE, " EXIT: %s():%d",         \
144            G_STRFUNC, __LINE__);                                        \
145      return;                                                            \
146   } G_STMT_END
147# define IDE_GOTO(_l)                                                    \
148   G_STMT_START {                                                        \
149      g_log(G_LOG_DOMAIN, IDE_LOG_LEVEL_TRACE, " GOTO: %s():%d ("#_l")", \
150            G_STRFUNC, __LINE__);                                        \
151      goto _l;                                                           \
152   } G_STMT_END
153# define IDE_RETURN(_r)                                                  \
154   G_STMT_START {                                                        \
155      ide_trace_function (G_STRFUNC,                                     \
156                          __trace_begin_time,                            \
157                          g_get_monotonic_time ());                      \
158      g_log(G_LOG_DOMAIN, IDE_LOG_LEVEL_TRACE, " EXIT: %s():%d ",        \
159            G_STRFUNC, __LINE__);                                        \
160      return _r;                                                         \
161   } G_STMT_END
162# define IDE_BACKTRACE                                                   \
163  G_STMT_START {                                                         \
164    gpointer btbuf[64];                                                  \
165    int btbuflen = backtrace (btbuf, G_N_ELEMENTS (btbuf));              \
166    char **symnames = backtrace_symbols (btbuf, btbuflen);               \
167    for (guint _i = 0; _i < btbuflen; _i++) {                            \
168      g_log(G_LOG_DOMAIN, IDE_LOG_LEVEL_TRACE, "TRACE: [%-2d]: %s",      \
169            _i, symnames[_i]);                                           \
170    }                                                                    \
171    free (symnames);                                                     \
172  } G_STMT_END
173#else
174# define IDE_TODO(_msg)          G_STMT_START {            } G_STMT_END
175# define IDE_PROBE               G_STMT_START {            } G_STMT_END
176# define IDE_TRACE_MSG(fmt, ...) G_STMT_START {            } G_STMT_END
177# define IDE_ENTRY               G_STMT_START {            } G_STMT_END
178# define IDE_GOTO(_l)            G_STMT_START { goto _l;   } G_STMT_END
179# define IDE_EXIT                G_STMT_START { return;    } G_STMT_END
180# define IDE_RETURN(_r)          G_STMT_START { return _r; } G_STMT_END
181# define IDE_BACKTRACE           G_STMT_START {            } G_STMT_END
182#endif
183
184#define _IDE_BUG(Component, Description, File, Line, Func, ...)                         \
185  G_STMT_START {                                                                        \
186    g_printerr ("-----------------------------------------------------------------\n"); \
187    g_printerr ("You've found a bug in Builder or one of its dependent libraries.\n");  \
188    g_printerr ("Please help us help you by filing a bug report at:\n");                \
189    g_printerr ("\n");                                                                  \
190    g_printerr ("@BUGREPORT_URL@&component=%s\n", Component);                           \
191    g_printerr ("\n");                                                                  \
192    g_printerr ("%s:%d in function %s()\n", File, Line, Func);                          \
193    g_printerr ("\n");                                                                  \
194    g_printerr (Description"\n", ##__VA_ARGS__);                                        \
195    g_printerr ("-----------------------------------------------------------------\n"); \
196  } G_STMT_END
197#define IDE_BUG(Component, Description, ...) \
198  _IDE_BUG(Component, Description, __FILE__, __LINE__, G_STRFUNC, ##__VA_ARGS__)
199
200G_END_DECLS
201
202#endif /* IDE_DEBUG_H */
203