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 | |