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

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

made it build again.

File size: 14.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 <iprt/file.h>
32#include <iprt/string.h>
33#include <iprt/alloc.h>
34#include <iprt/assert.h>
35#include <iprt/asm.h>
36#include <iprt/err.h>
37#include <iprt/thread.h>
38#include <iprt/alloca.h>
39#include "kDbgBase.h"
40#include "DBGInternal.h"
41#include "kLdrModPE.h"
42
43
44
45/*******************************************************************************
46* Structures and Typedefs *
47*******************************************************************************/
48/**
49 * A dbghelp based PE debug reader.
50 */
51typedef struct RTDBGMODPE
52{
53 /** The common module core. */
54 RTDBGMOD Core;
55 /** The image size. */
56 uint32_t cbImage;
57 /** The number of sections. (We've added the implicit header section.) */
58 int32_t cSections;
59 /** The section headers (variable size). The first section is the
60 * implicit header section.*/
61 IMAGE_SECTION_HEADER aSections[1];
62} RTDBGMODPE, *PRTDBGMODPE;
63
64
65/**
66 * Calcs the RVA for a segment:offset address.
67 *
68 * @returns IPRT status code.
69 *
70 * @param pModPe The PE debug module instance.
71 * @param iSegment The segment number. Special segments are dealt with as well.
72 * @param off The segment offset.
73 * @param puRVA Where to store the RVA on success.
74 */
75static int rtDbgModPeSegOffToRVA(PRTDBGMODPE pModPe, int32_t iSegment, RTUINTPTR off, uint32_t *puRVA)
76{
77 if (iSegment >= 0)
78 {
79 AssertMsgReturn(iSegment < pModPe->cSections, ("iSegment=%RX32 cSections=%RX32\n", iSegment, pModPe->cSections),
80 VERR_DBGMOD_INVALID_ADDRESS);
81 AssertMsgReturn(off < pModPe->aSections[iSegment].Misc.VirtualSize,
82 ("off=%RTptr VirtualSize=%RX32\n", off, pModPe->aSections[iSegment].Misc.VirtualSize),
83 VERR_DBGMOD_INVALID_ADDRESS);
84 *puRVA = pModPe->aSections[iSegment].VirtualAddress + off;
85 return VINF_SUCCESS;
86 }
87
88 if (iSegment == RTDBGSEG_RVA)
89 {
90 AssertMsgReturn(off < pModPe->cbImage, ("off=%RTptr, cbImage=%RX32\n", off, pModPe->cbImage),
91 VERR_DBGMOD_INVALID_ADDRESS);
92 *puRVA = off;
93 return VINF_SUCCESS;
94 }
95 AssertMsgFailedReturn(("iSegment=%RI32\n", iSegment), VERR_DBGMOD_INVALID_ADDRESS);
96}
97
98
99/**
100 * Calcs the segment:offset address for a RVA.
101 *
102 * @returns IPRT status code.
103 *
104 * @param pModPe The PE debug module instance.
105 * @param uRVA The RVA.
106 * @param piSegment Where to store the segment number.
107 * @param poff Where to store the segment offset.
108 */
109static int rtDbgModPeRVAToSegOff(PRTDBGMODPE pModPe, uint32_t uRVA, int32_t *piSegment, RTUINTPTR *poff)
110{
111 AssertMsgReturn(uRVA < pModPe->cbImage, ("uRVA=%RX32, cbImage=%RX32\n", uRVA, pModPe->cbImage),
112 VERR_DBGMOD_INVALID_ADDRESS);
113 for (int32_t iSegment = 0; iSegment < pModPe->cSections; iSegment++)
114 {
115 /** @todo should probably be less strict about address in the alignment gaps. */
116 uint32_t off = uRVA - pModPe->aSections[iSegment].VirtualAddress;
117 if (off < pModPe->aSections[iSegment].Misc.VirtualSize)
118 {
119 *poff = off;
120 *piSegment = iSegment;
121 return VINF_SUCCESS;
122 }
123 }
124 AssertMsgFailedReturn(("uRVA=%RX32\n", uRVA), VERR_DBGMOD_INVALID_ADDRESS);
125}
126
127
128/**
129 * @copydoc RTDBGMODOPS::pfnQueryLine
130 */
131static DECLCALLBACK(int) rtDbgModPEQueryLine(PRTDBGMOD pMod, int32_t iSegment, RTUINTPTR off, PRTDBGLINE pLine)
132{
133 PRTDBGMODPE pModPe = (PRTDBGMODPE)pMod;
134
135 /*
136 * Translate the address to an RVA.
137 */
138 uint32_t uRVA;
139 int rc = rtDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA);
140 if (RT_SUCCESS(rc))
141 {
142#if 0
143 DWORD64 off;
144 IMAGEHLP_LINE64 Line;
145 Line.SizeOfStruct = sizeof(Line);
146 if (g_pfnSymGetLineFromAddr64(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Line))
147 {
148 pLine->RVA = (RTUINTPTR)(Line.Address - pModPe->ImageBase);
149 rc = rtDbgModPeRVAToSegOff(pModPe, pLine->RVA, &pLine->iSegment, &pLine->offSegment);
150 pLine->iLine = Line.LineNumber;
151 pLine->cchFile = strlen(Line.FileName);
152 if (pLine->cchFile >= sizeof(pLine->szFile))
153 pLine->cchFile = sizeof(pLine->szFile) - 1;
154 memcpy(pLine->szFile, Line.FileName, pLine->cchFile + 1);
155 }
156 else
157 {
158 DWORD Err = GetLastError();
159 rc = RTErrConvertFromWin32(Err);
160 }
161#endif
162 rc = VERR_NOT_IMPLEMENTED;
163 }
164 return rc;
165}
166
167
168/**
169 * @copydoc RTDBGMODOPS::pfnQuerySymbol
170 */
171static DECLCALLBACK(int) rtDbgModPEQuerySymbol(PRTDBGMOD pMod, int32_t iSegment, RTUINTPTR off, PRTDBGSYMBOL pSym)
172{
173 PRTDBGMODPE pModPe = (PRTDBGMODPE)pMod;
174
175 /*
176 * Translate the address to an RVA.
177 */
178 uint32_t uRVA;
179 int rc = rtDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA);
180 if (RT_SUCCESS(rc))
181 {
182#if 0
183 DWORD64 off;
184 union
185 {
186 SYMBOL_INFO Sym;
187 char achBuffer[sizeof(SYMBOL_INFO) + RTDBG_SYMBOL_MAX];
188 } Buf;
189 Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO);
190 Buf.Sym.MaxNameLen = RTDBG_SYMBOL_MAX;
191 if (g_pfnSymFromAddr(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Buf.Sym))
192 {
193 pSym->cb = Buf.Sym.Size;
194 pSym->fFlags = 0;
195 if (Buf.Sym.Flags & SYMFLAG_FUNCTION)
196 pSym->fFlags |= RTDBGSYM_FLAGS_CODE;
197 else if (Buf.Sym.Flags & SYMFLAG_CONSTANT)
198 pSym->fFlags |= RTDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/
199 else
200 pSym->fFlags |= RTDBGSYM_FLAGS_DATA;
201 if (Buf.Sym.Flags & SYMFLAG_EXPORT)
202 pSym->fFlags |= RTDBGSYM_FLAGS_EXPORTED;
203 if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT))
204 {
205 pSym->iSegment = RTDBGSEG_ABS;
206 pSym->offSegment = (RTUINTPTR)Buf.Sym.Value;
207 pSym->RVA = (RTUINTPTR)Buf.Sym.Value;
208 }
209 else
210 {
211 pSym->RVA = (RTUINTPTR)(Buf.Sym.Address - pModPe->ImageBase);
212 rc = rtDbgModPeRVAToSegOff(pModPe, pSym->RVA, &pSym->iSegment, &pSym->offSegment);
213 }
214 pSym->cchName = (uint16_t)Buf.Sym.NameLen;
215 if (pSym->cchName >= sizeof(pSym->szName))
216 pSym->cchName = sizeof(pSym->szName) - 1;
217 memcpy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen);
218 pSym->szName[Buf.Sym.NameLen] = '\0';
219 }
220 else
221 {
222 DWORD Err = GetLastError();
223 rc = RTErrConvertFromWin32(Err);
224 }
225#endif
226 rc = VERR_NOT_IMPLEMENTED;
227 }
228 return rc;
229}
230
231
232/**
233 * @copydoc RTDBGMODOPS::pfnClose
234 */
235static DECLCALLBACK(int) rtDbgModPEClose(PRTDBGMOD pMod)
236{
237 PRTDBGMODPE pModPe = (PRTDBGMODPE)pMod;
238
239 //if (g_pfnSymCleanup(pModPe->hSymInst))
240 // return VINF_SUCCESS;
241 //
242 //DWORD Err = GetLastError();
243 //int rc = RTErrConvertFromWin32(Err);
244 //AssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc));
245 //return rc;
246 return VERR_NOT_IMPLEMENTED;
247}
248
249
250/**
251 * Methods for a PE module.
252 */
253static const RTDBGMODOPS g_rtDbgModPEOps =
254{
255 "PE (dbghelp)",
256 rtDbgModPEClose,
257 rtDbgModPEQuerySymbol,
258 rtDbgModPEQueryLine
259};
260
261
262/**
263 * Opens the debug info for a PE image using the windows dbghelp library.
264 *
265 * @returns IPRT status code.
266 *
267 * @param File The handle to the module.
268 * @param offHdr The offset of the PE header.
269 * @param pszModulePath The path to the module.
270 * @param ppDbgMod Where to store the module handle.
271 *
272 */
273int rtDbgModPEOpen(RTFILE File, RTFOFF offHdr, const char *pszModulePath, PRTDBGMOD *ppDbgMod)
274{
275 /*
276 * We need to read the section headers and get the image size.
277 */
278 IMAGE_FILE_HEADER FHdr;
279 int rc = RTFileReadAt(File, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader), &FHdr, sizeof(FHdr), NULL);
280 AssertRCReturn(rc, rc);
281
282 uint32_t cbImage;
283 if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
284 rc = RTFileReadAt(File, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage),
285 &cbImage, sizeof(cbImage), NULL);
286 else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
287 rc = RTFileReadAt(File, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage),
288 &cbImage, sizeof(cbImage), NULL);
289 else
290 AssertFailedReturn(VERR_BAD_EXE_FORMAT);
291 AssertRCReturn(rc, rc);
292
293 /*
294 * Allocate the module and read/construct the section headers.
295 */
296 PRTDBGMODPE pModPe = (PRTDBGMODPE)RTMemAlloc(KDBG_OFFSETOF(RTDBGMODPE, aSections[FHdr.NumberOfSections + 2]));
297 AssertReturn(pModPe, VERR_NO_MEMORY);
298 pModPe->Core.u32Magic = RTDBGMOD_MAGIC;
299 pModPe->Core.pOps = &g_rtDbgModPEOps;
300 pModPe->Core.File = File;
301 pModPe->cbImage = cbImage;
302 pModPe->cSections = 1 + FHdr.NumberOfSections;
303 rc = RTFileReadAt(File, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader,
304 &pModPe->aSections[1], sizeof(pModPe->aSections[0]) * FHdr.NumberOfSections, NULL);
305 if (RT_SUCCESS(rc))
306 {
307 PIMAGE_SECTION_HEADER pSH = &pModPe->aSections[0];
308 memcpy(pSH->Name, "headers", sizeof(pSH->Name));
309 pSH->Misc.VirtualSize = pModPe->aSections[1].VirtualAddress;
310 pSH->VirtualAddress = 0;
311 pSH->SizeOfRawData = pSH->Misc.VirtualSize;
312 pSH->PointerToRawData = 0;
313 pSH->PointerToRelocations = 0;
314 pSH->PointerToLinenumbers = 0;
315 pSH->NumberOfRelocations = 0;
316 pSH->NumberOfLinenumbers = 0;
317 pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ;
318
319 uint32_t uTheEnd = pModPe->aSections[FHdr.NumberOfSections].VirtualAddress
320 + pModPe->aSections[FHdr.NumberOfSections].Misc.VirtualSize;
321 if (uTheEnd < cbImage)
322 {
323 pSH = &pModPe->aSections[pModPe->cSections++];
324 memcpy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name));
325 pSH->Misc.VirtualSize = cbImage - uTheEnd;
326 pSH->VirtualAddress = uTheEnd;
327 pSH->SizeOfRawData = pSH->Misc.VirtualSize;
328 pSH->PointerToRawData = 0;
329 pSH->PointerToRelocations = 0;
330 pSH->PointerToLinenumbers = 0;
331 pSH->NumberOfRelocations = 0;
332 pSH->NumberOfLinenumbers = 0;
333 pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ;
334 }
335
336#if 0
337 /*
338 * Find a new dbghelp handle.
339 *
340 * We assume 4GB of handles outlast most debugging sessions, or in anyways that
341 * when we start reusing handles they are no longer in use. :-)
342 */
343 static volatile uint32_t s_u32LastHandle = 1;
344 HANDLE hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle);
345 while ( hSymInst == INVALID_HANDLE_VALUE
346 || hSymInst == (HANDLE)0
347 || hSymInst == GetCurrentProcess())
348 hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle);
349
350 /*
351 * Initialize dbghelp and try open the specified module.
352 */
353 if (g_pfnSymInitialize(hSymInst, NULL, FALSE))
354 {
355 g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
356
357 RTFileSeek(File, 0, RTFILE_SEEK_BEGIN, NULL); /* don't know if this is required or not... */
358 DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, (HANDLE)File, pszModulePath, NULL, 0x00400000, 0);
359 if (ImageBase)
360 {
361 pModPe->hSymInst = hSymInst;
362 pModPe->ImageBase = ImageBase;
363 *ppDbgMod = &pModPe->Core;
364 return rc;
365 }
366
367 DWORD Err = GetLastError();
368 rc = RTErrConvertFromWin32(Err);
369 AssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%Rrc\n", Err, rc));
370 g_pfnSymCleanup(hSymInst);
371 }
372 else
373 {
374 DWORD Err = GetLastError();
375 rc = RTErrConvertFromWin32(Err);
376 AssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc));
377 }
378#endif
379 rc = VERR_NOT_IMPLEMENTED;
380 }
381 else
382 AssertRC(rc);
383
384 RTMemFree(pModPe);
385 return rc;
386}
387
Note: See TracBrowser for help on using the repository browser.