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