1 //===-- NativeRegisterContextLinux_arm64.cpp --------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "NativeRegisterContextLinux_arm64.h"
11 
12 #include "lldb/lldb-private-forward.h"
13 #include "lldb/Core/DataBufferHeap.h"
14 #include "lldb/Core/Error.h"
15 #include "lldb/Core/RegisterValue.h"
16 #include "lldb/Host/common/NativeProcessProtocol.h"
17 #include "lldb/Host/common/NativeThreadProtocol.h"
18 #include "Plugins/Process/Linux/NativeProcessLinux.h"
19 
20 #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr))
21 
22 using namespace lldb;
23 using namespace lldb_private;
24 
25 // ARM64 general purpose registers.
26 static const uint32_t g_gpr_regnums_arm64[] =
27 {
28     gpr_x0_arm64,
29     gpr_x1_arm64,
30     gpr_x2_arm64,
31     gpr_x3_arm64,
32     gpr_x4_arm64,
33     gpr_x5_arm64,
34     gpr_x6_arm64,
35     gpr_x7_arm64,
36     gpr_x8_arm64,
37     gpr_x9_arm64,
38     gpr_x10_arm64,
39     gpr_x11_arm64,
40     gpr_x12_arm64,
41     gpr_x13_arm64,
42     gpr_x14_arm64,
43     gpr_x15_arm64,
44     gpr_x16_arm64,
45     gpr_x17_arm64,
46     gpr_x18_arm64,
47     gpr_x19_arm64,
48     gpr_x20_arm64,
49     gpr_x21_arm64,
50     gpr_x22_arm64,
51     gpr_x23_arm64,
52     gpr_x24_arm64,
53     gpr_x25_arm64,
54     gpr_x26_arm64,
55     gpr_x27_arm64,
56     gpr_x28_arm64,
57     gpr_fp_arm64,
58     gpr_lr_arm64,
59     gpr_sp_arm64,
60     gpr_pc_arm64,
61     gpr_cpsr_arm64,
62     LLDB_INVALID_REGNUM // register sets need to end with this flag
63 };
64 static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 1) == k_num_gpr_registers_arm64, \
65               "g_gpr_regnums_arm64 has wrong number of register infos");
66 
67 // ARM64 floating point registers.
68 static const uint32_t g_fpu_regnums_arm64[] =
69 {
70     fpu_v0_arm64,
71     fpu_v1_arm64,
72     fpu_v2_arm64,
73     fpu_v3_arm64,
74     fpu_v4_arm64,
75     fpu_v5_arm64,
76     fpu_v6_arm64,
77     fpu_v7_arm64,
78     fpu_v8_arm64,
79     fpu_v9_arm64,
80     fpu_v10_arm64,
81     fpu_v11_arm64,
82     fpu_v12_arm64,
83     fpu_v13_arm64,
84     fpu_v14_arm64,
85     fpu_v15_arm64,
86     fpu_v16_arm64,
87     fpu_v17_arm64,
88     fpu_v18_arm64,
89     fpu_v19_arm64,
90     fpu_v20_arm64,
91     fpu_v21_arm64,
92     fpu_v22_arm64,
93     fpu_v23_arm64,
94     fpu_v24_arm64,
95     fpu_v25_arm64,
96     fpu_v26_arm64,
97     fpu_v27_arm64,
98     fpu_v28_arm64,
99     fpu_v29_arm64,
100     fpu_v30_arm64,
101     fpu_v31_arm64,
102     fpu_fpsr_arm64,
103     fpu_fpcr_arm64,
104     LLDB_INVALID_REGNUM // register sets need to end with this flag
105 };
106 static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers_arm64, \
107               "g_fpu_regnums_arm64 has wrong number of register infos");
108 
109 namespace {
110     // Number of register sets provided by this context.
111     enum
112     {
113         k_num_register_sets = 2
114     };
115 }
116 
117 // Register sets for ARM64.
118 static const lldb_private::RegisterSet
119 g_reg_sets_arm64[k_num_register_sets] =
120 {
121     { "General Purpose Registers",  "gpr", k_num_gpr_registers_arm64, g_gpr_regnums_arm64 },
122     { "Floating Point Registers",   "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 }
123 };
124 
125 NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64 (
126         NativeThreadProtocol &native_thread,
127         uint32_t concrete_frame_idx,
128         RegisterInfoInterface *reg_info_interface_p) :
129     NativeRegisterContextRegisterInfo (native_thread, concrete_frame_idx, reg_info_interface_p)
130 {
131     switch (reg_info_interface_p->m_target_arch.GetMachine())
132     {
133         case llvm::Triple::aarch64:
134             m_reg_info.num_registers     = k_num_registers_arm64;
135             m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64;
136             m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64;
137             m_reg_info.last_gpr          = k_last_gpr_arm64;
138             m_reg_info.first_fpr         = k_first_fpr_arm64;
139             m_reg_info.last_fpr          = k_last_fpr_arm64;
140             m_reg_info.first_fpr_v       = fpu_v0_arm64;
141             m_reg_info.last_fpr_v        = fpu_v31_arm64;
142             m_reg_info.gpr_flags         = gpr_cpsr_arm64;
143             break;
144         default:
145             assert(false && "Unhandled target architecture.");
146             break;
147     }
148 
149     ::memset(&m_fpr, 0, sizeof (m_fpr));
150     ::memset(&m_gpr_arm64, 0, sizeof (m_gpr_arm64));
151 }
152 
153 uint32_t
154 NativeRegisterContextLinux_arm64::GetRegisterSetCount () const
155 {
156     return k_num_register_sets;
157 }
158 
159 const lldb_private::RegisterSet *
160 NativeRegisterContextLinux_arm64::GetRegisterSet (uint32_t set_index) const
161 {
162     if (set_index < k_num_register_sets)
163         return &g_reg_sets_arm64[set_index];
164 
165     return nullptr;
166 }
167 
168 lldb_private::Error
169 NativeRegisterContextLinux_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
170 {
171     Error error;
172 
173     if (!reg_info)
174     {
175         error.SetErrorString ("reg_info NULL");
176         return error;
177     }
178 
179     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
180 
181     if (IsFPR(reg))
182     {
183         if (!ReadFPR())
184         {
185             error.SetErrorString ("failed to read floating point register");
186             return error;
187         }
188     }
189     else
190     {
191         uint32_t full_reg = reg;
192         bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
193 
194         if (is_subreg)
195         {
196             // Read the full aligned 64-bit register.
197             full_reg = reg_info->invalidate_regs[0];
198         }
199 
200         error = ReadRegisterRaw(full_reg, reg_value);
201 
202         if (error.Success ())
203         {
204             // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
205             if (is_subreg && (reg_info->byte_offset & 0x1))
206                 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
207 
208             // If our return byte size was greater than the return value reg size, then
209             // use the type specified by reg_info rather than the uint64_t default
210             if (reg_value.GetByteSize() > reg_info->byte_size)
211                 reg_value.SetType(reg_info);
212         }
213         return error;
214     }
215 
216     // Get pointer to m_fpr variable and set the data from it.
217     assert (reg_info->byte_offset < sizeof m_fpr);
218     uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
219     switch (reg_info->byte_size)
220     {
221         case 2:
222             reg_value.SetUInt16(*(uint16_t *)src);
223             break;
224         case 4:
225             reg_value.SetUInt32(*(uint32_t *)src);
226             break;
227         case 8:
228             reg_value.SetUInt64(*(uint64_t *)src);
229             break;
230         default:
231             assert(false && "Unhandled data size.");
232             error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
233             break;
234     }
235 
236     return error;
237 }
238 
239 lldb_private::Error
240 NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
241 {
242     if (!reg_info)
243         return Error ("reg_info NULL");
244 
245     const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
246     if (reg_index == LLDB_INVALID_REGNUM)
247         return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
248 
249     if (IsGPR(reg_index))
250         return WriteRegisterRaw(reg_index, reg_value);
251 
252     if (IsFPR(reg_index))
253     {
254         // Get pointer to m_fpr variable and set the data to it.
255         assert (reg_info->byte_offset < sizeof(m_fpr));
256         uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset;
257         switch (reg_info->byte_size)
258         {
259             case 2:
260                 *(uint16_t *)dst = reg_value.GetAsUInt16();
261                 break;
262             case 4:
263                 *(uint32_t *)dst = reg_value.GetAsUInt32();
264                 break;
265             case 8:
266                 *(uint64_t *)dst = reg_value.GetAsUInt64();
267                 break;
268             default:
269                 assert(false && "Unhandled data size.");
270                 return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
271         }
272 
273         if (!WriteFPR())
274         {
275             return Error ("NativeRegisterContextLinux_arm64::WriteRegister: WriteFPR failed");
276         }
277 
278         return Error ();
279     }
280 
281     return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
282 }
283 
284 lldb_private::Error
285 NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
286 {
287     Error error;
288 
289     data_sp.reset (new lldb_private::DataBufferHeap (REG_CONTEXT_SIZE, 0));
290     if (!data_sp)
291         return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
292 
293     if (!ReadGPR ())
294     {
295         error.SetErrorString ("ReadGPR() failed");
296         return error;
297     }
298 
299     if (!ReadFPR ())
300     {
301         error.SetErrorString ("ReadFPR() failed");
302         return error;
303     }
304 
305     uint8_t *dst = data_sp->GetBytes ();
306     if (dst == nullptr)
307     {
308         error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
309         return error;
310     }
311 
312     ::memcpy (dst, &m_gpr_arm64, GetGPRSize());
313     dst += GetGPRSize();
314     ::memcpy (dst, &m_fpr, sizeof(m_fpr));
315 
316     return error;
317 }
318 
319 lldb_private::Error
320 NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
321 {
322     Error error;
323 
324     if (!data_sp)
325     {
326         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
327         return error;
328     }
329 
330     if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
331     {
332         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
333         return error;
334     }
335 
336 
337     uint8_t *src = data_sp->GetBytes ();
338     if (src == nullptr)
339     {
340         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
341         return error;
342     }
343     ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ());
344 
345     if (!WriteGPR ())
346     {
347         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteGPR() failed", __FUNCTION__);
348         return error;
349     }
350 
351     src += GetRegisterInfoInterface ().GetGPRSize ();
352     ::memcpy (&m_fpr, src, sizeof(m_fpr));
353 
354     if (!WriteFPR ())
355     {
356         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteFPR() failed", __FUNCTION__);
357         return error;
358     }
359 
360     return error;
361 }
362 
363 lldb_private::Error
364 NativeRegisterContextLinux_arm64::WriteRegisterRaw (uint32_t reg_index, const RegisterValue &reg_value)
365 {
366     Error error;
367 
368     uint32_t reg_to_write = reg_index;
369     RegisterValue value_to_write = reg_value;
370 
371     // Check if this is a subregister of a full register.
372     const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index);
373     if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
374     {
375         RegisterValue full_value;
376         uint32_t full_reg = reg_info->invalidate_regs[0];
377         const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
378 
379         // Read the full register.
380         error = ReadRegister(full_reg_info, full_value);
381         if (error.Fail ())
382             return error;
383 
384         lldb::ByteOrder byte_order = GetByteOrder();
385         uint8_t dst[RegisterValue::kMaxRegisterByteSize];
386 
387         // Get the bytes for the full register.
388         const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
389                                                                dst,
390                                                                sizeof(dst),
391                                                                byte_order,
392                                                                error);
393         if (error.Success() && dest_size)
394         {
395             uint8_t src[RegisterValue::kMaxRegisterByteSize];
396 
397             // Get the bytes for the source data.
398             const uint32_t src_size = reg_value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
399             if (error.Success() && src_size && (src_size < dest_size))
400             {
401                 // Copy the src bytes to the destination.
402                 memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
403                 // Set this full register as the value to write.
404                 value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
405                 value_to_write.SetType(full_reg_info);
406                 reg_to_write = full_reg;
407             }
408         }
409     }
410 
411     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
412     if (!process_sp)
413     {
414         error.SetErrorString ("NativeProcessProtocol is NULL");
415         return error;
416     }
417 
418     const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write);
419     assert (register_to_write_info_p && "register to write does not have valid RegisterInfo");
420     if (!register_to_write_info_p)
421     {
422         error.SetErrorStringWithFormat ("NativeRegisterContextLinux_arm64::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write);
423         return error;
424     }
425 
426     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
427     return process_p->WriteRegisterValue(m_thread.GetID(),
428                                          register_to_write_info_p->byte_offset,
429                                          register_to_write_info_p->name,
430                                          value_to_write);
431 }
432 
433 lldb_private::Error
434 NativeRegisterContextLinux_arm64::ReadRegisterRaw (uint32_t reg_index, RegisterValue &reg_value)
435 {
436     Error error;
437     const RegisterInfo *const reg_info = GetRegisterInfoAtIndex (reg_index);
438     if (!reg_info)
439     {
440         error.SetErrorStringWithFormat ("register %" PRIu32 " not found", reg_index);
441         return error;
442     }
443 
444     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
445     if (!process_sp)
446     {
447         error.SetErrorString ("NativeProcessProtocol is NULL");
448         return error;
449     }
450 
451     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
452     return process_p->ReadRegisterValue(m_thread.GetID(),
453                                         reg_info->byte_offset,
454                                         reg_info->name,
455                                         reg_info->byte_size,
456                                         reg_value);
457 }
458 
459 bool
460 NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const
461 {
462     return reg <= m_reg_info.last_gpr;   // GPR's come first.
463 }
464 
465 bool
466 NativeRegisterContextLinux_arm64::ReadGPR()
467 {
468     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
469     if (!process_sp)
470         return false;
471     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
472 
473     return process_p->ReadGPR (m_thread.GetID (), &m_gpr_arm64, GetRegisterInfoInterface ().GetGPRSize ()).Success();
474 }
475 
476 bool
477 NativeRegisterContextLinux_arm64::WriteGPR()
478 {
479     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
480     if (!process_sp)
481         return false;
482     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
483 
484     return process_p->WriteGPR (m_thread.GetID (), &m_gpr_arm64, GetRegisterInfoInterface ().GetGPRSize ()).Success();
485 }
486 
487 bool
488 NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const
489 {
490     return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
491 }
492 
493 bool
494 NativeRegisterContextLinux_arm64::ReadFPR ()
495 {
496     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
497     if (!process_sp)
498         return false;
499 
500     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
501     return process_p->ReadFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success();
502 }
503 
504 bool
505 NativeRegisterContextLinux_arm64::WriteFPR ()
506 {
507     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
508     if (!process_sp)
509         return false;
510 
511     NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
512     return process_p->WriteFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success();
513 }
514 
515 lldb::ByteOrder
516 NativeRegisterContextLinux_arm64::GetByteOrder() const
517 {
518     // Get the target process whose privileged thread was used for the register read.
519     lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
520 
521     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
522     if (!process_sp)
523         return byte_order;
524 
525     if (!process_sp->GetByteOrder (byte_order))
526     {
527         // FIXME log here
528     }
529 
530     return byte_order;
531 }
532 
533 size_t
534 NativeRegisterContextLinux_arm64::GetGPRSize() const
535 {
536     return GetRegisterInfoInterface().GetGPRSize();
537 }
538