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