2 * File dbghelp.c - generic routines (process) for dbghelp DLL
4 * Copyright (C) 2004, Eric Pouech
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.
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.
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
23 #include "dbghelp_private.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
31 * - support for symbols' types is still partly missing
33 * + we should store the underlying type for an enum in the symt_enum struct
34 * + for enums, we store the names & values (associated to the enum type),
35 * but those values are not directly usable from a debugger (that's why, I
36 * assume, that we have also to define constants for enum values, as
38 * + SymEnumTypes should only return *user* defined types (UDT, typedefs...) not
39 * all the types stored/used in the modules (like char*)
40 * - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across
41 * functions, and even across function blocks...). Basically, for *Next* to work
42 * it requires an address after the prolog of the func (the base address of the
44 * - most options (dbghelp_options) are not used (loading lines...)
45 * - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
46 * we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
47 * we could use hash if name isn't a RE, and fall back to a full search when we
50 * + we should add parameters' types to the function's signature
51 * while processing a function's parameters
52 * + add support for function-less labels (as MSC seems to define them)
55 * + when, in a same module, the same definition is used in several compilation
56 * units, we get several definitions of the same object (especially
57 * struct/union). we should find a way not to duplicate them
58 * + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
59 * global variable is defined several times (at different scopes). We are
60 * getting several of those while looking for a unique symbol. Part of the
61 * issue is that we don't give a scope to a static variable inside a function
63 * - implement the callback notification mechanism
66 unsigned dbghelp_options = SYMOPT_UNDNAME;
67 HANDLE hMsvcrt = NULL;
69 /***********************************************************************
70 * DllMain (DEBUGHLP.@)
72 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
76 case DLL_PROCESS_ATTACH: break;
77 case DLL_PROCESS_DETACH:
78 if (hMsvcrt) FreeLibrary(hMsvcrt);
80 case DLL_THREAD_ATTACH: break;
81 case DLL_THREAD_DETACH: break;
87 static struct process* process_first /* = NULL */;
89 /******************************************************************
90 * process_find_by_handle
93 struct process* process_find_by_handle(HANDLE hProcess)
97 for (p = process_first; p && p->handle != hProcess; p = p->next);
98 if (!p) SetLastError(ERROR_INVALID_HANDLE);
102 /******************************************************************
103 * validate_addr64 (internal)
106 BOOL validate_addr64(DWORD64 addr)
110 FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr));
111 SetLastError(ERROR_INVALID_PARAMETER);
117 /******************************************************************
118 * SymSetSearchPath (DBGHELP.@)
121 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PSTR searchPath)
123 struct process* pcs = process_find_by_handle(hProcess);
125 if (!pcs) return FALSE;
126 if (!searchPath) return FALSE;
128 HeapFree(GetProcessHeap(), 0, pcs->search_path);
129 pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(searchPath) + 1),
134 /***********************************************************************
135 * SymGetSearchPath (DBGHELP.@)
137 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, LPSTR szSearchPath,
138 DWORD SearchPathLength)
140 struct process* pcs = process_find_by_handle(hProcess);
141 if (!pcs) return FALSE;
143 lstrcpynA(szSearchPath, pcs->search_path, SearchPathLength);
147 /******************************************************************
150 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
151 * this assumes that hProcess is a handle on a valid process
153 static BOOL WINAPI process_invade_cb(char* name, DWORD base, DWORD size, void* user)
156 HANDLE hProcess = (HANDLE)user;
158 if (!GetModuleFileNameExA(hProcess, (HMODULE)base,
160 lstrcpynA(tmp, name, sizeof(tmp));
162 SymLoadModule(hProcess, 0, tmp, name, base, size);
166 /******************************************************************
167 * SymInitialize (DBGHELP.@)
169 * The initialisation of a dbghelp's context.
170 * Note that hProcess doesn't need to be a valid process handle (except
171 * when fInvadeProcess is TRUE).
172 * Since, we're also allow to load ELF (pure) libraries and Wine ELF libraries
173 * containing PE (and NE) module(s), here's how we handle it:
174 * - we load every module (ELF, NE, PE) passed in SymLoadModule
175 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
176 * synchronization: hProcess should be a valid process handle, and we hook
177 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
178 * our internal ELF modules representation (loading / unloading). This way,
179 * we'll pair every loaded builtin PE module with its ELF counterpart (and
180 * access its debug information).
181 * - if fInvadeProcess (in SymInitialize) is FALSE, we won't be able to
182 * make the peering between a builtin PE module and its ELF counterpart, hence
183 * we won't be able to provide the requested debug information. We'll
184 * however be able to load native PE modules (and their debug information)
185 * without any trouble.
186 * Note also that this scheme can be intertwined with the deferred loading
187 * mechanism (ie only load the debug information when we actually need it).
189 BOOL WINAPI SymInitialize(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess)
193 TRACE("(%p %s %u)\n", hProcess, debugstr_a(UserSearchPath), fInvadeProcess);
195 if (process_find_by_handle(hProcess))
196 FIXME("what to do ??\n");
198 pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
199 if (!pcs) return FALSE;
201 pcs->handle = hProcess;
205 pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(UserSearchPath) + 1),
213 pcs->search_path = HeapAlloc(GetProcessHeap(), 0, len = MAX_PATH);
214 while ((size = GetCurrentDirectoryA(len, pcs->search_path)) >= len)
215 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, len *= 2);
216 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1);
218 len = GetEnvironmentVariableA("_NT_SYMBOL_PATH", NULL, 0);
221 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
222 pcs->search_path[size] = ';';
223 GetEnvironmentVariableA("_NT_SYMBOL_PATH", pcs->search_path + size + 1, len);
226 len = GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", NULL, 0);
229 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
230 pcs->search_path[size] = ';';
231 GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", pcs->search_path + size + 1, len);
236 pcs->lmodules = NULL;
237 pcs->dbg_hdr_addr = 0;
238 pcs->next = process_first;
243 if (!elf_read_wine_loader_dbg_info(pcs))
245 SymCleanup(hProcess);
248 EnumerateLoadedModules(hProcess, process_invade_cb, (void*)hProcess);
249 elf_synchronize_module_list(pcs);
255 /******************************************************************
256 * SymCleanup (DBGHELP.@)
259 BOOL WINAPI SymCleanup(HANDLE hProcess)
261 struct process** ppcs;
262 struct process* next;
264 for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
266 if ((*ppcs)->handle == hProcess)
268 while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
270 HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
271 next = (*ppcs)->next;
272 HeapFree(GetProcessHeap(), 0, *ppcs);
280 /******************************************************************
281 * SymSetOptions (DBGHELP.@)
284 DWORD WINAPI SymSetOptions(DWORD opts)
286 return dbghelp_options = opts;
289 /******************************************************************
290 * SymGetOptions (DBGHELP.@)
293 DWORD WINAPI SymGetOptions(void)
295 return dbghelp_options;
298 /******************************************************************
299 * SymSetParentWindow (DBGHELP.@)
302 BOOL WINAPI SymSetParentWindow(HWND hwnd)
304 /* Save hwnd so it can be used as parent window */
305 FIXME("(%p): stub\n", hwnd);
309 /******************************************************************
310 * SymSetContext (DBGHELP.@)
313 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
314 PIMAGEHLP_CONTEXT Context)
316 struct process* pcs = process_find_by_handle(hProcess);
317 if (!pcs) return FALSE;
319 pcs->ctx_frame = *StackFrame;
320 /* MSDN states that Context is not (no longer?) used */
324 /***********************************************************************
325 * SymRegisterCallback (DBGHELP.@)
327 BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
328 PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
331 FIXME("(%p, %p, %p): stub\n", hProcess, CallbackFunction, UserContext);
332 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
336 /***********************************************************************
337 * SymRegisterCallback64 (DBGHELP.@)
339 BOOL WINAPI SymRegisterCallback64(HANDLE hProcess,
340 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
343 FIXME("(%p, %p, %s): stub\n",
344 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
345 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
349 /* This is imagehlp version not dbghelp !! */
350 static API_VERSION api_version = { 4, 0, 2, 0 };
352 /***********************************************************************
353 * ImagehlpApiVersion (DBGHELP.@)
355 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
360 /***********************************************************************
361 * ImagehlpApiVersionEx (DBGHELP.@)
363 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
365 if (!AppVersion) return NULL;
367 AppVersion->MajorVersion = api_version.MajorVersion;
368 AppVersion->MinorVersion = api_version.MinorVersion;
369 AppVersion->Revision = api_version.Revision;
370 AppVersion->Reserved = api_version.Reserved;