diff options
author | Johnny Chen <johnny.chen@apple.com> | 2012-01-05 21:48:15 +0000 |
---|---|---|
committer | Johnny Chen <johnny.chen@apple.com> | 2012-01-05 21:48:15 +0000 |
commit | 9ed5b49c45ba377cffbc5d0d893b5437f50228af (patch) | |
tree | 386909c95bde01a8a2071c1b5f7d2c78b5187c5a /lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp | |
parent | 9afd449e8ff4382d9479cfbc7acc38d74fbcfc76 (diff) | |
download | bcm5719-llvm-9ed5b49c45ba377cffbc5d0d893b5437f50228af.tar.gz bcm5719-llvm-9ed5b49c45ba377cffbc5d0d893b5437f50228af.zip |
Fix incomplete commit of http://llvm.org/viewvc/llvm-project?rev=147609&view=rev:
This patch combines common code from Linux and FreeBSD into
a new POSIX platform. It also contains fixes for 64bit FreeBSD.
The patch is based on changes by Mark Peek <mp@FreeBSD.org> and
"K. Macy" <kmacy@freebsd.org> in their github repo located at
https://github.com/fbsd/lldb.
llvm-svn: 147613
Diffstat (limited to 'lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp')
-rw-r--r-- | lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp | 594 |
1 files changed, 594 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp new file mode 100644 index 00000000000..67cf8a9311b --- /dev/null +++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp @@ -0,0 +1,594 @@ +//===-- ProcessPOSIX.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +#include <errno.h> + +// C++ Includes +// Other libraries and framework includes +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/State.h" +#include "lldb/Host/Host.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/Target.h" + +#include "ProcessPOSIX.h" +#include "ProcessPOSIXLog.h" +#include "Plugins/Process/Utility/InferiorCallPOSIX.h" +#include "ProcessMonitor.h" +#include "POSIXThread.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------------ +// Static functions. +#if 0 +Process* +ProcessPOSIX::CreateInstance(Target& target, Listener &listener) +{ + return new ProcessPOSIX(target, listener); +} + + +void +ProcessPOSIX::Initialize() +{ + static bool g_initialized = false; + + if (!g_initialized) + { + g_initialized = true; + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); + + Log::Callbacks log_callbacks = { + ProcessPOSIXLog::DisableLog, + ProcessPOSIXLog::EnableLog, + ProcessPOSIXLog::ListLogCategories + }; + + Log::RegisterLogChannel (ProcessPOSIX::GetPluginNameStatic(), log_callbacks); + } +} +#endif + +//------------------------------------------------------------------------------ +// Constructors and destructors. + +ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener) + : Process(target, listener), + m_monitor(NULL), + m_module(NULL), + m_in_limbo(false), + m_exit_now(false) +{ + // FIXME: Putting this code in the ctor and saving the byte order in a + // member variable is a hack to avoid const qual issues in GetByteOrder. + ObjectFile *obj_file = GetTarget().GetExecutableModule()->GetObjectFile(); + m_byte_order = obj_file->GetByteOrder(); +} + +ProcessPOSIX::~ProcessPOSIX() +{ + delete m_monitor; +} + +//------------------------------------------------------------------------------ +// Process protocol. + +bool +ProcessPOSIX::CanDebug(Target &target, bool plugin_specified_by_name) +{ + // For now we are just making sure the file exists for a given module + ModuleSP exe_module_sp(target.GetExecutableModule()); + if (exe_module_sp.get()) + return exe_module_sp->GetFileSpec().Exists(); + return false; +} + +Error +ProcessPOSIX::DoAttachToProcessWithID(lldb::pid_t pid) +{ + Error error; + assert(m_monitor == NULL); + + LogSP log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf ("ProcessPOSIX::%s(pid = %i)", __FUNCTION__, GetID()); + + m_monitor = new ProcessMonitor(this, pid, error); + + if (!error.Success()) + return error; + + SetID(pid); + return error; +} + +Error +ProcessPOSIX::WillLaunch(Module* module) +{ + Error error; + return error; +} + +const char * +ProcessPOSIX::GetFilePath( + const lldb_private::ProcessLaunchInfo::FileAction *file_action, + const char *default_path) +{ + const char *pts_name = "/dev/pts/"; + const char *path = NULL; + + if (file_action) + { + if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen) + path = file_action->GetPath(); + // By default the stdio paths passed in will be pseudo-terminal + // (/dev/pts). If so, convert to using a different default path + // instead to redirect I/O to the debugger console. This should + // also handle user overrides to /dev/null or a different file. + if (::strncmp(path, pts_name, ::strlen(pts_name)) == 0) + path = default_path; + } + + return path; +} + +Error +ProcessPOSIX::DoLaunch (Module *module, + const ProcessLaunchInfo &launch_info) +{ + Error error; + assert(m_monitor == NULL); + + SetPrivateState(eStateLaunching); + + const lldb_private::ProcessLaunchInfo::FileAction *file_action; + + // Default of NULL will mean to use existing open file descriptors + const char *stdin_path = NULL; + const char *stdout_path = NULL; + const char *stderr_path = NULL; + + file_action = launch_info.GetFileActionForFD (STDIN_FILENO); + stdin_path = GetFilePath(file_action, stdin_path); + + file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); + stdout_path = GetFilePath(file_action, stdout_path); + + file_action = launch_info.GetFileActionForFD (STDERR_FILENO); + stderr_path = GetFilePath(file_action, stderr_path); + + m_monitor = new ProcessMonitor (this, + module, + launch_info.GetArguments().GetConstArgumentVector(), + launch_info.GetEnvironmentEntries().GetConstArgumentVector(), + stdin_path, + stdout_path, + stderr_path, + error); + + m_module = module; + + if (!error.Success()) + return error; + + SetID(m_monitor->GetPID()); + return error; +} + +void +ProcessPOSIX::DidLaunch() +{ +} + +Error +ProcessPOSIX::DoResume() +{ + StateType state = GetPrivateState(); + + assert(state == eStateStopped || state == eStateCrashed); + + // We are about to resume a thread that will cause the process to exit so + // set our exit status now. Do not change our state if the inferior + // crashed. + if (state == eStateStopped) + { + if (m_in_limbo) + SetExitStatus(m_exit_status, NULL); + else + SetPrivateState(eStateRunning); + } + + bool did_resume = false; + 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()); + did_resume = thread->Resume() || did_resume; + } + assert(did_resume && "Process resume failed!"); + + return Error(); +} + +addr_t +ProcessPOSIX::GetImageInfoAddress() +{ + Target *target = &GetTarget(); + ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); + Address addr = obj_file->GetImageInfoAddress(); + + if (addr.IsValid()) + return addr.GetLoadAddress(target); + else + return LLDB_INVALID_ADDRESS; +} + +Error +ProcessPOSIX::DoHalt(bool &caused_stop) +{ + Error error; + + if (IsStopped()) + { + caused_stop = false; + } + else if (kill(GetID(), SIGSTOP)) + { + caused_stop = false; + error.SetErrorToErrno(); + } + else + { + caused_stop = true; + } + + return error; +} + +Error +ProcessPOSIX::DoDetach() +{ + Error error; + + error = m_monitor->Detach(); + if (error.Success()) + SetPrivateState(eStateDetached); + + return error; +} + +Error +ProcessPOSIX::DoSignal(int signal) +{ + Error error; + + if (kill(GetID(), signal)) + error.SetErrorToErrno(); + + return error; +} + +Error +ProcessPOSIX::DoDestroy() +{ + Error error; + + if (!HasExited()) + { + // Drive the exit event to completion (do not keep the inferior in + // limbo). + m_exit_now = true; + + if (kill(m_monitor->GetPID(), SIGKILL) && error.Success()) + { + error.SetErrorToErrno(); + return error; + } + + SetPrivateState(eStateExited); + } + + return error; +} + +void +ProcessPOSIX::SendMessage(const ProcessMessage &message) +{ + Mutex::Locker lock(m_message_mutex); + + switch (message.GetKind()) + { + default: + assert(false && "Unexpected process message!"); + break; + + case ProcessMessage::eInvalidMessage: + return; + + case ProcessMessage::eLimboMessage: + m_in_limbo = true; + m_exit_status = message.GetExitStatus(); + if (m_exit_now) + { + SetPrivateState(eStateExited); + m_monitor->Detach(); + } + else + SetPrivateState(eStateStopped); + break; + + case ProcessMessage::eExitMessage: + m_exit_status = message.GetExitStatus(); + SetExitStatus(m_exit_status, NULL); + break; + + case ProcessMessage::eTraceMessage: + case ProcessMessage::eBreakpointMessage: + SetPrivateState(eStateStopped); + break; + + case ProcessMessage::eSignalMessage: + case ProcessMessage::eSignalDeliveredMessage: + SetPrivateState(eStateStopped); + break; + + case ProcessMessage::eCrashMessage: + SetPrivateState(eStateCrashed); + break; + } + + m_message_queue.push(message); +} + +void +ProcessPOSIX::RefreshStateAfterStop() +{ + LogSP log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf ("ProcessPOSIX::%s()", __FUNCTION__); + + Mutex::Locker lock(m_message_mutex); + if (m_message_queue.empty()) + return; + + ProcessMessage &message = m_message_queue.front(); + + // Resolve the thread this message corresponds to and pass it along. + // FIXME: we're really dealing with the pid here. This should get + // fixed when this code is fixed to handle multiple threads. + lldb::tid_t tid = message.GetTID(); + if (log) + log->Printf ("ProcessPOSIX::%s() pid = %i", __FUNCTION__, tid); + POSIXThread *thread = static_cast<POSIXThread*>( + GetThreadList().FindThreadByID(tid, false).get()); + + assert(thread); + thread->Notify(message); + + m_message_queue.pop(); +} + +bool +ProcessPOSIX::IsAlive() +{ + StateType state = GetPrivateState(); + return state != eStateDetached && state != eStateExited && state != eStateInvalid; +} + +size_t +ProcessPOSIX::DoReadMemory(addr_t vm_addr, + void *buf, size_t size, Error &error) +{ + assert(m_monitor); + return m_monitor->ReadMemory(vm_addr, buf, size, error); +} + +size_t +ProcessPOSIX::DoWriteMemory(addr_t vm_addr, const void *buf, size_t size, + Error &error) +{ + assert(m_monitor); + return m_monitor->WriteMemory(vm_addr, buf, size, error); +} + +addr_t +ProcessPOSIX::DoAllocateMemory(size_t size, uint32_t permissions, + Error &error) +{ + addr_t allocated_addr = LLDB_INVALID_ADDRESS; + + unsigned prot = 0; + if (permissions & lldb::ePermissionsReadable) + prot |= eMmapProtRead; + if (permissions & lldb::ePermissionsWritable) + prot |= eMmapProtWrite; + if (permissions & lldb::ePermissionsExecutable) + prot |= eMmapProtExec; + + if (InferiorCallMmap(this, allocated_addr, 0, size, prot, + eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) { + m_addr_to_mmap_size[allocated_addr] = size; + error.Clear(); + } else { + allocated_addr = LLDB_INVALID_ADDRESS; + error.SetErrorStringWithFormat("unable to allocate %zu bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions)); + } + + return allocated_addr; +} + +Error +ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr) +{ + Error error; + MMapMap::iterator pos = m_addr_to_mmap_size.find(addr); + if (pos != m_addr_to_mmap_size.end() && + InferiorCallMunmap(this, addr, pos->second)) + m_addr_to_mmap_size.erase (pos); + else + error.SetErrorStringWithFormat("unable to deallocate memory at 0x%llx", addr); + + return error; +} + +size_t +ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) +{ + static const uint8_t g_i386_opcode[] = { 0xCC }; + + ArchSpec arch = GetTarget().GetArchitecture(); + const uint8_t *opcode = NULL; + size_t opcode_size = 0; + + switch (arch.GetCore()) + { + default: + assert(false && "CPU type not supported!"); + break; + + case ArchSpec::eCore_x86_32_i386: + case ArchSpec::eCore_x86_64_x86_64: + opcode = g_i386_opcode; + opcode_size = sizeof(g_i386_opcode); + break; + } + + bp_site->SetTrapOpcode(opcode, opcode_size); + return opcode_size; +} + +Error +ProcessPOSIX::EnableBreakpoint(BreakpointSite *bp_site) +{ + return EnableSoftwareBreakpoint(bp_site); +} + +Error +ProcessPOSIX::DisableBreakpoint(BreakpointSite *bp_site) +{ + return DisableSoftwareBreakpoint(bp_site); +} + +uint32_t +ProcessPOSIX::UpdateThreadListIfNeeded() +{ + // Do not allow recursive updates. + return m_thread_list.GetSize(false); +} + +uint32_t +ProcessPOSIX::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) +{ + LogSP log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf ("ProcessPOSIX::%s() (pid = %i)", __FUNCTION__, 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 (GetID(), false)); + if (!thread_sp) + thread_sp.reset(new POSIXThread(*this, GetID())); + + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf ("ProcessPOSIX::%s() updated pid = %i", __FUNCTION__, GetID()); + new_thread_list.AddThread(thread_sp); + + return new_thread_list.GetSize(false); +} + +ByteOrder +ProcessPOSIX::GetByteOrder() const +{ + // FIXME: We should be able to extract this value directly. See comment in + // ProcessPOSIX(). + return m_byte_order; +} + +size_t +ProcessPOSIX::PutSTDIN(const char *buf, size_t len, Error &error) +{ + ssize_t status; + if ((status = write(m_monitor->GetTerminalFD(), buf, len)) < 0) + { + error.SetErrorToErrno(); + return 0; + } + return status; +} + +size_t +ProcessPOSIX::GetSTDOUT(char *buf, size_t len, Error &error) +{ + ssize_t bytes_read; + + // The terminal file descriptor is always in non-block mode. + if ((bytes_read = read(m_monitor->GetTerminalFD(), buf, len)) < 0) + { + if (errno != EAGAIN) + error.SetErrorToErrno(); + return 0; + } + return bytes_read; +} + +size_t +ProcessPOSIX::GetSTDERR(char *buf, size_t len, Error &error) +{ + return GetSTDOUT(buf, len, error); +} + +UnixSignals & +ProcessPOSIX::GetUnixSignals() +{ + return m_signals; +} + +//------------------------------------------------------------------------------ +// Utility functions. + +bool +ProcessPOSIX::HasExited() +{ + switch (GetPrivateState()) + { + default: + break; + + case eStateDetached: + case eStateExited: + return true; + } + + return false; +} + +bool +ProcessPOSIX::IsStopped() +{ + switch (GetPrivateState()) + { + default: + break; + + case eStateStopped: + case eStateCrashed: + case eStateSuspended: + return true; + } + + return false; +} |