xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1 //===-- PlatformPOSIX.cpp ---------------------------------------*- C++ -*-===//
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 "PlatformPOSIX.h"
10 
11 #include "lldb/Core/Debugger.h"
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/ModuleSpec.h"
14 #include "lldb/Core/ValueObject.h"
15 #include "lldb/Expression/DiagnosticManager.h"
16 #include "lldb/Expression/FunctionCaller.h"
17 #include "lldb/Expression/UserExpression.h"
18 #include "lldb/Expression/UtilityFunction.h"
19 #include "lldb/Host/File.h"
20 #include "lldb/Host/FileCache.h"
21 #include "lldb/Host/FileSystem.h"
22 #include "lldb/Host/Host.h"
23 #include "lldb/Host/HostInfo.h"
24 #include "lldb/Host/ProcessLaunchInfo.h"
25 #include "lldb/Symbol/ClangASTContext.h"
26 #include "lldb/Target/DynamicLoader.h"
27 #include "lldb/Target/ExecutionContext.h"
28 #include "lldb/Target/Process.h"
29 #include "lldb/Target/Thread.h"
30 #include "lldb/Utility/CleanUp.h"
31 #include "lldb/Utility/DataBufferHeap.h"
32 #include "lldb/Utility/FileSpec.h"
33 #include "lldb/Utility/Log.h"
34 #include "lldb/Utility/StreamString.h"
35 
36 using namespace lldb;
37 using namespace lldb_private;
38 
39 /// Default Constructor
40 PlatformPOSIX::PlatformPOSIX(bool is_host)
41     : RemoteAwarePlatform(is_host), // This is the local host platform
42       m_option_group_platform_rsync(new OptionGroupPlatformRSync()),
43       m_option_group_platform_ssh(new OptionGroupPlatformSSH()),
44       m_option_group_platform_caching(new OptionGroupPlatformCaching()) {}
45 
46 /// Destructor.
47 ///
48 /// The destructor is virtual since this class is designed to be
49 /// inherited from by the plug-in instance.
50 PlatformPOSIX::~PlatformPOSIX() {}
51 
52 lldb_private::OptionGroupOptions *PlatformPOSIX::GetConnectionOptions(
53     lldb_private::CommandInterpreter &interpreter) {
54   auto iter = m_options.find(&interpreter), end = m_options.end();
55   if (iter == end) {
56     std::unique_ptr<lldb_private::OptionGroupOptions> options(
57         new OptionGroupOptions());
58     options->Append(m_option_group_platform_rsync.get());
59     options->Append(m_option_group_platform_ssh.get());
60     options->Append(m_option_group_platform_caching.get());
61     m_options[&interpreter] = std::move(options);
62   }
63 
64   return m_options.at(&interpreter).get();
65 }
66 
67 Status
68 PlatformPOSIX::ResolveExecutable(const ModuleSpec &module_spec,
69                                  lldb::ModuleSP &exe_module_sp,
70                                  const FileSpecList *module_search_paths_ptr) {
71   Status error;
72   // Nothing special to do here, just use the actual file and architecture
73 
74   char exe_path[PATH_MAX];
75   ModuleSpec resolved_module_spec(module_spec);
76 
77   if (IsHost()) {
78     // If we have "ls" as the exe_file, resolve the executable location based
79     // on the current path variables
80     if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) {
81       resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
82       resolved_module_spec.GetFileSpec().SetFile(exe_path,
83                                                  FileSpec::Style::native);
84       FileSystem::Instance().Resolve(resolved_module_spec.GetFileSpec());
85     }
86 
87     if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
88       FileSystem::Instance().ResolveExecutableLocation(
89           resolved_module_spec.GetFileSpec());
90 
91     // Resolve any executable within a bundle on MacOSX
92     Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
93 
94     if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
95       error.Clear();
96     else {
97       const uint32_t permissions = FileSystem::Instance().GetPermissions(
98           resolved_module_spec.GetFileSpec());
99       if (permissions && (permissions & eFilePermissionsEveryoneR) == 0)
100         error.SetErrorStringWithFormat(
101             "executable '%s' is not readable",
102             resolved_module_spec.GetFileSpec().GetPath().c_str());
103       else
104         error.SetErrorStringWithFormat(
105             "unable to find executable for '%s'",
106             resolved_module_spec.GetFileSpec().GetPath().c_str());
107     }
108   } else {
109     if (m_remote_platform_sp) {
110       error =
111           GetCachedExecutable(resolved_module_spec, exe_module_sp,
112                               module_search_paths_ptr, *m_remote_platform_sp);
113     } else {
114       // We may connect to a process and use the provided executable (Don't use
115       // local $PATH).
116 
117       // Resolve any executable within a bundle on MacOSX
118       Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
119 
120       if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()))
121         error.Clear();
122       else
123         error.SetErrorStringWithFormat("the platform is not currently "
124                                        "connected, and '%s' doesn't exist in "
125                                        "the system root.",
126                                        exe_path);
127     }
128   }
129 
130   if (error.Success()) {
131     if (resolved_module_spec.GetArchitecture().IsValid()) {
132       error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
133                                           module_search_paths_ptr, nullptr, nullptr);
134       if (error.Fail()) {
135         // If we failed, it may be because the vendor and os aren't known. If
136 	// that is the case, try setting them to the host architecture and give
137 	// it another try.
138         llvm::Triple &module_triple =
139             resolved_module_spec.GetArchitecture().GetTriple();
140         bool is_vendor_specified =
141             (module_triple.getVendor() != llvm::Triple::UnknownVendor);
142         bool is_os_specified =
143             (module_triple.getOS() != llvm::Triple::UnknownOS);
144         if (!is_vendor_specified || !is_os_specified) {
145           const llvm::Triple &host_triple =
146               HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple();
147 
148           if (!is_vendor_specified)
149             module_triple.setVendorName(host_triple.getVendorName());
150           if (!is_os_specified)
151             module_triple.setOSName(host_triple.getOSName());
152 
153           error = ModuleList::GetSharedModule(resolved_module_spec,
154                                               exe_module_sp, module_search_paths_ptr, nullptr, nullptr);
155         }
156       }
157 
158       // TODO find out why exe_module_sp might be NULL
159       if (error.Fail() || !exe_module_sp || !exe_module_sp->GetObjectFile()) {
160         exe_module_sp.reset();
161         error.SetErrorStringWithFormat(
162             "'%s' doesn't contain the architecture %s",
163             resolved_module_spec.GetFileSpec().GetPath().c_str(),
164             resolved_module_spec.GetArchitecture().GetArchitectureName());
165       }
166     } else {
167       // No valid architecture was specified, ask the platform for the
168       // architectures that we should be using (in the correct order) and see
169       // if we can find a match that way
170       StreamString arch_names;
171       for (uint32_t idx = 0; GetSupportedArchitectureAtIndex(
172                idx, resolved_module_spec.GetArchitecture());
173            ++idx) {
174         error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
175                                             module_search_paths_ptr, nullptr, nullptr);
176         // Did we find an executable using one of the
177         if (error.Success()) {
178           if (exe_module_sp && exe_module_sp->GetObjectFile())
179             break;
180           else
181             error.SetErrorToGenericError();
182         }
183 
184         if (idx > 0)
185           arch_names.PutCString(", ");
186         arch_names.PutCString(
187             resolved_module_spec.GetArchitecture().GetArchitectureName());
188       }
189 
190       if (error.Fail() || !exe_module_sp) {
191         if (FileSystem::Instance().Readable(
192                 resolved_module_spec.GetFileSpec())) {
193           error.SetErrorStringWithFormat(
194               "'%s' doesn't contain any '%s' platform architectures: %s",
195               resolved_module_spec.GetFileSpec().GetPath().c_str(),
196               GetPluginName().GetCString(), arch_names.GetData());
197         } else {
198           error.SetErrorStringWithFormat(
199               "'%s' is not readable",
200               resolved_module_spec.GetFileSpec().GetPath().c_str());
201         }
202       }
203     }
204   }
205 
206   return error;
207 }
208 
209 static uint32_t chown_file(Platform *platform, const char *path,
210                            uint32_t uid = UINT32_MAX,
211                            uint32_t gid = UINT32_MAX) {
212   if (!platform || !path || *path == 0)
213     return UINT32_MAX;
214 
215   if (uid == UINT32_MAX && gid == UINT32_MAX)
216     return 0; // pretend I did chown correctly - actually I just didn't care
217 
218   StreamString command;
219   command.PutCString("chown ");
220   if (uid != UINT32_MAX)
221     command.Printf("%d", uid);
222   if (gid != UINT32_MAX)
223     command.Printf(":%d", gid);
224   command.Printf("%s", path);
225   int status;
226   platform->RunShellCommand(command.GetData(), nullptr, &status, nullptr,
227                             nullptr, std::chrono::seconds(10));
228   return status;
229 }
230 
231 lldb_private::Status
232 PlatformPOSIX::PutFile(const lldb_private::FileSpec &source,
233                        const lldb_private::FileSpec &destination, uint32_t uid,
234                        uint32_t gid) {
235   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
236 
237   if (IsHost()) {
238     if (FileSpec::Equal(source, destination, true))
239       return Status();
240     // cp src dst
241     // chown uid:gid dst
242     std::string src_path(source.GetPath());
243     if (src_path.empty())
244       return Status("unable to get file path for source");
245     std::string dst_path(destination.GetPath());
246     if (dst_path.empty())
247       return Status("unable to get file path for destination");
248     StreamString command;
249     command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
250     int status;
251     RunShellCommand(command.GetData(), nullptr, &status, nullptr, nullptr,
252                     std::chrono::seconds(10));
253     if (status != 0)
254       return Status("unable to perform copy");
255     if (uid == UINT32_MAX && gid == UINT32_MAX)
256       return Status();
257     if (chown_file(this, dst_path.c_str(), uid, gid) != 0)
258       return Status("unable to perform chown");
259     return Status();
260   } else if (m_remote_platform_sp) {
261     if (GetSupportsRSync()) {
262       std::string src_path(source.GetPath());
263       if (src_path.empty())
264         return Status("unable to get file path for source");
265       std::string dst_path(destination.GetPath());
266       if (dst_path.empty())
267         return Status("unable to get file path for destination");
268       StreamString command;
269       if (GetIgnoresRemoteHostname()) {
270         if (!GetRSyncPrefix())
271           command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(),
272                          dst_path.c_str());
273         else
274           command.Printf("rsync %s %s %s%s", GetRSyncOpts(), src_path.c_str(),
275                          GetRSyncPrefix(), dst_path.c_str());
276       } else
277         command.Printf("rsync %s %s %s:%s", GetRSyncOpts(), src_path.c_str(),
278                        GetHostname(), dst_path.c_str());
279       if (log)
280         log->Printf("[PutFile] Running command: %s\n", command.GetData());
281       int retcode;
282       Host::RunShellCommand(command.GetData(), nullptr, &retcode, nullptr,
283                             nullptr, std::chrono::minutes(1));
284       if (retcode == 0) {
285         // Don't chown a local file for a remote system
286         //                if (chown_file(this,dst_path.c_str(),uid,gid) != 0)
287         //                    return Status("unable to perform chown");
288         return Status();
289       }
290       // if we are still here rsync has failed - let's try the slow way before
291       // giving up
292     }
293   }
294   return Platform::PutFile(source, destination, uid, gid);
295 }
296 
297 lldb_private::Status PlatformPOSIX::GetFile(
298     const lldb_private::FileSpec &source,      // remote file path
299     const lldb_private::FileSpec &destination) // local file path
300 {
301   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
302 
303   // Check the args, first.
304   std::string src_path(source.GetPath());
305   if (src_path.empty())
306     return Status("unable to get file path for source");
307   std::string dst_path(destination.GetPath());
308   if (dst_path.empty())
309     return Status("unable to get file path for destination");
310   if (IsHost()) {
311     if (FileSpec::Equal(source, destination, true))
312       return Status("local scenario->source and destination are the same file "
313                     "path: no operation performed");
314     // cp src dst
315     StreamString cp_command;
316     cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str());
317     int status;
318     RunShellCommand(cp_command.GetData(), nullptr, &status, nullptr, nullptr,
319                     std::chrono::seconds(10));
320     if (status != 0)
321       return Status("unable to perform copy");
322     return Status();
323   } else if (m_remote_platform_sp) {
324     if (GetSupportsRSync()) {
325       StreamString command;
326       if (GetIgnoresRemoteHostname()) {
327         if (!GetRSyncPrefix())
328           command.Printf("rsync %s %s %s", GetRSyncOpts(), src_path.c_str(),
329                          dst_path.c_str());
330         else
331           command.Printf("rsync %s %s%s %s", GetRSyncOpts(), GetRSyncPrefix(),
332                          src_path.c_str(), dst_path.c_str());
333       } else
334         command.Printf("rsync %s %s:%s %s", GetRSyncOpts(),
335                        m_remote_platform_sp->GetHostname(), src_path.c_str(),
336                        dst_path.c_str());
337       if (log)
338         log->Printf("[GetFile] Running command: %s\n", command.GetData());
339       int retcode;
340       Host::RunShellCommand(command.GetData(), nullptr, &retcode, nullptr,
341                             nullptr, std::chrono::minutes(1));
342       if (retcode == 0)
343         return Status();
344       // If we are here, rsync has failed - let's try the slow way before
345       // giving up
346     }
347     // open src and dst
348     // read/write, read/write, read/write, ...
349     // close src
350     // close dst
351     if (log)
352       log->Printf("[GetFile] Using block by block transfer....\n");
353     Status error;
354     user_id_t fd_src = OpenFile(source, File::eOpenOptionRead,
355                                 lldb::eFilePermissionsFileDefault, error);
356 
357     if (fd_src == UINT64_MAX)
358       return Status("unable to open source file");
359 
360     uint32_t permissions = 0;
361     error = GetFilePermissions(source, permissions);
362 
363     if (permissions == 0)
364       permissions = lldb::eFilePermissionsFileDefault;
365 
366     user_id_t fd_dst = FileCache::GetInstance().OpenFile(
367         destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite |
368                          File::eOpenOptionTruncate,
369         permissions, error);
370 
371     if (fd_dst == UINT64_MAX) {
372       if (error.Success())
373         error.SetErrorString("unable to open destination file");
374     }
375 
376     if (error.Success()) {
377       lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
378       uint64_t offset = 0;
379       error.Clear();
380       while (error.Success()) {
381         const uint64_t n_read = ReadFile(fd_src, offset, buffer_sp->GetBytes(),
382                                          buffer_sp->GetByteSize(), error);
383         if (error.Fail())
384           break;
385         if (n_read == 0)
386           break;
387         if (FileCache::GetInstance().WriteFile(fd_dst, offset,
388                                                buffer_sp->GetBytes(), n_read,
389                                                error) != n_read) {
390           if (!error.Fail())
391             error.SetErrorString("unable to write to destination file");
392           break;
393         }
394         offset += n_read;
395       }
396     }
397     // Ignore the close error of src.
398     if (fd_src != UINT64_MAX)
399       CloseFile(fd_src, error);
400     // And close the dst file descriptot.
401     if (fd_dst != UINT64_MAX &&
402         !FileCache::GetInstance().CloseFile(fd_dst, error)) {
403       if (!error.Fail())
404         error.SetErrorString("unable to close destination file");
405     }
406     return error;
407   }
408   return Platform::GetFile(source, destination);
409 }
410 
411 std::string PlatformPOSIX::GetPlatformSpecificConnectionInformation() {
412   StreamString stream;
413   if (GetSupportsRSync()) {
414     stream.PutCString("rsync");
415     if ((GetRSyncOpts() && *GetRSyncOpts()) ||
416         (GetRSyncPrefix() && *GetRSyncPrefix()) || GetIgnoresRemoteHostname()) {
417       stream.Printf(", options: ");
418       if (GetRSyncOpts() && *GetRSyncOpts())
419         stream.Printf("'%s' ", GetRSyncOpts());
420       stream.Printf(", prefix: ");
421       if (GetRSyncPrefix() && *GetRSyncPrefix())
422         stream.Printf("'%s' ", GetRSyncPrefix());
423       if (GetIgnoresRemoteHostname())
424         stream.Printf("ignore remote-hostname ");
425     }
426   }
427   if (GetSupportsSSH()) {
428     stream.PutCString("ssh");
429     if (GetSSHOpts() && *GetSSHOpts())
430       stream.Printf(", options: '%s' ", GetSSHOpts());
431   }
432   if (GetLocalCacheDirectory() && *GetLocalCacheDirectory())
433     stream.Printf("cache dir: %s", GetLocalCacheDirectory());
434   if (stream.GetSize())
435     return stream.GetString();
436   else
437     return "";
438 }
439 
440 const lldb::UnixSignalsSP &PlatformPOSIX::GetRemoteUnixSignals() {
441   if (IsRemote() && m_remote_platform_sp)
442     return m_remote_platform_sp->GetRemoteUnixSignals();
443   return Platform::GetRemoteUnixSignals();
444 }
445 
446 Status PlatformPOSIX::ConnectRemote(Args &args) {
447   Status error;
448   if (IsHost()) {
449     error.SetErrorStringWithFormat(
450         "can't connect to the host platform '%s', always connected",
451         GetPluginName().GetCString());
452   } else {
453     if (!m_remote_platform_sp)
454       m_remote_platform_sp =
455           Platform::Create(ConstString("remote-gdb-server"), error);
456 
457     if (m_remote_platform_sp && error.Success())
458       error = m_remote_platform_sp->ConnectRemote(args);
459     else
460       error.SetErrorString("failed to create a 'remote-gdb-server' platform");
461 
462     if (error.Fail())
463       m_remote_platform_sp.reset();
464   }
465 
466   if (error.Success() && m_remote_platform_sp) {
467     if (m_option_group_platform_rsync.get() &&
468         m_option_group_platform_ssh.get() &&
469         m_option_group_platform_caching.get()) {
470       if (m_option_group_platform_rsync->m_rsync) {
471         SetSupportsRSync(true);
472         SetRSyncOpts(m_option_group_platform_rsync->m_rsync_opts.c_str());
473         SetRSyncPrefix(m_option_group_platform_rsync->m_rsync_prefix.c_str());
474         SetIgnoresRemoteHostname(
475             m_option_group_platform_rsync->m_ignores_remote_hostname);
476       }
477       if (m_option_group_platform_ssh->m_ssh) {
478         SetSupportsSSH(true);
479         SetSSHOpts(m_option_group_platform_ssh->m_ssh_opts.c_str());
480       }
481       SetLocalCacheDirectory(
482           m_option_group_platform_caching->m_cache_dir.c_str());
483     }
484   }
485 
486   return error;
487 }
488 
489 Status PlatformPOSIX::DisconnectRemote() {
490   Status error;
491 
492   if (IsHost()) {
493     error.SetErrorStringWithFormat(
494         "can't disconnect from the host platform '%s', always connected",
495         GetPluginName().GetCString());
496   } else {
497     if (m_remote_platform_sp)
498       error = m_remote_platform_sp->DisconnectRemote();
499     else
500       error.SetErrorString("the platform is not currently connected");
501   }
502   return error;
503 }
504 
505 lldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info,
506                                       Debugger &debugger, Target *target,
507                                       Status &error) {
508   lldb::ProcessSP process_sp;
509   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
510 
511   if (IsHost()) {
512     if (target == nullptr) {
513       TargetSP new_target_sp;
514 
515       error = debugger.GetTargetList().CreateTarget(
516           debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
517       target = new_target_sp.get();
518       if (log)
519         log->Printf("PlatformPOSIX::%s created new target", __FUNCTION__);
520     } else {
521       error.Clear();
522       if (log)
523         log->Printf("PlatformPOSIX::%s target already existed, setting target",
524                     __FUNCTION__);
525     }
526 
527     if (target && error.Success()) {
528       debugger.GetTargetList().SetSelectedTarget(target);
529       if (log) {
530         ModuleSP exe_module_sp = target->GetExecutableModule();
531         log->Printf("PlatformPOSIX::%s set selected target to %p %s",
532                     __FUNCTION__, (void *)target,
533                     exe_module_sp
534                         ? exe_module_sp->GetFileSpec().GetPath().c_str()
535                         : "<null>");
536       }
537 
538       process_sp =
539           target->CreateProcess(attach_info.GetListenerForProcess(debugger),
540                                 attach_info.GetProcessPluginName(), nullptr);
541 
542       if (process_sp) {
543         ListenerSP listener_sp = attach_info.GetHijackListener();
544         if (listener_sp == nullptr) {
545           listener_sp =
546               Listener::MakeListener("lldb.PlatformPOSIX.attach.hijack");
547           attach_info.SetHijackListener(listener_sp);
548         }
549         process_sp->HijackProcessEvents(listener_sp);
550         error = process_sp->Attach(attach_info);
551       }
552     }
553   } else {
554     if (m_remote_platform_sp)
555       process_sp =
556           m_remote_platform_sp->Attach(attach_info, debugger, target, error);
557     else
558       error.SetErrorString("the platform is not currently connected");
559   }
560   return process_sp;
561 }
562 
563 lldb::ProcessSP
564 PlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
565                             Target *target, // Can be NULL, if NULL create a new
566                                             // target, else use existing one
567                             Status &error) {
568   ProcessSP process_sp;
569 
570   if (IsHost()) {
571     // We are going to hand this process off to debugserver which will be in
572     // charge of setting the exit status.  However, we still need to reap it
573     // from lldb. So, make sure we use a exit callback which does not set exit
574     // status.
575     const bool monitor_signals = false;
576     launch_info.SetMonitorProcessCallback(
577         &ProcessLaunchInfo::NoOpMonitorCallback, monitor_signals);
578     process_sp = Platform::DebugProcess(launch_info, debugger, target, error);
579   } else {
580     if (m_remote_platform_sp)
581       process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger,
582                                                       target, error);
583     else
584       error.SetErrorString("the platform is not currently connected");
585   }
586   return process_sp;
587 }
588 
589 void PlatformPOSIX::CalculateTrapHandlerSymbolNames() {
590   m_trap_handlers.push_back(ConstString("_sigtramp"));
591 }
592 
593 Status PlatformPOSIX::EvaluateLibdlExpression(
594     lldb_private::Process *process, const char *expr_cstr,
595     llvm::StringRef expr_prefix, lldb::ValueObjectSP &result_valobj_sp) {
596   DynamicLoader *loader = process->GetDynamicLoader();
597   if (loader) {
598     Status error = loader->CanLoadImage();
599     if (error.Fail())
600       return error;
601   }
602 
603   ThreadSP thread_sp(process->GetThreadList().GetExpressionExecutionThread());
604   if (!thread_sp)
605     return Status("Selected thread isn't valid");
606 
607   StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0));
608   if (!frame_sp)
609     return Status("Frame 0 isn't valid");
610 
611   ExecutionContext exe_ctx;
612   frame_sp->CalculateExecutionContext(exe_ctx);
613   EvaluateExpressionOptions expr_options;
614   expr_options.SetUnwindOnError(true);
615   expr_options.SetIgnoreBreakpoints(true);
616   expr_options.SetExecutionPolicy(eExecutionPolicyAlways);
617   expr_options.SetLanguage(eLanguageTypeC_plus_plus);
618   expr_options.SetTrapExceptions(false); // dlopen can't throw exceptions, so
619                                          // don't do the work to trap them.
620   expr_options.SetTimeout(process->GetUtilityExpressionTimeout());
621 
622   Status expr_error;
623   ExpressionResults result =
624       UserExpression::Evaluate(exe_ctx, expr_options, expr_cstr, expr_prefix,
625                                result_valobj_sp, expr_error);
626   if (result != eExpressionCompleted)
627     return expr_error;
628 
629   if (result_valobj_sp->GetError().Fail())
630     return result_valobj_sp->GetError();
631   return Status();
632 }
633 
634 std::unique_ptr<UtilityFunction>
635 PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx,
636                                             Status &error) {
637   // Remember to prepend this with the prefix from
638   // GetLibdlFunctionDeclarations. The returned values are all in
639   // __lldb_dlopen_result for consistency. The wrapper returns a void * but
640   // doesn't use it because UtilityFunctions don't work with void returns at
641   // present.
642   static const char *dlopen_wrapper_code = R"(
643   struct __lldb_dlopen_result {
644     void *image_ptr;
645     const char *error_str;
646   };
647 
648   extern void *memcpy(void *, const void *, size_t size);
649   extern size_t strlen(const char *);
650 
651 
652   void * __lldb_dlopen_wrapper (const char *name,
653                                 const char *path_strings,
654                                 char *buffer,
655                                 __lldb_dlopen_result *result_ptr)
656   {
657     // This is the case where the name is the full path:
658     if (!path_strings) {
659       result_ptr->image_ptr = dlopen(name, 2);
660       if (result_ptr->image_ptr)
661         result_ptr->error_str = nullptr;
662       return nullptr;
663     }
664 
665     // This is the case where we have a list of paths:
666     size_t name_len = strlen(name);
667     while (path_strings && path_strings[0] != '\0') {
668       size_t path_len = strlen(path_strings);
669       memcpy((void *) buffer, (void *) path_strings, path_len);
670       buffer[path_len] = '/';
671       char *target_ptr = buffer+path_len+1;
672       memcpy((void *) target_ptr, (void *) name, name_len + 1);
673       result_ptr->image_ptr = dlopen(buffer, 2);
674       if (result_ptr->image_ptr) {
675         result_ptr->error_str = nullptr;
676         break;
677       }
678       result_ptr->error_str = dlerror();
679       path_strings = path_strings + path_len + 1;
680     }
681     return nullptr;
682   }
683   )";
684 
685   static const char *dlopen_wrapper_name = "__lldb_dlopen_wrapper";
686   Process *process = exe_ctx.GetProcessSP().get();
687   // Insert the dlopen shim defines into our generic expression:
688   std::string expr(GetLibdlFunctionDeclarations(process));
689   expr.append(dlopen_wrapper_code);
690   Status utility_error;
691   DiagnosticManager diagnostics;
692 
693   std::unique_ptr<UtilityFunction> dlopen_utility_func_up(process
694       ->GetTarget().GetUtilityFunctionForLanguage(expr.c_str(),
695                                                   eLanguageTypeObjC,
696                                                   dlopen_wrapper_name,
697                                                   utility_error));
698   if (utility_error.Fail()) {
699     error.SetErrorStringWithFormat("dlopen error: could not make utility"
700                                    "function: %s", utility_error.AsCString());
701     return nullptr;
702   }
703   if (!dlopen_utility_func_up->Install(diagnostics, exe_ctx)) {
704     error.SetErrorStringWithFormat("dlopen error: could not install utility"
705                                    "function: %s",
706                                    diagnostics.GetString().c_str());
707     return nullptr;
708   }
709 
710   Value value;
711   ValueList arguments;
712   FunctionCaller *do_dlopen_function = nullptr;
713 
714   // Fetch the clang types we will need:
715   ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
716 
717   CompilerType clang_void_pointer_type
718       = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
719   CompilerType clang_char_pointer_type
720         = ast->GetBasicType(eBasicTypeChar).GetPointerType();
721 
722   // We are passing four arguments, the basename, the list of places to look,
723   // a buffer big enough for all the path + name combos, and
724   // a pointer to the storage we've made for the result:
725   value.SetValueType(Value::eValueTypeScalar);
726   value.SetCompilerType(clang_void_pointer_type);
727   arguments.PushValue(value);
728   value.SetCompilerType(clang_char_pointer_type);
729   arguments.PushValue(value);
730   arguments.PushValue(value);
731   arguments.PushValue(value);
732 
733   do_dlopen_function = dlopen_utility_func_up->MakeFunctionCaller(
734       clang_void_pointer_type, arguments, exe_ctx.GetThreadSP(), utility_error);
735   if (utility_error.Fail()) {
736     error.SetErrorStringWithFormat("dlopen error: could not make function"
737                                    "caller: %s", utility_error.AsCString());
738     return nullptr;
739   }
740 
741   do_dlopen_function = dlopen_utility_func_up->GetFunctionCaller();
742   if (!do_dlopen_function) {
743     error.SetErrorString("dlopen error: could not get function caller.");
744     return nullptr;
745   }
746 
747   // We made a good utility function, so cache it in the process:
748   return dlopen_utility_func_up;
749 }
750 
751 uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
752                                     const lldb_private::FileSpec &remote_file,
753                                     const std::vector<std::string> *paths,
754                                     lldb_private::Status &error,
755                                     lldb_private::FileSpec *loaded_image) {
756   if (loaded_image)
757     loaded_image->Clear();
758 
759   std::string path;
760   path = remote_file.GetPath();
761 
762   ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();
763   if (!thread_sp) {
764     error.SetErrorString("dlopen error: no thread available to call dlopen.");
765     return LLDB_INVALID_IMAGE_TOKEN;
766   }
767 
768   DiagnosticManager diagnostics;
769 
770   ExecutionContext exe_ctx;
771   thread_sp->CalculateExecutionContext(exe_ctx);
772 
773   Status utility_error;
774   UtilityFunction *dlopen_utility_func;
775   ValueList arguments;
776   FunctionCaller *do_dlopen_function = nullptr;
777 
778   // The UtilityFunction is held in the Process.  Platforms don't track the
779   // lifespan of the Targets that use them, we can't put this in the Platform.
780   dlopen_utility_func = process->GetLoadImageUtilityFunction(
781       this, [&]() -> std::unique_ptr<UtilityFunction> {
782         return MakeLoadImageUtilityFunction(exe_ctx, error);
783       });
784   // If we couldn't make it, the error will be in error, so we can exit here.
785   if (!dlopen_utility_func)
786     return LLDB_INVALID_IMAGE_TOKEN;
787 
788   do_dlopen_function = dlopen_utility_func->GetFunctionCaller();
789   if (!do_dlopen_function) {
790     error.SetErrorString("dlopen error: could not get function caller.");
791     return LLDB_INVALID_IMAGE_TOKEN;
792   }
793   arguments = do_dlopen_function->GetArgumentValues();
794 
795   // Now insert the path we are searching for and the result structure into the
796   // target.
797   uint32_t permissions = ePermissionsReadable|ePermissionsWritable;
798   size_t path_len = path.size() + 1;
799   lldb::addr_t path_addr = process->AllocateMemory(path_len,
800                                                    permissions,
801                                                    utility_error);
802   if (path_addr == LLDB_INVALID_ADDRESS) {
803     error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
804                                     "for path: %s", utility_error.AsCString());
805     return LLDB_INVALID_IMAGE_TOKEN;
806   }
807 
808   // Make sure we deallocate the input string memory:
809   CleanUp path_cleanup([process, path_addr] {
810       process->DeallocateMemory(path_addr);
811   });
812 
813   process->WriteMemory(path_addr, path.c_str(), path_len, utility_error);
814   if (utility_error.Fail()) {
815     error.SetErrorStringWithFormat("dlopen error: could not write path string:"
816                                     " %s", utility_error.AsCString());
817     return LLDB_INVALID_IMAGE_TOKEN;
818   }
819 
820   // Make space for our return structure.  It is two pointers big: the token
821   // and the error string.
822   const uint32_t addr_size = process->GetAddressByteSize();
823   lldb::addr_t return_addr = process->CallocateMemory(2*addr_size,
824                                                       permissions,
825                                                       utility_error);
826   if (utility_error.Fail()) {
827     error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
828                                     "for path: %s", utility_error.AsCString());
829     return LLDB_INVALID_IMAGE_TOKEN;
830   }
831 
832   // Make sure we deallocate the result structure memory
833   CleanUp return_cleanup([process, return_addr] {
834       process->DeallocateMemory(return_addr);
835   });
836 
837   // This will be the address of the storage for paths, if we are using them,
838   // or nullptr to signal we aren't.
839   lldb::addr_t path_array_addr = 0x0;
840   llvm::Optional<CleanUp> path_array_cleanup;
841 
842   // This is the address to a buffer large enough to hold the largest path
843   // conjoined with the library name we're passing in.  This is a convenience
844   // to avoid having to call malloc in the dlopen function.
845   lldb::addr_t buffer_addr = 0x0;
846   llvm::Optional<CleanUp> buffer_cleanup;
847 
848   // Set the values into our args and write them to the target:
849   if (paths != nullptr) {
850     // First insert the paths into the target.  This is expected to be a
851     // continuous buffer with the strings laid out null terminated and
852     // end to end with an empty string terminating the buffer.
853     // We also compute the buffer's required size as we go.
854     size_t buffer_size = 0;
855     std::string path_array;
856     for (auto path : *paths) {
857       // Don't insert empty paths, they will make us abort the path
858       // search prematurely.
859       if (path.empty())
860         continue;
861       size_t path_size = path.size();
862       path_array.append(path);
863       path_array.push_back('\0');
864       if (path_size > buffer_size)
865         buffer_size = path_size;
866     }
867     path_array.push_back('\0');
868 
869     path_array_addr = process->AllocateMemory(path_array.size(),
870                                               permissions,
871                                               utility_error);
872     if (path_array_addr == LLDB_INVALID_ADDRESS) {
873       error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
874                                       "for path array: %s",
875                                       utility_error.AsCString());
876       return LLDB_INVALID_IMAGE_TOKEN;
877     }
878 
879     // Make sure we deallocate the paths array.
880     path_array_cleanup.emplace([process, path_array_addr] {
881         process->DeallocateMemory(path_array_addr);
882     });
883 
884     process->WriteMemory(path_array_addr, path_array.data(),
885                          path_array.size(), utility_error);
886 
887     if (utility_error.Fail()) {
888       error.SetErrorStringWithFormat("dlopen error: could not write path array:"
889                                      " %s", utility_error.AsCString());
890       return LLDB_INVALID_IMAGE_TOKEN;
891     }
892     // Now make spaces in the target for the buffer.  We need to add one for
893     // the '/' that the utility function will insert and one for the '\0':
894     buffer_size += path.size() + 2;
895 
896     buffer_addr = process->AllocateMemory(buffer_size,
897                                           permissions,
898                                           utility_error);
899     if (buffer_addr == LLDB_INVALID_ADDRESS) {
900       error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
901                                       "for buffer: %s",
902                                       utility_error.AsCString());
903       return LLDB_INVALID_IMAGE_TOKEN;
904     }
905 
906     // Make sure we deallocate the buffer memory:
907     buffer_cleanup.emplace([process, buffer_addr] {
908         process->DeallocateMemory(buffer_addr);
909     });
910   }
911 
912   arguments.GetValueAtIndex(0)->GetScalar() = path_addr;
913   arguments.GetValueAtIndex(1)->GetScalar() = path_array_addr;
914   arguments.GetValueAtIndex(2)->GetScalar() = buffer_addr;
915   arguments.GetValueAtIndex(3)->GetScalar() = return_addr;
916 
917   lldb::addr_t func_args_addr = LLDB_INVALID_ADDRESS;
918 
919   diagnostics.Clear();
920   if (!do_dlopen_function->WriteFunctionArguments(exe_ctx,
921                                                  func_args_addr,
922                                                  arguments,
923                                                  diagnostics)) {
924     error.SetErrorStringWithFormat("dlopen error: could not write function "
925                                    "arguments: %s",
926                                    diagnostics.GetString().c_str());
927     return LLDB_INVALID_IMAGE_TOKEN;
928   }
929 
930   // Make sure we clean up the args structure.  We can't reuse it because the
931   // Platform lives longer than the process and the Platforms don't get a
932   // signal to clean up cached data when a process goes away.
933   CleanUp args_cleanup([do_dlopen_function, &exe_ctx, func_args_addr] {
934     do_dlopen_function->DeallocateFunctionResults(exe_ctx, func_args_addr);
935   });
936 
937   // Now run the caller:
938   EvaluateExpressionOptions options;
939   options.SetExecutionPolicy(eExecutionPolicyAlways);
940   options.SetLanguage(eLanguageTypeC_plus_plus);
941   options.SetIgnoreBreakpoints(true);
942   options.SetUnwindOnError(true);
943   options.SetTrapExceptions(false); // dlopen can't throw exceptions, so
944                                     // don't do the work to trap them.
945   options.SetTimeout(process->GetUtilityExpressionTimeout());
946   options.SetIsForUtilityExpr(true);
947 
948   Value return_value;
949   // Fetch the clang types we will need:
950   ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
951 
952   CompilerType clang_void_pointer_type
953       = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
954 
955   return_value.SetCompilerType(clang_void_pointer_type);
956 
957   ExpressionResults results = do_dlopen_function->ExecuteFunction(
958       exe_ctx, &func_args_addr, options, diagnostics, return_value);
959   if (results != eExpressionCompleted) {
960     error.SetErrorStringWithFormat("dlopen error: failed executing "
961                                    "dlopen wrapper function: %s",
962                                    diagnostics.GetString().c_str());
963     return LLDB_INVALID_IMAGE_TOKEN;
964   }
965 
966   // Read the dlopen token from the return area:
967   lldb::addr_t token = process->ReadPointerFromMemory(return_addr,
968                                                       utility_error);
969   if (utility_error.Fail()) {
970     error.SetErrorStringWithFormat("dlopen error: could not read the return "
971                                     "struct: %s", utility_error.AsCString());
972     return LLDB_INVALID_IMAGE_TOKEN;
973   }
974 
975   // The dlopen succeeded!
976   if (token != 0x0) {
977     if (loaded_image && buffer_addr != 0x0)
978     {
979       // Capture the image which was loaded.  We leave it in the buffer on
980       // exit from the dlopen function, so we can just read it from there:
981       std::string name_string;
982       process->ReadCStringFromMemory(buffer_addr, name_string, utility_error);
983       if (utility_error.Success())
984         loaded_image->SetFile(name_string, llvm::sys::path::Style::posix);
985     }
986     return process->AddImageToken(token);
987   }
988 
989   // We got an error, lets read in the error string:
990   std::string dlopen_error_str;
991   lldb::addr_t error_addr
992     = process->ReadPointerFromMemory(return_addr + addr_size, utility_error);
993   if (utility_error.Fail()) {
994     error.SetErrorStringWithFormat("dlopen error: could not read error string: "
995                                     "%s", utility_error.AsCString());
996     return LLDB_INVALID_IMAGE_TOKEN;
997   }
998 
999   size_t num_chars = process->ReadCStringFromMemory(error_addr + addr_size,
1000                                                     dlopen_error_str,
1001                                                     utility_error);
1002   if (utility_error.Success() && num_chars > 0)
1003     error.SetErrorStringWithFormat("dlopen error: %s",
1004                                    dlopen_error_str.c_str());
1005   else
1006     error.SetErrorStringWithFormat("dlopen failed for unknown reasons.");
1007 
1008   return LLDB_INVALID_IMAGE_TOKEN;
1009 }
1010 
1011 Status PlatformPOSIX::UnloadImage(lldb_private::Process *process,
1012                                   uint32_t image_token) {
1013   const addr_t image_addr = process->GetImagePtrFromToken(image_token);
1014   if (image_addr == LLDB_INVALID_ADDRESS)
1015     return Status("Invalid image token");
1016 
1017   StreamString expr;
1018   expr.Printf("dlclose((void *)0x%" PRIx64 ")", image_addr);
1019   llvm::StringRef prefix = GetLibdlFunctionDeclarations(process);
1020   lldb::ValueObjectSP result_valobj_sp;
1021   Status error = EvaluateLibdlExpression(process, expr.GetData(), prefix,
1022                                          result_valobj_sp);
1023   if (error.Fail())
1024     return error;
1025 
1026   if (result_valobj_sp->GetError().Fail())
1027     return result_valobj_sp->GetError();
1028 
1029   Scalar scalar;
1030   if (result_valobj_sp->ResolveValue(scalar)) {
1031     if (scalar.UInt(1))
1032       return Status("expression failed: \"%s\"", expr.GetData());
1033     process->ResetImageToken(image_token);
1034   }
1035   return Status();
1036 }
1037 
1038 llvm::StringRef
1039 PlatformPOSIX::GetLibdlFunctionDeclarations(lldb_private::Process *process) {
1040   return R"(
1041               extern "C" void* dlopen(const char*, int);
1042               extern "C" void* dlsym(void*, const char*);
1043               extern "C" int   dlclose(void*);
1044               extern "C" char* dlerror(void);
1045              )";
1046 }
1047 
1048 size_t PlatformPOSIX::ConnectToWaitingProcesses(Debugger &debugger,
1049                                                 Status &error) {
1050   if (m_remote_platform_sp)
1051     return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error);
1052   return Platform::ConnectToWaitingProcesses(debugger, error);
1053 }
1054 
1055 ConstString PlatformPOSIX::GetFullNameForDylib(ConstString basename) {
1056   if (basename.IsEmpty())
1057     return basename;
1058 
1059   StreamString stream;
1060   stream.Printf("lib%s.so", basename.GetCString());
1061   return ConstString(stream.GetString());
1062 }
1063