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