VirtualBox

source: kStuff/trunk/kDbg/kDbgModWinDbgHelp.cpp@ 2

Last change on this file since 2 was 2, checked in by bird, 17 years ago

Imported http://svn.netlabs.org/repos/libc/trunk/kStuff, revision 3612.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 25.2 KB
Line 
1/* $Id: kDbgModWinDbgHelp.cpp 2 2007-11-16 16:07:14Z bird $ */
2/** @file
3 * kDbg - The Debug Info Reader, DbgHelp Based Reader.
4 */
5
6/*
7 * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
8 *
9 * This file is part of kStuff.
10 *
11 * kStuff is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * In addition to the permissions in the GNU Lesser General Public
17 * License, you are granted unlimited permission to link the compiled
18 * version of this file into combinations with other programs, and to
19 * distribute those combinations without any restriction coming from
20 * the use of this file.
21 *
22 * kStuff is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
26 *
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with kStuff; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 * 02110-1301, USA
31 */
32
33/*******************************************************************************
34* Header Files *
35*******************************************************************************/
36#include <Windows.h>
37#define _IMAGEHLP64
38#include <DbgHelp.h>
39
40#include "kDbgInternal.h"
41#include <k/kHlpAlloc.h>
42#include <k/kHlpString.h>
43
44
45/*******************************************************************************
46* Global Variables *
47*******************************************************************************/
48/** The dbghelp.dll module handle. */
49static HMODULE g_hDbgHelp = NULL;
50/** Pointer to the dbhelp.dll SymInitialize function. */
51static BOOL (WINAPI *g_pfnSymInitialize)(IN HANDLE,IN LPSTR,IN BOOL);
52/** Pointer to the dbhelp.dll SymCleanup function. */
53static BOOL (WINAPI *g_pfnSymCleanup)(IN HANDLE);
54/** Pointer to the dbhelp.dll SymSetOptions function. */
55static DWORD (WINAPI *g_pfnSymSetOptions)(IN DWORD);
56/** Pointer to the dbhelp.dll SymLoadModule64 function. */
57static DWORD64 (WINAPI *g_pfnSymLoadModule64)(IN HANDLE, IN HANDLE, IN PCSTR, IN PCSTR ModuleName, IN DWORD64, IN DWORD);
58/** Pointer to the dbhelp.dll SymFromAddr function. */
59static DWORD (WINAPI *g_pfnSymFromAddr)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PSYMBOL_INFO);
60/** Pointer to the dbhelp.dll SymGetLineFromAddr64 function. */
61static DWORD (WINAPI *g_pfnSymGetLineFromAddr64)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PIMAGEHLP_LINE64);
62
63
64
65/*******************************************************************************
66* Structures and Typedefs *
67*******************************************************************************/
68/**
69 * A dbghelp based PE debug reader.
70 */
71typedef struct KDBGMODDBGHELP
72{
73 /** The common module core. */
74 KDBGMOD Core;
75 /** The image base. */
76 DWORD64 ImageBase;
77 /** The "process" handle we present dbghelp. */
78 HANDLE hSymInst;
79 /** The image size. */
80 KU32 cbImage;
81 /** The number of sections. (We've added the implicit header section.) */
82 KI32 cSections;
83 /** The section headers (variable size). The first section is the
84 * implicit header section.*/
85 IMAGE_SECTION_HEADER aSections[1];
86} KDBGMODDBGHELP, *PKDBGMODDBGHELP;
87
88
89/**
90 * Convers a Windows error to kDbg error code.
91 *
92 * @returns kDbg status code.
93 * @param rc The Windows error.
94 */
95static int kdbgModDHConvWinError(DWORD rc)
96{
97 switch (rc)
98 {
99 case 0: return 0;
100 default: return KERR_GENERAL_FAILURE;
101 }
102}
103
104
105/**
106 * Calcs the RVA for a segment:offset address.
107 *
108 * @returns IPRT status code.
109 *
110 * @param pModDH The PE debug module instance.
111 * @param iSegment The segment number. Special segments are dealt with as well.
112 * @param off The segment offset.
113 * @param puRVA Where to store the RVA on success.
114 */
115static int kdbgModDHSegOffToRVA(PKDBGMODDBGHELP pModDH, KI32 iSegment, KDBGADDR off, KU32 *puRVA)
116{
117 if (iSegment >= 0)
118 {
119 kDbgAssertMsgReturn(iSegment < pModDH->cSections, ("iSegment=%x cSections=%x\n", iSegment, pModDH->cSections),
120 KDBG_ERR_INVALID_ADDRESS);
121 kDbgAssertMsgReturn(off < pModDH->aSections[iSegment].Misc.VirtualSize,
122 ("off=" PRI_KDBGADDR " VirtualSize=%x\n", off, pModDH->aSections[iSegment].Misc.VirtualSize),
123 KDBG_ERR_INVALID_ADDRESS);
124 *puRVA = pModDH->aSections[iSegment].VirtualAddress + (KU32)off;
125 return 0;
126 }
127
128 if (iSegment == KDBGSEG_RVA)
129 {
130 kDbgAssertMsgReturn(off < pModDH->cbImage, ("off=" PRI_KDBGADDR ", cbImage=%x\n", off, pModDH->cbImage),
131 KDBG_ERR_INVALID_ADDRESS);
132 *puRVA = (KU32)off;
133 return 0;
134 }
135 kDbgAssertMsgFailedReturn(("iSegment=%d\n", iSegment), KDBG_ERR_INVALID_ADDRESS);
136}
137
138
139/**
140 * Calcs the segment:offset address for a RVA.
141 *
142 * @returns IPRT status code.
143 *
144 * @param pModDH The PE debug module instance.
145 * @param uRVA The RVA.
146 * @param piSegment Where to store the segment number.
147 * @param poff Where to store the segment offset.
148 */
149static int kdbgModDHRVAToSegOff(PKDBGMODDBGHELP pModDH, KU32 uRVA, KI32 *piSegment, KDBGADDR *poff)
150{
151 kDbgAssertMsgReturn(uRVA < pModDH->cbImage, ("uRVA=%x, cbImage=%x\n", uRVA, pModDH->cbImage),
152 KDBG_ERR_INVALID_ADDRESS);
153 for (KI32 iSegment = 0; iSegment < pModDH->cSections; iSegment++)
154 {
155 /** @todo should probably be less strict about address in the alignment gaps. */
156 KU32 off = uRVA - pModDH->aSections[iSegment].VirtualAddress;
157 if (off < pModDH->aSections[iSegment].Misc.VirtualSize)
158 {
159 *poff = off;
160 *piSegment = iSegment;
161 return 0;
162 }
163 }
164 kDbgAssertMsgFailedReturn(("uRVA=%x\n", uRVA), KDBG_ERR_INVALID_ADDRESS);
165}
166
167
168/**
169 * @copydoc KDBGMODOPS::pfnQueryLine
170 */
171static int kdbgModDHQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine)
172{
173 PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod;
174
175 /*
176 * Translate the address to an RVA.
177 */
178 KU32 uRVA;
179 int rc = kdbgModDHSegOffToRVA(pModDH, iSegment, off, &uRVA);
180 if (!rc)
181 {
182 DWORD64 off;
183 IMAGEHLP_LINE64 Line;
184 Line.SizeOfStruct = sizeof(Line);
185 if (g_pfnSymGetLineFromAddr64(pModDH->hSymInst, pModDH->ImageBase + uRVA, &off, &Line))
186 {
187 pLine->RVA = (KDBGADDR)(Line.Address - pModDH->ImageBase);
188 rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pLine->RVA, &pLine->iSegment, &pLine->offSegment);
189 pLine->iLine = Line.LineNumber;
190 KSIZE cchFile = kHlpStrLen(Line.FileName);
191 pLine->cchFile = cchFile < sizeof(pLine->szFile)
192 ? (KU16)cchFile
193 : (KU16)sizeof(pLine->szFile) - 1;
194 kHlpMemCopy(pLine->szFile, Line.FileName, pLine->cchFile);
195 pLine->szFile[pLine->cchFile] = '\0';
196 }
197 else
198 {
199 DWORD Err = GetLastError();
200 rc = kdbgModDHConvWinError(Err);
201 }
202 }
203 return rc;
204}
205
206
207/**
208 * @copydoc KDBGMODOPS::pfnQuerySymbol
209 */
210static int kdbgModDHQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym)
211{
212 PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod;
213
214 /*
215 * Translate the address to an RVA.
216 */
217 KU32 uRVA;
218 int rc = kdbgModDHSegOffToRVA(pModDH, iSegment, off, &uRVA);
219 if (!rc)
220 {
221 DWORD64 off;
222 union
223 {
224 SYMBOL_INFO Sym;
225 char achBuffer[sizeof(SYMBOL_INFO) + KDBG_SYMBOL_MAX];
226 } Buf;
227 Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO);
228 Buf.Sym.MaxNameLen = KDBG_SYMBOL_MAX;
229 if (g_pfnSymFromAddr(pModDH->hSymInst, pModDH->ImageBase + uRVA, &off, &Buf.Sym))
230 {
231 pSym->cb = Buf.Sym.Size;
232 pSym->Address = NIL_KDBGADDR;
233 pSym->fFlags = 0;
234 if (Buf.Sym.Flags & SYMFLAG_FUNCTION)
235 pSym->fFlags |= KDBGSYM_FLAGS_CODE;
236 else if (Buf.Sym.Flags & SYMFLAG_CONSTANT)
237 pSym->fFlags |= KDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/
238 else
239 pSym->fFlags |= KDBGSYM_FLAGS_DATA;
240 if (Buf.Sym.Flags & SYMFLAG_EXPORT)
241 pSym->fFlags |= KDBGSYM_FLAGS_EXPORTED;
242 if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT))
243 {
244 pSym->iSegment = KDBGSEG_ABS;
245 pSym->offSegment = (KDBGADDR)Buf.Sym.Value;
246 pSym->RVA = (KDBGADDR)Buf.Sym.Value;
247 }
248 else
249 {
250 pSym->RVA = (KDBGADDR)(Buf.Sym.Address - pModDH->ImageBase);
251 rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pSym->RVA, &pSym->iSegment, &pSym->offSegment);
252 }
253 pSym->cchName = (KU16)Buf.Sym.NameLen;
254 if (pSym->cchName >= sizeof(pSym->szName))
255 pSym->cchName = sizeof(pSym->szName) - 1;
256 kHlpMemCopy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen);
257 pSym->szName[Buf.Sym.NameLen] = '\0';
258 }
259 else
260 {
261 DWORD Err = GetLastError();
262 rc = kdbgModDHConvWinError(Err);
263 }
264 }
265 return rc;
266}
267
268
269/**
270 * @copydoc KDBGMODOPS::pfnClose
271 */
272static int kdbgModDHClose(PKDBGMOD pMod)
273{
274 PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod;
275
276 if (g_pfnSymCleanup(pModDH->hSymInst))
277 return 0;
278
279 DWORD Err = GetLastError();
280 int rc = kdbgModDHConvWinError(Err);
281 kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc));
282 return rc;
283}
284
285
286/**
287 * Checks if the specified dbghelp.dll is usable.
288 *
289 * @returns IPRT status code.
290 *
291 * @param pszPath the path to the dbghelp.dll.
292 */
293static int kdbgModDHTryDbgHelp(const char *pszPath, KU32 *pu32FileVersionMS, KU32 *pu32FileVersionLS)
294{
295 int rc;
296 DWORD dwHandle = 0;
297 DWORD cb = GetFileVersionInfoSize(pszPath, &dwHandle);
298 if (cb > 0)
299 {
300 void *pvBuf = alloca(cb);
301 if (GetFileVersionInfo(pszPath, dwHandle, cb, pvBuf))
302 {
303 UINT cbValue = 0;
304 VS_FIXEDFILEINFO *pFileInfo;
305 if (VerQueryValue(pvBuf, "\\", (void **)&pFileInfo, &cbValue))
306 {
307 /** @todo somehow reject 64-bit .dlls when in 32-bit mode... dwFileOS is completely useless. */
308 if ( *pu32FileVersionMS < pFileInfo->dwFileVersionMS
309 || ( *pu32FileVersionMS == pFileInfo->dwFileVersionMS
310 && *pu32FileVersionLS > pFileInfo->dwFileVersionLS))
311 {
312 *pu32FileVersionMS = pFileInfo->dwFileVersionMS;
313 *pu32FileVersionLS = pFileInfo->dwFileVersionLS;
314 }
315 if (pFileInfo->dwFileVersionMS >= 0x60004)
316 rc = 0;
317 else
318 rc = KDBG_ERR_DBGHLP_VERSION_MISMATCH;
319 }
320 else
321 rc = KERR_GENERAL_FAILURE;
322 }
323 else
324 rc = kdbgModDHConvWinError(GetLastError());
325 }
326 else
327 rc = kdbgModDHConvWinError(GetLastError());
328 return rc;
329}
330
331
332/**
333 * Find the dbghelp.dll
334 */
335static int kdbgModDHFindDbgHelp(char *pszPath, KSIZE cchPath)
336{
337 /*
338 * Try the current directory.
339 */
340 KU32 FileVersionMS = 0;
341 KU32 FileVersionLS = 0;
342 int rc = KERR_GENERAL_FAILURE;
343 static char s_szDbgHelp[] = "\\dbghelp.dll";
344 if (GetCurrentDirectory((DWORD)(cchPath - sizeof(s_szDbgHelp) + 1), pszPath))
345 {
346 strcat(pszPath, s_szDbgHelp);
347 int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
348 if (!rc2)
349 return rc2;
350 if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
351 rc = rc2;
352 }
353
354 /*
355 * Try the application directory.
356 */
357 if (GetModuleFileName(NULL, pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1)))
358 {
359 kHlpStrCat(kHlpStrRChr(pszPath, '\\'), s_szDbgHelp);
360 int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
361 if (!rc)
362 return rc2;
363 if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
364 rc = rc2;
365 }
366
367 /*
368 * Try the windows directory.
369 */
370 if (GetSystemDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1)))
371 {
372 kHlpStrCat(pszPath, s_szDbgHelp);
373 int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
374 if (!rc2)
375 return rc2;
376 if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
377 rc = rc2;
378 }
379
380 /*
381 * Try the windows directory.
382 */
383 if (GetWindowsDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1)))
384 {
385 kHlpStrCat(pszPath, s_szDbgHelp);
386 int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
387 if (!rc2)
388 return rc2;
389 if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
390 rc = rc2;
391 }
392
393 /*
394 * Try the path.
395 */
396 /** @todo find the actual path specs, I'm probably not doing this 100% correctly here. */
397 DWORD cb = GetEnvironmentVariable("PATH", NULL, 0) + 64;
398 char *pszSearchPath = (char *) alloca(cb);
399 if (GetEnvironmentVariable("PATH", pszSearchPath, cb) < cb)
400 {
401 char *psz = pszSearchPath;
402 while (*psz)
403 {
404 /* find the end of the path. */
405 char *pszEnd = kHlpStrChr(psz, ';');
406 if (!pszEnd)
407 pszEnd = kHlpStrChr(psz, '\0');
408 if (pszEnd != psz)
409 {
410 /* construct filename and try it out */
411 kHlpMemCopy(pszPath, psz, pszEnd - psz);
412 kHlpMemCopy(&pszPath[pszEnd - psz], s_szDbgHelp, sizeof(s_szDbgHelp));
413 int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
414 if (!rc2)
415 return rc2;
416 if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
417 rc = rc2;
418 }
419
420 /* next path */
421 if (!*pszEnd)
422 break;
423 psz = pszEnd + 1;
424 }
425 }
426
427 if (rc == KDBG_ERR_DBGHLP_VERSION_MISMATCH)
428 kDbgAssertMsgFailed(("dbghelp.dll found, but it was ancient! The highest file version found was 0x%08x'%08x.\n"
429 "This program require a file version of at least 0x00060004'00000000. Please download\n"
430 "the latest windbg and use the dbghelp.dll from that package. Just put it somewhere in\n"
431 "the PATH and we'll find it.\n", FileVersionMS, FileVersionLS));
432 else
433 kDbgAssertMsgFailed(("dbghelp.dll was not found! Download the latest windbg and use the dbghelp.dll\n"
434 "from that package - just put it somewhere in the PATH and we'll find it.\n"));
435 return rc;
436}
437
438
439/**
440 * Loads the dbghelp.dll, check that it's the right version, and
441 * resolves all the symbols we need.
442 *
443 * @returns IPRT status code.
444 */
445static int kdbgModDHLoadDbgHelp(void)
446{
447 if (g_hDbgHelp)
448 return 0;
449
450 /* primitive locking - make some useful API for this kind of spinning! */
451 static volatile long s_lLock = 0;
452 while (InterlockedCompareExchange(&s_lLock, 1, 0))
453 while (s_lLock)
454 Sleep(1);
455 if (g_hDbgHelp)
456 {
457 InterlockedExchange(&s_lLock, 0);
458 return 0;
459 }
460
461 /*
462 * Load it - try current dir first.
463 */
464 char szPath[260];
465 int rc = kdbgModDHFindDbgHelp(szPath, sizeof(szPath));
466 if (rc)
467 {
468 InterlockedExchange(&s_lLock, 0);
469 return rc;
470 }
471
472 HMODULE hmod = LoadLibraryEx(szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
473 if (!hmod)
474 {
475 DWORD Err = GetLastError();
476 int rc = kdbgModDHConvWinError(Err);
477 InterlockedExchange(&s_lLock, 0);
478 kDbgAssertMsgFailedReturn(("Failed to load '%s', Err=%d rc=%d\n", szPath, Err, rc), rc);
479 }
480
481 /*
482 * Check the API version (too).
483 */
484 LPAPI_VERSION (WINAPI *pfnImagehlpApiVersion)(VOID);
485 FARPROC *ppfn = (FARPROC *)&pfnImagehlpApiVersion;
486 *ppfn = GetProcAddress(hmod, "ImagehlpApiVersion");
487 if (*ppfn)
488 {
489 LPAPI_VERSION pVersion = pfnImagehlpApiVersion();
490 if ( pVersion
491 && ( pVersion->MajorVersion > 4
492 || (pVersion->MajorVersion == 4 && pVersion->MinorVersion > 0)
493 || (pVersion->MajorVersion == 4 && pVersion->MinorVersion == 0 && pVersion->Revision >= 5)
494 )
495 )
496 {
497 /*
498 * Resolve the entrypoints we need.
499 */
500 static const struct
501 {
502 const char *pszName;
503 FARPROC *ppfn;
504 } s_aFunctions[] =
505 {
506 { "SymInitialize", (FARPROC *)&g_pfnSymInitialize },
507 { "SymCleanup", (FARPROC *)&g_pfnSymCleanup },
508 { "SymSetOptions", (FARPROC *)&g_pfnSymSetOptions },
509 { "SymLoadModule64", (FARPROC *)&g_pfnSymLoadModule64 },
510 { "SymFromAddr", (FARPROC *)&g_pfnSymFromAddr },
511 { "SymFromAddr", (FARPROC *)&g_pfnSymFromAddr },
512 { "SymGetLineFromAddr64", (FARPROC *)&g_pfnSymGetLineFromAddr64 },
513 };
514 for (unsigned i = 0; i < K_ELEMENTS(s_aFunctions); i++)
515 {
516 FARPROC pfn = GetProcAddress(hmod, s_aFunctions[i].pszName);
517 if (!pfn)
518 {
519 DWORD Err = GetLastError();
520 rc = kdbgModDHConvWinError(Err);
521 kDbgAssertMsgFailed(("Failed to resolve %s in dbghelp, Err=%d rc=%d\n",
522 s_aFunctions[i].pszName, Err, rc));
523 break;
524 }
525 *s_aFunctions[i].ppfn = pfn;
526 }
527 if (!rc)
528 {
529 g_hDbgHelp = hmod;
530 Sleep(1);
531 InterlockedExchange(&s_lLock, 0);
532 return 0;
533 }
534 }
535 else
536 {
537 rc = KDBG_ERR_DBGHLP_VERSION_MISMATCH;
538 kDbgAssertMsgFailed(("ImagehlpApiVersion -> %p and MajorVersion=%d.\n", pVersion, pVersion ? pVersion->MajorVersion : 0));
539 }
540 }
541 else
542 {
543 DWORD Err = GetLastError();
544 rc = kdbgModDHConvWinError(Err);
545 kDbgAssertMsgFailed(("Failed to resolve ImagehlpApiVersionEx in dbghelp, Err=%d rc=%d\n", Err, rc));
546 }
547 FreeLibrary(hmod);
548 InterlockedExchange(&s_lLock, 0);
549 return rc;
550}
551
552
553/**
554 * @copydoc KDBGMODOPS::pfnOpen
555 */
556static int kdbgModDHOpen(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod)
557{
558 /*
559 * This reader doesn't support partial files.
560 * Also weed out small files early on as they cannot be
561 * PE images and will only cause read errors
562 */
563 if ( off != 0
564 || cb != KFOFF_MAX)
565 return KDBG_ERR_UNKOWN_FORMAT;
566 if (kRdrSize(pRdr) < sizeof(IMAGE_NT_HEADERS32) + sizeof(IMAGE_SECTION_HEADER))
567 return KDBG_ERR_UNKOWN_FORMAT;
568
569 /*
570 * We need to read the section headers and get the image size.
571 */
572 /* Find the PE header magic. */
573 KU32 offHdr = 0;
574 KU32 u32Magic;
575 int rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), 0);
576 kDbgAssertRCReturn(rc, rc);
577 if ((KU16)u32Magic == IMAGE_DOS_SIGNATURE)
578 {
579 rc = kRdrRead(pRdr, &offHdr, sizeof(offHdr), K_OFFSETOF(IMAGE_DOS_HEADER, e_lfanew));
580 kDbgAssertRCReturn(rc, rc);
581 if (!offHdr)
582 return KDBG_ERR_FORMAT_NOT_SUPPORTED;
583 if ( offHdr < sizeof(IMAGE_DOS_SIGNATURE)
584 || offHdr >= kRdrSize(pRdr) - 4)
585 return KDBG_ERR_BAD_EXE_FORMAT;
586
587 rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), offHdr);
588 kDbgAssertRCReturn(rc, rc);
589 }
590 if (u32Magic != IMAGE_NT_SIGNATURE)
591 return KDBG_ERR_FORMAT_NOT_SUPPORTED;
592
593 /* read the file header and the image size in the optional header.. */
594 IMAGE_FILE_HEADER FHdr;
595 rc = kRdrRead(pRdr, &FHdr, sizeof(FHdr), offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader));
596 kDbgAssertRCReturn(rc, rc);
597
598 KU32 cbImage;
599 if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
600 rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage),
601 offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage));
602 else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
603 rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage),
604 offHdr + K_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage));
605 else
606 kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT);
607 kDbgAssertRCReturn(rc, rc);
608
609 /*
610 * Load dbghelp.dll.
611 */
612 rc = kdbgModDHLoadDbgHelp();
613 if (rc)
614 return rc;
615
616 /*
617 * Allocate the module and read/construct the section headers.
618 */
619 PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)kHlpAlloc(K_OFFSETOF(KDBGMODDBGHELP, aSections[FHdr.NumberOfSections + 2]));
620 kDbgAssertReturn(pModDH, KERR_NO_MEMORY);
621 pModDH->Core.u32Magic = KDBGMOD_MAGIC;
622 pModDH->Core.pOps = &g_kDbgModWinDbgHelpOpen;
623 pModDH->Core.pRdr = pRdr;
624 pModDH->Core.fCloseRdr = fCloseRdr;
625 pModDH->Core.pLdrMod = pLdrMod;
626 pModDH->cbImage = cbImage;
627 pModDH->cSections = 1 + FHdr.NumberOfSections;
628
629 rc = kRdrRead(pRdr, &pModDH->aSections[1], sizeof(pModDH->aSections[0]) * FHdr.NumberOfSections,
630 offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader);
631 if (!rc)
632 {
633 PIMAGE_SECTION_HEADER pSH = &pModDH->aSections[0];
634 kHlpMemCopy(pSH->Name, "headers", sizeof(pSH->Name));
635 pSH->Misc.VirtualSize = pModDH->aSections[1].VirtualAddress;
636 pSH->VirtualAddress = 0;
637 pSH->SizeOfRawData = pSH->Misc.VirtualSize;
638 pSH->PointerToRawData = 0;
639 pSH->PointerToRelocations = 0;
640 pSH->PointerToLinenumbers = 0;
641 pSH->NumberOfRelocations = 0;
642 pSH->NumberOfLinenumbers = 0;
643 pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ;
644
645 KU32 uTheEnd = pModDH->aSections[FHdr.NumberOfSections].VirtualAddress
646 + pModDH->aSections[FHdr.NumberOfSections].Misc.VirtualSize;
647 if (uTheEnd < cbImage)
648 {
649 pSH = &pModDH->aSections[pModDH->cSections++];
650 kHlpMemCopy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name));
651 pSH->Misc.VirtualSize = cbImage - uTheEnd;
652 pSH->VirtualAddress = uTheEnd;
653 pSH->SizeOfRawData = pSH->Misc.VirtualSize;
654 pSH->PointerToRawData = 0;
655 pSH->PointerToRelocations = 0;
656 pSH->PointerToLinenumbers = 0;
657 pSH->NumberOfRelocations = 0;
658 pSH->NumberOfLinenumbers = 0;
659 pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ;
660 }
661
662 /*
663 * Find a new dbghelp handle.
664 *
665 * We assume 4GB of handles outlast most debugging sessions, or in anyways that
666 * when we start reusing handles they are no longer in use. :-)
667 */
668 static volatile long s_u32LastHandle = 1;
669 HANDLE hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle);
670 while ( hSymInst == INVALID_HANDLE_VALUE
671 || hSymInst == (HANDLE)0
672 || hSymInst == GetCurrentProcess())
673 hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle);
674
675 /*
676 * Initialize dbghelp and try open the specified module.
677 */
678 if (g_pfnSymInitialize(hSymInst, NULL, FALSE))
679 {
680 g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
681
682 KIPTR NativeFH = kRdrNativeFH(pRdr);
683 DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, NativeFH == -1 ? NULL : (HANDLE)NativeFH,
684 kRdrName(pRdr), NULL, 0x00400000, 0);
685 if (ImageBase)
686 {
687 pModDH->hSymInst = hSymInst;
688 pModDH->ImageBase = ImageBase;
689 *ppMod = &pModDH->Core;
690 return rc;
691 }
692
693 DWORD Err = GetLastError();
694 rc = kdbgModDHConvWinError(Err);
695 kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%d\n", Err, rc));
696 g_pfnSymCleanup(hSymInst);
697 }
698 else
699 {
700 DWORD Err = GetLastError();
701 rc = kdbgModDHConvWinError(Err);
702 kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc));
703 }
704 }
705 else
706 kDbgAssertRC(rc);
707
708 kHlpFree(pModDH);
709 return rc;
710}
711
712
713/**
714 * Methods for a PE module.
715 */
716const KDBGMODOPS g_kDbgModWinDbgHelpOpen =
717{
718 "Windows DbgHelp",
719 NULL,
720 kdbgModDHOpen,
721 kdbgModDHClose,
722 kdbgModDHQuerySymbol,
723 kdbgModDHQueryLine,
724 "Windows DbgHelp"
725};
726
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette