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 | |
12 | |
13 | |
14 | #include "lldb/lldb-enumerations.h" |
15 | #include "lldb/lldb-public.h" |
16 | |
17 | #include "lldb/Core/Debugger.h" |
18 | #include "lldb/Core/ValueObject.h" |
19 | #include "lldb/DataFormatters/ValueObjectPrinter.h" |
20 | #include "lldb/Interpreter/CommandInterpreter.h" |
21 | #include "lldb/Symbol/CompilerType.h" |
22 | #include "lldb/Target/StackFrame.h" |
23 | #include "lldb/Target/Target.h" |
24 | #include "lldb/Utility/StreamString.h" |
25 | |
26 | using namespace lldb; |
27 | using namespace lldb_private; |
28 | |
29 | TypeSummaryOptions::TypeSummaryOptions() = default; |
30 | |
31 | lldb::LanguageType TypeSummaryOptions::GetLanguage() const { return m_lang; } |
32 | |
33 | lldb::TypeSummaryCapping TypeSummaryOptions::GetCapping() const { |
34 | return m_capping; |
35 | } |
36 | |
37 | TypeSummaryOptions &TypeSummaryOptions::SetLanguage(lldb::LanguageType lang) { |
38 | m_lang = lang; |
39 | return *this; |
40 | } |
41 | |
42 | TypeSummaryOptions & |
43 | TypeSummaryOptions::SetCapping(lldb::TypeSummaryCapping cap) { |
44 | m_capping = cap; |
45 | return *this; |
46 | } |
47 | |
48 | TypeSummaryImpl::TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags) |
49 | : m_flags(flags), m_kind(kind) {} |
50 | |
51 | StringSummaryFormat::StringSummaryFormat(const TypeSummaryImpl::Flags &flags, |
52 | const char *format_cstr) |
53 | : TypeSummaryImpl(Kind::eSummaryString, flags), m_format_str() { |
54 | SetSummaryString(format_cstr); |
55 | } |
56 | |
57 | void StringSummaryFormat::SetSummaryString(const char *format_cstr) { |
58 | m_format.Clear(); |
59 | if (format_cstr && format_cstr[0]) { |
60 | m_format_str = format_cstr; |
61 | m_error = FormatEntity::Parse(format: format_cstr, entry&: m_format); |
62 | } else { |
63 | m_format_str.clear(); |
64 | m_error.Clear(); |
65 | } |
66 | } |
67 | |
68 | bool StringSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval, |
69 | const TypeSummaryOptions &options) { |
70 | if (!valobj) { |
71 | retval.assign(s: "NULL ValueObject" ); |
72 | return false; |
73 | } |
74 | |
75 | StreamString s; |
76 | ExecutionContext exe_ctx(valobj->GetExecutionContextRef()); |
77 | SymbolContext sc; |
78 | StackFrame *frame = exe_ctx.GetFramePtr(); |
79 | if (frame) |
80 | sc = frame->GetSymbolContext(resolve_scope: lldb::eSymbolContextEverything); |
81 | |
82 | if (IsOneLiner()) { |
83 | // We've already checked the case of a NULL valobj above. Let's put in an |
84 | // assert here to make sure someone doesn't take that out: |
85 | assert(valobj && "Must have a valid ValueObject to summarize" ); |
86 | ValueObjectPrinter printer(*valobj, &s, DumpValueObjectOptions()); |
87 | printer.PrintChildrenOneLiner(hide_names: HideNames(valobj)); |
88 | retval = std::string(s.GetString()); |
89 | return true; |
90 | } else { |
91 | if (FormatEntity::Format(entry: m_format, s, sc: &sc, exe_ctx: &exe_ctx, |
92 | addr: &sc.line_entry.range.GetBaseAddress(), valobj, |
93 | function_changed: false, initial_function: false)) { |
94 | retval.assign(str: std::string(s.GetString())); |
95 | return true; |
96 | } else { |
97 | retval.assign(s: "error: summary string parsing error" ); |
98 | return false; |
99 | } |
100 | } |
101 | } |
102 | |
103 | std::string StringSummaryFormat::GetDescription() { |
104 | StreamString sstr; |
105 | |
106 | sstr.Printf(format: "`%s`%s%s%s%s%s%s%s%s%s" , m_format_str.c_str(), |
107 | m_error.Fail() ? " error: " : "" , |
108 | m_error.Fail() ? m_error.AsCString() : "" , |
109 | Cascades() ? "" : " (not cascading)" , |
110 | !DoesPrintChildren(valobj: nullptr) ? "" : " (show children)" , |
111 | !DoesPrintValue(valobj: nullptr) ? " (hide value)" : "" , |
112 | IsOneLiner() ? " (one-line printout)" : "" , |
113 | SkipsPointers() ? " (skip pointers)" : "" , |
114 | SkipsReferences() ? " (skip references)" : "" , |
115 | HideNames(valobj: nullptr) ? " (hide member names)" : "" ); |
116 | return std::string(sstr.GetString()); |
117 | } |
118 | |
119 | CXXFunctionSummaryFormat::CXXFunctionSummaryFormat( |
120 | const TypeSummaryImpl::Flags &flags, Callback impl, const char *description) |
121 | : TypeSummaryImpl(Kind::eCallback, flags), m_impl(impl), |
122 | m_description(description ? description : "" ) {} |
123 | |
124 | bool CXXFunctionSummaryFormat::FormatObject(ValueObject *valobj, |
125 | std::string &dest, |
126 | const TypeSummaryOptions &options) { |
127 | dest.clear(); |
128 | StreamString stream; |
129 | if (!m_impl || !m_impl(*valobj, stream, options)) |
130 | return false; |
131 | dest = std::string(stream.GetString()); |
132 | return true; |
133 | } |
134 | |
135 | std::string CXXFunctionSummaryFormat::GetDescription() { |
136 | StreamString sstr; |
137 | sstr.Printf(format: "%s%s%s%s%s%s%s %s" , Cascades() ? "" : " (not cascading)" , |
138 | !DoesPrintChildren(valobj: nullptr) ? "" : " (show children)" , |
139 | !DoesPrintValue(valobj: nullptr) ? " (hide value)" : "" , |
140 | IsOneLiner() ? " (one-line printout)" : "" , |
141 | SkipsPointers() ? " (skip pointers)" : "" , |
142 | SkipsReferences() ? " (skip references)" : "" , |
143 | HideNames(valobj: nullptr) ? " (hide member names)" : "" , |
144 | m_description.c_str()); |
145 | return std::string(sstr.GetString()); |
146 | } |
147 | |
148 | ScriptSummaryFormat::ScriptSummaryFormat(const TypeSummaryImpl::Flags &flags, |
149 | const char *function_name, |
150 | const char *python_script) |
151 | : TypeSummaryImpl(Kind::eScript, flags), m_function_name(), |
152 | m_python_script(), m_script_function_sp() { |
153 | if (function_name) |
154 | m_function_name.assign(s: function_name); |
155 | if (python_script) |
156 | m_python_script.assign(s: python_script); |
157 | } |
158 | |
159 | bool ScriptSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval, |
160 | const TypeSummaryOptions &options) { |
161 | if (!valobj) |
162 | return false; |
163 | |
164 | TargetSP target_sp(valobj->GetTargetSP()); |
165 | |
166 | if (!target_sp) { |
167 | retval.assign(s: "error: no target" ); |
168 | return false; |
169 | } |
170 | |
171 | ScriptInterpreter *script_interpreter = |
172 | target_sp->GetDebugger().GetScriptInterpreter(); |
173 | |
174 | if (!script_interpreter) { |
175 | retval.assign(s: "error: no ScriptInterpreter" ); |
176 | return false; |
177 | } |
178 | |
179 | return script_interpreter->GetScriptedSummary( |
180 | function_name: m_function_name.c_str(), valobj: valobj->GetSP(), callee_wrapper_sp&: m_script_function_sp, options, |
181 | retval); |
182 | } |
183 | |
184 | std::string ScriptSummaryFormat::GetDescription() { |
185 | StreamString sstr; |
186 | sstr.Printf(format: "%s%s%s%s%s%s%s\n " , Cascades() ? "" : " (not cascading)" , |
187 | !DoesPrintChildren(valobj: nullptr) ? "" : " (show children)" , |
188 | !DoesPrintValue(valobj: nullptr) ? " (hide value)" : "" , |
189 | IsOneLiner() ? " (one-line printout)" : "" , |
190 | SkipsPointers() ? " (skip pointers)" : "" , |
191 | SkipsReferences() ? " (skip references)" : "" , |
192 | HideNames(valobj: nullptr) ? " (hide member names)" : "" ); |
193 | if (m_python_script.empty()) { |
194 | if (m_function_name.empty()) { |
195 | sstr.PutCString(cstr: "no backing script" ); |
196 | } else { |
197 | sstr.PutCString(cstr: m_function_name); |
198 | } |
199 | } else { |
200 | sstr.PutCString(cstr: m_python_script); |
201 | } |
202 | return std::string(sstr.GetString()); |
203 | } |
204 | |