2004-04-06 00:21:27 +02:00
|
|
|
/*
|
|
|
|
* File dbghelp.c - generic routines (process) for dbghelp DLL
|
|
|
|
*
|
|
|
|
* Copyright (C) 2004, Eric Pouech
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "dbghelp_private.h"
|
|
|
|
#include "winerror.h"
|
|
|
|
#include "psapi.h"
|
|
|
|
#include "wine/debug.h"
|
2005-12-20 11:49:24 +01:00
|
|
|
#include "wdbgexts.h"
|
2004-04-06 00:21:27 +02:00
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
|
|
|
|
|
|
|
/* TODO
|
|
|
|
* - support for symbols' types is still partly missing
|
|
|
|
* + C++ support
|
2004-04-19 04:58:27 +02:00
|
|
|
* + we should store the underlying type for an enum in the symt_enum struct
|
2004-11-19 19:02:47 +01:00
|
|
|
* + for enums, we store the names & values (associated to the enum type),
|
|
|
|
* but those values are not directly usable from a debugger (that's why, I
|
|
|
|
* assume, that we have also to define constants for enum values, as
|
|
|
|
* Codeview does BTW.
|
2005-11-18 13:05:44 +01:00
|
|
|
* + SymEnumTypes should only return *user* defined types (UDT, typedefs...) not
|
|
|
|
* all the types stored/used in the modules (like char*)
|
2005-03-01 11:39:49 +01:00
|
|
|
* - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across
|
|
|
|
* functions, and even across function blocks...). Basically, for *Next* to work
|
|
|
|
* it requires an address after the prolog of the func (the base address of the
|
|
|
|
* func doesn't work)
|
2004-11-19 19:02:47 +01:00
|
|
|
* - most options (dbghelp_options) are not used (loading lines...)
|
2004-05-24 21:08:19 +02:00
|
|
|
* - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
|
|
|
|
* we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
|
|
|
|
* we could use hash if name isn't a RE, and fall back to a full search when we
|
|
|
|
* get a full RE
|
2004-04-06 00:21:27 +02:00
|
|
|
* - msc:
|
2004-04-19 04:58:27 +02:00
|
|
|
* + we should add parameters' types to the function's signature
|
|
|
|
* while processing a function's parameters
|
2005-03-01 11:39:49 +01:00
|
|
|
* + add support for function-less labels (as MSC seems to define them)
|
2004-04-06 00:21:27 +02:00
|
|
|
* + C++ management
|
|
|
|
* - stabs:
|
2004-08-30 21:31:13 +02:00
|
|
|
* + when, in a same module, the same definition is used in several compilation
|
|
|
|
* units, we get several definitions of the same object (especially
|
|
|
|
* struct/union). we should find a way not to duplicate them
|
|
|
|
* + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
|
|
|
|
* global variable is defined several times (at different scopes). We are
|
|
|
|
* getting several of those while looking for a unique symbol. Part of the
|
|
|
|
* issue is that we don't give a scope to a static variable inside a function
|
2004-04-06 00:21:27 +02:00
|
|
|
* + C++ management
|
|
|
|
*/
|
|
|
|
|
|
|
|
unsigned dbghelp_options = SYMOPT_UNDNAME;
|
2004-11-19 19:02:47 +01:00
|
|
|
HANDLE hMsvcrt = NULL;
|
2004-04-06 00:21:27 +02:00
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* DllMain (DEBUGHLP.@)
|
|
|
|
*/
|
|
|
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
|
|
|
{
|
|
|
|
switch (fdwReason)
|
|
|
|
{
|
|
|
|
case DLL_PROCESS_ATTACH: break;
|
2004-11-19 19:02:47 +01:00
|
|
|
case DLL_PROCESS_DETACH:
|
|
|
|
if (hMsvcrt) FreeLibrary(hMsvcrt);
|
|
|
|
break;
|
2004-04-06 00:21:27 +02:00
|
|
|
case DLL_THREAD_ATTACH: break;
|
|
|
|
case DLL_THREAD_DETACH: break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct process* process_first /* = NULL */;
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
* process_find_by_handle
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
struct process* process_find_by_handle(HANDLE hProcess)
|
|
|
|
{
|
|
|
|
struct process* p;
|
|
|
|
|
|
|
|
for (p = process_first; p && p->handle != hProcess; p = p->next);
|
|
|
|
if (!p) SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2005-11-29 11:24:46 +01:00
|
|
|
/******************************************************************
|
|
|
|
* validate_addr64 (internal)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
BOOL validate_addr64(DWORD64 addr)
|
|
|
|
{
|
|
|
|
if (addr >> 32)
|
|
|
|
{
|
|
|
|
FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr));
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2004-04-06 00:21:27 +02:00
|
|
|
/******************************************************************
|
|
|
|
* SymSetSearchPath (DBGHELP.@)
|
|
|
|
*
|
|
|
|
*/
|
2006-01-23 16:37:48 +01:00
|
|
|
BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PCSTR searchPath)
|
2004-04-06 00:21:27 +02:00
|
|
|
{
|
|
|
|
struct process* pcs = process_find_by_handle(hProcess);
|
|
|
|
|
|
|
|
if (!pcs) return FALSE;
|
|
|
|
if (!searchPath) return FALSE;
|
|
|
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, pcs->search_path);
|
|
|
|
pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(searchPath) + 1),
|
|
|
|
searchPath);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* SymGetSearchPath (DBGHELP.@)
|
|
|
|
*/
|
|
|
|
BOOL WINAPI SymGetSearchPath(HANDLE hProcess, LPSTR szSearchPath,
|
|
|
|
DWORD SearchPathLength)
|
|
|
|
{
|
|
|
|
struct process* pcs = process_find_by_handle(hProcess);
|
|
|
|
if (!pcs) return FALSE;
|
|
|
|
|
2005-03-28 16:17:51 +02:00
|
|
|
lstrcpynA(szSearchPath, pcs->search_path, SearchPathLength);
|
2004-04-06 00:21:27 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
* invade_process
|
|
|
|
*
|
|
|
|
* SymInitialize helper: loads in dbghelp all known (and loaded modules)
|
|
|
|
* this assumes that hProcess is a handle on a valid process
|
|
|
|
*/
|
2005-03-01 11:39:49 +01:00
|
|
|
static BOOL WINAPI process_invade_cb(char* name, DWORD base, DWORD size, void* user)
|
2004-04-06 00:21:27 +02:00
|
|
|
{
|
2005-03-07 13:24:02 +01:00
|
|
|
char tmp[MAX_PATH];
|
|
|
|
HANDLE hProcess = (HANDLE)user;
|
|
|
|
|
|
|
|
if (!GetModuleFileNameExA(hProcess, (HMODULE)base,
|
|
|
|
tmp, sizeof(tmp)))
|
|
|
|
lstrcpynA(tmp, name, sizeof(tmp));
|
|
|
|
|
|
|
|
SymLoadModule(hProcess, 0, tmp, name, base, size);
|
2005-03-01 11:39:49 +01:00
|
|
|
return TRUE;
|
2004-04-06 00:21:27 +02:00
|
|
|
}
|
|
|
|
|
2006-01-23 16:30:03 +01:00
|
|
|
/******************************************************************
|
|
|
|
* check_live_target
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static BOOL check_live_target(struct process* pcs)
|
|
|
|
{
|
|
|
|
if (!GetProcessId(pcs->handle)) return FALSE;
|
2006-03-18 10:32:33 +01:00
|
|
|
if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE;
|
|
|
|
return elf_read_wine_loader_dbg_info(pcs);
|
2006-01-23 16:30:03 +01:00
|
|
|
}
|
|
|
|
|
2004-04-06 00:21:27 +02:00
|
|
|
/******************************************************************
|
|
|
|
* SymInitialize (DBGHELP.@)
|
|
|
|
*
|
|
|
|
* The initialisation of a dbghelp's context.
|
|
|
|
* Note that hProcess doesn't need to be a valid process handle (except
|
|
|
|
* when fInvadeProcess is TRUE).
|
|
|
|
* Since, we're also allow to load ELF (pure) libraries and Wine ELF libraries
|
|
|
|
* containing PE (and NE) module(s), here's how we handle it:
|
|
|
|
* - we load every module (ELF, NE, PE) passed in SymLoadModule
|
|
|
|
* - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
|
|
|
|
* synchronization: hProcess should be a valid process handle, and we hook
|
|
|
|
* ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
|
|
|
|
* our internal ELF modules representation (loading / unloading). This way,
|
|
|
|
* we'll pair every loaded builtin PE module with its ELF counterpart (and
|
|
|
|
* access its debug information).
|
2006-01-23 16:30:03 +01:00
|
|
|
* - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
|
|
|
|
* hProcess refers to a running process. We use some heuristics here, so YMMV.
|
|
|
|
* If we detect a live target, then we get the same handling as if
|
|
|
|
* fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
|
|
|
|
* we won't be able to make the peering between a builtin PE module and its ELF
|
|
|
|
* counterpart. Hence we won't be able to provide the requested debug
|
|
|
|
* information. We'll however be able to load native PE modules (and their
|
|
|
|
* debug information) without any trouble.
|
2004-04-06 00:21:27 +02:00
|
|
|
* Note also that this scheme can be intertwined with the deferred loading
|
|
|
|
* mechanism (ie only load the debug information when we actually need it).
|
|
|
|
*/
|
2006-01-23 16:37:48 +01:00
|
|
|
BOOL WINAPI SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess)
|
2004-04-06 00:21:27 +02:00
|
|
|
{
|
|
|
|
struct process* pcs;
|
|
|
|
|
|
|
|
TRACE("(%p %s %u)\n", hProcess, debugstr_a(UserSearchPath), fInvadeProcess);
|
|
|
|
|
|
|
|
if (process_find_by_handle(hProcess))
|
|
|
|
FIXME("what to do ??\n");
|
|
|
|
|
|
|
|
pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
|
|
|
|
if (!pcs) return FALSE;
|
|
|
|
|
|
|
|
pcs->handle = hProcess;
|
|
|
|
|
|
|
|
if (UserSearchPath)
|
|
|
|
{
|
|
|
|
pcs->search_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(UserSearchPath) + 1),
|
|
|
|
UserSearchPath);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned size;
|
|
|
|
unsigned len;
|
|
|
|
|
|
|
|
pcs->search_path = HeapAlloc(GetProcessHeap(), 0, len = MAX_PATH);
|
|
|
|
while ((size = GetCurrentDirectoryA(len, pcs->search_path)) >= len)
|
|
|
|
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, len *= 2);
|
|
|
|
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1);
|
|
|
|
|
|
|
|
len = GetEnvironmentVariableA("_NT_SYMBOL_PATH", NULL, 0);
|
|
|
|
if (len)
|
|
|
|
{
|
|
|
|
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
|
|
|
|
pcs->search_path[size] = ';';
|
|
|
|
GetEnvironmentVariableA("_NT_SYMBOL_PATH", pcs->search_path + size + 1, len);
|
|
|
|
size += 1 + len;
|
|
|
|
}
|
|
|
|
len = GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", NULL, 0);
|
|
|
|
if (len)
|
|
|
|
{
|
|
|
|
pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, size + 1 + len + 1);
|
|
|
|
pcs->search_path[size] = ';';
|
|
|
|
GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", pcs->search_path + size + 1, len);
|
|
|
|
size += 1 + len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pcs->lmodules = NULL;
|
|
|
|
pcs->dbg_hdr_addr = 0;
|
|
|
|
pcs->next = process_first;
|
|
|
|
process_first = pcs;
|
2006-01-23 16:30:03 +01:00
|
|
|
|
|
|
|
if (check_live_target(pcs))
|
2004-04-06 00:21:27 +02:00
|
|
|
{
|
2006-01-23 16:30:03 +01:00
|
|
|
if (fInvadeProcess)
|
|
|
|
EnumerateLoadedModules(hProcess, process_invade_cb, (void*)hProcess);
|
2004-04-06 00:21:27 +02:00
|
|
|
elf_synchronize_module_list(pcs);
|
|
|
|
}
|
2006-01-23 16:30:03 +01:00
|
|
|
else if (fInvadeProcess)
|
|
|
|
{
|
|
|
|
SymCleanup(hProcess);
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2005-03-01 11:39:49 +01:00
|
|
|
|
2004-04-06 00:21:27 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
* SymCleanup (DBGHELP.@)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
BOOL WINAPI SymCleanup(HANDLE hProcess)
|
|
|
|
{
|
|
|
|
struct process** ppcs;
|
|
|
|
struct process* next;
|
|
|
|
|
|
|
|
for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
|
|
|
|
{
|
|
|
|
if ((*ppcs)->handle == hProcess)
|
|
|
|
{
|
|
|
|
while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
|
|
|
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
|
|
|
|
next = (*ppcs)->next;
|
|
|
|
HeapFree(GetProcessHeap(), 0, *ppcs);
|
|
|
|
*ppcs = next;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
* SymSetOptions (DBGHELP.@)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
DWORD WINAPI SymSetOptions(DWORD opts)
|
|
|
|
{
|
2006-01-23 16:29:21 +01:00
|
|
|
struct process* pcs;
|
|
|
|
|
|
|
|
for (pcs = process_first; pcs; pcs = pcs->next)
|
|
|
|
{
|
|
|
|
pcs_callback(pcs, CBA_SET_OPTIONS, &opts);
|
|
|
|
}
|
2004-04-06 00:21:27 +02:00
|
|
|
return dbghelp_options = opts;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
* SymGetOptions (DBGHELP.@)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
DWORD WINAPI SymGetOptions(void)
|
|
|
|
{
|
|
|
|
return dbghelp_options;
|
|
|
|
}
|
|
|
|
|
2005-07-29 16:42:37 +02:00
|
|
|
/******************************************************************
|
|
|
|
* SymSetParentWindow (DBGHELP.@)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
BOOL WINAPI SymSetParentWindow(HWND hwnd)
|
|
|
|
{
|
|
|
|
/* Save hwnd so it can be used as parent window */
|
|
|
|
FIXME("(%p): stub\n", hwnd);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2004-04-06 00:21:27 +02:00
|
|
|
/******************************************************************
|
|
|
|
* SymSetContext (DBGHELP.@)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
|
|
|
|
PIMAGEHLP_CONTEXT Context)
|
|
|
|
{
|
|
|
|
struct process* pcs = process_find_by_handle(hProcess);
|
|
|
|
if (!pcs) return FALSE;
|
|
|
|
|
2006-01-23 16:30:25 +01:00
|
|
|
if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset &&
|
|
|
|
pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset &&
|
|
|
|
pcs->ctx_frame.StackOffset == StackFrame->StackOffset)
|
|
|
|
{
|
|
|
|
TRACE("Setting same frame {rtn=%s frm=%s stk=%s}\n",
|
|
|
|
wine_dbgstr_longlong(pcs->ctx_frame.ReturnOffset),
|
|
|
|
wine_dbgstr_longlong(pcs->ctx_frame.FrameOffset),
|
|
|
|
wine_dbgstr_longlong(pcs->ctx_frame.StackOffset));
|
|
|
|
SetLastError(ERROR_ACCESS_DENIED); /* latest MSDN says ERROR_SUCCESS */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2004-04-06 00:21:27 +02:00
|
|
|
pcs->ctx_frame = *StackFrame;
|
|
|
|
/* MSDN states that Context is not (no longer?) used */
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2006-01-23 16:29:21 +01:00
|
|
|
/******************************************************************
|
|
|
|
* reg_cb64to32 (internal)
|
|
|
|
*
|
|
|
|
* Registered callback for converting information from 64 bit to 32 bit
|
|
|
|
*/
|
|
|
|
static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user)
|
|
|
|
{
|
|
|
|
PSYMBOL_REGISTERED_CALLBACK cb32 = (PSYMBOL_REGISTERED_CALLBACK)(DWORD)(user >> 32);
|
|
|
|
DWORD user32 = (DWORD)user;
|
|
|
|
void* data32;
|
|
|
|
IMAGEHLP_DEFERRED_SYMBOL_LOAD64* idsl64;
|
|
|
|
IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl;
|
|
|
|
|
|
|
|
switch (action)
|
|
|
|
{
|
|
|
|
case CBA_DEBUG_INFO:
|
|
|
|
case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
|
|
|
|
case CBA_SET_OPTIONS:
|
|
|
|
case CBA_SYMBOLS_UNLOADED:
|
|
|
|
data32 = (void*)(DWORD)data;
|
|
|
|
break;
|
|
|
|
case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
|
|
|
|
case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
|
|
|
|
case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
|
|
|
|
case CBA_DEFERRED_SYMBOL_LOAD_START:
|
|
|
|
idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD)data;
|
|
|
|
if (!validate_addr64(idsl64->BaseOfImage))
|
|
|
|
return FALSE;
|
|
|
|
idsl.SizeOfStruct = sizeof(idsl);
|
|
|
|
idsl.BaseOfImage = (DWORD)idsl64->BaseOfImage;
|
|
|
|
idsl.CheckSum = idsl64->CheckSum;
|
|
|
|
idsl.TimeDateStamp = idsl64->TimeDateStamp;
|
|
|
|
memcpy(idsl.FileName, idsl64->FileName, sizeof(idsl.FileName));
|
|
|
|
idsl.Reparse = idsl64->Reparse;
|
|
|
|
data32 = &idsl;
|
|
|
|
break;
|
|
|
|
case CBA_DUPLICATE_SYMBOL:
|
|
|
|
case CBA_EVENT:
|
|
|
|
case CBA_READ_MEMORY:
|
|
|
|
default:
|
|
|
|
FIXME("No mapping for action %lu\n", action);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return cb32(hProcess, action, (PVOID)data32, (PVOID)user32);
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
* pcs_callback (internal)
|
|
|
|
*/
|
|
|
|
BOOL pcs_callback(const struct process* pcs, ULONG action, void* data)
|
|
|
|
{
|
|
|
|
TRACE("%p %lu %p\n", pcs, action, data);
|
|
|
|
if (!pcs->reg_cb) return FALSE;
|
|
|
|
return pcs->reg_cb(pcs->handle, action, (ULONG64)(DWORD_PTR)data, pcs->reg_user);
|
|
|
|
}
|
|
|
|
|
2004-04-06 00:21:27 +02:00
|
|
|
/***********************************************************************
|
|
|
|
* SymRegisterCallback (DBGHELP.@)
|
|
|
|
*/
|
|
|
|
BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
|
|
|
|
PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
|
|
|
|
PVOID UserContext)
|
|
|
|
{
|
2006-01-23 16:29:21 +01:00
|
|
|
DWORD64 tmp = ((ULONGLONG)(DWORD)CallbackFunction << 32) | (DWORD)UserContext;
|
|
|
|
return SymRegisterCallback64(hProcess, reg_cb64to32, tmp);
|
2004-04-06 00:21:27 +02:00
|
|
|
}
|
|
|
|
|
2005-11-29 10:42:49 +01:00
|
|
|
/***********************************************************************
|
|
|
|
* SymRegisterCallback64 (DBGHELP.@)
|
|
|
|
*/
|
|
|
|
BOOL WINAPI SymRegisterCallback64(HANDLE hProcess,
|
|
|
|
PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
|
|
|
|
ULONG64 UserContext)
|
|
|
|
{
|
2006-01-23 16:29:21 +01:00
|
|
|
struct process* pcs = process_find_by_handle(hProcess);
|
|
|
|
|
|
|
|
TRACE("(%p, %p, %s)\n",
|
2005-11-29 10:42:49 +01:00
|
|
|
hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
|
2006-01-23 16:29:21 +01:00
|
|
|
if (!pcs) return FALSE;
|
|
|
|
pcs->reg_cb = CallbackFunction;
|
|
|
|
pcs->reg_user = UserContext;
|
|
|
|
|
|
|
|
return TRUE;
|
2005-11-29 10:42:49 +01:00
|
|
|
}
|
|
|
|
|
2004-04-06 00:21:27 +02:00
|
|
|
/* This is imagehlp version not dbghelp !! */
|
|
|
|
static API_VERSION api_version = { 4, 0, 2, 0 };
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* ImagehlpApiVersion (DBGHELP.@)
|
|
|
|
*/
|
|
|
|
LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
|
|
|
|
{
|
|
|
|
return &api_version;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* ImagehlpApiVersionEx (DBGHELP.@)
|
|
|
|
*/
|
|
|
|
LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
|
|
|
|
{
|
|
|
|
if (!AppVersion) return NULL;
|
|
|
|
|
|
|
|
AppVersion->MajorVersion = api_version.MajorVersion;
|
|
|
|
AppVersion->MinorVersion = api_version.MinorVersion;
|
|
|
|
AppVersion->Revision = api_version.Revision;
|
|
|
|
AppVersion->Reserved = api_version.Reserved;
|
|
|
|
|
|
|
|
return AppVersion;
|
|
|
|
}
|
2005-12-20 11:49:24 +01:00
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
* ExtensionApiVersion (DBGHELP.@)
|
|
|
|
*/
|
|
|
|
LPEXT_API_VERSION WINAPI ExtensionApiVersion(void)
|
|
|
|
{
|
|
|
|
static EXT_API_VERSION eav = {5, 5, 5, 0};
|
|
|
|
return &eav;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
* WinDbgExtensionDllInit (DBGHELP.@)
|
|
|
|
*/
|
|
|
|
void WINAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis,
|
|
|
|
unsigned short major, unsigned short minor)
|
|
|
|
{
|
|
|
|
}
|