VirtualBox

source: kStuff/trunk/kDbg/kDbgModPE.cpp@ 2

Last change on this file since 2 was 2, checked in by bird, 17 years ago

Imported http://svn.netlabs.org/repos/libc/trunk/kStuff, revision 3612.

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