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

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

made kDbg compile again (not linking yet though).

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