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 #include <errno.h>
29
30 #include "gpgme.h" /* Required for gpgme_error stuff. */
31
32
33 /* Indirect stringification, requires __STDC__ to work. */
34 #define STRINGIFY(v) #v
35 #define XSTRINGIFY(v) STRINGIFY(v)
36
37
38 /*
39 * The debug levels.
40 *
41 * Note that TRACE_LOGBUFX uses the current debug level + 1.
42 */
43
44 #define DEBUG_INIT 1
45 #define DEBUG_GLOBAL 2
46 #define DEBUG_CTX 3
47 #define DEBUG_ENGINE 4
48 #define DEBUG_DATA 5
49 #define DEBUG_ASSUAN 6
50 #define DEBUG_SYSIO 7
51
52
53 /* Remove path components from filenames (i.e. __FILE__) for cleaner
54 logs. */
55 static inline const char *_gpgme_debug_srcname (const char *file)
56 GPGME_GCC_A_PURE;
57
58 static inline const char *
_gpgme_debug_srcname(const char * file)59 _gpgme_debug_srcname (const char *file)
60 {
61 const char *s = strrchr (file, '/');
62 return s? s+1:file;
63 }
64
65 /* Initialization helper function; see debug.c. */
66 int _gpgme_debug_set_debug_envvar (const char *value);
67
68 /* Called early to initialize the logging. */
69 void _gpgme_debug_subsystem_init (void);
70
71 /* Log the formatted string FORMAT at debug level LEVEL or higher. */
72 int _gpgme_debug (void **line, int level, int mode,
73 const char *func, const char *tagname, const char *tagvalue,
74 const char *format, ...) GPGRT_ATTR_PRINTF(7,8);
75
76
77 /* Add the formatted string FORMAT to the debug line *LINE. */
78 void _gpgme_debug_add (void **helper, const char *format, ...);
79
80 /* Finish construction of *LINE and send it to the debug output
81 stream. */
82 void _gpgme_debug_end (void **helper);
83
84 void _gpgme_debug_buffer (int lvl, const char *const fmt,
85 const char *const func, const char *const buffer,
86 size_t len);
87
88 void _gpgme_debug_frame_begin (void);
89 int _gpgme_debug_frame_end (void);
90
91 static inline gpgme_error_t
_gpgme_trace_gpgme_error(gpgme_error_t err,const char * file,int line)92 _gpgme_trace_gpgme_error (gpgme_error_t err, const char *file, int line)
93 {
94 _gpgme_debug (NULL, DEBUG_ENGINE, -1, NULL, NULL, NULL,
95 "%s:%d: returning error: %s\n",
96 _gpgme_debug_srcname (file), line, gpgme_strerror (err));
97 return err;
98 }
99
100
101 /* Trace support. */
102
103 /* FIXME: For now. */
104 #define _gpgme_debug_trace() 1
105
106 #define _TRACE(lvl, name, tag) \
107 int _gpgme_trace_level = lvl; \
108 const char *const _gpgme_trace_func = name; \
109 const char *const _gpgme_trace_tagname = STRINGIFY (tag); \
110 void *_gpgme_trace_tag = (void *) (uintptr_t) tag; \
111 _gpgme_debug_frame_begin ()
112
113 /* Note: We can't protect this with a do-while block. */
114 #define TRACE_BEG(lvl, name, tag, ...) \
115 _TRACE (lvl, name, tag); \
116 _gpgme_debug (NULL, _gpgme_trace_level, 1, \
117 _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \
118 __VA_ARGS__)
119
120 #define TRACE(lvl, name, tag, ...) do { \
121 _gpgme_debug_frame_begin (); \
122 _gpgme_debug (NULL, lvl, 0, name, STRINGIFY (tag), (void *)(uintptr_t)tag, \
123 __VA_ARGS__); \
124 _gpgme_debug_frame_end (); \
125 } while (0)
126
127
128 /* Trace a gpg-error and return it. */
129 #define TRACE_ERR(err) \
130 _trace_err ((err), _gpgme_trace_level, _gpgme_trace_func, __LINE__)
131 static inline gpg_error_t
_trace_err(gpg_error_t err,int lvl,const char * func,int line)132 _trace_err (gpg_error_t err, int lvl, const char *func, int line)
133 {
134 if (!err)
135 _gpgme_debug (NULL, lvl, 3, func, NULL, NULL, "");
136 else
137 _gpgme_debug (NULL, lvl, -1, NULL, NULL, NULL,
138 "%s:%d: error: %s <%s>\n",
139 func, line, gpgme_strerror (err), gpgme_strsource (err));
140 _gpgme_debug_frame_end ();
141 return err;
142 }
143
144 /* Trace a system call result and return it. */
145 #define TRACE_SYSRES(res) \
146 _trace_sysres ((res), _gpgme_trace_level, _gpgme_trace_func, __LINE__)
147 static inline int
_trace_sysres(int res,int lvl,const char * func,int line)148 _trace_sysres (int res, int lvl, const char *func, int line)
149 {
150 if (res >= 0)
151 _gpgme_debug (NULL, lvl, 3, func, NULL, NULL, "result=%d", res);
152 else
153 _gpgme_debug (NULL, lvl, -1, NULL, NULL, NULL,
154 "%s:%d: error: %s (%d)\n",
155 func, line, strerror (errno), errno);
156 _gpgme_debug_frame_end ();
157 return res;
158 }
159
160 /* Trace a system call error and return it. */
161 #define TRACE_SYSERR(rc) \
162 _trace_syserr ((rc), _gpgme_trace_level, _gpgme_trace_func, __LINE__)
163 static inline int
_trace_syserr(int rc,int lvl,const char * func,int line)164 _trace_syserr (int rc, int lvl, const char *func, int line)
165 {
166 if (!rc)
167 _gpgme_debug (NULL, lvl, 3, func, NULL, NULL, "result=0");
168 else
169 _gpgme_debug (NULL, lvl, -1, NULL, NULL, NULL,
170 "%s:%d: error: %s (%d)\n",
171 func, line, strerror (rc), rc);
172 _gpgme_debug_frame_end ();
173 return rc;
174 }
175
176 #define TRACE_SUC(...) do { \
177 _gpgme_debug (NULL, _gpgme_trace_level, 3, _gpgme_trace_func, NULL, NULL, \
178 __VA_ARGS__); \
179 _gpgme_debug_frame_end (); \
180 } while (0)
181
182 #define TRACE_LOG(...) do { \
183 _gpgme_debug (NULL, _gpgme_trace_level, 2, \
184 _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \
185 __VA_ARGS__); \
186 } while (0)
187
188 #define TRACE_LOGBUF(buf, len) do { \
189 _gpgme_debug_buffer (_gpgme_trace_level, "%s: check: %s", \
190 _gpgme_trace_func, buf, len); \
191 } while (0)
192
193 #define TRACE_LOGBUFX(buf, len) do { \
194 _gpgme_debug_buffer (_gpgme_trace_level+1, "%s: check: %s", \
195 _gpgme_trace_func, buf, len); \
196 } while (0)
197
198 #define TRACE_SEQ(hlp,...) do { \
199 _gpgme_debug (&(hlp), _gpgme_trace_level, 2, _gpgme_trace_func, \
200 _gpgme_trace_tagname, _gpgme_trace_tag, __VA_ARGS__); \
201 } while (0)
202
203 #define TRACE_ADD0(hlp,fmt) \
204 _gpgme_debug_add (&(hlp), fmt)
205 #define TRACE_ADD1(hlp,fmt,a) \
206 _gpgme_debug_add (&(hlp), fmt, (a))
207 #define TRACE_ADD2(hlp,fmt,a,b) \
208 _gpgme_debug_add (&(hlp), fmt, (a), (b))
209 #define TRACE_ADD3(hlp,fmt,a,b,c) \
210 _gpgme_debug_add (&(hlp), fmt, (a), (b), (c))
211 #define TRACE_END(hlp,fmt) \
212 _gpgme_debug_add (&(hlp), fmt); \
213 _gpgme_debug_end (&(hlp))
214
215 #define TRACE_ENABLED(hlp) (!!(hlp))
216
217 /* And finally a simple macro to trace the location of an error code.
218 This macro is independent of the other trace macros and may be used
219 without any preconditions. */
220 #define trace_gpg_error(e) \
221 _gpgme_trace_gpgme_error (gpg_error (e), __FILE__, __LINE__)
222
223
224 #endif /* DEBUG_H */
225