diff options
Diffstat (limited to 'src/debug/di/valuehome.cpp')
-rw-r--r-- | src/debug/di/valuehome.cpp | 1062 |
1 files changed, 1062 insertions, 0 deletions
diff --git a/src/debug/di/valuehome.cpp b/src/debug/di/valuehome.cpp new file mode 100644 index 0000000000..837afd5f8b --- /dev/null +++ b/src/debug/di/valuehome.cpp @@ -0,0 +1,1062 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// File: ValueHome.cpp +// + +// +//***************************************************************************** +#include "stdafx.h" +#include "primitives.h" + +// constructor to initialize an instance of EnregisteredValueHome +// Arguments: +// input: pFrame - frame to which the value belongs +// output: no out parameters, but the instance has been initialized +EnregisteredValueHome::EnregisteredValueHome(const CordbNativeFrame * pFrame): + m_pFrame(pFrame) +{ + _ASSERTE(pFrame != NULL); +} + +// ---------------------------------------------------------------------------- +// RegValueHome member function implementations +// ---------------------------------------------------------------------------- + +// initialize an instance of RemoteAddress for use in an IPC event buffer with values from this +// instance of a derived class of EnregisteredValueHome (see EnregisteredValueHome::CopyToIPCEType for full +// header comment) +void RegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) +{ + pRegAddr->kind = RAK_REG; + pRegAddr->reg1 = m_reg1Info.m_kRegNumber; + pRegAddr->reg1Addr = CORDB_ADDRESS_TO_PTR(m_reg1Info.m_regAddr); + pRegAddr->reg1Value = m_reg1Info.m_regValue; +} // RegValueHome::CopyToIPCEType + +// RegValueHome::SetContextRegister +// This will update a register in a given context, and in the regdisplay of a given frame. +// Arguments: +// input: pContext - context from which the register comes +// regnum - enumeration constant indicating which register is to be updated +// newVal - the new value for the register contents +// output: no out parameters, but the new value will be written to the context and the frame +// Notes: We don't take a data target here because we are directly writing process memory and passing +// in a context, which has the location to update. +// Throws +void RegValueHome::SetContextRegister(DT_CONTEXT * pContext, + CorDebugRegister regNum, + SIZE_T newVal) +{ + LPVOID rdRegAddr; + +#define _UpdateFrame() \ + if (m_pFrame != NULL) \ + { \ + rdRegAddr = m_pFrame->GetAddressOfRegister(regNum); \ + *(SIZE_T *)rdRegAddr = newVal; \ + } + + switch(regNum) + { + case REGISTER_INSTRUCTION_POINTER: CORDbgSetIP(pContext, (LPVOID)newVal); break; + case REGISTER_STACK_POINTER: CORDbgSetSP(pContext, (LPVOID)newVal); break; + +#if defined(DBG_TARGET_X86) + case REGISTER_FRAME_POINTER: CORDbgSetFP(pContext, (LPVOID)newVal); + _UpdateFrame(); break; + + case REGISTER_X86_EAX: pContext->Eax = newVal; + _UpdateFrame(); break; + case REGISTER_X86_ECX: pContext->Ecx = newVal; + _UpdateFrame(); break; + case REGISTER_X86_EDX: pContext->Edx = newVal; + _UpdateFrame(); break; + case REGISTER_X86_EBX: pContext->Ebx = newVal; + _UpdateFrame(); break; + case REGISTER_X86_ESI: pContext->Esi = newVal; + _UpdateFrame(); break; + case REGISTER_X86_EDI: pContext->Edi = newVal; + _UpdateFrame(); break; + +#elif defined(DBG_TARGET_AMD64) + case REGISTER_AMD64_RBP: pContext->Rbp = newVal; + _UpdateFrame(); break; + case REGISTER_AMD64_RAX: pContext->Rax = newVal; + _UpdateFrame(); break; + case REGISTER_AMD64_RCX: pContext->Rcx = newVal; + _UpdateFrame(); break; + case REGISTER_AMD64_RDX: pContext->Rdx = newVal; + _UpdateFrame(); break; + case REGISTER_AMD64_RBX: pContext->Rbx = newVal; + _UpdateFrame(); break; + case REGISTER_AMD64_RSI: pContext->Rsi = newVal; + _UpdateFrame(); break; + case REGISTER_AMD64_RDI: pContext->Rdi = newVal; + _UpdateFrame(); break; + case REGISTER_AMD64_R8: pContext->R8 = newVal; + _UpdateFrame(); break; + case REGISTER_AMD64_R9: pContext->R9 = newVal; + _UpdateFrame(); break; + case REGISTER_AMD64_R10: pContext->R10 = newVal; + _UpdateFrame(); break; + case REGISTER_AMD64_R11: pContext->R11 = newVal; + _UpdateFrame(); break; + case REGISTER_AMD64_R12: pContext->R12 = newVal; + _UpdateFrame(); break; + case REGISTER_AMD64_R13: pContext->R13 = newVal; + _UpdateFrame(); break; + case REGISTER_AMD64_R14: pContext->R14 = newVal; + _UpdateFrame(); break; + case REGISTER_AMD64_R15: pContext->R15 = newVal; + _UpdateFrame(); break; +#elif defined(DBG_TARGET_ARM) + case REGISTER_ARM_R0: pContext->R0 = newVal; + _UpdateFrame(); break; + case REGISTER_ARM_R1: pContext->R1 = newVal; + _UpdateFrame(); break; + case REGISTER_ARM_R2: pContext->R2 = newVal; + _UpdateFrame(); break; + case REGISTER_ARM_R3: pContext->R3 = newVal; + _UpdateFrame(); break; + case REGISTER_ARM_R4: pContext->R4 = newVal; + _UpdateFrame(); break; + case REGISTER_ARM_R5: pContext->R5 = newVal; + _UpdateFrame(); break; + case REGISTER_ARM_R6: pContext->R6 = newVal; + _UpdateFrame(); break; + case REGISTER_ARM_R7: pContext->R7 = newVal; + _UpdateFrame(); break; + case REGISTER_ARM_R8: pContext->R8 = newVal; + _UpdateFrame(); break; + case REGISTER_ARM_R9: pContext->R9 = newVal; + _UpdateFrame(); break; + case REGISTER_ARM_R10: pContext->R10 = newVal; + _UpdateFrame(); break; + case REGISTER_ARM_R11: pContext->R11 = newVal; + _UpdateFrame(); break; + case REGISTER_ARM_R12: pContext->R12 = newVal; + _UpdateFrame(); break; + case REGISTER_ARM_LR: pContext->Lr = newVal; + _UpdateFrame(); break; +#elif defined(DBG_TARGET_ARM64) + case REGISTER_ARM64_X0: + case REGISTER_ARM64_X1: + case REGISTER_ARM64_X2: + case REGISTER_ARM64_X3: + case REGISTER_ARM64_X4: + case REGISTER_ARM64_X5: + case REGISTER_ARM64_X6: + case REGISTER_ARM64_X7: + case REGISTER_ARM64_X8: + case REGISTER_ARM64_X9: + case REGISTER_ARM64_X10: + case REGISTER_ARM64_X11: + case REGISTER_ARM64_X12: + case REGISTER_ARM64_X13: + case REGISTER_ARM64_X14: + case REGISTER_ARM64_X15: + case REGISTER_ARM64_X16: + case REGISTER_ARM64_X17: + case REGISTER_ARM64_X18: + case REGISTER_ARM64_X19: + case REGISTER_ARM64_X20: + case REGISTER_ARM64_X21: + case REGISTER_ARM64_X22: + case REGISTER_ARM64_X23: + case REGISTER_ARM64_X24: + case REGISTER_ARM64_X25: + case REGISTER_ARM64_X26: + case REGISTER_ARM64_X27: + case REGISTER_ARM64_X28: pContext->X[regNum - REGISTER_ARM64_X0] = newVal; + _UpdateFrame(); break; + + case REGISTER_ARM64_LR: pContext->Lr = newVal; + _UpdateFrame(); break; +#endif + default: + _ASSERTE(!"Invalid register number!"); + ThrowHR(E_FAIL); + } +} // RegValueHome::SetContextRegister + +// RegValueHome::SetEnregisteredValue +// set a remote enregistered location to a new value (see code:EnregisteredValueHome::SetEnregisteredValue +// for full header comment) +void RegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) +{ + SIZE_T extendedVal = 0; + + // If the value is in a reg, then it's going to be a register's width (regardless of + // the actual width of the data). + // For signed types, like i2, i1, make sure we sign extend. + + if (fIsSigned) + { + // Sign extend. SSIZE_T is a register size signed value. + // Casting + switch(newValue.Size()) + { + case 1: _ASSERTE(sizeof( BYTE) == 1); + extendedVal = (SSIZE_T) *(char*)newValue.StartAddress(); break; + case 2: _ASSERTE(sizeof( WORD) == 2); + extendedVal = (SSIZE_T) *(short*)newValue.StartAddress(); break; + case 4: _ASSERTE(sizeof(DWORD) == 4); + extendedVal = (SSIZE_T) *(int*)newValue.StartAddress(); break; +#if defined(DBG_TARGET_WIN64) + case 8: _ASSERTE(sizeof(ULONGLONG) == 8); + extendedVal = (SSIZE_T) *(ULONGLONG*)newValue.StartAddress(); break; +#endif // DBG_TARGET_WIN64 + default: _ASSERTE(!"bad size"); + } + } + else + { + // Zero extend. + switch(newValue.Size()) + { + case 1: _ASSERTE(sizeof( BYTE) == 1); + extendedVal = *( BYTE*)newValue.StartAddress(); break; + case 2: _ASSERTE(sizeof( WORD) == 2); + extendedVal = *( WORD*)newValue.StartAddress(); break; + case 4: _ASSERTE(sizeof(DWORD) == 4); + extendedVal = *(DWORD*)newValue.StartAddress(); break; +#if defined(DBG_TARGET_WIN64) + case 8: _ASSERTE(sizeof(ULONGLONG) == 8); + extendedVal = *(ULONGLONG*)newValue.StartAddress(); break; +#endif // DBG_TARGET_WIN64 + default: _ASSERTE(!"bad size"); + } + } + + SetContextRegister(pContext, m_reg1Info.m_kRegNumber, extendedVal); // throws +} // RegValueHome::SetEnregisteredValue + +// RegValueHome::GetEnregisteredValue +// Gets an enregistered value and returns it to the caller (see EnregisteredValueHome::GetEnregisteredValue +// for full header comment) +void RegValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) +{ + UINT_PTR* reg = m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber); + PREFIX_ASSUME(reg != NULL); + _ASSERTE(sizeof(*reg) == valueOutBuffer.Size()); + + memcpy(valueOutBuffer.StartAddress(), reg, sizeof(*reg)); +} // RegValueHome::GetEnregisteredValue + + +// ---------------------------------------------------------------------------- +// RegRegValueHome member function implementations +// ---------------------------------------------------------------------------- + +// initialize an instance of RemoteAddress for use in an IPC event buffer with values from this +// instance of a derived class of EnregisteredValueHome (see EnregisteredValueHome::CopyToIPCEType for full +// header comment) +void RegRegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) +{ + pRegAddr->kind = RAK_REGREG; + pRegAddr->reg1 = m_reg1Info.m_kRegNumber; + pRegAddr->reg1Addr = CORDB_ADDRESS_TO_PTR(m_reg1Info.m_regAddr); + pRegAddr->reg1Value = m_reg1Info.m_regValue; + pRegAddr->u.reg2 = m_reg2Info.m_kRegNumber; + pRegAddr->u.reg2Addr = CORDB_ADDRESS_TO_PTR(m_reg2Info.m_regAddr); + pRegAddr->u.reg2Value = m_reg2Info.m_regValue; +} // RegRegValueHome::CopyToIPCEType + +// RegRegValueHome::SetEnregisteredValue +// set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue +// for full header comment) +void RegRegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) +{ + _ASSERTE(newValue.Size() == 8); + _ASSERTE(REG_SIZE == sizeof(void*)); + + // Split the new value into high and low parts. + SIZE_T highPart; + SIZE_T lowPart; + + memcpy(&lowPart, newValue.StartAddress(), REG_SIZE); + memcpy(&highPart, (BYTE *)newValue.StartAddress() + REG_SIZE, REG_SIZE); + + // Update the proper registers. + SetContextRegister(pContext, m_reg1Info.m_kRegNumber, highPart); // throws + SetContextRegister(pContext, m_reg2Info.m_kRegNumber, lowPart); // throws + + // update the frame's register display + void * valueAddress = (void *)(m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber)); + memcpy(valueAddress, newValue.StartAddress(), newValue.Size()); +} // RegRegValueHome::SetEnregisteredValue + +// RegRegValueHome::GetEnregisteredValue +// Gets an enregistered value and returns it to the caller (see EnregisteredValueHome::GetEnregisteredValue +// for full header comment) +void RegRegValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) +{ + UINT_PTR* highWordAddr = m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber); + PREFIX_ASSUME(highWordAddr != NULL); + + UINT_PTR* lowWordAddr = m_pFrame->GetAddressOfRegister(m_reg2Info.m_kRegNumber); + PREFIX_ASSUME(lowWordAddr != NULL); + + _ASSERTE(sizeof(*highWordAddr) + sizeof(*lowWordAddr) == valueOutBuffer.Size()); + + memcpy(valueOutBuffer.StartAddress(), lowWordAddr, sizeof(*lowWordAddr)); + memcpy((BYTE *)valueOutBuffer.StartAddress() + sizeof(*lowWordAddr), highWordAddr, sizeof(*highWordAddr)); + +} // RegRegValueHome::GetEnregisteredValue + + +// ---------------------------------------------------------------------------- +// RegMemValueHome member function implementations +// ---------------------------------------------------------------------------- + +// initialize an instance of RemoteAddress for use in an IPC event buffer with values from this +// instance of a derived class of EnregisteredValueHome (see EnregisteredValueHome::CopyToIPCEType for full +// header comment) +void RegMemValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) +{ + pRegAddr->kind = RAK_REGMEM; + pRegAddr->reg1 = m_reg1Info.m_kRegNumber; + pRegAddr->reg1Addr = CORDB_ADDRESS_TO_PTR(m_reg1Info.m_regAddr); + pRegAddr->reg1Value = m_reg1Info.m_regValue; + pRegAddr->addr = m_memAddr; +} // RegMemValueHome::CopyToIPCEType + +// RegMemValueHome::SetEnregisteredValue +// set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue +// for full header comment) +void RegMemValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) +{ + _ASSERTE(newValue.Size() == REG_SIZE >> 1); // make sure we have bytes for two registers + _ASSERTE(REG_SIZE == sizeof(void*)); + + // Split the new value into high and low parts. + SIZE_T highPart; + SIZE_T lowPart; + + memcpy(&lowPart, newValue.StartAddress(), REG_SIZE); + memcpy(&highPart, (BYTE *)newValue.StartAddress() + REG_SIZE, REG_SIZE); + + // Update the proper registers. + SetContextRegister(pContext, m_reg1Info.m_kRegNumber, highPart); // throws + + _ASSERTE(REG_SIZE == sizeof(lowPart)); + HRESULT hr = m_pFrame->GetProcess()->SafeReadStruct(m_memAddr, &lowPart); + IfFailThrow(hr); + +} // RegMemValueHome::SetEnregisteredValue + +// RegMemValueHome::GetEnregisteredValue +// Gets an enregistered value and returns it to the caller (see EnregisteredValueHome::GetEnregisteredValue +// for full header comment) +void RegMemValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) +{ + // Read the high bits from the register... + UINT_PTR* highBitsAddr = m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber); + PREFIX_ASSUME(highBitsAddr != NULL); + + // ... and the low bits from the remote process + DWORD lowBits; + HRESULT hr = m_pFrame->GetProcess()->SafeReadStruct(m_memAddr, &lowBits); + IfFailThrow(hr); + + _ASSERTE(sizeof(lowBits)+sizeof(*highBitsAddr) == valueOutBuffer.Size()); + + memcpy(valueOutBuffer.StartAddress(), &lowBits, sizeof(lowBits)); + memcpy((BYTE *)valueOutBuffer.StartAddress() + sizeof(lowBits), highBitsAddr, sizeof(*highBitsAddr)); + +} // RegMemValueHome::GetEnregisteredValue + + +// ---------------------------------------------------------------------------- +// MemRegValueHome member function implementations +// ---------------------------------------------------------------------------- + +// initialize an instance of RemoteAddress for use in an IPC event buffer with values from this +// instance of a derived class of EnregisteredValueHome (see EnregisteredValueHome::CopyToIPCEType for full +// header comment) +void MemRegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) +{ + pRegAddr->kind = RAK_MEMREG; + pRegAddr->reg1 = m_reg1Info.m_kRegNumber; + pRegAddr->reg1Addr = CORDB_ADDRESS_TO_PTR(m_reg1Info.m_regAddr); + pRegAddr->reg1Value = m_reg1Info.m_regValue; + pRegAddr->addr = m_memAddr; +} // MemRegValueHome::CopyToIPCEType + +// MemRegValueHome::SetEnregisteredValue +// set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue +// for full header comment) +void MemRegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) +{ + _ASSERTE(newValue.Size() == REG_SIZE << 1); // make sure we have bytes for two registers + _ASSERTE(REG_SIZE == sizeof(void *)); + + // Split the new value into high and low parts. + SIZE_T highPart; + SIZE_T lowPart; + + memcpy(&lowPart, newValue.StartAddress(), REG_SIZE); + memcpy(&highPart, (BYTE *)newValue.StartAddress() + REG_SIZE, REG_SIZE); + + // Update the proper registers. + SetContextRegister(pContext, m_reg1Info.m_kRegNumber, lowPart); // throws + + _ASSERTE(REG_SIZE == sizeof(highPart)); + HRESULT hr = m_pFrame->GetProcess()->SafeWriteStruct(m_memAddr, &highPart); + IfFailThrow(hr); +} // MemRegValueHome::SetEnregisteredValue + +// MemRegValueHome::GetEnregisteredValue +// Gets an enregistered value and returns it to the caller (see EnregisteredValueHome::GetEnregisteredValue +// for full header comment) +void MemRegValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) +{ + // Read the high bits from the remote process' memory + DWORD highBits; + HRESULT hr = m_pFrame->GetProcess()->SafeReadStruct(m_memAddr, &highBits); + IfFailThrow(hr); + + + // and the low bits from a register + UINT_PTR* lowBitsAddr = m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber); + PREFIX_ASSUME(lowBitsAddr != NULL); + + _ASSERTE(sizeof(*lowBitsAddr)+sizeof(highBits) == valueOutBuffer.Size()); + + memcpy(valueOutBuffer.StartAddress(), lowBitsAddr, sizeof(*lowBitsAddr)); + memcpy((BYTE *)valueOutBuffer.StartAddress() + sizeof(*lowBitsAddr), &highBits, sizeof(highBits)); + +} // MemRegValueHome::GetEnregisteredValue + +#if !defined(DBG_TARGET_ARM) // @ARMTODO + +// ---------------------------------------------------------------------------- +// FloatRegValueHome member function implementations +// ---------------------------------------------------------------------------- + +// initialize an instance of RemoteAddress for use in an IPC event buffer with values from this +// instance of a derived class of EnregisteredValueHome (see EnregisteredValueHome::CopyToIPCEType for full +// header comment) +void FloatRegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) +{ + pRegAddr->kind = RAK_FLOAT; + pRegAddr->reg1Addr = NULL; + pRegAddr->floatIndex = m_floatIndex; +} // FloatRegValueHome::CopyToIPCEType + +// FloatValueHome::SetEnregisteredValue +// set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue +// for full header comment) +void FloatRegValueHome::SetEnregisteredValue(MemoryRange newValue, + DT_CONTEXT * pContext, + bool fIsSigned) +{ + // TODO: : implement CordbValue::SetEnregisteredValue for RAK_FLOAT + #if defined(DBG_TARGET_AMD64) + PORTABILITY_ASSERT("NYI: SetEnregisteredValue (divalue.cpp): RAK_FLOAT for AMD64"); + #endif // DBG_TARGET_AMD64 + + _ASSERTE((newValue.Size() == 4) || (newValue.Size() == 8)); + + // Convert the input to a double. + double newVal = 0.0; + + memcpy(&newVal, newValue.StartAddress(), newValue.Size()); + + #if defined(DBG_TARGET_X86) + + // This is unfortunately non-portable. Luckily we can live with this for now since we only support + // Win/X86 debugging a Mac/X86 platform. + + #if !defined(_TARGET_X86_) + #error Unsupported target platform + #endif // !_TARGET_X86_ + + // What a pain, on X86 take the floating + // point state in the context and make it our current FP + // state, set the value into the current FP state, then + // save out the FP state into the context again and + // restore our original state. + DT_FLOATING_SAVE_AREA currentFPUState; + + __asm fnsave currentFPUState // save the current FPU state. + + // Copy the state out of the context. + DT_FLOATING_SAVE_AREA floatarea = pContext->FloatSave; + floatarea.StatusWord &= 0xFF00; // remove any error codes. + floatarea.ControlWord |= 0x3F; // mask all exceptions. + + __asm + { + fninit + frstor floatarea ;; reload the threads FPU state. + } + + double td; // temp double + double popArea[DebuggerIPCE_FloatCount]; + + // Pop off until we reach the value we want to change. + DWORD i = 0; + + while (i <= m_floatIndex) + { + __asm fstp td + popArea[i++] = td; + } + + __asm fld newVal; // push on the new value. + + // Push any values that we popled off back onto the stack, + // _except_ the last one, which was the one we changed. + i--; + + while (i > 0) + { + td = popArea[--i]; + __asm fld td + } + + // Save out the modified float area. + __asm fnsave floatarea + + // Put it into the context. + pContext->FloatSave= floatarea; + + // Restore our FPU state + __asm + { + fninit + frstor currentFPUState ;; restore our saved FPU state. + } + #endif // DBG_TARGET_X86 + + // update the thread's floating point stack + void * valueAddress = (void *) &(m_pFrame->m_pThread->m_floatValues[m_floatIndex]); + memcpy(valueAddress, newValue.StartAddress(), newValue.Size()); +} // FloatValueHome::SetEnregisteredValue + +// FloatRegValueHome::GetEnregisteredValue +// Throws E_NOTIMPL for attempts to get an enregistered value for a float register +void FloatRegValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) +{ + _ASSERTE(!"invalid variable home"); + ThrowHR(E_NOTIMPL); +} // FloatRegValueHome::GetEnregisteredValue + +#endif // !DBG_TARGET_ARM @ARMTODO + +// ============================================================================ +// RemoteValueHome implementation +// ============================================================================ + + // constructor + // Arguments: + // input: pProcess - the process to which the value belongs + // remoteValue - a buffer with the target address of the value and its size + // Note: It's possible a particular instance of CordbGenericValue may have neither a remote address nor a + // register address--FuncEval makes empty GenericValues for literals but for those, we will make a + // RegisterValueHome,so we can assert that we have a non-null remote address here + RemoteValueHome::RemoteValueHome(CordbProcess * pProcess, TargetBuffer remoteValue): + ValueHome(pProcess), + m_remoteValue(remoteValue) + { + _ASSERTE(remoteValue.pAddress != NULL); + } // RemoteValueHome::RemoteValueHome + +// Gets a value and returns it in dest +// virtual +void RemoteValueHome::GetValue(MemoryRange dest) +{ + _ASSERTE(dest.Size() == m_remoteValue.cbSize); + _ASSERTE((!m_remoteValue.IsEmpty()) && (dest.StartAddress() != NULL)); + m_pProcess->SafeReadBuffer(m_remoteValue, (BYTE *)dest.StartAddress()); +} // RemoteValueHome::GetValue + +// Sets a location to the value provided in src +// virtual +void RemoteValueHome::SetValue(MemoryRange src, CordbType * pType) +{ + _ASSERTE(!m_remoteValue.IsEmpty()); + _ASSERTE(src.Size() == m_remoteValue.cbSize); + _ASSERTE(src.StartAddress() != NULL); + m_pProcess->SafeWriteBuffer(m_remoteValue, (BYTE *)src.StartAddress()); +} // RemoteValueHome::SetValue + +// creates an ICDValue for a field or array element or for the value type of a boxed object +// virtual +void RemoteValueHome::CreateInternalValue(CordbType * pType, + SIZE_T offset, + void * localAddress, + ULONG32 size, + ICorDebugValue ** ppValue) +{ + // If we're creating an ICDValue for a field added with EnC, the local address will be null, since the field + // will not be included with the local cached copy of the ICDObjectValue to which the field belongs. + // This means we need to compute the size for the type of the field, and then determine whether this + // should also be the size for the localValue we pass to CreateValueByType. The only way we can tell if this + // is an EnC added field is if the local address is NULL. + ULONG32 localSize = localAddress != NULL ? size : 0; + + CordbAppDomain * pAppdomain = pType->GetAppDomain(); + + CordbValue::CreateValueByType(pAppdomain, + pType, + kUnboxed, + TargetBuffer(m_remoteValue.pAddress + offset, size), + MemoryRange(localAddress, localSize), + NULL, // remote reg + ppValue); // throws +} // RemoteValueHome::CreateInternalValue + +// Gets the value of a field or element of an existing ICDValue instance and returns it in dest +void RemoteValueHome::GetInternalValue(MemoryRange dest, SIZE_T offset) +{ + _ASSERTE((!m_remoteValue.IsEmpty()) && (dest.StartAddress() != NULL)); + + m_pProcess->SafeReadBuffer(TargetBuffer(m_remoteValue.pAddress + offset, (ULONG)dest.Size()), + (BYTE *)dest.StartAddress()); +} // RemoteValueHome::GetInternalValue + +// copies the register information from this to a RemoteAddress instance +// virtual +void RemoteValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) +{ + pRegAddr->kind = RAK_NONE; +} // RegisterValueHome::CopyToIPCEType + + +// ============================================================================ +// RegisterValueHome implementation +// ============================================================================ + +// constructor +// Arguments: +// input: pProcess - process for this value +// ppRemoteRegAddr - enregistered value information +// +RegisterValueHome::RegisterValueHome(CordbProcess * pProcess, + EnregisteredValueHomeHolder * ppRemoteRegAddr): + ValueHome(pProcess) +{ + EnregisteredValueHome * pRemoteRegAddr = ppRemoteRegAddr == NULL ? NULL : ppRemoteRegAddr->GetValue(); + // in the general case, we should have either a remote address or a register address, but FuncEval makes + // empty GenericValues for literals, so it's possible that we have neither address + + if (pRemoteRegAddr != NULL) + { + m_pRemoteRegAddr = pRemoteRegAddr; + // be sure not to delete the remote register information on exit + ppRemoteRegAddr->SuppressRelease(); + } + else + { + m_pRemoteRegAddr = NULL; + } + } // RegisterValueHome::RegisterValueHome + +// clean up resources as necessary +void RegisterValueHome::Clear() +{ + if (m_pRemoteRegAddr != NULL) + { + delete m_pRemoteRegAddr; + m_pRemoteRegAddr = NULL; + } +} // RegisterValueHome::Clear + +// Gets a value and returns it in dest +// virtual +void RegisterValueHome::GetValue(MemoryRange dest) +{ + // FuncEval makes empty CordbGenericValue instances for literals, which will have a RegisterValueHome, + // but we should not be calling this in that case; we should be able to assert that the register + // address isn't NULL + _ASSERTE(m_pRemoteRegAddr != NULL); + m_pRemoteRegAddr->GetEnregisteredValue(dest); // throws +} // RegisterValueHome::GetValue + +// Sets a location to the value provided in src +void RegisterValueHome::SetValue(MemoryRange src, CordbType * pType) +{ + SetEnregisteredValue(src, IsSigned(pType->m_elementType)); // throws +} // RegisterValueHome::SetValue + +// creates an ICDValue for a field or array element or for the value type of a boxed object +// virtual +void RegisterValueHome::CreateInternalValue(CordbType * pType, + SIZE_T offset, + void * localAddress, + ULONG32 size, + ICorDebugValue ** ppValue) +{ + TargetBuffer remoteValue(PTR_TO_CORDB_ADDRESS((void *)NULL),0); + EnregisteredValueHomeHolder pRemoteReg(NULL); + + _ASSERTE(m_pRemoteRegAddr != NULL); + // Remote register address is the same as the parent.... + /* + * <TODO> + * nickbe 10/17/2002 07:31:53 + * If this object consists of two register-sized fields, e.g. + * struct Point + * { + * int x; + * int y; + * }; + * then the variable home of this object is not necessarily the variable + * home for member data within this object. For example, if we have + * Point p; + * and p.x is in a register, while p.y is in memory, then clearly the + * home of p (RAK_REGMEM) is not the same as the home of p.x (RAK_MEM). + * + * Currently the JIT does not split compound objects in this way. It + * will only split an object that has exactly one field that is twice + * the size of the register + * </TODO> + */ + _ASSERTE(offset == 0); + pRemoteReg.Assign(m_pRemoteRegAddr->Clone()); + + EnregisteredValueHomeHolder * pRegHolder = pRemoteReg.GetAddr(); + + // create a value for the member field. + CordbValue::CreateValueByType(pType->GetAppDomain(), + pType, + kUnboxed, + EMPTY_BUFFER, // remote address + MemoryRange(localAddress, size), + pRegHolder, + ppValue); // throws +} // RegisterValueHome::CreateInternalValue + +// Gets the value of a field or element of an existing ICDValue instance and returns it in dest +// virtual +void RegisterValueHome::GetInternalValue(MemoryRange dest, SIZE_T offset) +{ + // currently, we can't have an enregistered value that has more than one field or element, so + // there's nothing to do here but ASSERT. If the JIT changes what can be enregistered, we'll have + // work to do here + _ASSERTE(!"Compound types are not enregistered--we shouldn't be here"); + ThrowHR(E_INVALIDARG); +} // RegisterValueHome::GetInternalValue + + +// copies the register information from this to a RemoteAddress instance +// virtual +void RegisterValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) +{ + if(m_pRemoteRegAddr != NULL) + { + m_pRemoteRegAddr->CopyToIPCEType(pRegAddr); + } + else + { + pRegAddr->kind = RAK_NONE; + } +} // RegisterValueHome::CopyToIPCEType + +// sets a remote enregistered location to a new value +// Arguments: +// input: src - contains the new value +// fIsSigned - indicates whether the new value is signed (needed for proper extension +// Return value: S_OK on success or CORDBG_E_SET_VALUE_NOT_ALLOWED_ON_NONLEAF_FRAME, CORDBG_E_CONTEXT_UNVAILABLE, +// or HRESULT values from writing process memory +void RegisterValueHome::SetEnregisteredValue(MemoryRange src, bool fIsSigned) +{ + _ASSERTE(m_pRemoteRegAddr != NULL); + // Get the thread's context so we can update it. + DT_CONTEXT * cTemp; + const CordbNativeFrame * frame = m_pRemoteRegAddr->GetFrame(); + + // Can't set an enregistered value unless the frame the value was + // from is also the current leaf frame. This is because we don't + // track where we get the registers from every frame from. + + if (!frame->IsLeafFrame()) + { + ThrowHR(CORDBG_E_SET_VALUE_NOT_ALLOWED_ON_NONLEAF_FRAME); + } + + HRESULT hr = S_OK; + EX_TRY + { + // This may throw, in which case we want to return our own HRESULT. + hr = frame->m_pThread->GetManagedContext(&cTemp); + } + EX_CATCH_HRESULT(hr); + if (FAILED(hr)) + { + // If we failed to get the context, then we must not be in a leaf frame. + ThrowHR(CORDBG_E_SET_VALUE_NOT_ALLOWED_ON_NONLEAF_FRAME); + } + + // Its important to copy this context that we're given a ptr to. + DT_CONTEXT c; + c = *cTemp; + + m_pRemoteRegAddr->SetEnregisteredValue(src, &c, fIsSigned); + + // Set the thread's modified context. + IfFailThrow(frame->m_pThread->SetManagedContext(&c)); +} // RegisterValueHome::SetEnregisteredValue + + +// Get an enregistered value from the register display of the native frame +// Arguments: +// output: dest - buffer will hold the register value +// Note: Throws E_NOTIMPL for attempts to get an enregistered value for a float register +// or for 64-bit platforms +void RegisterValueHome::GetEnregisteredValue(MemoryRange dest) +{ +#if !defined(DBG_TARGET_X86) + _ASSERTE(!"@TODO IA64/AMD64 -- Not Yet Implemented"); + ThrowHR(E_NOTIMPL); +#else // DBG_TARGET_X86 + _ASSERTE(m_pRemoteRegAddr != NULL); + + m_pRemoteRegAddr->GetEnregisteredValue(dest); // throws +#endif // !DBG_TARGET_X86 +} // RegisterValueHome::GetEnregisteredValue + +// Is this a signed type or unsigned type? +// Useful to known when we need to sign-extend. +bool RegisterValueHome::IsSigned(CorElementType elementType) +{ + switch (elementType) + { + case ELEMENT_TYPE_I1: + case ELEMENT_TYPE_I2: + case ELEMENT_TYPE_I4: + case ELEMENT_TYPE_I8: + case ELEMENT_TYPE_I: + return true; + + default: + return false; + } +} // RegisterValueHome::IsSigned + +// ============================================================================ +// HandleValueHome implementation +// ============================================================================ + +// +CORDB_ADDRESS HandleValueHome::GetAddress() +{ + _ASSERTE((m_pProcess != NULL) && !m_vmObjectHandle.IsNull()); + CORDB_ADDRESS handle = PTR_TO_CORDB_ADDRESS((void *)NULL); + EX_TRY + { + handle = m_pProcess->GetDAC()->GetHandleAddressFromVmHandle(m_vmObjectHandle); + } + EX_CATCH + { + } + EX_END_CATCH(SwallowAllExceptions); + return handle; +} + +// Gets a value and returns it in dest +// virtual +void HandleValueHome::GetValue(MemoryRange dest) +{ + _ASSERTE((m_pProcess != NULL) && !m_vmObjectHandle.IsNull()); + CORDB_ADDRESS objPtr = PTR_TO_CORDB_ADDRESS((void *)NULL); + objPtr = m_pProcess->GetDAC()->GetHandleAddressFromVmHandle(m_vmObjectHandle); + + _ASSERTE(dest.Size() <= sizeof(void *)); + _ASSERTE(dest.StartAddress() != NULL); + _ASSERTE(objPtr != NULL); + m_pProcess->SafeReadBuffer(TargetBuffer(objPtr, sizeof(void *)), (BYTE *)dest.StartAddress()); +} // HandleValueHome::GetValue + +// Sets a location to the value provided in src +// virtual +void HandleValueHome::SetValue(MemoryRange src, CordbType * pType) +{ + _ASSERTE(!m_vmObjectHandle.IsNull()); + + DebuggerIPCEvent event; + + m_pProcess->InitIPCEvent(&event, DB_IPCE_SET_REFERENCE, true, VMPTR_AppDomain::NullPtr()); + + event.SetReference.objectRefAddress = NULL; + event.SetReference.vmObjectHandle = m_vmObjectHandle; + event.SetReference.newReference = *((void **)src.StartAddress()); + + // Note: two-way event here... + IfFailThrow(m_pProcess->SendIPCEvent(&event, sizeof(DebuggerIPCEvent))); + + _ASSERTE(event.type == DB_IPCE_SET_REFERENCE_RESULT); + + IfFailThrow(event.hr); +} // HandleValueHome::SetValue + +// creates an ICDValue for a field or array element or for the value type of a boxed object +// virtual +void HandleValueHome::CreateInternalValue(CordbType * pType, + SIZE_T offset, + void * localAddress, + ULONG32 size, + ICorDebugValue ** ppValue) +{ + _ASSERTE(!"References don't have sub-objects--we shouldn't be here"); + ThrowHR(E_INVALIDARG); + +} // HandleValueHome::CreateInternalValue + +// Gets the value of a field or element of an existing ICDValue instance and returns it in dest +// virtual +void HandleValueHome::GetInternalValue(MemoryRange dest, SIZE_T offset) +{ + _ASSERTE(!"References don't have sub-objects--we shouldn't be here"); + ThrowHR(E_INVALIDARG); +} // HandleValueHome::GetInternalValue + +// copies the register information from this to a RemoteAddress instance +// virtual +void HandleValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) +{ + pRegAddr->kind = RAK_NONE; +} // HandleValueHome::CopyToIPCEType + +// ============================================================================ +// VCRemoteValueHome implementation +// ============================================================================ + +// Sets a location to the value provided in src +// Arguments: +// input: src - buffer containing the new value to be set--memory for this buffer is owned by the caller +// pType - type information for the value +// output: none, but sets the value on success +// Note: Throws CORDBG_E_CLASS_NOT_LOADED or errors from WriteProcessMemory or +// GetRemoteBuffer on failure +void VCRemoteValueHome::SetValue(MemoryRange src, CordbType * pType) +{ + _ASSERTE(!m_remoteValue.IsEmpty()); + + // send a Set Value Class message to the right side with the address of this value class, the address of + // the new data, and the class of the value class that we're setting. + DebuggerIPCEvent event; + + // First, we have to make room on the Left Side for the new data for the value class. We allocate + // memory on the Left Side for this, then write the new data across. The Set Value Class message will + // free the buffer when its done. + void *buffer = NULL; + IfFailThrow(m_pProcess->GetAndWriteRemoteBuffer(NULL, + m_remoteValue.cbSize, + CORDB_ADDRESS_TO_PTR(src.StartAddress()), + &buffer)); + + // Finally, send over the Set Value Class message. + m_pProcess->InitIPCEvent(&event, DB_IPCE_SET_VALUE_CLASS, true, VMPTR_AppDomain::NullPtr()); + event.SetValueClass.oldData = CORDB_ADDRESS_TO_PTR(m_remoteValue.pAddress); + event.SetValueClass.newData = buffer; + IfFailThrow(pType->TypeToBasicTypeData(&event.SetValueClass.type)); + + // Note: two-way event here... + IfFailThrow(m_pProcess->SendIPCEvent(&event, sizeof(DebuggerIPCEvent))); + + _ASSERTE(event.type == DB_IPCE_SET_VALUE_CLASS_RESULT); + + IfFailThrow(event.hr); +} // VCRemoteValueHome::SetValue + + +// ============================================================================ +// RefRemoteValueHome implementation +// ============================================================================ + +// constructor +// Arguments: +// input: pProcess - process for this value +// remoteValue - remote location information +// vmObjHandle - object handle +RefRemoteValueHome ::RefRemoteValueHome (CordbProcess * pProcess, + TargetBuffer remoteValue): + RemoteValueHome(pProcess, remoteValue) +{ + // caller supplies remoteValue, to work w/ Func-eval. + _ASSERTE((!remoteValue.IsEmpty()) && (remoteValue.cbSize == sizeof (void *))); + +} // RefRemoteValueHome::RefRemoteValueHome + +// Sets a location to the value provided in src +// Arguments: +// input: src - buffer containing the new value to be set--memory for this buffer is owned by the caller +// pType - type information for the value +// output: none, but sets the value on success +// Return Value: S_OK on success or CORDBG_E_CLASS_NOT_LOADED or errors from WriteProcessMemory or +// GetRemoteBuffer on failure +void RefRemoteValueHome::SetValue(MemoryRange src, CordbType * pType) +{ + // We had better have a remote address. + _ASSERTE(!m_remoteValue.IsEmpty()); + + // send a Set Reference message to the right side with the address of this reference and whether or not + // the reference points to a handle. + + // If it's a reference but not a GC root then just we can just treat it like raw data (like a DWORD). + // This would include things like "int*", and E_T_FNPTR. If it is a GC root, then we need to go over to + // the LS to update the WriteBarrier. + if ((pType != NULL) && !pType->IsGCRoot()) + { + m_pProcess->SafeWriteBuffer(m_remoteValue, (BYTE *)src.StartAddress()); + } + else + { + DebuggerIPCEvent event; + + m_pProcess->InitIPCEvent(&event, DB_IPCE_SET_REFERENCE, true, VMPTR_AppDomain::NullPtr()); + + event.SetReference.objectRefAddress = CORDB_ADDRESS_TO_PTR(m_remoteValue.pAddress); + event.SetReference.vmObjectHandle = VMPTR_OBJECTHANDLE::NullPtr(); + event.SetReference.newReference = *((void **)src.StartAddress()); + + // Note: two-way event here... + IfFailThrow(m_pProcess->SendIPCEvent(&event, sizeof(DebuggerIPCEvent))); + + _ASSERTE(event.type == DB_IPCE_SET_REFERENCE_RESULT); + + IfFailThrow(event.hr); + } +} // RefRemoteValueHome::SetValue + +// ============================================================================ +// RefValueHome implementation +// ============================================================================ + +// constructor +// Only one of the location types should be non-NULL, but we pass all of them to the +// constructor so we can instantiate m_pHome correctly. +// Arguments: +// input: pProcess - process to which the value belongs +// remoteValue - a target location holding the object reference +// ppRemoteRegAddr - information about the register that holds the object ref +// vmObjHandle - an object handle that holds the object ref +RefValueHome::RefValueHome(CordbProcess * pProcess, + TargetBuffer remoteValue, + EnregisteredValueHomeHolder * ppRemoteRegAddr, + VMPTR_OBJECTHANDLE vmObjHandle) +{ + if (!remoteValue.IsEmpty()) + { + NewHolder<ValueHome> pHome(new RefRemoteValueHome(pProcess, remoteValue)); + m_fNullObjHandle = true; + } + else if (!vmObjHandle.IsNull()) + { + NewHolder<ValueHome> pHome(new HandleValueHome(pProcess, vmObjHandle)); + m_fNullObjHandle = false; + } + else + { + NewHolder<ValueHome> pHome(new RegisterValueHome(pProcess, ppRemoteRegAddr)); + m_fNullObjHandle = true; + } + + +} // RefValueHome::RefValueHome + |