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

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

Moved k* into kStuff.

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