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