diff options
Diffstat (limited to 'source/Plugins/Platform')
-rw-r--r-- | source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h | 13 | ||||
-rw-r--r-- | source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp | 685 | ||||
-rw-r--r-- | source/Plugins/Platform/NetBSD/PlatformNetBSD.h | 177 | ||||
-rw-r--r-- | source/Plugins/Platform/POSIX/PlatformPOSIX.cpp | 185 | ||||
-rw-r--r-- | source/Plugins/Platform/POSIX/PlatformPOSIX.h | 60 | ||||
-rw-r--r-- | source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp | 125 | ||||
-rw-r--r-- | source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h | 33 |
7 files changed, 1202 insertions, 76 deletions
diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h index 67156e6ae37b..d1bfc438a341 100644 --- a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h +++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h @@ -22,6 +22,9 @@ namespace platform_freebsd { class PlatformFreeBSD : public Platform { public: + PlatformFreeBSD(bool is_host); + + ~PlatformFreeBSD() override; //------------------------------------------------------------ // Class functions @@ -42,14 +45,6 @@ namespace platform_freebsd { GetDescriptionStatic (bool is_host); //------------------------------------------------------------ - // Class Methods - //------------------------------------------------------------ - PlatformFreeBSD (bool is_host); - - virtual - ~PlatformFreeBSD(); - - //------------------------------------------------------------ // lldb_private::PluginInterface functions //------------------------------------------------------------ ConstString @@ -179,4 +174,4 @@ namespace platform_freebsd { } // namespace platform_freebsd } // namespace lldb_private -#endif // liblldb_PlatformFreeBSD_h_ +#endif // liblldb_PlatformFreeBSD_h_ diff --git a/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp b/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp new file mode 100644 index 000000000000..2979d1e438b7 --- /dev/null +++ b/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp @@ -0,0 +1,685 @@ +//===-- PlatformNetBSD.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PlatformNetBSD.h" +#include "lldb/Host/Config.h" + +// C Includes +#include <stdio.h> +#ifndef LLDB_DISABLE_POSIX +#include <sys/utsname.h> +#endif + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Breakpoint/BreakpointSite.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Target/Process.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::platform_netbsd; + +PlatformSP +PlatformNetBSD::CreateInstance(bool force, const ArchSpec *arch) +{ + // The only time we create an instance is when we are creating a remote + // netbsd platform + const bool is_host = false; + + bool create = force; + if (create == false && arch && arch->IsValid()) + { + const llvm::Triple &triple = arch->GetTriple(); + switch (triple.getOS()) + { + case llvm::Triple::NetBSD: + create = true; + break; + + default: + break; + } + } + if (create) + return PlatformSP(new PlatformNetBSD (is_host)); + return PlatformSP(); + +} + +ConstString +PlatformNetBSD::GetPluginNameStatic(bool is_host) +{ + if (is_host) + { + static ConstString g_host_name(Platform::GetHostPlatformName ()); + return g_host_name; + } + else + { + static ConstString g_remote_name("remote-netbsd"); + return g_remote_name; + } +} + +const char * +PlatformNetBSD::GetDescriptionStatic (bool is_host) +{ + if (is_host) + return "Local NetBSD user platform plug-in."; + else + return "Remote NetBSD user platform plug-in."; +} + +static uint32_t g_initialize_count = 0; + +void +PlatformNetBSD::Initialize () +{ + Platform::Initialize (); + + if (g_initialize_count++ == 0) + { +#if defined(__NetBSD__) + // Force a host flag to true for the default platform object. + PlatformSP default_platform_sp (new PlatformNetBSD(true)); + default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); + Platform::SetHostPlatform (default_platform_sp); +#endif + PluginManager::RegisterPlugin(PlatformNetBSD::GetPluginNameStatic(false), + PlatformNetBSD::GetDescriptionStatic(false), + PlatformNetBSD::CreateInstance); + } +} + +void +PlatformNetBSD::Terminate () +{ + if (g_initialize_count > 0 && --g_initialize_count == 0) + PluginManager::UnregisterPlugin (PlatformNetBSD::CreateInstance); + + Platform::Terminate (); +} + +bool +PlatformNetBSD::GetModuleSpec (const FileSpec& module_file_spec, + const ArchSpec& arch, + ModuleSpec &module_spec) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetModuleSpec (module_file_spec, arch, module_spec); + + return Platform::GetModuleSpec (module_file_spec, arch, module_spec); +} + +Error +PlatformNetBSD::RunShellCommand(const char *command, + const FileSpec &working_dir, + int *status_ptr, + int *signo_ptr, + std::string *command_output, + uint32_t timeout_sec) +{ + if (IsHost()) + return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec); + else + { + if (m_remote_platform_sp) + return m_remote_platform_sp->RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec); + else + return Error("unable to run a remote command without a platform"); + } +} + +Error +PlatformNetBSD::ResolveExecutable (const ModuleSpec &module_spec, + lldb::ModuleSP &exe_module_sp, + const FileSpecList *module_search_paths_ptr) +{ + Error error; + // Nothing special to do here, just use the actual file and architecture + + char exe_path[PATH_MAX]; + ModuleSpec resolved_module_spec(module_spec); + + if (IsHost()) + { + // If we have "ls" as the module_spec's file, resolve the executable location based on + // the current path variables + if (!resolved_module_spec.GetFileSpec().Exists()) + { + module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); + resolved_module_spec.GetFileSpec().SetFile(exe_path, true); + } + + if (!resolved_module_spec.GetFileSpec().Exists()) + resolved_module_spec.GetFileSpec().ResolveExecutableLocation (); + + if (resolved_module_spec.GetFileSpec().Exists()) + error.Clear(); + else + { + error.SetErrorStringWithFormat("unable to find executable for '%s'", resolved_module_spec.GetFileSpec().GetPath().c_str()); + } + } + else + { + if (m_remote_platform_sp) + { + error = GetCachedExecutable (resolved_module_spec, exe_module_sp, module_search_paths_ptr, *m_remote_platform_sp); + } + else + { + // We may connect to a process and use the provided executable (Don't use local $PATH). + + // Resolve any executable within a bundle on MacOSX + Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec()); + + if (resolved_module_spec.GetFileSpec().Exists()) + { + error.Clear(); + } + else + { + error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", resolved_module_spec.GetFileSpec().GetPath().c_str()); + } + } + } + + if (error.Success()) + { + if (resolved_module_spec.GetArchitecture().IsValid()) + { + error = ModuleList::GetSharedModule (resolved_module_spec, + exe_module_sp, + module_search_paths_ptr, + NULL, + NULL); + + if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL) + { + exe_module_sp.reset(); + error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s", + resolved_module_spec.GetFileSpec().GetPath().c_str(), + resolved_module_spec.GetArchitecture().GetArchitectureName()); + } + } + else + { + // No valid architecture was specified, ask the platform for + // the architectures that we should be using (in the correct order) + // and see if we can find a match that way + StreamString arch_names; + for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx) + { + error = ModuleList::GetSharedModule (resolved_module_spec, + exe_module_sp, + module_search_paths_ptr, + NULL, + NULL); + // Did we find an executable using one of the + if (error.Success()) + { + if (exe_module_sp && exe_module_sp->GetObjectFile()) + break; + else + error.SetErrorToGenericError(); + } + + if (idx > 0) + arch_names.PutCString (", "); + arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName()); + } + + if (error.Fail() || !exe_module_sp) + { + if (resolved_module_spec.GetFileSpec().Readable()) + { + error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s", + resolved_module_spec.GetFileSpec().GetPath().c_str(), + GetPluginName().GetCString(), + arch_names.GetString().c_str()); + } + else + { + error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str()); + } + } + } + } + + return error; +} + +// From PlatformMacOSX only +Error +PlatformNetBSD::GetFileWithUUID (const FileSpec &platform_file, + const UUID *uuid_ptr, + FileSpec &local_file) +{ + if (IsRemote()) + { + if (m_remote_platform_sp) + return m_remote_platform_sp->GetFileWithUUID (platform_file, uuid_ptr, local_file); + } + + // Default to the local case + local_file = platform_file; + return Error(); +} + + +//------------------------------------------------------------------ +/// Default Constructor +//------------------------------------------------------------------ +PlatformNetBSD::PlatformNetBSD (bool is_host) : + Platform(is_host), + m_remote_platform_sp() +{ +} + +bool +PlatformNetBSD::GetRemoteOSVersion () +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetOSVersion (m_major_os_version, + m_minor_os_version, + m_update_os_version); + return false; +} + +bool +PlatformNetBSD::GetRemoteOSBuildString (std::string &s) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetRemoteOSBuildString (s); + s.clear(); + return false; +} + +bool +PlatformNetBSD::GetRemoteOSKernelDescription (std::string &s) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetRemoteOSKernelDescription (s); + s.clear(); + return false; +} + +// Remote Platform subclasses need to override this function +ArchSpec +PlatformNetBSD::GetRemoteSystemArchitecture () +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetRemoteSystemArchitecture (); + return ArchSpec(); +} + + +const char * +PlatformNetBSD::GetHostname () +{ + if (IsHost()) + return Platform::GetHostname(); + + if (m_remote_platform_sp) + return m_remote_platform_sp->GetHostname (); + return NULL; +} + +bool +PlatformNetBSD::IsConnected () const +{ + if (IsHost()) + return true; + else if (m_remote_platform_sp) + return m_remote_platform_sp->IsConnected(); + return false; +} + +Error +PlatformNetBSD::ConnectRemote (Args& args) +{ + Error error; + if (IsHost()) + { + error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString()); + } + else + { + if (!m_remote_platform_sp) + m_remote_platform_sp = Platform::Create (ConstString("remote-gdb-server"), error); + + if (m_remote_platform_sp) + { + if (error.Success()) + { + if (m_remote_platform_sp) + { + error = m_remote_platform_sp->ConnectRemote (args); + } + else + { + error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>"); + } + } + } + else + error.SetErrorString ("failed to create a 'remote-gdb-server' platform"); + + if (error.Fail()) + m_remote_platform_sp.reset(); + } + + return error; +} + +Error +PlatformNetBSD::DisconnectRemote () +{ + Error error; + + if (IsHost()) + { + error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetPluginName().GetCString()); + } + else + { + if (m_remote_platform_sp) + error = m_remote_platform_sp->DisconnectRemote (); + else + error.SetErrorString ("the platform is not currently connected"); + } + return error; +} + +bool +PlatformNetBSD::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) +{ + bool success = false; + if (IsHost()) + { + success = Platform::GetProcessInfo (pid, process_info); + } + else if (m_remote_platform_sp) + { + success = m_remote_platform_sp->GetProcessInfo (pid, process_info); + } + return success; +} + +uint32_t +PlatformNetBSD::FindProcesses (const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) +{ + uint32_t match_count = 0; + if (IsHost()) + { + // Let the base class figure out the host details + match_count = Platform::FindProcesses (match_info, process_infos); + } + else + { + // If we are remote, we can only return results if we are connected + if (m_remote_platform_sp) + match_count = m_remote_platform_sp->FindProcesses (match_info, process_infos); + } + return match_count; +} + +const char * +PlatformNetBSD::GetUserName (uint32_t uid) +{ + // Check the cache in Platform in case we have already looked this uid up + const char *user_name = Platform::GetUserName(uid); + if (user_name) + return user_name; + + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->GetUserName(uid); + return NULL; +} + +const char * +PlatformNetBSD::GetGroupName (uint32_t gid) +{ + const char *group_name = Platform::GetGroupName(gid); + if (group_name) + return group_name; + + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->GetGroupName(gid); + return NULL; +} + + +Error +PlatformNetBSD::GetSharedModule (const ModuleSpec &module_spec, + Process* process, + ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + ModuleSP *old_module_sp_ptr, + bool *did_create_ptr) +{ + Error error; + module_sp.reset(); + + if (IsRemote()) + { + // If we have a remote platform always, let it try and locate + // the shared module first. + if (m_remote_platform_sp) + { + error = m_remote_platform_sp->GetSharedModule (module_spec, + process, + module_sp, + module_search_paths_ptr, + old_module_sp_ptr, + did_create_ptr); + } + } + + if (!module_sp) + { + // Fall back to the local platform and find the file locally + error = Platform::GetSharedModule (module_spec, + process, + module_sp, + module_search_paths_ptr, + old_module_sp_ptr, + did_create_ptr); + } + if (module_sp) + module_sp->SetPlatformFileSpec(module_spec.GetFileSpec()); + return error; +} + + +bool +PlatformNetBSD::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) +{ + if (IsHost()) + { + ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault); + if (hostArch.GetTriple().isOSNetBSD()) + { + if (idx == 0) + { + arch = hostArch; + return arch.IsValid(); + } + else if (idx == 1) + { + // If the default host architecture is 64-bit, look for a 32-bit variant + if (hostArch.IsValid() && hostArch.GetTriple().isArch64Bit()) + { + arch = HostInfo::GetArchitecture(HostInfo::eArchKind32); + return arch.IsValid(); + } + } + } + } + else + { + if (m_remote_platform_sp) + return m_remote_platform_sp->GetSupportedArchitectureAtIndex(idx, arch); + + llvm::Triple triple; + // Set the OS to NetBSD + triple.setOS(llvm::Triple::NetBSD); + // Set the architecture + switch (idx) + { + case 0: triple.setArchName("x86_64"); break; + case 1: triple.setArchName("i386"); break; + default: return false; + } + // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the vendor by + // calling triple.SetVendorName("unknown") so that it is a "unspecified unknown". + // This means when someone calls triple.GetVendorName() it will return an empty string + // which indicates that the vendor can be set when two architectures are merged + + // Now set the triple into "arch" and return true + arch.SetTriple(triple); + return true; + } + return false; +} + +void +PlatformNetBSD::GetStatus (Stream &strm) +{ +#ifndef LLDB_DISABLE_POSIX + struct ::utsname un; + + strm << " Host: "; + + ::memset(&un, 0, sizeof(utsname)); + if (::uname(&un) == -1) { + strm << "NetBSD" << '\n'; + } else { + strm << un.sysname << ' ' << un.release; + if (un.nodename[0] != '\0') + strm << " (" << un.nodename << ')'; + strm << '\n'; + + // Dump a common information about the platform status. + strm << "Host: " << un.sysname << ' ' << un.release << ' ' << un.version << '\n'; + } +#endif + + Platform::GetStatus(strm); +} + +size_t +PlatformNetBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site) +{ + ArchSpec arch = target.GetArchitecture(); + const uint8_t *trap_opcode = NULL; + size_t trap_opcode_size = 0; + + switch (arch.GetMachine()) + { + default: + assert(false && "Unhandled architecture in PlatformNetBSD::GetSoftwareBreakpointTrapOpcode()"); + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + { + static const uint8_t g_i386_opcode[] = { 0xCC }; + trap_opcode = g_i386_opcode; + trap_opcode_size = sizeof(g_i386_opcode); + } + break; + } + + if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) + return trap_opcode_size; + return 0; +} + + +void +PlatformNetBSD::CalculateTrapHandlerSymbolNames () +{ + m_trap_handlers.push_back (ConstString ("_sigtramp")); +} + +Error +PlatformNetBSD::LaunchProcess (ProcessLaunchInfo &launch_info) +{ + Error error; + if (IsHost()) + { + error = Platform::LaunchProcess (launch_info); + } + else + { + if (m_remote_platform_sp) + error = m_remote_platform_sp->LaunchProcess (launch_info); + else + error.SetErrorString ("the platform is not currently connected"); + } + return error; +} + +lldb::ProcessSP +PlatformNetBSD::Attach(ProcessAttachInfo &attach_info, + Debugger &debugger, + Target *target, + Error &error) +{ + lldb::ProcessSP process_sp; + if (IsHost()) + { + if (target == NULL) + { + TargetSP new_target_sp; + ArchSpec emptyArchSpec; + + error = debugger.GetTargetList().CreateTarget (debugger, + NULL, + emptyArchSpec, + false, + m_remote_platform_sp, + new_target_sp); + target = new_target_sp.get(); + } + else + error.Clear(); + + if (target && error.Success()) + { + debugger.GetTargetList().SetSelectedTarget(target); + // The netbsd always currently uses the GDB remote debugger plug-in + // so even when debugging locally we are debugging remotely! + // Just like the darwin plugin. + process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL); + + if (process_sp) + error = process_sp->Attach (attach_info); + } + } + else + { + if (m_remote_platform_sp) + process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error); + else + error.SetErrorString ("the platform is not currently connected"); + } + return process_sp; +} diff --git a/source/Plugins/Platform/NetBSD/PlatformNetBSD.h b/source/Plugins/Platform/NetBSD/PlatformNetBSD.h new file mode 100644 index 000000000000..b0187be99b05 --- /dev/null +++ b/source/Plugins/Platform/NetBSD/PlatformNetBSD.h @@ -0,0 +1,177 @@ +//===-- PlatformNetBSD.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_PlatformNetBSD_h_ +#define liblldb_PlatformNetBSD_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Target/Platform.h" + +namespace lldb_private { +namespace platform_netbsd { + + class PlatformNetBSD : public Platform + { + public: + PlatformNetBSD (bool is_host); + + ~PlatformNetBSD() override = default; + + //------------------------------------------------------------ + // Class functions + //------------------------------------------------------------ + static lldb::PlatformSP + CreateInstance(bool force, const ArchSpec *arch); + + static void + Initialize (); + + static void + Terminate (); + + static ConstString + GetPluginNameStatic (bool is_host); + + static const char * + GetDescriptionStatic (bool is_host); + + //------------------------------------------------------------ + // lldb_private::PluginInterface functions + //------------------------------------------------------------ + ConstString + GetPluginName() override + { + return GetPluginNameStatic (IsHost()); + } + + uint32_t + GetPluginVersion() override + { + return 1; + } + + const char * + GetDescription () override + { + return GetDescriptionStatic(IsHost()); + } + + //------------------------------------------------------------ + // lldb_private::Platform functions + //------------------------------------------------------------ + bool + GetModuleSpec(const FileSpec& module_file_spec, + const ArchSpec& arch, + ModuleSpec &module_spec) override; + + Error + RunShellCommand(const char *command, + const FileSpec &working_dir, + int *status_ptr, + int *signo_ptr, + std::string *command_output, + uint32_t timeout_sec) override; + + Error + ResolveExecutable(const ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr) override; + + size_t + GetSoftwareBreakpointTrapOpcode(Target &target, + BreakpointSite *bp_site) override; + + bool + GetRemoteOSVersion () override; + + bool + GetRemoteOSBuildString (std::string &s) override; + + bool + GetRemoteOSKernelDescription (std::string &s) override; + + // Remote Platform subclasses need to override this function + ArchSpec + GetRemoteSystemArchitecture() override; + + bool + IsConnected () const override; + + Error + ConnectRemote(Args& args) override; + + Error + DisconnectRemote() override; + + const char * + GetHostname () override; + + const char * + GetUserName (uint32_t uid) override; + + const char * + GetGroupName (uint32_t gid) override; + + bool + GetProcessInfo(lldb::pid_t pid, + ProcessInstanceInfo &proc_info) override; + + uint32_t + FindProcesses(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) override; + + Error + LaunchProcess(ProcessLaunchInfo &launch_info) override; + + lldb::ProcessSP + Attach(ProcessAttachInfo &attach_info, + Debugger &debugger, + Target *target, + Error &error) override; + + // NetBSD processes can not be launched by spawning and attaching. + bool + CanDebugProcess () override { return false; } + + // Only on PlatformMacOSX: + Error + GetFileWithUUID(const FileSpec &platform_file, + const UUID* uuid, FileSpec &local_file) override; + + Error + GetSharedModule(const ModuleSpec &module_spec, + Process* process, + lldb::ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + lldb::ModuleSP *old_module_sp_ptr, + bool *did_create_ptr) override; + + bool + GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override; + + void + GetStatus(Stream &strm) override; + + void + CalculateTrapHandlerSymbolNames () override; + + protected: + lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote netbsd OS + + private: + DISALLOW_COPY_AND_ASSIGN (PlatformNetBSD); + }; + +} // namespace platform_netbsd +} // namespace lldb_private + +#endif // liblldb_PlatformNetBSD_h_ diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index b4f841a16dec..c7564655a11b 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -19,13 +19,18 @@ #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/StreamString.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Expression/UserExpression.h" #include "lldb/Host/File.h" #include "lldb/Host/FileCache.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/ProcessLaunchInfo.h" +#include "lldb/Target/Thread.h" using namespace lldb; using namespace lldb_private; @@ -673,9 +678,12 @@ PlatformPOSIX::ConnectRemote (Args& args) if (m_options.get()) { OptionGroupOptions* options = m_options.get(); - const OptionGroupPlatformRSync* m_rsync_options = (OptionGroupPlatformRSync*)options->GetGroupWithOption('r'); - const OptionGroupPlatformSSH* m_ssh_options = (OptionGroupPlatformSSH*)options->GetGroupWithOption('s'); - const OptionGroupPlatformCaching* m_cache_options = (OptionGroupPlatformCaching*)options->GetGroupWithOption('c'); + const OptionGroupPlatformRSync *m_rsync_options = + static_cast<const OptionGroupPlatformRSync *>(options->GetGroupWithOption('r')); + const OptionGroupPlatformSSH *m_ssh_options = + static_cast<const OptionGroupPlatformSSH *>(options->GetGroupWithOption('s')); + const OptionGroupPlatformCaching *m_cache_options = + static_cast<const OptionGroupPlatformCaching *>(options->GetGroupWithOption('c')); if (m_rsync_options->m_rsync) { @@ -843,6 +851,175 @@ PlatformPOSIX::DebugProcess (ProcessLaunchInfo &launch_info, void PlatformPOSIX::CalculateTrapHandlerSymbolNames () -{ +{ m_trap_handlers.push_back (ConstString ("_sigtramp")); +} + +Error +PlatformPOSIX::EvaluateLibdlExpression(lldb_private::Process* process, + const char* expr_cstr, + const char* expr_prefix, + lldb::ValueObjectSP& result_valobj_sp) +{ + DynamicLoader *loader = process->GetDynamicLoader(); + if (loader) + { + Error error = loader->CanLoadImage(); + if (error.Fail()) + return error; + } + + ThreadSP thread_sp(process->GetThreadList().GetSelectedThread()); + if (!thread_sp) + return Error("Selected thread isn't valid"); + + StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0)); + if (!frame_sp) + return Error("Frame 0 isn't valid"); + + ExecutionContext exe_ctx; + frame_sp->CalculateExecutionContext(exe_ctx); + EvaluateExpressionOptions expr_options; + expr_options.SetUnwindOnError(true); + expr_options.SetIgnoreBreakpoints(true); + expr_options.SetExecutionPolicy(eExecutionPolicyAlways); + expr_options.SetLanguage(eLanguageTypeC_plus_plus); + + Error expr_error; + UserExpression::Evaluate(exe_ctx, + expr_options, + expr_cstr, + expr_prefix, + result_valobj_sp, + expr_error); + if (result_valobj_sp->GetError().Fail()) + return result_valobj_sp->GetError(); + return Error(); +} + +uint32_t +PlatformPOSIX::DoLoadImage(lldb_private::Process* process, + const lldb_private::FileSpec& remote_file, + lldb_private::Error& error) +{ + char path[PATH_MAX]; + remote_file.GetPath(path, sizeof(path)); + + StreamString expr; + expr.Printf(R"( + struct __lldb_dlopen_result { void *image_ptr; const char *error_str; } the_result; + the_result.image_ptr = dlopen ("%s", 2); + if (the_result.image_ptr == (void *) 0x0) + { + the_result.error_str = dlerror(); + } + else + { + the_result.error_str = (const char *) 0x0; + } + the_result; + )", + path); + const char *prefix = GetLibdlFunctionDeclarations(); + lldb::ValueObjectSP result_valobj_sp; + error = EvaluateLibdlExpression(process, expr.GetData(), prefix, result_valobj_sp); + if (error.Fail()) + return LLDB_INVALID_IMAGE_TOKEN; + + error = result_valobj_sp->GetError(); + if (error.Fail()) + return LLDB_INVALID_IMAGE_TOKEN; + + Scalar scalar; + ValueObjectSP image_ptr_sp = result_valobj_sp->GetChildAtIndex(0, true); + if (!image_ptr_sp || !image_ptr_sp->ResolveValue(scalar)) + { + error.SetErrorStringWithFormat("unable to load '%s'", path); + return LLDB_INVALID_IMAGE_TOKEN; + } + + addr_t image_ptr = scalar.ULongLong(LLDB_INVALID_ADDRESS); + if (image_ptr != 0 && image_ptr != LLDB_INVALID_ADDRESS) + return process->AddImageToken(image_ptr); + + if (image_ptr == 0) + { + ValueObjectSP error_str_sp = result_valobj_sp->GetChildAtIndex(1, true); + if (error_str_sp && error_str_sp->IsCStringContainer(true)) + { + DataBufferSP buffer_sp(new DataBufferHeap(10240,0)); + size_t num_chars = error_str_sp->ReadPointedString (buffer_sp, error, 10240).first; + if (error.Success() && num_chars > 0) + error.SetErrorStringWithFormat("dlopen error: %s", buffer_sp->GetBytes()); + else + error.SetErrorStringWithFormat("dlopen failed for unknown reasons."); + return LLDB_INVALID_IMAGE_TOKEN; + } + } + error.SetErrorStringWithFormat("unable to load '%s'", path); + return LLDB_INVALID_IMAGE_TOKEN; +} + +Error +PlatformPOSIX::UnloadImage (lldb_private::Process* process, uint32_t image_token) +{ + const addr_t image_addr = process->GetImagePtrFromToken(image_token); + if (image_addr == LLDB_INVALID_ADDRESS) + return Error("Invalid image token"); + + StreamString expr; + expr.Printf("dlclose((void *)0x%" PRIx64 ")", image_addr); + const char *prefix = GetLibdlFunctionDeclarations(); + lldb::ValueObjectSP result_valobj_sp; + Error error = EvaluateLibdlExpression(process, expr.GetData(), prefix, result_valobj_sp); + if (error.Fail()) + return error; + + if (result_valobj_sp->GetError().Fail()) + return result_valobj_sp->GetError(); + + Scalar scalar; + if (result_valobj_sp->ResolveValue(scalar)) + { + if (scalar.UInt(1)) + return Error("expression failed: \"%s\"", expr.GetData()); + process->ResetImageToken(image_token); + } + return Error(); } + +lldb::ProcessSP +PlatformPOSIX::ConnectProcess (const char* connect_url, + const char* plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Error &error) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->ConnectProcess(connect_url, + plugin_name, + debugger, + target, + error); + + return Platform::ConnectProcess(connect_url, plugin_name, debugger, target, error); +} + +const char* +PlatformPOSIX::GetLibdlFunctionDeclarations() const +{ + return R"( + extern "C" void* dlopen(const char*, int); + extern "C" void* dlsym(void*, const char*); + extern "C" int dlclose(void*); + extern "C" char* dlerror(void); + )"; +} + +size_t +PlatformPOSIX::ConnectToWaitingProcesses(Debugger& debugger, Error& error) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error); + return Platform::ConnectToWaitingProcesses(debugger, error); +} diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/source/Plugins/Platform/POSIX/PlatformPOSIX.h index 82686dcef6b0..60f6207d140b 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -12,7 +12,6 @@ // C Includes // C++ Includes - #include <memory> // Other libraries and framework includes @@ -23,11 +22,10 @@ class PlatformPOSIX : public lldb_private::Platform { public: - PlatformPOSIX (bool is_host); - - virtual - ~PlatformPOSIX(); - + PlatformPOSIX(bool is_host); + + ~PlatformPOSIX() override; + //------------------------------------------------------------ // lldb_private::Platform functions //------------------------------------------------------------ @@ -37,9 +35,8 @@ public: const lldb_private::ArchSpec& arch, lldb_private::ModuleSpec &module_spec) override; - lldb_private::OptionGroupOptions - *GetConnectionOptions( - lldb_private::CommandInterpreter &interpreter) override; + lldb_private::OptionGroupOptions* + GetConnectionOptions(lldb_private::CommandInterpreter &interpreter) override; const char * GetHostname () override; @@ -119,11 +116,11 @@ public: IsConnected () const override; lldb_private::Error - RunShellCommand(const char *command, // Shouldn't be NULL + RunShellCommand(const char *command, // Shouldn't be nullptr const lldb_private::FileSpec &working_dir, // Pass empty FileSpec 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 + int *status_ptr, // Pass nullptr if you don't want the process exit status + int *signo_ptr, // Pass nullptr if you don't want the signal that caused the process to exit + std::string *command_output, // Pass nullptr if you don't want the command output uint32_t timeout_sec) override; // Timeout in seconds to wait for shell program to finish lldb_private::Error @@ -150,13 +147,13 @@ public: lldb::ProcessSP Attach (lldb_private::ProcessAttachInfo &attach_info, lldb_private::Debugger &debugger, - lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one + lldb_private::Target *target, // Can be nullptr, if nullptr create a new target, else use existing one lldb_private::Error &error) override; lldb::ProcessSP DebugProcess (lldb_private::ProcessLaunchInfo &launch_info, lldb_private::Debugger &debugger, - lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one + lldb_private::Target *target, // Can be nullptr, if nullptr create a new target, else use existing one lldb_private::Error &error) override; std::string @@ -176,14 +173,39 @@ public: lldb_private::Error DisconnectRemote () override; + uint32_t + DoLoadImage (lldb_private::Process* process, + const lldb_private::FileSpec& remote_file, + lldb_private::Error& error) override; + + lldb_private::Error + UnloadImage (lldb_private::Process* process, uint32_t image_token) override; + + lldb::ProcessSP + ConnectProcess (const char* connect_url, + const char* plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Error &error) override; + + size_t + ConnectToWaitingProcesses(lldb_private::Debugger& debugger, lldb_private::Error& error) override; + protected: std::unique_ptr<lldb_private::OptionGroupOptions> m_options; - lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote POSIX-compliant OS - + + lldb_private::Error + EvaluateLibdlExpression(lldb_private::Process* process, + const char *expr_cstr, + const char *expr_prefix, + lldb::ValueObjectSP& result_valobj_sp); + + virtual const char* + GetLibdlFunctionDeclarations() const; + private: DISALLOW_COPY_AND_ASSIGN (PlatformPOSIX); - }; -#endif // liblldb_PlatformPOSIX_h_ +#endif // liblldb_PlatformPOSIX_h_ diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index b0e75d4f3457..f16ea017676f 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -21,6 +21,7 @@ #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSpec.h" @@ -40,23 +41,6 @@ using namespace lldb_private::platform_gdb_server; static bool g_initialized = false; -static std::string MakeGdbServerUrl( - const std::string &platform_scheme, - const std::string &platform_hostname, - uint16_t port) -{ - const char *override_scheme = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_SCHEME"); - const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME"); - const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET"); - int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0; - StreamString result; - result.Printf("%s://%s:%u", - override_scheme ? override_scheme : platform_scheme.c_str(), - override_hostname ? override_hostname : platform_hostname.c_str(), - port + port_offset); - return result.GetString(); -} - void PlatformRemoteGDBServer::Initialize () { @@ -590,9 +574,8 @@ PlatformRemoteGDBServer::DebugProcess (ProcessLaunchInfo &launch_info, if (IsConnected()) { lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; - uint16_t port = LaunchGDBserverAndGetPort(debugserver_pid); - - if (port == 0) + std::string connect_url; + if (!LaunchGDBServer(debugserver_pid, connect_url)) { error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ()); } @@ -623,8 +606,6 @@ PlatformRemoteGDBServer::DebugProcess (ProcessLaunchInfo &launch_info, if (process_sp) { - std::string connect_url = - MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port); error = process_sp->ConnectRemote (nullptr, connect_url.c_str()); // Retry the connect remote one time... if (error.Fail()) @@ -649,23 +630,36 @@ PlatformRemoteGDBServer::DebugProcess (ProcessLaunchInfo &launch_info, } -uint16_t -PlatformRemoteGDBServer::LaunchGDBserverAndGetPort (lldb::pid_t &pid) +bool +PlatformRemoteGDBServer::LaunchGDBServer (lldb::pid_t &pid, std::string &connect_url) { ArchSpec remote_arch = GetRemoteSystemArchitecture (); llvm::Triple &remote_triple = remote_arch.GetTriple (); + + uint16_t port = 0; + std::string socket_name; + bool launch_result = false; 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"); + launch_result = m_gdb_client.LaunchGDBServer ("127.0.0.1", pid, port, socket_name); } else { // All other hosts should use their actual hostname - return m_gdb_client.LaunchGDBserverAndGetPort (pid, NULL); + launch_result = m_gdb_client.LaunchGDBServer (nullptr, pid, port, socket_name); } + + if (!launch_result) + return false; + + connect_url = MakeGdbServerUrl(m_platform_scheme, + m_platform_hostname, + port, + (socket_name.empty()) ? nullptr : socket_name.c_str()); + return true; } bool @@ -686,9 +680,8 @@ PlatformRemoteGDBServer::Attach (ProcessAttachInfo &attach_info, if (IsConnected()) { lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; - uint16_t port = LaunchGDBserverAndGetPort(debugserver_pid); - - if (port == 0) + std::string connect_url; + if (!LaunchGDBServer(debugserver_pid, connect_url)) { error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ()); } @@ -716,11 +709,8 @@ PlatformRemoteGDBServer::Attach (ProcessAttachInfo &attach_info, // The darwin always currently uses the GDB remote debugger plug-in // so even when debugging locally we are debugging remotely! process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL); - if (process_sp) { - std::string connect_url = - MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port); error = process_sp->ConnectRemote(nullptr, connect_url.c_str()); if (error.Success()) { @@ -931,13 +921,8 @@ PlatformRemoteGDBServer::GetRemoteUnixSignals() return false; // We can live without short_name, description, etc. - std::string short_name{""}; - auto object_sp = dict->GetValueForKey("short_name"); - if (object_sp && object_sp->IsValid()) - short_name = object_sp->GetStringValue(); - bool suppress{false}; - object_sp = dict->GetValueForKey("suppress"); + auto object_sp = dict->GetValueForKey("suppress"); if (object_sp && object_sp->IsValid()) suppress = object_sp->GetBooleanValue(); @@ -958,7 +943,6 @@ PlatformRemoteGDBServer::GetRemoteUnixSignals() remote_signals_sp->AddSignal(signo, name.c_str(), - short_name.c_str(), suppress, stop, notify, description.c_str()); return true; @@ -969,3 +953,66 @@ PlatformRemoteGDBServer::GetRemoteUnixSignals() return m_remote_signals_sp; } + +std::string +PlatformRemoteGDBServer::MakeGdbServerUrl(const std::string &platform_scheme, + const std::string &platform_hostname, + uint16_t port, + const char* socket_name) +{ + const char *override_scheme = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_SCHEME"); + const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME"); + const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET"); + int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0; + + return MakeUrl(override_scheme ? override_scheme : platform_scheme.c_str(), + override_hostname ? override_hostname : platform_hostname.c_str(), + port + port_offset, + socket_name); +} + +std::string +PlatformRemoteGDBServer::MakeUrl(const char* scheme, + const char* hostname, + uint16_t port, + const char* path) +{ + StreamString result; + result.Printf("%s://%s", scheme, hostname); + if (port != 0) + result.Printf(":%u", port); + if (path) + result.Write(path, strlen(path)); + return result.GetString(); +} + +lldb::ProcessSP +PlatformRemoteGDBServer::ConnectProcess(const char* connect_url, + const char* plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Error &error) +{ + if (!IsRemote() || !IsConnected()) + { + error.SetErrorString("Not connected to remote gdb server"); + return nullptr; + } + return Platform::ConnectProcess(connect_url, plugin_name, debugger, target, error); +} + +size_t +PlatformRemoteGDBServer::GetPendingGdbServerList(std::vector<std::string>& connection_urls) +{ + std::vector<std::pair<uint16_t, std::string>> remote_servers; + m_gdb_client.QueryGDBServer(remote_servers); + for (const auto& gdbserver : remote_servers) + { + const char* socket_name_cstr = gdbserver.second.empty() ? nullptr : gdbserver.second.c_str(); + connection_urls.emplace_back(MakeGdbServerUrl(m_platform_scheme, + m_platform_hostname, + gdbserver.first, + socket_name_cstr)); + } + return connection_urls.size(); +} diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index 0bf013fdfb68..61136f1185e6 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -217,6 +217,16 @@ public: const lldb::UnixSignalsSP & GetRemoteUnixSignals() override; + lldb::ProcessSP + ConnectProcess (const char* connect_url, + const char* plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Error &error) override; + + virtual size_t + GetPendingGdbServerList(std::vector<std::string>& connection_urls); + protected: process_gdb_remote::GDBRemoteCommunicationClient m_gdb_client; std::string m_platform_description; // After we connect we can get a more complete description of what we are connected to @@ -225,16 +235,29 @@ protected: lldb::UnixSignalsSP m_remote_signals_sp; - // 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); + // Launch the debug server on the remote host - caller connects to launched + // debug server using connect_url. + // Subclasses should override this method if they want to do extra actions before or + // after launching the debug server. + virtual bool + LaunchGDBServer (lldb::pid_t &pid, std::string &connect_url); virtual bool KillSpawnedProcess (lldb::pid_t pid); + virtual std::string + MakeUrl(const char* scheme, + const char* hostname, + uint16_t port, + const char* path); + private: + std::string + MakeGdbServerUrl(const std::string &platform_scheme, + const std::string &platform_hostname, + uint16_t port, + const char* socket_name); + DISALLOW_COPY_AND_ASSIGN (PlatformRemoteGDBServer); }; |