Bug Summary

File:build/source/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
Warning:line 171, column 9
Although the value stored to 'cursor' is used in the enclosing expression, the value is never actually read from 'cursor'

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 DYLDRendezvous.cpp -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/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -isystem /usr/include/libxml2 -D HAVE_ROUND -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD -I /build/source/lldb/source/Plugins/DynamicLoader/POSIX-DYLD -I /build/source/lldb/include -I tools/lldb/include -I include -I /build/source/llvm/include -I /usr/include/python3.9 -I /build/source/clang/include -I tools/lldb/../clang/include -I /build/source/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-17/lib/clang/17/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/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -O2 -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-misleading-indentation -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-strict-aliasing -Wno-stringop-truncation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -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-2023-05-10-133810-16478-1 -x c++ /build/source/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
1//===-- DYLDRendezvous.cpp ------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Core/Module.h"
10#include "lldb/Symbol/ObjectFile.h"
11#include "lldb/Symbol/Symbol.h"
12#include "lldb/Symbol/SymbolContext.h"
13#include "lldb/Target/Platform.h"
14#include "lldb/Target/Process.h"
15#include "lldb/Target/Target.h"
16#include "lldb/Utility/ArchSpec.h"
17#include "lldb/Utility/LLDBLog.h"
18#include "lldb/Utility/Log.h"
19#include "lldb/Utility/Status.h"
20
21#include "llvm/Support/Path.h"
22
23#include "DYLDRendezvous.h"
24
25using namespace lldb;
26using namespace lldb_private;
27
28DYLDRendezvous::DYLDRendezvous(Process *process)
29 : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS(18446744073709551615UL)),
30 m_executable_interpreter(false), m_current(), m_previous(),
31 m_loaded_modules(), m_soentries(), m_added_soentries(),
32 m_removed_soentries() {
33 m_thread_info.valid = false;
34 UpdateExecutablePath();
35}
36
37addr_t DYLDRendezvous::ResolveRendezvousAddress() {
38 Log *log = GetLog(LLDBLog::DynamicLoader);
39 addr_t info_location;
40 addr_t info_addr;
41 Status error;
42
43 if (!m_process) {
44 LLDB_LOGF(log, "%s null process provided", __FUNCTION__)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s null process provided", __FUNCTION__
); } while (0)
;
45 return LLDB_INVALID_ADDRESS(18446744073709551615UL);
46 }
47
48 // Try to get it from our process. This might be a remote process and might
49 // grab it via some remote-specific mechanism.
50 info_location = m_process->GetImageInfoAddress();
51 LLDB_LOGF(log, "%s info_location = 0x%" PRIx64, __FUNCTION__, info_location)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s info_location = 0x%" "l" "x", __FUNCTION__
, info_location); } while (0)
;
52
53 // If the process fails to return an address, fall back to seeing if the
54 // local object file can help us find it.
55 if (info_location == LLDB_INVALID_ADDRESS(18446744073709551615UL)) {
56 Target *target = &m_process->GetTarget();
57 if (target) {
58 ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
59 Address addr = obj_file->GetImageInfoAddress(target);
60
61 if (addr.IsValid()) {
62 info_location = addr.GetLoadAddress(target);
63 LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s resolved via direct object file approach to 0x%"
"l" "x", __FUNCTION__, info_location); } while (0)
64 "%s resolved via direct object file approach to 0x%" PRIx64,do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s resolved via direct object file approach to 0x%"
"l" "x", __FUNCTION__, info_location); } while (0)
65 __FUNCTION__, info_location)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s resolved via direct object file approach to 0x%"
"l" "x", __FUNCTION__, info_location); } while (0)
;
66 } else {
67 const Symbol *_r_debug =
68 target->GetExecutableModule()->FindFirstSymbolWithNameAndType(
69 ConstString("_r_debug"));
70 if (_r_debug) {
71 info_addr = _r_debug->GetAddress().GetLoadAddress(target);
72 if (info_addr != LLDB_INVALID_ADDRESS(18446744073709551615UL)) {
73 LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s resolved by finding symbol '_r_debug' whose value is "
"0x%" "l" "x", __FUNCTION__, info_addr); } while (0)
74 "%s resolved by finding symbol '_r_debug' whose value is "do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s resolved by finding symbol '_r_debug' whose value is "
"0x%" "l" "x", __FUNCTION__, info_addr); } while (0)
75 "0x%" PRIx64,do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s resolved by finding symbol '_r_debug' whose value is "
"0x%" "l" "x", __FUNCTION__, info_addr); } while (0)
76 __FUNCTION__, info_addr)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s resolved by finding symbol '_r_debug' whose value is "
"0x%" "l" "x", __FUNCTION__, info_addr); } while (0)
;
77 m_executable_interpreter = true;
78 return info_addr;
79 }
80 }
81 LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s FAILED - direct object file approach did not yield a "
"valid address", __FUNCTION__); } while (0)
82 "%s FAILED - direct object file approach did not yield a "do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s FAILED - direct object file approach did not yield a "
"valid address", __FUNCTION__); } while (0)
83 "valid address",do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s FAILED - direct object file approach did not yield a "
"valid address", __FUNCTION__); } while (0)
84 __FUNCTION__)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s FAILED - direct object file approach did not yield a "
"valid address", __FUNCTION__); } while (0)
;
85 }
86 }
87 }
88
89 if (info_location == LLDB_INVALID_ADDRESS(18446744073709551615UL)) {
90 LLDB_LOGF(log, "%s FAILED - invalid info address", __FUNCTION__)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s FAILED - invalid info address", __FUNCTION__
); } while (0)
;
91 return LLDB_INVALID_ADDRESS(18446744073709551615UL);
92 }
93
94 LLDB_LOGF(log, "%s reading pointer (%" PRIu32 " bytes) from 0x%" PRIx64,do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s reading pointer (%" "u" " bytes) from 0x%"
"l" "x", __FUNCTION__, m_process->GetAddressByteSize(), info_location
); } while (0)
95 __FUNCTION__, m_process->GetAddressByteSize(), info_location)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s reading pointer (%" "u" " bytes) from 0x%"
"l" "x", __FUNCTION__, m_process->GetAddressByteSize(), info_location
); } while (0)
;
96
97 info_addr = m_process->ReadPointerFromMemory(info_location, error);
98 if (error.Fail()) {
99 LLDB_LOGF(log, "%s FAILED - could not read from the info location: %s",do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s FAILED - could not read from the info location: %s"
, __FUNCTION__, error.AsCString()); } while (0)
100 __FUNCTION__, error.AsCString())do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s FAILED - could not read from the info location: %s"
, __FUNCTION__, error.AsCString()); } while (0)
;
101 return LLDB_INVALID_ADDRESS(18446744073709551615UL);
102 }
103
104 if (info_addr == 0) {
105 LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s FAILED - the rendezvous address contained at 0x%"
"l" "x" " returned a null value", __FUNCTION__, info_location
); } while (0)
106 "%s FAILED - the rendezvous address contained at 0x%" PRIx64do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s FAILED - the rendezvous address contained at 0x%"
"l" "x" " returned a null value", __FUNCTION__, info_location
); } while (0)
107 " returned a null value",do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s FAILED - the rendezvous address contained at 0x%"
"l" "x" " returned a null value", __FUNCTION__, info_location
); } while (0)
108 __FUNCTION__, info_location)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("%s FAILED - the rendezvous address contained at 0x%"
"l" "x" " returned a null value", __FUNCTION__, info_location
); } while (0)
;
109 return LLDB_INVALID_ADDRESS(18446744073709551615UL);
110 }
111
112 return info_addr;
113}
114
115void DYLDRendezvous::UpdateExecutablePath() {
116 if (m_process) {
117 Log *log = GetLog(LLDBLog::DynamicLoader);
118 Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
119 if (exe_mod) {
120 m_exe_file_spec = exe_mod->GetPlatformFileSpec();
121 LLDB_LOGF(log, "DYLDRendezvous::%s exe module executable path set: '%s'",do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("DYLDRendezvous::%s exe module executable path set: '%s'"
, __FUNCTION__, m_exe_file_spec.GetPath().c_str()); } while (
0)
122 __FUNCTION__, m_exe_file_spec.GetPath().c_str())do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("DYLDRendezvous::%s exe module executable path set: '%s'"
, __FUNCTION__, m_exe_file_spec.GetPath().c_str()); } while (
0)
;
123 } else {
124 LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("DYLDRendezvous::%s cannot cache exe module path: null "
"executable module pointer", __FUNCTION__); } while (0)
125 "DYLDRendezvous::%s cannot cache exe module path: null "do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("DYLDRendezvous::%s cannot cache exe module path: null "
"executable module pointer", __FUNCTION__); } while (0)
126 "executable module pointer",do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("DYLDRendezvous::%s cannot cache exe module path: null "
"executable module pointer", __FUNCTION__); } while (0)
127 __FUNCTION__)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("DYLDRendezvous::%s cannot cache exe module path: null "
"executable module pointer", __FUNCTION__); } while (0)
;
128 }
129 }
130}
131
132bool DYLDRendezvous::Resolve() {
133 Log *log = GetLog(LLDBLog::DynamicLoader);
134
135 const size_t word_size = 4;
136 Rendezvous info;
137 size_t address_size;
138 size_t padding;
139 addr_t info_addr;
140 addr_t cursor;
141
142 address_size = m_process->GetAddressByteSize();
143 padding = address_size - word_size;
144 LLDB_LOGF(log,do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("DYLDRendezvous::%s address size: %"
"l" "u" ", padding %" "l" "u", __FUNCTION__, uint64_t(address_size
), uint64_t(padding)); } while (0)
145 "DYLDRendezvous::%s address size: %" PRIu64 ", padding %" PRIu64,do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("DYLDRendezvous::%s address size: %"
"l" "u" ", padding %" "l" "u", __FUNCTION__, uint64_t(address_size
), uint64_t(padding)); } while (0)
146 __FUNCTION__, uint64_t(address_size), uint64_t(padding))do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("DYLDRendezvous::%s address size: %"
"l" "u" ", padding %" "l" "u", __FUNCTION__, uint64_t(address_size
), uint64_t(padding)); } while (0)
;
147
148 if (m_rendezvous_addr == LLDB_INVALID_ADDRESS(18446744073709551615UL))
149 cursor = info_addr =
150 ResolveRendezvousAddress();
151 else
152 cursor = info_addr = m_rendezvous_addr;
153 LLDB_LOGF(log, "DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__,do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("DYLDRendezvous::%s cursor = 0x%" "l"
"x", __FUNCTION__, cursor); } while (0)
154 cursor)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("DYLDRendezvous::%s cursor = 0x%" "l"
"x", __FUNCTION__, cursor); } while (0)
;
155
156 if (cursor == LLDB_INVALID_ADDRESS(18446744073709551615UL))
157 return false;
158
159 if (!(cursor = ReadWord(cursor, &info.version, word_size)))
160 return false;
161
162 if (!(cursor = ReadPointer(cursor + padding, &info.map_addr)))
163 return false;
164
165 if (!(cursor = ReadPointer(cursor, &info.brk)))
166 return false;
167
168 if (!(cursor = ReadWord(cursor, &info.state, word_size)))
169 return false;
170
171 if (!(cursor = ReadPointer(cursor + padding, &info.ldbase)))
Although the value stored to 'cursor' is used in the enclosing expression, the value is never actually read from 'cursor'
172 return false;
173
174 // The rendezvous was successfully read. Update our internal state.
175 m_rendezvous_addr = info_addr;
176 m_previous = m_current;
177 m_current = info;
178
179 if (m_current.map_addr == 0)
180 return false;
181
182 if (UpdateSOEntriesFromRemote())
183 return true;
184
185 return UpdateSOEntries();
186}
187
188bool DYLDRendezvous::IsValid() {
189 return m_rendezvous_addr != LLDB_INVALID_ADDRESS(18446744073709551615UL);
190}
191
192DYLDRendezvous::RendezvousAction DYLDRendezvous::GetAction() const {
193 // If we have a core file, we will read the current rendezvous state
194 // from the core file's memory into m_current which can be in an inconsistent
195 // state, so we can't rely on its state to determine what we should do. We
196 // always need it to load all of the shared libraries one time when we attach
197 // to a core file.
198 if (IsCoreFile())
199 return eTakeSnapshot;
200
201 switch (m_current.state) {
202
203 case eConsistent:
204 switch (m_previous.state) {
205 // When the previous and current states are consistent this is the first
206 // time we have been asked to update. Just take a snapshot of the
207 // currently loaded modules.
208 case eConsistent:
209 return eTakeSnapshot;
210 // If we are about to add or remove a shared object clear out the current
211 // state and take a snapshot of the currently loaded images.
212 case eAdd:
213 return eAddModules;
214 case eDelete:
215 return eRemoveModules;
216 }
217 break;
218
219 case eAdd:
220 case eDelete:
221 return eNoAction;
222 }
223
224 return eNoAction;
225}
226
227bool DYLDRendezvous::UpdateSOEntriesFromRemote() {
228 auto action = GetAction();
229
230 if (action == eNoAction)
231 return false;
232
233 m_added_soentries.clear();
234 m_removed_soentries.clear();
235 if (action == eTakeSnapshot) {
236 // We already have the loaded list from the previous update so no need to
237 // find all the modules again.
238 if (!m_loaded_modules.m_list.empty())
239 return true;
240 }
241
242 llvm::Expected<LoadedModuleInfoList> module_list =
243 m_process->GetLoadedModuleList();
244 if (!module_list) {
245 llvm::consumeError(module_list.takeError());
246 return false;
247 }
248
249 switch (action) {
250 case eTakeSnapshot:
251 m_soentries.clear();
252 return SaveSOEntriesFromRemote(*module_list);
253 case eAddModules:
254 return AddSOEntriesFromRemote(*module_list);
255 case eRemoveModules:
256 return RemoveSOEntriesFromRemote(*module_list);
257 case eNoAction:
258 return false;
259 }
260 llvm_unreachable("Fully covered switch above!")::llvm::llvm_unreachable_internal("Fully covered switch above!"
, "lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp"
, 260)
;
261}
262
263bool DYLDRendezvous::UpdateSOEntries() {
264 m_added_soentries.clear();
265 m_removed_soentries.clear();
266 switch (GetAction()) {
267 case eTakeSnapshot:
268 m_soentries.clear();
269 return TakeSnapshot(m_soentries);
270 case eAddModules:
271 return AddSOEntries();
272 case eRemoveModules:
273 return RemoveSOEntries();
274 case eNoAction:
275 return false;
276 }
277 llvm_unreachable("Fully covered switch above!")::llvm::llvm_unreachable_internal("Fully covered switch above!"
, "lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp"
, 277)
;
278}
279
280bool DYLDRendezvous::FillSOEntryFromModuleInfo(
281 LoadedModuleInfoList::LoadedModuleInfo const &modInfo, SOEntry &entry) {
282 addr_t link_map_addr;
283 addr_t base_addr;
284 addr_t dyn_addr;
285 std::string name;
286
287 if (!modInfo.get_link_map(link_map_addr) || !modInfo.get_base(base_addr) ||
288 !modInfo.get_dynamic(dyn_addr) || !modInfo.get_name(name))
289 return false;
290
291 entry.link_addr = link_map_addr;
292 entry.base_addr = base_addr;
293 entry.dyn_addr = dyn_addr;
294
295 entry.file_spec.SetFile(name, FileSpec::Style::native);
296
297 UpdateBaseAddrIfNecessary(entry, name);
298
299 // not needed if we're using ModuleInfos
300 entry.next = 0;
301 entry.prev = 0;
302 entry.path_addr = 0;
303
304 return true;
305}
306
307bool DYLDRendezvous::SaveSOEntriesFromRemote(
308 const LoadedModuleInfoList &module_list) {
309 for (auto const &modInfo : module_list.m_list) {
310 SOEntry entry;
311 if (!FillSOEntryFromModuleInfo(modInfo, entry))
312 return false;
313
314 // Only add shared libraries and not the executable.
315 if (!SOEntryIsMainExecutable(entry)) {
316 UpdateFileSpecIfNecessary(entry);
317 m_soentries.push_back(entry);
318 }
319 }
320
321 m_loaded_modules = module_list;
322 return true;
323}
324
325bool DYLDRendezvous::AddSOEntriesFromRemote(
326 const LoadedModuleInfoList &module_list) {
327 for (auto const &modInfo : module_list.m_list) {
328 bool found = false;
329 for (auto const &existing : m_loaded_modules.m_list) {
330 if (modInfo == existing) {
331 found = true;
332 break;
333 }
334 }
335
336 if (found)
337 continue;
338
339 SOEntry entry;
340 if (!FillSOEntryFromModuleInfo(modInfo, entry))
341 return false;
342
343 // Only add shared libraries and not the executable.
344 if (!SOEntryIsMainExecutable(entry)) {
345 UpdateFileSpecIfNecessary(entry);
346 m_soentries.push_back(entry);
347 m_added_soentries.push_back(entry);
348 }
349 }
350
351 m_loaded_modules = module_list;
352 return true;
353}
354
355bool DYLDRendezvous::RemoveSOEntriesFromRemote(
356 const LoadedModuleInfoList &module_list) {
357 for (auto const &existing : m_loaded_modules.m_list) {
358 bool found = false;
359 for (auto const &modInfo : module_list.m_list) {
360 if (modInfo == existing) {
361 found = true;
362 break;
363 }
364 }
365
366 if (found)
367 continue;
368
369 SOEntry entry;
370 if (!FillSOEntryFromModuleInfo(existing, entry))
371 return false;
372
373 // Only add shared libraries and not the executable.
374 if (!SOEntryIsMainExecutable(entry)) {
375 auto pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
376 if (pos == m_soentries.end())
377 return false;
378
379 m_soentries.erase(pos);
380 m_removed_soentries.push_back(entry);
381 }
382 }
383
384 m_loaded_modules = module_list;
385 return true;
386}
387
388bool DYLDRendezvous::AddSOEntries() {
389 SOEntry entry;
390 iterator pos;
391
392 assert(m_previous.state == eAdd)(static_cast <bool> (m_previous.state == eAdd) ? void (
0) : __assert_fail ("m_previous.state == eAdd", "lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp"
, 392, __extension__ __PRETTY_FUNCTION__))
;
393
394 if (m_current.map_addr == 0)
395 return false;
396
397 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
398 if (!ReadSOEntryFromMemory(cursor, entry))
399 return false;
400
401 // Only add shared libraries and not the executable.
402 if (SOEntryIsMainExecutable(entry))
403 continue;
404
405 UpdateFileSpecIfNecessary(entry);
406
407 if (!llvm::is_contained(m_soentries, entry)) {
408 m_soentries.push_back(entry);
409 m_added_soentries.push_back(entry);
410 }
411 }
412
413 return true;
414}
415
416bool DYLDRendezvous::RemoveSOEntries() {
417 SOEntryList entry_list;
418 iterator pos;
419
420 assert(m_previous.state == eDelete)(static_cast <bool> (m_previous.state == eDelete) ? void
(0) : __assert_fail ("m_previous.state == eDelete", "lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp"
, 420, __extension__ __PRETTY_FUNCTION__))
;
421
422 if (!TakeSnapshot(entry_list))
423 return false;
424
425 for (iterator I = begin(); I != end(); ++I) {
426 if (!llvm::is_contained(entry_list, *I))
427 m_removed_soentries.push_back(*I);
428 }
429
430 m_soentries = entry_list;
431 return true;
432}
433
434bool DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry) {
435 // On some systes the executable is indicated by an empty path in the entry.
436 // On others it is the full path to the executable.
437
438 auto triple = m_process->GetTarget().GetArchitecture().GetTriple();
439 switch (triple.getOS()) {
440 case llvm::Triple::FreeBSD:
441 case llvm::Triple::NetBSD:
442 return entry.file_spec == m_exe_file_spec;
443 case llvm::Triple::Linux:
444 if (triple.isAndroid())
445 return entry.file_spec == m_exe_file_spec;
446 // If we are debugging ld.so, then all SOEntries should be treated as
447 // libraries, including the "main" one (denoted by an empty string).
448 if (!entry.file_spec && m_executable_interpreter)
449 return false;
450 return !entry.file_spec;
451 default:
452 return false;
453 }
454}
455
456bool DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) {
457 SOEntry entry;
458
459 if (m_current.map_addr == 0)
460 return false;
461
462 // Clear previous entries since we are about to obtain an up to date list.
463 entry_list.clear();
464
465 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
466 if (!ReadSOEntryFromMemory(cursor, entry))
467 return false;
468
469 // Only add shared libraries and not the executable.
470 if (SOEntryIsMainExecutable(entry))
471 continue;
472
473 UpdateFileSpecIfNecessary(entry);
474
475 entry_list.push_back(entry);
476 }
477
478 return true;
479}
480
481addr_t DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) {
482 Status error;
483
484 *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
485 if (error.Fail())
486 return 0;
487
488 return addr + size;
489}
490
491addr_t DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
492 Status error;
493
494 *dst = m_process->ReadPointerFromMemory(addr, error);
495 if (error.Fail())
496 return 0;
497
498 return addr + m_process->GetAddressByteSize();
499}
500
501std::string DYLDRendezvous::ReadStringFromMemory(addr_t addr) {
502 std::string str;
503 Status error;
504
505 if (addr == LLDB_INVALID_ADDRESS(18446744073709551615UL))
506 return std::string();
507
508 m_process->ReadCStringFromMemory(addr, str, error);
509
510 return str;
511}
512
513// Returns true if the load bias reported by the linker is incorrect for the
514// given entry. This function is used to handle cases where we want to work
515// around a bug in the system linker.
516static bool isLoadBiasIncorrect(Target &target, const std::string &file_path) {
517 // On Android L (API 21, 22) the load address of the "/system/bin/linker"
518 // isn't filled in correctly.
519 unsigned os_major = target.GetPlatform()->GetOSVersion().getMajor();
520 return target.GetArchitecture().GetTriple().isAndroid() &&
521 (os_major == 21 || os_major == 22) &&
522 (file_path == "/system/bin/linker" ||
523 file_path == "/system/bin/linker64");
524}
525
526void DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry,
527 std::string const &file_path) {
528 // If the load bias reported by the linker is incorrect then fetch the load
529 // address of the file from the proc file system.
530 if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) {
531 lldb::addr_t load_addr = LLDB_INVALID_ADDRESS(18446744073709551615UL);
532 bool is_loaded = false;
533 Status error =
534 m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr);
535 if (error.Success() && is_loaded)
536 entry.base_addr = load_addr;
537 }
538}
539
540void DYLDRendezvous::UpdateFileSpecIfNecessary(SOEntry &entry) {
541 // Updates filename if empty. It is useful while debugging ld.so,
542 // when the link map returns empty string for the main executable.
543 if (!entry.file_spec) {
544 MemoryRegionInfo region;
545 Status region_status =
546 m_process->GetMemoryRegionInfo(entry.dyn_addr, region);
547 if (!region.GetName().IsEmpty())
548 entry.file_spec.SetFile(region.GetName().AsCString(),
549 FileSpec::Style::native);
550 }
551}
552
553bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) {
554 entry.clear();
555
556 entry.link_addr = addr;
557
558 if (!(addr = ReadPointer(addr, &entry.base_addr)))
559 return false;
560
561 // mips adds an extra load offset field to the link map struct on FreeBSD and
562 // NetBSD (need to validate other OSes).
563 // http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?revision=217153&view=markup#l57
564 const ArchSpec &arch = m_process->GetTarget().GetArchitecture();
565 if ((arch.GetTriple().getOS() == llvm::Triple::FreeBSD ||
566 arch.GetTriple().getOS() == llvm::Triple::NetBSD) &&
567 arch.IsMIPS()) {
568 addr_t mips_l_offs;
569 if (!(addr = ReadPointer(addr, &mips_l_offs)))
570 return false;
571 if (mips_l_offs != 0 && mips_l_offs != entry.base_addr)
572 return false;
573 }
574
575 if (!(addr = ReadPointer(addr, &entry.path_addr)))
576 return false;
577
578 if (!(addr = ReadPointer(addr, &entry.dyn_addr)))
579 return false;
580
581 if (!(addr = ReadPointer(addr, &entry.next)))
582 return false;
583
584 if (!(addr = ReadPointer(addr, &entry.prev)))
585 return false;
586
587 std::string file_path = ReadStringFromMemory(entry.path_addr);
588 entry.file_spec.SetFile(file_path, FileSpec::Style::native);
589
590 UpdateBaseAddrIfNecessary(entry, file_path);
591
592 return true;
593}
594
595bool DYLDRendezvous::FindMetadata(const char *name, PThreadField field,
596 uint32_t &value) {
597 Target &target = m_process->GetTarget();
598
599 SymbolContextList list;
600 target.GetImages().FindSymbolsWithNameAndType(ConstString(name),
601 eSymbolTypeAny, list);
602 if (list.IsEmpty())
603 return false;
604
605 Address address = list[0].symbol->GetAddress();
606 addr_t addr = address.GetLoadAddress(&target);
607 if (addr == LLDB_INVALID_ADDRESS(18446744073709551615UL))
608 return false;
609
610 Status error;
611 value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(
612 addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error);
613 if (error.Fail())
614 return false;
615
616 if (field == eSize)
617 value /= 8; // convert bits to bytes
618
619 return true;
620}
621
622const DYLDRendezvous::ThreadInfo &DYLDRendezvous::GetThreadInfo() {
623 if (!m_thread_info.valid) {
624 bool ok = true;
625
626 ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset,
627 m_thread_info.dtv_offset);
628 ok &=
629 FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);
630 ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset,
631 m_thread_info.modid_offset);
632 ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset,
633 m_thread_info.tls_offset);
634
635 if (ok)
636 m_thread_info.valid = true;
637 }
638
639 return m_thread_info;
640}
641
642void DYLDRendezvous::DumpToLog(Log *log) const {
643 int state = GetState();
644
645 if (!log)
646 return;
647
648 log->PutCString("DYLDRendezvous:");
649 LLDB_LOGF(log, " Address: %" PRIx64, GetRendezvousAddress())do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" Address: %" "l" "x", GetRendezvousAddress
()); } while (0)
;
650 LLDB_LOGF(log, " Version: %" PRIu64, GetVersion())do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" Version: %" "l" "u", GetVersion(
)); } while (0)
;
651 LLDB_LOGF(log, " Link : %" PRIx64, GetLinkMapAddress())do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" Link : %" "l" "x", GetLinkMapAddress
()); } while (0)
;
652 LLDB_LOGF(log, " Break : %" PRIx64, GetBreakAddress())do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" Break : %" "l" "x", GetBreakAddress
()); } while (0)
;
653 LLDB_LOGF(log, " LDBase : %" PRIx64, GetLDBase())do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" LDBase : %" "l" "x", GetLDBase()
); } while (0)
;
654 LLDB_LOGF(log, " State : %s",do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" State : %s", (state == eConsistent
) ? "consistent" : (state == eAdd) ? "add" : (state == eDelete
) ? "delete" : "unknown"); } while (0)
655 (state == eConsistent)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" State : %s", (state == eConsistent
) ? "consistent" : (state == eAdd) ? "add" : (state == eDelete
) ? "delete" : "unknown"); } while (0)
656 ? "consistent"do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" State : %s", (state == eConsistent
) ? "consistent" : (state == eAdd) ? "add" : (state == eDelete
) ? "delete" : "unknown"); } while (0)
657 : (state == eAdd) ? "add"do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" State : %s", (state == eConsistent
) ? "consistent" : (state == eAdd) ? "add" : (state == eDelete
) ? "delete" : "unknown"); } while (0)
658 : (state == eDelete) ? "delete" : "unknown")do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" State : %s", (state == eConsistent
) ? "consistent" : (state == eAdd) ? "add" : (state == eDelete
) ? "delete" : "unknown"); } while (0)
;
659
660 iterator I = begin();
661 iterator E = end();
662
663 if (I != E)
664 log->PutCString("DYLDRendezvous SOEntries:");
665
666 for (int i = 1; I != E; ++I, ++i) {
667 LLDB_LOGF(log, "\n SOEntry [%d] %s", i, I->file_spec.GetPath().c_str())do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("\n SOEntry [%d] %s", i, I->file_spec
.GetPath().c_str()); } while (0)
;
668 LLDB_LOGF(log, " Base : %" PRIx64, I->base_addr)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" Base : %" "l" "x", I->base_addr
); } while (0)
;
669 LLDB_LOGF(log, " Path : %" PRIx64, I->path_addr)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" Path : %" "l" "x", I->path_addr
); } while (0)
;
670 LLDB_LOGF(log, " Dyn : %" PRIx64, I->dyn_addr)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" Dyn : %" "l" "x", I->dyn_addr
); } while (0)
;
671 LLDB_LOGF(log, " Next : %" PRIx64, I->next)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" Next : %" "l" "x", I->next
); } while (0)
;
672 LLDB_LOGF(log, " Prev : %" PRIx64, I->prev)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf(" Prev : %" "l" "x", I->prev
); } while (0)
;
673 }
674}
675
676bool DYLDRendezvous::IsCoreFile() const {
677 return !m_process->IsLiveDebugSession();
678}