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
32 * + debug start/stop in functions
33 * + parameters in function prototype...
35 * - most options (dbghelp_options) are not used (loading lines, decoration,
36 * deferring reading of module symbols, public symbols...)
37 * - (un)decoration is not handled (should make winedump's code a (.a) library
38 * and link it to winedump, and potentially to msvcrt and dbghelp (check best
39 * way not to duplicate code in msvcrt & dbghelp)
41 * + handle the debug_start & debug_end information block
42 * + get rid of MSC reading FIXME:s (lots of types are not defined)
45 * + we should add parameters' types to the function's signature
46 * while processing a function's parameters
47 * + should generate the func debug_{start,end} statements (black magic ?)
48 * + should identify the relay code in Wine and mark it as thunk type
50 * - implement the callback notification mechanism
53 unsigned dbghelp_options = SYMOPT_UNDNAME;
55 /***********************************************************************
56 * DllMain (DEBUGHLP.@)
58 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
62 case DLL_PROCESS_ATTACH: break;
63 case DLL_PROCESS_DETACH: break;
64 case DLL_THREAD_ATTACH: break;
65 case DLL_THREAD_DETACH: break;
71 static struct process* process_first /* = NULL */;
73 /******************************************************************
74 * process_find_by_handle
77 struct process* process_find_by_handle(HANDLE hProcess)
81 for (p = process_first; p && p->handle != hProcess; p = p->next);
82 if (!p) SetLastError(ERROR_INVALID_HANDLE);
86 /******************************************************************
87 * SymSetSearchPath (DBGHELP.@)
90 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PSTR searchPath)
92 struct process* pcs = process_find_by_handle(hProcess);
94 if (!pcs) return FALSE;
95 if (!searchPath) return FALSE;
97 HeapFree(GetProcessHeap(), 0, pcs->search_path);
98 pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(searchPath) + 1),
103 /***********************************************************************
104 * SymGetSearchPath (DBGHELP.@)
106 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, LPSTR szSearchPath,
107 DWORD SearchPathLength)
109 struct process* pcs = process_find_by_handle(hProcess);
110 if (!pcs) return FALSE;
112 strncpy(szSearchPath, pcs->search_path, SearchPathLength);
113 szSearchPath[SearchPathLength - 1] = '\0';
117 /******************************************************************
120 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
121 * this assumes that hProcess is a handle on a valid process
123 static BOOL process_invade(HANDLE hProcess)
126 char img[256], mod[256];
130 if (!EnumProcessModules(hProcess, hMods, sizeof(hMods), &sz))
131 return FALSE; /* FIXME should grow hMods */
133 for (i = 0; i < sz / sizeof(HMODULE); i++)
135 if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
136 !GetModuleFileNameExA(hProcess, hMods[i], img, sizeof(img)) ||
137 !GetModuleBaseNameA(hProcess, hMods[i], mod, sizeof(mod)) ||
138 !SymLoadModule(hProcess, 0, img, mod, (DWORD)mi.lpBaseOfDll, mi.SizeOfImage))
145 /******************************************************************
146 * SymInitialize (DBGHELP.@)
148 * The initialisation of a dbghelp's context.
149 * Note that hProcess doesn't need to be a valid process handle (except
150 * when fInvadeProcess is TRUE).
151 * Since, we're also allow to load ELF (pure) libraries and Wine ELF libraries
152 * containing PE (and NE) module(s), here's how we handle it:
153 * - we load every module (ELF, NE, PE) passed in SymLoadModule
154 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
155 * synchronization: hProcess should be a valid process handle, and we hook
156 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
157 * our internal ELF modules representation (loading / unloading). This way,
158 * we'll pair every loaded builtin PE module with its ELF counterpart (and
159 * access its debug information).
160 * - if fInvadeProcess (in SymInitialize) is FALSE, we won't be able to
161 * make the peering between a builtin PE module and its ELF counterpart, hence
162 * we won't be able to provide the requested debug information. We'll
163 * however be able to load native PE modules (and their debug information)
164 * without any trouble.
165 * Note also that this scheme can be intertwined with the deferred loading
166 * mechanism (ie only load the debug information when we actually need it).
168 BOOL WINAPI SymInitialize(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess)
172 TRACE("(%p %s %u)\n", hProcess, debugstr_a(UserSearchPath), fInvadeProcess);
174 if (process_find_by_handle(hProcess))
175 FIXME("what to do ??\n");
177 pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
178 if (!pcs) return FALSE;
180 pcs->handle = hProcess;
184 pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(UserSearchPath) + 1),
192 pcs->search_path = HeapAlloc(GetProcessHeap(), 0, len = MAX_PATH);
193 while ((size = GetCurrentDirectoryA(len, pcs->search_path)) >= len)
194 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, len *= 2);
195 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1);
197 len = GetEnvironmentVariableA("_NT_SYMBOL_PATH", NULL, 0);
200 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
201 pcs->search_path[size] = ';';
202 GetEnvironmentVariableA("_NT_SYMBOL_PATH", pcs->search_path + size + 1, len);
205 len = GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", NULL, 0);
208 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
209 pcs->search_path[size] = ';';
210 GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", pcs->search_path + size + 1, len);
215 pcs->lmodules = NULL;
216 pcs->dbg_hdr_addr = 0;
217 pcs->next = process_first;
222 pcs->dbg_hdr_addr = elf_read_wine_loader_dbg_info(pcs);
223 if (pcs->dbg_hdr_addr == 0)
225 SymCleanup(hProcess);
228 process_invade(hProcess);
229 elf_synchronize_module_list(pcs);
234 /******************************************************************
235 * SymCleanup (DBGHELP.@)
238 BOOL WINAPI SymCleanup(HANDLE hProcess)
240 struct process** ppcs;
241 struct process* next;
243 for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
245 if ((*ppcs)->handle == hProcess)
247 while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
249 HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
250 next = (*ppcs)->next;
251 HeapFree(GetProcessHeap(), 0, *ppcs);
259 /******************************************************************
260 * SymSetOptions (DBGHELP.@)
263 DWORD WINAPI SymSetOptions(DWORD opts)
265 return dbghelp_options = opts;
268 /******************************************************************
269 * SymGetOptions (DBGHELP.@)
272 DWORD WINAPI SymGetOptions(void)
274 return dbghelp_options;
277 /******************************************************************
278 * SymSetContext (DBGHELP.@)
281 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
282 PIMAGEHLP_CONTEXT Context)
284 struct process* pcs = process_find_by_handle(hProcess);
285 if (!pcs) return FALSE;
287 pcs->ctx_frame = *StackFrame;
288 /* MSDN states that Context is not (no longer?) used */
292 /***********************************************************************
293 * SymRegisterCallback (DBGHELP.@)
295 BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
296 PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
299 FIXME("(%p, %p, %p): stub\n", hProcess, CallbackFunction, UserContext);
300 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
304 /* This is imagehlp version not dbghelp !! */
305 static API_VERSION api_version = { 4, 0, 2, 0 };
307 /***********************************************************************
308 * ImagehlpApiVersion (DBGHELP.@)
310 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
315 /***********************************************************************
316 * ImagehlpApiVersionEx (DBGHELP.@)
318 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
320 if (!AppVersion) return NULL;
322 AppVersion->MajorVersion = api_version.MajorVersion;
323 AppVersion->MinorVersion = api_version.MinorVersion;
324 AppVersion->Revision = api_version.Revision;
325 AppVersion->Reserved = api_version.Reserved;