dbghelp.c 21.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20 21 22 23 24 25 26
 */

#include "config.h"

#include "dbghelp_private.h"
#include "winerror.h"
#include "psapi.h"
#include "wine/debug.h"
27
#include "wdbgexts.h"
Eric Pouech's avatar
Eric Pouech committed
28
#include "winnls.h"
29 30 31 32 33 34

WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);

/* TODO
 *  - support for symbols' types is still partly missing
 *      + C++ support
35
 *      + we should store the underlying type for an enum in the symt_enum struct
36 37 38 39
 *      + 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.
40 41
 *      + SymEnumTypes should only return *user* defined types (UDT, typedefs...) not
 *        all the types stored/used in the modules (like char*)
42 43 44 45
 *  - 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)
46
 *  - most options (dbghelp_options) are not used (loading lines...)
47 48 49 50
 *  - 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
51
 *  - msc:
52 53
 *      + we should add parameters' types to the function's signature
 *        while processing a function's parameters
54
 *      + add support for function-less labels (as MSC seems to define them)
55 56
 *      + C++ management
 *  - stabs: 
57 58 59 60 61 62 63
 *      + 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
64 65 66 67
 *      + C++ management
 */

unsigned   dbghelp_options = SYMOPT_UNDNAME;
68
HANDLE     hMsvcrt = NULL;
69 70 71 72 73 74 75 76 77

/***********************************************************************
 *           DllMain (DEBUGHLP.@)
 */
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:    break;
78 79 80
    case DLL_PROCESS_DETACH:
        if (hMsvcrt) FreeLibrary(hMsvcrt);
        break;
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
    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;
}

103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
/******************************************************************
 *             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;
}

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
/******************************************************************
 *		fetch_buffer
 *
 * Ensures process' internal buffer is large enough.
 */
void* fetch_buffer(struct process* pcs, unsigned size)
{
    if (size > pcs->buffer_size)
    {
        if (pcs->buffer)
            pcs->buffer = HeapReAlloc(GetProcessHeap(), 0, pcs->buffer, size);
        else
            pcs->buffer = HeapAlloc(GetProcessHeap(), 0, size);
        pcs->buffer_size = (pcs->buffer) ? size : 0;
    }
    return pcs->buffer;
}

136
/******************************************************************
Eric Pouech's avatar
Eric Pouech committed
137
 *		SymSetSearchPathW (DBGHELP.@)
138 139
 *
 */
Eric Pouech's avatar
Eric Pouech committed
140
BOOL WINAPI SymSetSearchPathW(HANDLE hProcess, PCWSTR searchPath)
141 142 143 144 145 146 147
{
    struct process* pcs = process_find_by_handle(hProcess);

    if (!pcs) return FALSE;
    if (!searchPath) return FALSE;

    HeapFree(GetProcessHeap(), 0, pcs->search_path);
Eric Pouech's avatar
Eric Pouech committed
148 149 150
    pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0, 
                                          (lstrlenW(searchPath) + 1) * sizeof(WCHAR)),
                                searchPath);
151 152 153
    return TRUE;
}

Eric Pouech's avatar
Eric Pouech committed
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
/******************************************************************
 *		SymSetSearchPath (DBGHELP.@)
 *
 */
BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PCSTR searchPath)
{
    BOOL        ret = FALSE;
    unsigned    len;
    WCHAR*      sp;

    len = MultiByteToWideChar(CP_ACP, 0, searchPath, -1, NULL, 0);
    if ((sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
    {
        MultiByteToWideChar(CP_ACP, 0, searchPath, -1, sp, len);

        ret = SymSetSearchPathW(hProcess, sp);
        HeapFree(GetProcessHeap(), 0, sp);
    }
    return ret;
}

175
/***********************************************************************
Eric Pouech's avatar
Eric Pouech committed
176
 *		SymGetSearchPathW (DBGHELP.@)
177
 */
178
BOOL WINAPI SymGetSearchPathW(HANDLE hProcess, PWSTR szSearchPath,
Eric Pouech's avatar
Eric Pouech committed
179
                              DWORD SearchPathLength)
180 181 182 183
{
    struct process* pcs = process_find_by_handle(hProcess);
    if (!pcs) return FALSE;

Eric Pouech's avatar
Eric Pouech committed
184
    lstrcpynW(szSearchPath, pcs->search_path, SearchPathLength);
185 186 187
    return TRUE;
}

Eric Pouech's avatar
Eric Pouech committed
188 189 190
/***********************************************************************
 *		SymGetSearchPath (DBGHELP.@)
 */
191
BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath,
Eric Pouech's avatar
Eric Pouech committed
192 193
                             DWORD SearchPathLength)
{
194
    WCHAR*      buffer = HeapAlloc(GetProcessHeap(), 0, SearchPathLength * sizeof(WCHAR));
Eric Pouech's avatar
Eric Pouech committed
195 196 197 198
    BOOL        ret = FALSE;

    if (buffer)
    {
199
        ret = SymGetSearchPathW(hProcess, buffer, SearchPathLength);
Eric Pouech's avatar
Eric Pouech committed
200 201 202 203 204 205 206 207
        if (ret)
            WideCharToMultiByte(CP_ACP, 0, buffer, SearchPathLength,
                                szSearchPath, SearchPathLength, NULL, NULL);
        HeapFree(GetProcessHeap(), 0, buffer);
    }
    return ret;
}

208 209 210 211 212 213
/******************************************************************
 *		invade_process
 *
 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
 * this assumes that hProcess is a handle on a valid process
 */
214
static BOOL WINAPI process_invade_cb(PCSTR name, ULONG base, ULONG size, PVOID user)
215
{
216 217 218 219 220 221 222 223
    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);
224
    return TRUE;
225 226
}

Eric Pouech's avatar
Eric Pouech committed
227 228 229 230 231 232 233
/******************************************************************
 *		check_live_target
 *
 */
static BOOL check_live_target(struct process* pcs)
{
    if (!GetProcessId(pcs->handle)) return FALSE;
234
    if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE;
235 236
    elf_read_wine_loader_dbg_info(pcs);
    return TRUE;
Eric Pouech's avatar
Eric Pouech committed
237 238
}

239
/******************************************************************
Eric Pouech's avatar
Eric Pouech committed
240
 *		SymInitializeW (DBGHELP.@)
241 242 243 244 245 246 247 248 249 250 251 252 253
 *
 * 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).
Eric Pouech's avatar
Eric Pouech committed
254 255 256 257 258 259 260 261
 * - 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.
262 263 264
 * Note also that this scheme can be intertwined with the deferred loading 
 * mechanism (ie only load the debug information when we actually need it).
 */
Eric Pouech's avatar
Eric Pouech committed
265
BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess)
266 267 268
{
    struct process*     pcs;

Eric Pouech's avatar
Eric Pouech committed
269
    TRACE("(%p %s %u)\n", hProcess, debugstr_w(UserSearchPath), fInvadeProcess);
270 271 272 273 274 275 276 277 278 279 280

    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)
    {
Eric Pouech's avatar
Eric Pouech committed
281 282 283
        pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0,      
                                              (lstrlenW(UserSearchPath) + 1) * sizeof(WCHAR)),
                                    UserSearchPath);
284 285 286 287 288
    }
    else
    {
        unsigned        size;
        unsigned        len;
Eric Pouech's avatar
Eric Pouech committed
289 290
        static const WCHAR      sym_path[] = {'_','N','T','_','S','Y','M','B','O','L','_','P','A','T','H',0};
        static const WCHAR      alt_sym_path[] = {'_','N','T','_','A','L','T','E','R','N','A','T','E','_','S','Y','M','B','O','L','_','P','A','T','H',0};
291

Eric Pouech's avatar
Eric Pouech committed
292 293 294 295
        pcs->search_path = HeapAlloc(GetProcessHeap(), 0, (len = MAX_PATH) * sizeof(WCHAR));
        while ((size = GetCurrentDirectoryW(len, pcs->search_path)) >= len)
            pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (len *= 2) * sizeof(WCHAR));
        pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1) * sizeof(WCHAR));
