1 //===-- GDBRemoteRegisterContext.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 "GDBRemoteRegisterContext.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 #include "lldb/Core/DataBufferHeap.h"
16 #include "lldb/Core/DataExtractor.h"
17 #include "lldb/Core/Scalar.h"
18 #include "lldb/Core/StreamString.h"
19 // Project includes
20 #include "Utility/StringExtractorGDBRemote.h"
21 #include "ProcessGDBRemote.h"
22 #include "ThreadGDBRemote.h"
23 #include "Utility/ARM_GCC_Registers.h"
24 #include "Utility/ARM_DWARF_Registers.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 //----------------------------------------------------------------------
30 // GDBRemoteRegisterContext constructor
31 //----------------------------------------------------------------------
32 GDBRemoteRegisterContext::GDBRemoteRegisterContext
33 (
34     ThreadGDBRemote &thread,
35     uint32_t concrete_frame_idx,
36     GDBRemoteDynamicRegisterInfo &reg_info,
37     bool read_all_at_once
38 ) :
39     RegisterContext (thread, concrete_frame_idx),
40     m_reg_info (reg_info),
41     m_reg_valid (),
42     m_reg_data (),
43     m_read_all_at_once (read_all_at_once)
44 {
45     // Resize our vector of bools to contain one bool for every register.
46     // We will use these boolean values to know when a register value
47     // is valid in m_reg_data.
48     m_reg_valid.resize (reg_info.GetNumRegisters());
49 
50     // Make a heap based buffer that is big enough to store all registers
51     DataBufferSP reg_data_sp(new DataBufferHeap (reg_info.GetRegisterDataByteSize(), 0));
52     m_reg_data.SetData (reg_data_sp);
53 
54 }
55 
56 //----------------------------------------------------------------------
57 // Destructor
58 //----------------------------------------------------------------------
59 GDBRemoteRegisterContext::~GDBRemoteRegisterContext()
60 {
61 }
62 
63 ProcessGDBRemote &
64 GDBRemoteRegisterContext::GetGDBProcess()
65 {
66     return static_cast<ProcessGDBRemote &>(m_thread.GetProcess());
67 }
68 
69 ThreadGDBRemote &
70 GDBRemoteRegisterContext::GetGDBThread()
71 {
72     return static_cast<ThreadGDBRemote &>(m_thread);
73 }
74 
75 void
76 GDBRemoteRegisterContext::InvalidateAllRegisters ()
77 {
78     SetAllRegisterValid (false);
79 }
80 
81 void
82 GDBRemoteRegisterContext::SetAllRegisterValid (bool b)
83 {
84     std::vector<bool>::iterator pos, end = m_reg_valid.end();
85     for (pos = m_reg_valid.begin(); pos != end; ++pos)
86         *pos = b;
87 }
88 
89 size_t
90 GDBRemoteRegisterContext::GetRegisterCount ()
91 {
92     return m_reg_info.GetNumRegisters ();
93 }
94 
95 const lldb::RegisterInfo *
96 GDBRemoteRegisterContext::GetRegisterInfoAtIndex (uint32_t reg)
97 {
98     return m_reg_info.GetRegisterInfoAtIndex (reg);
99 }
100 
101 size_t
102 GDBRemoteRegisterContext::GetRegisterSetCount ()
103 {
104     return m_reg_info.GetNumRegisterSets ();
105 }
106 
107 
108 
109 const lldb::RegisterSet *
110 GDBRemoteRegisterContext::GetRegisterSet (uint32_t reg_set)
111 {
112     return m_reg_info.GetRegisterSet (reg_set);
113 }
114 
115 
116 
117 bool
118 GDBRemoteRegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value)
119 {
120     // Read the register
121     if (ReadRegisterBytes (reg, m_reg_data))
122     {
123         const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
124         uint32_t offset = reg_info->byte_offset;
125         switch (reg_info->encoding)
126         {
127         case eEncodingUint:
128             switch (reg_info->byte_size)
129             {
130             case 1:
131             case 2:
132             case 4:
133                 value = m_reg_data.GetMaxU32 (&offset, reg_info->byte_size);
134                 return true;
135 
136             case 8:
137                 value = m_reg_data.GetMaxU64 (&offset, reg_info->byte_size);
138                 return true;
139             }
140             break;
141 
142         case eEncodingSint:
143             switch (reg_info->byte_size)
144             {
145             case 1:
146             case 2:
147             case 4:
148                 value = (int32_t)m_reg_data.GetMaxU32 (&offset, reg_info->byte_size);
149                 return true;
150 
151             case 8:
152                 value = m_reg_data.GetMaxS64 (&offset, reg_info->byte_size);
153                 return true;
154             }
155             break;
156 
157         case eEncodingIEEE754:
158             switch (reg_info->byte_size)
159             {
160             case sizeof (float):
161                 value = m_reg_data.GetFloat (&offset);
162                 return true;
163 
164             case sizeof (double):
165                 value = m_reg_data.GetDouble (&offset);
166                 return true;
167 
168             case sizeof (long double):
169                 value = m_reg_data.GetLongDouble (&offset);
170                 return true;
171             }
172             break;
173 
174         default:
175             break;
176         }
177     }
178     return false;
179 }
180 
181 void
182 GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response)
183 {
184     const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
185     assert (reg_info);
186 
187     // Invalidate if needed
188     InvalidateIfNeeded(false);
189 
190     const uint32_t reg_byte_size = reg_info->byte_size;
191     const size_t bytes_copied = response.GetHexBytes (const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_byte_size)), reg_byte_size, '\xcc');
192     bool success = bytes_copied == reg_byte_size;
193     if (success)
194     {
195         m_reg_valid[reg] = true;
196     }
197     else if (bytes_copied > 0)
198     {
199         // Only set register is valid to false if we copied some bytes, else
200         // leave it as it was.
201         m_reg_valid[reg] = false;
202     }
203 }
204 
205 
206 bool
207 GDBRemoteRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
208 {
209     GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote();
210 
211     InvalidateIfNeeded(false);
212 
213     const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
214     assert (reg_info);
215     if (!m_reg_valid[reg])
216     {
217         Mutex::Locker locker;
218         if (gdb_comm.GetSequenceMutex (locker))
219         {
220             const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
221             if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
222             {
223                 char packet[64];
224                 StringExtractorGDBRemote response;
225                 int packet_len = 0;
226                 if (m_read_all_at_once)
227                 {
228                     // Get all registers in one packet
229                     if (thread_suffix_supported)
230                         packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4x;", m_thread.GetID());
231                     else
232                         packet_len = ::snprintf (packet, sizeof(packet), "g");
233                     assert (packet_len < (sizeof(packet) - 1));
234                     if (gdb_comm.SendPacketAndWaitForResponse(packet, response, 1, false))
235                     {
236                         if (response.IsNormalPacket())
237                             if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize())
238                                 SetAllRegisterValid (true);
239                     }
240                 }
241                 else
242                 {
243                     // Get each register individually
244                     if (thread_suffix_supported)
245                         packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4x;", reg, m_thread.GetID());
246                     else
247                         packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg);
248                     assert (packet_len < (sizeof(packet) - 1));
249                     if (gdb_comm.SendPacketAndWaitForResponse(packet, response, 1, false))
250                         PrivateSetRegisterValue (reg, response);
251                 }
252             }
253         }
254 
255         // Make sure we got a valid register value after reading it
256         if (!m_reg_valid[reg])
257             return false;
258     }
259 
260     if (&data != &m_reg_data)
261     {
262         // If we aren't extracting into our own buffer (which
263         // only happens when this function is called from
264         // ReadRegisterValue(uint32_t, Scalar&)) then
265         // we transfer bytes from our buffer into the data
266         // buffer that was passed in
267         data.SetByteOrder (m_reg_data.GetByteOrder());
268         data.SetData (m_reg_data, reg_info->byte_offset, reg_info->byte_size);
269     }
270     return true;
271 }
272 
273 
274 bool
275 GDBRemoteRegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value)
276 {
277     const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
278     if (reg_info)
279     {
280         DataExtractor data;
281         if (value.GetData (data, reg_info->byte_size))
282             return WriteRegisterBytes (reg, data, 0);
283     }
284     return false;
285 }
286 
287 
288 bool
289 GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
290 {
291     GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote();
292 // FIXME: This check isn't right because IsRunning checks the Public state, but this
293 // is work you need to do - for instance in ShouldStop & friends - before the public
294 // state has been changed.
295 //    if (gdb_comm.IsRunning())
296 //        return false;
297 
298     const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
299 
300     if (reg_info)
301     {
302         // Grab a pointer to where we are going to put this register
303         uint8_t *dst = const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size));
304 
305         if (dst == NULL)
306             return false;
307 
308         // Grab a pointer to where we are going to grab the new value from
309         const uint8_t *src = data.PeekData(0, reg_info->byte_size);
310 
311         if (src == NULL)
312             return false;
313 
314         if (data.GetByteOrder() == m_reg_data.GetByteOrder())
315         {
316             // No swapping, just copy the bytes
317             ::memcpy (dst, src, reg_info->byte_size);
318         }
319         else
320         {
321             // Swap the bytes
322             for (uint32_t i=0; i<reg_info->byte_size; ++i)
323                 dst[i] = src[reg_info->byte_size - 1 - i];
324         }
325 
326         Mutex::Locker locker;
327         if (gdb_comm.GetSequenceMutex (locker))
328         {
329             const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
330             if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
331             {
332                 uint32_t offset, end_offset;
333                 StreamString packet;
334                 StringExtractorGDBRemote response;
335                 if (m_read_all_at_once)
336                 {
337                     // Get all registers in one packet
338                     packet.PutChar ('G');
339                     offset = 0;
340                     end_offset = m_reg_data.GetByteSize();
341 
342                     packet.PutBytesAsRawHex8 (m_reg_data.GetDataStart(),
343                                               m_reg_data.GetByteSize(),
344                                               eByteOrderHost,
345                                               eByteOrderHost);
346 
347                     if (thread_suffix_supported)
348                         packet.Printf (";thread:%4.4x;", m_thread.GetID());
349 
350                     // Invalidate all register values
351                     InvalidateIfNeeded (true);
352 
353                     if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
354                                                               packet.GetString().size(),
355                                                               response,
356                                                               1,
357                                                               false))
358                     {
359                         SetAllRegisterValid (false);
360                         if (response.IsOKPacket())
361                         {
362                             return true;
363                         }
364                     }
365                 }
366                 else
367                 {
368                     // Get each register individually
369                     packet.Printf ("P%x=", reg);
370                     packet.PutBytesAsRawHex8 (m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size),
371                                               reg_info->byte_size,
372                                               eByteOrderHost,
373                                               eByteOrderHost);
374 
375                     if (thread_suffix_supported)
376                         packet.Printf (";thread:%4.4x;", m_thread.GetID());
377 
378                     // Invalidate just this register
379                     m_reg_valid[reg] = false;
380                     if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
381                                                               packet.GetString().size(),
382                                                               response,
383                                                               1,
384                                                               false))
385                     {
386                         if (response.IsOKPacket())
387                         {
388                             return true;
389                         }
390                     }
391                 }
392             }
393         }
394     }
395     return false;
396 }
397 
398 
399 bool
400 GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
401 {
402     GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote();
403     StringExtractorGDBRemote response;
404 
405     Mutex::Locker locker;
406     if (gdb_comm.GetSequenceMutex (locker))
407     {
408         char packet[32];
409         const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
410         if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
411         {
412             int packet_len = 0;
413             if (thread_suffix_supported)
414                 packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4x", m_thread.GetID());
415             else
416                 packet_len = ::snprintf (packet, sizeof(packet), "g");
417             assert (packet_len < (sizeof(packet) - 1));
418 
419             if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, 1, false))
420             {
421                 if (response.IsErrorPacket())
422                     return false;
423 
424                 response.GetStringRef().insert(0, 1, 'G');
425                 if (thread_suffix_supported)
426                 {
427                     char thread_id_cstr[64];
428                     ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4x;", m_thread.GetID());
429                     response.GetStringRef().append (thread_id_cstr);
430                 }
431                 data_sp.reset (new DataBufferHeap (response.GetStringRef().c_str(),
432                                                    response.GetStringRef().size()));
433                 return true;
434             }
435         }
436     }
437     return false;
438 }
439 
440 bool
441 GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
442 {
443     if (!data_sp || data_sp->GetBytes() == NULL || data_sp->GetByteSize() == 0)
444         return false;
445 
446     GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote();
447     StringExtractorGDBRemote response;
448     Mutex::Locker locker;
449     if (gdb_comm.GetSequenceMutex (locker))
450     {
451         const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
452         if (thread_suffix_supported || GetGDBProcess().SetCurrentGDBRemoteThread(m_thread.GetID()))
453         {
454             if (gdb_comm.SendPacketAndWaitForResponse((const char *)data_sp->GetBytes(),
455                                                       data_sp->GetByteSize(),
456                                                       response,
457                                                       1,
458                                                       false))
459             {
460                 if (response.IsOKPacket())
461                     return true;
462             }
463         }
464     }
465     return false;
466 }
467 
468 
469 uint32_t
470 GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
471 {
472     return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num);
473 }
474 
475 void
476 GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters()
477 {
478     static lldb::RegisterInfo
479     g_register_infos[] =
480     {
481         //  NAME        ALT     SZ  OFF   ENCODING           FORMAT            COMPILER              DWARF               GENERIC              GDB                    LLDB NATIVE
482         //  ======      ======= ==  ====  =============      ============    ===============         ===============     =========             =====                   ===========
483         {   "r0",       NULL,   4,    0,  eEncodingUint,     eFormatHex,     { gcc_r0,               dwarf_r0,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,    0  }},
484         {   "r1",       NULL,   4,    4,  eEncodingUint,     eFormatHex,     { gcc_r1,               dwarf_r1,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,    1 }},
485         {   "r2",       NULL,   4,    8,  eEncodingUint,     eFormatHex,     { gcc_r2,               dwarf_r2,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,    2 }},
486         {   "r3",       NULL,   4,   12,  eEncodingUint,     eFormatHex,     { gcc_r3,               dwarf_r3,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,    3 }},
487         {   "r4",       NULL,   4,   16,  eEncodingUint,     eFormatHex,     { gcc_r4,               dwarf_r4,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,    4 }},
488         {   "r5",       NULL,   4,   20,  eEncodingUint,     eFormatHex,     { gcc_r5,               dwarf_r5,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,    5 }},
489         {   "r6",       NULL,   4,   24,  eEncodingUint,     eFormatHex,     { gcc_r6,               dwarf_r6,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,    6 }},
490         {   "r7",       NULL,   4,   28,  eEncodingUint,     eFormatHex,     { gcc_r7,               dwarf_r7,           LLDB_REGNUM_GENERIC_FP,  LLDB_INVALID_REGNUM, 7 }},
491         {   "r8",       NULL,   4,   32,  eEncodingUint,     eFormatHex,     { gcc_r8,               dwarf_r8,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,    8 }},
492         {   "r9",       NULL,   4,   36,  eEncodingUint,     eFormatHex,     { gcc_r9,               dwarf_r9,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,    9 }},
493         {   "r10",      NULL,   4,   40,  eEncodingUint,     eFormatHex,     { gcc_r10,              dwarf_r10,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,    10 }},
494         {   "r11",      NULL,   4,   44,  eEncodingUint,     eFormatHex,     { gcc_r11,              dwarf_r11,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,    11 }},
495         {   "r12",      NULL,   4,   48,  eEncodingUint,     eFormatHex,     { gcc_r12,              dwarf_r12,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,    12 }},
496         {   "sp",      "r13",   4,   52,  eEncodingUint,     eFormatHex,     { gcc_sp,               dwarf_sp,           LLDB_REGNUM_GENERIC_SP,  LLDB_INVALID_REGNUM, 13 }},
497         {   "lr",      "r14",   4,   56,  eEncodingUint,     eFormatHex,     { gcc_lr,               dwarf_lr,           LLDB_REGNUM_GENERIC_RA,  LLDB_INVALID_REGNUM, 14 }},
498         {   "pc",      "r15",   4,   60,  eEncodingUint,     eFormatHex,     { gcc_pc,               dwarf_pc,           LLDB_REGNUM_GENERIC_PC,  LLDB_INVALID_REGNUM, 15 }},
499         {   NULL,       NULL,  12,   64,  eEncodingIEEE754,  eFormatFloat,   { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS,  LLDB_INVALID_REGNUM, 16 }},
500         {   NULL,       NULL,  12,   76,  eEncodingIEEE754,  eFormatFloat,   { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS,  LLDB_INVALID_REGNUM, 17 }},
501         {   NULL,       NULL,  12,   88,  eEncodingIEEE754,  eFormatFloat,   { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS,  LLDB_INVALID_REGNUM, 18 }},
502         {   NULL,       NULL,  12,  100,  eEncodingIEEE754,  eFormatFloat,   { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS,  LLDB_INVALID_REGNUM, 19 }},
503         {   NULL,       NULL,  12,  112,  eEncodingIEEE754,  eFormatFloat,   { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS,  LLDB_INVALID_REGNUM, 20 }},
504         {   NULL,       NULL,  12,  124,  eEncodingIEEE754,  eFormatFloat,   { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS,  LLDB_INVALID_REGNUM, 21 }},
505         {   NULL,       NULL,  12,  136,  eEncodingIEEE754,  eFormatFloat,   { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS,  LLDB_INVALID_REGNUM, 22 }},
506         {   NULL,       NULL,  12,  148,  eEncodingIEEE754,  eFormatFloat,   { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS,  LLDB_INVALID_REGNUM, 23 }},
507         {   NULL,       NULL,  12,  160,  eEncodingIEEE754,  eFormatFloat,   { LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS, LLDB_REGNUM_GENERIC_FLAGS,  LLDB_INVALID_REGNUM, 24 }},
508         {   "cpsr",     "psr",  4,  172,  eEncodingUint,     eFormatHex,     { gcc_cpsr,             dwarf_cpsr,         LLDB_REGNUM_GENERIC_FLAGS,  LLDB_INVALID_REGNUM,  25 }},
509         {   "s0",       NULL,   4,  176,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s0,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     26 }},
510         {   "s1",       NULL,   4,  180,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s1,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     27 }},
511         {   "s2",       NULL,   4,  184,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s2,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     28 }},
512         {   "s3",       NULL,   4,  188,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s3,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     29 }},
513         {   "s4",       NULL,   4,  192,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s4,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     30 }},
514         {   "s5",       NULL,   4,  196,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s5,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     31 }},
515         {   "s6",       NULL,   4,  200,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s6,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     32 }},
516         {   "s7",       NULL,   4,  204,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s7,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     33 }},
517         {   "s8",       NULL,   4,  208,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s8,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     34 }},
518         {   "s9",       NULL,   4,  212,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s9,           LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     35 }},
519         {   "s10",      NULL,   4,  216,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s10,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     36 }},
520         {   "s11",      NULL,   4,  220,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s11,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     37 }},
521         {   "s12",      NULL,   4,  224,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s12,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     38 }},
522         {   "s13",      NULL,   4,  228,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s13,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     39 }},
523         {   "s14",      NULL,   4,  232,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s14,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     40 }},
524         {   "s15",      NULL,   4,  236,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s15,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     41 }},
525         {   "s16",      NULL,   4,  240,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s16,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     42 }},
526         {   "s17",      NULL,   4,  244,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s17,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     43 }},
527         {   "s18",      NULL,   4,  248,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s18,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     44 }},
528         {   "s19",      NULL,   4,  252,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s19,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     45 }},
529         {   "s20",      NULL,   4,  256,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s20,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     46 }},
530         {   "s21",      NULL,   4,  260,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s21,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     47 }},
531         {   "s22",      NULL,   4,  264,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s22,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     48 }},
532         {   "s23",      NULL,   4,  268,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s23,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     49 }},
533         {   "s24",      NULL,   4,  272,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s24,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     50 }},
534         {   "s25",      NULL,   4,  276,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s25,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     51 }},
535         {   "s26",      NULL,   4,  280,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s26,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     52 }},
536         {   "s27",      NULL,   4,  284,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s27,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     53 }},
537         {   "s28",      NULL,   4,  288,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s28,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     54 }},
538         {   "s29",      NULL,   4,  292,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s29,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     55 }},
539         {   "s30",      NULL,   4,  296,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s30,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     56 }},
540         {   "s31",      NULL,   4,  300,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_s31,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     57 }},
541         {   "fpscr",    NULL,   4,  304,  eEncodingUint,     eFormatHex,     { LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     58 }},
542         {   "d16",      NULL,   8,  308,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d16,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     59 }},
543         {   "d17",      NULL,   8,  316,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d17,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     60 }},
544         {   "d18",      NULL,   8,  324,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d18,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     61 }},
545         {   "d19",      NULL,   8,  332,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d19,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     62 }},
546         {   "d20",      NULL,   8,  340,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d20,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     63 }},
547         {   "d21",      NULL,   8,  348,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d21,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     64 }},
548         {   "d22",      NULL,   8,  356,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d22,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     65 }},
549         {   "d23",      NULL,   8,  364,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d23,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     66 }},
550         {   "d24",      NULL,   8,  372,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d24,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     67 }},
551         {   "d25",      NULL,   8,  380,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d25,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     68 }},
552         {   "d26",      NULL,   8,  388,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d26,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     69 }},
553         {   "d27",      NULL,   8,  396,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d27,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     70 }},
554         {   "d28",      NULL,   8,  404,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d28,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     71 }},
555         {   "d29",      NULL,   8,  412,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d29,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     72 }},
556         {   "d30",      NULL,   8,  420,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d30,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     73 }},
557         {   "d31",      NULL,   8,  428,  eEncodingIEEE754,  eFormatFloat,   { LLDB_INVALID_REGNUM,  dwarf_d31,          LLDB_INVALID_REGNUM,  LLDB_INVALID_REGNUM,     74 }},
558     };
559     static const uint32_t num_registers = sizeof (g_register_infos)/sizeof (lldb::RegisterInfo);
560     static ConstString gpr_reg_set ("General Purpose Registers");
561     static ConstString vfp_reg_set ("Floating Point Registers");
562     for (uint32_t i=0; i<num_registers; ++i)
563     {
564         ConstString name;
565         ConstString alt_name;
566         if (g_register_infos[i].name && g_register_infos[i].name[0])
567             name.SetCString(g_register_infos[i].name);
568         if (g_register_infos[i].alt_name && g_register_infos[i].alt_name[0])
569             alt_name.SetCString(g_register_infos[i].alt_name);
570 
571         AddRegister (g_register_infos[i], name, alt_name, i < 26 ? gpr_reg_set : vfp_reg_set);
572     }
573 }
574 
575