1 | //===-- RegisterContextThreadMemory.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 "lldb/Target/OperatingSystem.h" |
10 | #include "lldb/Target/Process.h" |
11 | #include "lldb/Target/Thread.h" |
12 | #include "lldb/Utility/Status.h" |
13 | #include "lldb/lldb-private.h" |
14 | |
15 | #include "RegisterContextThreadMemory.h" |
16 | |
17 | using namespace lldb; |
18 | using namespace lldb_private; |
19 | |
20 | RegisterContextThreadMemory::RegisterContextThreadMemory( |
21 | Thread &thread, lldb::addr_t register_data_addr) |
22 | : RegisterContext(thread, 0), m_thread_wp(thread.shared_from_this()), |
23 | m_reg_ctx_sp(), m_register_data_addr(register_data_addr), m_stop_id(0) {} |
24 | |
25 | RegisterContextThreadMemory::~RegisterContextThreadMemory() = default; |
26 | |
27 | void RegisterContextThreadMemory::UpdateRegisterContext() { |
28 | ThreadSP thread_sp(m_thread_wp.lock()); |
29 | if (thread_sp) { |
30 | ProcessSP process_sp(thread_sp->GetProcess()); |
31 | |
32 | if (process_sp) { |
33 | const uint32_t stop_id = process_sp->GetModID().GetStopID(); |
34 | if (m_stop_id != stop_id) { |
35 | m_stop_id = stop_id; |
36 | m_reg_ctx_sp.reset(); |
37 | } |
38 | if (!m_reg_ctx_sp) { |
39 | ThreadSP backing_thread_sp(thread_sp->GetBackingThread()); |
40 | if (backing_thread_sp) { |
41 | m_reg_ctx_sp = backing_thread_sp->GetRegisterContext(); |
42 | } else { |
43 | OperatingSystem *os = process_sp->GetOperatingSystem(); |
44 | if (os->IsOperatingSystemPluginThread(thread_sp)) |
45 | m_reg_ctx_sp = os->CreateRegisterContextForThread( |
46 | thread: thread_sp.get(), reg_data_addr: m_register_data_addr); |
47 | } |
48 | } |
49 | } else { |
50 | m_reg_ctx_sp.reset(); |
51 | } |
52 | } else { |
53 | m_reg_ctx_sp.reset(); |
54 | } |
55 | } |
56 | |
57 | // Subclasses must override these functions |
58 | void RegisterContextThreadMemory::InvalidateAllRegisters() { |
59 | UpdateRegisterContext(); |
60 | if (m_reg_ctx_sp) |
61 | m_reg_ctx_sp->InvalidateAllRegisters(); |
62 | } |
63 | |
64 | size_t RegisterContextThreadMemory::GetRegisterCount() { |
65 | UpdateRegisterContext(); |
66 | if (m_reg_ctx_sp) |
67 | return m_reg_ctx_sp->GetRegisterCount(); |
68 | return 0; |
69 | } |
70 | |
71 | const RegisterInfo * |
72 | RegisterContextThreadMemory::GetRegisterInfoAtIndex(size_t reg) { |
73 | UpdateRegisterContext(); |
74 | if (m_reg_ctx_sp) |
75 | return m_reg_ctx_sp->GetRegisterInfoAtIndex(reg); |
76 | return nullptr; |
77 | } |
78 | |
79 | size_t RegisterContextThreadMemory::GetRegisterSetCount() { |
80 | UpdateRegisterContext(); |
81 | if (m_reg_ctx_sp) |
82 | return m_reg_ctx_sp->GetRegisterSetCount(); |
83 | return 0; |
84 | } |
85 | |
86 | const RegisterSet *RegisterContextThreadMemory::GetRegisterSet(size_t reg_set) { |
87 | UpdateRegisterContext(); |
88 | if (m_reg_ctx_sp) |
89 | return m_reg_ctx_sp->GetRegisterSet(reg_set); |
90 | return nullptr; |
91 | } |
92 | |
93 | bool RegisterContextThreadMemory::ReadRegister(const RegisterInfo *reg_info, |
94 | RegisterValue ®_value) { |
95 | UpdateRegisterContext(); |
96 | if (m_reg_ctx_sp) |
97 | return m_reg_ctx_sp->ReadRegister(reg_info, reg_value); |
98 | return false; |
99 | } |
100 | |
101 | bool RegisterContextThreadMemory::WriteRegister( |
102 | const RegisterInfo *reg_info, const RegisterValue ®_value) { |
103 | UpdateRegisterContext(); |
104 | if (m_reg_ctx_sp) |
105 | return m_reg_ctx_sp->WriteRegister(reg_info, reg_value); |
106 | return false; |
107 | } |
108 | |
109 | bool RegisterContextThreadMemory::ReadAllRegisterValues( |
110 | lldb::WritableDataBufferSP &data_sp) { |
111 | UpdateRegisterContext(); |
112 | if (m_reg_ctx_sp) |
113 | return m_reg_ctx_sp->ReadAllRegisterValues(data_sp); |
114 | return false; |
115 | } |
116 | |
117 | bool RegisterContextThreadMemory::WriteAllRegisterValues( |
118 | const lldb::DataBufferSP &data_sp) { |
119 | UpdateRegisterContext(); |
120 | if (m_reg_ctx_sp) |
121 | return m_reg_ctx_sp->WriteAllRegisterValues(data_sp); |
122 | return false; |
123 | } |
124 | |
125 | bool RegisterContextThreadMemory::CopyFromRegisterContext( |
126 | lldb::RegisterContextSP reg_ctx_sp) { |
127 | UpdateRegisterContext(); |
128 | if (m_reg_ctx_sp) |
129 | return m_reg_ctx_sp->CopyFromRegisterContext(context: reg_ctx_sp); |
130 | return false; |
131 | } |
132 | |
133 | uint32_t RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber( |
134 | lldb::RegisterKind kind, uint32_t num) { |
135 | UpdateRegisterContext(); |
136 | if (m_reg_ctx_sp) |
137 | return m_reg_ctx_sp->ConvertRegisterKindToRegisterNumber(kind, num); |
138 | return false; |
139 | } |
140 | |
141 | uint32_t RegisterContextThreadMemory::NumSupportedHardwareBreakpoints() { |
142 | UpdateRegisterContext(); |
143 | if (m_reg_ctx_sp) |
144 | return m_reg_ctx_sp->NumSupportedHardwareBreakpoints(); |
145 | return false; |
146 | } |
147 | |
148 | uint32_t RegisterContextThreadMemory::SetHardwareBreakpoint(lldb::addr_t addr, |
149 | size_t size) { |
150 | UpdateRegisterContext(); |
151 | if (m_reg_ctx_sp) |
152 | return m_reg_ctx_sp->SetHardwareBreakpoint(addr, size); |
153 | return 0; |
154 | } |
155 | |
156 | bool RegisterContextThreadMemory::ClearHardwareBreakpoint(uint32_t hw_idx) { |
157 | UpdateRegisterContext(); |
158 | if (m_reg_ctx_sp) |
159 | return m_reg_ctx_sp->ClearHardwareBreakpoint(hw_idx); |
160 | return false; |
161 | } |
162 | |
163 | uint32_t RegisterContextThreadMemory::NumSupportedHardwareWatchpoints() { |
164 | UpdateRegisterContext(); |
165 | if (m_reg_ctx_sp) |
166 | return m_reg_ctx_sp->NumSupportedHardwareWatchpoints(); |
167 | return 0; |
168 | } |
169 | |
170 | uint32_t RegisterContextThreadMemory::SetHardwareWatchpoint(lldb::addr_t addr, |
171 | size_t size, |
172 | bool read, |
173 | bool write) { |
174 | UpdateRegisterContext(); |
175 | if (m_reg_ctx_sp) |
176 | return m_reg_ctx_sp->SetHardwareWatchpoint(addr, size, read, write); |
177 | return 0; |
178 | } |
179 | |
180 | bool RegisterContextThreadMemory::ClearHardwareWatchpoint(uint32_t hw_index) { |
181 | UpdateRegisterContext(); |
182 | if (m_reg_ctx_sp) |
183 | return m_reg_ctx_sp->ClearHardwareWatchpoint(hw_index); |
184 | return false; |
185 | } |
186 | |
187 | bool RegisterContextThreadMemory::HardwareSingleStep(bool enable) { |
188 | UpdateRegisterContext(); |
189 | if (m_reg_ctx_sp) |
190 | return m_reg_ctx_sp->HardwareSingleStep(enable); |
191 | return false; |
192 | } |
193 | |
194 | Status RegisterContextThreadMemory::ReadRegisterValueFromMemory( |
195 | const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, |
196 | uint32_t src_len, RegisterValue ®_value) { |
197 | UpdateRegisterContext(); |
198 | if (m_reg_ctx_sp) |
199 | return m_reg_ctx_sp->ReadRegisterValueFromMemory(reg_info, src_addr, |
200 | src_len, reg_value); |
201 | Status error; |
202 | error.SetErrorString("invalid register context" ); |
203 | return error; |
204 | } |
205 | |
206 | Status RegisterContextThreadMemory::WriteRegisterValueToMemory( |
207 | const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, |
208 | uint32_t dst_len, const RegisterValue ®_value) { |
209 | UpdateRegisterContext(); |
210 | if (m_reg_ctx_sp) |
211 | return m_reg_ctx_sp->WriteRegisterValueToMemory(reg_info, dst_addr, dst_len, |
212 | reg_value); |
213 | Status error; |
214 | error.SetErrorString("invalid register context" ); |
215 | return error; |
216 | } |
217 | |