diff options
Diffstat (limited to 'source/Host/linux')
-rw-r--r-- | source/Host/linux/AbstractSocket.cpp | 31 | ||||
-rw-r--r-- | source/Host/linux/Host.cpp | 393 | ||||
-rw-r--r-- | source/Host/linux/HostInfoLinux.cpp | 282 | ||||
-rw-r--r-- | source/Host/linux/HostThreadLinux.cpp | 52 | ||||
-rw-r--r-- | source/Host/linux/LibcGlue.cpp | 30 | ||||
-rw-r--r-- | source/Host/linux/ThisThread.cpp | 29 |
6 files changed, 817 insertions, 0 deletions
diff --git a/source/Host/linux/AbstractSocket.cpp b/source/Host/linux/AbstractSocket.cpp new file mode 100644 index 0000000000000..8ac0107123bb3 --- /dev/null +++ b/source/Host/linux/AbstractSocket.cpp @@ -0,0 +1,31 @@ +//===-- AbstractSocket.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/Host/linux/AbstractSocket.h" + +#include "llvm/ADT/StringRef.h" + +using namespace lldb; +using namespace lldb_private; + +AbstractSocket::AbstractSocket(bool child_processes_inherit, Error &error) + : DomainSocket(ProtocolUnixAbstract, child_processes_inherit, error) +{ +} + +size_t +AbstractSocket::GetNameOffset() const +{ + return 1; +} + +void +AbstractSocket::DeleteSocketFile(llvm::StringRef name) +{ +} diff --git a/source/Host/linux/Host.cpp b/source/Host/linux/Host.cpp new file mode 100644 index 0000000000000..cb7369fe7aec4 --- /dev/null +++ b/source/Host/linux/Host.cpp @@ -0,0 +1,393 @@ +//===-- source/Host/linux/Host.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +#include <stdio.h> +#include <sys/utsname.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <fcntl.h> + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Target/Process.h" + +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#ifdef __ANDROID_NDK__ +#include "lldb/Host/android/Android.h" +#endif +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" + +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Symbol/ObjectFile.h" +#include "Plugins/Process/Linux/ProcFileReader.h" + +using namespace lldb; +using namespace lldb_private; + +typedef enum ProcessStateFlags +{ + eProcessStateRunning = (1u << 0), // Running + eProcessStateSleeping = (1u << 1), // Sleeping in an interruptible wait + eProcessStateWaiting = (1u << 2), // Waiting in an uninterruptible disk sleep + eProcessStateZombie = (1u << 3), // Zombie + eProcessStateTracedOrStopped = (1u << 4), // Traced or stopped (on a signal) + eProcessStatePaging = (1u << 5) // Paging +} ProcessStateFlags; + +typedef struct ProcessStatInfo +{ + lldb::pid_t ppid; // Parent Process ID + uint32_t fProcessState; // ProcessStateFlags +} ProcessStatInfo; + +// Get the process info with additional information from /proc/$PID/stat (like process state, and tracer pid). +static bool GetProcessAndStatInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info, ProcessStatInfo &stat_info, lldb::pid_t &tracerpid); + +static bool +ReadProcPseudoFileStat (lldb::pid_t pid, ProcessStatInfo& stat_info) +{ + // Read the /proc/$PID/stat file. + lldb::DataBufferSP buf_sp = process_linux::ProcFileReader::ReadIntoDataBuffer (pid, "stat"); + + // The filename of the executable is stored in parenthesis right after the pid. We look for the closing + // parenthesis for the filename and work from there in case the name has something funky like ')' in it. + const char *filename_end = strrchr ((const char *)buf_sp->GetBytes(), ')'); + if (filename_end) + { + char state = '\0'; + int ppid = LLDB_INVALID_PROCESS_ID; + + // Read state and ppid. + sscanf (filename_end + 1, " %c %d", &state, &ppid); + + stat_info.ppid = ppid; + + switch (state) + { + case 'R': + stat_info.fProcessState |= eProcessStateRunning; + break; + case 'S': + stat_info.fProcessState |= eProcessStateSleeping; + break; + case 'D': + stat_info.fProcessState |= eProcessStateWaiting; + break; + case 'Z': + stat_info.fProcessState |= eProcessStateZombie; + break; + case 'T': + stat_info.fProcessState |= eProcessStateTracedOrStopped; + break; + case 'W': + stat_info.fProcessState |= eProcessStatePaging; + break; + } + + return true; + } + + return false; +} + +static void +GetLinuxProcessUserAndGroup (lldb::pid_t pid, ProcessInstanceInfo &process_info, lldb::pid_t &tracerpid) +{ + tracerpid = 0; + uint32_t rUid = UINT32_MAX; // Real User ID + uint32_t eUid = UINT32_MAX; // Effective User ID + uint32_t rGid = UINT32_MAX; // Real Group ID + uint32_t eGid = UINT32_MAX; // Effective Group ID + + // Read the /proc/$PID/status file and parse the Uid:, Gid:, and TracerPid: fields. + lldb::DataBufferSP buf_sp = process_linux::ProcFileReader::ReadIntoDataBuffer (pid, "status"); + + static const char uid_token[] = "Uid:"; + char *buf_uid = strstr ((char *)buf_sp->GetBytes(), uid_token); + if (buf_uid) + { + // Real, effective, saved set, and file system UIDs. Read the first two. + buf_uid += sizeof(uid_token); + rUid = strtol (buf_uid, &buf_uid, 10); + eUid = strtol (buf_uid, &buf_uid, 10); + } + + static const char gid_token[] = "Gid:"; + char *buf_gid = strstr ((char *)buf_sp->GetBytes(), gid_token); + if (buf_gid) + { + // Real, effective, saved set, and file system GIDs. Read the first two. + buf_gid += sizeof(gid_token); + rGid = strtol (buf_gid, &buf_gid, 10); + eGid = strtol (buf_gid, &buf_gid, 10); + } + + static const char tracerpid_token[] = "TracerPid:"; + char *buf_tracerpid = strstr((char *)buf_sp->GetBytes(), tracerpid_token); + if (buf_tracerpid) + { + // Tracer PID. 0 if we're not being debugged. + buf_tracerpid += sizeof(tracerpid_token); + tracerpid = strtol (buf_tracerpid, &buf_tracerpid, 10); + } + + process_info.SetUserID (rUid); + process_info.SetEffectiveUserID (eUid); + process_info.SetGroupID (rGid); + process_info.SetEffectiveGroupID (eGid); +} + +lldb::DataBufferSP +Host::GetAuxvData(lldb_private::Process *process) +{ + return process_linux::ProcFileReader::ReadIntoDataBuffer (process->GetID(), "auxv"); +} + +lldb::DataBufferSP +Host::GetAuxvData (lldb::pid_t pid) +{ + return process_linux::ProcFileReader::ReadIntoDataBuffer (pid, "auxv"); +} + +static bool +IsDirNumeric(const char *dname) +{ + for (; *dname; dname++) + { + if (!isdigit (*dname)) + return false; + } + return true; +} + +uint32_t +Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) +{ + static const char procdir[] = "/proc/"; + + DIR *dirproc = opendir (procdir); + if (dirproc) + { + struct dirent *direntry = NULL; + const uid_t our_uid = getuid(); + const lldb::pid_t our_pid = getpid(); + bool all_users = match_info.GetMatchAllUsers(); + + while ((direntry = readdir (dirproc)) != NULL) + { + if (direntry->d_type != DT_DIR || !IsDirNumeric (direntry->d_name)) + continue; + + lldb::pid_t pid = atoi (direntry->d_name); + + // Skip this process. + if (pid == our_pid) + continue; + + lldb::pid_t tracerpid; + ProcessStatInfo stat_info; + ProcessInstanceInfo process_info; + + if (!GetProcessAndStatInfo (pid, process_info, stat_info, tracerpid)) + continue; + + // Skip if process is being debugged. + if (tracerpid != 0) + continue; + + // Skip zombies. + if (stat_info.fProcessState & eProcessStateZombie) + continue; + + // Check for user match if we're not matching all users and not running as root. + if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid)) + continue; + + if (match_info.Matches (process_info)) + { + process_infos.Append (process_info); + } + } + + closedir (dirproc); + } + + return process_infos.GetSize(); +} + +bool +Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach) +{ + bool tids_changed = false; + static const char procdir[] = "/proc/"; + static const char taskdir[] = "/task/"; + std::string process_task_dir = procdir + std::to_string(pid) + taskdir; + DIR *dirproc = opendir (process_task_dir.c_str()); + + if (dirproc) + { + struct dirent *direntry = NULL; + while ((direntry = readdir (dirproc)) != NULL) + { + if (direntry->d_type != DT_DIR || !IsDirNumeric (direntry->d_name)) + continue; + + lldb::tid_t tid = atoi(direntry->d_name); + TidMap::iterator it = tids_to_attach.find(tid); + if (it == tids_to_attach.end()) + { + tids_to_attach.insert(TidPair(tid, false)); + tids_changed = true; + } + } + closedir (dirproc); + } + + return tids_changed; +} + +static bool +GetELFProcessCPUType (const char *exe_path, ProcessInstanceInfo &process_info) +{ + // Clear the architecture. + process_info.GetArchitecture().Clear(); + + ModuleSpecList specs; + FileSpec filespec (exe_path, false); + const size_t num_specs = ObjectFile::GetModuleSpecifications (filespec, 0, 0, specs); + // GetModuleSpecifications() could fail if the executable has been deleted or is locked. + // But it shouldn't return more than 1 architecture. + assert(num_specs <= 1 && "Linux plugin supports only a single architecture"); + if (num_specs == 1) + { + ModuleSpec module_spec; + if (specs.GetModuleSpecAtIndex (0, module_spec) && module_spec.GetArchitecture().IsValid()) + { + process_info.GetArchitecture () = module_spec.GetArchitecture(); + return true; + } + } + return false; +} + +static bool +GetProcessAndStatInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info, ProcessStatInfo &stat_info, lldb::pid_t &tracerpid) +{ + tracerpid = 0; + process_info.Clear(); + ::memset (&stat_info, 0, sizeof(stat_info)); + stat_info.ppid = LLDB_INVALID_PROCESS_ID; + + // Use special code here because proc/[pid]/exe is a symbolic link. + char link_path[PATH_MAX]; + char exe_path[PATH_MAX] = ""; + if (snprintf (link_path, PATH_MAX, "/proc/%" PRIu64 "/exe", pid) <= 0) + return false; + + ssize_t len = readlink (link_path, exe_path, sizeof(exe_path) - 1); + if (len <= 0) + return false; + + // readlink does not append a null byte. + exe_path[len] = 0; + + // If the binary has been deleted, the link name has " (deleted)" appended. + // Remove if there. + static const ssize_t deleted_len = strlen(" (deleted)"); + if (len > deleted_len && + !strcmp(exe_path + len - deleted_len, " (deleted)")) + { + exe_path[len - deleted_len] = 0; + } + else + { + GetELFProcessCPUType (exe_path, process_info); + } + + process_info.SetProcessID(pid); + process_info.GetExecutableFile().SetFile(exe_path, false); + process_info.GetArchitecture().MergeFrom(HostInfo::GetArchitecture()); + + lldb::DataBufferSP buf_sp; + + // Get the process environment. + buf_sp = process_linux::ProcFileReader::ReadIntoDataBuffer(pid, "environ"); + Args &info_env = process_info.GetEnvironmentEntries(); + char *next_var = (char *)buf_sp->GetBytes(); + char *end_buf = next_var + buf_sp->GetByteSize(); + while (next_var < end_buf && 0 != *next_var) + { + info_env.AppendArgument(next_var); + next_var += strlen(next_var) + 1; + } + + // Get the command line used to start the process. + buf_sp = process_linux::ProcFileReader::ReadIntoDataBuffer(pid, "cmdline"); + + // Grab Arg0 first, if there is one. + char *cmd = (char *)buf_sp->GetBytes(); + if (cmd) + { + process_info.SetArg0(cmd); + + // Now process any remaining arguments. + Args &info_args = process_info.GetArguments(); + char *next_arg = cmd + strlen(cmd) + 1; + end_buf = cmd + buf_sp->GetByteSize(); + while (next_arg < end_buf && 0 != *next_arg) + { + info_args.AppendArgument(next_arg); + next_arg += strlen(next_arg) + 1; + } + } + + // Read /proc/$PID/stat to get our parent pid. + if (ReadProcPseudoFileStat (pid, stat_info)) + { + process_info.SetParentProcessID (stat_info.ppid); + } + + // Get User and Group IDs and get tracer pid. + GetLinuxProcessUserAndGroup (pid, process_info, tracerpid); + + return true; +} + +bool +Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) +{ + lldb::pid_t tracerpid; + ProcessStatInfo stat_info; + + return GetProcessAndStatInfo (pid, process_info, stat_info, tracerpid); +} + +size_t +Host::GetEnvironment (StringList &env) +{ + char **host_env = environ; + char *env_entry; + size_t i; + for (i=0; (env_entry = host_env[i]) != NULL; ++i) + env.AppendString(env_entry); + return i; +} + +Error +Host::ShellExpandArguments (ProcessLaunchInfo &launch_info) +{ + return Error("unimplemented"); +} diff --git a/source/Host/linux/HostInfoLinux.cpp b/source/Host/linux/HostInfoLinux.cpp new file mode 100644 index 0000000000000..4732a2a571b66 --- /dev/null +++ b/source/Host/linux/HostInfoLinux.cpp @@ -0,0 +1,282 @@ +//===-- HostInfoLinux.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/Core/Log.h" +#include "lldb/Host/linux/HostInfoLinux.h" + +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <sys/utsname.h> + +#include <algorithm> +#include <mutex> // std::once + +using namespace lldb_private; + +namespace +{ +struct HostInfoLinuxFields +{ + HostInfoLinuxFields() + : m_os_major(0) + , m_os_minor(0) + , m_os_update(0) + { + } + + std::string m_distribution_id; + uint32_t m_os_major; + uint32_t m_os_minor; + uint32_t m_os_update; +}; + +HostInfoLinuxFields *g_fields = nullptr; +} + +void +HostInfoLinux::Initialize() +{ + HostInfoPosix::Initialize(); + + g_fields = new HostInfoLinuxFields(); +} + +uint32_t +HostInfoLinux::GetMaxThreadNameLength() +{ + return 16; +} + +bool +HostInfoLinux::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update) +{ + static bool success = false; + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { + + struct utsname un; + if (uname(&un) == 0) + { + int status = sscanf(un.release, "%u.%u.%u", &g_fields->m_os_major, &g_fields->m_os_minor, &g_fields->m_os_update); + if (status == 3) + success = true; + else + { + // Some kernels omit the update version, so try looking for just "X.Y" and + // set update to 0. + g_fields->m_os_update = 0; + status = sscanf(un.release, "%u.%u", &g_fields->m_os_major, &g_fields->m_os_minor); + if (status == 2) + success = true; + } + } + }); + + + major = g_fields->m_os_major; + minor = g_fields->m_os_minor; + update = g_fields->m_os_update; + return success; +} + +bool +HostInfoLinux::GetOSBuildString(std::string &s) +{ + struct utsname un; + ::memset(&un, 0, sizeof(utsname)); + s.clear(); + + if (uname(&un) < 0) + return false; + + s.assign(un.release); + return true; +} + +bool +HostInfoLinux::GetOSKernelDescription(std::string &s) +{ + struct utsname un; + + ::memset(&un, 0, sizeof(utsname)); + s.clear(); + + if (uname(&un) < 0) + return false; + + s.assign(un.version); + return true; +} + +llvm::StringRef +HostInfoLinux::GetDistributionId() +{ + // Try to run 'lbs_release -i', and use that response + // for the distribution id. + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST)); + if (log) + log->Printf("attempting to determine Linux distribution..."); + + // check if the lsb_release command exists at one of the + // following paths + const char *const exe_paths[] = {"/bin/lsb_release", "/usr/bin/lsb_release"}; + + for (size_t exe_index = 0; exe_index < sizeof(exe_paths) / sizeof(exe_paths[0]); ++exe_index) + { + const char *const get_distribution_info_exe = exe_paths[exe_index]; + if (access(get_distribution_info_exe, F_OK)) + { + // this exe doesn't exist, move on to next exe + if (log) + log->Printf("executable doesn't exist: %s", get_distribution_info_exe); + continue; + } + + // execute the distribution-retrieval command, read output + std::string get_distribution_id_command(get_distribution_info_exe); + get_distribution_id_command += " -i"; + + FILE *file = popen(get_distribution_id_command.c_str(), "r"); + if (!file) + { + if (log) + log->Printf("failed to run command: \"%s\", cannot retrieve " + "platform information", + get_distribution_id_command.c_str()); + break; + } + + // retrieve the distribution id string. + char distribution_id[256] = {'\0'}; + if (fgets(distribution_id, sizeof(distribution_id) - 1, file) != NULL) + { + if (log) + log->Printf("distribution id command returned \"%s\"", distribution_id); + + const char *const distributor_id_key = "Distributor ID:\t"; + if (strstr(distribution_id, distributor_id_key)) + { + // strip newlines + std::string id_string(distribution_id + strlen(distributor_id_key)); + id_string.erase(std::remove(id_string.begin(), id_string.end(), '\n'), id_string.end()); + + // lower case it and convert whitespace to underscores + std::transform(id_string.begin(), id_string.end(), id_string.begin(), [](char ch) + { + return tolower(isspace(ch) ? '_' : ch); + }); + + g_fields->m_distribution_id = id_string; + if (log) + log->Printf("distribution id set to \"%s\"", g_fields->m_distribution_id.c_str()); + } + else + { + if (log) + log->Printf("failed to find \"%s\" field in \"%s\"", distributor_id_key, distribution_id); + } + } + else + { + if (log) + log->Printf("failed to retrieve distribution id, \"%s\" returned no" + " lines", + get_distribution_id_command.c_str()); + } + + // clean up the file + pclose(file); + } + }); + + return g_fields->m_distribution_id.c_str(); +} + +FileSpec +HostInfoLinux::GetProgramFileSpec() +{ + static FileSpec g_program_filespec; + + if (!g_program_filespec) + { + char exe_path[PATH_MAX]; + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); + if (len > 0) + { + exe_path[len] = 0; + g_program_filespec.SetFile(exe_path, false); + } + } + + return g_program_filespec; +} + +bool +HostInfoLinux::ComputeSupportExeDirectory(FileSpec &file_spec) +{ + if (HostInfoPosix::ComputeSupportExeDirectory(file_spec) && + file_spec.IsAbsolute() && + file_spec.Exists()) + return true; + file_spec.GetDirectory() = GetProgramFileSpec().GetDirectory(); + return !file_spec.GetDirectory().IsEmpty(); +} + +bool +HostInfoLinux::ComputeSystemPluginsDirectory(FileSpec &file_spec) +{ + FileSpec temp_file("/usr/lib/lldb", true); + file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str()); + return true; +} + +bool +HostInfoLinux::ComputeUserPluginsDirectory(FileSpec &file_spec) +{ + // XDG Base Directory Specification + // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + // If XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb. + const char *xdg_data_home = getenv("XDG_DATA_HOME"); + if (xdg_data_home && xdg_data_home[0]) + { + std::string user_plugin_dir(xdg_data_home); + user_plugin_dir += "/lldb"; + file_spec.GetDirectory().SetCString(user_plugin_dir.c_str()); + } + else + file_spec.GetDirectory().SetCString("~/.local/share/lldb"); + return true; +} + +void +HostInfoLinux::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64) +{ + HostInfoPosix::ComputeHostArchitectureSupport(arch_32, arch_64); + + const char *distribution_id = GetDistributionId().data(); + + // On Linux, "unknown" in the vendor slot isn't what we want for the default + // triple. It's probably an artifact of config.guess. + if (arch_32.IsValid()) + { + arch_32.SetDistributionId(distribution_id); + if (arch_32.GetTriple().getVendor() == llvm::Triple::UnknownVendor) + arch_32.GetTriple().setVendorName(llvm::StringRef()); + } + if (arch_64.IsValid()) + { + arch_64.SetDistributionId(distribution_id); + if (arch_64.GetTriple().getVendor() == llvm::Triple::UnknownVendor) + arch_64.GetTriple().setVendorName(llvm::StringRef()); + } +} diff --git a/source/Host/linux/HostThreadLinux.cpp b/source/Host/linux/HostThreadLinux.cpp new file mode 100644 index 0000000000000..2312ced0107b8 --- /dev/null +++ b/source/Host/linux/HostThreadLinux.cpp @@ -0,0 +1,52 @@ +//===-- HostThreadLinux.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/Core/DataBuffer.h" +#include "lldb/Host/linux/HostThreadLinux.h" +#include "Plugins/Process/Linux/ProcFileReader.h" + +#include "llvm/ADT/SmallVector.h" + +#include <pthread.h> + +using namespace lldb_private; + +HostThreadLinux::HostThreadLinux() + : HostThreadPosix() +{ +} + +HostThreadLinux::HostThreadLinux(lldb::thread_t thread) + : HostThreadPosix(thread) +{ +} + +void +HostThreadLinux::SetName(lldb::thread_t thread, llvm::StringRef name) +{ +#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__) + ::pthread_setname_np(thread, name.data()); +#else + (void) thread; + (void) name; +#endif +} + +void +HostThreadLinux::GetName(lldb::thread_t thread, llvm::SmallVectorImpl<char> &name) +{ + // Read /proc/$TID/comm file. + lldb::DataBufferSP buf_sp = process_linux::ProcFileReader::ReadIntoDataBuffer(thread, "comm"); + const char *comm_str = (const char *)buf_sp->GetBytes(); + const char *cr_str = ::strchr(comm_str, '\n'); + size_t length = cr_str ? (cr_str - comm_str) : strlen(comm_str); + + name.clear(); + name.append(comm_str, comm_str + length); +} diff --git a/source/Host/linux/LibcGlue.cpp b/source/Host/linux/LibcGlue.cpp new file mode 100644 index 0000000000000..63d026f76c628 --- /dev/null +++ b/source/Host/linux/LibcGlue.cpp @@ -0,0 +1,30 @@ +//===-- LibcGlue.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// This file adds functions missing from libc on older versions of linux + +#include <unistd.h> +#include <sys/syscall.h> +#include <lldb/Host/linux/Uio.h> +#include <cerrno> + +#ifndef HAVE_PROCESS_VM_READV // If the syscall wrapper is not available, provide one. +ssize_t process_vm_readv(::pid_t pid, + const struct iovec *local_iov, unsigned long liovcnt, + const struct iovec *remote_iov, unsigned long riovcnt, + unsigned long flags) +{ +#ifdef HAVE_NR_PROCESS_VM_READV // If we have the syscall number, we can issue the syscall ourselves. + return syscall(__NR_process_vm_readv, pid, local_iov, liovcnt, remote_iov, riovcnt, flags); +#else // If not, let's pretend the syscall is not present. + errno = ENOSYS; + return -1; +#endif +} +#endif diff --git a/source/Host/linux/ThisThread.cpp b/source/Host/linux/ThisThread.cpp new file mode 100644 index 0000000000000..1c68c8ba16d74 --- /dev/null +++ b/source/Host/linux/ThisThread.cpp @@ -0,0 +1,29 @@ +//===-- ThisThread.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/Host/HostNativeThread.h" +#include "lldb/Host/ThisThread.h" + +#include "llvm/ADT/SmallVector.h" + +#include <pthread.h> + +using namespace lldb_private; + +void +ThisThread::SetName(llvm::StringRef name) +{ + HostNativeThread::SetName(::pthread_self(), name); +} + +void +ThisThread::GetName(llvm::SmallVectorImpl<char> &name) +{ + HostNativeThread::GetName(::pthread_self(), name); +} |