- implemented support for function debug start/stop and labels (msc.c
[wine/hacks.git] / dlls / dbghelp / dbghelp.c
blob3ee317b55224b9f9142081061b826eeec4b4db84
1 /*
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
21 #include "config.h"
23 #include "dbghelp_private.h"
24 #include "winerror.h"
25 #include "psapi.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
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
52 unsigned dbghelp_options = SYMOPT_UNDNAME;
54 /***********************************************************************
55 * DllMain (DEBUGHLP.@)
57 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
59 switch (fdwReason)
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;
67 return TRUE;
70 static struct process* process_first /* = NULL */;
72 /******************************************************************
73 * process_find_by_handle
76 struct process* process_find_by_handle(HANDLE hProcess)
78 struct process* p;
80 for (p = process_first; p && p->handle != hProcess; p = p->next);
81 if (!p) SetLastError(ERROR_INVALID_HANDLE);
82 return p;
85 /******************************************************************
86 * SymSetSearchPath (DBGHELP.@)
89 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PSTR searchPath)
91 struct process* pcs = process_find_by_handle(hProcess);
93 if (!pcs) return FALSE;
94 if (!searchPath) return FALSE;
96 HeapFree(GetProcessHeap(), 0, pcs->search_path);
97 pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(searchPath) + 1),
98 searchPath);
99 return TRUE;
102 /***********************************************************************
103 * SymGetSearchPath (DBGHELP.@)
105 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, LPSTR szSearchPath,
106 DWORD SearchPathLength)
108 struct process* pcs = process_find_by_handle(hProcess);
109 if (!pcs) return FALSE;
111 strncpy(szSearchPath, pcs->search_path, SearchPathLength);
112 szSearchPath[SearchPathLength - 1] = '\0';
113 return TRUE;
116 /******************************************************************
117 * invade_process
119 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
120 * this assumes that hProcess is a handle on a valid process
122 static BOOL process_invade(HANDLE hProcess)
124 HMODULE hMods[256];
125 char img[256], mod[256];
126 DWORD i, sz;
127 MODULEINFO mi;
129 if (!EnumProcessModules(hProcess, hMods, sizeof(hMods), &sz))
130 return FALSE; /* FIXME should grow hMods */
132 for (i = 0; i < sz / sizeof(HMODULE); i++)
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;
141 return sz != 0;
144 /******************************************************************
145 * SymInitialize (DBGHELP.@)
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).
167 BOOL WINAPI SymInitialize(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess)
169 struct process* pcs;
171 TRACE("(%p %s %u)\n", hProcess, debugstr_a(UserSearchPath), fInvadeProcess);
173 if (process_find_by_handle(hProcess))
174 FIXME("what to do ??\n");
176 pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
177 if (!pcs) return FALSE;
179 pcs->handle = hProcess;
181 if (UserSearchPath)
183 pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(UserSearchPath) + 1),
184 UserSearchPath);
186 else
188 unsigned size;
189 unsigned len;
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);
196 len = GetEnvironmentVariableA("_NT_SYMBOL_PATH", NULL, 0);
197 if (len)
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;
204 len = GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", NULL, 0);
205 if (len)
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;
214 pcs->lmodules = NULL;
215 pcs->dbg_hdr_addr = 0;
216 pcs->next = process_first;
217 process_first = pcs;
219 if (fInvadeProcess)
221 pcs->dbg_hdr_addr = elf_read_wine_loader_dbg_info(pcs);
222 if (pcs->dbg_hdr_addr == 0)
224 SymCleanup(hProcess);
225 return FALSE;
227 process_invade(hProcess);
228 elf_synchronize_module_list(pcs);
230 return TRUE;
233 /******************************************************************
234 * SymCleanup (DBGHELP.@)
237 BOOL WINAPI SymCleanup(HANDLE hProcess)
239 struct process** ppcs;
240 struct process* next;
242 for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
244 if ((*ppcs)->handle == hProcess)
246 while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
248 HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
249 next = (*ppcs)->next;
250 HeapFree(GetProcessHeap(), 0, *ppcs);
251 *ppcs = next;
252 return TRUE;
255 return FALSE;
258 /******************************************************************
259 * SymSetOptions (DBGHELP.@)
262 DWORD WINAPI SymSetOptions(DWORD opts)
264 return dbghelp_options = opts;
267 /******************************************************************
268 * SymGetOptions (DBGHELP.@)
271 DWORD WINAPI SymGetOptions(void)
273 return dbghelp_options;
276 /******************************************************************
277 * SymSetContext (DBGHELP.@)
280 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
281 PIMAGEHLP_CONTEXT Context)
283 struct process* pcs = process_find_by_handle(hProcess);
284 if (!pcs) return FALSE;
286 pcs->ctx_frame = *StackFrame;
287 /* MSDN states that Context is not (no longer?) used */
288 return TRUE;
291 /***********************************************************************
292 * SymRegisterCallback (DBGHELP.@)
294 BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
295 PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
296 PVOID UserContext)
298 FIXME("(%p, %p, %p): stub\n", hProcess, CallbackFunction, UserContext);
299 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
300 return FALSE;
303 /* This is imagehlp version not dbghelp !! */
304 static API_VERSION api_version = { 4, 0, 2, 0 };
306 /***********************************************************************
307 * ImagehlpApiVersion (DBGHELP.@)
309 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
311 return &api_version;
314 /***********************************************************************
315 * ImagehlpApiVersionEx (DBGHELP.@)
317 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
319 if (!AppVersion) return NULL;
321 AppVersion->MajorVersion = api_version.MajorVersion;
322 AppVersion->MinorVersion = api_version.MinorVersion;
323 AppVersion->Revision = api_version.Revision;
324 AppVersion->Reserved = api_version.Reserved;
326 return AppVersion;