diff options
author | emaste <emaste@FreeBSD.org> | 2013-08-23 18:06:42 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2013-08-23 18:06:42 +0000 |
commit | 424d4dadd208e2a1e9a43c3d55f47f03ba0c4509 (patch) | |
tree | 05d762b98a499804ce690e6ce04033f1ddf4dee6 /contrib/llvm/tools/lldb/source/Target/Platform.cpp | |
parent | cde487f27a84e02a560384f75178fddca68740f6 (diff) | |
parent | dcd15f81789e389c1cb27d264fcdddfd0a6002bd (diff) | |
download | FreeBSD-src-424d4dadd208e2a1e9a43c3d55f47f03ba0c4509.zip FreeBSD-src-424d4dadd208e2a1e9a43c3d55f47f03ba0c4509.tar.gz |
Merge lldb r188801 to contrib/llvm/tools/lldb/
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Target/Platform.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Target/Platform.cpp | 779 |
1 files changed, 779 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Target/Platform.cpp b/contrib/llvm/tools/lldb/source/Target/Platform.cpp new file mode 100644 index 0000000..e6d3bc7 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Target/Platform.cpp @@ -0,0 +1,779 @@ +//===-- Platform.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/Target/Platform.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/BreakpointIDList.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Host/Host.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + +// Use a singleton function for g_local_platform_sp to avoid init +// constructors since LLDB is often part of a shared library +static PlatformSP& +GetDefaultPlatformSP () +{ + static PlatformSP g_default_platform_sp; + return g_default_platform_sp; +} + +static Mutex & +GetConnectedPlatformListMutex () +{ + static Mutex g_remote_connected_platforms_mutex (Mutex::eMutexTypeRecursive); + return g_remote_connected_platforms_mutex; +} +static std::vector<PlatformSP> & +GetConnectedPlatformList () +{ + static std::vector<PlatformSP> g_remote_connected_platforms; + return g_remote_connected_platforms; +} + + +const char * +Platform::GetHostPlatformName () +{ + return "host"; +} + +//------------------------------------------------------------------ +/// Get the native host platform plug-in. +/// +/// There should only be one of these for each host that LLDB runs +/// upon that should be statically compiled in and registered using +/// preprocessor macros or other similar build mechanisms. +/// +/// This platform will be used as the default platform when launching +/// or attaching to processes unless another platform is specified. +//------------------------------------------------------------------ +PlatformSP +Platform::GetDefaultPlatform () +{ + return GetDefaultPlatformSP (); +} + +void +Platform::SetDefaultPlatform (const lldb::PlatformSP &platform_sp) +{ + // The native platform should use its static void Platform::Initialize() + // function to register itself as the native platform. + GetDefaultPlatformSP () = platform_sp; +} + +Error +Platform::GetFile (const FileSpec &platform_file, + const UUID *uuid_ptr, + FileSpec &local_file) +{ + // Default to the local case + local_file = platform_file; + return Error(); +} + +FileSpecList +Platform::LocateExecutableScriptingResources (Target *target, Module &module) +{ + return FileSpecList(); +} + +Platform* +Platform::FindPlugin (Process *process, const ConstString &plugin_name) +{ + PlatformCreateInstance create_callback = NULL; + if (plugin_name) + { + create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (plugin_name); + if (create_callback) + { + ArchSpec arch; + if (process) + { + arch = process->GetTarget().GetArchitecture(); + } + std::unique_ptr<Platform> instance_ap(create_callback(process, &arch)); + if (instance_ap.get()) + return instance_ap.release(); + } + } + else + { + for (uint32_t idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)) != NULL; ++idx) + { + std::unique_ptr<Platform> instance_ap(create_callback(process, nullptr)); + if (instance_ap.get()) + return instance_ap.release(); + } + } + return NULL; +} + +Error +Platform::GetSharedModule (const ModuleSpec &module_spec, + ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + ModuleSP *old_module_sp_ptr, + bool *did_create_ptr) +{ + // Don't do any path remapping for the default implementation + // of the platform GetSharedModule function, just call through + // to our static ModuleList function. Platform subclasses that + // implement remote debugging, might have a developer kits + // installed that have cached versions of the files for the + // remote target, or might implement a download and cache + // locally implementation. + const bool always_create = false; + return ModuleList::GetSharedModule (module_spec, + module_sp, + module_search_paths_ptr, + old_module_sp_ptr, + did_create_ptr, + always_create); +} + +PlatformSP +Platform::Create (const char *platform_name, Error &error) +{ + PlatformCreateInstance create_callback = NULL; + lldb::PlatformSP platform_sp; + if (platform_name && platform_name[0]) + { + ConstString const_platform_name (platform_name); + create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (const_platform_name); + if (create_callback) + platform_sp.reset(create_callback(true, NULL)); + else + error.SetErrorStringWithFormat ("unable to find a plug-in for the platform named \"%s\"", platform_name); + } + else + error.SetErrorString ("invalid platform name"); + return platform_sp; +} + + +PlatformSP +Platform::Create (const ArchSpec &arch, ArchSpec *platform_arch_ptr, Error &error) +{ + lldb::PlatformSP platform_sp; + if (arch.IsValid()) + { + uint32_t idx; + PlatformCreateInstance create_callback; + // First try exact arch matches across all platform plug-ins + bool exact = true; + for (idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex (idx)); ++idx) + { + if (create_callback) + { + platform_sp.reset(create_callback(false, &arch)); + if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, exact, platform_arch_ptr)) + return platform_sp; + } + } + // Next try compatible arch matches across all platform plug-ins + exact = false; + for (idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex (idx)); ++idx) + { + if (create_callback) + { + platform_sp.reset(create_callback(false, &arch)); + if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, exact, platform_arch_ptr)) + return platform_sp; + } + } + } + else + error.SetErrorString ("invalid platform name"); + if (platform_arch_ptr) + platform_arch_ptr->Clear(); + platform_sp.reset(); + return platform_sp; +} + +uint32_t +Platform::GetNumConnectedRemotePlatforms () +{ + Mutex::Locker locker (GetConnectedPlatformListMutex ()); + return GetConnectedPlatformList().size(); +} + +PlatformSP +Platform::GetConnectedRemotePlatformAtIndex (uint32_t idx) +{ + PlatformSP platform_sp; + { + Mutex::Locker locker (GetConnectedPlatformListMutex ()); + if (idx < GetConnectedPlatformList().size()) + platform_sp = GetConnectedPlatformList ()[idx]; + } + return platform_sp; +} + +//------------------------------------------------------------------ +/// Default Constructor +//------------------------------------------------------------------ +Platform::Platform (bool is_host) : + m_is_host (is_host), + m_os_version_set_while_connected (false), + m_system_arch_set_while_connected (false), + m_sdk_sysroot (), + m_sdk_build (), + m_remote_url (), + m_name (), + m_major_os_version (UINT32_MAX), + m_minor_os_version (UINT32_MAX), + m_update_os_version (UINT32_MAX), + m_system_arch(), + m_uid_map_mutex (Mutex::eMutexTypeNormal), + m_gid_map_mutex (Mutex::eMutexTypeNormal), + m_uid_map(), + m_gid_map(), + m_max_uid_name_len (0), + m_max_gid_name_len (0) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf ("%p Platform::Platform()", this); +} + +//------------------------------------------------------------------ +/// Destructor. +/// +/// The destructor is virtual since this class is designed to be +/// inherited from by the plug-in instance. +//------------------------------------------------------------------ +Platform::~Platform() +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf ("%p Platform::~Platform()", this); +} + +void +Platform::GetStatus (Stream &strm) +{ + uint32_t major = UINT32_MAX; + uint32_t minor = UINT32_MAX; + uint32_t update = UINT32_MAX; + std::string s; + strm.Printf (" Platform: %s\n", GetPluginName().GetCString()); + + ArchSpec arch (GetSystemArchitecture()); + if (arch.IsValid()) + { + if (!arch.GetTriple().str().empty()) + strm.Printf(" Triple: %s\n", arch.GetTriple().str().c_str()); + } + + if (GetOSVersion(major, minor, update)) + { + strm.Printf("OS Version: %u", major); + if (minor != UINT32_MAX) + strm.Printf(".%u", minor); + if (update != UINT32_MAX) + strm.Printf(".%u", update); + + if (GetOSBuildString (s)) + strm.Printf(" (%s)", s.c_str()); + + strm.EOL(); + } + + if (GetOSKernelDescription (s)) + strm.Printf(" Kernel: %s\n", s.c_str()); + + if (IsHost()) + { + strm.Printf(" Hostname: %s\n", GetHostname()); + } + else + { + const bool is_connected = IsConnected(); + if (is_connected) + strm.Printf(" Hostname: %s\n", GetHostname()); + strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no"); + } +} + + +bool +Platform::GetOSVersion (uint32_t &major, + uint32_t &minor, + uint32_t &update) +{ + bool success = m_major_os_version != UINT32_MAX; + if (IsHost()) + { + if (!success) + { + // We have a local host platform + success = Host::GetOSVersion (m_major_os_version, + m_minor_os_version, + m_update_os_version); + m_os_version_set_while_connected = success; + } + } + else + { + // We have a remote platform. We can only fetch the remote + // OS version if we are connected, and we don't want to do it + // more than once. + + const bool is_connected = IsConnected(); + + bool fetch = false; + if (success) + { + // We have valid OS version info, check to make sure it wasn't + // manually set prior to connecting. If it was manually set prior + // to connecting, then lets fetch the actual OS version info + // if we are now connected. + if (is_connected && !m_os_version_set_while_connected) + fetch = true; + } + else + { + // We don't have valid OS version info, fetch it if we are connected + fetch = is_connected; + } + + if (fetch) + { + success = GetRemoteOSVersion (); + m_os_version_set_while_connected = success; + } + } + + if (success) + { + major = m_major_os_version; + minor = m_minor_os_version; + update = m_update_os_version; + } + return success; +} + +bool +Platform::GetOSBuildString (std::string &s) +{ + if (IsHost()) + return Host::GetOSBuildString (s); + else + return GetRemoteOSBuildString (s); +} + +bool +Platform::GetOSKernelDescription (std::string &s) +{ + if (IsHost()) + return Host::GetOSKernelDescription (s); + else + return GetRemoteOSKernelDescription (s); +} + +ConstString +Platform::GetName () +{ + const char *name = GetHostname(); + if (name == NULL || name[0] == '\0') + return GetPluginName(); + return ConstString (name); +} + +const char * +Platform::GetHostname () +{ + if (IsHost()) + return "localhost"; + + if (m_name.empty()) + return NULL; + return m_name.c_str(); +} + +const char * +Platform::GetUserName (uint32_t uid) +{ + const char *user_name = GetCachedUserName(uid); + if (user_name) + return user_name; + if (IsHost()) + { + std::string name; + if (Host::GetUserName(uid, name)) + return SetCachedUserName (uid, name.c_str(), name.size()); + } + return NULL; +} + +const char * +Platform::GetGroupName (uint32_t gid) +{ + const char *group_name = GetCachedGroupName(gid); + if (group_name) + return group_name; + if (IsHost()) + { + std::string name; + if (Host::GetGroupName(gid, name)) + return SetCachedGroupName (gid, name.c_str(), name.size()); + } + return NULL; +} + +bool +Platform::SetOSVersion (uint32_t major, + uint32_t minor, + uint32_t update) +{ + if (IsHost()) + { + // We don't need anyone setting the OS version for the host platform, + // we should be able to figure it out by calling Host::GetOSVersion(...). + return false; + } + else + { + // We have a remote platform, allow setting the target OS version if + // we aren't connected, since if we are connected, we should be able to + // request the remote OS version from the connected platform. + if (IsConnected()) + return false; + else + { + // We aren't connected and we might want to set the OS version + // ahead of time before we connect so we can peruse files and + // use a local SDK or PDK cache of support files to disassemble + // or do other things. + m_major_os_version = major; + m_minor_os_version = minor; + m_update_os_version = update; + return true; + } + } + return false; +} + + +Error +Platform::ResolveExecutable (const FileSpec &exe_file, + const ArchSpec &exe_arch, + lldb::ModuleSP &exe_module_sp, + const FileSpecList *module_search_paths_ptr) +{ + Error error; + if (exe_file.Exists()) + { + ModuleSpec module_spec (exe_file, exe_arch); + if (module_spec.GetArchitecture().IsValid()) + { + error = ModuleList::GetSharedModule (module_spec, + exe_module_sp, + module_search_paths_ptr, + NULL, + NULL); + } + 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 + for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, module_spec.GetArchitecture()); ++idx) + { + error = ModuleList::GetSharedModule (module_spec, + exe_module_sp, + module_search_paths_ptr, + NULL, + NULL); + // Did we find an executable using one of the + if (error.Success() && exe_module_sp) + break; + } + } + } + else + { + error.SetErrorStringWithFormat ("'%s' does not exist", + exe_file.GetPath().c_str()); + } + return error; +} + +Error +Platform::ResolveSymbolFile (Target &target, + const ModuleSpec &sym_spec, + FileSpec &sym_file) +{ + Error error; + if (sym_spec.GetSymbolFileSpec().Exists()) + sym_file = sym_spec.GetSymbolFileSpec(); + else + error.SetErrorString("unable to resolve symbol file"); + return error; + +} + + + +bool +Platform::ResolveRemotePath (const FileSpec &platform_path, + FileSpec &resolved_platform_path) +{ + resolved_platform_path = platform_path; + return resolved_platform_path.ResolvePath(); +} + + +const ArchSpec & +Platform::GetSystemArchitecture() +{ + if (IsHost()) + { + if (!m_system_arch.IsValid()) + { + // We have a local host platform + m_system_arch = Host::GetArchitecture(); + m_system_arch_set_while_connected = m_system_arch.IsValid(); + } + } + else + { + // We have a remote platform. We can only fetch the remote + // system architecture if we are connected, and we don't want to do it + // more than once. + + const bool is_connected = IsConnected(); + + bool fetch = false; + if (m_system_arch.IsValid()) + { + // We have valid OS version info, check to make sure it wasn't + // manually set prior to connecting. If it was manually set prior + // to connecting, then lets fetch the actual OS version info + // if we are now connected. + if (is_connected && !m_system_arch_set_while_connected) + fetch = true; + } + else + { + // We don't have valid OS version info, fetch it if we are connected + fetch = is_connected; + } + + if (fetch) + { + m_system_arch = GetRemoteSystemArchitecture (); + m_system_arch_set_while_connected = m_system_arch.IsValid(); + } + } + return m_system_arch; +} + + +Error +Platform::ConnectRemote (Args& args) +{ + Error error; + if (IsHost()) + error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetPluginName().GetCString()); + else + error.SetErrorStringWithFormat ("Platform::ConnectRemote() is not supported by %s", GetPluginName().GetCString()); + return error; +} + +Error +Platform::DisconnectRemote () +{ + Error error; + if (IsHost()) + error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetPluginName().GetCString()); + else + error.SetErrorStringWithFormat ("Platform::DisconnectRemote() is not supported by %s", GetPluginName().GetCString()); + return error; +} + +bool +Platform::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) +{ + // Take care of the host case so that each subclass can just + // call this function to get the host functionality. + if (IsHost()) + return Host::GetProcessInfo (pid, process_info); + return false; +} + +uint32_t +Platform::FindProcesses (const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) +{ + // Take care of the host case so that each subclass can just + // call this function to get the host functionality. + uint32_t match_count = 0; + if (IsHost()) + match_count = Host::FindProcesses (match_info, process_infos); + return match_count; +} + + +Error +Platform::LaunchProcess (ProcessLaunchInfo &launch_info) +{ + Error error; + // Take care of the host case so that each subclass can just + // call this function to get the host functionality. + if (IsHost()) + { + if (::getenv ("LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY")) + launch_info.GetFlags().Set (eLaunchFlagLaunchInTTY); + + if (launch_info.GetFlags().Test (eLaunchFlagLaunchInShell)) + { + const bool is_localhost = true; + const bool will_debug = launch_info.GetFlags().Test(eLaunchFlagDebug); + const bool first_arg_is_full_shell_command = false; + if (!launch_info.ConvertArgumentsForLaunchingInShell (error, + is_localhost, + will_debug, + first_arg_is_full_shell_command)) + return error; + } + + error = Host::LaunchProcess (launch_info); + } + else + error.SetErrorString ("base lldb_private::Platform class can't launch remote processes"); + return error; +} + +lldb::ProcessSP +Platform::DebugProcess (ProcessLaunchInfo &launch_info, + Debugger &debugger, + Target *target, // Can be NULL, if NULL create a new target, else use existing one + Listener &listener, + Error &error) +{ + ProcessSP process_sp; + // Make sure we stop at the entry point + launch_info.GetFlags ().Set (eLaunchFlagDebug); + // We always launch the process we are going to debug in a separate process + // group, since then we can handle ^C interrupts ourselves w/o having to worry + // about the target getting them as well. + launch_info.SetLaunchInSeparateProcessGroup(true); + + error = LaunchProcess (launch_info); + if (error.Success()) + { + if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) + { + ProcessAttachInfo attach_info (launch_info); + process_sp = Attach (attach_info, debugger, target, listener, error); + if (process_sp) + { + // Since we attached to the process, it will think it needs to detach + // if the process object just goes away without an explicit call to + // Process::Kill() or Process::Detach(), so let it know to kill the + // process if this happens. + process_sp->SetShouldDetach (false); + + // If we didn't have any file actions, the pseudo terminal might + // have been used where the slave side was given as the file to + // open for stdin/out/err after we have already opened the master + // so we can read/write stdin/out/err. + int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); + if (pty_fd != lldb_utility::PseudoTerminal::invalid_fd) + { + process_sp->SetSTDIOFileDescriptor(pty_fd); + } + } + } + } + return process_sp; +} + + +lldb::PlatformSP +Platform::GetPlatformForArchitecture (const ArchSpec &arch, ArchSpec *platform_arch_ptr) +{ + lldb::PlatformSP platform_sp; + Error error; + if (arch.IsValid()) + platform_sp = Platform::Create (arch, platform_arch_ptr, error); + return platform_sp; +} + + +//------------------------------------------------------------------ +/// Lets a platform answer if it is compatible with a given +/// architecture and the target triple contained within. +//------------------------------------------------------------------ +bool +Platform::IsCompatibleArchitecture (const ArchSpec &arch, bool exact_arch_match, ArchSpec *compatible_arch_ptr) +{ + // If the architecture is invalid, we must answer true... + if (arch.IsValid()) + { + ArchSpec platform_arch; + // Try for an exact architecture match first. + if (exact_arch_match) + { + for (uint32_t arch_idx=0; GetSupportedArchitectureAtIndex (arch_idx, platform_arch); ++arch_idx) + { + if (arch.IsExactMatch(platform_arch)) + { + if (compatible_arch_ptr) + *compatible_arch_ptr = platform_arch; + return true; + } + } + } + else + { + for (uint32_t arch_idx=0; GetSupportedArchitectureAtIndex (arch_idx, platform_arch); ++arch_idx) + { + if (arch.IsCompatibleMatch(platform_arch)) + { + if (compatible_arch_ptr) + *compatible_arch_ptr = platform_arch; + return true; + } + } + } + } + if (compatible_arch_ptr) + compatible_arch_ptr->Clear(); + return false; + +} + + +lldb::BreakpointSP +Platform::SetThreadCreationBreakpoint (lldb_private::Target &target) +{ + return lldb::BreakpointSP(); +} + +size_t +Platform::GetEnvironment (StringList &environment) +{ + environment.Clear(); + return false; +} + |