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
15
18#include "lldb/Target/Target.h"
20#include "lldb/Utility/Endian.h"
22#include "lldb/Utility/Status.h"
23#include "lldb/Utility/Stream.h"
26#include "llvm/Support/ErrorExtras.h"
27#include <optional>
28
29using namespace lldb;
30using namespace lldb_private;
31using namespace lldb_private::formatters;
32
33namespace {
34
36
37class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
38 /*
39 (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char,
40 std::char_traits<char>, std::allocator<char> > > >) ibeg = {
41 (_Base_ptr) _M_node = 0x0000000100103910 {
42 (std::_Rb_tree_color) _M_color = _S_black
43 (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
44 (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
45 (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
46 }
47 }
48 */
49
50public:
51 explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
52
53 llvm::Expected<uint32_t> CalculateNumChildren() override;
54
55 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
56
57 lldb::ChildCacheState Update() override;
58
59 llvm::Expected<size_t> GetIndexOfChildWithName(llvm::StringRef name) override;
60
61private:
62 ExecutionContextRef m_exe_ctx_ref;
63 lldb::addr_t m_pair_address = 0;
64 CompilerType m_pair_type;
65 lldb::ValueObjectSP m_pair_sp;
66};
67
68class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
69public:
70 explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
71
72 llvm::Expected<uint32_t> CalculateNumChildren() override;
73
74 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
75
76 lldb::ChildCacheState Update() override;
77
78 llvm::Expected<size_t> GetIndexOfChildWithName(llvm::StringRef name) override;
79
80private:
81 // The lifetime of a ValueObject and all its derivative ValueObjects
82 // (children, clones, etc.) is managed by a ClusterManager. These
83 // objects are only destroyed when every shared pointer to any of them
84 // is destroyed, so we must not store a shared pointer to any ValueObject
85 // derived from our backend ValueObject (since we're in the same cluster).
86 ValueObject *m_ptr_obj = nullptr; // Underlying pointer (held, not owned)
87};
88
89} // end of anonymous namespace
90
91LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd(
92 lldb::ValueObjectSP valobj_sp)
93 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type(),
94 m_pair_sp() {
95 if (valobj_sp)
96 Update();
97}
98
99lldb::ChildCacheState LibstdcppMapIteratorSyntheticFrontEnd::Update() {
100 ValueObjectSP valobj_sp = m_backend.GetSP();
101 if (!valobj_sp)
103
104 TargetSP target_sp(valobj_sp->GetTargetSP());
105
106 if (!target_sp)
108
109 bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
110
111 if (!valobj_sp)
113 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
114
115 ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName("_M_node"));
116 if (!_M_node_sp)
118
119 m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
120 if (m_pair_address == 0)
122
123 m_pair_address += (is_64bit ? 32 : 16);
124
125 CompilerType my_type(valobj_sp->GetCompilerType());
126 if (my_type.GetNumTemplateArguments() >= 1) {
127 CompilerType pair_type = my_type.GetTypeTemplateArgument(0);
128 if (!pair_type)
130 m_pair_type = pair_type;
131 } else
133
135}
136
137llvm::Expected<uint32_t>
138LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
139 return 2;
140}
141
143LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
144 if (m_pair_address != 0 && m_pair_type) {
145 if (!m_pair_sp)
146 m_pair_sp = CreateChildValueObjectFromAddress("pair", m_pair_address,
147 m_exe_ctx_ref, m_pair_type);
148 if (m_pair_sp)
149 return m_pair_sp->GetChildAtIndex(idx);
150 }
151 return lldb::ValueObjectSP();
152}
153
154llvm::Expected<size_t>
155LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
156 llvm::StringRef name) {
157 if (name == "first")
158 return 0;
159 if (name == "second")
160 return 1;
161 return llvm::createStringErrorV("type has no child named '{0}'", name);
162}
163
164SyntheticChildrenFrontEnd *
166 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
167 return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp)
168 : nullptr);
169}
170
171/*
172 (lldb) fr var ibeg --ptr-depth 1
173 (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >)
174 ibeg = {
175 _M_current = 0x00000001001037a0 {
176 *_M_current = 1
177 }
178 }
179 */
180
181SyntheticChildrenFrontEnd *
183 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
184 return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(
185 valobj_sp, {ConstString("_M_current")})
186 : nullptr);
187}
188
190 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
191 ValueObjectSP ptr = valobj.GetChildAtNamePath({"_M_dataplus", "_M_p"});
192 if (!ptr || !ptr->GetError().Success())
193 stream << "Summary Unavailable";
194 else
195 stream << ptr->GetSummaryAsCString();
196
197 return true;
198}
199
200template <StringPrinter::StringElementType element_type>
201static bool formatStringViewImpl(ValueObject &valobj, Stream &stream,
202 const TypeSummaryOptions &summary_options,
203 std::string prefix_token) {
204 auto data_sp = valobj.GetChildMemberWithName("_M_str");
205 auto size_sp = valobj.GetChildMemberWithName("_M_len");
206 if (!data_sp || !size_sp)
207 return false;
208
209 bool success = false;
210 uint64_t size = size_sp->GetValueAsUnsigned(0, &success);
211 if (!success) {
212 stream << "Summary Unavailable";
213 return true;
214 }
215
216 StreamString scratch_stream;
218 scratch_stream, summary_options, data_sp, size, prefix_token);
219
220 if (success)
221 stream << scratch_stream.GetData();
222 else
223 stream << "Summary Unavailable";
224 return true;
225}
226
228 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
229 auto wchar_t_size = GetWCharByteSize(valobj);
230 if (!wchar_t_size)
231 return false;
232
233 switch (*wchar_t_size) {
234 case 1:
236 options, "L");
237 case 2:
239 options, "L");
240 case 4:
242 options, "L");
243 }
244 return false;
245}
246
247template <StringElementType element_type>
248static constexpr const char *getPrefixToken() {
249 switch (element_type) {
250 case StringElementType::ASCII:
251 return "";
252 case StringElementType::UTF8:
253 return "u8";
254 case StringElementType::UTF16:
255 return "u";
256 case StringElementType::UTF32:
257 return "U";
258 }
259 llvm_unreachable("invalid element type");
260}
261
262template <StringPrinter::StringElementType element_type>
268
270 StringElementType::ASCII>(ValueObject &, Stream &,
271 const TypeSummaryOptions &);
273 StringElementType::UTF8>(ValueObject &, Stream &,
274 const TypeSummaryOptions &);
276 StringElementType::UTF16>(ValueObject &, Stream &,
277 const TypeSummaryOptions &);
279 StringElementType::UTF32>(ValueObject &, Stream &,
280 const TypeSummaryOptions &);
281
282LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(
283 lldb::ValueObjectSP valobj_sp)
284 : SyntheticChildrenFrontEnd(*valobj_sp) {
285 if (valobj_sp)
286 Update();
287}
288
289llvm::Expected<uint32_t>
290LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() {
291 return 1;
292}
293
295LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
296 if (!m_ptr_obj)
297 return nullptr;
298
299 if (idx == 0)
300 return m_ptr_obj->GetSP();
301
302 if (idx == 1) {
303 ValueObjectSP valobj_sp = m_backend.GetSP();
304 if (!valobj_sp)
305 return nullptr;
306
307 Status status;
308 ValueObjectSP value_sp = m_ptr_obj->Dereference(status);
309 if (status.Success())
310 return value_sp;
311 }
312 return lldb::ValueObjectSP();
313}
314
315lldb::ChildCacheState LibStdcppSharedPtrSyntheticFrontEnd::Update() {
316 auto backend = m_backend.GetSP();
317 if (!backend)
319
320 auto valobj_sp = backend->GetNonSyntheticValue();
321 if (!valobj_sp)
323
324 auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_M_ptr");
325 if (!ptr_obj_sp)
327
328 auto cast_ptr_sp = GetDesugaredSmartPointerValue(*ptr_obj_sp, *valobj_sp);
329 if (!cast_ptr_sp)
331
332 m_ptr_obj = cast_ptr_sp->Clone("pointer").get();
333
335}
336
337llvm::Expected<size_t>
338LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(
339 llvm::StringRef name) {
340 if (name == "pointer")
341 return 0;
342
343 if (name == "object" || name == "$$dereference$$")
344 return 1;
345
346 return llvm::createStringErrorV("type has no child named '{0}'", name);
347}
348
349SyntheticChildrenFrontEnd *
351 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
352 return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp)
353 : nullptr);
354}
355
357 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
358 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
359 if (!valobj_sp)
360 return false;
361
362 ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_M_ptr"));
363 if (!ptr_sp)
364 return false;
365
366 DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options);
367
368 ValueObjectSP pi_sp = valobj_sp->GetChildAtNamePath({"_M_refcount", "_M_pi"});
369 if (!pi_sp)
370 return false;
371
372 bool success;
373 uint64_t pi_addr = pi_sp->GetValueAsUnsigned(0, &success);
374 // Empty control field. We're done.
375 if (!success || pi_addr == 0)
376 return true;
377
378 int64_t shared_count = 0;
379 if (auto count_sp = pi_sp->GetChildMemberWithName("_M_use_count")) {
380 bool success;
381 shared_count = count_sp->GetValueAsSigned(0, &success);
382 if (!success)
383 return false;
384
385 stream.Printf(" strong=%" PRId64, shared_count);
386 }
387
388 // _M_weak_count is the number of weak references + (_M_use_count != 0).
389 if (auto weak_count_sp = pi_sp->GetChildMemberWithName("_M_weak_count")) {
390 bool success;
391 int64_t count = weak_count_sp->GetValueAsUnsigned(0, &success);
392 if (!success)
393 return false;
394
395 stream.Printf(" weak=%" PRId64, count - (shared_count != 0));
396 }
397
398 return true;
399}
400
401static uint64_t LibStdcppVariantNposValue(size_t index_byte_size) {
402 switch (index_byte_size) {
403 case 1:
404 return 0xff;
405 case 2:
406 return 0xffff;
407 default:
408 return 0xffff'ffff;
409 }
410}
411
413 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
414 ValueObjectSP valobj_sp = valobj.GetNonSyntheticValue();
415 if (!valobj_sp)
416 return false;
417
418 ValueObjectSP index_obj = valobj_sp->GetChildMemberWithName("_M_index");
419 ValueObjectSP data_obj = valobj_sp->GetChildMemberWithName("_M_u");
420 if (!index_obj || !data_obj)
421 return false;
422
423 auto index_bytes_or_err = index_obj->GetByteSize();
424 if (!index_bytes_or_err) {
426 index_bytes_or_err.takeError(),
427 "failed to get variant index byte size: {0}");
428 return false;
429 }
430 auto npos_value = LibStdcppVariantNposValue(*index_bytes_or_err);
431 auto index = index_obj->GetValueAsUnsigned(0);
432 if (index == npos_value) {
433 stream.Printf(" No Value");
434 return true;
435 }
436
437 auto variant_type =
438 valobj_sp->GetCompilerType().GetCanonicalType().GetNonReferenceType();
439 if (!variant_type)
440 return false;
441 if (index >= variant_type.GetNumTemplateArguments(true)) {
442 stream.Printf(" <Invalid>");
443 return true;
444 }
445
446 auto active_type = variant_type.GetTypeTemplateArgument(index, true);
447 stream << " Active Type = " << active_type.GetDisplayTypeName() << " ";
448 return true;
449}
450
451static std::optional<int64_t>
453 lldb::ValueObjectSP value_sp = valobj.GetChildMemberWithName("_M_value");
454 if (!value_sp)
455 return std::nullopt;
456 bool success;
457 int64_t value = value_sp->GetValueAsSigned(0, &success);
458 if (!success)
459 return std::nullopt;
460 return value;
461}
462
464 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
465 std::optional<int64_t> value = LibStdcppExtractOrderingValue(valobj);
466 if (!value)
467 return false;
468 switch (*value) {
469 case -1:
470 stream << "less";
471 break;
472 case 0:
473 stream << "equivalent";
474 break;
475 case 1:
476 stream << "greater";
477 break;
478 case -128:
479 case 2:
480 stream << "unordered";
481 break;
482 default:
483 return false;
484 }
485 return true;
486}
487
489 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
490 std::optional<int64_t> value = LibStdcppExtractOrderingValue(valobj);
491 if (!value)
492 return false;
493 switch (*value) {
494 case -1:
495 stream << "less";
496 break;
497 case 0:
498 stream << "equivalent";
499 break;
500 case 1:
501 stream << "greater";
502 break;
503 default:
504 return false;
505 }
506 return true;
507}
508
510 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
511 std::optional<int64_t> value = LibStdcppExtractOrderingValue(valobj);
512 if (!value)
513 return false;
514 switch (*value) {
515 case -1:
516 stream << "less";
517 break;
518 case 0:
519 stream << "equal";
520 break;
521 case 1:
522 stream << "greater";
523 break;
524 default:
525 return false;
526 }
527 return true;
528}
529
531 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
532 ValueObjectSP impl_sp = valobj.GetChildMemberWithName("_M_impl");
533 if (!impl_sp)
534 return false;
535
536 ValueObjectSP file_sp = impl_sp->GetChildMemberWithName("_M_file_name");
537 ValueObjectSP function_sp =
538 impl_sp->GetChildMemberWithName("_M_function_name");
539 ValueObjectSP line_sp = impl_sp->GetChildMemberWithName("_M_line");
540 ValueObjectSP column_sp = impl_sp->GetChildMemberWithName("_M_column");
541
542 if (!file_sp || !function_sp || !line_sp || !column_sp)
543 return false;
544
545 bool success = false;
546 uint64_t line = line_sp->GetValueAsUnsigned(0, &success);
547 if (!success)
548 return false;
549
550 uint64_t column = column_sp->GetValueAsUnsigned(0, &success);
551 if (!success)
552 return false;
553
554 const char *file = file_sp->GetSummaryAsCString();
555 stream.Format("{0}:{1}:{2}", file ? file : "<unknown>", line, column);
556
557 if (const char *function = function_sp->GetSummaryAsCString())
558 stream.Printf(" (%s)", function);
559
560 return true;
561}
static bool formatStringViewImpl(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options, std::string prefix_token)
Definition LibCxx.cpp:725
static constexpr const char * getPrefixToken()
static std::optional< int64_t > LibStdcppExtractOrderingValue(ValueObject &valobj)
static uint64_t LibStdcppVariantNposValue(size_t index_byte_size)
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:405
StringPrinter::StringElementType StringElementType
static std::optional< size_t > CalculateNumChildren(CompilerType container_elem_type, uint64_t num_elements, CompilerType element_type)
Calculates the number of elements stored in a container (with element type 'container_elem_type') as ...
bool Success() const
Test for success condition.
Definition Status.cpp:303
const char * GetData() const
A stream class that can stream formatted output to a file.
Definition Stream.h:28
void Format(const char *format, Args &&... args)
Forwards the arguments to llvm::formatv and writes to the stream.
Definition Stream.h:370
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
lldb::ValueObjectSP GetSP()
virtual lldb::ValueObjectSP GetChildMemberWithName(llvm::StringRef name, bool can_create=true)
lldb::ValueObjectSP GetChildAtNamePath(llvm::ArrayRef< llvm::StringRef > names)
virtual lldb::ValueObjectSP Clone(llvm::StringRef new_name)
Creates a copy of the ValueObject with a new name and setting the current ValueObject as its parent.
virtual lldb::ValueObjectSP Dereference(Status &error)
virtual lldb::ValueObjectSP GetNonSyntheticValue()
lldb::ValueObjectSP GetDesugaredSmartPointerValue(ValueObject &ptr, ValueObject &container)
Return the ValueObjectSP of the underlying pointer member whose type is a desugared 'std::shared_ptr:...
Definition Generic.cpp:13
bool LibStdcppStringViewSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
bool LibStdcppStrongOrderingSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
std::optional< uint64_t > GetWCharByteSize(ValueObject &valobj)
bool StringBufferSummaryProvider(Stream &stream, const TypeSummaryOptions &summary_options, lldb::ValueObjectSP location_sp, uint64_t size, std::string prefix_token)
Print a summary for a string buffer to stream.
bool LibStdcppSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
bool LibStdcppStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
SyntheticChildrenFrontEnd * LibStdcppVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
SyntheticChildrenFrontEnd * LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
bool LibStdcppPartialOrderingSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
SyntheticChildrenFrontEnd * LibStdcppSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
bool LibStdcppSourceLocationSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
bool LibStdcppVariantSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
void DumpCxxSmartPtrPointerSummary(Stream &stream, ValueObject &ptr, const TypeSummaryOptions &options)
Prints the summary for the pointer value of a C++ std::unique_ptr/stdshared_ptr/stdweak_ptr.
bool LibStdcppWStringViewSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
bool LibStdcppWeakOrderingSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
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
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::Target > TargetSP