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