/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, |
129 | 0 | "NativeRegisterContext::%s using reg index %" PRIu32 |
130 | 0 | " (default %" PRIu64 ")", |
131 | 0 | __FUNCTION__, reg, fail_value); |
132 | |
|
133 | 0 | const uint64_t retval = ReadRegisterAsUnsigned(reg, fail_value); |
134 | |
|
135 | 0 | LLDB_LOGF(log, "NativeRegisterContext::%s " PRIu32 " retval %" PRIu64, |
136 | 0 | __FUNCTION__, retval); |
137 | |
|
138 | 0 | return retval; |
139 | 0 | } |
140 | | |
141 | | lldb::addr_t |
142 | 0 | NativeRegisterContext::GetPCfromBreakpointLocation(lldb::addr_t fail_value) { |
143 | 0 | return GetPC(fail_value); |
144 | 0 | } |
145 | | |
146 | 0 | Status NativeRegisterContext::SetPC(lldb::addr_t pc) { |
147 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
148 | 0 | LLDB_REGNUM_GENERIC_PC); |
149 | 0 | return WriteRegisterFromUnsigned(reg, pc); |
150 | 0 | } |
151 | | |
152 | 0 | lldb::addr_t NativeRegisterContext::GetSP(lldb::addr_t fail_value) { |
153 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
154 | 0 | LLDB_REGNUM_GENERIC_SP); |
155 | 0 | return ReadRegisterAsUnsigned(reg, fail_value); |
156 | 0 | } |
157 | | |
158 | 0 | Status NativeRegisterContext::SetSP(lldb::addr_t sp) { |
159 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
160 | 0 | LLDB_REGNUM_GENERIC_SP); |
161 | 0 | return WriteRegisterFromUnsigned(reg, sp); |
162 | 0 | } |
163 | | |
164 | 0 | lldb::addr_t NativeRegisterContext::GetFP(lldb::addr_t fail_value) { |
165 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
166 | 0 | LLDB_REGNUM_GENERIC_FP); |
167 | 0 | return ReadRegisterAsUnsigned(reg, fail_value); |
168 | 0 | } |
169 | | |
170 | 0 | Status NativeRegisterContext::SetFP(lldb::addr_t fp) { |
171 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
172 | 0 | LLDB_REGNUM_GENERIC_FP); |
173 | 0 | return WriteRegisterFromUnsigned(reg, fp); |
174 | 0 | } |
175 | | |
176 | 0 | lldb::addr_t NativeRegisterContext::GetReturnAddress(lldb::addr_t fail_value) { |
177 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
178 | 0 | LLDB_REGNUM_GENERIC_RA); |
179 | 0 | return ReadRegisterAsUnsigned(reg, fail_value); |
180 | 0 | } |
181 | | |
182 | 0 | lldb::addr_t NativeRegisterContext::GetFlags(lldb::addr_t fail_value) { |
183 | 0 | uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, |
184 | 0 | LLDB_REGNUM_GENERIC_FLAGS); |
185 | 0 | return ReadRegisterAsUnsigned(reg, fail_value); |
186 | 0 | } |
187 | | |
188 | | lldb::addr_t |
189 | | NativeRegisterContext::ReadRegisterAsUnsigned(uint32_t reg, |
190 | 0 | lldb::addr_t fail_value) { |
191 | 0 | if (reg != LLDB_INVALID_REGNUM) |
192 | 0 | return ReadRegisterAsUnsigned(GetRegisterInfoAtIndex(reg), fail_value); |
193 | 0 | return fail_value; |
194 | 0 | } |
195 | | |
196 | | uint64_t |
197 | | NativeRegisterContext::ReadRegisterAsUnsigned(const RegisterInfo *reg_info, |
198 | 0 | lldb::addr_t fail_value) { |
199 | 0 | Log *log = GetLog(LLDBLog::Thread); |
200 | |
|
201 | 0 | if (reg_info) { |
202 | 0 | RegisterValue value; |
203 | 0 | Status error = ReadRegister(reg_info, value); |
204 | 0 | if (error.Success()) { |
205 | 0 | LLDB_LOGF(log, |
206 | 0 | "NativeRegisterContext::%s ReadRegister() succeeded, value " |
207 | 0 | "%" PRIu64, |
208 | 0 | __FUNCTION__, value.GetAsUInt64()); |
209 | 0 | return value.GetAsUInt64(); |
210 | 0 | } else { |
211 | 0 | LLDB_LOGF(log, |
212 | 0 | "NativeRegisterContext::%s ReadRegister() failed, error %s", |
213 | 0 | __FUNCTION__, error.AsCString()); |
214 | 0 | } |
215 | 0 | } else { |
216 | 0 | LLDB_LOGF(log, "NativeRegisterContext::%s ReadRegister() null reg_info", |
217 | 0 | __FUNCTION__); |
218 | 0 | } |
219 | 0 | return fail_value; |
220 | 0 | } |
221 | | |
222 | | Status NativeRegisterContext::WriteRegisterFromUnsigned(uint32_t reg, |
223 | 0 | uint64_t uval) { |
224 | 0 | if (reg == LLDB_INVALID_REGNUM) |
225 | 0 | return Status("NativeRegisterContext::%s (): reg is invalid", __FUNCTION__); |
226 | 0 | return WriteRegisterFromUnsigned(GetRegisterInfoAtIndex(reg), uval); |
227 | 0 | } |
228 | | |
229 | | Status |
230 | | NativeRegisterContext::WriteRegisterFromUnsigned(const RegisterInfo *reg_info, |
231 | 0 | uint64_t uval) { |
232 | 0 | assert(reg_info); |
233 | 0 | if (!reg_info) |
234 | 0 | return Status("reg_info is nullptr"); |
235 | | |
236 | 0 | RegisterValue value; |
237 | 0 | if (!value.SetUInt(uval, reg_info->byte_size)) |
238 | 0 | return Status("RegisterValue::SetUInt () failed"); |
239 | | |
240 | 0 | return WriteRegister(reg_info, value); |
241 | 0 | } |
242 | | |
243 | 0 | lldb::tid_t NativeRegisterContext::GetThreadID() const { |
244 | 0 | return m_thread.GetID(); |
245 | 0 | } |
246 | | |
247 | 0 | uint32_t NativeRegisterContext::NumSupportedHardwareBreakpoints() { return 0; } |
248 | | |
249 | | uint32_t NativeRegisterContext::SetHardwareBreakpoint(lldb::addr_t addr, |
250 | 0 | size_t size) { |
251 | 0 | return LLDB_INVALID_INDEX32; |
252 | 0 | } |
253 | | |
254 | 0 | Status NativeRegisterContext::ClearAllHardwareBreakpoints() { |
255 | 0 | return Status("not implemented"); |
256 | 0 | } |
257 | | |
258 | 0 | bool NativeRegisterContext::ClearHardwareBreakpoint(uint32_t hw_idx) { |
259 | 0 | return false; |
260 | 0 | } |
261 | | |
262 | | Status NativeRegisterContext::GetHardwareBreakHitIndex(uint32_t &bp_index, |
263 | 0 | lldb::addr_t trap_addr) { |
264 | 0 | bp_index = LLDB_INVALID_INDEX32; |
265 | 0 | return Status("not implemented"); |
266 | 0 | } |
267 | | |
268 | 0 | uint32_t NativeRegisterContext::NumSupportedHardwareWatchpoints() { return 0; } |
269 | | |
270 | | uint32_t NativeRegisterContext::SetHardwareWatchpoint(lldb::addr_t addr, |
271 | | size_t size, |
272 | 0 | uint32_t watch_flags) { |
273 | 0 | return LLDB_INVALID_INDEX32; |
274 | 0 | } |
275 | | |
276 | 0 | bool NativeRegisterContext::ClearHardwareWatchpoint(uint32_t hw_index) { |
277 | 0 | return false; |
278 | 0 | } |
279 | | |
280 | 0 | Status NativeRegisterContext::ClearWatchpointHit(uint32_t hw_index) { |
281 | 0 | return Status("not implemented"); |
282 | 0 | } |
283 | | |
284 | 0 | Status NativeRegisterContext::ClearAllHardwareWatchpoints() { |
285 | 0 | return Status("not implemented"); |
286 | 0 | } |
287 | | |
288 | 0 | Status NativeRegisterContext::IsWatchpointHit(uint32_t wp_index, bool &is_hit) { |
289 | 0 | is_hit = false; |
290 | 0 | return Status("not implemented"); |
291 | 0 | } |
292 | | |
293 | | Status NativeRegisterContext::GetWatchpointHitIndex(uint32_t &wp_index, |
294 | 0 | lldb::addr_t trap_addr) { |
295 | 0 | wp_index = LLDB_INVALID_INDEX32; |
296 | 0 | return Status("not implemented"); |
297 | 0 | } |
298 | | |
299 | | Status NativeRegisterContext::IsWatchpointVacant(uint32_t wp_index, |
300 | 0 | bool &is_vacant) { |
301 | 0 | is_vacant = false; |
302 | 0 | return Status("not implemented"); |
303 | 0 | } |
304 | | |
305 | 0 | lldb::addr_t NativeRegisterContext::GetWatchpointAddress(uint32_t wp_index) { |
306 | 0 | return LLDB_INVALID_ADDRESS; |
307 | 0 | } |
308 | | |
309 | 0 | lldb::addr_t NativeRegisterContext::GetWatchpointHitAddress(uint32_t wp_index) { |
310 | 0 | return LLDB_INVALID_ADDRESS; |
311 | 0 | } |
312 | | |
313 | 0 | bool NativeRegisterContext::HardwareSingleStep(bool enable) { return false; } |
314 | | |
315 | | Status NativeRegisterContext::ReadRegisterValueFromMemory( |
316 | | const RegisterInfo *reg_info, lldb::addr_t src_addr, size_t src_len, |
317 | 0 | RegisterValue ®_value) { |
318 | 0 | Status error; |
319 | 0 | if (reg_info == nullptr) { |
320 | 0 | error.SetErrorString("invalid register info argument."); |
321 | 0 | return error; |
322 | 0 | } |
323 | | |
324 | | // Moving from addr into a register |
325 | | // |
326 | | // Case 1: src_len == dst_len |
327 | | // |
328 | | // |AABBCCDD| Address contents |
329 | | // |AABBCCDD| Register contents |
330 | | // |
331 | | // Case 2: src_len > dst_len |
332 | | // |
333 | | // Status! (The register should always be big enough to hold the data) |
334 | | // |
335 | | // Case 3: src_len < dst_len |
336 | | // |
337 | | // |AABB| Address contents |
338 | | // |AABB0000| Register contents [on little-endian hardware] |
339 | | // |0000AABB| Register contents [on big-endian hardware] |
340 | 0 | if (src_len > RegisterValue::kMaxRegisterByteSize) { |
341 | 0 | error.SetErrorString("register too small to receive memory data"); |
342 | 0 | return error; |
343 | 0 | } |
344 | | |
345 | 0 | const size_t dst_len = reg_info->byte_size; |
346 | |
|
347 | 0 | if (src_len > dst_len) { |
348 | 0 | error.SetErrorStringWithFormat( |
349 | 0 | "%" PRIu64 " bytes is too big to store in register %s (%" PRIu64 |
350 | 0 | " bytes)", |
351 | 0 | static_cast<uint64_t>(src_len), reg_info->name, |
352 | 0 | static_cast<uint64_t>(dst_len)); |
353 | 0 | return error; |
354 | 0 | } |
355 | | |
356 | 0 | NativeProcessProtocol &process = m_thread.GetProcess(); |
357 | 0 | uint8_t src[RegisterValue::kMaxRegisterByteSize]; |
358 | | |
359 | | // Read the memory |
360 | 0 | size_t bytes_read; |
361 | 0 | error = process.ReadMemory(src_addr, src, src_len, bytes_read); |
362 | 0 | if (error.Fail()) |
363 | 0 | return error; |
364 | | |
365 | | // Make sure the memory read succeeded... |
366 | 0 | if (bytes_read != src_len) { |
367 | | // This might happen if we read _some_ bytes but not all |
368 | 0 | error.SetErrorStringWithFormat("read %" PRIu64 " of %" PRIu64 " bytes", |
369 | 0 | static_cast<uint64_t>(bytes_read), |
370 | 0 | static_cast<uint64_t>(src_len)); |
371 | 0 | return error; |
372 | 0 | } |
373 | | |
374 | | // We now have a memory buffer that contains the part or all of the register |
375 | | // value. Set the register value using this memory data. |
376 | | // TODO: we might need to add a parameter to this function in case the byte |
377 | | // order of the memory data doesn't match the process. For now we are |
378 | | // assuming they are the same. |
379 | 0 | reg_value.SetFromMemoryData(*reg_info, src, src_len, process.GetByteOrder(), |
380 | 0 | error); |
381 | |
|
382 | 0 | return error; |
383 | 0 | } |
384 | | |
385 | | Status NativeRegisterContext::WriteRegisterValueToMemory( |
386 | | const RegisterInfo *reg_info, lldb::addr_t dst_addr, size_t dst_len, |
387 | 0 | const RegisterValue ®_value) { |
388 | 0 | Status error; |
389 | 0 | if (reg_info == nullptr) { |
390 | 0 | error.SetErrorString("Invalid register info argument."); |
391 | 0 | return error; |
392 | 0 | } |
393 | | |
394 | 0 | uint8_t dst[RegisterValue::kMaxRegisterByteSize]; |
395 | 0 | NativeProcessProtocol &process = m_thread.GetProcess(); |
396 | | |
397 | | // TODO: we might need to add a parameter to this function in case the byte |
398 | | // order of the memory data doesn't match the process. For now we are |
399 | | // assuming they are the same. |
400 | 0 | const size_t bytes_copied = reg_value.GetAsMemoryData( |
401 | 0 | *reg_info, dst, dst_len, process.GetByteOrder(), error); |
402 | |
|
403 | 0 | if (error.Success()) { |
404 | 0 | if (bytes_copied == 0) { |
405 | 0 | error.SetErrorString("byte copy failed."); |
406 | 0 | } else { |
407 | 0 | size_t bytes_written; |
408 | 0 | error = process.WriteMemory(dst_addr, dst, bytes_copied, bytes_written); |
409 | 0 | if (error.Fail()) |
410 | 0 | return error; |
411 | | |
412 | 0 | if (bytes_written != bytes_copied) { |
413 | | // This might happen if we read _some_ bytes but not all |
414 | 0 | error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64 |
415 | 0 | " bytes", |
416 | 0 | static_cast<uint64_t>(bytes_written), |
417 | 0 | static_cast<uint64_t>(bytes_copied)); |
418 | 0 | } |
419 | 0 | } |
420 | 0 | } |
421 | | |
422 | 0 | return error; |
423 | 0 | } |
424 | | |
425 | | uint32_t |
426 | | NativeRegisterContext::ConvertRegisterKindToRegisterNumber(uint32_t kind, |
427 | 0 | uint32_t num) const { |
428 | 0 | const uint32_t num_regs = GetRegisterCount(); |
429 | |
|
430 | 0 | assert(kind < kNumRegisterKinds); |
431 | 0 | for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { |
432 | 0 | const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx); |
433 | |
|
434 | 0 | if (reg_info->kinds[kind] == num) |
435 | 0 | return reg_idx; |
436 | 0 | } |
437 | | |
438 | 0 | return LLDB_INVALID_REGNUM; |
439 | 0 | } |
440 | | |
441 | | std::vector<uint32_t> |
442 | 0 | NativeRegisterContext::GetExpeditedRegisters(ExpeditedRegs expType) const { |
443 | 0 | if (expType == ExpeditedRegs::Minimal) { |
444 | | // Expedite only a minimum set of important generic registers. |
445 | 0 | static const uint32_t k_expedited_registers[] = { |
446 | 0 | LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP, |
447 | 0 | LLDB_REGNUM_GENERIC_RA}; |
448 | |
|
449 | 0 | std::vector<uint32_t> expedited_reg_nums; |
450 | 0 | for (uint32_t gen_reg : k_expedited_registers) { |
451 | 0 | uint32_t reg_num = |
452 | 0 | ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, gen_reg); |
453 | 0 | if (reg_num == LLDB_INVALID_REGNUM) |
454 | 0 | continue; // Target does not support the given register. |
455 | 0 | else |
456 | 0 | expedited_reg_nums.push_back(reg_num); |
457 | 0 | } |
458 | |
|
459 | 0 | return expedited_reg_nums; |
460 | 0 | } |
461 | | |
462 | 0 | if (GetRegisterSetCount() > 0 && expType == ExpeditedRegs::Full) |
463 | 0 | return std::vector<uint32_t>(GetRegisterSet(0)->registers, |
464 | 0 | GetRegisterSet(0)->registers + |
465 | 0 | GetRegisterSet(0)->num_registers); |
466 | | |
467 | 0 | return std::vector<uint32_t>(); |
468 | 0 | } |