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
source_rb_compare(const void * key,const struct wine_rb_entry * entry)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 */
source_find(const char * name)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 */
source_new(struct module * module,const char * base,const char * name)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 */
source_get(const struct module * module,unsigned idx)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 */
SymEnumSourceFilesW(HANDLE hProcess,ULONG64 ModBase,PCWSTR Mask,PSYM_ENUMSOURCEFILES_CALLBACKW cbSrcFiles,PVOID UserContext)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
enum_source_files_W_to_A(PSOURCEFILEW source_file,PVOID context)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 */
SymEnumSourceFiles(HANDLE hProcess,ULONG64 ModBase,PCSTR Mask,PSYM_ENUMSOURCEFILES_CALLBACK cbSrcFiles,PVOID UserContext)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 */
SymEnumSourceLines(HANDLE hProcess,ULONG64 base,PCSTR obj,PCSTR file,DWORD line,DWORD flags,PSYM_ENUMLINES_CALLBACK EnumLinesCallback,PVOID UserContext)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 */
SymEnumSourceLinesW(HANDLE hProcess,ULONG64 base,PCWSTR obj,PCWSTR file,DWORD line,DWORD flags,PSYM_ENUMLINES_CALLBACKW EnumLinesCallback,PVOID UserContext)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 */
SymGetSourceFileToken(HANDLE hProcess,ULONG64 base,PCSTR src,PVOID * token,DWORD * size)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 */
SymGetSourceFileTokenW(HANDLE hProcess,ULONG64 base,PCWSTR src,PVOID * token,DWORD * size)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