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