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

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

kProfile Mark II. Some early/old code.

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