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