/** * Populate DBGF_AS_RC with PATM symbols. * * Called by dbgfR3AsLazyPopulate when DBGF_AS_RC or DBGF_AS_RC_AND_GC_GLOBAL is * accessed for the first time. * * @param pVM The cross context VM structure. * @param hDbgAs The DBGF_AS_RC address space handle. */ VMMR3_INT_DECL(void) PATMR3DbgPopulateAddrSpace(PVM pVM, RTDBGAS hDbgAs) { AssertReturnVoid(VM_IS_RAW_MODE_ENABLED(pVM)); /* * Add a fake debug module for the PATMGCSTATE structure. */ RTDBGMOD hDbgMod; int rc = RTDbgModCreate(&hDbgMod, "patmgcstate", sizeof(PATMGCSTATE), 0 /*fFlags*/); if (RT_SUCCESS(rc)) { ADD_MEMBER(hDbgMod, PATMGCSTATE, uVMFlags, "uVMFlags"); ADD_MEMBER(hDbgMod, PATMGCSTATE, uPendingAction, "uPendingAction"); ADD_MEMBER(hDbgMod, PATMGCSTATE, uPatchCalls, "uPatchCalls"); ADD_MEMBER(hDbgMod, PATMGCSTATE, uScratch, "uScratch"); ADD_MEMBER(hDbgMod, PATMGCSTATE, uIretEFlags, "uIretEFlags"); ADD_MEMBER(hDbgMod, PATMGCSTATE, uIretCS, "uIretCS"); ADD_MEMBER(hDbgMod, PATMGCSTATE, uIretEIP, "uIretEIP"); ADD_MEMBER(hDbgMod, PATMGCSTATE, Psp, "Psp"); ADD_MEMBER(hDbgMod, PATMGCSTATE, fPIF, "fPIF"); ADD_MEMBER(hDbgMod, PATMGCSTATE, GCPtrInhibitInterrupts, "GCPtrInhibitInterrupts"); ADD_MEMBER(hDbgMod, PATMGCSTATE, GCCallPatchTargetAddr, "GCCallPatchTargetAddr"); ADD_MEMBER(hDbgMod, PATMGCSTATE, GCCallReturnAddr, "GCCallReturnAddr"); ADD_MEMBER(hDbgMod, PATMGCSTATE, Restore.uEAX, "Restore.uEAX"); ADD_MEMBER(hDbgMod, PATMGCSTATE, Restore.uECX, "Restore.uECX"); ADD_MEMBER(hDbgMod, PATMGCSTATE, Restore.uEDI, "Restore.uEDI"); ADD_MEMBER(hDbgMod, PATMGCSTATE, Restore.eFlags, "Restore.eFlags"); ADD_MEMBER(hDbgMod, PATMGCSTATE, Restore.uFlags, "Restore.uFlags"); rc = RTDbgAsModuleLink(hDbgAs, hDbgMod, pVM->patm.s.pGCStateGC, 0 /*fFlags*/); AssertLogRelRC(rc); RTDbgModRelease(hDbgMod); } /* * Add something for the stats so we get some kind of symbols for * references to them while disassembling patches. */ rc = RTDbgModCreate(&hDbgMod, "patmstats", PATM_STAT_MEMSIZE, 0 /*fFlags*/); if (RT_SUCCESS(rc)) { ADD_FUNC(hDbgMod, pVM->patm.s.pStatsGC, pVM->patm.s.pStatsGC, PATM_STAT_MEMSIZE, "PATMMemStatsStart"); rc = RTDbgAsModuleLink(hDbgAs, hDbgMod, pVM->patm.s.pStatsGC, 0 /*fFlags*/); AssertLogRelRC(rc); RTDbgModRelease(hDbgMod); } /* * Add a fake debug module for the patches and stack. */ rc = RTDbgModCreate(&hDbgMod, "patches", pVM->patm.s.cbPatchMem + PATM_STACK_TOTAL_SIZE + PAGE_SIZE, 0 /*fFlags*/); if (RT_SUCCESS(rc)) { pVM->patm.s.hDbgModPatchMem = hDbgMod; patmR3DbgAddPatches(pVM, hDbgMod); rc = RTDbgAsModuleLink(hDbgAs, hDbgMod, pVM->patm.s.pPatchMemGC, 0 /*fFlags*/); AssertLogRelRC(rc); } }
/** * Loads the kernel symbols from the kallsyms tables. * * @returns VBox status code. * @param pUVM The user mode VM handle. * @param pThis The Linux digger data. */ static int dbgDiggerLinuxLoadKernelSymbols(PUVM pUVM, PDBGDIGGERLINUX pThis) { /* * Allocate memory for temporary table copies, reading the tables as we go. */ uint32_t const cbGuestAddr = pThis->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t); void *pvAddresses = RTMemAllocZ(pThis->cKernelSymbols * cbGuestAddr); int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &pThis->AddrKernelAddresses, pvAddresses, pThis->cKernelSymbols * cbGuestAddr); if (RT_SUCCESS(rc)) { uint8_t *pbNames = (uint8_t *)RTMemAllocZ(pThis->cbKernelNames); rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &pThis->AddrKernelNames, pbNames, pThis->cbKernelNames); if (RT_SUCCESS(rc)) { char *pszzTokens = (char *)RTMemAllocZ(pThis->cbKernelTokenTable); rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &pThis->AddrKernelTokenTable, pszzTokens, pThis->cbKernelTokenTable); if (RT_SUCCESS(rc)) { uint16_t *paoffTokens = (uint16_t *)RTMemAllocZ(256 * sizeof(uint16_t)); rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &pThis->AddrKernelTokenIndex, paoffTokens, 256 * sizeof(uint16_t)); if (RT_SUCCESS(rc)) { /* * Figure out the kernel start and end. */ RTGCUINTPTR uKernelStart = pThis->AddrKernelAddresses.FlatPtr; RTGCUINTPTR uKernelEnd = pThis->AddrKernelTokenIndex.FlatPtr + 256 * sizeof(uint16_t); uint32_t i; if (cbGuestAddr == sizeof(uint64_t)) { uint64_t *pauAddrs = (uint64_t *)pvAddresses; for (i = 0; i < pThis->cKernelSymbols; i++) if ( pauAddrs[i] < uKernelStart && LNX64_VALID_ADDRESS(pauAddrs[i]) && uKernelStart - pauAddrs[i] < LNX_MAX_KERNEL_SIZE) uKernelStart = pauAddrs[i]; for (i = pThis->cKernelSymbols - 1; i > 0; i--) if ( pauAddrs[i] > uKernelEnd && LNX64_VALID_ADDRESS(pauAddrs[i]) && pauAddrs[i] - uKernelEnd < LNX_MAX_KERNEL_SIZE) uKernelEnd = pauAddrs[i]; } else { uint32_t *pauAddrs = (uint32_t *)pvAddresses; for (i = 0; i < pThis->cKernelSymbols; i++) if ( pauAddrs[i] < uKernelStart && LNX32_VALID_ADDRESS(pauAddrs[i]) && uKernelStart - pauAddrs[i] < LNX_MAX_KERNEL_SIZE) uKernelStart = pauAddrs[i]; for (i = pThis->cKernelSymbols - 1; i > 0; i--) if ( pauAddrs[i] > uKernelEnd && LNX32_VALID_ADDRESS(pauAddrs[i]) && pauAddrs[i] - uKernelEnd < LNX_MAX_KERNEL_SIZE) uKernelEnd = pauAddrs[i]; } RTGCUINTPTR cbKernel = uKernelEnd - uKernelStart; pThis->cbKernel = (uint32_t)cbKernel; DBGFR3AddrFromFlat(pUVM, &pThis->AddrKernelBase, uKernelStart); Log(("dbgDiggerLinuxLoadKernelSymbols: uKernelStart=%RGv cbKernel=%#x\n", uKernelStart, cbKernel)); /* * Create a module for the kernel. */ RTDBGMOD hMod; rc = RTDbgModCreate(&hMod, "vmlinux", cbKernel, 0 /*fFlags*/); if (RT_SUCCESS(rc)) { rc = RTDbgModSetTag(hMod, DIG_LNX_MOD_TAG); AssertRC(rc); rc = VINF_SUCCESS; /* * Enumerate the symbols. */ uint8_t const *pbCurAddr = (uint8_t const *)pvAddresses; uint32_t offName = 0; uint32_t cLeft = pThis->cKernelSymbols; while (cLeft-- > 0 && RT_SUCCESS(rc)) { /* Decode the symbol name first. */ if (RT_LIKELY(offName < pThis->cbKernelNames)) { uint8_t cbName = pbNames[offName++]; if (RT_LIKELY(offName + cbName <= pThis->cbKernelNames)) { char szSymbol[4096]; uint32_t offSymbol = 0; while (cbName-- > 0) { uint8_t bEnc = pbNames[offName++]; uint16_t offToken = paoffTokens[bEnc]; if (RT_LIKELY(offToken < pThis->cbKernelTokenTable)) { const char *pszToken = &pszzTokens[offToken]; char ch; while ((ch = *pszToken++) != '\0') if (offSymbol < sizeof(szSymbol) - 1) szSymbol[offSymbol++] = ch; } else { rc = VERR_INVALID_UTF8_ENCODING; break; } } szSymbol[offSymbol < sizeof(szSymbol) ? offSymbol : sizeof(szSymbol) - 1] = '\0'; /* The address. */ RTGCUINTPTR uSymAddr = cbGuestAddr == sizeof(uint64_t) ? *(uint64_t *)pbCurAddr : *(uint32_t *)pbCurAddr; pbCurAddr += cbGuestAddr; /* Add it without the type char. */ if (uSymAddr - uKernelStart <= cbKernel) { rc = RTDbgModSymbolAdd(hMod, &szSymbol[1], RTDBGSEGIDX_RVA, uSymAddr - uKernelStart, 0 /*cb*/, 0 /*fFlags*/, NULL); if (RT_FAILURE(rc)) { if ( rc == VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE || rc == VERR_DBG_INVALID_RVA || rc == VERR_DBG_ADDRESS_CONFLICT || rc == VERR_DBG_DUPLICATE_SYMBOL) { Log2(("dbgDiggerLinuxLoadKernelSymbols: RTDbgModSymbolAdd(,%s,) failed %Rrc (ignored)\n", szSymbol, rc)); rc = VINF_SUCCESS; } else Log(("dbgDiggerLinuxLoadKernelSymbols: RTDbgModSymbolAdd(,%s,) failed %Rrc\n", szSymbol, rc)); } } } else { rc = VERR_END_OF_STRING; Log(("dbgDiggerLinuxLoadKernelSymbols: offName=%#x cLeft=%#x cbName=%#x cbKernelNames=%#x\n", offName, cLeft, cbName, pThis->cbKernelNames)); } } else { rc = VERR_END_OF_STRING; Log(("dbgDiggerLinuxLoadKernelSymbols: offName=%#x cLeft=%#x cbKernelNames=%#x\n", offName, cLeft, pThis->cbKernelNames)); } } /* * Link the module into the address space. */ if (RT_SUCCESS(rc)) { RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL); if (hAs != NIL_RTDBGAS) rc = RTDbgAsModuleLink(hAs, hMod, uKernelStart, RTDBGASLINK_FLAGS_REPLACE); else rc = VERR_INTERNAL_ERROR; RTDbgAsRelease(hAs); } else Log(("dbgDiggerLinuxFindTokenIndex: Failed: %Rrc\n", rc)); RTDbgModRelease(hMod); } else Log(("dbgDiggerLinuxFindTokenIndex: RTDbgModCreate failed: %Rrc\n", rc)); } else Log(("dbgDiggerLinuxFindTokenIndex: Reading token index at %RGv failed: %Rrc\n", pThis->AddrKernelTokenIndex.FlatPtr, rc)); RTMemFree(paoffTokens); } else Log(("dbgDiggerLinuxFindTokenIndex: Reading token table at %RGv failed: %Rrc\n", pThis->AddrKernelTokenTable.FlatPtr, rc)); RTMemFree(pszzTokens); } else Log(("dbgDiggerLinuxFindTokenIndex: Reading encoded names at %RGv failed: %Rrc\n", pThis->AddrKernelNames.FlatPtr, rc)); RTMemFree(pbNames); } else Log(("dbgDiggerLinuxFindTokenIndex: Reading symbol addresses at %RGv failed: %Rrc\n", pThis->AddrKernelAddresses.FlatPtr, rc)); RTMemFree(pvAddresses); return rc; }