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
28 #include "wine/debug.h"
29 #include "wine/exception.h"
34 #include "msvcrt/excpt.h"
36 WINE_DECLARE_DEBUG_CHANNEL(tid);
38 /* ---------------------------------------------------------------------- */
42 char *str_pos; /* current position in strings buffer */
43 char *out_pos; /* current position in output buffer */
44 char strings[1024]; /* buffer for temporary strings */
45 char output[1024]; /* current output line */
48 static struct debug_info initial_thread_info; /* debug info for initial thread */
50 /* filter for page-fault exceptions */
51 static WINE_EXCEPTION_FILTER(page_fault)
53 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
54 return EXCEPTION_EXECUTE_HANDLER;
55 return EXCEPTION_CONTINUE_SEARCH;
58 /* get the debug info pointer for the current thread */
59 static inline struct debug_info *get_info(void)
61 struct debug_info *info = NtCurrentTeb()->debug_info;
63 if (!info) NtCurrentTeb()->debug_info = info = &initial_thread_info;
66 info->str_pos = info->strings;
67 info->out_pos = info->output;
72 /* allocate some tmp space for a string */
73 static void *gimme1(int n)
75 struct debug_info *info = get_info();
76 char *res = info->str_pos;
78 if (res + n >= &info->strings[sizeof(info->strings)]) res = info->strings;
79 info->str_pos = res + n;
83 /* release extra space that we requested in gimme1() */
84 static inline void release( void *ptr )
86 struct debug_info *info = NtCurrentTeb()->debug_info;
90 /* put an ASCII string into the debug buffer */
91 inline static char *put_string_a( const char *src, int n )
96 else if (n > 200) n = 200;
97 dst = res = gimme1 (n * 4 + 6);
99 while (n-- > 0 && *src)
101 unsigned char c = *src++;
104 case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
105 case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
106 case '\t': *dst++ = '\\'; *dst++ = 't'; break;
107 case '"': *dst++ = '\\'; *dst++ = '"'; break;
108 case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
110 if (c >= ' ' && c <= 126)
115 *dst++ = '0' + ((c >> 6) & 7);
116 *dst++ = '0' + ((c >> 3) & 7);
117 *dst++ = '0' + ((c >> 0) & 7);
133 /* put a Unicode string into the debug buffer */
134 inline static char *put_string_w( const WCHAR *src, int n )
139 else if (n > 200) n = 200;
140 dst = res = gimme1 (n * 5 + 7);
143 while (n-- > 0 && *src)
148 case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
149 case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
150 case '\t': *dst++ = '\\'; *dst++ = 't'; break;
151 case '"': *dst++ = '\\'; *dst++ = '"'; break;
152 case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
154 if (c >= ' ' && c <= 126)
159 sprintf(dst,"%04x",c);
176 /***********************************************************************
177 * wine_dbgstr_an (NTDLL.@)
179 const char *wine_dbgstr_an( const char *src, int n )
182 struct debug_info *info = get_info();
186 if (!src) return "(null)";
188 sprintf(res, "#%04x", LOWORD(src) );
191 /* save current position to restore it on exception */
192 old_pos = info->str_pos;
195 res = put_string_a( src, n );
206 /***********************************************************************
207 * wine_dbgstr_wn (NTDLL.@)
209 const char *wine_dbgstr_wn( const WCHAR *src, int n )
212 struct debug_info *info = get_info();
216 if (!src) return "(null)";
218 sprintf(res, "#%04x", LOWORD(src) );
222 /* save current position to restore it on exception */
223 old_pos = info->str_pos;
226 res = put_string_w( src, n );
237 /***********************************************************************
238 * wine_dbgstr_guid (NTDLL.@)
240 const char *wine_dbgstr_guid( const GUID *id )
244 if (!id) return "(null)";
248 sprintf( str, "<guid-0x%04x>", LOWORD(id) );
253 sprintf( str, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
254 id->Data1, id->Data2, id->Data3,
255 id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
256 id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
261 /***********************************************************************
262 * wine_dbg_vprintf (NTDLL.@)
264 int wine_dbg_vprintf( const char *format, va_list args )
266 struct debug_info *info = get_info();
269 int ret = vsnprintf( info->out_pos, sizeof(info->output) - (info->out_pos - info->output),
272 /* make sure we didn't exceed the buffer length
273 * the two checks are due to glibc changes in vsnprintfs return value
274 * the buffer size can be exceeded in case of a missing \n in
276 if ((ret == -1) || (ret >= sizeof(info->output) - (info->out_pos - info->output)))
278 fprintf( stderr, "wine_dbg_vprintf: debugstr buffer overflow (contents: '%s')\n",
280 info->out_pos = info->output;
284 p = strrchr( info->out_pos, '\n' );
285 if (!p) info->out_pos += ret;
288 char *pos = info->output;
290 write( 2, pos, p - pos );
291 /* move beginning of next line to start of buffer */
292 while ((*pos = *p++)) pos++;
298 /***********************************************************************
299 * wine_dbg_printf (NTDLL.@)
301 int wine_dbg_printf(const char *format, ...)
306 va_start(valist, format);
307 ret = wine_dbg_vprintf( format, valist );
312 /***********************************************************************
313 * wine_dbg_log (NTDLL.@)
315 int wine_dbg_log(enum __WINE_DEBUG_CLASS cls, const char *channel,
316 const char *function, const char *format, ... )
318 static const char *classes[__WINE_DBCL_COUNT] = { "fixme", "err", "warn", "trace" };
322 va_start(valist, format);
324 ret = wine_dbg_printf( "%08lx:", (DWORD)NtCurrentTeb()->tid );
325 if (cls < __WINE_DBCL_COUNT)
326 ret += wine_dbg_printf( "%s:%s:%s ", classes[cls], channel + 1, function );
328 ret += wine_dbg_vprintf( format, valist );