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

Last change on this file since 3557 was 3557, checked in by bird, 18 years ago

DBGFSYMBOL::Address

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