diff options
Diffstat (limited to 'source/Plugins/Process')
66 files changed, 6945 insertions, 3846 deletions
diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp index ea26d972b860..952ec95f5873 100644 --- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp @@ -122,11 +122,47 @@ ProcessFreeBSD::Terminate() { } +Error +ProcessFreeBSD::DoDetach(bool keep_stopped) +{ + Error error; + if (keep_stopped) + { + error.SetErrorString("Detaching with keep_stopped true is not currently supported on FreeBSD."); + return error; + } + + error = m_monitor->Detach(GetID()); + + if (error.Success()) + SetPrivateState(eStateDetached); + + return error; +} + bool ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) { - // XXX haxx - new_thread_list = old_thread_list; - - return false; + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf ("ProcessFreeBSD::%s() (pid = %" PRIu64 ")", __FUNCTION__, GetID()); + + bool has_updated = false; + const lldb::pid_t pid = GetID(); + // Update the process thread list with this new thread. + // FIXME: We should be using tid, not pid. + assert(m_monitor); + ThreadSP thread_sp (old_thread_list.FindThreadByID (pid, false)); + if (!thread_sp) { + ProcessSP me = this->shared_from_this(); + thread_sp.reset(new POSIXThread(*me, pid)); + has_updated = true; + } + + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf ("ProcessFreeBSD::%s() updated tid = %" PRIu64, __FUNCTION__, pid); + + new_thread_list.AddThread(thread_sp); + + return has_updated; // the list has been updated } diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h index 5f79b74cad30..fb549745b80c 100644 --- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h +++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h @@ -54,6 +54,9 @@ public: ProcessFreeBSD(lldb_private::Target& target, lldb_private::Listener &listener); + virtual lldb_private::Error + DoDetach(bool keep_stopped); + virtual bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list); diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index 9fd51d2d640a..3833fa6baf85 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -70,12 +70,12 @@ PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); if (log) { - log->Printf("ptrace(%s, %lu, %p, %x) called from file %s line %d", + log->Printf("ptrace(%s, %" PRIu64 ", %p, %x) called from file %s line %d", reqName, pid, addr, data, file, line); if (req == PT_IO) { struct ptrace_io_desc *pi = (struct ptrace_io_desc *) addr; - log->Printf("PT_IO: op=%s offs=%zx size=%ld", + log->Printf("PT_IO: op=%s offs=%zx size=%zu", Get_PT_IO_OP(pi->piod_op), (size_t)pi->piod_offs, pi->piod_len); } } @@ -704,23 +704,16 @@ ProcessMonitor::ProcessMonitor(ProcessPOSIX *process, m_operation_thread(LLDB_INVALID_HOST_THREAD), m_monitor_thread(LLDB_INVALID_HOST_THREAD), m_pid(LLDB_INVALID_PROCESS_ID), - m_server_mutex(Mutex::eMutexTypeRecursive), m_terminal_fd(-1), - m_client_fd(-1), - m_server_fd(-1) + m_operation(0) { - std::unique_ptr<LaunchArgs> args; - - args.reset(new LaunchArgs(this, module, argv, envp, - stdin_path, stdout_path, stderr_path, working_dir)); + std::unique_ptr<LaunchArgs> args(new LaunchArgs(this, module, argv, envp, + stdin_path, stdout_path, stderr_path, + working_dir)); - // Server/client descriptors. - if (!EnableIPC()) - { - error.SetErrorToGenericError(); - error.SetErrorString("Monitor failed to initialize."); - } + sem_init(&m_operation_pending, 0, 0); + sem_init(&m_operation_done, 0, 0); StartLaunchOpThread(args.get(), error); if (!error.Success()) @@ -765,21 +758,14 @@ ProcessMonitor::ProcessMonitor(ProcessPOSIX *process, m_operation_thread(LLDB_INVALID_HOST_THREAD), m_monitor_thread(LLDB_INVALID_HOST_THREAD), m_pid(pid), - m_server_mutex(Mutex::eMutexTypeRecursive), m_terminal_fd(-1), - m_client_fd(-1), - m_server_fd(-1) + m_operation(0) { - std::unique_ptr<AttachArgs> args; + sem_init(&m_operation_pending, 0, 0); + sem_init(&m_operation_done, 0, 0); - args.reset(new AttachArgs(this, pid)); - // Server/client descriptors. - if (!EnableIPC()) - { - error.SetErrorToGenericError(); - error.SetErrorString("Monitor failed to initialize."); - } + std::unique_ptr<AttachArgs> args(new AttachArgs(this, pid)); StartAttachOpThread(args.get(), error); if (!error.Success()) @@ -855,7 +841,6 @@ ProcessMonitor::Launch(LaunchArgs *args) { ProcessMonitor *monitor = args->m_monitor; ProcessFreeBSD &process = monitor->GetProcess(); - lldb::ProcessSP processSP = process.shared_from_this(); const char **argv = args->m_argv; const char **envp = args->m_envp; const char *stdin_path = args->m_stdin_path; @@ -868,21 +853,10 @@ ProcessMonitor::Launch(LaunchArgs *args) char err_str[err_len]; lldb::pid_t pid; - lldb::ThreadSP inferior; - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - // Propagate the environment if one is not supplied. if (envp == NULL || envp[0] == NULL) envp = const_cast<const char **>(environ); - // Pseudo terminal setup. - if (!terminal.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, err_str, err_len)) - { - args->m_error.SetErrorToGenericError(); - args->m_error.SetErrorString("Could not open controlling TTY."); - goto FINISH; - } - if ((pid = terminal.Fork(err_str, err_len)) == -1) { args->m_error.SetErrorToGenericError(); @@ -1002,32 +976,12 @@ ProcessMonitor::Launch(LaunchArgs *args) if (!EnsureFDFlags(monitor->m_terminal_fd, O_NONBLOCK, args->m_error)) goto FINISH; - // Update the process thread list with this new thread. - inferior.reset(process.CreateNewPOSIXThread(*processSP, pid)); - if (log) - log->Printf ("ProcessMonitor::%s() adding pid = %" PRIu64, __FUNCTION__, pid); - process.GetThreadList().AddThread(inferior); - - // Let our process instance know the thread has stopped. - process.SendMessage(ProcessMessage::Trace(pid)); + process.SendMessage(ProcessMessage::Attach(pid)); FINISH: return args->m_error.Success(); } -bool -ProcessMonitor::EnableIPC() -{ - int fd[2]; - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) - return false; - - m_client_fd = fd[0]; - m_server_fd = fd[1]; - return true; -} - void ProcessMonitor::StartAttachOpThread(AttachArgs *args, lldb_private::Error &error) { @@ -1059,9 +1013,6 @@ ProcessMonitor::Attach(AttachArgs *args) ProcessMonitor *monitor = args->m_monitor; ProcessFreeBSD &process = monitor->GetProcess(); - lldb::ProcessSP processSP = process.shared_from_this(); - ThreadList &tl = process.GetThreadList(); - lldb::ThreadSP inferior; if (pid <= 1) { @@ -1084,14 +1035,9 @@ ProcessMonitor::Attach(AttachArgs *args) goto FINISH; } - // Update the process thread list with the attached thread. - inferior.reset(process.CreateNewPOSIXThread(*processSP, pid)); - tl.AddThread(inferior); + process.SendMessage(ProcessMessage::Attach(pid)); - // Let our process instance know the thread has stopped. - process.SendMessage(ProcessMessage::Trace(pid)); - - FINISH: +FINISH: return args->m_error.Success(); } @@ -1393,78 +1339,37 @@ void ProcessMonitor::ServeOperation(OperationArgs *args) { int status; - pollfd fdset; ProcessMonitor *monitor = args->m_monitor; - fdset.fd = monitor->m_server_fd; - fdset.events = POLLIN | POLLPRI; - fdset.revents = 0; - // We are finised with the arguments and are ready to go. Sync with the // parent thread and start serving operations on the inferior. sem_post(&args->m_semaphore); for (;;) { - if ((status = poll(&fdset, 1, -1)) < 0) - { - switch (errno) - { - default: - assert(false && "Unexpected poll() failure!"); - continue; + // wait for next pending operation + sem_wait(&monitor->m_operation_pending); - case EINTR: continue; // Just poll again. - case EBADF: return; // Connection terminated. - } - } - - assert(status == 1 && "Too many descriptors!"); + monitor->m_operation->Execute(monitor); - if (fdset.revents & POLLIN) - { - Operation *op = NULL; - - READ_AGAIN: - if ((status = read(fdset.fd, &op, sizeof(op))) < 0) - { - // There is only one acceptable failure. - assert(errno == EINTR); - goto READ_AGAIN; - } - if (status == 0) - continue; // Poll again. The connection probably terminated. - assert(status == sizeof(op)); - op->Execute(monitor); - write(fdset.fd, &op, sizeof(op)); - } + // notify calling thread that operation is complete + sem_post(&monitor->m_operation_done); } } void ProcessMonitor::DoOperation(Operation *op) { - int status; - Operation *ack = NULL; - Mutex::Locker lock(m_server_mutex); + Mutex::Locker lock(m_operation_mutex); - // FIXME: Do proper error checking here. - write(m_client_fd, &op, sizeof(op)); + m_operation = op; -READ_AGAIN: - if ((status = read(m_client_fd, &ack, sizeof(ack))) < 0) - { - // If interrupted by a signal handler try again. Otherwise the monitor - // thread probably died and we have a stale file descriptor -- abort the - // operation. - if (errno == EINTR) - goto READ_AGAIN; - return; - } + // notify operation thread that an operation is ready to be processed + sem_post(&m_operation_pending); - assert(status == sizeof(ack)); - assert(ack == op && "Invalid monitor thread response!"); + // wait for operation to complete + sem_wait(&m_operation_done); } size_t @@ -1556,6 +1461,12 @@ ProcessMonitor::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, un } bool +ProcessMonitor::ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value) +{ + return false; +} + +bool ProcessMonitor::Resume(lldb::tid_t tid, uint32_t signo) { bool result; @@ -1648,9 +1559,36 @@ ProcessMonitor::StopMonitor() { StopMonitoringChildProcess(); StopOpThread(); - CloseFD(m_terminal_fd); - CloseFD(m_client_fd); - CloseFD(m_server_fd); + sem_destroy(&m_operation_pending); + sem_destroy(&m_operation_done); + + // Note: ProcessPOSIX passes the m_terminal_fd file descriptor to + // Process::SetSTDIOFileDescriptor, which in turn transfers ownership of + // the descriptor to a ConnectionFileDescriptor object. Consequently + // even though still has the file descriptor, we shouldn't close it here. +} + +// FIXME: On Linux, when a new thread is created, we receive to notifications, +// (1) a SIGTRAP|PTRACE_EVENT_CLONE from the main process thread with the +// child thread id as additional information, and (2) a SIGSTOP|SI_USER from +// the new child thread indicating that it has is stopped because we attached. +// We have no guarantee of the order in which these arrive, but we need both +// before we are ready to proceed. We currently keep a list of threads which +// have sent the initial SIGSTOP|SI_USER event. Then when we receive the +// SIGTRAP|PTRACE_EVENT_CLONE notification, if the initial stop has not occurred +// we call ProcessMonitor::WaitForInitialTIDStop() to wait for it. +// +// Right now, the above logic is in ProcessPOSIX, so we need a definition of +// this function in the FreeBSD ProcessMonitor implementation even if it isn't +// logically needed. +// +// We really should figure out what actually happens on FreeBSD and move the +// Linux-specific logic out of ProcessPOSIX as needed. + +bool +ProcessMonitor::WaitForInitialTIDStop(lldb::tid_t tid) +{ + return true; } void @@ -1665,13 +1603,3 @@ ProcessMonitor::StopOpThread() Host::ThreadJoin(m_operation_thread, &result, NULL); m_operation_thread = LLDB_INVALID_HOST_THREAD; } - -void -ProcessMonitor::CloseFD(int &fd) -{ - if (fd != -1) - { - close(fd); - fd = -1; - } -} diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h index ce66c03f2f8c..4a9b48370444 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h @@ -160,6 +160,10 @@ public: bool WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset); + /// Reads the value of the thread-specific pointer for a given thread ID. + bool + ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value); + /// Writes a ptrace_lwpinfo structure corresponding to the given thread ID /// to the memory region pointed to by @p lwpinfo. bool @@ -193,6 +197,10 @@ public: void StopMonitor(); + // Waits for the initial stop message from a new thread. + bool + WaitForInitialTIDStop(lldb::tid_t tid); + private: ProcessFreeBSD *m_process; @@ -200,12 +208,17 @@ private: lldb::thread_t m_monitor_thread; lldb::pid_t m_pid; - - lldb_private::Mutex m_server_mutex; int m_terminal_fd; - int m_client_fd; - int m_server_fd; + // current operation which must be executed on the privileged thread + Operation *m_operation; + lldb_private::Mutex m_operation_mutex; + + // semaphores notified when Operation is ready to be processed and when + // the operation is complete. + sem_t m_operation_pending; + sem_t m_operation_done; + struct OperationArgs { OperationArgs(ProcessMonitor *monitor); @@ -252,9 +265,6 @@ private: static bool Launch(LaunchArgs *args); - bool - EnableIPC(); - struct AttachArgs : OperationArgs { AttachArgs(ProcessMonitor *monitor, @@ -314,9 +324,6 @@ private: /// Stops the operation thread used to attach/launch a process. void StopOpThread(); - - void - CloseFD(int &fd); }; #endif // #ifndef liblldb_ProcessMonitor_H_ diff --git a/source/Plugins/Process/POSIX/POSIXThread.cpp b/source/Plugins/Process/POSIX/POSIXThread.cpp index 93c296679df2..16399748c544 100644 --- a/source/Plugins/Process/POSIX/POSIXThread.cpp +++ b/source/Plugins/Process/POSIX/POSIXThread.cpp @@ -29,10 +29,12 @@ #include "ProcessPOSIX.h" #include "ProcessPOSIXLog.h" #include "ProcessMonitor.h" -#include "RegisterContext_i386.h" -#include "RegisterContext_x86_64.h" -#include "RegisterContextPOSIX.h" +#include "RegisterContextPOSIXProcessMonitor_mips64.h" +#include "RegisterContextPOSIXProcessMonitor_x86.h" +#include "RegisterContextLinux_i386.h" #include "RegisterContextLinux_x86_64.h" +#include "RegisterContextFreeBSD_i386.h" +#include "RegisterContextFreeBSD_mips64.h" #include "RegisterContextFreeBSD_x86_64.h" #include "UnwindLLDB.h" @@ -46,7 +48,8 @@ POSIXThread::POSIXThread(Process &process, lldb::tid_t tid) m_frame_ap (), m_breakpoint (), m_thread_name_valid (false), - m_thread_name () + m_thread_name (), + m_posix_thread(NULL) { Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) @@ -138,34 +141,66 @@ POSIXThread::GetRegisterContext() { if (!m_reg_context_sp) { - ArchSpec arch = Host::GetArchitecture(); + m_posix_thread = NULL; - switch (arch.GetCore()) + RegisterInfoInterface *reg_interface = NULL; + const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture(); + + switch (target_arch.GetCore()) { - default: - assert(false && "CPU type not supported!"); - break; - - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: - m_reg_context_sp.reset(new RegisterContext_i386(*this, 0)); - break; - - case ArchSpec::eCore_x86_64_x86_64: - switch (arch.GetTriple().getOS()) + case ArchSpec::eCore_mips64: { - case llvm::Triple::FreeBSD: - m_reg_context_sp.reset(new RegisterContextFreeBSD_x86_64(*this, 0)); - break; - case llvm::Triple::Linux: - m_reg_context_sp.reset(new RegisterContextLinux_x86_64(*this, 0)); - break; - default: - assert(false && "OS not supported"); - break; + RegisterInfoInterface *reg_interface = NULL; + + switch (target_arch.GetTriple().getOS()) + { + case llvm::Triple::FreeBSD: + reg_interface = new RegisterContextFreeBSD_mips64(target_arch); + break; + default: + assert(false && "OS not supported"); + break; + } + + if (reg_interface) + { + RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + } + break; } - break; + + case ArchSpec::eCore_x86_32_i386: + case ArchSpec::eCore_x86_32_i486: + case ArchSpec::eCore_x86_32_i486sx: + case ArchSpec::eCore_x86_64_x86_64: + { + switch (target_arch.GetTriple().getOS()) + { + case llvm::Triple::FreeBSD: + reg_interface = new RegisterContextFreeBSD_x86_64(target_arch); + break; + case llvm::Triple::Linux: + reg_interface = new RegisterContextLinux_x86_64(target_arch); + break; + default: + assert(false && "OS not supported"); + break; + } + + if (reg_interface) + { + RegisterContextPOSIXProcessMonitor_x86_64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_x86_64(*this, 0, reg_interface); + m_posix_thread = reg_ctx; + m_reg_context_sp.reset(reg_ctx); + } + break; + } + + default: + assert(false && "CPU type not supported!"); + break; } } return m_reg_context_sp; @@ -195,6 +230,17 @@ POSIXThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame) return reg_ctx_sp; } +lldb::addr_t +POSIXThread::GetThreadPointer () +{ + ProcessMonitor &monitor = GetMonitor(); + addr_t addr; + if (monitor.ReadThreadPointer (GetID(), addr)) + return addr; + else + return LLDB_INVALID_ADDRESS; +} + bool POSIXThread::CalculateStopInfo() { @@ -314,6 +360,10 @@ POSIXThread::Notify(const ProcessMessage &message) case ProcessMessage::eNewThreadMessage: ThreadNotify(message); break; + + case ProcessMessage::eExecMessage: + ExecNotify(message); + break; } } @@ -328,7 +378,7 @@ POSIXThread::EnableHardwareWatchpoint(Watchpoint *wp) bool wp_read = wp->WatchpointRead(); bool wp_write = wp->WatchpointWrite(); uint32_t wp_hw_index = wp->GetHardwareIndex(); - RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX(); + POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); if (reg_ctx) wp_set = reg_ctx->SetHardwareWatchpointWithIndex(wp_addr, wp_size, wp_read, wp_write, @@ -365,7 +415,7 @@ POSIXThread::FindVacantWatchpointIndex() uint32_t hw_index = LLDB_INVALID_INDEX32; uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); uint32_t wp_idx; - RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX(); + POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); if (reg_ctx) { for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) @@ -387,7 +437,7 @@ POSIXThread::BreakNotify(const ProcessMessage &message) Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); assert(GetRegisterContext()); - status = GetRegisterContextPOSIX()->UpdateAfterBreakpoint(); + status = GetPOSIXBreakpointProtocol()->UpdateAfterBreakpoint(); assert(status && "Breakpoint update failed!"); // With our register state restored, resolve the breakpoint object @@ -399,31 +449,22 @@ POSIXThread::BreakNotify(const ProcessMessage &message) lldb::BreakpointSiteSP bp_site(GetProcess()->GetBreakpointSiteList().FindByAddress(pc)); // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, - // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that - // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc. - if (bp_site && bp_site->ValidForThisThread(this)) + // we create a stop reason with should_stop=false. If there is no breakpoint location, then report + // an invalid stop reason. We don't need to worry about stepping over the breakpoint here, that will + // be taken care of when the thread resumes and notices that there's a breakpoint under the pc. + if (bp_site) { lldb::break_id_t bp_id = bp_site->GetID(); - if (GetProcess()->GetThreadList().SetSelectedThreadByID(GetID())) + if (bp_site->ValidForThisThread(this)) SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id)); else - assert(false && "Invalid thread ID during BreakNotify."); - } - else - { - const ThreadSpec *spec = bp_site ? - bp_site->GetOwnerAtIndex(0)->GetOptionsNoCreate()->GetThreadSpecNoCreate() : 0; - - if (spec && spec->TIDMatches(*this)) - assert(false && "BreakpointSite is invalid for the current ThreadSpec."); - else { - if (!m_stop_info_sp) { - StopInfoSP invalid_stop_info_sp; - SetStopInfo (invalid_stop_info_sp); - } + const bool should_stop = false; + SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id, should_stop)); } } + else + SetStopInfo(StopInfoSP()); } void @@ -436,7 +477,7 @@ POSIXThread::WatchNotify(const ProcessMessage &message) log->Printf ("POSIXThread::%s () Hardware Watchpoint Address = 0x%8.8" PRIx64, __FUNCTION__, halt_addr); - RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX(); + POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); if (reg_ctx) { uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); @@ -532,22 +573,26 @@ POSIXThread::GetRegisterIndexFromOffset(unsigned offset) llvm_unreachable("CPU type not supported!"); break; + case ArchSpec::eCore_mips64: case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_32_i486: case ArchSpec::eCore_x86_32_i486sx: case ArchSpec::eCore_x86_64_x86_64: { - RegisterContextSP base = GetRegisterContext(); - if (base) { - RegisterContextPOSIX &context = static_cast<RegisterContextPOSIX &>(*base); - reg = context.GetRegisterIndexFromOffset(offset); - } + POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); + reg = reg_ctx->GetRegisterIndexFromOffset(offset); } break; } return reg; } +void +POSIXThread::ExecNotify(const ProcessMessage &message) +{ + SetStopInfo (StopInfo::CreateStopReasonWithExec(*this)); +} + const char * POSIXThread::GetRegisterName(unsigned reg) { @@ -560,6 +605,7 @@ POSIXThread::GetRegisterName(unsigned reg) assert(false && "CPU type not supported!"); break; + case ArchSpec::eCore_mips64: case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_32_i486: case ArchSpec::eCore_x86_32_i486sx: diff --git a/source/Plugins/Process/POSIX/POSIXThread.h b/source/Plugins/Process/POSIX/POSIXThread.h index d051d23860df..51d6645f209d 100644 --- a/source/Plugins/Process/POSIX/POSIXThread.h +++ b/source/Plugins/Process/POSIX/POSIXThread.h @@ -21,7 +21,7 @@ class ProcessMessage; class ProcessMonitor; -class RegisterContextPOSIX; +class POSIXBreakpointProtocol; //------------------------------------------------------------------------------ // @class POSIXThread @@ -59,6 +59,9 @@ public: virtual lldb::RegisterContextSP CreateRegisterContextForFrame (lldb_private::StackFrame *frame); + virtual lldb::addr_t + GetThreadPointer (); + //-------------------------------------------------------------------------- // These functions provide a mapping from the register offset // back to the register index or name for use in debugging or log @@ -92,15 +95,12 @@ public: uint32_t FindVacantWatchpointIndex(); protected: - RegisterContextPOSIX * - GetRegisterContextPOSIX () + POSIXBreakpointProtocol * + GetPOSIXBreakpointProtocol () { if (!m_reg_context_sp) m_reg_context_sp = GetRegisterContext(); -#if 0 - return dynamic_cast<RegisterContextPOSIX*>(m_reg_context_sp.get()); -#endif - return (RegisterContextPOSIX *)m_reg_context_sp.get(); + return m_posix_thread; } std::unique_ptr<lldb_private::StackFrame> m_frame_ap; @@ -109,6 +109,7 @@ protected: bool m_thread_name_valid; std::string m_thread_name; + POSIXBreakpointProtocol *m_posix_thread; ProcessMonitor & GetMonitor(); @@ -125,6 +126,7 @@ protected: void CrashNotify(const ProcessMessage &message); void ThreadNotify(const ProcessMessage &message); void ExitNotify(const ProcessMessage &message); + void ExecNotify(const ProcessMessage &message); lldb_private::Unwind * GetUnwinder(); diff --git a/source/Plugins/Process/POSIX/ProcessMessage.cpp b/source/Plugins/Process/POSIX/ProcessMessage.cpp index 60a29e07cea8..5c53627f9e0b 100644 --- a/source/Plugins/Process/POSIX/ProcessMessage.cpp +++ b/source/Plugins/Process/POSIX/ProcessMessage.cpp @@ -218,6 +218,9 @@ ProcessMessage::PrintKind(Kind kind) case eInvalidMessage: str = "eInvalidMessage"; break; + case eAttachMessage: + str = "eAttachMessage"; + break; case eExitMessage: str = "eExitMessage"; break; @@ -245,6 +248,9 @@ ProcessMessage::PrintKind(Kind kind) case eNewThreadMessage: str = "eNewThreadMessage"; break; + case eExecMessage: + str = "eExecMessage"; + break; } #endif diff --git a/source/Plugins/Process/POSIX/ProcessMessage.h b/source/Plugins/Process/POSIX/ProcessMessage.h index c6c460c13445..40462d0f0e13 100644 --- a/source/Plugins/Process/POSIX/ProcessMessage.h +++ b/source/Plugins/Process/POSIX/ProcessMessage.h @@ -23,6 +23,7 @@ public: enum Kind { eInvalidMessage, + eAttachMessage, eExitMessage, eLimboMessage, eSignalMessage, @@ -31,7 +32,8 @@ public: eBreakpointMessage, eWatchpointMessage, eCrashMessage, - eNewThreadMessage + eNewThreadMessage, + eExecMessage }; enum CrashReason @@ -79,6 +81,11 @@ public: lldb::tid_t GetTID() const { return m_tid; } + /// Indicates that the process @p pid has successfully attached. + static ProcessMessage Attach(lldb::pid_t pid) { + return ProcessMessage(pid, eAttachMessage); + } + /// Indicates that the thread @p tid is about to exit with status @p status. static ProcessMessage Limbo(lldb::tid_t tid, int status) { return ProcessMessage(tid, eLimboMessage, status); @@ -127,6 +134,11 @@ public: return ProcessMessage(tid, eExitMessage, status); } + /// Indicates that the thread @p pid has exec'd. + static ProcessMessage Exec(lldb::tid_t tid) { + return ProcessMessage(tid, eExecMessage); + } + int GetExitStatus() const { assert(GetKind() == eExitMessage || GetKind() == eLimboMessage); return m_status; diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp index f04631ddf914..70ad3a66d9ef 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp +++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp @@ -289,12 +289,11 @@ ProcessPOSIX::GetImageInfoAddress() { Target *target = &GetTarget(); ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); - Address addr = obj_file->GetImageInfoAddress(); + Address addr = obj_file->GetImageInfoAddress(target); - if (addr.IsValid()) + if (addr.IsValid()) return addr.GetLoadAddress(target); - else - return LLDB_INVALID_ADDRESS; + return LLDB_INVALID_ADDRESS; } Error @@ -319,34 +318,6 @@ ProcessPOSIX::DoHalt(bool &caused_stop) } Error -ProcessPOSIX::DoDetach(bool keep_stopped) -{ - Error error; - if (keep_stopped) - { - // FIXME: If you want to implement keep_stopped, - // this would be the place to do it. - error.SetErrorString("Detaching with keep_stopped true is not currently supported on this platform."); - return error; - } - - Mutex::Locker lock(m_thread_list.GetMutex()); - - uint32_t thread_count = m_thread_list.GetSize(false); - for (uint32_t i = 0; i < thread_count; ++i) - { - POSIXThread *thread = static_cast<POSIXThread*>( - m_thread_list.GetThreadAtIndex(i, false).get()); - error = m_monitor->Detach(thread->GetID()); - } - - if (error.Success()) - SetPrivateState(eStateDetached); - - return error; -} - -Error ProcessPOSIX::DoSignal(int signal) { Error error; @@ -381,6 +352,31 @@ ProcessPOSIX::DoDestroy() } void +ProcessPOSIX::DoDidExec() +{ + Target *target = &GetTarget(); + if (target) + { + PlatformSP platform_sp (target->GetPlatform()); + assert (platform_sp.get()); + if (platform_sp) + { + ProcessInstanceInfo process_info; + platform_sp->GetProcessInfo(GetID(), process_info); + ModuleSP exe_module_sp; + FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); + Error error = platform_sp->ResolveExecutable(process_info.GetExecutableFile(), + target->GetArchitecture(), + exe_module_sp, + executable_search_paths.GetSize() ? &executable_search_paths : NULL); + if (!error.Success()) + return; + target->SetExecutableModule(exe_module_sp, true); + } + } +} + +void ProcessPOSIX::SendMessage(const ProcessMessage &message) { Mutex::Locker lock(m_message_mutex); @@ -395,6 +391,10 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message) case ProcessMessage::eInvalidMessage: return; + case ProcessMessage::eAttachMessage: + SetPrivateState(eStateStopped); + return; + case ProcessMessage::eLimboMessage: assert(thread); thread->SetState(eStateStopped); @@ -442,15 +442,38 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message) case ProcessMessage::eBreakpointMessage: case ProcessMessage::eTraceMessage: case ProcessMessage::eWatchpointMessage: - case ProcessMessage::eNewThreadMessage: case ProcessMessage::eCrashMessage: assert(thread); thread->SetState(eStateStopped); StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); break; + + case ProcessMessage::eNewThreadMessage: + { + lldb::tid_t new_tid = message.GetChildTID(); + if (WaitingForInitialStop(new_tid)) + { + m_monitor->WaitForInitialTIDStop(new_tid); + } + assert(thread); + thread->SetState(eStateStopped); + StopAllThreads(message.GetTID()); + SetPrivateState(eStateStopped); + break; } + case ProcessMessage::eExecMessage: + { + assert(thread); + thread->SetState(eStateStopped); + StopAllThreads(message.GetTID()); + SetPrivateState(eStateStopped); + break; + } + } + + m_message_queue.push(message); } @@ -473,6 +496,12 @@ ProcessPOSIX::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid) return added_to_set; } +bool +ProcessPOSIX::WaitingForInitialStop(lldb::tid_t stop_tid) +{ + return (m_seen_initial_stop.find(stop_tid) == m_seen_initial_stop.end()); +} + POSIXThread * ProcessPOSIX::CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid) { @@ -499,8 +528,6 @@ ProcessPOSIX::RefreshStateAfterStop() lldb::tid_t tid = message.GetTID(); if (log) log->Printf ("ProcessPOSIX::%s(), message_queue size = %d, pid = %" PRIi64, __FUNCTION__, (int)m_message_queue.size(), tid); - POSIXThread *thread = static_cast<POSIXThread*>( - GetThreadList().FindThreadByID(tid, false).get()); if (message.GetKind() == ProcessMessage::eNewThreadMessage) { @@ -517,6 +544,8 @@ ProcessPOSIX::RefreshStateAfterStop() m_thread_list.RefreshStateAfterStop(); + POSIXThread *thread = static_cast<POSIXThread*>( + GetThreadList().FindThreadByID(tid, false).get()); if (thread) thread->Notify(message); @@ -813,19 +842,21 @@ ProcessPOSIX::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thre if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) log->Printf ("ProcessPOSIX::%s() (pid = %" PRIi64 ")", __FUNCTION__, GetID()); + bool has_updated = false; // Update the process thread list with this new thread. // FIXME: We should be using tid, not pid. assert(m_monitor); ThreadSP thread_sp (old_thread_list.FindThreadByID (GetID(), false)); if (!thread_sp) { thread_sp.reset(CreateNewPOSIXThread(*this, GetID())); + has_updated = true; } if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) log->Printf ("ProcessPOSIX::%s() updated pid = %" PRIi64, __FUNCTION__, GetID()); new_thread_list.AddThread(thread_sp); - return new_thread_list.GetSize(false) > 0; + return has_updated; // the list has been updated } ByteOrder diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.h b/source/Plugins/Process/POSIX/ProcessPOSIX.h index 48b19bac47e7..790041be321a 100644 --- a/source/Plugins/Process/POSIX/ProcessPOSIX.h +++ b/source/Plugins/Process/POSIX/ProcessPOSIX.h @@ -70,7 +70,7 @@ public: DoHalt(bool &caused_stop); virtual lldb_private::Error - DoDetach(bool keep_stopped); + DoDetach(bool keep_stopped) = 0; virtual lldb_private::Error DoSignal(int signal); @@ -79,6 +79,9 @@ public: DoDestroy(); virtual void + DoDidExec(); + + virtual void RefreshStateAfterStop(); virtual bool @@ -167,6 +170,9 @@ public: bool AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid); + bool + WaitingForInitialStop(lldb::tid_t stop_tid); + virtual POSIXThread * CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid); diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.cpp b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.cpp new file mode 100644 index 000000000000..50ec8d414a12 --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.cpp @@ -0,0 +1,78 @@ +//===-- RegisterContextFreeBSD_i386.cpp ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include "RegisterContextPOSIX_x86.h" +#include "RegisterContextFreeBSD_i386.h" + +using namespace lldb_private; +using namespace lldb; + +// http://svnweb.freebsd.org/base/head/sys/x86/include/reg.h +struct GPR +{ + uint32_t fs; + uint32_t es; + uint32_t ds; + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t isp; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + uint32_t trapno; + uint32_t err; + uint32_t eip; + uint32_t cs; + uint32_t eflags; + uint32_t esp; + uint32_t ss; + uint32_t gs; +}; + +#define DR_SIZE 0 +#define DR_OFFSET(reg_index) 0 + +//--------------------------------------------------------------------------- +// Include RegisterInfos_i386 to declare our g_register_infos_i386 structure. +//--------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_I386_STRUCT +#include "RegisterInfos_i386.h" +#undef DECLARE_REGISTER_INFOS_I386_STRUCT + +RegisterContextFreeBSD_i386::RegisterContextFreeBSD_i386(const ArchSpec &target_arch) : + RegisterInfoInterface(target_arch) +{ +} + +RegisterContextFreeBSD_i386::~RegisterContextFreeBSD_i386() +{ +} + +size_t +RegisterContextFreeBSD_i386::GetGPRSize() +{ + return sizeof(GPR); +} + +const RegisterInfo * +RegisterContextFreeBSD_i386::GetRegisterInfo() +{ + switch (m_target_arch.GetCore()) + { + case ArchSpec::eCore_x86_32_i386: + case ArchSpec::eCore_x86_32_i486: + case ArchSpec::eCore_x86_32_i486sx: + return g_register_infos_i386; + default: + assert(false && "Unhandled target architecture."); + return NULL; + } +} diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.h b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.h new file mode 100644 index 000000000000..4ec2ad3e9706 --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.h @@ -0,0 +1,29 @@ +//===-- RegisterContextFreeBSD_i386.h ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextFreeBSD_i386_H_ +#define liblldb_RegisterContextFreeBSD_i386_H_ + +#include "RegisterContextPOSIX.h" + +class RegisterContextFreeBSD_i386 + : public RegisterInfoInterface +{ +public: + RegisterContextFreeBSD_i386(const lldb_private::ArchSpec &target_arch); + virtual ~RegisterContextFreeBSD_i386(); + + size_t + GetGPRSize(); + + const lldb_private::RegisterInfo * + GetRegisterInfo(); +}; + +#endif diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.cpp b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.cpp new file mode 100644 index 000000000000..4714251fd2dc --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.cpp @@ -0,0 +1,90 @@ +//===-- RegisterContextFreeBSD_mips64.cpp ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include <vector> +#include "RegisterContextPOSIX_mips64.h" +#include "RegisterContextFreeBSD_mips64.h" + +using namespace lldb_private; +using namespace lldb; + +// http://svnweb.freebsd.org/base/head/sys/mips/include/regnum.h +typedef struct _GPR +{ + uint64_t zero; + uint64_t r1; + uint64_t r2; + uint64_t r3; + uint64_t r4; + uint64_t r5; + uint64_t r6; + uint64_t r7; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t r16; + uint64_t r17; + uint64_t r18; + uint64_t r19; + uint64_t r20; + uint64_t r21; + uint64_t r22; + uint64_t r23; + uint64_t r24; + uint64_t r25; + uint64_t r26; + uint64_t r27; + uint64_t gp; + uint64_t sp; + uint64_t r30; + uint64_t ra; + uint64_t sr; + uint64_t mullo; + uint64_t mulhi; + uint64_t badvaddr; + uint64_t cause; + uint64_t pc; + uint64_t ic; + uint64_t dummy; +} GPR; + +//--------------------------------------------------------------------------- +// Include RegisterInfos_mips64 to declare our g_register_infos_mips64 structure. +//--------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_MIPS64_STRUCT +#include "RegisterInfos_mips64.h" +#undef DECLARE_REGISTER_INFOS_MIPS64_STRUCT + +RegisterContextFreeBSD_mips64::RegisterContextFreeBSD_mips64(const ArchSpec &target_arch) : + RegisterInfoInterface(target_arch) +{ +} + +RegisterContextFreeBSD_mips64::~RegisterContextFreeBSD_mips64() +{ +} + +size_t +RegisterContextFreeBSD_mips64::GetGPRSize() +{ + return sizeof(GPR); +} + +const RegisterInfo * +RegisterContextFreeBSD_mips64::GetRegisterInfo() +{ + assert (m_target_arch.GetCore() == ArchSpec::eCore_mips64); + return g_register_infos_mips64; +} + diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.h b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.h new file mode 100644 index 000000000000..9ee767955347 --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_mips64.h @@ -0,0 +1,29 @@ +//===-- RegisterContextFreeBSD_mips64.h -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextFreeBSD_mips64_H_ +#define liblldb_RegisterContextFreeBSD_mips64_H_ + +#include "RegisterContextPOSIX.h" + +class RegisterContextFreeBSD_mips64: + public RegisterInfoInterface +{ +public: + RegisterContextFreeBSD_mips64(const lldb_private::ArchSpec &target_arch); + virtual ~RegisterContextFreeBSD_mips64(); + + size_t + GetGPRSize(); + + const lldb_private::RegisterInfo * + GetRegisterInfo(); +}; + +#endif diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp index 0fb9dc1cb3dc..471734580fff 100644 --- a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp +++ b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextFreeBSD_x86_64.h ------------------------*- C++ -*-===// +//===-- RegisterContextFreeBSD_x86_64.cpp ----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,27 +7,15 @@ // //===---------------------------------------------------------------------===// -#include "RegisterContextFreeBSD_x86_64.h" #include <vector> +#include "RegisterContextPOSIX_x86.h" +#include "RegisterContextFreeBSD_i386.h" +#include "RegisterContextFreeBSD_x86_64.h" using namespace lldb_private; +using namespace lldb; -// Computes the offset of the given GPR in the user data area. -#define GPR_OFFSET(regname) \ - (offsetof(GPR, regname)) - -// Update the FreeBSD specific information (offset and size). -#define UPDATE_GPR_INFO(reg) \ -do { \ - GetRegisterContext()[gpr_##reg].byte_size = sizeof(GPR::reg); \ - GetRegisterContext()[gpr_##reg].byte_offset = GPR_OFFSET(reg); \ -} while(false); - -#define UPDATE_I386_GPR_INFO(i386_reg, reg) \ -do { \ - GetRegisterContext()[gpr_##i386_reg].byte_offset = GPR_OFFSET(reg); \ -} while(false); - +// http://svnweb.freebsd.org/base/head/sys/x86/include/reg.h typedef struct _GPR { uint64_t r15; @@ -58,15 +46,47 @@ typedef struct _GPR uint64_t ss; } GPR; -// Use a singleton function to avoid global constructors in shared libraries. -static std::vector<RegisterInfo> & GetRegisterContext () { - static std::vector<RegisterInfo> g_register_infos; - return g_register_infos; +#define DR_SIZE 0 +#define DR_OFFSET(reg_index) 0 + +//--------------------------------------------------------------------------- +// Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64 structure. +//--------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_X86_64_STRUCT +#include "RegisterInfos_x86_64.h" +#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT + +static const RegisterInfo * +GetRegisterInfo_i386(const lldb_private::ArchSpec& arch) +{ + static std::vector<lldb_private::RegisterInfo> g_register_infos; + + // Allocate RegisterInfo only once + if (g_register_infos.empty()) + { + // Copy the register information from base class + std::unique_ptr<RegisterContextFreeBSD_i386> reg_interface(new RegisterContextFreeBSD_i386 (arch)); + const RegisterInfo *base_info = reg_interface->GetRegisterInfo(); + g_register_infos.insert(g_register_infos.end(), &base_info[0], &base_info[k_num_registers_i386]); + + //--------------------------------------------------------------------------- + // Include RegisterInfos_x86_64 to update the g_register_infos structure + // with x86_64 offsets. + //--------------------------------------------------------------------------- + #define UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS + #include "RegisterInfos_x86_64.h" + #undef UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS + } + + return &g_register_infos[0]; } +RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(const ArchSpec &target_arch) : + RegisterInfoInterface(target_arch) +{ +} -RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(Thread &thread, uint32_t concrete_frame_idx): - RegisterContext_x86_64(thread, concrete_frame_idx) +RegisterContextFreeBSD_x86_64::~RegisterContextFreeBSD_x86_64() { } @@ -79,58 +99,17 @@ RegisterContextFreeBSD_x86_64::GetGPRSize() const RegisterInfo * RegisterContextFreeBSD_x86_64::GetRegisterInfo() { - // Allocate RegisterInfo only once - if (GetRegisterContext().empty()) + switch (m_target_arch.GetCore()) { - // Copy the register information from base class - const RegisterInfo *base_info = RegisterContext_x86_64::GetRegisterInfo(); - if (base_info) - { - GetRegisterContext().insert(GetRegisterContext().end(), &base_info[0], &base_info[k_num_registers]); - // Update the FreeBSD specific register information (offset and size). - UpdateRegisterInfo(); - } + case ArchSpec::eCore_x86_32_i386: + case ArchSpec::eCore_x86_32_i486: + case ArchSpec::eCore_x86_32_i486sx: + return GetRegisterInfo_i386 (m_target_arch); + case ArchSpec::eCore_x86_64_x86_64: + return g_register_infos_x86_64; + default: + assert(false && "Unhandled target architecture."); + return NULL; } - return &GetRegisterContext()[0]; -} - -void -RegisterContextFreeBSD_x86_64::UpdateRegisterInfo() -{ - UPDATE_GPR_INFO(rax); - UPDATE_GPR_INFO(rbx); - UPDATE_GPR_INFO(rcx); - UPDATE_GPR_INFO(rdx); - UPDATE_GPR_INFO(rdi); - UPDATE_GPR_INFO(rsi); - UPDATE_GPR_INFO(rbp); - UPDATE_GPR_INFO(rsp); - UPDATE_GPR_INFO(r8); - UPDATE_GPR_INFO(r9); - UPDATE_GPR_INFO(r10); - UPDATE_GPR_INFO(r11); - UPDATE_GPR_INFO(r12); - UPDATE_GPR_INFO(r13); - UPDATE_GPR_INFO(r14); - UPDATE_GPR_INFO(r15); - UPDATE_GPR_INFO(rip); - UPDATE_GPR_INFO(rflags); - UPDATE_GPR_INFO(cs); - UPDATE_GPR_INFO(fs); - UPDATE_GPR_INFO(gs); - UPDATE_GPR_INFO(ss); - UPDATE_GPR_INFO(ds); - UPDATE_GPR_INFO(es); - - UPDATE_I386_GPR_INFO(eax, rax); - UPDATE_I386_GPR_INFO(ebx, rbx); - UPDATE_I386_GPR_INFO(ecx, rcx); - UPDATE_I386_GPR_INFO(edx, rdx); - UPDATE_I386_GPR_INFO(edi, rdi); - UPDATE_I386_GPR_INFO(esi, rsi); - UPDATE_I386_GPR_INFO(ebp, rbp); - UPDATE_I386_GPR_INFO(esp, rsp); - UPDATE_I386_GPR_INFO(eip, rip); - UPDATE_I386_GPR_INFO(eflags, rflags); } diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h index ffff40a9c65b..731bb0ea6bcc 100644 --- a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h +++ b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h @@ -1,4 +1,4 @@ -//===-- RegisterContextFreeBSD_x86_64.h ---------------------------*- C++ -*-===// +//===-- RegisterContextFreeBSD_x86_64.h -------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,23 +10,20 @@ #ifndef liblldb_RegisterContextFreeBSD_x86_64_H_ #define liblldb_RegisterContextFreeBSD_x86_64_H_ -#include "Plugins/Process/POSIX/RegisterContext_x86_64.h" +#include "RegisterContextPOSIX.h" class RegisterContextFreeBSD_x86_64: - public RegisterContext_x86_64 + public RegisterInfoInterface { public: - RegisterContextFreeBSD_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx); + RegisterContextFreeBSD_x86_64(const lldb_private::ArchSpec &target_arch); + virtual ~RegisterContextFreeBSD_x86_64(); size_t GetGPRSize(); -protected: - virtual const lldb_private::RegisterInfo * + const lldb_private::RegisterInfo * GetRegisterInfo(); - - virtual void - UpdateRegisterInfo(); }; #endif diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_i386.cpp b/source/Plugins/Process/POSIX/RegisterContextLinux_i386.cpp new file mode 100644 index 000000000000..0828efbc6c3c --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextLinux_i386.cpp @@ -0,0 +1,96 @@ +//===-- RegisterContextLinux_i386.cpp --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include "RegisterContextPOSIX_x86.h" +#include "RegisterContextLinux_i386.h" + +using namespace lldb_private; +using namespace lldb; + +struct GPR +{ + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t esi; + uint32_t edi; + uint32_t ebp; + uint32_t eax; + uint32_t ds; + uint32_t es; + uint32_t fs; + uint32_t gs; + uint32_t orig_ax; + uint32_t eip; + uint32_t cs; + uint32_t eflags; + uint32_t esp; + uint32_t ss; +}; + +struct UserArea +{ + GPR regs; // General purpose registers. + int32_t fpvalid; // True if FPU is being used. + FXSAVE i387; // FPU registers. + uint32_t tsize; // Text segment size. + uint32_t dsize; // Data segment size. + uint32_t ssize; // Stack segment size. + uint32_t start_code; // VM address of text. + uint32_t start_stack; // VM address of stack bottom (top in rsp). + int32_t signal; // Signal causing core dump. + int32_t reserved; // Unused. + uint32_t ar0; // Location of GPR's. + uint32_t fpstate; // Location of FPR's. Should be a FXSTATE *, but this + // has to be 32-bits even on 64-bit systems. + uint32_t magic; // Identifier for core dumps. + char u_comm[32]; // Command causing core dump. + uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7). +}; + +#define DR_SIZE sizeof(UserArea::u_debugreg[0]) +#define DR_OFFSET(reg_index) \ + (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index])) + +//--------------------------------------------------------------------------- +// Include RegisterInfos_i386 to declare our g_register_infos_i386 structure. +//--------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_I386_STRUCT +#include "RegisterInfos_i386.h" +#undef DECLARE_REGISTER_INFOS_I386_STRUCT + +RegisterContextLinux_i386::RegisterContextLinux_i386(const ArchSpec &target_arch) : + RegisterInfoInterface(target_arch) +{ +} + +RegisterContextLinux_i386::~RegisterContextLinux_i386() +{ +} + +size_t +RegisterContextLinux_i386::GetGPRSize() +{ + return sizeof(GPR); +} + +const RegisterInfo * +RegisterContextLinux_i386::GetRegisterInfo() +{ + switch (m_target_arch.GetCore()) + { + case ArchSpec::eCore_x86_32_i386: + case ArchSpec::eCore_x86_32_i486: + case ArchSpec::eCore_x86_32_i486sx: + return g_register_infos_i386; + default: + assert(false && "Unhandled target architecture."); + return NULL; + } +} diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_i386.h b/source/Plugins/Process/POSIX/RegisterContextLinux_i386.h new file mode 100644 index 000000000000..81afdbf8b1cf --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextLinux_i386.h @@ -0,0 +1,29 @@ +//===-- RegisterContextLinux_i386.h -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextLinux_i386_H_ +#define liblldb_RegisterContextLinux_i386_H_ + +#include "RegisterContextPOSIX.h" + +class RegisterContextLinux_i386 + : public RegisterInfoInterface +{ +public: + RegisterContextLinux_i386(const lldb_private::ArchSpec &target_arch); + virtual ~RegisterContextLinux_i386(); + + size_t + GetGPRSize(); + + const lldb_private::RegisterInfo * + GetRegisterInfo(); +}; + +#endif diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp index c1aea2a41a1f..5434ddfcf38b 100644 --- a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp +++ b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterContextLinux_x86_64.h --------------------------*- C++ -*-===// +//===-- RegisterContextLinux_x86_64.cpp ------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,36 +7,13 @@ // //===---------------------------------------------------------------------===// -#include "llvm/Support/Compiler.h" -#include "RegisterContextLinux_x86_64.h" #include <vector> +#include "RegisterContextPOSIX_x86.h" +#include "RegisterContextLinux_i386.h" +#include "RegisterContextLinux_x86_64.h" using namespace lldb_private; - -// Computes the offset of the given GPR in the user data area. -#define GPR_OFFSET(regname) \ - (offsetof(GPR, regname)) - -// Update the Linux specific information (offset and size). -#define UPDATE_GPR_INFO(reg) \ -do { \ - GetRegisterContext()[gpr_##reg].byte_size = sizeof(GPR::reg); \ - GetRegisterContext()[gpr_##reg].byte_offset = GPR_OFFSET(reg); \ -} while(false); - -#define UPDATE_I386_GPR_INFO(i386_reg, reg) \ -do { \ - GetRegisterContext()[gpr_##i386_reg].byte_offset = GPR_OFFSET(reg); \ -} while(false); - -#define DR_OFFSET(reg_index) \ - (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index])) - -#define UPDATE_DR_INFO(reg_index) \ -do { \ - GetRegisterContext()[dr##reg_index].byte_size = sizeof(UserArea::u_debugreg[0]); \ - GetRegisterContext()[dr##reg_index].byte_offset = DR_OFFSET(reg_index); \ -} while(false); +using namespace lldb; typedef struct _GPR { @@ -69,8 +46,6 @@ typedef struct _GPR uint64_t gs; } GPR; -typedef RegisterContext_x86_64::FXSAVE FXSAVE; - struct UserArea { GPR gpr; // General purpose registers. @@ -94,14 +69,48 @@ struct UserArea uint64_t fault_address; // Control register CR3. }; -// Use a singleton function to avoid global constructors in shared libraries. -static std::vector<RegisterInfo> & GetRegisterContext () { - static std::vector<RegisterInfo> g_register_infos; - return g_register_infos; +#define DR_SIZE sizeof(UserArea::u_debugreg[0]) +#define DR_OFFSET(reg_index) \ + (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index])) + +//--------------------------------------------------------------------------- +// Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64 structure. +//--------------------------------------------------------------------------- +#define DECLARE_REGISTER_INFOS_X86_64_STRUCT +#include "RegisterInfos_x86_64.h" +#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT + +static const RegisterInfo * +GetRegisterInfo_i386(const lldb_private::ArchSpec &arch) +{ + static std::vector<lldb_private::RegisterInfo> g_register_infos; + + // Allocate RegisterInfo only once + if (g_register_infos.empty()) + { + // Copy the register information from base class + std::unique_ptr<RegisterContextLinux_i386> reg_interface(new RegisterContextLinux_i386 (arch)); + const RegisterInfo *base_info = reg_interface->GetRegisterInfo(); + g_register_infos.insert(g_register_infos.end(), &base_info[0], &base_info[k_num_registers_i386]); + + //--------------------------------------------------------------------------- + // Include RegisterInfos_x86_64 to update the g_register_infos structure + // with x86_64 offsets. + //--------------------------------------------------------------------------- + #define UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS + #include "RegisterInfos_x86_64.h" + #undef UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS + } + + return &g_register_infos[0]; +} + +RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(const ArchSpec &target_arch) : + RegisterInfoInterface(target_arch) +{ } -RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(Thread &thread, uint32_t concrete_frame_idx): - RegisterContext_x86_64(thread, concrete_frame_idx) +RegisterContextLinux_x86_64::~RegisterContextLinux_x86_64() { } @@ -114,67 +123,17 @@ RegisterContextLinux_x86_64::GetGPRSize() const RegisterInfo * RegisterContextLinux_x86_64::GetRegisterInfo() { - // Allocate RegisterInfo only once - if (GetRegisterContext().empty()) + switch (m_target_arch.GetCore()) { - // Copy the register information from base class - const RegisterInfo *base_info = RegisterContext_x86_64::GetRegisterInfo(); - if (base_info) - { - GetRegisterContext().insert(GetRegisterContext().end(), &base_info[0], &base_info[k_num_registers]); - // Update the Linux specific register information (offset and size). - UpdateRegisterInfo(); - } + case ArchSpec::eCore_x86_32_i386: + case ArchSpec::eCore_x86_32_i486: + case ArchSpec::eCore_x86_32_i486sx: + return GetRegisterInfo_i386 (m_target_arch); + case ArchSpec::eCore_x86_64_x86_64: + return g_register_infos_x86_64; + default: + assert(false && "Unhandled target architecture."); + return NULL; } - return &GetRegisterContext()[0]; -} - -void -RegisterContextLinux_x86_64::UpdateRegisterInfo() -{ - UPDATE_GPR_INFO(rax); - UPDATE_GPR_INFO(rbx); - UPDATE_GPR_INFO(rcx); - UPDATE_GPR_INFO(rdx); - UPDATE_GPR_INFO(rdi); - UPDATE_GPR_INFO(rsi); - UPDATE_GPR_INFO(rbp); - UPDATE_GPR_INFO(rsp); - UPDATE_GPR_INFO(r8); - UPDATE_GPR_INFO(r9); - UPDATE_GPR_INFO(r10); - UPDATE_GPR_INFO(r11); - UPDATE_GPR_INFO(r12); - UPDATE_GPR_INFO(r13); - UPDATE_GPR_INFO(r14); - UPDATE_GPR_INFO(r15); - UPDATE_GPR_INFO(rip); - UPDATE_GPR_INFO(rflags); - UPDATE_GPR_INFO(cs); - UPDATE_GPR_INFO(fs); - UPDATE_GPR_INFO(gs); - UPDATE_GPR_INFO(ss); - UPDATE_GPR_INFO(ds); - UPDATE_GPR_INFO(es); - - UPDATE_I386_GPR_INFO(eax, rax); - UPDATE_I386_GPR_INFO(ebx, rbx); - UPDATE_I386_GPR_INFO(ecx, rcx); - UPDATE_I386_GPR_INFO(edx, rdx); - UPDATE_I386_GPR_INFO(edi, rdi); - UPDATE_I386_GPR_INFO(esi, rsi); - UPDATE_I386_GPR_INFO(ebp, rbp); - UPDATE_I386_GPR_INFO(esp, rsp); - UPDATE_I386_GPR_INFO(eip, rip); - UPDATE_I386_GPR_INFO(eflags, rflags); - - UPDATE_DR_INFO(0); - UPDATE_DR_INFO(1); - UPDATE_DR_INFO(2); - UPDATE_DR_INFO(3); - UPDATE_DR_INFO(4); - UPDATE_DR_INFO(5); - UPDATE_DR_INFO(6); - UPDATE_DR_INFO(7); } diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h index 1509ef55b8dc..21c809b5dc33 100644 --- a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h +++ b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h @@ -10,23 +10,20 @@ #ifndef liblldb_RegisterContextLinux_x86_64_H_ #define liblldb_RegisterContextLinux_x86_64_H_ -#include "Plugins/Process/POSIX/RegisterContext_x86_64.h" +#include "RegisterContextPOSIX.h" -class RegisterContextLinux_x86_64: - public RegisterContext_x86_64 +class RegisterContextLinux_x86_64 + : public RegisterInfoInterface { public: - RegisterContextLinux_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx); + RegisterContextLinux_x86_64(const lldb_private::ArchSpec &target_arch); + virtual ~RegisterContextLinux_x86_64(); size_t GetGPRSize(); -protected: - virtual const lldb_private::RegisterInfo * + const lldb_private::RegisterInfo * GetRegisterInfo(); - - virtual void - UpdateRegisterInfo(); }; #endif diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX.h b/source/Plugins/Process/POSIX/RegisterContextPOSIX.h index 63ae01e83a90..e48c528403e3 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIX.h +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIX.h @@ -13,20 +13,19 @@ // C Includes // C++ Includes // Other libraries and framework includes +#include "lldb/Core/ArchSpec.h" #include "lldb/Target/RegisterContext.h" //------------------------------------------------------------------------------ -/// @class RegisterContextPOSIX +/// @class POSIXBreakpointProtocol /// /// @brief Extends RegisterClass with a few virtual operations useful on POSIX. -class RegisterContextPOSIX - : public lldb_private::RegisterContext +class POSIXBreakpointProtocol { public: - RegisterContextPOSIX(lldb_private::Thread &thread, - uint32_t concrete_frame_idx) - : RegisterContext(thread, concrete_frame_idx) + POSIXBreakpointProtocol() { m_watchpoints_initialized = false; } + virtual ~POSIXBreakpointProtocol() {} /// Updates the register state of the associated thread after hitting a /// breakpoint (if that make sense for the architecture). Default @@ -35,36 +34,61 @@ public: /// /// @return /// True if the operation succeeded and false otherwise. - virtual bool UpdateAfterBreakpoint() { return true; } + virtual bool UpdateAfterBreakpoint() = 0; /// Determines the index in lldb's register file given a kernel byte offset. virtual unsigned - GetRegisterIndexFromOffset(unsigned offset) { return LLDB_INVALID_REGNUM; } + GetRegisterIndexFromOffset(unsigned offset) = 0; // Checks to see if a watchpoint specified by hw_index caused the inferior // to stop. virtual bool - IsWatchpointHit (uint32_t hw_index) { return false; } + IsWatchpointHit (uint32_t hw_index) = 0; // Resets any watchpoints that have been hit. virtual bool - ClearWatchpointHits () { return false; } + ClearWatchpointHits () = 0; // Returns the watchpoint address associated with a watchpoint hardware // index. virtual lldb::addr_t - GetWatchpointAddress (uint32_t hw_index) { return LLDB_INVALID_ADDRESS; } + GetWatchpointAddress (uint32_t hw_index) = 0; virtual bool - IsWatchpointVacant (uint32_t hw_index) { return false; } + IsWatchpointVacant (uint32_t hw_index) = 0; virtual bool SetHardwareWatchpointWithIndex (lldb::addr_t addr, size_t size, bool read, bool write, - uint32_t hw_index) { return false; } + uint32_t hw_index) = 0; + + // From lldb_private::RegisterContext + virtual uint32_t + NumSupportedHardwareWatchpoints () = 0; protected: bool m_watchpoints_initialized; }; +//------------------------------------------------------------------------------ +/// @class RegisterInfoInterface +/// +/// @brief RegisterInfo interface to patch RegisterInfo structure for archs. +class RegisterInfoInterface +{ +public: + RegisterInfoInterface(const lldb_private::ArchSpec& target_arch) : m_target_arch(target_arch) {} + virtual ~RegisterInfoInterface () {} + + virtual size_t + GetGPRSize () = 0; + + virtual const lldb_private::RegisterInfo * + GetRegisterInfo () = 0; + +public: + lldb_private::ArchSpec m_target_arch; +}; + #endif // #ifndef liblldb_RegisterContextPOSIX_H_ + diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp new file mode 100644 index 000000000000..f70d00e98a3e --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.cpp @@ -0,0 +1,318 @@ +//===-- RegisterContextPOSIXProcessMonitor_mips64.h ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include "lldb/Target/Thread.h" +#include "lldb/Core/RegisterValue.h" + +#include "RegisterContextPOSIX_mips64.h" +#include "ProcessPOSIX.h" +#include "RegisterContextPOSIXProcessMonitor_mips64.h" +#include "ProcessMonitor.h" + +using namespace lldb_private; +using namespace lldb; + +#define REG_CONTEXT_SIZE (GetGPRSize()) + +RegisterContextPOSIXProcessMonitor_mips64::RegisterContextPOSIXProcessMonitor_mips64(Thread &thread, + uint32_t concrete_frame_idx, + RegisterInfoInterface *register_info) + : RegisterContextPOSIX_mips64(thread, concrete_frame_idx, register_info) +{ +} + +ProcessMonitor & +RegisterContextPOSIXProcessMonitor_mips64::GetMonitor() +{ + ProcessSP base = CalculateProcess(); + ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get()); + return process->GetMonitor(); +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::ReadGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::ReadFPR() +{ + // XXX not yet implemented + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::WriteGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::WriteFPR() +{ + // XXX not yet implemented + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::ReadRegister(const unsigned reg, + RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(const unsigned reg, + const RegisterValue &value) +{ + unsigned reg_to_write = reg; + RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) + { + Error error; + ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, + dst, + sizeof(dst), + byte_order, + error); + if (error.Success() && dest_size) + { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) + { + // Copy the src bytes to the destination. + memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; + } + } + } + } + + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), + value_to_write); +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + if (!reg_info) + return false; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsFPR(reg)) + { + if (!ReadFPR()) + return false; + } + else + { + uint32_t full_reg = reg; + bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); + + if (is_subreg) + { + // Read the full aligned 64-bit register. + full_reg = reg_info->invalidate_regs[0]; + } + + bool success = ReadRegister(full_reg, value); + + if (success) + { + // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. + if (is_subreg && (reg_info->byte_offset & 0x1)) + value.SetUInt64(value.GetAsUInt64() >> 8); + + // If our return byte size was greater than the return value reg size, then + // use the type specified by reg_info rather than the uint64_t default + if (value.GetByteSize() > reg_info->byte_size) + value.SetType(reg_info); + } + return success; + } + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsGPR(reg)) + return WriteRegister(reg, value); + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::ReadAllRegisterValues(DataBufferSP &data_sp) +{ + bool success = false; + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR () && ReadFPR ()) + { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) + { + ::memcpy (dst, &m_gpr_mips64, GetGPRSize()); + dst += GetGPRSize(); + } + } + return success; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::WriteAllRegisterValues(const DataBufferSP &data_sp) +{ + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + uint8_t *src = data_sp->GetBytes(); + if (src) + { + ::memcpy (&m_gpr_mips64, src, GetGPRSize()); + + if (WriteGPR()) + { + src += GetGPRSize(); + } + } + } + return success; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpoint(addr_t addr, size_t size, + bool read, bool write) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; + + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) + { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, + read, write, + hw_index); + } + + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::ClearHardwareWatchpoint(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::HardwareSingleStep(bool enable) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::UpdateAfterBreakpoint() +{ + // PC points one byte past the int3 responsible for the breakpoint. + lldb::addr_t pc; + + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; + + SetPC(pc - 1); + return true; +} + +unsigned +RegisterContextPOSIXProcessMonitor_mips64::GetRegisterIndexFromOffset(unsigned offset) +{ + unsigned reg; + for (reg = 0; reg < k_num_registers_mips64; reg++) + { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < k_num_registers_mips64 && "Invalid register offset."); + return reg; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointHit(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::ClearWatchpointHits() +{ + return false; +} + +addr_t +RegisterContextPOSIXProcessMonitor_mips64::GetWatchpointAddress(uint32_t hw_index) +{ + return LLDB_INVALID_ADDRESS; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointVacant(uint32_t hw_index) +{ + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, + bool read, bool write, + uint32_t hw_index) +{ + return false; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_mips64::NumSupportedHardwareWatchpoints() +{ + return 0; +} + diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h new file mode 100644 index 000000000000..8f545eef0d5e --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_mips64.h @@ -0,0 +1,95 @@ +//===-- RegisterContextPOSIXProcessMonitor_mips64.h -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_ +#define liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_ + +#include "Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h" + +class RegisterContextPOSIXProcessMonitor_mips64: + public RegisterContextPOSIX_mips64, + public POSIXBreakpointProtocol +{ +public: + RegisterContextPOSIXProcessMonitor_mips64(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + RegisterInfoInterface *register_info); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + + // lldb_private::RegisterContext + bool + ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + + bool + WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + + bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + uint32_t + SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + + bool + ClearHardwareWatchpoint(uint32_t hw_index); + + bool + HardwareSingleStep(bool enable); + + // POSIXBreakpointProtocol + bool + UpdateAfterBreakpoint(); + + unsigned + GetRegisterIndexFromOffset(unsigned offset); + + bool + IsWatchpointHit(uint32_t hw_index); + + bool + ClearWatchpointHits(); + + lldb::addr_t + GetWatchpointAddress(uint32_t hw_index); + + bool + IsWatchpointVacant(uint32_t hw_index); + + bool + SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + + uint32_t + NumSupportedHardwareWatchpoints(); + +private: + ProcessMonitor & + GetMonitor(); +}; + +#endif diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp new file mode 100644 index 000000000000..98e0bce68678 --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp @@ -0,0 +1,634 @@ +//===-- RegisterContextPOSIXProcessMonitor_x86.h ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#include "lldb/Target/Thread.h" +#include "lldb/Core/RegisterValue.h" + +#include "ProcessPOSIX.h" +#include "RegisterContextPOSIXProcessMonitor_x86.h" +#include "ProcessMonitor.h" + +using namespace lldb_private; +using namespace lldb; + +// Support ptrace extensions even when compiled without required kernel support +#ifndef NT_X86_XSTATE + #define NT_X86_XSTATE 0x202 +#endif + +#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(FPR)) + +static uint32_t +size_and_rw_bits(size_t size, bool read, bool write) +{ + uint32_t rw; + + if (read) + rw = 0x3; // READ or READ/WRITE + else if (write) + rw = 0x1; // WRITE + else + assert(0 && "read and write cannot both be false"); + + switch (size) + { + case 1: + return rw; + case 2: + return (0x1 << 2) | rw; + case 4: + return (0x3 << 2) | rw; + case 8: + return (0x2 << 2) | rw; + default: + assert(0 && "invalid size, must be one of 1, 2, 4, or 8"); + } +} + +RegisterContextPOSIXProcessMonitor_x86_64::RegisterContextPOSIXProcessMonitor_x86_64(Thread &thread, + uint32_t concrete_frame_idx, + RegisterInfoInterface *register_info) + : RegisterContextPOSIX_x86(thread, concrete_frame_idx, register_info) +{ +} + +ProcessMonitor & +RegisterContextPOSIXProcessMonitor_x86_64::GetMonitor() +{ + ProcessSP base = CalculateProcess(); + ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get()); + return process->GetMonitor(); +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::ReadGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::ReadFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + if (GetFPRType() == eFXSAVE) + return monitor.ReadFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); + + if (GetFPRType() == eXSAVE) + return monitor.ReadRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE); + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::WriteGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize()); +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::WriteFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + if (GetFPRType() == eFXSAVE) + return monitor.WriteFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); + + if (GetFPRType() == eXSAVE) + return monitor.WriteRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE); + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister(const unsigned reg, + RegisterValue &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister(const unsigned reg, + const RegisterValue &value) +{ + unsigned reg_to_write = reg; + RegisterValue value_to_write = value; + + // Check if this is a subregister of a full register. + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) + { + RegisterValue full_value; + uint32_t full_reg = reg_info->invalidate_regs[0]; + const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); + + // Read the full register. + if (ReadRegister(full_reg_info, full_value)) + { + Error error; + ByteOrder byte_order = GetByteOrder(); + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the full register. + const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, + dst, + sizeof(dst), + byte_order, + error); + if (error.Success() && dest_size) + { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Get the bytes for the source data. + const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); + if (error.Success() && src_size && (src_size < dest_size)) + { + // Copy the src bytes to the destination. + memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); + // Set this full register as the value to write. + value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); + value_to_write.SetType(full_reg_info); + reg_to_write = full_reg; + } + } + } + } + + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), + value_to_write); +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + if (!reg_info) + return false; + + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsFPR(reg, GetFPRType())) + { + if (!ReadFPR()) + return false; + } + else + { + uint32_t full_reg = reg; + bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); + + if (is_subreg) + { + // Read the full aligned 64-bit register. + full_reg = reg_info->invalidate_regs[0]; + } + + bool success = ReadRegister(full_reg, value); + + if (success) + { + // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. + if (is_subreg && (reg_info->byte_offset & 0x1)) + value.SetUInt64(value.GetAsUInt64() >> 8); + + // If our return byte size was greater than the return value reg size, then + // use the type specified by reg_info rather than the uint64_t default + if (value.GetByteSize() > reg_info->byte_size) + value.SetType(reg_info); + } + return success; + } + + if (reg_info->encoding == eEncodingVector) + { + ByteOrder byte_order = GetByteOrder(); + + if (byte_order != ByteOrder::eByteOrderInvalid) + { + if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st) + value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, reg_info->byte_size, byte_order); + if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm) + value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, reg_info->byte_size, byte_order); + if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm) + value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, reg_info->byte_size, byte_order); + if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) + { + // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes + if (GetFPRType() == eXSAVE && CopyXSTATEtoYMM(reg, byte_order)) + value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, reg_info->byte_size, byte_order); + else + return false; + } + return value.GetType() == RegisterValue::eTypeBytes; + } + return false; + } + + // Get pointer to m_fpr.xstate.fxsave variable and set the data from it. + assert (reg_info->byte_offset < sizeof(m_fpr)); + uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; + switch (reg_info->byte_size) + { + case 2: + value.SetUInt16(*(uint16_t *)src); + return true; + case 4: + value.SetUInt32(*(uint32_t *)src); + return true; + case 8: + value.SetUInt64(*(uint64_t *)src); + return true; + default: + assert(false && "Unhandled data size."); + return false; + } +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + + if (IsGPR(reg)) + return WriteRegister(reg, value); + + if (IsFPR(reg, GetFPRType())) + { + if (reg_info->encoding == eEncodingVector) + { + if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st) + ::memcpy (m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, value.GetBytes(), value.GetByteSize()); + + if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm) + ::memcpy (m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, value.GetBytes(), value.GetByteSize()); + + if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm) + ::memcpy (m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, value.GetBytes(), value.GetByteSize()); + + if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) + { + if (GetFPRType() != eXSAVE) + return false; // the target processor does not support AVX + + // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes + ::memcpy (m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, value.GetBytes(), value.GetByteSize()); + if (false == CopyYMMtoXSTATE(reg, GetByteOrder())) + return false; + } + } + else + { + // Get pointer to m_fpr.xstate.fxsave variable and set the data to it. + assert (reg_info->byte_offset < sizeof(m_fpr)); + uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset; + switch (reg_info->byte_size) + { + case 2: + *(uint16_t *)dst = value.GetAsUInt16(); + break; + case 4: + *(uint32_t *)dst = value.GetAsUInt32(); + break; + case 8: + *(uint64_t *)dst = value.GetAsUInt64(); + break; + default: + assert(false && "Unhandled data size."); + return false; + } + } + + if (WriteFPR()) + { + if (IsAVX(reg)) + return CopyYMMtoXSTATE(reg, GetByteOrder()); + return true; + } + } + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::ReadAllRegisterValues(DataBufferSP &data_sp) +{ + bool success = false; + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (data_sp && ReadGPR () && ReadFPR ()) + { + uint8_t *dst = data_sp->GetBytes(); + success = dst != 0; + + if (success) + { + ::memcpy (dst, &m_gpr_x86_64, GetGPRSize()); + dst += GetGPRSize(); + } + if (GetFPRType() == eFXSAVE) + ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); + + if (GetFPRType() == eXSAVE) + { + ByteOrder byte_order = GetByteOrder(); + + // Assemble the YMM register content from the register halves. + for (uint32_t reg = m_reg_info.first_ymm; success && reg <= m_reg_info.last_ymm; ++reg) + success = CopyXSTATEtoYMM(reg, byte_order); + + if (success) + { + // Copy the extended register state including the assembled ymm registers. + ::memcpy (dst, &m_fpr, sizeof(m_fpr)); + } + } + } + return success; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::WriteAllRegisterValues(const DataBufferSP &data_sp) +{ + bool success = false; + if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) + { + uint8_t *src = data_sp->GetBytes(); + if (src) + { + ::memcpy (&m_gpr_x86_64, src, GetGPRSize()); + + if (WriteGPR()) + { + src += GetGPRSize(); + if (GetFPRType() == eFXSAVE) + ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave)); + if (GetFPRType() == eXSAVE) + ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave)); + + success = WriteFPR(); + if (success) + { + success = true; + + if (GetFPRType() == eXSAVE) + { + ByteOrder byte_order = GetByteOrder(); + + // Parse the YMM register content from the register halves. + for (uint32_t reg = m_reg_info.first_ymm; success && reg <= m_reg_info.last_ymm; ++reg) + success = CopyYMMtoXSTATE(reg, byte_order); + } + } + } + } + } + return success; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_x86_64::SetHardwareWatchpoint(addr_t addr, size_t size, + bool read, bool write) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + uint32_t hw_index; + + for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) + { + if (IsWatchpointVacant(hw_index)) + return SetHardwareWatchpointWithIndex(addr, size, + read, write, + hw_index); + } + + return LLDB_INVALID_INDEX32; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::ClearHardwareWatchpoint(uint32_t hw_index) +{ + if (hw_index < NumSupportedHardwareWatchpoints()) + { + RegisterValue current_dr7_bits; + + if (ReadRegister(m_reg_info.first_dr + 7, current_dr7_bits)) + { + uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() & ~(3 << (2*hw_index)); + + if (WriteRegister(m_reg_info.first_dr + 7, RegisterValue(new_dr7_bits))) + return true; + } + } + + return false; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::HardwareSingleStep(bool enable) +{ + enum { TRACE_BIT = 0x100 }; + uint64_t rflags; + + if ((rflags = ReadRegisterAsUnsigned(m_reg_info.gpr_flags, -1UL)) == -1UL) + return false; + + if (enable) + { + if (rflags & TRACE_BIT) + return true; + + rflags |= TRACE_BIT; + } + else + { + if (!(rflags & TRACE_BIT)) + return false; + + rflags &= ~TRACE_BIT; + } + + return WriteRegisterFromUnsigned(m_reg_info.gpr_flags, rflags); +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::UpdateAfterBreakpoint() +{ + // PC points one byte past the int3 responsible for the breakpoint. + lldb::addr_t pc; + + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; + + SetPC(pc - 1); + return true; +} + +unsigned +RegisterContextPOSIXProcessMonitor_x86_64::GetRegisterIndexFromOffset(unsigned offset) +{ + unsigned reg; + for (reg = 0; reg < m_reg_info.num_registers; reg++) + { + if (GetRegisterInfo()[reg].byte_offset == offset) + break; + } + assert(reg < m_reg_info.num_registers && "Invalid register offset."); + return reg; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::IsWatchpointHit(uint32_t hw_index) +{ + bool is_hit = false; + + if (m_watchpoints_initialized == false) + { + // Reset the debug status and debug control registers + RegisterValue zero_bits = RegisterValue(uint64_t(0)); + if (!WriteRegister(m_reg_info.first_dr + 6, zero_bits) || !WriteRegister(m_reg_info.first_dr + 7, zero_bits)) + assert(false && "Could not initialize watchpoint registers"); + m_watchpoints_initialized = true; + } + + if (hw_index < NumSupportedHardwareWatchpoints()) + { + RegisterValue value; + + if (ReadRegister(m_reg_info.first_dr + 6, value)) + { + uint64_t val = value.GetAsUInt64(); + is_hit = val & (1 << hw_index); + } + } + + return is_hit; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::ClearWatchpointHits() +{ + return WriteRegister(m_reg_info.first_dr + 6, RegisterValue((uint64_t)0)); +} + +addr_t +RegisterContextPOSIXProcessMonitor_x86_64::GetWatchpointAddress(uint32_t hw_index) +{ + addr_t wp_monitor_addr = LLDB_INVALID_ADDRESS; + + if (hw_index < NumSupportedHardwareWatchpoints()) + { + if (!IsWatchpointVacant(hw_index)) + { + RegisterValue value; + + if (ReadRegister(m_reg_info.first_dr + hw_index, value)) + wp_monitor_addr = value.GetAsUInt64(); + } + } + + return wp_monitor_addr; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::IsWatchpointVacant(uint32_t hw_index) +{ + bool is_vacant = false; + RegisterValue value; + + assert(hw_index < NumSupportedHardwareWatchpoints()); + + if (m_watchpoints_initialized == false) + { + // Reset the debug status and debug control registers + RegisterValue zero_bits = RegisterValue(uint64_t(0)); + if (!WriteRegister(m_reg_info.first_dr + 6, zero_bits) || !WriteRegister(m_reg_info.first_dr + 7, zero_bits)) + assert(false && "Could not initialize watchpoint registers"); + m_watchpoints_initialized = true; + } + + if (ReadRegister(m_reg_info.first_dr + 7, value)) + { + uint64_t val = value.GetAsUInt64(); + is_vacant = (val & (3 << 2*hw_index)) == 0; + } + + return is_vacant; +} + +bool +RegisterContextPOSIXProcessMonitor_x86_64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, + bool read, bool write, + uint32_t hw_index) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + + if (num_hw_watchpoints == 0 || hw_index >= num_hw_watchpoints) + return false; + + if (!(size == 1 || size == 2 || size == 4 || size == 8)) + return false; + + if (read == false && write == false) + return false; + + if (!IsWatchpointVacant(hw_index)) + return false; + + // Set both dr7 (debug control register) and dri (debug address register). + + // dr7{7-0} encodes the local/global enable bits: + // global enable --. .-- local enable + // | | + // v v + // dr0 -> bits{1-0} + // dr1 -> bits{3-2} + // dr2 -> bits{5-4} + // dr3 -> bits{7-6} + // + // dr7{31-16} encodes the rw/len bits: + // b_x+3, b_x+2, b_x+1, b_x + // where bits{x+1, x} => rw + // 0b00: execute, 0b01: write, 0b11: read-or-write, + // 0b10: io read-or-write (unused) + // and bits{x+3, x+2} => len + // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte + // + // dr0 -> bits{19-16} + // dr1 -> bits{23-20} + // dr2 -> bits{27-24} + // dr3 -> bits{31-28} + if (hw_index < num_hw_watchpoints) + { + RegisterValue current_dr7_bits; + + if (ReadRegister(m_reg_info.first_dr + 7, current_dr7_bits)) + { + uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() | + (1 << (2*hw_index) | + size_and_rw_bits(size, read, write) << + (16+4*hw_index)); + + if (WriteRegister(m_reg_info.first_dr + hw_index, RegisterValue(addr)) && + WriteRegister(m_reg_info.first_dr + 7, RegisterValue(new_dr7_bits))) + return true; + } + } + + return false; +} + +uint32_t +RegisterContextPOSIXProcessMonitor_x86_64::NumSupportedHardwareWatchpoints() +{ + // Available debug address registers: dr0, dr1, dr2, dr3 + return 4; +} + diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h new file mode 100644 index 000000000000..2b64fa8003a2 --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.h @@ -0,0 +1,95 @@ +//===-- RegisterContextPOSIXProcessMonitor_x86.h ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIXProcessMonitor_x86_H_ +#define liblldb_RegisterContextPOSIXProcessMonitor_x86_H_ + +#include "Plugins/Process/POSIX/RegisterContextPOSIX_x86.h" + +class RegisterContextPOSIXProcessMonitor_x86_64: + public RegisterContextPOSIX_x86, + public POSIXBreakpointProtocol +{ +public: + RegisterContextPOSIXProcessMonitor_x86_64(lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + RegisterInfoInterface *register_info); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + + // lldb_private::RegisterContext + bool + ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); + + bool + WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); + + bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + uint32_t + SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write); + + bool + ClearHardwareWatchpoint(uint32_t hw_index); + + bool + HardwareSingleStep(bool enable); + + // POSIXBreakpointProtocol + bool + UpdateAfterBreakpoint(); + + unsigned + GetRegisterIndexFromOffset(unsigned offset); + + bool + IsWatchpointHit(uint32_t hw_index); + + bool + ClearWatchpointHits(); + + lldb::addr_t + GetWatchpointAddress(uint32_t hw_index); + + bool + IsWatchpointVacant(uint32_t hw_index); + + bool + SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index); + + uint32_t + NumSupportedHardwareWatchpoints(); + +private: + ProcessMonitor & + GetMonitor(); +}; + +#endif diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.cpp new file mode 100644 index 000000000000..45c99aec1657 --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.cpp @@ -0,0 +1,238 @@ +//===-- RegisterContextPOSIX_mips64.cpp -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <cstring> +#include <errno.h> +#include <stdint.h> + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Host/Endian.h" +#include "llvm/Support/Compiler.h" + +#include "ProcessPOSIX.h" +#include "RegisterContextPOSIX_mips64.h" +#include "Plugins/Process/elf-core/ProcessElfCore.h" + +using namespace lldb_private; +using namespace lldb; + +static const +uint32_t g_gpr_regnums[] = +{ + gpr_zero_mips64, + gpr_r1_mips64, + gpr_r2_mips64, + gpr_r3_mips64, + gpr_r4_mips64, + gpr_r5_mips64, + gpr_r6_mips64, + gpr_r7_mips64, + gpr_r8_mips64, + gpr_r9_mips64, + gpr_r10_mips64, + gpr_r11_mips64, + gpr_r12_mips64, + gpr_r13_mips64, + gpr_r14_mips64, + gpr_r15_mips64, + gpr_r16_mips64, + gpr_r17_mips64, + gpr_r18_mips64, + gpr_r19_mips64, + gpr_r20_mips64, + gpr_r21_mips64, + gpr_r22_mips64, + gpr_r23_mips64, + gpr_r24_mips64, + gpr_r25_mips64, + gpr_r26_mips64, + gpr_r27_mips64, + gpr_gp_mips64, + gpr_sp_mips64, + gpr_r30_mips64, + gpr_ra_mips64, + gpr_sr_mips64, + gpr_mullo_mips64, + gpr_mulhi_mips64, + gpr_badvaddr_mips64, + gpr_cause_mips64, + gpr_pc_mips64, + gpr_ic_mips64, + gpr_dummy_mips64 +}; + +// Number of register sets provided by this context. +enum +{ + k_num_register_sets = 1 +}; + +static const RegisterSet +g_reg_sets_mips64[k_num_register_sets] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers_mips64, g_gpr_regnums }, +}; + +bool RegisterContextPOSIX_mips64::IsGPR(unsigned reg) +{ + return reg <= k_num_gpr_registers_mips64; // GPR's come first. +} + +bool +RegisterContextPOSIX_mips64::IsFPR(unsigned reg) +{ + // XXX + return false; +} + +RegisterContextPOSIX_mips64::RegisterContextPOSIX_mips64(Thread &thread, + uint32_t concrete_frame_idx, + RegisterInfoInterface *register_info) + : RegisterContext(thread, concrete_frame_idx) +{ + m_register_info_ap.reset(register_info); + + // elf-core yet to support ReadFPR() + ProcessSP base = CalculateProcess(); + if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic()) + return; +} + +RegisterContextPOSIX_mips64::~RegisterContextPOSIX_mips64() +{ +} + +void +RegisterContextPOSIX_mips64::Invalidate() +{ +} + +void +RegisterContextPOSIX_mips64::InvalidateAllRegisters() +{ +} + +unsigned +RegisterContextPOSIX_mips64::GetRegisterOffset(unsigned reg) +{ + assert(reg < k_num_registers_mips64 && "Invalid register number."); + return GetRegisterInfo()[reg].byte_offset; +} + +unsigned +RegisterContextPOSIX_mips64::GetRegisterSize(unsigned reg) +{ + assert(reg < k_num_registers_mips64 && "Invalid register number."); + return GetRegisterInfo()[reg].byte_size; +} + +size_t +RegisterContextPOSIX_mips64::GetRegisterCount() +{ + size_t num_registers = k_num_registers_mips64; + return num_registers; +} + +size_t +RegisterContextPOSIX_mips64::GetGPRSize() +{ + return m_register_info_ap->GetGPRSize(); +} + +const RegisterInfo * +RegisterContextPOSIX_mips64::GetRegisterInfo() +{ + // Commonly, this method is overridden and g_register_infos is copied and specialized. + // So, use GetRegisterInfo() rather than g_register_infos in this scope. + return m_register_info_ap->GetRegisterInfo (); +} + +const RegisterInfo * +RegisterContextPOSIX_mips64::GetRegisterInfoAtIndex(size_t reg) +{ + if (reg < k_num_registers_mips64) + return &GetRegisterInfo()[reg]; + else + return NULL; +} + +size_t +RegisterContextPOSIX_mips64::GetRegisterSetCount() +{ + size_t sets = 0; + for (size_t set = 0; set < k_num_register_sets; ++set) + { + if (IsRegisterSetAvailable(set)) + ++sets; + } + + return sets; +} + +const RegisterSet * +RegisterContextPOSIX_mips64::GetRegisterSet(size_t set) +{ + if (IsRegisterSetAvailable(set)) + return &g_reg_sets_mips64[set]; + else + return NULL; +} + +const char * +RegisterContextPOSIX_mips64::GetRegisterName(unsigned reg) +{ + assert(reg < k_num_registers_mips64 && "Invalid register offset."); + return GetRegisterInfo()[reg].name; +} + +lldb::ByteOrder +RegisterContextPOSIX_mips64::GetByteOrder() +{ + // Get the target process whose privileged thread was used for the register read. + lldb::ByteOrder byte_order = eByteOrderInvalid; + Process *process = CalculateProcess().get(); + + if (process) + byte_order = process->GetByteOrder(); + return byte_order; +} + +bool +RegisterContextPOSIX_mips64::IsRegisterSetAvailable(size_t set_index) +{ + size_t num_sets = k_num_register_sets; + + return (set_index < num_sets); +} + +// Used when parsing DWARF and EH frame information and any other +// object file sections that contain register numbers in them. +uint32_t +RegisterContextPOSIX_mips64::ConvertRegisterKindToRegisterNumber(uint32_t kind, + uint32_t num) +{ + 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; +} + diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h b/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h new file mode 100644 index 000000000000..a2a7d1f45271 --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h @@ -0,0 +1,138 @@ +//===-- RegisterContextPOSIX_mips64.h ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIX_mips64_H_ +#define liblldb_RegisterContextPOSIX_mips64_H_ + +#include "lldb/Core/Log.h" +#include "RegisterContextPOSIX.h" +#include "RegisterContext_mips64.h" + +class ProcessMonitor; + +// --------------------------------------------------------------------------- +// Internal codes for all mips64 registers. +// --------------------------------------------------------------------------- +enum +{ + k_first_gpr_mips64, + gpr_zero_mips64 = k_first_gpr_mips64, + gpr_r1_mips64, + gpr_r2_mips64, + gpr_r3_mips64, + gpr_r4_mips64, + gpr_r5_mips64, + gpr_r6_mips64, + gpr_r7_mips64, + gpr_r8_mips64, + gpr_r9_mips64, + gpr_r10_mips64, + gpr_r11_mips64, + gpr_r12_mips64, + gpr_r13_mips64, + gpr_r14_mips64, + gpr_r15_mips64, + gpr_r16_mips64, + gpr_r17_mips64, + gpr_r18_mips64, + gpr_r19_mips64, + gpr_r20_mips64, + gpr_r21_mips64, + gpr_r22_mips64, + gpr_r23_mips64, + gpr_r24_mips64, + gpr_r25_mips64, + gpr_r26_mips64, + gpr_r27_mips64, + gpr_gp_mips64, + gpr_sp_mips64, + gpr_r30_mips64, + gpr_ra_mips64, + gpr_sr_mips64, + gpr_mullo_mips64, + gpr_mulhi_mips64, + gpr_badvaddr_mips64, + gpr_cause_mips64, + gpr_pc_mips64, + gpr_ic_mips64, + gpr_dummy_mips64, + + k_num_registers_mips64, + k_num_gpr_registers_mips64 = k_num_registers_mips64 +}; + +class RegisterContextPOSIX_mips64 + : public lldb_private::RegisterContext +{ +public: + RegisterContextPOSIX_mips64 (lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + RegisterInfoInterface *register_info); + + ~RegisterContextPOSIX_mips64(); + + void + Invalidate(); + + void + InvalidateAllRegisters(); + + size_t + GetRegisterCount(); + + virtual size_t + GetGPRSize(); + + virtual unsigned + GetRegisterSize(unsigned reg); + + virtual unsigned + GetRegisterOffset(unsigned reg); + + const lldb_private::RegisterInfo * + GetRegisterInfoAtIndex(size_t reg); + + size_t + GetRegisterSetCount(); + + const lldb_private::RegisterSet * + GetRegisterSet(size_t set); + + const char * + GetRegisterName(unsigned reg); + + uint32_t + ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num); + +protected: + uint64_t m_gpr_mips64[k_num_gpr_registers_mips64]; // general purpose registers. + std::unique_ptr<RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux) + + // Determines if an extended register set is supported on the processor running the inferior process. + virtual bool + IsRegisterSetAvailable(size_t set_index); + + virtual const lldb_private::RegisterInfo * + GetRegisterInfo(); + + bool + IsGPR(unsigned reg); + + bool + IsFPR(unsigned reg); + + lldb::ByteOrder GetByteOrder(); + + virtual bool ReadGPR() = 0; + virtual bool ReadFPR() = 0; + virtual bool WriteGPR() = 0; + virtual bool WriteFPR() = 0; +}; + +#endif // #ifndef liblldb_RegisterContextPOSIX_mips64_H_ diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.cpp new file mode 100644 index 000000000000..9ae541a6309b --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.cpp @@ -0,0 +1,666 @@ +//===-- RegisterContextPOSIX_x86.cpp ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <cstring> +#include <errno.h> +#include <stdint.h> + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Host/Endian.h" +#include "llvm/Support/Compiler.h" + +#include "ProcessPOSIX.h" +#include "RegisterContext_x86.h" +#include "RegisterContextPOSIX_x86.h" +#include "Plugins/Process/elf-core/ProcessElfCore.h" + +using namespace lldb_private; +using namespace lldb; + +const uint32_t +g_gpr_regnums_i386[] = +{ + gpr_eax_i386, + gpr_ebx_i386, + gpr_ecx_i386, + gpr_edx_i386, + gpr_edi_i386, + gpr_esi_i386, + gpr_ebp_i386, + gpr_esp_i386, + gpr_eip_i386, + gpr_eflags_i386, + gpr_cs_i386, + gpr_fs_i386, + gpr_gs_i386, + gpr_ss_i386, + gpr_ds_i386, + gpr_es_i386, + gpr_ax_i386, + gpr_bx_i386, + gpr_cx_i386, + gpr_dx_i386, + gpr_di_i386, + gpr_si_i386, + gpr_bp_i386, + gpr_sp_i386, + gpr_ah_i386, + gpr_bh_i386, + gpr_ch_i386, + gpr_dh_i386, + gpr_al_i386, + gpr_bl_i386, + gpr_cl_i386, + gpr_dl_i386 +}; +static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) == k_num_gpr_registers_i386, + "g_gpr_regnums_i386 has wrong number of register infos"); + +const uint32_t +g_fpu_regnums_i386[] = +{ + fpu_fctrl_i386, + fpu_fstat_i386, + fpu_ftag_i386, + fpu_fop_i386, + fpu_fiseg_i386, + fpu_fioff_i386, + fpu_foseg_i386, + fpu_fooff_i386, + fpu_mxcsr_i386, + fpu_mxcsrmask_i386, + fpu_st0_i386, + fpu_st1_i386, + fpu_st2_i386, + fpu_st3_i386, + fpu_st4_i386, + fpu_st5_i386, + fpu_st6_i386, + fpu_st7_i386, + fpu_mm0_i386, + fpu_mm1_i386, + fpu_mm2_i386, + fpu_mm3_i386, + fpu_mm4_i386, + fpu_mm5_i386, + fpu_mm6_i386, + fpu_mm7_i386, + fpu_xmm0_i386, + fpu_xmm1_i386, + fpu_xmm2_i386, + fpu_xmm3_i386, + fpu_xmm4_i386, + fpu_xmm5_i386, + fpu_xmm6_i386, + fpu_xmm7_i386 +}; +static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) == k_num_fpr_registers_i386, + "g_fpu_regnums_i386 has wrong number of register infos"); + +const uint32_t +g_avx_regnums_i386[] = +{ + fpu_ymm0_i386, + fpu_ymm1_i386, + fpu_ymm2_i386, + fpu_ymm3_i386, + fpu_ymm4_i386, + fpu_ymm5_i386, + fpu_ymm6_i386, + fpu_ymm7_i386 +}; +static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) == k_num_avx_registers_i386, + " g_avx_regnums_i386 has wrong number of register infos"); + +static const +uint32_t g_gpr_regnums_x86_64[] = +{ + gpr_rax_x86_64, + gpr_rbx_x86_64, + gpr_rcx_x86_64, + gpr_rdx_x86_64, + gpr_rdi_x86_64, + gpr_rsi_x86_64, + gpr_rbp_x86_64, + gpr_rsp_x86_64, + gpr_r8_x86_64, + gpr_r9_x86_64, + gpr_r10_x86_64, + gpr_r11_x86_64, + gpr_r12_x86_64, + gpr_r13_x86_64, + gpr_r14_x86_64, + gpr_r15_x86_64, + gpr_rip_x86_64, + gpr_rflags_x86_64, + gpr_cs_x86_64, + gpr_fs_x86_64, + gpr_gs_x86_64, + gpr_ss_x86_64, + gpr_ds_x86_64, + gpr_es_x86_64, + gpr_eax_x86_64, + gpr_ebx_x86_64, + gpr_ecx_x86_64, + gpr_edx_x86_64, + gpr_edi_x86_64, + gpr_esi_x86_64, + gpr_ebp_x86_64, + gpr_esp_x86_64, + gpr_r8d_x86_64, // Low 32 bits or r8 + gpr_r9d_x86_64, // Low 32 bits or r9 + gpr_r10d_x86_64, // Low 32 bits or r10 + gpr_r11d_x86_64, // Low 32 bits or r11 + gpr_r12d_x86_64, // Low 32 bits or r12 + gpr_r13d_x86_64, // Low 32 bits or r13 + gpr_r14d_x86_64, // Low 32 bits or r14 + gpr_r15d_x86_64, // Low 32 bits or r15 + gpr_ax_x86_64, + gpr_bx_x86_64, + gpr_cx_x86_64, + gpr_dx_x86_64, + gpr_di_x86_64, + gpr_si_x86_64, + gpr_bp_x86_64, + gpr_sp_x86_64, + gpr_r8w_x86_64, // Low 16 bits or r8 + gpr_r9w_x86_64, // Low 16 bits or r9 + gpr_r10w_x86_64, // Low 16 bits or r10 + gpr_r11w_x86_64, // Low 16 bits or r11 + gpr_r12w_x86_64, // Low 16 bits or r12 + gpr_r13w_x86_64, // Low 16 bits or r13 + gpr_r14w_x86_64, // Low 16 bits or r14 + gpr_r15w_x86_64, // Low 16 bits or r15 + gpr_ah_x86_64, + gpr_bh_x86_64, + gpr_ch_x86_64, + gpr_dh_x86_64, + gpr_al_x86_64, + gpr_bl_x86_64, + gpr_cl_x86_64, + gpr_dl_x86_64, + gpr_dil_x86_64, + gpr_sil_x86_64, + gpr_bpl_x86_64, + gpr_spl_x86_64, + gpr_r8l_x86_64, // Low 8 bits or r8 + gpr_r9l_x86_64, // Low 8 bits or r9 + gpr_r10l_x86_64, // Low 8 bits or r10 + gpr_r11l_x86_64, // Low 8 bits or r11 + gpr_r12l_x86_64, // Low 8 bits or r12 + gpr_r13l_x86_64, // Low 8 bits or r13 + gpr_r14l_x86_64, // Low 8 bits or r14 + gpr_r15l_x86_64, // Low 8 bits or r15 +}; +static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) == k_num_gpr_registers_x86_64, + "g_gpr_regnums_x86_64 has wrong number of register infos"); + +static const uint32_t +g_fpu_regnums_x86_64[] = +{ + fpu_fctrl_x86_64, + fpu_fstat_x86_64, + fpu_ftag_x86_64, + fpu_fop_x86_64, + fpu_fiseg_x86_64, + fpu_fioff_x86_64, + fpu_foseg_x86_64, + fpu_fooff_x86_64, + fpu_mxcsr_x86_64, + fpu_mxcsrmask_x86_64, + fpu_st0_x86_64, + fpu_st1_x86_64, + fpu_st2_x86_64, + fpu_st3_x86_64, + fpu_st4_x86_64, + fpu_st5_x86_64, + fpu_st6_x86_64, + fpu_st7_x86_64, + fpu_mm0_x86_64, + fpu_mm1_x86_64, + fpu_mm2_x86_64, + fpu_mm3_x86_64, + fpu_mm4_x86_64, + fpu_mm5_x86_64, + fpu_mm6_x86_64, + fpu_mm7_x86_64, + fpu_xmm0_x86_64, + fpu_xmm1_x86_64, + fpu_xmm2_x86_64, + fpu_xmm3_x86_64, + fpu_xmm4_x86_64, + fpu_xmm5_x86_64, + fpu_xmm6_x86_64, + fpu_xmm7_x86_64, + fpu_xmm8_x86_64, + fpu_xmm9_x86_64, + fpu_xmm10_x86_64, + fpu_xmm11_x86_64, + fpu_xmm12_x86_64, + fpu_xmm13_x86_64, + fpu_xmm14_x86_64, + fpu_xmm15_x86_64 +}; +static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) == k_num_fpr_registers_x86_64, + "g_fpu_regnums_x86_64 has wrong number of register infos"); + +static const uint32_t +g_avx_regnums_x86_64[] = +{ + fpu_ymm0_x86_64, + fpu_ymm1_x86_64, + fpu_ymm2_x86_64, + fpu_ymm3_x86_64, + fpu_ymm4_x86_64, + fpu_ymm5_x86_64, + fpu_ymm6_x86_64, + fpu_ymm7_x86_64, + fpu_ymm8_x86_64, + fpu_ymm9_x86_64, + fpu_ymm10_x86_64, + fpu_ymm11_x86_64, + fpu_ymm12_x86_64, + fpu_ymm13_x86_64, + fpu_ymm14_x86_64, + fpu_ymm15_x86_64 +}; +static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) == k_num_avx_registers_x86_64, + "g_avx_regnums_x86_64 has wrong number of register infos"); + +uint32_t RegisterContextPOSIX_x86::g_contained_eax[] = { gpr_eax_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_ebx[] = { gpr_ebx_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_ecx[] = { gpr_ecx_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_edx[] = { gpr_edx_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_edi[] = { gpr_edi_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_esi[] = { gpr_esi_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_ebp[] = { gpr_ebp_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_esp[] = { gpr_esp_i386, LLDB_INVALID_REGNUM }; + +uint32_t RegisterContextPOSIX_x86::g_invalidate_eax[] = { gpr_eax_i386, gpr_ax_i386, gpr_ah_i386, gpr_al_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_ebx[] = { gpr_ebx_i386, gpr_bx_i386, gpr_bh_i386, gpr_bl_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_ecx[] = { gpr_ecx_i386, gpr_cx_i386, gpr_ch_i386, gpr_cl_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_edx[] = { gpr_edx_i386, gpr_dx_i386, gpr_dh_i386, gpr_dl_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_edi[] = { gpr_edi_i386, gpr_di_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_esi[] = { gpr_esi_i386, gpr_si_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_ebp[] = { gpr_ebp_i386, gpr_bp_i386, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_esp[] = { gpr_esp_i386, gpr_sp_i386, LLDB_INVALID_REGNUM }; + +uint32_t RegisterContextPOSIX_x86::g_contained_rax[] = { gpr_rax_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_rbx[] = { gpr_rbx_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_rcx[] = { gpr_rcx_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_rdx[] = { gpr_rdx_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_rdi[] = { gpr_rdi_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_rsi[] = { gpr_rsi_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_rbp[] = { gpr_rbp_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_rsp[] = { gpr_rsp_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r8[] = { gpr_r8_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r9[] = { gpr_r9_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r10[] = { gpr_r10_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r11[] = { gpr_r11_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r12[] = { gpr_r12_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r13[] = { gpr_r13_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r14[] = { gpr_r14_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_contained_r15[] = { gpr_r15_x86_64, LLDB_INVALID_REGNUM }; + +uint32_t RegisterContextPOSIX_x86::g_invalidate_rax[] = { gpr_rax_x86_64, gpr_eax_x86_64, gpr_ax_x86_64, gpr_ah_x86_64, gpr_al_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_rbx[] = { gpr_rbx_x86_64, gpr_ebx_x86_64, gpr_bx_x86_64, gpr_bh_x86_64, gpr_bl_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_rcx[] = { gpr_rcx_x86_64, gpr_ecx_x86_64, gpr_cx_x86_64, gpr_ch_x86_64, gpr_cl_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_rdx[] = { gpr_rdx_x86_64, gpr_edx_x86_64, gpr_dx_x86_64, gpr_dh_x86_64, gpr_dl_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_rdi[] = { gpr_rdi_x86_64, gpr_edi_x86_64, gpr_di_x86_64, gpr_dil_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_rsi[] = { gpr_rsi_x86_64, gpr_esi_x86_64, gpr_si_x86_64, gpr_sil_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_rbp[] = { gpr_rbp_x86_64, gpr_ebp_x86_64, gpr_bp_x86_64, gpr_bpl_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_rsp[] = { gpr_rsp_x86_64, gpr_esp_x86_64, gpr_sp_x86_64, gpr_spl_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r8[] = { gpr_r8_x86_64, gpr_r8d_x86_64, gpr_r8w_x86_64, gpr_r8l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r9[] = { gpr_r9_x86_64, gpr_r9d_x86_64, gpr_r9w_x86_64, gpr_r9l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r10[] = { gpr_r10_x86_64, gpr_r10d_x86_64, gpr_r10w_x86_64, gpr_r10l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r11[] = { gpr_r11_x86_64, gpr_r11d_x86_64, gpr_r11w_x86_64, gpr_r11l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r12[] = { gpr_r12_x86_64, gpr_r12d_x86_64, gpr_r12w_x86_64, gpr_r12l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r13[] = { gpr_r13_x86_64, gpr_r13d_x86_64, gpr_r13w_x86_64, gpr_r13l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r14[] = { gpr_r14_x86_64, gpr_r14d_x86_64, gpr_r14w_x86_64, gpr_r14l_x86_64, LLDB_INVALID_REGNUM }; +uint32_t RegisterContextPOSIX_x86::g_invalidate_r15[] = { gpr_r15_x86_64, gpr_r15d_x86_64, gpr_r15w_x86_64, gpr_r15l_x86_64, LLDB_INVALID_REGNUM }; + +// Number of register sets provided by this context. +enum +{ + k_num_extended_register_sets = 1, + k_num_register_sets = 3 +}; + +static const RegisterSet +g_reg_sets_i386[k_num_register_sets] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers_i386, g_gpr_regnums_i386 }, + { "Floating Point Registers", "fpu", k_num_fpr_registers_i386, g_fpu_regnums_i386 }, + { "Advanced Vector Extensions", "avx", k_num_avx_registers_i386, g_avx_regnums_i386 } +}; + +static const RegisterSet +g_reg_sets_x86_64[k_num_register_sets] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers_x86_64, g_gpr_regnums_x86_64 }, + { "Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, g_fpu_regnums_x86_64 }, + { "Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, g_avx_regnums_x86_64 } +}; + +bool RegisterContextPOSIX_x86::IsGPR(unsigned reg) +{ + return reg <= m_reg_info.last_gpr; // GPR's come first. +} + +bool RegisterContextPOSIX_x86::IsFPR(unsigned reg) +{ + return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); +} + +bool RegisterContextPOSIX_x86::IsAVX(unsigned reg) +{ + return (m_reg_info.first_ymm <= reg && reg <= m_reg_info.last_ymm); +} + +bool RegisterContextPOSIX_x86::IsFPR(unsigned reg, FPRType fpr_type) +{ + bool generic_fpr = IsFPR(reg); + + if (fpr_type == eXSAVE) + return generic_fpr || IsAVX(reg); + return generic_fpr; +} + +RegisterContextPOSIX_x86::RegisterContextPOSIX_x86(Thread &thread, + uint32_t concrete_frame_idx, + RegisterInfoInterface *register_info) + : RegisterContext(thread, concrete_frame_idx) +{ + m_register_info_ap.reset(register_info); + + switch (register_info->m_target_arch.GetCore()) + { + case ArchSpec::eCore_x86_32_i386: + case ArchSpec::eCore_x86_32_i486: + case ArchSpec::eCore_x86_32_i486sx: + m_reg_info.num_registers = k_num_registers_i386; + m_reg_info.num_gpr_registers = k_num_gpr_registers_i386; + m_reg_info.num_fpr_registers = k_num_fpr_registers_i386; + m_reg_info.num_avx_registers = k_num_avx_registers_i386; + m_reg_info.last_gpr = k_last_gpr_i386; + m_reg_info.first_fpr = k_first_fpr_i386; + m_reg_info.last_fpr = k_last_fpr_i386; + m_reg_info.first_st = fpu_st0_i386; + m_reg_info.last_st = fpu_st7_i386; + m_reg_info.first_mm = fpu_mm0_i386; + m_reg_info.last_mm = fpu_mm7_i386; + m_reg_info.first_xmm = fpu_xmm0_i386; + m_reg_info.last_xmm = fpu_xmm7_i386; + m_reg_info.first_ymm = fpu_ymm0_i386; + m_reg_info.last_ymm = fpu_ymm7_i386; + m_reg_info.first_dr = dr0_i386; + m_reg_info.gpr_flags = gpr_eflags_i386; + break; + case ArchSpec::eCore_x86_64_x86_64: + m_reg_info.num_registers = k_num_registers_x86_64; + m_reg_info.num_gpr_registers = k_num_gpr_registers_x86_64; + m_reg_info.num_fpr_registers = k_num_fpr_registers_x86_64; + m_reg_info.num_avx_registers = k_num_avx_registers_x86_64; + m_reg_info.last_gpr = k_last_gpr_x86_64; + m_reg_info.first_fpr = k_first_fpr_x86_64; + m_reg_info.last_fpr = k_last_fpr_x86_64; + m_reg_info.first_st = fpu_st0_x86_64; + m_reg_info.last_st = fpu_st7_x86_64; + m_reg_info.first_mm = fpu_mm0_x86_64; + m_reg_info.last_mm = fpu_mm7_x86_64; + m_reg_info.first_xmm = fpu_xmm0_x86_64; + m_reg_info.last_xmm = fpu_xmm15_x86_64; + m_reg_info.first_ymm = fpu_ymm0_x86_64; + m_reg_info.last_ymm = fpu_ymm15_x86_64; + m_reg_info.first_dr = dr0_x86_64; + m_reg_info.gpr_flags = gpr_rflags_x86_64; + break; + default: + assert(false && "Unhandled target architecture."); + break; + } + + // Initialize m_iovec to point to the buffer and buffer size + // using the conventions of Berkeley style UIO structures, as required + // by PTRACE extensions. + m_iovec.iov_base = &m_fpr.xstate.xsave; + m_iovec.iov_len = sizeof(m_fpr.xstate.xsave); + + ::memset(&m_fpr, 0, sizeof(FPR)); + + // elf-core yet to support ReadFPR() + ProcessSP base = CalculateProcess(); + if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic()) + return; + + m_fpr_type = eNotValid; +} + +RegisterContextPOSIX_x86::~RegisterContextPOSIX_x86() +{ +} + +RegisterContextPOSIX_x86::FPRType RegisterContextPOSIX_x86::GetFPRType() +{ + if (m_fpr_type == eNotValid) + { + // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx + m_fpr_type = eXSAVE; // extended floating-point registers, if available + if (false == ReadFPR()) + m_fpr_type = eFXSAVE; // assume generic floating-point registers + } + return m_fpr_type; +} + +void +RegisterContextPOSIX_x86::Invalidate() +{ +} + +void +RegisterContextPOSIX_x86::InvalidateAllRegisters() +{ +} + +unsigned +RegisterContextPOSIX_x86::GetRegisterOffset(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register number."); + return GetRegisterInfo()[reg].byte_offset; +} + +unsigned +RegisterContextPOSIX_x86::GetRegisterSize(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register number."); + return GetRegisterInfo()[reg].byte_size; +} + +size_t +RegisterContextPOSIX_x86::GetRegisterCount() +{ + size_t num_registers = m_reg_info.num_gpr_registers + m_reg_info.num_fpr_registers; + if (GetFPRType() == eXSAVE) + return num_registers + m_reg_info.num_avx_registers; + return num_registers; +} + +size_t +RegisterContextPOSIX_x86::GetGPRSize() +{ + return m_register_info_ap->GetGPRSize (); +} + +const RegisterInfo * +RegisterContextPOSIX_x86::GetRegisterInfo() +{ + // Commonly, this method is overridden and g_register_infos is copied and specialized. + // So, use GetRegisterInfo() rather than g_register_infos in this scope. + return m_register_info_ap->GetRegisterInfo (); +} + +const RegisterInfo * +RegisterContextPOSIX_x86::GetRegisterInfoAtIndex(size_t reg) +{ + if (reg < m_reg_info.num_registers) + return &GetRegisterInfo()[reg]; + else + return NULL; +} + +size_t +RegisterContextPOSIX_x86::GetRegisterSetCount() +{ + size_t sets = 0; + for (size_t set = 0; set < k_num_register_sets; ++set) + { + if (IsRegisterSetAvailable(set)) + ++sets; + } + + return sets; +} + +const RegisterSet * +RegisterContextPOSIX_x86::GetRegisterSet(size_t set) +{ + if (IsRegisterSetAvailable(set)) + { + switch (m_register_info_ap->m_target_arch.GetCore()) + { + case ArchSpec::eCore_x86_32_i386: + case ArchSpec::eCore_x86_32_i486: + case ArchSpec::eCore_x86_32_i486sx: + return &g_reg_sets_i386[set]; + case ArchSpec::eCore_x86_64_x86_64: + return &g_reg_sets_x86_64[set]; + default: + assert(false && "Unhandled target architecture."); + return NULL; + } + } + return NULL; +} + +const char * +RegisterContextPOSIX_x86::GetRegisterName(unsigned reg) +{ + assert(reg < m_reg_info.num_registers && "Invalid register offset."); + return GetRegisterInfo()[reg].name; +} + +lldb::ByteOrder +RegisterContextPOSIX_x86::GetByteOrder() +{ + // Get the target process whose privileged thread was used for the register read. + lldb::ByteOrder byte_order = eByteOrderInvalid; + Process *process = CalculateProcess().get(); + + if (process) + byte_order = process->GetByteOrder(); + return byte_order; +} + +// Parse ymm registers and into xmm.bytes and ymmh.bytes. +bool RegisterContextPOSIX_x86::CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order) +{ + if (!IsAVX(reg)) + return false; + + if (byte_order == eByteOrderLittle) + { + ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes, + m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, + sizeof(XMMReg)); + ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes, + m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg), + sizeof(YMMHReg)); + return true; + } + + if (byte_order == eByteOrderBig) + { + ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes, + m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg), + sizeof(XMMReg)); + ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes, + m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, + sizeof(YMMHReg)); + return true; + } + return false; // unsupported or invalid byte order +} + +// Concatenate xmm.bytes with ymmh.bytes +bool RegisterContextPOSIX_x86::CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order) +{ + if (!IsAVX(reg)) + return false; + + if (byte_order == eByteOrderLittle) + { + ::memcpy(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, + m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes, + sizeof(XMMReg)); + ::memcpy(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg), + m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes, + sizeof(YMMHReg)); + return true; + } + + if (byte_order == eByteOrderBig) + { + ::memcpy(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg), + m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes, + sizeof(XMMReg)); + ::memcpy(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, + m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes, + sizeof(YMMHReg)); + return true; + } + return false; // unsupported or invalid byte order +} + +bool +RegisterContextPOSIX_x86::IsRegisterSetAvailable(size_t set_index) +{ + // Note: Extended register sets are assumed to be at the end of g_reg_sets... + size_t num_sets = k_num_register_sets - k_num_extended_register_sets; + + if (GetFPRType() == eXSAVE) // ...and to start with AVX registers. + ++num_sets; + return (set_index < num_sets); +} + + +// Used when parsing DWARF and EH frame information and any other +// object file sections that contain register numbers in them. +uint32_t +RegisterContextPOSIX_x86::ConvertRegisterKindToRegisterNumber(uint32_t kind, + uint32_t num) +{ + 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; +} + diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.h b/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.h new file mode 100644 index 000000000000..5e922025b830 --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIX_x86.h @@ -0,0 +1,462 @@ +//===-- RegisterContextPOSIX_x86.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextPOSIX_x86_H_ +#define liblldb_RegisterContextPOSIX_x86_H_ + +#include "lldb/Core/Log.h" +#include "RegisterContextPOSIX.h" +#include "RegisterContext_x86.h" + +class ProcessMonitor; + +//--------------------------------------------------------------------------- +// Internal codes for all i386 registers. +//--------------------------------------------------------------------------- +enum +{ + k_first_gpr_i386, + gpr_eax_i386 = k_first_gpr_i386, + gpr_ebx_i386, + gpr_ecx_i386, + gpr_edx_i386, + gpr_edi_i386, + gpr_esi_i386, + gpr_ebp_i386, + gpr_esp_i386, + gpr_eip_i386, + gpr_eflags_i386, + gpr_cs_i386, + gpr_fs_i386, + gpr_gs_i386, + gpr_ss_i386, + gpr_ds_i386, + gpr_es_i386, + + k_first_alias_i386, + gpr_ax_i386 = k_first_alias_i386, + gpr_bx_i386, + gpr_cx_i386, + gpr_dx_i386, + gpr_di_i386, + gpr_si_i386, + gpr_bp_i386, + gpr_sp_i386, + gpr_ah_i386, + gpr_bh_i386, + gpr_ch_i386, + gpr_dh_i386, + gpr_al_i386, + gpr_bl_i386, + gpr_cl_i386, + gpr_dl_i386, + k_last_alias_i386 = gpr_dl_i386, + + k_last_gpr_i386 = k_last_alias_i386, + + k_first_fpr_i386, + fpu_fctrl_i386 = k_first_fpr_i386, + fpu_fstat_i386, + fpu_ftag_i386, + fpu_fop_i386, + fpu_fiseg_i386, + fpu_fioff_i386, + fpu_foseg_i386, + fpu_fooff_i386, + fpu_mxcsr_i386, + fpu_mxcsrmask_i386, + fpu_st0_i386, + fpu_st1_i386, + fpu_st2_i386, + fpu_st3_i386, + fpu_st4_i386, + fpu_st5_i386, + fpu_st6_i386, + fpu_st7_i386, + fpu_mm0_i386, + fpu_mm1_i386, + fpu_mm2_i386, + fpu_mm3_i386, + fpu_mm4_i386, + fpu_mm5_i386, + fpu_mm6_i386, + fpu_mm7_i386, + fpu_xmm0_i386, + fpu_xmm1_i386, + fpu_xmm2_i386, + fpu_xmm3_i386, + fpu_xmm4_i386, + fpu_xmm5_i386, + fpu_xmm6_i386, + fpu_xmm7_i386, + k_last_fpr_i386 = fpu_xmm7_i386, + + k_first_avx_i386, + fpu_ymm0_i386 = k_first_avx_i386, + fpu_ymm1_i386, + fpu_ymm2_i386, + fpu_ymm3_i386, + fpu_ymm4_i386, + fpu_ymm5_i386, + fpu_ymm6_i386, + fpu_ymm7_i386, + k_last_avx_i386 = fpu_ymm7_i386, + + dr0_i386, + dr1_i386, + dr2_i386, + dr3_i386, + dr4_i386, + dr5_i386, + dr6_i386, + dr7_i386, + + k_num_registers_i386, + k_num_gpr_registers_i386 = k_last_gpr_i386 - k_first_gpr_i386 + 1, + k_num_fpr_registers_i386 = k_last_fpr_i386 - k_first_fpr_i386 + 1, + k_num_avx_registers_i386 = k_last_avx_i386 - k_first_avx_i386 + 1 +}; + +//--------------------------------------------------------------------------- +// Internal codes for all x86_64 registers. +//--------------------------------------------------------------------------- +enum +{ + k_first_gpr_x86_64, + gpr_rax_x86_64 = k_first_gpr_x86_64, + gpr_rbx_x86_64, + gpr_rcx_x86_64, + gpr_rdx_x86_64, + gpr_rdi_x86_64, + gpr_rsi_x86_64, + gpr_rbp_x86_64, + gpr_rsp_x86_64, + gpr_r8_x86_64, + gpr_r9_x86_64, + gpr_r10_x86_64, + gpr_r11_x86_64, + gpr_r12_x86_64, + gpr_r13_x86_64, + gpr_r14_x86_64, + gpr_r15_x86_64, + gpr_rip_x86_64, + gpr_rflags_x86_64, + gpr_cs_x86_64, + gpr_fs_x86_64, + gpr_gs_x86_64, + gpr_ss_x86_64, + gpr_ds_x86_64, + gpr_es_x86_64, + + k_first_alias_x86_64, + gpr_eax_x86_64 = k_first_alias_x86_64, + gpr_ebx_x86_64, + gpr_ecx_x86_64, + gpr_edx_x86_64, + gpr_edi_x86_64, + gpr_esi_x86_64, + gpr_ebp_x86_64, + gpr_esp_x86_64, + gpr_r8d_x86_64, // Low 32 bits of r8 + gpr_r9d_x86_64, // Low 32 bits of r9 + gpr_r10d_x86_64, // Low 32 bits of r10 + gpr_r11d_x86_64, // Low 32 bits of r11 + gpr_r12d_x86_64, // Low 32 bits of r12 + gpr_r13d_x86_64, // Low 32 bits of r13 + gpr_r14d_x86_64, // Low 32 bits of r14 + gpr_r15d_x86_64, // Low 32 bits of r15 + gpr_ax_x86_64, + gpr_bx_x86_64, + gpr_cx_x86_64, + gpr_dx_x86_64, + gpr_di_x86_64, + gpr_si_x86_64, + gpr_bp_x86_64, + gpr_sp_x86_64, + gpr_r8w_x86_64, // Low 16 bits of r8 + gpr_r9w_x86_64, // Low 16 bits of r9 + gpr_r10w_x86_64, // Low 16 bits of r10 + gpr_r11w_x86_64, // Low 16 bits of r11 + gpr_r12w_x86_64, // Low 16 bits of r12 + gpr_r13w_x86_64, // Low 16 bits of r13 + gpr_r14w_x86_64, // Low 16 bits of r14 + gpr_r15w_x86_64, // Low 16 bits of r15 + gpr_ah_x86_64, + gpr_bh_x86_64, + gpr_ch_x86_64, + gpr_dh_x86_64, + gpr_al_x86_64, + gpr_bl_x86_64, + gpr_cl_x86_64, + gpr_dl_x86_64, + gpr_dil_x86_64, + gpr_sil_x86_64, + gpr_bpl_x86_64, + gpr_spl_x86_64, + gpr_r8l_x86_64, // Low 8 bits of r8 + gpr_r9l_x86_64, // Low 8 bits of r9 + gpr_r10l_x86_64, // Low 8 bits of r10 + gpr_r11l_x86_64, // Low 8 bits of r11 + gpr_r12l_x86_64, // Low 8 bits of r12 + gpr_r13l_x86_64, // Low 8 bits of r13 + gpr_r14l_x86_64, // Low 8 bits of r14 + gpr_r15l_x86_64, // Low 8 bits of r15 + k_last_alias_x86_64 = gpr_r15l_x86_64, + + k_last_gpr_x86_64 = k_last_alias_x86_64, + + k_first_fpr_x86_64, + fpu_fctrl_x86_64 = k_first_fpr_x86_64, + fpu_fstat_x86_64, + fpu_ftag_x86_64, + fpu_fop_x86_64, + fpu_fiseg_x86_64, + fpu_fioff_x86_64, + fpu_foseg_x86_64, + fpu_fooff_x86_64, + fpu_mxcsr_x86_64, + fpu_mxcsrmask_x86_64, + fpu_st0_x86_64, + fpu_st1_x86_64, + fpu_st2_x86_64, + fpu_st3_x86_64, + fpu_st4_x86_64, + fpu_st5_x86_64, + fpu_st6_x86_64, + fpu_st7_x86_64, + fpu_mm0_x86_64, + fpu_mm1_x86_64, + fpu_mm2_x86_64, + fpu_mm3_x86_64, + fpu_mm4_x86_64, + fpu_mm5_x86_64, + fpu_mm6_x86_64, + fpu_mm7_x86_64, + fpu_xmm0_x86_64, + fpu_xmm1_x86_64, + fpu_xmm2_x86_64, + fpu_xmm3_x86_64, + fpu_xmm4_x86_64, + fpu_xmm5_x86_64, + fpu_xmm6_x86_64, + fpu_xmm7_x86_64, + fpu_xmm8_x86_64, + fpu_xmm9_x86_64, + fpu_xmm10_x86_64, + fpu_xmm11_x86_64, + fpu_xmm12_x86_64, + fpu_xmm13_x86_64, + fpu_xmm14_x86_64, + fpu_xmm15_x86_64, + k_last_fpr_x86_64 = fpu_xmm15_x86_64, + + k_first_avx_x86_64, + fpu_ymm0_x86_64 = k_first_avx_x86_64, + fpu_ymm1_x86_64, + fpu_ymm2_x86_64, + fpu_ymm3_x86_64, + fpu_ymm4_x86_64, + fpu_ymm5_x86_64, + fpu_ymm6_x86_64, + fpu_ymm7_x86_64, + fpu_ymm8_x86_64, + fpu_ymm9_x86_64, + fpu_ymm10_x86_64, + fpu_ymm11_x86_64, + fpu_ymm12_x86_64, + fpu_ymm13_x86_64, + fpu_ymm14_x86_64, + fpu_ymm15_x86_64, + k_last_avx_x86_64 = fpu_ymm15_x86_64, + + dr0_x86_64, + dr1_x86_64, + dr2_x86_64, + dr3_x86_64, + dr4_x86_64, + dr5_x86_64, + dr6_x86_64, + dr7_x86_64, + + k_num_registers_x86_64, + k_num_gpr_registers_x86_64 = k_last_gpr_x86_64 - k_first_gpr_x86_64 + 1, + k_num_fpr_registers_x86_64 = k_last_fpr_x86_64 - k_first_fpr_x86_64 + 1, + k_num_avx_registers_x86_64 = k_last_avx_x86_64 - k_first_avx_x86_64 + 1 +}; + +class RegisterContextPOSIX_x86 + : public lldb_private::RegisterContext +{ +public: + RegisterContextPOSIX_x86 (lldb_private::Thread &thread, + uint32_t concrete_frame_idx, + RegisterInfoInterface *register_info); + + ~RegisterContextPOSIX_x86(); + + void + Invalidate(); + + void + InvalidateAllRegisters(); + + size_t + GetRegisterCount(); + + virtual size_t + GetGPRSize(); + + virtual unsigned + GetRegisterSize(unsigned reg); + + virtual unsigned + GetRegisterOffset(unsigned reg); + + const lldb_private::RegisterInfo * + GetRegisterInfoAtIndex(size_t reg); + + size_t + GetRegisterSetCount(); + + const lldb_private::RegisterSet * + GetRegisterSet(size_t set); + + const char * + GetRegisterName(unsigned reg); + + uint32_t + ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num); + + //--------------------------------------------------------------------------- + // Note: prefer kernel definitions over user-land + //--------------------------------------------------------------------------- + enum FPRType + { + eNotValid = 0, + eFSAVE, // TODO + eFXSAVE, + eSOFT, // TODO + eXSAVE + }; + + static uint32_t g_contained_eax[]; + static uint32_t g_contained_ebx[]; + static uint32_t g_contained_ecx[]; + static uint32_t g_contained_edx[]; + static uint32_t g_contained_edi[]; + static uint32_t g_contained_esi[]; + static uint32_t g_contained_ebp[]; + static uint32_t g_contained_esp[]; + + static uint32_t g_invalidate_eax[]; + static uint32_t g_invalidate_ebx[]; + static uint32_t g_invalidate_ecx[]; + static uint32_t g_invalidate_edx[]; + static uint32_t g_invalidate_edi[]; + static uint32_t g_invalidate_esi[]; + static uint32_t g_invalidate_ebp[]; + static uint32_t g_invalidate_esp[]; + + static uint32_t g_contained_rax[]; + static uint32_t g_contained_rbx[]; + static uint32_t g_contained_rcx[]; + static uint32_t g_contained_rdx[]; + static uint32_t g_contained_rdi[]; + static uint32_t g_contained_rsi[]; + static uint32_t g_contained_rbp[]; + static uint32_t g_contained_rsp[]; + static uint32_t g_contained_r8[]; + static uint32_t g_contained_r9[]; + static uint32_t g_contained_r10[]; + static uint32_t g_contained_r11[]; + static uint32_t g_contained_r12[]; + static uint32_t g_contained_r13[]; + static uint32_t g_contained_r14[]; + static uint32_t g_contained_r15[]; + + static uint32_t g_invalidate_rax[]; + static uint32_t g_invalidate_rbx[]; + static uint32_t g_invalidate_rcx[]; + static uint32_t g_invalidate_rdx[]; + static uint32_t g_invalidate_rdi[]; + static uint32_t g_invalidate_rsi[]; + static uint32_t g_invalidate_rbp[]; + static uint32_t g_invalidate_rsp[]; + static uint32_t g_invalidate_r8[]; + static uint32_t g_invalidate_r9[]; + static uint32_t g_invalidate_r10[]; + static uint32_t g_invalidate_r11[]; + static uint32_t g_invalidate_r12[]; + static uint32_t g_invalidate_r13[]; + static uint32_t g_invalidate_r14[]; + static uint32_t g_invalidate_r15[]; + +protected: + struct RegInfo + { + uint32_t num_registers; + uint32_t num_gpr_registers; + uint32_t num_fpr_registers; + uint32_t num_avx_registers; + + uint32_t last_gpr; + uint32_t first_fpr; + uint32_t last_fpr; + + uint32_t first_st; + uint32_t last_st; + uint32_t first_mm; + uint32_t last_mm; + uint32_t first_xmm; + uint32_t last_xmm; + uint32_t first_ymm; + uint32_t last_ymm; + + uint32_t first_dr; + uint32_t gpr_flags; + }; + + uint64_t m_gpr_x86_64[k_num_gpr_registers_x86_64]; // 64-bit general purpose registers. + RegInfo m_reg_info; + FPRType m_fpr_type; // determines the type of data stored by union FPR, if any. + FPR m_fpr; // floating-point registers including extended register sets. + IOVEC m_iovec; // wrapper for xsave. + YMM m_ymm_set; // copy of ymmh and xmm register halves. + std::unique_ptr<RegisterInfoInterface> m_register_info_ap; // Register Info Interface (FreeBSD or Linux) + + // Determines if an extended register set is supported on the processor running the inferior process. + virtual bool + IsRegisterSetAvailable(size_t set_index); + + virtual const lldb_private::RegisterInfo * + GetRegisterInfo(); + + bool + IsGPR(unsigned reg); + + bool + IsFPR(unsigned reg); + + bool + IsAVX(unsigned reg); + + lldb::ByteOrder GetByteOrder(); + + bool CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order); + bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order); + bool IsFPR(unsigned reg, FPRType fpr_type); + FPRType GetFPRType(); + + virtual bool ReadGPR() = 0; + virtual bool ReadFPR() = 0; + virtual bool WriteGPR() = 0; + virtual bool WriteFPR() = 0; +}; + +#endif // #ifndef liblldb_RegisterContextPOSIX_x86_H_ diff --git a/source/Plugins/Process/POSIX/RegisterContext_i386.cpp b/source/Plugins/Process/POSIX/RegisterContext_i386.cpp deleted file mode 100644 index 49676bd3fc73..000000000000 --- a/source/Plugins/Process/POSIX/RegisterContext_i386.cpp +++ /dev/null @@ -1,551 +0,0 @@ -//===-- RegisterContextPOSIX_i386.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/Core/DataExtractor.h" -#include "lldb/Target/Thread.h" -#include "lldb/Host/Endian.h" -#include "llvm/Support/Compiler.h" - -#include "ProcessPOSIX.h" -#include "ProcessPOSIXLog.h" -#include "ProcessMonitor.h" -#include "RegisterContext_i386.h" -#include "RegisterContext_x86.h" - -using namespace lldb_private; -using namespace lldb; - -enum -{ - k_first_gpr, - gpr_eax = k_first_gpr, - gpr_ebx, - gpr_ecx, - gpr_edx, - gpr_edi, - gpr_esi, - gpr_ebp, - gpr_esp, - gpr_ss, - gpr_eflags, -#ifdef __FreeBSD__ - gpr_orig_ax, -#endif - gpr_eip, - gpr_cs, - gpr_ds, - gpr_es, - gpr_fs, - gpr_gs, - k_last_gpr = gpr_gs, - - k_first_fpr, - fpu_fcw = k_first_fpr, - fpu_fsw, - fpu_ftw, - fpu_fop, - fpu_ip, - fpu_cs, - fpu_foo, - fpu_fos, - fpu_mxcsr, - fpu_stmm0, - fpu_stmm1, - fpu_stmm2, - fpu_stmm3, - fpu_stmm4, - fpu_stmm5, - fpu_stmm6, - fpu_stmm7, - fpu_xmm0, - fpu_xmm1, - fpu_xmm2, - fpu_xmm3, - fpu_xmm4, - fpu_xmm5, - fpu_xmm6, - fpu_xmm7, - k_last_fpr = fpu_xmm7, - - k_num_registers, - k_num_gpr_registers = k_last_gpr - k_first_gpr + 1, - k_num_fpu_registers = k_last_fpr - k_first_fpr + 1 -}; - -// Number of register sets provided by this context. -enum -{ - k_num_register_sets = 2 -}; - -static const -uint32_t g_gpr_regnums[k_num_gpr_registers] = -{ - gpr_eax, - gpr_ebx, - gpr_ecx, - gpr_edx, - gpr_edi, - gpr_esi, - gpr_ebp, - gpr_esp, - gpr_ss, - gpr_eflags, -#ifdef __FreeBSD__ - gpr_orig_ax, -#endif - gpr_eip, - gpr_cs, - gpr_ds, - gpr_es, - gpr_fs, - gpr_gs, -}; - -static const uint32_t -g_fpu_regnums[k_num_fpu_registers] = -{ - fpu_fcw, - fpu_fsw, - fpu_ftw, - fpu_fop, - fpu_ip, - fpu_cs, - fpu_foo, - fpu_fos, - fpu_mxcsr, - fpu_stmm0, - fpu_stmm1, - fpu_stmm2, - fpu_stmm3, - fpu_stmm4, - fpu_stmm5, - fpu_stmm6, - fpu_stmm7, - fpu_xmm0, - fpu_xmm1, - fpu_xmm2, - fpu_xmm3, - fpu_xmm4, - fpu_xmm5, - fpu_xmm6, - fpu_xmm7, -}; - -static const RegisterSet -g_reg_sets[k_num_register_sets] = -{ - { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums }, - { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums } -}; - -// Computes the offset of the given GPR in the user data area. -#define GPR_OFFSET(regname) \ - (offsetof(RegisterContext_i386::UserArea, regs) + \ - offsetof(RegisterContext_i386::GPR, regname)) - -// Computes the offset of the given FPR in the user data area. -#define FPR_OFFSET(regname) \ - (offsetof(RegisterContext_i386::UserArea, i387) + \ - offsetof(RegisterContext_i386::FPU, regname)) - -// Number of bytes needed to represent a GPR. -#define GPR_SIZE(reg) sizeof(((RegisterContext_i386::GPR*)NULL)->reg) - -// Number of bytes needed to represent a FPR. -#define FPR_SIZE(reg) sizeof(((RegisterContext_i386::FPU*)NULL)->reg) - -// Number of bytes needed to represent the i'th FP register. -#define FP_SIZE sizeof(((RegisterContext_i386::MMSReg*)NULL)->bytes) - -// Number of bytes needed to represent an XMM register. -#define XMM_SIZE sizeof(RegisterContext_i386::XMMReg) - -#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ - { #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg }, NULL, NULL } - -#define DEFINE_FPR(reg, kind1, kind2, kind3, kind4) \ - { #reg, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, fpu_##reg }, NULL, NULL } - -#define DEFINE_FP(reg, i) \ - { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \ - eEncodingVector, eFormatVectorOfUInt8, \ - { dwarf_##reg##i, dwarf_##reg##i, \ - LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i }, NULL, NULL } - -#define DEFINE_XMM(reg, i) \ - { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \ - eEncodingVector, eFormatVectorOfUInt8, \ - { dwarf_##reg##i, dwarf_##reg##i, \ - LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i }, NULL, NULL } - -static RegisterInfo -g_register_infos[k_num_registers] = -{ - // General purpose registers. - DEFINE_GPR(eax, NULL, gcc_eax, dwarf_eax, LLDB_INVALID_REGNUM, gdb_eax), - DEFINE_GPR(ebx, NULL, gcc_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, gdb_ebx), - DEFINE_GPR(ecx, NULL, gcc_ecx, dwarf_ecx, LLDB_INVALID_REGNUM, gdb_ecx), - DEFINE_GPR(edx, NULL, gcc_edx, dwarf_edx, LLDB_INVALID_REGNUM, gdb_edx), - DEFINE_GPR(edi, NULL, gcc_edi, dwarf_edi, LLDB_INVALID_REGNUM, gdb_edi), - DEFINE_GPR(esi, NULL, gcc_esi, dwarf_esi, LLDB_INVALID_REGNUM, gdb_esi), - DEFINE_GPR(ebp, "fp", gcc_ebp, dwarf_ebp, LLDB_INVALID_REGNUM, gdb_ebp), - DEFINE_GPR(esp, "sp", gcc_esp, dwarf_esp, LLDB_INVALID_REGNUM, gdb_esp), - DEFINE_GPR(ss, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ss), - DEFINE_GPR(eflags, "flags", gcc_eflags, dwarf_eflags, LLDB_INVALID_REGNUM, gdb_eflags), - DEFINE_GPR(eip, "pc", gcc_eip, dwarf_eip, LLDB_INVALID_REGNUM, gdb_eip), - DEFINE_GPR(cs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_cs), - DEFINE_GPR(ds, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ds), - DEFINE_GPR(es, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_es), - DEFINE_GPR(fs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fs), - DEFINE_GPR(gs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gs), - - // Floating point registers. - DEFINE_FPR(fcw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fcw), - DEFINE_FPR(fsw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fsw), - DEFINE_FPR(ftw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftw), - DEFINE_FPR(fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop), - DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ip), - DEFINE_FPR(cs, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_cs), - DEFINE_FPR(foo, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_dp), - DEFINE_FPR(fos, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ds), - DEFINE_FPR(mxcsr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_mxcsr), - - DEFINE_FP(stmm, 0), - DEFINE_FP(stmm, 1), - DEFINE_FP(stmm, 2), - DEFINE_FP(stmm, 3), - DEFINE_FP(stmm, 4), - DEFINE_FP(stmm, 5), - DEFINE_FP(stmm, 6), - DEFINE_FP(stmm, 7), - - // XMM registers - DEFINE_XMM(xmm, 0), - DEFINE_XMM(xmm, 1), - DEFINE_XMM(xmm, 2), - DEFINE_XMM(xmm, 3), - DEFINE_XMM(xmm, 4), - DEFINE_XMM(xmm, 5), - DEFINE_XMM(xmm, 6), - DEFINE_XMM(xmm, 7), - -}; - -#ifndef NDEBUG -static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo)); -#endif - -static unsigned GetRegOffset(unsigned reg) -{ - assert(reg < k_num_registers && "Invalid register number."); - return g_register_infos[reg].byte_offset; -} - -static unsigned GetRegSize(unsigned reg) -{ - assert(reg < k_num_registers && "Invalid register number."); - return g_register_infos[reg].byte_size; -} - -RegisterContext_i386::RegisterContext_i386(Thread &thread, - uint32_t concrete_frame_idx) - : RegisterContextPOSIX(thread, concrete_frame_idx) -{ -} - -RegisterContext_i386::~RegisterContext_i386() -{ -} - -ProcessMonitor & -RegisterContext_i386::GetMonitor() -{ - ProcessSP base = CalculateProcess(); - ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get()); - return process->GetMonitor(); -} - -void -RegisterContext_i386::Invalidate() -{ -} - -void -RegisterContext_i386::InvalidateAllRegisters() -{ -} - -size_t -RegisterContext_i386::GetRegisterCount() -{ - assert(k_num_register_infos == k_num_registers); - return k_num_registers; -} - -const RegisterInfo * -RegisterContext_i386::GetRegisterInfoAtIndex(size_t reg) -{ - assert(k_num_register_infos == k_num_registers); - if (reg < k_num_registers) - return &g_register_infos[reg]; - else - return NULL; -} - -size_t -RegisterContext_i386::GetRegisterSetCount() -{ - return k_num_register_sets; -} - -const RegisterSet * -RegisterContext_i386::GetRegisterSet(size_t set) -{ - if (set < k_num_register_sets) - return &g_reg_sets[set]; - else - return NULL; -} - -unsigned -RegisterContext_i386::GetRegisterIndexFromOffset(unsigned offset) -{ - unsigned reg; - for (reg = 0; reg < k_num_registers; reg++) - { - if (g_register_infos[reg].byte_offset == offset) - break; - } - assert(reg < k_num_registers && "Invalid register offset."); - return reg; -} - -const char * -RegisterContext_i386::GetRegisterName(unsigned reg) -{ - assert(reg < k_num_registers && "Invalid register offset."); - return g_register_infos[reg].name; -} - -bool -RegisterContext_i386::ReadRegister(const RegisterInfo *reg_info, - RegisterValue &value) -{ - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadRegisterValue(m_thread.GetID(), GetRegOffset(reg), - GetRegisterName(reg), GetRegSize(reg), value); -} - -bool -RegisterContext_i386::ReadAllRegisterValues(DataBufferSP &data_sp) -{ - return false; -} - -bool RegisterContext_i386::WriteRegister(const RegisterInfo *reg_info, - const RegisterValue &value) -{ - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteRegisterValue(m_thread.GetID(), GetRegOffset(reg), - GetRegisterName(reg), value); -} - -bool -RegisterContext_i386::WriteAllRegisterValues(const DataBufferSP &data) -{ - return false; -} - -bool -RegisterContext_i386::UpdateAfterBreakpoint() -{ - // PC points one byte past the int3 responsible for the breakpoint. - lldb::addr_t pc; - - if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) - return false; - - SetPC(pc - 1); - return true; -} - -uint32_t -RegisterContext_i386::ConvertRegisterKindToRegisterNumber(uint32_t kind, - uint32_t num) -{ - if (kind == eRegisterKindGeneric) - { - switch (num) - { - case LLDB_REGNUM_GENERIC_PC: return gpr_eip; - case LLDB_REGNUM_GENERIC_SP: return gpr_esp; - case LLDB_REGNUM_GENERIC_FP: return gpr_ebp; - case LLDB_REGNUM_GENERIC_FLAGS: return gpr_eflags; - case LLDB_REGNUM_GENERIC_RA: - default: - return LLDB_INVALID_REGNUM; - } - } - - if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF) - { - switch (num) - { - case dwarf_eax: return gpr_eax; - case dwarf_edx: return gpr_edx; - case dwarf_ecx: return gpr_ecx; - case dwarf_ebx: return gpr_ebx; - case dwarf_esi: return gpr_esi; - case dwarf_edi: return gpr_edi; - case dwarf_ebp: return gpr_ebp; - case dwarf_esp: return gpr_esp; - case dwarf_eip: return gpr_eip; - case dwarf_xmm0: return fpu_xmm0; - case dwarf_xmm1: return fpu_xmm1; - case dwarf_xmm2: return fpu_xmm2; - case dwarf_xmm3: return fpu_xmm3; - case dwarf_xmm4: return fpu_xmm4; - case dwarf_xmm5: return fpu_xmm5; - case dwarf_xmm6: return fpu_xmm6; - case dwarf_xmm7: return fpu_xmm7; - case dwarf_stmm0: return fpu_stmm0; - case dwarf_stmm1: return fpu_stmm1; - case dwarf_stmm2: return fpu_stmm2; - case dwarf_stmm3: return fpu_stmm3; - case dwarf_stmm4: return fpu_stmm4; - case dwarf_stmm5: return fpu_stmm5; - case dwarf_stmm6: return fpu_stmm6; - case dwarf_stmm7: return fpu_stmm7; - default: - return LLDB_INVALID_REGNUM; - } - } - - if (kind == eRegisterKindGDB) - { - switch (num) - { - case gdb_eax : return gpr_eax; - case gdb_ebx : return gpr_ebx; - case gdb_ecx : return gpr_ecx; - case gdb_edx : return gpr_edx; - case gdb_esi : return gpr_esi; - case gdb_edi : return gpr_edi; - case gdb_ebp : return gpr_ebp; - case gdb_esp : return gpr_esp; - case gdb_eip : return gpr_eip; - case gdb_eflags : return gpr_eflags; - case gdb_cs : return gpr_cs; - case gdb_ss : return gpr_ss; - case gdb_ds : return gpr_ds; - case gdb_es : return gpr_es; - case gdb_fs : return gpr_fs; - case gdb_gs : return gpr_gs; - case gdb_stmm0 : return fpu_stmm0; - case gdb_stmm1 : return fpu_stmm1; - case gdb_stmm2 : return fpu_stmm2; - case gdb_stmm3 : return fpu_stmm3; - case gdb_stmm4 : return fpu_stmm4; - case gdb_stmm5 : return fpu_stmm5; - case gdb_stmm6 : return fpu_stmm6; - case gdb_stmm7 : return fpu_stmm7; - case gdb_fcw : return fpu_fcw; - case gdb_fsw : return fpu_fsw; - case gdb_ftw : return fpu_ftw; - case gdb_fpu_cs : return fpu_cs; - case gdb_ip : return fpu_ip; - case gdb_fpu_ds : return fpu_fos; - case gdb_dp : return fpu_foo; - case gdb_fop : return fpu_fop; - case gdb_xmm0 : return fpu_xmm0; - case gdb_xmm1 : return fpu_xmm1; - case gdb_xmm2 : return fpu_xmm2; - case gdb_xmm3 : return fpu_xmm3; - case gdb_xmm4 : return fpu_xmm4; - case gdb_xmm5 : return fpu_xmm5; - case gdb_xmm6 : return fpu_xmm6; - case gdb_xmm7 : return fpu_xmm7; - case gdb_mxcsr : return fpu_mxcsr; - default: - return LLDB_INVALID_REGNUM; - } - } - else if (kind == eRegisterKindLLDB) - { - return num; - } - - return LLDB_INVALID_REGNUM; -} - -bool -RegisterContext_i386::HardwareSingleStep(bool enable) -{ - enum { TRACE_BIT = 0x100 }; - uint64_t eflags; - - if ((eflags = ReadRegisterAsUnsigned(gpr_eflags, -1UL)) == -1UL) - return false; - - if (enable) - { - if (eflags & TRACE_BIT) - return true; - - eflags |= TRACE_BIT; - } - else - { - if (!(eflags & TRACE_BIT)) - return false; - - eflags &= ~TRACE_BIT; - } - - return WriteRegisterFromUnsigned(gpr_eflags, eflags); -} - -void -RegisterContext_i386::LogGPR(const char *title) -{ - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS)); - if (log) - { - if (title) - log->Printf ("%s", title); - for (uint32_t i=0; i<k_num_gpr_registers; i++) - { - uint32_t reg = gpr_eax + i; - log->Printf("%12s = 0x%8.8" PRIx64, g_register_infos[reg].name, ((uint64_t*)&user.regs)[reg]); - } - } -} - -bool -RegisterContext_i386::ReadGPR() -{ - bool result; - - ProcessMonitor &monitor = GetMonitor(); - result = monitor.ReadGPR(m_thread.GetID(), &user.regs, sizeof(user.regs)); - LogGPR("RegisterContext_i386::ReadGPR()"); - return result; -} - -bool -RegisterContext_i386::ReadFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadFPR(m_thread.GetID(), &user.i387, sizeof(user.i387)); -} diff --git a/source/Plugins/Process/POSIX/RegisterContext_i386.h b/source/Plugins/Process/POSIX/RegisterContext_i386.h deleted file mode 100644 index 96066c47b815..000000000000 --- a/source/Plugins/Process/POSIX/RegisterContext_i386.h +++ /dev/null @@ -1,169 +0,0 @@ -//===-- RegisterContext_i386.h ------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContext_i386_h_ -#define liblldb_RegisterContext_i386_h_ - -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes -#include "lldb/Core/Log.h" -#include "RegisterContextPOSIX.h" - -class RegisterContext_i386 : public RegisterContextPOSIX -{ -public: - RegisterContext_i386(lldb_private::Thread &thread, - uint32_t concreate_frame_idx); - - ~RegisterContext_i386(); - - void - Invalidate(); - - void - InvalidateAllRegisters(); - - size_t - GetRegisterCount(); - - const lldb_private::RegisterInfo * - GetRegisterInfoAtIndex(size_t reg); - - size_t - GetRegisterSetCount(); - - const lldb_private::RegisterSet * - GetRegisterSet(size_t set); - - unsigned - GetRegisterIndexFromOffset(unsigned offset); - - const char * - GetRegisterName(unsigned reg); - - bool - ReadRegisterValue(uint32_t reg, lldb_private::Scalar &value); - - bool - ReadRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data); - - virtual bool - ReadRegister(const lldb_private::RegisterInfo *reg_info, - lldb_private::RegisterValue &value); - - bool - ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - - bool - WriteRegisterValue(uint32_t reg, const lldb_private::Scalar &value); - - bool - WriteRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data, - uint32_t data_offset = 0); - - virtual bool - WriteRegister(const lldb_private::RegisterInfo *reg_info, - const lldb_private::RegisterValue &value); - - bool - WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - - uint32_t - ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num); - - bool - HardwareSingleStep(bool enable); - - bool - UpdateAfterBreakpoint(); - - struct GPR - { - uint32_t ebx; - uint32_t ecx; - uint32_t edx; - uint32_t esi; - uint32_t edi; - uint32_t ebp; - uint32_t eax; - uint32_t ds; - uint32_t es; - uint32_t fs; - uint32_t gs; - uint32_t orig_ax; - uint32_t eip; - uint32_t cs; - uint32_t eflags; - uint32_t esp; - uint32_t ss; - }; - - struct MMSReg - { - uint8_t bytes[8]; - }; - - struct XMMReg - { - uint8_t bytes[16]; - }; - - struct FPU - { - uint16_t fcw; - uint16_t fsw; - uint16_t ftw; - uint16_t fop; - uint32_t ip; - uint32_t cs; - uint32_t foo; - uint32_t fos; - uint32_t mxcsr; - uint32_t reserved; - MMSReg stmm[8]; - XMMReg xmm[8]; - uint32_t pad[56]; - }; - - // A user area like this no longer exists on FreeBSD - // making this a Linux artifact. Nonetheless, it is safe - // leaving it here while the code is being cleaned up and generalized. - - struct UserArea - { - GPR regs; // General purpose registers. - int32_t fpvalid; // True if FPU is being used. - FPU i387; // FPU registers. - uint32_t tsize; // Text segment size. - uint32_t dsize; // Data segment size. - uint32_t ssize; // Stack segment size. - uint32_t start_code; // VM address of text. - uint32_t start_stack; // VM address of stack bottom (top in rsp). - int32_t signal; // Signal causing core dump. - int32_t reserved; // Unused. - uint32_t ar0; // Location of GPR's. - FPU* fpstate; // Location of FPR's. - uint32_t magic; // Identifier for core dumps. - char u_comm[32]; // Command causing core dump. - uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7). - }; -private: - UserArea user; - - ProcessMonitor &GetMonitor(); - - void LogGPR(const char *title); - - bool ReadGPR(); - bool ReadFPR(); -}; - -#endif // #ifndef liblldb_RegisterContext_i386_h_ diff --git a/source/Plugins/Process/POSIX/RegisterContext_mips64.h b/source/Plugins/Process/POSIX/RegisterContext_mips64.h new file mode 100644 index 000000000000..dfd473d7cbec --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterContext_mips64.h @@ -0,0 +1,104 @@ +//===-- RegisterContext_mips64.h --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContext_mips64_H_ +#define liblldb_RegisterContext_mips64_H_ + +// GCC and DWARF Register numbers (eRegisterKindGCC & eRegisterKindDWARF) +enum +{ + // GP Registers + gcc_dwarf_zero_mips64 = 0, + gcc_dwarf_r1_mips64, + gcc_dwarf_r2_mips64, + gcc_dwarf_r3_mips64, + gcc_dwarf_r4_mips64, + gcc_dwarf_r5_mips64, + gcc_dwarf_r6_mips64, + gcc_dwarf_r7_mips64, + gcc_dwarf_r8_mips64, + gcc_dwarf_r9_mips64, + gcc_dwarf_r10_mips64, + gcc_dwarf_r11_mips64, + gcc_dwarf_r12_mips64, + gcc_dwarf_r13_mips64, + gcc_dwarf_r14_mips64, + gcc_dwarf_r15_mips64, + gcc_dwarf_r16_mips64, + gcc_dwarf_r17_mips64, + gcc_dwarf_r18_mips64, + gcc_dwarf_r19_mips64, + gcc_dwarf_r20_mips64, + gcc_dwarf_r21_mips64, + gcc_dwarf_r22_mips64, + gcc_dwarf_r23_mips64, + gcc_dwarf_r24_mips64, + gcc_dwarf_r25_mips64, + gcc_dwarf_r26_mips64, + gcc_dwarf_r27_mips64, + gcc_dwarf_gp_mips64, + gcc_dwarf_sp_mips64, + gcc_dwarf_r30_mips64, + gcc_dwarf_ra_mips64, + gcc_dwarf_sr_mips64, + gcc_dwarf_lo_mips64, + gcc_dwarf_hi_mips64, + gcc_dwarf_bad_mips64, + gcc_dwarf_cause_mips64, + gcc_dwarf_pc_mips64, + gcc_dwarf_ic_mips64, + gcc_dwarf_dummy_mips64 +}; + +// GDB Register numbers (eRegisterKindGDB) +enum +{ + gdb_zero_mips64 = 0, + gdb_r1_mips64, + gdb_r2_mips64, + gdb_r3_mips64, + gdb_r4_mips64, + gdb_r5_mips64, + gdb_r6_mips64, + gdb_r7_mips64, + gdb_r8_mips64, + gdb_r9_mips64, + gdb_r10_mips64, + gdb_r11_mips64, + gdb_r12_mips64, + gdb_r13_mips64, + gdb_r14_mips64, + gdb_r15_mips64, + gdb_r16_mips64, + gdb_r17_mips64, + gdb_r18_mips64, + gdb_r19_mips64, + gdb_r20_mips64, + gdb_r21_mips64, + gdb_r22_mips64, + gdb_r23_mips64, + gdb_r24_mips64, + gdb_r25_mips64, + gdb_r26_mips64, + gdb_r27_mips64, + gdb_gp_mips64, + gdb_sp_mips64, + gdb_r30_mips64, + gdb_ra_mips64, + gdb_sr_mips64, + gdb_lo_mips64, + gdb_hi_mips64, + gdb_bad_mips64, + gdb_cause_mips64, + gdb_pc_mips64, + gdb_ic_mips64, + gdb_dummy_mips64 +}; + +#endif // liblldb_RegisterContext_mips64_H_ diff --git a/source/Plugins/Process/POSIX/RegisterContext_x86.h b/source/Plugins/Process/POSIX/RegisterContext_x86.h index 61a25c407758..df3e1e5a84bf 100644 --- a/source/Plugins/Process/POSIX/RegisterContext_x86.h +++ b/source/Plugins/Process/POSIX/RegisterContext_x86.h @@ -1,4 +1,4 @@ -//===-- RegisterContext_x86.h ---------------------------*- C++ -*-===// +//===-- RegisterContext_x86.h -----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,101 +10,470 @@ #ifndef liblldb_RegisterContext_x86_H_ #define liblldb_RegisterContext_x86_H_ +//--------------------------------------------------------------------------- +// i386 gcc, dwarf, gdb enums +//--------------------------------------------------------------------------- + +// Register numbers seen in eh_frame (eRegisterKindGCC) +// +// From Jason Molenda: "gcc registers" is the register numbering used in the eh_frame +// CFI. The only registers that are described in eh_frame CFI are those that are +// preserved across function calls aka callee-saved aka non-volatile. And none +// of the floating point registers on x86 are preserved across function calls. +// +// The only reason there is a "gcc register" and a "dwarf register" is because of a +// mistake years and years ago with i386 where they got esp and ebp +// backwards when they emitted the eh_frame instructions. Once there were +// binaries In The Wild using the reversed numbering, we had to stick with it +// forever. +enum +{ + // 2nd parameter in DwarfRegNum() is regnum for exception handling on x86-32. + // See http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register + gcc_eax_i386 = 0, + gcc_ecx_i386, + gcc_edx_i386, + gcc_ebx_i386, + gcc_ebp_i386, // Warning: these are switched from dwarf values + gcc_esp_i386, // + gcc_esi_i386, + gcc_edi_i386, + gcc_eip_i386, + gcc_eflags_i386, + gcc_st0_i386 = 12, + gcc_st1_i386, + gcc_st2_i386, + gcc_st3_i386, + gcc_st4_i386, + gcc_st5_i386, + gcc_st6_i386, + gcc_st7_i386, + gcc_xmm0_i386 = 21, + gcc_xmm1_i386, + gcc_xmm2_i386, + gcc_xmm3_i386, + gcc_xmm4_i386, + gcc_xmm5_i386, + gcc_xmm6_i386, + gcc_xmm7_i386, + gcc_mm0_i386 = 29, + gcc_mm1_i386, + gcc_mm2_i386, + gcc_mm3_i386, + gcc_mm4_i386, + gcc_mm5_i386, + gcc_mm6_i386, + gcc_mm7_i386, +}; + +// DWARF register numbers (eRegisterKindDWARF) +// Intel's x86 or IA-32 enum { - gcc_eax = 0, - gcc_ecx, - gcc_edx, - gcc_ebx, - gcc_ebp, - gcc_esp, - gcc_esi, - gcc_edi, - gcc_eip, - gcc_eflags + // General Purpose Registers. + dwarf_eax_i386 = 0, + dwarf_ecx_i386, + dwarf_edx_i386, + dwarf_ebx_i386, + dwarf_esp_i386, + dwarf_ebp_i386, + dwarf_esi_i386, + dwarf_edi_i386, + dwarf_eip_i386, + dwarf_eflags_i386, + // Floating Point Registers + dwarf_st0_i386 = 11, + dwarf_st1_i386, + dwarf_st2_i386, + dwarf_st3_i386, + dwarf_st4_i386, + dwarf_st5_i386, + dwarf_st6_i386, + dwarf_st7_i386, + // SSE Registers + dwarf_xmm0_i386 = 21, + dwarf_xmm1_i386, + dwarf_xmm2_i386, + dwarf_xmm3_i386, + dwarf_xmm4_i386, + dwarf_xmm5_i386, + dwarf_xmm6_i386, + dwarf_xmm7_i386, + // MMX Registers + dwarf_mm0_i386 = 29, + dwarf_mm1_i386, + dwarf_mm2_i386, + dwarf_mm3_i386, + dwarf_mm4_i386, + dwarf_mm5_i386, + dwarf_mm6_i386, + dwarf_mm7_i386, + dwarf_fctrl_i386 = 37, // x87 control word + dwarf_fstat_i386 = 38, // x87 status word + dwarf_mxcsr_i386 = 39, + dwarf_es_i386 = 40, + dwarf_cs_i386 = 41, + dwarf_ss_i386 = 42, + dwarf_ds_i386 = 43, + dwarf_fs_i386 = 44, + dwarf_gs_i386 = 45 + + // I believe the ymm registers use the dwarf_xmm%_i386 register numbers and + // then differentiate based on size of the register. }; +// Register numbers GDB uses (eRegisterKindGDB) +// +// From Jason Molenda: The "gdb numbers" are what you would see in the stabs debug format. enum { - dwarf_eax = 0, - dwarf_ecx, - dwarf_edx, - dwarf_ebx, - dwarf_esp, - dwarf_ebp, - dwarf_esi, - dwarf_edi, - dwarf_eip, - dwarf_eflags, - dwarf_stmm0 = 11, - dwarf_stmm1, - dwarf_stmm2, - dwarf_stmm3, - dwarf_stmm4, - dwarf_stmm5, - dwarf_stmm6, - dwarf_stmm7, - dwarf_xmm0 = 21, - dwarf_xmm1, - dwarf_xmm2, - dwarf_xmm3, - dwarf_xmm4, - dwarf_xmm5, - dwarf_xmm6, - dwarf_xmm7 + gdb_eax_i386, + gdb_ecx_i386, + gdb_edx_i386, + gdb_ebx_i386, + gdb_esp_i386, + gdb_ebp_i386, + gdb_esi_i386, + gdb_edi_i386, + gdb_eip_i386, + gdb_eflags_i386, + gdb_cs_i386, + gdb_ss_i386, + gdb_ds_i386, + gdb_es_i386, + gdb_fs_i386, + gdb_gs_i386, + gdb_st0_i386 = 16, + gdb_st1_i386, + gdb_st2_i386, + gdb_st3_i386, + gdb_st4_i386, + gdb_st5_i386, + gdb_st6_i386, + gdb_st7_i386, + gdb_fctrl_i386, // FPU Control Word + gdb_fstat_i386, // FPU Status Word + gdb_ftag_i386, // FPU Tag Word + gdb_fiseg_i386, // FPU IP Selector + gdb_fioff_i386, // FPU IP Offset + gdb_foseg_i386, // FPU Operand Pointer Selector + gdb_fooff_i386, // FPU Operand Pointer Offset + gdb_fop_i386, // Last Instruction Opcode + gdb_xmm0_i386 = 32, + gdb_xmm1_i386, + gdb_xmm2_i386, + gdb_xmm3_i386, + gdb_xmm4_i386, + gdb_xmm5_i386, + gdb_xmm6_i386, + gdb_xmm7_i386, + gdb_mxcsr_i386 = 40, + gdb_ymm0h_i386, + gdb_ymm1h_i386, + gdb_ymm2h_i386, + gdb_ymm3h_i386, + gdb_ymm4h_i386, + gdb_ymm5h_i386, + gdb_ymm6h_i386, + gdb_ymm7h_i386, + gdb_mm0_i386, + gdb_mm1_i386, + gdb_mm2_i386, + gdb_mm3_i386, + gdb_mm4_i386, + gdb_mm5_i386, + gdb_mm6_i386, + gdb_mm7_i386, }; +//--------------------------------------------------------------------------- +// AMD x86_64, AMD64, Intel EM64T, or Intel 64 gcc, dwarf, gdb enums +//--------------------------------------------------------------------------- + +// GCC and DWARF Register numbers (eRegisterKindGCC & eRegisterKindDWARF) +// This is the spec I used (as opposed to x86-64-abi-0.99.pdf): +// http://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf enum { - gdb_eax = 0, - gdb_ecx = 1, - gdb_edx = 2, - gdb_ebx = 3, - gdb_esp = 4, - gdb_ebp = 5, - gdb_esi = 6, - gdb_edi = 7, - gdb_eip = 8, - gdb_eflags = 9, - gdb_cs = 10, - gdb_ss = 11, - gdb_ds = 12, - gdb_es = 13, - gdb_fs = 14, - gdb_gs = 15, - gdb_stmm0 = 16, - gdb_stmm1 = 17, - gdb_stmm2 = 18, - gdb_stmm3 = 19, - gdb_stmm4 = 20, - gdb_stmm5 = 21, - gdb_stmm6 = 22, - gdb_stmm7 = 23, - gdb_fcw = 24, - gdb_fsw = 25, - gdb_ftw = 26, - gdb_fpu_cs = 27, - gdb_ip = 28, - gdb_fpu_ds = 29, - gdb_dp = 30, - gdb_fop = 31, - gdb_xmm0 = 32, - gdb_xmm1 = 33, - gdb_xmm2 = 34, - gdb_xmm3 = 35, - gdb_xmm4 = 36, - gdb_xmm5 = 37, - gdb_xmm6 = 38, - gdb_xmm7 = 39, - gdb_mxcsr = 40, - gdb_mm0 = 41, - gdb_mm1 = 42, - gdb_mm2 = 43, - gdb_mm3 = 44, - gdb_mm4 = 45, - gdb_mm5 = 46, - gdb_mm6 = 47, - gdb_mm7 = 48 + // GP Registers + gcc_dwarf_rax_x86_64 = 0, + gcc_dwarf_rdx_x86_64, + gcc_dwarf_rcx_x86_64, + gcc_dwarf_rbx_x86_64, + gcc_dwarf_rsi_x86_64, + gcc_dwarf_rdi_x86_64, + gcc_dwarf_rbp_x86_64, + gcc_dwarf_rsp_x86_64, + // Extended GP Registers + gcc_dwarf_r8_x86_64 = 8, + gcc_dwarf_r9_x86_64, + gcc_dwarf_r10_x86_64, + gcc_dwarf_r11_x86_64, + gcc_dwarf_r12_x86_64, + gcc_dwarf_r13_x86_64, + gcc_dwarf_r14_x86_64, + gcc_dwarf_r15_x86_64, + // Return Address (RA) mapped to RIP + gcc_dwarf_rip_x86_64 = 16, + // SSE Vector Registers + gcc_dwarf_xmm0_x86_64 = 17, + gcc_dwarf_xmm1_x86_64, + gcc_dwarf_xmm2_x86_64, + gcc_dwarf_xmm3_x86_64, + gcc_dwarf_xmm4_x86_64, + gcc_dwarf_xmm5_x86_64, + gcc_dwarf_xmm6_x86_64, + gcc_dwarf_xmm7_x86_64, + gcc_dwarf_xmm8_x86_64, + gcc_dwarf_xmm9_x86_64, + gcc_dwarf_xmm10_x86_64, + gcc_dwarf_xmm11_x86_64, + gcc_dwarf_xmm12_x86_64, + gcc_dwarf_xmm13_x86_64, + gcc_dwarf_xmm14_x86_64, + gcc_dwarf_xmm15_x86_64, + // Floating Point Registers + gcc_dwarf_st0_x86_64 = 33, + gcc_dwarf_st1_x86_64, + gcc_dwarf_st2_x86_64, + gcc_dwarf_st3_x86_64, + gcc_dwarf_st4_x86_64, + gcc_dwarf_st5_x86_64, + gcc_dwarf_st6_x86_64, + gcc_dwarf_st7_x86_64, + // MMX Registers + gcc_dwarf_mm0_x86_64 = 41, + gcc_dwarf_mm1_x86_64, + gcc_dwarf_mm2_x86_64, + gcc_dwarf_mm3_x86_64, + gcc_dwarf_mm4_x86_64, + gcc_dwarf_mm5_x86_64, + gcc_dwarf_mm6_x86_64, + gcc_dwarf_mm7_x86_64, + // Control and Status Flags Register + gcc_dwarf_rflags_x86_64 = 49, + // selector registers + gcc_dwarf_es_x86_64 = 50, + gcc_dwarf_cs_x86_64, + gcc_dwarf_ss_x86_64, + gcc_dwarf_ds_x86_64, + gcc_dwarf_fs_x86_64, + gcc_dwarf_gs_x86_64, + // Floating point control registers + gcc_dwarf_mxcsr_x86_64 = 64, // Media Control and Status + gcc_dwarf_fctrl_x86_64, // x87 control word + gcc_dwarf_fstat_x86_64, // x87 status word + // Upper Vector Registers + gcc_dwarf_ymm0h_x86_64 = 67, + gcc_dwarf_ymm1h_x86_64, + gcc_dwarf_ymm2h_x86_64, + gcc_dwarf_ymm3h_x86_64, + gcc_dwarf_ymm4h_x86_64, + gcc_dwarf_ymm5h_x86_64, + gcc_dwarf_ymm6h_x86_64, + gcc_dwarf_ymm7h_x86_64, + gcc_dwarf_ymm8h_x86_64, + gcc_dwarf_ymm9h_x86_64, + gcc_dwarf_ymm10h_x86_64, + gcc_dwarf_ymm11h_x86_64, + gcc_dwarf_ymm12h_x86_64, + gcc_dwarf_ymm13h_x86_64, + gcc_dwarf_ymm14h_x86_64, + gcc_dwarf_ymm15h_x86_64, + // AVX2 Vector Mask Registers + // gcc_dwarf_k0_x86_64 = 118, + // gcc_dwarf_k1_x86_64, + // gcc_dwarf_k2_x86_64, + // gcc_dwarf_k3_x86_64, + // gcc_dwarf_k4_x86_64, + // gcc_dwarf_k5_x86_64, + // gcc_dwarf_k6_x86_64, + // gcc_dwarf_k7_x86_64, +}; + +// GDB Register numbers (eRegisterKindGDB) +enum +{ + // GP Registers + gdb_rax_x86_64 = 0, + gdb_rbx_x86_64, + gdb_rcx_x86_64, + gdb_rdx_x86_64, + gdb_rsi_x86_64, + gdb_rdi_x86_64, + gdb_rbp_x86_64, + gdb_rsp_x86_64, + // Extended GP Registers + gdb_r8_x86_64, + gdb_r9_x86_64, + gdb_r10_x86_64, + gdb_r11_x86_64, + gdb_r12_x86_64, + gdb_r13_x86_64, + gdb_r14_x86_64, + gdb_r15_x86_64, + // Return Address (RA) mapped to RIP + gdb_rip_x86_64, + // Control and Status Flags Register + gdb_rflags_x86_64, + gdb_cs_x86_64, + gdb_ss_x86_64, + gdb_ds_x86_64, + gdb_es_x86_64, + gdb_fs_x86_64, + gdb_gs_x86_64, + // Floating Point Registers + gdb_st0_x86_64, + gdb_st1_x86_64, + gdb_st2_x86_64, + gdb_st3_x86_64, + gdb_st4_x86_64, + gdb_st5_x86_64, + gdb_st6_x86_64, + gdb_st7_x86_64, + gdb_fctrl_x86_64, + gdb_fstat_x86_64, + gdb_ftag_x86_64, + gdb_fiseg_x86_64, + gdb_fioff_x86_64, + gdb_foseg_x86_64, + gdb_fooff_x86_64, + gdb_fop_x86_64, + // SSE Vector Registers + gdb_xmm0_x86_64 = 40, + gdb_xmm1_x86_64, + gdb_xmm2_x86_64, + gdb_xmm3_x86_64, + gdb_xmm4_x86_64, + gdb_xmm5_x86_64, + gdb_xmm6_x86_64, + gdb_xmm7_x86_64, + gdb_xmm8_x86_64, + gdb_xmm9_x86_64, + gdb_xmm10_x86_64, + gdb_xmm11_x86_64, + gdb_xmm12_x86_64, + gdb_xmm13_x86_64, + gdb_xmm14_x86_64, + gdb_xmm15_x86_64, + // Floating point control registers + gdb_mxcsr_x86_64 = 56, + gdb_ymm0h_x86_64, + gdb_ymm1h_x86_64, + gdb_ymm2h_x86_64, + gdb_ymm3h_x86_64, + gdb_ymm4h_x86_64, + gdb_ymm5h_x86_64, + gdb_ymm6h_x86_64, + gdb_ymm7h_x86_64, + gdb_ymm8h_x86_64, + gdb_ymm9h_x86_64, + gdb_ymm10h_x86_64, + gdb_ymm11h_x86_64, + gdb_ymm12h_x86_64, + gdb_ymm13h_x86_64, + gdb_ymm14h_x86_64, + gdb_ymm15h_x86_64 +}; + +//--------------------------------------------------------------------------- +// Generic floating-point registers +//--------------------------------------------------------------------------- + +struct MMSReg +{ + uint8_t bytes[10]; + uint8_t pad[6]; +}; + +struct XMMReg +{ + uint8_t bytes[16]; // 128-bits for each XMM register +}; + +// i387_fxsave_struct +struct FXSAVE +{ + uint16_t fctrl; // FPU Control Word (fcw) + uint16_t fstat; // FPU Status Word (fsw) + uint16_t ftag; // FPU Tag Word (ftw) + uint16_t fop; // Last Instruction Opcode (fop) + union + { + struct + { + uint64_t fip; // Instruction Pointer + uint64_t fdp; // Data Pointer + } x86_64; + struct + { + uint32_t fioff; // FPU IP Offset (fip) + uint32_t fiseg; // FPU IP Selector (fcs) + uint32_t fooff; // FPU Operand Pointer Offset (foo) + uint32_t foseg; // FPU Operand Pointer Selector (fos) + } i386; + } ptr; + uint32_t mxcsr; // MXCSR Register State + uint32_t mxcsrmask; // MXCSR Mask + MMSReg stmm[8]; // 8*16 bytes for each FP-reg = 128 bytes + XMMReg xmm[16]; // 16*16 bytes for each XMM-reg = 256 bytes + uint32_t padding[24]; +}; + +//--------------------------------------------------------------------------- +// Extended floating-point registers +//--------------------------------------------------------------------------- + +struct YMMHReg +{ + uint8_t bytes[16]; // 16 * 8 bits for the high bytes of each YMM register +}; + +struct YMMReg +{ + uint8_t bytes[32]; // 16 * 16 bits for each YMM register +}; + +struct YMM +{ + YMMReg ymm[16]; // assembled from ymmh and xmm registers +}; + +struct XSAVE_HDR +{ + uint64_t xstate_bv; // OS enabled xstate mask to determine the extended states supported by the processor + uint64_t reserved1[2]; + uint64_t reserved2[5]; +} __attribute__((packed)); + +// x86 extensions to FXSAVE (i.e. for AVX processors) +struct XSAVE +{ + FXSAVE i387; // floating point registers typical in i387_fxsave_struct + XSAVE_HDR header; // The xsave_hdr_struct can be used to determine if the following extensions are usable + YMMHReg ymmh[16]; // High 16 bytes of each of 16 YMM registers (the low bytes are in FXSAVE.xmm for compatibility with SSE) + // Slot any extensions to the register file here +} __attribute__((packed, aligned (64))); + +// Floating-point registers +struct FPR +{ + // Thread state for the floating-point unit of the processor read by ptrace. + union XSTATE + { + FXSAVE fxsave; // Generic floating-point registers. + XSAVE xsave; // x86 extended processor state. + } xstate; +}; + +//--------------------------------------------------------------------------- +// ptrace PTRACE_GETREGSET, PTRACE_SETREGSET structure +//--------------------------------------------------------------------------- + +struct IOVEC +{ + void *iov_base; // pointer to XSAVE + size_t iov_len; // sizeof(XSAVE) }; #endif diff --git a/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp b/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp deleted file mode 100644 index 617b18484e5a..000000000000 --- a/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp +++ /dev/null @@ -1,1563 +0,0 @@ -//===-- RegisterContext_x86_64.cpp -------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <cstring> -#include <errno.h> -#include <stdint.h> - -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/DataExtractor.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/Scalar.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" -#include "lldb/Host/Endian.h" -#include "llvm/Support/Compiler.h" - -#include "ProcessPOSIX.h" -#if defined(__linux__) or defined(__FreeBSD__) -#include "ProcessMonitor.h" -#endif -#include "RegisterContext_i386.h" -#include "RegisterContext_x86.h" -#include "RegisterContext_x86_64.h" -#include "Plugins/Process/elf-core/ProcessElfCore.h" - -using namespace lldb_private; -using namespace lldb; - -// Support ptrace extensions even when compiled without required kernel support -#ifndef NT_X86_XSTATE - #define NT_X86_XSTATE 0x202 -#endif - -enum -{ - gcc_dwarf_gpr_rax = 0, - gcc_dwarf_gpr_rdx, - gcc_dwarf_gpr_rcx, - gcc_dwarf_gpr_rbx, - gcc_dwarf_gpr_rsi, - gcc_dwarf_gpr_rdi, - gcc_dwarf_gpr_rbp, - gcc_dwarf_gpr_rsp, - gcc_dwarf_gpr_r8, - gcc_dwarf_gpr_r9, - gcc_dwarf_gpr_r10, - gcc_dwarf_gpr_r11, - gcc_dwarf_gpr_r12, - gcc_dwarf_gpr_r13, - gcc_dwarf_gpr_r14, - gcc_dwarf_gpr_r15, - gcc_dwarf_gpr_rip, - gcc_dwarf_fpu_xmm0, - gcc_dwarf_fpu_xmm1, - gcc_dwarf_fpu_xmm2, - gcc_dwarf_fpu_xmm3, - gcc_dwarf_fpu_xmm4, - gcc_dwarf_fpu_xmm5, - gcc_dwarf_fpu_xmm6, - gcc_dwarf_fpu_xmm7, - gcc_dwarf_fpu_xmm8, - gcc_dwarf_fpu_xmm9, - gcc_dwarf_fpu_xmm10, - gcc_dwarf_fpu_xmm11, - gcc_dwarf_fpu_xmm12, - gcc_dwarf_fpu_xmm13, - gcc_dwarf_fpu_xmm14, - gcc_dwarf_fpu_xmm15, - gcc_dwarf_fpu_stmm0, - gcc_dwarf_fpu_stmm1, - gcc_dwarf_fpu_stmm2, - gcc_dwarf_fpu_stmm3, - gcc_dwarf_fpu_stmm4, - gcc_dwarf_fpu_stmm5, - gcc_dwarf_fpu_stmm6, - gcc_dwarf_fpu_stmm7, - gcc_dwarf_fpu_ymm0, - gcc_dwarf_fpu_ymm1, - gcc_dwarf_fpu_ymm2, - gcc_dwarf_fpu_ymm3, - gcc_dwarf_fpu_ymm4, - gcc_dwarf_fpu_ymm5, - gcc_dwarf_fpu_ymm6, - gcc_dwarf_fpu_ymm7, - gcc_dwarf_fpu_ymm8, - gcc_dwarf_fpu_ymm9, - gcc_dwarf_fpu_ymm10, - gcc_dwarf_fpu_ymm11, - gcc_dwarf_fpu_ymm12, - gcc_dwarf_fpu_ymm13, - gcc_dwarf_fpu_ymm14, - gcc_dwarf_fpu_ymm15 -}; - -enum -{ - gdb_gpr_rax = 0, - gdb_gpr_rbx = 1, - gdb_gpr_rcx = 2, - gdb_gpr_rdx = 3, - gdb_gpr_rsi = 4, - gdb_gpr_rdi = 5, - gdb_gpr_rbp = 6, - gdb_gpr_rsp = 7, - gdb_gpr_r8 = 8, - gdb_gpr_r9 = 9, - gdb_gpr_r10 = 10, - gdb_gpr_r11 = 11, - gdb_gpr_r12 = 12, - gdb_gpr_r13 = 13, - gdb_gpr_r14 = 14, - gdb_gpr_r15 = 15, - gdb_gpr_rip = 16, - gdb_gpr_rflags = 17, - gdb_gpr_cs = 18, - gdb_gpr_ss = 19, - gdb_gpr_ds = 20, - gdb_gpr_es = 21, - gdb_gpr_fs = 22, - gdb_gpr_gs = 23, - gdb_fpu_stmm0 = 24, - gdb_fpu_stmm1 = 25, - gdb_fpu_stmm2 = 26, - gdb_fpu_stmm3 = 27, - gdb_fpu_stmm4 = 28, - gdb_fpu_stmm5 = 29, - gdb_fpu_stmm6 = 30, - gdb_fpu_stmm7 = 31, - gdb_fpu_fcw = 32, - gdb_fpu_fsw = 33, - gdb_fpu_ftw = 34, - gdb_fpu_cs_64 = 35, - gdb_fpu_ip = 36, - gdb_fpu_ds_64 = 37, - gdb_fpu_dp = 38, - gdb_fpu_fop = 39, - gdb_fpu_xmm0 = 40, - gdb_fpu_xmm1 = 41, - gdb_fpu_xmm2 = 42, - gdb_fpu_xmm3 = 43, - gdb_fpu_xmm4 = 44, - gdb_fpu_xmm5 = 45, - gdb_fpu_xmm6 = 46, - gdb_fpu_xmm7 = 47, - gdb_fpu_xmm8 = 48, - gdb_fpu_xmm9 = 49, - gdb_fpu_xmm10 = 50, - gdb_fpu_xmm11 = 51, - gdb_fpu_xmm12 = 52, - gdb_fpu_xmm13 = 53, - gdb_fpu_xmm14 = 54, - gdb_fpu_xmm15 = 55, - gdb_fpu_mxcsr = 56, - gdb_fpu_ymm0 = 57, - gdb_fpu_ymm1 = 58, - gdb_fpu_ymm2 = 59, - gdb_fpu_ymm3 = 60, - gdb_fpu_ymm4 = 61, - gdb_fpu_ymm5 = 62, - gdb_fpu_ymm6 = 63, - gdb_fpu_ymm7 = 64, - gdb_fpu_ymm8 = 65, - gdb_fpu_ymm9 = 66, - gdb_fpu_ymm10 = 67, - gdb_fpu_ymm11 = 68, - gdb_fpu_ymm12 = 69, - gdb_fpu_ymm13 = 70, - gdb_fpu_ymm14 = 71, - gdb_fpu_ymm15 = 72 -}; - -static const -uint32_t g_gpr_regnums[k_num_gpr_registers] = -{ - gpr_rax, - gpr_rbx, - gpr_rcx, - gpr_rdx, - gpr_rdi, - gpr_rsi, - gpr_rbp, - gpr_rsp, - gpr_r8, - gpr_r9, - gpr_r10, - gpr_r11, - gpr_r12, - gpr_r13, - gpr_r14, - gpr_r15, - gpr_rip, - gpr_rflags, - gpr_cs, - gpr_fs, - gpr_gs, - gpr_ss, - gpr_ds, - gpr_es, - gpr_eax, - gpr_ebx, - gpr_ecx, - gpr_edx, - gpr_edi, - gpr_esi, - gpr_ebp, - gpr_esp, - gpr_eip, - gpr_eflags -}; - -static const uint32_t -g_fpu_regnums[k_num_fpr_registers] = -{ - fpu_fcw, - fpu_fsw, - fpu_ftw, - fpu_fop, - fpu_ip, - fpu_cs, - fpu_dp, - fpu_ds, - fpu_mxcsr, - fpu_mxcsrmask, - fpu_stmm0, - fpu_stmm1, - fpu_stmm2, - fpu_stmm3, - fpu_stmm4, - fpu_stmm5, - fpu_stmm6, - fpu_stmm7, - fpu_xmm0, - fpu_xmm1, - fpu_xmm2, - fpu_xmm3, - fpu_xmm4, - fpu_xmm5, - fpu_xmm6, - fpu_xmm7, - fpu_xmm8, - fpu_xmm9, - fpu_xmm10, - fpu_xmm11, - fpu_xmm12, - fpu_xmm13, - fpu_xmm14, - fpu_xmm15 -}; - -static const uint32_t -g_avx_regnums[k_num_avx_registers] = -{ - fpu_ymm0, - fpu_ymm1, - fpu_ymm2, - fpu_ymm3, - fpu_ymm4, - fpu_ymm5, - fpu_ymm6, - fpu_ymm7, - fpu_ymm8, - fpu_ymm9, - fpu_ymm10, - fpu_ymm11, - fpu_ymm12, - fpu_ymm13, - fpu_ymm14, - fpu_ymm15 -}; - -// Number of register sets provided by this context. -enum -{ - k_num_extended_register_sets = 1, - k_num_register_sets = 3 -}; - -static const RegisterSet -g_reg_sets[k_num_register_sets] = -{ - { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums }, - { "Floating Point Registers", "fpu", k_num_fpr_registers, g_fpu_regnums }, - { "Advanced Vector Extensions", "avx", k_num_avx_registers, g_avx_regnums } -}; - -// Computes the offset of the given FPR in the extended data area. -#define FPR_OFFSET(regname) \ - (offsetof(RegisterContext_x86_64::FPR, xstate) + \ - offsetof(RegisterContext_x86_64::FXSAVE, regname)) - -// Computes the offset of the YMM register assembled from register halves. -#define YMM_OFFSET(regname) \ - (offsetof(RegisterContext_x86_64::YMM, regname)) - -// Number of bytes needed to represent a i386 GPR -#define GPR_i386_SIZE(reg) sizeof(((RegisterContext_i386::GPR*)NULL)->reg) - -// Number of bytes needed to represent a FPR. -#define FPR_SIZE(reg) sizeof(((RegisterContext_x86_64::FXSAVE*)NULL)->reg) - -// Number of bytes needed to represent the i'th FP register. -#define FP_SIZE sizeof(((RegisterContext_x86_64::MMSReg*)NULL)->bytes) - -// Number of bytes needed to represent an XMM register. -#define XMM_SIZE sizeof(RegisterContext_x86_64::XMMReg) - -// Number of bytes needed to represent a YMM register. -#define YMM_SIZE sizeof(RegisterContext_x86_64::YMMReg) - -// Note that the size and offset will be updated by platform-specific classes. -#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ - { #reg, alt, 0, 0, eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg }, NULL, NULL } - -// Dummy data for RegisterInfo::value_regs as expected by DumpRegisterSet. -static uint32_t value_regs = LLDB_INVALID_REGNUM; - -#define DEFINE_GPR_i386(reg_i386, reg_x86_64, alt, kind1, kind2, kind3, kind4) \ - { #reg_i386, alt, GPR_i386_SIZE(reg_i386), 0, eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg_i386 }, &value_regs, NULL } - -#define DEFINE_FPR(reg, kind1, kind2, kind3, kind4) \ - { #reg, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, fpu_##reg }, NULL, NULL } - -#define DEFINE_FP(reg, i) \ - { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \ - eEncodingVector, eFormatVectorOfUInt8, \ - { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \ - LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL } - -#define DEFINE_XMM(reg, i) \ - { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \ - eEncodingVector, eFormatVectorOfUInt8, \ - { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \ - LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL } - -#define DEFINE_YMM(reg, i) \ - { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(reg[i]), \ - eEncodingVector, eFormatVectorOfUInt8, \ - { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \ - LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL } - -#define DEFINE_DR(reg, i) \ - { #reg#i, NULL, 0, 0, eEncodingUint, eFormatHex, \ - { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL } - -#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(RegisterContext_x86_64::FPR)) - -static RegisterInfo -g_register_infos[k_num_registers] = -{ - // General purpose registers. - DEFINE_GPR(rax, NULL, gcc_dwarf_gpr_rax, gcc_dwarf_gpr_rax, LLDB_INVALID_REGNUM, gdb_gpr_rax), - DEFINE_GPR(rbx, NULL, gcc_dwarf_gpr_rbx, gcc_dwarf_gpr_rbx, LLDB_INVALID_REGNUM, gdb_gpr_rbx), - DEFINE_GPR(rcx, NULL, gcc_dwarf_gpr_rcx, gcc_dwarf_gpr_rcx, LLDB_INVALID_REGNUM, gdb_gpr_rcx), - DEFINE_GPR(rdx, NULL, gcc_dwarf_gpr_rdx, gcc_dwarf_gpr_rdx, LLDB_INVALID_REGNUM, gdb_gpr_rdx), - DEFINE_GPR(rdi, NULL, gcc_dwarf_gpr_rdi, gcc_dwarf_gpr_rdi, LLDB_INVALID_REGNUM, gdb_gpr_rdi), - DEFINE_GPR(rsi, NULL, gcc_dwarf_gpr_rsi, gcc_dwarf_gpr_rsi, LLDB_INVALID_REGNUM, gdb_gpr_rsi), - DEFINE_GPR(rbp, "fp", gcc_dwarf_gpr_rbp, gcc_dwarf_gpr_rbp, LLDB_REGNUM_GENERIC_FP, gdb_gpr_rbp), - DEFINE_GPR(rsp, "sp", gcc_dwarf_gpr_rsp, gcc_dwarf_gpr_rsp, LLDB_REGNUM_GENERIC_SP, gdb_gpr_rsp), - DEFINE_GPR(r8, NULL, gcc_dwarf_gpr_r8, gcc_dwarf_gpr_r8, LLDB_INVALID_REGNUM, gdb_gpr_r8), - DEFINE_GPR(r9, NULL, gcc_dwarf_gpr_r9, gcc_dwarf_gpr_r9, LLDB_INVALID_REGNUM, gdb_gpr_r9), - DEFINE_GPR(r10, NULL, gcc_dwarf_gpr_r10, gcc_dwarf_gpr_r10, LLDB_INVALID_REGNUM, gdb_gpr_r10), - DEFINE_GPR(r11, NULL, gcc_dwarf_gpr_r11, gcc_dwarf_gpr_r11, LLDB_INVALID_REGNUM, gdb_gpr_r11), - DEFINE_GPR(r12, NULL, gcc_dwarf_gpr_r12, gcc_dwarf_gpr_r12, LLDB_INVALID_REGNUM, gdb_gpr_r12), - DEFINE_GPR(r13, NULL, gcc_dwarf_gpr_r13, gcc_dwarf_gpr_r13, LLDB_INVALID_REGNUM, gdb_gpr_r13), - DEFINE_GPR(r14, NULL, gcc_dwarf_gpr_r14, gcc_dwarf_gpr_r14, LLDB_INVALID_REGNUM, gdb_gpr_r14), - DEFINE_GPR(r15, NULL, gcc_dwarf_gpr_r15, gcc_dwarf_gpr_r15, LLDB_INVALID_REGNUM, gdb_gpr_r15), - DEFINE_GPR(rip, "pc", gcc_dwarf_gpr_rip, gcc_dwarf_gpr_rip, LLDB_REGNUM_GENERIC_PC, gdb_gpr_rip), - DEFINE_GPR(rflags, "flags", LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, gdb_gpr_rflags), - DEFINE_GPR(cs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_cs), - DEFINE_GPR(fs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_fs), - DEFINE_GPR(gs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_gs), - DEFINE_GPR(ss, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_ss), - DEFINE_GPR(ds, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_ds), - DEFINE_GPR(es, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_es), - // i386 registers - DEFINE_GPR_i386(eax, rax, NULL, gcc_eax, dwarf_eax, LLDB_INVALID_REGNUM, gdb_eax), - DEFINE_GPR_i386(ebx, rbx, NULL, gcc_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, gdb_ebx), - DEFINE_GPR_i386(ecx, rcx, NULL, gcc_ecx, dwarf_ecx, LLDB_INVALID_REGNUM, gdb_ecx), - DEFINE_GPR_i386(edx, rdx, NULL, gcc_edx, dwarf_edx, LLDB_INVALID_REGNUM, gdb_edx), - DEFINE_GPR_i386(edi, rdi, NULL, gcc_edi, dwarf_edi, LLDB_INVALID_REGNUM, gdb_edi), - DEFINE_GPR_i386(esi, rsi, NULL, gcc_esi, dwarf_esi, LLDB_INVALID_REGNUM, gdb_esi), - DEFINE_GPR_i386(ebp, rbp, "fp", gcc_ebp, dwarf_ebp, LLDB_REGNUM_GENERIC_FP, gdb_ebp), - DEFINE_GPR_i386(esp, rsp, "sp", gcc_esp, dwarf_esp, LLDB_REGNUM_GENERIC_SP, gdb_esp), - DEFINE_GPR_i386(eip, rip, "pc", gcc_eip, dwarf_eip, LLDB_REGNUM_GENERIC_PC, gdb_eip), - DEFINE_GPR_i386(eflags, rflags, "flags", gcc_eflags, dwarf_eflags, LLDB_REGNUM_GENERIC_FLAGS, gdb_eflags), - // i387 Floating point registers. - DEFINE_FPR(fcw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fcw), - DEFINE_FPR(fsw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fsw), - DEFINE_FPR(ftw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ftw), - DEFINE_FPR(fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fop), - DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ip), - // FIXME: Extract segment from ip. - DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_cs_64), - DEFINE_FPR(dp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_dp), - // FIXME: Extract segment from dp. - DEFINE_FPR(dp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ds_64), - DEFINE_FPR(mxcsr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_mxcsr), - DEFINE_FPR(mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - - // FP registers. - DEFINE_FP(stmm, 0), - DEFINE_FP(stmm, 1), - DEFINE_FP(stmm, 2), - DEFINE_FP(stmm, 3), - DEFINE_FP(stmm, 4), - DEFINE_FP(stmm, 5), - DEFINE_FP(stmm, 6), - DEFINE_FP(stmm, 7), - - // XMM registers - DEFINE_XMM(xmm, 0), - DEFINE_XMM(xmm, 1), - DEFINE_XMM(xmm, 2), - DEFINE_XMM(xmm, 3), - DEFINE_XMM(xmm, 4), - DEFINE_XMM(xmm, 5), - DEFINE_XMM(xmm, 6), - DEFINE_XMM(xmm, 7), - DEFINE_XMM(xmm, 8), - DEFINE_XMM(xmm, 9), - DEFINE_XMM(xmm, 10), - DEFINE_XMM(xmm, 11), - DEFINE_XMM(xmm, 12), - DEFINE_XMM(xmm, 13), - DEFINE_XMM(xmm, 14), - DEFINE_XMM(xmm, 15), - - // Copy of YMM registers assembled from xmm and ymmh - DEFINE_YMM(ymm, 0), - DEFINE_YMM(ymm, 1), - DEFINE_YMM(ymm, 2), - DEFINE_YMM(ymm, 3), - DEFINE_YMM(ymm, 4), - DEFINE_YMM(ymm, 5), - DEFINE_YMM(ymm, 6), - DEFINE_YMM(ymm, 7), - DEFINE_YMM(ymm, 8), - DEFINE_YMM(ymm, 9), - DEFINE_YMM(ymm, 10), - DEFINE_YMM(ymm, 11), - DEFINE_YMM(ymm, 12), - DEFINE_YMM(ymm, 13), - DEFINE_YMM(ymm, 14), - DEFINE_YMM(ymm, 15), - - // Debug registers for lldb internal use - DEFINE_DR(dr, 0), - DEFINE_DR(dr, 1), - DEFINE_DR(dr, 2), - DEFINE_DR(dr, 3), - DEFINE_DR(dr, 4), - DEFINE_DR(dr, 5), - DEFINE_DR(dr, 6), - DEFINE_DR(dr, 7) -}; - -static bool IsGPR(unsigned reg) -{ - return reg <= k_last_gpr; // GPR's come first. -} - -static bool IsAVX(unsigned reg) -{ - return (k_first_avx <= reg && reg <= k_last_avx); -} -static bool IsFPR(unsigned reg) -{ - return (k_first_fpr <= reg && reg <= k_last_fpr); -} - - -bool RegisterContext_x86_64::IsFPR(unsigned reg, FPRType fpr_type) -{ - bool generic_fpr = ::IsFPR(reg); - if (fpr_type == eXSAVE) - return generic_fpr || IsAVX(reg); - - return generic_fpr; -} - -RegisterContext_x86_64::RegisterContext_x86_64(Thread &thread, - uint32_t concrete_frame_idx) - : RegisterContextPOSIX(thread, concrete_frame_idx) -{ - // Initialize m_iovec to point to the buffer and buffer size - // using the conventions of Berkeley style UIO structures, as required - // by PTRACE extensions. - m_iovec.iov_base = &m_fpr.xstate.xsave; - m_iovec.iov_len = sizeof(m_fpr.xstate.xsave); - - ::memset(&m_fpr, 0, sizeof(RegisterContext_x86_64::FPR)); - - // elf-core yet to support ReadFPR() - ProcessSP base = CalculateProcess(); - if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic()) - return; - - // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx - m_fpr_type = eXSAVE; // extended floating-point registers, if available - if (false == ReadFPR()) - m_fpr_type = eFXSAVE; // assume generic floating-point registers -} - -RegisterContext_x86_64::~RegisterContext_x86_64() -{ -} - -void -RegisterContext_x86_64::Invalidate() -{ -} - -void -RegisterContext_x86_64::InvalidateAllRegisters() -{ -} - -unsigned -RegisterContext_x86_64::GetRegisterOffset(unsigned reg) -{ - assert(reg < k_num_registers && "Invalid register number."); - return GetRegisterInfo()[reg].byte_offset; -} - -unsigned -RegisterContext_x86_64::GetRegisterSize(unsigned reg) -{ - assert(reg < k_num_registers && "Invalid register number."); - return GetRegisterInfo()[reg].byte_size; -} - -size_t -RegisterContext_x86_64::GetRegisterCount() -{ - size_t num_registers = k_num_gpr_registers + k_num_fpr_registers; - if (m_fpr_type == eXSAVE) - return num_registers + k_num_avx_registers; - return num_registers; -} - -const RegisterInfo * -RegisterContext_x86_64::GetRegisterInfo() -{ - // Commonly, this method is overridden and g_register_infos is copied and specialized. - // So, use GetRegisterInfo() rather than g_register_infos in this scope. - return g_register_infos; -} - -const RegisterInfo * -RegisterContext_x86_64::GetRegisterInfoAtIndex(size_t reg) -{ - if (reg < k_num_registers) - return &GetRegisterInfo()[reg]; - else - return NULL; -} - -size_t -RegisterContext_x86_64::GetRegisterSetCount() -{ - size_t sets = 0; - for (size_t set = 0; set < k_num_register_sets; ++set) - if (IsRegisterSetAvailable(set)) - ++sets; - - return sets; -} - -const RegisterSet * -RegisterContext_x86_64::GetRegisterSet(size_t set) -{ - if (IsRegisterSetAvailable(set)) - return &g_reg_sets[set]; - else - return NULL; -} - -unsigned -RegisterContext_x86_64::GetRegisterIndexFromOffset(unsigned offset) -{ - unsigned reg; - for (reg = 0; reg < k_num_registers; reg++) - { - if (GetRegisterInfo()[reg].byte_offset == offset) - break; - } - assert(reg < k_num_registers && "Invalid register offset."); - return reg; -} - -const char * -RegisterContext_x86_64::GetRegisterName(unsigned reg) -{ - assert(reg < k_num_registers && "Invalid register offset."); - return GetRegisterInfo()[reg].name; -} - -lldb::ByteOrder -RegisterContext_x86_64::GetByteOrder() -{ - // Get the target process whose privileged thread was used for the register read. - lldb::ByteOrder byte_order = eByteOrderInvalid; - Process *process = CalculateProcess().get(); - - if (process) - byte_order = process->GetByteOrder(); - return byte_order; -} - -// Parse ymm registers and into xmm.bytes and ymmh.bytes. -bool RegisterContext_x86_64::CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order) -{ - if (!IsAVX(reg)) - return false; - - if (byte_order == eByteOrderLittle) { - ::memcpy(m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes, - m_ymm_set.ymm[reg - fpu_ymm0].bytes, - sizeof(RegisterContext_x86_64::XMMReg)); - ::memcpy(m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes, - m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg), - sizeof(RegisterContext_x86_64::YMMHReg)); - return true; - } - - if (byte_order == eByteOrderBig) { - ::memcpy(m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes, - m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg), - sizeof(RegisterContext_x86_64::XMMReg)); - ::memcpy(m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes, - m_ymm_set.ymm[reg - fpu_ymm0].bytes, - sizeof(RegisterContext_x86_64::YMMHReg)); - return true; - } - return false; // unsupported or invalid byte order -} - -// Concatenate xmm.bytes with ymmh.bytes -bool RegisterContext_x86_64::CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order) -{ - if (!IsAVX(reg)) - return false; - - if (byte_order == eByteOrderLittle) { - ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes, - m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes, - sizeof(RegisterContext_x86_64::XMMReg)); - ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg), - m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes, - sizeof(RegisterContext_x86_64::YMMHReg)); - return true; - } - if (byte_order == eByteOrderBig) { - ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg), - m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes, - sizeof(RegisterContext_x86_64::XMMReg)); - ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes, - m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes, - sizeof(RegisterContext_x86_64::YMMHReg)); - return true; - } - return false; // unsupported or invalid byte order -} - -bool -RegisterContext_x86_64::IsRegisterSetAvailable(size_t set_index) -{ - // Note: Extended register sets are assumed to be at the end of g_reg_sets... - size_t num_sets = k_num_register_sets - k_num_extended_register_sets; - if (m_fpr_type == eXSAVE) // ...and to start with AVX registers. - ++num_sets; - - return (set_index < num_sets); -} - -bool -RegisterContext_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) -{ - if (!reg_info) - return false; - - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - - if (IsFPR(reg, m_fpr_type)) { - if (!ReadFPR()) - return false; - } - else { - bool success = ReadRegister(reg, value); - - // If an i386 register should be parsed from an x86_64 register... - if (success && reg >= k_first_i386 && reg <= k_last_i386) - if (value.GetByteSize() > reg_info->byte_size) - value.SetType(reg_info); // ...use the type specified by reg_info rather than the uint64_t default - return success; - } - - if (reg_info->encoding == eEncodingVector) { - ByteOrder byte_order = GetByteOrder(); - - if (byte_order != ByteOrder::eByteOrderInvalid) { - if (reg >= fpu_stmm0 && reg <= fpu_stmm7) { - value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, byte_order); - } - if (reg >= fpu_xmm0 && reg <= fpu_xmm15) { - value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, byte_order); - } - if (reg >= fpu_ymm0 && reg <= fpu_ymm15) { - // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes - if (m_fpr_type == eXSAVE && CopyXSTATEtoYMM(reg, byte_order)) - value.SetBytes(m_ymm_set.ymm[reg - fpu_ymm0].bytes, reg_info->byte_size, byte_order); - else - return false; - } - return value.GetType() == RegisterValue::eTypeBytes; - } - return false; - } - - // Note that lldb uses slightly different naming conventions from sys/user.h - switch (reg) - { - default: - return false; - case fpu_dp: - value = m_fpr.xstate.fxsave.dp; - break; - case fpu_fcw: - value = m_fpr.xstate.fxsave.fcw; - break; - case fpu_fsw: - value = m_fpr.xstate.fxsave.fsw; - break; - case fpu_ip: - value = m_fpr.xstate.fxsave.ip; - break; - case fpu_fop: - value = m_fpr.xstate.fxsave.fop; - break; - case fpu_ftw: - value = m_fpr.xstate.fxsave.ftw; - break; - case fpu_mxcsr: - value = m_fpr.xstate.fxsave.mxcsr; - break; - case fpu_mxcsrmask: - value = m_fpr.xstate.fxsave.mxcsrmask; - break; - } - return true; -} - -bool -RegisterContext_x86_64::ReadAllRegisterValues(DataBufferSP &data_sp) -{ - bool success = false; - data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); - if (data_sp && ReadGPR () && ReadFPR ()) - { - uint8_t *dst = data_sp->GetBytes(); - success = dst != 0; - - if (success) { - ::memcpy (dst, &m_gpr, GetGPRSize()); - dst += GetGPRSize(); - } - if (m_fpr_type == eFXSAVE) - ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); - - if (m_fpr_type == eXSAVE) { - ByteOrder byte_order = GetByteOrder(); - - // Assemble the YMM register content from the register halves. - for (uint32_t reg = fpu_ymm0; success && reg <= fpu_ymm15; ++reg) - success = CopyXSTATEtoYMM(reg, byte_order); - - if (success) { - // Copy the extended register state including the assembled ymm registers. - ::memcpy (dst, &m_fpr, sizeof(m_fpr)); - } - } - } - return success; -} - -bool -RegisterContext_x86_64::WriteRegister(const lldb_private::RegisterInfo *reg_info, - const lldb_private::RegisterValue &value) -{ - const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - if (IsGPR(reg)) { - return WriteRegister(reg, value); - } - - if (IsFPR(reg, m_fpr_type)) { - switch (reg) - { - default: - if (reg_info->encoding != eEncodingVector) - return false; - - if (reg >= fpu_stmm0 && reg <= fpu_stmm7) - ::memcpy (m_fpr.xstate.fxsave.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize()); - - if (reg >= fpu_xmm0 && reg <= fpu_xmm15) - ::memcpy (m_fpr.xstate.fxsave.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize()); - - if (reg >= fpu_ymm0 && reg <= fpu_ymm15) { - if (m_fpr_type != eXSAVE) - return false; // the target processor does not support AVX - - // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes - ::memcpy (m_ymm_set.ymm[reg - fpu_ymm0].bytes, value.GetBytes(), value.GetByteSize()); - if (false == CopyYMMtoXSTATE(reg, GetByteOrder())) - return false; - } - break; - case fpu_dp: - m_fpr.xstate.fxsave.dp = value.GetAsUInt64(); - break; - case fpu_fcw: - m_fpr.xstate.fxsave.fcw = value.GetAsUInt16(); - break; - case fpu_fsw: - m_fpr.xstate.fxsave.fsw = value.GetAsUInt16(); - break; - case fpu_ip: - m_fpr.xstate.fxsave.ip = value.GetAsUInt64(); - break; - case fpu_fop: - m_fpr.xstate.fxsave.fop = value.GetAsUInt16(); - break; - case fpu_ftw: - m_fpr.xstate.fxsave.ftw = value.GetAsUInt16(); - break; - case fpu_mxcsr: - m_fpr.xstate.fxsave.mxcsr = value.GetAsUInt32(); - break; - case fpu_mxcsrmask: - m_fpr.xstate.fxsave.mxcsrmask = value.GetAsUInt32(); - break; - } - if (WriteFPR()) { - if (IsAVX(reg)) - return CopyYMMtoXSTATE(reg, GetByteOrder()); - return true; - } - } - return false; -} - -bool -RegisterContext_x86_64::WriteAllRegisterValues(const DataBufferSP &data_sp) -{ - bool success = false; - if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) - { - uint8_t *src = data_sp->GetBytes(); - if (src) { - ::memcpy (&m_gpr, src, GetGPRSize()); - - if (WriteGPR()) { - src += GetGPRSize(); - if (m_fpr_type == eFXSAVE) - ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave)); - if (m_fpr_type == eXSAVE) - ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave)); - - success = WriteFPR(); - if (success) { - success = true; - - if (m_fpr_type == eXSAVE) { - ByteOrder byte_order = GetByteOrder(); - - // Parse the YMM register content from the register halves. - for (uint32_t reg = fpu_ymm0; success && reg <= fpu_ymm15; ++reg) - success = CopyYMMtoXSTATE(reg, byte_order); - } - } - } - } - } - return success; -} - -bool -RegisterContext_x86_64::UpdateAfterBreakpoint() -{ - // PC points one byte past the int3 responsible for the breakpoint. - lldb::addr_t pc; - - if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) - return false; - - SetPC(pc - 1); - return true; -} - -uint32_t -RegisterContext_x86_64::ConvertRegisterKindToRegisterNumber(uint32_t kind, - uint32_t num) -{ - const Process *process = CalculateProcess().get(); - if (process) - { - const ArchSpec arch = process->GetTarget().GetArchitecture();; - switch (arch.GetCore()) - { - default: - assert(false && "CPU type not supported!"); - break; - - case ArchSpec::eCore_x86_32_i386: - case ArchSpec::eCore_x86_32_i486: - case ArchSpec::eCore_x86_32_i486sx: - { - if (kind == eRegisterKindGeneric) - { - switch (num) - { - case LLDB_REGNUM_GENERIC_PC: return gpr_eip; - case LLDB_REGNUM_GENERIC_SP: return gpr_esp; - case LLDB_REGNUM_GENERIC_FP: return gpr_ebp; - case LLDB_REGNUM_GENERIC_FLAGS: return gpr_eflags; - case LLDB_REGNUM_GENERIC_RA: - default: - return LLDB_INVALID_REGNUM; - } - } - - if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF) - { - switch (num) - { - case dwarf_eax: return gpr_eax; - case dwarf_edx: return gpr_edx; - case dwarf_ecx: return gpr_ecx; - case dwarf_ebx: return gpr_ebx; - case dwarf_esi: return gpr_esi; - case dwarf_edi: return gpr_edi; - case dwarf_ebp: return gpr_ebp; - case dwarf_esp: return gpr_esp; - case dwarf_eip: return gpr_eip; - case dwarf_xmm0: return fpu_xmm0; - case dwarf_xmm1: return fpu_xmm1; - case dwarf_xmm2: return fpu_xmm2; - case dwarf_xmm3: return fpu_xmm3; - case dwarf_xmm4: return fpu_xmm4; - case dwarf_xmm5: return fpu_xmm5; - case dwarf_xmm6: return fpu_xmm6; - case dwarf_xmm7: return fpu_xmm7; - case dwarf_stmm0: return fpu_stmm0; - case dwarf_stmm1: return fpu_stmm1; - case dwarf_stmm2: return fpu_stmm2; - case dwarf_stmm3: return fpu_stmm3; - case dwarf_stmm4: return fpu_stmm4; - case dwarf_stmm5: return fpu_stmm5; - case dwarf_stmm6: return fpu_stmm6; - case dwarf_stmm7: return fpu_stmm7; - default: - return LLDB_INVALID_REGNUM; - } - } - - if (kind == eRegisterKindGDB) - { - switch (num) - { - case gdb_eax : return gpr_eax; - case gdb_ebx : return gpr_ebx; - case gdb_ecx : return gpr_ecx; - case gdb_edx : return gpr_edx; - case gdb_esi : return gpr_esi; - case gdb_edi : return gpr_edi; - case gdb_ebp : return gpr_ebp; - case gdb_esp : return gpr_esp; - case gdb_eip : return gpr_eip; - case gdb_eflags : return gpr_eflags; - case gdb_cs : return gpr_cs; - case gdb_ss : return gpr_ss; - case gdb_ds : return gpr_ds; - case gdb_es : return gpr_es; - case gdb_fs : return gpr_fs; - case gdb_gs : return gpr_gs; - case gdb_stmm0 : return fpu_stmm0; - case gdb_stmm1 : return fpu_stmm1; - case gdb_stmm2 : return fpu_stmm2; - case gdb_stmm3 : return fpu_stmm3; - case gdb_stmm4 : return fpu_stmm4; - case gdb_stmm5 : return fpu_stmm5; - case gdb_stmm6 : return fpu_stmm6; - case gdb_stmm7 : return fpu_stmm7; - case gdb_fcw : return fpu_fcw; - case gdb_fsw : return fpu_fsw; - case gdb_ftw : return fpu_ftw; - case gdb_fpu_cs : return fpu_cs; - case gdb_ip : return fpu_ip; - case gdb_fpu_ds : return fpu_ds; //fpu_fos - case gdb_dp : return fpu_dp; //fpu_foo - case gdb_fop : return fpu_fop; - case gdb_xmm0 : return fpu_xmm0; - case gdb_xmm1 : return fpu_xmm1; - case gdb_xmm2 : return fpu_xmm2; - case gdb_xmm3 : return fpu_xmm3; - case gdb_xmm4 : return fpu_xmm4; - case gdb_xmm5 : return fpu_xmm5; - case gdb_xmm6 : return fpu_xmm6; - case gdb_xmm7 : return fpu_xmm7; - case gdb_mxcsr : return fpu_mxcsr; - default: - return LLDB_INVALID_REGNUM; - } - } - else if (kind == eRegisterKindLLDB) - { - return num; - } - - break; - } - - case ArchSpec::eCore_x86_64_x86_64: - { - if (kind == eRegisterKindGeneric) - { - switch (num) - { - case LLDB_REGNUM_GENERIC_PC: return gpr_rip; - case LLDB_REGNUM_GENERIC_SP: return gpr_rsp; - case LLDB_REGNUM_GENERIC_FP: return gpr_rbp; - case LLDB_REGNUM_GENERIC_FLAGS: return gpr_rflags; - case LLDB_REGNUM_GENERIC_RA: - default: - return LLDB_INVALID_REGNUM; - } - } - - if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF) - { - switch (num) - { - case gcc_dwarf_gpr_rax: return gpr_rax; - case gcc_dwarf_gpr_rdx: return gpr_rdx; - case gcc_dwarf_gpr_rcx: return gpr_rcx; - case gcc_dwarf_gpr_rbx: return gpr_rbx; - case gcc_dwarf_gpr_rsi: return gpr_rsi; - case gcc_dwarf_gpr_rdi: return gpr_rdi; - case gcc_dwarf_gpr_rbp: return gpr_rbp; - case gcc_dwarf_gpr_rsp: return gpr_rsp; - case gcc_dwarf_gpr_r8: return gpr_r8; - case gcc_dwarf_gpr_r9: return gpr_r9; - case gcc_dwarf_gpr_r10: return gpr_r10; - case gcc_dwarf_gpr_r11: return gpr_r11; - case gcc_dwarf_gpr_r12: return gpr_r12; - case gcc_dwarf_gpr_r13: return gpr_r13; - case gcc_dwarf_gpr_r14: return gpr_r14; - case gcc_dwarf_gpr_r15: return gpr_r15; - case gcc_dwarf_gpr_rip: return gpr_rip; - case gcc_dwarf_fpu_xmm0: return fpu_xmm0; - case gcc_dwarf_fpu_xmm1: return fpu_xmm1; - case gcc_dwarf_fpu_xmm2: return fpu_xmm2; - case gcc_dwarf_fpu_xmm3: return fpu_xmm3; - case gcc_dwarf_fpu_xmm4: return fpu_xmm4; - case gcc_dwarf_fpu_xmm5: return fpu_xmm5; - case gcc_dwarf_fpu_xmm6: return fpu_xmm6; - case gcc_dwarf_fpu_xmm7: return fpu_xmm7; - case gcc_dwarf_fpu_xmm8: return fpu_xmm8; - case gcc_dwarf_fpu_xmm9: return fpu_xmm9; - case gcc_dwarf_fpu_xmm10: return fpu_xmm10; - case gcc_dwarf_fpu_xmm11: return fpu_xmm11; - case gcc_dwarf_fpu_xmm12: return fpu_xmm12; - case gcc_dwarf_fpu_xmm13: return fpu_xmm13; - case gcc_dwarf_fpu_xmm14: return fpu_xmm14; - case gcc_dwarf_fpu_xmm15: return fpu_xmm15; - case gcc_dwarf_fpu_stmm0: return fpu_stmm0; - case gcc_dwarf_fpu_stmm1: return fpu_stmm1; - case gcc_dwarf_fpu_stmm2: return fpu_stmm2; - case gcc_dwarf_fpu_stmm3: return fpu_stmm3; - case gcc_dwarf_fpu_stmm4: return fpu_stmm4; - case gcc_dwarf_fpu_stmm5: return fpu_stmm5; - case gcc_dwarf_fpu_stmm6: return fpu_stmm6; - case gcc_dwarf_fpu_stmm7: return fpu_stmm7; - case gcc_dwarf_fpu_ymm0: return fpu_ymm0; - case gcc_dwarf_fpu_ymm1: return fpu_ymm1; - case gcc_dwarf_fpu_ymm2: return fpu_ymm2; - case gcc_dwarf_fpu_ymm3: return fpu_ymm3; - case gcc_dwarf_fpu_ymm4: return fpu_ymm4; - case gcc_dwarf_fpu_ymm5: return fpu_ymm5; - case gcc_dwarf_fpu_ymm6: return fpu_ymm6; - case gcc_dwarf_fpu_ymm7: return fpu_ymm7; - case gcc_dwarf_fpu_ymm8: return fpu_ymm8; - case gcc_dwarf_fpu_ymm9: return fpu_ymm9; - case gcc_dwarf_fpu_ymm10: return fpu_ymm10; - case gcc_dwarf_fpu_ymm11: return fpu_ymm11; - case gcc_dwarf_fpu_ymm12: return fpu_ymm12; - case gcc_dwarf_fpu_ymm13: return fpu_ymm13; - case gcc_dwarf_fpu_ymm14: return fpu_ymm14; - case gcc_dwarf_fpu_ymm15: return fpu_ymm15; - default: - return LLDB_INVALID_REGNUM; - } - } - - if (kind == eRegisterKindGDB) - { - switch (num) - { - case gdb_gpr_rax : return gpr_rax; - case gdb_gpr_rbx : return gpr_rbx; - case gdb_gpr_rcx : return gpr_rcx; - case gdb_gpr_rdx : return gpr_rdx; - case gdb_gpr_rsi : return gpr_rsi; - case gdb_gpr_rdi : return gpr_rdi; - case gdb_gpr_rbp : return gpr_rbp; - case gdb_gpr_rsp : return gpr_rsp; - case gdb_gpr_r8 : return gpr_r8; - case gdb_gpr_r9 : return gpr_r9; - case gdb_gpr_r10 : return gpr_r10; - case gdb_gpr_r11 : return gpr_r11; - case gdb_gpr_r12 : return gpr_r12; - case gdb_gpr_r13 : return gpr_r13; - case gdb_gpr_r14 : return gpr_r14; - case gdb_gpr_r15 : return gpr_r15; - case gdb_gpr_rip : return gpr_rip; - case gdb_gpr_rflags : return gpr_rflags; - case gdb_gpr_cs : return gpr_cs; - case gdb_gpr_ss : return gpr_ss; - case gdb_gpr_ds : return gpr_ds; - case gdb_gpr_es : return gpr_es; - case gdb_gpr_fs : return gpr_fs; - case gdb_gpr_gs : return gpr_gs; - case gdb_fpu_stmm0 : return fpu_stmm0; - case gdb_fpu_stmm1 : return fpu_stmm1; - case gdb_fpu_stmm2 : return fpu_stmm2; - case gdb_fpu_stmm3 : return fpu_stmm3; - case gdb_fpu_stmm4 : return fpu_stmm4; - case gdb_fpu_stmm5 : return fpu_stmm5; - case gdb_fpu_stmm6 : return fpu_stmm6; - case gdb_fpu_stmm7 : return fpu_stmm7; - case gdb_fpu_fcw : return fpu_fcw; - case gdb_fpu_fsw : return fpu_fsw; - case gdb_fpu_ftw : return fpu_ftw; - case gdb_fpu_cs_64 : return fpu_cs; - case gdb_fpu_ip : return fpu_ip; - case gdb_fpu_ds_64 : return fpu_ds; - case gdb_fpu_dp : return fpu_dp; - case gdb_fpu_fop : return fpu_fop; - case gdb_fpu_xmm0 : return fpu_xmm0; - case gdb_fpu_xmm1 : return fpu_xmm1; - case gdb_fpu_xmm2 : return fpu_xmm2; - case gdb_fpu_xmm3 : return fpu_xmm3; - case gdb_fpu_xmm4 : return fpu_xmm4; - case gdb_fpu_xmm5 : return fpu_xmm5; - case gdb_fpu_xmm6 : return fpu_xmm6; - case gdb_fpu_xmm7 : return fpu_xmm7; - case gdb_fpu_xmm8 : return fpu_xmm8; - case gdb_fpu_xmm9 : return fpu_xmm9; - case gdb_fpu_xmm10 : return fpu_xmm10; - case gdb_fpu_xmm11 : return fpu_xmm11; - case gdb_fpu_xmm12 : return fpu_xmm12; - case gdb_fpu_xmm13 : return fpu_xmm13; - case gdb_fpu_xmm14 : return fpu_xmm14; - case gdb_fpu_xmm15 : return fpu_xmm15; - case gdb_fpu_mxcsr : return fpu_mxcsr; - case gdb_fpu_ymm0 : return fpu_ymm0; - case gdb_fpu_ymm1 : return fpu_ymm1; - case gdb_fpu_ymm2 : return fpu_ymm2; - case gdb_fpu_ymm3 : return fpu_ymm3; - case gdb_fpu_ymm4 : return fpu_ymm4; - case gdb_fpu_ymm5 : return fpu_ymm5; - case gdb_fpu_ymm6 : return fpu_ymm6; - case gdb_fpu_ymm7 : return fpu_ymm7; - case gdb_fpu_ymm8 : return fpu_ymm8; - case gdb_fpu_ymm9 : return fpu_ymm9; - case gdb_fpu_ymm10 : return fpu_ymm10; - case gdb_fpu_ymm11 : return fpu_ymm11; - case gdb_fpu_ymm12 : return fpu_ymm12; - case gdb_fpu_ymm13 : return fpu_ymm13; - case gdb_fpu_ymm14 : return fpu_ymm14; - case gdb_fpu_ymm15 : return fpu_ymm15; - default: - return LLDB_INVALID_REGNUM; - } - } - else if (kind == eRegisterKindLLDB) - { - return num; - } - } - } - } - - return LLDB_INVALID_REGNUM; -} - -uint32_t -RegisterContext_x86_64::NumSupportedHardwareWatchpoints() -{ - // Available debug address registers: dr0, dr1, dr2, dr3 - return 4; -} - -bool -RegisterContext_x86_64::IsWatchpointVacant(uint32_t hw_index) -{ - bool is_vacant = false; - RegisterValue value; - - assert(hw_index < NumSupportedHardwareWatchpoints()); - - if (m_watchpoints_initialized == false) - { - // Reset the debug status and debug control registers - RegisterValue zero_bits = RegisterValue(uint64_t(0)); - if (!WriteRegister(dr6, zero_bits) || !WriteRegister(dr7, zero_bits)) - assert(false && "Could not initialize watchpoint registers"); - m_watchpoints_initialized = true; - } - - if (ReadRegister(dr7, value)) - { - uint64_t val = value.GetAsUInt64(); - is_vacant = (val & (3 << 2*hw_index)) == 0; - } - - return is_vacant; -} - -static uint32_t -size_and_rw_bits(size_t size, bool read, bool write) -{ - uint32_t rw; - if (read) { - rw = 0x3; // READ or READ/WRITE - } else if (write) { - rw = 0x1; // WRITE - } else { - assert(0 && "read and write cannot both be false"); - } - - switch (size) { - case 1: - return rw; - case 2: - return (0x1 << 2) | rw; - case 4: - return (0x3 << 2) | rw; - case 8: - return (0x2 << 2) | rw; - default: - assert(0 && "invalid size, must be one of 1, 2, 4, or 8"); - } -} - -uint32_t -RegisterContext_x86_64::SetHardwareWatchpoint(addr_t addr, size_t size, - bool read, bool write) -{ - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - uint32_t hw_index; - - for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) - { - if (IsWatchpointVacant(hw_index)) - return SetHardwareWatchpointWithIndex(addr, size, - read, write, - hw_index); - } - - return LLDB_INVALID_INDEX32; -} - -bool -RegisterContext_x86_64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size, - bool read, bool write, - uint32_t hw_index) -{ - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - - if (num_hw_watchpoints == 0 || hw_index >= num_hw_watchpoints) - return false; - - if (!(size == 1 || size == 2 || size == 4 || size == 8)) - return false; - - if (read == false && write == false) - return false; - - if (!IsWatchpointVacant(hw_index)) - return false; - - // Set both dr7 (debug control register) and dri (debug address register). - - // dr7{7-0} encodes the local/gloabl enable bits: - // global enable --. .-- local enable - // | | - // v v - // dr0 -> bits{1-0} - // dr1 -> bits{3-2} - // dr2 -> bits{5-4} - // dr3 -> bits{7-6} - // - // dr7{31-16} encodes the rw/len bits: - // b_x+3, b_x+2, b_x+1, b_x - // where bits{x+1, x} => rw - // 0b00: execute, 0b01: write, 0b11: read-or-write, - // 0b10: io read-or-write (unused) - // and bits{x+3, x+2} => len - // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte - // - // dr0 -> bits{19-16} - // dr1 -> bits{23-20} - // dr2 -> bits{27-24} - // dr3 -> bits{31-28} - if (hw_index < num_hw_watchpoints) - { - RegisterValue current_dr7_bits; - - if (ReadRegister(dr7, current_dr7_bits)) - { - uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() | - (1 << (2*hw_index) | - size_and_rw_bits(size, read, write) << - (16+4*hw_index)); - - if (WriteRegister(dr0 + hw_index, RegisterValue(addr)) && - WriteRegister(dr7, RegisterValue(new_dr7_bits))) - return true; - } - } - - return false; -} - -bool -RegisterContext_x86_64::ClearHardwareWatchpoint(uint32_t hw_index) -{ - if (hw_index < NumSupportedHardwareWatchpoints()) - { - RegisterValue current_dr7_bits; - - if (ReadRegister(dr7, current_dr7_bits)) - { - uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() & ~(3 << (2*hw_index)); - - if (WriteRegister(dr7, RegisterValue(new_dr7_bits))) - return true; - } - } - - return false; -} - -bool -RegisterContext_x86_64::IsWatchpointHit(uint32_t hw_index) -{ - bool is_hit = false; - - if (m_watchpoints_initialized == false) - { - // Reset the debug status and debug control registers - RegisterValue zero_bits = RegisterValue(uint64_t(0)); - if (!WriteRegister(dr6, zero_bits) || !WriteRegister(dr7, zero_bits)) - assert(false && "Could not initialize watchpoint registers"); - m_watchpoints_initialized = true; - } - - if (hw_index < NumSupportedHardwareWatchpoints()) - { - RegisterValue value; - - if (ReadRegister(dr6, value)) - { - uint64_t val = value.GetAsUInt64(); - is_hit = val & (1 << hw_index); - } - } - - return is_hit; -} - -addr_t -RegisterContext_x86_64::GetWatchpointAddress(uint32_t hw_index) -{ - addr_t wp_monitor_addr = LLDB_INVALID_ADDRESS; - - if (hw_index < NumSupportedHardwareWatchpoints()) - { - if (!IsWatchpointVacant(hw_index)) - { - RegisterValue value; - - if (ReadRegister(dr0 + hw_index, value)) - wp_monitor_addr = value.GetAsUInt64(); - } - } - - return wp_monitor_addr; -} - - -bool -RegisterContext_x86_64::ClearWatchpointHits() -{ - return WriteRegister(dr6, RegisterValue((uint64_t)0)); -} - -bool -RegisterContext_x86_64::HardwareSingleStep(bool enable) -{ - enum { TRACE_BIT = 0x100 }; - uint64_t rflags; - - if ((rflags = ReadRegisterAsUnsigned(gpr_rflags, -1UL)) == -1UL) - return false; - - if (enable) - { - if (rflags & TRACE_BIT) - return true; - - rflags |= TRACE_BIT; - } - else - { - if (!(rflags & TRACE_BIT)) - return false; - - rflags &= ~TRACE_BIT; - } - - return WriteRegisterFromUnsigned(gpr_rflags, rflags); -} - -#if defined(__linux__) or defined(__FreeBSD__) - -ProcessMonitor & -RegisterContext_x86_64::GetMonitor() -{ - ProcessSP base = CalculateProcess(); - ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get()); - return process->GetMonitor(); -} - -bool -RegisterContext_x86_64::ReadGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadGPR(m_thread.GetID(), &m_gpr, GetGPRSize()); -} - -bool -RegisterContext_x86_64::ReadFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - if (m_fpr_type == eFXSAVE) - return monitor.ReadFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); - - if (m_fpr_type == eXSAVE) - return monitor.ReadRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE); - return false; -} - -bool -RegisterContext_x86_64::WriteGPR() -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteGPR(m_thread.GetID(), &m_gpr, GetGPRSize()); -} - -bool -RegisterContext_x86_64::WriteFPR() -{ - ProcessMonitor &monitor = GetMonitor(); - if (m_fpr_type == eFXSAVE) - return monitor.WriteFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave)); - - if (m_fpr_type == eXSAVE) - return monitor.WriteRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE); - return false; -} - -bool -RegisterContext_x86_64::ReadRegister(const unsigned reg, - RegisterValue &value) -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.ReadRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg), - GetRegisterName(reg), - GetRegisterSize(reg), - value); -} - -bool -RegisterContext_x86_64::WriteRegister(const unsigned reg, - const RegisterValue &value) -{ - ProcessMonitor &monitor = GetMonitor(); - return monitor.WriteRegisterValue(m_thread.GetID(), - GetRegisterOffset(reg), - GetRegisterName(reg), - value); -} - -#else - -bool -RegisterContext_x86_64::ReadGPR() -{ - llvm_unreachable("not implemented"); - return false; -} - -bool -RegisterContext_x86_64::ReadFPR() -{ - llvm_unreachable("not implemented"); - return false; -} - -bool -RegisterContext_x86_64::WriteGPR() -{ - llvm_unreachable("not implemented"); - return false; -} - -bool -RegisterContext_x86_64::WriteFPR() -{ - llvm_unreachable("not implemented"); - return false; -} - -bool -RegisterContext_x86_64::ReadRegister(const unsigned reg, - RegisterValue &value) -{ - llvm_unreachable("not implemented"); - return false; -} - -bool -RegisterContext_x86_64::WriteRegister(const unsigned reg, - const RegisterValue &value) -{ - llvm_unreachable("not implemented"); - return false; -} - -#endif diff --git a/source/Plugins/Process/POSIX/RegisterContext_x86_64.h b/source/Plugins/Process/POSIX/RegisterContext_x86_64.h deleted file mode 100644 index 9d59bd78e547..000000000000 --- a/source/Plugins/Process/POSIX/RegisterContext_x86_64.h +++ /dev/null @@ -1,347 +0,0 @@ -//===-- RegisterContext_x86_64.h ---------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContext_x86_64_H_ -#define liblldb_RegisterContext_x86_64_H_ - -#include "lldb/Core/Log.h" -#include "RegisterContextPOSIX.h" - -class ProcessMonitor; - -// Internal codes for all x86_64 registers. -enum -{ - k_first_gpr, - gpr_rax = k_first_gpr, - gpr_rbx, - gpr_rcx, - gpr_rdx, - gpr_rdi, - gpr_rsi, - gpr_rbp, - gpr_rsp, - gpr_r8, - gpr_r9, - gpr_r10, - gpr_r11, - gpr_r12, - gpr_r13, - gpr_r14, - gpr_r15, - gpr_rip, - gpr_rflags, - gpr_cs, - gpr_fs, - gpr_gs, - gpr_ss, - gpr_ds, - gpr_es, - k_first_i386, - gpr_eax = k_first_i386, - gpr_ebx, - gpr_ecx, - gpr_edx, - gpr_edi, - gpr_esi, - gpr_ebp, - gpr_esp, - gpr_eip, - gpr_eflags, // eRegisterKindLLDB == 33 - k_last_i386 = gpr_eflags, - k_last_gpr = gpr_eflags, - - k_first_fpr, - fpu_fcw = k_first_fpr, - fpu_fsw, - fpu_ftw, - fpu_fop, - fpu_ip, - fpu_cs, - fpu_dp, - fpu_ds, - fpu_mxcsr, - fpu_mxcsrmask, - fpu_stmm0, - fpu_stmm1, - fpu_stmm2, - fpu_stmm3, - fpu_stmm4, - fpu_stmm5, - fpu_stmm6, - fpu_stmm7, - fpu_xmm0, - fpu_xmm1, - fpu_xmm2, - fpu_xmm3, - fpu_xmm4, - fpu_xmm5, - fpu_xmm6, - fpu_xmm7, - fpu_xmm8, - fpu_xmm9, - fpu_xmm10, - fpu_xmm11, - fpu_xmm12, - fpu_xmm13, - fpu_xmm14, - fpu_xmm15, - k_last_fpr = fpu_xmm15, - k_first_avx, - fpu_ymm0 = k_first_avx, - fpu_ymm1, - fpu_ymm2, - fpu_ymm3, - fpu_ymm4, - fpu_ymm5, - fpu_ymm6, - fpu_ymm7, - fpu_ymm8, - fpu_ymm9, - fpu_ymm10, - fpu_ymm11, - fpu_ymm12, - fpu_ymm13, - fpu_ymm14, - fpu_ymm15, - k_last_avx = fpu_ymm15, - - dr0, - dr1, - dr2, - dr3, - dr4, - dr5, - dr6, - dr7, - - k_num_registers, - k_num_gpr_registers = k_last_gpr - k_first_gpr + 1, - k_num_fpr_registers = k_last_fpr - k_first_fpr + 1, - k_num_avx_registers = k_last_avx - k_first_avx + 1 -}; - -class RegisterContext_x86_64 - : public RegisterContextPOSIX -{ -public: - RegisterContext_x86_64 (lldb_private::Thread &thread, - uint32_t concrete_frame_idx); - - ~RegisterContext_x86_64(); - - void - Invalidate(); - - void - InvalidateAllRegisters(); - - size_t - GetRegisterCount(); - - virtual size_t - GetGPRSize() = 0; - - virtual unsigned - GetRegisterSize(unsigned reg); - - virtual unsigned - GetRegisterOffset(unsigned reg); - - const lldb_private::RegisterInfo * - GetRegisterInfoAtIndex(size_t reg); - - size_t - GetRegisterSetCount(); - - const lldb_private::RegisterSet * - GetRegisterSet(size_t set); - - unsigned - GetRegisterIndexFromOffset(unsigned offset); - - const char * - GetRegisterName(unsigned reg); - - virtual bool - ReadRegister(const lldb_private::RegisterInfo *reg_info, - lldb_private::RegisterValue &value); - - bool - ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - - virtual bool - WriteRegister(const lldb_private::RegisterInfo *reg_info, - const lldb_private::RegisterValue &value); - - bool - WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - - uint32_t - ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num); - - uint32_t - NumSupportedHardwareWatchpoints(); - - uint32_t - SetHardwareWatchpoint(lldb::addr_t, size_t size, bool read, bool write); - - bool - SetHardwareWatchpointWithIndex(lldb::addr_t, size_t size, bool read, - bool write, uint32_t hw_index); - - bool - ClearHardwareWatchpoint(uint32_t hw_index); - - bool - HardwareSingleStep(bool enable); - - bool - UpdateAfterBreakpoint(); - - bool - IsWatchpointVacant(uint32_t hw_index); - - bool - IsWatchpointHit (uint32_t hw_index); - - lldb::addr_t - GetWatchpointAddress (uint32_t hw_index); - - bool - ClearWatchpointHits(); - - //--------------------------------------------------------------------------- - // Generic floating-point registers - //--------------------------------------------------------------------------- - - struct MMSReg - { - uint8_t bytes[10]; - uint8_t pad[6]; - }; - - struct XMMReg - { - uint8_t bytes[16]; // 128-bits for each XMM register - }; - - struct FXSAVE - { - uint16_t fcw; - uint16_t fsw; - uint16_t ftw; - uint16_t fop; - uint64_t ip; - uint64_t dp; - uint32_t mxcsr; - uint32_t mxcsrmask; - MMSReg stmm[8]; - XMMReg xmm[16]; - uint32_t padding[24]; - }; - - //--------------------------------------------------------------------------- - // Extended floating-point registers - //--------------------------------------------------------------------------- - struct YMMHReg - { - uint8_t bytes[16]; // 16 * 8 bits for the high bytes of each YMM register - }; - - struct YMMReg - { - uint8_t bytes[32]; // 16 * 16 bits for each YMM register - }; - - struct YMM - { - YMMReg ymm[16]; // assembled from ymmh and xmm registers - }; - - struct XSAVE_HDR - { - uint64_t xstate_bv; // OS enabled xstate mask to determine the extended states supported by the processor - uint64_t reserved1[2]; - uint64_t reserved2[5]; - } __attribute__((packed)); - - // x86 extensions to FXSAVE (i.e. for AVX processors) - struct XSAVE - { - FXSAVE i387; // floating point registers typical in i387_fxsave_struct - XSAVE_HDR header; // The xsave_hdr_struct can be used to determine if the following extensions are usable - YMMHReg ymmh[16]; // High 16 bytes of each of 16 YMM registers (the low bytes are in FXSAVE.xmm for compatibility with SSE) - // Slot any extensions to the register file here - } __attribute__((packed, aligned (64))); - - struct IOVEC - { - void *iov_base; // pointer to XSAVE - size_t iov_len; // sizeof(XSAVE) - }; - - //--------------------------------------------------------------------------- - // Note: prefer kernel definitions over user-land - //--------------------------------------------------------------------------- - enum FPRType - { - eNotValid = 0, - eFSAVE, // TODO - eFXSAVE, - eSOFT, // TODO - eXSAVE - }; - - // Floating-point registers - struct FPR - { - // Thread state for the floating-point unit of the processor read by ptrace. - union XSTATE { - FXSAVE fxsave; // Generic floating-point registers. - XSAVE xsave; // x86 extended processor state. - } xstate; - }; - -protected: - // Determines if an extended register set is supported on the processor running the inferior process. - virtual bool - IsRegisterSetAvailable(size_t set_index); - - virtual const lldb_private::RegisterInfo * - GetRegisterInfo(); - - virtual bool - ReadRegister(const unsigned reg, lldb_private::RegisterValue &value); - - virtual bool - WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value); - -private: - uint64_t m_gpr[k_num_gpr_registers]; // general purpose registers. - FPRType m_fpr_type; // determines the type of data stored by union FPR, if any. - FPR m_fpr; // floating-point registers including extended register sets. - IOVEC m_iovec; // wrapper for xsave. - YMM m_ymm_set; // copy of ymmh and xmm register halves. - - ProcessMonitor &GetMonitor(); - lldb::ByteOrder GetByteOrder(); - - bool CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order); - bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order); - bool IsFPR(unsigned reg, FPRType fpr_type); - - bool ReadGPR(); - bool ReadFPR(); - - bool WriteGPR(); - bool WriteFPR(); -}; - -#endif // #ifndef liblldb_RegisterContext_x86_64_H_ diff --git a/source/Plugins/Process/POSIX/RegisterInfos_i386.h b/source/Plugins/Process/POSIX/RegisterInfos_i386.h new file mode 100644 index 000000000000..7c516568cd62 --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterInfos_i386.h @@ -0,0 +1,207 @@ +//===-- RegisterInfos_i386.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +#include "llvm/Support/Compiler.h" + +#ifdef DECLARE_REGISTER_INFOS_I386_STRUCT + +// Computes the offset of the given GPR in the user data area. +#define GPR_OFFSET(regname) \ + (LLVM_EXTENSION offsetof(GPR, regname)) + +// Computes the offset of the given FPR in the extended data area. +#define FPR_OFFSET(regname) \ + (LLVM_EXTENSION offsetof(FPR, xstate) + \ + LLVM_EXTENSION offsetof(FXSAVE, regname)) + +// Computes the offset of the YMM register assembled from register halves. +#define YMM_OFFSET(regname) \ + (LLVM_EXTENSION offsetof(YMM, regname)) + +// Number of bytes needed to represent a FPR. +#define FPR_SIZE(reg) sizeof(((FXSAVE*)NULL)->reg) + +// Number of bytes needed to represent the i'th FP register. +#define FP_SIZE sizeof(((MMSReg*)NULL)->bytes) + +// Number of bytes needed to represent an XMM register. +#define XMM_SIZE sizeof(XMMReg) + +// Number of bytes needed to represent a YMM register. +#define YMM_SIZE sizeof(YMMReg) + +// Note that the size and offset will be updated by platform-specific classes. +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ + { #reg, alt, sizeof(GPR::reg), GPR_OFFSET(reg), eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_i386 }, NULL, NULL } + +#define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \ + { #name, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4, fpu_##name##_i386 }, NULL, NULL } + +// RegisterKind: GCC, DWARF, Generic, GDB, LLDB + +#define DEFINE_FP_ST(reg, i) \ + { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ + eEncodingVector, eFormatVectorOfUInt8, \ + { gcc_st##i##_i386, dwarf_st##i##_i386, LLDB_INVALID_REGNUM, gdb_st##i##_i386, fpu_st##i##_i386 }, \ + NULL, NULL } + +#define DEFINE_FP_MM(reg, i) \ + { #reg#i, NULL, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ + eEncodingUint, eFormatHex, \ + { gcc_mm##i##_i386, dwarf_mm##i##_i386, LLDB_INVALID_REGNUM, gdb_mm##i##_i386, fpu_mm##i##_i386 }, \ + NULL, NULL } + +#define DEFINE_XMM(reg, i) \ + { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \ + eEncodingVector, eFormatVectorOfUInt8, \ + { gcc_##reg##i##_i386, dwarf_##reg##i##_i386, LLDB_INVALID_REGNUM, gdb_##reg##i##_i386, fpu_##reg##i##_i386}, \ + NULL, NULL } + +// I believe the YMM registers use dwarf_xmm_%_i386 register numbers and then differentiate based on register size. +#define DEFINE_YMM(reg, i) \ + { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(reg[i]), \ + eEncodingVector, eFormatVectorOfUInt8, \ + { LLDB_INVALID_REGNUM, dwarf_xmm##i##_i386, LLDB_INVALID_REGNUM, gdb_##reg##i##h_i386, fpu_##reg##i##_i386 }, \ + NULL, NULL } + +#define DEFINE_DR(reg, i) \ + { #reg#i, NULL, DR_SIZE, DR_OFFSET(i), eEncodingUint, eFormatHex, \ + { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL } + +#define DEFINE_GPR_PSEUDO_16(reg16, reg32) \ + { #reg16, NULL, 2, GPR_OFFSET(reg32), eEncodingUint, \ + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg16##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 } +#define DEFINE_GPR_PSEUDO_8H(reg8, reg32) \ + { #reg8, NULL, 1, GPR_OFFSET(reg32)+1, eEncodingUint, \ + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 } +#define DEFINE_GPR_PSEUDO_8L(reg8, reg32) \ + { #reg8, NULL, 1, GPR_OFFSET(reg32), eEncodingUint, \ + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 } + +static RegisterInfo +g_register_infos_i386[] = +{ + // General purpose registers. + DEFINE_GPR(eax, NULL, gcc_eax_i386, dwarf_eax_i386, LLDB_INVALID_REGNUM, gdb_eax_i386), + DEFINE_GPR(ebx, NULL, gcc_ebx_i386, dwarf_ebx_i386, LLDB_INVALID_REGNUM, gdb_ebx_i386), + DEFINE_GPR(ecx, NULL, gcc_ecx_i386, dwarf_ecx_i386, LLDB_INVALID_REGNUM, gdb_ecx_i386), + DEFINE_GPR(edx, NULL, gcc_edx_i386, dwarf_edx_i386, LLDB_INVALID_REGNUM, gdb_edx_i386), + DEFINE_GPR(edi, NULL, gcc_edi_i386, dwarf_edi_i386, LLDB_INVALID_REGNUM, gdb_edi_i386), + DEFINE_GPR(esi, NULL, gcc_esi_i386, dwarf_esi_i386, LLDB_INVALID_REGNUM, gdb_esi_i386), + DEFINE_GPR(ebp, "fp", gcc_ebp_i386, dwarf_ebp_i386, LLDB_REGNUM_GENERIC_FP, gdb_ebp_i386), + DEFINE_GPR(esp, "sp", gcc_esp_i386, dwarf_esp_i386, LLDB_REGNUM_GENERIC_SP, gdb_esp_i386), + DEFINE_GPR(eip, "pc", gcc_eip_i386, dwarf_eip_i386, LLDB_REGNUM_GENERIC_PC, gdb_eip_i386), + DEFINE_GPR(eflags, "flags", gcc_eflags_i386, dwarf_eflags_i386, LLDB_REGNUM_GENERIC_FLAGS, gdb_eflags_i386), + DEFINE_GPR(cs, NULL, LLDB_INVALID_REGNUM, dwarf_cs_i386, LLDB_INVALID_REGNUM, gdb_cs_i386), + DEFINE_GPR(fs, NULL, LLDB_INVALID_REGNUM, dwarf_fs_i386, LLDB_INVALID_REGNUM, gdb_fs_i386), + DEFINE_GPR(gs, NULL, LLDB_INVALID_REGNUM, dwarf_gs_i386, LLDB_INVALID_REGNUM, gdb_gs_i386), + DEFINE_GPR(ss, NULL, LLDB_INVALID_REGNUM, dwarf_ss_i386, LLDB_INVALID_REGNUM, gdb_ss_i386), + DEFINE_GPR(ds, NULL, LLDB_INVALID_REGNUM, dwarf_ds_i386, LLDB_INVALID_REGNUM, gdb_ds_i386), + DEFINE_GPR(es, NULL, LLDB_INVALID_REGNUM, dwarf_es_i386, LLDB_INVALID_REGNUM, gdb_es_i386), + + DEFINE_GPR_PSEUDO_16(ax, eax), + DEFINE_GPR_PSEUDO_16(bx, ebx), + DEFINE_GPR_PSEUDO_16(cx, ecx), + DEFINE_GPR_PSEUDO_16(dx, edx), + DEFINE_GPR_PSEUDO_16(di, edi), + DEFINE_GPR_PSEUDO_16(si, esi), + DEFINE_GPR_PSEUDO_16(bp, ebp), + DEFINE_GPR_PSEUDO_16(sp, esp), + DEFINE_GPR_PSEUDO_8H(ah, eax), + DEFINE_GPR_PSEUDO_8H(bh, ebx), + DEFINE_GPR_PSEUDO_8H(ch, ecx), + DEFINE_GPR_PSEUDO_8H(dh, edx), + DEFINE_GPR_PSEUDO_8L(al, eax), + DEFINE_GPR_PSEUDO_8L(bl, ebx), + DEFINE_GPR_PSEUDO_8L(cl, ecx), + DEFINE_GPR_PSEUDO_8L(dl, edx), + + // i387 Floating point registers. + DEFINE_FPR(fctrl, fctrl, LLDB_INVALID_REGNUM, dwarf_fctrl_i386, LLDB_INVALID_REGNUM, gdb_fctrl_i386), + DEFINE_FPR(fstat, fstat, LLDB_INVALID_REGNUM, dwarf_fstat_i386, LLDB_INVALID_REGNUM, gdb_fstat_i386), + DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftag_i386), + DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop_i386), + DEFINE_FPR(fiseg, ptr.i386.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_i386), + DEFINE_FPR(fioff, ptr.i386.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_i386), + DEFINE_FPR(foseg, ptr.i386.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_i386), + DEFINE_FPR(fooff, ptr.i386.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_i386), + DEFINE_FPR(mxcsr, mxcsr, LLDB_INVALID_REGNUM, dwarf_mxcsr_i386, LLDB_INVALID_REGNUM, gdb_mxcsr_i386), + DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + + // FP registers. + DEFINE_FP_ST(st, 0), + DEFINE_FP_ST(st, 1), + DEFINE_FP_ST(st, 2), + DEFINE_FP_ST(st, 3), + DEFINE_FP_ST(st, 4), + DEFINE_FP_ST(st, 5), + DEFINE_FP_ST(st, 6), + DEFINE_FP_ST(st, 7), + DEFINE_FP_MM(mm, 0), + DEFINE_FP_MM(mm, 1), + DEFINE_FP_MM(mm, 2), + DEFINE_FP_MM(mm, 3), + DEFINE_FP_MM(mm, 4), + DEFINE_FP_MM(mm, 5), + DEFINE_FP_MM(mm, 6), + DEFINE_FP_MM(mm, 7), + + // XMM registers + DEFINE_XMM(xmm, 0), + DEFINE_XMM(xmm, 1), + DEFINE_XMM(xmm, 2), + DEFINE_XMM(xmm, 3), + DEFINE_XMM(xmm, 4), + DEFINE_XMM(xmm, 5), + DEFINE_XMM(xmm, 6), + DEFINE_XMM(xmm, 7), + + // Copy of YMM registers assembled from xmm and ymmh + DEFINE_YMM(ymm, 0), + DEFINE_YMM(ymm, 1), + DEFINE_YMM(ymm, 2), + DEFINE_YMM(ymm, 3), + DEFINE_YMM(ymm, 4), + DEFINE_YMM(ymm, 5), + DEFINE_YMM(ymm, 6), + DEFINE_YMM(ymm, 7), + + // Debug registers for lldb internal use + DEFINE_DR(dr, 0), + DEFINE_DR(dr, 1), + DEFINE_DR(dr, 2), + DEFINE_DR(dr, 3), + DEFINE_DR(dr, 4), + DEFINE_DR(dr, 5), + DEFINE_DR(dr, 6), + DEFINE_DR(dr, 7) +}; +static_assert((sizeof(g_register_infos_i386) / sizeof(g_register_infos_i386[0])) == k_num_registers_i386, + "g_register_infos_x86_64 has wrong number of register infos"); + +#undef GPR_OFFSET +#undef FPR_OFFSET +#undef YMM_OFFSET +#undef FPR_SIZE +#undef FP_SIZE +#undef XMM_SIZE +#undef YMM_SIZE +#undef DEFINE_GPR +#undef DEFINE_FPR +#undef DEFINE_FP +#undef DEFINE_XMM +#undef DEFINE_YMM +#undef DEFINE_DR +#undef DEFINE_GPR_PSEUDO_16 +#undef DEFINE_GPR_PSEUDO_8H +#undef DEFINE_GPR_PSEUDO_8L + +#endif // DECLARE_REGISTER_INFOS_I386_STRUCT diff --git a/source/Plugins/Process/POSIX/RegisterInfos_mips64.h b/source/Plugins/Process/POSIX/RegisterInfos_mips64.h new file mode 100644 index 000000000000..13526e3680b7 --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterInfos_mips64.h @@ -0,0 +1,74 @@ +//===-- RegisterInfos_mips64.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +// Computes the offset of the given GPR in the user data area. +#define GPR_OFFSET(regname) \ + (offsetof(GPR, regname)) + +#ifdef DECLARE_REGISTER_INFOS_MIPS64_STRUCT + +// Note that the size and offset will be updated by platform-specific classes. +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ + { #reg, alt, sizeof(GPR::reg), GPR_OFFSET(reg), eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL } + +static RegisterInfo +g_register_infos_mips64[] = +{ + // General purpose registers. GCC, DWARF, Generic, GDB + DEFINE_GPR(zero, "r0", gcc_dwarf_zero_mips64, gcc_dwarf_zero_mips64, LLDB_INVALID_REGNUM, gdb_zero_mips64), + DEFINE_GPR(r1, NULL, gcc_dwarf_r1_mips64, gcc_dwarf_r1_mips64, LLDB_INVALID_REGNUM, gdb_r1_mips64), + DEFINE_GPR(r2, NULL, gcc_dwarf_r2_mips64, gcc_dwarf_r2_mips64, LLDB_INVALID_REGNUM, gdb_r2_mips64), + DEFINE_GPR(r3, NULL, gcc_dwarf_r3_mips64, gcc_dwarf_r3_mips64, LLDB_INVALID_REGNUM, gdb_r3_mips64), + DEFINE_GPR(r4, NULL, gcc_dwarf_r4_mips64, gcc_dwarf_r4_mips64, LLDB_INVALID_REGNUM, gdb_r4_mips64), + DEFINE_GPR(r5, NULL, gcc_dwarf_r5_mips64, gcc_dwarf_r5_mips64, LLDB_INVALID_REGNUM, gdb_r5_mips64), + DEFINE_GPR(r6, NULL, gcc_dwarf_r6_mips64, gcc_dwarf_r6_mips64, LLDB_INVALID_REGNUM, gdb_r6_mips64), + DEFINE_GPR(r7, NULL, gcc_dwarf_r7_mips64, gcc_dwarf_r7_mips64, LLDB_INVALID_REGNUM, gdb_r7_mips64), + DEFINE_GPR(r8, NULL, gcc_dwarf_r8_mips64, gcc_dwarf_r8_mips64, LLDB_INVALID_REGNUM, gdb_r8_mips64), + DEFINE_GPR(r9, NULL, gcc_dwarf_r9_mips64, gcc_dwarf_r9_mips64, LLDB_INVALID_REGNUM, gdb_r9_mips64), + DEFINE_GPR(r10, NULL, gcc_dwarf_r10_mips64, gcc_dwarf_r10_mips64, LLDB_INVALID_REGNUM, gdb_r10_mips64), + DEFINE_GPR(r11, NULL, gcc_dwarf_r11_mips64, gcc_dwarf_r11_mips64, LLDB_INVALID_REGNUM, gdb_r11_mips64), + DEFINE_GPR(r12, NULL, gcc_dwarf_r12_mips64, gcc_dwarf_r12_mips64, LLDB_INVALID_REGNUM, gdb_r12_mips64), + DEFINE_GPR(r13, NULL, gcc_dwarf_r13_mips64, gcc_dwarf_r13_mips64, LLDB_INVALID_REGNUM, gdb_r13_mips64), + DEFINE_GPR(r14, NULL, gcc_dwarf_r14_mips64, gcc_dwarf_r14_mips64, LLDB_INVALID_REGNUM, gdb_r14_mips64), + DEFINE_GPR(r15, NULL, gcc_dwarf_r15_mips64, gcc_dwarf_r15_mips64, LLDB_INVALID_REGNUM, gdb_r15_mips64), + DEFINE_GPR(r16, NULL, gcc_dwarf_r16_mips64, gcc_dwarf_r16_mips64, LLDB_INVALID_REGNUM, gdb_r16_mips64), + DEFINE_GPR(r17, NULL, gcc_dwarf_r17_mips64, gcc_dwarf_r17_mips64, LLDB_INVALID_REGNUM, gdb_r17_mips64), + DEFINE_GPR(r18, NULL, gcc_dwarf_r18_mips64, gcc_dwarf_r18_mips64, LLDB_INVALID_REGNUM, gdb_r18_mips64), + DEFINE_GPR(r19, NULL, gcc_dwarf_r19_mips64, gcc_dwarf_r19_mips64, LLDB_INVALID_REGNUM, gdb_r19_mips64), + DEFINE_GPR(r20, NULL, gcc_dwarf_r20_mips64, gcc_dwarf_r20_mips64, LLDB_INVALID_REGNUM, gdb_r20_mips64), + DEFINE_GPR(r21, NULL, gcc_dwarf_r21_mips64, gcc_dwarf_r21_mips64, LLDB_INVALID_REGNUM, gdb_r21_mips64), + DEFINE_GPR(r22, NULL, gcc_dwarf_r22_mips64, gcc_dwarf_r22_mips64, LLDB_INVALID_REGNUM, gdb_r22_mips64), + DEFINE_GPR(r23, NULL, gcc_dwarf_r23_mips64, gcc_dwarf_r23_mips64, LLDB_INVALID_REGNUM, gdb_r23_mips64), + DEFINE_GPR(r24, NULL, gcc_dwarf_r24_mips64, gcc_dwarf_r24_mips64, LLDB_INVALID_REGNUM, gdb_r24_mips64), + DEFINE_GPR(r25, NULL, gcc_dwarf_r25_mips64, gcc_dwarf_r25_mips64, LLDB_INVALID_REGNUM, gdb_r25_mips64), + DEFINE_GPR(r26, NULL, gcc_dwarf_r26_mips64, gcc_dwarf_r26_mips64, LLDB_INVALID_REGNUM, gdb_r26_mips64), + DEFINE_GPR(r27, NULL, gcc_dwarf_r27_mips64, gcc_dwarf_r27_mips64, LLDB_INVALID_REGNUM, gdb_r27_mips64), + DEFINE_GPR(gp, "r28", gcc_dwarf_gp_mips64, gcc_dwarf_gp_mips64, LLDB_INVALID_REGNUM, gdb_gp_mips64), + DEFINE_GPR(sp, "r29", gcc_dwarf_sp_mips64, gcc_dwarf_sp_mips64, LLDB_REGNUM_GENERIC_SP, gdb_sp_mips64), + DEFINE_GPR(r30, NULL, gcc_dwarf_r30_mips64, gcc_dwarf_r30_mips64, LLDB_INVALID_REGNUM, gdb_r30_mips64), + DEFINE_GPR(ra, "r31", gcc_dwarf_ra_mips64, gcc_dwarf_ra_mips64, LLDB_INVALID_REGNUM, gdb_ra_mips64), + DEFINE_GPR(sr, NULL, gcc_dwarf_sr_mips64, gcc_dwarf_sr_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(mullo, NULL, gcc_dwarf_lo_mips64, gcc_dwarf_lo_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(mulhi, NULL, gcc_dwarf_hi_mips64, gcc_dwarf_hi_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(badvaddr, NULL, gcc_dwarf_bad_mips64, gcc_dwarf_bad_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(cause, NULL, gcc_dwarf_cause_mips64, gcc_dwarf_cause_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(pc, "pc", gcc_dwarf_pc_mips64, gcc_dwarf_pc_mips64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), + DEFINE_GPR(ic, NULL, gcc_dwarf_ic_mips64, gcc_dwarf_ic_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_GPR(dummy, NULL, gcc_dwarf_dummy_mips64, gcc_dwarf_dummy_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), +}; +static_assert((sizeof(g_register_infos_mips64) / sizeof(g_register_infos_mips64[0])) == k_num_registers_mips64, + "g_register_infos_mips64 has wrong number of register infos"); + +#undef DEFINE_GPR + +#endif // DECLARE_REGISTER_INFOS_MIPS64_STRUCT + +#undef GPR_OFFSET + diff --git a/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h b/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h new file mode 100644 index 000000000000..1bab88cd5727 --- /dev/null +++ b/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h @@ -0,0 +1,409 @@ +//===-- RegisterInfos_x86_64.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +#include "llvm/Support/Compiler.h" + +// Computes the offset of the given GPR in the user data area. +#define GPR_OFFSET(regname) \ + (LLVM_EXTENSION offsetof(GPR, regname)) + +// Computes the offset of the given FPR in the extended data area. +#define FPR_OFFSET(regname) \ + (LLVM_EXTENSION offsetof(FPR, xstate) + \ + LLVM_EXTENSION offsetof(FXSAVE, regname)) + +// Computes the offset of the YMM register assembled from register halves. +#define YMM_OFFSET(regname) \ + (LLVM_EXTENSION offsetof(YMM, regname)) + +#ifdef DECLARE_REGISTER_INFOS_X86_64_STRUCT + +// Number of bytes needed to represent a FPR. +#define FPR_SIZE(reg) sizeof(((FXSAVE*)NULL)->reg) + +// Number of bytes needed to represent the i'th FP register. +#define FP_SIZE sizeof(((MMSReg*)NULL)->bytes) + +// Number of bytes needed to represent an XMM register. +#define XMM_SIZE sizeof(XMMReg) + +// Number of bytes needed to represent a YMM register. +#define YMM_SIZE sizeof(YMMReg) + +// RegisterKind: GCC, DWARF, Generic, GDB, LLDB + +// Note that the size and offset will be updated by platform-specific classes. +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ + { #reg, alt, sizeof(GPR::reg), GPR_OFFSET(reg), eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_x86_64 }, NULL, NULL } + +#define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \ + { #name, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4, fpu_##name##_x86_64 }, NULL, NULL } + +#define DEFINE_FP_ST(reg, i) \ + { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ + eEncodingVector, eFormatVectorOfUInt8, \ + { gcc_dwarf_st##i##_x86_64, gcc_dwarf_st##i##_x86_64, LLDB_INVALID_REGNUM, gdb_st##i##_x86_64, fpu_st##i##_x86_64 }, \ + NULL, NULL } + +#define DEFINE_FP_MM(reg, i) \ + { #reg#i, NULL, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ + eEncodingUint, eFormatHex, \ + { gcc_dwarf_mm##i##_x86_64, gcc_dwarf_mm##i##_x86_64, LLDB_INVALID_REGNUM, gdb_st##i##_x86_64, fpu_mm##i##_x86_64 }, \ + NULL, NULL } + +#define DEFINE_XMM(reg, i) \ + { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \ + eEncodingVector, eFormatVectorOfUInt8, \ + { gcc_dwarf_##reg##i##_x86_64, gcc_dwarf_##reg##i##_x86_64, LLDB_INVALID_REGNUM, gdb_##reg##i##_x86_64, fpu_##reg##i##_x86_64}, \ + NULL, NULL } + +#define DEFINE_YMM(reg, i) \ + { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(reg[i]), \ + eEncodingVector, eFormatVectorOfUInt8, \ + { gcc_dwarf_##reg##i##h_x86_64, gcc_dwarf_##reg##i##h_x86_64, LLDB_INVALID_REGNUM, gdb_##reg##i##h_x86_64, fpu_##reg##i##_x86_64 }, \ + NULL, NULL } + +#define DEFINE_DR(reg, i) \ + { #reg#i, NULL, DR_SIZE, DR_OFFSET(i), eEncodingUint, eFormatHex, \ + { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL } + +#define DEFINE_GPR_PSEUDO_32(reg32, reg64) \ + { #reg32, NULL, 4, GPR_OFFSET(reg64), eEncodingUint, \ + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg32##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } +#define DEFINE_GPR_PSEUDO_16(reg16, reg64) \ + { #reg16, NULL, 2, GPR_OFFSET(reg64), eEncodingUint, \ + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg16##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } +#define DEFINE_GPR_PSEUDO_8H(reg8, reg64) \ + { #reg8, NULL, 1, GPR_OFFSET(reg64)+1, eEncodingUint, \ + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } +#define DEFINE_GPR_PSEUDO_8L(reg8, reg64) \ + { #reg8, NULL, 1, GPR_OFFSET(reg64), eEncodingUint, \ + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } + +static RegisterInfo +g_register_infos_x86_64[] = +{ + // General purpose registers. GCC, DWARF, Generic, GDB + DEFINE_GPR(rax, NULL, gcc_dwarf_rax_x86_64, gcc_dwarf_rax_x86_64, LLDB_INVALID_REGNUM, gdb_rax_x86_64), + DEFINE_GPR(rbx, NULL, gcc_dwarf_rbx_x86_64, gcc_dwarf_rbx_x86_64, LLDB_INVALID_REGNUM, gdb_rbx_x86_64), + DEFINE_GPR(rcx, "arg4", gcc_dwarf_rcx_x86_64, gcc_dwarf_rcx_x86_64, LLDB_INVALID_REGNUM, gdb_rcx_x86_64), + DEFINE_GPR(rdx, "arg3", gcc_dwarf_rdx_x86_64, gcc_dwarf_rdx_x86_64, LLDB_INVALID_REGNUM, gdb_rdx_x86_64), + DEFINE_GPR(rdi, "arg1", gcc_dwarf_rdi_x86_64, gcc_dwarf_rdi_x86_64, LLDB_INVALID_REGNUM, gdb_rdi_x86_64), + DEFINE_GPR(rsi, "arg2", gcc_dwarf_rsi_x86_64, gcc_dwarf_rsi_x86_64, LLDB_INVALID_REGNUM, gdb_rsi_x86_64), + DEFINE_GPR(rbp, "fp", gcc_dwarf_rbp_x86_64, gcc_dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP, gdb_rbp_x86_64), + DEFINE_GPR(rsp, "sp", gcc_dwarf_rsp_x86_64, gcc_dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP, gdb_rsp_x86_64), + DEFINE_GPR(r8, "arg5", gcc_dwarf_r8_x86_64, gcc_dwarf_r8_x86_64, LLDB_INVALID_REGNUM, gdb_r8_x86_64), + DEFINE_GPR(r9, "arg6", gcc_dwarf_r9_x86_64, gcc_dwarf_r9_x86_64, LLDB_INVALID_REGNUM, gdb_r9_x86_64), + DEFINE_GPR(r10, NULL, gcc_dwarf_r10_x86_64, gcc_dwarf_r10_x86_64, LLDB_INVALID_REGNUM, gdb_r10_x86_64), + DEFINE_GPR(r11, NULL, gcc_dwarf_r11_x86_64, gcc_dwarf_r11_x86_64, LLDB_INVALID_REGNUM, gdb_r11_x86_64), + DEFINE_GPR(r12, NULL, gcc_dwarf_r12_x86_64, gcc_dwarf_r12_x86_64, LLDB_INVALID_REGNUM, gdb_r12_x86_64), + DEFINE_GPR(r13, NULL, gcc_dwarf_r13_x86_64, gcc_dwarf_r13_x86_64, LLDB_INVALID_REGNUM, gdb_r13_x86_64), + DEFINE_GPR(r14, NULL, gcc_dwarf_r14_x86_64, gcc_dwarf_r14_x86_64, LLDB_INVALID_REGNUM, gdb_r14_x86_64), + DEFINE_GPR(r15, NULL, gcc_dwarf_r15_x86_64, gcc_dwarf_r15_x86_64, LLDB_INVALID_REGNUM, gdb_r15_x86_64), + DEFINE_GPR(rip, "pc", gcc_dwarf_rip_x86_64, gcc_dwarf_rip_x86_64, LLDB_REGNUM_GENERIC_PC, gdb_rip_x86_64), + DEFINE_GPR(rflags, "flags", gcc_dwarf_rflags_x86_64, gcc_dwarf_rflags_x86_64, LLDB_REGNUM_GENERIC_FLAGS, gdb_rflags_x86_64), + DEFINE_GPR(cs, NULL, gcc_dwarf_cs_x86_64, gcc_dwarf_cs_x86_64, LLDB_INVALID_REGNUM, gdb_cs_x86_64), + DEFINE_GPR(fs, NULL, gcc_dwarf_fs_x86_64, gcc_dwarf_fs_x86_64, LLDB_INVALID_REGNUM, gdb_fs_x86_64), + DEFINE_GPR(gs, NULL, gcc_dwarf_gs_x86_64, gcc_dwarf_gs_x86_64, LLDB_INVALID_REGNUM, gdb_gs_x86_64), + DEFINE_GPR(ss, NULL, gcc_dwarf_ss_x86_64, gcc_dwarf_ss_x86_64, LLDB_INVALID_REGNUM, gdb_ss_x86_64), + DEFINE_GPR(ds, NULL, gcc_dwarf_ds_x86_64, gcc_dwarf_ds_x86_64, LLDB_INVALID_REGNUM, gdb_ds_x86_64), + DEFINE_GPR(es, NULL, gcc_dwarf_es_x86_64, gcc_dwarf_es_x86_64, LLDB_INVALID_REGNUM, gdb_es_x86_64), + + DEFINE_GPR_PSEUDO_32(eax, rax), + DEFINE_GPR_PSEUDO_32(ebx, rbx), + DEFINE_GPR_PSEUDO_32(ecx, rcx), + DEFINE_GPR_PSEUDO_32(edx, rdx), + DEFINE_GPR_PSEUDO_32(edi, rdi), + DEFINE_GPR_PSEUDO_32(esi, rsi), + DEFINE_GPR_PSEUDO_32(ebp, rbp), + DEFINE_GPR_PSEUDO_32(esp, rsp), + DEFINE_GPR_PSEUDO_32(r8d, r8), + DEFINE_GPR_PSEUDO_32(r9d, r9), + DEFINE_GPR_PSEUDO_32(r10d, r10), + DEFINE_GPR_PSEUDO_32(r11d, r11), + DEFINE_GPR_PSEUDO_32(r12d, r12), + DEFINE_GPR_PSEUDO_32(r13d, r13), + DEFINE_GPR_PSEUDO_32(r14d, r14), + DEFINE_GPR_PSEUDO_32(r15d, r15), + DEFINE_GPR_PSEUDO_16(ax, rax), + DEFINE_GPR_PSEUDO_16(bx, rbx), + DEFINE_GPR_PSEUDO_16(cx, rcx), + DEFINE_GPR_PSEUDO_16(dx, rdx), + DEFINE_GPR_PSEUDO_16(di, rdi), + DEFINE_GPR_PSEUDO_16(si, rsi), + DEFINE_GPR_PSEUDO_16(bp, rbp), + DEFINE_GPR_PSEUDO_16(sp, rsp), + DEFINE_GPR_PSEUDO_16(r8w, r8), + DEFINE_GPR_PSEUDO_16(r9w, r9), + DEFINE_GPR_PSEUDO_16(r10w, r10), + DEFINE_GPR_PSEUDO_16(r11w, r11), + DEFINE_GPR_PSEUDO_16(r12w, r12), + DEFINE_GPR_PSEUDO_16(r13w, r13), + DEFINE_GPR_PSEUDO_16(r14w, r14), + DEFINE_GPR_PSEUDO_16(r15w, r15), + DEFINE_GPR_PSEUDO_8H(ah, rax), + DEFINE_GPR_PSEUDO_8H(bh, rbx), + DEFINE_GPR_PSEUDO_8H(ch, rcx), + DEFINE_GPR_PSEUDO_8H(dh, rdx), + DEFINE_GPR_PSEUDO_8L(al, rax), + DEFINE_GPR_PSEUDO_8L(bl, rbx), + DEFINE_GPR_PSEUDO_8L(cl, rcx), + DEFINE_GPR_PSEUDO_8L(dl, rdx), + DEFINE_GPR_PSEUDO_8L(dil, rdi), + DEFINE_GPR_PSEUDO_8L(sil, rsi), + DEFINE_GPR_PSEUDO_8L(bpl, rbp), + DEFINE_GPR_PSEUDO_8L(spl, rsp), + DEFINE_GPR_PSEUDO_8L(r8l, r8), + DEFINE_GPR_PSEUDO_8L(r9l, r9), + DEFINE_GPR_PSEUDO_8L(r10l, r10), + DEFINE_GPR_PSEUDO_8L(r11l, r11), + DEFINE_GPR_PSEUDO_8L(r12l, r12), + DEFINE_GPR_PSEUDO_8L(r13l, r13), + DEFINE_GPR_PSEUDO_8L(r14l, r14), + DEFINE_GPR_PSEUDO_8L(r15l, r15), + + // i387 Floating point registers. GCC, DWARF, Generic, GDB + DEFINE_FPR(fctrl, fctrl, gcc_dwarf_fctrl_x86_64, gcc_dwarf_fctrl_x86_64, LLDB_INVALID_REGNUM, gdb_fctrl_x86_64), + DEFINE_FPR(fstat, fstat, gcc_dwarf_fstat_x86_64, gcc_dwarf_fstat_x86_64, LLDB_INVALID_REGNUM, gdb_fstat_x86_64), + DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftag_x86_64), + DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop_x86_64), + DEFINE_FPR(fiseg, ptr.i386.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_x86_64), + DEFINE_FPR(fioff, ptr.i386.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_x86_64), + DEFINE_FPR(foseg, ptr.i386.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_x86_64), + DEFINE_FPR(fooff, ptr.i386.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_x86_64), + DEFINE_FPR(mxcsr, mxcsr, gcc_dwarf_mxcsr_x86_64, gcc_dwarf_mxcsr_x86_64, LLDB_INVALID_REGNUM, gdb_mxcsr_x86_64), + DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + + // FP registers. + DEFINE_FP_ST(st, 0), + DEFINE_FP_ST(st, 1), + DEFINE_FP_ST(st, 2), + DEFINE_FP_ST(st, 3), + DEFINE_FP_ST(st, 4), + DEFINE_FP_ST(st, 5), + DEFINE_FP_ST(st, 6), + DEFINE_FP_ST(st, 7), + DEFINE_FP_MM(mm, 0), + DEFINE_FP_MM(mm, 1), + DEFINE_FP_MM(mm, 2), + DEFINE_FP_MM(mm, 3), + DEFINE_FP_MM(mm, 4), + DEFINE_FP_MM(mm, 5), + DEFINE_FP_MM(mm, 6), + DEFINE_FP_MM(mm, 7), + + // XMM registers + DEFINE_XMM(xmm, 0), + DEFINE_XMM(xmm, 1), + DEFINE_XMM(xmm, 2), + DEFINE_XMM(xmm, 3), + DEFINE_XMM(xmm, 4), + DEFINE_XMM(xmm, 5), + DEFINE_XMM(xmm, 6), + DEFINE_XMM(xmm, 7), + DEFINE_XMM(xmm, 8), + DEFINE_XMM(xmm, 9), + DEFINE_XMM(xmm, 10), + DEFINE_XMM(xmm, 11), + DEFINE_XMM(xmm, 12), + DEFINE_XMM(xmm, 13), + DEFINE_XMM(xmm, 14), + DEFINE_XMM(xmm, 15), + + // Copy of YMM registers assembled from xmm and ymmh + DEFINE_YMM(ymm, 0), + DEFINE_YMM(ymm, 1), + DEFINE_YMM(ymm, 2), + DEFINE_YMM(ymm, 3), + DEFINE_YMM(ymm, 4), + DEFINE_YMM(ymm, 5), + DEFINE_YMM(ymm, 6), + DEFINE_YMM(ymm, 7), + DEFINE_YMM(ymm, 8), + DEFINE_YMM(ymm, 9), + DEFINE_YMM(ymm, 10), + DEFINE_YMM(ymm, 11), + DEFINE_YMM(ymm, 12), + DEFINE_YMM(ymm, 13), + DEFINE_YMM(ymm, 14), + DEFINE_YMM(ymm, 15), + + // Debug registers for lldb internal use + DEFINE_DR(dr, 0), + DEFINE_DR(dr, 1), + DEFINE_DR(dr, 2), + DEFINE_DR(dr, 3), + DEFINE_DR(dr, 4), + DEFINE_DR(dr, 5), + DEFINE_DR(dr, 6), + DEFINE_DR(dr, 7) +}; +static_assert((sizeof(g_register_infos_x86_64) / sizeof(g_register_infos_x86_64[0])) == k_num_registers_x86_64, + "g_register_infos_x86_64 has wrong number of register infos"); + +#undef FPR_SIZE +#undef FP_SIZE +#undef XMM_SIZE +#undef YMM_SIZE +#undef DEFINE_GPR +#undef DEFINE_FPR +#undef DEFINE_FP +#undef DEFINE_XMM +#undef DEFINE_YMM +#undef DEFINE_DR +#undef DEFINE_GPR_PSEUDO_32 +#undef DEFINE_GPR_PSEUDO_16 +#undef DEFINE_GPR_PSEUDO_8H +#undef DEFINE_GPR_PSEUDO_8L + +#endif // DECLARE_REGISTER_INFOS_X86_64_STRUCT + + +#ifdef UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS + +#define UPDATE_GPR_INFO(reg, reg64) \ +do { \ + g_register_infos[gpr_##reg##_i386].byte_offset = GPR_OFFSET(reg64); \ +} while(false); + +#define UPDATE_GPR_INFO_8H(reg, reg64) \ +do { \ + g_register_infos[gpr_##reg##_i386].byte_offset = GPR_OFFSET(reg64) + 1; \ +} while(false); + +#define UPDATE_FPR_INFO(reg, reg64) \ +do { \ + g_register_infos[fpu_##reg##_i386].byte_offset = FPR_OFFSET(reg64); \ +} while(false); + +#define UPDATE_FP_INFO(reg, i) \ +do { \ + g_register_infos[fpu_##reg##i##_i386].byte_offset = FPR_OFFSET(stmm[i]); \ +} while(false); + +#define UPDATE_XMM_INFO(reg, i) \ +do { \ + g_register_infos[fpu_##reg##i##_i386].byte_offset = FPR_OFFSET(reg[i]); \ +} while(false); + +#define UPDATE_YMM_INFO(reg, i) \ +do { \ + g_register_infos[fpu_##reg##i##_i386].byte_offset = YMM_OFFSET(reg[i]); \ +} while(false); + +#define UPDATE_DR_INFO(reg_index) \ +do { \ + g_register_infos[dr##reg_index##_i386].byte_offset = DR_OFFSET(reg_index); \ +} while(false); + + // Update the register offsets + UPDATE_GPR_INFO(eax, rax); + UPDATE_GPR_INFO(ebx, rbx); + UPDATE_GPR_INFO(ecx, rcx); + UPDATE_GPR_INFO(edx, rdx); + UPDATE_GPR_INFO(edi, rdi); + UPDATE_GPR_INFO(esi, rsi); + UPDATE_GPR_INFO(ebp, rbp); + UPDATE_GPR_INFO(esp, rsp); + UPDATE_GPR_INFO(eip, rip); + UPDATE_GPR_INFO(eflags, rflags); + UPDATE_GPR_INFO(cs, cs); + UPDATE_GPR_INFO(fs, fs); + UPDATE_GPR_INFO(gs, gs); + UPDATE_GPR_INFO(ss, ss); + UPDATE_GPR_INFO(ds, ds); + UPDATE_GPR_INFO(es, es); + + UPDATE_GPR_INFO(ax, rax); + UPDATE_GPR_INFO(bx, rbx); + UPDATE_GPR_INFO(cx, rcx); + UPDATE_GPR_INFO(dx, rdx); + UPDATE_GPR_INFO(di, rdi); + UPDATE_GPR_INFO(si, rsi); + UPDATE_GPR_INFO(bp, rbp); + UPDATE_GPR_INFO(sp, rsp); + UPDATE_GPR_INFO_8H(ah, rax); + UPDATE_GPR_INFO_8H(bh, rbx); + UPDATE_GPR_INFO_8H(ch, rcx); + UPDATE_GPR_INFO_8H(dh, rdx); + UPDATE_GPR_INFO(al, rax); + UPDATE_GPR_INFO(bl, rbx); + UPDATE_GPR_INFO(cl, rcx); + UPDATE_GPR_INFO(dl, rdx); + + UPDATE_FPR_INFO(fctrl, fctrl); + UPDATE_FPR_INFO(fstat, fstat); + UPDATE_FPR_INFO(ftag, ftag); + UPDATE_FPR_INFO(fop, fop); + UPDATE_FPR_INFO(fiseg, ptr.i386.fiseg); + UPDATE_FPR_INFO(fioff, ptr.i386.fioff); + UPDATE_FPR_INFO(fooff, ptr.i386.fooff); + UPDATE_FPR_INFO(foseg, ptr.i386.foseg); + UPDATE_FPR_INFO(mxcsr, mxcsr); + UPDATE_FPR_INFO(mxcsrmask, mxcsrmask); + + UPDATE_FP_INFO(st, 0); + UPDATE_FP_INFO(st, 1); + UPDATE_FP_INFO(st, 2); + UPDATE_FP_INFO(st, 3); + UPDATE_FP_INFO(st, 4); + UPDATE_FP_INFO(st, 5); + UPDATE_FP_INFO(st, 6); + UPDATE_FP_INFO(st, 7); + UPDATE_FP_INFO(mm, 0); + UPDATE_FP_INFO(mm, 1); + UPDATE_FP_INFO(mm, 2); + UPDATE_FP_INFO(mm, 3); + UPDATE_FP_INFO(mm, 4); + UPDATE_FP_INFO(mm, 5); + UPDATE_FP_INFO(mm, 6); + UPDATE_FP_INFO(mm, 7); + + UPDATE_XMM_INFO(xmm, 0); + UPDATE_XMM_INFO(xmm, 1); + UPDATE_XMM_INFO(xmm, 2); + UPDATE_XMM_INFO(xmm, 3); + UPDATE_XMM_INFO(xmm, 4); + UPDATE_XMM_INFO(xmm, 5); + UPDATE_XMM_INFO(xmm, 6); + UPDATE_XMM_INFO(xmm, 7); + + UPDATE_YMM_INFO(ymm, 0); + UPDATE_YMM_INFO(ymm, 1); + UPDATE_YMM_INFO(ymm, 2); + UPDATE_YMM_INFO(ymm, 3); + UPDATE_YMM_INFO(ymm, 4); + UPDATE_YMM_INFO(ymm, 5); + UPDATE_YMM_INFO(ymm, 6); + UPDATE_YMM_INFO(ymm, 7); + + UPDATE_DR_INFO(0); + UPDATE_DR_INFO(1); + UPDATE_DR_INFO(2); + UPDATE_DR_INFO(3); + UPDATE_DR_INFO(4); + UPDATE_DR_INFO(5); + UPDATE_DR_INFO(6); + UPDATE_DR_INFO(7); + +#undef UPDATE_GPR_INFO +#undef UPDATE_GPR_INFO_8H +#undef UPDATE_FPR_INFO +#undef UPDATE_FP_INFO +#undef UPDATE_XMM_INFO +#undef UPDATE_YMM_INFO +#undef UPDATE_DR_INFO + +#endif // UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS + +#undef GPR_OFFSET +#undef FPR_OFFSET +#undef YMM_OFFSET diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp index 0c95d66cef94..dc90b7ae02c3 100644 --- a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -16,6 +16,9 @@ // Other libraries and framework includes // Project includes #include "lldb/Interpreter/Args.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/DataFormatters/FormatManager.h" #ifndef LLDB_DISABLE_PYTHON #include "lldb/Interpreter/PythonDataObjects.h" @@ -29,18 +32,24 @@ DynamicRegisterInfo::DynamicRegisterInfo () : m_sets (), m_set_reg_nums (), m_set_names (), - m_reg_data_byte_size (0) + m_value_regs_map (), + m_invalidate_regs_map (), + m_reg_data_byte_size (0), + m_finalized (false) { } -DynamicRegisterInfo::DynamicRegisterInfo (const lldb_private::PythonDictionary &dict) : +DynamicRegisterInfo::DynamicRegisterInfo (const lldb_private::PythonDictionary &dict, ByteOrder byte_order) : m_regs (), m_sets (), m_set_reg_nums (), m_set_names (), - m_reg_data_byte_size (0) + m_value_regs_map (), + m_invalidate_regs_map (), + m_reg_data_byte_size (0), + m_finalized (false) { - SetRegisterInfo (dict); + SetRegisterInfo (dict, byte_order); } DynamicRegisterInfo::~DynamicRegisterInfo () @@ -49,8 +58,10 @@ DynamicRegisterInfo::~DynamicRegisterInfo () size_t -DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict) +DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict, + ByteOrder byte_order) { + assert(!m_finalized); #ifndef LLDB_DISABLE_PYTHON PythonList sets (dict.GetItemForKey("sets")); if (sets) @@ -89,6 +100,12 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict PythonString gcc_pystr("gcc"); PythonString dwarf_pystr("dwarf"); PythonString generic_pystr("generic"); + PythonString slice_pystr("slice"); + PythonString composite_pystr("composite"); + PythonString invalidate_regs_pystr("invalidate-regs"); + +// typedef std::map<std::string, std::vector<std::string> > InvalidateNameMap; +// InvalidateNameMap invalidate_map; for (uint32_t i=0; i<num_regs; ++i) { PythonDictionary reg_info_dict(regs.GetItemAtIndex(i)); @@ -96,6 +113,8 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict { // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2, 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', }, RegisterInfo reg_info; + std::vector<uint32_t> value_regs; + std::vector<uint32_t> invalidate_regs; bzero (®_info, sizeof(reg_info)); reg_info.name = ConstString (reg_info_dict.GetItemForKeyAsString(name_pystr)).GetCString(); @@ -111,16 +130,177 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict if (reg_info.byte_offset == UINT32_MAX) { - Clear(); - return 0; + // No offset for this register, see if the register has a value expression + // which indicates this register is part of another register. Value expressions + // are things like "rax[31:0]" which state that the current register's value + // is in a concrete register "rax" in bits 31:0. If there is a value expression + // we can calculate the offset + bool success = false; + const char *slice_cstr = reg_info_dict.GetItemForKeyAsString(slice_pystr); + if (slice_cstr) + { + // Slices use the following format: + // REGNAME[MSBIT:LSBIT] + // REGNAME - name of the register to grab a slice of + // MSBIT - the most significant bit at which the current register value starts at + // LSBIT - the least significant bit at which the current register value ends at + static RegularExpression g_bitfield_regex("([A-Za-z_][A-Za-z0-9_]*)\\[([0-9]+):([0-9]+)\\]"); + RegularExpression::Match regex_match(3); + if (g_bitfield_regex.Execute(slice_cstr, ®ex_match)) + { + llvm::StringRef reg_name_str; + std::string msbit_str; + std::string lsbit_str; + if (regex_match.GetMatchAtIndex(slice_cstr, 1, reg_name_str) && + regex_match.GetMatchAtIndex(slice_cstr, 2, msbit_str) && + regex_match.GetMatchAtIndex(slice_cstr, 3, lsbit_str)) + { + const uint32_t msbit = Args::StringToUInt32(msbit_str.c_str(), UINT32_MAX); + const uint32_t lsbit = Args::StringToUInt32(lsbit_str.c_str(), UINT32_MAX); + if (msbit != UINT32_MAX && lsbit != UINT32_MAX) + { + if (msbit > lsbit) + { + const uint32_t msbyte = msbit / 8; + const uint32_t lsbyte = lsbit / 8; + + ConstString containing_reg_name(reg_name_str); + + RegisterInfo *containing_reg_info = GetRegisterInfo (containing_reg_name); + if (containing_reg_info) + { + const uint32_t max_bit = containing_reg_info->byte_size * 8; + if (msbit < max_bit && lsbit < max_bit) + { + m_invalidate_regs_map[containing_reg_info->kinds[eRegisterKindLLDB]].push_back(i); + m_value_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]); + m_invalidate_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]); + + if (byte_order == eByteOrderLittle) + { + success = true; + reg_info.byte_offset = containing_reg_info->byte_offset + lsbyte; + } + else if (byte_order == eByteOrderBig) + { + success = true; + reg_info.byte_offset = containing_reg_info->byte_offset + msbyte; + } + else + { + assert(!"Invalid byte order"); + } + } + else + { + if (msbit > max_bit) + printf("error: msbit (%u) must be less than the bitsize of the register (%u)\n", msbit, max_bit); + else + printf("error: lsbit (%u) must be less than the bitsize of the register (%u)\n", lsbit, max_bit); + } + } + else + { + printf("error: invalid concrete register \"%s\"\n", containing_reg_name.GetCString()); + } + } + else + { + printf("error: msbit (%u) must be greater than lsbit (%u)\n", msbit, lsbit); + } + } + else + { + printf("error: msbit (%u) and lsbit (%u) must be valid\n", msbit, lsbit); + } + } + else + { + // TODO: print error invalid slice string that doesn't follow the format + printf("error: failed to extract regex matches for parsing the register bitfield regex\n"); + + } + } + else + { + // TODO: print error invalid slice string that doesn't follow the format + printf("error: failed to match against register bitfield regex\n"); + } + } + else + { + PythonList composite_reg_list (reg_info_dict.GetItemForKey(composite_pystr)); + if (composite_reg_list) + { + const size_t num_composite_regs = composite_reg_list.GetSize(); + if (num_composite_regs > 0) + { + uint32_t composite_offset = UINT32_MAX; + for (uint32_t composite_idx=0; composite_idx<num_composite_regs; ++composite_idx) + { + PythonString composite_reg_name_pystr(composite_reg_list.GetItemAtIndex(composite_idx)); + if (composite_reg_name_pystr) + { + ConstString composite_reg_name(composite_reg_name_pystr.GetString()); + if (composite_reg_name) + { + RegisterInfo *composite_reg_info = GetRegisterInfo (composite_reg_name); + if (composite_reg_info) + { + if (composite_offset > composite_reg_info->byte_offset) + composite_offset = composite_reg_info->byte_offset; + m_value_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]); + m_invalidate_regs_map[composite_reg_info->kinds[eRegisterKindLLDB]].push_back(i); + m_invalidate_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]); + } + else + { + // TODO: print error invalid slice string that doesn't follow the format + printf("error: failed to find composite register by name: \"%s\"\n", composite_reg_name.GetCString()); + } + } + else + { + printf("error: 'composite' key contained an empty string\n"); + } + } + else + { + printf("error: 'composite' list value wasn't a python string\n"); + } + } + if (composite_offset != UINT32_MAX) + { + reg_info.byte_offset = composite_offset; + success = m_value_regs_map.find(i) != m_value_regs_map.end(); + } + else + { + printf("error: 'composite' registers must specify at least one real register\n"); + } + } + else + { + printf("error: 'composite' list was empty\n"); + } + } + } + + + if (!success) + { + Clear(); + return 0; + } } - reg_info.byte_size = reg_info_dict.GetItemForKeyAsInteger(bitsize_pystr, 0) / 8; - - if (reg_info.byte_size == 0) + const int64_t bitsize = reg_info_dict.GetItemForKeyAsInteger(bitsize_pystr, 0); + if (bitsize == 0) { Clear(); return 0; } + + reg_info.byte_size = bitsize / 8; const char *format_cstr = reg_info_dict.GetItemForKeyAsString(format_pystr); if (format_cstr) @@ -132,13 +312,15 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict } } else - reg_info.format = eFormatHex; - + { + reg_info.format = (Format)reg_info_dict.GetItemForKeyAsInteger (format_pystr, eFormatHex); + } + const char *encoding_cstr = reg_info_dict.GetItemForKeyAsString(encoding_pystr); if (encoding_cstr) reg_info.encoding = Args::StringToEncoding (encoding_cstr, eEncodingUint); else - reg_info.encoding = eEncodingUint; + reg_info.encoding = (Encoding)reg_info_dict.GetItemForKeyAsInteger (encoding_pystr, eEncodingUint); const int64_t set = reg_info_dict.GetItemForKeyAsInteger(set_pystr, -1); if (set >= m_sets.size()) @@ -147,11 +329,75 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict return 0; } + // Fill in the register numbers reg_info.kinds[lldb::eRegisterKindLLDB] = i; reg_info.kinds[lldb::eRegisterKindGDB] = i; reg_info.kinds[lldb::eRegisterKindGCC] = reg_info_dict.GetItemForKeyAsInteger(gcc_pystr, LLDB_INVALID_REGNUM); reg_info.kinds[lldb::eRegisterKindDWARF] = reg_info_dict.GetItemForKeyAsInteger(dwarf_pystr, LLDB_INVALID_REGNUM); - reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister (reg_info_dict.GetItemForKeyAsString(generic_pystr)); + const char *generic_cstr = reg_info_dict.GetItemForKeyAsString(generic_pystr); + if (generic_cstr) + reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister (generic_cstr); + else + reg_info.kinds[lldb::eRegisterKindGeneric] = reg_info_dict.GetItemForKeyAsInteger(generic_pystr, LLDB_INVALID_REGNUM); + + // Check if this register invalidates any other register values when it is modified + PythonList invalidate_reg_list (reg_info_dict.GetItemForKey(invalidate_regs_pystr)); + if (invalidate_reg_list) + { + const size_t num_regs = invalidate_reg_list.GetSize(); + if (num_regs > 0) + { + for (uint32_t idx=0; idx<num_regs; ++idx) + { + PythonObject invalidate_reg_object (invalidate_reg_list.GetItemAtIndex(idx)); + PythonString invalidate_reg_name_pystr(invalidate_reg_object); + if (invalidate_reg_name_pystr) + { + ConstString invalidate_reg_name(invalidate_reg_name_pystr.GetString()); + if (invalidate_reg_name) + { + RegisterInfo *invalidate_reg_info = GetRegisterInfo (invalidate_reg_name); + if (invalidate_reg_info) + { + m_invalidate_regs_map[i].push_back(invalidate_reg_info->kinds[eRegisterKindLLDB]); + } + else + { + // TODO: print error invalid slice string that doesn't follow the format + printf("error: failed to find a 'invalidate-regs' register for \"%s\" while parsing register \"%s\"\n", invalidate_reg_name.GetCString(), reg_info.name); + } + } + else + { + printf("error: 'invalidate-regs' list value was an empty string\n"); + } + } + else + { + PythonInteger invalidate_reg_num(invalidate_reg_object); + + if (invalidate_reg_num) + { + const int64_t r = invalidate_reg_num.GetInteger(); + if (r != UINT64_MAX) + m_invalidate_regs_map[i].push_back(r); + else + printf("error: 'invalidate-regs' list value wasn't a valid integer\n"); + } + else + { + printf("error: 'invalidate-regs' list value wasn't a python string or integer\n"); + } + } + } + } + else + { + printf("error: 'invalidate-regs' contained an empty list\n"); + } + } + + // Calculate the register offset const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size; if (m_reg_data_byte_size < end_reg_offset) m_reg_data_byte_size = end_reg_offset; @@ -169,7 +415,7 @@ DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict Finalize (); } #endif - return 0; + return m_regs.size(); } @@ -179,10 +425,22 @@ DynamicRegisterInfo::AddRegister (RegisterInfo ®_info, ConstString ®_alt_name, ConstString &set_name) { + assert(!m_finalized); const uint32_t reg_num = m_regs.size(); reg_info.name = reg_name.AsCString(); assert (reg_info.name); reg_info.alt_name = reg_alt_name.AsCString(NULL); + uint32_t i; + if (reg_info.value_regs) + { + for (i=0; reg_info.value_regs[i] != LLDB_INVALID_REGNUM; ++i) + m_value_regs_map[reg_num].push_back(reg_info.value_regs[i]); + } + if (reg_info.invalidate_regs) + { + for (i=0; reg_info.invalidate_regs[i] != LLDB_INVALID_REGNUM; ++i) + m_invalidate_regs_map[reg_num].push_back(reg_info.invalidate_regs[i]); + } m_regs.push_back (reg_info); uint32_t set = GetRegisterSetIndexByName (set_name, true); assert (set < m_sets.size()); @@ -197,12 +455,99 @@ DynamicRegisterInfo::AddRegister (RegisterInfo ®_info, void DynamicRegisterInfo::Finalize () { - for (uint32_t set = 0; set < m_sets.size(); ++set) + if (m_finalized) + return; + + m_finalized = true; + const size_t num_sets = m_sets.size(); + for (size_t set = 0; set < num_sets; ++set) { assert (m_sets.size() == m_set_reg_nums.size()); m_sets[set].num_registers = m_set_reg_nums[set].size(); m_sets[set].registers = &m_set_reg_nums[set][0]; } + + // sort and unique all value registers and make sure each is terminated with + // LLDB_INVALID_REGNUM + + for (reg_to_regs_map::iterator pos = m_value_regs_map.begin(), end = m_value_regs_map.end(); + pos != end; + ++pos) + { + if (pos->second.size() > 1) + { + std::sort (pos->second.begin(), pos->second.end()); + reg_num_collection::iterator unique_end = std::unique (pos->second.begin(), pos->second.end()); + if (unique_end != pos->second.end()) + pos->second.erase(unique_end, pos->second.end()); + } + assert (!pos->second.empty()); + if (pos->second.back() != LLDB_INVALID_REGNUM) + pos->second.push_back(LLDB_INVALID_REGNUM); + } + + // Now update all value_regs with each register info as needed + const size_t num_regs = m_regs.size(); + for (size_t i=0; i<num_regs; ++i) + { + if (m_value_regs_map.find(i) != m_value_regs_map.end()) + m_regs[i].value_regs = m_value_regs_map[i].data(); + else + m_regs[i].value_regs = NULL; + } + + // Expand all invalidation dependencies + for (reg_to_regs_map::iterator pos = m_invalidate_regs_map.begin(), end = m_invalidate_regs_map.end(); + pos != end; + ++pos) + { + const uint32_t reg_num = pos->first; + + if (m_regs[reg_num].value_regs) + { + reg_num_collection extra_invalid_regs; + for (const uint32_t invalidate_reg_num : pos->second) + { + reg_to_regs_map::iterator invalidate_pos = m_invalidate_regs_map.find(invalidate_reg_num); + if (invalidate_pos != m_invalidate_regs_map.end()) + { + for (const uint32_t concrete_invalidate_reg_num : invalidate_pos->second) + { + if (concrete_invalidate_reg_num != reg_num) + extra_invalid_regs.push_back(concrete_invalidate_reg_num); + } + } + } + pos->second.insert(pos->second.end(), extra_invalid_regs.begin(), extra_invalid_regs.end()); + } + } + + // sort and unique all invalidate registers and make sure each is terminated with + // LLDB_INVALID_REGNUM + for (reg_to_regs_map::iterator pos = m_invalidate_regs_map.begin(), end = m_invalidate_regs_map.end(); + pos != end; + ++pos) + { + if (pos->second.size() > 1) + { + std::sort (pos->second.begin(), pos->second.end()); + reg_num_collection::iterator unique_end = std::unique (pos->second.begin(), pos->second.end()); + if (unique_end != pos->second.end()) + pos->second.erase(unique_end, pos->second.end()); + } + assert (!pos->second.empty()); + if (pos->second.back() != LLDB_INVALID_REGNUM) + pos->second.push_back(LLDB_INVALID_REGNUM); + } + + // Now update all invalidate_regs with each register info as needed + for (size_t i=0; i<num_regs; ++i) + { + if (m_invalidate_regs_map.find(i) != m_invalidate_regs_map.end()) + m_regs[i].invalidate_regs = m_invalidate_regs_map[i].data(); + else + m_regs[i].invalidate_regs = NULL; + } } size_t @@ -276,4 +621,83 @@ DynamicRegisterInfo::Clear() m_sets.clear(); m_set_reg_nums.clear(); m_set_names.clear(); + m_value_regs_map.clear(); + m_invalidate_regs_map.clear(); + m_reg_data_byte_size = 0; + m_finalized = false; +} + +void +DynamicRegisterInfo::Dump () const +{ + StreamFile s(stdout, false); + const size_t num_regs = m_regs.size(); + s.Printf("%p: DynamicRegisterInfo contains %zu registers:\n", this, num_regs); + for (size_t i=0; i<num_regs; ++i) + { + s.Printf("[%3zu] name = %-10s", i, m_regs[i].name); + s.Printf(", size = %2u, offset = %4u, encoding = %u, format = %-10s", + m_regs[i].byte_size, + m_regs[i].byte_offset, + m_regs[i].encoding, + FormatManager::GetFormatAsCString (m_regs[i].format)); + if (m_regs[i].kinds[eRegisterKindGDB] != LLDB_INVALID_REGNUM) + s.Printf(", gdb = %3u", m_regs[i].kinds[eRegisterKindGDB]); + if (m_regs[i].kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM) + s.Printf(", dwarf = %3u", m_regs[i].kinds[eRegisterKindDWARF]); + if (m_regs[i].kinds[eRegisterKindGCC] != LLDB_INVALID_REGNUM) + s.Printf(", gcc = %3u", m_regs[i].kinds[eRegisterKindGCC]); + if (m_regs[i].kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM) + s.Printf(", generic = %3u", m_regs[i].kinds[eRegisterKindGeneric]); + if (m_regs[i].alt_name) + s.Printf(", alt-name = %s", m_regs[i].alt_name); + if (m_regs[i].value_regs) + { + s.Printf(", value_regs = [ "); + for (size_t j=0; m_regs[i].value_regs[j] != LLDB_INVALID_REGNUM; ++j) + { + s.Printf("%s ", m_regs[m_regs[i].value_regs[j]].name); + } + s.Printf("]"); + } + if (m_regs[i].invalidate_regs) + { + s.Printf(", invalidate_regs = [ "); + for (size_t j=0; m_regs[i].invalidate_regs[j] != LLDB_INVALID_REGNUM; ++j) + { + s.Printf("%s ", m_regs[m_regs[i].invalidate_regs[j]].name); + } + s.Printf("]"); + } + s.EOL(); + } + + const size_t num_sets = m_sets.size(); + s.Printf("%p: DynamicRegisterInfo contains %zu register sets:\n", this, num_sets); + for (size_t i=0; i<num_sets; ++i) + { + s.Printf("set[%zu] name = %s, regs = [", i, m_sets[i].name); + for (size_t idx=0; idx<m_sets[i].num_registers; ++idx) + { + s.Printf("%s ", m_regs[m_sets[i].registers[idx]].name); + } + s.Printf("]\n"); + } +} + + + +lldb_private::RegisterInfo * +DynamicRegisterInfo::GetRegisterInfo (const lldb_private::ConstString ®_name) +{ + for (auto ®_info : m_regs) + { + // We can use pointer comparison since we used a ConstString to set + // the "name" member in AddRegister() + if (reg_info.name == reg_name.GetCString()) + { + return ®_info; + } + } + return NULL; } diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/source/Plugins/Process/Utility/DynamicRegisterInfo.h index a11cd333545f..a41c77e49f9d 100644 --- a/source/Plugins/Process/Utility/DynamicRegisterInfo.h +++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.h @@ -13,6 +13,7 @@ // C Includes // C++ Includes #include <vector> +#include <map> // Other libraries and framework includes // Project includes @@ -24,13 +25,15 @@ class DynamicRegisterInfo public: DynamicRegisterInfo (); - DynamicRegisterInfo (const lldb_private::PythonDictionary &dict); + DynamicRegisterInfo (const lldb_private::PythonDictionary &dict, + lldb::ByteOrder byte_order); virtual ~DynamicRegisterInfo (); size_t - SetRegisterInfo (const lldb_private::PythonDictionary &dict); + SetRegisterInfo (const lldb_private::PythonDictionary &dict, + lldb::ByteOrder byte_order); void AddRegister (lldb_private::RegisterInfo ®_info, @@ -63,6 +66,9 @@ public: ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const; void + Dump () const; + + void Clear(); protected: @@ -74,12 +80,19 @@ protected: typedef std::vector <uint32_t> reg_num_collection; typedef std::vector <reg_num_collection> set_reg_num_collection; typedef std::vector <lldb_private::ConstString> name_collection; + typedef std::map<uint32_t, reg_num_collection> reg_to_regs_map; + + lldb_private::RegisterInfo * + GetRegisterInfo (const lldb_private::ConstString ®_name); reg_collection m_regs; set_collection m_sets; set_reg_num_collection m_set_reg_nums; name_collection m_set_names; + reg_to_regs_map m_value_regs_map; + reg_to_regs_map m_invalidate_regs_map; size_t m_reg_data_byte_size; // The number of bytes required to store all registers + bool m_finalized; }; #endif // lldb_DynamicRegisterInfo_h_ diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 499d6d766150..8b22d6457ada 100644 --- a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -17,8 +17,19 @@ #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadPlanCallFunction.h" +#include "lldb/Host/Config.h" +#ifndef LLDB_DISABLE_POSIX #include <sys/mman.h> +#else +// define them +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 +#define MAP_PRIVATE 2 +#define MAP_ANON 0x1000 +#endif using namespace lldb; using namespace lldb_private; diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index 1ffc30da5762..c19aec3a02c7 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -369,8 +369,13 @@ RegisterContextLLDB::InitializeNonZerothFrame() return; } + bool resolve_tail_call_address = true; // m_current_pc can be one past the address range of the function... + uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, + eSymbolContextFunction | eSymbolContextSymbol, + m_sym_ctx, resolve_tail_call_address); + // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us. - if ((pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) + if ((resolved_scope & eSymbolContextSymbol) == eSymbolContextSymbol) { m_sym_ctx_valid = true; } @@ -387,35 +392,18 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (m_sym_ctx_valid == false) decr_pc_and_recompute_addr_range = true; - // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp), - // and our "current" pc is the start of a function... + // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp), and + // our "current" pc is the start of a function or our "current" pc is one past the end of a function... if (m_sym_ctx_valid && GetNextFrame()->m_frame_type != eSigtrampFrame && GetNextFrame()->m_frame_type != eDebuggerFrame && addr_range.GetBaseAddress().IsValid() - && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() - && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset()) + && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()) { - decr_pc_and_recompute_addr_range = true; - } - - // We need to back up the pc by 1 byte and re-search for the Symbol to handle the case where the "saved pc" - // value is pointing to the next function, e.g. if a function ends with a CALL instruction. - // FIXME this may need to be an architectural-dependent behavior; if so we'll need to add a member function - // to the ABI plugin and consult that. - if (decr_pc_and_recompute_addr_range) - { - Address temporary_pc(m_current_pc); - temporary_pc.SetOffset(m_current_pc.GetOffset() - 1); - m_sym_ctx.Clear(false); - m_sym_ctx_valid = false; - if ((pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) + if (addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset() || + addr_range.GetBaseAddress().GetOffset() + addr_range.GetByteSize() == m_current_pc.GetOffset()) { - m_sym_ctx_valid = true; - } - if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range)) - { - m_sym_ctx_valid = false; + decr_pc_and_recompute_addr_range = true; } } @@ -632,6 +620,10 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp); } + else + { + UnwindLogMsg ("unable to get architectural default UnwindPlan from ABI plugin"); + } bool behaves_like_zeroth_frame = false; if (IsFrameZero () @@ -648,9 +640,10 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // in the zeroth frame, we need to use the "unwind at first instruction" arch default UnwindPlan // Also, if this Process can report on memory region attributes, any non-executable region means // we jumped through a bad function pointer - handle the same way as 0x0. - // Note, if the symbol context has a function for the symbol, then we don't need to do this check. + // Note, if we have a symbol context & a symbol, we don't want to follow this code path. This is + // for jumping to memory regions without any information available. - if ((!m_sym_ctx_valid || m_sym_ctx.function == NULL) && behaves_like_zeroth_frame && m_current_pc.IsValid()) + if ((!m_sym_ctx_valid || m_sym_ctx.symbol == NULL) && behaves_like_zeroth_frame && m_current_pc.IsValid()) { uint32_t permissions; addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()); @@ -757,8 +750,24 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () return unwind_plan_sp; } + // If we're on the first instruction of a function, and we have an architectural default UnwindPlan + // for the initial instruction of a function, use that. + if (m_current_offset_backed_up_one == 0) + { + unwind_plan_sp = func_unwinders_sp->GetUnwindPlanArchitectureDefaultAtFunctionEntry (m_thread); + if (unwind_plan_sp) + { + UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString()); + return unwind_plan_sp; + } + } + // If nothing else, use the architectural default UnwindPlan and hope that does the job. - UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", arch_default_unwind_plan_sp->GetSourceName().GetCString()); + if (arch_default_unwind_plan_sp) + UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", arch_default_unwind_plan_sp->GetSourceName().GetCString()); + else + UnwindLogMsg ("Unable to find any UnwindPlan for full unwind of this frame."); + return arch_default_unwind_plan_sp; } @@ -1101,7 +1110,8 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum); if (reg_info && abi->RegisterIsVolatile (reg_info)) { - UnwindLogMsg ("did not supply reg location for %d because it is volatile", lldb_regnum); + UnwindLogMsg ("did not supply reg location for %d (%s) because it is volatile", + lldb_regnum, reg_info->name ? reg_info->name : "??"); return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile; } } @@ -1186,7 +1196,8 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat DataExtractor dwarfdata (unwindplan_regloc.GetDWARFExpressionBytes(), unwindplan_regloc.GetDWARFExpressionLength(), process->GetByteOrder(), process->GetAddressByteSize()); - DWARFExpression dwarfexpr (dwarfdata, 0, unwindplan_regloc.GetDWARFExpressionLength()); + ModuleSP opcode_ctx; + DWARFExpression dwarfexpr (opcode_ctx, dwarfdata, 0, unwindplan_regloc.GetDWARFExpressionLength()); dwarfexpr.SetRegisterKind (unwindplan_registerkind); Value result; Error error; diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp index 2c3eee452488..5b6d9fe9f3bb 100644 --- a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp +++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp @@ -147,9 +147,9 @@ RegisterContextMacOSXFrameBackchain::ReadRegister (const RegisterInfo *reg_info, } break; - // TOOD: need a better way to detect when "long double" types are + // TOOD: need a better way to detect when "long double" types are // the same bytes size as "double" -#if !defined(__arm__) +#if !defined(__arm__) && !defined(_MSC_VER) && !defined(__mips__) case sizeof (long double): if (sizeof (long double) == sizeof(uint32_t)) { diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp index 0eea00363498..552ae501bd21 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -185,21 +185,7 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) } goto unwind_done; } - if (!m_frames.empty()) - { - if (m_frames.back()->start_pc == cursor_sp->start_pc) - { - if (m_frames.back()->cfa == cursor_sp->cfa) - goto unwind_done; // Infinite loop where the current cursor is the same as the previous one... - else if (abi && abi->StackUsesFrames()) - { - // We might have a CFA that is not using the frame pointer and - // we want to validate that the frame pointer is valid. - if (reg_ctx_sp->GetFP() == 0) - goto unwind_done; - } - } - } + cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; m_frames.push_back (cursor_sp); return true; diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp index dd553ce36c89..acb3154f6290 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -338,9 +338,9 @@ ProcessElfCore::GetImageInfoAddress() { Target *target = &GetTarget(); ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); - Address addr = obj_file->GetImageInfoAddress(); + Address addr = obj_file->GetImageInfoAddress(target); - if (addr.IsValid()) + if (addr.IsValid()) return addr.GetLoadAddress(target); return LLDB_INVALID_ADDRESS; } @@ -363,13 +363,6 @@ enum { NT_FREEBSD_PROCSTAT_AUXV = 16 }; -/// Align the given value to next boundary specified by the alignment bytes -static uint32_t -AlignToNext(uint32_t value, int alignment_bytes) -{ - return (value + alignment_bytes - 1) & ~(alignment_bytes - 1); -} - /// Note Structure found in ELF core dumps. /// This is PT_NOTE type program/segments in the core file. struct ELFNote @@ -421,7 +414,7 @@ struct ELFNote } } - const char *cstr = data.GetCStr(offset, AlignToNext(n_namesz, 4)); + const char *cstr = data.GetCStr(offset, llvm::RoundUpToAlignment(n_namesz, 4)); if (cstr == NULL) { Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); @@ -441,7 +434,8 @@ ParseFreeBSDPrStatus(ThreadData *thread_data, DataExtractor &data, ArchSpec &arch) { lldb::offset_t offset = 0; - bool have_padding = (arch.GetMachine() == llvm::Triple::x86_64); + bool have_padding = (arch.GetMachine() == llvm::Triple::mips64 || + arch.GetMachine() == llvm::Triple::x86_64); int pr_version = data.GetU32(&offset); Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); @@ -525,7 +519,7 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader * size_t note_start, note_size; note_start = offset; - note_size = AlignToNext(note.n_descsz, 4); + note_size = llvm::RoundUpToAlignment(note.n_descsz, 4); // Store the NOTE information in the current thread DataExtractor note_data (segment_data, note_start, note_size); diff --git a/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp b/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp deleted file mode 100644 index 6210175f9a7f..000000000000 --- a/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp +++ /dev/null @@ -1,68 +0,0 @@ -//===-- RegisterContextCoreFreeBSD_x86_64.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/Core/DataExtractor.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Target/Thread.h" -#include "RegisterContextCoreFreeBSD_x86_64.h" - -RegisterContextCoreFreeBSD_x86_64::RegisterContextCoreFreeBSD_x86_64(Thread &thread, - const DataExtractor &gpregset, const DataExtractor &fpregset) - : RegisterContextFreeBSD_x86_64(thread, 0) -{ - size_t size, len; - - size = GetGPRSize(); - m_gpregset = new uint8_t[size]; - len = gpregset.ExtractBytes(0, size, lldb::eByteOrderLittle, m_gpregset); - assert(len == size); -} - -RegisterContextCoreFreeBSD_x86_64::~RegisterContextCoreFreeBSD_x86_64() -{ - delete [] m_gpregset; -} - -bool -RegisterContextCoreFreeBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) -{ - value = *(uint64_t *)(m_gpregset + reg_info->byte_offset); - return true; -} - -bool -RegisterContextCoreFreeBSD_x86_64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) -{ - return false; -} - -bool -RegisterContextCoreFreeBSD_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) -{ - return false; -} - -bool -RegisterContextCoreFreeBSD_x86_64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) -{ - return false; -} - -bool -RegisterContextCoreFreeBSD_x86_64::UpdateAfterBreakpoint() -{ - return false; -} - -bool -RegisterContextCoreFreeBSD_x86_64::HardwareSingleStep(bool enable) -{ - return false; -} - diff --git a/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h b/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h deleted file mode 100644 index acd594a6e666..000000000000 --- a/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h +++ /dev/null @@ -1,47 +0,0 @@ -//===-- RegisterContextCoreFreeBSD_x86_64.h ----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===---------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextCoreFreeBSD_x86_64_H_ -#define liblldb_RegisterContextCoreFreeBSD_x86_64_H_ - -#include "Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h" - -using namespace lldb_private; - -class RegisterContextCoreFreeBSD_x86_64: public RegisterContextFreeBSD_x86_64 -{ -public: - RegisterContextCoreFreeBSD_x86_64 (Thread &thread, const DataExtractor &gpregset, - const DataExtractor &fpregset); - - ~RegisterContextCoreFreeBSD_x86_64(); - - virtual bool - ReadRegister(const RegisterInfo *reg_info, RegisterValue &value); - - bool - ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - - virtual bool - WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value); - - bool - WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - - bool - HardwareSingleStep(bool enable); - - bool - UpdateAfterBreakpoint(); - -private: - uint8_t *m_gpregset; -}; - -#endif // #ifndef liblldb_RegisterContextCoreFreeBSD_x86_64_H_ diff --git a/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp b/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp deleted file mode 100644 index d9e3f6d5f90b..000000000000 --- a/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp +++ /dev/null @@ -1,68 +0,0 @@ -//===-- RegisterContextCoreLinux_x86_64.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/Core/DataExtractor.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Target/Thread.h" -#include "RegisterContextCoreLinux_x86_64.h" - -RegisterContextCoreLinux_x86_64::RegisterContextCoreLinux_x86_64(Thread &thread, - const DataExtractor &gpregset, - const DataExtractor &fpregset) - : RegisterContextLinux_x86_64(thread, 0) -{ - size_t size, len; - - size = GetGPRSize(); - m_gpregset = new uint8_t[size]; - len = gpregset.ExtractBytes(0, size, lldb::eByteOrderLittle, m_gpregset); - assert(len == size); -} - -RegisterContextCoreLinux_x86_64::~RegisterContextCoreLinux_x86_64() -{ - delete [] m_gpregset; -} - -bool -RegisterContextCoreLinux_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) -{ - value = *(uint64_t *)(m_gpregset + reg_info->byte_offset); - return true; -} - -bool -RegisterContextCoreLinux_x86_64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) -{ - return false; -} - -bool -RegisterContextCoreLinux_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) -{ - return false; -} - -bool -RegisterContextCoreLinux_x86_64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) -{ - return false; -} - -bool -RegisterContextCoreLinux_x86_64::UpdateAfterBreakpoint() -{ - return false; -} - -bool -RegisterContextCoreLinux_x86_64::HardwareSingleStep(bool enable) -{ - return false; -} diff --git a/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h b/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h deleted file mode 100644 index 9cf545afd56a..000000000000 --- a/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h +++ /dev/null @@ -1,54 +0,0 @@ -//===-- RegisterContextCoreLinux_x86_64.h ----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===---------------------------------------------------------------------===// - -#ifndef liblldb_RegisterContextCoreLinux_x86_64_H_ -#define liblldb_RegisterContextCoreLinux_x86_64_H_ - -#include "Plugins/Process/POSIX/RegisterContextLinux_x86_64.h" - -using namespace lldb_private; - -class RegisterContextCoreLinux_x86_64: public RegisterContextLinux_x86_64 -{ -public: - RegisterContextCoreLinux_x86_64 (Thread &thread, const DataExtractor &gpregset, - const DataExtractor &fpregset); - - ~RegisterContextCoreLinux_x86_64(); - - virtual bool - ReadRegister(const RegisterInfo *reg_info, RegisterValue &value); - - bool - ReadAllRegisterValues(lldb::DataBufferSP &data_sp); - - virtual bool - WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value); - - bool - WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); - - bool - HardwareSingleStep(bool enable); - - bool - UpdateAfterBreakpoint(); - -protected: - bool - ReadFPR() - { - assert(0); - } - -private: - uint8_t *m_gpregset; -}; - -#endif // #ifndef liblldb_RegisterContextCoreLinux_x86_64_H_ diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp new file mode 100644 index 000000000000..b95a51130ca7 --- /dev/null +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp @@ -0,0 +1,94 @@ +//===-- RegisterContextCorePOSIX_mips64.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/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" +#include "RegisterContextPOSIX.h" +#include "RegisterContextPOSIXCore_mips64.h" + +using namespace lldb_private; + +RegisterContextCorePOSIX_mips64::RegisterContextCorePOSIX_mips64(Thread &thread, + RegisterInfoInterface *register_info, + const DataExtractor &gpregset, + const DataExtractor &fpregset) + : RegisterContextPOSIX_mips64(thread, 0, register_info) +{ + size_t i; + lldb::offset_t offset = 0; + + for (i = 0; i < k_num_gpr_registers_mips64; i++) + { + m_reg[i] = gpregset.GetU64(&offset); + } +} + +RegisterContextCorePOSIX_mips64::~RegisterContextCorePOSIX_mips64() +{ +} + +bool +RegisterContextCorePOSIX_mips64::ReadGPR() +{ + return true; +} + +bool +RegisterContextCorePOSIX_mips64::ReadFPR() +{ + return false; +} + +bool +RegisterContextCorePOSIX_mips64::WriteGPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_mips64::WriteFPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_mips64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + int reg_num = reg_info->byte_offset / 8; + assert(reg_num < k_num_gpr_registers_mips64); + value = m_reg[reg_num]; + return true; +} + +bool +RegisterContextCorePOSIX_mips64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_mips64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + return false; +} + +bool +RegisterContextCorePOSIX_mips64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_mips64::HardwareSingleStep(bool enable) +{ + return false; +} diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h new file mode 100644 index 000000000000..92e486bf2235 --- /dev/null +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h @@ -0,0 +1,58 @@ +//===-- RegisterContextCorePOSIX_mips64.h ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextCorePOSIX_mips64_H_ +#define liblldb_RegisterContextCorePOSIX_mips64_H_ + +#include "Plugins/Process/POSIX/RegisterContextPOSIX_mips64.h" + +class RegisterContextCorePOSIX_mips64 : + public RegisterContextPOSIX_mips64 +{ +public: + RegisterContextCorePOSIX_mips64 (lldb_private::Thread &thread, + RegisterInfoInterface *register_info, + const lldb_private::DataExtractor &gpregset, + const lldb_private::DataExtractor &fpregset); + + ~RegisterContextCorePOSIX_mips64(); + + virtual bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + virtual bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + bool + HardwareSingleStep(bool enable); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + +private: + uint64_t m_reg[40]; +}; + +#endif // #ifndef liblldb_RegisterContextCorePOSIX_mips64_H_ diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp new file mode 100644 index 000000000000..610506c20a0b --- /dev/null +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp @@ -0,0 +1,92 @@ +//===-- RegisterContextCorePOSIX_x86_64.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/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" +#include "RegisterContextPOSIX.h" +#include "RegisterContextPOSIXCore_x86_64.h" + +using namespace lldb_private; + +RegisterContextCorePOSIX_x86_64::RegisterContextCorePOSIX_x86_64(Thread &thread, + RegisterInfoInterface *register_info, + const DataExtractor &gpregset, + const DataExtractor &fpregset) + : RegisterContextPOSIX_x86 (thread, 0, register_info) +{ + size_t size, len; + + size = GetGPRSize(); + m_gpregset = new uint8_t[size]; + len = gpregset.ExtractBytes (0, size, lldb::eByteOrderLittle, m_gpregset); + assert(len == size); +} + +RegisterContextCorePOSIX_x86_64::~RegisterContextCorePOSIX_x86_64() +{ + delete [] m_gpregset; +} + +bool +RegisterContextCorePOSIX_x86_64::ReadGPR() +{ + return m_gpregset != NULL; +} + +bool +RegisterContextCorePOSIX_x86_64::ReadFPR() +{ + return false; +} + +bool +RegisterContextCorePOSIX_x86_64::WriteGPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_x86_64::WriteFPR() +{ + assert(0); + return false; +} + +bool +RegisterContextCorePOSIX_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + value = *(uint64_t *)(m_gpregset + reg_info->byte_offset); + return true; +} + +bool +RegisterContextCorePOSIX_x86_64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + return false; +} + +bool +RegisterContextCorePOSIX_x86_64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextCorePOSIX_x86_64::HardwareSingleStep(bool enable) +{ + return false; +} diff --git a/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h new file mode 100644 index 000000000000..d4ea14fab7b1 --- /dev/null +++ b/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h @@ -0,0 +1,58 @@ +//===-- RegisterContextCorePOSIX_x86_64.h ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextCorePOSIX_x86_64_H_ +#define liblldb_RegisterContextCorePOSIX_x86_64_H_ + +#include "Plugins/Process/POSIX/RegisterContextPOSIX_x86.h" + +class RegisterContextCorePOSIX_x86_64 : + public RegisterContextPOSIX_x86 +{ +public: + RegisterContextCorePOSIX_x86_64 (lldb_private::Thread &thread, + RegisterInfoInterface *register_info, + const lldb_private::DataExtractor &gpregset, + const lldb_private::DataExtractor &fpregset); + + ~RegisterContextCorePOSIX_x86_64(); + + virtual bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + virtual bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + bool + HardwareSingleStep(bool enable); + +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + +private: + uint8_t *m_gpregset; +}; + +#endif // #ifndef liblldb_RegisterContextCorePOSIX_x86_64_H_ diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/source/Plugins/Process/elf-core/ThreadElfCore.cpp index a7229663dc89..3bda86dc0f73 100644 --- a/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -16,8 +16,11 @@ #include "ThreadElfCore.h" #include "ProcessElfCore.h" -#include "RegisterContextCoreFreeBSD_x86_64.h" -#include "RegisterContextCoreLinux_x86_64.h" +#include "RegisterContextLinux_x86_64.h" +#include "RegisterContextFreeBSD_mips64.h" +#include "RegisterContextFreeBSD_x86_64.h" +#include "RegisterContextPOSIXCore_mips64.h" +#include "RegisterContextPOSIXCore_x86_64.h" using namespace lldb; using namespace lldb_private; @@ -84,14 +87,28 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame) ArchSpec arch = process->GetArchitecture(); switch (arch.GetMachine()) { + case llvm::Triple::mips64: + switch (arch.GetTriple().getOS()) + { + case llvm::Triple::FreeBSD: + m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, new RegisterContextFreeBSD_mips64(arch), m_gpregset_data, m_fpregset_data)); + break; + default: + if (log) + log->Printf ("elf-core::%s:: OS(%d) not supported", + __FUNCTION__, arch.GetTriple().getOS()); + assert (false && "OS not supported"); + break; + } + break; case llvm::Triple::x86_64: switch (arch.GetTriple().getOS()) { case llvm::Triple::FreeBSD: - m_thread_reg_ctx_sp.reset(new RegisterContextCoreFreeBSD_x86_64 (*this, m_gpregset_data, m_fpregset_data)); + m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, new RegisterContextFreeBSD_x86_64(arch), m_gpregset_data, m_fpregset_data)); break; case llvm::Triple::Linux: - m_thread_reg_ctx_sp.reset(new RegisterContextCoreLinux_x86_64 (*this, m_gpregset_data, m_fpregset_data)); + m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, new RegisterContextLinux_x86_64(arch), m_gpregset_data, m_fpregset_data)); break; default: if (log) diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.h b/source/Plugins/Process/elf-core/ThreadElfCore.h index ca6339d7ec9d..2661edfa50cd 100644 --- a/source/Plugins/Process/elf-core/ThreadElfCore.h +++ b/source/Plugins/Process/elf-core/ThreadElfCore.h @@ -29,6 +29,10 @@ struct compat_timeval #define ELFLINUXPRSTATUS64_SIZE (112) #define ELFLINUXPRPSINFO64_SIZE (132) +#undef si_signo +#undef si_code +#undef si_errno + struct ELFLinuxPrStatus { int32_t si_signo; diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index d7efdf2302d8..f67e1b5d49c3 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -133,7 +133,11 @@ GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, const char *listener_name, bool is_platform) : Communication(comm_name), +#ifdef LLDB_CONFIGURATION_DEBUG + m_packet_timeout (1000), +#else m_packet_timeout (1), +#endif m_sequence_mutex (Mutex::eMutexTypeRecursive), m_public_is_running (false), m_private_is_running (false), @@ -173,7 +177,7 @@ GDBRemoteCommunication::SendAck () char ch = '+'; const size_t bytes_written = Write (&ch, 1, status, NULL); if (log) - log->Printf ("<%4zu> send packet: %c", bytes_written, ch); + log->Printf ("<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch); m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written); return bytes_written; } @@ -186,7 +190,7 @@ GDBRemoteCommunication::SendNack () char ch = '-'; const size_t bytes_written = Write (&ch, 1, status, NULL); if (log) - log->Printf ("<%4zu> send packet: %c", bytes_written, ch); + log->Printf("<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch); m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written); return bytes_written; } @@ -222,7 +226,7 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le if (!m_history.DidDumpToLog ()) m_history.Dump (log); - log->Printf ("<%4zu> send packet: %.*s", bytes_written, (int)packet.GetSize(), packet.GetData()); + log->Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)packet.GetSize(), packet.GetData()); } m_history.AddPacket (packet.GetString(), packet.GetSize(), History::ePacketTypeSend, bytes_written); @@ -456,13 +460,38 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri if (!m_history.DidDumpToLog ()) m_history.Dump (log); - log->Printf ("<%4zu> read packet: %.*s", total_length, (int)(total_length), m_bytes.c_str()); + log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); } m_history.AddPacket (m_bytes.c_str(), total_length, History::ePacketTypeRecv, total_length); - packet_str.assign (m_bytes, content_start, content_length); - + // Clear packet_str in case there is some existing data in it. + packet_str.clear(); + // Copy the packet from m_bytes to packet_str expanding the + // run-length encoding in the process. + // Reserve enough byte for the most common case (no RLE used) + packet_str.reserve(m_bytes.length()); + for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_start + content_length; ++c) + { + if (*c == '*') + { + // '*' indicates RLE. Next character will give us the + // repeat count and previous character is what is to be + // repeated. + char char_to_repeat = packet_str.back(); + // Number of time the previous character is repeated + int repeat_count = *++c + 3 - ' '; + // We have the char_to_repeat and repeat_count. Now push + // it in the packet. + for (int i = 0; i < repeat_count; ++i) + packet_str.push_back(char_to_repeat); + } + else + { + packet_str.push_back(*c); + } + } + if (m_bytes[0] == '$') { assert (checksum_idx < m_bytes.size()); diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index ca594a8f3fd5..2ac7d20c6c60 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -11,6 +11,8 @@ #include "GDBRemoteCommunicationClient.h" // C Includes +#include <sys/stat.h> + // C++ Includes #include <sstream> @@ -20,6 +22,7 @@ #include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Core/Log.h" #include "lldb/Core/State.h" +#include "lldb/Core/StreamGDBRemote.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/Endian.h" #include "lldb/Host/Host.h" @@ -29,10 +32,15 @@ #include "Utility/StringExtractorGDBRemote.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" +#include "lldb/Host/Config.h" using namespace lldb; using namespace lldb_private; +#ifdef LLDB_DISABLE_POSIX +#define SIGSTOP 17 +#endif + //---------------------------------------------------------------------- // GDBRemoteCommunicationClient constructor //---------------------------------------------------------------------- @@ -56,6 +64,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_watchpoints_trigger_after_instruction(eLazyBoolCalculate), m_attach_or_wait_reply(eLazyBoolCalculate), m_prepare_for_reg_writing_reply (eLazyBoolCalculate), + m_supports_p (eLazyBoolCalculate), m_supports_qProcessInfoPID (true), m_supports_qfProcessInfo (true), m_supports_qUserName (true), @@ -66,6 +75,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_supports_z2 (true), m_supports_z3 (true), m_supports_z4 (true), + m_supports_QEnvironment (true), + m_supports_QEnvironmentHexEncoded (true), m_curr_tid (LLDB_INVALID_THREAD_ID), m_curr_tid_run (LLDB_INVALID_THREAD_ID), m_num_supported_hardware_watchpoints (0), @@ -79,7 +90,11 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_process_arch(), m_os_version_major (UINT32_MAX), m_os_version_minor (UINT32_MAX), - m_os_version_update (UINT32_MAX) + m_os_version_update (UINT32_MAX), + m_os_build (), + m_os_kernel (), + m_hostname (), + m_default_packet_timeout (0) { } @@ -192,6 +207,7 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_vCont_C = eLazyBoolCalculate; m_supports_vCont_s = eLazyBoolCalculate; m_supports_vCont_S = eLazyBoolCalculate; + m_supports_p = eLazyBoolCalculate; m_qHostInfo_is_valid = eLazyBoolCalculate; m_qProcessInfo_is_valid = eLazyBoolCalculate; m_supports_alloc_dealloc_memory = eLazyBoolCalculate; @@ -209,6 +225,8 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_z2 = true; m_supports_z3 = true; m_supports_z4 = true; + m_supports_QEnvironment = true; + m_supports_QEnvironmentHexEncoded = true; m_host_arch.Clear(); m_process_arch.Clear(); } @@ -287,6 +305,32 @@ GDBRemoteCommunicationClient::GetVContSupported (char flavor) return false; } +// Check if the target supports 'p' packet. It sends out a 'p' +// packet and checks the response. A normal packet will tell us +// that support is available. +// +// Takes a valid thread ID because p needs to apply to a thread. +bool +GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid) +{ + if (m_supports_p == eLazyBoolCalculate) + { + StringExtractorGDBRemote response; + m_supports_p = eLazyBoolNo; + char packet[256]; + if (GetThreadSuffixSupported()) + snprintf(packet, sizeof(packet), "p0;thread:%" PRIx64 ";", tid); + else + snprintf(packet, sizeof(packet), "p0"); + + if (SendPacketAndWaitForResponse(packet, response, false)) + { + if (response.IsNormalResponse()) + m_supports_p = eLazyBoolYes; + } + } + return m_supports_p; +} size_t GDBRemoteCommunicationClient::SendPacketAndWaitForResponse @@ -978,15 +1022,61 @@ GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_valu if (name_equal_value && name_equal_value[0]) { StreamString packet; - packet.Printf("QEnvironment:%s", name_equal_value); + bool send_hex_encoding = false; + for (const char *p = name_equal_value; *p != '\0' && send_hex_encoding == false; ++p) + { + if (isprint(*p)) + { + switch (*p) + { + case '$': + case '#': + send_hex_encoding = true; + break; + default: + break; + } + } + else + { + // We have non printable characters, lets hex encode this... + send_hex_encoding = true; + } + } + StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (send_hex_encoding) { - if (response.IsOKResponse()) - return 0; - uint8_t error = response.GetError(); - if (error) - return error; + if (m_supports_QEnvironmentHexEncoded) + { + packet.PutCString("QEnvironmentHexEncoded:"); + packet.PutBytesAsRawHex8 (name_equal_value, strlen(name_equal_value)); + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + if (response.IsUnsupportedResponse()) + m_supports_QEnvironmentHexEncoded = false; + } + } + + } + else if (m_supports_QEnvironment) + { + packet.Printf("QEnvironment:%s", name_equal_value); + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + { + if (response.IsOKResponse()) + return 0; + uint8_t error = response.GetError(); + if (error) + return error; + if (response.IsUnsupportedResponse()) + m_supports_QEnvironment = false; + } } } return -1; @@ -1213,6 +1303,15 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) else --num_keys_decoded; } + else if (name.compare("default_packet_timeout") == 0) + { + m_default_packet_timeout = Args::StringToUInt32(value.c_str(), 0); + if (m_default_packet_timeout > 0) + { + SetPacketTimeout(m_default_packet_timeout); + ++num_keys_decoded; + } + } } @@ -1347,6 +1446,14 @@ GDBRemoteCommunicationClient::GetHostArchitecture () return m_host_arch; } +uint32_t +GDBRemoteCommunicationClient::GetHostDefaultPacketTimeout () +{ + if (m_qHostInfo_is_valid == eLazyBoolCalculate) + GetHostInfo (); + return m_default_packet_timeout; +} + addr_t GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions) { @@ -2132,21 +2239,37 @@ GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t } uint16_t -GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort () +GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid) { + pid = LLDB_INVALID_PROCESS_ID; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qLaunchGDBServer", strlen("qLaunchGDBServer"), response, false)) + StreamString stream; + stream.PutCString("qLaunchGDBServer:port:0;"); + std::string hostname; + if (Host::GetHostname (hostname)) + { + // Make the GDB server we launch only accept connections from this host + stream.Printf("host:%s;", hostname.c_str()); + } + else + { + // Make the GDB server we launch accept connections from any host since we can't figure out the hostname + stream.Printf("host:*;"); + } + const char *packet = stream.GetData(); + int packet_len = stream.GetSize(); + + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) { std::string name; std::string value; uint16_t port = 0; - //lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; while (response.GetNameColonValue(name, value)) { - if (name.size() == 4 && name.compare("port") == 0) + if (name.compare("port") == 0) port = Args::StringToUInt32(value.c_str(), 0, 0); -// if (name.size() == 3 && name.compare("pid") == 0) -// pid = Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0); + else if (name.compare("pid") == 0) + pid = Args::StringToUInt64(value.c_str(), LLDB_INVALID_PROCESS_ID, 0); } return port; } @@ -2154,6 +2277,23 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort () } bool +GDBRemoteCommunicationClient::KillSpawnedProcess (lldb::pid_t pid) +{ + StreamString stream; + stream.Printf ("qKillSpawnedProcess:%" PRId64 , pid); + const char *packet = stream.GetData(); + int packet_len = stream.GetSize(); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.IsOKResponse()) + return true; + } + return false; +} + +bool GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid) { if (m_curr_tid == tid) @@ -2222,7 +2362,9 @@ GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtracto assert (packet_len < (int)sizeof(packet)); if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) { - if (response.IsNormalResponse()) + if (response.IsUnsupportedResponse()) + m_supports_qThreadStopInfo = false; + else if (response.IsNormalResponse()) return true; else return false; @@ -2232,8 +2374,6 @@ GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtracto m_supports_qThreadStopInfo = false; } } -// if (SetCurrentThread (tid)) -// return GetStopReply (response); return false; } @@ -2346,3 +2486,326 @@ GDBRemoteCommunicationClient::GetShlibInfoAddr() return LLDB_INVALID_ADDRESS; } +lldb_private::Error +GDBRemoteCommunicationClient::RunShellCommand (const char *command, // Shouldn't be NULL + const char *working_dir, // Pass NULL to use the current working directory + int *status_ptr, // Pass NULL if you don't want the process exit status + int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit + std::string *command_output, // Pass NULL if you don't want the command output + uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish +{ + lldb_private::StreamString stream; + stream.PutCString("qPlatform_RunCommand:"); + stream.PutBytesAsRawHex8(command, strlen(command)); + stream.PutChar(','); + stream.PutHex32(timeout_sec); + if (working_dir && *working_dir) + { + stream.PutChar(','); + stream.PutBytesAsRawHex8(working_dir, strlen(working_dir)); + } + const char *packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() != 'F') + return Error("malformed reply"); + if (response.GetChar() != ',') + return Error("malformed reply"); + uint32_t exitcode = response.GetHexMaxU32(false, UINT32_MAX); + if (exitcode == UINT32_MAX) + return Error("unable to run remote process"); + else if (status_ptr) + *status_ptr = exitcode; + if (response.GetChar() != ',') + return Error("malformed reply"); + uint32_t signo = response.GetHexMaxU32(false, UINT32_MAX); + if (signo_ptr) + *signo_ptr = signo; + if (response.GetChar() != ',') + return Error("malformed reply"); + std::string output; + response.GetEscapedBinaryData(output); + if (command_output) + command_output->assign(output); + return Error(); + } + return Error("unable to send packet"); +} + +uint32_t +GDBRemoteCommunicationClient::MakeDirectory (const std::string &path, + mode_t mode) +{ + lldb_private::StreamString stream; + stream.PutCString("qPlatform_IO_MkDir:"); + stream.PutHex32(mode); + stream.PutChar(','); + stream.PutBytesAsRawHex8(path.c_str(), path.size()); + const char *packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + return response.GetHexMaxU32(false, UINT32_MAX); + } + return UINT32_MAX; + +} + +static uint64_t +ParseHostIOPacketResponse (StringExtractorGDBRemote &response, + uint64_t fail_result, + Error &error) +{ + response.SetFilePos(0); + if (response.GetChar() != 'F') + return fail_result; + int32_t result = response.GetS32 (-2); + if (result == -2) + return fail_result; + if (response.GetChar() == ',') + { + int result_errno = response.GetS32 (-2); + if (result_errno != -2) + error.SetError(result_errno, eErrorTypePOSIX); + else + error.SetError(-1, eErrorTypeGeneric); + } + else + error.Clear(); + return result; +} +lldb::user_id_t +GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec, + uint32_t flags, + mode_t mode, + Error &error) +{ + lldb_private::StreamString stream; + stream.PutCString("vFile:open:"); + std::string path (file_spec.GetPath()); + if (path.empty()) + return UINT64_MAX; + stream.PutCStringAsRawHex8(path.c_str()); + stream.PutChar(','); + const uint32_t posix_open_flags = File::ConvertOpenOptionsForPOSIXOpen(flags); + stream.PutHex32(posix_open_flags); + stream.PutChar(','); + stream.PutHex32(mode); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + return ParseHostIOPacketResponse (response, UINT64_MAX, error); + } + return UINT64_MAX; +} + +bool +GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd, + Error &error) +{ + lldb_private::StreamString stream; + stream.Printf("vFile:close:%i", (int)fd); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + return ParseHostIOPacketResponse (response, -1, error) == 0; + } + return false; +} + +// Extension of host I/O packets to get the file size. +lldb::user_id_t +GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_spec) +{ + lldb_private::StreamString stream; + stream.PutCString("vFile:size:"); + std::string path (file_spec.GetPath()); + stream.PutCStringAsRawHex8(path.c_str()); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() != 'F') + return UINT64_MAX; + uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX); + return retcode; + } + return UINT64_MAX; +} + +uint32_t +GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& file_spec, Error &error) +{ + lldb_private::StreamString stream; + stream.PutCString("vFile:mode:"); + std::string path (file_spec.GetPath()); + stream.PutCStringAsRawHex8(path.c_str()); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() != 'F') + { + error.SetErrorStringWithFormat ("invalid response to '%s' packet", packet); + return 0; + } + const uint32_t mode = response.GetS32(-1); + if (mode == -1) + { + if (response.GetChar() == ',') + { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + else + error.SetErrorToGenericError(); + } + } + else + error.Clear(); + return mode & (S_IRWXU|S_IRWXG|S_IRWXO); + } + else + { + error.SetErrorStringWithFormat ("failed to send '%s' packet", packet); + } + return 0; +} + +uint64_t +GDBRemoteCommunicationClient::ReadFile (lldb::user_id_t fd, + uint64_t offset, + void *dst, + uint64_t dst_len, + Error &error) +{ + lldb_private::StreamString stream; + stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len, offset); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() != 'F') + return 0; + uint32_t retcode = response.GetHexMaxU32(false, UINT32_MAX); + if (retcode == UINT32_MAX) + return retcode; + const char next = (response.Peek() ? *response.Peek() : 0); + if (next == ',') + return 0; + if (next == ';') + { + response.GetChar(); // skip the semicolon + std::string buffer; + if (response.GetEscapedBinaryData(buffer)) + { + const uint64_t data_to_write = std::min<uint64_t>(dst_len, buffer.size()); + if (data_to_write > 0) + memcpy(dst, &buffer[0], data_to_write); + return data_to_write; + } + } + } + return 0; +} + +uint64_t +GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd, + uint64_t offset, + const void* src, + uint64_t src_len, + Error &error) +{ + lldb_private::StreamGDBRemote stream; + stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset); + stream.PutEscapedBytes(src, src_len); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() != 'F') + { + error.SetErrorStringWithFormat("write file failed"); + return 0; + } + uint64_t bytes_written = response.GetU64(UINT64_MAX); + if (bytes_written == UINT64_MAX) + { + error.SetErrorToGenericError(); + if (response.GetChar() == ',') + { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + } + return 0; + } + return bytes_written; + } + else + { + error.SetErrorString ("failed to send vFile:pwrite packet"); + } + return 0; +} + +// Extension of host I/O packets to get whether a file exists. +bool +GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec) +{ + lldb_private::StreamString stream; + stream.PutCString("vFile:exists:"); + std::string path (file_spec.GetPath()); + stream.PutCStringAsRawHex8(path.c_str()); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() != 'F') + return false; + if (response.GetChar() != ',') + return false; + bool retcode = (response.GetChar() != '0'); + return retcode; + } + return false; +} + +bool +GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_spec, + uint64_t &high, + uint64_t &low) +{ + lldb_private::StreamString stream; + stream.PutCString("vFile:MD5:"); + std::string path (file_spec.GetPath()); + stream.PutCStringAsRawHex8(path.c_str()); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() != 'F') + return false; + if (response.GetChar() != ',') + return false; + if (response.Peek() && *response.Peek() == 'x') + return false; + low = response.GetHexMaxU64(false, UINT64_MAX); + high = response.GetHexMaxU64(false, UINT64_MAX); + return true; + } + return false; +} diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 5bb8387b9094..d5535bbb1df3 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -89,7 +89,10 @@ public: GetLaunchSuccess (std::string &error_str); uint16_t - LaunchGDBserverAndGetPort (); + LaunchGDBserverAndGetPort (lldb::pid_t &pid); + + bool + KillSpawnedProcess (lldb::pid_t pid); //------------------------------------------------------------------ /// Sends a GDB remote protocol 'A' packet that delivers program @@ -217,6 +220,9 @@ public: const lldb_private::ArchSpec & GetHostArchitecture (); + + uint32_t + GetHostDefaultPacketTimeout(); const lldb_private::ArchSpec & GetProcessArchitecture (); @@ -225,6 +231,9 @@ public: GetVContSupported (char flavor); bool + GetpPacketSupported (lldb::tid_t tid); + + bool GetVAttachOrWaitSupported (); bool @@ -347,10 +356,61 @@ public: return m_interrupt_sent; } + virtual lldb::user_id_t + OpenFile (const lldb_private::FileSpec& file_spec, + uint32_t flags, + mode_t mode, + lldb_private::Error &error); + + virtual bool + CloseFile (lldb::user_id_t fd, + lldb_private::Error &error); + + virtual lldb::user_id_t + GetFileSize (const lldb_private::FileSpec& file_spec); + + virtual uint32_t + GetFilePermissions(const lldb_private::FileSpec& file_spec, + lldb_private::Error &error); + + virtual uint64_t + ReadFile (lldb::user_id_t fd, + uint64_t offset, + void *dst, + uint64_t dst_len, + lldb_private::Error &error); + + virtual uint64_t + WriteFile (lldb::user_id_t fd, + uint64_t offset, + const void* src, + uint64_t src_len, + lldb_private::Error &error); + + virtual uint32_t + MakeDirectory (const std::string &path, + mode_t mode); + + virtual bool + GetFileExists (const lldb_private::FileSpec& file_spec); + + virtual lldb_private::Error + RunShellCommand (const char *command, // Shouldn't be NULL + const char *working_dir, // Pass NULL to use the current working directory + int *status_ptr, // Pass NULL if you don't want the process exit status + int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit + std::string *command_output, // Pass NULL if you don't want the command output + uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish + + virtual bool + CalculateMD5 (const lldb_private::FileSpec& file_spec, + uint64_t &high, + uint64_t &low); + std::string HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process, StringExtractorGDBRemote &inputStringExtractor); - + protected: bool @@ -377,6 +437,7 @@ protected: lldb_private::LazyBool m_watchpoints_trigger_after_instruction; lldb_private::LazyBool m_attach_or_wait_reply; lldb_private::LazyBool m_prepare_for_reg_writing_reply; + lldb_private::LazyBool m_supports_p; bool m_supports_qProcessInfoPID:1, @@ -388,7 +449,9 @@ protected: m_supports_z1:1, m_supports_z2:1, m_supports_z3:1, - m_supports_z4:1; + m_supports_z4:1, + m_supports_QEnvironment:1, + m_supports_QEnvironmentHexEncoded:1; lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations @@ -416,6 +479,7 @@ protected: std::string m_os_build; std::string m_os_kernel; std::string m_hostname; + uint32_t m_default_packet_timeout; bool DecodeProcessInfoResponse (StringExtractorGDBRemote &response, diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 3a14e9fe759a..df036cdcc8e0 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -7,8 +7,10 @@ // //===----------------------------------------------------------------------===// +#include <errno.h> #include "GDBRemoteCommunicationServer.h" +#include "lldb/Core/StreamGDBRemote.h" // C Includes // C++ Includes @@ -20,6 +22,7 @@ #include "lldb/Core/State.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/Endian.h" +#include "lldb/Host/File.h" #include "lldb/Host/Host.h" #include "lldb/Host/TimeValue.h" #include "lldb/Target/Process.h" @@ -40,11 +43,31 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) : m_async_thread (LLDB_INVALID_HOST_THREAD), m_process_launch_info (), m_process_launch_error (), + m_spawned_pids (), + m_spawned_pids_mutex (Mutex::eMutexTypeRecursive), m_proc_infos (), m_proc_infos_index (0), m_lo_port_num (0), - m_hi_port_num (0) + m_hi_port_num (0), + m_next_port (0), + m_use_port_range (false) { + // We seldom need to override the port number that the debugserver process + // starts with. We just pass in 0 to let the system choose a random port. + // In rare situation where the need arises, use two environment variables + // to override. + uint16_t lo_port_num = 0; + uint16_t hi_port_num = 0; + const char *lo_port_c_str = getenv("LLDB_PLATFORM_START_DEBUG_SERVER_LO_PORT"); + if (lo_port_c_str) + lo_port_num = ::atoi(lo_port_c_str); + const char *hi_port_c_str = getenv("LLDB_PLATFORM_START_DEBUG_SERVER_HI_PORT"); + if (hi_port_c_str) + hi_port_num = ::atoi(hi_port_c_str); + if (lo_port_num && hi_port_num && lo_port_num < hi_port_num) + { + SetPortRange(lo_port_num, hi_port_num); + } } //---------------------------------------------------------------------- @@ -65,7 +88,7 @@ GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() // log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID()); // // StringExtractorGDBRemote packet; -// +// // while () // { // if (packet. @@ -79,9 +102,9 @@ GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() //} // bool -GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, +GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, Error &error, - bool &interrupt, + bool &interrupt, bool &quit) { StringExtractorGDBRemote packet; @@ -103,7 +126,7 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, error.SetErrorString("interrupt received"); interrupt = true; break; - + case StringExtractorGDBRemote::eServerPacketType_unimplemented: return SendUnimplementedResponse (packet.GetStringRef().c_str()) > 0; @@ -112,22 +135,25 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo: return Handle_qfProcessInfo (packet); - + case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo: return Handle_qsProcessInfo (packet); - + case StringExtractorGDBRemote::eServerPacketType_qC: return Handle_qC (packet); - + case StringExtractorGDBRemote::eServerPacketType_qHostInfo: return Handle_qHostInfo (packet); - + case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer: return Handle_qLaunchGDBServer (packet); - + + case StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess: + return Handle_qKillSpawnedProcess (packet); + case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess: return Handle_qLaunchSuccess (packet); - + case StringExtractorGDBRemote::eServerPacketType_qGroupName: return Handle_qGroupName (packet); @@ -142,24 +168,60 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, case StringExtractorGDBRemote::eServerPacketType_QEnvironment: return Handle_QEnvironment (packet); - + + case StringExtractorGDBRemote::eServerPacketType_QLaunchArch: + return Handle_QLaunchArch (packet); + case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR: return Handle_QSetDisableASLR (packet); - + case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN: return Handle_QSetSTDIN (packet); - + case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT: return Handle_QSetSTDOUT (packet); - + case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR: return Handle_QSetSTDERR (packet); - + case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir: return Handle_QSetWorkingDir (packet); case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode: return Handle_QStartNoAckMode (packet); + + case StringExtractorGDBRemote::eServerPacketType_qPlatform_IO_MkDir: + return Handle_qPlatform_IO_MkDir (packet); + + case StringExtractorGDBRemote::eServerPacketType_qPlatform_RunCommand: + return Handle_qPlatform_RunCommand (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_Open: + return Handle_vFile_Open (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_Close: + return Handle_vFile_Close (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_pRead: + return Handle_vFile_pRead (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_pWrite: + return Handle_vFile_pWrite (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_Size: + return Handle_vFile_Size (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_Mode: + return Handle_vFile_Mode (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_Exists: + return Handle_vFile_Exists (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_Stat: + return Handle_vFile_Stat (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_MD5: + return Handle_vFile_MD5 (packet); } return true; } @@ -207,7 +269,7 @@ bool GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet) { StreamString response; - + // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00 ArchSpec host_arch (Host::GetArchitecture ()); @@ -222,12 +284,12 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet response.Printf ("cputype:%u;", cpu); if (sub != LLDB_INVALID_CPUTYPE) response.Printf ("cpusubtype:%u;", sub); - + if (cpu == ArchSpec::kCore_arm_any) response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes. else response.Printf("watchpoint_exceptions_received:after;"); - + switch (lldb::endian::InlHostByteOrder()) { case eByteOrderBig: response.PutCString ("endian:big;"); break; @@ -235,7 +297,7 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet case eByteOrderPDP: response.PutCString ("endian:pdp;"); break; default: response.PutCString ("endian:unknown;"); break; } - + uint32_t major = UINT32_MAX; uint32_t minor = UINT32_MAX; uint32_t update = UINT32_MAX; @@ -273,7 +335,7 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } - + return SendPacketNoLock (response.GetData(), response.GetSize()) > 0; } @@ -319,7 +381,7 @@ GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote & return SendErrorResponse (1); } -bool +bool GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet) { m_proc_infos_index = 0; @@ -329,7 +391,7 @@ GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &pa packet.SetFilePos(::strlen ("qfProcessInfo")); if (packet.GetChar() == ':') { - + std::string key; std::string value; while (packet.GetNameColonValue(key, value)) @@ -360,11 +422,11 @@ GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &pa { match_info.SetNameMatchType (eNameMatchContains); } - else if (value.compare("regex") == 0) + else if (value.compare("regex") == 0) { match_info.SetNameMatchType (eNameMatchRegularExpression); } - else + else { success = false; } @@ -405,7 +467,7 @@ GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &pa { success = false; } - + if (!success) return SendErrorResponse (2); } @@ -420,7 +482,7 @@ GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &pa return SendErrorResponse (3); } -bool +bool GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &packet) { if (m_proc_infos_index < m_proc_infos.GetSize()) @@ -433,7 +495,7 @@ GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &pa return SendErrorResponse (4); } -bool +bool GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet) { // Packet format: "qUserName:%i" where %i is the uid @@ -450,10 +512,10 @@ GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet } } return SendErrorResponse (5); - + } -bool +bool GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet) { // Packet format: "qGroupName:%i" where %i is the gid @@ -539,11 +601,11 @@ AcceptPortFromInferior (void *arg) // for (int i=0; i<num_retries; i++) // { // struct proc_bsdinfo bsd_info; -// int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO, -// (uint64_t) 0, -// &bsd_info, +// int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO, +// (uint64_t) 0, +// &bsd_info, // PROC_PIDTBSDINFO_SIZE); -// +// // switch (error) // { // case EINVAL: @@ -551,10 +613,10 @@ AcceptPortFromInferior (void *arg) // case ESRCH: // case EPERM: // return false; -// +// // default: // break; -// +// // case 0: // if (bsd_info.pbi_status == SSTOP) // return true; @@ -567,9 +629,9 @@ AcceptPortFromInferior (void *arg) bool GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) { - // The 'A' packet is the most over designed packet ever here with - // redundant argument indexes, redundant argument lengths and needed hex - // encoded argument string values. Really all that is needed is a comma + // The 'A' packet is the most over designed packet ever here with + // redundant argument indexes, redundant argument lengths and needed hex + // encoded argument string values. Really all that is needed is a comma // separated hex encoded argument value list, but we will stay true to the // documented version of the 'A' packet here... @@ -615,7 +677,7 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) if (packet.GetChar() != ',') success = false; } - + if (success) { if (arg_idx == 0) @@ -649,11 +711,11 @@ GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet) response.Printf("QC%" PRIx64, pid); if (m_is_platform) { - // If we launch a process and this GDB server is acting as a platform, - // then we need to clear the process launch state so we can start + // If we launch a process and this GDB server is acting as a platform, + // then we need to clear the process launch state so we can start // launching another process. In order to launch a process a bunch or // packets need to be sent: environment packets, working directory, - // disable ASLR, and many more settings. When we launch a process we + // disable ASLR, and many more settings. When we launch a process we // then need to know when to clear this information. Currently we are // selecting the 'qC' packet as that packet which seems to make the most // sense. @@ -666,8 +728,30 @@ GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet) } bool +GDBRemoteCommunicationServer::DebugserverProcessReaped (lldb::pid_t pid) +{ + Mutex::Locker locker (m_spawned_pids_mutex); + return m_spawned_pids.erase(pid) > 0; +} +bool +GDBRemoteCommunicationServer::ReapDebugserverProcess (void *callback_baton, + lldb::pid_t pid, + bool exited, + int signal, // Zero for no signal + int status) // Exit value of process if signal is zero +{ + GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton; + server->DebugserverProcessReaped (pid); + return true; +} + +bool GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) { +#ifdef _WIN32 + // No unix sockets on windows + return false; +#else // Spawn a local debugserver as a platform so we can then attach or launch // a process... @@ -677,49 +761,101 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote ConnectionFileDescriptor file_conn; char connect_url[PATH_MAX]; Error error; - char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX"; - if (::mktemp (unix_socket_name) == NULL) + std::string hostname; + // TODO: /tmp/ should not be hardcoded. User might want to override /tmp + // with the TMPDIR environnement variable + char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX"; + if (::mkstemp (unix_socket_name) == -1) { - error.SetErrorString ("failed to make temporary path for a unix socket"); + error.SetErrorStringWithFormat("failed to make temporary path for a unix socket: %s", strerror(errno)); } else { + packet.SetFilePos(::strlen ("qLaunchGDBServer:")); + std::string name; + std::string value; + uint16_t port = UINT16_MAX; + while (packet.GetNameColonValue(name, value)) + { + if (name.compare ("host") == 0) + hostname.swap(value); + else if (name.compare ("port") == 0) + port = Args::StringToUInt32(value.c_str(), 0, 0); + } + if (port == UINT16_MAX) + port = GetAndUpdateNextPort(); + ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name); // Spawn a new thread to accept the port that gets bound after // binding to port 0 (zero). - lldb::thread_t accept_thread = Host::ThreadCreate (unix_socket_name, - AcceptPortFromInferior, - connect_url, - &error); - + lldb::thread_t accept_thread = LLDB_INVALID_HOST_THREAD; + + if (port == 0) + { + accept_thread = Host::ThreadCreate (unix_socket_name, + AcceptPortFromInferior, + connect_url, + &error); + } + if (IS_VALID_LLDB_HOST_THREAD(accept_thread)) { - // Spawn a debugserver and try to get + // Spawn a debugserver and try to get the port it listens to. ProcessLaunchInfo debugserver_launch_info; - error = StartDebugserverProcess ("localhost:0", - unix_socket_name, + StreamString host_and_port; + if (hostname.empty()) + hostname = "localhost"; + host_and_port.Printf("%s:%u", hostname.c_str(), port); + const char *host_and_port_cstr = host_and_port.GetString().c_str(); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr); + error = StartDebugserverProcess (host_and_port_cstr, + unix_socket_name, debugserver_launch_info); - + lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); + + if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + { + { + Mutex::Locker locker (m_spawned_pids_mutex); + m_spawned_pids.insert(debugserver_pid); + } + Host::StartMonitoringChildProcess (ReapDebugserverProcess, this, debugserver_pid, false); + } + if (error.Success()) { bool success = false; - - thread_result_t accept_thread_result = NULL; - if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error)) + + if (accept_thread) { - if (accept_thread_result) + thread_result_t accept_thread_result = NULL; + if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error)) { - uint16_t port = (intptr_t)accept_thread_result; - char response[256]; - const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port); - assert (response_len < (int)sizeof(response)); - //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); - success = SendPacketNoLock (response, response_len) > 0; + if (accept_thread_result) + { + port = (intptr_t)accept_thread_result; + char response[256]; + const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port); + assert (response_len < sizeof(response)); + //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); + success = SendPacketNoLock (response, response_len) > 0; + } } } + else + { + char response[256]; + const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port); + assert (response_len < sizeof(response)); + //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); + success = SendPacketNoLock (response, response_len) > 0; + + } ::unlink (unix_socket_name); - + if (!success) { if (debugserver_pid != LLDB_INVALID_PROCESS_ID) @@ -730,7 +866,61 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote } } } - return SendErrorResponse (13); + return SendErrorResponse (9); +#endif +} + +bool +GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) +{ + // Spawn a local debugserver as a platform so we can then attach or launch + // a process... + + if (m_is_platform) + { + packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); + + lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); + + // Scope for locker + { + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return SendErrorResponse (10); + } + Host::Kill (pid, SIGTERM); + + for (size_t i=0; i<10; ++i) + { + // Scope for locker + { + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return true; + } + usleep (10000); + } + + // Scope for locker + { + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return true; + } + Host::Kill (pid, SIGKILL); + + for (size_t i=0; i<10; ++i) + { + // Scope for locker + { + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return true; + } + usleep (10000); + } + } + return SendErrorResponse (10); } bool @@ -738,7 +928,7 @@ GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &p { if (m_process_launch_error.Success()) return SendOKResponse(); - StreamString response; + StreamString response; response.PutChar('E'); response.PutCString(m_process_launch_error.AsCString("<unknown error>")); return SendPacketNoLock (response.GetData(), response.GetSize()); @@ -754,7 +944,22 @@ GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &pa m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek()); return SendOKResponse (); } - return SendErrorResponse (9); + return SendErrorResponse (11); +} + +bool +GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen ("QLaunchArch:")); + const uint32_t bytes_left = packet.GetBytesLeft(); + if (bytes_left > 0) + { + const char* arch_triple = packet.Peek(); + ArchSpec arch_spec(arch_triple,NULL); + m_process_launch_info.SetArchitecture(arch_spec); + return SendOKResponse(); + } + return SendErrorResponse(12); } bool @@ -792,7 +997,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet m_process_launch_info.AppendFileAction(file_action); return SendOKResponse (); } - return SendErrorResponse (10); + return SendErrorResponse (13); } bool @@ -809,7 +1014,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packe m_process_launch_info.AppendFileAction(file_action); return SendOKResponse (); } - return SendErrorResponse (11); + return SendErrorResponse (14); } bool @@ -826,7 +1031,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packe m_process_launch_info.AppendFileAction(file_action); return SendOKResponse (); } - return SendErrorResponse (12); + return SendErrorResponse (15); } bool @@ -837,3 +1042,277 @@ GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote & m_send_acks = false; return true; } + +bool +GDBRemoteCommunicationServer::Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("qPlatform_IO_MkDir:")); + mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); + if (packet.GetChar() != ',') + return false; + std::string path; + packet.GetHexByteString(path); + uint32_t retcode = Host::MakeDirectory(path.c_str(),mode); + StreamString response; + response.PutHex32(retcode); + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; +} + +bool +GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("vFile:open:")); + std::string path; + packet.GetHexByteStringTerminatedBy(path,','); + if (path.size() == 0) + return false; + if (packet.GetChar() != ',') + return false; + uint32_t flags = packet.GetHexMaxU32(false, UINT32_MAX); + if (packet.GetChar() != ',') + return false; + mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); + Error error; + int fd = ::open (path.c_str(), flags, mode); + const int save_errno = fd == -1 ? errno : 0; + StreamString response; + response.PutChar('F'); + response.Printf("%i", fd); + if (save_errno) + response.Printf(",%i", save_errno); + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; +} + +bool +GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("vFile:close:")); + int fd = packet.GetS32(-1); + Error error; + int err = -1; + int save_errno = 0; + if (fd >= 0) + { + err = close(fd); + save_errno = err == -1 ? errno : 0; + } + else + { + save_errno = EINVAL; + } + StreamString response; + response.PutChar('F'); + response.Printf("%i", err); + if (save_errno) + response.Printf(",%i", save_errno); + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; +} + +bool +GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet) +{ +#ifdef _WIN32 + // Not implemented on Windows + return false; +#else + StreamGDBRemote response; + packet.SetFilePos(::strlen("vFile:pread:")); + int fd = packet.GetS32(-1); + if (packet.GetChar() != ',') + return false; + uint64_t count = packet.GetU64(UINT64_MAX); + if (packet.GetChar() != ',') + return false; + uint64_t offset = packet.GetU64(UINT32_MAX); + if (count == UINT64_MAX) + { + response.Printf("F-1:%i", EINVAL); + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; + } + std::string buffer(count, 0); + const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset); + const int save_errno = bytes_read == -1 ? errno : 0; + response.PutChar('F'); + response.Printf("%zi", bytes_read); + if (save_errno) + response.Printf(",%i", save_errno); + else + { + response.PutChar(';'); + response.PutEscapedBytes(&buffer[0], bytes_read); + } + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; +#endif +} + +bool +GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet) +{ +#ifdef _WIN32 + // Not implemented on Windows + return false; +#else + packet.SetFilePos(::strlen("vFile:pwrite:")); + + StreamGDBRemote response; + response.PutChar('F'); + + int fd = packet.GetU32(UINT32_MAX); + if (packet.GetChar() != ',') + return false; + off_t offset = packet.GetU64(UINT32_MAX); + if (packet.GetChar() != ',') + return false; + std::string buffer; + if (packet.GetEscapedBinaryData(buffer)) + { + const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset); + const int save_errno = bytes_written == -1 ? errno : 0; + response.Printf("%zi", bytes_written); + if (save_errno) + response.Printf(",%i", save_errno); + } + else + { + response.Printf ("-1,%i", EINVAL); + } + + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; +#endif +} + +bool +GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("vFile:size:")); + std::string path; + packet.GetHexByteString(path); + if (path.empty()) + return false; + lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false)); + StreamString response; + response.PutChar('F'); + response.PutHex64(retcode); + if (retcode == UINT64_MAX) + { + response.PutChar(','); + response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode() + } + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; +} + +bool +GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("vFile:mode:")); + std::string path; + packet.GetHexByteString(path); + if (path.empty()) + return false; + Error error; + const uint32_t mode = File::GetPermissions(path.c_str(), error); + StreamString response; + response.Printf("F%u", mode); + if (mode == 0 || error.Fail()) + response.Printf(",%i", (int)error.GetError()); + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; +} + +bool +GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("vFile:exists:")); + std::string path; + packet.GetHexByteString(path); + if (path.empty()) + return false; + bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false)); + StreamString response; + response.PutChar('F'); + response.PutChar(','); + if (retcode) + response.PutChar('1'); + else + response.PutChar('0'); + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; +} + +bool +GDBRemoteCommunicationServer::Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("qPlatform_RunCommand:")); + std::string path; + std::string working_dir; + packet.GetHexByteStringTerminatedBy(path,','); + if (path.size() == 0) + return false; + if (packet.GetChar() != ',') + return false; + // FIXME: add timeout to qPlatform_RunCommand packet + // uint32_t timeout = packet.GetHexMaxU32(false, 32); + uint32_t timeout = 10; + if (packet.GetChar() == ',') + packet.GetHexByteString(working_dir); + int status, signo; + std::string output; + Error err = Host::RunShellCommand(path.c_str(), + working_dir.empty() ? NULL : working_dir.c_str(), + &status, &signo, &output, timeout); + StreamGDBRemote response; + if (err.Fail()) + { + response.PutCString("F,"); + response.PutHex32(UINT32_MAX); + } + else + { + response.PutCString("F,"); + response.PutHex32(status); + response.PutChar(','); + response.PutHex32(signo); + response.PutChar(','); + response.PutEscapedBytes(output.c_str(), output.size()); + } + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; +} + +bool +GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet) +{ + return false; +} + +bool +GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("vFile:exists:")); + std::string path; + packet.GetHexByteString(path); + if (path.size() == 0) + return false; + uint64_t a,b; + StreamGDBRemote response; + if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false) + { + response.PutCString("F,"); + response.PutCString("x"); + } + else + { + response.PutCString("F,"); + response.PutHex64(a); + response.PutHex64(b); + } + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; +} diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index cce0e4e64c1e..64f6f8de1a21 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -12,10 +12,12 @@ // C Includes // C++ Includes +#include <vector> +#include <set> // Other libraries and framework includes // Project includes +#include "lldb/Host/Mutex.h" #include "lldb/Target/Process.h" - #include "GDBRemoteCommunication.h" class ProcessGDBRemote; @@ -60,6 +62,21 @@ public: { m_lo_port_num = lo_port_num; m_hi_port_num = hi_port_num; + m_next_port = m_lo_port_num; + m_use_port_range = true; + } + + // If we are using a port range, get and update the next port to be used variable. + // Otherwise, just return 0. + uint16_t + GetAndUpdateNextPort () + { + if (!m_use_port_range) + return 0; + uint16_t val = m_next_port; + if (++m_next_port > m_hi_port_num) + m_next_port = m_lo_port_num; + return val; } protected: @@ -68,11 +85,16 @@ protected: lldb::thread_t m_async_thread; lldb_private::ProcessLaunchInfo m_process_launch_info; lldb_private::Error m_process_launch_error; + std::set<lldb::pid_t> m_spawned_pids; + lldb_private::Mutex m_spawned_pids_mutex; lldb_private::ProcessInstanceInfoList m_proc_infos; uint32_t m_proc_infos_index; uint16_t m_lo_port_num; uint16_t m_hi_port_num; //PortToPIDMap m_port_to_pid_map; + uint16_t m_next_port; + bool m_use_port_range; + size_t SendUnimplementedResponse (const char *packet); @@ -85,7 +107,7 @@ protected: bool Handle_A (StringExtractorGDBRemote &packet); - + bool Handle_qLaunchSuccess (StringExtractorGDBRemote &packet); @@ -94,8 +116,14 @@ protected: bool Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet); + + bool + Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet); bool + Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet); + + bool Handle_qProcessInfoPID (StringExtractorGDBRemote &packet); bool @@ -120,6 +148,9 @@ protected: Handle_QEnvironment (StringExtractorGDBRemote &packet); bool + Handle_QLaunchArch (StringExtractorGDBRemote &packet); + + bool Handle_QSetDisableASLR (StringExtractorGDBRemote &packet); bool @@ -137,7 +168,47 @@ protected: bool Handle_QSetSTDERR (StringExtractorGDBRemote &packet); + bool + Handle_vFile_Open (StringExtractorGDBRemote &packet); + + bool + Handle_vFile_Close (StringExtractorGDBRemote &packet); + + bool + Handle_vFile_pRead (StringExtractorGDBRemote &packet); + + bool + Handle_vFile_pWrite (StringExtractorGDBRemote &packet); + + bool + Handle_vFile_Size (StringExtractorGDBRemote &packet); + + bool + Handle_vFile_Mode (StringExtractorGDBRemote &packet); + + bool + Handle_vFile_Exists (StringExtractorGDBRemote &packet); + + bool + Handle_vFile_Stat (StringExtractorGDBRemote &packet); + + bool + Handle_vFile_MD5 (StringExtractorGDBRemote &packet); + + bool + Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet); + private: + bool + DebugserverProcessReaped (lldb::pid_t pid); + + static bool + ReapDebugserverProcess (void *callback_baton, + lldb::pid_t pid, + bool exited, + int signal, + int status); + //------------------------------------------------------------------ // For GDBRemoteCommunicationServer only //------------------------------------------------------------------ diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index b1612a5f3c2f..c4e468f89f35 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -17,6 +17,9 @@ #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Scalar.h" #include "lldb/Core/StreamString.h" +#ifndef LLDB_DISABLE_PYTHON +#include "lldb/Interpreter/PythonDataObjects.h" +#endif #include "lldb/Target/ExecutionContext.h" #include "lldb/Utility/Utils.h" // Project includes @@ -54,7 +57,7 @@ GDBRemoteRegisterContext::GDBRemoteRegisterContext // 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); - + m_reg_data.SetByteOrder(thread.GetProcess()->GetByteOrder()); } //---------------------------------------------------------------------- @@ -696,6 +699,7 @@ GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, ui return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num); } + void GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) { diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 3110ddf8edf9..7a49d693d44e 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -21,23 +21,20 @@ #include "lldb/Core/ConstString.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Target/RegisterContext.h" +#include "Plugins/Process/Utility/DynamicRegisterInfo.h" + #include "GDBRemoteCommunicationClient.h" class ThreadGDBRemote; class ProcessGDBRemote; class StringExtractor; -class GDBRemoteDynamicRegisterInfo +class GDBRemoteDynamicRegisterInfo : + public DynamicRegisterInfo { public: GDBRemoteDynamicRegisterInfo () : - m_regs (), - m_sets (), - m_set_reg_nums (), - m_reg_names (), - m_reg_alt_names (), - m_set_names (), - m_reg_data_byte_size (0) + DynamicRegisterInfo() { } @@ -46,151 +43,8 @@ public: } void - AddRegister (lldb_private::RegisterInfo reg_info, - lldb_private::ConstString ®_name, - lldb_private::ConstString ®_alt_name, - lldb_private::ConstString &set_name) - { - const uint32_t reg_num = (uint32_t)m_regs.size(); - m_reg_names.push_back (reg_name); - m_reg_alt_names.push_back (reg_alt_name); - reg_info.name = reg_name.AsCString(); - assert (reg_info.name); - reg_info.alt_name = reg_alt_name.AsCString(NULL); - uint32_t i; - if (reg_info.value_regs) - { - for (i=0; reg_info.value_regs[i] != LLDB_INVALID_REGNUM; ++i) - m_value_regs_map[reg_num].push_back(reg_info.value_regs[i]); - m_value_regs_map[reg_num].push_back(LLDB_INVALID_REGNUM); - reg_info.value_regs = m_value_regs_map[reg_num].data(); - } - if (reg_info.invalidate_regs) - { - for (i=0; reg_info.invalidate_regs[i] != LLDB_INVALID_REGNUM; ++i) - m_invalidate_regs_map[reg_num].push_back(reg_info.invalidate_regs[i]); - m_invalidate_regs_map[reg_num].push_back(LLDB_INVALID_REGNUM); - reg_info.invalidate_regs = m_invalidate_regs_map[reg_num].data(); - } - m_regs.push_back (reg_info); - uint32_t set = GetRegisterSetIndexByName (set_name); - assert (set < m_sets.size()); - assert (set < m_set_reg_nums.size()); - assert (set < m_set_names.size()); - m_set_reg_nums[set].push_back(reg_num); - size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size; - if (m_reg_data_byte_size < end_reg_offset) - m_reg_data_byte_size = end_reg_offset; - } - - void - Finalize () - { - for (uint32_t set = 0; set < m_sets.size(); ++set) - { - assert (m_sets.size() == m_set_reg_nums.size()); - m_sets[set].num_registers = m_set_reg_nums[set].size(); - m_sets[set].registers = &m_set_reg_nums[set][0]; - } - } - - size_t - GetNumRegisters() const - { - return m_regs.size(); - } - - size_t - GetNumRegisterSets() const - { - return m_sets.size(); - } - - size_t - GetRegisterDataByteSize() const - { - return m_reg_data_byte_size; - } - - const lldb_private::RegisterInfo * - GetRegisterInfoAtIndex (uint32_t i) const - { - if (i < m_regs.size()) - return &m_regs[i]; - return NULL; - } - - const lldb_private::RegisterSet * - GetRegisterSet (uint32_t i) const - { - if (i < m_sets.size()) - return &m_sets[i]; - return NULL; - } - - uint32_t - GetRegisterSetIndexByName (lldb_private::ConstString &set_name) - { - name_collection::iterator pos, end = m_set_names.end(); - for (pos = m_set_names.begin(); pos != end; ++pos) - { - if (*pos == set_name) - return static_cast<uint32_t>(std::distance (m_set_names.begin(), pos)); - } - - m_set_names.push_back(set_name); - m_set_reg_nums.resize(m_set_reg_nums.size()+1); - lldb_private::RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL }; - m_sets.push_back (new_set); - return static_cast<uint32_t>(m_sets.size() - 1); - } - - uint32_t - ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const - { - reg_collection::const_iterator pos, end = m_regs.end(); - for (pos = m_regs.begin(); pos != end; ++pos) - { - if (pos->kinds[kind] == num) - return static_cast<uint32_t>(std::distance (m_regs.begin(), pos)); - } - - return LLDB_INVALID_REGNUM; - } - void - Clear() - { - m_regs.clear(); - m_sets.clear(); - m_set_reg_nums.clear(); - m_reg_names.clear(); - m_reg_alt_names.clear(); - m_set_names.clear(); - } - - void HardcodeARMRegisters(bool from_scratch); -protected: - //------------------------------------------------------------------ - // Classes that inherit from GDBRemoteRegisterContext can see and modify these - //------------------------------------------------------------------ - typedef std::vector <lldb_private::RegisterInfo> reg_collection; - typedef std::vector <lldb_private::RegisterSet> set_collection; - typedef std::vector <uint32_t> reg_num_collection; - typedef std::vector <reg_num_collection> set_reg_num_collection; - typedef std::vector <lldb_private::ConstString> name_collection; - typedef std::map<uint32_t, reg_num_collection> reg_to_regs_map; - - reg_collection m_regs; - set_collection m_sets; - set_reg_num_collection m_set_reg_nums; - name_collection m_reg_names; - name_collection m_reg_alt_names; - name_collection m_set_names; - reg_to_regs_map m_value_regs_map; - reg_to_regs_map m_invalidate_regs_map; - size_t m_reg_data_byte_size; // The number of bytes required to store all registers }; class GDBRemoteRegisterContext : public lldb_private::RegisterContext diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index d27207f121d3..aff9c7bc977c 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -8,13 +8,16 @@ //===----------------------------------------------------------------------===// #include "lldb/lldb-python.h" +#include "lldb/Host/Config.h" // C Includes #include <errno.h> -#include <spawn.h> #include <stdlib.h> +#ifndef LLDB_DISABLE_POSIX +#include <spawn.h> #include <netinet/in.h> #include <sys/mman.h> // for mmap +#endif #include <sys/stat.h> #include <sys/types.h> #include <time.h> @@ -46,6 +49,9 @@ #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" +#ifndef LLDB_DISABLE_PYTHON +#include "lldb/Interpreter/PythonDataObjects.h" +#endif #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Target.h" @@ -94,12 +100,14 @@ namespace { g_properties[] = { { "packet-timeout" , OptionValue::eTypeUInt64 , true , 1, NULL, NULL, "Specify the default packet timeout in seconds." }, + { "target-definition-file" , OptionValue::eTypeFileSpec , true, 0 , NULL, NULL, "The file that provides the description for remote target registers." }, { NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL } }; enum { - ePropertyPacketTimeout + ePropertyPacketTimeout, + ePropertyTargetDefinitionFile }; class PluginProperties : public Properties @@ -130,6 +138,20 @@ namespace { const uint32_t idx = ePropertyPacketTimeout; return m_collection_sp->GetPropertyAtIndexAsUInt64(NULL, idx, g_properties[idx].default_uint_value); } + + bool + SetPacketTimeout(uint64_t timeout) + { + const uint32_t idx = ePropertyPacketTimeout; + return m_collection_sp->SetPropertyAtIndexAsUInt64(NULL, idx, timeout); + } + + FileSpec + GetTargetDefinitionFile () const + { + const uint32_t idx = ePropertyTargetDefinitionFile; + return m_collection_sp->GetPropertyAtIndexAsFileSpec (NULL, idx); + } }; typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP; @@ -254,13 +276,13 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) : m_continue_C_tids (), m_continue_s_tids (), m_continue_S_tids (), - m_dispatch_queue_offsets_addr (LLDB_INVALID_ADDRESS), m_max_memory_size (512), m_addr_to_mmap_size (), m_thread_create_bp_sp (), m_waiting_for_attach (false), m_destroy_tried_resuming (false), - m_command_sp () + m_command_sp (), + m_breakpoint_pc_offset (0) { m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue"); @@ -305,6 +327,48 @@ ProcessGDBRemote::GetPluginVersion() return 1; } +bool +ProcessGDBRemote::ParsePythonTargetDefinition(const FileSpec &target_definition_fspec) +{ +#ifndef LLDB_DISABLE_PYTHON + ScriptInterpreter *interpreter = GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); + Error error; + lldb::ScriptInterpreterObjectSP module_object_sp (interpreter->LoadPluginModule(target_definition_fspec, error)); + if (module_object_sp) + { + lldb::ScriptInterpreterObjectSP target_definition_sp (interpreter->GetDynamicSettings(module_object_sp, + &GetTarget(), + "gdb-server-target-definition", + error)); + + PythonDictionary target_dict(target_definition_sp); + + if (target_dict) + { + PythonDictionary host_info_dict (target_dict.GetItemForKey("host-info")); + if (host_info_dict) + { + ArchSpec host_arch (host_info_dict.GetItemForKeyAsString(PythonString("triple"))); + + if (!host_arch.IsCompatibleMatch(GetTarget().GetArchitecture())) + { + GetTarget().SetArchitecture(host_arch); + } + + } + m_breakpoint_pc_offset = target_dict.GetItemForKeyAsInteger("breakpoint-pc-offset", 0); + + if (m_register_info.SetRegisterInfo (target_dict, GetTarget().GetArchitecture().GetByteOrder()) > 0) + { + return true; + } + } + } +#endif + return false; +} + + void ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) { @@ -480,6 +544,28 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) } } + // Check if qHostInfo specified a specific packet timeout for this connection. + // If so then lets update our setting so the user knows what the timeout is + // and can see it. + const uint32_t host_packet_timeout = m_gdb_comm.GetHostDefaultPacketTimeout(); + if (host_packet_timeout) + { + GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout); + } + + + if (reg_num == 0) + { + FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile (); + + if (target_definition_fspec) + { + // See if we can get register definitions from a python file + if (ParsePythonTargetDefinition (target_definition_fspec)) + return; + } + } + // We didn't get anything if the accumulated reg_num is zero. See if we are // debugging ARM and fill with a hard coded register set until we can get an // updated debugserver down on the devices. @@ -561,6 +647,11 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) GetThreadList(); if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false)) { + if (!m_target.GetArchitecture().IsValid()) { // Make sure we have an architecture + m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + } + + const StateType state = SetThreadStopInfo (m_last_stop_packet); if (state == eStateStopped) { @@ -759,6 +850,10 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_ if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false)) { + if (!m_target.GetArchitecture().IsValid()) { // Make sure we have an architecture + m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + } + SetPrivateState (SetThreadStopInfo (m_last_stop_packet)); if (!disable_stdio) @@ -863,8 +958,6 @@ ProcessGDBRemote::DidLaunchOrAttach () log->Printf ("ProcessGDBRemote::DidLaunch()"); if (GetID() != LLDB_INVALID_PROCESS_ID) { - m_dispatch_queue_offsets_addr = LLDB_INVALID_ADDRESS; - BuildDynamicRegisterInfo (false); // See if the GDB server supports the qHostInfo information @@ -1654,7 +1747,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) // Currently we are going to assume SIGTRAP means we are either // hitting a breakpoint or hardware single stepping. handled = true; - addr_t pc = thread_sp->GetRegisterContext()->GetPC(); + addr_t pc = thread_sp->GetRegisterContext()->GetPC() + m_breakpoint_pc_offset; lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); if (bp_site_sp) @@ -1664,6 +1757,8 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc. if (bp_site_sp->ValidForThisThread (thread_sp.get())) { + if(m_breakpoint_pc_offset != 0) + thread_sp->GetRegisterContext()->SetPC(pc); thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID())); } else @@ -2220,7 +2315,7 @@ ProcessGDBRemote::EnableBreakpointSite (BreakpointSite *bp_site) { const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site); - if (bp_site->HardwarePreferred()) + if (bp_site->HardwareRequired()) { // Try and set hardware breakpoint, and if that fails, fall through // and set a software breakpoint? @@ -2230,12 +2325,19 @@ ProcessGDBRemote::EnableBreakpointSite (BreakpointSite *bp_site) { bp_site->SetEnabled(true); bp_site->SetType (BreakpointSite::eHardware); - return error; } + else + { + error.SetErrorString("failed to set hardware breakpoint (hardware breakpoint resources might be exhausted or unavailable)"); + } + } + else + { + error.SetErrorString("hardware breakpoints are not supported"); } + return error; } - - if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointSoftware)) + else if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointSoftware)) { if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, true, addr, bp_op_size) == 0) { @@ -2687,7 +2789,7 @@ ProcessGDBRemote::KillDebugserverProcess () { if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) { - ::kill (m_debugserver_pid, SIGINT); + Host::Kill (m_debugserver_pid, SIGINT); m_debugserver_pid = LLDB_INVALID_PROCESS_ID; } } @@ -2794,7 +2896,7 @@ ProcessGDBRemote::StopAsyncThread () } -void * +thread_result_t ProcessGDBRemote::AsyncThread (void *arg) { ProcessGDBRemote *process = (ProcessGDBRemote*) arg; @@ -2916,97 +3018,6 @@ ProcessGDBRemote::AsyncThread (void *arg) return NULL; } -const char * -ProcessGDBRemote::GetDispatchQueueNameForThread -( - addr_t thread_dispatch_qaddr, - std::string &dispatch_queue_name -) -{ - dispatch_queue_name.clear(); - if (thread_dispatch_qaddr != 0 && thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) - { - // Cache the dispatch_queue_offsets_addr value so we don't always have - // to look it up - if (m_dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS) - { - static ConstString g_dispatch_queue_offsets_symbol_name ("dispatch_queue_offsets"); - const Symbol *dispatch_queue_offsets_symbol = NULL; - ModuleSpec libSystem_module_spec (FileSpec("libSystem.B.dylib", false)); - ModuleSP module_sp(GetTarget().GetImages().FindFirstModule (libSystem_module_spec)); - if (module_sp) - dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData); - - if (dispatch_queue_offsets_symbol == NULL) - { - ModuleSpec libdispatch_module_spec (FileSpec("libdispatch.dylib", false)); - module_sp = GetTarget().GetImages().FindFirstModule (libdispatch_module_spec); - if (module_sp) - dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData); - } - if (dispatch_queue_offsets_symbol) - m_dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetAddress().GetLoadAddress(&m_target); - - if (m_dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS) - return NULL; - } - - uint8_t memory_buffer[8]; - DataExtractor data (memory_buffer, - sizeof(memory_buffer), - m_target.GetArchitecture().GetByteOrder(), - m_target.GetArchitecture().GetAddressByteSize()); - - // Excerpt from src/queue_private.h - struct dispatch_queue_offsets_s - { - uint16_t dqo_version; - uint16_t dqo_label; // in version 1-3, offset to string; in version 4+, offset to a pointer to a string - uint16_t dqo_label_size; // in version 1-3, length of string; in version 4+, size of a (void*) in this process - } dispatch_queue_offsets; - - - Error error; - if (ReadMemory (m_dispatch_queue_offsets_addr, memory_buffer, sizeof(dispatch_queue_offsets), error) == sizeof(dispatch_queue_offsets)) - { - lldb::offset_t data_offset = 0; - if (data.GetU16(&data_offset, &dispatch_queue_offsets.dqo_version, sizeof(dispatch_queue_offsets)/sizeof(uint16_t))) - { - if (ReadMemory (thread_dispatch_qaddr, &memory_buffer, data.GetAddressByteSize(), error) == data.GetAddressByteSize()) - { - data_offset = 0; - lldb::addr_t queue_addr = data.GetAddress(&data_offset); - if (dispatch_queue_offsets.dqo_version >= 4) - { - // libdispatch versions 4+, pointer to dispatch name is in the - // queue structure. - lldb::addr_t pointer_to_label_address = queue_addr + dispatch_queue_offsets.dqo_label; - if (ReadMemory (pointer_to_label_address, &memory_buffer, data.GetAddressByteSize(), error) == data.GetAddressByteSize()) - { - data_offset = 0; - lldb::addr_t label_addr = data.GetAddress(&data_offset); - ReadCStringFromMemory (label_addr, dispatch_queue_name, error); - } - } - else - { - // libdispatch versions 1-3, dispatch name is a fixed width char array - // in the queue structure. - lldb::addr_t label_addr = queue_addr + dispatch_queue_offsets.dqo_label; - dispatch_queue_name.resize(dispatch_queue_offsets.dqo_label_size, '\0'); - size_t bytes_read = ReadMemory (label_addr, &dispatch_queue_name[0], dispatch_queue_offsets.dqo_label_size, error); - if (bytes_read < dispatch_queue_offsets.dqo_label_size) - dispatch_queue_name.erase (bytes_read); - } - } - } - } - } - if (dispatch_queue_name.empty()) - return NULL; - return dispatch_queue_name.c_str(); -} - //uint32_t //ProcessGDBRemote::ListProcessesMatchingName (const char *name, StringList &matches, std::vector<lldb::pid_t> &pids) //{ diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index e104b7191eab..b18ac5b1723e 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -291,6 +291,12 @@ protected: void SetLastStopPacket (const StringExtractorGDBRemote &response); + bool + ParsePythonTargetDefinition(const lldb_private::FileSpec &target_definition_fspec); + + bool + ParseRegisters(lldb_private::ScriptInterpreterObject *registers_array); + //------------------------------------------------------------------ /// Broadcaster event bits definitions. //------------------------------------------------------------------ @@ -326,13 +332,13 @@ protected: tid_sig_collection m_continue_C_tids; // 'C' for continue with signal tid_collection m_continue_s_tids; // 's' for step tid_sig_collection m_continue_S_tids; // 'S' for step with signal - lldb::addr_t m_dispatch_queue_offsets_addr; size_t m_max_memory_size; // The maximum number of bytes to read/write when reading and writing memory MMapMap m_addr_to_mmap_size; lldb::BreakpointSP m_thread_create_bp_sp; bool m_waiting_for_attach; bool m_destroy_tried_resuming; lldb::CommandObjectSP m_command_sp; + int64_t m_breakpoint_pc_offset; bool StartAsyncThread (); @@ -340,7 +346,7 @@ protected: void StopAsyncThread (); - static void * + static lldb::thread_result_t AsyncThread (void *arg); static bool diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 38fb84d66ef3..4e475c80bdab 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -10,16 +10,17 @@ #include "ThreadGDBRemote.h" +#include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/DataExtractor.h" -#include "lldb/Core/StreamString.h" #include "lldb/Core/State.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/Unwind.h" -#include "lldb/Breakpoint/Watchpoint.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" @@ -73,13 +74,38 @@ ThreadGDBRemote::GetQueueName () ProcessSP process_sp (GetProcess()); if (process_sp) { - ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get()); - return gdb_process->GetDispatchQueueNameForThread (m_thread_dispatch_qaddr, m_dispatch_queue_name); + PlatformSP platform_sp (process_sp->GetTarget().GetPlatform()); + if (platform_sp) + { + m_dispatch_queue_name = platform_sp->GetQueueNameForThreadQAddress (process_sp.get(), m_thread_dispatch_qaddr); + } + if (m_dispatch_queue_name.length() > 0) + { + return m_dispatch_queue_name.c_str(); + } } } return NULL; } +queue_id_t +ThreadGDBRemote::GetQueueID () +{ + if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS) + { + ProcessSP process_sp (GetProcess()); + if (process_sp) + { + PlatformSP platform_sp (process_sp->GetTarget().GetPlatform()); + if (platform_sp) + { + return platform_sp->GetQueueIDForThreadQAddress (process_sp.get(), m_thread_dispatch_qaddr); + } + } + } + return LLDB_INVALID_QUEUE_ID; +} + void ThreadGDBRemote::WillResume (StateType resume_state) { @@ -164,7 +190,6 @@ lldb::RegisterContextSP ThreadGDBRemote::CreateRegisterContextForFrame (StackFrame *frame) { lldb::RegisterContextSP reg_ctx_sp; - const bool read_all_registers_at_once = false; uint32_t concrete_frame_idx = 0; if (frame) @@ -177,6 +202,8 @@ ThreadGDBRemote::CreateRegisterContextForFrame (StackFrame *frame) if (process_sp) { ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get()); + // read_all_registers_at_once will be true if 'p' packet is not supported. + bool read_all_registers_at_once = !gdb_process->GetGDBRemote().GetpPacketSupported (GetID()); reg_ctx_sp.reset (new GDBRemoteRegisterContext (*this, concrete_frame_idx, gdb_process->m_register_info, read_all_registers_at_once)); } } diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index 50a3f19c6505..dd4cc036ef8b 100644 --- a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -38,6 +38,9 @@ public: virtual const char * GetQueueName (); + virtual lldb::queue_id_t + GetQueueID (); + virtual lldb::RegisterContextSP GetRegisterContext (); |