/**
 * 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;
}
Esempio n. 5
0
/** @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;
}
Esempio n. 6
0
/**
 * 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;
}