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