LLDB mainline
LibStdcpp.cpp
Go to the documentation of this file.
1//===-- LibStdcpp.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 "LibStdcpp.h"
10#include "LibCxx.h"
11
17#include "lldb/Target/Target.h"
19#include "lldb/Utility/Endian.h"
20#include "lldb/Utility/Status.h"
21#include "lldb/Utility/Stream.h"
22#include <optional>
23
24using namespace lldb;
25using namespace lldb_private;
26using namespace lldb_private::formatters;
27
28namespace {
29
30class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
31 /*
32 (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char,
33 std::char_traits<char>, std::allocator<char> > > >) ibeg = {
34 (_Base_ptr) _M_node = 0x0000000100103910 {
35 (std::_Rb_tree_color) _M_color = _S_black
36 (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
37 (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
38 (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
39 }
40 }
41 */
42
43public:
44 explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
45
46 llvm::Expected<uint32_t> CalculateNumChildren() override;
47
48 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
49
51
52 bool MightHaveChildren() override;
53
54 size_t GetIndexOfChildWithName(ConstString name) override;
55
56private:
57 ExecutionContextRef m_exe_ctx_ref;
58 lldb::addr_t m_pair_address = 0;
59 CompilerType m_pair_type;
60 lldb::ValueObjectSP m_pair_sp;
61};
62
63class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
64public:
65 explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
66
67 llvm::Expected<uint32_t> CalculateNumChildren() override;
68
69 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
70
72
73 bool MightHaveChildren() override;
74
75 size_t GetIndexOfChildWithName(ConstString name) override;
76private:
77
78 // The lifetime of a ValueObject and all its derivative ValueObjects
79 // (children, clones, etc.) is managed by a ClusterManager. These
80 // objects are only destroyed when every shared pointer to any of them
81 // is destroyed, so we must not store a shared pointer to any ValueObject
82 // derived from our backend ValueObject (since we're in the same cluster).
83 ValueObject* m_ptr_obj = nullptr; // Underlying pointer (held, not owned)
84 ValueObject* m_obj_obj = nullptr; // Underlying object (held, not owned)
85};
86
87} // end of anonymous namespace
88
89LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd(
90 lldb::ValueObjectSP valobj_sp)
91 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type(),
92 m_pair_sp() {
93 if (valobj_sp)
94 Update();
95}
96
97lldb::ChildCacheState LibstdcppMapIteratorSyntheticFrontEnd::Update() {
98 ValueObjectSP valobj_sp = m_backend.GetSP();
99 if (!valobj_sp)
101
102 TargetSP target_sp(valobj_sp->GetTargetSP());
103
104 if (!target_sp)
106
107 bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
108
109 if (!valobj_sp)
111 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
112
113 ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName("_M_node"));
114 if (!_M_node_sp)
116
117 m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
118 if (m_pair_address == 0)
120
121 m_pair_address += (is_64bit ? 32 : 16);
122
123 CompilerType my_type(valobj_sp->GetCompilerType());
124 if (my_type.GetNumTemplateArguments() >= 1) {
125 CompilerType pair_type = my_type.GetTypeTemplateArgument(0);
126 if (!pair_type)
128 m_pair_type = pair_type;
129 } else
131
133}
134
135llvm::Expected<uint32_t>
136LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
137 return 2;
138}
139
141LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
142 if (m_pair_address != 0 && m_pair_type) {
143 if (!m_pair_sp)
144 m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address,
145 m_exe_ctx_ref, m_pair_type);
146 if (m_pair_sp)
147 return m_pair_sp->GetChildAtIndex(idx);
148 }
149 return lldb::ValueObjectSP();
150}
151
152bool LibstdcppMapIteratorSyntheticFrontEnd::MightHaveChildren() { return true; }
153
154size_t LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
155 ConstString name) {
156 if (name == "first")
157 return 0;
158 if (name == "second")
159 return 1;
160 return UINT32_MAX;
161}
162
166 return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp)
167 : nullptr);
168}
169
170/*
171 (lldb) fr var ibeg --ptr-depth 1
172 (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >)
173 ibeg = {
174 _M_current = 0x00000001001037a0 {
175 *_M_current = 1
176 }
177 }
178 */
179
183 return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(
184 valobj_sp, {ConstString("_M_current")})
185 : nullptr);
186}
187
190 llvm::ArrayRef<ConstString> item_names)
191 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
192 m_item_names(item_names), m_item_sp() {
193 if (valobj_sp)
194 Update();
195}
196
198 m_item_sp.reset();
199
200 ValueObjectSP valobj_sp = m_backend.GetSP();
201 if (!valobj_sp)
203
204 if (!valobj_sp)
206
207 ValueObjectSP item_ptr =
209 if (!item_ptr)
211 if (item_ptr->GetValueAsUnsigned(0) == 0)
213 Status err;
214 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
216 "item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref,
217 item_ptr->GetCompilerType().GetPointeeType());
218 if (err.Fail())
219 m_item_sp.reset();
221}
222
223llvm::Expected<uint32_t>
225 return 1;
226}
227
230 if (idx == 0)
231 return m_item_sp;
232 return lldb::ValueObjectSP();
233}
234
236
238 ConstString name) {
239 if (name == "item")
240 return 0;
241 return UINT32_MAX;
242}
243
245 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
246 const bool scalar_is_load_addr = true;
247 AddressType addr_type;
248 lldb::addr_t addr_of_string = LLDB_INVALID_ADDRESS;
249 if (valobj.IsPointerOrReferenceType()) {
251 ValueObjectSP pointee_sp = valobj.Dereference(error);
252 if (pointee_sp && error.Success())
253 addr_of_string = pointee_sp->GetAddressOf(scalar_is_load_addr, &addr_type);
254 } else
255 addr_of_string =
256 valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
257 if (addr_of_string != LLDB_INVALID_ADDRESS) {
258 switch (addr_type) {
259 case eAddressTypeLoad: {
260 ProcessSP process_sp(valobj.GetProcessSP());
261 if (!process_sp)
262 return false;
263
266 lldb::addr_t addr_of_data =
267 process_sp->ReadPointerFromMemory(addr_of_string, error);
268 if (error.Fail() || addr_of_data == 0 ||
269 addr_of_data == LLDB_INVALID_ADDRESS)
270 return false;
271 options.SetLocation(addr_of_data);
272 options.SetTargetSP(valobj.GetTargetSP());
273 options.SetStream(&stream);
274 options.SetNeedsZeroTermination(false);
275 options.SetBinaryZeroIsTerminator(true);
276 lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(
277 addr_of_string + process_sp->GetAddressByteSize(), error);
278 if (error.Fail())
279 return false;
280 options.SetSourceSize(size_of_data);
281 options.SetHasSourceSize(true);
282
284 StringPrinter::StringElementType::UTF8>(options)) {
285 stream.Printf("Summary Unavailable");
286 return true;
287 } else
288 return true;
289 } break;
290 case eAddressTypeHost:
291 break;
293 case eAddressTypeFile:
294 break;
295 }
296 }
297 return false;
298}
299
301 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
302 const bool scalar_is_load_addr = true;
303 AddressType addr_type;
304 lldb::addr_t addr_of_string =
305 valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
306 if (addr_of_string != LLDB_INVALID_ADDRESS) {
307 switch (addr_type) {
308 case eAddressTypeLoad: {
309 ProcessSP process_sp(valobj.GetProcessSP());
310 if (!process_sp)
311 return false;
312
313 CompilerType wchar_compiler_type =
315
316 if (!wchar_compiler_type)
317 return false;
318
319 // Safe to pass nullptr for exe_scope here.
320 std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
321 if (!size)
322 return false;
323 const uint32_t wchar_size = *size;
324
327 lldb::addr_t addr_of_data =
328 process_sp->ReadPointerFromMemory(addr_of_string, error);
329 if (error.Fail() || addr_of_data == 0 ||
330 addr_of_data == LLDB_INVALID_ADDRESS)
331 return false;
332 options.SetLocation(addr_of_data);
333 options.SetTargetSP(valobj.GetTargetSP());
334 options.SetStream(&stream);
335 options.SetNeedsZeroTermination(false);
336 options.SetBinaryZeroIsTerminator(false);
337 lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(
338 addr_of_string + process_sp->GetAddressByteSize(), error);
339 if (error.Fail())
340 return false;
341 options.SetSourceSize(size_of_data);
342 options.SetHasSourceSize(true);
343 options.SetPrefixToken("L");
344
345 switch (wchar_size) {
346 case 8:
348 StringPrinter::StringElementType::UTF8>(options);
349 case 16:
351 StringPrinter::StringElementType::UTF16>(options);
352 case 32:
354 StringPrinter::StringElementType::UTF32>(options);
355 default:
356 stream.Printf("size for wchar_t is not valid");
357 return true;
358 }
359 return true;
360 } break;
361 case eAddressTypeHost:
362 break;
364 case eAddressTypeFile:
365 break;
366 }
367 }
368 return false;
369}
370
371LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(
372 lldb::ValueObjectSP valobj_sp)
373 : SyntheticChildrenFrontEnd(*valobj_sp) {
374 if (valobj_sp)
375 Update();
376}
377
378llvm::Expected<uint32_t>
379LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() {
380 return 1;
381}
382
384LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
385 if (idx == 0)
386 return m_ptr_obj->GetSP();
387 if (idx == 1) {
388 if (m_ptr_obj && !m_obj_obj) {
390 ValueObjectSP obj_obj = m_ptr_obj->Dereference(error);
391 if (error.Success())
392 m_obj_obj = obj_obj->Clone(ConstString("object")).get();
393 }
394 if (m_obj_obj)
395 return m_obj_obj->GetSP();
396 }
397 return lldb::ValueObjectSP();
398}
399
400lldb::ChildCacheState LibStdcppSharedPtrSyntheticFrontEnd::Update() {
401 auto backend = m_backend.GetSP();
402 if (!backend)
404
405 auto valobj_sp = backend->GetNonSyntheticValue();
406 if (!valobj_sp)
408
409 auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_M_ptr");
410 if (!ptr_obj_sp)
412
413 m_ptr_obj = ptr_obj_sp->Clone(ConstString("pointer")).get();
414 m_obj_obj = nullptr;
415
417}
418
419bool LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren() { return true; }
420
421size_t LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(
422 ConstString name) {
423 if (name == "pointer")
424 return 0;
425 if (name == "object" || name == "$$dereference$$")
426 return 1;
427 return UINT32_MAX;
428}
429
433 return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp)
434 : nullptr);
435}
436
438 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
439 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
440 if (!valobj_sp)
441 return false;
442
443 ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_M_ptr"));
444 if (!ptr_sp)
445 return false;
446
447 ValueObjectSP usecount_sp(
448 valobj_sp->GetChildAtNamePath({"_M_refcount", "_M_pi", "_M_use_count"}));
449 if (!usecount_sp)
450 return false;
451
452 if (ptr_sp->GetValueAsUnsigned(0) == 0 ||
453 usecount_sp->GetValueAsUnsigned(0) == 0) {
454 stream.Printf("nullptr");
455 return true;
456 }
457
459 ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
460 if (pointee_sp && error.Success()) {
461 if (pointee_sp->DumpPrintableRepresentation(
465 false)) {
466 return true;
467 }
468 }
469
470 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
471 return true;
472}
static llvm::raw_ostream & error(Stream &strm)
Generic representation of a type in a programming language.
Definition: CompilerType.h:36
CompilerType GetTypeTemplateArgument(size_t idx, bool expand_pack=false) const
CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) const
Create related types using the current type's AST.
std::optional< uint64_t > GetBitSize(ExecutionContextScope *exe_scope) const
Return the size of the type in bits.
A uniqued constant string class.
Definition: ConstString.h:40
Execution context objects refer to objects in the execution of the program that is being debugged.
An error handling class.
Definition: Status.h:44
bool Fail() const
Test for error condition.
Definition: Status.cpp:181
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:134
virtual lldb::ValueObjectSP GetChildAtIndex(uint32_t idx)=0
virtual lldb::ChildCacheState Update()=0
This function is assumed to always succeed and if it fails, the front-end should know to deal with it...
virtual size_t GetIndexOfChildWithName(ConstString name)=0
virtual llvm::Expected< uint32_t > CalculateNumChildren()=0
lldb::ValueObjectSP CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, CompilerType type)
CompilerType GetCompilerType()
Definition: ValueObject.h:352
lldb::ValueObjectSP GetSP()
Definition: ValueObject.h:545
lldb::ProcessSP GetProcessSP() const
Definition: ValueObject.h:338
virtual lldb::addr_t GetAddressOf(bool scalar_is_load_address=true, AddressType *address_type=nullptr)
lldb::TargetSP GetTargetSP() const
Definition: ValueObject.h:334
virtual lldb::ValueObjectSP Dereference(Status &error)
virtual lldb::ValueObjectSP GetNonSyntheticValue()
Definition: ValueObject.h:582
static bool ReadStringAndDumpToStream(const ReadStringAndDumpToStreamOptions &options)
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override
Definition: LibStdcpp.cpp:229
size_t GetIndexOfChildWithName(ConstString name) override
Definition: LibStdcpp.cpp:237
llvm::Expected< uint32_t > CalculateNumChildren() override
Definition: LibStdcpp.cpp:224
lldb::ChildCacheState Update() override
This function is assumed to always succeed and if it fails, the front-end should know to deal with it...
Definition: LibStdcpp.cpp:197
VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp, llvm::ArrayRef< ConstString > item_names)
Definition: LibStdcpp.cpp:189
llvm::SmallVector< ConstString, 2 > m_item_names
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:82
#define UINT32_MAX
Definition: lldb-defines.h:19
lldb::ValueObjectSP GetChildMemberWithName(ValueObject &obj, llvm::ArrayRef< ConstString > alternative_names)
Find a child member of obj_sp, trying all alternative names in order.
Definition: LibCxx.cpp:37
bool LibStdcppSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: LibStdcpp.cpp:437
bool LibStdcppStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: LibStdcpp.cpp:244
bool LibStdcppWStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: LibStdcpp.cpp:300
SyntheticChildrenFrontEnd * LibStdcppVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
Definition: LibStdcpp.cpp:181
SyntheticChildrenFrontEnd * LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
Definition: LibStdcpp.cpp:164
SyntheticChildrenFrontEnd * LibStdcppSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
Definition: LibStdcpp.cpp:431
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
@ eAddressTypeFile
Address is an address as found in an object or symbol file.
@ eAddressTypeLoad
Address is an address as in the current target inferior process.
@ eAddressTypeHost
Address is an address in the process that is running this code.
Definition: SBAddress.h:15
ChildCacheState
Specifies if children need to be re-computed after a call to SyntheticChildrenFrontEnd::Update.
@ eRefetch
Children need to be recomputed dynamically.
@ eReuse
Children did not change and don't need to be recomputed; re-use what we computed the last time we cal...
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Definition: lldb-forward.h:472
std::shared_ptr< lldb_private::Process > ProcessSP
Definition: lldb-forward.h:381
uint64_t addr_t
Definition: lldb-types.h:79
std::shared_ptr< lldb_private::Target > TargetSP
Definition: lldb-forward.h:436