xref: /llvm-project/lldb/source/DataFormatters/TypeSummary.cpp (revision 87659a17d0703c1244211d9f8d1f0c21e816f0e1)
1 //===-- TypeSummary.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/DataFormatters/TypeSummary.h"
10 
11 #include "FormatterBytecode.h"
12 #include "lldb/lldb-enumerations.h"
13 #include "lldb/lldb-public.h"
14 
15 #include "lldb/Core/Debugger.h"
16 #include "lldb/DataFormatters/ValueObjectPrinter.h"
17 #include "lldb/Interpreter/CommandInterpreter.h"
18 #include "lldb/Symbol/CompilerType.h"
19 #include "lldb/Target/StackFrame.h"
20 #include "lldb/Target/Target.h"
21 #include "lldb/Utility/StreamString.h"
22 #include "lldb/ValueObject/ValueObject.h"
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 
27 TypeSummaryOptions::TypeSummaryOptions() = default;
28 
29 lldb::LanguageType TypeSummaryOptions::GetLanguage() const { return m_lang; }
30 
31 lldb::TypeSummaryCapping TypeSummaryOptions::GetCapping() const {
32   return m_capping;
33 }
34 
35 TypeSummaryOptions &TypeSummaryOptions::SetLanguage(lldb::LanguageType lang) {
36   m_lang = lang;
37   return *this;
38 }
39 
40 TypeSummaryOptions &
41 TypeSummaryOptions::SetCapping(lldb::TypeSummaryCapping cap) {
42   m_capping = cap;
43   return *this;
44 }
45 
46 TypeSummaryImpl::TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags)
47     : m_flags(flags), m_kind(kind) {}
48 
49 std::string TypeSummaryImpl::GetSummaryKindName() {
50   switch (m_kind) {
51   case Kind::eSummaryString:
52     return "string";
53   case Kind::eCallback:
54     return "callback";
55   case Kind::eScript:
56     return "python";
57   case Kind::eInternal:
58     return "c++";
59   case Kind::eBytecode:
60     return "bytecode";
61   }
62 }
63 
64 StringSummaryFormat::StringSummaryFormat(const TypeSummaryImpl::Flags &flags,
65                                          const char *format_cstr)
66     : TypeSummaryImpl(Kind::eSummaryString, flags), m_format_str() {
67   SetSummaryString(format_cstr);
68 }
69 
70 void StringSummaryFormat::SetSummaryString(const char *format_cstr) {
71   m_format.Clear();
72   if (format_cstr && format_cstr[0]) {
73     m_format_str = format_cstr;
74     m_error = FormatEntity::Parse(format_cstr, m_format);
75   } else {
76     m_format_str.clear();
77     m_error.Clear();
78   }
79 }
80 
81 bool StringSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval,
82                                        const TypeSummaryOptions &options) {
83   if (!valobj) {
84     retval.assign("NULL ValueObject");
85     return false;
86   }
87 
88   StreamString s;
89   ExecutionContext exe_ctx(valobj->GetExecutionContextRef());
90   SymbolContext sc;
91   StackFrame *frame = exe_ctx.GetFramePtr();
92   if (frame)
93     sc = frame->GetSymbolContext(lldb::eSymbolContextEverything);
94 
95   if (IsOneLiner()) {
96     // We've already checked the case of a NULL valobj above.  Let's put in an
97     // assert here to make sure someone doesn't take that out:
98     assert(valobj && "Must have a valid ValueObject to summarize");
99     ValueObjectPrinter printer(*valobj, &s, DumpValueObjectOptions());
100     printer.PrintChildrenOneLiner(HideNames(valobj));
101     retval = std::string(s.GetString());
102     return true;
103   } else {
104     if (FormatEntity::Format(m_format, s, &sc, &exe_ctx,
105                              &sc.line_entry.range.GetBaseAddress(), valobj,
106                              false, false)) {
107       retval.assign(std::string(s.GetString()));
108       return true;
109     } else {
110       retval.assign("error: summary string parsing error");
111       return false;
112     }
113   }
114 }
115 
116 std::string StringSummaryFormat::GetDescription() {
117   StreamString sstr;
118 
119   sstr.Printf("`%s`%s%s%s%s%s%s%s%s%s", m_format_str.c_str(),
120               m_error.Fail() ? " error: " : "",
121               m_error.Fail() ? m_error.AsCString() : "",
122               Cascades() ? "" : " (not cascading)",
123               !DoesPrintChildren(nullptr) ? "" : " (show children)",
124               !DoesPrintValue(nullptr) ? " (hide value)" : "",
125               IsOneLiner() ? " (one-line printout)" : "",
126               SkipsPointers() ? " (skip pointers)" : "",
127               SkipsReferences() ? " (skip references)" : "",
128               HideNames(nullptr) ? " (hide member names)" : "");
129   return std::string(sstr.GetString());
130 }
131 
132 std::string StringSummaryFormat::GetName() { return m_format_str; }
133 
134 CXXFunctionSummaryFormat::CXXFunctionSummaryFormat(
135     const TypeSummaryImpl::Flags &flags, Callback impl, const char *description)
136     : TypeSummaryImpl(Kind::eCallback, flags), m_impl(impl),
137       m_description(description ? description : "") {}
138 
139 bool CXXFunctionSummaryFormat::FormatObject(ValueObject *valobj,
140                                             std::string &dest,
141                                             const TypeSummaryOptions &options) {
142   dest.clear();
143   StreamString stream;
144   if (!m_impl || !m_impl(*valobj, stream, options))
145     return false;
146   dest = std::string(stream.GetString());
147   return true;
148 }
149 
150 std::string CXXFunctionSummaryFormat::GetDescription() {
151   StreamString sstr;
152   sstr.Printf("%s%s%s%s%s%s%s %s", Cascades() ? "" : " (not cascading)",
153               !DoesPrintChildren(nullptr) ? "" : " (show children)",
154               !DoesPrintValue(nullptr) ? " (hide value)" : "",
155               IsOneLiner() ? " (one-line printout)" : "",
156               SkipsPointers() ? " (skip pointers)" : "",
157               SkipsReferences() ? " (skip references)" : "",
158               HideNames(nullptr) ? " (hide member names)" : "",
159               m_description.c_str());
160   return std::string(sstr.GetString());
161 }
162 
163 std::string CXXFunctionSummaryFormat::GetName() { return m_description; }
164 
165 ScriptSummaryFormat::ScriptSummaryFormat(const TypeSummaryImpl::Flags &flags,
166                                          const char *function_name,
167                                          const char *python_script)
168     : TypeSummaryImpl(Kind::eScript, flags), m_function_name(),
169       m_python_script(), m_script_function_sp() {
170   // Take preference in the python script name over the function name.
171   if (function_name) {
172     m_function_name.assign(function_name);
173     m_script_formatter_name = function_name;
174   }
175   if (python_script) {
176     m_python_script.assign(python_script);
177     m_script_formatter_name = python_script;
178   }
179 
180   // Python scripts include the tabbing of the function def so we remove the
181   // leading spaces.
182   m_script_formatter_name = m_script_formatter_name.erase(
183       0, m_script_formatter_name.find_first_not_of(' '));
184 }
185 
186 bool ScriptSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval,
187                                        const TypeSummaryOptions &options) {
188   if (!valobj)
189     return false;
190 
191   TargetSP target_sp(valobj->GetTargetSP());
192 
193   if (!target_sp) {
194     retval.assign("error: no target");
195     return false;
196   }
197 
198   ScriptInterpreter *script_interpreter =
199       target_sp->GetDebugger().GetScriptInterpreter();
200 
201   if (!script_interpreter) {
202     retval.assign("error: no ScriptInterpreter");
203     return false;
204   }
205 
206   return script_interpreter->GetScriptedSummary(
207       m_function_name.c_str(), valobj->GetSP(), m_script_function_sp, options,
208       retval);
209 }
210 
211 std::string ScriptSummaryFormat::GetDescription() {
212   StreamString sstr;
213   sstr.Printf("%s%s%s%s%s%s%s\n  ", Cascades() ? "" : " (not cascading)",
214               !DoesPrintChildren(nullptr) ? "" : " (show children)",
215               !DoesPrintValue(nullptr) ? " (hide value)" : "",
216               IsOneLiner() ? " (one-line printout)" : "",
217               SkipsPointers() ? " (skip pointers)" : "",
218               SkipsReferences() ? " (skip references)" : "",
219               HideNames(nullptr) ? " (hide member names)" : "");
220   if (m_python_script.empty()) {
221     if (m_function_name.empty()) {
222       sstr.PutCString("no backing script");
223     } else {
224       sstr.PutCString(m_function_name);
225     }
226   } else {
227     sstr.PutCString(m_python_script);
228   }
229   return std::string(sstr.GetString());
230 }
231 
232 std::string ScriptSummaryFormat::GetName() { return m_script_formatter_name; }
233 
234 BytecodeSummaryFormat::BytecodeSummaryFormat(
235     const TypeSummaryImpl::Flags &flags,
236     std::unique_ptr<llvm::MemoryBuffer> bytecode)
237     : TypeSummaryImpl(Kind::eBytecode, flags), m_bytecode(std::move(bytecode)) {
238 }
239 
240 bool BytecodeSummaryFormat::FormatObject(ValueObject *valobj,
241                                          std::string &retval,
242                                          const TypeSummaryOptions &options) {
243   if (!valobj)
244     return false;
245 
246   TargetSP target_sp(valobj->GetTargetSP());
247 
248   if (!target_sp) {
249     retval.assign("error: no target");
250     return false;
251   }
252 
253   std::vector<FormatterBytecode::ControlStackElement> control(
254       {m_bytecode->getBuffer()});
255   FormatterBytecode::DataStack data({valobj->GetSP()});
256   llvm::Error error = FormatterBytecode::Interpret(
257       control, data, FormatterBytecode::sel_summary);
258   if (error) {
259     retval = llvm::toString(std::move(error));
260     return false;
261   }
262   if (!data.size()) {
263     retval = "empty stack";
264     return false;
265   }
266   auto &top = data.back();
267   retval = "";
268   llvm::raw_string_ostream os(retval);
269   if (auto s = std::get_if<std::string>(&top))
270     os << *s;
271   else if (auto u = std::get_if<uint64_t>(&top))
272     os << *u;
273   else if (auto i = std::get_if<int64_t>(&top))
274     os << *i;
275   else if (auto valobj = std::get_if<ValueObjectSP>(&top)) {
276     if (!valobj->get())
277       os << "empty object";
278     else
279       os << valobj->get()->GetValueAsCString();
280   } else if (auto type = std::get_if<CompilerType>(&top)) {
281     os << type->TypeDescription();
282   } else if (auto sel = std::get_if<FormatterBytecode::Selectors>(&top)) {
283     os << toString(*sel);
284   }
285   return true;
286 }
287 
288 std::string BytecodeSummaryFormat::GetDescription() {
289   StreamString sstr;
290   sstr.Printf("%s%s%s%s%s%s%s\n  ", Cascades() ? "" : " (not cascading)",
291               !DoesPrintChildren(nullptr) ? "" : " (show children)",
292               !DoesPrintValue(nullptr) ? " (hide value)" : "",
293               IsOneLiner() ? " (one-line printout)" : "",
294               SkipsPointers() ? " (skip pointers)" : "",
295               SkipsReferences() ? " (skip references)" : "",
296               HideNames(nullptr) ? " (hide member names)" : "");
297   // FIXME: sstr.PutCString(disassembly);
298   return std::string(sstr.GetString());
299 }
300 
301 std::string BytecodeSummaryFormat::GetName() {
302   return "LLDB bytecode formatter";
303 }
304