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