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