1 /* 2 * File source.c - source files management 3 * 4 * Copyright (C) 2004, Eric Pouech. 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 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 * 20 */ 21 #include <stdlib.h> 22 #include <stdio.h> 23 #include <string.h> 24 #include <assert.h> 25 26 #include "dbghelp_private.h" 27 #ifndef DBGHELP_STATIC_LIB 28 #include "wine/debug.h" 29 #endif 30 31 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); 32 33 static struct module* rb_module; 34 struct source_rb 35 { 36 struct wine_rb_entry entry; 37 unsigned source; 38 }; 39 40 int source_rb_compare(const void *key, const struct wine_rb_entry *entry) 41 { 42 const struct source_rb *t = WINE_RB_ENTRY_VALUE(entry, const struct source_rb, entry); 43 44 return strcmp((const char*)key, rb_module->sources + t->source); 45 } 46 47 /****************************************************************** 48 * source_find 49 * 50 * check whether a source file has already been stored 51 */ 52 static unsigned source_find(const char* name) 53 { 54 struct wine_rb_entry* e; 55 56 e = wine_rb_get(&rb_module->sources_offsets_tree, name); 57 if (!e) return -1; 58 return WINE_RB_ENTRY_VALUE(e, struct source_rb, entry)->source; 59 } 60 61 /****************************************************************** 62 * source_new 63 * 64 * checks if source exists. if not, add it 65 */ 66 unsigned source_new(struct module* module, const char* base, const char* name) 67 { 68 unsigned ret = -1; 69 const char* full; 70 char* tmp = NULL; 71 72 if (!name) return ret; 73 if (!base || *name == '/') 74 full = name; 75 else 76 { 77 unsigned bsz = strlen(base); 78 79 tmp = HeapAlloc(GetProcessHeap(), 0, bsz + 1 + strlen(name) + 1); 80 if (!tmp) return ret; 81 full = tmp; 82 strcpy(tmp, base); 83 if (tmp[bsz - 1] != '/') tmp[bsz++] = '/'; 84 strcpy(&tmp[bsz], name); 85 } 86 rb_module = module; 87 if (!module->sources || (ret = source_find(full)) == (unsigned)-1) 88 { 89 char* new; 90 int len = strlen(full) + 1; 91 struct source_rb* rb; 92 93 if (module->sources_used + len + 1 > module->sources_alloc) 94 { 95 if (!module->sources) 96 { 97 module->sources_alloc = (module->sources_used + len + 1 + 255) & ~255; 98 new = HeapAlloc(GetProcessHeap(), 0, module->sources_alloc); 99 } 100 else 101 { 102 module->sources_alloc = max( module->sources_alloc * 2, 103 (module->sources_used + len + 1 + 255) & ~255 ); 104 new = HeapReAlloc(GetProcessHeap(), 0, module->sources, 105 module->sources_alloc); 106 } 107 if (!new) goto done; 108 module->sources = new; 109 } 110 ret = module->sources_used; 111 memcpy(module->sources + module->sources_used, full, len); 112 module->sources_used += len; 113 module->sources[module->sources_used] = '\0'; 114 if ((rb = pool_alloc(&module->pool, sizeof(*rb)))) 115 { 116 rb->source = ret; 117 wine_rb_put(&module->sources_offsets_tree, full, &rb->entry); 118 } 119 } 120 done: 121 HeapFree(GetProcessHeap(), 0, tmp); 122 return ret; 123 } 124 125 /****************************************************************** 126 * source_get 127 * 128 * returns a stored source file name 129 */ 130 const char* source_get(const struct module* module, unsigned idx) 131 { 132 if (idx == -1) return ""; 133 assert(module->sources); 134 return module->sources + idx; 135 } 136 137 /****************************************************************** 138 * SymEnumSourceFilesW (DBGHELP.@) 139 * 140 */ 141 BOOL WINAPI SymEnumSourceFilesW(HANDLE hProcess, ULONG64 ModBase, PCWSTR Mask, 142 PSYM_ENUMSOURCEFILES_CALLBACKW cbSrcFiles, 143 PVOID UserContext) 144 { 145 struct module_pair pair; 146 SOURCEFILEW sf; 147 char* ptr; 148 WCHAR* conversion_buffer = NULL; 149 DWORD conversion_buffer_len = 0; 150 151 if (!cbSrcFiles) return FALSE; 152 pair.pcs = process_find_by_handle(hProcess); 153 if (!pair.pcs) return FALSE; 154 155 if (ModBase) 156 { 157 pair.requested = module_find_by_addr(pair.pcs, ModBase, DMT_UNKNOWN); 158 if (!module_get_debug(&pair)) return FALSE; 159 } 160 else 161 { 162 if (Mask[0] == '!') 163 { 164 pair.requested = module_find_by_nameW(pair.pcs, Mask + 1); 165 if (!module_get_debug(&pair)) return FALSE; 166 } 167 else 168 { 169 FIXME("Unsupported yet (should get info from current context)\n"); 170 return FALSE; 171 } 172 } 173 if (!pair.effective->sources) return FALSE; 174 for (ptr = pair.effective->sources; *ptr; ptr += strlen(ptr) + 1) 175 { 176 DWORD len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0); 177 178 if (len > conversion_buffer_len) 179 { 180 HeapFree(GetProcessHeap(), 0, conversion_buffer); 181 conversion_buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 182 if (!conversion_buffer) return FALSE; 183 conversion_buffer_len = len; 184 } 185 186 MultiByteToWideChar(CP_ACP, 0, ptr, -1, conversion_buffer, len); 187 188 /* FIXME: not using Mask */ 189 sf.ModBase = ModBase; 190 sf.FileName = conversion_buffer; 191 if (!cbSrcFiles(&sf, UserContext)) break; 192 } 193 194 HeapFree(GetProcessHeap(), 0, conversion_buffer); 195 return TRUE; 196 } 197 198 struct enum_sources_files_context 199 { 200 PSYM_ENUMSOURCEFILES_CALLBACK callbackA; 201 PVOID caller_context; 202 char *conversion_buffer; 203 DWORD conversion_buffer_len; 204 DWORD callback_error; 205 }; 206 207 static BOOL CALLBACK enum_source_files_W_to_A(PSOURCEFILEW source_file, PVOID context) 208 { 209 struct enum_sources_files_context *ctx = context; 210 SOURCEFILE source_fileA; 211 DWORD len; 212 213 len = WideCharToMultiByte(CP_ACP, 0, source_file->FileName, -1, NULL, 0, NULL, NULL); 214 if (len > ctx->conversion_buffer_len) 215 { 216 char *ptr = ctx->conversion_buffer ? HeapReAlloc(GetProcessHeap(), 0, ctx->conversion_buffer, len) : 217 HeapAlloc(GetProcessHeap(), 0, len); 218 219 if (!ptr) 220 { 221 ctx->callback_error = ERROR_OUTOFMEMORY; 222 return FALSE; 223 } 224 225 ctx->conversion_buffer = ptr; 226 ctx->conversion_buffer_len = len; 227 } 228 229 WideCharToMultiByte(CP_ACP, 0, source_file->FileName, -1, ctx->conversion_buffer, len, NULL, NULL); 230 231 source_fileA.ModBase = source_file->ModBase; 232 source_fileA.FileName = ctx->conversion_buffer; 233 return ctx->callbackA(&source_fileA, ctx->caller_context); 234 } 235 236 /****************************************************************** 237 * SymEnumSourceFiles (DBGHELP.@) 238 * 239 */ 240 BOOL WINAPI SymEnumSourceFiles(HANDLE hProcess, ULONG64 ModBase, PCSTR Mask, 241 PSYM_ENUMSOURCEFILES_CALLBACK cbSrcFiles, 242 PVOID UserContext) 243 { 244 WCHAR *maskW = NULL; 245 PSYM_ENUMSOURCEFILES_CALLBACKW callbackW; 246 PVOID context; 247 struct enum_sources_files_context callback_context = {cbSrcFiles, UserContext}; 248 BOOL ret; 249 250 if (Mask) 251 { 252 DWORD len = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0); 253 254 maskW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 255 if (!maskW) 256 { 257 SetLastError(ERROR_OUTOFMEMORY); 258 return FALSE; 259 } 260 261 MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, len); 262 } 263 264 if (cbSrcFiles) 265 { 266 callbackW = enum_source_files_W_to_A; 267 context = &callback_context; 268 } 269 else 270 { 271 callbackW = NULL; 272 context = UserContext; 273 } 274 275 ret = SymEnumSourceFilesW(hProcess, ModBase, maskW, callbackW, context); 276 277 if (callback_context.callback_error) 278 { 279 SetLastError(callback_context.callback_error); 280 ret = FALSE; 281 } 282 283 HeapFree(GetProcessHeap(), 0, callback_context.conversion_buffer); 284 HeapFree(GetProcessHeap(), 0, maskW); 285 286 return ret; 287 } 288 289 /****************************************************************** 290 * SymEnumSourceLines (DBGHELP.@) 291 * 292 */ 293 BOOL WINAPI SymEnumSourceLines(HANDLE hProcess, ULONG64 base, PCSTR obj, 294 PCSTR file, DWORD line, DWORD flags, 295 PSYM_ENUMLINES_CALLBACK EnumLinesCallback, 296 PVOID UserContext) 297 { 298 FIXME("%p %s %s %s %u %u %p %p: stub!\n", 299 hProcess, wine_dbgstr_longlong(base), debugstr_a(obj), debugstr_a(file), 300 line, flags, EnumLinesCallback, UserContext); 301 SetLastError(ERROR_NOT_SUPPORTED); 302 return FALSE; 303 } 304 305 /****************************************************************** 306 * SymEnumSourceLinesW(DBGHELP.@) 307 * 308 */ 309 BOOL WINAPI SymEnumSourceLinesW(HANDLE hProcess, ULONG64 base, PCWSTR obj, 310 PCWSTR file, DWORD line, DWORD flags, 311 PSYM_ENUMLINES_CALLBACKW EnumLinesCallback, 312 PVOID UserContext) 313 { 314 FIXME("%p %s %s %s %u %u %p %p: stub!\n", 315 hProcess, wine_dbgstr_longlong(base), debugstr_w(obj), debugstr_w(file), 316 line, flags, EnumLinesCallback, UserContext); 317 SetLastError(ERROR_NOT_SUPPORTED); 318 return FALSE; 319 } 320 321 /****************************************************************** 322 * SymGetSourceFileToken (DBGHELP.@) 323 * 324 */ 325 BOOL WINAPI SymGetSourceFileToken(HANDLE hProcess, ULONG64 base, 326 PCSTR src, PVOID* token, DWORD* size) 327 { 328 FIXME("%p %s %s %p %p: stub!\n", 329 hProcess, wine_dbgstr_longlong(base), debugstr_a(src), token, size); 330 SetLastError(ERROR_NOT_SUPPORTED); 331 return FALSE; 332 } 333 334 /****************************************************************** 335 * SymGetSourceFileTokenW (DBGHELP.@) 336 * 337 */ 338 BOOL WINAPI SymGetSourceFileTokenW(HANDLE hProcess, ULONG64 base, 339 PCWSTR src, PVOID* token, DWORD* size) 340 { 341 FIXME("%p %s %s %p %p: stub!\n", 342 hProcess, wine_dbgstr_longlong(base), debugstr_w(src), token, size); 343 SetLastError(ERROR_NOT_SUPPORTED); 344 return FALSE; 345 } 346