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