Bug Summary

File:src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
Warning:line 682, column 3
Value stored to 'do_dlopen_function' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name PlatformPOSIX.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/llvm/include -I /usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../include -I /usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/obj -I /usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/obj/../include -D NDEBUG -D __STDC_LIMIT_MACROS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D LLVM_PREFIX="/usr" -I /usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/include -I /usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source -I /usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/clang/include -internal-isystem /usr/include/c++/v1 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/obj -ferror-limit 19 -fvisibility-inlines-hidden -fwrapv -stack-protector 2 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c++ /usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
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
35using namespace lldb;
36using namespace lldb_private;
37
38/// Default Constructor
39PlatformPOSIX::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.
49PlatformPOSIX::~PlatformPOSIX() = default;
50
51lldb_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
66static uint32_t chown_file(Platform *platform, const char *path,
67 uint32_t uid = UINT32_MAX0xffffffffU,
68 uint32_t gid = UINT32_MAX0xffffffffU) {
69 if (!platform || !path || *path == 0)
70 return UINT32_MAX0xffffffffU;
71
72 if (uid == UINT32_MAX0xffffffffU && gid == UINT32_MAX0xffffffffU)
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_MAX0xffffffffU)
78 command.Printf("%d", uid);
79 if (gid != UINT32_MAX0xffffffffU)
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
88lldb_private::Status
89PlatformPOSIX::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(1u << 25)));
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_MAX0xffffffffU && gid == UINT32_MAX0xffffffffU)
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())do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("[PutFile] Running command: %s\n", command
.GetData()); } while (0)
;
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
153lldb_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(1u << 25)));
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())do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("[GetFile] Running command: %s\n", command
.GetData()); } while (0)
;
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")do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("[GetFile] Using block by block transfer....\n"
); } while (0)
;
207 Status error;
208 user_id_t fd_src = OpenFile(source, File::eOpenOptionRead,
209 lldb::eFilePermissionsFileDefault, error);
210
211 if (fd_src == UINT64_MAX0xffffffffffffffffULL)
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_MAX0xffffffffffffffffULL) {
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_MAX0xffffffffffffffffULL)
253 CloseFile(fd_src, error);
254 // And close the dst file descriptot.
255 if (fd_dst != UINT64_MAX0xffffffffffffffffULL &&
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
265std::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
294const lldb::UnixSignalsSP &PlatformPOSIX::GetRemoteUnixSignals() {
295 if (IsRemote() && m_remote_platform_sp)
296 return m_remote_platform_sp->GetRemoteUnixSignals();
297 return Platform::GetRemoteUnixSignals();
298}
299
300Status 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
343Status 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
359lldb::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(1u << 25)));
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__)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("PlatformPOSIX::%s created new target"
, __FUNCTION__); } while (0)
;
373 } else {
374 error.Clear();
375 LLDB_LOGF(log, "PlatformPOSIX::%s target already existed, setting target",do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("PlatformPOSIX::%s target already existed, setting target"
, __FUNCTION__); } while (0)
376 __FUNCTION__)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("PlatformPOSIX::%s target already existed, setting target"
, __FUNCTION__); } while (0)
;
377 }
378
379 if (target && error.Success()) {
380 if (log) {
381 ModuleSP exe_module_sp = target->GetExecutableModule();
382 LLDB_LOGF(log, "PlatformPOSIX::%s set selected target to %p %s",do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("PlatformPOSIX::%s set selected target to %p %s"
, __FUNCTION__, (void *)target, exe_module_sp ? exe_module_sp
->GetFileSpec().GetPath().c_str() : "<null>"); } while
(0)
383 __FUNCTION__, (void *)target,do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("PlatformPOSIX::%s set selected target to %p %s"
, __FUNCTION__, (void *)target, exe_module_sp ? exe_module_sp
->GetFileSpec().GetPath().c_str() : "<null>"); } while
(0)
384 exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str()do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("PlatformPOSIX::%s set selected target to %p %s"
, __FUNCTION__, (void *)target, exe_module_sp ? exe_module_sp
->GetFileSpec().GetPath().c_str() : "<null>"); } while
(0)
385 : "<null>")do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("PlatformPOSIX::%s set selected target to %p %s"
, __FUNCTION__, (void *)target, exe_module_sp ? exe_module_sp
->GetFileSpec().GetPath().c_str() : "<null>"); } while
(0)
;
386 }
387
388 process_sp =
389 target->CreateProcess(attach_info.GetListenerForProcess(debugger),
390 "gdb-remote", nullptr, true);
391
392 if (process_sp) {
393 ListenerSP listener_sp = attach_info.GetHijackListener();
394 if (listener_sp == nullptr) {
395 listener_sp =
396 Listener::MakeListener("lldb.PlatformPOSIX.attach.hijack");
397 attach_info.SetHijackListener(listener_sp);
398 }
399 process_sp->HijackProcessEvents(listener_sp);
400 error = process_sp->Attach(attach_info);
401 }
402 }
403 } else {
404 if (m_remote_platform_sp)
405 process_sp =
406 m_remote_platform_sp->Attach(attach_info, debugger, target, error);
407 else
408 error.SetErrorString("the platform is not currently connected");
409 }
410 return process_sp;
411}
412
413lldb::ProcessSP
414PlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
415 Target *target, // Can be NULL, if NULL create a new
416 // target, else use existing one
417 Status &error) {
418 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM(1u << 25)));
419 LLDB_LOG(log, "target {0}", target)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp"
, __func__, "target {0}", target); } while (0)
;
420
421 ProcessSP process_sp;
422
423 if (!IsHost()) {
424 if (m_remote_platform_sp)
425 process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger,
426 target, error);
427 else
428 error.SetErrorString("the platform is not currently connected");
429 return process_sp;
430 }
431
432 //
433 // For local debugging, we'll insist on having ProcessGDBRemote create the
434 // process.
435 //
436
437 // Make sure we stop at the entry point
438 launch_info.GetFlags().Set(eLaunchFlagDebug);
439
440 // We always launch the process we are going to debug in a separate process
441 // group, since then we can handle ^C interrupts ourselves w/o having to
442 // worry about the target getting them as well.
443 launch_info.SetLaunchInSeparateProcessGroup(true);
444
445 // Ensure we have a target.
446 if (target == nullptr) {
447 LLDB_LOG(log, "creating new target")do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp"
, __func__, "creating new target"); } while (0)
;
448 TargetSP new_target_sp;
449 error = debugger.GetTargetList().CreateTarget(
450 debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
451 if (error.Fail()) {
452 LLDB_LOG(log, "failed to create new target: {0}", error)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp"
, __func__, "failed to create new target: {0}", error); } while
(0)
;
453 return process_sp;
454 }
455
456 target = new_target_sp.get();
457 if (!target) {
458 error.SetErrorString("CreateTarget() returned nullptr");
459 LLDB_LOG(log, "error: {0}", error)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp"
, __func__, "error: {0}", error); } while (0)
;
460 return process_sp;
461 }
462 }
463
464 // Now create the gdb-remote process.
465 LLDB_LOG(log, "having target create process with gdb-remote plugin")do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp"
, __func__, "having target create process with gdb-remote plugin"
); } while (0)
;
466 process_sp =
467 target->CreateProcess(launch_info.GetListener(), "gdb-remote", nullptr,
468 true);
469
470 if (!process_sp) {
471 error.SetErrorString("CreateProcess() failed for gdb-remote process");
472 LLDB_LOG(log, "error: {0}", error)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp"
, __func__, "error: {0}", error); } while (0)
;
473 return process_sp;
474 }
475
476 LLDB_LOG(log, "successfully created process")do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp"
, __func__, "successfully created process"); } while (0)
;
477 // Adjust launch for a hijacker.
478 ListenerSP listener_sp;
479 if (!launch_info.GetHijackListener()) {
480 LLDB_LOG(log, "setting up hijacker")do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp"
, __func__, "setting up hijacker"); } while (0)
;
481 listener_sp =
482 Listener::MakeListener("lldb.PlatformLinux.DebugProcess.hijack");
483 launch_info.SetHijackListener(listener_sp);
484 process_sp->HijackProcessEvents(listener_sp);
485 }
486
487 // Log file actions.
488 if (log) {
489 LLDB_LOG(log, "launching process with the following file actions:")do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp"
, __func__, "launching process with the following file actions:"
); } while (0)
;
490 StreamString stream;
491 size_t i = 0;
492 const FileAction *file_action;
493 while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) {
494 file_action->Dump(stream);
495 LLDB_LOG(log, "{0}", stream.GetData())do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp"
, __func__, "{0}", stream.GetData()); } while (0)
;
496 stream.Clear();
497 }
498 }
499
500 // Do the launch.
501 error = process_sp->Launch(launch_info);
502 if (error.Success()) {
503 // Handle the hijacking of process events.
504 if (listener_sp) {
505 const StateType state = process_sp->WaitForProcessToStop(
506 llvm::None, nullptr, false, listener_sp);
507
508 LLDB_LOG(log, "pid {0} state {0}", process_sp->GetID(), state)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp"
, __func__, "pid {0} state {0}", process_sp->GetID(), state
); } while (0)
;
509 }
510
511 // Hook up process PTY if we have one (which we should for local debugging
512 // with llgs).
513 int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor();
514 if (pty_fd != PseudoTerminal::invalid_fd) {
515 process_sp->SetSTDIOFileDescriptor(pty_fd);
516 LLDB_LOG(log, "hooked up STDIO pty to process")do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp"
, __func__, "hooked up STDIO pty to process"); } while (0)
;
517 } else
518 LLDB_LOG(log, "not using process STDIO pty")do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp"
, __func__, "not using process STDIO pty"); } while (0)
;
519 } else {
520 LLDB_LOG(log, "{0}", error)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Format("/usr/src/gnu/usr.bin/clang/liblldbPluginPlatform/../../../llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp"
, __func__, "{0}", error); } while (0)
;
521 // FIXME figure out appropriate cleanup here. Do we delete the target? Do
522 // we delete the process? Does our caller do that?
523 }
524
525 return process_sp;
526}
527
528void PlatformPOSIX::CalculateTrapHandlerSymbolNames() {
529 m_trap_handlers.push_back(ConstString("_sigtramp"));
530}
531
532Status PlatformPOSIX::EvaluateLibdlExpression(
533 lldb_private::Process *process, const char *expr_cstr,
534 llvm::StringRef expr_prefix, lldb::ValueObjectSP &result_valobj_sp) {
535 DynamicLoader *loader = process->GetDynamicLoader();
536 if (loader) {
537 Status error = loader->CanLoadImage();
538 if (error.Fail())
539 return error;
540 }
541
542 ThreadSP thread_sp(process->GetThreadList().GetExpressionExecutionThread());
543 if (!thread_sp)
544 return Status("Selected thread isn't valid");
545
546 StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0));
547 if (!frame_sp)
548 return Status("Frame 0 isn't valid");
549
550 ExecutionContext exe_ctx;
551 frame_sp->CalculateExecutionContext(exe_ctx);
552 EvaluateExpressionOptions expr_options;
553 expr_options.SetUnwindOnError(true);
554 expr_options.SetIgnoreBreakpoints(true);
555 expr_options.SetExecutionPolicy(eExecutionPolicyAlways);
556 expr_options.SetLanguage(eLanguageTypeC_plus_plus);
557 expr_options.SetTrapExceptions(false); // dlopen can't throw exceptions, so
558 // don't do the work to trap them.
559 expr_options.SetTimeout(process->GetUtilityExpressionTimeout());
560
561 Status expr_error;
562 ExpressionResults result =
563 UserExpression::Evaluate(exe_ctx, expr_options, expr_cstr, expr_prefix,
564 result_valobj_sp, expr_error);
565 if (result != eExpressionCompleted)
566 return expr_error;
567
568 if (result_valobj_sp->GetError().Fail())
569 return result_valobj_sp->GetError();
570 return Status();
571}
572
573std::unique_ptr<UtilityFunction>
574PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx,
575 Status &error) {
576 // Remember to prepend this with the prefix from
577 // GetLibdlFunctionDeclarations. The returned values are all in
578 // __lldb_dlopen_result for consistency. The wrapper returns a void * but
579 // doesn't use it because UtilityFunctions don't work with void returns at
580 // present.
581 //
582 // Use lazy binding so as to not make dlopen()'s success conditional on
583 // forcing every symbol in the library.
584 //
585 // In general, the debugger should allow programs to load & run with
586 // libraries as far as they can, instead of defaulting to being super-picky
587 // about unavailable symbols.
588 //
589 // The value "1" appears to imply lazy binding (RTLD_LAZY) on both Darwin
590 // and other POSIX OSes.
591 static const char *dlopen_wrapper_code = R"(
592 const int RTLD_LAZY = 1;
593
594 struct __lldb_dlopen_result {
595 void *image_ptr;
596 const char *error_str;
597 };
598
599 extern void *memcpy(void *, const void *, size_t size);
600 extern size_t strlen(const char *);
601
602
603 void * __lldb_dlopen_wrapper (const char *name,
604 const char *path_strings,
605 char *buffer,
606 __lldb_dlopen_result *result_ptr)
607 {
608 // This is the case where the name is the full path:
609 if (!path_strings) {
610 result_ptr->image_ptr = dlopen(name, RTLD_LAZY);
611 if (result_ptr->image_ptr)
612 result_ptr->error_str = nullptr;
613 return nullptr;
614 }
615
616 // This is the case where we have a list of paths:
617 size_t name_len = strlen(name);
618 while (path_strings && path_strings[0] != '\0') {
619 size_t path_len = strlen(path_strings);
620 memcpy((void *) buffer, (void *) path_strings, path_len);
621 buffer[path_len] = '/';
622 char *target_ptr = buffer+path_len+1;
623 memcpy((void *) target_ptr, (void *) name, name_len + 1);
624 result_ptr->image_ptr = dlopen(buffer, RTLD_LAZY);
625 if (result_ptr->image_ptr) {
626 result_ptr->error_str = nullptr;
627 break;
628 }
629 result_ptr->error_str = dlerror();
630 path_strings = path_strings + path_len + 1;
631 }
632 return nullptr;
633 }
634 )";
635
636 static const char *dlopen_wrapper_name = "__lldb_dlopen_wrapper";
637 Process *process = exe_ctx.GetProcessSP().get();
638 // Insert the dlopen shim defines into our generic expression:
639 std::string expr(std::string(GetLibdlFunctionDeclarations(process)));
640 expr.append(dlopen_wrapper_code);
641 Status utility_error;
642 DiagnosticManager diagnostics;
643
644 auto utility_fn_or_error = process->GetTarget().CreateUtilityFunction(
645 std::move(expr), dlopen_wrapper_name, eLanguageTypeObjC, exe_ctx);
646 if (!utility_fn_or_error) {
647 std::string error_str = llvm::toString(utility_fn_or_error.takeError());
648 error.SetErrorStringWithFormat("dlopen error: could not create utility"
649 "function: %s",
650 error_str.c_str());
651 return nullptr;
652 }
653 std::unique_ptr<UtilityFunction> dlopen_utility_func_up =
654 std::move(*utility_fn_or_error);
655
656 Value value;
657 ValueList arguments;
658 FunctionCaller *do_dlopen_function = nullptr;
659
660 // Fetch the clang types we will need:
661 TypeSystemClang *ast =
662 ScratchTypeSystemClang::GetForTarget(process->GetTarget());
663 if (!ast)
664 return nullptr;
665
666 CompilerType clang_void_pointer_type
667 = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
668 CompilerType clang_char_pointer_type
669 = ast->GetBasicType(eBasicTypeChar).GetPointerType();
670
671 // We are passing four arguments, the basename, the list of places to look,
672 // a buffer big enough for all the path + name combos, and
673 // a pointer to the storage we've made for the result:
674 value.SetValueType(Value::ValueType::Scalar);
675 value.SetCompilerType(clang_void_pointer_type);
676 arguments.PushValue(value);
677 value.SetCompilerType(clang_char_pointer_type);
678 arguments.PushValue(value);
679 arguments.PushValue(value);
680 arguments.PushValue(value);
681
682 do_dlopen_function = dlopen_utility_func_up->MakeFunctionCaller(
Value stored to 'do_dlopen_function' is never read
683 clang_void_pointer_type, arguments, exe_ctx.GetThreadSP(), utility_error);
684 if (utility_error.Fail()) {
685 error.SetErrorStringWithFormat("dlopen error: could not make function"
686 "caller: %s", utility_error.AsCString());
687 return nullptr;
688 }
689
690 do_dlopen_function = dlopen_utility_func_up->GetFunctionCaller();
691 if (!do_dlopen_function) {
692 error.SetErrorString("dlopen error: could not get function caller.");
693 return nullptr;
694 }
695
696 // We made a good utility function, so cache it in the process:
697 return dlopen_utility_func_up;
698}
699
700uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process,
701 const lldb_private::FileSpec &remote_file,
702 const std::vector<std::string> *paths,
703 lldb_private::Status &error,
704 lldb_private::FileSpec *loaded_image) {
705 if (loaded_image)
706 loaded_image->Clear();
707
708 std::string path;
709 path = remote_file.GetPath();
710
711 ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();
712 if (!thread_sp) {
713 error.SetErrorString("dlopen error: no thread available to call dlopen.");
714 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
715 }
716
717 DiagnosticManager diagnostics;
718
719 ExecutionContext exe_ctx;
720 thread_sp->CalculateExecutionContext(exe_ctx);
721
722 Status utility_error;
723 UtilityFunction *dlopen_utility_func;
724 ValueList arguments;
725 FunctionCaller *do_dlopen_function = nullptr;
726
727 // The UtilityFunction is held in the Process. Platforms don't track the
728 // lifespan of the Targets that use them, we can't put this in the Platform.
729 dlopen_utility_func = process->GetLoadImageUtilityFunction(
730 this, [&]() -> std::unique_ptr<UtilityFunction> {
731 return MakeLoadImageUtilityFunction(exe_ctx, error);
732 });
733 // If we couldn't make it, the error will be in error, so we can exit here.
734 if (!dlopen_utility_func)
735 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
736
737 do_dlopen_function = dlopen_utility_func->GetFunctionCaller();
738 if (!do_dlopen_function) {
739 error.SetErrorString("dlopen error: could not get function caller.");
740 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
741 }
742 arguments = do_dlopen_function->GetArgumentValues();
743
744 // Now insert the path we are searching for and the result structure into the
745 // target.
746 uint32_t permissions = ePermissionsReadable|ePermissionsWritable;
747 size_t path_len = path.size() + 1;
748 lldb::addr_t path_addr = process->AllocateMemory(path_len,
749 permissions,
750 utility_error);
751 if (path_addr == LLDB_INVALID_ADDRESS0xffffffffffffffffULL) {
752 error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
753 "for path: %s", utility_error.AsCString());
754 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
755 }
756
757 // Make sure we deallocate the input string memory:
758 auto path_cleanup = llvm::make_scope_exit([process, path_addr] {
759 // Deallocate the buffer.
760 process->DeallocateMemory(path_addr);
761 });
762
763 process->WriteMemory(path_addr, path.c_str(), path_len, utility_error);
764 if (utility_error.Fail()) {
765 error.SetErrorStringWithFormat("dlopen error: could not write path string:"
766 " %s", utility_error.AsCString());
767 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
768 }
769
770 // Make space for our return structure. It is two pointers big: the token
771 // and the error string.
772 const uint32_t addr_size = process->GetAddressByteSize();
773 lldb::addr_t return_addr = process->CallocateMemory(2*addr_size,
774 permissions,
775 utility_error);
776 if (utility_error.Fail()) {
777 error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
778 "for path: %s", utility_error.AsCString());
779 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
780 }
781
782 // Make sure we deallocate the result structure memory
783 auto return_cleanup = llvm::make_scope_exit([process, return_addr] {
784 // Deallocate the buffer
785 process->DeallocateMemory(return_addr);
786 });
787
788 // This will be the address of the storage for paths, if we are using them,
789 // or nullptr to signal we aren't.
790 lldb::addr_t path_array_addr = 0x0;
791 llvm::Optional<llvm::detail::scope_exit<std::function<void()>>>
792 path_array_cleanup;
793
794 // This is the address to a buffer large enough to hold the largest path
795 // conjoined with the library name we're passing in. This is a convenience
796 // to avoid having to call malloc in the dlopen function.
797 lldb::addr_t buffer_addr = 0x0;
798 llvm::Optional<llvm::detail::scope_exit<std::function<void()>>>
799 buffer_cleanup;
800
801 // Set the values into our args and write them to the target:
802 if (paths != nullptr) {
803 // First insert the paths into the target. This is expected to be a
804 // continuous buffer with the strings laid out null terminated and
805 // end to end with an empty string terminating the buffer.
806 // We also compute the buffer's required size as we go.
807 size_t buffer_size = 0;
808 std::string path_array;
809 for (auto path : *paths) {
810 // Don't insert empty paths, they will make us abort the path
811 // search prematurely.
812 if (path.empty())
813 continue;
814 size_t path_size = path.size();
815 path_array.append(path);
816 path_array.push_back('\0');
817 if (path_size > buffer_size)
818 buffer_size = path_size;
819 }
820 path_array.push_back('\0');
821
822 path_array_addr = process->AllocateMemory(path_array.size(),
823 permissions,
824 utility_error);
825 if (path_array_addr == LLDB_INVALID_ADDRESS0xffffffffffffffffULL) {
826 error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
827 "for path array: %s",
828 utility_error.AsCString());
829 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
830 }
831
832 // Make sure we deallocate the paths array.
833 path_array_cleanup.emplace([process, path_array_addr]() {
834 // Deallocate the path array.
835 process->DeallocateMemory(path_array_addr);
836 });
837
838 process->WriteMemory(path_array_addr, path_array.data(),
839 path_array.size(), utility_error);
840
841 if (utility_error.Fail()) {
842 error.SetErrorStringWithFormat("dlopen error: could not write path array:"
843 " %s", utility_error.AsCString());
844 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
845 }
846 // Now make spaces in the target for the buffer. We need to add one for
847 // the '/' that the utility function will insert and one for the '\0':
848 buffer_size += path.size() + 2;
849
850 buffer_addr = process->AllocateMemory(buffer_size,
851 permissions,
852 utility_error);
853 if (buffer_addr == LLDB_INVALID_ADDRESS0xffffffffffffffffULL) {
854 error.SetErrorStringWithFormat("dlopen error: could not allocate memory"
855 "for buffer: %s",
856 utility_error.AsCString());
857 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
858 }
859
860 // Make sure we deallocate the buffer memory:
861 buffer_cleanup.emplace([process, buffer_addr]() {
862 // Deallocate the buffer.
863 process->DeallocateMemory(buffer_addr);
864 });
865 }
866
867 arguments.GetValueAtIndex(0)->GetScalar() = path_addr;
868 arguments.GetValueAtIndex(1)->GetScalar() = path_array_addr;
869 arguments.GetValueAtIndex(2)->GetScalar() = buffer_addr;
870 arguments.GetValueAtIndex(3)->GetScalar() = return_addr;
871
872 lldb::addr_t func_args_addr = LLDB_INVALID_ADDRESS0xffffffffffffffffULL;
873
874 diagnostics.Clear();
875 if (!do_dlopen_function->WriteFunctionArguments(exe_ctx,
876 func_args_addr,
877 arguments,
878 diagnostics)) {
879 error.SetErrorStringWithFormat("dlopen error: could not write function "
880 "arguments: %s",
881 diagnostics.GetString().c_str());
882 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
883 }
884
885 // Make sure we clean up the args structure. We can't reuse it because the
886 // Platform lives longer than the process and the Platforms don't get a
887 // signal to clean up cached data when a process goes away.
888 auto args_cleanup =
889 llvm::make_scope_exit([do_dlopen_function, &exe_ctx, func_args_addr] {
890 do_dlopen_function->DeallocateFunctionResults(exe_ctx, func_args_addr);
891 });
892
893 // Now run the caller:
894 EvaluateExpressionOptions options;
895 options.SetExecutionPolicy(eExecutionPolicyAlways);
896 options.SetLanguage(eLanguageTypeC_plus_plus);
897 options.SetIgnoreBreakpoints(true);
898 options.SetUnwindOnError(true);
899 options.SetTrapExceptions(false); // dlopen can't throw exceptions, so
900 // don't do the work to trap them.
901 options.SetTimeout(process->GetUtilityExpressionTimeout());
902 options.SetIsForUtilityExpr(true);
903
904 Value return_value;
905 // Fetch the clang types we will need:
906 TypeSystemClang *ast =
907 ScratchTypeSystemClang::GetForTarget(process->GetTarget());
908 if (!ast) {
909 error.SetErrorString("dlopen error: Unable to get TypeSystemClang");
910 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
911 }
912
913 CompilerType clang_void_pointer_type
914 = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
915
916 return_value.SetCompilerType(clang_void_pointer_type);
917
918 ExpressionResults results = do_dlopen_function->ExecuteFunction(
919 exe_ctx, &func_args_addr, options, diagnostics, return_value);
920 if (results != eExpressionCompleted) {
921 error.SetErrorStringWithFormat("dlopen error: failed executing "
922 "dlopen wrapper function: %s",
923 diagnostics.GetString().c_str());
924 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
925 }
926
927 // Read the dlopen token from the return area:
928 lldb::addr_t token = process->ReadPointerFromMemory(return_addr,
929 utility_error);
930 if (utility_error.Fail()) {
931 error.SetErrorStringWithFormat("dlopen error: could not read the return "
932 "struct: %s", utility_error.AsCString());
933 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
934 }
935
936 // The dlopen succeeded!
937 if (token != 0x0) {
938 if (loaded_image && buffer_addr != 0x0)
939 {
940 // Capture the image which was loaded. We leave it in the buffer on
941 // exit from the dlopen function, so we can just read it from there:
942 std::string name_string;
943 process->ReadCStringFromMemory(buffer_addr, name_string, utility_error);
944 if (utility_error.Success())
945 loaded_image->SetFile(name_string, llvm::sys::path::Style::posix);
946 }
947 return process->AddImageToken(token);
948 }
949
950 // We got an error, lets read in the error string:
951 std::string dlopen_error_str;
952 lldb::addr_t error_addr
953 = process->ReadPointerFromMemory(return_addr + addr_size, utility_error);
954 if (utility_error.Fail()) {
955 error.SetErrorStringWithFormat("dlopen error: could not read error string: "
956 "%s", utility_error.AsCString());
957 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
958 }
959
960 size_t num_chars = process->ReadCStringFromMemory(error_addr + addr_size,
961 dlopen_error_str,
962 utility_error);
963 if (utility_error.Success() && num_chars > 0)
964 error.SetErrorStringWithFormat("dlopen error: %s",
965 dlopen_error_str.c_str());
966 else
967 error.SetErrorStringWithFormat("dlopen failed for unknown reasons.");
968
969 return LLDB_INVALID_IMAGE_TOKEN0xffffffffU;
970}
971
972Status PlatformPOSIX::UnloadImage(lldb_private::Process *process,
973 uint32_t image_token) {
974 const addr_t image_addr = process->GetImagePtrFromToken(image_token);
975 if (image_addr == LLDB_INVALID_ADDRESS0xffffffffffffffffULL)
976 return Status("Invalid image token");
977
978 StreamString expr;
979 expr.Printf("dlclose((void *)0x%" PRIx64"llx" ")", image_addr);
980 llvm::StringRef prefix = GetLibdlFunctionDeclarations(process);
981 lldb::ValueObjectSP result_valobj_sp;
982 Status error = EvaluateLibdlExpression(process, expr.GetData(), prefix,
983 result_valobj_sp);
984 if (error.Fail())
985 return error;
986
987 if (result_valobj_sp->GetError().Fail())
988 return result_valobj_sp->GetError();
989
990 Scalar scalar;
991 if (result_valobj_sp->ResolveValue(scalar)) {
992 if (scalar.UInt(1))
993 return Status("expression failed: \"%s\"", expr.GetData());
994 process->ResetImageToken(image_token);
995 }
996 return Status();
997}
998
999llvm::StringRef
1000PlatformPOSIX::GetLibdlFunctionDeclarations(lldb_private::Process *process) {
1001 return R"(
1002 extern "C" void* dlopen(const char*, int);
1003 extern "C" void* dlsym(void*, const char*);
1004 extern "C" int dlclose(void*);
1005 extern "C" char* dlerror(void);
1006 )";
1007}
1008
1009ConstString PlatformPOSIX::GetFullNameForDylib(ConstString basename) {
1010 if (basename.IsEmpty())
1011 return basename;
1012
1013 StreamString stream;
1014 stream.Printf("lib%s.so", basename.GetCString());
1015 return ConstString(stream.GetString());
1016}