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 | #include <optional> |
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(file_spec: resolved_module_spec.GetFileSpec())) { |
45 | resolved_module_spec.GetFileSpec().GetPath(path: exe_path, max_path_length: sizeof(exe_path)); |
46 | resolved_module_spec.GetFileSpec().SetFile(path: exe_path, |
47 | style: FileSpec::Style::native); |
48 | FileSystem::Instance().Resolve(file_spec&: resolved_module_spec.GetFileSpec()); |
49 | } |
50 | |
51 | if (!FileSystem::Instance().Exists(file_spec: resolved_module_spec.GetFileSpec())) |
52 | FileSystem::Instance().ResolveExecutableLocation( |
53 | file_spec&: resolved_module_spec.GetFileSpec()); |
54 | |
55 | // Resolve any executable within a bundle on MacOSX |
56 | Host::ResolveExecutableInBundle(file&: resolved_module_spec.GetFileSpec()); |
57 | |
58 | if (FileSystem::Instance().Exists(file_spec: resolved_module_spec.GetFileSpec())) |
59 | error.Clear(); |
60 | else { |
61 | const uint32_t permissions = FileSystem::Instance().GetPermissions( |
62 | file_spec: 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(module_spec&: resolved_module_spec, module_sp&: 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(file&: resolved_module_spec.GetFileSpec()); |
83 | |
84 | if (FileSystem::Instance().Exists(file_spec: 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(module_spec: resolved_module_spec, module_sp&: exe_module_sp, |
96 | module_search_paths_ptr, old_modules: nullptr, did_create_ptr: 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(arch_kind: 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(module_spec: resolved_module_spec, |
117 | module_sp&: exe_module_sp, module_search_paths_ptr, old_modules: nullptr, did_create_ptr: 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 | ArchSpec process_host_arch; |
136 | for (const ArchSpec &arch : |
137 | GetSupportedArchitectures(process_host_arch)) { |
138 | resolved_module_spec.GetArchitecture() = arch; |
139 | error = ModuleList::GetSharedModule(module_spec: resolved_module_spec, module_sp&: exe_module_sp, |
140 | module_search_paths_ptr, old_modules: nullptr, did_create_ptr: nullptr); |
141 | // Did we find an executable using one of the |
142 | if (error.Success()) { |
143 | if (exe_module_sp && exe_module_sp->GetObjectFile()) |
144 | break; |
145 | else |
146 | error.SetErrorToGenericError(); |
147 | } |
148 | |
149 | arch_names << LS << arch.GetArchitectureName(); |
150 | } |
151 | |
152 | if (error.Fail() || !exe_module_sp) { |
153 | if (FileSystem::Instance().Readable( |
154 | file_spec: resolved_module_spec.GetFileSpec())) { |
155 | error.SetErrorStringWithFormatv( |
156 | format: "'{0}' doesn't contain any '{1}' platform architectures: {2}" , |
157 | args&: resolved_module_spec.GetFileSpec(), args: GetPluginName(), |
158 | args: arch_names.GetData()); |
159 | } else { |
160 | error.SetErrorStringWithFormat( |
161 | "'%s' is not readable" , |
162 | resolved_module_spec.GetFileSpec().GetPath().c_str()); |
163 | } |
164 | } |
165 | } |
166 | } |
167 | |
168 | return error; |
169 | } |
170 | |
171 | Status RemoteAwarePlatform::RunShellCommand( |
172 | llvm::StringRef command, const FileSpec &working_dir, int *status_ptr, |
173 | int *signo_ptr, std::string *command_output, |
174 | const Timeout<std::micro> &timeout) { |
175 | return RunShellCommand(interpreter: llvm::StringRef(), command, working_dir, status_ptr, |
176 | signo_ptr, command_output, timeout); |
177 | } |
178 | |
179 | Status RemoteAwarePlatform::RunShellCommand( |
180 | llvm::StringRef shell, llvm::StringRef command, const FileSpec &working_dir, |
181 | int *status_ptr, int *signo_ptr, std::string *command_output, |
182 | const Timeout<std::micro> &timeout) { |
183 | if (m_remote_platform_sp) |
184 | return m_remote_platform_sp->RunShellCommand(shell, command, working_dir, |
185 | status_ptr, signo_ptr, |
186 | command_output, timeout); |
187 | return Platform::RunShellCommand(shell, command, working_dir, status_ptr, |
188 | signo_ptr, command_output, timeout); |
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, permissions: file_permissions); |
195 | return Platform::MakeDirectory(file_spec, permissions: 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 (m_remote_platform_sp) |
218 | return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error); |
219 | return Platform::OpenFile(file_spec, flags, mode, error); |
220 | } |
221 | |
222 | bool RemoteAwarePlatform::CloseFile(lldb::user_id_t fd, Status &error) { |
223 | if (m_remote_platform_sp) |
224 | return m_remote_platform_sp->CloseFile(fd, error); |
225 | return Platform::CloseFile(fd, error); |
226 | } |
227 | |
228 | uint64_t RemoteAwarePlatform::ReadFile(lldb::user_id_t fd, uint64_t offset, |
229 | void *dst, uint64_t dst_len, |
230 | Status &error) { |
231 | if (m_remote_platform_sp) |
232 | return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error); |
233 | return Platform::ReadFile(fd, offset, dst, dst_len, error); |
234 | } |
235 | |
236 | uint64_t RemoteAwarePlatform::WriteFile(lldb::user_id_t fd, uint64_t offset, |
237 | const void *src, uint64_t src_len, |
238 | Status &error) { |
239 | if (m_remote_platform_sp) |
240 | return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error); |
241 | return Platform::WriteFile(fd, offset, src, src_len, error); |
242 | } |
243 | |
244 | lldb::user_id_t RemoteAwarePlatform::GetFileSize(const FileSpec &file_spec) { |
245 | if (m_remote_platform_sp) |
246 | return m_remote_platform_sp->GetFileSize(file_spec); |
247 | return Platform::GetFileSize(file_spec); |
248 | } |
249 | |
250 | Status RemoteAwarePlatform::CreateSymlink(const FileSpec &src, |
251 | const FileSpec &dst) { |
252 | if (m_remote_platform_sp) |
253 | return m_remote_platform_sp->CreateSymlink(src, dst); |
254 | return Platform::CreateSymlink(src, dst); |
255 | } |
256 | |
257 | bool RemoteAwarePlatform::GetFileExists(const FileSpec &file_spec) { |
258 | if (m_remote_platform_sp) |
259 | return m_remote_platform_sp->GetFileExists(file_spec); |
260 | return Platform::GetFileExists(file_spec); |
261 | } |
262 | |
263 | Status RemoteAwarePlatform::Unlink(const FileSpec &file_spec) { |
264 | if (m_remote_platform_sp) |
265 | return m_remote_platform_sp->Unlink(file_spec); |
266 | return Platform::Unlink(file_spec); |
267 | } |
268 | |
269 | bool RemoteAwarePlatform::CalculateMD5(const FileSpec &file_spec, uint64_t &low, |
270 | uint64_t &high) { |
271 | if (m_remote_platform_sp) |
272 | return m_remote_platform_sp->CalculateMD5(file_spec, low, high); |
273 | return Platform::CalculateMD5(file_spec, low, high); |
274 | } |
275 | |
276 | FileSpec RemoteAwarePlatform::GetRemoteWorkingDirectory() { |
277 | if (IsRemote() && m_remote_platform_sp) |
278 | return m_remote_platform_sp->GetRemoteWorkingDirectory(); |
279 | return Platform::GetRemoteWorkingDirectory(); |
280 | } |
281 | |
282 | bool RemoteAwarePlatform::SetRemoteWorkingDirectory( |
283 | const FileSpec &working_dir) { |
284 | if (IsRemote() && m_remote_platform_sp) |
285 | return m_remote_platform_sp->SetRemoteWorkingDirectory(working_dir); |
286 | return Platform::SetRemoteWorkingDirectory(working_dir); |
287 | } |
288 | |
289 | Status RemoteAwarePlatform::GetFileWithUUID(const FileSpec &platform_file, |
290 | const UUID *uuid_ptr, |
291 | FileSpec &local_file) { |
292 | if (IsRemote() && m_remote_platform_sp) |
293 | return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr, |
294 | local_file); |
295 | |
296 | // Default to the local case |
297 | local_file = platform_file; |
298 | return Status(); |
299 | } |
300 | |
301 | bool RemoteAwarePlatform::GetRemoteOSVersion() { |
302 | if (m_remote_platform_sp) { |
303 | m_os_version = m_remote_platform_sp->GetOSVersion(); |
304 | return !m_os_version.empty(); |
305 | } |
306 | return false; |
307 | } |
308 | |
309 | std::optional<std::string> RemoteAwarePlatform::GetRemoteOSBuildString() { |
310 | if (m_remote_platform_sp) |
311 | return m_remote_platform_sp->GetRemoteOSBuildString(); |
312 | return std::nullopt; |
313 | } |
314 | |
315 | std::optional<std::string> RemoteAwarePlatform::GetRemoteOSKernelDescription() { |
316 | if (m_remote_platform_sp) |
317 | return m_remote_platform_sp->GetRemoteOSKernelDescription(); |
318 | return std::nullopt; |
319 | } |
320 | |
321 | ArchSpec RemoteAwarePlatform::GetRemoteSystemArchitecture() { |
322 | if (m_remote_platform_sp) |
323 | return m_remote_platform_sp->GetRemoteSystemArchitecture(); |
324 | return ArchSpec(); |
325 | } |
326 | |
327 | const char *RemoteAwarePlatform::GetHostname() { |
328 | if (m_remote_platform_sp) |
329 | return m_remote_platform_sp->GetHostname(); |
330 | return Platform::GetHostname(); |
331 | } |
332 | |
333 | UserIDResolver &RemoteAwarePlatform::GetUserIDResolver() { |
334 | if (m_remote_platform_sp) |
335 | return m_remote_platform_sp->GetUserIDResolver(); |
336 | return Platform::GetUserIDResolver(); |
337 | } |
338 | |
339 | Environment RemoteAwarePlatform::GetEnvironment() { |
340 | if (m_remote_platform_sp) |
341 | return m_remote_platform_sp->GetEnvironment(); |
342 | return Platform::GetEnvironment(); |
343 | } |
344 | |
345 | bool RemoteAwarePlatform::IsConnected() const { |
346 | if (m_remote_platform_sp) |
347 | return m_remote_platform_sp->IsConnected(); |
348 | return Platform::IsConnected(); |
349 | } |
350 | |
351 | bool RemoteAwarePlatform::GetProcessInfo(lldb::pid_t pid, |
352 | ProcessInstanceInfo &process_info) { |
353 | if (m_remote_platform_sp) |
354 | return m_remote_platform_sp->GetProcessInfo(pid, proc_info&: process_info); |
355 | return Platform::GetProcessInfo(pid, proc_info&: process_info); |
356 | } |
357 | |
358 | uint32_t |
359 | RemoteAwarePlatform::FindProcesses(const ProcessInstanceInfoMatch &match_info, |
360 | ProcessInstanceInfoList &process_infos) { |
361 | if (m_remote_platform_sp) |
362 | return m_remote_platform_sp->FindProcesses(match_info, proc_infos&: process_infos); |
363 | return Platform::FindProcesses(match_info, proc_infos&: process_infos); |
364 | } |
365 | |
366 | lldb::ProcessSP RemoteAwarePlatform::ConnectProcess(llvm::StringRef connect_url, |
367 | llvm::StringRef plugin_name, |
368 | Debugger &debugger, |
369 | Target *target, |
370 | Status &error) { |
371 | if (m_remote_platform_sp) |
372 | return m_remote_platform_sp->ConnectProcess(connect_url, plugin_name, |
373 | debugger, target, error); |
374 | return Platform::ConnectProcess(connect_url, plugin_name, debugger, target, |
375 | error); |
376 | } |
377 | |
378 | Status RemoteAwarePlatform::LaunchProcess(ProcessLaunchInfo &launch_info) { |
379 | if (m_remote_platform_sp) |
380 | return m_remote_platform_sp->LaunchProcess(launch_info); |
381 | return Platform::LaunchProcess(launch_info); |
382 | } |
383 | |
384 | Status RemoteAwarePlatform::KillProcess(const lldb::pid_t pid) { |
385 | if (m_remote_platform_sp) |
386 | return m_remote_platform_sp->KillProcess(pid); |
387 | return Platform::KillProcess(pid); |
388 | } |
389 | |
390 | size_t RemoteAwarePlatform::ConnectToWaitingProcesses(Debugger &debugger, |
391 | Status &error) { |
392 | if (m_remote_platform_sp) |
393 | return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error); |
394 | return Platform::ConnectToWaitingProcesses(debugger, error); |
395 | } |
396 | |