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
23 #include "dbghelp_private.h"
26 #ifndef DBGHELP_STATIC_LIB
29 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp
);
36 * - support for symbols' types is still partly missing
38 * + we should store the underlying type for an enum in the symt_enum struct
39 * + for enums, we store the names & values (associated to the enum type),
40 * but those values are not directly usable from a debugger (that's why, I
41 * assume, that we have also to define constants for enum values, as
43 * + SymEnumTypes should only return *user* defined types (UDT, typedefs...) not
44 * all the types stored/used in the modules (like char*)
45 * - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across
46 * functions, and even across function blocks...). Basically, for *Next* to work
47 * it requires an address after the prolog of the func (the base address of the
49 * - most options (dbghelp_options) are not used (loading lines...)
50 * - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
51 * we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
52 * we could use hash if name isn't a RE, and fall back to a full search when we
55 * + we should add parameters' types to the function's signature
56 * while processing a function's parameters
57 * + add support for function-less labels (as MSC seems to define them)
60 * + when, in a same module, the same definition is used in several compilation
61 * units, we get several definitions of the same object (especially
62 * struct/union). we should find a way not to duplicate them
63 * + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
64 * global variable is defined several times (at different scopes). We are
65 * getting several of those while looking for a unique symbol. Part of the
66 * issue is that we don't give a scope to a static variable inside a function
70 unsigned dbghelp_options
= SYMOPT_UNDNAME
;
71 HANDLE hMsvcrt
= NULL
;
73 /***********************************************************************
74 * DllMain (DEBUGHLP.@)
76 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
80 case DLL_PROCESS_ATTACH
: break;
81 case DLL_PROCESS_DETACH
:
82 if (hMsvcrt
) FreeLibrary(hMsvcrt
);
84 case DLL_THREAD_ATTACH
: break;
85 case DLL_THREAD_DETACH
: break;
91 static struct process
* process_first
/* = NULL */;
93 /******************************************************************
94 * process_find_by_handle
97 struct process
* process_find_by_handle(HANDLE hProcess
)
101 for (p
= process_first
; p
&& p
->handle
!= hProcess
; p
= p
->next
);
102 if (!p
) SetLastError(ERROR_INVALID_HANDLE
);
106 /******************************************************************
107 * validate_addr64 (internal)
110 BOOL
validate_addr64(DWORD64 addr
)
112 if (sizeof(void*) == sizeof(int) && (addr
>> 32))
114 FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr
));
115 SetLastError(ERROR_INVALID_PARAMETER
);
121 /******************************************************************
124 * Ensures process' internal buffer is large enough.
126 void* fetch_buffer(struct process
* pcs
, unsigned size
)
128 if (size
> pcs
->buffer_size
)
131 pcs
->buffer
= HeapReAlloc(GetProcessHeap(), 0, pcs
->buffer
, size
);
133 pcs
->buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
134 pcs
->buffer_size
= (pcs
->buffer
) ? size
: 0;
139 #ifndef DBGHELP_STATIC_LIB
140 const char* wine_dbgstr_addr(const ADDRESS64
* addr
)
142 if (!addr
) return "(null)";
146 return wine_dbg_sprintf("flat<%s>", wine_dbgstr_longlong(addr
->Offset
));
148 return wine_dbg_sprintf("1616<%04x:%04x>", addr
->Segment
, (DWORD
)addr
->Offset
);
150 return wine_dbg_sprintf("1632<%04x:%08x>", addr
->Segment
, (DWORD
)addr
->Offset
);
152 return wine_dbg_sprintf("real<%04x:%04x>", addr
->Segment
, (DWORD
)addr
->Offset
);
159 extern struct cpu cpu_i386
, cpu_x86_64
, cpu_ppc
, cpu_arm
, cpu_arm64
;
161 #ifndef DBGHELP_STATIC_LIB
162 static struct cpu
* dbghelp_cpus
[] = {&cpu_i386
, &cpu_x86_64
, &cpu_ppc
, &cpu_arm
, &cpu_arm64
, NULL
};
164 static struct cpu
* dbghelp_cpus
[] = {&cpu_i386
, NULL
};
167 struct cpu
* dbghelp_current_cpu
=
168 #if defined(__i386__) || defined(DBGHELP_STATIC_LIB)
170 #elif defined(__x86_64__)
172 #elif defined(__powerpc__)
174 #elif defined(__arm__)
176 #elif defined(__aarch64__)
179 #error define support for your CPU
183 struct cpu
* cpu_find(DWORD machine
)
187 for (cpu
= dbghelp_cpus
; *cpu
; cpu
++)
189 if (cpu
[0]->machine
== machine
) return cpu
[0];
194 /******************************************************************
195 * SymSetSearchPathW (DBGHELP.@)
198 BOOL WINAPI
SymSetSearchPathW(HANDLE hProcess
, PCWSTR searchPath
)
200 struct process
* pcs
= process_find_by_handle(hProcess
);
202 if (!pcs
) return FALSE
;
203 if (!searchPath
) return FALSE
;
205 HeapFree(GetProcessHeap(), 0, pcs
->search_path
);
206 pcs
->search_path
= lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
207 (lstrlenW(searchPath
) + 1) * sizeof(WCHAR
)),
212 /******************************************************************
213 * SymSetSearchPath (DBGHELP.@)
216 BOOL WINAPI
SymSetSearchPath(HANDLE hProcess
, PCSTR searchPath
)
222 len
= MultiByteToWideChar(CP_ACP
, 0, searchPath
, -1, NULL
, 0);
223 if ((sp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))))
225 MultiByteToWideChar(CP_ACP
, 0, searchPath
, -1, sp
, len
);
227 ret
= SymSetSearchPathW(hProcess
, sp
);
228 HeapFree(GetProcessHeap(), 0, sp
);
233 /***********************************************************************
234 * SymGetSearchPathW (DBGHELP.@)
236 BOOL WINAPI
SymGetSearchPathW(HANDLE hProcess
, PWSTR szSearchPath
,
237 DWORD SearchPathLength
)
239 struct process
* pcs
= process_find_by_handle(hProcess
);
240 if (!pcs
) return FALSE
;
242 lstrcpynW(szSearchPath
, pcs
->search_path
, SearchPathLength
);
246 /***********************************************************************
247 * SymGetSearchPath (DBGHELP.@)
249 BOOL WINAPI
SymGetSearchPath(HANDLE hProcess
, PSTR szSearchPath
,
250 DWORD SearchPathLength
)
252 WCHAR
* buffer
= HeapAlloc(GetProcessHeap(), 0, SearchPathLength
* sizeof(WCHAR
));
257 ret
= SymGetSearchPathW(hProcess
, buffer
, SearchPathLength
);
259 WideCharToMultiByte(CP_ACP
, 0, buffer
, SearchPathLength
,
260 szSearchPath
, SearchPathLength
, NULL
, NULL
);
261 HeapFree(GetProcessHeap(), 0, buffer
);
266 /******************************************************************
269 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
270 * this assumes that hProcess is a handle on a valid process
272 static BOOL WINAPI
process_invade_cb(PCWSTR name
, ULONG64 base
, ULONG size
, PVOID user
)
275 HANDLE hProcess
= user
;
277 if (!GetModuleFileNameExW(hProcess
, (HMODULE
)(DWORD_PTR
)base
,
278 tmp
, sizeof(tmp
) / sizeof(WCHAR
)))
279 lstrcpynW(tmp
, name
, sizeof(tmp
) / sizeof(WCHAR
));
281 SymLoadModuleExW(hProcess
, 0, tmp
, name
, base
, size
, NULL
, 0);
285 /******************************************************************
289 static BOOL
check_live_target(struct process
* pcs
)
291 if (!GetProcessId(pcs
->handle
)) return FALSE
;
292 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL
, 0)) return FALSE
;
293 #ifndef DBGHELP_STATIC_LIB
294 if (!elf_read_wine_loader_dbg_info(pcs
))
295 macho_read_wine_loader_dbg_info(pcs
);
300 /******************************************************************
301 * SymInitializeW (DBGHELP.@)
303 * The initialisation of a dbghelp's context.
304 * Note that hProcess doesn't need to be a valid process handle (except
305 * when fInvadeProcess is TRUE).
306 * Since, we're also allow to load ELF (pure) libraries and Wine ELF libraries
307 * containing PE (and NE) module(s), here's how we handle it:
308 * - we load every module (ELF, NE, PE) passed in SymLoadModule
309 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
310 * synchronization: hProcess should be a valid process handle, and we hook
311 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
312 * our internal ELF modules representation (loading / unloading). This way,
313 * we'll pair every loaded builtin PE module with its ELF counterpart (and
314 * access its debug information).
315 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
316 * hProcess refers to a running process. We use some heuristics here, so YMMV.
317 * If we detect a live target, then we get the same handling as if
318 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
319 * we won't be able to make the peering between a builtin PE module and its ELF
320 * counterpart. Hence we won't be able to provide the requested debug
321 * information. We'll however be able to load native PE modules (and their
322 * debug information) without any trouble.
323 * Note also that this scheme can be intertwined with the deferred loading
324 * mechanism (ie only load the debug information when we actually need it).
326 BOOL WINAPI
SymInitializeW(HANDLE hProcess
, PCWSTR UserSearchPath
, BOOL fInvadeProcess
)
330 TRACE("(%p %s %u)\n", hProcess
, debugstr_w(UserSearchPath
), fInvadeProcess
);
332 if (process_find_by_handle(hProcess
)){
333 WARN("the symbols for this process have already been initialized!\n");
335 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call.
336 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed.
337 Native still returns TRUE even if the process has already been initialized. */
341 pcs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pcs
));
342 if (!pcs
) return FALSE
;
344 pcs
->handle
= hProcess
;
348 pcs
->search_path
= lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
349 (lstrlenW(UserSearchPath
) + 1) * sizeof(WCHAR
)),
356 static const WCHAR sym_path
[] = {'_','N','T','_','S','Y','M','B','O','L','_','P','A','T','H',0};
357 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};
359 pcs
->search_path
= HeapAlloc(GetProcessHeap(), 0, (len
= MAX_PATH
) * sizeof(WCHAR
));
360 while ((size
= GetCurrentDirectoryW(len
, pcs
->search_path
)) >= len
)
361 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (len
*= 2) * sizeof(WCHAR
));
362 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (size
+ 1) * sizeof(WCHAR
));
364 len
= GetEnvironmentVariableW(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(sym_path
, pcs
->search_path
+ size
+ 1, len
);
372 len
= GetEnvironmentVariableW(alt_sym_path
, NULL
, 0);
375 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (size
+ 1 + len
+ 1) * sizeof(WCHAR
));
376 pcs
->search_path
[size
] = ';';
377 GetEnvironmentVariableW(alt_sym_path
, pcs
->search_path
+ size
+ 1, len
);
381 pcs
->lmodules
= NULL
;
382 pcs
->dbg_hdr_addr
= 0;
383 pcs
->next
= process_first
;
386 #ifndef DBGHELP_STATIC_LIB
387 if (check_live_target(pcs
))
390 EnumerateLoadedModulesW64(hProcess
, process_invade_cb
, hProcess
);
391 elf_synchronize_module_list(pcs
);
392 macho_synchronize_module_list(pcs
);
394 else if (fInvadeProcess
)
396 SymCleanup(hProcess
);
397 SetLastError(ERROR_INVALID_PARAMETER
);
405 /******************************************************************
406 * SymInitialize (DBGHELP.@)
410 BOOL WINAPI
SymInitialize(HANDLE hProcess
, PCSTR UserSearchPath
, BOOL fInvadeProcess
)
419 len
= MultiByteToWideChar(CP_ACP
, 0, UserSearchPath
, -1, NULL
, 0);
420 sp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
421 MultiByteToWideChar(CP_ACP
, 0, UserSearchPath
, -1, sp
, len
);
424 ret
= SymInitializeW(hProcess
, sp
, fInvadeProcess
);
425 HeapFree(GetProcessHeap(), 0, sp
);
429 /******************************************************************
430 * SymCleanup (DBGHELP.@)
433 BOOL WINAPI
SymCleanup(HANDLE hProcess
)
435 struct process
** ppcs
;
436 struct process
* next
;
438 for (ppcs
= &process_first
; *ppcs
; ppcs
= &(*ppcs
)->next
)
440 if ((*ppcs
)->handle
== hProcess
)
442 while ((*ppcs
)->lmodules
) module_remove(*ppcs
, (*ppcs
)->lmodules
);
444 HeapFree(GetProcessHeap(), 0, (*ppcs
)->search_path
);
445 next
= (*ppcs
)->next
;
446 HeapFree(GetProcessHeap(), 0, *ppcs
);
452 ERR("this process has not had SymInitialize() called for it!\n");
456 /******************************************************************
457 * SymSetOptions (DBGHELP.@)
460 DWORD WINAPI
SymSetOptions(DWORD opts
)
464 for (pcs
= process_first
; pcs
; pcs
= pcs
->next
)
466 pcs_callback(pcs
, CBA_SET_OPTIONS
, &opts
);
468 return dbghelp_options
= opts
;
471 /******************************************************************
472 * SymGetOptions (DBGHELP.@)
475 DWORD WINAPI
SymGetOptions(void)
477 return dbghelp_options
;
480 /******************************************************************
481 * SymSetParentWindow (DBGHELP.@)
484 BOOL WINAPI
SymSetParentWindow(HWND hwnd
)
486 /* Save hwnd so it can be used as parent window */
487 FIXME("(%p): stub\n", hwnd
);
491 /******************************************************************
492 * SymSetContext (DBGHELP.@)
495 BOOL WINAPI
SymSetContext(HANDLE hProcess
, PIMAGEHLP_STACK_FRAME StackFrame
,
496 PIMAGEHLP_CONTEXT Context
)
498 struct process
* pcs
= process_find_by_handle(hProcess
);
499 if (!pcs
) return FALSE
;
501 if (pcs
->ctx_frame
.ReturnOffset
== StackFrame
->ReturnOffset
&&
502 pcs
->ctx_frame
.FrameOffset
== StackFrame
->FrameOffset
&&
503 pcs
->ctx_frame
.StackOffset
== StackFrame
->StackOffset
)
505 TRACE("Setting same frame {rtn=%s frm=%s stk=%s}\n",
506 wine_dbgstr_longlong(pcs
->ctx_frame
.ReturnOffset
),
507 wine_dbgstr_longlong(pcs
->ctx_frame
.FrameOffset
),
508 wine_dbgstr_longlong(pcs
->ctx_frame
.StackOffset
));
509 pcs
->ctx_frame
.InstructionOffset
= StackFrame
->InstructionOffset
;
510 SetLastError(ERROR_ACCESS_DENIED
); /* latest MSDN says ERROR_SUCCESS */
514 pcs
->ctx_frame
= *StackFrame
;
515 /* MSDN states that Context is not (no longer?) used */
519 /******************************************************************
520 * reg_cb64to32 (internal)
522 * Registered callback for converting information from 64 bit to 32 bit
524 static BOOL CALLBACK
reg_cb64to32(HANDLE hProcess
, ULONG action
, ULONG64 data
, ULONG64 user
)
526 struct process
* pcs
= process_find_by_handle(hProcess
);
528 IMAGEHLP_DEFERRED_SYMBOL_LOAD64
* idsl64
;
529 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl
;
531 if (!pcs
) return FALSE
;
535 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL
:
536 case CBA_SET_OPTIONS
:
537 case CBA_SYMBOLS_UNLOADED
:
538 data32
= (void*)(DWORD_PTR
)data
;
540 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE
:
541 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE
:
542 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL
:
543 case CBA_DEFERRED_SYMBOL_LOAD_START
:
544 idsl64
= (IMAGEHLP_DEFERRED_SYMBOL_LOAD64
*)(DWORD_PTR
)data
;
545 if (!validate_addr64(idsl64
->BaseOfImage
))
547 idsl
.SizeOfStruct
= sizeof(idsl
);
548 idsl
.BaseOfImage
= (DWORD
)idsl64
->BaseOfImage
;
549 idsl
.CheckSum
= idsl64
->CheckSum
;
550 idsl
.TimeDateStamp
= idsl64
->TimeDateStamp
;
551 memcpy(idsl
.FileName
, idsl64
->FileName
, sizeof(idsl
.FileName
));
552 idsl
.Reparse
= idsl64
->Reparse
;
555 case CBA_DUPLICATE_SYMBOL
:
557 case CBA_READ_MEMORY
:
559 FIXME("No mapping for action %u\n", action
);
562 return pcs
->reg_cb32(hProcess
, action
, data32
, (PVOID
)(DWORD_PTR
)user
);
565 /******************************************************************
566 * pcs_callback (internal)
568 BOOL
pcs_callback(const struct process
* pcs
, ULONG action
, void* data
)
570 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl
;
572 TRACE("%p %u %p\n", pcs
, action
, data
);
574 if (!pcs
->reg_cb
) return FALSE
;
575 if (!pcs
->reg_is_unicode
)
577 IMAGEHLP_DEFERRED_SYMBOL_LOADW64
* idslW
;
582 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL
:
583 case CBA_SET_OPTIONS
:
584 case CBA_SYMBOLS_UNLOADED
:
586 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE
:
587 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE
:
588 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL
:
589 case CBA_DEFERRED_SYMBOL_LOAD_START
:
591 idsl
.SizeOfStruct
= sizeof(idsl
);
592 idsl
.BaseOfImage
= idslW
->BaseOfImage
;
593 idsl
.CheckSum
= idslW
->CheckSum
;
594 idsl
.TimeDateStamp
= idslW
->TimeDateStamp
;
595 WideCharToMultiByte(CP_ACP
, 0, idslW
->FileName
, -1,
596 idsl
.FileName
, sizeof(idsl
.FileName
), NULL
, NULL
);
597 idsl
.Reparse
= idslW
->Reparse
;
600 case CBA_DUPLICATE_SYMBOL
:
602 case CBA_READ_MEMORY
:
604 FIXME("No mapping for action %u\n", action
);
608 return pcs
->reg_cb(pcs
->handle
, action
, (ULONG64
)(DWORD_PTR
)data
, pcs
->reg_user
);
611 /******************************************************************
614 * Helper for registering a callback.
616 static BOOL
sym_register_cb(HANDLE hProcess
,
617 PSYMBOL_REGISTERED_CALLBACK64 cb
,
618 PSYMBOL_REGISTERED_CALLBACK cb32
,
619 DWORD64 user
, BOOL unicode
)
621 struct process
* pcs
= process_find_by_handle(hProcess
);
623 if (!pcs
) return FALSE
;
625 pcs
->reg_cb32
= cb32
;
626 pcs
->reg_is_unicode
= unicode
;
627 pcs
->reg_user
= user
;
632 /***********************************************************************
633 * SymRegisterCallback (DBGHELP.@)
635 BOOL WINAPI
SymRegisterCallback(HANDLE hProcess
,
636 PSYMBOL_REGISTERED_CALLBACK CallbackFunction
,
639 TRACE("(%p, %p, %p)\n",
640 hProcess
, CallbackFunction
, UserContext
);
641 return sym_register_cb(hProcess
, reg_cb64to32
, CallbackFunction
, (DWORD_PTR
)UserContext
, FALSE
);
644 /***********************************************************************
645 * SymRegisterCallback64 (DBGHELP.@)
647 BOOL WINAPI
SymRegisterCallback64(HANDLE hProcess
,
648 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction
,
651 TRACE("(%p, %p, %s)\n",
652 hProcess
, CallbackFunction
, wine_dbgstr_longlong(UserContext
));
653 return sym_register_cb(hProcess
, CallbackFunction
, NULL
, UserContext
, FALSE
);
656 /***********************************************************************
657 * SymRegisterCallbackW64 (DBGHELP.@)
659 BOOL WINAPI
SymRegisterCallbackW64(HANDLE hProcess
,
660 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction
,
663 TRACE("(%p, %p, %s)\n",
664 hProcess
, CallbackFunction
, wine_dbgstr_longlong(UserContext
));
665 return sym_register_cb(hProcess
, CallbackFunction
, NULL
, UserContext
, TRUE
);
668 /* This is imagehlp version not dbghelp !! */
669 static API_VERSION api_version
= { 4, 0, 2, 0 };
671 /***********************************************************************
672 * ImagehlpApiVersion (DBGHELP.@)
674 LPAPI_VERSION WINAPI
ImagehlpApiVersion(VOID
)
679 /***********************************************************************
680 * ImagehlpApiVersionEx (DBGHELP.@)
682 LPAPI_VERSION WINAPI
ImagehlpApiVersionEx(LPAPI_VERSION AppVersion
)
684 if (!AppVersion
) return NULL
;
686 AppVersion
->MajorVersion
= api_version
.MajorVersion
;
687 AppVersion
->MinorVersion
= api_version
.MinorVersion
;
688 AppVersion
->Revision
= api_version
.Revision
;
689 AppVersion
->Reserved
= api_version
.Reserved
;
694 /******************************************************************
695 * ExtensionApiVersion (DBGHELP.@)
697 LPEXT_API_VERSION WINAPI
ExtensionApiVersion(void)
699 static EXT_API_VERSION eav
= {5, 5, 5, 0};
703 /******************************************************************
704 * WinDbgExtensionDllInit (DBGHELP.@)
706 void WINAPI
WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis
,
707 unsigned short major
, unsigned short minor
)