xref: /freebsd-src/contrib/llvm-project/lldb/source/Target/RemoteAwarePlatform.cpp (revision 5e801ac66d24704442eba426ed13c3effb8a34e7)
1 //===-- RemoteAwarePlatform.cpp -------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Target/RemoteAwarePlatform.h"
10 #include "lldb/Core/Module.h"
11 #include "lldb/Core/ModuleList.h"
12 #include "lldb/Core/ModuleSpec.h"
13 #include "lldb/Host/FileCache.h"
14 #include "lldb/Host/FileSystem.h"
15 #include "lldb/Host/Host.h"
16 #include "lldb/Host/HostInfo.h"
17 #include "lldb/Utility/StreamString.h"
18 
19 using namespace lldb_private;
20 using namespace lldb;
21 
22 bool RemoteAwarePlatform::GetModuleSpec(const FileSpec &module_file_spec,
23                                         const ArchSpec &arch,
24                                         ModuleSpec &module_spec) {
25   if (m_remote_platform_sp)
26     return m_remote_platform_sp->GetModuleSpec(module_file_spec, arch,
27                                                module_spec);
28 
29   return false;
30 }
31 
32 Status RemoteAwarePlatform::ResolveExecutable(
33     const ModuleSpec &module_spec, ModuleSP &exe_module_sp,
34     const FileSpecList *module_search_paths_ptr) {
35   Status error;
36   // Nothing special to do here, just use the actual file and architecture
37 
38   char exe_path[PATH_MAX];
39   ModuleSpec resolved_module_spec(module_spec);
40 
41   if (IsHost()) {
42     // If we have "ls" as the exe_file, resolve the executable location based
43     // on the current path variables
44     if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) {
45       resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
46       resolved_module_spec.GetFileSpec().SetFile(exe_path,
47                                                  FileSpec::Style::native);
48       FileSystem::Instance().Resolve(resolved_module_spec.GetFileSpec());
49     }
50 
51     if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
52       FileSystem::Instance().ResolveExecutableLocation(
53           resolved_module_spec.GetFileSpec());
54 
55     // Resolve any executable within a bundle on MacOSX
56     Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
57 
58     if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
59       error.Clear();
60     else {
61       const uint32_t permissions = FileSystem::Instance().GetPermissions(
62           resolved_module_spec.GetFileSpec());
63       if (permissions && (permissions & eFilePermissionsEveryoneR) == 0)
64         error.SetErrorStringWithFormat(
65             "executable '%s' is not readable",
66             resolved_module_spec.GetFileSpec().GetPath().c_str());
67       else
68         error.SetErrorStringWithFormat(
69             "unable to find executable for '%s'",
70             resolved_module_spec.GetFileSpec().GetPath().c_str());
71     }
72   } else {
73     if (m_remote_platform_sp) {
74       return GetCachedExecutable(resolved_module_spec, exe_module_sp,
75                                  module_search_paths_ptr);
76     }
77 
78     // We may connect to a process and use the provided executable (Don't use
79     // local $PATH).
80 
81     // Resolve any executable within a bundle on MacOSX
82     Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
83 
84     if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
85       error.Clear();
86     else
87       error.SetErrorStringWithFormat("the platform is not currently "
88                                      "connected, and '%s' doesn't exist in "
89                                      "the system root.",
90                                      exe_path);
91   }
92 
93   if (error.Success()) {
94     if (resolved_module_spec.GetArchitecture().IsValid()) {
95       error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
96                                           module_search_paths_ptr, nullptr, nullptr);
97       if (error.Fail()) {
98         // If we failed, it may be because the vendor and os aren't known. If
99 	// that is the case, try setting them to the host architecture and give
100 	// it another try.
101         llvm::Triple &module_triple =
102             resolved_module_spec.GetArchitecture().GetTriple();
103         bool is_vendor_specified =
104             (module_triple.getVendor() != llvm::Triple::UnknownVendor);
105         bool is_os_specified =
106             (module_triple.getOS() != llvm::Triple::UnknownOS);
107         if (!is_vendor_specified || !is_os_specified) {
108           const llvm::Triple &host_triple =
109               HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple();
110 
111           if (!is_vendor_specified)
112             module_triple.setVendorName(host_triple.getVendorName());
113           if (!is_os_specified)
114             module_triple.setOSName(host_triple.getOSName());
115 
116           error = ModuleList::GetSharedModule(resolved_module_spec,
117                                               exe_module_sp, module_search_paths_ptr, nullptr, nullptr);
118         }
119       }
120 
121       // TODO find out why exe_module_sp might be NULL
122       if (error.Fail() || !exe_module_sp || !exe_module_sp->GetObjectFile()) {
123         exe_module_sp.reset();
124         error.SetErrorStringWithFormat(
125             "'%s' doesn't contain the architecture %s",
126             resolved_module_spec.GetFileSpec().GetPath().c_str(),
127             resolved_module_spec.GetArchitecture().GetArchitectureName());
128       }
129     } else {
130       // No valid architecture was specified, ask the platform for the
131       // architectures that we should be using (in the correct order) and see
132       // if we can find a match that way
133       StreamString arch_names;
134       for (uint32_t idx = 0; GetSupportedArchitectureAtIndex(
135                idx, resolved_module_spec.GetArchitecture());
136            ++idx) {
137         error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
138                                             module_search_paths_ptr, nullptr, nullptr);
139         // Did we find an executable using one of the
140         if (error.Success()) {
141           if (exe_module_sp && exe_module_sp->GetObjectFile())
142             break;
143           else
144             error.SetErrorToGenericError();
145         }
146 
147         if (idx > 0)
148           arch_names.PutCString(", ");
149         arch_names.PutCString(
150             resolved_module_spec.GetArchitecture().GetArchitectureName());
151       }
152 
153       if (error.Fail() || !exe_module_sp) {
154         if (FileSystem::Instance().Readable(
155                 resolved_module_spec.GetFileSpec())) {
156           error.SetErrorStringWithFormatv(
157               "'{0}' doesn't contain any '{1}' platform architectures: {2}",
158               resolved_module_spec.GetFileSpec(), GetPluginName(),
159               arch_names.GetData());
160         } else {
161           error.SetErrorStringWithFormat(
162               "'%s' is not readable",
163               resolved_module_spec.GetFileSpec().GetPath().c_str());
164         }
165       }
166     }
167   }
168 
169   return error;
170 }
171 
172 Status RemoteAwarePlatform::RunShellCommand(
173     llvm::StringRef command, const FileSpec &working_dir, int *status_ptr,
174     int *signo_ptr, std::string *command_output,
175     const Timeout<std::micro> &timeout) {
176   return RunShellCommand(llvm::StringRef(), command, working_dir, status_ptr,
177                          signo_ptr, command_output, timeout);
178 }
179 
180 Status RemoteAwarePlatform::RunShellCommand(
181     llvm::StringRef shell, llvm::StringRef command, const FileSpec &working_dir,
182     int *status_ptr, int *signo_ptr, std::string *command_output,
183     const Timeout<std::micro> &timeout) {
184   if (IsHost())
185     return Host::RunShellCommand(shell, command, working_dir, status_ptr,
186                                  signo_ptr, command_output, timeout);
187   if (m_remote_platform_sp)
188     return m_remote_platform_sp->RunShellCommand(shell, command, working_dir,
189                                                  status_ptr, signo_ptr,
190                                                  command_output, timeout);
191   return Status("unable to run a remote command without a platform");
192 }
193 
194 Status RemoteAwarePlatform::MakeDirectory(const FileSpec &file_spec,
195                                           uint32_t file_permissions) {
196   if (m_remote_platform_sp)
197     return m_remote_platform_sp->MakeDirectory(file_spec, file_permissions);
198   return Platform::MakeDirectory(file_spec, file_permissions);
199 }
200 
201 Status RemoteAwarePlatform::GetFilePermissions(const FileSpec &file_spec,
202                                                uint32_t &file_permissions) {
203   if (m_remote_platform_sp)
204     return m_remote_platform_sp->GetFilePermissions(file_spec,
205                                                     file_permissions);
206   return Platform::GetFilePermissions(file_spec, file_permissions);
207 }
208 
209 Status RemoteAwarePlatform::SetFilePermissions(const FileSpec &file_spec,
210                                                uint32_t file_permissions) {
211   if (m_remote_platform_sp)
212     return m_remote_platform_sp->SetFilePermissions(file_spec,
213                                                     file_permissions);
214   return Platform::SetFilePermissions(file_spec, file_permissions);
215 }
216 
217 lldb::user_id_t RemoteAwarePlatform::OpenFile(const FileSpec &file_spec,
218                                               File::OpenOptions flags,
219                                               uint32_t mode, Status &error) {
220   if (IsHost())
221     return FileCache::GetInstance().OpenFile(file_spec, flags, mode, error);
222   if (m_remote_platform_sp)
223     return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error);
224   return Platform::OpenFile(file_spec, flags, mode, error);
225 }
226 
227 bool RemoteAwarePlatform::CloseFile(lldb::user_id_t fd, Status &error) {
228   if (IsHost())
229     return FileCache::GetInstance().CloseFile(fd, error);
230   if (m_remote_platform_sp)
231     return m_remote_platform_sp->CloseFile(fd, error);
232   return Platform::CloseFile(fd, error);
233 }
234 
235 uint64_t RemoteAwarePlatform::ReadFile(lldb::user_id_t fd, uint64_t offset,
236                                        void *dst, uint64_t dst_len,
237                                        Status &error) {
238   if (IsHost())
239     return FileCache::GetInstance().ReadFile(fd, offset, dst, dst_len, error);
240   if (m_remote_platform_sp)
241     return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error);
242   return Platform::ReadFile(fd, offset, dst, dst_len, error);
243 }
244 
245 uint64_t RemoteAwarePlatform::WriteFile(lldb::user_id_t fd, uint64_t offset,
246                                         const void *src, uint64_t src_len,
247                                         Status &error) {
248   if (IsHost())
249     return FileCache::GetInstance().WriteFile(fd, offset, src, src_len, error);
250   if (m_remote_platform_sp)
251     return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error);
252   return Platform::WriteFile(fd, offset, src, src_len, error);
253 }
254 
255 lldb::user_id_t RemoteAwarePlatform::GetFileSize(const FileSpec &file_spec) {
256   if (IsHost()) {
257     uint64_t Size;
258     if (llvm::sys::fs::file_size(file_spec.GetPath(), Size))
259       return 0;
260     return Size;
261   }
262   if (m_remote_platform_sp)
263     return m_remote_platform_sp->GetFileSize(file_spec);
264   return Platform::GetFileSize(file_spec);
265 }
266 
267 Status RemoteAwarePlatform::CreateSymlink(const FileSpec &src,
268                                           const FileSpec &dst) {
269   if (IsHost())
270     return FileSystem::Instance().Symlink(src, dst);
271   if (m_remote_platform_sp)
272     return m_remote_platform_sp->CreateSymlink(src, dst);
273   return Platform::CreateSymlink(src, dst);
274 }
275 
276 bool RemoteAwarePlatform::GetFileExists(const FileSpec &file_spec) {
277   if (IsHost())
278     return FileSystem::Instance().Exists(file_spec);
279   if (m_remote_platform_sp)
280     return m_remote_platform_sp->GetFileExists(file_spec);
281   return Platform::GetFileExists(file_spec);
282 }
283 
284 Status RemoteAwarePlatform::Unlink(const FileSpec &file_spec) {
285   if (IsHost())
286     return llvm::sys::fs::remove(file_spec.GetPath());
287   if (m_remote_platform_sp)
288     return m_remote_platform_sp->Unlink(file_spec);
289   return Platform::Unlink(file_spec);
290 }
291 
292 bool RemoteAwarePlatform::CalculateMD5(const FileSpec &file_spec, uint64_t &low,
293                                        uint64_t &high) {
294   if (IsHost())
295     return Platform::CalculateMD5(file_spec, low, high);
296   if (m_remote_platform_sp)
297     return m_remote_platform_sp->CalculateMD5(file_spec, low, high);
298   return false;
299 }
300 
301 FileSpec RemoteAwarePlatform::GetRemoteWorkingDirectory() {
302   if (IsRemote() && m_remote_platform_sp)
303     return m_remote_platform_sp->GetRemoteWorkingDirectory();
304   return Platform::GetRemoteWorkingDirectory();
305 }
306 
307 bool RemoteAwarePlatform::SetRemoteWorkingDirectory(
308     const FileSpec &working_dir) {
309   if (IsRemote() && m_remote_platform_sp)
310     return m_remote_platform_sp->SetRemoteWorkingDirectory(working_dir);
311   return Platform::SetRemoteWorkingDirectory(working_dir);
312 }
313 
314 Status RemoteAwarePlatform::GetFileWithUUID(const FileSpec &platform_file,
315                                             const UUID *uuid_ptr,
316                                             FileSpec &local_file) {
317   if (IsRemote() && m_remote_platform_sp)
318     return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr,
319                                                  local_file);
320 
321   // Default to the local case
322   local_file = platform_file;
323   return Status();
324 }
325 
326 bool RemoteAwarePlatform::GetRemoteOSVersion() {
327   if (m_remote_platform_sp) {
328     m_os_version = m_remote_platform_sp->GetOSVersion();
329     return !m_os_version.empty();
330   }
331   return false;
332 }
333 
334 llvm::Optional<std::string> RemoteAwarePlatform::GetRemoteOSBuildString() {
335   if (m_remote_platform_sp)
336     return m_remote_platform_sp->GetRemoteOSBuildString();
337   return llvm::None;
338 }
339 
340 llvm::Optional<std::string> RemoteAwarePlatform::GetRemoteOSKernelDescription() {
341   if (m_remote_platform_sp)
342     return m_remote_platform_sp->GetRemoteOSKernelDescription();
343   return llvm::None;
344 }
345 
346 ArchSpec RemoteAwarePlatform::GetRemoteSystemArchitecture() {
347   if (m_remote_platform_sp)
348     return m_remote_platform_sp->GetRemoteSystemArchitecture();
349   return ArchSpec();
350 }
351 
352 const char *RemoteAwarePlatform::GetHostname() {
353   if (IsHost())
354     return Platform::GetHostname();
355   if (m_remote_platform_sp)
356     return m_remote_platform_sp->GetHostname();
357   return nullptr;
358 }
359 
360 UserIDResolver &RemoteAwarePlatform::GetUserIDResolver() {
361   if (IsHost())
362     return HostInfo::GetUserIDResolver();
363   if (m_remote_platform_sp)
364     return m_remote_platform_sp->GetUserIDResolver();
365   return UserIDResolver::GetNoopResolver();
366 }
367 
368 Environment RemoteAwarePlatform::GetEnvironment() {
369   if (IsRemote()) {
370     if (m_remote_platform_sp)
371       return m_remote_platform_sp->GetEnvironment();
372     return Environment();
373   }
374   return Host::GetEnvironment();
375 }
376 
377 bool RemoteAwarePlatform::IsConnected() const {
378   if (IsHost())
379     return true;
380   else if (m_remote_platform_sp)
381     return m_remote_platform_sp->IsConnected();
382   return false;
383 }
384 
385 bool RemoteAwarePlatform::GetProcessInfo(lldb::pid_t pid,
386                                          ProcessInstanceInfo &process_info) {
387   if (IsHost())
388     return Platform::GetProcessInfo(pid, process_info);
389   if (m_remote_platform_sp)
390     return m_remote_platform_sp->GetProcessInfo(pid, process_info);
391   return false;
392 }
393 
394 uint32_t
395 RemoteAwarePlatform::FindProcesses(const ProcessInstanceInfoMatch &match_info,
396                                    ProcessInstanceInfoList &process_infos) {
397   if (IsHost())
398     return Platform::FindProcesses(match_info, process_infos);
399   if (m_remote_platform_sp)
400     return m_remote_platform_sp->FindProcesses(match_info, process_infos);
401   return 0;
402 }
403 
404 lldb::ProcessSP RemoteAwarePlatform::ConnectProcess(llvm::StringRef connect_url,
405                                                     llvm::StringRef plugin_name,
406                                                     Debugger &debugger,
407                                                     Target *target,
408                                                     Status &error) {
409   if (m_remote_platform_sp)
410     return m_remote_platform_sp->ConnectProcess(connect_url, plugin_name,
411                                                 debugger, target, error);
412   return Platform::ConnectProcess(connect_url, plugin_name, debugger, target,
413                                   error);
414 }
415 
416 Status RemoteAwarePlatform::LaunchProcess(ProcessLaunchInfo &launch_info) {
417   Status error;
418 
419   if (IsHost()) {
420     error = Platform::LaunchProcess(launch_info);
421   } else {
422     if (m_remote_platform_sp)
423       error = m_remote_platform_sp->LaunchProcess(launch_info);
424     else
425       error.SetErrorString("the platform is not currently connected");
426   }
427   return error;
428 }
429 
430 Status RemoteAwarePlatform::KillProcess(const lldb::pid_t pid) {
431   if (IsHost())
432     return Platform::KillProcess(pid);
433   if (m_remote_platform_sp)
434     return m_remote_platform_sp->KillProcess(pid);
435   return Status("the platform is not currently connected");
436 }
437 
438 size_t RemoteAwarePlatform::ConnectToWaitingProcesses(Debugger &debugger,
439                                                 Status &error) {
440   if (m_remote_platform_sp)
441     return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error);
442   return Platform::ConnectToWaitingProcesses(debugger, error);
443 }
444