LibStdcppUniquePointer.cpp revision 360784
1//===-- LibStdcppUniquePointer.cpp ------------------------------*- C++ -*-===//
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
11#include "lldb/Core/ValueObject.h"
12#include "lldb/DataFormatters/FormattersHelpers.h"
13#include "lldb/DataFormatters/TypeSynthetic.h"
14#include "lldb/Utility/ConstString.h"
15
16#include <memory>
17#include <vector>
18
19using namespace lldb;
20using namespace lldb_private;
21using namespace lldb_private::formatters;
22
23namespace {
24
25class LibStdcppUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
26public:
27  explicit LibStdcppUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
28
29  size_t CalculateNumChildren() override;
30
31  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
32
33  bool Update() override;
34
35  bool MightHaveChildren() override;
36
37  size_t GetIndexOfChildWithName(ConstString name) override;
38
39  bool GetSummary(Stream &stream, const TypeSummaryOptions &options);
40
41private:
42  // The lifetime of a ValueObject and all its derivative ValueObjects
43  // (children, clones, etc.) is managed by a ClusterManager. These
44  // objects are only destroyed when every shared pointer to any of them
45  // is destroyed, so we must not store a shared pointer to any ValueObject
46  // derived from our backend ValueObject (since we're in the same cluster).
47  ValueObject* m_ptr_obj = nullptr;
48  ValueObject* m_obj_obj = nullptr;
49  ValueObject* m_del_obj = nullptr;
50
51  ValueObjectSP GetTuple();
52};
53
54} // end of anonymous namespace
55
56LibStdcppUniquePtrSyntheticFrontEnd::LibStdcppUniquePtrSyntheticFrontEnd(
57    lldb::ValueObjectSP valobj_sp)
58    : SyntheticChildrenFrontEnd(*valobj_sp) {
59  Update();
60}
61
62ValueObjectSP LibStdcppUniquePtrSyntheticFrontEnd::GetTuple() {
63  ValueObjectSP valobj_backend_sp = m_backend.GetSP();
64
65  if (!valobj_backend_sp)
66    return nullptr;
67
68  ValueObjectSP valobj_sp = valobj_backend_sp->GetNonSyntheticValue();
69  if (!valobj_sp)
70    return nullptr;
71
72  ValueObjectSP obj_child_sp =
73      valobj_sp->GetChildMemberWithName(ConstString("_M_t"), true);
74  if (!obj_child_sp)
75      return nullptr;
76
77  ValueObjectSP obj_subchild_sp =
78      obj_child_sp->GetChildMemberWithName(ConstString("_M_t"), true);
79
80  // if there is a _M_t subchild, the tuple is found in the obj_subchild_sp
81  // (for libstdc++ 6.0.23).
82  if (obj_subchild_sp) {
83    return obj_subchild_sp;
84  }
85
86  return obj_child_sp;
87}
88
89bool LibStdcppUniquePtrSyntheticFrontEnd::Update() {
90  ValueObjectSP tuple_sp = GetTuple();
91
92  if (!tuple_sp)
93    return false;
94
95  std::unique_ptr<SyntheticChildrenFrontEnd> tuple_frontend(
96      LibStdcppTupleSyntheticFrontEndCreator(nullptr, tuple_sp));
97
98  ValueObjectSP ptr_obj = tuple_frontend->GetChildAtIndex(0);
99  if (ptr_obj)
100    m_ptr_obj = ptr_obj->Clone(ConstString("pointer")).get();
101
102  ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(1);
103  if (del_obj)
104    m_del_obj = del_obj->Clone(ConstString("deleter")).get();
105
106  if (m_ptr_obj) {
107    Status error;
108    ValueObjectSP obj_obj = m_ptr_obj->Dereference(error);
109    if (error.Success()) {
110      m_obj_obj = obj_obj->Clone(ConstString("object")).get();
111    }
112  }
113
114  return false;
115}
116
117bool LibStdcppUniquePtrSyntheticFrontEnd::MightHaveChildren() { return true; }
118
119lldb::ValueObjectSP
120LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
121  if (idx == 0 && m_ptr_obj)
122    return m_ptr_obj->GetSP();
123  if (idx == 1 && m_del_obj)
124    return m_del_obj->GetSP();
125  if (idx == 2 && m_obj_obj)
126    return m_obj_obj->GetSP();
127  return lldb::ValueObjectSP();
128}
129
130size_t LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() {
131  if (m_del_obj)
132    return 2;
133  return 1;
134}
135
136size_t LibStdcppUniquePtrSyntheticFrontEnd::GetIndexOfChildWithName(
137    ConstString name) {
138  if (name == "ptr" || name == "pointer")
139    return 0;
140  if (name == "del" || name == "deleter")
141    return 1;
142  if (name == "obj" || name == "object" || name == "$$dereference$$")
143    return 2;
144  return UINT32_MAX;
145}
146
147bool LibStdcppUniquePtrSyntheticFrontEnd::GetSummary(
148    Stream &stream, const TypeSummaryOptions &options) {
149  if (!m_ptr_obj)
150    return false;
151
152  bool success;
153  uint64_t ptr_value = m_ptr_obj->GetValueAsUnsigned(0, &success);
154  if (!success)
155    return false;
156  if (ptr_value == 0)
157    stream.Printf("nullptr");
158  else
159    stream.Printf("0x%" PRIx64, ptr_value);
160  return true;
161}
162
163SyntheticChildrenFrontEnd *
164lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator(
165    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
166  return (valobj_sp ? new LibStdcppUniquePtrSyntheticFrontEnd(valobj_sp)
167                    : nullptr);
168}
169
170bool lldb_private::formatters::LibStdcppUniquePointerSummaryProvider(
171    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
172  LibStdcppUniquePtrSyntheticFrontEnd formatter(valobj.GetSP());
173  return formatter.GetSummary(stream, options);
174}
175