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 }