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 size_t CalculateNumChildren() override;
47
48 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
49
50 bool Update() override;
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 size_t CalculateNumChildren() override;
68
69 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
70
71 bool Update() override;
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
97bool LibstdcppMapIteratorSyntheticFrontEnd::Update() {
98 ValueObjectSP valobj_sp = m_backend.GetSP();
99 if (!valobj_sp)
100 return false;
101
102 TargetSP target_sp(valobj_sp->GetTargetSP());
103
104 if (!target_sp)
105 return false;
106
107 bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
108
109 if (!valobj_sp)
110 return false;
111 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
112
113 ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName("_M_node", true));
114 if (!_M_node_sp)
115 return false;
116
117 m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
118 if (m_pair_address == 0)
119 return false;
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)
127 return false;
128 m_pair_type = pair_type;
129 } else
130 return false;
131
132 return true;
133}
134
135size_t LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
136 return 2;
137}
138
139lldb::ValueObjectSP
140LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
141 if (m_pair_address != 0 && m_pair_type) {
142 if (!m_pair_sp)
143 m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address,
144 m_exe_ctx_ref, m_pair_type);
145 if (m_pair_sp)
146 return m_pair_sp->GetChildAtIndex(idx, true);
147 }
148 return lldb::ValueObjectSP();
149}
150
151bool LibstdcppMapIteratorSyntheticFrontEnd::MightHaveChildren() { return true; }
152
153size_t LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
154 ConstString name) {
155 if (name == "first")
156 return 0;
157 if (name == "second")
158 return 1;
159 return UINT32_MAX;
160}
161
164 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
165 return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp)
166 : nullptr);
167}
168
169/*
170 (lldb) fr var ibeg --ptr-depth 1
171 (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >)
172 ibeg = {
173 _M_current = 0x00000001001037a0 {
174 *_M_current = 1
175 }
176 }
177 */
178
181 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
182 return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(
183 valobj_sp, {ConstString("_M_current")})
184 : nullptr);
185}
186
188 VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp,
189 llvm::ArrayRef<ConstString> item_names)
190 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
191 m_item_names(item_names), m_item_sp() {
192 if (valobj_sp)
193 Update();
194}
195
197 m_item_sp.reset();
198
199 ValueObjectSP valobj_sp = m_backend.GetSP();
200 if (!valobj_sp)
201 return false;
202
203 if (!valobj_sp)
204 return false;
205
206 ValueObjectSP item_ptr =
208 if (!item_ptr)
209 return false;
210 if (item_ptr->GetValueAsUnsigned(0) == 0)
211 return false;
212 Status err;
213 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
215 "item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref,
216 item_ptr->GetCompilerType().GetPointeeType());
217 if (err.Fail())
218 m_item_sp.reset();
219 return false;
220}
221
223
224lldb::ValueObjectSP
226 if (idx == 0)
227 return m_item_sp;
228 return lldb::ValueObjectSP();
229}
230
232
234 ConstString name) {
235 if (name == "item")
236 return 0;
237 return UINT32_MAX;
238}
239
241 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
242 const bool scalar_is_load_addr = true;
243 AddressType addr_type;
244 lldb::addr_t addr_of_string = LLDB_INVALID_ADDRESS;
245 if (valobj.IsPointerOrReferenceType()) {
247 ValueObjectSP pointee_sp = valobj.Dereference(error);
248 if (pointee_sp && error.Success())
249 addr_of_string = pointee_sp->GetAddressOf(scalar_is_load_addr, &addr_type);
250 } else
251 addr_of_string =
252 valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
253 if (addr_of_string != LLDB_INVALID_ADDRESS) {
254 switch (addr_type) {
255 case eAddressTypeLoad: {
256 ProcessSP process_sp(valobj.GetProcessSP());
257 if (!process_sp)
258 return false;
259
262 lldb::addr_t addr_of_data =
263 process_sp->ReadPointerFromMemory(addr_of_string, error);
264 if (error.Fail() || addr_of_data == 0 ||
265 addr_of_data == LLDB_INVALID_ADDRESS)
266 return false;
267 options.SetLocation(addr_of_data);
268 options.SetTargetSP(valobj.GetTargetSP());
269 options.SetStream(&stream);
270 options.SetNeedsZeroTermination(false);
271 options.SetBinaryZeroIsTerminator(true);
272 lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(
273 addr_of_string + process_sp->GetAddressByteSize(), error);
274 if (error.Fail())
275 return false;
276 options.SetSourceSize(size_of_data);
277 options.SetHasSourceSize(true);
278
280 StringPrinter::StringElementType::UTF8>(options)) {
281 stream.Printf("Summary Unavailable");
282 return true;
283 } else
284 return true;
285 } break;
286 case eAddressTypeHost:
287 break;
289 case eAddressTypeFile:
290 break;
291 }
292 }
293 return false;
294}
295
297 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
298 const bool scalar_is_load_addr = true;
299 AddressType addr_type;
300 lldb::addr_t addr_of_string =
301 valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
302 if (addr_of_string != LLDB_INVALID_ADDRESS) {
303 switch (addr_type) {
304 case eAddressTypeLoad: {
305 ProcessSP process_sp(valobj.GetProcessSP());
306 if (!process_sp)
307 return false;
308
309 CompilerType wchar_compiler_type =
311
312 if (!wchar_compiler_type)
313 return false;
314
315 // Safe to pass nullptr for exe_scope here.
316 std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
317 if (!size)
318 return false;
319 const uint32_t wchar_size = *size;
320
323 lldb::addr_t addr_of_data =
324 process_sp->ReadPointerFromMemory(addr_of_string, error);
325 if (error.Fail() || addr_of_data == 0 ||
326 addr_of_data == LLDB_INVALID_ADDRESS)
327 return false;
328 options.SetLocation(addr_of_data);
329 options.SetTargetSP(valobj.GetTargetSP());
330 options.SetStream(&stream);
331 options.SetNeedsZeroTermination(false);
332 options.SetBinaryZeroIsTerminator(false);
333 lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(
334 addr_of_string + process_sp->GetAddressByteSize(), error);
335 if (error.Fail())
336 return false;
337 options.SetSourceSize(size_of_data);
338 options.SetHasSourceSize(true);
339 options.SetPrefixToken("L");
340
341 switch (wchar_size) {
342 case 8:
344 StringPrinter::StringElementType::UTF8>(options);
345 case 16:
347 StringPrinter::StringElementType::UTF16>(options);
348 case 32:
350 StringPrinter::StringElementType::UTF32>(options);
351 default:
352 stream.Printf("size for wchar_t is not valid");
353 return true;
354 }
355 return true;
356 } break;
357 case eAddressTypeHost:
358 break;
360 case eAddressTypeFile:
361 break;
362 }
363 }
364 return false;
365}
366
367LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(
368 lldb::ValueObjectSP valobj_sp)
369 : SyntheticChildrenFrontEnd(*valobj_sp) {
370 if (valobj_sp)
371 Update();
372}
373
374size_t LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() { return 1; }
375
376lldb::ValueObjectSP
377LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
378 if (idx == 0)
379 return m_ptr_obj->GetSP();
380 if (idx == 1)
381 return m_obj_obj->GetSP();
382
383 return lldb::ValueObjectSP();
384}
385
386bool LibStdcppSharedPtrSyntheticFrontEnd::Update() {
387 auto backend = m_backend.GetSP();
388 if (!backend)
389 return false;
390
391 auto valobj_sp = backend->GetNonSyntheticValue();
392 if (!valobj_sp)
393 return false;
394
395 auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_M_ptr", true);
396 if (!ptr_obj_sp)
397 return false;
398
399 m_ptr_obj = ptr_obj_sp->Clone(ConstString("pointer")).get();
400
401 if (m_ptr_obj) {
403 ValueObjectSP obj_obj = m_ptr_obj->Dereference(error);
404 if (error.Success()) {
405 m_obj_obj = obj_obj->Clone(ConstString("object")).get();
406 }
407 }
408
409 return false;
410}
411
412bool LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren() { return true; }
413
414size_t LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(
415 ConstString name) {
416 if (name == "pointer")
417 return 0;
418 if (name == "object" || name == "$$dereference$$")
419 return 1;
420 return UINT32_MAX;
421}
422
425 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
426 return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp)
427 : nullptr);
428}
429
431 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
432 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
433 if (!valobj_sp)
434 return false;
435
436 ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_M_ptr", true));
437 if (!ptr_sp)
438 return false;
439
440 ValueObjectSP usecount_sp(
441 valobj_sp->GetChildAtNamePath({"_M_refcount", "_M_pi", "_M_use_count"}));
442 if (!usecount_sp)
443 return false;
444
445 if (ptr_sp->GetValueAsUnsigned(0) == 0 ||
446 usecount_sp->GetValueAsUnsigned(0) == 0) {
447 stream.Printf("nullptr");
448 return true;
449 }
450
452 ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
453 if (pointee_sp && error.Success()) {
454 if (pointee_sp->DumpPrintableRepresentation(
458 false)) {
459 return true;
460 }
461 }
462
463 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
464 return true;
465}
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:107
virtual size_t GetIndexOfChildWithName(ConstString name)=0
virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx)=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:554
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 bool IsPointerOrReferenceType()
Definition: ValueObject.h:388
virtual lldb::ValueObjectSP GetNonSyntheticValue()
Definition: ValueObject.h:591
static bool ReadStringAndDumpToStream(const ReadStringAndDumpToStreamOptions &options)
size_t GetIndexOfChildWithName(ConstString name) override
Definition: LibStdcpp.cpp:233
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
Definition: LibStdcpp.cpp:225
VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp, llvm::ArrayRef< ConstString > item_names)
Definition: LibStdcpp.cpp:188
llvm::SmallVector< ConstString, 2 > m_item_names
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:74
#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:38
bool LibStdcppSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: LibStdcpp.cpp:430
bool LibStdcppStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: LibStdcpp.cpp:240
bool LibStdcppWStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: LibStdcpp.cpp:296
SyntheticChildrenFrontEnd * LibStdcppVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
Definition: LibStdcpp.cpp:180
SyntheticChildrenFrontEnd * LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
Definition: LibStdcpp.cpp:163
SyntheticChildrenFrontEnd * LibStdcppSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
Definition: LibStdcpp.cpp:424
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
uint64_t addr_t
Definition: lldb-types.h:79