#include "lldb/Target/Platform.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Log.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;
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";
}
PlatformSP
Platform::GetDefaultPlatform ()
{
return GetDefaultPlatformSP ();
}
void
Platform::SetDefaultPlatform (const lldb::PlatformSP &platform_sp)
{
GetDefaultPlatformSP () = platform_sp;
}
Error
Platform::GetFile (const FileSpec &platform_file,
const UUID *uuid_ptr,
FileSpec &local_file)
{
local_file = platform_file;
return Error();
}
Error
Platform::GetSharedModule (const FileSpec &platform_file,
const ArchSpec &arch,
const UUID *uuid_ptr,
const ConstString *object_name_ptr,
off_t object_offset,
ModuleSP &module_sp,
ModuleSP *old_module_sp_ptr,
bool *did_create_ptr)
{
const bool always_create = false;
return ModuleList::GetSharedModule (platform_file,
arch,
uuid_ptr,
object_name_ptr,
object_offset,
module_sp,
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])
{
create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (platform_name);
if (create_callback)
platform_sp.reset(create_callback());
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;
}
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;
}
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)
{
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
log->Printf ("%p Platform::Platform()", this);
}
Platform::~Platform()
{
LogSP 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", GetShortPluginName());
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)
{
success = Host::GetOSVersion (m_major_os_version,
m_minor_os_version,
m_update_os_version);
m_os_version_set_while_connected = success;
}
}
else
{
const bool is_connected = IsConnected();
bool fetch = false;
if (success)
{
if (is_connected && !m_os_version_set_while_connected)
fetch = true;
}
else
{
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);
}
const char *
Platform::GetName ()
{
const char *name = GetHostname();
if (name == NULL || name[0] == '\0')
name = GetShortPluginName();
return 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())
{
return false;
}
else
{
if (IsConnected())
return false;
else
{
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)
{
Error error;
if (exe_file.Exists())
{
if (exe_arch.IsValid())
{
error = ModuleList::GetSharedModule (exe_file,
exe_arch,
NULL,
NULL,
0,
exe_module_sp,
NULL,
NULL);
}
else
{
ArchSpec platform_arch;
for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, platform_arch); ++idx)
{
error = ModuleList::GetSharedModule (exe_file,
platform_arch,
NULL,
NULL,
0,
exe_module_sp,
NULL,
NULL);
if (error.Success() && exe_module_sp)
break;
}
}
}
else
{
error.SetErrorStringWithFormat ("'%s%s%s' does not exist",
exe_file.GetDirectory().AsCString(""),
exe_file.GetDirectory() ? "/" : "",
exe_file.GetFilename().AsCString(""));
}
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())
{
m_system_arch = Host::GetArchitecture();
m_system_arch_set_while_connected = m_system_arch.IsValid();
}
}
else
{
const bool is_connected = IsConnected();
bool fetch = false;
if (m_system_arch.IsValid())
{
if (is_connected && !m_system_arch_set_while_connected)
fetch = true;
}
else
{
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.", GetShortPluginName());
else
error.SetErrorStringWithFormat ("Platform::ConnectRemote() is not supported by %s", GetShortPluginName());
return error;
}
Error
Platform::DisconnectRemote ()
{
Error error;
if (IsHost())
error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetShortPluginName());
else
error.SetErrorStringWithFormat ("Platform::DisconnectRemote() is not supported by %s", GetShortPluginName());
return error;
}
bool
Platform::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
{
if (IsHost())
return Host::GetProcessInfo (pid, process_info);
return false;
}
uint32_t
Platform::FindProcesses (const ProcessInstanceInfoMatch &match_info,
ProcessInstanceInfoList &process_infos)
{
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;
if (IsHost())
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, Listener &listener,
Error &error)
{
ProcessSP process_sp;
launch_info.GetFlags ().Set (eLaunchFlagDebug);
error = LaunchProcess (launch_info);
if (error.Success())
{
lldb::pid_t pid = launch_info.GetProcessID();
if (pid != LLDB_INVALID_PROCESS_ID)
{
process_sp = Attach (pid, debugger, target, listener, error);
}
}
return process_sp;
}