296

Eric Pouech's avatar
Eric Pouech committed
297
        len = GetEnvironmentVariableW(sym_path, NULL, 0);
298 299
        if (len)
        {
Eric Pouech's avatar
Eric Pouech committed
300
            pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1 + len + 1) * sizeof(WCHAR));
301
            pcs->search_path[size] = ';';
Eric Pouech's avatar
Eric Pouech committed
302
            GetEnvironmentVariableW(sym_path, pcs->search_path + size + 1, len);
303 304
            size += 1 + len;
        }
Eric Pouech's avatar
Eric Pouech committed
305
        len = GetEnvironmentVariableW(alt_sym_path, NULL, 0);
306 307
        if (len)
        {
Eric Pouech's avatar
Eric Pouech committed
308
            pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1 + len + 1) * sizeof(WCHAR));
309
            pcs->search_path[size] = ';';
Eric Pouech's avatar
Eric Pouech committed
310
            GetEnvironmentVariableW(alt_sym_path, pcs->search_path + size + 1, len);
311 312 313 314 315 316 317 318
            size += 1 + len;
        }
    }

    pcs->lmodules = NULL;
    pcs->dbg_hdr_addr = 0;
    pcs->next = process_first;
    process_first = pcs;
Eric Pouech's avatar
Eric Pouech committed
319 320
    
    if (check_live_target(pcs))
321
    {
Eric Pouech's avatar
Eric Pouech committed
322 323
        if (fInvadeProcess)
            EnumerateLoadedModules(hProcess, process_invade_cb, (void*)hProcess);
324 325
        elf_synchronize_module_list(pcs);
    }
Eric Pouech's avatar
Eric Pouech committed
326 327 328 329 330 331
    else if (fInvadeProcess)
    {
        SymCleanup(hProcess);
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }
332

333 334 335
    return TRUE;
}

Eric Pouech's avatar
Eric Pouech committed
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
/******************************************************************
 *		SymInitialize (DBGHELP.@)
 *
 *
 */
BOOL WINAPI SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess)
{
    WCHAR*              sp = NULL;
    BOOL                ret;

    if (UserSearchPath)
    {
        unsigned len;

        len = MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, NULL, 0);
        sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
        MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, sp, len);
    }

    ret = SymInitializeW(hProcess, sp, fInvadeProcess);
    HeapFree(GetProcessHeap(), 0, sp);
    return ret;
}

360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
/******************************************************************
 *		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)
{
391 392 393 394 395 396
    struct process* pcs;

    for (pcs = process_first; pcs; pcs = pcs->next)
    {
        pcs_callback(pcs, CBA_SET_OPTIONS, &opts);
    }
397 398 399 400 401 402 403 404 405 406 407 408
    return dbghelp_options = opts;
}

/******************************************************************
 *		SymGetOptions (DBGHELP.@)
 *
 */
DWORD WINAPI SymGetOptions(void)
{
    return dbghelp_options;
}

409 410 411 412 413 414 415 416 417 418 419
/******************************************************************
 *		SymSetParentWindow (DBGHELP.@)
 *
 */
BOOL WINAPI SymSetParentWindow(HWND hwnd)
{
    /* Save hwnd so it can be used as parent window */
    FIXME("(%p): stub\n", hwnd);
    return TRUE;
}

420 421 422 423 424 425 426 427 428 429
/******************************************************************
 *		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;

430 431 432 433 434 435 436 437
    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));
438
        pcs->ctx_frame.InstructionOffset = StackFrame->InstructionOffset;
439 440 441 442
        SetLastError(ERROR_ACCESS_DENIED); /* latest MSDN says ERROR_SUCCESS */
        return FALSE;
    }

443 444 445 446 447
    pcs->ctx_frame = *StackFrame;
    /* MSDN states that Context is not (no longer?) used */
    return TRUE;
}

