1 //===-- source/Host/linux/Host.cpp ------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 #include <stdio.h> 12 #include <sys/utsname.h> 13 #include <sys/types.h> 14 #include <sys/stat.h> 15 #include <fcntl.h> 16 17 18 // C++ Includes 19 // Other libraries and framework includes 20 // Project includes 21 #include "lldb/Core/Error.h" 22 #include "lldb/Target/Process.h" 23 24 #include "lldb/Host/Host.h" 25 #include "lldb/Core/DataBufferHeap.h" 26 #include "lldb/Core/DataExtractor.h" 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 namespace 32 { 33 34 lldb::DataBufferSP 35 ReadProcPseudoFile(lldb::pid_t pid, const char *name) 36 { 37 static const size_t path_size = 128; 38 static char path[path_size]; 39 lldb::DataBufferSP buf_sp; 40 41 int fd; 42 43 // Ideally, we would simply create a FileSpec and call ReadFileContents. 44 // However, files in procfs have zero size (since they are, in general, 45 // dynamically generated by the kernel) which is incompatible with the 46 // current ReadFileContents implementation. Therefore we simply stream the 47 // data into a DataBuffer ourselves. 48 if (snprintf(path, path_size, "/proc/%" PRIu64 "/%s", pid, name) < 0) 49 return buf_sp; 50 51 if ((fd = open(path, O_RDONLY, 0)) < 0) 52 return buf_sp; 53 54 size_t bytes_read = 0; 55 std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0)); 56 for (;;) 57 { 58 size_t avail = buf_ap->GetByteSize() - bytes_read; 59 ssize_t status = read(fd, buf_ap->GetBytes() + bytes_read, avail); 60 61 if (status < 0) 62 break; 63 64 bytes_read += status; 65 66 if (status == 0) 67 { 68 buf_ap->SetByteSize(bytes_read); 69 buf_sp.reset(buf_ap.release()); 70 break; 71 } 72 73 if (avail - status == 0) 74 buf_ap->SetByteSize(2 * buf_ap->GetByteSize()); 75 } 76 77 return buf_sp; 78 } 79 80 } // anonymous namespace 81 82 bool 83 Host::GetOSVersion(uint32_t &major, 84 uint32_t &minor, 85 uint32_t &update) 86 { 87 struct utsname un; 88 int status; 89 90 if (uname(&un)) 91 return false; 92 93 status = sscanf(un.release, "%u.%u.%u", &major, &minor, &update); 94 return status == 3; 95 } 96 97 Error 98 Host::LaunchProcess (ProcessLaunchInfo &launch_info) 99 { 100 Error error; 101 assert(!"Not implemented yet!!!"); 102 return error; 103 } 104 105 lldb::DataBufferSP 106 Host::GetAuxvData(lldb_private::Process *process) 107 { 108 return ReadProcPseudoFile(process->GetID(), "auxv"); 109 } 110 111 112 bool 113 Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) 114 { 115 process_info.Clear(); 116 process_info.SetProcessID(pid); 117 118 // Architecture is intentionally omitted because that's better resolved 119 // in other places (see ProcessPOSIX::DoAttachWithID(). 120 121 // Use special code here because proc/[pid]/exe is a symbolic link. 122 char link_path[PATH_MAX]; 123 char exe_path[PATH_MAX] = ""; 124 if (snprintf(link_path, PATH_MAX, "/proc/%" PRIu64 "/exe", pid) > 0) 125 { 126 ssize_t len = readlink(link_path, exe_path, sizeof(exe_path) - 1); 127 if (len > 0) 128 exe_path[len] = 0; 129 130 static const ssize_t deleted_len = strlen(" (deleted)"); 131 if (len > deleted_len && 132 !strcmp(exe_path + len - deleted_len, " (deleted)")) 133 { 134 exe_path[len - deleted_len] = 0; 135 } 136 } 137 process_info.GetExecutableFile().SetFile(exe_path, false); 138 139 lldb::DataBufferSP buf_sp; 140 141 // Get the process environment. 142 buf_sp = ReadProcPseudoFile(pid, "environ"); 143 Args &info_env = process_info.GetEnvironmentEntries(); 144 char *next_var = (char *)buf_sp->GetBytes(); 145 char *end_buf = next_var + buf_sp->GetByteSize(); 146 while (next_var < end_buf && 0 != *next_var) 147 { 148 info_env.AppendArgument(next_var); 149 next_var += strlen(next_var) + 1; 150 } 151 152 // Get the commond line used to start the process. 153 buf_sp = ReadProcPseudoFile(pid, "cmdline"); 154 155 // Grab Arg0 first. 156 char *cmd = (char *)buf_sp->GetBytes(); 157 process_info.SetArg0(cmd); 158 159 // Now process any remaining arguments. 160 Args &info_args = process_info.GetArguments(); 161 char *next_arg = cmd + strlen(cmd) + 1; 162 end_buf = cmd + buf_sp->GetByteSize(); 163 while (next_arg < end_buf && 0 != *next_arg) 164 { 165 info_args.AppendArgument(next_arg); 166 next_arg += strlen(next_arg) + 1; 167 } 168 169 // FIXME: Parse /proc/<pid>/status to get uid, gid, euid, egid and parent_pid 170 171 return true; 172 }