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

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

errors and stuff.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.3 KB
Line 
1/* $Id: kDbgModPE.cpp 3541 2007-08-25 03:46: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-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 = KERR_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 = KERR_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 KERR_NOT_IMPLEMENTED;
238}
239
240
241/**
242 * Opens the debug info for a PE image using the windows dbghelp library.
243 *
244 * @returns IPRT status code.
245 *
246 * @param pFile The handle to the module.
247 * @param offHdr The offset of the PE header.
248 * @param pszModulePath The path to the module.
249 * @param ppDbgMod Where to store the module handle.
250 *
251 */
252int kdbgModPEOpen(PKDBGHLPFILE pFile, int64_t offHdr, const char *pszModulePath, PKDBGMOD *ppDbgMod)
253{
254 /*
255 * We need to read the section headers and get the image size.
256 */
257 IMAGE_FILE_HEADER FHdr;
258 int rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader), &FHdr, sizeof(FHdr));
259 kDbgAssertRCReturn(rc, rc);
260
261 uint32_t cbImage;
262 if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
263 rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage),
264 &cbImage, sizeof(cbImage));
265 else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
266 rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage),
267 &cbImage, sizeof(cbImage));
268 else
269 kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT);
270 kDbgAssertRCReturn(rc, rc);
271
272 /*
273 * Allocate the module and read/construct the section headers.
274 */
275 PKDBGMODPE pModPe = (PKDBGMODPE)kDbgHlpAlloc(KDBG_OFFSETOF(KDBGMODPE, aSections[FHdr.NumberOfSections + 2]));
276 kDbgAssertReturn(pModPe, KERR_NO_MEMORY);
277 pModPe->Core.u32Magic = KDBGMOD_MAGIC;
278 pModPe->Core.pOps = &g_kDbgModPeOps;
279 pModPe->Core.pFile = pFile;
280 pModPe->cbImage = cbImage;
281 pModPe->cSections = 1 + FHdr.NumberOfSections;
282 rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader,
283 &pModPe->aSections[1], sizeof(pModPe->aSections[0]) * FHdr.NumberOfSections);
284 if (!rc)
285 {
286 PIMAGE_SECTION_HEADER pSH = &pModPe->aSections[0];
287 memcpy(pSH->Name, "headers", sizeof(pSH->Name));
288 pSH->Misc.VirtualSize = pModPe->aSections[1].VirtualAddress;
289 pSH->VirtualAddress = 0;
290 pSH->SizeOfRawData = pSH->Misc.VirtualSize;
291 pSH->PointerToRawData = 0;
292 pSH->PointerToRelocations = 0;
293 pSH->PointerToLinenumbers = 0;
294 pSH->NumberOfRelocations = 0;
295 pSH->NumberOfLinenumbers = 0;
296 pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ;
297
298 uint32_t uTheEnd = pModPe->aSections[FHdr.NumberOfSections].VirtualAddress
299 + pModPe->aSections[FHdr.NumberOfSections].Misc.VirtualSize;
300 if (uTheEnd < cbImage)
301 {
302 pSH = &pModPe->aSections[pModPe->cSections++];
303 memcpy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name));
304 pSH->Misc.VirtualSize = cbImage - uTheEnd;
305 pSH->VirtualAddress = uTheEnd;
306 pSH->SizeOfRawData = pSH->Misc.VirtualSize;
307 pSH->PointerToRawData = 0;
308 pSH->PointerToRelocations = 0;
309 pSH->PointerToLinenumbers = 0;
310 pSH->NumberOfRelocations = 0;
311 pSH->NumberOfLinenumbers = 0;
312 pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ;
313 }
314
315#if 0
316 /*
317 * Find a new dbghelp handle.
318 *
319 * We assume 4GB of handles outlast most debugging sessions, or in anyways that
320 * when we start reusing handles they are no longer in use. :-)
321 */
322 static volatile uint32_t s_u32LastHandle = 1;
323 HANDLE hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle);
324 while ( hSymInst == INVALID_HANDLE_VALUE
325 || hSymInst == (HANDLE)0
326 || hSymInst == GetCurrentProcess())
327 hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle);
328
329 /*
330 * Initialize dbghelp and try open the specified module.
331 */
332 if (g_pfnSymInitialize(hSymInst, NULL, FALSE))
333 {
334 g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
335
336 kDbgHlpSeek(pFile, 0); /* don't know if this is required or not... */
337 DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, (HANDLE)File, pszModulePath, NULL, 0x00400000, 0);
338 if (ImageBase)
339 {
340 pModPe->hSymInst = hSymInst;
341 pModPe->ImageBase = ImageBase;
342 *ppDbgMod = &pModPe->Core;
343 return rc;
344 }
345
346 DWORD Err = GetLastError();
347 rc = kDbgModPeConvWinError(Err);
348 kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%Rrc\n", Err, rc));
349 g_pfnSymCleanup(hSymInst);
350 }
351 else
352 {
353 DWORD Err = GetLastError();
354 rc = kDbgModPeConvWinError(Err);
355 kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc));
356 }
357#endif
358 rc = KERR_NOT_IMPLEMENTED;
359 }
360 else
361 kDbgAssertRC(rc);
362
363 kDbgHlpFree(pModPe);
364 return rc;
365}
366
367
368/**
369 * Methods for a PE module.
370 */
371const KDBGMODOPS g_kDbgModPeOps =
372{
373 "PE",
374 kDbgModPeClose,
375 kDbgModPeQuerySymbol,
376 kDbgModPeQueryLine
377};
378
379
380
Note: See TracBrowser for help on using the repository browser.