/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Host/common/NativeRegisterContext.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- NativeRegisterContext.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/Host/common/NativeRegisterContext.h" |
10 | | #include "lldb/Utility/LLDBLog.h" |
11 | | #include "lldb/Utility/RegisterValue.h" |
12 | | |
13 | | #include "lldb/Host/PosixApi.h" |
14 | | #include "lldb/Host/common/NativeProcessProtocol.h" |
15 | | #include "lldb/Host/common/NativeThreadProtocol.h" |
16 | | |
17 | | using namespace lldb; |
18 | | using namespace lldb_private; |
19 | | |
20 | | NativeRegisterContext::NativeRegisterContext(NativeThreadProtocol &thread) |
21 | 0 | : m_thread(thread) {} |
22 | | |
23 | | // Destructor |
24 | 0 | NativeRegisterContext::~NativeRegisterContext() = default; |
25 | | |
26 | | // FIXME revisit invalidation, process stop ids, etc. Right now we don't |
27 | | // support caching in NativeRegisterContext. We can do this later by utilizing |
28 | | // NativeProcessProtocol::GetStopID () and adding a stop id to |
29 | | // NativeRegisterContext. |
30 | | |
31 | | // void |
32 | | // NativeRegisterContext::InvalidateIfNeeded (bool force) { |
33 | | // ProcessSP process_sp (m_thread.GetProcess()); |
34 | | // bool invalidate = force; |
35 | | // uint32_t process_stop_id = UINT32_MAX; |
36 | | |
37 | | // if (process_sp) |
38 | | // process_stop_id = process_sp->GetStopID(); |
39 | | // else |
40 | | // invalidate = true; |
41 | | |
42 | | // if (!invalidate) |
43 | | // invalidate = process_stop_id != GetStopID(); |
44 | | |
45 | | // if (invalidate) |
46 | | // { |
47 | | // InvalidateAllRegisters (); |
48 | | // SetStopID (process_stop_id); |
49 | | // } |
50 | | // } |
51 | | |
52 | | const RegisterInfo * |
53 | | NativeRegisterContext::GetRegisterInfoByName(llvm::StringRef reg_name, |
54 | 0 | uint32_t start_idx) { |
55 | 0 | if (reg_name.empty()) |
56 | 0 | return nullptr; |
57 | | |
58 | | // Generic register names take precedence over specific register names. |
59 | | // For example, on x86 we want "sp" to refer to the complete RSP/ESP register |
60 | | // rather than the 16-bit SP pseudo-register. |
61 | 0 | uint32_t generic_reg = Args::StringToGenericRegister(reg_name); |
62 | 0 | if (generic_reg != LLDB_INVALID_REGNUM) { |
63 | 0 | const RegisterInfo *reg_info = |
64 | 0 | GetRegisterInfo(eRegisterKindGeneric, generic_reg); |
65 | 0 | if (reg_info) |
66 | 0 | return reg_info; |
67 | 0 | } |
68 | | |
69 | 0 | const uint32_t num_registers = GetRegisterCount(); |
70 | 0 | for (uint32_t reg = start_idx; reg < num_registers; ++reg) { |
71 | 0 | const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); |
72 | |
|
73 | 0 | if (reg_name.equals_insensitive(reg_info->name) || |
74 | 0 | reg_name.equals_insensitive(reg_info->alt_name)) |
75 | 0 | return reg_info; |
76 | 0 | } |
77 | | |
78 | 0 | return nullptr; |
79 | 0 | } |
80 | | |
81 | | const RegisterInfo *NativeRegisterContext::GetRegisterInfo(uint32_t kind, |
82 | 0 | uint32_t num) { |
83 | 0 | const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num); |
84 | 0 | if (reg_num == LLDB_INVALID_REGNUM) |
85 | 0 | return nullptr; |
86 | 0 | return GetRegisterInfoAtIndex(reg_num); |
87 | 0 | } |
88 | | |
89 | 0 | const char *NativeRegisterContext::GetRegisterName(uint32_t reg) { |
90 | 0 | const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); |
91 | 0 | if (reg_info) |
92 | 0 | return reg_info->name; |
93 | 0 | return nullptr; |
94 | 0 | } |
95 | | |
96 | | const char *NativeRegisterContext::GetRegisterSetNameForRegisterAtIndex( |
97 | 0 | uint32_t reg_index) const { |
98 | 0 | const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); |
99 | 0 | if (!reg_info) |
100 | 0 | return nullptr; |
101 | | |
102 | 0 | for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) { |
103 | 0 | const RegisterSet *const reg_set = GetRegisterSet(set_index); |
104 | 0 | if (!reg_set) |
105 | 0 | continue; |
106 | | |
107 | 0 | for (uint32_t reg_num_index = 0; reg_num_index < reg_set->num_registers; |
108 | 0 | ++reg_num_index) { |
109 | 0 | const uint32_t reg_num = reg_set->registers[reg_num_index]; |
110 | | // FIXME double check we're checking the right register kind here. |
111 | 0 | if (reg_info->kinds[RegisterKind::eRegisterKindLLDB] == reg_num) { |
112 | | // The given register is a member of this register set. Return the |
113 | | // register set name. |
114 | 0 | return reg_set->name; |
115 | 0 | } |
116 | 0 | } |
117 | 0 | } |
118 | | |
119 | | // Didn't find it. |
120 | 0 | return nullptr; |
121 | 0 | } |
122 | | |
123 | 0 | lldb::addr_t NativeRegisterContext::GetPC(lldb::addr_t fail_value) { |
124 | 0 | Log *log = GetLog(LLDBLog::Thread); |
125 | |
|
126 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
127 | 0 | LLDB_REGNUM_GENERIC_PC); |
128 | 0 | LLDB_LOGF(log, "Using reg index %" PRIu32 " (default %" PRIu64 ")", reg, |
129 | 0 | fail_value); |
130 | |
|
131 | 0 | const uint64_t retval = ReadRegisterAsUnsigned(reg, fail_value); |
132 | |
|
133 | 0 | LLDB_LOGF(log, PRIu32 " retval %" PRIu64, retval); |
134 | |
|
135 | 0 | return retval; |
136 | 0 | } |
137 | | |
138 | | lldb::addr_t |
139 | 0 | NativeRegisterContext::GetPCfromBreakpointLocation(lldb::addr_t fail_value) { |
140 | 0 | return GetPC(fail_value); |
141 | 0 | } |
142 | | |
143 | 0 | Status NativeRegisterContext::SetPC(lldb::addr_t pc) { |
144 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
145 | 0 | LLDB_REGNUM_GENERIC_PC); |
146 | 0 | return WriteRegisterFromUnsigned(reg, pc); |
147 | 0 | } |
148 | | |
149 | 0 | lldb::addr_t NativeRegisterContext::GetSP(lldb::addr_t fail_value) { |
150 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
151 | 0 | LLDB_REGNUM_GENERIC_SP); |
152 | 0 | return ReadRegisterAsUnsigned(reg, fail_value); |
153 | 0 | } |
154 | | |
155 | 0 | Status NativeRegisterContext::SetSP(lldb::addr_t sp) { |
156 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
157 | 0 | LLDB_REGNUM_GENERIC_SP); |
158 | 0 | return WriteRegisterFromUnsigned(reg, sp); |
159 | 0 | } |
160 | | |
161 | 0 | lldb::addr_t NativeRegisterContext::GetFP(lldb::addr_t fail_value) { |
162 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
163 | 0 | LLDB_REGNUM_GENERIC_FP); |
164 | 0 | return ReadRegisterAsUnsigned(reg, fail_value); |
165 | 0 | } |
166 | | |
167 | 0 | Status NativeRegisterContext::SetFP(lldb::addr_t fp) { |
168 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
169 | 0 | LLDB_REGNUM_GENERIC_FP); |
170 | 0 | return WriteRegisterFromUnsigned(reg, fp); |
171 | 0 | } |
172 | | |
173 | 0 | lldb::addr_t NativeRegisterContext::GetReturnAddress(lldb::addr_t fail_value) { |
174 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
175 | 0 | LLDB_REGNUM_GENERIC_RA); |
176 | 0 | return ReadRegisterAsUnsigned(reg, fail_value); |
177 | 0 | } |
178 | | |
179 | 0 | lldb::addr_t NativeRegisterContext::GetFlags(lldb::addr_t fail_value) { |
180 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
181 | 0 | LLDB_REGNUM_GENERIC_FLAGS); |
182 | 0 | return ReadRegisterAsUnsigned(reg, fail_value); |
183 | 0 | } |
184 | | |
185 | | lldb::addr_t |
186 | | NativeRegisterContext::ReadRegisterAsUnsigned(uint32_t reg, |
187 | 0 | lldb::addr_t fail_value) { |
188 | 0 | if (reg != LLDB_INVALID_REGNUM) |
189 | 0 | return ReadRegisterAsUnsigned(GetRegisterInfoAtIndex(reg), fail_value); |
190 | 0 | return fail_value; |
191 | 0 | } |
192 | | |
193 | | uint64_t |
194 | | NativeRegisterContext::ReadRegisterAsUnsigned(const RegisterInfo *reg_info, |
195 | 0 | lldb::addr_t fail_value) { |
196 | 0 | Log *log = GetLog(LLDBLog::Thread); |
197 | |
|
198 | 0 | if (reg_info) { |
199 | 0 | RegisterValue value; |
200 | 0 | Status error = ReadRegister(reg_info, value); |
201 | 0 | if (error.Success()) { |
202 | 0 | LLDB_LOGF(log, |
203 | 0 | "Read register succeeded: value " |
204 | 0 | "%" PRIu64, |
205 | 0 | value.GetAsUInt64()); |
206 | 0 | return value.GetAsUInt64(); |
207 | 0 | } else { |
208 | 0 | LLDB_LOGF(log, "Read register failed: error %s", error.AsCString()); |
209 | 0 | } |
210 | 0 | } else { |
211 | 0 | LLDB_LOGF(log, "Read register failed: null reg_info"); |
212 | 0 | } |
213 | 0 | return fail_value; |
214 | 0 | } |
215 | | |
216 | | Status NativeRegisterContext::WriteRegisterFromUnsigned(uint32_t reg, |
217 | 0 | uint64_t uval) { |
218 | 0 | if (reg == LLDB_INVALID_REGNUM) |
219 | 0 | return Status("Write register failed: reg is invalid"); |
220 | 0 | return WriteRegisterFromUnsigned(GetRegisterInfoAtIndex(reg), uval); |
221 | 0 | } |
222 | | |
223 | | Status |
224 | | NativeRegisterContext::WriteRegisterFromUnsigned(const RegisterInfo *reg_info, |
225 | 0 | uint64_t uval) { |
226 | 0 | assert(reg_info); |
227 | 0 | if (!reg_info) |
228 | 0 | return Status("reg_info is nullptr"); |
229 | | |
230 | 0 | RegisterValue value; |
231 | 0 | if (!value.SetUInt(uval, reg_info->byte_size)) |
232 | 0 | return Status("RegisterValue::SetUInt () failed"); |
233 | | |
234 | 0 | return WriteRegister(reg_info, value); |
235 | 0 | } |
236 | | |
237 | 0 | lldb::tid_t NativeRegisterContext::GetThreadID() const { |
238 | 0 | return m_thread.GetID(); |
239 | 0 | } |
240 | | |
241 | 0 | uint32_t NativeRegisterContext::NumSupportedHardwareBreakpoints() { return 0; } |
242 | | |
243 | | uint32_t NativeRegisterContext::SetHardwareBreakpoint(lldb::addr_t addr, |
244 | 0 | size_t size) { |
245 | 0 | return LLDB_INVALID_INDEX32; |
246 | 0 | } |
247 | | |
248 | 0 | Status NativeRegisterContext::ClearAllHardwareBreakpoints() { |
249 | 0 | return Status("not implemented"); |
250 | 0 | } |
251 | | |
252 | 0 | bool NativeRegisterContext::ClearHardwareBreakpoint(uint32_t hw_idx) { |
253 | 0 | return false; |
254 | 0 | } |
255 | | |
256 | | Status NativeRegisterContext::GetHardwareBreakHitIndex(uint32_t &bp_index, |
257 | 0 | lldb::addr_t trap_addr) { |
258 | 0 | bp_index = LLDB_INVALID_INDEX32; |
259 | 0 | return Status("not implemented"); |
260 | 0 | } |
261 | | |
262 | 0 | uint32_t NativeRegisterContext::NumSupportedHardwareWatchpoints() { return 0; } |
263 | | |
264 | | uint32_t NativeRegisterContext::SetHardwareWatchpoint(lldb::addr_t addr, |
265 | | size_t size, |
266 | 0 | uint32_t watch_flags) { |
267 | 0 | return LLDB_INVALID_INDEX32; |
268 | 0 | } |
269 | | |
270 | 0 | bool NativeRegisterContext::ClearHardwareWatchpoint(uint32_t hw_index) { |
271 | 0 | return false; |
272 | 0 | } |
273 | | |
274 | 0 | Status NativeRegisterContext::ClearWatchpointHit(uint32_t hw_index) { |
275 | 0 | return Status("not implemented"); |
276 | 0 | } |
277 | | |
278 | 0 | Status NativeRegisterContext::ClearAllHardwareWatchpoints() { |
279 | 0 | return Status("not implemented"); |
280 | 0 | } |
281 | | |
282 | 0 | Status NativeRegisterContext::IsWatchpointHit(uint32_t wp_index, bool &is_hit) { |
283 | 0 | is_hit = false; |
284 | 0 | return Status("not implemented"); |
285 | 0 | } |
286 | | |
287 | | Status NativeRegisterContext::GetWatchpointHitIndex(uint32_t &wp_index, |
288 | 0 | lldb::addr_t trap_addr) { |
289 | 0 | wp_index = LLDB_INVALID_INDEX32; |
290 | 0 | return Status("not implemented"); |
291 | 0 | } |
292 | | |
293 | | Status NativeRegisterContext::IsWatchpointVacant(uint32_t wp_index, |
294 | 0 | bool &is_vacant) { |
295 | 0 | is_vacant = false; |
296 | 0 | return Status("not implemented"); |
297 | 0 | } |
298 | | |
299 | 0 | lldb::addr_t NativeRegisterContext::GetWatchpointAddress(uint32_t wp_index) { |
300 | 0 | return LLDB_INVALID_ADDRESS; |
301 | 0 | } |
302 | | |
303 | 0 | lldb::addr_t NativeRegisterContext::GetWatchpointHitAddress(uint32_t wp_index) { |
304 | 0 | return LLDB_INVALID_ADDRESS; |
305 | 0 | } |
306 | | |
307 | 0 | bool NativeRegisterContext::HardwareSingleStep(bool enable) { return false; } |
308 | | |
309 | | Status NativeRegisterContext::ReadRegisterValueFromMemory( |
310 | | const RegisterInfo *reg_info, lldb::addr_t src_addr, size_t src_len, |
311 | 0 | RegisterValue ®_value) { |
312 | 0 | Status error; |
313 | 0 | if (reg_info == nullptr) { |
314 | 0 | error.SetErrorString("invalid register info argument."); |
315 | 0 | return error; |
316 | 0 | } |
317 | | |
318 | | // Moving from addr into a register |
319 | | // |
320 | | // Case 1: src_len == dst_len |
321 | | // |
322 | | // |AABBCCDD| Address contents |
323 | | // |AABBCCDD| Register contents |
324 | | // |
325 | | // Case 2: src_len > dst_len |
326 | | // |
327 | | // Status! (The register should always be big enough to hold the data) |
328 | | // |
329 | | // Case 3: src_len < dst_len |
330 | | // |
331 | | // |AABB| Address contents |
332 | | // |AABB0000| Register contents [on little-endian hardware] |
333 | | // |0000AABB| Register contents [on big-endian hardware] |
334 | 0 | const size_t dst_len = reg_info->byte_size; |
335 | |
|
336 | 0 | if (src_len > dst_len) { |
337 | 0 | error.SetErrorStringWithFormat( |
338 | 0 | "%" PRIu64 " bytes is too big to store in register %s (%" PRIu64 |
339 | 0 | " bytes)", |
340 | 0 | static_cast<uint64_t>(src_len), reg_info->name, |
341 | 0 | static_cast<uint64_t>(dst_len)); |
342 | 0 | return error; |
343 | 0 | } |
344 | | |
345 | 0 | NativeProcessProtocol &process = m_thread.GetProcess(); |
346 | 0 | RegisterValue::BytesContainer src(src_len); |
347 | | |
348 | | // Read the memory |
349 | 0 | size_t bytes_read; |
350 | 0 | error = process.ReadMemory(src_addr, src.data(), src_len, bytes_read); |
351 | 0 | if (error.Fail()) |
352 | 0 | return error; |
353 | | |
354 | | // Make sure the memory read succeeded... |
355 | 0 | if (bytes_read != src_len) { |
356 | | // This might happen if we read _some_ bytes but not all |
357 | 0 | error.SetErrorStringWithFormat("read %" PRIu64 " of %" PRIu64 " bytes", |
358 | 0 | static_cast<uint64_t>(bytes_read), |
359 | 0 | static_cast<uint64_t>(src_len)); |
360 | 0 | return error; |
361 | 0 | } |
362 | | |
363 | | // We now have a memory buffer that contains the part or all of the register |
364 | | // value. Set the register value using this memory data. |
365 | | // TODO: we might need to add a parameter to this function in case the byte |
366 | | // order of the memory data doesn't match the process. For now we are |
367 | | // assuming they are the same. |
368 | 0 | reg_value.SetFromMemoryData(*reg_info, src.data(), src_len, |
369 | 0 | process.GetByteOrder(), error); |
370 | |
|
371 | 0 | return error; |
372 | 0 | } |
373 | | |
374 | | Status NativeRegisterContext::WriteRegisterValueToMemory( |
375 | | const RegisterInfo *reg_info, lldb::addr_t dst_addr, size_t dst_len, |
376 | 0 | const RegisterValue ®_value) { |
377 | 0 | Status error; |
378 | 0 | if (reg_info == nullptr) { |
379 | 0 | error.SetErrorString("Invalid register info argument."); |
380 | 0 | return error; |
381 | 0 | } |
382 | | |
383 | 0 | RegisterValue::BytesContainer dst(dst_len); |
384 | 0 | NativeProcessProtocol &process = m_thread.GetProcess(); |
385 | | |
386 | | // TODO: we might need to add a parameter to this function in case the byte |
387 | | // order of the memory data doesn't match the process. For now we are |
388 | | // assuming they are the same. |
389 | 0 | const size_t bytes_copied = reg_value.GetAsMemoryData( |
390 | 0 | *reg_info, dst.data(), dst_len, process.GetByteOrder(), error); |
391 | |
|
392 | 0 | if (error.Success()) { |
393 | 0 | if (bytes_copied == 0) { |
394 | 0 | error.SetErrorString("byte copy failed."); |
395 | 0 | } else { |
396 | 0 | size_t bytes_written; |
397 | 0 | error = process.WriteMemory(dst_addr, dst.data(), bytes_copied, |
398 | 0 | bytes_written); |
399 | 0 | if (error.Fail()) |
400 | 0 | return error; |
401 | | |
402 | 0 | if (bytes_written != bytes_copied) { |
403 | | // This might happen if we read _some_ bytes but not all |
404 | 0 | error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64 |
405 | 0 | " bytes", |
406 | 0 | static_cast<uint64_t>(bytes_written), |
407 | 0 | static_cast<uint64_t>(bytes_copied)); |
408 | 0 | } |
409 | 0 | } |
410 | 0 | } |
411 | | |
412 | 0 | return error; |
413 | 0 | } |
414 | | |
415 | | uint32_t |
416 | | NativeRegisterContext::ConvertRegisterKindToRegisterNumber(uint32_t kind, |
417 | 0 | uint32_t num) const { |
418 | 0 | const uint32_t num_regs = GetRegisterCount(); |
419 | |
|
420 | 0 | assert(kind < kNumRegisterKinds); |
421 | 0 | for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { |
422 | 0 | const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx); |
423 | |
|
424 | 0 | if (reg_info->kinds[kind] == num) |
425 | 0 | return reg_idx; |
426 | 0 | } |
427 | | |
428 | 0 | return LLDB_INVALID_REGNUM; |
429 | 0 | } |
430 | | |
431 | | std::vector<uint32_t> |
432 | 0 | NativeRegisterContext::GetExpeditedRegisters(ExpeditedRegs expType) const { |
433 | 0 | if (expType == ExpeditedRegs::Minimal) { |
434 | | // Expedite only a minimum set of important generic registers. |
435 | 0 | static const uint32_t k_expedited_registers[] = { |
436 | 0 | LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP, |
437 | 0 | LLDB_REGNUM_GENERIC_RA}; |
438 | |
|
439 | 0 | std::vector<uint32_t> expedited_reg_nums; |
440 | 0 | for (uint32_t gen_reg : k_expedited_registers) { |
441 | 0 | uint32_t reg_num = |
442 | 0 | ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, gen_reg); |
443 | 0 | if (reg_num == LLDB_INVALID_REGNUM) |
444 | 0 | continue; // Target does not support the given register. |
445 | 0 | else |
446 | 0 | expedited_reg_nums.push_back(reg_num); |
447 | 0 | } |
448 | |
|
449 | 0 | return expedited_reg_nums; |
450 | 0 | } |
451 | | |
452 | 0 | if (GetRegisterSetCount() > 0 && expType == ExpeditedRegs::Full) |
453 | 0 | return std::vector<uint32_t>(GetRegisterSet(0)->registers, |
454 | 0 | GetRegisterSet(0)->registers + |
455 | 0 | GetRegisterSet(0)->num_registers); |
456 | | |
457 | 0 | return std::vector<uint32_t>(); |
458 | 0 | } |