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 * + 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 * + for enums, we store the names & values (associated to the enum type),
37 * but those values are not directly usable from a debugger (that's why, I
38 * assume, that we have also to define constants for enum values, as
40 * + SymGetType(TI_GET_LENGTH) takes a ULONG64 (yurk, ugly)
41 * - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across
42 * functions, and even across function blocks...). Basically, for *Next* to work
43 * it requires an address after the prolog of the func (the base address of the
45 * - most options (dbghelp_options) are not used (loading lines...)
46 * - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
47 * we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
48 * we could use hash if name isn't a RE, and fall back to a full search when we
51 * + we should add parameters' types to the function's signature
52 * while processing a function's parameters
53 * + add support for function-less labels (as MSC seems to define them)
56 * + when, in a same module, the same definition is used in several compilation
57 * units, we get several definitions of the same object (especially
58 * struct/union). we should find a way not to duplicate them
59 * + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
60 * global variable is defined several times (at different scopes). We are
61 * getting several of those while looking for a unique symbol. Part of the
62 * issue is that we don't give a scope to a static variable inside a function
64 * - implement the callback notification mechanism
67 unsigned dbghelp_options
= SYMOPT_UNDNAME
;
68 HANDLE hMsvcrt
= NULL
;
70 /***********************************************************************
71 * DllMain (DEBUGHLP.@)
73 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
77 case DLL_PROCESS_ATTACH
: break;
78 case DLL_PROCESS_DETACH
:
79 if (hMsvcrt
) FreeLibrary(hMsvcrt
);
81 case DLL_THREAD_ATTACH
: break;
82 case DLL_THREAD_DETACH
: break;
88 static struct process
* process_first
/* = NULL */;
90 /******************************************************************
91 * process_find_by_handle
94 struct process
* process_find_by_handle(HANDLE hProcess
)
98 for (p
= process_first
; p
&& p
->handle
!= hProcess
; p
= p
->next
);
99 if (!p
) SetLastError(ERROR_INVALID_HANDLE
);
103 /******************************************************************
104 * SymSetSearchPath (DBGHELP.@)
107 BOOL WINAPI
SymSetSearchPath(HANDLE hProcess
, PSTR searchPath
)
109 struct process
* pcs
= process_find_by_handle(hProcess
);
111 if (!pcs
) return FALSE
;
112 if (!searchPath
) return FALSE
;
114 HeapFree(GetProcessHeap(), 0, pcs
->search_path
);
115 pcs
->search_path
= strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(searchPath
) + 1),
120 /***********************************************************************
121 * SymGetSearchPath (DBGHELP.@)
123 BOOL WINAPI
SymGetSearchPath(HANDLE hProcess
, LPSTR szSearchPath
,
124 DWORD SearchPathLength
)
126 struct process
* pcs
= process_find_by_handle(hProcess
);
127 if (!pcs
) return FALSE
;
129 lstrcpynA(szSearchPath
, pcs
->search_path
, SearchPathLength
);
133 /******************************************************************
136 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
137 * this assumes that hProcess is a handle on a valid process
139 static BOOL WINAPI
process_invade_cb(char* name
, DWORD base
, DWORD size
, void* user
)
142 HANDLE hProcess
= (HANDLE
)user
;
144 if (!GetModuleFileNameExA(hProcess
, (HMODULE
)base
,
146 lstrcpynA(tmp
, name
, sizeof(tmp
));
148 SymLoadModule(hProcess
, 0, tmp
, name
, base
, size
);
152 /******************************************************************
153 * SymInitialize (DBGHELP.@)
155 * The initialisation of a dbghelp's context.
156 * Note that hProcess doesn't need to be a valid process handle (except
157 * when fInvadeProcess is TRUE).
158 * Since, we're also allow to load ELF (pure) libraries and Wine ELF libraries
159 * containing PE (and NE) module(s), here's how we handle it:
160 * - we load every module (ELF, NE, PE) passed in SymLoadModule
161 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
162 * synchronization: hProcess should be a valid process handle, and we hook
163 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
164 * our internal ELF modules representation (loading / unloading). This way,
165 * we'll pair every loaded builtin PE module with its ELF counterpart (and
166 * access its debug information).
167 * - if fInvadeProcess (in SymInitialize) is FALSE, we won't be able to
168 * make the peering between a builtin PE module and its ELF counterpart, hence
169 * we won't be able to provide the requested debug information. We'll
170 * however be able to load native PE modules (and their debug information)
171 * without any trouble.
172 * Note also that this scheme can be intertwined with the deferred loading
173 * mechanism (ie only load the debug information when we actually need it).
175 BOOL WINAPI
SymInitialize(HANDLE hProcess
, PSTR UserSearchPath
, BOOL fInvadeProcess
)
179 TRACE("(%p %s %u)\n", hProcess
, debugstr_a(UserSearchPath
), fInvadeProcess
);
181 if (process_find_by_handle(hProcess
))
182 FIXME("what to do ??\n");
184 pcs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pcs
));
185 if (!pcs
) return FALSE
;
187 pcs
->handle
= hProcess
;
191 pcs
->search_path
= strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(UserSearchPath
) + 1),
199 pcs
->search_path
= HeapAlloc(GetProcessHeap(), 0, len
= MAX_PATH
);
200 while ((size
= GetCurrentDirectoryA(len
, pcs
->search_path
)) >= len
)
201 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, len
*= 2);
202 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, size
+ 1);
204 len
= GetEnvironmentVariableA("_NT_SYMBOL_PATH", NULL
, 0);
207 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, size
+ 1 + len
+ 1);
208 pcs
->search_path
[size
] = ';';
209 GetEnvironmentVariableA("_NT_SYMBOL_PATH", pcs
->search_path
+ size
+ 1, len
);
212 len
= GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", NULL
, 0);
215 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, size
+ 1 + len
+ 1);
216 pcs
->search_path
[size
] = ';';
217 GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", pcs
->search_path
+ size
+ 1, len
);
222 pcs
->lmodules
= NULL
;
223 pcs
->dbg_hdr_addr
= 0;
224 pcs
->next
= process_first
;
229 if (!elf_read_wine_loader_dbg_info(pcs
))
231 SymCleanup(hProcess
);
234 EnumerateLoadedModules(hProcess
, process_invade_cb
, (void*)hProcess
);
235 elf_synchronize_module_list(pcs
);
241 /******************************************************************
242 * SymCleanup (DBGHELP.@)
245 BOOL WINAPI
SymCleanup(HANDLE hProcess
)
247 struct process
** ppcs
;
248 struct process
* next
;
250 for (ppcs
= &process_first
; *ppcs
; ppcs
= &(*ppcs
)->next
)
252 if ((*ppcs
)->handle
== hProcess
)
254 while ((*ppcs
)->lmodules
) module_remove(*ppcs
, (*ppcs
)->lmodules
);
256 HeapFree(GetProcessHeap(), 0, (*ppcs
)->search_path
);
257 next
= (*ppcs
)->next
;
258 HeapFree(GetProcessHeap(), 0, *ppcs
);
266 /******************************************************************
267 * SymSetOptions (DBGHELP.@)
270 DWORD WINAPI
SymSetOptions(DWORD opts
)
272 return dbghelp_options
= opts
;
275 /******************************************************************
276 * SymGetOptions (DBGHELP.@)
279 DWORD WINAPI
SymGetOptions(void)
281 return dbghelp_options
;
284 /******************************************************************
285 * SymSetParentWindow (DBGHELP.@)
288 BOOL WINAPI
SymSetParentWindow(HWND hwnd
)
290 /* Save hwnd so it can be used as parent window */
291 FIXME("(%p): stub\n", hwnd
);
295 /******************************************************************
296 * SymSetContext (DBGHELP.@)
299 BOOL WINAPI
SymSetContext(HANDLE hProcess
, PIMAGEHLP_STACK_FRAME StackFrame
,
300 PIMAGEHLP_CONTEXT Context
)
302 struct process
* pcs
= process_find_by_handle(hProcess
);
303 if (!pcs
) return FALSE
;
305 pcs
->ctx_frame
= *StackFrame
;
306 /* MSDN states that Context is not (no longer?) used */
310 /***********************************************************************
311 * SymRegisterCallback (DBGHELP.@)
313 BOOL WINAPI
SymRegisterCallback(HANDLE hProcess
,
314 PSYMBOL_REGISTERED_CALLBACK CallbackFunction
,
317 FIXME("(%p, %p, %p): stub\n", hProcess
, CallbackFunction
, UserContext
);
318 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
322 /* This is imagehlp version not dbghelp !! */
323 static API_VERSION api_version
= { 4, 0, 2, 0 };
325 /***********************************************************************
326 * ImagehlpApiVersion (DBGHELP.@)
328 LPAPI_VERSION WINAPI
ImagehlpApiVersion(VOID
)
333 /***********************************************************************
334 * ImagehlpApiVersionEx (DBGHELP.@)
336 LPAPI_VERSION WINAPI
ImagehlpApiVersionEx(LPAPI_VERSION AppVersion
)
338 if (!AppVersion
) return NULL
;
340 AppVersion
->MajorVersion
= api_version
.MajorVersion
;
341 AppVersion
->MinorVersion
= api_version
.MinorVersion
;
342 AppVersion
->Revision
= api_version
.Revision
;
343 AppVersion
->Reserved
= api_version
.Reserved
;