configure: Changes from running autconf after previous patch.
[wine/hacks.git] / dlls / dbghelp / dbghelp.c
blob0966f27ca4492a9e2a5f026e189aef0e10254a71
1 /*
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 "config.h"
23 #include "dbghelp_private.h"
24 #include "winerror.h"
25 #include "psapi.h"
26 #include "wine/debug.h"
27 #include "wdbgexts.h"
28 #include "winnls.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
32 /* TODO
33 * - support for symbols' types is still partly missing
34 * + C++ support
35 * + we should store the underlying type for an enum in the symt_enum struct
36 * + for enums, we store the names & values (associated to the enum type),
37 * but those values are not directly usable from a debugger (that's why, I
38 * assume, that we have also to define constants for enum values, as
39 * Codeview does BTW.
40 * + SymEnumTypes should only return *user* defined types (UDT, typedefs...) not
41 * all the types stored/used in the modules (like char*)
42 * - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across
43 * functions, and even across function blocks...). Basically, for *Next* to work
44 * it requires an address after the prolog of the func (the base address of the
45 * func doesn't work)
46 * - most options (dbghelp_options) are not used (loading lines...)
47 * - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
48 * we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
49 * we could use hash if name isn't a RE, and fall back to a full search when we
50 * get a full RE
51 * - msc:
52 * + we should add parameters' types to the function's signature
53 * while processing a function's parameters
54 * + add support for function-less labels (as MSC seems to define them)
55 * + C++ management
56 * - stabs:
57 * + when, in a same module, the same definition is used in several compilation
58 * units, we get several definitions of the same object (especially
59 * struct/union). we should find a way not to duplicate them
60 * + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
61 * global variable is defined several times (at different scopes). We are
62 * getting several of those while looking for a unique symbol. Part of the
63 * issue is that we don't give a scope to a static variable inside a function
64 * + C++ management
67 unsigned dbghelp_options = SYMOPT_UNDNAME;
68 HANDLE hMsvcrt = NULL;
70 /***********************************************************************
71 * DllMain (DEBUGHLP.@)
73 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
75 switch (fdwReason)
77 case DLL_PROCESS_ATTACH: break;
78 case DLL_PROCESS_DETACH:
79 if (hMsvcrt) FreeLibrary(hMsvcrt);
80 break;
81 case DLL_THREAD_ATTACH: break;
82 case DLL_THREAD_DETACH: break;
83 default: break;
85 return TRUE;
88 static struct process* process_first /* = NULL */;
90 /******************************************************************
91 * process_find_by_handle
94 struct process* process_find_by_handle(HANDLE hProcess)
96 struct process* p;
98 for (p = process_first; p && p->handle != hProcess; p = p->next);
99 if (!p) SetLastError(ERROR_INVALID_HANDLE);
100 return p;
103 /******************************************************************
104 * validate_addr64 (internal)
107 BOOL validate_addr64(DWORD64 addr)
109 if (sizeof(void*) == sizeof(int) && (addr >> 32))
111 FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr));
112 SetLastError(ERROR_INVALID_PARAMETER);
113 return FALSE;
115 return TRUE;
118 /******************************************************************
119 * fetch_buffer
121 * Ensures process' internal buffer is large enough.
123 void* fetch_buffer(struct process* pcs, unsigned size)
125 if (size > pcs->buffer_size)
127 if (pcs->buffer)
128 pcs->buffer = HeapReAlloc(GetProcessHeap(), 0, pcs->buffer, size);
129 else
130 pcs->buffer = HeapAlloc(GetProcessHeap(), 0, size);
131 pcs->buffer_size = (pcs->buffer) ? size : 0;
133 return pcs->buffer;
136 const char* wine_dbgstr_addr(const ADDRESS64* addr)
138 if (!addr) return "(null)";
139 switch (addr->Mode)
141 case AddrModeFlat:
142 return wine_dbg_sprintf("flat<%s>", wine_dbgstr_longlong(addr->Offset));
143 case AddrMode1616:
144 return wine_dbg_sprintf("1616<%04x:%04x>", addr->Segment, (DWORD)addr->Offset);
145 case AddrMode1632:
146 return wine_dbg_sprintf("1632<%04x:%08x>", addr->Segment, (DWORD)addr->Offset);
147 case AddrModeReal:
148 return wine_dbg_sprintf("real<%04x:%04x>", addr->Segment, (DWORD)addr->Offset);
149 default:
150 return "unknown";
154 extern struct cpu cpu_i386, cpu_x86_64, cpu_ppc;
156 static struct cpu* dbghelp_cpus[] = {&cpu_i386, &cpu_x86_64, &cpu_ppc, NULL};
157 struct cpu* dbghelp_current_cpu =
158 #if defined(__i386__)
159 &cpu_i386
160 #elif defined(__x86_64__)
161 &cpu_x86_64
162 #elif defined(__powerpc__)
163 &cpu_ppc
164 #else
165 #error define support for your CPU
166 #endif
169 struct cpu* cpu_find(DWORD machine)
171 struct cpu** cpu;
173 for (cpu = dbghelp_cpus ; *cpu; cpu++)
175 if (cpu[0]->machine == machine) return cpu[0];
177 return NULL;
180 /******************************************************************
181 * SymSetSearchPathW (DBGHELP.@)
184 BOOL WINAPI SymSetSearchPathW(HANDLE hProcess, PCWSTR searchPath)
186 struct process* pcs = process_find_by_handle(hProcess);
188 if (!pcs) return FALSE;
189 if (!searchPath) return FALSE;
191 HeapFree(GetProcessHeap(), 0, pcs->search_path);
192 pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
193 (lstrlenW(searchPath) + 1) * sizeof(WCHAR)),
194 searchPath);
195 return TRUE;
198 /******************************************************************
199 * SymSetSearchPath (DBGHELP.@)
202 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PCSTR searchPath)
204 BOOL ret = FALSE;
205 unsigned len;
206 WCHAR* sp;
208 len = MultiByteToWideChar(CP_ACP, 0, searchPath, -1, NULL, 0);
209 if ((sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
211 MultiByteToWideChar(CP_ACP, 0, searchPath, -1, sp, len);
213 ret = SymSetSearchPathW(hProcess, sp);
214 HeapFree(GetProcessHeap(), 0, sp);
216 return ret;
219 /***********************************************************************
220 * SymGetSearchPathW (DBGHELP.@)
222 BOOL WINAPI SymGetSearchPathW(HANDLE hProcess, PWSTR szSearchPath,
223 DWORD SearchPathLength)
225 struct process* pcs = process_find_by_handle(hProcess);
226 if (!pcs) return FALSE;
228 lstrcpynW(szSearchPath, pcs->search_path, SearchPathLength);
229 return TRUE;
232 /***********************************************************************
233 * SymGetSearchPath (DBGHELP.@)
235 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath,
236 DWORD SearchPathLength)
238 WCHAR* buffer = HeapAlloc(GetProcessHeap(), 0, SearchPathLength * sizeof(WCHAR));
239 BOOL ret = FALSE;
241 if (buffer)
243 ret = SymGetSearchPathW(hProcess, buffer, SearchPathLength);
244 if (ret)
245 WideCharToMultiByte(CP_ACP, 0, buffer, SearchPathLength,
246 szSearchPath, SearchPathLength, NULL, NULL);
247 HeapFree(GetProcessHeap(), 0, buffer);
249 return ret;
252 /******************************************************************
253 * invade_process
255 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
256 * this assumes that hProcess is a handle on a valid process
258 static BOOL WINAPI process_invade_cb(PCWSTR name, ULONG64 base, ULONG size, PVOID user)
260 WCHAR tmp[MAX_PATH];
261 HANDLE hProcess = user;
263 if (!GetModuleFileNameExW(hProcess, (HMODULE)(DWORD_PTR)base,
264 tmp, sizeof(tmp) / sizeof(WCHAR)))
265 lstrcpynW(tmp, name, sizeof(tmp) / sizeof(WCHAR));
267 SymLoadModuleExW(hProcess, 0, tmp, name, base, size, NULL, 0);
268 return TRUE;
271 /******************************************************************
272 * check_live_target
275 static BOOL check_live_target(struct process* pcs)
277 if (!GetProcessId(pcs->handle)) return FALSE;
278 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE;
279 if (!elf_read_wine_loader_dbg_info(pcs))
280 macho_read_wine_loader_dbg_info(pcs);
281 return TRUE;
284 /******************************************************************
285 * SymInitializeW (DBGHELP.@)
287 * The initialisation of a dbghelp's context.
288 * Note that hProcess doesn't need to be a valid process handle (except
289 * when fInvadeProcess is TRUE).
290 * Since, we're also allow to load ELF (pure) libraries and Wine ELF libraries
291 * containing PE (and NE) module(s), here's how we handle it:
292 * - we load every module (ELF, NE, PE) passed in SymLoadModule
293 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
294 * synchronization: hProcess should be a valid process handle, and we hook
295 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
296 * our internal ELF modules representation (loading / unloading). This way,
297 * we'll pair every loaded builtin PE module with its ELF counterpart (and
298 * access its debug information).
299 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
300 * hProcess refers to a running process. We use some heuristics here, so YMMV.
301 * If we detect a live target, then we get the same handling as if
302 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
303 * we won't be able to make the peering between a builtin PE module and its ELF
304 * counterpart. Hence we won't be able to provide the requested debug
305 * information. We'll however be able to load native PE modules (and their
306 * debug information) without any trouble.
307 * Note also that this scheme can be intertwined with the deferred loading
308 * mechanism (ie only load the debug information when we actually need it).
310 BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess)
312 struct process* pcs;
314 TRACE("(%p %s %u)\n", hProcess, debugstr_w(UserSearchPath), fInvadeProcess);
316 if (process_find_by_handle(hProcess)){
317 WARN("the symbols for this process have already been initialized!\n");
319 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call.
320 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed.
321 Native still returns TRUE even if the process has already been initialized. */
322 return TRUE;
325 pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
326 if (!pcs) return FALSE;
328 pcs->handle = hProcess;
330 if (UserSearchPath)
332 pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
333 (lstrlenW(UserSearchPath) + 1) * sizeof(WCHAR)),
334 UserSearchPath);
336 else
338 unsigned size;
339 unsigned len;
340 static const WCHAR sym_path[] = {'_','N','T','_','S','Y','M','B','O','L','_','P','A','T','H',0};
341 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};
343 pcs->search_path = HeapAlloc(GetProcessHeap(), 0, (len = MAX_PATH) * sizeof(WCHAR));
344 while ((size = GetCurrentDirectoryW(len, pcs->search_path)) >= len)
345 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (len *= 2) * sizeof(WCHAR));
346 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1) * sizeof(WCHAR));
348 len = GetEnvironmentVariableW(sym_path, NULL, 0);
349 if (len)
351 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1 + len + 1) * sizeof(WCHAR));
352 pcs->search_path[size] = ';';
353 GetEnvironmentVariableW(sym_path, pcs->search_path + size + 1, len);
354 size += 1 + len;
356 len = GetEnvironmentVariableW(alt_sym_path, NULL, 0);
357 if (len)
359 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1 + len + 1) * sizeof(WCHAR));
360 pcs->search_path[size] = ';';
361 GetEnvironmentVariableW(alt_sym_path, pcs->search_path + size + 1, len);
365 pcs->lmodules = NULL;
366 pcs->dbg_hdr_addr = 0;
367 pcs->next = process_first;
368 process_first = pcs;
370 if (check_live_target(pcs))
372 if (fInvadeProcess)
373 EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess);
374 elf_synchronize_module_list(pcs);
375 macho_synchronize_module_list(pcs);
377 else if (fInvadeProcess)
379 SymCleanup(hProcess);
380 SetLastError(ERROR_INVALID_PARAMETER);
381 return FALSE;
384 return TRUE;
387 /******************************************************************
388 * SymInitialize (DBGHELP.@)
392 BOOL WINAPI SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess)
394 WCHAR* sp = NULL;
395 BOOL ret;
397 if (UserSearchPath)
399 unsigned len;
401 len = MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, NULL, 0);
402 sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
403 MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, sp, len);
406 ret = SymInitializeW(hProcess, sp, fInvadeProcess);
407 HeapFree(GetProcessHeap(), 0, sp);
408 return ret;
411 /******************************************************************
412 * SymCleanup (DBGHELP.@)
415 BOOL WINAPI SymCleanup(HANDLE hProcess)
417 struct process** ppcs;
418 struct process* next;
420 for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
422 if ((*ppcs)->handle == hProcess)
424 while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
426 HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
427 next = (*ppcs)->next;
428 HeapFree(GetProcessHeap(), 0, *ppcs);
429 *ppcs = next;
430 return TRUE;
434 ERR("this process has not had SymInitialize() called for it!\n");
435 return FALSE;
438 /******************************************************************
439 * SymSetOptions (DBGHELP.@)
442 DWORD WINAPI SymSetOptions(DWORD opts)
444 struct process* pcs;
446 for (pcs = process_first; pcs; pcs = pcs->next)
448 pcs_callback(pcs, CBA_SET_OPTIONS, &opts);
450 return dbghelp_options = opts;
453 /******************************************************************
454 * SymGetOptions (DBGHELP.@)
457 DWORD WINAPI SymGetOptions(void)
459 return dbghelp_options;
462 /******************************************************************
463 * SymSetParentWindow (DBGHELP.@)
466 BOOL WINAPI SymSetParentWindow(HWND hwnd)
468 /* Save hwnd so it can be used as parent window */
469 FIXME("(%p): stub\n", hwnd);
470 return TRUE;
473 /******************************************************************
474 * SymSetContext (DBGHELP.@)
477 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
478 PIMAGEHLP_CONTEXT Context)
480 struct process* pcs = process_find_by_handle(hProcess);
481 if (!pcs) return FALSE;
483 if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset &&
484 pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset &&
485 pcs->ctx_frame.StackOffset == StackFrame->StackOffset)
487 TRACE("Setting same frame {rtn=%s frm=%s stk=%s}\n",
488 wine_dbgstr_longlong(pcs->ctx_frame.ReturnOffset),
489 wine_dbgstr_longlong(pcs->ctx_frame.FrameOffset),
490 wine_dbgstr_longlong(pcs->ctx_frame.StackOffset));
491 pcs->ctx_frame.InstructionOffset = StackFrame->InstructionOffset;
492 SetLastError(ERROR_ACCESS_DENIED); /* latest MSDN says ERROR_SUCCESS */
493 return FALSE;
496 pcs->ctx_frame = *StackFrame;
497 /* MSDN states that Context is not (no longer?) used */
498 return TRUE;
501 /******************************************************************
502 * reg_cb64to32 (internal)
504 * Registered callback for converting information from 64 bit to 32 bit
506 static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user)
508 struct process* pcs = process_find_by_handle(hProcess);
509 void* data32;
510 IMAGEHLP_DEFERRED_SYMBOL_LOAD64* idsl64;
511 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl;
513 if (!pcs) return FALSE;
514 switch (action)
516 case CBA_DEBUG_INFO:
517 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
518 case CBA_SET_OPTIONS:
519 case CBA_SYMBOLS_UNLOADED:
520 data32 = (void*)(DWORD_PTR)data;
521 break;
522 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
523 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
524 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
525 case CBA_DEFERRED_SYMBOL_LOAD_START:
526 idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD_PTR)data;
527 if (!validate_addr64(idsl64->BaseOfImage))
528 return FALSE;
529 idsl.SizeOfStruct = sizeof(idsl);
530 idsl.BaseOfImage = (DWORD)idsl64->BaseOfImage;
531 idsl.CheckSum = idsl64->CheckSum;
532 idsl.TimeDateStamp = idsl64->TimeDateStamp;
533 memcpy(idsl.FileName, idsl64->FileName, sizeof(idsl.FileName));
534 idsl.Reparse = idsl64->Reparse;
535 data32 = &idsl;
536 break;
537 case CBA_DUPLICATE_SYMBOL:
538 case CBA_EVENT:
539 case CBA_READ_MEMORY:
540 default:
541 FIXME("No mapping for action %u\n", action);
542 return FALSE;
544 return pcs->reg_cb32(hProcess, action, data32, (PVOID)(DWORD_PTR)user);
547 /******************************************************************
548 * pcs_callback (internal)
550 BOOL pcs_callback(const struct process* pcs, ULONG action, void* data)
552 TRACE("%p %u %p\n", pcs, action, data);
554 if (!pcs->reg_cb) return FALSE;
555 if (!pcs->reg_is_unicode)
557 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl;
558 IMAGEHLP_DEFERRED_SYMBOL_LOADW64* idslW;
560 switch (action)
562 case CBA_DEBUG_INFO:
563 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
564 case CBA_SET_OPTIONS:
565 case CBA_SYMBOLS_UNLOADED:
566 break;
567 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
568 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
569 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
570 case CBA_DEFERRED_SYMBOL_LOAD_START:
571 idslW = data;
572 idsl.SizeOfStruct = sizeof(idsl);
573 idsl.BaseOfImage = idslW->BaseOfImage;
574 idsl.CheckSum = idslW->CheckSum;
575 idsl.TimeDateStamp = idslW->TimeDateStamp;
576 WideCharToMultiByte(CP_ACP, 0, idslW->FileName, -1,
577 idsl.FileName, sizeof(idsl.FileName), NULL, NULL);
578 idsl.Reparse = idslW->Reparse;
579 data = &idsl;
580 break;
581 case CBA_DUPLICATE_SYMBOL:
582 case CBA_EVENT:
583 case CBA_READ_MEMORY:
584 default:
585 FIXME("No mapping for action %u\n", action);
586 return FALSE;
589 return pcs->reg_cb(pcs->handle, action, (ULONG64)(DWORD_PTR)data, pcs->reg_user);
592 /******************************************************************
593 * sym_register_cb
595 * Helper for registering a callback.
597 static BOOL sym_register_cb(HANDLE hProcess,
598 PSYMBOL_REGISTERED_CALLBACK64 cb,
599 PSYMBOL_REGISTERED_CALLBACK cb32,
600 DWORD64 user, BOOL unicode)
602 struct process* pcs = process_find_by_handle(hProcess);
604 if (!pcs) return FALSE;
605 pcs->reg_cb = cb;
606 pcs->reg_cb32 = cb32;
607 pcs->reg_is_unicode = unicode;
608 pcs->reg_user = user;
610 return TRUE;
613 /***********************************************************************
614 * SymRegisterCallback (DBGHELP.@)
616 BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
617 PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
618 PVOID UserContext)
620 TRACE("(%p, %p, %p)\n",
621 hProcess, CallbackFunction, UserContext);
622 return sym_register_cb(hProcess, reg_cb64to32, CallbackFunction, (DWORD_PTR)UserContext, FALSE);
625 /***********************************************************************
626 * SymRegisterCallback64 (DBGHELP.@)
628 BOOL WINAPI SymRegisterCallback64(HANDLE hProcess,
629 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
630 ULONG64 UserContext)
632 TRACE("(%p, %p, %s)\n",
633 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
634 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, FALSE);
637 /***********************************************************************
638 * SymRegisterCallbackW64 (DBGHELP.@)
640 BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess,
641 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
642 ULONG64 UserContext)
644 TRACE("(%p, %p, %s)\n",
645 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
646 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, TRUE);
649 /* This is imagehlp version not dbghelp !! */
650 static API_VERSION api_version = { 4, 0, 2, 0 };
652 /***********************************************************************
653 * ImagehlpApiVersion (DBGHELP.@)
655 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
657 return &api_version;
660 /***********************************************************************
661 * ImagehlpApiVersionEx (DBGHELP.@)
663 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
665 if (!AppVersion) return NULL;
667 AppVersion->MajorVersion = api_version.MajorVersion;
668 AppVersion->MinorVersion = api_version.MinorVersion;
669 AppVersion->Revision = api_version.Revision;
670 AppVersion->Reserved = api_version.Reserved;
672 return AppVersion;
675 /******************************************************************
676 * ExtensionApiVersion (DBGHELP.@)
678 LPEXT_API_VERSION WINAPI ExtensionApiVersion(void)
680 static EXT_API_VERSION eav = {5, 5, 5, 0};
681 return &eav;
684 /******************************************************************
685 * WinDbgExtensionDllInit (DBGHELP.@)
687 void WINAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis,
688 unsigned short major, unsigned short minor)