wined3d: Initialise WINED3DVERTEXELEMENT's Reg field in
[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 #include "wdbgexts.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
30
31 /* TODO
32  *  - support for symbols' types is still partly missing
33  *      + C++ support
34  *      + we should store the underlying type for an enum in the symt_enum struct
35  *      + for enums, we store the names & values (associated to the enum type), 
36  *        but those values are not directly usable from a debugger (that's why, I
37  *        assume, that we have also to define constants for enum values, as 
38  *        Codeview does BTW.
39  *      + SymEnumTypes should only return *user* defined types (UDT, typedefs...) not
40  *        all the types stored/used in the modules (like char*)
41  *  - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across
42  *    functions, and even across function blocks...). Basically, for *Next* to work
43  *    it requires an address after the prolog of the func (the base address of the 
44  *    func doesn't work)
45  *  - most options (dbghelp_options) are not used (loading lines...)
46  *  - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
47  *    we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
48  *    we could use hash if name isn't a RE, and fall back to a full search when we
49  *    get a full RE
50  *  - msc:
51  *      + we should add parameters' types to the function's signature
52  *        while processing a function's parameters
53  *      + add support for function-less labels (as MSC seems to define them)
54  *      + C++ management
55  *  - stabs: 
56  *      + when, in a same module, the same definition is used in several compilation
57  *        units, we get several definitions of the same object (especially 
58  *        struct/union). we should find a way not to duplicate them
59  *      + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
60  *        global variable is defined several times (at different scopes). We are
61  *        getting several of those while looking for a unique symbol. Part of the 
62  *        issue is that we don't give a scope to a static variable inside a function
63  *      + C++ management
64  */
65
66 unsigned   dbghelp_options = SYMOPT_UNDNAME;
67 HANDLE     hMsvcrt = NULL;
68
69 /***********************************************************************
70  *           DllMain (DEBUGHLP.@)
71  */
72 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
73 {
74     switch (fdwReason)
75     {
76     case DLL_PROCESS_ATTACH:    break;
77     case DLL_PROCESS_DETACH:
78         if (hMsvcrt) FreeLibrary(hMsvcrt);
79         break;
80     case DLL_THREAD_ATTACH:     break;
81     case DLL_THREAD_DETACH:     break;
82     default:                    break;
83     }
84     return TRUE;
85 }
86
87 static struct process* process_first /* = NULL */;
88
89 /******************************************************************
90  *              process_find_by_handle
91  *
92  */
93 struct process*    process_find_by_handle(HANDLE hProcess)
94 {
95     struct process* p;
96
97     for (p = process_first; p && p->handle != hProcess; p = p->next);
98     if (!p) SetLastError(ERROR_INVALID_HANDLE);
99     return p;
100 }
101
102 /******************************************************************
103  *             validate_addr64 (internal)
104  *
105  */
106 BOOL validate_addr64(DWORD64 addr)
107 {
108     if (addr >> 32)
109     {
110         FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr));
111         SetLastError(ERROR_INVALID_PARAMETER);
112         return FALSE;
113     }
114     return TRUE;
115 }
116
117 /******************************************************************
118  *              SymSetSearchPath (DBGHELP.@)
119  *
120  */
121 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PCSTR searchPath)
122 {
123     struct process* pcs = process_find_by_handle(hProcess);
124
125     if (!pcs) return FALSE;
126     if (!searchPath) return FALSE;
127
128     HeapFree(GetProcessHeap(), 0, pcs->search_path);
129     pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(searchPath) + 1),
130                               searchPath);
131     return TRUE;
132 }
133
134 /***********************************************************************
135  *              SymGetSearchPath (DBGHELP.@)
136  */
137 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, LPSTR szSearchPath, 
138                              DWORD SearchPathLength)
139 {
140     struct process* pcs = process_find_by_handle(hProcess);
141     if (!pcs) return FALSE;
142
143     lstrcpynA(szSearchPath, pcs->search_path, SearchPathLength);
144     return TRUE;
145 }
146
147 /******************************************************************
148  *              invade_process
149  *
150  * SymInitialize helper: loads in dbghelp all known (and loaded modules)
151  * this assumes that hProcess is a handle on a valid process
152  */
153 static BOOL WINAPI process_invade_cb(char* name, DWORD base, DWORD size, void* user)
154 {
155     char        tmp[MAX_PATH];
156     HANDLE      hProcess = (HANDLE)user;
157
158     if (!GetModuleFileNameExA(hProcess, (HMODULE)base, 
159                               tmp, sizeof(tmp)))
160         lstrcpynA(tmp, name, sizeof(tmp));
161
162     SymLoadModule(hProcess, 0, tmp, name, base, size);
163     return TRUE;
164 }
165
166 /******************************************************************
167  *              check_live_target
168  *
169  */
170 static BOOL check_live_target(struct process* pcs)
171 {
172     if (!GetProcessId(pcs->handle)) return FALSE;
173     if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE;
174     return elf_read_wine_loader_dbg_info(pcs);
175 }
176
177 /******************************************************************
178  *              SymInitialize (DBGHELP.@)
179  *
180  * The initialisation of a dbghelp's context.
181  * Note that hProcess doesn't need to be a valid process handle (except
182  * when fInvadeProcess is TRUE).
183  * Since, we're also allow to load ELF (pure) libraries and Wine ELF libraries 
184  * containing PE (and NE) module(s), here's how we handle it:
185  * - we load every module (ELF, NE, PE) passed in SymLoadModule
186  * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
187  *   synchronization: hProcess should be a valid process handle, and we hook
188  *   ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
189  *   our internal ELF modules representation (loading / unloading). This way,
190  *   we'll pair every loaded builtin PE module with its ELF counterpart (and
191  *   access its debug information).
192  * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the 
193  *   hProcess refers to a running process. We use some heuristics here, so YMMV.
194  *   If we detect a live target, then we get the same handling as if
195  *   fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
196  *   we won't be able to make the peering between a builtin PE module and its ELF
197  *   counterpart. Hence we won't be able to provide the requested debug
198  *   information. We'll however be able to load native PE modules (and their
199  *   debug information) without any trouble.
200  * Note also that this scheme can be intertwined with the deferred loading 
201  * mechanism (ie only load the debug information when we actually need it).
202  */
203 BOOL WINAPI SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess)
204 {
205     struct process*     pcs;
206
207     TRACE("(%p %s %u)\n", hProcess, debugstr_a(UserSearchPath), fInvadeProcess);
208
209     if (process_find_by_handle(hProcess))
210         FIXME("what to do ??\n");
211
212     pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
213     if (!pcs) return FALSE;
214
215     pcs->handle = hProcess;
216
217     if (UserSearchPath)
218     {
219         pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(UserSearchPath) + 1), 
220                                   UserSearchPath);
221     }
222     else
223     {
224         unsigned        size;
225         unsigned        len;
226
227         pcs->search_path = HeapAlloc(GetProcessHeap(), 0, len = MAX_PATH);
228         while ((size = GetCurrentDirectoryA(len, pcs->search_path)) >= len)
229             pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, len *= 2);
230         pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1);
231
232         len = GetEnvironmentVariableA("_NT_SYMBOL_PATH", NULL, 0);
233         if (len)
234         {
235             pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
236             pcs->search_path[size] = ';';
237             GetEnvironmentVariableA("_NT_SYMBOL_PATH", pcs->search_path + size + 1, len);
238             size += 1 + len;
239         }
240         len = GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", NULL, 0);
241         if (len)
242         {
243             pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
244             pcs->search_path[size] = ';';
245             GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", pcs->search_path + size + 1, len);
246             size += 1 + len;
247         }
248     }
249
250     pcs->lmodules = NULL;
251     pcs->dbg_hdr_addr = 0;
252     pcs->next = process_first;
253     process_first = pcs;
254     
255     if (check_live_target(pcs))
256     {
257         if (fInvadeProcess)
258             EnumerateLoadedModules(hProcess, process_invade_cb, (void*)hProcess);
259         elf_synchronize_module_list(pcs);
260     }
261     else if (fInvadeProcess)
262     {
263         SymCleanup(hProcess);
264         SetLastError(ERROR_INVALID_PARAMETER);
265         return FALSE;
266     }
267
268     return TRUE;
269 }
270
271 /******************************************************************
272  *              SymCleanup (DBGHELP.@)
273  *
274  */
275 BOOL WINAPI SymCleanup(HANDLE hProcess)
276 {
277     struct process**    ppcs;
278     struct process*     next;
279
280     for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
281     {
282         if ((*ppcs)->handle == hProcess)
283         {
284             while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
285
286             HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
287             next = (*ppcs)->next;
288             HeapFree(GetProcessHeap(), 0, *ppcs);
289             *ppcs = next;
290             return TRUE;
291         }
292     }
293     return FALSE;
294 }
295
296 /******************************************************************
297  *              SymSetOptions (DBGHELP.@)
298  *
299  */
300 DWORD WINAPI SymSetOptions(DWORD opts)
301 {
302     struct process* pcs;
303
304     for (pcs = process_first; pcs; pcs = pcs->next)
305     {
306         pcs_callback(pcs, CBA_SET_OPTIONS, &opts);
307     }
308     return dbghelp_options = opts;
309 }
310
311 /******************************************************************
312  *              SymGetOptions (DBGHELP.@)
313  *
314  */
315 DWORD WINAPI SymGetOptions(void)
316 {
317     return dbghelp_options;
318 }
319
320 /******************************************************************
321  *              SymSetParentWindow (DBGHELP.@)
322  *
323  */
324 BOOL WINAPI SymSetParentWindow(HWND hwnd)
325 {
326     /* Save hwnd so it can be used as parent window */
327     FIXME("(%p): stub\n", hwnd);
328     return TRUE;
329 }
330
331 /******************************************************************
332  *              SymSetContext (DBGHELP.@)
333  *
334  */
335 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
336                           PIMAGEHLP_CONTEXT Context)
337 {
338     struct process* pcs = process_find_by_handle(hProcess);
339     if (!pcs) return FALSE;
340
341     if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset &&
342         pcs->ctx_frame.FrameOffset  == StackFrame->FrameOffset  &&
343         pcs->ctx_frame.StackOffset  == StackFrame->StackOffset)
344     {
345         TRACE("Setting same frame {rtn=%s frm=%s stk=%s}\n",
346               wine_dbgstr_longlong(pcs->ctx_frame.ReturnOffset),
347               wine_dbgstr_longlong(pcs->ctx_frame.FrameOffset),
348               wine_dbgstr_longlong(pcs->ctx_frame.StackOffset));
349         SetLastError(ERROR_ACCESS_DENIED); /* latest MSDN says ERROR_SUCCESS */
350         return FALSE;
351     }
352
353     pcs->ctx_frame = *StackFrame;
354     /* MSDN states that Context is not (no longer?) used */
355     return TRUE;
356 }
357
358 /******************************************************************
359  *              reg_cb64to32 (internal)
360  *
361  * Registered callback for converting information from 64 bit to 32 bit
362  */
363 static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user)
364 {
365     PSYMBOL_REGISTERED_CALLBACK         cb32 = (PSYMBOL_REGISTERED_CALLBACK)(DWORD)(user >> 32);
366     DWORD                               user32 = (DWORD)user;
367     void*                               data32;
368     IMAGEHLP_DEFERRED_SYMBOL_LOAD64*    idsl64;
369     IMAGEHLP_DEFERRED_SYMBOL_LOAD       idsl;
370
371     switch (action)
372     {
373     case CBA_DEBUG_INFO:
374     case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
375     case CBA_SET_OPTIONS:
376     case CBA_SYMBOLS_UNLOADED:
377         data32 = (void*)(DWORD)data;
378         break;
379     case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
380     case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
381     case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
382     case CBA_DEFERRED_SYMBOL_LOAD_START:
383         idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD)data;
384         if (!validate_addr64(idsl64->BaseOfImage))
385             return FALSE;
386         idsl.SizeOfStruct = sizeof(idsl);
387         idsl.BaseOfImage = (DWORD)idsl64->BaseOfImage;
388         idsl.CheckSum = idsl64->CheckSum;
389         idsl.TimeDateStamp = idsl64->TimeDateStamp;
390         memcpy(idsl.FileName, idsl64->FileName, sizeof(idsl.FileName));
391         idsl.Reparse = idsl64->Reparse;
392         data32 = &idsl;
393         break;
394     case CBA_DUPLICATE_SYMBOL:
395     case CBA_EVENT:
396     case CBA_READ_MEMORY:
397     default:
398         FIXME("No mapping for action %lu\n", action);
399         return FALSE;
400     }
401     return cb32(hProcess, action, (PVOID)data32, (PVOID)user32);
402 }
403
404 /******************************************************************
405  *              pcs_callback (internal)
406  */
407 BOOL pcs_callback(const struct process* pcs, ULONG action, void* data)
408 {
409     TRACE("%p %lu %p\n", pcs, action, data);
410     if (!pcs->reg_cb) return FALSE;
411     return pcs->reg_cb(pcs->handle, action, (ULONG64)(DWORD_PTR)data, pcs->reg_user);
412 }
413
414 /***********************************************************************
415  *              SymRegisterCallback (DBGHELP.@)
416  */
417 BOOL WINAPI SymRegisterCallback(HANDLE hProcess, 
418                                 PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
419                                 PVOID UserContext)
420 {
421     DWORD64 tmp = ((ULONGLONG)(DWORD)CallbackFunction << 32) | (DWORD)UserContext;
422     return SymRegisterCallback64(hProcess, reg_cb64to32, tmp);
423 }
424
425 /***********************************************************************
426  *              SymRegisterCallback64 (DBGHELP.@)
427  */
428 BOOL WINAPI SymRegisterCallback64(HANDLE hProcess, 
429                                   PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
430                                   ULONG64 UserContext)
431 {
432     struct process* pcs = process_find_by_handle(hProcess);
433
434     TRACE("(%p, %p, %s)\n", 
435           hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
436     if (!pcs) return FALSE;
437     pcs->reg_cb = CallbackFunction;
438     pcs->reg_user = UserContext;
439
440     return TRUE;
441 }
442
443 /* This is imagehlp version not dbghelp !! */
444 static API_VERSION api_version = { 4, 0, 2, 0 };
445
446 /***********************************************************************
447  *           ImagehlpApiVersion (DBGHELP.@)
448  */
449 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
450 {
451     return &api_version;
452 }
453
454 /***********************************************************************
455  *           ImagehlpApiVersionEx (DBGHELP.@)
456  */
457 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
458 {
459     if (!AppVersion) return NULL;
460
461     AppVersion->MajorVersion = api_version.MajorVersion;
462     AppVersion->MinorVersion = api_version.MinorVersion;
463     AppVersion->Revision = api_version.Revision;
464     AppVersion->Reserved = api_version.Reserved;
465
466     return AppVersion;
467 }
468
469 /******************************************************************
470  *              ExtensionApiVersion (DBGHELP.@)
471  */
472 LPEXT_API_VERSION WINAPI ExtensionApiVersion(void)
473 {
474     static EXT_API_VERSION      eav = {5, 5, 5, 0};
475     return &eav;
476 }
477
478 /******************************************************************
479  *              WinDbgExtensionDllInit (DBGHELP.@)
480  */
481 void WINAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis,
482                                    unsigned short major, unsigned short minor)
483 {
484 }