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