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 * - 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)
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)
47 * + should identify the relay code in Wine and mark it as thunk type
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
)
61 case DLL_PROCESS_ATTACH
: break;
62 case DLL_PROCESS_DETACH
: break;
63 case DLL_THREAD_ATTACH
: break;
64 case DLL_THREAD_DETACH
: break;
70 static struct process
* process_first
/* = NULL */;
72 /******************************************************************
73 * process_find_by_handle
76 struct process
* process_find_by_handle(HANDLE hProcess
)
80 for (p
= process_first
; p
&& p
->handle
!= hProcess
; p
= p
->next
);
81 if (!p
) SetLastError(ERROR_INVALID_HANDLE
);
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),
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';
116 /******************************************************************
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
)
125 char img
[256], mod
[256];
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
))
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
)
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
;
183 pcs
->search_path
= strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(UserSearchPath
) + 1),
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);
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
);
204 len
= GetEnvironmentVariableA("_NT_ALTERNATE_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_ALTERNATE_SYMBOL_PATH", pcs
->search_path
+ size
+ 1, len
);
214 pcs
->lmodules
= NULL
;
215 pcs
->dbg_hdr_addr
= 0;
216 pcs
->next
= process_first
;
221 pcs
->dbg_hdr_addr
= elf_read_wine_loader_dbg_info(pcs
);
222 if (pcs
->dbg_hdr_addr
== 0)
224 SymCleanup(hProcess
);
227 process_invade(hProcess
);
228 elf_synchronize_module_list(pcs
);
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
);
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 */
291 /***********************************************************************
292 * SymRegisterCallback (DBGHELP.@)
294 BOOL WINAPI
SymRegisterCallback(HANDLE hProcess
,
295 PSYMBOL_REGISTERED_CALLBACK CallbackFunction
,
298 FIXME("(%p, %p, %p): stub\n", hProcess
, CallbackFunction
, UserContext
);
299 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
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
)
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
;