Bug Summary

File:lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
Warning:line 663, column 3
Value stored to 'do_dlopen_function' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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