source: trunk/kProfile/dbgModPE-win.cpp@ 3526

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

made it build again.

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