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