/* $Id: $ */ /** @file * * kProfile Mark 2 - Debug Info Reader * * Copyright (c) 2006 knut st. osmundsen * * * This file is part of kLIBC. * * kLIBC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * kLIBC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kLIBC; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include #include #include "DBGInternal.h" #include "internal/ldrMZ.h" #include "internal/ldrPE.h" /** * Opens the debug info for a specified executable module. * * @returns IPRT status code. * @param pszModulePath The path to the executable module. * @param ppDbgMod Where to store the debug module handle. */ RTDECL(int) RTDbgModuleOpen(const char *pszModulePath, PRTDBGMOD *ppDbgMod) { /* * Validate input. */ AssertMsgReturn(VALID_PTR(pszModulePath), ("%p\n", pszModulePath), VERR_INVALID_POINTER); AssertMsgReturn(*pszModulePath, ("%p\n", pszModulePath), VERR_INVALID_PARAMETER); AssertMsgReturn(VALID_PTR(ppDbgMod), ("%p\n", ppDbgMod), VERR_INVALID_POINTER); *ppDbgMod = NULL; /* * The file and try figure out the format. */ RTFILE File; int rc = RTFileOpen(&File, pszModulePath, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN); if (RT_FAILURE(rc)) return rc; RTFOFF offHdr = 0; union { uint32_t au32[4]; uint16_t au16[8]; uint8_t ab[16]; } Buf; rc = RTFileRead(File, &Buf, sizeof(Buf), NULL); if ( RT_SUCCESS(rc) && Buf.au16[0] == IMAGE_DOS_SIGNATURE) { /* new header? */ uint32_t offNewHeader; rc = RTFileReadAt(File, OFFSETOF(IMAGE_DOS_HEADER, e_lfanew), &offNewHeader, sizeof(offNewHeader), NULL); if (RT_SUCCESS(rc) && offNewHeader) { offHdr = offNewHeader; rc = RTFileReadAt(File, offNewHeader, &Buf, sizeof(Buf), NULL); } } if (RT_SUCCESS(rc)) { if (Buf.au16[0] == IMAGE_DOS_SIGNATURE) rc = VERR_NOT_SUPPORTED; #ifdef IMAGE_NE_SIGNATURE else if (Buf.au16[0] == IMAGE_NE_SIGNATURE) rc = VERR_NOT_SUPPORTED; #endif #ifdef IMAGE_LX_SIGNATURE else if (Buf.au16[0] == IMAGE_LX_SIGNATURE) rc = VERR_NOT_SUPPORTED; #endif #ifdef IMAGE_LE_SIGNATURE else if (Buf.au16[0] == IMAGE_LE_SIGNATURE) rc = VERR_NOT_SUPPORTED; #endif #ifdef IMAGE_ELF_SIGNATURE else if (Buf.au32[0] == IMAGE_ELF_SIGNATURE) rc = VERR_NOT_SUPPORTED; #endif #ifdef IMAGE_NT_SIGNATURE else if (Buf.au32[0] == IMAGE_NT_SIGNATURE) rc = rtDbgModPEOpen(File, offHdr, pszModulePath, ppDbgMod); #endif /** @todo there are a number of text file formats too which I want to support. */ else rc = VERR_NOT_SUPPORTED; } if (RT_FAILURE(rc)) RTFileClose(File); return rc; } /** * Validates a debug module handle. * All necessary asserting will be taken care of here. * * @returns True / false. * @param pMod The debug module handle. */ DECLINLINE(bool) rtDbgModIsValid(PRTDBGMOD pMod) { AssertMsgReturn(VALID_PTR(pMod), ("%p", pMod), false); AssertMsgReturn(pMod->u32Magic == RTDBGMOD_MAGIC, ("%RX32", pMod->u32Magic), false); AssertMsgReturn(VALID_PTR(pMod->pOps), ("%p", pMod->pOps), false); return true; } /** * Closes the module. * * @returns IPRT status code. * @param pMod The module handle. */ RTDECL(int) RTDbgModuleClose(PRTDBGMOD pMod) { if (!rtDbgModIsValid(pMod)) return VERR_INVALID_PARAMETER; int rc = pMod->pOps->pfnClose(pMod); if (RT_SUCCESS(rc)) RTMemFree(pMod); return rc; } /** * Gets a symbol by segment:offset. * This will be approximated to the nearest symbol if there is no exact match. * * @returns IPRT status code. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param pSym Where to store the symbol details. */ RTDECL(int) RTDbgModuleQuerySymbol(PRTDBGMOD pMod, int32_t iSegment, RTUINTPTR off, PRTDBGSYMBOL pSym) { if (!rtDbgModIsValid(pMod)) return VERR_INVALID_PARAMETER; AssertMsgReturn(VALID_PTR(pSym), ("%p", pSym), VERR_INVALID_POINTER); return pMod->pOps->pfnQuerySymbol(pMod, iSegment, off, pSym); } /** * Gets & allocates a symbol by segment:offset. * This will be approximated to the nearest symbol if there is no exact match. * * @returns IPRT status code. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param ppSym Where to store the pointer to the symbol info. * Free the returned symbol using RTDbgSymbolFree(). */ RTDECL(int) RTDbgModuleQuerySymbolA(PRTDBGMOD pMod, int32_t iSegment, RTUINTPTR off, PPRTDBGSYMBOL ppSym) { AssertMsgReturn(VALID_PTR(ppSym), ("%p\n", ppSym), VERR_INVALID_POINTER); RTDBGSYMBOL Sym; int rc = RTDbgModuleQuerySymbol(pMod, iSegment, off, &Sym); if (RT_SUCCESS(rc)) { *ppSym = RTDbgSymbolDup(&Sym); if (!*ppSym) rc = VERR_NO_MEMORY; } else *ppSym = NULL; return rc; } /** * Gets a line number entry by segment:offset. * This will be approximated to the nearest line number there is no exact match. * * @returns IPRT status code. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param pLine Where to store the line number details. */ RTDECL(int) RTDbgModuleQueryLine(PRTDBGMOD pMod, int32_t iSegment, RTUINTPTR off, PRTDBGLINE pLine) { if (!rtDbgModIsValid(pMod)) return VERR_INVALID_PARAMETER; AssertMsgReturn(VALID_PTR(pLine), ("%p", pLine), VERR_INVALID_POINTER); return pMod->pOps->pfnQueryLine(pMod, iSegment, off, pLine); } /** * Gets & allocates a line number entry by segment:offset. * This will be approximated to the nearest line number there is no exact match. * * @returns IPRT status code. * @param pMod The module. * @param iSegment The segment this offset is relative to. * The -1 segment is special, it means that the addres is relative to * the image base. The image base is where the first bit of the image * is mapped during load. * @param off The offset into the segment. * @param ppLine Where to store the pointer to the line number info. * Free the returned line number using RTDbgLineFree(). */ RTDECL(int) RTDbgModuleQueryLineA(PRTDBGMOD pMod, int32_t iSegment, RTUINTPTR off, PPRTDBGLINE ppLine) { AssertMsgReturn(VALID_PTR(ppLine), ("%p\n", ppLine), VERR_INVALID_POINTER); RTDBGLINE Line; int rc = RTDbgModuleQueryLine(pMod, iSegment, off, &Line); if (RT_SUCCESS(rc)) { *ppLine = RTDbgLineDup(&Line); if (!*ppLine) rc = VERR_NO_MEMORY; } else *ppLine = NULL; return rc; }