xref: /reactos/dll/win32/dbghelp/source.c (revision 53221834)
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