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