Added mappings for a few messages.
[wine] / dlls / ntdll / debugtools.c
1 /*
2  * Debugging functions
3  */
4
5 #include <assert.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <ctype.h>
11
12 #include "debugtools.h"
13 #include "thread.h"
14 #include "winbase.h"
15 #include "winnt.h"
16 #include "wtypes.h"
17
18 DECLARE_DEBUG_CHANNEL(tid);
19
20 /* ---------------------------------------------------------------------- */
21
22 struct debug_info
23 {
24     char *str_pos;       /* current position in strings buffer */
25     char *out_pos;       /* current position in output buffer */
26     char  strings[1024]; /* buffer for temporary strings */
27     char  output[1024];  /* current output line */
28 };
29
30 static struct debug_info tmp;
31
32 /* get the debug info pointer for the current thread */
33 static inline struct debug_info *get_info(void)
34 {
35     struct debug_info *info = NtCurrentTeb()->debug_info;
36     if (!info)
37     {
38         if (!tmp.str_pos)
39         {
40             tmp.str_pos = tmp.strings;
41             tmp.out_pos = tmp.output;
42         }
43         if (!GetProcessHeap()) return &tmp;
44         /* setup the temp structure in case HeapAlloc wants to print something */
45         NtCurrentTeb()->debug_info = &tmp;
46         info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) );
47         info->str_pos = info->strings;
48         info->out_pos = info->output;
49         NtCurrentTeb()->debug_info = info;
50     }
51     return info;
52 }
53
54 /* allocate some tmp space for a string */
55 static void *gimme1(int n)
56 {
57     struct debug_info *info = get_info();
58     char *res = info->str_pos;
59
60     if (res + n >= &info->strings[sizeof(info->strings)]) res = info->strings;
61     info->str_pos = res + n;
62     return res;
63 }
64
65 /* release extra space that we requested in gimme1() */
66 static inline void release( void *ptr )
67 {
68     struct debug_info *info = NtCurrentTeb()->debug_info;
69     info->str_pos = ptr;
70 }
71
72 /***********************************************************************
73  *              wine_dbgstr_an (NTDLL.@)
74  */
75 const char *wine_dbgstr_an( const char *src, int n )
76 {
77     char *dst, *res;
78
79     if (!HIWORD(src))
80     {
81         if (!src) return "(null)";
82         res = gimme1(6);
83         sprintf(res, "#%04x", LOWORD(src) );
84         return res;
85     }
86     if (n < 0) n = 0;
87     else if (n > 200) n = 200;
88     dst = res = gimme1 (n * 4 + 6);
89     *dst++ = '"';
90     while (n-- > 0 && *src)
91     {
92         unsigned char c = *src++;
93         switch (c)
94         {
95         case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
96         case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
97         case '\t': *dst++ = '\\'; *dst++ = 't'; break;
98         case '"': *dst++ = '\\'; *dst++ = '"'; break;
99         case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
100         default:
101             if (c >= ' ' && c <= 126)
102                 *dst++ = c;
103             else
104             {
105                 *dst++ = '\\';
106                 *dst++ = '0' + ((c >> 6) & 7);
107                 *dst++ = '0' + ((c >> 3) & 7);
108                 *dst++ = '0' + ((c >> 0) & 7);
109             }
110         }
111     }
112     *dst++ = '"';
113     if (*src)
114     {
115         *dst++ = '.';
116         *dst++ = '.';
117         *dst++ = '.';
118     }
119     *dst++ = '\0';
120     release( dst );
121     return res;
122 }
123
124 /***********************************************************************
125  *              wine_dbgstr_wn (NTDLL.@)
126  */
127 const char *wine_dbgstr_wn( const WCHAR *src, int n )
128 {
129     char *dst, *res;
130
131     if (!HIWORD(src))
132     {
133         if (!src) return "(null)";
134         res = gimme1(6);
135         sprintf(res, "#%04x", LOWORD(src) );
136         return res;
137     }
138     if (n < 0) n = 0;
139     else if (n > 200) n = 200;
140     dst = res = gimme1 (n * 5 + 7);
141     *dst++ = 'L';
142     *dst++ = '"';
143     while (n-- > 0 && *src)
144     {
145         WCHAR c = *src++;
146         switch (c)
147         {
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;
153         default:
154             if (c >= ' ' && c <= 126)
155                 *dst++ = c;
156             else
157             {
158                 *dst++ = '\\';
159                 sprintf(dst,"%04x",c);
160                 dst+=4;
161             }
162         }
163     }
164     *dst++ = '"';
165     if (*src)
166     {
167         *dst++ = '.';
168         *dst++ = '.';
169         *dst++ = '.';
170     }
171     *dst++ = '\0';
172     release( dst );
173     return res;
174 }
175
176 /***********************************************************************
177  *              wine_dbgstr_guid (NTDLL.@)
178  */
179 const char *wine_dbgstr_guid( const GUID *id )
180 {
181     char *str;
182
183     if (!id) return "(null)";
184     if (!HIWORD(id))
185     {
186         str = gimme1(12);
187         sprintf( str, "<guid-0x%04x>", LOWORD(id) );
188     }
189     else
190     {
191         str = gimme1(40);
192         sprintf( str, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
193                  id->Data1, id->Data2, id->Data3,
194                  id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
195                  id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
196     }
197     return str;
198 }
199
200 /***********************************************************************
201  *              wine_dbg_vprintf (NTDLL.@)
202  */
203 int wine_dbg_vprintf( const char *format, va_list args )
204 {
205     struct debug_info *info = get_info();
206     char *p;
207
208     int ret = vsnprintf( info->out_pos, sizeof(info->output) - (info->out_pos - info->output),
209                          format, args );
210
211     /* make sure we didn't exceed the buffer length
212      * the two checks are due to glibc changes in vsnprintfs return value
213      * the buffer size can be exceeded in case of a missing \n in
214      * debug output */
215     if ((ret == -1) || (ret >= sizeof(info->output) - (info->out_pos - info->output)))
216     {
217        fprintf( stderr, "wine_dbg_vprintf: debugstr buffer overflow (contents: '%s')\n",
218                 info->output);
219        info->out_pos = info->output;
220        abort();
221     }
222
223     p = strrchr( info->out_pos, '\n' );
224     if (!p) info->out_pos += ret;
225     else
226     {
227         char *pos = info->output;
228         p++;
229         write( 2, pos, p - pos );
230         /* move beginning of next line to start of buffer */
231         while ((*pos = *p++)) pos++;
232         info->out_pos = pos;
233     }
234     return ret;
235 }
236
237 /***********************************************************************
238  *              wine_dbg_printf (NTDLL.@)
239  */
240 int wine_dbg_printf(const char *format, ...)
241 {
242     int ret;
243     va_list valist;
244
245     va_start(valist, format);
246     ret = wine_dbg_vprintf( format, valist );
247     va_end(valist);
248     return ret;
249 }
250
251 /***********************************************************************
252  *              wine_dbg_log (NTDLL.@)
253  */
254 int wine_dbg_log(enum __DEBUG_CLASS cls, const char *channel,
255                  const char *function, const char *format, ... )
256 {
257     static const char *classes[__DBCL_COUNT] = { "fixme", "err", "warn", "trace" };
258     va_list valist;
259     int ret = 0;
260
261     va_start(valist, format);
262     if (TRACE_ON(tid))
263         ret = wine_dbg_printf( "%08lx:", (DWORD)NtCurrentTeb()->tid );
264     if (cls < __DBCL_COUNT)
265         ret += wine_dbg_printf( "%s:%s:%s ", classes[cls], channel + 1, function );
266     if (format)
267         ret += wine_dbg_vprintf( format, valist );
268     va_end(valist);
269     return ret;
270 }