| 1 | //===-- RegisterContextMemory.cpp -----------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "RegisterContextMemory.h" |
| 10 | |
| 11 | #include "lldb/Target/Process.h" |
| 12 | #include "lldb/Target/Thread.h" |
| 13 | #include "lldb/Utility/DataBufferHeap.h" |
| 14 | #include "lldb/Utility/RegisterValue.h" |
| 15 | #include "lldb/Utility/Status.h" |
| 16 | |
| 17 | using namespace lldb; |
| 18 | using namespace lldb_private; |
| 19 | |
| 20 | // RegisterContextMemory constructor |
| 21 | RegisterContextMemory::RegisterContextMemory(Thread &thread, |
| 22 | uint32_t concrete_frame_idx, |
| 23 | DynamicRegisterInfo ®_infos, |
| 24 | addr_t reg_data_addr) |
| 25 | : RegisterContext(thread, concrete_frame_idx), m_reg_infos(reg_infos), |
| 26 | m_reg_valid(), m_reg_data(), m_reg_data_addr(reg_data_addr) { |
| 27 | // Resize our vector of bools to contain one bool for every register. We will |
| 28 | // use these boolean values to know when a register value is valid in |
| 29 | // m_reg_data. |
| 30 | const size_t num_regs = reg_infos.GetNumRegisters(); |
| 31 | assert(num_regs > 0); |
| 32 | m_reg_valid.resize(new_size: num_regs); |
| 33 | |
| 34 | // Make a heap based buffer that is big enough to store all registers |
| 35 | m_data = |
| 36 | std::make_shared<DataBufferHeap>(args: reg_infos.GetRegisterDataByteSize(), args: 0); |
| 37 | m_reg_data.SetData(data_sp: m_data); |
| 38 | } |
| 39 | |
| 40 | // Destructor |
| 41 | RegisterContextMemory::~RegisterContextMemory() = default; |
| 42 | |
| 43 | void RegisterContextMemory::InvalidateAllRegisters() { |
| 44 | if (m_reg_data_addr != LLDB_INVALID_ADDRESS) |
| 45 | SetAllRegisterValid(false); |
| 46 | } |
| 47 | |
| 48 | void RegisterContextMemory::SetAllRegisterValid(bool b) { |
| 49 | std::vector<bool>::iterator pos, end = m_reg_valid.end(); |
| 50 | for (pos = m_reg_valid.begin(); pos != end; ++pos) |
| 51 | *pos = b; |
| 52 | } |
| 53 | |
| 54 | size_t RegisterContextMemory::GetRegisterCount() { |
| 55 | return m_reg_infos.GetNumRegisters(); |
| 56 | } |
| 57 | |
| 58 | const RegisterInfo *RegisterContextMemory::GetRegisterInfoAtIndex(size_t reg) { |
| 59 | return m_reg_infos.GetRegisterInfoAtIndex(i: reg); |
| 60 | } |
| 61 | |
| 62 | size_t RegisterContextMemory::GetRegisterSetCount() { |
| 63 | return m_reg_infos.GetNumRegisterSets(); |
| 64 | } |
| 65 | |
| 66 | const RegisterSet *RegisterContextMemory::GetRegisterSet(size_t reg_set) { |
| 67 | return m_reg_infos.GetRegisterSet(i: reg_set); |
| 68 | } |
| 69 | |
| 70 | uint32_t RegisterContextMemory::ConvertRegisterKindToRegisterNumber( |
| 71 | lldb::RegisterKind kind, uint32_t num) { |
| 72 | return m_reg_infos.ConvertRegisterKindToRegisterNumber(kind, num); |
| 73 | } |
| 74 | |
| 75 | bool RegisterContextMemory::ReadRegister(const RegisterInfo *reg_info, |
| 76 | RegisterValue ®_value) { |
| 77 | const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB]; |
| 78 | if (!m_reg_valid[reg_num]) { |
| 79 | if (!ReadAllRegisterValues(data_sp&: m_data)) |
| 80 | return false; |
| 81 | } |
| 82 | const bool partial_data_ok = false; |
| 83 | return reg_value |
| 84 | .SetValueFromData(reg_info: *reg_info, data&: m_reg_data, offset: reg_info->byte_offset, |
| 85 | partial_data_ok) |
| 86 | .Success(); |
| 87 | } |
| 88 | |
| 89 | bool RegisterContextMemory::WriteRegister(const RegisterInfo *reg_info, |
| 90 | const RegisterValue ®_value) { |
| 91 | if (m_reg_data_addr != LLDB_INVALID_ADDRESS) { |
| 92 | const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB]; |
| 93 | addr_t reg_addr = m_reg_data_addr + reg_info->byte_offset; |
| 94 | Status error(WriteRegisterValueToMemory(reg_info, dst_addr: reg_addr, |
| 95 | dst_len: reg_info->byte_size, reg_value)); |
| 96 | m_reg_valid[reg_num] = false; |
| 97 | return error.Success(); |
| 98 | } |
| 99 | return false; |
| 100 | } |
| 101 | |
| 102 | bool RegisterContextMemory::ReadAllRegisterValues( |
| 103 | WritableDataBufferSP &data_sp) { |
| 104 | if (m_reg_data_addr != LLDB_INVALID_ADDRESS) { |
| 105 | ProcessSP process_sp(CalculateProcess()); |
| 106 | if (process_sp) { |
| 107 | Status error; |
| 108 | if (process_sp->ReadMemory(vm_addr: m_reg_data_addr, buf: data_sp->GetBytes(), |
| 109 | size: data_sp->GetByteSize(), |
| 110 | error) == data_sp->GetByteSize()) { |
| 111 | SetAllRegisterValid(true); |
| 112 | return true; |
| 113 | } |
| 114 | } |
| 115 | } |
| 116 | return false; |
| 117 | } |
| 118 | |
| 119 | bool RegisterContextMemory::WriteAllRegisterValues( |
| 120 | const DataBufferSP &data_sp) { |
| 121 | if (m_reg_data_addr != LLDB_INVALID_ADDRESS) { |
| 122 | ProcessSP process_sp(CalculateProcess()); |
| 123 | if (process_sp) { |
| 124 | Status error; |
| 125 | SetAllRegisterValid(false); |
| 126 | if (process_sp->WriteMemory(vm_addr: m_reg_data_addr, buf: data_sp->GetBytes(), |
| 127 | size: data_sp->GetByteSize(), |
| 128 | error) == data_sp->GetByteSize()) |
| 129 | return true; |
| 130 | } |
| 131 | } |
| 132 | return false; |
| 133 | } |
| 134 | |
| 135 | void RegisterContextMemory::SetAllRegisterData( |
| 136 | const lldb::DataBufferSP &data_sp) { |
| 137 | m_reg_data.SetData(data_sp); |
| 138 | SetAllRegisterValid(true); |
| 139 | } |
| 140 | |