]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Host/netbsd/Host.cpp
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Host / netbsd / Host.cpp
1 //===-- source/Host/netbsd/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 <dlfcn.h>
12 #include <execinfo.h>
13 #include <stdio.h>
14 #include <sys/proc.h>
15 #include <sys/sysctl.h>
16 #include <sys/types.h>
17
18 #include <limits.h>
19
20 #include <elf.h>
21 #include <kvm.h>
22 #include <sys/exec.h>
23 #include <sys/ptrace.h>
24
25 // C++ Includes
26 // Other libraries and framework includes
27 // Project includes
28 #include "lldb/Host/Host.h"
29 #include "lldb/Host/HostInfo.h"
30 #include "lldb/Target/Process.h"
31 #include "lldb/Utility/DataBufferHeap.h"
32 #include "lldb/Utility/DataExtractor.h"
33 #include "lldb/Utility/Endian.h"
34 #include "lldb/Utility/Log.h"
35 #include "lldb/Utility/NameMatches.h"
36 #include "lldb/Utility/Status.h"
37 #include "lldb/Utility/StreamString.h"
38
39 #include "llvm/Support/Host.h"
40
41 extern "C" {
42 extern char **environ;
43 }
44
45 using namespace lldb;
46 using namespace lldb_private;
47
48 Environment Host::GetEnvironment() { return Environment(environ); }
49
50 static bool GetNetBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
51                                  ProcessInstanceInfo &process_info) {
52   if (!process_info.ProcessIDIsValid())
53     return false;
54
55   int pid = process_info.GetProcessID();
56
57   int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV};
58
59   char arg_data[8192];
60   size_t arg_data_size = sizeof(arg_data);
61   if (::sysctl(mib, 4, arg_data, &arg_data_size, NULL, 0) != 0)
62     return false;
63
64   DataExtractor data(arg_data, arg_data_size, endian::InlHostByteOrder(),
65                      sizeof(void *));
66   lldb::offset_t offset = 0;
67   const char *cstr;
68
69   cstr = data.GetCStr(&offset);
70   if (!cstr)
71     return false;
72
73   process_info.GetExecutableFile().SetFile(cstr, false,
74                                            FileSpec::Style::native);
75
76   if (!(match_info_ptr == NULL ||
77         NameMatches(process_info.GetExecutableFile().GetFilename().GetCString(),
78                     match_info_ptr->GetNameMatchType(),
79                     match_info_ptr->GetProcessInfo().GetName())))
80     return false;
81
82   Args &proc_args = process_info.GetArguments();
83   while (1) {
84     const uint8_t *p = data.PeekData(offset, 1);
85     while ((p != NULL) && (*p == '\0') && offset < arg_data_size) {
86       ++offset;
87       p = data.PeekData(offset, 1);
88     }
89     if (p == NULL || offset >= arg_data_size)
90       break;
91
92     cstr = data.GetCStr(&offset);
93     if (!cstr)
94       break;
95
96     proc_args.AppendArgument(llvm::StringRef(cstr));
97   }
98
99   return true;
100 }
101
102 static bool GetNetBSDProcessCPUType(ProcessInstanceInfo &process_info) {
103   if (process_info.ProcessIDIsValid()) {
104     process_info.GetArchitecture() =
105         HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
106     return true;
107   }
108   process_info.GetArchitecture().Clear();
109   return false;
110 }
111
112 static bool GetNetBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {
113   ::kvm_t *kdp;
114   char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */
115
116   struct ::kinfo_proc2 *proc_kinfo;
117   const int pid = process_info.GetProcessID();
118   int nproc;
119
120   if (!process_info.ProcessIDIsValid())
121     goto error;
122
123   if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)
124     goto error;
125
126   if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_PID, pid,
127                                    sizeof(struct ::kinfo_proc2), &nproc)) ==
128       NULL) {
129     ::kvm_close(kdp);
130     goto error;
131   }
132
133   if (nproc < 1) {
134     ::kvm_close(kdp); /* XXX: we don't check for error here */
135     goto error;
136   }
137
138   process_info.SetParentProcessID(proc_kinfo->p_ppid);
139   process_info.SetUserID(proc_kinfo->p_ruid);
140   process_info.SetGroupID(proc_kinfo->p_rgid);
141   process_info.SetEffectiveUserID(proc_kinfo->p_uid);
142   process_info.SetEffectiveGroupID(proc_kinfo->p_gid);
143
144   ::kvm_close(kdp); /* XXX: we don't check for error here */
145
146   return true;
147
148 error:
149   process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);
150   process_info.SetUserID(UINT32_MAX);
151   process_info.SetGroupID(UINT32_MAX);
152   process_info.SetEffectiveUserID(UINT32_MAX);
153   process_info.SetEffectiveGroupID(UINT32_MAX);
154   return false;
155 }
156
157 uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
158                              ProcessInstanceInfoList &process_infos) {
159   const ::pid_t our_pid = ::getpid();
160   const ::uid_t our_uid = ::getuid();
161
162   const bool all_users =
163       match_info.GetMatchAllUsers() ||
164       // Special case, if lldb is being run as root we can attach to anything
165       (our_uid == 0);
166
167   kvm_t *kdp;
168   char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */
169   if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)
170     return 0;
171
172   struct ::kinfo_proc2 *proc_kinfo;
173   int nproc;
174   if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_ALL, 0,
175                                    sizeof(struct ::kinfo_proc2), &nproc)) ==
176       NULL) {
177     ::kvm_close(kdp);
178     return 0;
179   }
180
181   for (int i = 0; i < nproc; i++) {
182     if (proc_kinfo[i].p_pid < 1)
183       continue; /* not valid */
184     /* Make sure the user is acceptable */
185     if (!all_users && proc_kinfo[i].p_ruid != our_uid)
186       continue;
187
188     if (proc_kinfo[i].p_pid == our_pid ||  // Skip this process
189         proc_kinfo[i].p_pid == 0 ||        // Skip kernel (kernel pid is 0)
190         proc_kinfo[i].p_stat == LSZOMB ||  // Zombies are bad
191         proc_kinfo[i].p_flag & P_TRACED || // Being debugged?
192         proc_kinfo[i].p_flag & P_WEXIT)    // Working on exiting
193       continue;
194
195     // Every thread is a process in NetBSD, but all the threads of a single
196     // process have the same pid. Do not store the process info in the result
197     // list if a process with given identifier is already registered there.
198     if (proc_kinfo[i].p_nlwps > 1) {
199       bool already_registered = false;
200       for (size_t pi = 0; pi < process_infos.GetSize(); pi++) {
201         if (process_infos.GetProcessIDAtIndex(pi) == proc_kinfo[i].p_pid) {
202           already_registered = true;
203           break;
204         }
205       }
206
207       if (already_registered)
208         continue;
209     }
210     ProcessInstanceInfo process_info;
211     process_info.SetProcessID(proc_kinfo[i].p_pid);
212     process_info.SetParentProcessID(proc_kinfo[i].p_ppid);
213     process_info.SetUserID(proc_kinfo[i].p_ruid);
214     process_info.SetGroupID(proc_kinfo[i].p_rgid);
215     process_info.SetEffectiveUserID(proc_kinfo[i].p_uid);
216     process_info.SetEffectiveGroupID(proc_kinfo[i].p_gid);
217     // Make sure our info matches before we go fetch the name and cpu type
218     if (match_info.Matches(process_info) &&
219         GetNetBSDProcessArgs(&match_info, process_info)) {
220       GetNetBSDProcessCPUType(process_info);
221       if (match_info.Matches(process_info))
222         process_infos.Append(process_info);
223     }
224   }
225
226   kvm_close(kdp); /* XXX: we don't check for error here */
227
228   return process_infos.GetSize();
229 }
230
231 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
232   process_info.SetProcessID(pid);
233
234   if (GetNetBSDProcessArgs(NULL, process_info)) {
235     GetNetBSDProcessCPUType(process_info);
236     GetNetBSDProcessUserAndGroup(process_info);
237     return true;
238   }
239
240   process_info.Clear();
241   return false;
242 }
243
244 Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
245   return Status("unimplemented");
246 }