core: Protect the trace macros for fun and profit.
[gpgme.git] / src / debug.h
1 /* debug.h - interface to debugging functions
2    Copyright (C) 2002, 2004, 2005, 2007 g10 Code GmbH
3
4    This file is part of GPGME.
5
6    GPGME is free software; you can redistribute it and/or modify it
7    under the terms of the GNU Lesser General Public License as
8    published by the Free Software Foundation; either version 2.1 of
9    the License, or (at your option) any later version.
10
11    GPGME is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19    02111-1307, USA.  */
20
21 #ifndef DEBUG_H
22 #define DEBUG_H
23
24 #include <string.h>
25 #ifdef HAVE_STDINT_H
26 #include <stdint.h>
27 #endif
28
29 #include "gpgme.h"  /* Required for gpgme_error stuff.  */
30
31
32 /* Indirect stringification, requires __STDC__ to work.  */
33 #define STRINGIFY(v) #v
34 #define XSTRINGIFY(v) STRINGIFY(v)
35
36 \f
37 /*
38  * The debug levels.
39  *
40  * Note that TRACE_LOGBUFX uses the current debug level + 1.
41  */
42
43 #define DEBUG_INIT      1
44 #define DEBUG_GLOBAL    2
45 #define DEBUG_CTX       3
46 #define DEBUG_ENGINE    4
47 #define DEBUG_DATA      5
48 #define DEBUG_ASSUAN    6
49 #define DEBUG_SYSIO     7
50
51 \f
52 /* Remove path components from filenames (i.e. __FILE__) for cleaner
53    logs. */
54 static inline const char *_gpgme_debug_srcname (const char *file)
55                                                 GPGME_GCC_A_PURE;
56
57 static inline const char *
58 _gpgme_debug_srcname (const char *file)
59 {
60   const char *s = strrchr (file, '/');
61   return s? s+1:file;
62 }
63
64 /* Initialization helper function; see debug.c.  */
65 int _gpgme_debug_set_debug_envvar (const char *value);
66
67 /* Called early to initialize the logging.  */
68 void _gpgme_debug_subsystem_init (void);
69
70 /* Log the formatted string FORMAT at debug level LEVEL or higher.  */
71 int  _gpgme_debug (int level, int mode,
72                    const char *func, const char *tagname, const char *tagvalue,
73                    const char *format, ...) GPGRT_ATTR_PRINTF(6,7);
74
75
76 /* Start a new debug line in *LINE, logged at level LEVEL or higher,
77    and starting with the formatted string FORMAT.  */
78 void _gpgme_debug_begin (void **helper, int level, const char *format, ...);
79
80 /* Add the formatted string FORMAT to the debug line *LINE.  */
81 void _gpgme_debug_add (void **helper, const char *format, ...);
82
83 /* Finish construction of *LINE and send it to the debug output
84    stream.  */
85 void _gpgme_debug_end (void **helper);
86
87 void _gpgme_debug_buffer (int lvl, const char *const fmt,
88                           const char *const func, const char *const buffer,
89                           size_t len);
90
91 void _gpgme_debug_frame_begin (void);
92 int  _gpgme_debug_frame_end (void);
93
94 static inline gpgme_error_t
95 _gpgme_trace_gpgme_error (gpgme_error_t err, const char *file, int line)
96 {
97   _gpgme_debug (DEBUG_ENGINE, -1, NULL, NULL, NULL,
98                 "%s:%d: returning error: %s\n",
99                 _gpgme_debug_srcname (file), line, gpgme_strerror (err));
100   return err;
101 }
102
103 \f
104 /* Trace support.  */
105
106 /* FIXME: For now.  */
107 #define _gpgme_debug_trace() 1
108
109 #define _TRACE(lvl, name, tag)                                  \
110   int _gpgme_trace_level = lvl;                                 \
111   const char *const _gpgme_trace_func = name;                   \
112   const char *const _gpgme_trace_tagname = STRINGIFY (tag);     \
113   void *_gpgme_trace_tag = (void *) (uintptr_t) tag; \
114   _gpgme_debug_frame_begin ()
115
116 /* Note: We can't protect this with a do-while block.  */
117 #define TRACE_BEG(lvl, name, tag, ...)                                  \
118   _TRACE (lvl, name, tag);                                              \
119   _gpgme_debug (_gpgme_trace_level, 1,                                  \
120                 _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \
121                 __VA_ARGS__)
122
123 #define TRACE(lvl, name, tag, ...) do {                                 \
124     _gpgme_debug_frame_begin ();                                        \
125     _gpgme_debug (lvl, 0, name, STRINGIFY (tag), (void *)(uintptr_t)tag, \
126                   __VA_ARGS__);                                         \
127     _gpgme_debug_frame_end ();                                          \
128   } while (0)
129
130
131 /* Trace a gpg-error and return it.  */
132 #define TRACE_ERR(err) \
133     _trace_err ((err), _gpgme_trace_level, _gpgme_trace_func, __LINE__)
134 static inline gpg_error_t
135 _trace_err (gpg_error_t err, int lvl, const char *func, int line)
136 {
137   if (!err)
138     _gpgme_debug (lvl, 3, func, NULL, NULL, "");
139   else
140     _gpgme_debug (lvl, -1, NULL, NULL, NULL,
141                   "%s:%d: error: %s <%s>\n",
142                   func, line,  gpgme_strerror (err), gpgme_strsource (err));
143   _gpgme_debug_frame_end ();
144   return err;
145 }
146
147 /* Trace a system call result and return it.  */
148 #define TRACE_SYSRES(res) \
149     _trace_sysres ((res), _gpgme_trace_level, _gpgme_trace_func, __LINE__)
150 static inline int
151 _trace_sysres (int res, int lvl, const char *func, int line)
152 {
153   if (res >= 0)
154     _gpgme_debug (lvl, 3, func, NULL, NULL, "result=%d", res);
155   else
156     _gpgme_debug (lvl, -1, NULL, NULL, NULL,
157                   "%s:%d: error: %s (%d)\n",
158                   func, line,  strerror (res), res);
159   _gpgme_debug_frame_end ();
160   return res;
161 }
162
163 /* Trace a system call error and return it.  */
164 #define TRACE_SYSERR(rc) \
165     _trace_syserr ((rc), _gpgme_trace_level, _gpgme_trace_func, __LINE__)
166 static inline int
167 _trace_syserr (int rc, int lvl, const char *func, int line)
168 {
169   if (!rc)
170     _gpgme_debug (lvl, 3, func, NULL, NULL, "result=0");
171   else
172     _gpgme_debug (lvl, -1, NULL, NULL, NULL,
173                   "%s:%d: error: %s (%d)\n",
174                   func, line, strerror (rc), rc);
175   _gpgme_debug_frame_end ();
176   return rc;
177 }
178
179 #define TRACE_SUC(...) do {                                             \
180     _gpgme_debug (_gpgme_trace_level, 3, _gpgme_trace_func, NULL, NULL, \
181                   __VA_ARGS__);                                         \
182     _gpgme_debug_frame_end ();                                          \
183   } while (0)
184
185 #define TRACE_LOG(...) do {                                             \
186     _gpgme_debug (_gpgme_trace_level, 2,                                \
187                   _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \
188                   __VA_ARGS__);                                         \
189   } while (0)
190
191 #define TRACE_LOGBUF(buf, len) do {                             \
192     _gpgme_debug_buffer (_gpgme_trace_level, "%s: check: %s",   \
193                          _gpgme_trace_func, buf, len);          \
194   } while (0)
195
196 #define TRACE_LOGBUFX(buf, len) do {                                    \
197     _gpgme_debug_buffer (_gpgme_trace_level+1, "%s: check: %s",         \
198                          _gpgme_trace_func, buf, len); \
199   } while (0)
200
201 #define TRACE_SEQ(hlp,fmt) do {                                         \
202     _gpgme_debug_begin (&(hlp), _gpgme_trace_level,                     \
203                         "%s: check: %s=%p, " fmt, _gpgme_trace_func,    \
204                         _gpgme_trace_tagname, _gpgme_trace_tag);        \
205   } while (0)
206
207 #define TRACE_ADD0(hlp,fmt) \
208   _gpgme_debug_add (&(hlp), fmt)
209 #define TRACE_ADD1(hlp,fmt,a) \
210   _gpgme_debug_add (&(hlp), fmt, (a))
211 #define TRACE_ADD2(hlp,fmt,a,b) \
212   _gpgme_debug_add (&(hlp), fmt, (a), (b))
213 #define TRACE_ADD3(hlp,fmt,a,b,c) \
214   _gpgme_debug_add (&(hlp), fmt, (a), (b), (c))
215 #define TRACE_END(hlp,fmt) \
216   _gpgme_debug_add (&(hlp), fmt); \
217   _gpgme_debug_end (&(hlp))
218
219 #define TRACE_ENABLED(hlp) (!!(hlp))
220
221 /* And finally a simple macro to trace the location of an error code.
222    This macro is independent of the other trace macros and may be used
223    without any preconditions.  */
224 #define trace_gpg_error(e) \
225   _gpgme_trace_gpgme_error (gpg_error (e), __FILE__, __LINE__)
226
227
228 #endif  /* DEBUG_H */