Commit | Line | Data |
---|---|---|
94613ab0 AJ |
1 | /* |
2 | * Debugging functions | |
0799c1a7 AJ |
3 | * |
4 | * Copyright 2000 Alexandre Julliard | |
5 | * | |
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. | |
10 | * | |
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. | |
15 | * | |
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 | |
360a3f91 | 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
94613ab0 AJ |
19 | */ |
20 | ||
84555cc7 AJ |
21 | #include "config.h" |
22 | #include "wine/port.h" | |
57bf4506 | 23 | |
508c4d93 | 24 | #include <assert.h> |
94613ab0 AJ |
25 | #include <stdio.h> |
26 | #include <stdlib.h> | |
27 | #include <string.h> | |
d016f819 PS |
28 | #ifdef HAVE_UNISTD_H |
29 | # include <unistd.h> | |
30 | #endif | |
94613ab0 AJ |
31 | #include <ctype.h> |
32 | ||
0799c1a7 | 33 | #include "wine/debug.h" |
42a074df | 34 | #include "wine/exception.h" |
35389149 | 35 | #include "wine/library.h" |
0aa28b5b | 36 | #include "wine/unicode.h" |
94613ab0 | 37 | #include "winnt.h" |
9c1de6de | 38 | #include "winternl.h" |
737d4be8 | 39 | #include "excpt.h" |
e5e1844d | 40 | #include "ntdll_misc.h" |
94613ab0 | 41 | |
0799c1a7 | 42 | WINE_DECLARE_DEBUG_CHANNEL(tid); |
e17d1a36 | 43 | |
a443761b AJ |
44 | static struct __wine_debug_functions default_funcs; |
45 | ||
94613ab0 AJ |
46 | /* ---------------------------------------------------------------------- */ |
47 | ||
94613ab0 AJ |
48 | /* get the debug info pointer for the current thread */ |
49 | static inline struct debug_info *get_info(void) | |
50 | { | |
ab29aa21 | 51 | return ntdll_get_thread_data()->debug_info; |
94613ab0 AJ |
52 | } |
53 | ||
54 | /* allocate some tmp space for a string */ | |
a443761b | 55 | static char *get_temp_buffer( size_t n ) |
94613ab0 AJ |
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() */ | |
a443761b | 66 | static void release_temp_buffer( char *ptr, size_t size ) |
94613ab0 | 67 | { |
ab29aa21 | 68 | struct debug_info *info = get_info(); |
a443761b | 69 | info->str_pos = ptr + size; |
94613ab0 AJ |
70 | } |
71 | ||
42a074df | 72 | /*********************************************************************** |
0aa28b5b | 73 | * NTDLL_dbgstr_an |
42a074df | 74 | */ |
0aa28b5b | 75 | static const char *NTDLL_dbgstr_an( const char *src, int n ) |
42a074df | 76 | { |
a443761b | 77 | const char *res; |
6ca71d39 | 78 | struct debug_info *info = get_info(); |
42a074df | 79 | /* save current position to restore it on exception */ |
a443761b AJ |
80 | char *old_pos = info->str_pos; |
81 | ||
42a074df JG |
82 | __TRY |
83 | { | |
a443761b | 84 | res = default_funcs.dbgstr_an( src, n ); |
42a074df | 85 | } |
ae964ac8 | 86 | __EXCEPT_PAGE_FAULT |
42a074df | 87 | { |
a443761b | 88 | release_temp_buffer( old_pos, 0 ); |
42a074df JG |
89 | return "(invalid)"; |
90 | } | |
91 | __ENDTRY | |
92 | return res; | |
93 | } | |
94 | ||
95 | /*********************************************************************** | |
0aa28b5b | 96 | * NTDLL_dbgstr_wn |
42a074df | 97 | */ |
0aa28b5b | 98 | static const char *NTDLL_dbgstr_wn( const WCHAR *src, int n ) |
42a074df | 99 | { |
a443761b | 100 | const char *res; |
6ca71d39 | 101 | struct debug_info *info = get_info(); |
42a074df | 102 | /* save current position to restore it on exception */ |
a443761b AJ |
103 | char *old_pos = info->str_pos; |
104 | ||
42a074df JG |
105 | __TRY |
106 | { | |
a443761b | 107 | res = default_funcs.dbgstr_wn( src, n ); |
42a074df | 108 | } |
ae964ac8 | 109 | __EXCEPT_PAGE_FAULT |
42a074df | 110 | { |
a443761b | 111 | release_temp_buffer( old_pos, 0 ); |
42a074df JG |
112 | return "(invalid)"; |
113 | } | |
114 | __ENDTRY | |
115 | return res; | |
116 | } | |
117 | ||
024d6c50 | 118 | /*********************************************************************** |
0aa28b5b | 119 | * NTDLL_dbg_vprintf |
024d6c50 | 120 | */ |
0aa28b5b | 121 | static int NTDLL_dbg_vprintf( const char *format, va_list args ) |
94613ab0 AJ |
122 | { |
123 | struct debug_info *info = get_info(); | |
508c4d93 | 124 | char *p; |
94613ab0 | 125 | |
508c4d93 CM |
126 | int ret = vsnprintf( info->out_pos, sizeof(info->output) - (info->out_pos - info->output), |
127 | format, args ); | |
128 | ||
129 | /* make sure we didn't exceed the buffer length | |
26af8221 AM |
130 | * the two checks are due to glibc changes in vsnprintfs return value |
131 | * the buffer size can be exceeded in case of a missing \n in | |
132 | * debug output */ | |
133 | if ((ret == -1) || (ret >= sizeof(info->output) - (info->out_pos - info->output))) | |
134 | { | |
135 | fprintf( stderr, "wine_dbg_vprintf: debugstr buffer overflow (contents: '%s')\n", | |
136 | info->output); | |
137 | info->out_pos = info->output; | |
138 | abort(); | |
139 | } | |
508c4d93 CM |
140 | |
141 | p = strrchr( info->out_pos, '\n' ); | |
94613ab0 AJ |
142 | if (!p) info->out_pos += ret; |
143 | else | |
144 | { | |
145 | char *pos = info->output; | |
146 | p++; | |
147 | write( 2, pos, p - pos ); | |
148 | /* move beginning of next line to start of buffer */ | |
149 | while ((*pos = *p++)) pos++; | |
150 | info->out_pos = pos; | |
151 | } | |
152 | return ret; | |
153 | } | |
154 | ||
024d6c50 | 155 | /*********************************************************************** |
0aa28b5b | 156 | * NTDLL_dbg_vlog |
024d6c50 | 157 | */ |
75c27e17 | 158 | static int NTDLL_dbg_vlog( enum __wine_debug_class cls, struct __wine_debug_channel *channel, |
0aa28b5b | 159 | const char *function, const char *format, va_list args ) |
94613ab0 | 160 | { |
949e065c AJ |
161 | static const char * const classes[] = { "fixme", "err", "warn", "trace" }; |
162 | struct debug_info *info = get_info(); | |
864dc598 | 163 | int ret = 0; |
94613ab0 | 164 | |
949e065c AJ |
165 | /* only print header if we are at the beginning of the line */ |
166 | if (info->out_pos == info->output || info->out_pos[-1] == '\n') | |
167 | { | |
168 | if (TRACE_ON(tid)) | |
02f28139 | 169 | ret = wine_dbg_printf( "%04lx:", GetCurrentThreadId() ); |
949e065c | 170 | if (cls < sizeof(classes)/sizeof(classes[0])) |
75c27e17 | 171 | ret += wine_dbg_printf( "%s:%s:%s ", classes[cls], channel->name, function ); |
949e065c | 172 | } |
864dc598 | 173 | if (format) |
0aa28b5b | 174 | ret += NTDLL_dbg_vprintf( format, args ); |
864dc598 | 175 | return ret; |
94613ab0 | 176 | } |
0aa28b5b | 177 | |
75c27e17 AJ |
178 | |
179 | static const struct __wine_debug_functions funcs = | |
180 | { | |
a443761b AJ |
181 | get_temp_buffer, |
182 | release_temp_buffer, | |
75c27e17 AJ |
183 | NTDLL_dbgstr_an, |
184 | NTDLL_dbgstr_wn, | |
75c27e17 AJ |
185 | NTDLL_dbg_vprintf, |
186 | NTDLL_dbg_vlog | |
187 | }; | |
188 | ||
0aa28b5b AJ |
189 | /*********************************************************************** |
190 | * debug_init | |
191 | */ | |
af542075 | 192 | void debug_init(void) |
0aa28b5b | 193 | { |
a443761b | 194 | __wine_dbg_set_functions( &funcs, &default_funcs, sizeof(funcs) ); |
0aa28b5b | 195 | } |