xref: /reactos/sdk/lib/rtl/wine_debug.c (revision b09b5584)
1 
2 #define WIN32_NO_STATUS
3 #include <windef.h>
4 #include <ndk/rtlfuncs.h>
5 #include <wine/debug.h>
6 
7 NTSTATUS NTAPI vDbgPrintExWithPrefix(PCCH, ULONG, ULONG, PCCH, va_list);
8 
9 static struct
10 {
11     HANDLE thread;
12     void* allocations;
13 } s_alloactions[32];
14 
15 static int find_thread_slot()
16 {
17     HANDLE thread = NtCurrentTeb()->ClientId.UniqueThread;
18     for (int i = 0; i < ARRAYSIZE(s_alloactions); i++)
19     {
20         if (s_alloactions[i].thread == thread)
21         {
22             return i;
23         }
24     }
25     return -1;
26 }
27 
28 static int get_thread_slot()
29 {
30     int slot = find_thread_slot();
31     if (slot != -1)
32     {
33         return slot;
34     }
35 
36     HANDLE thread = NtCurrentTeb()->ClientId.UniqueThread;
37     for (int i = 0; i < ARRAYSIZE(s_alloactions); i++)
38     {
39         if (s_alloactions[i].thread == NULL)
40         {
41             if (InterlockedCompareExchangePointer(&s_alloactions[i].thread, thread, NULL) == NULL)
42             {
43                 return i;
44             }
45         }
46     }
47 
48     return -1;
49 }
50 
51 static char *alloc_buffer(size_t size)
52 {
53     int slot = get_thread_slot();
54     if (slot == -1)
55     {
56         return NULL;
57     }
58 
59     void** buffer = (void**)RtlAllocateHeap(RtlGetProcessHeap(), 0, size + sizeof(void*));
60     if (buffer == NULL)
61     {
62         return NULL;
63     }
64 
65     *buffer = s_alloactions[slot].allocations;
66     s_alloactions[slot].allocations = buffer;
67 
68     return (char*)(buffer + 1);
69 }
70 
71 static void free_buffers(void)
72 {
73     int slot = find_thread_slot();
74     if (slot != -1)
75     {
76         return;
77     }
78 
79     void* buffer = s_alloactions[slot].allocations;
80     while (buffer != NULL)
81     {
82         void* next = *(void**)buffer;
83         RtlFreeHeap(RtlGetProcessHeap(), 0, buffer);
84         buffer = next;
85     }
86 
87     s_alloactions[slot].allocations = NULL;
88     s_alloactions[slot].thread = NULL;
89 }
90 
91 const char *wine_dbg_vsprintf(const char *format, va_list valist)
92 {
93     char* buffer;
94     int len;
95 
96     len = vsnprintf(NULL, 0, format, valist);
97     buffer = alloc_buffer(len + 1);
98     if (buffer == NULL)
99     {
100         return "<allocation failed>";
101     }
102     len = vsnprintf(buffer, len, format, valist);
103     buffer[len] = 0;
104     return buffer;
105 }
106 
107 /* printf with temp buffer allocation */
108 const char *wine_dbg_sprintf( const char *format, ... )
109 {
110     const char *ret;
111     va_list valist;
112 
113     va_start(valist, format);
114     ret = wine_dbg_vsprintf( format, valist );
115     va_end(valist);
116     return ret;
117 }
118 
119 const char *wine_dbgstr_wn( const WCHAR *str, int n )
120 {
121     if (!((ULONG_PTR)str >> 16))
122     {
123         if (!str) return "(null)";
124         return wine_dbg_sprintf("#%04x", LOWORD(str) );
125     }
126     if (n == -1)
127     {
128         n = (int)wcslen(str);
129     }
130     if (n < 0) n = 0;
131 
132     return wine_dbg_sprintf("%.*S", n, str);
133 }
134 
135 /* From wine/dlls/ntdll/misc.c */
136 LPCSTR debugstr_us( const UNICODE_STRING *us )
137 {
138     if (!us) return "<null>";
139     return debugstr_wn(us->Buffer, us->Length / sizeof(WCHAR));
140 }
141 
142 static int default_dbg_vprintf( const char *format, va_list args )
143 {
144     return vDbgPrintExWithPrefix("", -1, 0, format, args);
145 }
146 
147 int wine_dbg_printf(const char *format, ... )
148 {
149     int ret;
150     va_list valist;
151 
152     va_start(valist, format);
153     ret = default_dbg_vprintf(format, valist);
154     va_end(valist);
155     free_buffers();
156     return ret;
157 }
158 
159 static int winefmt_default_dbg_vlog( enum __wine_debug_class cls, struct __wine_debug_channel *channel,
160                                      const char *file, const char *func, const int line, const char *format, va_list args )
161 {
162     int ret = 0;
163 
164     ret += wine_dbg_printf("%04x:", HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess) );
165     ret += wine_dbg_printf("%04x:", HandleToULong(NtCurrentTeb()->ClientId.UniqueThread) );
166 
167     if (format)
168         ret += default_dbg_vprintf(format, args);
169     return ret;
170 }
171 
172 #define __wine_dbg_get_channel_flags(channel) \
173     ((channel) ? (channel)->flags : 0)
174 
175 int ros_dbg_log( enum __wine_debug_class cls, struct __wine_debug_channel *channel,
176                   const char *file, const char *func, const int line, const char *format, ... )
177 {
178     int ret;
179     va_list valist;
180 
181     if (!(__wine_dbg_get_channel_flags(channel) & (1 << cls))) return -1;
182 
183     va_start(valist, format);
184     ret = winefmt_default_dbg_vlog(cls, channel, file, func, line, format, valist);
185     va_end(valist);
186     return ret;
187 }
188