Fixed some issues found by winapi_check.
[wine/dcerpc.git] / dlls / ntdll / debugtools.c
blobc10cf531eed5b852e97b6a9342ee717bfbad6fae
1 /*
2 * Debugging functions
4 * Copyright 2000 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but 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.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <ctype.h>
31 #include "wine/debug.h"
32 #include "wine/exception.h"
33 #include "wine/library.h"
34 #include "wine/unicode.h"
35 #include "thread.h"
36 #include "winbase.h"
37 #include "winnt.h"
38 #include "ntddk.h"
39 #include "msvcrt/excpt.h"
41 WINE_DECLARE_DEBUG_CHANNEL(tid);
43 /* ---------------------------------------------------------------------- */
45 struct debug_info
47 char *str_pos; /* current position in strings buffer */
48 char *out_pos; /* current position in output buffer */
49 char strings[1024]; /* buffer for temporary strings */
50 char output[1024]; /* current output line */
53 static struct debug_info initial_thread_info; /* debug info for initial thread */
55 /* filter for page-fault exceptions */
56 static WINE_EXCEPTION_FILTER(page_fault)
58 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
59 return EXCEPTION_EXECUTE_HANDLER;
60 return EXCEPTION_CONTINUE_SEARCH;
63 /* get the debug info pointer for the current thread */
64 static inline struct debug_info *get_info(void)
66 struct debug_info *info = NtCurrentTeb()->debug_info;
68 if (!info) NtCurrentTeb()->debug_info = info = &initial_thread_info;
69 if (!info->str_pos)
71 info->str_pos = info->strings;
72 info->out_pos = info->output;
74 return info;
77 /* allocate some tmp space for a string */
78 static void *gimme1(int n)
80 struct debug_info *info = get_info();
81 char *res = info->str_pos;
83 if (res + n >= &info->strings[sizeof(info->strings)]) res = info->strings;
84 info->str_pos = res + n;
85 return res;
88 /* release extra space that we requested in gimme1() */
89 static inline void release( void *ptr )
91 struct debug_info *info = NtCurrentTeb()->debug_info;
92 info->str_pos = ptr;
95 /* put an ASCII string into the debug buffer */
96 inline static char *put_string_a( const char *src, int n )
98 char *dst, *res;
100 if (n == -1) n = strlen(src);
101 if (n < 0) n = 0;
102 else if (n > 200) n = 200;
103 dst = res = gimme1 (n * 4 + 6);
104 *dst++ = '"';
105 while (n-- > 0)
107 unsigned char c = *src++;
108 switch (c)
110 case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
111 case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
112 case '\t': *dst++ = '\\'; *dst++ = 't'; break;
113 case '"': *dst++ = '\\'; *dst++ = '"'; break;
114 case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
115 default:
116 if (c >= ' ' && c <= 126)
117 *dst++ = c;
118 else
120 *dst++ = '\\';
121 *dst++ = '0' + ((c >> 6) & 7);
122 *dst++ = '0' + ((c >> 3) & 7);
123 *dst++ = '0' + ((c >> 0) & 7);
127 *dst++ = '"';
128 if (*src)
130 *dst++ = '.';
131 *dst++ = '.';
132 *dst++ = '.';
134 *dst++ = '\0';
135 release( dst );
136 return res;
139 /* put a Unicode string into the debug buffer */
140 inline static char *put_string_w( const WCHAR *src, int n )
142 char *dst, *res;
144 if (n == -1) n = strlenW(src);
145 if (n < 0) n = 0;
146 else if (n > 200) n = 200;
147 dst = res = gimme1 (n * 5 + 7);
148 *dst++ = 'L';
149 *dst++ = '"';
150 while (n-- > 0)
152 WCHAR c = *src++;
153 switch (c)
155 case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
156 case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
157 case '\t': *dst++ = '\\'; *dst++ = 't'; break;
158 case '"': *dst++ = '\\'; *dst++ = '"'; break;
159 case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
160 default:
161 if (c >= ' ' && c <= 126)
162 *dst++ = c;
163 else
165 *dst++ = '\\';
166 sprintf(dst,"%04x",c);
167 dst+=4;
171 *dst++ = '"';
172 if (*src)
174 *dst++ = '.';
175 *dst++ = '.';
176 *dst++ = '.';
178 *dst++ = '\0';
179 release( dst );
180 return res;
183 /***********************************************************************
184 * NTDLL_dbgstr_an
186 static const char *NTDLL_dbgstr_an( const char *src, int n )
188 char *res, *old_pos;
189 struct debug_info *info = get_info();
191 if (!HIWORD(src))
193 if (!src) return "(null)";
194 res = gimme1(6);
195 sprintf(res, "#%04x", LOWORD(src) );
196 return res;
198 /* save current position to restore it on exception */
199 old_pos = info->str_pos;
200 __TRY
202 res = put_string_a( src, n );
204 __EXCEPT(page_fault)
206 release( old_pos );
207 return "(invalid)";
209 __ENDTRY
210 return res;
213 /***********************************************************************
214 * NTDLL_dbgstr_wn
216 static const char *NTDLL_dbgstr_wn( const WCHAR *src, int n )
218 char *res, *old_pos;
219 struct debug_info *info = get_info();
221 if (!HIWORD(src))
223 if (!src) return "(null)";
224 res = gimme1(6);
225 sprintf(res, "#%04x", LOWORD(src) );
226 return res;
229 /* save current position to restore it on exception */
230 old_pos = info->str_pos;
231 __TRY
233 res = put_string_w( src, n );
235 __EXCEPT(page_fault)
237 release( old_pos );
238 return "(invalid)";
240 __ENDTRY
241 return res;
244 /***********************************************************************
245 * NTDLL_dbgstr_guid
247 static const char *NTDLL_dbgstr_guid( const GUID *id )
249 char *str;
251 if (!id) return "(null)";
252 if (!HIWORD(id))
254 str = gimme1(12);
255 sprintf( str, "<guid-0x%04x>", LOWORD(id) );
257 else
259 str = gimme1(40);
260 sprintf( str, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
261 id->Data1, id->Data2, id->Data3,
262 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
263 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
265 return str;
268 /***********************************************************************
269 * NTDLL_dbg_vprintf
271 static int NTDLL_dbg_vprintf( const char *format, va_list args )
273 struct debug_info *info = get_info();
274 char *p;
276 int ret = vsnprintf( info->out_pos, sizeof(info->output) - (info->out_pos - info->output),
277 format, args );
279 /* make sure we didn't exceed the buffer length
280 * the two checks are due to glibc changes in vsnprintfs return value
281 * the buffer size can be exceeded in case of a missing \n in
282 * debug output */
283 if ((ret == -1) || (ret >= sizeof(info->output) - (info->out_pos - info->output)))
285 fprintf( stderr, "wine_dbg_vprintf: debugstr buffer overflow (contents: '%s')\n",
286 info->output);
287 info->out_pos = info->output;
288 abort();
291 p = strrchr( info->out_pos, '\n' );
292 if (!p) info->out_pos += ret;
293 else
295 char *pos = info->output;
296 p++;
297 write( 2, pos, p - pos );
298 /* move beginning of next line to start of buffer */
299 while ((*pos = *p++)) pos++;
300 info->out_pos = pos;
302 return ret;
305 /***********************************************************************
306 * NTDLL_dbg_vlog
308 static int NTDLL_dbg_vlog( int cls, const char *channel,
309 const char *function, const char *format, va_list args )
311 static const char *classes[] = { "fixme", "err", "warn", "trace" };
312 int ret = 0;
314 if (TRACE_ON(tid))
315 ret = wine_dbg_printf( "%08lx:", (DWORD)NtCurrentTeb()->tid );
316 if (cls < sizeof(classes)/sizeof(classes[0]))
317 ret += wine_dbg_printf( "%s:%s:%s ", classes[cls], channel + 1, function );
318 if (format)
319 ret += NTDLL_dbg_vprintf( format, args );
320 return ret;
323 /***********************************************************************
324 * debug_init
326 DECL_GLOBAL_CONSTRUCTOR(debug_init)
328 __wine_dbgstr_an = NTDLL_dbgstr_an;
329 __wine_dbgstr_wn = NTDLL_dbgstr_wn;
330 __wine_dbgstr_guid = NTDLL_dbgstr_guid;
331 __wine_dbg_vprintf = NTDLL_dbg_vprintf;
332 __wine_dbg_vlog = NTDLL_dbg_vlog;