448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
/******************************************************************
 *		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:
488
        FIXME("No mapping for action %u\n", action);
489 490 491 492 493 494 495 496 497 498
        return FALSE;
    }
    return cb32(hProcess, action, (PVOID)data32, (PVOID)user32);
}

/******************************************************************
 *		pcs_callback (internal)
 */
BOOL pcs_callback(const struct process* pcs, ULONG action, void* data)
{
499
    TRACE("%p %u %p\n", pcs, action, data);
500

501
    if (!pcs->reg_cb) return FALSE;
502
    if (!pcs->reg_is_unicode)
503
    {
504 505
        IMAGEHLP_DEFERRED_SYMBOL_LOAD64     idsl;
        IMAGEHLP_DEFERRED_SYMBOL_LOADW64*   idslW;
506 507 508 509 510 511 512 513 514 515 516 517

        switch (action)
        {
        case CBA_DEBUG_INFO:
        case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
        case CBA_SET_OPTIONS:
        case CBA_SYMBOLS_UNLOADED:
            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:
518 519 520 521 522 523 524 525 526
            idslW = (IMAGEHLP_DEFERRED_SYMBOL_LOADW64*)(DWORD)data;
            idsl.SizeOfStruct = sizeof(idsl);
            idsl.BaseOfImage = idslW->BaseOfImage;
            idsl.CheckSum = idslW->CheckSum;
            idsl.TimeDateStamp = idslW->TimeDateStamp;
            WideCharToMultiByte(CP_ACP, 0, idslW->FileName, -1,
                                idsl.FileName, sizeof(idsl.FileName), NULL, NULL);
            idsl.Reparse = idslW->Reparse;
            data = &idsl;
527 528 529 530 531
            break;
        case CBA_DUPLICATE_SYMBOL:
        case CBA_EVENT:
        case CBA_READ_MEMORY:
        default:
532
            FIXME("No mapping for action %u\n", action);
533 534 535
            return FALSE;
        }
    }
536 537 538
    return pcs->reg_cb(pcs->handle, action, (ULONG64)(DWORD_PTR)data, pcs->reg_user);
}

539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
/******************************************************************
 *		sym_register_cb
 *
 * Helper for registering a callback.
 */
static BOOL sym_register_cb(HANDLE hProcess, 
                            PSYMBOL_REGISTERED_CALLBACK64 cb,
                            DWORD64 user, BOOL unicode)
{
    struct process* pcs = process_find_by_handle(hProcess);

    if (!pcs) return FALSE;
    pcs->reg_cb = cb;
    pcs->reg_is_unicode = unicode;
    pcs->reg_user = user;

    return TRUE;
}

558 559 560 561 562 563 564
/***********************************************************************
 *		SymRegisterCallback (DBGHELP.@)
 */
BOOL WINAPI SymRegisterCallback(HANDLE hProcess, 
                                PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
                                PVOID UserContext)
{
565
    DWORD64 tmp = ((ULONGLONG)(DWORD)CallbackFunction << 32) | (DWORD)UserContext;
566 567 568
    TRACE("(%p, %p, %p)\n", 
          hProcess, CallbackFunction, UserContext);
    return sym_register_cb(hProcess, reg_cb64to32, tmp, FALSE);
569 570
}

571 572 573 574 575 576 577
/***********************************************************************
 *		SymRegisterCallback64 (DBGHELP.@)
 */
BOOL WINAPI SymRegisterCallback64(HANDLE hProcess, 
                                  PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
                                  ULONG64 UserContext)
{
578
    TRACE("(%p, %p, %s)\n", 
579
          hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
580 581
    return sym_register_cb(hProcess, CallbackFunction, UserContext, FALSE);
}
582

583 584 585 586 587 588 589 590 591 592
/***********************************************************************
 *		SymRegisterCallbackW64 (DBGHELP.@)
 */
BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess, 
                                   PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
                                   ULONG64 UserContext)
{
    TRACE("(%p, %p, %s)\n", 
          hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
    return sym_register_cb(hProcess, CallbackFunction, UserContext, TRUE);
593 594
}

595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
/* 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;
}
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636

/******************************************************************
 *		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)
{
}