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