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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "dbghelp_private.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp
);
28 * - support for symbols' types is still partly missing
30 * + we should store the underlying type for an enum in the symt_enum struct
31 * + for enums, we store the names & values (associated to the enum type),
32 * but those values are not directly usable from a debugger (that's why, I
33 * assume, that we have also to define constants for enum values, as
35 * + SymEnumTypes should only return *user* defined types (UDT, typedefs...) not
36 * all the types stored/used in the modules (like char*)
37 * - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across
38 * functions, and even across function blocks...). Basically, for *Next* to work
39 * it requires an address after the prolog of the func (the base address of the
41 * - most options (dbghelp_options) are not used (loading lines...)
42 * - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
43 * we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
44 * we could use hash if name isn't a RE, and fall back to a full search when we
47 * + we should add parameters' types to the function's signature
48 * while processing a function's parameters
49 * + add support for function-less labels (as MSC seems to define them)
52 * + when, in a same module, the same definition is used in several compilation
53 * units, we get several definitions of the same object (especially
54 * struct/union). we should find a way not to duplicate them
55 * + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
56 * global variable is defined several times (at different scopes). We are
57 * getting several of those while looking for a unique symbol. Part of the
58 * issue is that we don't give a scope to a static variable inside a function
62 unsigned dbghelp_options
= SYMOPT_UNDNAME
;
63 HANDLE hMsvcrt
= NULL
;
65 /***********************************************************************
66 * DllMain (DEBUGHLP.@)
68 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
72 case DLL_PROCESS_ATTACH
: break;
73 case DLL_PROCESS_DETACH
:
74 if (hMsvcrt
) FreeLibrary(hMsvcrt
);
76 case DLL_THREAD_ATTACH
: break;
77 case DLL_THREAD_DETACH
: break;
83 static struct process
* process_first
/* = NULL */;
85 /******************************************************************
86 * process_find_by_handle
89 struct process
* process_find_by_handle(HANDLE hProcess
)
93 for (p
= process_first
; p
&& p
->handle
!= hProcess
; p
= p
->next
);
94 if (!p
) SetLastError(ERROR_INVALID_HANDLE
);
98 /******************************************************************
99 * validate_addr64 (internal)
102 BOOL
validate_addr64(DWORD64 addr
)
104 if (sizeof(void*) == sizeof(int) && (addr
>> 32))
106 FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr
));
107 SetLastError(ERROR_INVALID_PARAMETER
);
113 /******************************************************************
116 * Ensures process' internal buffer is large enough.
118 void* fetch_buffer(struct process
* pcs
, unsigned size
)
120 if (size
> pcs
->buffer_size
)
123 pcs
->buffer
= HeapReAlloc(GetProcessHeap(), 0, pcs
->buffer
, size
);
125 pcs
->buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
126 pcs
->buffer_size
= (pcs
->buffer
) ? size
: 0;
131 #ifndef DBGHELP_STATIC_LIB
132 const char* wine_dbgstr_addr(const ADDRESS64
* addr
)
134 if (!addr
) return "(null)";
138 return wine_dbg_sprintf("flat<%s>", wine_dbgstr_longlong(addr
->Offset
));
140 return wine_dbg_sprintf("1616<%04x:%04x>", addr
->Segment
, (DWORD
)addr
->Offset
);
142 return wine_dbg_sprintf("1632<%04x:%08x>", addr
->Segment
, (DWORD
)addr
->Offset
);
144 return wine_dbg_sprintf("real<%04x:%04x>", addr
->Segment
, (DWORD
)addr
->Offset
);
151 extern struct cpu cpu_i386
, cpu_x86_64
, cpu_ppc
, cpu_arm
, cpu_arm64
;
153 #ifndef DBGHELP_STATIC_LIB
154 static struct cpu
* dbghelp_cpus
[] = {&cpu_i386
, &cpu_x86_64
, &cpu_ppc
, &cpu_arm
, &cpu_arm64
, NULL
};
156 static struct cpu
* dbghelp_cpus
[] = {&cpu_i386
, NULL
};
159 struct cpu
* dbghelp_current_cpu
=
160 #if defined(__i386__) || defined(DBGHELP_STATIC_LIB)
162 #elif defined(__x86_64__)
164 #elif defined(__powerpc__)
166 #elif defined(__arm__)
168 #elif defined(__aarch64__)
171 #error define support for your CPU
175 struct cpu
* cpu_find(DWORD machine
)
179 for (cpu
= dbghelp_cpus
; *cpu
; cpu
++)
181 if (cpu
[0]->machine
== machine
) return cpu
[0];
186 /******************************************************************
187 * SymSetSearchPathW (DBGHELP.@)
190 BOOL WINAPI
SymSetSearchPathW(HANDLE hProcess
, PCWSTR searchPath
)
192 struct process
* pcs
= process_find_by_handle(hProcess
);
194 if (!pcs
) return FALSE
;
195 if (!searchPath
) return FALSE
;
197 HeapFree(GetProcessHeap(), 0, pcs
->search_path
);
198 pcs
->search_path
= lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
199 (lstrlenW(searchPath
) + 1) * sizeof(WCHAR
)),
204 /******************************************************************
205 * SymSetSearchPath (DBGHELP.@)
208 BOOL WINAPI
SymSetSearchPath(HANDLE hProcess
, PCSTR searchPath
)
214 len
= MultiByteToWideChar(CP_ACP
, 0, searchPath
, -1, NULL
, 0);
215 if ((sp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))))
217 MultiByteToWideChar(CP_ACP
, 0, searchPath
, -1, sp
, len
);
219 ret
= SymSetSearchPathW(hProcess
, sp
);
220 HeapFree(GetProcessHeap(), 0, sp
);
225 /***********************************************************************
226 * SymGetSearchPathW (DBGHELP.@)
228 BOOL WINAPI
SymGetSearchPathW(HANDLE hProcess
, PWSTR szSearchPath
,
229 DWORD SearchPathLength
)
231 struct process
* pcs
= process_find_by_handle(hProcess
);
232 if (!pcs
) return FALSE
;
234 lstrcpynW(szSearchPath
, pcs
->search_path
, SearchPathLength
);
238 /***********************************************************************
239 * SymGetSearchPath (DBGHELP.@)
241 BOOL WINAPI
SymGetSearchPath(HANDLE hProcess
, PSTR szSearchPath
,
242 DWORD SearchPathLength
)
244 WCHAR
* buffer
= HeapAlloc(GetProcessHeap(), 0, SearchPathLength
* sizeof(WCHAR
));
249 ret
= SymGetSearchPathW(hProcess
, buffer
, SearchPathLength
);
251 WideCharToMultiByte(CP_ACP
, 0, buffer
, SearchPathLength
,
252 szSearchPath
, SearchPathLength
, NULL
, NULL
);
253 HeapFree(GetProcessHeap(), 0, buffer
);
258 /******************************************************************
261 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
262 * this assumes that hProcess is a handle on a valid process
264 static BOOL WINAPI
process_invade_cb(PCWSTR name
, ULONG64 base
, ULONG size
, PVOID user
)
267 HANDLE hProcess
= user
;
269 if (!GetModuleFileNameExW(hProcess
, (HMODULE
)(DWORD_PTR
)base
,
270 tmp
, sizeof(tmp
) / sizeof(WCHAR
)))
271 lstrcpynW(tmp
, name
, sizeof(tmp
) / sizeof(WCHAR
));
273 SymLoadModuleExW(hProcess
, 0, tmp
, name
, base
, size
, NULL
, 0);
277 /******************************************************************
281 static BOOL
check_live_target(struct process
* pcs
)
283 if (!GetProcessId(pcs
->handle
)) return FALSE
;
284 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL
, 0)) return FALSE
;
285 #ifndef DBGHELP_STATIC_LIB
286 if (!elf_read_wine_loader_dbg_info(pcs
))
287 macho_read_wine_loader_dbg_info(pcs
);
292 /******************************************************************
293 * SymInitializeW (DBGHELP.@)
295 * The initialisation of a dbghelp's context.
296 * Note that hProcess doesn't need to be a valid process handle (except
297 * when fInvadeProcess is TRUE).
298 * Since, we're also allow to load ELF (pure) libraries and Wine ELF libraries
299 * containing PE (and NE) module(s), here's how we handle it:
300 * - we load every module (ELF, NE, PE) passed in SymLoadModule
301 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
302 * synchronization: hProcess should be a valid process handle, and we hook
303 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
304 * our internal ELF modules representation (loading / unloading). This way,
305 * we'll pair every loaded builtin PE module with its ELF counterpart (and
306 * access its debug information).
307 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
308 * hProcess refers to a running process. We use some heuristics here, so YMMV.
309 * If we detect a live target, then we get the same handling as if
310 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
311 * we won't be able to make the peering between a builtin PE module and its ELF
312 * counterpart. Hence we won't be able to provide the requested debug
313 * information. We'll however be able to load native PE modules (and their
314 * debug information) without any trouble.
315 * Note also that this scheme can be intertwined with the deferred loading
316 * mechanism (ie only load the debug information when we actually need it).
318 BOOL WINAPI
SymInitializeW(HANDLE hProcess
, PCWSTR UserSearchPath
, BOOL fInvadeProcess
)
322 TRACE("(%p %s %u)\n", hProcess
, debugstr_w(UserSearchPath
), fInvadeProcess
);
324 if (process_find_by_handle(hProcess
)){
325 WARN("the symbols for this process have already been initialized!\n");
327 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call.
328 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed.
329 Native still returns TRUE even if the process has already been initialized. */
333 pcs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pcs
));
334 if (!pcs
) return FALSE
;
336 pcs
->handle
= hProcess
;
340 pcs
->search_path
= lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
341 (lstrlenW(UserSearchPath
) + 1) * sizeof(WCHAR
)),
348 static const WCHAR sym_path
[] = {'_','N','T','_','S','Y','M','B','O','L','_','P','A','T','H',0};
349 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};
351 pcs
->search_path
= HeapAlloc(GetProcessHeap(), 0, (len
= MAX_PATH
) * sizeof(WCHAR
));
352 while ((size
= GetCurrentDirectoryW(len
, pcs
->search_path
)) >= len
)
353 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (len
*= 2) * sizeof(WCHAR
));
354 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (size
+ 1) * sizeof(WCHAR
));
356 len
= GetEnvironmentVariableW(sym_path
, NULL
, 0);
359 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (size
+ 1 + len
+ 1) * sizeof(WCHAR
));
360 pcs
->search_path
[size
] = ';';
361 GetEnvironmentVariableW(sym_path
, pcs
->search_path
+ size
+ 1, len
);
364 len
= GetEnvironmentVariableW(alt_sym_path
, NULL
, 0);
367 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (size
+ 1 + len
+ 1) * sizeof(WCHAR
));
368 pcs
->search_path
[size
] = ';';
369 GetEnvironmentVariableW(alt_sym_path
, pcs
->search_path
+ size
+ 1, len
);
373 pcs
->lmodules
= NULL
;
374 pcs
->dbg_hdr_addr
= 0;
375 pcs
->next
= process_first
;
378 #ifndef DBGHELP_STATIC_LIB
379 if (check_live_target(pcs
))
382 EnumerateLoadedModulesW64(hProcess
, process_invade_cb
, hProcess
);
383 elf_synchronize_module_list(pcs
);
384 macho_synchronize_module_list(pcs
);
386 else if (fInvadeProcess
)
388 SymCleanup(hProcess
);
389 SetLastError(ERROR_INVALID_PARAMETER
);
397 /******************************************************************
398 * SymInitialize (DBGHELP.@)
402 BOOL WINAPI
SymInitialize(HANDLE hProcess
, PCSTR UserSearchPath
, BOOL fInvadeProcess
)
411 len
= MultiByteToWideChar(CP_ACP
, 0, UserSearchPath
, -1, NULL
, 0);
412 sp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
413 MultiByteToWideChar(CP_ACP
, 0, UserSearchPath
, -1, sp
, len
);
416 ret
= SymInitializeW(hProcess
, sp
, fInvadeProcess
);
417 HeapFree(GetProcessHeap(), 0, sp
);
421 /******************************************************************
422 * SymCleanup (DBGHELP.@)
425 BOOL WINAPI
SymCleanup(HANDLE hProcess
)
427 struct process
** ppcs
;
428 struct process
* next
;
430 for (ppcs
= &process_first
; *ppcs
; ppcs
= &(*ppcs
)->next
)
432 if ((*ppcs
)->handle
== hProcess
)
434 while ((*ppcs
)->lmodules
) module_remove(*ppcs
, (*ppcs
)->lmodules
);
436 HeapFree(GetProcessHeap(), 0, (*ppcs
)->search_path
);
437 next
= (*ppcs
)->next
;
438 HeapFree(GetProcessHeap(), 0, *ppcs
);
444 ERR("this process has not had SymInitialize() called for it!\n");
448 /******************************************************************
449 * SymSetOptions (DBGHELP.@)
452 DWORD WINAPI
SymSetOptions(DWORD opts
)
456 for (pcs
= process_first
; pcs
; pcs
= pcs
->next
)
458 pcs_callback(pcs
, CBA_SET_OPTIONS
, &opts
);
460 return dbghelp_options
= opts
;
463 /******************************************************************
464 * SymGetOptions (DBGHELP.@)
467 DWORD WINAPI
SymGetOptions(void)
469 return dbghelp_options
;
472 /******************************************************************
473 * SymSetParentWindow (DBGHELP.@)
476 BOOL WINAPI
SymSetParentWindow(HWND hwnd
)
478 /* Save hwnd so it can be used as parent window */
479 FIXME("(%p): stub\n", hwnd
);
483 /******************************************************************
484 * SymSetContext (DBGHELP.@)
487 BOOL WINAPI
SymSetContext(HANDLE hProcess
, PIMAGEHLP_STACK_FRAME StackFrame
,
488 PIMAGEHLP_CONTEXT Context
)
490 struct process
* pcs
= process_find_by_handle(hProcess
);
491 if (!pcs
) return FALSE
;
493 if (pcs
->ctx_frame
.ReturnOffset
== StackFrame
->ReturnOffset
&&
494 pcs
->ctx_frame
.FrameOffset
== StackFrame
->FrameOffset
&&
495 pcs
->ctx_frame
.StackOffset
== StackFrame
->StackOffset
)
497 TRACE("Setting same frame {rtn=%s frm=%s stk=%s}\n",
498 wine_dbgstr_longlong(pcs
->ctx_frame
.ReturnOffset
),
499 wine_dbgstr_longlong(pcs
->ctx_frame
.FrameOffset
),
500 wine_dbgstr_longlong(pcs
->ctx_frame
.StackOffset
));
501 pcs
->ctx_frame
.InstructionOffset
= StackFrame
->InstructionOffset
;
502 SetLastError(ERROR_ACCESS_DENIED
); /* latest MSDN says ERROR_SUCCESS */
506 pcs
->ctx_frame
= *StackFrame
;
507 /* MSDN states that Context is not (no longer?) used */
511 /******************************************************************
512 * reg_cb64to32 (internal)
514 * Registered callback for converting information from 64 bit to 32 bit
516 static BOOL CALLBACK
reg_cb64to32(HANDLE hProcess
, ULONG action
, ULONG64 data
, ULONG64 user
)
518 struct process
* pcs
= process_find_by_handle(hProcess
);
520 IMAGEHLP_DEFERRED_SYMBOL_LOAD64
* idsl64
;
521 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl
;
523 if (!pcs
) return FALSE
;
527 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL
:
528 case CBA_SET_OPTIONS
:
529 case CBA_SYMBOLS_UNLOADED
:
530 data32
= (void*)(DWORD_PTR
)data
;
532 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE
:
533 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE
:
534 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL
:
535 case CBA_DEFERRED_SYMBOL_LOAD_START
:
536 idsl64
= (IMAGEHLP_DEFERRED_SYMBOL_LOAD64
*)(DWORD_PTR
)data
;
537 if (!validate_addr64(idsl64
->BaseOfImage
))
539 idsl
.SizeOfStruct
= sizeof(idsl
);
540 idsl
.BaseOfImage
= (DWORD
)idsl64
->BaseOfImage
;
541 idsl
.CheckSum
= idsl64
->CheckSum
;
542 idsl
.TimeDateStamp
= idsl64
->TimeDateStamp
;
543 memcpy(idsl
.FileName
, idsl64
->FileName
, sizeof(idsl
.FileName
));
544 idsl
.Reparse
= idsl64
->Reparse
;
547 case CBA_DUPLICATE_SYMBOL
:
549 case CBA_READ_MEMORY
:
551 FIXME("No mapping for action %u\n", action
);
554 return pcs
->reg_cb32(hProcess
, action
, data32
, (PVOID
)(DWORD_PTR
)user
);
557 /******************************************************************
558 * pcs_callback (internal)
560 BOOL
pcs_callback(const struct process
* pcs
, ULONG action
, void* data
)
562 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl
;
564 TRACE("%p %u %p\n", pcs
, action
, data
);
566 if (!pcs
->reg_cb
) return FALSE
;
567 if (!pcs
->reg_is_unicode
)
569 IMAGEHLP_DEFERRED_SYMBOL_LOADW64
* idslW
;
574 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL
:
575 case CBA_SET_OPTIONS
:
576 case CBA_SYMBOLS_UNLOADED
:
578 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE
:
579 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE
:
580 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL
:
581 case CBA_DEFERRED_SYMBOL_LOAD_START
:
583 idsl
.SizeOfStruct
= sizeof(idsl
);
584 idsl
.BaseOfImage
= idslW
->BaseOfImage
;
585 idsl
.CheckSum
= idslW
->CheckSum
;
586 idsl
.TimeDateStamp
= idslW
->TimeDateStamp
;
587 WideCharToMultiByte(CP_ACP
, 0, idslW
->FileName
, -1,
588 idsl
.FileName
, sizeof(idsl
.FileName
), NULL
, NULL
);
589 idsl
.Reparse
= idslW
->Reparse
;
592 case CBA_DUPLICATE_SYMBOL
:
594 case CBA_READ_MEMORY
:
596 FIXME("No mapping for action %u\n", action
);
600 return pcs
->reg_cb(pcs
->handle
, action
, (ULONG64
)(DWORD_PTR
)data
, pcs
->reg_user
);
603 /******************************************************************
606 * Helper for registering a callback.
608 static BOOL
sym_register_cb(HANDLE hProcess
,
609 PSYMBOL_REGISTERED_CALLBACK64 cb
,
610 PSYMBOL_REGISTERED_CALLBACK cb32
,
611 DWORD64 user
, BOOL unicode
)
613 struct process
* pcs
= process_find_by_handle(hProcess
);
615 if (!pcs
) return FALSE
;
617 pcs
->reg_cb32
= cb32
;
618 pcs
->reg_is_unicode
= unicode
;
619 pcs
->reg_user
= user
;
624 /***********************************************************************
625 * SymRegisterCallback (DBGHELP.@)
627 BOOL WINAPI
SymRegisterCallback(HANDLE hProcess
,
628 PSYMBOL_REGISTERED_CALLBACK CallbackFunction
,
631 TRACE("(%p, %p, %p)\n",
632 hProcess
, CallbackFunction
, UserContext
);
633 return sym_register_cb(hProcess
, reg_cb64to32
, CallbackFunction
, (DWORD_PTR
)UserContext
, FALSE
);
636 /***********************************************************************
637 * SymRegisterCallback64 (DBGHELP.@)
639 BOOL WINAPI
SymRegisterCallback64(HANDLE hProcess
,
640 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction
,
643 TRACE("(%p, %p, %s)\n",
644 hProcess
, CallbackFunction
, wine_dbgstr_longlong(UserContext
));
645 return sym_register_cb(hProcess
, CallbackFunction
, NULL
, UserContext
, FALSE
);
648 /***********************************************************************
649 * SymRegisterCallbackW64 (DBGHELP.@)
651 BOOL WINAPI
SymRegisterCallbackW64(HANDLE hProcess
,
652 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction
,
655 TRACE("(%p, %p, %s)\n",
656 hProcess
, CallbackFunction
, wine_dbgstr_longlong(UserContext
));
657 return sym_register_cb(hProcess
, CallbackFunction
, NULL
, UserContext
, TRUE
);
660 /* This is imagehlp version not dbghelp !! */
661 static API_VERSION api_version
= { 4, 0, 2, 0 };
663 /***********************************************************************
664 * ImagehlpApiVersion (DBGHELP.@)
666 LPAPI_VERSION WINAPI
ImagehlpApiVersion(VOID
)
671 /***********************************************************************
672 * ImagehlpApiVersionEx (DBGHELP.@)
674 LPAPI_VERSION WINAPI
ImagehlpApiVersionEx(LPAPI_VERSION AppVersion
)
676 if (!AppVersion
) return NULL
;
678 AppVersion
->MajorVersion
= api_version
.MajorVersion
;
679 AppVersion
->MinorVersion
= api_version
.MinorVersion
;
680 AppVersion
->Revision
= api_version
.Revision
;
681 AppVersion
->Reserved
= api_version
.Reserved
;
686 /******************************************************************
687 * ExtensionApiVersion (DBGHELP.@)
689 LPEXT_API_VERSION WINAPI
ExtensionApiVersion(void)
691 static EXT_API_VERSION eav
= {5, 5, 5, 0};
695 /******************************************************************
696 * WinDbgExtensionDllInit (DBGHELP.@)
698 void WINAPI
WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis
,
699 unsigned short major
, unsigned short minor
)