source: trunk/kProfile/dbgModPE-win32.cpp@ 3524

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

kProfile Mark II. Some early/old code.

File size: 24.1 KB
Line 
1/* $Id: $ */
2/** @file
3 *
4 * kProfile Mark 2 - Debug Info Reader, DbgHelp Base Reader.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird-src-spam@anduin.net.de>
7 *
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 <iprt/file.h>
36#include <iprt/string.h>
37#include <iprt/alloc.h>
38#include <iprt/assert.h>
39#include <iprt/asm.h>
40#include <iprt/err.h>
41#include <iprt/thread.h>
42#include <iprt/alloca.h>
43#include "DBGInternal.h"
44
45
46//#include "internal/ldrPE.h"
47
48/*******************************************************************************
49* Global Variables *
50*******************************************************************************/
51/** The dbghelp.dll module handle. */
52static HMODULE g_hDbgHelp = NULL;
53/** Pointer to the dbhelp.dll SymInitialize function. */
54static BOOL (WINAPI *g_pfnSymInitialize)(IN HANDLE,IN LPSTR,IN BOOL);
55/** Pointer to the dbhelp.dll SymCleanup function. */
56static BOOL (WINAPI *g_pfnSymCleanup)(IN HANDLE);
57/** Pointer to the dbhelp.dll SymSetOptions function. */
58static DWORD (WINAPI *g_pfnSymSetOptions)(IN DWORD);
59/** Pointer to the dbhelp.dll SymLoadModule64 function. */
60static DWORD64 (WINAPI *g_pfnSymLoadModule64)(IN HANDLE, IN HANDLE, IN PCSTR, IN PCSTR ModuleName, IN DWORD64, IN DWORD);
61/** Pointer to the dbhelp.dll SymFromAddr function. */
62static DWORD (WINAPI *g_pfnSymFromAddr)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PSYMBOL_INFO);
63/** Pointer to the dbhelp.dll SymGetLineFromAddr64 function. */
64static DWORD (WINAPI *g_pfnSymGetLineFromAddr64)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PIMAGEHLP_LINE64);
65
66
67
68/*******************************************************************************
69* Structures and Typedefs *
70*******************************************************************************/
71/**
72 * A dbghelp based PE debug reader.
73 */
74typedef struct RTDBGMODPE
75{
76 /** The common module core. */
77 RTDBGMOD Core;
78 /** The image base. */
79 DWORD64 ImageBase;
80 /** The "process" handle we present dbghelp. */
81 HANDLE hSymInst;
82 /** The image size. */
83 uint32_t cbImage;
84 /** The number of sections. (We've added the implicit header section.) */
85 int32_t cSections;
86 /** The section headers (variable size). The first section is the
87 * implicit header section.*/
88 IMAGE_SECTION_HEADER aSections[1];
89} RTDBGMODPE, *PRTDBGMODPE;
90
91
92/**
93 * Calcs the RVA for a segment:offset address.
94 *
95 * @returns IPRT status code.
96 *
97 * @param pModPe The PE debug module instance.
98 * @param iSegment The segment number. Special segments are dealt with as well.
99 * @param off The segment offset.
100 * @param puRVA Where to store the RVA on success.
101 */
102static int rtDbgModPeSegOffToRVA(PRTDBGMODPE pModPe, int32_t iSegment, RTUINTPTR off, uint32_t *puRVA)
103{
104 if (iSegment >= 0)
105 {
106 AssertMsgReturn(iSegment < pModPe->cSections, ("iSegment=%RX32 cSections=%RX32\n", iSegment, pModPe->cSections),
107 VERR_DBGMOD_INVALID_ADDRESS);
108 AssertMsgReturn(off < pModPe->aSections[iSegment].Misc.VirtualSize,
109 ("off=%RTptr VirtualSize=%RX32\n", off, pModPe->aSections[iSegment].Misc.VirtualSize),
110 VERR_DBGMOD_INVALID_ADDRESS);
111 *puRVA = pModPe->aSections[iSegment].VirtualAddress + off;
112 return VINF_SUCCESS;
113 }
114
115 if (iSegment == RTDBGSEG_RVA)
116 {
117 AssertMsgReturn(off < pModPe->cbImage, ("off=%RTptr, cbImage=%RX32\n", off, pModPe->cbImage),
118 VERR_DBGMOD_INVALID_ADDRESS);
119 *puRVA = off;
120 return VINF_SUCCESS;
121 }
122 AssertMsgFailedReturn(("iSegment=%RI32\n", iSegment), VERR_DBGMOD_INVALID_ADDRESS);
123}
124
125
126/**
127 * Calcs the segment:offset address for a RVA.
128 *
129 * @returns IPRT status code.
130 *
131 * @param pModPe The PE debug module instance.
132 * @param uRVA The RVA.
133 * @param piSegment Where to store the segment number.
134 * @param poff Where to store the segment offset.
135 */
136static int rtDbgModPeRVAToSegOff(PRTDBGMODPE pModPe, uint32_t uRVA, int32_t *piSegment, RTUINTPTR *poff)
137{
138 AssertMsgReturn(uRVA < pModPe->cbImage, ("uRVA=%RX32, cbImage=%RX32\n", uRVA, pModPe->cbImage),
139 VERR_DBGMOD_INVALID_ADDRESS);
140 for (int32_t iSegment = 0; iSegment < pModPe->cSections; iSegment++)
141 {
142 /** @todo should probably be less strict about address in the alignment gaps. */
143 uint32_t off = uRVA - pModPe->aSections[iSegment].VirtualAddress;
144 if (off < pModPe->aSections[iSegment].Misc.VirtualSize)
145 {
146 *poff = off;
147 *piSegment = iSegment;
148 return VINF_SUCCESS;
149 }
150 }
151 AssertMsgFailedReturn(("uRVA=%RX32\n", uRVA), VERR_DBGMOD_INVALID_ADDRESS);
152}
153
154
155/**
156 * @copydoc RTDBGMODOPS::pfnQueryLine
157 */
158static DECLCALLBACK(int) rtDbgModPEQueryLine(PRTDBGMOD pMod, int32_t iSegment, RTUINTPTR off, PRTDBGLINE pLine)
159{
160 PRTDBGMODPE pModPe = (PRTDBGMODPE)pMod;
161
162 /*
163 * Translate the address to an RVA.
164 */
165 uint32_t uRVA;
166 int rc = rtDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA);
167 if (RT_SUCCESS(rc))
168 {
169 DWORD64 off;
170 IMAGEHLP_LINE64 Line;
171 Line.SizeOfStruct = sizeof(Line);
172 if (g_pfnSymGetLineFromAddr64(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Line))
173 {
174 pLine->RVA = (RTUINTPTR)(Line.Address - pModPe->ImageBase);
175 rc = rtDbgModPeRVAToSegOff(pModPe, pLine->RVA, &pLine->iSegment, &pLine->offSegment);
176 pLine->iLine = Line.LineNumber;
177 pLine->cchFile = strlen(Line.FileName);
178 if (pLine->cchFile >= sizeof(pLine->szFile))
179 pLine->cchFile = sizeof(pLine->szFile) - 1;
180 memcpy(pLine->szFile, Line.FileName, pLine->cchFile + 1);
181 }
182 else
183 {
184 DWORD Err = GetLastError();
185 rc = RTErrConvertFromWin32(Err);
186 }
187 }
188 return rc;
189}
190
191
192/**
193 * @copydoc RTDBGMODOPS::pfnQuerySymbol
194 */
195static DECLCALLBACK(int) rtDbgModPEQuerySymbol(PRTDBGMOD pMod, int32_t iSegment, RTUINTPTR off, PRTDBGSYMBOL pSym)
196{
197 PRTDBGMODPE pModPe = (PRTDBGMODPE)pMod;
198
199 /*
200 * Translate the address to an RVA.
201 */
202 uint32_t uRVA;
203 int rc = rtDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA);
204 if (RT_SUCCESS(rc))
205 {
206 DWORD64 off;
207 union
208 {
209 SYMBOL_INFO Sym;
210 char achBuffer[sizeof(SYMBOL_INFO) + RTDBG_SYMBOL_MAX];
211 } Buf;
212 Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO);
213 Buf.Sym.MaxNameLen = RTDBG_SYMBOL_MAX;
214 if (g_pfnSymFromAddr(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Buf.Sym))
215 {
216 pSym->cb = Buf.Sym.Size;
217 pSym->fFlags = 0;
218 if (Buf.Sym.Flags & SYMFLAG_FUNCTION)
219 pSym->fFlags |= RTDBGSYM_FLAGS_CODE;
220 else if (Buf.Sym.Flags & SYMFLAG_CONSTANT)
221 pSym->fFlags |= RTDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/
222 else
223 pSym->fFlags |= RTDBGSYM_FLAGS_DATA;
224 if (Buf.Sym.Flags & SYMFLAG_EXPORT)
225 pSym->fFlags |= RTDBGSYM_FLAGS_EXPORTED;
226 if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT))
227 {
228 pSym->iSegment = RTDBGSEG_ABS;
229 pSym->offSegment = (RTUINTPTR)Buf.Sym.Value;
230 pSym->RVA = (RTUINTPTR)Buf.Sym.Value;
231 }
232 else
233 {
234 pSym->RVA = (RTUINTPTR)(Buf.Sym.Address - pModPe->ImageBase);
235 rc = rtDbgModPeRVAToSegOff(pModPe, pSym->RVA, &pSym->iSegment, &pSym->offSegment);
236 }
237 pSym->cchName = (uint16_t)Buf.Sym.NameLen;
238 if (pSym->cchName >= sizeof(pSym->szName))
239 pSym->cchName = sizeof(pSym->szName) - 1;
240 memcpy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen);
241 pSym->szName[Buf.Sym.NameLen] = '\0';
242 }
243 else
244 {
245 DWORD Err = GetLastError();
246 rc = RTErrConvertFromWin32(Err);
247 }
248 }
249 return rc;
250}
251
252
253/**
254 * @copydoc RTDBGMODOPS::pfnClose
255 */
256static DECLCALLBACK(int) rtDbgModPEClose(PRTDBGMOD pMod)
257{
258 PRTDBGMODPE pModPe = (PRTDBGMODPE)pMod;
259
260 if (g_pfnSymCleanup(pModPe->hSymInst))
261 return VINF_SUCCESS;
262
263 DWORD Err = GetLastError();
264 int rc = RTErrConvertFromWin32(Err);
265 AssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc));
266 return rc;
267}
268
269
270/**
271 * Methods for a PE module.
272 */
273static const RTDBGMODOPS g_rtDbgModPEOps =
274{
275 "PE (dbghelp)",
276 rtDbgModPEClose,
277 rtDbgModPEQuerySymbol,
278 rtDbgModPEQueryLine
279};
280
281
282/**
283 * Checks if the specified dbghelp.dll is usable.
284 *
285 * @returns IPRT status code.
286 *
287 * @param pszPath the path to the dbghelp.dll.
288 */
289static int rtDbgModPETryDbgHelp(const char *pszPath, uint32_t *pu32FileVersionMS, uint32_t *pu32FileVersionLS)
290{
291 int rc;
292 DWORD dwHandle = 0;
293 DWORD cb = GetFileVersionInfoSize(pszPath, &dwHandle);
294 if (cb > 0)
295 {
296 void *pvBuf = alloca(cb);
297 if (GetFileVersionInfo(pszPath, dwHandle, cb, pvBuf))
298 {
299 UINT cbValue = 0;
300 VS_FIXEDFILEINFO *pFileInfo;
301 if (VerQueryValue(pvBuf, "\\", (void **)&pFileInfo, &cbValue))
302 {
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 = VINF_SUCCESS;
312 else
313 rc = VERR_VERSION_MISMATCH;
314 }
315 else
316 rc = VERR_GENERAL_FAILURE;
317 }
318 else
319 rc = RTErrConvertFromWin32(GetLastError());
320 }
321 else
322 rc = RTErrConvertFromWin32(GetLastError());
323 return rc;
324}
325
326
327/**
328 * Find the dbghelp.dll
329 */
330static int rtDbgModPEFindDbgHelp(char *pszPath, size_t cchPath)
331{
332 /*
333 * Try the current directory.
334 */
335 uint32_t FileVersionMS = 0;
336 uint32_t FileVersionLS = 0;
337 int rc = VERR_GENERAL_FAILURE;
338 static char s_szDbgHelp[] = "\\dbghelp.dll";
339 if (GetCurrentDirectory(cchPath - sizeof(s_szDbgHelp) + 1, pszPath))
340 {
341 strcat(pszPath, s_szDbgHelp);
342 int rc2 = rtDbgModPETryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
343 if (RT_SUCCESS(rc2))
344 return rc2;
345 if (rc != VERR_VERSION_MISMATCH)
346 rc = rc2;
347 }
348
349 /*
350 * Try the application directory.
351 */
352 if (GetModuleFileName(NULL, pszPath, cchPath - sizeof(s_szDbgHelp) + 1))
353 {
354 strcat(strrchr(pszPath, '\\'), s_szDbgHelp);
355 int rc2 = rtDbgModPETryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
356 if (RT_SUCCESS(rc))
357 return rc2;
358 if (rc != VERR_VERSION_MISMATCH)
359 rc = rc2;
360 }
361
362 /*
363 * Try the windows directory.
364 */
365 if (GetSystemDirectory(pszPath, cchPath - sizeof(s_szDbgHelp) + 1))
366 {
367 strcat(pszPath, s_szDbgHelp);
368 int rc2 = rtDbgModPETryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
369 if (RT_SUCCESS(rc2))
370 return rc2;
371 if (rc != VERR_VERSION_MISMATCH)
372 rc = rc2;
373 }
374
375 /*
376 * Try the windows directory.
377 */
378 if (GetWindowsDirectory(pszPath, cchPath - sizeof(s_szDbgHelp) + 1))
379 {
380 strcat(pszPath, s_szDbgHelp);
381 int rc2 = rtDbgModPETryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
382 if (RT_SUCCESS(rc2))
383 return rc2;
384 if (rc != VERR_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 = strchr(psz, ';');
401 if (!pszEnd)
402 pszEnd = strchr(psz, '\0');
403 if (pszEnd != psz)
404 {
405 /* construct filename and try it out */
406 memcpy(pszPath, psz, pszEnd - psz);
407 memcpy(&pszPath[pszEnd - psz], s_szDbgHelp, sizeof(s_szDbgHelp));
408 int rc2 = rtDbgModPETryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
409 if (RT_SUCCESS(rc2))
410 return rc2;
411 if (rc != VERR_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 == VERR_VERSION_MISMATCH)
423 AssertMsgFailed(("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 AssertMsgFailed(("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 rtDbgModPELoadDbgHelp(void)
441{
442 if (g_hDbgHelp)
443 return VINF_SUCCESS;
444
445 /* primitive locking - make some useful API for this kind of spinning! */
446 static volatile uint32_t s_u32Lock = 0;
447 while (!ASMAtomicCmpXchgU32(&s_u32Lock, 1, 0))
448 while (s_u32Lock)
449 RTThreadYield();
450 if (g_hDbgHelp)
451 {
452 ASMAtomicXchgU32(&s_u32Lock, 0);
453 return VINF_SUCCESS;
454 }
455
456 /*
457 * Load it - try current dir first.
458 */
459 char szPath[260];
460 int rc = rtDbgModPEFindDbgHelp(szPath, sizeof(szPath));
461 if (RT_FAILURE(rc))
462 {
463 ASMAtomicXchgU32(&s_u32Lock, 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 = RTErrConvertFromWin32(Err);
472 AssertMsgFailedReturn(("Failed to load '%s', Err=%d rc=%Rrc\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 < ELEMENTS(s_aFunctions); i++)
509 {
510 FARPROC pfn = GetProcAddress(hmod, s_aFunctions[i].pszName);
511 if (!pfn)
512 {
513 DWORD Err = GetLastError();
514 rc = RTErrConvertFromWin32(Err);
515 AssertMsgFailed(("Failed to resolve %s in dbghelp, Err=%d rc=%Rrc\n",
516 s_aFunctions[i].pszName, Err, rc));
517 break;
518 }
519 *s_aFunctions[i].ppfn = pfn;
520 }
521 if (RT_SUCCESS(rc))
522 {
523 ASMAtomicXchgSize(&g_hDbgHelp, hmod);
524 ASMAtomicXchgU32(&s_u32Lock, 0);
525 return VINF_SUCCESS;
526 }
527 }
528 else
529 {
530 rc = VERR_VERSION_MISMATCH;
531 AssertMsgFailed(("ImagehlpApiVersion -> %p and MajorVersion=%d.\n", pVersion, pVersion ? pVersion->MajorVersion : 0));
532 }
533 }
534 else
535 {
536 DWORD Err = GetLastError();
537 rc = RTErrConvertFromWin32(Err);
538 AssertMsgFailed(("Failed to resolve ImagehlpApiVersionEx in dbghelp, Err=%d rc=%Rrc\n", Err, rc));
539 }
540 FreeLibrary(hmod);
541 ASMAtomicXchgU32(&s_u32Lock, 0);
542 return rc;
543}
544
545
546/**
547 * Opens the debug info for a PE image using the windows dbghelp library.
548 *
549 * @returns IPRT status code.
550 *
551 * @param File The handle to the module.
552 * @param offHdr The offset of the PE header.
553 * @param pszModulePath The path to the module.
554 * @param ppDbgMod Where to store the module handle.
555 *
556 */
557int rtDbgModPEOpen(RTFILE File, RTFOFF offHdr, const char *pszModulePath, PRTDBGMOD *ppDbgMod)
558{
559 /*
560 * We need to read the section headers and get the image size.
561 */
562 IMAGE_FILE_HEADER FHdr;
563 int rc = RTFileReadAt(File, offHdr + OFFSETOF(IMAGE_NT_HEADERS32, FileHeader), &FHdr, sizeof(FHdr), NULL);
564 AssertRCReturn(rc, rc);
565
566 uint32_t cbImage;
567 if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
568 rc = RTFileReadAt(File, offHdr + OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage),
569 &cbImage, sizeof(cbImage), NULL);
570 else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
571 rc = RTFileReadAt(File, offHdr + OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage),
572 &cbImage, sizeof(cbImage), NULL);
573 else
574 AssertFailedReturn(VERR_BAD_EXE_FORMAT);
575 AssertRCReturn(rc, rc);
576
577 /*
578 * Load dbghelp.dll.
579 */
580 rc = rtDbgModPELoadDbgHelp();
581 if (RT_FAILURE(rc))
582 return rc;
583
584 /*
585 * Allocate the module and read/construct the section headers.
586 */
587 PRTDBGMODPE pModPe = (PRTDBGMODPE)RTMemAlloc(OFFSETOF(RTDBGMODPE, aSections[FHdr.NumberOfSections + 2]));
588 AssertReturn(pModPe, VERR_NO_MEMORY);
589 pModPe->Core.u32Magic = RTDBGMOD_MAGIC;
590 pModPe->Core.pOps = &g_rtDbgModPEOps;
591 pModPe->Core.File = File;
592 pModPe->cbImage = cbImage;
593 pModPe->cSections = 1 + FHdr.NumberOfSections;
594 rc = RTFileReadAt(File, offHdr + OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader,
595 &pModPe->aSections[1], sizeof(pModPe->aSections[0]) * FHdr.NumberOfSections, NULL);
596 if (RT_SUCCESS(rc))
597 {
598 PIMAGE_SECTION_HEADER pSH = &pModPe->aSections[0];
599 memcpy(pSH->Name, "headers", sizeof(pSH->Name));
600 pSH->Misc.VirtualSize = pModPe->aSections[1].VirtualAddress;
601 pSH->VirtualAddress = 0;
602 pSH->SizeOfRawData = pSH->Misc.VirtualSize;
603 pSH->PointerToRawData = 0;
604 pSH->PointerToRelocations = 0;
605 pSH->PointerToLinenumbers = 0;
606 pSH->NumberOfRelocations = 0;
607 pSH->NumberOfLinenumbers = 0;
608 pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ;
609
610 uint32_t uTheEnd = pModPe->aSections[FHdr.NumberOfSections].VirtualAddress
611 + pModPe->aSections[FHdr.NumberOfSections].Misc.VirtualSize;
612 if (uTheEnd < cbImage)
613 {
614 pSH = &pModPe->aSections[pModPe->cSections++];
615 memcpy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name));
616 pSH->Misc.VirtualSize = cbImage - uTheEnd;
617 pSH->VirtualAddress = uTheEnd;
618 pSH->SizeOfRawData = pSH->Misc.VirtualSize;
619 pSH->PointerToRawData = 0;
620 pSH->PointerToRelocations = 0;
621 pSH->PointerToLinenumbers = 0;
622 pSH->NumberOfRelocations = 0;
623 pSH->NumberOfLinenumbers = 0;
624 pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ;
625 }
626
627 /*
628 * Find a new dbghelp handle.
629 *
630 * We assume 4GB of handles outlast most debugging sessions, or in anyways that
631 * when we start reusing handles they are no longer in use. :-)
632 */
633 static volatile uint32_t s_u32LastHandle = 1;
634 HANDLE hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle);
635 while ( hSymInst == INVALID_HANDLE_VALUE
636 || hSymInst == (HANDLE)0
637 || hSymInst == GetCurrentProcess())
638 hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle);
639
640 /*
641 * Initialize dbghelp and try open the specified module.
642 */
643 if (g_pfnSymInitialize(hSymInst, NULL, FALSE))
644 {
645 g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
646
647 RTFileSeek(File, 0, RTFILE_SEEK_BEGIN, NULL); /* don't know if this is required or not... */
648 DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, (HANDLE)File, pszModulePath, NULL, 0x00400000, 0);
649 if (ImageBase)
650 {
651 pModPe->hSymInst = hSymInst;
652 pModPe->ImageBase = ImageBase;
653 *ppDbgMod = &pModPe->Core;
654 return rc;
655 }
656
657 DWORD Err = GetLastError();
658 rc = RTErrConvertFromWin32(Err);
659 AssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%Rrc\n", Err, rc));
660 g_pfnSymCleanup(hSymInst);
661 }
662 else
663 {
664 DWORD Err = GetLastError();
665 rc = RTErrConvertFromWin32(Err);
666 AssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc));
667 }
668 }
669 else
670 AssertRC(rc);
671
672 RTMemFree(pModPe);
673 return rc;
674}
675
Note: See TracBrowser for help on using the repository browser.