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