VirtualBox

source: kStuff/trunk/kDbg/kDbgModPE.cpp

Last change on this file was 29, checked in by bird, 15 years ago

Finally got around execute the switch to the MIT license.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.7 KB
Line 
1/* $Id: kDbgModPE.cpp 29 2009-07-01 20:30:29Z bird $ */
2/** @file
3 * kDbg - The Debug Info Reader, PE Module (Generic).
4 */
5
6/*
7 * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include "kDbg.h"
35#include "kDbgInternal.h"
36#include <kLdrModPE.h>
37#include <string.h>
38
39
40/*******************************************************************************
41* Structures and Typedefs *
42*******************************************************************************/
43/**
44 * A dbghelp based PE debug reader.
45 */
46typedef struct KDBGMODPE
47{
48 /** The common module core. */
49 KDBGMOD Core;
50 /** The image size. */
51 uint32_t cbImage;
52 /** The number of sections. (We've added the implicit header section.) */
53 int32_t cSections;
54 /** The section headers (variable size). The first section is the
55 * implicit header section.*/
56 IMAGE_SECTION_HEADER aSections[1];
57} KDBGMODPE, *PKDBGMODPE;
58
59
60/**
61 * Calcs the RVA for a segment:offset address.
62 *
63 * @returns IPRT status code.
64 *
65 * @param pModPe The PE debug module instance.
66 * @param iSegment The segment number. Special segments are dealt with as well.
67 * @param off The segment offset.
68 * @param puRVA Where to store the RVA on success.
69 */
70static int kDbgModPeSegOffToRVA(PKDBGMODPE pModPe, int32_t iSegment, KDBGADDR off, uint32_t *puRVA)
71{
72 if (iSegment >= 0)
73 {
74 kDbgAssertMsgReturn(iSegment < pModPe->cSections, ("iSegment=%x cSections=%x\n", iSegment, pModPe->cSections),
75 KDBG_ERR_INVALID_ADDRESS);
76 kDbgAssertMsgReturn(off < pModPe->aSections[iSegment].Misc.VirtualSize,
77 ("off=" PRI_KDBGADDR " VirtualSize=%x\n", off, pModPe->aSections[iSegment].Misc.VirtualSize),
78 KDBG_ERR_INVALID_ADDRESS);
79 *puRVA = pModPe->aSections[iSegment].VirtualAddress + (uint32_t)off;
80 return 0;
81 }
82
83 if (iSegment == KDBGSEG_RVA)
84 {
85 kDbgAssertMsgReturn(off < pModPe->cbImage, ("off=" PRI_KDBGADDR ", cbImage=%x\n", off, pModPe->cbImage),
86 KDBG_ERR_INVALID_ADDRESS);
87 *puRVA = (uint32_t)off;
88 return 0;
89 }
90 kDbgAssertMsgFailedReturn(("iSegment=%d\n", iSegment), KDBG_ERR_INVALID_ADDRESS);
91}
92
93
94/**
95 * Calcs the segment:offset address for a RVA.
96 *
97 * @returns IPRT status code.
98 *
99 * @param pModPe The PE debug module instance.
100 * @param uRVA The RVA.
101 * @param piSegment Where to store the segment number.
102 * @param poff Where to store the segment offset.
103 */
104static int kDbgModPeRVAToSegOff(PKDBGMODPE pModPe, uint32_t uRVA, int32_t *piSegment, KDBGADDR *poff)
105{
106 kDbgAssertMsgReturn(uRVA < pModPe->cbImage, ("uRVA=%x, cbImage=%x\n", uRVA, pModPe->cbImage),
107 KDBG_ERR_INVALID_ADDRESS);
108 for (int32_t iSegment = 0; iSegment < pModPe->cSections; iSegment++)
109 {
110 /** @todo should probably be less strict about address in the alignment gaps. */
111 uint32_t off = uRVA - pModPe->aSections[iSegment].VirtualAddress;
112 if (off < pModPe->aSections[iSegment].Misc.VirtualSize)
113 {
114 *poff = off;
115 *piSegment = iSegment;
116 return 0;
117 }
118 }
119 kDbgAssertMsgFailedReturn(("uRVA=%x\n", uRVA), KDBG_ERR_INVALID_ADDRESS);
120}
121
122
123/**
124 * @copydoc KDBGMODOPS::pfnQueryLine
125 */
126static int kDbgModPeQueryLine(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGLINE pLine)
127{
128 PKDBGMODPE pModPe = (PKDBGMODPE)pMod;
129
130 /*
131 * Translate the address to an RVA.
132 */
133 uint32_t uRVA;
134 int rc = kDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA);
135 if (!rc)
136 {
137#if 0
138 DWORD64 off;
139 IMAGEHLP_LINE64 Line;
140 Line.SizeOfStruct = sizeof(Line);
141 if (g_pfnSymGetLineFromAddr64(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Line))
142 {
143 pLine->RVA = (KDBGADDR)(Line.Address - pModPe->ImageBase);
144 rc = kDbgModPeRVAToSegOff(pModPe, pLine->RVA, &pLine->iSegment, &pLine->offSegment);
145 pLine->iLine = Line.LineNumber;
146 pLine->cchFile = strlen(Line.FileName);
147 if (pLine->cchFile >= sizeof(pLine->szFile))
148 pLine->cchFile = sizeof(pLine->szFile) - 1;
149 memcpy(pLine->szFile, Line.FileName, pLine->cchFile + 1);
150 }
151 else
152 {
153 DWORD Err = GetLastError();
154 rc = kDbgModPeConvWinError(Err);
155 }
156#endif
157 rc = KERR_NOT_IMPLEMENTED;
158 }
159 return rc;
160}
161
162
163/**
164 * @copydoc KDBGMODOPS::pfnQuerySymbol
165 */
166static int kDbgModPeQuerySymbol(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGSYMBOL pSym)
167{
168 PKDBGMODPE pModPe = (PKDBGMODPE)pMod;
169
170 /*
171 * Translate the address to an RVA.
172 */
173 uint32_t uRVA;
174 int rc = kDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA);
175 if (!rc)
176 {
177#if 0
178 DWORD64 off;
179 union
180 {
181 SYMBOL_INFO Sym;
182 char achBuffer[sizeof(SYMBOL_INFO) + KDBG_SYMBOL_MAX];
183 } Buf;
184 Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO);
185 Buf.Sym.MaxNameLen = KDBG_SYMBOL_MAX;
186 if (g_pfnSymFromAddr(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Buf.Sym))
187 {
188 pSym->cb = Buf.Sym.Size;
189 pSym->fFlags = 0;
190 if (Buf.Sym.Flags & SYMFLAG_FUNCTION)
191 pSym->fFlags |= KDBGSYM_FLAGS_CODE;
192 else if (Buf.Sym.Flags & SYMFLAG_CONSTANT)
193 pSym->fFlags |= KDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/
194 else
195 pSym->fFlags |= KDBGSYM_FLAGS_DATA;
196 if (Buf.Sym.Flags & SYMFLAG_EXPORT)
197 pSym->fFlags |= KDBGSYM_FLAGS_EXPORTED;
198 if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT))
199 {
200 pSym->iSegment = KDBGSEG_ABS;
201 pSym->offSegment = (KDBGADDR)Buf.Sym.Value;
202 pSym->RVA = (KDBGADDR)Buf.Sym.Value;
203 }
204 else
205 {
206 pSym->RVA = (KDBGADDR)(Buf.Sym.Address - pModPe->ImageBase);
207 rc = kDbgModPeRVAToSegOff(pModPe, pSym->RVA, &pSym->iSegment, &pSym->offSegment);
208 }
209 pSym->cchName = (uint16_t)Buf.Sym.NameLen;
210 if (pSym->cchName >= sizeof(pSym->szName))
211 pSym->cchName = sizeof(pSym->szName) - 1;
212 memcpy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen);
213 pSym->szName[Buf.Sym.NameLen] = '\0';
214 }
215 else
216 {
217 DWORD Err = GetLastError();
218 rc = kDbgModPeConvWinError(Err);
219 }
220#endif
221 rc = KERR_NOT_IMPLEMENTED;
222 }
223 return rc;
224}
225
226
227/**
228 * @copydoc KDBGMODOPS::pfnClose
229 */
230static int kDbgModPeClose(PKDBGMOD pMod)
231{
232 PKDBGMODPE pModPe = (PKDBGMODPE)pMod;
233
234 //if (g_pfnSymCleanup(pModPe->hSymInst))
235 // return 0;
236 //
237 //DWORD Err = GetLastError();
238 //int rc = kDbgModPeConvWinError(Err);
239 //kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc));
240 //return rc;
241 return KERR_NOT_IMPLEMENTED;
242}
243
244
245/**
246 * Opens the debug info for a PE image using the windows dbghelp library.
247 *
248 * @returns IPRT status code.
249 *
250 * @param pFile The handle to the module.
251 * @param offHdr The offset of the PE header.
252 * @param pszModulePath The path to the module.
253 * @param ppDbgMod Where to store the module handle.
254 *
255 */
256int kdbgModPEOpen(PKDBGHLPFILE pFile, int64_t offHdr, const char *pszModulePath, PKDBGMOD *ppDbgMod)
257{
258 /*
259 * We need to read the section headers and get the image size.
260 */
261 IMAGE_FILE_HEADER FHdr;
262 int rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader), &FHdr, sizeof(FHdr));
263 kDbgAssertRCReturn(rc, rc);
264
265 uint32_t cbImage;
266 if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
267 rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage),
268 &cbImage, sizeof(cbImage));
269 else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
270 rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage),
271 &cbImage, sizeof(cbImage));
272 else
273 kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT);
274 kDbgAssertRCReturn(rc, rc);
275
276 /*
277 * Allocate the module and read/construct the section headers.
278 */
279 PKDBGMODPE pModPe = (PKDBGMODPE)kDbgHlpAlloc(KDBG_OFFSETOF(KDBGMODPE, aSections[FHdr.NumberOfSections + 2]));
280 kDbgAssertReturn(pModPe, KERR_NO_MEMORY);
281 pModPe->Core.u32Magic = KDBGMOD_MAGIC;
282 pModPe->Core.pOps = &g_kDbgModPeOps;
283 pModPe->Core.pFile = pFile;
284 pModPe->cbImage = cbImage;
285 pModPe->cSections = 1 + FHdr.NumberOfSections;
286 rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader,
287 &pModPe->aSections[1], sizeof(pModPe->aSections[0]) * FHdr.NumberOfSections);
288 if (!rc)
289 {
290 PIMAGE_SECTION_HEADER pSH = &pModPe->aSections[0];
291 memcpy(pSH->Name, "headers", sizeof(pSH->Name));
292 pSH->Misc.VirtualSize = pModPe->aSections[1].VirtualAddress;
293 pSH->VirtualAddress = 0;
294 pSH->SizeOfRawData = pSH->Misc.VirtualSize;
295 pSH->PointerToRawData = 0;
296 pSH->PointerToRelocations = 0;
297 pSH->PointerToLinenumbers = 0;
298 pSH->NumberOfRelocations = 0;
299 pSH->NumberOfLinenumbers = 0;
300 pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ;
301
302 uint32_t uTheEnd = pModPe->aSections[FHdr.NumberOfSections].VirtualAddress
303 + pModPe->aSections[FHdr.NumberOfSections].Misc.VirtualSize;
304 if (uTheEnd < cbImage)
305 {
306 pSH = &pModPe->aSections[pModPe->cSections++];
307 memcpy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name));
308 pSH->Misc.VirtualSize = cbImage - uTheEnd;
309 pSH->VirtualAddress = uTheEnd;
310 pSH->SizeOfRawData = pSH->Misc.VirtualSize;
311 pSH->PointerToRawData = 0;
312 pSH->PointerToRelocations = 0;
313 pSH->PointerToLinenumbers = 0;
314 pSH->NumberOfRelocations = 0;
315 pSH->NumberOfLinenumbers = 0;
316 pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ;
317 }
318
319#if 0
320 /*
321 * Find a new dbghelp handle.
322 *
323 * We assume 4GB of handles outlast most debugging sessions, or in anyways that
324 * when we start reusing handles they are no longer in use. :-)
325 */
326 static volatile uint32_t s_u32LastHandle = 1;
327 HANDLE hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle);
328 while ( hSymInst == INVALID_HANDLE_VALUE
329 || hSymInst == (HANDLE)0
330 || hSymInst == GetCurrentProcess())
331 hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle);
332
333 /*
334 * Initialize dbghelp and try open the specified module.
335 */
336 if (g_pfnSymInitialize(hSymInst, NULL, FALSE))
337 {
338 g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
339
340 kDbgHlpSeek(pFile, 0); /* don't know if this is required or not... */
341 DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, (HANDLE)File, pszModulePath, NULL, 0x00400000, 0);
342 if (ImageBase)
343 {
344 pModPe->hSymInst = hSymInst;
345 pModPe->ImageBase = ImageBase;
346 *ppDbgMod = &pModPe->Core;
347 return rc;
348 }
349
350 DWORD Err = GetLastError();
351 rc = kDbgModPeConvWinError(Err);
352 kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%Rrc\n", Err, rc));
353 g_pfnSymCleanup(hSymInst);
354 }
355 else
356 {
357 DWORD Err = GetLastError();
358 rc = kDbgModPeConvWinError(Err);
359 kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc));
360 }
361#endif
362 rc = KERR_NOT_IMPLEMENTED;
363 }
364 else
365 kDbgAssertRC(rc);
366
367 kDbgHlpFree(pModPe);
368 return rc;
369}
370
371
372/**
373 * Methods for a PE module.
374 */
375const KDBGMODOPS g_kDbgModPeOps =
376{
377 "PE",
378 kDbgModPeClose,
379 kDbgModPeQuerySymbol,
380 kDbgModPeQueryLine
381};
382
383
384
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette