//===-- NativeRegisterContext.cpp -------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Core/Log.h" #include "lldb/Core/RegisterValue.h" #include "lldb/lldb-private-log.h" #include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Host/common/NativeThreadProtocol.h" using namespace lldb; using namespace lldb_private; NativeRegisterContext::NativeRegisterContext (NativeThreadProtocol &thread, uint32_t concrete_frame_idx) : m_thread (thread), m_concrete_frame_idx (concrete_frame_idx) { } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- NativeRegisterContext::~NativeRegisterContext() { } // FIXME revisit invalidation, process stop ids, etc. Right now we don't // support caching in NativeRegisterContext. We can do this later by // utilizing NativeProcessProtocol::GetStopID () and adding a stop id to // NativeRegisterContext. // void // NativeRegisterContext::InvalidateIfNeeded (bool force) // { // ProcessSP process_sp (m_thread.GetProcess()); // bool invalidate = force; // uint32_t process_stop_id = UINT32_MAX; // if (process_sp) // process_stop_id = process_sp->GetStopID(); // else // invalidate = true; // if (!invalidate) // invalidate = process_stop_id != GetStopID(); // if (invalidate) // { // InvalidateAllRegisters (); // SetStopID (process_stop_id); // } // } const RegisterInfo * NativeRegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx) { if (reg_name && reg_name[0]) { const uint32_t num_registers = GetRegisterCount(); for (uint32_t reg = start_idx; reg < num_registers; ++reg) { const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg); if ((reg_info->name != nullptr && ::strcasecmp (reg_info->name, reg_name) == 0) || (reg_info->alt_name != nullptr && ::strcasecmp (reg_info->alt_name, reg_name) == 0)) { return reg_info; } } } return nullptr; } const RegisterInfo * NativeRegisterContext::GetRegisterInfo (uint32_t kind, uint32_t num) { const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num); if (reg_num == LLDB_INVALID_REGNUM) return nullptr; return GetRegisterInfoAtIndex (reg_num); } const char * NativeRegisterContext::GetRegisterName (uint32_t reg) { const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg); if (reg_info) return reg_info->name; return nullptr; } const char* NativeRegisterContext::GetRegisterSetNameForRegisterAtIndex (uint32_t reg_index) const { const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); if (!reg_info) return nullptr; for (uint32_t set_index = 0; set_index < GetRegisterSetCount (); ++set_index) { const RegisterSet *const reg_set = GetRegisterSet (set_index); if (!reg_set) continue; for (uint32_t reg_num_index = 0; reg_num_index < reg_set->num_registers; ++reg_num_index) { const uint32_t reg_num = reg_set->registers[reg_num_index]; // FIXME double check we're checking the right register kind here. if (reg_info->kinds[RegisterKind::eRegisterKindLLDB] == reg_num) { // The given register is a member of this register set. Return the register set name. return reg_set->name; } } } // Didn't find it. return nullptr; } lldb::addr_t NativeRegisterContext::GetPC (lldb::addr_t fail_value) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); if (log) log->Printf ("NativeRegisterContext::%s using reg index %" PRIu32 " (default %" PRIu64 ")", __FUNCTION__, reg, fail_value); const uint64_t retval = ReadRegisterAsUnsigned (reg, fail_value); if (log) log->Printf ("NativeRegisterContext::%s " PRIu32 " retval %" PRIu64, __FUNCTION__, retval); return retval; } Error NativeRegisterContext::SetPC (lldb::addr_t pc) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); return WriteRegisterFromUnsigned (reg, pc); } lldb::addr_t NativeRegisterContext::GetSP (lldb::addr_t fail_value) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); return ReadRegisterAsUnsigned (reg, fail_value); } Error NativeRegisterContext::SetSP (lldb::addr_t sp) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); return WriteRegisterFromUnsigned (reg, sp); } lldb::addr_t NativeRegisterContext::GetFP (lldb::addr_t fail_value) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP); return ReadRegisterAsUnsigned (reg, fail_value); } Error NativeRegisterContext::SetFP (lldb::addr_t fp) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP); return WriteRegisterFromUnsigned (reg, fp); } lldb::addr_t NativeRegisterContext::GetReturnAddress (lldb::addr_t fail_value) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); return ReadRegisterAsUnsigned (reg, fail_value); } lldb::addr_t NativeRegisterContext::GetFlags (lldb::addr_t fail_value) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); return ReadRegisterAsUnsigned (reg, fail_value); } lldb::addr_t NativeRegisterContext::ReadRegisterAsUnsigned (uint32_t reg, lldb::addr_t fail_value) { if (reg != LLDB_INVALID_REGNUM) return ReadRegisterAsUnsigned (GetRegisterInfoAtIndex (reg), fail_value); return fail_value; } uint64_t NativeRegisterContext::ReadRegisterAsUnsigned (const RegisterInfo *reg_info, lldb::addr_t fail_value) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); if (reg_info) { RegisterValue value; Error error = ReadRegister (reg_info, value); if (error.Success ()) { if (log) log->Printf ("NativeRegisterContext::%s ReadRegister() succeeded, value %" PRIu64, __FUNCTION__, value.GetAsUInt64()); return value.GetAsUInt64(); } else { if (log) log->Printf ("NativeRegisterContext::%s ReadRegister() failed, error %s", __FUNCTION__, error.AsCString ()); } } else { if (log) log->Printf ("NativeRegisterContext::%s ReadRegister() null reg_info", __FUNCTION__); } return fail_value; } Error NativeRegisterContext::WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval) { if (reg == LLDB_INVALID_REGNUM) return Error ("NativeRegisterContext::%s (): reg is invalid", __FUNCTION__); return WriteRegisterFromUnsigned (GetRegisterInfoAtIndex (reg), uval); } Error NativeRegisterContext::WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval) { assert (reg_info); if (!reg_info) return Error ("reg_info is nullptr"); RegisterValue value; if (!value.SetUInt(uval, reg_info->byte_size)) return Error ("RegisterValue::SetUInt () failed"); return WriteRegister (reg_info, value); } lldb::tid_t NativeRegisterContext::GetThreadID() const { return m_thread.GetID(); } uint32_t NativeRegisterContext::NumSupportedHardwareBreakpoints () { return 0; } uint32_t NativeRegisterContext::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) { return LLDB_INVALID_INDEX32; } bool NativeRegisterContext::ClearHardwareBreakpoint (uint32_t hw_idx) { return false; } uint32_t NativeRegisterContext::NumSupportedHardwareWatchpoints () { return 0; } uint32_t NativeRegisterContext::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags) { return LLDB_INVALID_INDEX32; } bool NativeRegisterContext::ClearHardwareWatchpoint (uint32_t hw_index) { return false; } Error NativeRegisterContext::ClearAllHardwareWatchpoints () { return Error ("not implemented"); } bool NativeRegisterContext::HardwareSingleStep (bool enable) { return false; } Error NativeRegisterContext::ReadRegisterValueFromMemory ( const RegisterInfo *reg_info, lldb::addr_t src_addr, lldb::addr_t src_len, RegisterValue ®_value) { Error error; if (reg_info == nullptr) { error.SetErrorString ("invalid register info argument."); return error; } // Moving from addr into a register // // Case 1: src_len == dst_len // // |AABBCCDD| Address contents // |AABBCCDD| Register contents // // Case 2: src_len > dst_len // // Error! (The register should always be big enough to hold the data) // // Case 3: src_len < dst_len // // |AABB| Address contents // |AABB0000| Register contents [on little-endian hardware] // |0000AABB| Register contents [on big-endian hardware] if (src_len > RegisterValue::kMaxRegisterByteSize) { error.SetErrorString ("register too small to receive memory data"); return error; } const lldb::addr_t dst_len = reg_info->byte_size; if (src_len > dst_len) { error.SetErrorStringWithFormat("%" PRIu64 " bytes is too big to store in register %s (%" PRIu64 " bytes)", src_len, reg_info->name, dst_len); return error; } NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); if (!process_sp) { error.SetErrorString("invalid process"); return error; } uint8_t src[RegisterValue::kMaxRegisterByteSize]; // Read the memory lldb::addr_t bytes_read; error = process_sp->ReadMemory (src_addr, src, src_len, bytes_read); if (error.Fail ()) return error; // Make sure the memory read succeeded... if (bytes_read != src_len) { // This might happen if we read _some_ bytes but not all error.SetErrorStringWithFormat("read %" PRIu64 " of %" PRIu64 " bytes", bytes_read, src_len); return error; } // We now have a memory buffer that contains the part or all of the register // value. Set the register value using this memory data. // TODO: we might need to add a parameter to this function in case the byte // order of the memory data doesn't match the process. For now we are assuming // they are the same. lldb::ByteOrder byte_order; if (!process_sp->GetByteOrder (byte_order)) { error.SetErrorString ( "NativeProcessProtocol::GetByteOrder () failed"); return error; } reg_value.SetFromMemoryData ( reg_info, src, src_len, byte_order, error); return error; } Error NativeRegisterContext::WriteRegisterValueToMemory ( const RegisterInfo *reg_info, lldb::addr_t dst_addr, lldb::addr_t dst_len, const RegisterValue ®_value) { uint8_t dst[RegisterValue::kMaxRegisterByteSize]; Error error; NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); if (process_sp) { // TODO: we might need to add a parameter to this function in case the byte // order of the memory data doesn't match the process. For now we are assuming // they are the same. lldb::ByteOrder byte_order; if (!process_sp->GetByteOrder (byte_order)) return Error ("NativeProcessProtocol::GetByteOrder () failed"); const lldb::addr_t bytes_copied = reg_value.GetAsMemoryData ( reg_info, dst, dst_len, byte_order, error); if (error.Success()) { if (bytes_copied == 0) { error.SetErrorString("byte copy failed."); } else { lldb::addr_t bytes_written; error = process_sp->WriteMemory (dst_addr, dst, bytes_copied, bytes_written); if (error.Fail ()) return error; if (bytes_written != bytes_copied) { // This might happen if we read _some_ bytes but not all error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64 " bytes", bytes_written, bytes_copied); } } } } else error.SetErrorString("invalid process"); return error; } uint32_t NativeRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const { const uint32_t num_regs = GetRegisterCount(); assert (kind < kNumRegisterKinds); for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx); if (reg_info->kinds[kind] == num) return reg_idx; } return LLDB_INVALID_REGNUM; }