summaryrefslogtreecommitdiffstats
path: root/lldb/source/Host
diff options
context:
space:
mode:
authorDaniel Malea <daniel.malea@intel.com>2013-08-26 23:57:52 +0000
committerDaniel Malea <daniel.malea@intel.com>2013-08-26 23:57:52 +0000
commite0f8f574c7f41f5b61ec01aa290d52fc55a3f3c9 (patch)
treec519b347e7428c3b28956c9165b661b11b468470 /lldb/source/Host
parent6b16b43ef95d2ffbad889601f26786ecdbd914b4 (diff)
downloadbcm5719-llvm-e0f8f574c7f41f5b61ec01aa290d52fc55a3f3c9.tar.gz
bcm5719-llvm-e0f8f574c7f41f5b61ec01aa290d52fc55a3f3c9.zip
merge lldb-platform-work branch (and assorted fixes) into trunk
Summary: This merge brings in the improved 'platform' command that knows how to interface with remote machines; that is, query OS/kernel information, push and pull files, run shell commands, etc... and implementation for the new communication packets that back that interface, at least on Darwin based operating systems via the POSIXPlatform class. Linux support is coming soon. Verified the test suite runs cleanly on Linux (x86_64), build OK on Mac OS X Mountain Lion. Additional improvements (not in the source SVN branch 'lldb-platform-work'): - cmake build scripts for lldb-platform - cleanup test suite - documentation stub for qPlatform_RunCommand - use log class instead of printf() directly - reverted work-in-progress-looking changes from test/types/TestAbstract.py that work towards running the test suite remotely. - add new logging category 'platform' Reviewers: Matt Kopec, Greg Clayton Review: http://llvm-reviews.chandlerc.com/D1493 llvm-svn: 189295
Diffstat (limited to 'lldb/source/Host')
-rw-r--r--lldb/source/Host/common/File.cpp109
-rw-r--r--lldb/source/Host/common/FileSpec.cpp135
-rw-r--r--lldb/source/Host/common/Host.cpp172
-rw-r--r--lldb/source/Host/freebsd/Host.cpp315
-rw-r--r--lldb/source/Host/macosx/Host.mm7
5 files changed, 713 insertions, 25 deletions
diff --git a/lldb/source/Host/common/File.cpp b/lldb/source/Host/common/File.cpp
index 343312fb484..ec33bca4905 100644
--- a/lldb/source/Host/common/File.cpp
+++ b/lldb/source/Host/common/File.cpp
@@ -83,6 +83,20 @@ File::File(const char *path, uint32_t options, uint32_t permissions) :
Open (path, options, permissions);
}
+File::File (const FileSpec& filespec,
+ uint32_t options,
+ uint32_t permissions) :
+ m_descriptor (kInvalidDescriptor),
+ m_stream (kInvalidStream),
+ m_options (0),
+ m_owned (false)
+{
+ if (filespec)
+ {
+ Open (filespec.GetPath().c_str(), options, permissions);
+ }
+}
+
File::File (const File &rhs) :
m_descriptor (kInvalidDescriptor),
m_stream (kInvalidStream),
@@ -261,6 +275,53 @@ File::Open (const char *path, uint32_t options, uint32_t permissions)
return error;
}
+uint32_t
+File::GetPermissions (const char *path, Error &error)
+{
+ if (path && path[0])
+ {
+ struct stat file_stats;
+ if (::stat (path, &file_stats) == -1)
+ error.SetErrorToErrno();
+ else
+ {
+ error.Clear();
+ return file_stats.st_mode; // All bits from lldb_private::File::Permissions match those in POSIX mode bits
+ }
+ }
+ else
+ {
+ if (path)
+ error.SetErrorString ("invalid path");
+ else
+ error.SetErrorString ("empty path");
+ }
+ return 0;
+}
+
+uint32_t
+File::GetPermissions(Error &error) const
+{
+ int fd = GetDescriptor();
+ if (fd != kInvalidDescriptor)
+ {
+ struct stat file_stats;
+ if (::fstat (fd, &file_stats) == -1)
+ error.SetErrorToErrno();
+ else
+ {
+ error.Clear();
+ return file_stats.st_mode; // All bits from lldb_private::File::Permissions match those in POSIX mode bits
+ }
+ }
+ else
+ {
+ error.SetErrorString ("invalid file descriptor");
+ }
+ return 0;
+}
+
+
Error
File::Close ()
{
@@ -755,3 +816,51 @@ File::PrintfVarArg (const char *format, va_list args)
}
return result;
}
+
+mode_t
+File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
+{
+ mode_t mode = 0;
+ if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
+ mode |= O_RDWR;
+ else if (open_options & eOpenOptionWrite)
+ mode |= O_WRONLY;
+
+ if (open_options & eOpenOptionAppend)
+ mode |= O_APPEND;
+
+ if (open_options & eOpenOptionTruncate)
+ mode |= O_TRUNC;
+
+ if (open_options & eOpenOptionNonBlocking)
+ mode |= O_NONBLOCK;
+
+ if (open_options & eOpenOptionCanCreateNewOnly)
+ mode |= O_CREAT | O_EXCL;
+ else if (open_options & eOpenOptionCanCreate)
+ mode |= O_CREAT;
+
+ return mode;
+}
+
+#define O_RDONLY 0x0000 /* open for reading only */
+#define O_WRONLY 0x0001 /* open for writing only */
+#define O_RDWR 0x0002 /* open for reading and writing */
+#define O_ACCMODE 0x0003 /* mask for above modes */
+#define O_NONBLOCK 0x0004 /* no delay */
+#define O_APPEND 0x0008 /* set append mode */
+#define O_SYNC 0x0080 /* synch I/O file integrity */
+#define O_SHLOCK 0x0010 /* open with shared file lock */
+#define O_EXLOCK 0x0020 /* open with exclusive file lock */
+#define O_ASYNC 0x0040 /* signal pgrp when data ready */
+#define O_FSYNC O_SYNC /* source compatibility: do not use */
+#define O_NOFOLLOW 0x0100 /* don't follow symlinks */
+#define O_CREAT 0x0200 /* create if nonexistant */
+#define O_TRUNC 0x0400 /* truncate to zero length */
+#define O_EXCL 0x0800 /* error if already exists */
+#define O_EVTONLY 0x8000 /* descriptor requested for event notifications only */
+#define O_NOCTTY 0x20000 /* don't assign controlling terminal */
+#define O_DIRECTORY 0x100000
+#define O_SYMLINK 0x200000 /* allow open of a symlink */
+#define O_DSYNC 0x400000 /* synch I/O data integrity */
+#define O_CLOEXEC 0x1000000 /* implicitly set FD_CLOEXEC */
diff --git a/lldb/source/Host/common/FileSpec.cpp b/lldb/source/Host/common/FileSpec.cpp
index 0bf7681aa48..66818453bc0 100644
--- a/lldb/source/Host/common/FileSpec.cpp
+++ b/lldb/source/Host/common/FileSpec.cpp
@@ -29,6 +29,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
+#include "lldb/Core/StreamString.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Core/DataBufferHeap.h"
@@ -1106,6 +1107,140 @@ FileSpec::EnumerateDirectory
return eEnumerateDirectoryResultNext;
}
+FileSpec
+FileSpec::CopyByAppendingPathComponent (const char *new_path) const
+{
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ return FileSpec(new_path,resolve);
+ StreamString stream;
+ if (m_filename.IsEmpty())
+ stream.Printf("%s/%s",m_directory.GetCString(),new_path);
+ else if (m_directory.IsEmpty())
+ stream.Printf("%s/%s",m_filename.GetCString(),new_path);
+ else
+ stream.Printf("%s/%s/%s",m_directory.GetCString(), m_filename.GetCString(),new_path);
+ return FileSpec(stream.GetData(),resolve);
+}
+
+FileSpec
+FileSpec::CopyByRemovingLastPathComponent () const
+{
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ return FileSpec("",resolve);
+ if (m_directory.IsEmpty())
+ return FileSpec("",resolve);
+ if (m_filename.IsEmpty())
+ {
+ const char* dir_cstr = m_directory.GetCString();
+ const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
+
+ // check for obvious cases before doing the full thing
+ if (!last_slash_ptr)
+ return FileSpec("",resolve);
+ if (last_slash_ptr == dir_cstr)
+ return FileSpec("/",resolve);
+
+ size_t last_slash_pos = last_slash_ptr - dir_cstr+1;
+ ConstString new_path(dir_cstr,last_slash_pos);
+ return FileSpec(new_path.GetCString(),resolve);
+ }
+ else
+ return FileSpec(m_directory.GetCString(),resolve);
+}
+
+const char*
+FileSpec::GetLastPathComponent () const
+{
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ return NULL;
+ if (m_filename.IsEmpty())
+ {
+ const char* dir_cstr = m_directory.GetCString();
+ const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
+ if (last_slash_ptr == NULL)
+ return m_directory.GetCString();
+ if (last_slash_ptr == dir_cstr)
+ {
+ if (last_slash_ptr[1] == 0)
+ return last_slash_ptr;
+ else
+ return last_slash_ptr+1;
+ }
+ if (last_slash_ptr[1] != 0)
+ return last_slash_ptr+1;
+ const char* penultimate_slash_ptr = last_slash_ptr;
+ while (*penultimate_slash_ptr)
+ {
+ --penultimate_slash_ptr;
+ if (penultimate_slash_ptr == dir_cstr)
+ break;
+ if (*penultimate_slash_ptr == '/')
+ break;
+ }
+ ConstString new_path(penultimate_slash_ptr+1,last_slash_ptr-penultimate_slash_ptr);
+ return new_path.AsCString();
+ }
+ return m_filename.GetCString();
+}
+
+void
+FileSpec::AppendPathComponent (const char *new_path)
+{
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ {
+ SetFile(new_path,resolve);
+ return;
+ }
+ StreamString stream;
+ if (m_filename.IsEmpty())
+ stream.Printf("%s/%s",m_directory.GetCString(),new_path);
+ else if (m_directory.IsEmpty())
+ stream.Printf("%s/%s",m_filename.GetCString(),new_path);
+ else
+ stream.Printf("%s/%s/%s",m_directory.GetCString(), m_filename.GetCString(),new_path);
+ SetFile(stream.GetData(), resolve);
+}
+
+void
+FileSpec::RemoveLastPathComponent ()
+{
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ {
+ SetFile("",resolve);
+ return;
+ }
+ if (m_directory.IsEmpty())
+ {
+ SetFile("",resolve);
+ return;
+ }
+ if (m_filename.IsEmpty())
+ {
+ const char* dir_cstr = m_directory.GetCString();
+ const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
+
+ // check for obvious cases before doing the full thing
+ if (!last_slash_ptr)
+ {
+ SetFile("",resolve);
+ return;
+ }
+ if (last_slash_ptr == dir_cstr)
+ {
+ SetFile("/",resolve);
+ return;
+ }
+ size_t last_slash_pos = last_slash_ptr - dir_cstr+1;
+ ConstString new_path(dir_cstr,last_slash_pos);
+ SetFile(new_path.GetCString(),resolve);
+ }
+ else
+ SetFile(m_directory.GetCString(),resolve);
+}
//------------------------------------------------------------------
/// Returns true if the filespec represents an implementation source
/// file (files with a ".c", ".cpp", ".m", ".mm" (many more)
diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp
index 826069b358c..efe97237d42 100644
--- a/lldb/source/Host/common/Host.cpp
+++ b/lldb/source/Host/common/Host.cpp
@@ -1472,7 +1472,11 @@ Host::RunShellCommand (const char *command,
error = LaunchProcess (launch_info);
const lldb::pid_t pid = launch_info.GetProcessID();
- if (pid != LLDB_INVALID_PROCESS_ID)
+
+ if (error.Success() && pid == LLDB_INVALID_PROCESS_ID)
+ error.SetErrorString("failed to get process ID");
+
+ if (error.Success())
{
// The process successfully launched, so we can defer ownership of
// "shell_info" to the MonitorShellCommand callback function that will
@@ -1524,10 +1528,6 @@ Host::RunShellCommand (const char *command,
}
shell_info->can_delete.SetValue(true, eBroadcastAlways);
}
- else
- {
- error.SetErrorString("failed to get process ID");
- }
if (output_file_path)
::unlink (output_file_path);
@@ -1613,9 +1613,169 @@ Host::SetCrashDescription (const char *description)
}
lldb::pid_t
-LaunchApplication (const FileSpec &app_file_spec)
+Host::LaunchApplication (const FileSpec &app_file_spec)
{
return LLDB_INVALID_PROCESS_ID;
}
+uint32_t
+Host::MakeDirectory (const char* path, mode_t mode)
+{
+ return UINT32_MAX;
+}
+#endif
+
+typedef std::map<lldb::user_id_t, lldb::FileSP> FDToFileMap;
+FDToFileMap& GetFDToFileMap()
+{
+ static FDToFileMap g_fd2filemap;
+ return g_fd2filemap;
+}
+
+lldb::user_id_t
+Host::OpenFile (const FileSpec& file_spec,
+ uint32_t flags,
+ mode_t mode,
+ Error &error)
+{
+ std::string path (file_spec.GetPath());
+ if (path.empty())
+ {
+ error.SetErrorString("empty path");
+ return UINT64_MAX;
+ }
+ FileSP file_sp(new File());
+ error = file_sp->Open(path.c_str(),flags,mode);
+ if (file_sp->IsValid() == false)
+ return UINT64_MAX;
+ lldb::user_id_t fd = file_sp->GetDescriptor();
+ GetFDToFileMap()[fd] = file_sp;
+ return fd;
+}
+
+bool
+Host::CloseFile (lldb::user_id_t fd, Error &error)
+{
+ if (fd == UINT64_MAX)
+ {
+ error.SetErrorString ("invalid file descriptor");
+ return false;
+ }
+ FDToFileMap& file_map = GetFDToFileMap();
+ FDToFileMap::iterator pos = file_map.find(fd);
+ if (pos == file_map.end())
+ {
+ error.SetErrorStringWithFormat ("invalid host file descriptor %" PRIu64, fd);
+ return false;
+ }
+ FileSP file_sp = pos->second;
+ if (!file_sp)
+ {
+ error.SetErrorString ("invalid host backing file");
+ return false;
+ }
+ error = file_sp->Close();
+ file_map.erase(pos);
+ return error.Success();
+}
+
+uint64_t
+Host::WriteFile (lldb::user_id_t fd, uint64_t offset, const void* src, uint64_t src_len, Error &error)
+{
+ if (fd == UINT64_MAX)
+ {
+ error.SetErrorString ("invalid file descriptor");
+ return UINT64_MAX;
+ }
+ FDToFileMap& file_map = GetFDToFileMap();
+ FDToFileMap::iterator pos = file_map.find(fd);
+ if (pos == file_map.end())
+ {
+ error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64 , fd);
+ return false;
+ }
+ FileSP file_sp = pos->second;
+ if (!file_sp)
+ {
+ error.SetErrorString ("invalid host backing file");
+ return UINT64_MAX;
+ }
+ if (file_sp->SeekFromStart(offset, &error) != offset || error.Fail())
+ return UINT64_MAX;
+ size_t bytes_written = src_len;
+ error = file_sp->Write(src, bytes_written);
+ if (error.Fail())
+ return UINT64_MAX;
+ return bytes_written;
+}
+
+uint64_t
+Host::ReadFile (lldb::user_id_t fd, uint64_t offset, void* dst, uint64_t dst_len, Error &error)
+{
+ if (fd == UINT64_MAX)
+ {
+ error.SetErrorString ("invalid file descriptor");
+ return UINT64_MAX;
+ }
+ FDToFileMap& file_map = GetFDToFileMap();
+ FDToFileMap::iterator pos = file_map.find(fd);
+ if (pos == file_map.end())
+ {
+ error.SetErrorStringWithFormat ("invalid host file descriptor %" PRIu64, fd);
+ return false;
+ }
+ FileSP file_sp = pos->second;
+ if (!file_sp)
+ {
+ error.SetErrorString ("invalid host backing file");
+ return UINT64_MAX;
+ }
+ if (file_sp->SeekFromStart(offset, &error) != offset || error.Fail())
+ return UINT64_MAX;
+ size_t bytes_read = dst_len;
+ error = file_sp->Read(dst ,bytes_read);
+ if (error.Fail())
+ return UINT64_MAX;
+ return bytes_read;
+}
+
+lldb::user_id_t
+Host::GetFileSize (const FileSpec& file_spec)
+{
+ return file_spec.GetByteSize();
+}
+
+bool
+Host::GetFileExists (const FileSpec& file_spec)
+{
+ return file_spec.Exists();
+}
+
+bool
+Host::CalculateMD5 (const FileSpec& file_spec,
+ uint64_t &low,
+ uint64_t &high)
+{
+#if defined (__APPLE__)
+ StreamString md5_cmd_line;
+ md5_cmd_line.Printf("md5 -q '%s'", file_spec.GetPath().c_str());
+ std::string hash_string;
+ Error err = Host::RunShellCommand(md5_cmd_line.GetData(), NULL, NULL, NULL, &hash_string, 60);
+ if (err.Fail())
+ return false;
+ // a correctly formed MD5 is 16-bytes, that is 32 hex digits
+ // if the output is any other length it is probably wrong
+ if (hash_string.size() != 32)
+ return false;
+ std::string part1(hash_string,0,16);
+ std::string part2(hash_string,16);
+ const char* part1_cstr = part1.c_str();
+ const char* part2_cstr = part2.c_str();
+ high = ::strtoull(part1_cstr, NULL, 16);
+ low = ::strtoull(part2_cstr, NULL, 16);
+ return true;
+#else
+ // your own MD5 implementation here
+ return false;
#endif
+}
diff --git a/lldb/source/Host/freebsd/Host.cpp b/lldb/source/Host/freebsd/Host.cpp
index 405e7eacf5a..b748cdfa4da 100644
--- a/lldb/source/Host/freebsd/Host.cpp
+++ b/lldb/source/Host/freebsd/Host.cpp
@@ -15,11 +15,13 @@
#include <sys/user.h>
#include <sys/utsname.h>
#include <sys/sysctl.h>
+#include <sys/proc.h>
#include <sys/ptrace.h>
#include <sys/exec.h>
#include <machine/elf.h>
+#include <spawn.h>
// C++ Includes
// Other libraries and framework includes
@@ -27,13 +29,17 @@
#include "lldb/Core/Error.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
+#include "lldb/Core/Module.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/Platform.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"
+#include "lldb/Utility/CleanUp.h"
+
#include "llvm/Support/Host.h"
@@ -44,7 +50,6 @@ extern "C" {
using namespace lldb;
using namespace lldb_private;
-
class FreeBSDThread
{
public:
@@ -120,7 +125,8 @@ Host::GetEnvironment (StringList &env)
{
char *v;
char **var = environ;
- for (; var != NULL && *var != NULL; ++var) {
+ for (; var != NULL && *var != NULL; ++var)
+ {
v = strchr(*var, (int)'-');
if (v == NULL)
continue;
@@ -135,8 +141,8 @@ Host::GetOSVersion(uint32_t &major,
uint32_t &update)
{
struct utsname un;
- int status;
+ ::memset(&un, 0, sizeof(utsname));
if (uname(&un) < 0)
return false;
@@ -144,11 +150,196 @@ Host::GetOSVersion(uint32_t &major,
return status == 2;
}
+// The posix_spawn() and posix_spawnp() functions first appeared in FreeBSD 8.0.
+static Error
+LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, ::pid_t &pid)
+{
+ Error error;
+ LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
+
+ assert(exe_path);
+ assert(!launch_info.GetFlags().Test (eLaunchFlagDebug));
+
+ posix_spawnattr_t attr;
+
+ error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX);
+ error.LogIfError(log.get(), "::posix_spawnattr_init ( &attr )");
+ if (error.Fail())
+ return error;
+
+ // Make a quick class that will cleanup the posix spawn attributes in case
+ // we return in the middle of this function.
+ lldb_utility::CleanUp <posix_spawnattr_t *, int> posix_spawnattr_cleanup(&attr, posix_spawnattr_destroy);
+
+ sigset_t no_signals;
+ sigset_t all_signals;
+ sigemptyset (&no_signals);
+ sigfillset (&all_signals);
+ ::posix_spawnattr_setsigmask(&attr, &all_signals);
+ ::posix_spawnattr_setsigdefault(&attr, &no_signals);
+
+ short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
+
+ error.SetError( ::posix_spawnattr_setflags (&attr, flags), eErrorTypePOSIX);
+ error.LogIfError(log.get(), "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", flags);
+ if (error.Fail())
+ return error;
+
+ const size_t num_file_actions = launch_info.GetNumFileActions ();
+ posix_spawn_file_actions_t file_actions, *file_action_ptr = NULL;
+ // Make a quick class that will cleanup the posix spawn attributes in case
+ // we return in the middle of this function.
+ lldb_utility::CleanUp <posix_spawn_file_actions_t *, int>
+ posix_spawn_file_actions_cleanup (file_action_ptr, NULL, posix_spawn_file_actions_destroy);
+
+ if (num_file_actions > 0)
+ {
+ error.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX);
+ error.LogIfError(log.get(), "::posix_spawn_file_actions_init ( &file_actions )");
+ if (error.Fail())
+ return error;
+
+ file_action_ptr = &file_actions;
+ posix_spawn_file_actions_cleanup.set(file_action_ptr);
+
+ for (size_t i = 0; i < num_file_actions; ++i)
+ {
+ const ProcessLaunchInfo::FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i);
+ if (launch_file_action &&
+ !ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (&file_actions,
+ launch_file_action,
+ log.get(),
+ error))
+ return error;
+ }
+ }
+
+ // Change working directory if neccessary.
+ char current_dir[PATH_MAX];
+ current_dir[0] = '\0';
+
+ const char *working_dir = launch_info.GetWorkingDirectory();
+ if (working_dir != NULL)
+ {
+ if (::getcwd(current_dir, sizeof(current_dir)) == NULL)
+ {
+ error.SetError(errno, eErrorTypePOSIX);
+ error.LogIfError(log.get(), "unable to save the current directory");
+ return error;
+ }
+
+ if (::chdir(working_dir) == -1)
+ {
+ error.SetError(errno, eErrorTypePOSIX);
+ error.LogIfError(log.get(), "unable to change working directory to %s", working_dir);
+ return error;
+ }
+ }
+
+ const char *tmp_argv[2];
+ char * const *argv = (char * const*)launch_info.GetArguments().GetConstArgumentVector();
+ char * const *envp = (char * const*)launch_info.GetEnvironmentEntries().GetConstArgumentVector();
+
+ // Prepare minimal argument list if we didn't get it from the launch_info structure.
+ // We must pass argv into posix_spawnp and it must contain at least two items -
+ // pointer to an executable and NULL.
+ if (argv == NULL)
+ {
+ tmp_argv[0] = exe_path;
+ tmp_argv[1] = NULL;
+ argv = (char * const*)tmp_argv;
+ }
+
+ error.SetError (::posix_spawnp (&pid,
+ exe_path,
+ (num_file_actions > 0) ? &file_actions : NULL,
+ &attr,
+ argv,
+ envp),
+ eErrorTypePOSIX);
+
+ error.LogIfError(log.get(), "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )",
+ pid, exe_path, file_action_ptr, &attr, argv, envp);
+
+ // Change back the current directory.
+ // NOTE: do not override previously established error from posix_spawnp.
+ if (working_dir != NULL && ::chdir(current_dir) == -1 && error.Success())
+ {
+ error.SetError(errno, eErrorTypePOSIX);
+ error.LogIfError(log.get(), "unable to change current directory back to %s",
+ current_dir);
+ }
+
+ return error;
+}
+
+
Error
Host::LaunchProcess (ProcessLaunchInfo &launch_info)
{
Error error;
- assert(!"Not implemented yet!!!");
+ char exe_path[PATH_MAX];
+
+ PlatformSP host_platform_sp (Platform::GetDefaultPlatform ());
+
+ const ArchSpec &arch_spec = launch_info.GetArchitecture();
+
+ FileSpec exe_spec(launch_info.GetExecutableFile());
+
+ FileSpec::FileType file_type = exe_spec.GetFileType();
+ if (file_type != FileSpec::eFileTypeRegular)
+ {
+ lldb::ModuleSP exe_module_sp;
+ error = host_platform_sp->ResolveExecutable (exe_spec,
+ arch_spec,
+ exe_module_sp,
+ NULL);
+
+ if (error.Fail())
+ return error;
+
+ if (exe_module_sp)
+ exe_spec = exe_module_sp->GetFileSpec();
+}
+
+ if (exe_spec.Exists())
+ {
+ exe_spec.GetPath (exe_path, sizeof(exe_path));
+ }
+ else
+ {
+ launch_info.GetExecutableFile().GetPath (exe_path, sizeof(exe_path));
+ error.SetErrorStringWithFormat ("executable doesn't exist: '%s'", exe_path);
+ return error;
+ }
+
+ assert(!launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY));
+
+ ::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ error = LaunchProcessPosixSpawn(exe_path, launch_info, pid);
+
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ // If all went well, then set the process ID into the launch info
+ launch_info.SetProcessID(pid);
+
+ // Make sure we reap any processes we spawn or we will have zombies.
+ if (!launch_info.MonitorProcess())
+ {
+ const bool monitor_signals = false;
+ StartMonitoringChildProcess (Process::SetProcessExitStatus,
+ NULL,
+ pid,
+ monitor_signals);
+ }
+ }
+ else
+ {
+ // Invalid process ID, something didn't go well
+ if (error.Success())
+ error.SetErrorString ("process launch failed for unknown reasons");
+ }
return error;
}
@@ -156,13 +347,17 @@ bool
Host::GetOSBuildString (std::string &s)
{
int mib[2] = { CTL_KERN, KERN_OSREV };
- char cstr[PATH_MAX];
- size_t cstr_len = sizeof(cstr);
- if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
+ char osrev_str[12];
+ uint32_t osrev = 0;
+ size_t osrev_len = sizeof(osrev);
+
+ if (::sysctl (mib, 2, &osrev, &osrev_len, NULL, 0) == 0)
{
- s.assign (cstr, cstr_len);
+ ::snprintf(osrev_str, sizeof(osrev_str), "%-8.8u", osrev);
+ s.assign (osrev_str);
return true;
}
+
s.clear();
return false;
}
@@ -170,23 +365,25 @@ Host::GetOSBuildString (std::string &s)
bool
Host::GetOSKernelDescription (std::string &s)
{
- int mib[2] = { CTL_KERN, KERN_VERSION };
- char cstr[PATH_MAX];
- size_t cstr_len = sizeof(cstr);
- if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
- {
- s.assign (cstr, cstr_len);
- return true;
- }
+ struct utsname un;
+
+ ::memset(&un, 0, sizeof(utsname));
s.clear();
+
+ if (uname(&un) < 0)
return false;
+
+ s.assign (un.version);
+
+ return true;
}
static bool
GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
ProcessInstanceInfo &process_info)
{
- if (process_info.ProcessIDIsValid()) {
+ if (process_info.ProcessIDIsValid())
+ {
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, (int)process_info.GetProcessID() };
char arg_data[8192];
@@ -235,7 +432,8 @@ GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
static bool
GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info)
{
- if (process_info.ProcessIDIsValid()) {
+ if (process_info.ProcessIDIsValid())
+ {
process_info.GetArchitecture() = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
return true;
}
@@ -279,16 +477,95 @@ GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info)
return false;
}
+uint32_t
+Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
+{
+ std::vector<struct kinfo_proc> kinfos;
+
+ int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
+
+ size_t pid_data_size = 0;
+ if (::sysctl (mib, 3, NULL, &pid_data_size, NULL, 0) != 0)
+ return 0;
+
+ // Add a few extra in case a few more show up
+ const size_t estimated_pid_count = (pid_data_size / sizeof(struct kinfo_proc)) + 10;
+
+ kinfos.resize (estimated_pid_count);
+ pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
+
+ if (::sysctl (mib, 3, &kinfos[0], &pid_data_size, NULL, 0) != 0)
+ return 0;
+
+ const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
+
+ bool all_users = match_info.GetMatchAllUsers();
+ const lldb::pid_t our_pid = getpid();
+ const uid_t our_uid = getuid();
+ for (int i = 0; i < actual_pid_count; i++)
+ {
+ const struct kinfo_proc &kinfo = kinfos[i];
+ const bool kinfo_user_matches = (all_users ||
+ (kinfo.ki_ruid == our_uid) ||
+ // Special case, if lldb is being run as root we can attach to anything.
+ (our_uid == 0)
+ );
+
+ if (kinfo_user_matches == false || // Make sure the user is acceptable
+ kinfo.ki_pid == our_pid || // Skip this process
+ kinfo.ki_pid == 0 || // Skip kernel (kernel pid is zero)
+ kinfo.ki_stat == SZOMB || // Zombies are bad, they like brains...
+ kinfo.ki_flag & P_TRACED || // Being debugged?
+ kinfo.ki_flag & P_WEXIT) // Working on exiting
+ continue;
+
+ // Every thread is a process in FreeBSD, but all the threads of a single process
+ // have the same pid. Do not store the process info in the result list if a process
+ // with given identifier is already registered there.
+ bool already_registered = false;
+ for (uint32_t pi = 0;
+ !already_registered &&
+ (const int)kinfo.ki_numthreads > 1 &&
+ pi < (const uint32_t)process_infos.GetSize(); pi++)
+ already_registered = (process_infos.GetProcessIDAtIndex(pi) == (uint32_t)kinfo.ki_pid);
+
+ if (already_registered)
+ continue;
+
+ ProcessInstanceInfo process_info;
+ process_info.SetProcessID (kinfo.ki_pid);
+ process_info.SetParentProcessID (kinfo.ki_ppid);
+ process_info.SetUserID (kinfo.ki_ruid);
+ process_info.SetGroupID (kinfo.ki_rgid);
+ process_info.SetEffectiveUserID (kinfo.ki_svuid);
+ process_info.SetEffectiveGroupID (kinfo.ki_svgid);
+
+ // Make sure our info matches before we go fetch the name and cpu type
+ if (match_info.Matches (process_info) &&
+ GetFreeBSDProcessArgs (&match_info, process_info))
+ {
+ GetFreeBSDProcessCPUType (process_info);
+ if (match_info.Matches (process_info))
+ process_infos.Append (process_info);
+ }
+ }
+
+ return process_infos.GetSize();
+}
+
bool
Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
{
process_info.SetProcessID(pid);
- if (GetFreeBSDProcessArgs(NULL, process_info)) {
+
+ if (GetFreeBSDProcessArgs(NULL, process_info))
+ {
// should use libprocstat instead of going right into sysctl?
GetFreeBSDProcessCPUType(process_info);
GetFreeBSDProcessUserAndGroup(process_info);
return true;
}
+
process_info.Clear();
return false;
}
diff --git a/lldb/source/Host/macosx/Host.mm b/lldb/source/Host/macosx/Host.mm
index 47a9b0aac6b..2a1891bf3fe 100644
--- a/lldb/source/Host/macosx/Host.mm
+++ b/lldb/source/Host/macosx/Host.mm
@@ -1984,3 +1984,10 @@ Host::GetAuxvData(lldb_private::Process *process)
{
return lldb::DataBufferSP();
}
+
+uint32_t
+Host::MakeDirectory (const char* path, mode_t mode)
+{
+ return ::mkdir(path,mode);
+}
+
OpenPOWER on IntegriCloud