//===-- LibUnwindRegisterContext.cpp ----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "LibUnwindRegisterContext.h" // C Includes // C++ Includes // Other libraries and framework includes #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Target/Thread.h" // Project includes using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- // LibUnwindRegisterContext constructor //---------------------------------------------------------------------- LibUnwindRegisterContext::LibUnwindRegisterContext ( Thread &thread, StackFrame *frame, const lldb_private::unw_cursor_t& unwind_cursor ) : RegisterContext (thread, frame), m_unwind_cursor (unwind_cursor), m_unwind_cursor_is_valid (true) { } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- LibUnwindRegisterContext::~LibUnwindRegisterContext() { } void LibUnwindRegisterContext::Invalidate () { m_unwind_cursor_is_valid = false; } size_t LibUnwindRegisterContext::GetRegisterCount () { return m_thread.GetRegisterContext()->GetRegisterCount(); } const lldb::RegisterInfo * LibUnwindRegisterContext::GetRegisterInfoAtIndex (uint32_t reg) { return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg); } size_t LibUnwindRegisterContext::GetRegisterSetCount () { return m_thread.GetRegisterContext()->GetRegisterSetCount(); } const lldb::RegisterSet * LibUnwindRegisterContext::GetRegisterSet (uint32_t reg_set) { return m_thread.GetRegisterContext()->GetRegisterSet (reg_set); } bool LibUnwindRegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value) { if (m_unwind_cursor_is_valid == false) return false; // Read the register unw_word_t reg_value; if (unw_get_reg (&m_unwind_cursor, reg, ®_value) != UNW_ESUCCESS) return false; const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg); switch (reg_info->encoding) { case eEncodingUint: switch (reg_info->byte_size) { case 1: case 2: case 4: value = (uint32_t)reg_value; return true; case 8: value = (uint64_t)reg_value; return true; } break; case eEncodingSint: switch (reg_info->byte_size) { case 1: case 2: case 4: value = (int32_t)reg_value; return true; case 8: value = (int64_t)reg_value; return true; } break; case eEncodingIEEE754: if (reg_info->byte_size > sizeof(unw_word_t)) return false; switch (reg_info->byte_size) { case sizeof (float): if (sizeof (float) == sizeof(uint32_t)) { value = (uint32_t)reg_value; return true; } else if (sizeof (float) == sizeof(uint64_t)) { value = (uint64_t)reg_value; return true; } break; case sizeof (double): if (sizeof (double) == sizeof(uint32_t)) { value = (uint32_t)reg_value; return true; } else if (sizeof (double) == sizeof(uint64_t)) { value = (uint64_t)reg_value; return true; } break; case sizeof (long double): if (sizeof (long double) == sizeof(uint32_t)) { value = (uint32_t)reg_value; return true; } else if (sizeof (long double) == sizeof(uint64_t)) { value = (uint64_t)reg_value; return true; } break; } break; default: break; } return false; } bool LibUnwindRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data) { Scalar reg_value; if (ReadRegisterValue (reg, reg_value)) { if (reg_value.GetData(data)) { // "reg_value" is local and now "data" points to the data within // "reg_value", so we must make a copy that will live within "data" DataBufferSP data_sp (new DataBufferHeap (data.GetDataStart(), data.GetByteSize())); data.SetData (data_sp, 0, data.GetByteSize()); return true; } } return false; } bool LibUnwindRegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value) { const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg); if (reg_info == NULL) return false; unw_word_t reg_value = 0; switch (value.GetType()) { case Scalar::e_void: return false; case Scalar::e_sint: reg_value = value.SInt(); break; case Scalar::e_uint: reg_value = value.UInt(); break; case Scalar::e_slong: reg_value = value.SLong(); break; case Scalar::e_ulong: reg_value = value.ULong(); break; case Scalar::e_slonglong: reg_value = value.SLongLong(); break; case Scalar::e_ulonglong: reg_value = value.ULongLong(); break; case Scalar::e_float: if (sizeof (float) == sizeof (unsigned int)) reg_value = value.UInt(); else if (sizeof (float) == sizeof (unsigned long)) reg_value = value.ULong(); else if (sizeof (float) == sizeof (unsigned long long)) reg_value = value.ULongLong(); else return false; break; case Scalar::e_double: if (sizeof (double) == sizeof (unsigned int)) reg_value = value.UInt(); else if (sizeof (double) == sizeof (unsigned long)) reg_value = value.ULong(); else if (sizeof (double) == sizeof (unsigned long long)) reg_value = value.ULongLong(); else return false; break; case Scalar::e_long_double: if (sizeof (long double) == sizeof (unsigned int)) reg_value = value.UInt(); else if (sizeof (long double) == sizeof (unsigned long)) reg_value = value.ULong(); else if (sizeof (long double) == sizeof (unsigned long long)) reg_value = value.ULongLong(); else return false; break; } return unw_set_reg (&m_unwind_cursor, reg, reg_value) == UNW_ESUCCESS; } bool LibUnwindRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset) { const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg); if (reg_info == NULL) return false; if (reg_info->byte_size > sizeof (unw_word_t)) return false; Scalar value; uint32_t offset = data_offset; switch (reg_info->encoding) { case eEncodingUint: if (reg_info->byte_size <= 4) value = data.GetMaxU32 (&offset, reg_info->byte_size); else if (reg_info->byte_size <= 8) value = data.GetMaxU64 (&offset, reg_info->byte_size); else return false; break; case eEncodingSint: if (reg_info->byte_size <= 4) value = (int32_t)data.GetMaxU32 (&offset, reg_info->byte_size); else if (reg_info->byte_size <= 8) value = data.GetMaxS64 (&offset, reg_info->byte_size); else return false; break; case eEncodingIEEE754: switch (reg_info->byte_size) { case sizeof (float): value = data.GetFloat (&offset); break; case sizeof (double): value = data.GetDouble (&offset); break; case sizeof (long double): value = data.GetLongDouble (&offset); break; default: return false; } default: return false; } return WriteRegisterValue (reg, value); } bool LibUnwindRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) { // libunwind frames can't handle this it doesn't always have all register // values. This call should only be called on frame zero anyway so there // shouldn't be any problem return false; } bool LibUnwindRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) { // Since this class doesn't respond to "ReadAllRegisterValues()", it must // not have been the one that saved all the register values. So we just let // the thread's register context (the register context for frame zero) do // the writing. return m_thread.GetRegisterContext()->WriteAllRegisterValues(data_sp); } uint32_t LibUnwindRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) { return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num); }