source: trunk/kDbg/kDbgModPE-win.cpp@ 3528

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

Some refactoring and OS abstraction by instroducing kDbgHlp.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 23.1 KB
Line 
1/* $Id: kDbgModPE-win.cpp 3528 2007-08-20 02:43:13Z 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
37
38/*******************************************************************************
39* Global Variables *
40*******************************************************************************/
41/** The dbghelp.dll module handle. */
42static HMODULE g_hDbgHelp = NULL;
43/** Pointer to the dbhelp.dll SymInitialize function. */
44static BOOL (WINAPI *g_pfnSymInitialize)(IN HANDLE,IN LPSTR,IN BOOL);
45/** Pointer to the dbhelp.dll SymCleanup function. */
46static BOOL (WINAPI *g_pfnSymCleanup)(IN HANDLE);
47/** Pointer to the dbhelp.dll SymSetOptions function. */
48static DWORD (WINAPI *g_pfnSymSetOptions)(IN DWORD);
49/** Pointer to the dbhelp.dll SymLoadModule64 function. */
50static DWORD64 (WINAPI *g_pfnSymLoadModule64)(IN HANDLE, IN HANDLE, IN PCSTR, IN PCSTR ModuleName, IN DWORD64, IN DWORD);
51/** Pointer to the dbhelp.dll SymFromAddr function. */
52static DWORD (WINAPI *g_pfnSymFromAddr)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PSYMBOL_INFO);
53/** Pointer to the dbhelp.dll SymGetLineFromAddr64 function. */
54static DWORD (WINAPI *g_pfnSymGetLineFromAddr64)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PIMAGEHLP_LINE64);
55
56
57
58/*******************************************************************************
59* Structures and Typedefs *
60*******************************************************************************/
61/**
62 * A dbghelp based PE debug reader.
63 */
64typedef struct KDBGMODPE
65{
66 /** The common module core. */
67 KDBGMOD Core;
68 /** The image base. */
69 DWORD64 ImageBase;
70 /** The "process" handle we present dbghelp. */
71 HANDLE hSymInst;
72 /** The image size. */
73 uint32_t cbImage;
74 /** The number of sections. (We've added the implicit header section.) */
75 int32_t cSections;
76 /** The section headers (variable size). The first section is the
77 * implicit header section.*/
78 IMAGE_SECTION_HEADER aSections[1];
79} KDBGMODPE, *PKDBGMODPE;
80
81
82/**
83 * Calcs the RVA for a segment:offset address.
84 *
85 * @returns IPRT status code.
86 *
87 * @param pModPe The PE debug module instance.
88 * @param iSegment The segment number. Special segments are dealt with as well.
89 * @param off The segment offset.
90 * @param puRVA Where to store the RVA on success.
91 */
92static int rtDbgModPeSegOffToRVA(PKDBGMODPE pModPe, int32_t iSegment, KDBGADDR off, uint32_t *puRVA)
93{
94 if (iSegment >= 0)
95 {
96 kDbgAssertMsgReturn(iSegment < pModPe->cSections, ("iSegment=%x cSections=%x\n", iSegment, pModPe->cSections),
97 KDBG_ERR_INVALID_ADDRESS);
98 kDbgAssertMsgReturn(off < pModPe->aSections[iSegment].Misc.VirtualSize,
99 ("off=" PRI_KDBGADDR " VirtualSize=%x\n", off, pModPe->aSections[iSegment].Misc.VirtualSize),
100 KDBG_ERR_INVALID_ADDRESS);
101 *puRVA = pModPe->aSections[iSegment].VirtualAddress + off;
102 return 0;
103 }
104
105 if (iSegment == KDBGSEG_RVA)
106 {
107 kDbgAssertMsgReturn(off < pModPe->cbImage, ("off=" PRI_KDBGADDR ", cbImage=%x\n", off, pModPe->cbImage),
108 KDBG_ERR_INVALID_ADDRESS);
109 *puRVA = off;
110 return 0;
111 }
112 AssertMsgFailedReturn(("iSegment=%RI32\n", iSegment), KDBG_ERR_INVALID_ADDRESS);
113}
114
115
116/**
117 * Calcs the segment:offset address for a RVA.
118 *
119 * @returns IPRT status code.
120 *
121 * @param pModPe The PE debug module instance.
122 * @param uRVA The RVA.
123 * @param piSegment Where to store the segment number.
124 * @param poff Where to store the segment offset.
125 */
126static int rtDbgModPeRVAToSegOff(PKDBGMODPE pModPe, uint32_t uRVA, int32_t *piSegment, KDBGADDR *poff)
127{
128 kDbgAssertMsgReturn(uRVA < pModPe->cbImage, ("uRVA=%x, cbImage=%x\n", uRVA, pModPe->cbImage),
129 KDBG_ERR_INVALID_ADDRESS);
130 for (int32_t iSegment = 0; iSegment < pModPe->cSections; iSegment++)
131 {
132 /** @todo should probably be less strict about address in the alignment gaps. */
133 uint32_t off = uRVA - pModPe->aSections[iSegment].VirtualAddress;
134 if (off < pModPe->aSections[iSegment].Misc.VirtualSize)
135 {
136 *poff = off;
137 *piSegment = iSegment;
138 return 0;
139 }
140 }
141 AssertMsgFailedReturn(("uRVA=%x\n", uRVA), KDBG_ERR_INVALID_ADDRESS);
142}
143
144
145/**
146 * @copydoc KDBGMODOPS::pfnQueryLine
147 */
148static DECLCALLBACK(int) rtDbgModPEQueryLine(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGLINE pLine)
149{
150 PKDBGMODPE pModPe = (PKDBGMODPE)pMod;
151
152 /*
153 * Translate the address to an RVA.
154 */
155 uint32_t uRVA;
156 int rc = rtDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA);
157 if (!rc)
158 {
159 DWORD64 off;
160 IMAGEHLP_LINE64 Line;
161 Line.SizeOfStruct = sizeof(Line);
162 if (g_pfnSymGetLineFromAddr64(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Line))
163 {
164 pLine->RVA = (KDBGADDR)(Line.Address - pModPe->ImageBase);
165 rc = rtDbgModPeRVAToSegOff(pModPe, pLine->RVA, &pLine->iSegment, &pLine->offSegment);
166 pLine->iLine = Line.LineNumber;
167 pLine->cchFile = strlen(Line.FileName);
168 if (pLine->cchFile >= sizeof(pLine->szFile))
169 pLine->cchFile = sizeof(pLine->szFile) - 1;
170 memcpy(pLine->szFile, Line.FileName, pLine->cchFile + 1);
171 }
172 else
173 {
174 DWORD Err = GetLastError();
175 rc = RTErrConvertFromWin32(Err);
176 }
177 }
178 return rc;
179}
180
181
182/**
183 * @copydoc KDBGMODOPS::pfnQuerySymbol
184 */
185static DECLCALLBACK(int) rtDbgModPEQuerySymbol(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGSYMBOL pSym)
186{
187 PKDBGMODPE pModPe = (PKDBGMODPE)pMod;
188
189 /*
190 * Translate the address to an RVA.
191 */
192 uint32_t uRVA;
193 int rc = rtDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA);
194 if (!rc)
195 {
196 DWORD64 off;
197 union
198 {
199 SYMBOL_INFO Sym;
200 char achBuffer[sizeof(SYMBOL_INFO) + KDBG_SYMBOL_MAX];
201 } Buf;
202 Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO);
203 Buf.Sym.MaxNameLen = KDBG_SYMBOL_MAX;
204 if (g_pfnSymFromAddr(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Buf.Sym))
205 {
206 pSym->cb = Buf.Sym.Size;
207 pSym->fFlags = 0;
208 if (Buf.Sym.Flags & SYMFLAG_FUNCTION)
209 pSym->fFlags |= KDBGSYM_FLAGS_CODE;
210 else if (Buf.Sym.Flags & SYMFLAG_CONSTANT)
211 pSym->fFlags |= KDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/
212 else
213 pSym->fFlags |= KDBGSYM_FLAGS_DATA;
214 if (Buf.Sym.Flags & SYMFLAG_EXPORT)
215 pSym->fFlags |= KDBGSYM_FLAGS_EXPORTED;
216 if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT))
217 {
218 pSym->iSegment = KDBGSEG_ABS;
219 pSym->offSegment = (KDBGADDR)Buf.Sym.Value;
220 pSym->RVA = (KDBGADDR)Buf.Sym.Value;
221 }
222 else
223 {
224 pSym->RVA = (KDBGADDR)(Buf.Sym.Address - pModPe->ImageBase);
225 rc = rtDbgModPeRVAToSegOff(pModPe, pSym->RVA, &pSym->iSegment, &pSym->offSegment);
226 }
227 pSym->cchName = (uint16_t)Buf.Sym.NameLen;
228 if (pSym->cchName >= sizeof(pSym->szName))
229 pSym->cchName = sizeof(pSym->szName) - 1;
230 memcpy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen);
231 pSym->szName[Buf.Sym.NameLen] = '\0';
232 }
233 else
234 {
235 DWORD Err = GetLastError();
236 rc = RTErrConvertFromWin32(Err);
237 }
238 }
239 return rc;
240}
241
242
243/**
244 * @copydoc KDBGMODOPS::pfnClose
245 */
246static DECLCALLBACK(int) rtDbgModPEClose(PKDBGMOD pMod)
247{
248 PKDBGMODPE pModPe = (PKDBGMODPE)pMod;
249
250 if (g_pfnSymCleanup(pModPe->hSymInst))
251 return 0;
252
253 DWORD Err = GetLastError();
254 int rc = RTErrConvertFromWin32(Err);
255 AssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc));
256 return rc;
257}
258
259
260/**
261 * Methods for a PE module.
262 */
263static const KDBGMODOPS g_rtDbgModPEOps =
264{
265 "PE (dbghelp)",
266 rtDbgModPEClose,
267 rtDbgModPEQuerySymbol,
268 rtDbgModPEQueryLine
269};
270
271
272/**
273 * Checks if the specified dbghelp.dll is usable.
274 *
275 * @returns IPRT status code.
276 *
277 * @param pszPath the path to the dbghelp.dll.
278 */
279static int rtDbgModPETryDbgHelp(const char *pszPath, uint32_t *pu32FileVersionMS, uint32_t *pu32FileVersionLS)
280{
281 int rc;
282 DWORD dwHandle = 0;
283 DWORD cb = GetFileVersionInfoSize(pszPath, &dwHandle);
284 if (cb > 0)
285 {
286 void *pvBuf = alloca(cb);
287 if (GetFileVersionInfo(pszPath, dwHandle, cb, pvBuf))
288 {
289 UINT cbValue = 0;
290 VS_FIXEDFILEINFO *pFileInfo;
291 if (VerQueryValue(pvBuf, "\\", (void **)&pFileInfo, &cbValue))
292 {
293 if ( *pu32FileVersionMS < pFileInfo->dwFileVersionMS
294 || ( *pu32FileVersionMS == pFileInfo->dwFileVersionMS
295 && *pu32FileVersionLS > pFileInfo->dwFileVersionLS))
296 {
297 *pu32FileVersionMS = pFileInfo->dwFileVersionMS;
298 *pu32FileVersionLS = pFileInfo->dwFileVersionLS;
299 }
300 if (pFileInfo->dwFileVersionMS >= 0x60004)
301 rc = 0;
302 else
303 rc = VERR_VERSION_MISMATCH;
304 }
305 else
306 rc = VERR_GENERAL_FAILURE;
307 }
308 else
309 rc = RTErrConvertFromWin32(GetLastError());
310 }
311 else
312 rc = RTErrConvertFromWin32(GetLastError());
313 return rc;
314}
315
316
317/**
318 * Find the dbghelp.dll
319 */
320static int rtDbgModPEFindDbgHelp(char *pszPath, size_t cchPath)
321{
322 /*
323 * Try the current directory.
324 */
325 uint32_t FileVersionMS = 0;
326 uint32_t FileVersionLS = 0;
327 int rc = VERR_GENERAL_FAILURE;
328 static char s_szDbgHelp[] = "\\dbghelp.dll";
329 if (GetCurrentDirectory(cchPath - sizeof(s_szDbgHelp) + 1, pszPath))
330 {
331 strcat(pszPath, s_szDbgHelp);
332 int rc2 = rtDbgModPETryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
333 if (RT_SUCCESS(rc2))
334 return rc2;
335 if (rc != VERR_VERSION_MISMATCH)
336 rc = rc2;
337 }
338
339 /*
340 * Try the application directory.
341 */
342 if (GetModuleFileName(NULL, pszPath, cchPath - sizeof(s_szDbgHelp) + 1))
343 {
344 strcat(strrchr(pszPath, '\\'), s_szDbgHelp);
345 int rc2 = rtDbgModPETryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
346 if (!rc)
347 return rc2;
348 if (rc != VERR_VERSION_MISMATCH)
349 rc = rc2;
350 }
351
352 /*
353 * Try the windows directory.
354 */
355 if (GetSystemDirectory(pszPath, cchPath - sizeof(s_szDbgHelp) + 1))
356 {
357 strcat(pszPath, s_szDbgHelp);
358 int rc2 = rtDbgModPETryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
359 if (RT_SUCCESS(rc2))
360 return rc2;
361 if (rc != VERR_VERSION_MISMATCH)
362 rc = rc2;
363 }
364
365 /*
366 * Try the windows directory.
367 */
368 if (GetWindowsDirectory(pszPath, cchPath - sizeof(s_szDbgHelp) + 1))
369 {
370 strcat(pszPath, s_szDbgHelp);
371 int rc2 = rtDbgModPETryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
372 if (RT_SUCCESS(rc2))
373 return rc2;
374 if (rc != VERR_VERSION_MISMATCH)
375 rc = rc2;
376 }
377
378 /*
379 * Try the path.
380 */
381 /** @todo find the actual path specs, I'm probably not doing this 100% correctly here. */
382 DWORD cb = GetEnvironmentVariable("PATH", NULL, 0) + 64;
383 char *pszSearchPath = (char *) alloca(cb);
384 if (GetEnvironmentVariable("PATH", pszSearchPath, cb) < cb)
385 {
386 char *psz = pszSearchPath;
387 while (*psz)
388 {
389 /* find the end of the path. */
390 char *pszEnd = strchr(psz, ';');
391 if (!pszEnd)
392 pszEnd = strchr(psz, '\0');
393 if (pszEnd != psz)
394 {
395 /* construct filename and try it out */
396 memcpy(pszPath, psz, pszEnd - psz);
397 memcpy(&pszPath[pszEnd - psz], s_szDbgHelp, sizeof(s_szDbgHelp));
398 int rc2 = rtDbgModPETryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
399 if (RT_SUCCESS(rc2))
400 return rc2;
401 if (rc != VERR_VERSION_MISMATCH)
402 rc = rc2;
403 }
404
405 /* next path */
406 if (!*pszEnd)
407 break;
408 psz = pszEnd + 1;
409 }
410 }
411
412 if (rc == VERR_VERSION_MISMATCH)
413 AssertMsgFailed(("dbghelp.dll found, but it was ancient! The highest file version found was 0x%08x'%08x.\n"
414 "This program require a file version of at least 0x00060004'00000000. Please download\n"
415 "the latest windbg and use the dbghelp.dll from that package. Just put it somewhere in\n"
416 "the PATH and we'll find it.\n", FileVersionMS, FileVersionLS));
417 else
418 AssertMsgFailed(("dbghelp.dll was not found! Download the latest windbg and use the dbghelp.dll\n"
419 "from that package - just put it somewhere in the PATH and we'll find it.\n"));
420 return rc;
421}
422
423
424/**
425 * Loads the dbghelp.dll, check that it's the right version, and
426 * resolves all the symbols we need.
427 *
428 * @returns IPRT status code.
429 */
430static int rtDbgModPELoadDbgHelp(void)
431{
432 if (g_hDbgHelp)
433 return 0;
434
435 /* primitive locking - make some useful API for this kind of spinning! */
436 static volatile uint32_t s_u32Lock = 0;
437 while (!ASMAtomicCmpXchgU32(&s_u32Lock, 1, 0))
438 while (s_u32Lock)
439 RTThreadYield();
440 if (g_hDbgHelp)
441 {
442 ASMAtomicXchgU32(&s_u32Lock, 0);
443 return 0;
444 }
445
446 /*
447 * Load it - try current dir first.
448 */
449 char szPath[260];
450 int rc = rtDbgModPEFindDbgHelp(szPath, sizeof(szPath));
451 if (rc)
452 {
453 ASMAtomicXchgU32(&s_u32Lock, 0);
454 return rc;
455 }
456
457 HMODULE hmod = LoadLibraryEx(szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
458 if (!hmod)
459 {
460 DWORD Err = GetLastError();
461 int rc = RTErrConvertFromWin32(Err);
462 AssertMsgFailedReturn(("Failed to load '%s', Err=%d rc=%Rrc\n", szPath, Err, rc), rc);
463 }
464
465 /*
466 * Check the API version (too).
467 */
468 LPAPI_VERSION (WINAPI *pfnImagehlpApiVersion)(VOID);
469 FARPROC *ppfn = (FARPROC *)&pfnImagehlpApiVersion;
470 *ppfn = GetProcAddress(hmod, "ImagehlpApiVersion");
471 if (*ppfn)
472 {
473 LPAPI_VERSION pVersion = pfnImagehlpApiVersion();
474 if ( pVersion
475 && ( pVersion->MajorVersion > 4
476 || (pVersion->MajorVersion == 4 && pVersion->MinorVersion > 0)
477 || (pVersion->MajorVersion == 4 && pVersion->MinorVersion == 0 && pVersion->Revision >= 5)
478 )
479 )
480 {
481 /*
482 * Resolve the entrypoints we need.
483 */
484 static const struct
485 {
486 const char *pszName;
487 FARPROC *ppfn;
488 } s_aFunctions[] =
489 {
490 { "SymInitialize", (FARPROC *)&g_pfnSymInitialize },
491 { "SymCleanup", (FARPROC *)&g_pfnSymCleanup },
492 { "SymSetOptions", (FARPROC *)&g_pfnSymSetOptions },
493 { "SymLoadModule64", (FARPROC *)&g_pfnSymLoadModule64 },
494 { "SymFromAddr", (FARPROC *)&g_pfnSymFromAddr },
495 { "SymFromAddr", (FARPROC *)&g_pfnSymFromAddr },
496 { "SymGetLineFromAddr64", (FARPROC *)&g_pfnSymGetLineFromAddr64 },
497 };
498 for (unsigned i = 0; i < ELEMENTS(s_aFunctions); i++)
499 {
500 FARPROC pfn = GetProcAddress(hmod, s_aFunctions[i].pszName);
501 if (!pfn)
502 {
503 DWORD Err = GetLastError();
504 rc = RTErrConvertFromWin32(Err);
505 AssertMsgFailed(("Failed to resolve %s in dbghelp, Err=%d rc=%Rrc\n",
506 s_aFunctions[i].pszName, Err, rc));
507 break;
508 }
509 *s_aFunctions[i].ppfn = pfn;
510 }
511 if (!rc)
512 {
513 ASMAtomicXchgSize(&g_hDbgHelp, hmod);
514 ASMAtomicXchgU32(&s_u32Lock, 0);
515 return 0;
516 }
517 }
518 else
519 {
520 rc = VERR_VERSION_MISMATCH;
521 AssertMsgFailed(("ImagehlpApiVersion -> %p and MajorVersion=%d.\n", pVersion, pVersion ? pVersion->MajorVersion : 0));
522 }
523 }
524 else
525 {
526 DWORD Err = GetLastError();
527 rc = RTErrConvertFromWin32(Err);
528 AssertMsgFailed(("Failed to resolve ImagehlpApiVersionEx in dbghelp, Err=%d rc=%Rrc\n", Err, rc));
529 }
530 FreeLibrary(hmod);
531 ASMAtomicXchgU32(&s_u32Lock, 0);
532 return rc;
533}
534
535
536/**
537 * Opens the debug info for a PE image using the windows dbghelp library.
538 *
539 * @returns IPRT status code.
540 *
541 * @param File The handle to the module.
542 * @param offHdr The offset of the PE header.
543 * @param pszModulePath The path to the module.
544 * @param ppDbgMod Where to store the module handle.
545 *
546 */
547int kdbgModPEOpen(RTFILE File, int64_t offHdr, const char *pszModulePath, PKDBGMOD *ppDbgMod)
548{
549 /*
550 * We need to read the section headers and get the image size.
551 */
552 IMAGE_FILE_HEADER FHdr;
553 int rc = kDbgHlpReadAt(File, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader), &FHdr, sizeof(FHdr), NULL);
554 AssertRCReturn(rc, rc);
555
556 uint32_t cbImage;
557 if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
558 rc = kDbgHlpReadAt(File, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage),
559 &cbImage, sizeof(cbImage), NULL);
560 else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
561 rc = kDbgHlpReadAt(File, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage),
562 &cbImage, sizeof(cbImage), NULL);
563 else
564 AssertFailedReturn(VERR_BAD_EXE_FORMAT);
565 AssertRCReturn(rc, rc);
566
567 /*
568 * Load dbghelp.dll.
569 */
570 rc = rtDbgModPELoadDbgHelp();
571 if (rc)
572 return rc;
573
574 /*
575 * Allocate the module and read/construct the section headers.
576 */
577 PKDBGMODPE pModPe = (PKDBGMODPE)RTMemAlloc(KDBG_OFFSETOF(KDBGMODPE, aSections[FHdr.NumberOfSections + 2]));
578 AssertReturn(pModPe, KDBG_ERR_NO_MEMORY);
579 pModPe->Core.u32Magic = KDBGMOD_MAGIC;
580 pModPe->Core.pOps = &g_rtDbgModPEOps;
581 pModPe->Core.File = File;
582 pModPe->cbImage = cbImage;
583 pModPe->cSections = 1 + FHdr.NumberOfSections;
584 rc = kDbgHlpReadAt(File, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader,
585 &pModPe->aSections[1], sizeof(pModPe->aSections[0]) * FHdr.NumberOfSections, NULL);
586 if (!rc)
587 {
588 PIMAGE_SECTION_HEADER pSH = &pModPe->aSections[0];
589 memcpy(pSH->Name, "headers", sizeof(pSH->Name));
590 pSH->Misc.VirtualSize = pModPe->aSections[1].VirtualAddress;
591 pSH->VirtualAddress = 0;
592 pSH->SizeOfRawData = pSH->Misc.VirtualSize;
593 pSH->PointerToRawData = 0;
594 pSH->PointerToRelocations = 0;
595 pSH->PointerToLinenumbers = 0;
596 pSH->NumberOfRelocations = 0;
597 pSH->NumberOfLinenumbers = 0;
598 pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ;
599
600 uint32_t uTheEnd = pModPe->aSections[FHdr.NumberOfSections].VirtualAddress
601 + pModPe->aSections[FHdr.NumberOfSections].Misc.VirtualSize;
602 if (uTheEnd < cbImage)
603 {
604 pSH = &pModPe->aSections[pModPe->cSections++];
605 memcpy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name));
606 pSH->Misc.VirtualSize = cbImage - uTheEnd;
607 pSH->VirtualAddress = uTheEnd;
608 pSH->SizeOfRawData = pSH->Misc.VirtualSize;
609 pSH->PointerToRawData = 0;
610 pSH->PointerToRelocations = 0;
611 pSH->PointerToLinenumbers = 0;
612 pSH->NumberOfRelocations = 0;
613 pSH->NumberOfLinenumbers = 0;
614 pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ;
615 }
616
617 /*
618 * Find a new dbghelp handle.
619 *
620 * We assume 4GB of handles outlast most debugging sessions, or in anyways that
621 * when we start reusing handles they are no longer in use. :-)
622 */
623 static volatile uint32_t s_u32LastHandle = 1;
624 HANDLE hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle);
625 while ( hSymInst == INVALID_HANDLE_VALUE
626 || hSymInst == (HANDLE)0
627 || hSymInst == GetCurrentProcess())
628 hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle);
629
630 /*
631 * Initialize dbghelp and try open the specified module.
632 */
633 if (g_pfnSymInitialize(hSymInst, NULL, FALSE))
634 {
635 g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
636
637 RTFileSeek(File, 0, RTFILE_SEEK_BEGIN, NULL); /* don't know if this is required or not... */
638 DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, (HANDLE)File, pszModulePath, NULL, 0x00400000, 0);
639 if (ImageBase)
640 {
641 pModPe->hSymInst = hSymInst;
642 pModPe->ImageBase = ImageBase;
643 *ppDbgMod = &pModPe->Core;
644 return rc;
645 }
646
647 DWORD Err = GetLastError();
648 rc = RTErrConvertFromWin32(Err);
649 AssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%Rrc\n", Err, rc));
650 g_pfnSymCleanup(hSymInst);
651 }
652 else
653 {
654 DWORD Err = GetLastError();
655 rc = RTErrConvertFromWin32(Err);
656 AssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc));
657 }
658 }
659 else
660 AssertRC(rc);
661
662 kDbgHlpFree(pModPe);
663 return rc;
664}
665
Note: See TracBrowser for help on using the repository browser.