//===-- 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 #include #include #include #include // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/Core/Error.h" #include "lldb/Target/Process.h" #include "lldb/Host/Host.h" #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataExtractor.h" using namespace lldb; using namespace lldb_private; namespace { lldb::DataBufferSP ReadProcPseudoFile(lldb::pid_t pid, const char *name) { static const size_t path_size = 128; static char path[path_size]; lldb::DataBufferSP buf_sp; int fd; // Ideally, we would simply create a FileSpec and call ReadFileContents. // However, files in procfs have zero size (since they are, in general, // dynamically generated by the kernel) which is incompatible with the // current ReadFileContents implementation. Therefore we simply stream the // data into a DataBuffer ourselves. if (snprintf(path, path_size, "/proc/%" PRIu64 "/%s", pid, name) < 0) return buf_sp; if ((fd = open(path, O_RDONLY, 0)) < 0) return buf_sp; size_t bytes_read = 0; std::unique_ptr buf_ap(new DataBufferHeap(1024, 0)); for (;;) { size_t avail = buf_ap->GetByteSize() - bytes_read; ssize_t status = read(fd, buf_ap->GetBytes() + bytes_read, avail); if (status < 0) break; bytes_read += status; if (status == 0) { buf_ap->SetByteSize(bytes_read); buf_sp.reset(buf_ap.release()); break; } if (avail - status == 0) buf_ap->SetByteSize(2 * buf_ap->GetByteSize()); } return buf_sp; } } // anonymous namespace bool Host::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update) { struct utsname un; int status; if (uname(&un)) return false; status = sscanf(un.release, "%u.%u.%u", &major, &minor, &update); return status == 3; } Error Host::LaunchProcess (ProcessLaunchInfo &launch_info) { Error error; assert(!"Not implemented yet!!!"); return error; } lldb::DataBufferSP Host::GetAuxvData(lldb_private::Process *process) { return ReadProcPseudoFile(process->GetID(), "auxv"); } bool Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) { process_info.Clear(); process_info.SetProcessID(pid); // Architecture is intentionally omitted because that's better resolved // in other places (see ProcessPOSIX::DoAttachWithID(). // 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) { ssize_t len = readlink(link_path, exe_path, sizeof(exe_path) - 1); if (len > 0) exe_path[len] = 0; 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; } } process_info.GetExecutableFile().SetFile(exe_path, false); lldb::DataBufferSP buf_sp; // Get the process environment. buf_sp = ReadProcPseudoFile(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 commond line used to start the process. buf_sp = ReadProcPseudoFile(pid, "cmdline"); // Grab Arg0 first. char *cmd = (char *)buf_sp->GetBytes(); 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; } // FIXME: Parse /proc//status to get uid, gid, euid, egid and parent_pid return true; }