1068f8a7eSTamas Berghammer //===-- NativeRegisterContextLinux.cpp --------------------------*- C++ -*-===// 2068f8a7eSTamas Berghammer // 3068f8a7eSTamas Berghammer // The LLVM Compiler Infrastructure 4068f8a7eSTamas Berghammer // 5068f8a7eSTamas Berghammer // This file is distributed under the University of Illinois Open Source 6068f8a7eSTamas Berghammer // License. See LICENSE.TXT for details. 7068f8a7eSTamas Berghammer // 8068f8a7eSTamas Berghammer //===----------------------------------------------------------------------===// 9068f8a7eSTamas Berghammer 10068f8a7eSTamas Berghammer #include "NativeRegisterContextLinux.h" 11068f8a7eSTamas Berghammer 12068f8a7eSTamas Berghammer #include "lldb/Core/RegisterValue.h" 13068f8a7eSTamas Berghammer #include "lldb/Host/common/NativeProcessProtocol.h" 14068f8a7eSTamas Berghammer #include "lldb/Host/common/NativeThreadProtocol.h" 15068f8a7eSTamas Berghammer #include "lldb/Host/linux/Ptrace.h" 16068f8a7eSTamas Berghammer 17068f8a7eSTamas Berghammer #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 18068f8a7eSTamas Berghammer 19068f8a7eSTamas Berghammer using namespace lldb_private; 20068f8a7eSTamas Berghammer using namespace lldb_private::process_linux; 21068f8a7eSTamas Berghammer 22068f8a7eSTamas Berghammer NativeRegisterContextLinux::NativeRegisterContextLinux(NativeThreadProtocol &native_thread, 23068f8a7eSTamas Berghammer uint32_t concrete_frame_idx, 24068f8a7eSTamas Berghammer RegisterInfoInterface *reg_info_interface_p) : 25068f8a7eSTamas Berghammer NativeRegisterContextRegisterInfo(native_thread, concrete_frame_idx, reg_info_interface_p) 26068f8a7eSTamas Berghammer {} 27068f8a7eSTamas Berghammer 28068f8a7eSTamas Berghammer lldb::ByteOrder 29068f8a7eSTamas Berghammer NativeRegisterContextLinux::GetByteOrder() const 30068f8a7eSTamas Berghammer { 31068f8a7eSTamas Berghammer // Get the target process whose privileged thread was used for the register read. 32068f8a7eSTamas Berghammer lldb::ByteOrder byte_order = lldb::eByteOrderInvalid; 33068f8a7eSTamas Berghammer 34068f8a7eSTamas Berghammer NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 35068f8a7eSTamas Berghammer if (!process_sp) 36068f8a7eSTamas Berghammer return byte_order; 37068f8a7eSTamas Berghammer 38068f8a7eSTamas Berghammer if (!process_sp->GetByteOrder (byte_order)) 39068f8a7eSTamas Berghammer { 40068f8a7eSTamas Berghammer // FIXME log here 41068f8a7eSTamas Berghammer } 42068f8a7eSTamas Berghammer 43068f8a7eSTamas Berghammer return byte_order; 44068f8a7eSTamas Berghammer } 45068f8a7eSTamas Berghammer 46068f8a7eSTamas Berghammer Error 47068f8a7eSTamas Berghammer NativeRegisterContextLinux::ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value) 48068f8a7eSTamas Berghammer { 49068f8a7eSTamas Berghammer const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); 50068f8a7eSTamas Berghammer if (!reg_info) 51068f8a7eSTamas Berghammer return Error("register %" PRIu32 " not found", reg_index); 52068f8a7eSTamas Berghammer 53068f8a7eSTamas Berghammer NativeProcessProtocolSP process_sp(m_thread.GetProcess()); 54068f8a7eSTamas Berghammer if (!process_sp) 55068f8a7eSTamas Berghammer return Error("NativeProcessProtocol is NULL"); 56068f8a7eSTamas Berghammer 57068f8a7eSTamas Berghammer NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); 58c7512fdcSPavel Labath return process_p->DoOperation([&] { 59c7512fdcSPavel Labath return DoReadRegisterValue(reg_info->byte_offset, reg_info->name, reg_info->byte_size, reg_value); 60c7512fdcSPavel Labath }); 61068f8a7eSTamas Berghammer } 62068f8a7eSTamas Berghammer 63068f8a7eSTamas Berghammer Error 64068f8a7eSTamas Berghammer NativeRegisterContextLinux::WriteRegisterRaw(uint32_t reg_index, const RegisterValue ®_value) 65068f8a7eSTamas Berghammer { 66068f8a7eSTamas Berghammer uint32_t reg_to_write = reg_index; 67068f8a7eSTamas Berghammer RegisterValue value_to_write = reg_value; 68068f8a7eSTamas Berghammer 69068f8a7eSTamas Berghammer // Check if this is a subregister of a full register. 70068f8a7eSTamas Berghammer const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index); 71068f8a7eSTamas Berghammer if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) 72068f8a7eSTamas Berghammer { 73068f8a7eSTamas Berghammer Error error; 74068f8a7eSTamas Berghammer 75068f8a7eSTamas Berghammer RegisterValue full_value; 76068f8a7eSTamas Berghammer uint32_t full_reg = reg_info->invalidate_regs[0]; 77068f8a7eSTamas Berghammer const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); 78068f8a7eSTamas Berghammer 79068f8a7eSTamas Berghammer // Read the full register. 80068f8a7eSTamas Berghammer error = ReadRegister(full_reg_info, full_value); 81068f8a7eSTamas Berghammer if (error.Fail ()) 82068f8a7eSTamas Berghammer return error; 83068f8a7eSTamas Berghammer 84068f8a7eSTamas Berghammer lldb::ByteOrder byte_order = GetByteOrder(); 85068f8a7eSTamas Berghammer uint8_t dst[RegisterValue::kMaxRegisterByteSize]; 86068f8a7eSTamas Berghammer 87068f8a7eSTamas Berghammer // Get the bytes for the full register. 88068f8a7eSTamas Berghammer const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, 89068f8a7eSTamas Berghammer dst, 90068f8a7eSTamas Berghammer sizeof(dst), 91068f8a7eSTamas Berghammer byte_order, 92068f8a7eSTamas Berghammer error); 93068f8a7eSTamas Berghammer if (error.Success() && dest_size) 94068f8a7eSTamas Berghammer { 95068f8a7eSTamas Berghammer uint8_t src[RegisterValue::kMaxRegisterByteSize]; 96068f8a7eSTamas Berghammer 97068f8a7eSTamas Berghammer // Get the bytes for the source data. 98068f8a7eSTamas Berghammer const uint32_t src_size = reg_value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); 99068f8a7eSTamas Berghammer if (error.Success() && src_size && (src_size < dest_size)) 100068f8a7eSTamas Berghammer { 101068f8a7eSTamas Berghammer // Copy the src bytes to the destination. 102068f8a7eSTamas Berghammer memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); 103068f8a7eSTamas Berghammer // Set this full register as the value to write. 104068f8a7eSTamas Berghammer value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); 105068f8a7eSTamas Berghammer value_to_write.SetType(full_reg_info); 106068f8a7eSTamas Berghammer reg_to_write = full_reg; 107068f8a7eSTamas Berghammer } 108068f8a7eSTamas Berghammer } 109068f8a7eSTamas Berghammer } 110068f8a7eSTamas Berghammer 111068f8a7eSTamas Berghammer NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 112068f8a7eSTamas Berghammer if (!process_sp) 113068f8a7eSTamas Berghammer return Error("NativeProcessProtocol is NULL"); 114068f8a7eSTamas Berghammer 115068f8a7eSTamas Berghammer const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write); 116068f8a7eSTamas Berghammer assert (register_to_write_info_p && "register to write does not have valid RegisterInfo"); 117068f8a7eSTamas Berghammer if (!register_to_write_info_p) 118068f8a7eSTamas Berghammer return Error("NativeRegisterContextLinux::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write); 119068f8a7eSTamas Berghammer 120068f8a7eSTamas Berghammer NativeProcessLinux* process_p = static_cast<NativeProcessLinux*> (process_sp.get ()); 121c7512fdcSPavel Labath return process_p->DoOperation([&] { 122c7512fdcSPavel Labath return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value); 123c7512fdcSPavel Labath }); 124068f8a7eSTamas Berghammer } 125068f8a7eSTamas Berghammer 126068f8a7eSTamas Berghammer Error 127068f8a7eSTamas Berghammer NativeRegisterContextLinux::ReadGPR() 128068f8a7eSTamas Berghammer { 129068f8a7eSTamas Berghammer NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 130068f8a7eSTamas Berghammer if (!process_sp) 131068f8a7eSTamas Berghammer return Error("NativeProcessProtocol is NULL"); 132068f8a7eSTamas Berghammer 133068f8a7eSTamas Berghammer void* buf = GetGPRBuffer(); 134068f8a7eSTamas Berghammer if (!buf) 135068f8a7eSTamas Berghammer return Error("GPR buffer is NULL"); 136068f8a7eSTamas Berghammer size_t buf_size = GetGPRSize(); 137068f8a7eSTamas Berghammer 138068f8a7eSTamas Berghammer NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); 139c7512fdcSPavel Labath return process_p->DoOperation([&] { return DoReadGPR(buf, buf_size); }); 140068f8a7eSTamas Berghammer } 141068f8a7eSTamas Berghammer 142068f8a7eSTamas Berghammer Error 143068f8a7eSTamas Berghammer NativeRegisterContextLinux::WriteGPR() 144068f8a7eSTamas Berghammer { 145068f8a7eSTamas Berghammer NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 146068f8a7eSTamas Berghammer if (!process_sp) 147068f8a7eSTamas Berghammer return Error("NativeProcessProtocol is NULL"); 148068f8a7eSTamas Berghammer 149068f8a7eSTamas Berghammer void* buf = GetGPRBuffer(); 150068f8a7eSTamas Berghammer if (!buf) 151068f8a7eSTamas Berghammer return Error("GPR buffer is NULL"); 152068f8a7eSTamas Berghammer size_t buf_size = GetGPRSize(); 153068f8a7eSTamas Berghammer 154068f8a7eSTamas Berghammer NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); 155c7512fdcSPavel Labath return process_p->DoOperation([&] { return DoWriteGPR(buf, buf_size); }); 156068f8a7eSTamas Berghammer } 157068f8a7eSTamas Berghammer 158068f8a7eSTamas Berghammer Error 159068f8a7eSTamas Berghammer NativeRegisterContextLinux::ReadFPR() 160068f8a7eSTamas Berghammer { 161068f8a7eSTamas Berghammer NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 162068f8a7eSTamas Berghammer if (!process_sp) 163068f8a7eSTamas Berghammer return Error("NativeProcessProtocol is NULL"); 164068f8a7eSTamas Berghammer 165068f8a7eSTamas Berghammer void* buf = GetFPRBuffer(); 166068f8a7eSTamas Berghammer if (!buf) 167068f8a7eSTamas Berghammer return Error("GPR buffer is NULL"); 168068f8a7eSTamas Berghammer size_t buf_size = GetFPRSize(); 169068f8a7eSTamas Berghammer 170068f8a7eSTamas Berghammer NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); 171c7512fdcSPavel Labath return process_p->DoOperation([&] { return DoReadFPR(buf, buf_size); }); 172068f8a7eSTamas Berghammer } 173068f8a7eSTamas Berghammer 174068f8a7eSTamas Berghammer Error 175068f8a7eSTamas Berghammer NativeRegisterContextLinux::WriteFPR() 176068f8a7eSTamas Berghammer { 177068f8a7eSTamas Berghammer NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 178068f8a7eSTamas Berghammer if (!process_sp) 179068f8a7eSTamas Berghammer return Error("NativeProcessProtocol is NULL"); 180068f8a7eSTamas Berghammer 181068f8a7eSTamas Berghammer void* buf = GetFPRBuffer(); 182068f8a7eSTamas Berghammer if (!buf) 183068f8a7eSTamas Berghammer return Error("GPR buffer is NULL"); 184068f8a7eSTamas Berghammer size_t buf_size = GetFPRSize(); 185068f8a7eSTamas Berghammer 186068f8a7eSTamas Berghammer NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); 187c7512fdcSPavel Labath return process_p->DoOperation([&] { return DoWriteFPR(buf, buf_size); }); 188068f8a7eSTamas Berghammer } 189068f8a7eSTamas Berghammer 190068f8a7eSTamas Berghammer Error 191068f8a7eSTamas Berghammer NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size, unsigned int regset) 192068f8a7eSTamas Berghammer { 193068f8a7eSTamas Berghammer NativeProcessProtocolSP process_sp (m_thread.GetProcess()); 194068f8a7eSTamas Berghammer if (!process_sp) 195068f8a7eSTamas Berghammer return Error("NativeProcessProtocol is NULL"); 196068f8a7eSTamas Berghammer NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); 197068f8a7eSTamas Berghammer 198c7512fdcSPavel Labath return process_p->DoOperation([&] { 199*4a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), 200*4a9babb2SPavel Labath static_cast<void *>(®set), buf, buf_size); 201c7512fdcSPavel Labath }); 202068f8a7eSTamas Berghammer } 203068f8a7eSTamas Berghammer 204068f8a7eSTamas Berghammer Error 205068f8a7eSTamas Berghammer NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size, unsigned int regset) 206068f8a7eSTamas Berghammer { 207068f8a7eSTamas Berghammer NativeProcessProtocolSP process_sp (m_thread.GetProcess()); 208068f8a7eSTamas Berghammer if (!process_sp) 209068f8a7eSTamas Berghammer return Error("NativeProcessProtocol is NULL"); 210068f8a7eSTamas Berghammer NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get()); 211068f8a7eSTamas Berghammer 212c7512fdcSPavel Labath return process_p->DoOperation([&] { 213*4a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), 214*4a9babb2SPavel Labath static_cast<void *>(®set), buf, buf_size); 215c7512fdcSPavel Labath }); 216068f8a7eSTamas Berghammer } 217068f8a7eSTamas Berghammer 218c7512fdcSPavel Labath Error 219c7512fdcSPavel Labath NativeRegisterContextLinux::DoReadRegisterValue(uint32_t offset, 220068f8a7eSTamas Berghammer const char* reg_name, 221068f8a7eSTamas Berghammer uint32_t size, 222068f8a7eSTamas Berghammer RegisterValue &value) 223068f8a7eSTamas Berghammer { 224c7512fdcSPavel Labath Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS)); 225c7512fdcSPavel Labath 226*4a9babb2SPavel Labath long data; 227*4a9babb2SPavel Labath Error error = NativeProcessLinux::PtraceWrapper( 228*4a9babb2SPavel Labath PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), nullptr, 0, &data); 229c7512fdcSPavel Labath 230c7512fdcSPavel Labath if (error.Success()) 231*4a9babb2SPavel Labath value = static_cast<lldb::addr_t>(data); 232c7512fdcSPavel Labath 233c7512fdcSPavel Labath if (log) 234c7512fdcSPavel Labath log->Printf ("NativeRegisterContextLinux::%s() reg %s: 0x%" PRIx64, __FUNCTION__, reg_name, data); 235c7512fdcSPavel Labath 236c7512fdcSPavel Labath return error; 237068f8a7eSTamas Berghammer } 238068f8a7eSTamas Berghammer 239c7512fdcSPavel Labath Error 240c7512fdcSPavel Labath NativeRegisterContextLinux::DoWriteRegisterValue(uint32_t offset, 241068f8a7eSTamas Berghammer const char* reg_name, 242068f8a7eSTamas Berghammer const RegisterValue &value) 243068f8a7eSTamas Berghammer { 244c7512fdcSPavel Labath Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS)); 245c7512fdcSPavel Labath 246c7512fdcSPavel Labath void* buf = reinterpret_cast<void *>(value.GetAsUInt64()); 247c7512fdcSPavel Labath 248c7512fdcSPavel Labath if (log) 249c7512fdcSPavel Labath log->Printf ("NativeRegisterContextLinux::%s() reg %s: %p", __FUNCTION__, reg_name, buf); 250c7512fdcSPavel Labath 251*4a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper( 252*4a9babb2SPavel Labath PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), buf); 253068f8a7eSTamas Berghammer } 254068f8a7eSTamas Berghammer 255c7512fdcSPavel Labath Error 256c7512fdcSPavel Labath NativeRegisterContextLinux::DoReadGPR(void *buf, size_t buf_size) 257068f8a7eSTamas Berghammer { 258*4a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), nullptr, buf, buf_size); 259068f8a7eSTamas Berghammer } 260068f8a7eSTamas Berghammer 261c7512fdcSPavel Labath Error 262c7512fdcSPavel Labath NativeRegisterContextLinux::DoWriteGPR(void *buf, size_t buf_size) 263068f8a7eSTamas Berghammer { 264*4a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(), nullptr, buf, buf_size); 265068f8a7eSTamas Berghammer } 266068f8a7eSTamas Berghammer 267c7512fdcSPavel Labath Error 268c7512fdcSPavel Labath NativeRegisterContextLinux::DoReadFPR(void *buf, size_t buf_size) 269068f8a7eSTamas Berghammer { 270*4a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), nullptr, buf, buf_size); 271068f8a7eSTamas Berghammer } 272068f8a7eSTamas Berghammer 273c7512fdcSPavel Labath Error 274c7512fdcSPavel Labath NativeRegisterContextLinux::DoWriteFPR(void *buf, size_t buf_size) 275068f8a7eSTamas Berghammer { 276*4a9babb2SPavel Labath return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), nullptr, buf, buf_size); 277068f8a7eSTamas Berghammer } 278