Index: cmake/LLDBDependencies.cmake =================================================================== --- cmake/LLDBDependencies.cmake +++ cmake/LLDBDependencies.cmake @@ -25,6 +25,7 @@ lldbPluginObjectContainerMachOArchive lldbPluginProcessGDBRemote lldbPluginProcessUtility + lldbPluginPlatformAndroid lldbPluginPlatformGDB lldbPluginPlatformFreeBSD lldbPluginPlatformKalimba Index: include/lldb/Host/Host.h =================================================================== --- include/lldb/Host/Host.h +++ include/lldb/Host/Host.h @@ -236,12 +236,16 @@ GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info); #if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined (__NetBSD__) +#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__) + static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info); static Error LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &launch_info, lldb::pid_t &pid); static bool AddPosixSpawnFileAction(void *file_actions, const FileAction *info, Log *log, Error &error); -#endif + +#endif // !defined(__ANDROID__) && !defined(__ANDROID_NDK__) +#endif // defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__) static const lldb_private::UnixSignalsSP& GetUnixSignals (); Index: include/lldb/Host/HostInfo.h =================================================================== --- include/lldb/Host/HostInfo.h +++ include/lldb/Host/HostInfo.h @@ -38,8 +38,13 @@ #include "lldb/Host/windows/HostInfoWindows.h" #define HOST_INFO_TYPE HostInfoWindows #elif defined(__linux__) +#if defined(__ANDROID_NDK__) +#include "lldb/Host/android/HostInfoAndroid.h" +#define HOST_INFO_TYPE HostInfoAndroid +#else #include "lldb/Host/linux/HostInfoLinux.h" #define HOST_INFO_TYPE HostInfoLinux +#endif #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include "lldb/Host/freebsd/HostInfoFreeBSD.h" #define HOST_INFO_TYPE HostInfoFreeBSD Index: include/lldb/Host/android/HostInfoAndroid.h =================================================================== --- /dev/null +++ include/lldb/Host/android/HostInfoAndroid.h @@ -0,0 +1,33 @@ +//===-- HostInfoAndroid.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_Host_android_HostInfoAndroid_h_ +#define lldb_Host_android_HostInfoAndroid_h_ + +#include "lldb/Host/linux/HostInfoLinux.h" + +namespace lldb_private +{ + +class HostInfoAndroid : public HostInfoLinux +{ + friend class HostInfoBase; + + private: + // Static class, unconstructable. + HostInfoAndroid(); + ~HostInfoAndroid(); + + protected: + static void ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64); +}; + +} // end of namespace lldb_private + +#endif // #ifndef lldb_Host_android_HostInfoAndroid_h_ Index: include/lldb/Host/android/ProcessLauncherAndroid.h =================================================================== --- /dev/null +++ include/lldb/Host/android/ProcessLauncherAndroid.h @@ -0,0 +1,26 @@ +//===-- ProcessLauncherAndroid.h --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_Host_android_ProcessLauncherAndroid_h_ +#define lldb_Host_android_ProcessLauncherAndroid_h_ + +#include "lldb/Host/ProcessLauncher.h" + +namespace lldb_private +{ + +class ProcessLauncherAndroid : public ProcessLauncher +{ + public: + virtual HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error); +}; + +} // end of namespace lldb_private + +#endif Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -740,6 +740,10 @@ 6D55B2901A8A806200A70529 /* GDBRemoteCommunicationServerCommon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D55B28D1A8A806200A70529 /* GDBRemoteCommunicationServerCommon.cpp */; }; 6D55B2911A8A806200A70529 /* GDBRemoteCommunicationServerLLGS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D55B28E1A8A806200A70529 /* GDBRemoteCommunicationServerLLGS.cpp */; }; 6D55B2921A8A806200A70529 /* GDBRemoteCommunicationServerPlatform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D55B28F1A8A806200A70529 /* GDBRemoteCommunicationServerPlatform.cpp */; }; + 6D55BAED1A8CD0A800A70529 /* PlatformAndroid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D55BAE91A8CD08C00A70529 /* PlatformAndroid.cpp */; }; + 6D55BAEE1A8CD0B200A70529 /* PlatformAndroidRemoteGDBServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D55BAEB1A8CD08C00A70529 /* PlatformAndroidRemoteGDBServer.cpp */; }; + 6D55BAEF1A8CD0B700A70529 /* PlatformAndroid.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D55BAEA1A8CD08C00A70529 /* PlatformAndroid.h */; }; + 6D55BAF01A8CD0BD00A70529 /* PlatformAndroidRemoteGDBServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D55BAEC1A8CD08C00A70529 /* PlatformAndroidRemoteGDBServer.h */; }; 8C2D6A53197A1EAF006989C9 /* MemoryHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2D6A52197A1EAF006989C9 /* MemoryHistory.cpp */; }; 8C2D6A5E197A250F006989C9 /* MemoryHistoryASan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */; }; 8CCB017E19BA28A80009FD44 /* ThreadCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CCB017A19BA283D0009FD44 /* ThreadCollection.cpp */; }; @@ -2357,6 +2361,16 @@ 6D55B2931A8A808400A70529 /* GDBRemoteCommunicationServerCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDBRemoteCommunicationServerCommon.h; sourceTree = ""; }; 6D55B2941A8A808400A70529 /* GDBRemoteCommunicationServerLLGS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDBRemoteCommunicationServerLLGS.h; sourceTree = ""; }; 6D55B2951A8A808400A70529 /* GDBRemoteCommunicationServerPlatform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GDBRemoteCommunicationServerPlatform.h; sourceTree = ""; }; + 6D55BAE01A8CD03D00A70529 /* HostInfoAndroid.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = HostInfoAndroid.cpp; path = source/Host/android/HostInfoAndroid.cpp; sourceTree = ""; }; + 6D55BAE11A8CD03D00A70529 /* ProcessLauncherAndroid.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ProcessLauncherAndroid.cpp; path = source/Host/android/ProcessLauncherAndroid.cpp; sourceTree = ""; }; + 6D55BAE21A8CD06000A70529 /* Android.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Android.h; path = include/lldb/Host/android/Android.h; sourceTree = ""; }; + 6D55BAE31A8CD06000A70529 /* Config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Config.h; path = include/lldb/Host/android/Config.h; sourceTree = ""; }; + 6D55BAE41A8CD06000A70529 /* HostInfoAndroid.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = HostInfoAndroid.h; path = include/lldb/Host/android/HostInfoAndroid.h; sourceTree = ""; }; + 6D55BAE51A8CD06000A70529 /* ProcessLauncherAndroid.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ProcessLauncherAndroid.h; path = include/lldb/Host/android/ProcessLauncherAndroid.h; sourceTree = ""; }; + 6D55BAE91A8CD08C00A70529 /* PlatformAndroid.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PlatformAndroid.cpp; sourceTree = ""; }; + 6D55BAEA1A8CD08C00A70529 /* PlatformAndroid.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PlatformAndroid.h; sourceTree = ""; }; + 6D55BAEB1A8CD08C00A70529 /* PlatformAndroidRemoteGDBServer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PlatformAndroidRemoteGDBServer.cpp; sourceTree = ""; }; + 6D55BAEC1A8CD08C00A70529 /* PlatformAndroidRemoteGDBServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PlatformAndroidRemoteGDBServer.h; sourceTree = ""; }; 8C2D6A52197A1EAF006989C9 /* MemoryHistory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MemoryHistory.cpp; path = source/Target/MemoryHistory.cpp; sourceTree = ""; }; 8C2D6A54197A1EBE006989C9 /* MemoryHistory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MemoryHistory.h; path = include/lldb/Target/MemoryHistory.h; sourceTree = ""; }; 8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryHistoryASan.cpp; sourceTree = ""; }; @@ -4255,6 +4269,7 @@ 26BC7DD010F1B7C100F91463 /* Host */ = { isa = PBXGroup; children = ( + 6D55B29B1A8CCFF000A70529 /* android */, 33E5E8451A6736D30024ED68 /* StringConvert.h */, 69A01E1A1236C5D400C660B5 /* common */, 3FDFE53919A29399009756A7 /* freebsd */, @@ -4563,6 +4578,7 @@ 26C5577E132575B6008FD8FE /* Platform */ = { isa = PBXGroup; children = ( + 6D55BAE61A8CD08C00A70529 /* Android */, 2694E99814FC0BB30076DE67 /* FreeBSD */, 264A97BC133918A30017F0BE /* GDB Server */, 23042D0F1976C9D800621B2C /* Kalimba */, @@ -4930,6 +4946,30 @@ path = source/Host/common; sourceTree = ""; }; + 6D55B29B1A8CCFF000A70529 /* android */ = { + isa = PBXGroup; + children = ( + 6D55BAE21A8CD06000A70529 /* Android.h */, + 6D55BAE31A8CD06000A70529 /* Config.h */, + 6D55BAE41A8CD06000A70529 /* HostInfoAndroid.h */, + 6D55BAE51A8CD06000A70529 /* ProcessLauncherAndroid.h */, + 6D55BAE01A8CD03D00A70529 /* HostInfoAndroid.cpp */, + 6D55BAE11A8CD03D00A70529 /* ProcessLauncherAndroid.cpp */, + ); + name = android; + sourceTree = ""; + }; + 6D55BAE61A8CD08C00A70529 /* Android */ = { + isa = PBXGroup; + children = ( + 6D55BAE91A8CD08C00A70529 /* PlatformAndroid.cpp */, + 6D55BAEA1A8CD08C00A70529 /* PlatformAndroid.h */, + 6D55BAEB1A8CD08C00A70529 /* PlatformAndroidRemoteGDBServer.cpp */, + 6D55BAEC1A8CD08C00A70529 /* PlatformAndroidRemoteGDBServer.h */, + ); + path = Android; + sourceTree = ""; + }; 8C2D6A58197A1FB9006989C9 /* MemoryHistory */ = { isa = PBXGroup; children = ( @@ -5232,6 +5272,7 @@ 260CC63415D04377002BF2E0 /* OptionValueFileSpec.h in Headers */, 26CFDCA11861638D000E63E5 /* Editline.h in Headers */, 26BC17B018C7F4CB00D2196D /* RegisterContextPOSIXCore_x86_64.h in Headers */, + 6D55BAF01A8CD0BD00A70529 /* PlatformAndroidRemoteGDBServer.h in Headers */, AF9B8F34182DB52900DA866F /* SystemRuntimeMacOSX.h in Headers */, 26474CB518D0CB180073DEBA /* RegisterContextLinux_x86_64.h in Headers */, 26D1804716CEE12C00EDFB5B /* TimeSpecTimeout.h in Headers */, @@ -5247,6 +5288,7 @@ 26D1804516CEE12500EDFB5B /* KQueue.h in Headers */, AF77E0A21A033D360096C0EA /* RegisterContextFreeBSD_powerpc.h in Headers */, 260CC63715D04377002BF2E0 /* OptionValueSInt64.h in Headers */, + 6D55BAEF1A8CD0B700A70529 /* PlatformAndroid.h in Headers */, AF061F8C182C980000B6A19C /* HistoryUnwind.h in Headers */, 264A58EC1A7DBC8C00A6B1B0 /* OptionValueFormatEntity.h in Headers */, 260CC63815D04377002BF2E0 /* OptionValueString.h in Headers */, @@ -5879,6 +5921,7 @@ 2689003713353E0400698AC0 /* DataBufferMemoryMap.cpp in Sources */, 2689003813353E0400698AC0 /* DataExtractor.cpp in Sources */, 2689003913353E0400698AC0 /* Debugger.cpp in Sources */, + 6D55BAEE1A8CD0B200A70529 /* PlatformAndroidRemoteGDBServer.cpp in Sources */, 2689003A13353E0400698AC0 /* Disassembler.cpp in Sources */, 236124A51986B4E2004EFC37 /* Socket.cpp in Sources */, 3FDFDDBF199D345E009756A7 /* FileCache.cpp in Sources */, @@ -6082,6 +6125,7 @@ 268900F013353E6F00698AC0 /* Process.cpp in Sources */, 26BC17AD18C7F4CB00D2196D /* RegisterContextPOSIXCore_mips64.cpp in Sources */, 268900F113353E6F00698AC0 /* RegisterContext.cpp in Sources */, + 6D55BAED1A8CD0A800A70529 /* PlatformAndroid.cpp in Sources */, 268900F213353E6F00698AC0 /* SectionLoadList.cpp in Sources */, 942AFF0519F84ABF007B43B4 /* LibCxxVector.cpp in Sources */, 268900F313353E6F00698AC0 /* StackFrame.cpp in Sources */, Index: source/Host/CMakeLists.txt =================================================================== --- source/Host/CMakeLists.txt +++ source/Host/CMakeLists.txt @@ -71,9 +71,14 @@ posix/HostProcessPosix.cpp posix/HostThreadPosix.cpp posix/PipePosix.cpp - posix/ProcessLauncherPosix.cpp ) + if (NOT __ANDROID_NDK__) + add_host_subdirectory(posix + posix/ProcessLauncherPosix.cpp + ) + endif() + if (CMAKE_SYSTEM_NAME MATCHES "Darwin") include_directories(SYSTEM ${LIBXML2_INCLUDE_DIR}) add_host_subdirectory(macosx @@ -93,6 +98,8 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "Linux") if (__ANDROID_NDK__) add_host_subdirectory(android + android/HostInfoAndroid.cpp + android/ProcessLauncherAndroid.cpp linux/Host.cpp linux/HostInfoLinux.cpp linux/HostThreadLinux.cpp Index: source/Host/android/HostInfoAndroid.cpp =================================================================== --- /dev/null +++ source/Host/android/HostInfoAndroid.cpp @@ -0,0 +1,28 @@ +//===-- HostInfoAndroid.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/android/HostInfoAndroid.h" +#include "lldb/Host/linux/HostInfoLinux.h" + +using namespace lldb_private; + +void +HostInfoAndroid::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64) +{ + HostInfoLinux::ComputeHostArchitectureSupport(arch_32, arch_64); + + if (arch_32.IsValid()) + { + arch_32.GetTriple().setEnvironment(llvm::Triple::Android); + } + if (arch_64.IsValid()) + { + arch_64.GetTriple().setEnvironment(llvm::Triple::Android); + } +} Index: source/Host/android/ProcessLauncherAndroid.cpp =================================================================== --- /dev/null +++ source/Host/android/ProcessLauncherAndroid.cpp @@ -0,0 +1,59 @@ +//===-- ProcessLauncherAndroid.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/Host.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/android/ProcessLauncherAndroid.h" + +#include "lldb/Target/ProcessLaunchInfo.h" + +#include + +using namespace lldb; +using namespace lldb_private; + +HostProcess +ProcessLauncherAndroid::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) +{ + // TODO: Handle other launch parameters specified in launc_info + + char exe_path[PATH_MAX]; + launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path)); + + const size_t err_len = 1024; + char err_str[err_len]; + + lldb::pid_t pid = ::fork (); + if (pid < 0) + { + // Fork failed + error.SetErrorStringWithFormat("Fork failed with error message: %s", strerror(errno)); + return HostProcess(LLDB_INVALID_PROCESS_ID); + } + else if (pid == 0) + { + // Child process + const char **argv = launch_info.GetArguments().GetConstArgumentVector(); + const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector(); + const char *working_dir = launch_info.GetWorkingDirectory(); + + if (working_dir != nullptr && working_dir[0]) + { + if (::chdir(working_dir) != 0) + exit(-1); + } + + execve(argv[0], + const_cast(argv), + const_cast(envp)); + exit(-1); + } + + return HostProcess(pid); +} Index: source/Host/common/Host.cpp =================================================================== --- source/Host/common/Host.cpp +++ source/Host/common/Host.cpp @@ -64,6 +64,8 @@ #if defined(_WIN32) #include "lldb/Host/windows/ProcessLauncherWindows.h" +#elif defined(__ANDROID__) || defined(__ANDROID_NDK__) +#include "lldb/Host/android/ProcessLauncherAndroid.h" #else #include "lldb/Host/posix/ProcessLauncherPosix.h" #endif @@ -671,13 +673,13 @@ // systems #if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__) +#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__) // this method needs to be visible to macosx/Host.cpp and // common/Host.cpp. short Host::GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) { -#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__) short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; #if defined (__APPLE__) @@ -720,17 +722,12 @@ #endif #endif // #if defined (__APPLE__) return flags; -#else - assert(false && "Host::GetPosixspawnFlags() not supported on Android"); - return 0; -#endif } Error Host::LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &launch_info, lldb::pid_t &pid) { Error error; -#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__) Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS)); posix_spawnattr_t attr; @@ -920,9 +917,6 @@ } #endif } -#else - error.SetErrorString("Host::LaunchProcessPosixSpawn() not supported on Android"); -#endif return error; } @@ -930,7 +924,6 @@ bool Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, Log *log, Error &error) { -#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__) if (info == NULL) return false; @@ -993,12 +986,9 @@ break; } return error.Success(); -#else - error.SetErrorString("Host::AddPosixSpawnFileAction() not supported on Android"); - return false; -#endif } -#endif // LaunchProcedssPosixSpawn: Apple, Linux, FreeBSD and other GLIBC systems +#endif // !defined(__ANDROID__) && !defined(__ANDROID_NDK__) +#endif // defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || defined(__NetBSD__) || defined(_WIN32) // The functions below implement process launching via posix_spawn() for Linux, @@ -1010,6 +1000,8 @@ std::unique_ptr delegate_launcher; #if defined(_WIN32) delegate_launcher.reset(new ProcessLauncherWindows()); +#elif defined(__ANDROID__) || defined(__ANDROID_NDK__) + delegate_launcher.reset(new ProcessLauncherAndroid()); #else delegate_launcher.reset(new ProcessLauncherPosix()); #endif Index: source/Plugins/Platform/Android/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/Platform/Android/CMakeLists.txt @@ -0,0 +1,6 @@ +set(LLVM_NO_RTTI 1) + +add_lldb_library(lldbPluginPlatformAndroid + PlatformAndroid.cpp + PlatformAndroidRemoteGDBServer.cpp + ) Index: source/Plugins/Platform/Android/Makefile =================================================================== --- /dev/null +++ source/Plugins/Platform/Android/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/Platform/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 := lldbPluginPlatformAndroid +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile Index: source/Plugins/Platform/Android/PlatformAndroid.h =================================================================== --- /dev/null +++ source/Plugins/Platform/Android/PlatformAndroid.h @@ -0,0 +1,68 @@ +//===-- PlatformAndroid.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_PlatformAndroid_h_ +#define liblldb_PlatformAndroid_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "Plugins/Platform/Linux/PlatformLinux.h" + +namespace lldb_private { + + class PlatformAndroid : public PlatformLinux + { + public: + static void + Initialize (); + + static void + Terminate (); + + PlatformAndroid (); + + virtual + ~PlatformAndroid(); + + //------------------------------------------------------------ + // lldb_private::PluginInterface functions + //------------------------------------------------------------ + static lldb::PlatformSP + CreateInstance (bool force, const lldb_private::ArchSpec *arch); + + static lldb_private::ConstString + GetPluginNameStatic (); + + static const char * + GetPluginDescriptionStatic (); + + lldb_private::ConstString + GetPluginName() override; + + uint32_t + GetPluginVersion() override + { + return 1; + } + + //------------------------------------------------------------ + // lldb_private::Platform functions + //------------------------------------------------------------ + + lldb_private::Error + ConnectRemote (lldb_private::Args& args) override; + + private: + DISALLOW_COPY_AND_ASSIGN (PlatformAndroid); + }; +} // namespace lldb_private + +#endif // liblldb_PlatformAndroid_h_ Index: source/Plugins/Platform/Android/PlatformAndroid.cpp =================================================================== --- /dev/null +++ source/Plugins/Platform/Android/PlatformAndroid.cpp @@ -0,0 +1,156 @@ +//===-- PlatformAndroid.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 +// C++ Includes +// Other libraries and framework includes +#include "lldb/Core/Log.h" +#include "lldb/Core/PluginManager.h" + +// Project includes +#include "PlatformAndroid.h" +#include "PlatformAndroidRemoteGDBServer.h" + +using namespace lldb; +using namespace lldb_private; + +static uint32_t g_initialize_count = 0; + +void +PlatformAndroid::Initialize () +{ + if (g_initialize_count++ == 0) + { + PluginManager::RegisterPlugin (PlatformAndroid::GetPluginNameStatic(), + PlatformAndroid::GetPluginDescriptionStatic(), + PlatformAndroid::CreateInstance); + } +} + +void +PlatformAndroid::Terminate () +{ + if (g_initialize_count > 0) + { + if (--g_initialize_count == 0) + { + PluginManager::UnregisterPlugin (PlatformAndroid::CreateInstance); + } + } +} + +PlatformSP +PlatformAndroid::CreateInstance (bool force, const ArchSpec *arch) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); + if (log) + { + const char *arch_name; + if (arch && arch->GetArchitectureName ()) + arch_name = arch->GetArchitectureName (); + else + arch_name = ""; + + const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : ""; + + log->Printf ("PlatformAndroid::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr); + } + + bool create = force; + if (create == false && arch && arch->IsValid()) + { + const llvm::Triple &triple = arch->GetTriple(); + switch (triple.getVendor()) + { + case llvm::Triple::PC: + create = true; + break; + +#if defined(__ANDROID__) + // Only accept "unknown" for the vendor if the host is android and + // it "unknown" wasn't specified (it was just returned because it + // was NOT specified_ + case llvm::Triple::VendorType::UnknownVendor: + create = !arch->TripleVendorWasSpecified(); + break; +#endif + default: + break; + } + + if (create) + { + switch (triple.getOS()) + { + case llvm::Triple::Linux: + break; + +#if defined(__ANDROID__) + // Only accept "unknown" for the OS if the host is android and + // it "unknown" wasn't specified (it was just returned because it + // was NOT specified) + case llvm::Triple::OSType::UnknownOS: + create = !arch->TripleOSWasSpecified(); + break; +#endif + default: + create = false; + break; + } + } + } + + if (create) + { + if (log) + log->Printf ("PlatformAndroid::%s() creating remote-android platform", __FUNCTION__); + return PlatformSP(new PlatformAndroid()); + } + + if (log) + log->Printf ("PlatformAndroid::%s() aborting creation of remote-android platform", __FUNCTION__); + + return PlatformSP(); +} + +PlatformAndroid::PlatformAndroid () : + PlatformLinux(false) // Platform android is always a remote target +{ +} + +PlatformAndroid::~PlatformAndroid() +{ +} + +lldb_private::ConstString +PlatformAndroid::GetPluginNameStatic () +{ + static ConstString g_remote_name("remote-android"); + return g_remote_name; +} + +const char * +PlatformAndroid::GetPluginDescriptionStatic () +{ + return "Remote Android user platform plug-in."; +} + +lldb_private::ConstString +PlatformAndroid::GetPluginName() +{ + return GetPluginNameStatic(); +} + +Error +PlatformAndroid::ConnectRemote (Args& args) +{ + if (!m_remote_platform_sp) + m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer()); + return PlatformLinux::ConnectRemote (args); +} Index: source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h =================================================================== --- /dev/null +++ source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h @@ -0,0 +1,50 @@ +//===-- PlatformAndroidRemoteGDBServer.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_PlatformAndroidRemoteGDBServer_h_ +#define liblldb_PlatformAndroidRemoteGDBServer_h_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h" + +class PlatformAndroidRemoteGDBServer : public PlatformRemoteGDBServer +{ +public: + PlatformAndroidRemoteGDBServer (); + + virtual + ~PlatformAndroidRemoteGDBServer (); + + lldb_private::Error + ConnectRemote (lldb_private::Args& args) override; + + lldb_private::Error + DisconnectRemote () override; + +protected: + std::map> m_port_forwards; + + uint16_t + LaunchGDBserverAndGetPort (lldb::pid_t &pid) override; + + bool + KillSpawnedProcess (lldb::pid_t pid) override; + +private: + DISALLOW_COPY_AND_ASSIGN (PlatformAndroidRemoteGDBServer); + +}; + +#endif // liblldb_PlatformAndroidRemoteGDBServer_h_ Index: source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp =================================================================== --- /dev/null +++ source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp @@ -0,0 +1,224 @@ +//===-- PlatformAndroidRemoteGDBServer.cpp ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Other libraries and framework includes +#include "lldb/Core/Error.h" +#include "lldb/Host/ConnectionFileDescriptor.h" +#include "llvm/ADT/StringRef.h" + +// Project includes +#include "PlatformAndroidRemoteGDBServer.h" +#include "Utility/UriParser.h" + +using namespace lldb; +using namespace lldb_private; + +static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform +static const uint32_t g_adb_timeout = 10000; // 10 ms + +static void +SendMessageToAdb (Connection& conn, const std::string& packet, Error& error) +{ + ConnectionStatus status; + + char length_buffer[5]; + snprintf (length_buffer, sizeof (length_buffer), "%04zx", packet.size()); + + conn.Write (length_buffer, 4, status, &error); + if (error.Fail ()) + return; + + conn.Write (packet.c_str(), packet.size(), status, &error); +} + +static std::string +ReadMessageFromAdb (Connection& conn, bool has_okay, Error& error) +{ + ConnectionStatus status; + + char buffer[5]; + buffer[4] = 0; + + if (has_okay) + { + conn.Read (buffer, 4, g_adb_timeout, status, &error); + if (error.Fail ()) + return ""; + + if (strncmp (buffer, "OKAY", 4) != 0) + { + error.SetErrorStringWithFormat ("\"OKAY\" expected from adb, received: \"%s\"", buffer); + return ""; + } + } + + conn.Read (buffer, 4, g_adb_timeout, status, &error); + if (error.Fail()) + return ""; + + size_t packet_len = 0; + sscanf(buffer, "%zx", &packet_len); + std::string result(packet_len, 0); + conn.Read (&result[0], packet_len, g_adb_timeout, status, &error); + if (error.Fail ()) + return ""; + + return result; +} + +static Error +ForwardPortWithAdb (uint16_t port, std::string& device_id) +{ + Error error; + + { + // Fetch the device list from ADB and if only 1 device found then use that device + // TODO: Handle the case when more device is available + std::unique_ptr conn (new ConnectionFileDescriptor ()); + if (conn->Connect ("connect://localhost:5037", &error) != eConnectionStatusSuccess) + return error; + + SendMessageToAdb (*conn, "host:devices", error); + if (error.Fail ()) + return error; + std::string in_buffer = ReadMessageFromAdb (*conn, true, error); + + llvm::StringRef deviceList(in_buffer); + std::pair devices = deviceList.split ('\n'); + if (devices.first.size () == 0 || devices.second.size () > 0) + { + error.SetErrorString ("Wrong number of devices returned from ADB"); + return error; + } + + device_id = devices.first.split ('\t').first; + } + + { + // Forward the port to the (only) connected device + std::unique_ptr conn (new ConnectionFileDescriptor ()); + if (conn->Connect ("connect://localhost:5037", &error) != eConnectionStatusSuccess) + return error; + + char port_buffer[32]; + snprintf (port_buffer, sizeof (port_buffer), "tcp:%d;tcp:%d", port, port); + + std::string out_buffer = "host-serial:" + device_id + ":forward:" + port_buffer; + SendMessageToAdb (*conn, out_buffer, error); + if (error.Fail ()) + return error; + + std::string in_buffer = ReadMessageFromAdb (*conn, false, error); + if (in_buffer != "OKAY") + error.SetErrorString (in_buffer.c_str ()); + } + + return error; +} + +static Error +DeleteForwardPortWithAdb (uint16_t port, const std::string& device_id) +{ + Error error; + + std::unique_ptr conn (new ConnectionFileDescriptor ()); + if (conn->Connect ("connect://localhost:5037", &error) != eConnectionStatusSuccess) + return error; + + char port_buffer[16]; + snprintf (port_buffer, sizeof (port_buffer), "tcp:%d", port); + + std::string out_buffer = "host-serial:" + device_id + ":killforward:" + port_buffer; + SendMessageToAdb (*conn, out_buffer, error); + if (error.Fail ()) + return error; + + std::string in_buffer = ReadMessageFromAdb (*conn, true, error); + if (in_buffer != "OKAY") + error.SetErrorString (in_buffer.c_str ()); + + return error; +} + +PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer () +{ +} + +PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer () +{ + for (const auto& it : m_port_forwards) + { + DeleteForwardPortWithAdb (it.second.first, it.second.second); + } +} + +uint16_t +PlatformAndroidRemoteGDBServer::LaunchGDBserverAndGetPort (lldb::pid_t &pid) +{ + uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort (pid, "127.0.0.1"); + if (port == 0) + return port; + + std::string device_id; + Error error = ForwardPortWithAdb (port, device_id); + if (error.Fail ()) + return 0; + + m_port_forwards[pid] = std::make_pair (port, device_id); + + return port; +} + +bool +PlatformAndroidRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid) +{ + auto it = m_port_forwards.find (pid); + if (it != m_port_forwards.end ()) + { + DeleteForwardPortWithAdb (it->second.first, it->second.second); + m_port_forwards.erase (it); + } + + return m_gdb_client.KillSpawnedProcess (pid); +} + +Error +PlatformAndroidRemoteGDBServer::ConnectRemote (Args& args) +{ + if (args.GetArgumentCount () != 1) + return Error ("\"platform connect\" takes a single argument: "); + + int port; + std::string scheme, host, path; + const char *url = args.GetArgumentAtIndex (0); + if (!UriParser::Parse (url, scheme, host, port, path)) + return Error ("invalid uri"); + + std::string device_id; + Error error = ForwardPortWithAdb (port, device_id); + if (error.Fail ()) + return error; + + m_port_forwards[g_remote_platform_pid] = std::make_pair (port, device_id); + + return PlatformRemoteGDBServer::ConnectRemote (args); +} + +Error +PlatformAndroidRemoteGDBServer::DisconnectRemote () +{ + auto it = m_port_forwards.find (g_remote_platform_pid); + if (it != m_port_forwards.end ()) + { + DeleteForwardPortWithAdb (it->second.first, it->second.second); + m_port_forwards.erase (it); + } + + return PlatformRemoteGDBServer::DisconnectRemote (); +} Index: source/Plugins/Platform/CMakeLists.txt =================================================================== --- source/Plugins/Platform/CMakeLists.txt +++ source/Plugins/Platform/CMakeLists.txt @@ -11,3 +11,4 @@ add_subdirectory(POSIX) add_subdirectory(gdb-server) add_subdirectory(Kalimba) +add_subdirectory(Android) Index: source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h =================================================================== --- source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -217,6 +217,15 @@ std::string m_platform_description; // After we connect we can get a more complete description of what we are connected to std::string m_platform_hostname; + // Launch the lldb-gdbserver on the remote host and return the port it is listening on or 0 on + // failure. Subclasses should override this method if they want to do extra actions before or + // after launching the lldb-gdbserver. + virtual uint16_t + LaunchGDBserverAndGetPort (lldb::pid_t &pid); + + virtual bool + KillSpawnedProcess (lldb::pid_t pid); + private: DISALLOW_COPY_AND_ASSIGN (PlatformRemoteGDBServer); Index: source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp =================================================================== --- source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -522,7 +522,7 @@ Error PlatformRemoteGDBServer::KillProcess (const lldb::pid_t pid) { - if (!m_gdb_client.KillSpawnedProcess(pid)) + if (!KillSpawnedProcess(pid)) return Error("failed to kill remote spawned process"); return Error(); } @@ -539,22 +539,8 @@ if (IsConnected()) { lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; - ArchSpec remote_arch = GetRemoteSystemArchitecture(); - llvm::Triple &remote_triple = remote_arch.GetTriple(); - uint16_t port = 0; - if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS) - { - // When remote debugging to iOS, we use a USB mux that always talks - // to localhost, so we will need the remote debugserver to accept connections - // only from localhost, no matter what our current hostname is - port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "127.0.0.1"); - } - else - { - // All other hosts should use their actual hostname - port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, NULL); - } - + uint16_t port = LaunchGDBserverAndGetPort(debugserver_pid); + if (port == 0) { error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ()); @@ -605,7 +591,7 @@ else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) { printf ("error: connect remote failed (%s)\n", error.AsCString()); - m_gdb_client.KillSpawnedProcess(debugserver_pid); + KillSpawnedProcess(debugserver_pid); } } } @@ -617,7 +603,32 @@ } } return process_sp; - + +} + +uint16_t +PlatformRemoteGDBServer::LaunchGDBserverAndGetPort (lldb::pid_t &pid) +{ + ArchSpec remote_arch = GetRemoteSystemArchitecture (); + llvm::Triple &remote_triple = remote_arch.GetTriple (); + if (remote_triple.getVendor () == llvm::Triple::Apple && remote_triple.getOS () == llvm::Triple::IOS) + { + // When remote debugging to iOS, we use a USB mux that always talks + // to localhost, so we will need the remote debugserver to accept connections + // only from localhost, no matter what our current hostname is + return m_gdb_client.LaunchGDBserverAndGetPort (pid, "127.0.0.1"); + } + else + { + // All other hosts should use their actual hostname + return m_gdb_client.LaunchGDBserverAndGetPort (pid, NULL); + } +} + +bool +PlatformRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid) +{ + return m_gdb_client.KillSpawnedProcess (pid); } lldb::ProcessSP @@ -632,22 +643,8 @@ if (IsConnected()) { lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; - ArchSpec remote_arch = GetRemoteSystemArchitecture(); - llvm::Triple &remote_triple = remote_arch.GetTriple(); - uint16_t port = 0; - if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS) - { - // When remote debugging to iOS, we use a USB mux that always talks - // to localhost, so we will need the remote debugserver to accept connections - // only from localhost, no matter what our current hostname is - port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "127.0.0.1"); - } - else - { - // All other hosts should use their actual hostname - port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, NULL); - } - + uint16_t port = LaunchGDBserverAndGetPort(debugserver_pid); + if (port == 0) { error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ()); @@ -700,7 +697,7 @@ if (error.Fail() && debugserver_pid != LLDB_INVALID_PROCESS_ID) { - m_gdb_client.KillSpawnedProcess(debugserver_pid); + KillSpawnedProcess(debugserver_pid); } } } Index: source/lldb.cpp =================================================================== --- source/lldb.cpp +++ source/lldb.cpp @@ -43,6 +43,7 @@ #include "Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h" #include "Plugins/ObjectFile/ELF/ObjectFileELF.h" #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" +#include "Plugins/Platform/Android/PlatformAndroid.h" #include "Plugins/Platform/FreeBSD/PlatformFreeBSD.h" #include "Plugins/Platform/Linux/PlatformLinux.h" #include "Plugins/Platform/POSIX/PlatformPOSIX.h" @@ -173,6 +174,7 @@ PlatformLinux::Initialize(); PlatformWindows::Initialize(); PlatformKalimba::Initialize(); + PlatformAndroid::Initialize(); SymbolFileDWARFDebugMap::Initialize(); ItaniumABILanguageRuntime::Initialize(); #ifndef LLDB_DISABLE_PYTHON @@ -269,6 +271,7 @@ PlatformLinux::Terminate(); PlatformWindows::Terminate(); PlatformKalimba::Terminate(); + PlatformAndroid::Terminate(); SymbolFileDWARFDebugMap::Terminate(); ItaniumABILanguageRuntime::Terminate(); #ifndef LLDB_DISABLE_PYTHON