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

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

kDbgDump can open itself now, not bad.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 24.9 KB
Line 
1/* $Id: kDbgModWinDbgHelp.cpp 3552 2007-08-26 02:15:22Z 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->fFlags = 0;
228 if (Buf.Sym.Flags & SYMFLAG_FUNCTION)
229 pSym->fFlags |= KDBGSYM_FLAGS_CODE;
230 else if (Buf.Sym.Flags & SYMFLAG_CONSTANT)
231 pSym->fFlags |= KDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/
232 else
233 pSym->fFlags |= KDBGSYM_FLAGS_DATA;
234 if (Buf.Sym.Flags & SYMFLAG_EXPORT)
235 pSym->fFlags |= KDBGSYM_FLAGS_EXPORTED;
236 if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT))
237 {
238 pSym->iSegment = KDBGSEG_ABS;
239 pSym->offSegment = (KDBGADDR)Buf.Sym.Value;
240 pSym->RVA = (KDBGADDR)Buf.Sym.Value;
241 }
242 else
243 {
244 pSym->RVA = (KDBGADDR)(Buf.Sym.Address - pModDH->ImageBase);
245 rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pSym->RVA, &pSym->iSegment, &pSym->offSegment);
246 }
247 pSym->cchName = (KU16)Buf.Sym.NameLen;
248 if (pSym->cchName >= sizeof(pSym->szName))
249 pSym->cchName = sizeof(pSym->szName) - 1;
250 kHlpMemCopy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen);
251 pSym->szName[Buf.Sym.NameLen] = '\0';
252 }
253 else
254 {
255 DWORD Err = GetLastError();
256 rc = kdbgModDHConvWinError(Err);
257 }
258 }
259 return rc;
260}
261
262
263/**
264 * @copydoc KDBGMODOPS::pfnClose
265 */
266static int kdbgModDHClose(PKDBGMOD pMod)
267{
268 PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod;
269
270 if (g_pfnSymCleanup(pModDH->hSymInst))
271 return 0;
272
273 DWORD Err = GetLastError();
274 int rc = kdbgModDHConvWinError(Err);
275 kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc));
276 return rc;
277}
278
279
280/**
281 * Checks if the specified dbghelp.dll is usable.
282 *
283 * @returns IPRT status code.
284 *
285 * @param pszPath the path to the dbghelp.dll.
286 */
287static int kdbgModDHTryDbgHelp(const char *pszPath, KU32 *pu32FileVersionMS, KU32 *pu32FileVersionLS)
288{
289 int rc;
290 DWORD dwHandle = 0;
291 DWORD cb = GetFileVersionInfoSize(pszPath, &dwHandle);
292 if (cb > 0)
293 {
294 void *pvBuf = alloca(cb);
295 if (GetFileVersionInfo(pszPath, dwHandle, cb, pvBuf))
296 {
297 UINT cbValue = 0;
298 VS_FIXEDFILEINFO *pFileInfo;
299 if (VerQueryValue(pvBuf, "\\", (void **)&pFileInfo, &cbValue))
300 {
301 /** @todo somehow reject 64-bit .dlls when in 32-bit mode... dwFileOS is completely useless. */
302 if ( *pu32FileVersionMS < pFileInfo->dwFileVersionMS
303 || ( *pu32FileVersionMS == pFileInfo->dwFileVersionMS
304 && *pu32FileVersionLS > pFileInfo->dwFileVersionLS))
305 {
306 *pu32FileVersionMS = pFileInfo->dwFileVersionMS;
307 *pu32FileVersionLS = pFileInfo->dwFileVersionLS;
308 }
309 if (pFileInfo->dwFileVersionMS >= 0x60004)
310 rc = 0;
311 else
312 rc = KDBG_ERR_DBGHLP_VERSION_MISMATCH;
313 }
314 else
315 rc = KERR_GENERAL_FAILURE;
316 }
317 else
318 rc = kdbgModDHConvWinError(GetLastError());
319 }
320 else
321 rc = kdbgModDHConvWinError(GetLastError());
322 return rc;
323}
324
325
326/**
327 * Find the dbghelp.dll
328 */
329static int kdbgModDHFindDbgHelp(char *pszPath, KSIZE cchPath)
330{
331 /*
332 * Try the current directory.
333 */
334 KU32 FileVersionMS = 0;
335 KU32 FileVersionLS = 0;
336 int rc = KERR_GENERAL_FAILURE;
337 static char s_szDbgHelp[] = "\\dbghelp.dll";
338 if (GetCurrentDirectory((DWORD)(cchPath - sizeof(s_szDbgHelp) + 1), pszPath))
339 {
340 strcat(pszPath, s_szDbgHelp);
341 int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
342 if (!rc2)
343 return rc2;
344 if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
345 rc = rc2;
346 }
347
348 /*
349 * Try the application directory.
350 */
351 if (GetModuleFileName(NULL, pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1)))
352 {
353 kHlpStrCat(kHlpStrRChr(pszPath, '\\'), s_szDbgHelp);
354 int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
355 if (!rc)
356 return rc2;
357 if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
358 rc = rc2;
359 }
360
361 /*
362 * Try the windows directory.
363 */
364 if (GetSystemDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1)))
365 {
366 kHlpStrCat(pszPath, s_szDbgHelp);
367 int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
368 if (!rc2)
369 return rc2;
370 if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
371 rc = rc2;
372 }
373
374 /*
375 * Try the windows directory.
376 */
377 if (GetWindowsDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1)))
378 {
379 kHlpStrCat(pszPath, s_szDbgHelp);
380 int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
381 if (!rc2)
382 return rc2;
383 if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
384 rc = rc2;
385 }
386
387 /*
388 * Try the path.
389 */
390 /** @todo find the actual path specs, I'm probably not doing this 100% correctly here. */
391 DWORD cb = GetEnvironmentVariable("PATH", NULL, 0) + 64;
392 char *pszSearchPath = (char *) alloca(cb);
393 if (GetEnvironmentVariable("PATH", pszSearchPath, cb) < cb)
394 {
395 char *psz = pszSearchPath;
396 while (*psz)
397 {
398 /* find the end of the path. */
399 char *pszEnd = kHlpStrChr(psz, ';');
400 if (!pszEnd)
401 pszEnd = kHlpStrChr(psz, '\0');
402 if (pszEnd != psz)
403 {
404 /* construct filename and try it out */
405 kHlpMemCopy(pszPath, psz, pszEnd - psz);
406 kHlpMemCopy(&pszPath[pszEnd - psz], s_szDbgHelp, sizeof(s_szDbgHelp));
407 int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
408 if (!rc2)
409 return rc2;
410 if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
411 rc = rc2;
412 }
413
414 /* next path */
415 if (!*pszEnd)
416 break;
417 psz = pszEnd + 1;
418 }
419 }
420
421 if (rc == KDBG_ERR_DBGHLP_VERSION_MISMATCH)
422 kDbgAssertMsgFailed(("dbghelp.dll found, but it was ancient! The highest file version found was 0x%08x'%08x.\n"
423 "This program require a file version of at least 0x00060004'00000000. Please download\n"
424 "the latest windbg and use the dbghelp.dll from that package. Just put it somewhere in\n"
425 "the PATH and we'll find it.\n", FileVersionMS, FileVersionLS));
426 else
427 kDbgAssertMsgFailed(("dbghelp.dll was not found! Download the latest windbg and use the dbghelp.dll\n"
428 "from that package - just put it somewhere in the PATH and we'll find it.\n"));
429 return rc;
430}
431
432
433/**
434 * Loads the dbghelp.dll, check that it's the right version, and
435 * resolves all the symbols we need.
436 *
437 * @returns IPRT status code.
438 */
439static int kdbgModDHLoadDbgHelp(void)
440{
441 if (g_hDbgHelp)
442 return 0;
443
444 /* primitive locking - make some useful API for this kind of spinning! */
445 static volatile long s_lLock = 0;
446 while (InterlockedCompareExchange(&s_lLock, 1, 0))
447 while (s_lLock)
448 Sleep(1);
449 if (g_hDbgHelp)
450 {
451 InterlockedExchange(&s_lLock, 0);
452 return 0;
453 }
454
455 /*
456 * Load it - try current dir first.
457 */
458 char szPath[260];
459 int rc = kdbgModDHFindDbgHelp(szPath, sizeof(szPath));
460 if (rc)
461 {
462 InterlockedExchange(&s_lLock, 0);
463 return rc;
464 }
465
466 HMODULE hmod = LoadLibraryEx(szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
467 if (!hmod)
468 {
469 DWORD Err = GetLastError();
470 int rc = kdbgModDHConvWinError(Err);
471 kDbgAssertMsgFailedReturn(("Failed to load '%s', Err=%d rc=%d\n", szPath, Err, rc), rc);
472 }
473
474 /*
475 * Check the API version (too).
476 */
477 LPAPI_VERSION (WINAPI *pfnImagehlpApiVersion)(VOID);
478 FARPROC *ppfn = (FARPROC *)&pfnImagehlpApiVersion;
479 *ppfn = GetProcAddress(hmod, "ImagehlpApiVersion");
480 if (*ppfn)
481 {
482 LPAPI_VERSION pVersion = pfnImagehlpApiVersion();
483 if ( pVersion
484 && ( pVersion->MajorVersion > 4
485 || (pVersion->MajorVersion == 4 && pVersion->MinorVersion > 0)
486 || (pVersion->MajorVersion == 4 && pVersion->MinorVersion == 0 && pVersion->Revision >= 5)
487 )
488 )
489 {
490 /*
491 * Resolve the entrypoints we need.
492 */
493 static const struct
494 {
495 const char *pszName;
496 FARPROC *ppfn;
497 } s_aFunctions[] =
498 {
499 { "SymInitialize", (FARPROC *)&g_pfnSymInitialize },
500 { "SymCleanup", (FARPROC *)&g_pfnSymCleanup },
501 { "SymSetOptions", (FARPROC *)&g_pfnSymSetOptions },
502 { "SymLoadModule64", (FARPROC *)&g_pfnSymLoadModule64 },
503 { "SymFromAddr", (FARPROC *)&g_pfnSymFromAddr },
504 { "SymFromAddr", (FARPROC *)&g_pfnSymFromAddr },
505 { "SymGetLineFromAddr64", (FARPROC *)&g_pfnSymGetLineFromAddr64 },
506 };
507 for (unsigned i = 0; i < K_ELEMENTS(s_aFunctions); i++)
508 {
509 FARPROC pfn = GetProcAddress(hmod, s_aFunctions[i].pszName);
510 if (!pfn)
511 {
512 DWORD Err = GetLastError();
513 rc = kdbgModDHConvWinError(Err);
514 kDbgAssertMsgFailed(("Failed to resolve %s in dbghelp, Err=%d rc=%d\n",
515 s_aFunctions[i].pszName, Err, rc));
516 break;
517 }
518 *s_aFunctions[i].ppfn = pfn;
519 }
520 if (!rc)
521 {
522 //InterlockedExchange(&g_hDbgHelp, hmod);
523 g_hDbgHelp = hmod;
524 Sleep(1);
525 InterlockedExchange(&s_lLock, 0);
526 return 0;
527 }
528 }
529 else
530 {
531 rc = KDBG_ERR_DBGHLP_VERSION_MISMATCH;
532 kDbgAssertMsgFailed(("ImagehlpApiVersion -> %p and MajorVersion=%d.\n", pVersion, pVersion ? pVersion->MajorVersion : 0));
533 }
534 }
535 else
536 {
537 DWORD Err = GetLastError();
538 rc = kdbgModDHConvWinError(Err);
539 kDbgAssertMsgFailed(("Failed to resolve ImagehlpApiVersionEx in dbghelp, Err=%d rc=%d\n", Err, rc));
540 }
541 FreeLibrary(hmod);
542 InterlockedExchange(&s_lLock, 0);
543 return rc;
544}
545
546
547/**
548 * @copydoc KDBGMODOPS::pfnOpen
549 */
550static int kdbgModDHOpen(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod)
551{
552 /*
553 * This reader doesn't support partial files.
554 * Also weed out small files early on as they cannot be
555 * PE images and will only cause read errors
556 */
557 if ( off != 0
558 || cb != KFOFF_MAX)
559 return KDBG_ERR_UNKOWN_FORMAT;
560 if (kRdrSize(pRdr) < sizeof(IMAGE_NT_HEADERS32) + sizeof(IMAGE_SECTION_HEADER))
561 return KDBG_ERR_UNKOWN_FORMAT;
562
563 /*
564 * We need to read the section headers and get the image size.
565 */
566 /* Find the PE header magic. */
567 KU32 offHdr = 0;
568 KU32 u32Magic;
569 int rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), 0);
570 kDbgAssertRCReturn(rc, rc);
571 if ((KU16)u32Magic == IMAGE_DOS_SIGNATURE)
572 {
573 rc = kRdrRead(pRdr, &offHdr, sizeof(offHdr), K_OFFSETOF(IMAGE_DOS_HEADER, e_lfanew));
574 kDbgAssertRCReturn(rc, rc);
575 if (!offHdr)
576 return KDBG_ERR_FORMAT_NOT_SUPPORTED;
577 if ( offHdr < sizeof(IMAGE_DOS_SIGNATURE)
578 || offHdr >= kRdrSize(pRdr) - 4)
579 return KDBG_ERR_BAD_EXE_FORMAT;
580
581 rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), offHdr);
582 kDbgAssertRCReturn(rc, rc);
583 }
584 if (u32Magic != IMAGE_NT_SIGNATURE)
585 return KDBG_ERR_FORMAT_NOT_SUPPORTED;
586
587 /* read the file header and the image size in the optional header.. */
588 IMAGE_FILE_HEADER FHdr;
589 rc = kRdrRead(pRdr, &FHdr, sizeof(FHdr), offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader));
590 kDbgAssertRCReturn(rc, rc);
591
592 KU32 cbImage;
593 if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
594 rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage),
595 offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage));
596 else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
597 rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage),
598 offHdr + K_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage));
599 else
600 kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT);
601 kDbgAssertRCReturn(rc, rc);
602
603 /*
604 * Load dbghelp.dll.
605 */
606 rc = kdbgModDHLoadDbgHelp();
607 if (rc)
608 return rc;
609
610 /*
611 * Allocate the module and read/construct the section headers.
612 */
613 PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)kHlpAlloc(K_OFFSETOF(KDBGMODDBGHELP, aSections[FHdr.NumberOfSections + 2]));
614 kDbgAssertReturn(pModDH, KERR_NO_MEMORY);
615 pModDH->Core.u32Magic = KDBGMOD_MAGIC;
616 pModDH->Core.pOps = &g_kDbgModWinDbgHelpOpen;
617 pModDH->Core.pRdr = pRdr;
618 pModDH->Core.fCloseRdr = fCloseRdr;
619 pModDH->Core.pLdrMod = pLdrMod;
620 pModDH->cbImage = cbImage;
621 pModDH->cSections = 1 + FHdr.NumberOfSections;
622
623 rc = kRdrRead(pRdr, &pModDH->aSections[1], sizeof(pModDH->aSections[0]) * FHdr.NumberOfSections,
624 offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader);
625 if (!rc)
626 {
627 PIMAGE_SECTION_HEADER pSH = &pModDH->aSections[0];
628 kHlpMemCopy(pSH->Name, "headers", sizeof(pSH->Name));
629 pSH->Misc.VirtualSize = pModDH->aSections[1].VirtualAddress;
630 pSH->VirtualAddress = 0;
631 pSH->SizeOfRawData = pSH->Misc.VirtualSize;
632 pSH->PointerToRawData = 0;
633 pSH->PointerToRelocations = 0;
634 pSH->PointerToLinenumbers = 0;
635 pSH->NumberOfRelocations = 0;
636 pSH->NumberOfLinenumbers = 0;
637 pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ;
638
639 KU32 uTheEnd = pModDH->aSections[FHdr.NumberOfSections].VirtualAddress
640 + pModDH->aSections[FHdr.NumberOfSections].Misc.VirtualSize;
641 if (uTheEnd < cbImage)
642 {
643 pSH = &pModDH->aSections[pModDH->cSections++];
644 kHlpMemCopy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name));
645 pSH->Misc.VirtualSize = cbImage - uTheEnd;
646 pSH->VirtualAddress = uTheEnd;
647 pSH->SizeOfRawData = pSH->Misc.VirtualSize;
648 pSH->PointerToRawData = 0;
649 pSH->PointerToRelocations = 0;
650 pSH->PointerToLinenumbers = 0;
651 pSH->NumberOfRelocations = 0;
652 pSH->NumberOfLinenumbers = 0;
653 pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ;
654 }
655
656 /*
657 * Find a new dbghelp handle.
658 *
659 * We assume 4GB of handles outlast most debugging sessions, or in anyways that
660 * when we start reusing handles they are no longer in use. :-)
661 */
662 static volatile long s_u32LastHandle = 1;
663 HANDLE hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle);
664 while ( hSymInst == INVALID_HANDLE_VALUE
665 || hSymInst == (HANDLE)0
666 || hSymInst == GetCurrentProcess())
667 hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle);
668
669 /*
670 * Initialize dbghelp and try open the specified module.
671 */
672 if (g_pfnSymInitialize(hSymInst, NULL, FALSE))
673 {
674 g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
675
676 KIPTR NativeFH = kRdrNativeFH(pRdr);
677 DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, NativeFH == -1 ? NULL : (HANDLE)NativeFH,
678 kRdrName(pRdr), NULL, 0x00400000, 0);
679 if (ImageBase)
680 {
681 pModDH->hSymInst = hSymInst;
682 pModDH->ImageBase = ImageBase;
683 *ppMod = &pModDH->Core;
684 return rc;
685 }
686
687 DWORD Err = GetLastError();
688 rc = kdbgModDHConvWinError(Err);
689 kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%d\n", Err, rc));
690 g_pfnSymCleanup(hSymInst);
691 }
692 else
693 {
694 DWORD Err = GetLastError();
695 rc = kdbgModDHConvWinError(Err);
696 kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc));
697 }
698 }
699 else
700 kDbgAssertRC(rc);
701
702 kHlpFree(pModDH);
703 return rc;
704}
705
706
707/**
708 * Methods for a PE module.
709 */
710const KDBGMODOPS g_kDbgModWinDbgHelpOpen =
711{
712 "Windows DbgHelp",
713 NULL,
714 kdbgModDHOpen,
715 kdbgModDHClose,
716 kdbgModDHQuerySymbol,
717 kdbgModDHQueryLine,
718 "Windows DbgHelp"
719};
720
Note: See TracBrowser for help on using the repository browser.