/**
 * Links the segments of the module into the address space.
 *
 * @returns VBox status code on failure.
 *
 * @param   hAs     The address space.
 * @param   hMod    The module.
 * @param   paSegs  Array of segment indexes and load addresses.
 * @param   cSegs   The number of segments in the array.
 */
static int dbgDiggerCommonLinkElfSegs(RTDBGAS hAs, RTDBGMOD hMod, PDBGDIGGERELFSEG paSegs, uint32_t cSegs)
{
    for (uint32_t i = 0; i < cSegs; i++)
        if (paSegs[i].iSeg != NIL_RTDBGSEGIDX)
        {
            int rc = RTDbgAsModuleLinkSeg(hAs, hMod, paSegs[i].iSeg, paSegs[i].uLoadAddr, RTDBGASLINK_FLAGS_REPLACE);
            if (RT_FAILURE(rc))
            {
                RTDbgAsModuleUnlink(hAs, hMod);
                return rc;
            }
        }
    return VINF_SUCCESS;
}
/**
 * Wrapper around RTDbgAsModuleByName and RTDbgAsModuleUnlink.
 *
 * Unlinks all mappings matching the given module name.
 *
 * @returns VBox status code.
 * @param   pUVM            The user mode VM handle.
 * @param   hDbgAs          The address space handle.
 * @param   pszModName      The name of the module to unlink.
 */
VMMR3DECL(int) DBGFR3AsUnlinkModuleByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszModName)
{
    /*
     * Input validation.
     */
    UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
    RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
    if (hRealAS == NIL_RTDBGAS)
        return VERR_INVALID_HANDLE;

    /*
     * Do the job.
     */
    RTDBGMOD hMod;
    int rc = RTDbgAsModuleByName(hRealAS, pszModName, 0, &hMod);
    if (RT_SUCCESS(rc))
    {
        for (;;)
        {
            rc = RTDbgAsModuleUnlink(hRealAS, hMod);
            RTDbgModRelease(hMod);
            if (RT_FAILURE(rc))
                break;
            rc = RTDbgAsModuleByName(hRealAS, pszModName, 0, &hMod);
            if (RT_FAILURE_NP(rc))
            {
                if (rc == VERR_NOT_FOUND)
                    rc = VINF_SUCCESS;
                break;
            }
        }
    }

    RTDbgAsRelease(hRealAS);
    return rc;
}
/**
 * Relocates the RC address space.
 *
 * @param   pUVM        The user mode VM handle.
 * @param   offDelta    The relocation delta.
 */
void dbgfR3AsRelocate(PUVM pUVM, RTGCUINTPTR offDelta)
{
    /*
     * We will relocate the raw-mode context modules by offDelta if they have
     * been injected into the the DBGF_AS_RC map.
     */
    if (   pUVM->dbgf.s.afAsAliasPopuplated[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC)]
        && offDelta != 0)
    {
        RTDBGAS hAs = pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC)];

        /* Take a snapshot of the modules as we might have overlapping
           addresses between the previous and new mapping. */
        RTDbgAsLockExcl(hAs);
        uint32_t cModules = RTDbgAsModuleCount(hAs);
        if (cModules > 0 && cModules < _4K)
        {
            struct DBGFASRELOCENTRY
            {
                RTDBGMOD    hDbgMod;
                RTRCPTR     uOldAddr;
            } *paEntries = (struct DBGFASRELOCENTRY *)RTMemTmpAllocZ(sizeof(paEntries[0]) * cModules);
            if (paEntries)
            {
                /* Snapshot. */
                for (uint32_t i = 0; i < cModules; i++)
                {
                    paEntries[i].hDbgMod = RTDbgAsModuleByIndex(hAs, i);
                    AssertLogRelMsg(paEntries[i].hDbgMod != NIL_RTDBGMOD, ("iModule=%#x\n", i));

                    RTDBGASMAPINFO  aMappings[1] = { { 0, 0 } };
                    uint32_t        cMappings = 1;
                    int rc = RTDbgAsModuleQueryMapByIndex(hAs, i, &aMappings[0], &cMappings, 0 /*fFlags*/);
                    if (RT_SUCCESS(rc) && cMappings == 1 && aMappings[0].iSeg == NIL_RTDBGSEGIDX)
                        paEntries[i].uOldAddr = (RTRCPTR)aMappings[0].Address;
                    else
                        AssertLogRelMsgFailed(("iModule=%#x rc=%Rrc cMappings=%#x.\n", i, rc, cMappings));
                }

                /* Unlink them. */
                for (uint32_t i = 0; i < cModules; i++)
                {
                    int rc = RTDbgAsModuleUnlink(hAs, paEntries[i].hDbgMod);
                    AssertLogRelMsg(RT_SUCCESS(rc), ("iModule=%#x rc=%Rrc hDbgMod=%p\n", i, rc, paEntries[i].hDbgMod));
                }

                /* Link them at the new locations. */
                for (uint32_t i = 0; i < cModules; i++)
                {
                    RTRCPTR uNewAddr = paEntries[i].uOldAddr + offDelta;
                    int rc = RTDbgAsModuleLink(hAs, paEntries[i].hDbgMod, uNewAddr,
                                               RTDBGASLINK_FLAGS_REPLACE);
                    AssertLogRelMsg(RT_SUCCESS(rc),
                                    ("iModule=%#x rc=%Rrc hDbgMod=%p %RRv -> %RRv\n", i, rc, paEntries[i].hDbgMod,
                                     paEntries[i].uOldAddr, uNewAddr));
                    RTDbgModRelease(paEntries[i].hDbgMod);
                }

                RTMemTmpFree(paEntries);
            }
            else
                AssertLogRelMsgFailed(("No memory for %#x modules.\n", cModules));
        }
        else
            AssertLogRelMsgFailed(("cModules=%#x\n", cModules));
        RTDbgAsUnlockExcl(hAs);
    }
}