Add support for REG_EXPAND_SZ in set_registry_variables().
[wine] / dlls / dbghelp / dbghelp.c
1 /*
2  * File dbghelp.c - generic routines (process) for dbghelp DLL
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include "dbghelp_private.h"
24 #include "winerror.h"
25 #include "psapi.h"
26 #include "wine/debug.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
29
30 /* TODO
31  *  - support for symbols' types is still partly missing
32  *      + C++ support
33  *      + funcargtype:s are (partly) wrong: they should be a specific struct (like
34  *        typedef) pointing to the actual type (and not a direct access)
35  *      + we should store the underlying type for an enum in the symt_enum struct
36  *  - most options (dbghelp_options) are not used (loading lines, decoration...)
37  *  - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
38  *    we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
39  *    we could use hash if name isn't a RE, and fall back to a full search when we
40  *    get a full RE
41  *  - (un)decoration is not handled (should make winedump's code a (.a) library
42  *    and link it to winedump, and potentially to msvcrt and dbghelp (check best
43  *    way not to duplicate code in msvcrt & dbghelp)
44  *  - msc:
45  *      + we should add parameters' types to the function's signature
46  *        while processing a function's parameters
47  *      + get rid of MSC reading FIXME:s (lots of types are not defined)
48  *      + C++ management
49  *  - stabs: 
50  *      + when, in a same module, the same definition is used in several compilation
51  *        units, we get several definitions of the same object (especially 
52  *        struct/union). we should find a way not to duplicate them
53  *      + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
54  *        global variable is defined several times (at different scopes). We are
55  *        getting several of those while looking for a unique symbol. Part of the 
56  *        issue is that we don't give a scope to a static variable inside a function
57  *      + C++ management
58  *  - implement the callback notification mechanism
59  */
60
61 unsigned   dbghelp_options = SYMOPT_UNDNAME;
62
63 /***********************************************************************
64  *           DllMain (DEBUGHLP.@)
65  */
66 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
67 {
68     switch (fdwReason)
69     {
70     case DLL_PROCESS_ATTACH:    break;
71     case DLL_PROCESS_DETACH:    break;
72     case DLL_THREAD_ATTACH:     break;
73     case DLL_THREAD_DETACH:     break;
74     default:                    break;
75     }
76     return TRUE;
77 }
78
79 static struct process* process_first /* = NULL */;
80
81 /******************************************************************
82  *              process_find_by_handle
83  *
84  */
85 struct process*    process_find_by_handle(HANDLE hProcess)
86 {
87     struct process* p;
88
89     for (p = process_first; p && p->handle != hProcess; p = p->next);
90     if (!p) SetLastError(ERROR_INVALID_HANDLE);
91     return p;
92 }
93
94 /******************************************************************
95  *              SymSetSearchPath (DBGHELP.@)
96  *
97  */
98 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PSTR searchPath)
99 {
100     struct process* pcs = process_find_by_handle(hProcess);
101
102     if (!pcs) return FALSE;
103     if (!searchPath) return FALSE;
104
105     HeapFree(GetProcessHeap(), 0, pcs->search_path);
106     pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(searchPath) + 1),
107                               searchPath);
108     return TRUE;
109 }
110
111 /***********************************************************************
112  *              SymGetSearchPath (DBGHELP.@)
113  */
114 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, LPSTR szSearchPath, 
115                              DWORD SearchPathLength)
116 {
117     struct process* pcs = process_find_by_handle(hProcess);
118     if (!pcs) return FALSE;
119
120     strncpy(szSearchPath, pcs->search_path, SearchPathLength);
121     szSearchPath[SearchPathLength - 1] = '\0';
122     return TRUE;
123 }
124
125 /******************************************************************
126  *              invade_process
127  *
128  * SymInitialize helper: loads in dbghelp all known (and loaded modules)
129  * this assumes that hProcess is a handle on a valid process
130  */
131 static BOOL process_invade(HANDLE hProcess)
132 {
133     HMODULE     hMods[256];
134     char        img[256];
135     DWORD       i, sz;
136     MODULEINFO  mi;
137
138     if (!EnumProcessModules(hProcess, hMods, sizeof(hMods), &sz))
139         return FALSE; /* FIXME should grow hMods */
140     
141     for (i = 0; i < sz / sizeof(HMODULE); i++)
142     {
143         if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
144             !GetModuleFileNameExA(hProcess, hMods[i], img, sizeof(img)) ||
145             !SymLoadModule(hProcess, 0, img, NULL, (DWORD)mi.lpBaseOfDll, mi.SizeOfImage))
146             return FALSE;
147     }
148
149     return sz != 0;
150 }
151
152 /******************************************************************
153  *              SymInitialize (DBGHELP.@)
154  *
155  * The initialisation of a dbghelp's context.
156  * Note that hProcess doesn't need to be a valid process handle (except
157  * when fInvadeProcess is TRUE).
158  * Since, we're also allow to load ELF (pure) libraries and Wine ELF libraries 
159  * containing PE (and NE) module(s), here's how we handle it:
160  * - we load every module (ELF, NE, PE) passed in SymLoadModule
161  * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
162  *   synchronization: hProcess should be a valid process handle, and we hook
163  *   ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
164  *   our internal ELF modules representation (loading / unloading). This way,
165  *   we'll pair every loaded builtin PE module with its ELF counterpart (and
166  *   access its debug information).
167  * - if fInvadeProcess (in SymInitialize) is FALSE, we won't be able to
168  *   make the peering between a builtin PE module and its ELF counterpart, hence
169  *   we won't be able to provide the requested debug information. We'll
170  *   however be able to load native PE modules (and their debug information)
171  *   without any trouble.
172  * Note also that this scheme can be intertwined with the deferred loading 
173  * mechanism (ie only load the debug information when we actually need it).
174  */
175 BOOL WINAPI SymInitialize(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess)
176 {
177     struct process*     pcs;
178
179     TRACE("(%p %s %u)\n", hProcess, debugstr_a(UserSearchPath), fInvadeProcess);
180
181     if (process_find_by_handle(hProcess))
182         FIXME("what to do ??\n");
183
184     pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
185     if (!pcs) return FALSE;
186
187     pcs->handle = hProcess;
188
189     if (UserSearchPath)
190     {
191         pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(UserSearchPath) + 1), 
192                                   UserSearchPath);
193     }
194     else
195     {
196         unsigned        size;
197         unsigned        len;
198
199         pcs->search_path = HeapAlloc(GetProcessHeap(), 0, len = MAX_PATH);
200         while ((size = GetCurrentDirectoryA(len, pcs->search_path)) >= len)
201             pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, len *= 2);
202         pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1);
203
204         len = GetEnvironmentVariableA("_NT_SYMBOL_PATH", NULL, 0);
205         if (len)
206         {
207             pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
208             pcs->search_path[size] = ';';
209             GetEnvironmentVariableA("_NT_SYMBOL_PATH", pcs->search_path + size + 1, len);
210             size += 1 + len;
211         }
212         len = GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", NULL, 0);
213         if (len)
214         {
215             pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
216             pcs->search_path[size] = ';';
217             GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", pcs->search_path + size + 1, len);
218             size += 1 + len;
219         }
220     }
221
222     pcs->lmodules = NULL;
223     pcs->dbg_hdr_addr = 0;
224     pcs->next = process_first;
225     process_first = pcs;
226
227     if (fInvadeProcess)
228     {
229         if (!elf_read_wine_loader_dbg_info(pcs))
230         {
231             SymCleanup(hProcess);
232             return FALSE;
233         }
234         process_invade(hProcess);
235         elf_synchronize_module_list(pcs);
236     }
237     return TRUE;
238 }
239
240 /******************************************************************
241  *              SymCleanup (DBGHELP.@)
242  *
243  */
244 BOOL WINAPI SymCleanup(HANDLE hProcess)
245 {
246     struct process**    ppcs;
247     struct process*     next;
248
249     for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
250     {
251         if ((*ppcs)->handle == hProcess)
252         {
253             while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
254
255             HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
256             next = (*ppcs)->next;
257             HeapFree(GetProcessHeap(), 0, *ppcs);
258             *ppcs = next;
259             return TRUE;
260         }
261     }
262     return FALSE;
263 }
264
265 /******************************************************************
266  *              SymSetOptions (DBGHELP.@)
267  *
268  */
269 DWORD WINAPI SymSetOptions(DWORD opts)
270 {
271     return dbghelp_options = opts;
272 }
273
274 /******************************************************************
275  *              SymGetOptions (DBGHELP.@)
276  *
277  */
278 DWORD WINAPI SymGetOptions(void)
279 {
280     return dbghelp_options;
281 }
282
283 /******************************************************************
284  *              SymSetContext (DBGHELP.@)
285  *
286  */
287 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
288                           PIMAGEHLP_CONTEXT Context)
289 {
290     struct process* pcs = process_find_by_handle(hProcess);
291     if (!pcs) return FALSE;
292
293     pcs->ctx_frame = *StackFrame;
294     /* MSDN states that Context is not (no longer?) used */
295     return TRUE;
296 }
297
298 /***********************************************************************
299  *              SymRegisterCallback (DBGHELP.@)
300  */
301 BOOL WINAPI SymRegisterCallback(HANDLE hProcess, 
302                                 PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
303                                 PVOID UserContext)
304 {
305     FIXME("(%p, %p, %p): stub\n", hProcess, CallbackFunction, UserContext);
306     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
307     return FALSE;
308 }
309
310 /* This is imagehlp version not dbghelp !! */
311 static API_VERSION api_version = { 4, 0, 2, 0 };
312
313 /***********************************************************************
314  *           ImagehlpApiVersion (DBGHELP.@)
315  */
316 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
317 {
318     return &api_version;
319 }
320
321 /***********************************************************************
322  *           ImagehlpApiVersionEx (DBGHELP.@)
323  */
324 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
325 {
326     if (!AppVersion) return NULL;
327
328     AppVersion->MajorVersion = api_version.MajorVersion;
329     AppVersion->MinorVersion = api_version.MinorVersion;
330     AppVersion->Revision = api_version.Revision;
331     AppVersion->Reserved = api_version.Reserved;
332
333     return AppVersion;
334 }