Host.cpp revision c350e13fd3351613345141bee7d8b2543df54636
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 <dirent.h>
16#include <fcntl.h>
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#include "lldb/Core/ModuleSpec.h"
29#include "lldb/Symbol/ObjectFile.h"
30
31using namespace lldb;
32using namespace lldb_private;
33
34typedef enum ProcessStateFlags
35{
36    eProcessStateRunning           = (1u << 0), // Running
37    eProcessStateSleeping          = (1u << 1), // Sleeping in an interruptible wait
38    eProcessStateWaiting           = (1u << 2), // Waiting in an uninterruptible disk sleep
39    eProcessStateZombie            = (1u << 3), // Zombie
40    eProcessStateTracedOrStopped   = (1u << 4), // Traced or stopped (on a signal)
41    eProcessStatePaging            = (1u << 5)  // Paging
42} ProcessStateFlags;
43
44typedef struct ProcessStatInfo
45{
46    lldb::pid_t ppid;           // Parent Process ID
47    uint32_t fProcessState;     // ProcessStateFlags
48} ProcessStatInfo;
49
50// Get the process info with additional information from /proc/$PID/stat (like process state, and tracer pid).
51static bool GetProcessAndStatInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info, ProcessStatInfo &stat_info, lldb::pid_t &tracerpid);
52
53
54namespace
55{
56
57lldb::DataBufferSP
58ReadProcPseudoFile (lldb::pid_t pid, const char *name)
59{
60    int fd;
61    char path[PATH_MAX];
62
63    // Make sure we've got a nil terminated buffer for all the folks calling
64    // GetBytes() directly off our returned DataBufferSP if we hit an error.
65    lldb::DataBufferSP buf_sp (new DataBufferHeap(1, 0));
66
67    // Ideally, we would simply create a FileSpec and call ReadFileContents.
68    // However, files in procfs have zero size (since they are, in general,
69    // dynamically generated by the kernel) which is incompatible with the
70    // current ReadFileContents implementation. Therefore we simply stream the
71    // data into a DataBuffer ourselves.
72    if (snprintf (path, PATH_MAX, "/proc/%" PRIu64 "/%s", pid, name) > 0)
73    {
74        if ((fd = open (path, O_RDONLY, 0)) >= 0)
75        {
76            size_t bytes_read = 0;
77            std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0));
78
79            for (;;)
80            {
81                size_t avail = buf_ap->GetByteSize() - bytes_read;
82                ssize_t status = read (fd, buf_ap->GetBytes() + bytes_read, avail);
83
84                if (status < 0)
85                    break;
86
87                if (status == 0)
88                {
89                    buf_ap->SetByteSize (bytes_read);
90                    buf_sp.reset (buf_ap.release());
91                    break;
92                }
93
94                bytes_read += status;
95
96                if (avail - status == 0)
97                    buf_ap->SetByteSize (2 * buf_ap->GetByteSize());
98            }
99
100            close (fd);
101        }
102    }
103
104    return buf_sp;
105}
106
107} // anonymous namespace
108
109static bool
110ReadProcPseudoFileStat (lldb::pid_t pid, ProcessStatInfo& stat_info)
111{
112    // Read the /proc/$PID/stat file.
113    lldb::DataBufferSP buf_sp = ReadProcPseudoFile (pid, "stat");
114
115    // The filename of the executable is stored in parenthesis right after the pid. We look for the closing
116    // parenthesis for the filename and work from there in case the name has something funky like ')' in it.
117    const char *filename_end = strrchr ((const char *)buf_sp->GetBytes(), ')');
118    if (filename_end)
119    {
120        char state = '\0';
121        int ppid = LLDB_INVALID_PROCESS_ID;
122
123        // Read state and ppid.
124        sscanf (filename_end + 1, " %c %d", &state, &ppid);
125
126        stat_info.ppid = ppid;
127
128        switch (state)
129        {
130            case 'R':
131                stat_info.fProcessState |= eProcessStateRunning;
132                break;
133            case 'S':
134                stat_info.fProcessState |= eProcessStateSleeping;
135                break;
136            case 'D':
137                stat_info.fProcessState |= eProcessStateWaiting;
138                break;
139            case 'Z':
140                stat_info.fProcessState |= eProcessStateZombie;
141                break;
142            case 'T':
143                stat_info.fProcessState |= eProcessStateTracedOrStopped;
144                break;
145            case 'W':
146                stat_info.fProcessState |= eProcessStatePaging;
147                break;
148        }
149
150        return true;
151    }
152
153    return false;
154}
155
156static void
157GetLinuxProcessUserAndGroup (lldb::pid_t pid, ProcessInstanceInfo &process_info, lldb::pid_t &tracerpid)
158{
159    tracerpid = 0;
160    uint32_t rUid = UINT32_MAX;     // Real User ID
161    uint32_t eUid = UINT32_MAX;     // Effective User ID
162    uint32_t rGid = UINT32_MAX;     // Real Group ID
163    uint32_t eGid = UINT32_MAX;     // Effective Group ID
164
165    // Read the /proc/$PID/status file and parse the Uid:, Gid:, and TracerPid: fields.
166    lldb::DataBufferSP buf_sp = ReadProcPseudoFile (pid, "status");
167
168    static const char uid_token[] = "Uid:";
169    char *buf_uid = strstr ((char *)buf_sp->GetBytes(), uid_token);
170    if (buf_uid)
171    {
172        // Real, effective, saved set, and file system UIDs. Read the first two.
173        buf_uid += sizeof(uid_token);
174        rUid = strtol (buf_uid, &buf_uid, 10);
175        eUid = strtol (buf_uid, &buf_uid, 10);
176    }
177
178    static const char gid_token[] = "Gid:";
179    char *buf_gid = strstr ((char *)buf_sp->GetBytes(), gid_token);
180    if (buf_gid)
181    {
182        // Real, effective, saved set, and file system GIDs. Read the first two.
183        buf_gid += sizeof(gid_token);
184        rGid = strtol (buf_gid, &buf_gid, 10);
185        eGid = strtol (buf_gid, &buf_gid, 10);
186    }
187
188    static const char tracerpid_token[] = "TracerPid:";
189    char *buf_tracerpid = strstr((char *)buf_sp->GetBytes(), tracerpid_token);
190    if (buf_tracerpid)
191    {
192        // Tracer PID. 0 if we're not being debugged.
193        buf_tracerpid += sizeof(tracerpid_token);
194        tracerpid = strtol (buf_tracerpid, &buf_tracerpid, 10);
195    }
196
197    process_info.SetUserID (rUid);
198    process_info.SetEffectiveUserID (eUid);
199    process_info.SetGroupID (rGid);
200    process_info.SetEffectiveGroupID (eGid);
201}
202
203bool
204Host::GetOSVersion(uint32_t &major,
205                   uint32_t &minor,
206                   uint32_t &update)
207{
208    struct utsname un;
209    int status;
210
211    if (uname(&un))
212        return false;
213
214    status = sscanf(un.release, "%u.%u.%u", &major, &minor, &update);
215    return status == 3;
216}
217
218Error
219Host::LaunchProcess (ProcessLaunchInfo &launch_info)
220{
221    Error error;
222    assert(!"Not implemented yet!!!");
223    return error;
224}
225
226lldb::DataBufferSP
227Host::GetAuxvData(lldb_private::Process *process)
228{
229    return ReadProcPseudoFile(process->GetID(), "auxv");
230}
231
232static bool
233IsDirNumeric(const char *dname)
234{
235    for (; *dname; dname++)
236    {
237        if (!isdigit (*dname))
238            return false;
239    }
240    return true;
241}
242
243uint32_t
244Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
245{
246    static const char procdir[] = "/proc/";
247
248    DIR *dirproc = opendir (procdir);
249    if (dirproc)
250    {
251        struct dirent *direntry = NULL;
252        const uid_t our_uid = getuid();
253        const lldb::pid_t our_pid = getpid();
254        bool all_users = match_info.GetMatchAllUsers();
255
256        while ((direntry = readdir (dirproc)) != NULL)
257        {
258            if (direntry->d_type != DT_DIR || !IsDirNumeric (direntry->d_name))
259                continue;
260
261            lldb::pid_t pid = atoi (direntry->d_name);
262
263            // Skip this process.
264            if (pid == our_pid)
265                continue;
266
267            lldb::pid_t tracerpid;
268            ProcessStatInfo stat_info;
269            ProcessInstanceInfo process_info;
270
271            if (!GetProcessAndStatInfo (pid, process_info, stat_info, tracerpid))
272                continue;
273
274            // Skip if process is being debugged.
275            if (tracerpid != 0)
276                continue;
277
278            // Skip zombies.
279            if (stat_info.fProcessState & eProcessStateZombie)
280                continue;
281
282            // Check for user match if we're not matching all users and not running as root.
283            if (!all_users && (our_uid != 0) && (process_info.GetUserID() != our_uid))
284                continue;
285
286            if (match_info.Matches (process_info))
287            {
288                process_infos.Append (process_info);
289            }
290        }
291
292        closedir (dirproc);
293    }
294
295    return process_infos.GetSize();
296}
297
298bool
299Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach)
300{
301    bool tids_changed = false;
302    static const char procdir[] = "/proc/";
303    static const char taskdir[] = "/task/";
304    std::string process_task_dir = procdir + std::to_string(pid) + taskdir;
305    DIR *dirproc = opendir (process_task_dir.c_str());
306
307    if (dirproc)
308    {
309        struct dirent *direntry = NULL;
310        while ((direntry = readdir (dirproc)) != NULL)
311        {
312            if (direntry->d_type != DT_DIR || !IsDirNumeric (direntry->d_name))
313                continue;
314
315            lldb::tid_t tid = atoi(direntry->d_name);
316            TidMap::iterator it = tids_to_attach.find(tid);
317            if (it == tids_to_attach.end())
318            {
319                tids_to_attach.insert(TidPair(tid, false));
320                tids_changed = true;
321            }
322        }
323        closedir (dirproc);
324    }
325
326    return tids_changed;
327}
328
329static bool
330GetELFProcessCPUType (const char *exe_path, ProcessInstanceInfo &process_info)
331{
332    // Clear the architecture.
333    process_info.GetArchitecture().Clear();
334
335    ModuleSpecList specs;
336    FileSpec filespec (exe_path, false);
337    const size_t num_specs = ObjectFile::GetModuleSpecifications (filespec, 0, specs);
338    // GetModuleSpecifications() could fail if the executable has been deleted or is locked.
339    // But it shouldn't return more than 1 architecture.
340    assert(num_specs <= 1 && "Linux plugin supports only a single architecture");
341    if (num_specs == 1)
342    {
343        ModuleSpec module_spec;
344        if (specs.GetModuleSpecAtIndex (0, module_spec) && module_spec.GetArchitecture().IsValid())
345        {
346            process_info.GetArchitecture () = module_spec.GetArchitecture();
347            return true;
348        }
349    }
350    return false;
351}
352
353static bool
354GetProcessAndStatInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info, ProcessStatInfo &stat_info, lldb::pid_t &tracerpid)
355{
356    tracerpid = 0;
357    process_info.Clear();
358    ::memset (&stat_info, 0, sizeof(stat_info));
359    stat_info.ppid = LLDB_INVALID_PROCESS_ID;
360
361    // Use special code here because proc/[pid]/exe is a symbolic link.
362    char link_path[PATH_MAX];
363    char exe_path[PATH_MAX] = "";
364    if (snprintf (link_path, PATH_MAX, "/proc/%" PRIu64 "/exe", pid) <= 0)
365        return false;
366
367    ssize_t len = readlink (link_path, exe_path, sizeof(exe_path) - 1);
368    if (len <= 0)
369        return false;
370
371    // readlink does not append a null byte.
372    exe_path[len] = 0;
373
374    // If the binary has been deleted, the link name has " (deleted)" appended.
375    //  Remove if there.
376    static const ssize_t deleted_len = strlen(" (deleted)");
377    if (len > deleted_len &&
378        !strcmp(exe_path + len - deleted_len, " (deleted)"))
379    {
380        exe_path[len - deleted_len] = 0;
381    }
382    else
383    {
384        GetELFProcessCPUType (exe_path, process_info);
385    }
386
387    process_info.SetProcessID(pid);
388    process_info.GetExecutableFile().SetFile(exe_path, false);
389
390    lldb::DataBufferSP buf_sp;
391
392    // Get the process environment.
393    buf_sp = ReadProcPseudoFile(pid, "environ");
394    Args &info_env = process_info.GetEnvironmentEntries();
395    char *next_var = (char *)buf_sp->GetBytes();
396    char *end_buf = next_var + buf_sp->GetByteSize();
397    while (next_var < end_buf && 0 != *next_var)
398    {
399        info_env.AppendArgument(next_var);
400        next_var += strlen(next_var) + 1;
401    }
402
403    // Get the commond line used to start the process.
404    buf_sp = ReadProcPseudoFile(pid, "cmdline");
405
406    // Grab Arg0 first.
407    char *cmd = (char *)buf_sp->GetBytes();
408    process_info.SetArg0(cmd);
409
410    // Now process any remaining arguments.
411    Args &info_args = process_info.GetArguments();
412    char *next_arg = cmd + strlen(cmd) + 1;
413    end_buf = cmd + buf_sp->GetByteSize();
414    while (next_arg < end_buf && 0 != *next_arg)
415    {
416        info_args.AppendArgument(next_arg);
417        next_arg += strlen(next_arg) + 1;
418    }
419
420    // Read /proc/$PID/stat to get our parent pid.
421    if (ReadProcPseudoFileStat (pid, stat_info))
422    {
423        process_info.SetParentProcessID (stat_info.ppid);
424    }
425
426    // Get User and Group IDs and get tracer pid.
427    GetLinuxProcessUserAndGroup (pid, process_info, tracerpid);
428
429    return true;
430}
431
432bool
433Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
434{
435    lldb::pid_t tracerpid;
436    ProcessStatInfo stat_info;
437
438    return GetProcessAndStatInfo (pid, process_info, stat_info, tracerpid);
439}
440
441void
442Host::ThreadCreated (const char *thread_name)
443{
444    if (!Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name))
445    {
446        // pthread_setname_np_func can fail if the thread name is longer than
447        //  the supported limit on Linux. When this occurs, the error ERANGE is returned
448        // and SetThreadName will fail. Let's drop it down to 16 characters and try again.
449        char namebuf[16];
450
451        // Thread names are coming in like '<lldb.comm.debugger.edit>' and '<lldb.comm.debugger.editline>'
452        // So just chopping the end of the string off leads to a lot of similar named threads.
453        // Go through the thread name and search for the last dot and use that.
454        const char *lastdot = ::strrchr( thread_name, '.' );
455
456        if (lastdot && lastdot != thread_name)
457            thread_name = lastdot + 1;
458        ::strncpy (namebuf, thread_name, sizeof(namebuf));
459        namebuf[ sizeof(namebuf) - 1 ] = 0;
460
461        int namebuflen = strlen(namebuf);
462        if (namebuflen > 0)
463        {
464            if (namebuf[namebuflen - 1] == '(' || namebuf[namebuflen - 1] == '>')
465            {
466                // Trim off trailing '(' and '>' characters for a bit more cleanup.
467                namebuflen--;
468                namebuf[namebuflen] = 0;
469            }
470            Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, namebuf);
471        }
472    }
473}
474
475void
476Host::Backtrace (Stream &strm, uint32_t max_frames)
477{
478    // TODO: Is there a way to backtrace the current process on linux?
479}
480
481size_t
482Host::GetEnvironment (StringList &env)
483{
484    // TODO: Is there a way to the host environment for this process on linux?
485    return 0;
486}
487