wldap32: Added configure checks for some potentially missing functions.
[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  *  - implement the callback notification mechanism
65  */
66
67 unsigned   dbghelp_options = SYMOPT_UNDNAME;
68 HANDLE     hMsvcrt = NULL;
69
70 /***********************************************************************
71  *           DllMain (DEBUGHLP.@)
72  */
73 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
74 {
75     switch (fdwReason)
76     {
77     case DLL_PROCESS_ATTACH:    break;
78     case DLL_PROCESS_DETACH:
79         if (hMsvcrt) FreeLibrary(hMsvcrt);
80         break;
81     case DLL_THREAD_ATTACH:     break;
82     case DLL_THREAD_DETACH:     break;
83     default:                    break;
84     }
85     return TRUE;
86 }
87
88 static struct process* process_first /* = NULL */;
89
90 /******************************************************************
91  *              process_find_by_handle
92  *
93  */
94 struct process*    process_find_by_handle(HANDLE hProcess)
95 {
96     struct process* p;
97
98     for (p = process_first; p && p->handle != hProcess; p = p->next);
99     if (!p) SetLastError(ERROR_INVALID_HANDLE);
100     return p;
101 }
102
103 /******************************************************************
104  *             validate_addr64 (internal)
105  *
106  */
107 BOOL validate_addr64(DWORD64 addr)
108 {
109     if (addr >> 32)
110     {
111         FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr));
112         SetLastError(ERROR_INVALID_PARAMETER);
113         return FALSE;
114     }
115     return TRUE;
116 }
117
118 /******************************************************************
119  *              SymSetSearchPath (DBGHELP.@)
120  *
121  */
122 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PSTR searchPath)
123 {
124     struct process* pcs = process_find_by_handle(hProcess);
125
126     if (!pcs) return FALSE;
127     if (!searchPath) return FALSE;
128
129     HeapFree(GetProcessHeap(), 0, pcs->search_path);
130     pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(searchPath) + 1),
131                               searchPath);
132     return TRUE;
133 }
134
135 /***********************************************************************
136  *              SymGetSearchPath (DBGHELP.@)
137  */
138 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, LPSTR szSearchPath, 
139                              DWORD SearchPathLength)
140 {
141     struct process* pcs = process_find_by_handle(hProcess);
142     if (!pcs) return FALSE;
143
144     lstrcpynA(szSearchPath, pcs->search_path, SearchPathLength);
145     return TRUE;
146 }
147
148 /******************************************************************
149  *              invade_process
150  *
151  * SymInitialize helper: loads in dbghelp all known (and loaded modules)
152  * this assumes that hProcess is a handle on a valid process
153  */
154 static BOOL WINAPI process_invade_cb(char* name, DWORD base, DWORD size, void* user)
155 {
156     char        tmp[MAX_PATH];
157     HANDLE      hProcess = (HANDLE)user;
158
159     if (!GetModuleFileNameExA(hProcess, (HMODULE)base, 
160                               tmp, sizeof(tmp)))
161         lstrcpynA(tmp, name, sizeof(tmp));
162
163     SymLoadModule(hProcess, 0, tmp, name, base, size);
164     return TRUE;
165 }
166
167 /******************************************************************
168  *              SymInitialize (DBGHELP.@)
169  *
170  * The initialisation of a dbghelp's context.
171  * Note that hProcess doesn't need to be a valid process handle (except
172  * when fInvadeProcess is TRUE).
173  * Since, we're also allow to load ELF (pure) libraries and Wine ELF libraries 
174  * containing PE (and NE) module(s), here's how we handle it:
175  * - we load every module (ELF, NE, PE) passed in SymLoadModule
176  * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
177  *   synchronization: hProcess should be a valid process handle, and we hook
178  *   ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
179  *   our internal ELF modules representation (loading / unloading). This way,
180  *   we'll pair every loaded builtin PE module with its ELF counterpart (and
181  *   access its debug information).
182  * - if fInvadeProcess (in SymInitialize) is FALSE, we won't be able to
183  *   make the peering between a builtin PE module and its ELF counterpart, hence
184  *   we won't be able to provide the requested debug information. We'll
185  *   however be able to load native PE modules (and their debug information)
186  *   without any trouble.
187  * Note also that this scheme can be intertwined with the deferred loading 
188  * mechanism (ie only load the debug information when we actually need it).
189  */
190 BOOL WINAPI SymInitialize(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess)
191 {
192     struct process*     pcs;
193
194     TRACE("(%p %s %u)\n", hProcess, debugstr_a(UserSearchPath), fInvadeProcess);
195
196     if (process_find_by_handle(hProcess))
197         FIXME("what to do ??\n");
198
199     pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
200     if (!pcs) return FALSE;
201
202     pcs->handle = hProcess;
203
204     if (UserSearchPath)
205     {
206         pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(UserSearchPath) + 1), 
207                                   UserSearchPath);
208     }
209     else
210     {
211         unsigned        size;
212         unsigned        len;
213
214         pcs->search_path = HeapAlloc(GetProcessHeap(), 0, len = MAX_PATH);
215         while ((size = GetCurrentDirectoryA(len, pcs->search_path)) >= len)
216             pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, len *= 2);
217         pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1);
218
219         len = GetEnvironmentVariableA("_NT_SYMBOL_PATH", NULL, 0);
220         if (len)
221         {
222             pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
223             pcs->search_path[size] = ';';
224             GetEnvironmentVariableA("_NT_SYMBOL_PATH", pcs->search_path + size + 1, len);
225             size += 1 + len;
226         }
227         len = GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", NULL, 0);
228         if (len)
229         {
230             pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
231             pcs->search_path[size] = ';';
232             GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", pcs->search_path + size + 1, len);
233             size += 1 + len;
234         }
235     }
236
237     pcs->lmodules = NULL;
238     pcs->dbg_hdr_addr = 0;
239     pcs->next = process_first;
240     process_first = pcs;
241
242     if (fInvadeProcess)
243     {
244         if (!elf_read_wine_loader_dbg_info(pcs))
245         {
246             SymCleanup(hProcess);
247             return FALSE;
248         }
249         EnumerateLoadedModules(hProcess, process_invade_cb, (void*)hProcess);
250         elf_synchronize_module_list(pcs);
251     }
252
253     return TRUE;
254 }
255
256 /******************************************************************
257  *              SymCleanup (DBGHELP.@)
258  *
259  */
260 BOOL WINAPI SymCleanup(HANDLE hProcess)
261 {
262     struct process**    ppcs;
263     struct process*     next;
264
265     for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
266     {
267         if ((*ppcs)->handle == hProcess)
268         {
269             while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
270
271             HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
272             next = (*ppcs)->next;
273             HeapFree(GetProcessHeap(), 0, *ppcs);
274             *ppcs = next;
275             return TRUE;
276         }
277     }
278     return FALSE;
279 }
280
281 /******************************************************************
282  *              SymSetOptions (DBGHELP.@)
283  *
284  */
285 DWORD WINAPI SymSetOptions(DWORD opts)
286 {
287     return dbghelp_options = opts;
288 }
289
290 /******************************************************************
291  *              SymGetOptions (DBGHELP.@)
292  *
293  */
294 DWORD WINAPI SymGetOptions(void)
295 {
296     return dbghelp_options;
297 }
298
299 /******************************************************************
300  *              SymSetParentWindow (DBGHELP.@)
301  *
302  */
303 BOOL WINAPI SymSetParentWindow(HWND hwnd)
304 {
305     /* Save hwnd so it can be used as parent window */
306     FIXME("(%p): stub\n", hwnd);
307     return TRUE;
308 }
309
310 /******************************************************************
311  *              SymSetContext (DBGHELP.@)
312  *
313  */
314 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
315                           PIMAGEHLP_CONTEXT Context)
316 {
317     struct process* pcs = process_find_by_handle(hProcess);
318     if (!pcs) return FALSE;
319
320     pcs->ctx_frame = *StackFrame;
321     /* MSDN states that Context is not (no longer?) used */
322     return TRUE;
323 }
324
325 /***********************************************************************
326  *              SymRegisterCallback (DBGHELP.@)
327  */
328 BOOL WINAPI SymRegisterCallback(HANDLE hProcess, 
329                                 PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
330                                 PVOID UserContext)
331 {
332     FIXME("(%p, %p, %p): stub\n", hProcess, CallbackFunction, UserContext);
333     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
334     return FALSE;
335 }
336
337 /***********************************************************************
338  *              SymRegisterCallback64 (DBGHELP.@)
339  */
340 BOOL WINAPI SymRegisterCallback64(HANDLE hProcess, 
341                                   PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
342                                   ULONG64 UserContext)
343 {
344     FIXME("(%p, %p, %s): stub\n", 
345           hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
346     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
347     return FALSE;
348 }
349
350 /* This is imagehlp version not dbghelp !! */
351 static API_VERSION api_version = { 4, 0, 2, 0 };
352
353 /***********************************************************************
354  *           ImagehlpApiVersion (DBGHELP.@)
355  */
356 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
357 {
358     return &api_version;
359 }
360
361 /***********************************************************************
362  *           ImagehlpApiVersionEx (DBGHELP.@)
363  */
364 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
365 {
366     if (!AppVersion) return NULL;
367
368     AppVersion->MajorVersion = api_version.MajorVersion;
369     AppVersion->MinorVersion = api_version.MinorVersion;
370     AppVersion->Revision = api_version.Revision;
371     AppVersion->Reserved = api_version.Reserved;
372
373     return AppVersion;
374 }
375
376 /******************************************************************
377  *              ExtensionApiVersion (DBGHELP.@)
378  */
379 LPEXT_API_VERSION WINAPI ExtensionApiVersion(void)
380 {
381     static EXT_API_VERSION      eav = {5, 5, 5, 0};
382     return &eav;
383 }
384
385 /******************************************************************
386  *              WinDbgExtensionDllInit (DBGHELP.@)
387  */
388 void WINAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis,
389                                    unsigned short major, unsigned short minor)
390 {
391 }