llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
Greg Clayton ce1ffcf8a2 <rdar://problem/13020634>
Fixed the 32, 16, and 8 bit pseudo regs for x86_64 (real reg of "rax" which subvalues "eax", "ax", etc...) to correctly get updated when stepping. Also fixed it so actual registers can specify what other registers must be invalidated when a register is modified. Previously, only pseudo registers could invalidate other registers.

Modified the LLDB qRegisterInfo extension to the GDB remote interface to support specifying the containing registers with the new "container-regs" key whose value is a comma separated list of register numbers. Also added a "invalidate-regs" key whose value is also a comma separated list of register numbers. 

Removed the hack GDBRemoteDynamicRegisterInfo::Addx86_64ConvenienceRegisters() function and modified "debugserver" to specify the registers correctly using the new "container-regs" and "invalidate-regs" keys.

llvm-svn: 173096
2013-01-21 22:17:50 +00:00

936 lines
54 KiB
C++

//===-- GDBRemoteRegisterContext.cpp ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "GDBRemoteRegisterContext.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Utility/Utils.h"
// Project includes
#include "Utility/StringExtractorGDBRemote.h"
#include "ProcessGDBRemote.h"
#include "ProcessGDBRemoteLog.h"
#include "ThreadGDBRemote.h"
#include "Utility/ARM_GCC_Registers.h"
#include "Utility/ARM_DWARF_Registers.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// GDBRemoteRegisterContext constructor
//----------------------------------------------------------------------
GDBRemoteRegisterContext::GDBRemoteRegisterContext
(
ThreadGDBRemote &thread,
uint32_t concrete_frame_idx,
GDBRemoteDynamicRegisterInfo &reg_info,
bool read_all_at_once
) :
RegisterContext (thread, concrete_frame_idx),
m_reg_info (reg_info),
m_reg_valid (),
m_reg_data (),
m_read_all_at_once (read_all_at_once)
{
// Resize our vector of bools to contain one bool for every register.
// We will use these boolean values to know when a register value
// is valid in m_reg_data.
m_reg_valid.resize (reg_info.GetNumRegisters());
// Make a heap based buffer that is big enough to store all registers
DataBufferSP reg_data_sp(new DataBufferHeap (reg_info.GetRegisterDataByteSize(), 0));
m_reg_data.SetData (reg_data_sp);
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
GDBRemoteRegisterContext::~GDBRemoteRegisterContext()
{
}
void
GDBRemoteRegisterContext::InvalidateAllRegisters ()
{
SetAllRegisterValid (false);
}
void
GDBRemoteRegisterContext::SetAllRegisterValid (bool b)
{
std::vector<bool>::iterator pos, end = m_reg_valid.end();
for (pos = m_reg_valid.begin(); pos != end; ++pos)
*pos = b;
}
size_t
GDBRemoteRegisterContext::GetRegisterCount ()
{
return m_reg_info.GetNumRegisters ();
}
const RegisterInfo *
GDBRemoteRegisterContext::GetRegisterInfoAtIndex (uint32_t reg)
{
return m_reg_info.GetRegisterInfoAtIndex (reg);
}
size_t
GDBRemoteRegisterContext::GetRegisterSetCount ()
{
return m_reg_info.GetNumRegisterSets ();
}
const RegisterSet *
GDBRemoteRegisterContext::GetRegisterSet (uint32_t reg_set)
{
return m_reg_info.GetRegisterSet (reg_set);
}
bool
GDBRemoteRegisterContext::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
{
// Read the register
if (ReadRegisterBytes (reg_info, m_reg_data))
{
const bool partial_data_ok = false;
Error error (value.SetValueFromData(reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok));
return error.Success();
}
return false;
}
bool
GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response)
{
const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
if (reg_info == NULL)
return false;
// Invalidate if needed
InvalidateIfNeeded(false);
const uint32_t reg_byte_size = reg_info->byte_size;
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');
bool success = bytes_copied == reg_byte_size;
if (success)
{
SetRegisterIsValid(reg, true);
}
else if (bytes_copied > 0)
{
// Only set register is valid to false if we copied some bytes, else
// leave it as it was.
SetRegisterIsValid(reg, false);
}
return success;
}
// Helper function for GDBRemoteRegisterContext::ReadRegisterBytes().
bool
GDBRemoteRegisterContext::GetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
GDBRemoteCommunicationClient &gdb_comm)
{
char packet[64];
StringExtractorGDBRemote response;
int packet_len = 0;
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
if (gdb_comm.GetThreadSuffixSupported())
packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, m_thread.GetID());
else
packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg);
assert (packet_len < (sizeof(packet) - 1));
if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false))
return PrivateSetRegisterValue (reg, response);
return false;
}
bool
GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data)
{
ExecutionContext exe_ctx (CalculateThread());
Process *process = exe_ctx.GetProcessPtr();
Thread *thread = exe_ctx.GetThreadPtr();
if (process == NULL || thread == NULL)
return false;
GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
InvalidateIfNeeded(false);
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
if (!GetRegisterIsValid(reg))
{
Mutex::Locker locker;
if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read register."))
{
const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
ProcessSP process_sp (m_thread.GetProcess());
if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetID()))
{
char packet[64];
StringExtractorGDBRemote response;
int packet_len = 0;
if (m_read_all_at_once)
{
// Get all registers in one packet
if (thread_suffix_supported)
packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", m_thread.GetID());
else
packet_len = ::snprintf (packet, sizeof(packet), "g");
assert (packet_len < (sizeof(packet) - 1));
if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false))
{
if (response.IsNormalResponse())
if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize())
SetAllRegisterValid (true);
}
}
else if (reg_info->value_regs)
{
// Process this composite register request by delegating to the constituent
// primordial registers.
// Index of the primordial register.
bool success = true;
for (uint32_t idx = 0; success; ++idx)
{
const uint32_t prim_reg = reg_info->value_regs[idx];
if (prim_reg == LLDB_INVALID_REGNUM)
break;
// We have a valid primordial regsiter as our constituent.
// Grab the corresponding register info.
const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg);
if (prim_reg_info == NULL)
success = false;
else
{
// Read the containing register if it hasn't already been read
if (!GetRegisterIsValid(prim_reg))
success = GetPrimordialRegister(prim_reg_info, gdb_comm);
}
}
if (success)
{
// If we reach this point, all primordial register requests have succeeded.
// Validate this composite register.
SetRegisterIsValid (reg_info, true);
}
}
else
{
// Get each register individually
GetPrimordialRegister(reg_info, gdb_comm);
}
}
}
else
{
LogSP log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
#if LLDB_CONFIGURATION_DEBUG
StreamString strm;
gdb_comm.DumpHistory(strm);
Host::SetCrashDescription (strm.GetData());
assert (!"Didn't get sequence mutex for read register.");
#else
if (log)
{
if (log->GetVerbose())
{
StreamString strm;
gdb_comm.DumpHistory(strm);
log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\":\n%s", reg_info->name, strm.GetData());
}
else
{
log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\"", reg_info->name);
}
}
#endif
}
// Make sure we got a valid register value after reading it
if (!GetRegisterIsValid(reg))
return false;
}
if (&data != &m_reg_data)
{
// If we aren't extracting into our own buffer (which
// only happens when this function is called from
// ReadRegisterValue(uint32_t, Scalar&)) then
// we transfer bytes from our buffer into the data
// buffer that was passed in
data.SetByteOrder (m_reg_data.GetByteOrder());
data.SetData (m_reg_data, reg_info->byte_offset, reg_info->byte_size);
}
return true;
}
bool
GDBRemoteRegisterContext::WriteRegister (const RegisterInfo *reg_info,
const RegisterValue &value)
{
DataExtractor data;
if (value.GetData (data))
return WriteRegisterBytes (reg_info, data, 0);
return false;
}
// Helper function for GDBRemoteRegisterContext::WriteRegisterBytes().
bool
GDBRemoteRegisterContext::SetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
GDBRemoteCommunicationClient &gdb_comm)
{
StreamString packet;
StringExtractorGDBRemote response;
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
packet.Printf ("P%x=", reg);
packet.PutBytesAsRawHex8 (m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size),
reg_info->byte_size,
lldb::endian::InlHostByteOrder(),
lldb::endian::InlHostByteOrder());
if (gdb_comm.GetThreadSuffixSupported())
packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetID());
// Invalidate just this register
SetRegisterIsValid(reg, false);
if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
packet.GetString().size(),
response,
false))
{
if (response.IsOKResponse())
return true;
}
return false;
}
void
GDBRemoteRegisterContext::SyncThreadState(Process *process)
{
// NB. We assume our caller has locked the sequence mutex.
GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *) process)->GetGDBRemote());
if (!gdb_comm.GetSyncThreadStateSupported())
return;
StreamString packet;
StringExtractorGDBRemote response;
packet.Printf ("QSyncThreadState:%4.4" PRIx64 ";", m_thread.GetID());
if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
packet.GetString().size(),
response,
false))
{
if (response.IsOKResponse())
InvalidateAllRegisters();
}
}
bool
GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo *reg_info, DataExtractor &data, uint32_t data_offset)
{
ExecutionContext exe_ctx (CalculateThread());
Process *process = exe_ctx.GetProcessPtr();
Thread *thread = exe_ctx.GetThreadPtr();
if (process == NULL || thread == NULL)
return false;
GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
// FIXME: This check isn't right because IsRunning checks the Public state, but this
// is work you need to do - for instance in ShouldStop & friends - before the public
// state has been changed.
// if (gdb_comm.IsRunning())
// return false;
// Grab a pointer to where we are going to put this register
uint8_t *dst = const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size));
if (dst == NULL)
return false;
if (data.CopyByteOrderedData (data_offset, // src offset
reg_info->byte_size, // src length
dst, // dst
reg_info->byte_size, // dst length
m_reg_data.GetByteOrder())) // dst byte order
{
Mutex::Locker locker;
if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write register."))
{
const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
ProcessSP process_sp (m_thread.GetProcess());
if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetID()))
{
StreamString packet;
StringExtractorGDBRemote response;
if (m_read_all_at_once)
{
// Set all registers in one packet
packet.PutChar ('G');
packet.PutBytesAsRawHex8 (m_reg_data.GetDataStart(),
m_reg_data.GetByteSize(),
lldb::endian::InlHostByteOrder(),
lldb::endian::InlHostByteOrder());
if (thread_suffix_supported)
packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetID());
// Invalidate all register values
InvalidateIfNeeded (true);
if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
packet.GetString().size(),
response,
false))
{
SetAllRegisterValid (false);
if (response.IsOKResponse())
{
return true;
}
}
}
else
{
bool success = true;
if (reg_info->value_regs)
{
// This register is part of another register. In this case we read the actual
// register data for any "value_regs", and once all that data is read, we will
// have enough data in our register context bytes for the value of this register
// Invalidate this composite register first.
for (uint32_t idx = 0; success; ++idx)
{
const uint32_t reg = reg_info->value_regs[idx];
if (reg == LLDB_INVALID_REGNUM)
break;
// We have a valid primordial regsiter as our constituent.
// Grab the corresponding register info.
const RegisterInfo *value_reg_info = GetRegisterInfoAtIndex(reg);
if (value_reg_info == NULL)
success = false;
else
success = SetPrimordialRegister(value_reg_info, gdb_comm);
}
}
else
{
// This is an actual register, write it
success = SetPrimordialRegister(reg_info, gdb_comm);
}
// Check if writing this register will invalidate any other register values?
// If so, invalidate them
if (reg_info->invalidate_regs)
{
for (uint32_t idx = 0, reg = reg_info->invalidate_regs[0];
reg != LLDB_INVALID_REGNUM;
reg = reg_info->invalidate_regs[++idx])
{
SetRegisterIsValid(reg, false);
}
}
return success;
}
}
}
else
{
LogSP log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
if (log)
{
if (log->GetVerbose())
{
StreamString strm;
gdb_comm.DumpHistory(strm);
log->Printf("error: failed to get packet sequence mutex, not sending write register for \"%s\":\n%s", reg_info->name, strm.GetData());
}
else
log->Printf("error: failed to get packet sequence mutex, not sending write register for \"%s\"", reg_info->name);
}
}
}
return false;
}
bool
GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
{
ExecutionContext exe_ctx (CalculateThread());
Process *process = exe_ctx.GetProcessPtr();
Thread *thread = exe_ctx.GetThreadPtr();
if (process == NULL || thread == NULL)
return false;
GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
StringExtractorGDBRemote response;
Mutex::Locker locker;
if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers."))
{
SyncThreadState(process);
char packet[32];
const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
ProcessSP process_sp (m_thread.GetProcess());
if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetID()))
{
int packet_len = 0;
if (thread_suffix_supported)
packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetID());
else
packet_len = ::snprintf (packet, sizeof(packet), "g");
assert (packet_len < (sizeof(packet) - 1));
if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false))
{
if (response.IsErrorResponse())
return false;
std::string &response_str = response.GetStringRef();
if (isxdigit(response_str[0]))
{
response_str.insert(0, 1, 'G');
if (thread_suffix_supported)
{
char thread_id_cstr[64];
::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetID());
response_str.append (thread_id_cstr);
}
data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size()));
return true;
}
}
}
}
else
{
LogSP log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
if (log)
{
if (log->GetVerbose())
{
StreamString strm;
gdb_comm.DumpHistory(strm);
log->Printf("error: failed to get packet sequence mutex, not sending read all registers:\n%s", strm.GetData());
}
else
log->Printf("error: failed to get packet sequence mutex, not sending read all registers");
}
}
data_sp.reset();
return false;
}
bool
GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
{
if (!data_sp || data_sp->GetBytes() == NULL || data_sp->GetByteSize() == 0)
return false;
ExecutionContext exe_ctx (CalculateThread());
Process *process = exe_ctx.GetProcessPtr();
Thread *thread = exe_ctx.GetThreadPtr();
if (process == NULL || thread == NULL)
return false;
GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
StringExtractorGDBRemote response;
Mutex::Locker locker;
if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write all registers."))
{
const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
ProcessSP process_sp (m_thread.GetProcess());
if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetID()))
{
// The data_sp contains the entire G response packet including the
// G, and if the thread suffix is supported, it has the thread suffix
// as well.
const char *G_packet = (const char *)data_sp->GetBytes();
size_t G_packet_len = data_sp->GetByteSize();
if (gdb_comm.SendPacketAndWaitForResponse (G_packet,
G_packet_len,
response,
false))
{
if (response.IsOKResponse())
return true;
else if (response.IsErrorResponse())
{
uint32_t num_restored = 0;
// We need to manually go through all of the registers and
// restore them manually
response.GetStringRef().assign (G_packet, G_packet_len);
response.SetFilePos(1); // Skip the leading 'G'
DataBufferHeap buffer (m_reg_data.GetByteSize(), 0);
DataExtractor restore_data (buffer.GetBytes(),
buffer.GetByteSize(),
m_reg_data.GetByteOrder(),
m_reg_data.GetAddressByteSize());
const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(),
restore_data.GetByteSize(),
'\xcc');
if (bytes_extracted < restore_data.GetByteSize())
restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder());
//ReadRegisterBytes (const RegisterInfo *reg_info, RegisterValue &value, DataExtractor &data)
const RegisterInfo *reg_info;
// We have to march the offset of each register along in the
// buffer to make sure we get the right offset.
uint32_t reg_byte_offset = 0;
for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, reg_byte_offset += reg_info->byte_size)
{
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
// Skip composite registers.
if (reg_info->value_regs)
continue;
// Only write down the registers that need to be written
// if we are going to be doing registers individually.
bool write_reg = true;
const uint32_t reg_byte_size = reg_info->byte_size;
const char *restore_src = (const char *)restore_data.PeekData(reg_byte_offset, reg_byte_size);
if (restore_src)
{
if (GetRegisterIsValid(reg))
{
const char *current_src = (const char *)m_reg_data.PeekData(reg_byte_offset, reg_byte_size);
if (current_src)
write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0;
}
if (write_reg)
{
StreamString packet;
packet.Printf ("P%x=", reg);
packet.PutBytesAsRawHex8 (restore_src,
reg_byte_size,
lldb::endian::InlHostByteOrder(),
lldb::endian::InlHostByteOrder());
if (thread_suffix_supported)
packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetID());
SetRegisterIsValid(reg, false);
if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
packet.GetString().size(),
response,
false))
{
if (response.IsOKResponse())
++num_restored;
}
}
}
}
return num_restored > 0;
}
}
}
}
else
{
LogSP log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
if (log)
{
if (log->GetVerbose())
{
StreamString strm;
gdb_comm.DumpHistory(strm);
log->Printf("error: failed to get packet sequence mutex, not sending write all registers:\n%s", strm.GetData());
}
else
log->Printf("error: failed to get packet sequence mutex, not sending write all registers");
}
}
return false;
}
uint32_t
GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
{
return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num);
}
void
GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch)
{
// For Advanced SIMD and VFP register mapping.
static uint32_t g_d0_regs[] = { 26, 27, LLDB_INVALID_REGNUM }; // (s0, s1)
static uint32_t g_d1_regs[] = { 28, 29, LLDB_INVALID_REGNUM }; // (s2, s3)
static uint32_t g_d2_regs[] = { 30, 31, LLDB_INVALID_REGNUM }; // (s4, s5)
static uint32_t g_d3_regs[] = { 32, 33, LLDB_INVALID_REGNUM }; // (s6, s7)
static uint32_t g_d4_regs[] = { 34, 35, LLDB_INVALID_REGNUM }; // (s8, s9)
static uint32_t g_d5_regs[] = { 36, 37, LLDB_INVALID_REGNUM }; // (s10, s11)
static uint32_t g_d6_regs[] = { 38, 39, LLDB_INVALID_REGNUM }; // (s12, s13)
static uint32_t g_d7_regs[] = { 40, 41, LLDB_INVALID_REGNUM }; // (s14, s15)
static uint32_t g_d8_regs[] = { 42, 43, LLDB_INVALID_REGNUM }; // (s16, s17)
static uint32_t g_d9_regs[] = { 44, 45, LLDB_INVALID_REGNUM }; // (s18, s19)
static uint32_t g_d10_regs[] = { 46, 47, LLDB_INVALID_REGNUM }; // (s20, s21)
static uint32_t g_d11_regs[] = { 48, 49, LLDB_INVALID_REGNUM }; // (s22, s23)
static uint32_t g_d12_regs[] = { 50, 51, LLDB_INVALID_REGNUM }; // (s24, s25)
static uint32_t g_d13_regs[] = { 52, 53, LLDB_INVALID_REGNUM }; // (s26, s27)
static uint32_t g_d14_regs[] = { 54, 55, LLDB_INVALID_REGNUM }; // (s28, s29)
static uint32_t g_d15_regs[] = { 56, 57, LLDB_INVALID_REGNUM }; // (s30, s31)
static uint32_t g_q0_regs[] = { 26, 27, 28, 29, LLDB_INVALID_REGNUM }; // (d0, d1) -> (s0, s1, s2, s3)
static uint32_t g_q1_regs[] = { 30, 31, 32, 33, LLDB_INVALID_REGNUM }; // (d2, d3) -> (s4, s5, s6, s7)
static uint32_t g_q2_regs[] = { 34, 35, 36, 37, LLDB_INVALID_REGNUM }; // (d4, d5) -> (s8, s9, s10, s11)
static uint32_t g_q3_regs[] = { 38, 39, 40, 41, LLDB_INVALID_REGNUM }; // (d6, d7) -> (s12, s13, s14, s15)
static uint32_t g_q4_regs[] = { 42, 43, 44, 45, LLDB_INVALID_REGNUM }; // (d8, d9) -> (s16, s17, s18, s19)
static uint32_t g_q5_regs[] = { 46, 47, 48, 49, LLDB_INVALID_REGNUM }; // (d10, d11) -> (s20, s21, s22, s23)
static uint32_t g_q6_regs[] = { 50, 51, 52, 53, LLDB_INVALID_REGNUM }; // (d12, d13) -> (s24, s25, s26, s27)
static uint32_t g_q7_regs[] = { 54, 55, 56, 57, LLDB_INVALID_REGNUM }; // (d14, d15) -> (s28, s29, s30, s31)
static uint32_t g_q8_regs[] = { 59, 60, LLDB_INVALID_REGNUM }; // (d16, d17)
static uint32_t g_q9_regs[] = { 61, 62, LLDB_INVALID_REGNUM }; // (d18, d19)
static uint32_t g_q10_regs[] = { 63, 64, LLDB_INVALID_REGNUM }; // (d20, d21)
static uint32_t g_q11_regs[] = { 65, 66, LLDB_INVALID_REGNUM }; // (d22, d23)
static uint32_t g_q12_regs[] = { 67, 68, LLDB_INVALID_REGNUM }; // (d24, d25)
static uint32_t g_q13_regs[] = { 69, 70, LLDB_INVALID_REGNUM }; // (d26, d27)
static uint32_t g_q14_regs[] = { 71, 72, LLDB_INVALID_REGNUM }; // (d28, d29)
static uint32_t g_q15_regs[] = { 73, 74, LLDB_INVALID_REGNUM }; // (d30, d31)
// This is our array of composite registers, with each element coming from the above register mappings.
static uint32_t *g_composites[] = {
g_d0_regs, g_d1_regs, g_d2_regs, g_d3_regs, g_d4_regs, g_d5_regs, g_d6_regs, g_d7_regs,
g_d8_regs, g_d9_regs, g_d10_regs, g_d11_regs, g_d12_regs, g_d13_regs, g_d14_regs, g_d15_regs,
g_q0_regs, g_q1_regs, g_q2_regs, g_q3_regs, g_q4_regs, g_q5_regs, g_q6_regs, g_q7_regs,
g_q8_regs, g_q9_regs, g_q10_regs, g_q11_regs, g_q12_regs, g_q13_regs, g_q14_regs, g_q15_regs
};
static RegisterInfo g_register_infos[] = {
// NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
// ====== ====== === === ============= ============ =================== =================== ====================== === ==== ========== ===============
{ "r0", "arg1", 4, 0, eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1,0, 0 }, NULL, NULL},
{ "r1", "arg2", 4, 0, eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2,1, 1 }, NULL, NULL},
{ "r2", "arg3", 4, 0, eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3,2, 2 }, NULL, NULL},
{ "r3", "arg4", 4, 0, eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4,3, 3 }, NULL, NULL},
{ "r4", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, 4, 4 }, NULL, NULL},
{ "r5", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, 5, 5 }, NULL, NULL},
{ "r6", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, 6, 6 }, NULL, NULL},
{ "r7", "fp", 4, 0, eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, 7, 7 }, NULL, NULL},
{ "r8", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, 8, 8 }, NULL, NULL},
{ "r9", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, 9, 9 }, NULL, NULL},
{ "r10", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, 10, 10 }, NULL, NULL},
{ "r11", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, 11, 11 }, NULL, NULL},
{ "r12", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, 12, 12 }, NULL, NULL},
{ "sp", "r13", 4, 0, eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, 13, 13 }, NULL, NULL},
{ "lr", "r14", 4, 0, eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, 14, 14 }, NULL, NULL},
{ "pc", "r15", 4, 0, eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, 15, 15 }, NULL, NULL},
{ "f0", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 16, 16 }, NULL, NULL},
{ "f1", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 17, 17 }, NULL, NULL},
{ "f2", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 18, 18 }, NULL, NULL},
{ "f3", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 19, 19 }, NULL, NULL},
{ "f4", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 20, 20 }, NULL, NULL},
{ "f5", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 21, 21 }, NULL, NULL},
{ "f6", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 22, 22 }, NULL, NULL},
{ "f7", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 23, 23 }, NULL, NULL},
{ "fps", NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 24, 24 }, NULL, NULL},
{ "cpsr","flags", 4, 0, eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_INVALID_REGNUM, 25, 25 }, NULL, NULL},
{ "s0", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, 26, 26 }, NULL, NULL},
{ "s1", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, 27, 27 }, NULL, NULL},
{ "s2", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, 28, 28 }, NULL, NULL},
{ "s3", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, 29, 29 }, NULL, NULL},
{ "s4", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, 30, 30 }, NULL, NULL},
{ "s5", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, 31, 31 }, NULL, NULL},
{ "s6", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, 32, 32 }, NULL, NULL},
{ "s7", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, 33, 33 }, NULL, NULL},
{ "s8", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, 34, 34 }, NULL, NULL},
{ "s9", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, 35, 35 }, NULL, NULL},
{ "s10", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, 36, 36 }, NULL, NULL},
{ "s11", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, 37, 37 }, NULL, NULL},
{ "s12", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, 38, 38 }, NULL, NULL},
{ "s13", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, 39, 39 }, NULL, NULL},
{ "s14", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, 40, 40 }, NULL, NULL},
{ "s15", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, 41, 41 }, NULL, NULL},
{ "s16", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, 42, 42 }, NULL, NULL},
{ "s17", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, 43, 43 }, NULL, NULL},
{ "s18", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, 44, 44 }, NULL, NULL},
{ "s19", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, 45, 45 }, NULL, NULL},
{ "s20", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, 46, 46 }, NULL, NULL},
{ "s21", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, 47, 47 }, NULL, NULL},
{ "s22", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, 48, 48 }, NULL, NULL},
{ "s23", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, 49, 49 }, NULL, NULL},
{ "s24", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, 50, 50 }, NULL, NULL},
{ "s25", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, 51, 51 }, NULL, NULL},
{ "s26", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, 52, 52 }, NULL, NULL},
{ "s27", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, 53, 53 }, NULL, NULL},
{ "s28", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, 54, 54 }, NULL, NULL},
{ "s29", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, 55, 55 }, NULL, NULL},
{ "s30", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, 56, 56 }, NULL, NULL},
{ "s31", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, 57, 57 }, NULL, NULL},
{ "fpscr",NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 58, 58 }, NULL, NULL},
{ "d16", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, 59, 59 }, NULL, NULL},
{ "d17", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, 60, 60 }, NULL, NULL},
{ "d18", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, 61, 61 }, NULL, NULL},
{ "d19", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, 62, 62 }, NULL, NULL},
{ "d20", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, 63, 63 }, NULL, NULL},
{ "d21", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, 64, 64 }, NULL, NULL},
{ "d22", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, 65, 65 }, NULL, NULL},
{ "d23", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, 66, 66 }, NULL, NULL},
{ "d24", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, 67, 67 }, NULL, NULL},
{ "d25", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, 68, 68 }, NULL, NULL},
{ "d26", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, 69, 69 }, NULL, NULL},
{ "d27", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, 70, 70 }, NULL, NULL},
{ "d28", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, 71, 71 }, NULL, NULL},
{ "d29", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, 72, 72 }, NULL, NULL},
{ "d30", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, 73, 73 }, NULL, NULL},
{ "d31", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, 74, 74 }, NULL, NULL},
{ "d0", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d0, LLDB_INVALID_REGNUM, 75, 75 }, g_d0_regs, NULL},
{ "d1", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d1, LLDB_INVALID_REGNUM, 76, 76 }, g_d1_regs, NULL},
{ "d2", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d2, LLDB_INVALID_REGNUM, 77, 77 }, g_d2_regs, NULL},
{ "d3", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d3, LLDB_INVALID_REGNUM, 78, 78 }, g_d3_regs, NULL},
{ "d4", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d4, LLDB_INVALID_REGNUM, 79, 79 }, g_d4_regs, NULL},
{ "d5", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d5, LLDB_INVALID_REGNUM, 80, 80 }, g_d5_regs, NULL},
{ "d6", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d6, LLDB_INVALID_REGNUM, 81, 81 }, g_d6_regs, NULL},
{ "d7", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d7, LLDB_INVALID_REGNUM, 82, 82 }, g_d7_regs, NULL},
{ "d8", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d8, LLDB_INVALID_REGNUM, 83, 83 }, g_d8_regs, NULL},
{ "d9", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d9, LLDB_INVALID_REGNUM, 84, 84 }, g_d9_regs, NULL},
{ "d10", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d10, LLDB_INVALID_REGNUM, 85, 85 }, g_d10_regs, NULL},
{ "d11", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d11, LLDB_INVALID_REGNUM, 86, 86 }, g_d11_regs, NULL},
{ "d12", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d12, LLDB_INVALID_REGNUM, 87, 87 }, g_d12_regs, NULL},
{ "d13", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d13, LLDB_INVALID_REGNUM, 88, 88 }, g_d13_regs, NULL},
{ "d14", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d14, LLDB_INVALID_REGNUM, 89, 89 }, g_d14_regs, NULL},
{ "d15", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d15, LLDB_INVALID_REGNUM, 90, 90 }, g_d15_regs, NULL},
{ "q0", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q0, LLDB_INVALID_REGNUM, 91, 91 }, g_q0_regs, NULL},
{ "q1", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q1, LLDB_INVALID_REGNUM, 92, 92 }, g_q1_regs, NULL},
{ "q2", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q2, LLDB_INVALID_REGNUM, 93, 93 }, g_q2_regs, NULL},
{ "q3", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q3, LLDB_INVALID_REGNUM, 94, 94 }, g_q3_regs, NULL},
{ "q4", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q4, LLDB_INVALID_REGNUM, 95, 95 }, g_q4_regs, NULL},
{ "q5", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q5, LLDB_INVALID_REGNUM, 96, 96 }, g_q5_regs, NULL},
{ "q6", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q6, LLDB_INVALID_REGNUM, 97, 97 }, g_q6_regs, NULL},
{ "q7", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q7, LLDB_INVALID_REGNUM, 98, 98 }, g_q7_regs, NULL},
{ "q8", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q8, LLDB_INVALID_REGNUM, 99, 99 }, g_q8_regs, NULL},
{ "q9", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q9, LLDB_INVALID_REGNUM, 100, 100 }, g_q9_regs, NULL},
{ "q10", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q10, LLDB_INVALID_REGNUM, 101, 101 }, g_q10_regs, NULL},
{ "q11", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q11, LLDB_INVALID_REGNUM, 102, 102 }, g_q11_regs, NULL},
{ "q12", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q12, LLDB_INVALID_REGNUM, 103, 103 }, g_q12_regs, NULL},
{ "q13", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q13, LLDB_INVALID_REGNUM, 104, 104 }, g_q13_regs, NULL},
{ "q14", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q14, LLDB_INVALID_REGNUM, 105, 105 }, g_q14_regs, NULL},
{ "q15", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q15, LLDB_INVALID_REGNUM, 106, 106 }, g_q15_regs, NULL}
};
static const uint32_t num_registers = llvm::array_lengthof(g_register_infos);
static ConstString gpr_reg_set ("General Purpose Registers");
static ConstString sfp_reg_set ("Software Floating Point Registers");
static ConstString vfp_reg_set ("Floating Point Registers");
uint32_t i;
if (from_scratch)
{
// Calculate the offsets of the registers
// Note that the layout of the "composite" registers (d0-d15 and q0-q15) which comes after the
// "primordial" registers is important. This enables us to calculate the offset of the composite
// register by using the offset of its first primordial register. For example, to calculate the
// offset of q0, use s0's offset.
if (g_register_infos[2].byte_offset == 0)
{
uint32_t byte_offset = 0;
for (i=0; i<num_registers; ++i)
{
// For primordial registers, increment the byte_offset by the byte_size to arrive at the
// byte_offset for the next register. Otherwise, we have a composite register whose
// offset can be calculated by consulting the offset of its first primordial register.
if (!g_register_infos[i].value_regs)
{
g_register_infos[i].byte_offset = byte_offset;
byte_offset += g_register_infos[i].byte_size;
}
else
{
const uint32_t first_primordial_reg = g_register_infos[i].value_regs[0];
g_register_infos[i].byte_offset = g_register_infos[first_primordial_reg].byte_offset;
}
}
}
for (i=0; i<num_registers; ++i)
{
ConstString name;
ConstString alt_name;
if (g_register_infos[i].name && g_register_infos[i].name[0])
name.SetCString(g_register_infos[i].name);
if (g_register_infos[i].alt_name && g_register_infos[i].alt_name[0])
alt_name.SetCString(g_register_infos[i].alt_name);
if (i <= 15 || i == 25)
AddRegister (g_register_infos[i], name, alt_name, gpr_reg_set);
else if (i <= 24)
AddRegister (g_register_infos[i], name, alt_name, sfp_reg_set);
else
AddRegister (g_register_infos[i], name, alt_name, vfp_reg_set);
}
}
else
{
// Add composite registers to our primordial registers, then.
const uint32_t num_composites = llvm::array_lengthof(g_composites);
const uint32_t num_primordials = GetNumRegisters();
RegisterInfo *g_comp_register_infos = g_register_infos + (num_registers - num_composites);
for (i=0; i<num_composites; ++i)
{
ConstString name;
ConstString alt_name;
const uint32_t first_primordial_reg = g_comp_register_infos[i].value_regs[0];
const char *reg_name = g_register_infos[first_primordial_reg].name;
if (reg_name && reg_name[0])
{
for (uint32_t j = 0; j < num_primordials; ++j)
{
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(j);
// Find a matching primordial register info entry.
if (reg_info && reg_info->name && ::strcasecmp(reg_info->name, reg_name) == 0)
{
// The name matches the existing primordial entry.
// Find and assign the offset, and then add this composite register entry.
g_comp_register_infos[i].byte_offset = reg_info->byte_offset;
name.SetCString(g_comp_register_infos[i].name);
AddRegister(g_comp_register_infos[i], name, alt_name, vfp_reg_set);
}
}
}
}
}
}