/** * Adds a new entry to a manifest. * * The entry name rules: * - The entry name can contain any character defined by unicode, except * control characters, ':', '(' and ')'. The exceptions are mainly there * because of uncertainty around how various formats handles these. * - It is considered case sensitive. * - Forward (unix) and backward (dos) slashes are considered path * separators and converted to forward slashes. * * @returns IPRT status code. * @retval VWRN_ALREADY_EXISTS if the entry already exists. * * @param hManifest The manifest handle. * @param pszEntry The entry name (UTF-8). * * @remarks Some manifest formats will not be able to store an entry without * any attributes. So, this is just here in case it comes in handy * when dealing with formats which can. */ RTDECL(int) RTManifestEntryAdd(RTMANIFEST hManifest, const char *pszEntry) { RTMANIFESTINT *pThis = hManifest; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE); AssertPtr(pszEntry); bool fNeedNormalization; size_t cchEntry; int rc = rtManifestValidateNameEntry(pszEntry, &fNeedNormalization, &cchEntry); AssertRCReturn(rc, rc); /* * Only add one if it does not already exist. */ PRTMANIFESTENTRY pEntry; rc = rtManifestGetEntry(pThis, pszEntry, fNeedNormalization, cchEntry, &pEntry); if (rc == VERR_NOT_FOUND) { pEntry = (PRTMANIFESTENTRY)RTMemAlloc(RT_OFFSETOF(RTMANIFESTENTRY, szName[cchEntry + 1])); if (pEntry) { pEntry->StrCore.cchString = cchEntry; pEntry->StrCore.pszString = pEntry->szName; pEntry->Attributes = NULL; pEntry->cAttributes = 0; memcpy(pEntry->szName, pszEntry, cchEntry + 1); if (fNeedNormalization) rtManifestNormalizeEntry(pEntry->szName); if (RTStrSpaceInsert(&pThis->Entries, &pEntry->StrCore)) { pThis->cEntries++; rc = VINF_SUCCESS; } else { RTMemFree(pEntry); rc = VERR_INTERNAL_ERROR_4; } } else rc = VERR_NO_MEMORY; } else if (RT_SUCCESS(rc)) rc = VWRN_ALREADY_EXISTS; return rc; }
/** * Sets an attribute of a manifest entry. * * @returns IPRT status code. * @param hManifest The manifest handle. * @param pszEntry The entry name. This will automatically be * added if there was no previous call to * RTManifestEntryAdd for this name. See * RTManifestEntryAdd for the entry name rules. * @param pszAttr The attribute name. If this already exists, * its value will be replaced. * @param pszValue The value string. * @param fType The attribute type, pass * RTMANIFEST_ATTR_UNKNOWN if not known. */ RTDECL(int) RTManifestEntrySetAttr(RTMANIFEST hManifest, const char *pszEntry, const char *pszAttr, const char *pszValue, uint32_t fType) { RTMANIFESTINT *pThis = hManifest; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, VERR_INVALID_HANDLE); AssertPtr(pszEntry); AssertPtr(pszAttr); AssertPtr(pszValue); AssertReturn(RT_IS_POWER_OF_TWO(fType) && fType < RTMANIFEST_ATTR_END, VERR_INVALID_PARAMETER); bool fNeedNormalization; size_t cchEntry; int rc = rtManifestValidateNameEntry(pszEntry, &fNeedNormalization, &cchEntry); AssertRCReturn(rc, rc); /* * Resolve the entry, adding one if necessary. */ PRTMANIFESTENTRY pEntry; rc = rtManifestGetEntry(pThis, pszEntry, fNeedNormalization, cchEntry, &pEntry); if (rc == VERR_NOT_FOUND) { pEntry = (PRTMANIFESTENTRY)RTMemAlloc(RT_OFFSETOF(RTMANIFESTENTRY, szName[cchEntry + 1])); if (!pEntry) return VERR_NO_MEMORY; pEntry->StrCore.cchString = cchEntry; pEntry->StrCore.pszString = pEntry->szName; pEntry->Attributes = NULL; pEntry->cAttributes = 0; memcpy(pEntry->szName, pszEntry, cchEntry + 1); if (fNeedNormalization) rtManifestNormalizeEntry(pEntry->szName); if (!RTStrSpaceInsert(&pThis->Entries, &pEntry->StrCore)) { RTMemFree(pEntry); return VERR_INTERNAL_ERROR_4; } pThis->cEntries++; } else if (RT_FAILURE(rc)) return rc; return rtManifestSetAttrWorker(pEntry, pszAttr, pszValue, fType); }
/** * Worker common to RTManifestSetAttr and RTManifestEntrySetAttr. * * @returns IPRT status code. * @param pEntry Pointer to the entry. * @param pszAttr The name of the attribute to add. * @param pszValue The value string. * @param fType The attribute type type. */ static int rtManifestSetAttrWorker(PRTMANIFESTENTRY pEntry, const char *pszAttr, const char *pszValue, uint32_t fType) { char *pszValueCopy; int rc = RTStrDupEx(&pszValueCopy, pszValue); if (RT_FAILURE(rc)) return rc; /* * Does the attribute exist already? */ AssertCompileMemberOffset(RTMANIFESTATTR, StrCore, 0); PRTMANIFESTATTR pAttr = (PRTMANIFESTATTR)RTStrSpaceGet(&pEntry->Attributes, pszAttr); if (pAttr) { RTStrFree(pAttr->pszValue); pAttr->pszValue = pszValueCopy; pAttr->fType = fType; } else { size_t cbName = strlen(pszAttr) + 1; pAttr = (PRTMANIFESTATTR)RTMemAllocVar(RT_OFFSETOF(RTMANIFESTATTR, szName[cbName])); if (!pAttr) { RTStrFree(pszValueCopy); return VERR_NO_MEMORY; } memcpy(pAttr->szName, pszAttr, cbName); pAttr->StrCore.pszString = pAttr->szName; pAttr->StrCore.cchString = cbName - 1; pAttr->pszValue = pszValueCopy; pAttr->fType = fType; if (RT_UNLIKELY(!RTStrSpaceInsert(&pEntry->Attributes, &pAttr->StrCore))) { AssertFailed(); RTStrFree(pszValueCopy); RTMemFree(pAttr); return VERR_INTERNAL_ERROR_4; } pEntry->cAttributes++; } return VINF_SUCCESS; }
/** * Adds the address space to the database. * * @returns VBox status code. * @param pUVM The user mode VM handle. * @param hDbgAs The address space handle. The reference of the caller * will NOT be consumed. * @param ProcId The process id or NIL_RTPROCESS. */ VMMR3DECL(int) DBGFR3AsAdd(PUVM pUVM, RTDBGAS hDbgAs, RTPROCESS ProcId) { /* * Input validation. */ UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); const char *pszName = RTDbgAsName(hDbgAs); if (!pszName) return VERR_INVALID_HANDLE; uint32_t cRefs = RTDbgAsRetain(hDbgAs); if (cRefs == UINT32_MAX) return VERR_INVALID_HANDLE; /* * Allocate a tracking node. */ int rc = VERR_NO_MEMORY; PDBGFASDBNODE pDbNode = (PDBGFASDBNODE)MMR3HeapAllocU(pUVM, MM_TAG_DBGF_AS, sizeof(*pDbNode)); if (pDbNode) { pDbNode->HandleCore.Key = hDbgAs; pDbNode->PidCore.Key = ProcId; pDbNode->NameCore.pszString = pszName; pDbNode->NameCore.cchString = strlen(pszName); DBGF_AS_DB_LOCK_WRITE(pUVM); if (RTStrSpaceInsert(&pUVM->dbgf.s.AsNameSpace, &pDbNode->NameCore)) { if (RTAvlPVInsert(&pUVM->dbgf.s.AsHandleTree, &pDbNode->HandleCore)) { DBGF_AS_DB_UNLOCK_WRITE(pUVM); return VINF_SUCCESS; } /* bail out */ RTStrSpaceRemove(&pUVM->dbgf.s.AsNameSpace, pszName); } DBGF_AS_DB_UNLOCK_WRITE(pUVM); MMR3HeapFree(pDbNode); } RTDbgAsRelease(hDbgAs); return rc; }
/** @copydoc RTDBGMODVTDBG::pfnSymbolAdd */ static DECLCALLBACK(int) rtDbgModContainer_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol, RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags, uint32_t *piOrdinal) { PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv; /* * Address validation. The other arguments have already been validated. */ AssertMsgReturn( iSeg == RTDBGSEGIDX_ABS || iSeg < pThis->cSegs, ("iSeg=%#x cSegs=%#x\n", iSeg, pThis->cSegs), VERR_DBG_INVALID_SEGMENT_INDEX); AssertMsgReturn( iSeg >= RTDBGSEGIDX_SPECIAL_FIRST || off <= pThis->paSegs[iSeg].cb, ("off=%RTptr cb=%RTptr cbSeg=%RTptr\n", off, cb, pThis->paSegs[iSeg].cb), VERR_DBG_INVALID_SEGMENT_OFFSET); /* Be a little relaxed wrt to the symbol size. */ int rc = VINF_SUCCESS; if (iSeg != RTDBGSEGIDX_ABS && off + cb > pThis->paSegs[iSeg].cb) { cb = pThis->paSegs[iSeg].cb - off; rc = VINF_DBG_ADJUSTED_SYM_SIZE; } /* * Create a new entry. */ PRTDBGMODCTNSYMBOL pSymbol = (PRTDBGMODCTNSYMBOL)RTMemAllocZ(sizeof(*pSymbol)); if (!pSymbol) return VERR_NO_MEMORY; pSymbol->AddrCore.Key = off; pSymbol->AddrCore.KeyLast = off + (cb ? cb - 1 : 0); pSymbol->OrdinalCore.Key = pThis->iNextSymbolOrdinal; pSymbol->iSeg = iSeg; pSymbol->cb = cb; pSymbol->fFlags = fFlags; pSymbol->NameCore.pszString = RTStrCacheEnterN(g_hDbgModStrCache, pszSymbol, cchSymbol); if (pSymbol->NameCore.pszString) { if (RTStrSpaceInsert(&pThis->Names, &pSymbol->NameCore)) { PAVLRUINTPTRTREE pAddrTree = iSeg == RTDBGSEGIDX_ABS ? &pThis->AbsAddrTree : &pThis->paSegs[iSeg].SymAddrTree; if (RTAvlrUIntPtrInsert(pAddrTree, &pSymbol->AddrCore)) { if (RTAvlU32Insert(&pThis->SymbolOrdinalTree, &pSymbol->OrdinalCore)) { if (piOrdinal) *piOrdinal = pThis->iNextSymbolOrdinal; pThis->iNextSymbolOrdinal++; return rc; } /* bail out */ rc = VERR_INTERNAL_ERROR_5; RTAvlrUIntPtrRemove(pAddrTree, pSymbol->AddrCore.Key); } else rc = VERR_DBG_ADDRESS_CONFLICT; RTStrSpaceRemove(&pThis->Names, pSymbol->NameCore.pszString); } else rc = VERR_DBG_DUPLICATE_SYMBOL; RTStrCacheRelease(g_hDbgModStrCache, pSymbol->NameCore.pszString); } else rc = VERR_NO_MEMORY; RTMemFree(pSymbol); return rc; }
/** * Evaluate a function call. * * @returns VBox status code. * @param pThis The interpreter context. * @param pFn The function execute. */ static int vdScriptInterpreterFnCall(PVDSCRIPTINTERPCTX pThis, PVDSCRIPTFN pFn) { int rc = VINF_SUCCESS; if (!pFn->fExternal) { PVDSCRIPTASTFN pAstFn = pFn->Type.Internal.pAstFn; /* Add function call cleanup marker on the stack first. */ rc = vdScriptInterpreterPushNonDataCtrlEntry(pThis, VDSCRIPTINTERPCTRLTYPE_FN_CALL_CLEANUP); if (RT_SUCCESS(rc)) { /* Create function call frame and set it up. */ PVDSCRIPTINTERPFNCALL pFnCall = (PVDSCRIPTINTERPFNCALL)RTMemAllocZ(sizeof(VDSCRIPTINTERPFNCALL)); if (pFnCall) { pFnCall->pCaller = pThis->pFnCallCurr; pFnCall->ScopeRoot.pParent = NULL; pFnCall->ScopeRoot.hStrSpaceVar = NULL; pFnCall->pScopeCurr = &pFnCall->ScopeRoot; /* Add the variables, remember order. The first variable in the argument has the value at the top of the value stack. */ PVDSCRIPTASTFNARG pArg = RTListGetFirst(&pAstFn->ListArgs, VDSCRIPTASTFNARG, Core.ListNode); for (unsigned i = 0; i < pAstFn->cArgs; i++) { PVDSCRIPTINTERPVAR pVar = (PVDSCRIPTINTERPVAR)RTMemAllocZ(sizeof(VDSCRIPTINTERPVAR)); if (pVar) { pVar->Core.pszString = pArg->pArgIde->aszIde; pVar->Core.cchString = pArg->pArgIde->cchIde; vdScriptInterpreterPopValue(pThis, &pVar->Value); bool fInserted = RTStrSpaceInsert(&pFnCall->ScopeRoot.hStrSpaceVar, &pVar->Core); Assert(fInserted); } else { rc = vdScriptInterpreterError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Out of memory creating a variable"); break; } pArg = RTListGetNext(&pAstFn->ListArgs, pArg, VDSCRIPTASTFNARG, Core.ListNode); } if (RT_SUCCESS(rc)) { /* * Push compount statement on the control stack and make the newly created * call frame the current one. */ rc = vdScriptInterpreterPushAstEntry(pThis, &pAstFn->pCompoundStmts->Core); if (RT_SUCCESS(rc)) pThis->pFnCallCurr = pFnCall; } if (RT_FAILURE(rc)) { RTStrSpaceDestroy(&pFnCall->ScopeRoot.hStrSpaceVar, vdScriptInterpreterVarSpaceDestroy, NULL); RTMemFree(pFnCall); } } else rc = vdScriptInterpreterError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Out of memory creating a call frame"); } } else { /* External function call, build the argument list. */ if (pFn->cArgs) { PVDSCRIPTARG paArgs = (PVDSCRIPTARG)RTMemAllocZ(pFn->cArgs * sizeof(VDSCRIPTARG)); if (paArgs) { for (unsigned i = 0; i < pFn->cArgs; i++) vdScriptInterpreterPopValue(pThis, &paArgs[i]); rc = pFn->Type.External.pfnCallback(paArgs, pFn->Type.External.pvUser); RTMemFree(paArgs); } else rc = vdScriptInterpreterError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Out of memory creating argument array for external function call"); } else rc = pFn->Type.External.pfnCallback(NULL, pFn->Type.External.pvUser); } return rc; }
/** * Insert a record into the symbol tree. */ static int dbgfR3SymbolInsert(PVM pVM, const char *pszName, RTGCPTR Address, size_t cb, PDBGFMOD pModule) { /* * Make the address space node. */ size_t cchName = strlen(pszName) + 1; PDBGFSYM pSym = (PDBGFSYM)MMR3HeapAlloc(pVM, MM_TAG_DBGF_SYMBOL, RT_OFFSETOF(DBGFSYM, szName[cchName])); if (pSym) { pSym->Core.Key = Address; pSym->Core.KeyLast = Address + cb; pSym->pModule = pModule; memcpy(pSym->szName, pszName, cchName); PDBGFSYM pOld = (PDBGFSYM)RTAvlrGCPtrRangeGet(&pVM->dbgf.s.SymbolTree, (RTGCPTR)Address); if (pOld) { pSym->Core.KeyLast = pOld->Core.KeyLast; if (pOld->Core.Key == pSym->Core.Key) { pOld = (PDBGFSYM)RTAvlrGCPtrRemove(&pVM->dbgf.s.SymbolTree, (RTGCPTR)Address); AssertRelease(pOld); MMR3HeapFree(pOld); } else pOld->Core.KeyLast = Address - 1; if (RTAvlrGCPtrInsert(&pVM->dbgf.s.SymbolTree, &pSym->Core)) { /* * Make the name space node. */ PDBGFSYMSPACE pName = (PDBGFSYMSPACE)RTStrSpaceGet(pVM->dbgf.s.pSymbolSpace, pszName); if (!pName) { /* make new symbol space node. */ pName = (PDBGFSYMSPACE)MMR3HeapAlloc(pVM, MM_TAG_DBGF_SYMBOL, sizeof(*pName) + cchName); if (pName) { pName->Core.pszString = (char *)memcpy(pName + 1, pszName, cchName); pName->pSym = pSym; if (RTStrSpaceInsert(pVM->dbgf.s.pSymbolSpace, &pName->Core)) return VINF_SUCCESS; } else return VINF_SUCCESS; } else { /* Add to existing symbol name. */ pSym->pNext = pName->pSym; pName->pSym = pSym; return VINF_SUCCESS; } } AssertReleaseMsgFailed(("Failed to insert %RGv-%RGv!\n", pSym->Core.Key, pSym->Core.KeyLast)); } else AssertMsgFailed(("pOld! %RGv %s\n", pSym->Core.Key, pszName)); return VERR_INTERNAL_ERROR; } return VERR_NO_MEMORY; }