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       llvm::ListSeparator LS;
135       ArchSpec process_host_arch;
136       for (const ArchSpec &arch :
137            GetSupportedArchitectures(process_host_arch)) {
138         resolved_module_spec.GetArchitecture() = arch;
139         error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
140                                             module_search_paths_ptr, nullptr, nullptr);
141         // Did we find an executable using one of the
142         if (error.Success()) {
143           if (exe_module_sp && exe_module_sp->GetObjectFile())
144             break;
145           else
146             error.SetErrorToGenericError();
147         }
148 
149         arch_names << LS << arch.GetArchitectureName();
150       }
151 
152       if (error.Fail() || !exe_module_sp) {
153         if (FileSystem::Instance().Readable(
154                 resolved_module_spec.GetFileSpec())) {
155           error.SetErrorStringWithFormatv(
156               "'{0}' doesn't contain any '{1}' platform architectures: {2}",
157               resolved_module_spec.GetFileSpec(), GetPluginName(),
158               arch_names.GetData());
159         } else {
160           error.SetErrorStringWithFormat(
161               "'%s' is not readable",
162               resolved_module_spec.GetFileSpec().GetPath().c_str());
163         }
164       }
165     }
166   }
167 
168   return error;
169 }
170 
171 Status RemoteAwarePlatform::RunShellCommand(
172     llvm::StringRef command, const FileSpec &working_dir, int *status_ptr,
173     int *signo_ptr, std::string *command_output,
174     const Timeout<std::micro> &timeout) {
175   return RunShellCommand(llvm::StringRef(), command, working_dir, status_ptr,
176                          signo_ptr, command_output, timeout);
177 }
178 
179 Status RemoteAwarePlatform::RunShellCommand(
180     llvm::StringRef shell, llvm::StringRef command, const FileSpec &working_dir,
181     int *status_ptr, int *signo_ptr, std::string *command_output,
182     const Timeout<std::micro> &timeout) {
183   if (IsHost())
184     return Host::RunShellCommand(shell, command, working_dir, status_ptr,
185                                  signo_ptr, command_output, timeout);
186   if (m_remote_platform_sp)
187     return m_remote_platform_sp->RunShellCommand(shell, command, working_dir,
188                                                  status_ptr, signo_ptr,
189                                                  command_output, timeout);
190   return Status("unable to run a remote command without a platform");
191 }
192 
193 Status RemoteAwarePlatform::MakeDirectory(const FileSpec &file_spec,
194                                           uint32_t file_permissions) {
195   if (m_remote_platform_sp)
196     return m_remote_platform_sp->MakeDirectory(file_spec, file_permissions);
197   return Platform::MakeDirectory(file_spec, file_permissions);
198 }
199 
200 Status RemoteAwarePlatform::GetFilePermissions(const FileSpec &file_spec,
201                                                uint32_t &file_permissions) {
202   if (m_remote_platform_sp)
203     return m_remote_platform_sp->GetFilePermissions(file_spec,
204                                                     file_permissions);
205   return Platform::GetFilePermissions(file_spec, file_permissions);
206 }
207 
208 Status RemoteAwarePlatform::SetFilePermissions(const FileSpec &file_spec,
209                                                uint32_t file_permissions) {
210   if (m_remote_platform_sp)
211     return m_remote_platform_sp->SetFilePermissions(file_spec,
212                                                     file_permissions);
213   return Platform::SetFilePermissions(file_spec, file_permissions);
214 }
215 
216 lldb::user_id_t RemoteAwarePlatform::OpenFile(const FileSpec &file_spec,
217                                               File::OpenOptions flags,
218                                               uint32_t mode, Status &error) {
219   if (IsHost())
220     return FileCache::GetInstance().OpenFile(file_spec, flags, mode, error);
221   if (m_remote_platform_sp)
222     return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error);
223   return Platform::OpenFile(file_spec, flags, mode, error);
224 }
225 
226 bool RemoteAwarePlatform::CloseFile(lldb::user_id_t fd, Status &error) {
227   if (IsHost())
228     return FileCache::GetInstance().CloseFile(fd, error);
229   if (m_remote_platform_sp)
230     return m_remote_platform_sp->CloseFile(fd, error);
231   return Platform::CloseFile(fd, error);
232 }
233 
234 uint64_t RemoteAwarePlatform::ReadFile(lldb::user_id_t fd, uint64_t offset,
235                                        void *dst, uint64_t dst_len,
236                                        Status &error) {
237   if (IsHost())
238     return FileCache::GetInstance().ReadFile(fd, offset, dst, dst_len, error);
239   if (m_remote_platform_sp)
240     return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error);
241   return Platform::ReadFile(fd, offset, dst, dst_len, error);
242 }
243 
244 uint64_t RemoteAwarePlatform::WriteFile(lldb::user_id_t fd, uint64_t offset,
245                                         const void *src, uint64_t src_len,
246                                         Status &error) {
247   if (IsHost())
248     return FileCache::GetInstance().WriteFile(fd, offset, src, src_len, error);
249   if (m_remote_platform_sp)
250     return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error);
251   return Platform::WriteFile(fd, offset, src, src_len, error);
252 }
253 
254 lldb::user_id_t RemoteAwarePlatform::GetFileSize(const FileSpec &file_spec) {
255   if (IsHost()) {
256     uint64_t Size;
257     if (llvm::sys::fs::file_size(file_spec.GetPath(), Size))
258       return 0;
259     return Size;
260   }
261   if (m_remote_platform_sp)
262     return m_remote_platform_sp->GetFileSize(file_spec);
263   return Platform::GetFileSize(file_spec);
264 }
265 
266 Status RemoteAwarePlatform::CreateSymlink(const FileSpec &src,
267                                           const FileSpec &dst) {
268   if (IsHost())
269     return FileSystem::Instance().Symlink(src, dst);
270   if (m_remote_platform_sp)
271     return m_remote_platform_sp->CreateSymlink(src, dst);
272   return Platform::CreateSymlink(src, dst);
273 }
274 
275 bool RemoteAwarePlatform::GetFileExists(const FileSpec &file_spec) {
276   if (IsHost())
277     return FileSystem::Instance().Exists(file_spec);
278   if (m_remote_platform_sp)
279     return m_remote_platform_sp->GetFileExists(file_spec);
280   return Platform::GetFileExists(file_spec);
281 }
282 
283 Status RemoteAwarePlatform::Unlink(const FileSpec &file_spec) {
284   if (IsHost())
285     return llvm::sys::fs::remove(file_spec.GetPath());
286   if (m_remote_platform_sp)
287     return m_remote_platform_sp->Unlink(file_spec);
288   return Platform::Unlink(file_spec);
289 }
290 
291 bool RemoteAwarePlatform::CalculateMD5(const FileSpec &file_spec, uint64_t &low,
292                                        uint64_t &high) {
293   if (IsHost())
294     return Platform::CalculateMD5(file_spec, low, high);
295   if (m_remote_platform_sp)
296     return m_remote_platform_sp->CalculateMD5(file_spec, low, high);
297   return false;
298 }
299 
300 FileSpec RemoteAwarePlatform::GetRemoteWorkingDirectory() {
301   if (IsRemote() && m_remote_platform_sp)
302     return m_remote_platform_sp->GetRemoteWorkingDirectory();
303   return Platform::GetRemoteWorkingDirectory();
304 }
305 
306 bool RemoteAwarePlatform::SetRemoteWorkingDirectory(
307     const FileSpec &working_dir) {
308   if (IsRemote() && m_remote_platform_sp)
309     return m_remote_platform_sp->SetRemoteWorkingDirectory(working_dir);
310   return Platform::SetRemoteWorkingDirectory(working_dir);
311 }
312 
313 Status RemoteAwarePlatform::GetFileWithUUID(const FileSpec &platform_file,
314                                             const UUID *uuid_ptr,
315                                             FileSpec &local_file) {
316   if (IsRemote() && m_remote_platform_sp)
317     return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr,
318                                                  local_file);
319 
320   // Default to the local case
321   local_file = platform_file;
322   return Status();
323 }
324 
325 bool RemoteAwarePlatform::GetRemoteOSVersion() {
326   if (m_remote_platform_sp) {
327     m_os_version = m_remote_platform_sp->GetOSVersion();
328     return !m_os_version.empty();
329   }
330   return false;
331 }
332 
333 llvm::Optional<std::string> RemoteAwarePlatform::GetRemoteOSBuildString() {
334   if (m_remote_platform_sp)
335     return m_remote_platform_sp->GetRemoteOSBuildString();
336   return llvm::None;
337 }
338 
339 llvm::Optional<std::string> RemoteAwarePlatform::GetRemoteOSKernelDescription() {
340   if (m_remote_platform_sp)
341     return m_remote_platform_sp->GetRemoteOSKernelDescription();
342   return llvm::None;
343 }
344 
345 ArchSpec RemoteAwarePlatform::GetRemoteSystemArchitecture() {
346   if (m_remote_platform_sp)
347     return m_remote_platform_sp->GetRemoteSystemArchitecture();
348   return ArchSpec();
349 }
350 
351 const char *RemoteAwarePlatform::GetHostname() {
352   if (IsHost())
353     return Platform::GetHostname();
354   if (m_remote_platform_sp)
355     return m_remote_platform_sp->GetHostname();
356   return nullptr;
357 }
358 
359 UserIDResolver &RemoteAwarePlatform::GetUserIDResolver() {
360   if (IsHost())
361     return HostInfo::GetUserIDResolver();
362   if (m_remote_platform_sp)
363     return m_remote_platform_sp->GetUserIDResolver();
364   return UserIDResolver::GetNoopResolver();
365 }
366 
367 Environment RemoteAwarePlatform::GetEnvironment() {
368   if (IsRemote()) {
369     if (m_remote_platform_sp)
370       return m_remote_platform_sp->GetEnvironment();
371     return Environment();
372   }
373   return Host::GetEnvironment();
374 }
375 
376 bool RemoteAwarePlatform::IsConnected() const {
377   if (IsHost())
378     return true;
379   else if (m_remote_platform_sp)
380     return m_remote_platform_sp->IsConnected();
381   return false;
382 }
383 
384 bool RemoteAwarePlatform::GetProcessInfo(lldb::pid_t pid,
385                                          ProcessInstanceInfo &process_info) {
386   if (IsHost())
387     return Platform::GetProcessInfo(pid, process_info);
388   if (m_remote_platform_sp)
389     return m_remote_platform_sp->GetProcessInfo(pid, process_info);
390   return false;
391 }
392 
393 uint32_t
394 RemoteAwarePlatform::FindProcesses(const ProcessInstanceInfoMatch &match_info,
395                                    ProcessInstanceInfoList &process_infos) {
396   if (IsHost())
397     return Platform::FindProcesses(match_info, process_infos);
398   if (m_remote_platform_sp)
399     return m_remote_platform_sp->FindProcesses(match_info, process_infos);
400   return 0;
401 }
402 
403 lldb::ProcessSP RemoteAwarePlatform::ConnectProcess(llvm::StringRef connect_url,
404                                                     llvm::StringRef plugin_name,
405                                                     Debugger &debugger,
406                                                     Target *target,
407                                                     Status &error) {
408   if (m_remote_platform_sp)
409     return m_remote_platform_sp->ConnectProcess(connect_url, plugin_name,
410                                                 debugger, target, error);
411   return Platform::ConnectProcess(connect_url, plugin_name, debugger, target,
412                                   error);
413 }
414 
415 Status RemoteAwarePlatform::LaunchProcess(ProcessLaunchInfo &launch_info) {
416   Status error;
417 
418   if (IsHost()) {
419     error = Platform::LaunchProcess(launch_info);
420   } else {
421     if (m_remote_platform_sp)
422       error = m_remote_platform_sp->LaunchProcess(launch_info);
423     else
424       error.SetErrorString("the platform is not currently connected");
425   }
426   return error;
427 }
428 
429 Status RemoteAwarePlatform::KillProcess(const lldb::pid_t pid) {
430   if (IsHost())
431     return Platform::KillProcess(pid);
432   if (m_remote_platform_sp)
433     return m_remote_platform_sp->KillProcess(pid);
434   return Status("the platform is not currently connected");
435 }
436 
437 size_t RemoteAwarePlatform::ConnectToWaitingProcesses(Debugger &debugger,
438                                                 Status &error) {
439   if (m_remote_platform_sp)
440     return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error);
441   return Platform::ConnectToWaitingProcesses(debugger, error);
442 }
443