diff options
Diffstat (limited to 'source/Host/common/Host.cpp')
-rw-r--r-- | source/Host/common/Host.cpp | 599 |
1 files changed, 510 insertions, 89 deletions
diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp index a7bad00..296e4b4 100644 --- a/source/Host/common/Host.cpp +++ b/source/Host/common/Host.cpp @@ -10,26 +10,33 @@ #include "lldb/lldb-python.h" // C includes -#include <dlfcn.h> #include <errno.h> -#include <grp.h> #include <limits.h> +#include <sys/types.h> +#ifdef _WIN32 +#include "lldb/Host/windows/windows.h" +#include <winsock2.h> +#include <WS2tcpip.h> +#else +#include <dlfcn.h> +#include <grp.h> #include <netdb.h> #include <pwd.h> -#include <sys/types.h> +#endif + +#if !defined (__GNU__) && !defined (_WIN32) +// Does not exist under GNU/HURD or Windows #include <sys/sysctl.h> -#include <unistd.h> +#endif #if defined (__APPLE__) - -#include <dispatch/dispatch.h> -#include <libproc.h> -#include <mach-o/dyld.h> #include <mach/mach_port.h> - +#include <mach/mach_init.h> +#include <mach-o/dyld.h> #endif #if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) +#include <spawn.h> #include <sys/wait.h> #include <sys/syscall.h> #endif @@ -44,6 +51,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/ThreadSafeSTLMap.h" #include "lldb/Host/Config.h" @@ -52,21 +60,18 @@ #include "lldb/Host/Mutex.h" #include "lldb/Target/Process.h" #include "lldb/Target/TargetList.h" +#include "lldb/Utility/CleanUp.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Host.h" -#include "llvm/Support/MachO.h" #include "llvm/Support/raw_ostream.h" - - - using namespace lldb; using namespace lldb_private; -#if !defined (__APPLE__) +#if !defined (__APPLE__) && !defined (_WIN32) struct MonitorInfo { lldb::pid_t pid; // The process ID to monitor @@ -75,7 +80,7 @@ struct MonitorInfo bool monitor_signals; // If true, call the callback when "pid" gets signaled. }; -static void * +static thread_result_t MonitorChildProcessThreadFunction (void *arg); lldb::thread_t @@ -89,7 +94,7 @@ Host::StartMonitoringChildProcess { lldb::thread_t thread = LLDB_INVALID_HOST_THREAD; MonitorInfo * info_ptr = new MonitorInfo(); - + info_ptr->pid = pid; info_ptr->callback = callback; info_ptr->callback_baton = callback_baton; @@ -133,7 +138,7 @@ private: int m_old_state; // Save the old cancelability state. }; -static void * +static thread_result_t MonitorChildProcessThreadFunction (void *arg) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); @@ -145,9 +150,11 @@ MonitorChildProcessThreadFunction (void *arg) const Host::MonitorChildProcessCallback callback = info->callback; void * const callback_baton = info->callback_baton; - const lldb::pid_t pid = info->pid; const bool monitor_signals = info->monitor_signals; + assert (info->pid <= UINT32_MAX); + const ::pid_t pid = monitor_signals ? -1 * info->pid : info->pid; + delete info; int status = -1; @@ -160,12 +167,12 @@ MonitorChildProcessThreadFunction (void *arg) { log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS); if (log) - log->Printf("%s ::wait_pid (pid = %" PRIu64 ", &status, options = %i)...", function, pid, options); + log->Printf("%s ::wait_pid (pid = %" PRIi32 ", &status, options = %i)...", function, pid, options); // Wait for all child processes ::pthread_testcancel (); // Get signals from all children with same process group of pid - const lldb::pid_t wait_pid = ::waitpid (-1*pid, &status, options); + const ::pid_t wait_pid = ::waitpid (pid, &status, options); ::pthread_testcancel (); if (wait_pid == -1) @@ -200,7 +207,7 @@ MonitorChildProcessThreadFunction (void *arg) { signal = WTERMSIG(status); status_cstr = "SIGNALED"; - if (wait_pid == pid) { + if (wait_pid == abs(pid)) { exited = true; exit_status = -1; } @@ -216,7 +223,7 @@ MonitorChildProcessThreadFunction (void *arg) log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS); if (log) - log->Printf ("%s ::waitpid (pid = %" PRIu64 ", &status, options = %i) => pid = %" PRIu64 ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", + log->Printf ("%s ::waitpid (pid = %" PRIi32 ", &status, options = %i) => pid = %" PRIi32 ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", function, wait_pid, options, @@ -233,7 +240,7 @@ MonitorChildProcessThreadFunction (void *arg) callback_return = callback (callback_baton, wait_pid, exited, signal, exit_status); // If our process exited, then this thread should exit - if (exited && wait_pid == pid) + if (exited && wait_pid == abs(pid)) { if (log) log->Printf ("%s (arg = %p) thread exiting because pid received exit signal...", __FUNCTION__, arg); @@ -259,6 +266,9 @@ MonitorChildProcessThreadFunction (void *arg) return NULL; } +#endif // #if !defined (__APPLE__) && !defined (_WIN32) + +#if !defined (__APPLE__) void Host::SystemLog (SystemLogType type, const char *format, va_list args) @@ -266,7 +276,7 @@ Host::SystemLog (SystemLogType type, const char *format, va_list args) vfprintf (stderr, format, args); } -#endif // #if !defined (__APPLE__) +#endif void Host::SystemLog (SystemLogType type, const char *format, ...) @@ -277,12 +287,6 @@ Host::SystemLog (SystemLogType type, const char *format, ...) va_end (args); } -size_t -Host::GetPageSize() -{ - return ::getpagesize(); -} - const ArchSpec & Host::GetArchitecture (SystemDefaultArchitecture arch_kind) { @@ -445,6 +449,8 @@ Host::GetCurrentProcessID() return ::getpid(); } +#ifndef _WIN32 + lldb::tid_t Host::GetCurrentThreadID() { @@ -521,6 +527,8 @@ Host::GetSignalAsCString (int signo) return NULL; } +#endif + void Host::WillTerminate () { @@ -563,6 +571,9 @@ struct HostThreadCreateInfo }; static thread_result_t +#ifdef _WIN32 +__stdcall +#endif ThreadCreateTrampoline (thread_arg_t arg) { HostThreadCreateInfo *info = (HostThreadCreateInfo *)arg; @@ -592,7 +603,12 @@ Host::ThreadCreate // Host::ThreadCreateTrampoline will delete this pointer for us. HostThreadCreateInfo *info_ptr = new HostThreadCreateInfo (thread_name, thread_fptr, thread_arg); +#ifdef _WIN32 + thread = ::_beginthreadex(0, 0, ThreadCreateTrampoline, info_ptr, 0, NULL); + int err = thread <= 0 ? GetLastError() : 0; +#else int err = ::pthread_create (&thread, NULL, ThreadCreateTrampoline, info_ptr); +#endif if (err == 0) { if (error) @@ -606,6 +622,8 @@ Host::ThreadCreate return LLDB_INVALID_HOST_THREAD; } +#ifndef _WIN32 + bool Host::ThreadCancel (lldb::thread_t thread, Error *error) { @@ -633,6 +651,26 @@ Host::ThreadJoin (lldb::thread_t thread, thread_result_t *thread_result_ptr, Err return err == 0; } +lldb::thread_key_t +Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback) +{ + pthread_key_t key; + ::pthread_key_create (&key, callback); + return key; +} + +void* +Host::ThreadLocalStorageGet(lldb::thread_key_t key) +{ + return ::pthread_getspecific (key); +} + +void +Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value) +{ + ::pthread_setspecific (key, value); +} + bool Host::SetThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name) { @@ -723,9 +761,13 @@ Host::SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid, } return Host::SetThreadName (pid, tid, namebuf); } + + ::free(namebuf); return false; } +#endif + FileSpec Host::GetProgramFileSpec () { @@ -771,19 +813,6 @@ Host::GetProgramFileSpec () return g_program_filespec; } -FileSpec -Host::GetModuleFileSpecForHostAddress (const void *host_addr) -{ - FileSpec module_filespec; - Dl_info info; - if (::dladdr (host_addr, &info)) - { - if (info.dli_fname) - module_filespec.SetFile(info.dli_fname, true); - } - return module_filespec; -} - #if !defined (__APPLE__) // see Host.mm bool @@ -800,6 +829,8 @@ Host::ResolveExecutableInBundle (FileSpec &file) } #endif +#ifndef _WIN32 + // Opaque info that tracks a dynamic library that was loaded struct DynamicLibraryInfo { @@ -924,6 +955,21 @@ Host::DynamicLibraryGetSymbol (void *opaque, const char *symbol_name, Error &err return NULL; } +FileSpec +Host::GetModuleFileSpecForHostAddress (const void *host_addr) +{ + FileSpec module_filespec; + Dl_info info; + if (::dladdr (host_addr, &info)) + { + if (info.dli_fname) + module_filespec.SetFile(info.dli_fname, true); + } + return module_filespec; +} + +#endif + bool Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) { @@ -944,7 +990,7 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) g_lldb_so_dir = lldb_file_spec.GetDirectory(); } file_spec.GetDirectory() = g_lldb_so_dir; - return file_spec.GetDirectory(); + return (bool)file_spec.GetDirectory(); } break; @@ -975,7 +1021,7 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) } } file_spec.GetDirectory() = g_lldb_support_exe_dir; - return file_spec.GetDirectory(); + return (bool)file_spec.GetDirectory(); } break; @@ -1007,12 +1053,15 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) #endif } file_spec.GetDirectory() = g_lldb_headers_dir; - return file_spec.GetDirectory(); + return (bool)file_spec.GetDirectory(); } break; -#ifndef LLDB_DISABLE_PYTHON - case ePathTypePythonDir: +#ifdef LLDB_DISABLE_PYTHON + case ePathTypePythonDir: + return false; +#else + case ePathTypePythonDir: { static ConstString g_lldb_python_dir; if (!g_lldb_python_dir) @@ -1049,7 +1098,7 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) } } file_spec.GetDirectory() = g_lldb_python_dir; - return file_spec.GetDirectory(); + return (bool)file_spec.GetDirectory(); } break; #endif @@ -1116,7 +1165,7 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) } } file_spec.GetDirectory() = g_lldb_user_plugin_dir; - return file_spec.GetDirectory(); + return (bool)file_spec.GetDirectory(); #elif defined (__linux__) static ConstString g_lldb_user_plugin_dir; if (!g_lldb_user_plugin_dir) @@ -1147,7 +1196,7 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) g_lldb_user_plugin_dir.SetCString(lldb_file_spec.GetPath().c_str()); } file_spec.GetDirectory() = g_lldb_user_plugin_dir; - return file_spec.GetDirectory(); + return (bool)file_spec.GetDirectory(); #endif // TODO: where would user LLDB plug-ins be located on other systems? return false; @@ -1175,6 +1224,8 @@ Host::GetHostname (std::string &s) return false; } +#ifndef _WIN32 + const char * Host::GetUserName (uint32_t uid, std::string &user_name) { @@ -1234,22 +1285,6 @@ Host::GetGroupName (uint32_t gid, std::string &group_name) return NULL; } -#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) // see macosx/Host.mm -bool -Host::GetOSBuildString (std::string &s) -{ - s.clear(); - return false; -} - -bool -Host::GetOSKernelDescription (std::string &s) -{ - s.clear(); - return false; -} -#endif - uint32_t Host::GetUserID () { @@ -1274,16 +1309,32 @@ Host::GetEffectiveGroupID () return getegid(); } -#if !defined (__APPLE__) && !defined(__linux__) +#endif + +#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) // see macosx/Host.mm +bool +Host::GetOSBuildString (std::string &s) +{ + s.clear(); + return false; +} + +bool +Host::GetOSKernelDescription (std::string &s) +{ + s.clear(); + return false; +} +#endif + +#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) && !defined(__linux__) uint32_t Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) { process_infos.Clear(); return process_infos.GetSize(); } -#endif // #if !defined (__APPLE__) && !defined(__linux__) -#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) && !defined(__linux__) bool Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) { @@ -1386,7 +1437,8 @@ Host::RunShellCommand (const char *command, launch_info.ConvertArgumentsForLaunchingInShell (error, localhost, will_debug, - first_arg_is_full_shell_command); + first_arg_is_full_shell_command, + 0); } else { @@ -1425,23 +1477,31 @@ 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 // get called when the process dies. We release the unique pointer as it // doesn't need to delete the ShellInfo anymore. ShellInfo *shell_info = shell_info_ap.release(); + TimeValue *timeout_ptr = nullptr; TimeValue timeout_time(TimeValue::Now()); - timeout_time.OffsetWithSeconds(timeout_sec); + if (timeout_sec > 0) { + timeout_time.OffsetWithSeconds(timeout_sec); + timeout_ptr = &timeout_time; + } bool timed_out = false; - shell_info->process_reaped.WaitForValueEqualTo(true, &timeout_time, &timed_out); + shell_info->process_reaped.WaitForValueEqualTo(true, timeout_ptr, &timed_out); if (timed_out) { error.SetErrorString("timed out waiting for shell command to complete"); - + // Kill the process since it didn't complete withint the timeout specified - ::kill (pid, SIGKILL); + Kill (pid, SIGKILL); // Wait for the monitor callback to get the message timeout_time = TimeValue::Now(); timeout_time.OffsetWithSeconds(1); @@ -1477,10 +1537,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); @@ -1490,6 +1546,212 @@ Host::RunShellCommand (const char *command, return error; } +#if defined(__linux__) or defined(__FreeBSD__) +// The functions below implement process launching via posix_spawn() for Linux +// and FreeBSD. + +// 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; + Log *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, "::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, "::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, "::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, + 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, "unable to save the current directory"); + return error; + } + + if (::chdir(working_dir) == -1) + { + error.SetError(errno, eErrorTypePOSIX); + error.LogIfError(log, "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, "::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, "unable to change current directory back to %s", + current_dir); + } + + return error; +} + + +Error +Host::LaunchProcess (ProcessLaunchInfo &launch_info) +{ + Error error; + 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; +} + +#endif // defined(__linux__) or defined(__FreeBSD__) + +#ifndef _WIN32 + +size_t +Host::GetPageSize() +{ + return ::getpagesize(); +} uint32_t Host::GetNumberCPUS () @@ -1500,14 +1762,7 @@ Host::GetNumberCPUS () #if defined(__APPLE__) or defined (__linux__) or defined (__FreeBSD__) or defined (__FreeBSD_kernel__) g_num_cores = ::sysconf(_SC_NPROCESSORS_ONLN); - -#elif defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) - - // Header file for this might need to be included at the top of this file - SYSTEM_INFO system_info; - ::GetSystemInfo (&system_info); - g_num_cores = system_info.dwNumberOfProcessors; - + #else // Assume POSIX support if a host specific case has not been supplied above @@ -1540,7 +1795,13 @@ Host::GetNumberCPUS () return g_num_cores; } +void +Host::Kill(lldb::pid_t pid, int signo) +{ + ::kill(pid, signo); +} +#endif #if !defined (__APPLE__) bool @@ -1560,9 +1821,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 +} |