Index: cmake/LLDBDependencies.cmake =================================================================== --- cmake/LLDBDependencies.cmake +++ cmake/LLDBDependencies.cmake @@ -76,7 +76,14 @@ lldbPluginProcessPOSIX lldbPluginProcessElfCore lldbPluginJITLoaderGDB - ) + ) +endif () + +# Android only libraries +if ( __ANDROID_NDK__ ) + list(APPEND LLDB_USED_LIBS + lldbPluginProcessAndroid + ) endif () # FreeBSD-only libraries Index: source/Host/common/Host.cpp =================================================================== --- source/Host/common/Host.cpp +++ source/Host/common/Host.cpp @@ -142,6 +142,10 @@ }; #endif // __ANDROID_NDK__ +#ifdef __ANDROID__ +static void SigChldHandler(int) {} +#endif // __ANDROID__ + static thread_result_t MonitorChildProcessThreadFunction (void *arg) { @@ -167,6 +171,13 @@ #endif const int options = __WALL; +#ifdef __ANDROID__ + struct sigaction sigChldAction; + ::sigaction(SIGCHLD, NULL, &sigChldAction); + sigChldAction.sa_handler = SigChldHandler; + ::sigaction(SIGCHLD, &sigChldAction, NULL); +#endif // __ANDROID__ + while (1) { log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS); @@ -185,7 +196,19 @@ if (wait_pid == -1) { if (errno == EINTR) + { +#ifdef __ANDROID__ + // On Android we have to call the callback on EINTR also because the monitor thread + // is stopped with sending a SIGCHLD and then returning true from the callback + if (callback (callback_baton, -1, false, 0, 0)) + { + if (log) + log->Printf ("%s (arg = %p) thread exiting because callback returned true...", __FUNCTION__, arg); + break; + } +#endif // __ANDROID__ continue; + } else { if (log) Index: source/Plugins/Platform/Android/PlatformAndroid.h =================================================================== --- source/Plugins/Platform/Android/PlatformAndroid.h +++ source/Plugins/Platform/Android/PlatformAndroid.h @@ -60,6 +60,16 @@ lldb_private::Error ConnectRemote (lldb_private::Args& args) override; + Error + LaunchNativeProcess (ProcessLaunchInfo &launch_info, + lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate, + NativeProcessProtocolSP &process_sp) override; + + Error + AttachNativeProcess (lldb::pid_t pid, + lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate, + NativeProcessProtocolSP &process_sp) override; + private: DISALLOW_COPY_AND_ASSIGN (PlatformAndroid); }; Index: source/Plugins/Platform/Android/PlatformAndroid.cpp =================================================================== --- source/Plugins/Platform/Android/PlatformAndroid.cpp +++ source/Plugins/Platform/Android/PlatformAndroid.cpp @@ -11,6 +11,7 @@ // C++ Includes // Other libraries and framework includes #include "lldb/Core/Log.h" +#include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Host/HostInfo.h" @@ -18,6 +19,10 @@ #include "PlatformAndroid.h" #include "PlatformAndroidRemoteGDBServer.h" +#if defined(__ANDROID__) +#include "../../Process/Android/NativeProcessAndroid.h" +#endif + using namespace lldb; using namespace lldb_private; @@ -180,3 +185,50 @@ m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer()); return PlatformLinux::ConnectRemote (args); } + +Error +PlatformAndroid::LaunchNativeProcess ( + ProcessLaunchInfo &launch_info, + lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate, + NativeProcessProtocolSP &process_sp) +{ +#if !defined(__ANDROID__) + return Error("Only implemented on Android hosts"); +#else + if (!IsHost ()) + return Error("PlatformAndroid::%s (): cannot launch a debug process when not the host", __FUNCTION__); + + // Retrieve the exe module. + lldb::ModuleSP exe_module_sp; + ModuleSpec exe_module_spec(launch_info.GetExecutableFile(), launch_info.GetArchitecture()); + + Error error = ResolveExecutable (exe_module_spec, exe_module_sp, NULL); + if (!error.Success ()) + return error; + + if (!exe_module_sp) + return Error("exe_module_sp could not be resolved for %s", launch_info.GetExecutableFile ().GetPath ().c_str ()); + + // Launch it for debugging + return NativeProcessAndroid::LaunchProcess (exe_module_sp.get (), + launch_info, + native_delegate, + process_sp); +#endif +} + +Error +PlatformAndroid::AttachNativeProcess (lldb::pid_t pid, + lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate, + NativeProcessProtocolSP &process_sp) +{ +#if !defined(__ANDROID__) + return Error("Only implemented on Android hosts"); +#else + if (!IsHost ()) + return Error("PlatformAndroid::%s (): cannot attach to a debug process when not the host", __FUNCTION__); + + // Launch it for debugging + return NativeProcessAndroid::AttachToProcess (pid, native_delegate, process_sp); +#endif +} \ No newline at end of file Index: source/Plugins/Process/Android/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/Process/Android/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LLVM_NO_RTTI 1) + +include_directories(.) +include_directories(../Linux) + +add_lldb_library(lldbPluginProcessAndroid + NativeProcessAndroid.cpp + ) + Index: source/Plugins/Process/Android/Makefile =================================================================== --- /dev/null +++ source/Plugins/Process/Android/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/Process/Android/Makefile -------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../../.. +LIBRARYNAME := lldbPluginProcessAndroid +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile Index: source/Plugins/Process/Android/NativeProcessAndroid.h =================================================================== --- /dev/null +++ source/Plugins/Process/Android/NativeProcessAndroid.h @@ -0,0 +1,72 @@ +//===-- NativeProcessAndroid.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_NativeProcessAndroid_H_ +#define liblldb_NativeProcessAndroid_H_ + +#include "NativeProcessLinux.h" + +namespace lldb_private +{ + + class NativeProcessAndroid : public NativeProcessLinux + { + public: + // --------------------------------------------------------------------- + // Public Static Methods + // --------------------------------------------------------------------- + static Error + LaunchProcess (Module *exe_module, + ProcessLaunchInfo &launch_info, + NativeProcessProtocol::NativeDelegate &native_delegate, + NativeProcessProtocolSP &native_process_sp); + + static Error + AttachToProcess (lldb::pid_t pid, + NativeProcessProtocol::NativeDelegate &native_delegate, + NativeProcessProtocolSP &native_process_sp); + + protected: + // Launches an inferior process ready for debugging. Forms the + // implementation of Process::DoLaunch. + void + LaunchInferior (Module *module, + char const *argv[], + char const *envp[], + const std::string &stdin_path, + const std::string &stdout_path, + const std::string &stderr_path, + const char *working_dir, + const ProcessLaunchInfo &launch_info, + Error &error) override; + + // Attaches to an existing process. Forms the + // implementation of Process::DoLaunch. + void + AttachToInferior (lldb::pid_t pid, Error &error) override; + + HostThread + StartMonitorThread () override; + + // Stops the child monitor thread. + void + StopMonitoringChildProcess() override; + + private: + bool m_monitor_thread_running; + + NativeProcessAndroid(); + + static bool + MonitorCallback(void *callback_baton, lldb::pid_t pid, bool exited, int signal, int status); + }; + +} // end of namespace lldb_private + +#endif // liblldb_NativeProcessAndroid_H_ Index: source/Plugins/Process/Android/NativeProcessAndroid.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/Android/NativeProcessAndroid.cpp @@ -0,0 +1,116 @@ +//===-- NativeProcessAndroid.cpp ------------------------------ -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "NativeProcessAndroid.h" +#include "NativeProcessLinux.h" +#include "ThreadStateCoordinator.h" + +// Other libraries and framework includes +#include "lldb/Core/Error.h" +#include "lldb/Host/HostNativeThread.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/ProcessLaunchInfo.h" + +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" + +using namespace lldb; +using namespace lldb_private; + +NativeProcessAndroid::NativeProcessAndroid() : + m_monitor_thread_running (false) +{ +} + +lldb_private::Error +NativeProcessAndroid::LaunchProcess (Module *exe_module, + ProcessLaunchInfo &launch_info, + NativeProcessProtocol::NativeDelegate &native_delegate, + NativeProcessProtocolSP &native_process_sp) +{ + native_process_sp.reset (new NativeProcessAndroid ()); + return NativeProcessLinux::LaunchProcessHelper (exe_module, launch_info, native_delegate, + native_process_sp); +} + +lldb_private::Error +NativeProcessAndroid::AttachToProcess (lldb::pid_t pid, + NativeProcessProtocol::NativeDelegate &native_delegate, + NativeProcessProtocolSP &native_process_sp) +{ + native_process_sp.reset (new NativeProcessAndroid ()); + return NativeProcessLinux::AttachToProcessHelper (pid, native_delegate, native_process_sp); +} + +void +NativeProcessAndroid::LaunchInferior (Module *module, + const char *argv[], + const char *envp[], + const std::string &stdin_path, + const std::string &stdout_path, + const std::string &stderr_path, + const char *working_dir, + const lldb_private::ProcessLaunchInfo &launch_info, + lldb_private::Error &error) +{ + NativeProcessLinux::LaunchInferior (module, argv, envp, stdin_path, stdout_path, stderr_path, + working_dir, launch_info, error); + if (error.Success ()) + m_monitor_thread_running = true; +} + +void +NativeProcessAndroid::AttachToInferior (lldb::pid_t pid, lldb_private::Error &error) +{ + NativeProcessLinux::AttachToInferior (pid, error); + if (error.Success ()) + m_monitor_thread_running = true; +} + +bool +NativeProcessAndroid::MonitorCallback (void *callback_baton, + lldb::pid_t pid, + bool exited, + int signal, + int status) +{ + if ((::pid_t)pid == -1) + { + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); + + NativeProcessAndroid *const process = static_cast(callback_baton); + assert (process && "process is null"); + if (!process) + { + if (log) + log->Printf ("NativeProcessAndroid::%s pid %" PRIu64 " callback_baton was null, can't determine process to use", __FUNCTION__, pid); + return true; + } + + return !process->m_monitor_thread_running; + } + + return NativeProcessLinux::MonitorCallback (callback_baton, pid, exited, signal, status); +} + +void +NativeProcessAndroid::StopMonitoringChildProcess() +{ + if (m_monitor_thread.IsJoinable()) + { + m_monitor_thread_running = false; + ::pthread_kill(m_monitor_thread.GetNativeThread().GetSystemHandle(), SIGCHLD); + m_monitor_thread.Join(nullptr); + } +} + +HostThread +NativeProcessAndroid::StartMonitorThread () +{ + return Host::StartMonitoringChildProcess (NativeProcessAndroid::MonitorCallback, this, GetID (), true); +} Index: source/Plugins/Process/CMakeLists.txt =================================================================== --- source/Plugins/Process/CMakeLists.txt +++ source/Plugins/Process/CMakeLists.txt @@ -1,4 +1,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux") + if (__ANDROID_NDK__) + add_subdirectory(Android) + endif() add_subdirectory(Linux) add_subdirectory(POSIX) elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") Index: source/Plugins/Process/Linux/NativeProcessLinux.h =================================================================== --- source/Plugins/Process/Linux/NativeProcessLinux.h +++ source/Plugins/Process/Linux/NativeProcessLinux.h @@ -163,16 +163,8 @@ /// For instance, the extended floating-point register set. Error WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset); - - protected: - // --------------------------------------------------------------------- - // NativeProcessProtocol protected interface - // --------------------------------------------------------------------- - Error - GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint, size_t &actual_opcode_size, const uint8_t *&trap_opcode_bytes) override; - - private: + protected: lldb_private::ArchSpec m_arch; HostThread m_operation_thread; @@ -194,6 +186,56 @@ std::unique_ptr m_coordinator_up; HostThread m_coordinator_thread; + static lldb_private::Error + LaunchProcessHelper (Module *exe_module, + ProcessLaunchInfo &launch_info, + NativeProcessProtocol::NativeDelegate &native_delegate, + NativeProcessProtocolSP &native_process_sp); + + static lldb_private::Error + AttachToProcessHelper (lldb::pid_t pid, + NativeProcessProtocol::NativeDelegate &native_delegate, + NativeProcessProtocolSP &native_process_sp); + + NativeProcessLinux (); + + // --------------------------------------------------------------------- + // NativeProcessProtocol protected interface + // --------------------------------------------------------------------- + Error + GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint, + size_t &actual_opcode_size, + const uint8_t *&trap_opcode_bytes) override; + + /// Launches an inferior process ready for debugging. Forms the + /// implementation of Process::DoLaunch. + virtual void + LaunchInferior (Module *module, + char const *argv[], + char const *envp[], + const std::string &stdin_path, + const std::string &stdout_path, + const std::string &stderr_path, + const char *working_dir, + const lldb_private::ProcessLaunchInfo &launch_info, + Error &error); + + /// Attaches to an existing process. Forms the + /// implementation of Process::DoLaunch. + virtual void + AttachToInferior (lldb::pid_t pid, Error &error); + + virtual HostThread + StartMonitorThread (); + + /// Stops the child monitor thread. + virtual void + StopMonitoringChildProcess(); + + static bool + MonitorCallback(void *callback_baton, lldb::pid_t pid, bool exited, int signal, int status); + + private: struct OperationArgs { OperationArgs(NativeProcessLinux *monitor); @@ -246,27 +288,6 @@ // --------------------------------------------------------------------- // Private Instance Methods // --------------------------------------------------------------------- - NativeProcessLinux (); - - /// Launches an inferior process ready for debugging. Forms the - /// implementation of Process::DoLaunch. - void - LaunchInferior ( - Module *module, - char const *argv[], - char const *envp[], - const std::string &stdin_path, - const std::string &stdout_path, - const std::string &stderr_path, - const char *working_dir, - const lldb_private::ProcessLaunchInfo &launch_info, - Error &error); - - /// Attaches to an existing process. Forms the - /// implementation of Process::DoLaunch. - void - AttachToInferior (lldb::pid_t pid, Error &error); - void StartLaunchOpThread(LaunchArgs *args, lldb_private::Error &error); @@ -294,10 +315,6 @@ static bool DupDescriptor(const char *path, int fd, int flags); - static bool - MonitorCallback(void *callback_baton, - lldb::pid_t pid, bool exited, int signal, int status); - void MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid); @@ -321,10 +338,6 @@ void DoOperation(void *op); - /// Stops the child monitor thread. - void - StopMonitoringChildProcess(); - /// Stops the operation thread used to attach/launch a process. void StopOpThread(); Index: source/Plugins/Process/Linux/NativeProcessLinux.cpp =================================================================== --- source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -38,6 +38,7 @@ #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/ThreadLauncher.h" +#include "lldb/Host/linux/HostThreadLinux.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Target/Process.h" @@ -1153,6 +1154,32 @@ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate, NativeProcessProtocolSP &native_process_sp) { + native_process_sp.reset (new NativeProcessLinux ()); + return NativeProcessLinux::LaunchProcessHelper (exe_module, launch_info, native_delegate, + native_process_sp); +} + +lldb_private::Error +NativeProcessLinux::AttachToProcess ( + lldb::pid_t pid, + lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate, + NativeProcessProtocolSP &native_process_sp) +{ + native_process_sp.reset (new NativeProcessLinux ()); + return NativeProcessLinux::AttachToProcessHelper (pid, native_delegate, native_process_sp); +} + +// ----------------------------------------------------------------------------- +// Protected Static Methods +// ----------------------------------------------------------------------------- + +lldb_private::Error +NativeProcessLinux::LaunchProcessHelper ( + lldb_private::Module *exe_module, + lldb_private::ProcessLaunchInfo &launch_info, + lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate, + NativeProcessProtocolSP &native_process_sp) +{ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); Error error; @@ -1206,9 +1233,6 @@ log->Printf ("NativeProcessLinux::%s leaving STDERR as is", __FUNCTION__); } - // Create the NativeProcessLinux in launch mode. - native_process_sp.reset (new NativeProcessLinux ()); - if (log) { int i = 0; @@ -1251,7 +1275,7 @@ } lldb_private::Error -NativeProcessLinux::AttachToProcess ( +NativeProcessLinux::AttachToProcessHelper ( lldb::pid_t pid, lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate, NativeProcessProtocolSP &native_process_sp) @@ -1272,7 +1296,8 @@ if (!error.Success ()) return error; - std::shared_ptr native_process_linux_sp (new NativeProcessLinux ()); + std::shared_ptr native_process_linux_sp ( + std::static_pointer_cast (native_process_sp)); if (!native_process_linux_sp->RegisterNativeDelegate (native_delegate)) { @@ -1284,7 +1309,6 @@ if (!error.Success ()) return error; - native_process_sp = native_process_linux_sp; return error; } @@ -1378,8 +1402,7 @@ } // Finally, start monitoring the child process for change in state. - m_monitor_thread = Host::StartMonitoringChildProcess( - NativeProcessLinux::MonitorCallback, this, GetID(), true); + m_monitor_thread = StartMonitorThread(); if (!m_monitor_thread.IsJoinable()) { error.SetErrorToGenericError(); @@ -1468,8 +1491,7 @@ } // Finally, start monitoring the child process for change in state. - m_monitor_thread = Host::StartMonitoringChildProcess ( - NativeProcessLinux::MonitorCallback, this, GetID (), true); + m_monitor_thread = StartMonitorThread(); if (!m_monitor_thread.IsJoinable()) { error.SetErrorToGenericError (); @@ -1478,6 +1500,12 @@ } } +HostThread +NativeProcessLinux::StartMonitorThread () +{ + return Host::StartMonitoringChildProcess (NativeProcessLinux::MonitorCallback, this, GetID (), true); +} + void NativeProcessLinux::Terminate () { @@ -1953,10 +1981,10 @@ // Main process monitoring waitpid-loop handler. bool NativeProcessLinux::MonitorCallback(void *callback_baton, - lldb::pid_t pid, - bool exited, - int signal, - int status) + lldb::pid_t pid, + bool exited, + int signal, + int status) { Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));