1 //===-- TypeSynthetic.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 10 11 12 #include "lldb/lldb-enumerations.h" 13 #include "lldb/lldb-public.h" 14 15 #include "lldb/Core/Debugger.h" 16 #include "lldb/DataFormatters/TypeSynthetic.h" 17 #include "lldb/Interpreter/CommandInterpreter.h" 18 #include "lldb/Interpreter/ScriptInterpreter.h" 19 #include "lldb/Symbol/CompilerType.h" 20 #include "lldb/Target/Target.h" 21 #include "lldb/Utility/StreamString.h" 22 23 using namespace lldb; 24 using namespace lldb_private; 25 26 void TypeFilterImpl::AddExpressionPath(const std::string &path) { 27 bool need_add_dot = true; 28 if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[') 29 need_add_dot = false; 30 // add a '.' symbol to help forgetful users 31 if (!need_add_dot) 32 m_expression_paths.push_back(path); 33 else 34 m_expression_paths.push_back(std::string(".") + path); 35 } 36 37 bool TypeFilterImpl::SetExpressionPathAtIndex(size_t i, 38 const std::string &path) { 39 if (i >= GetCount()) 40 return false; 41 bool need_add_dot = true; 42 if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[') 43 need_add_dot = false; 44 // add a '.' symbol to help forgetful users 45 if (!need_add_dot) 46 m_expression_paths[i] = path; 47 else 48 m_expression_paths[i] = std::string(".") + path; 49 return true; 50 } 51 52 size_t 53 TypeFilterImpl::FrontEnd::GetIndexOfChildWithName(ConstString name) { 54 const char *name_cstr = name.GetCString(); 55 if (name_cstr) { 56 for (size_t i = 0; i < filter->GetCount(); i++) { 57 const char *expr_cstr = filter->GetExpressionPathAtIndex(i); 58 if (expr_cstr) { 59 if (*expr_cstr == '.') 60 expr_cstr++; 61 else if (*expr_cstr == '-' && *(expr_cstr + 1) == '>') 62 expr_cstr += 2; 63 } 64 if (expr_cstr) { 65 if (!::strcmp(name_cstr, expr_cstr)) 66 return i; 67 } 68 } 69 } 70 return UINT32_MAX; 71 } 72 73 std::string TypeFilterImpl::GetDescription() { 74 StreamString sstr; 75 sstr.Printf("%s%s%s {\n", Cascades() ? "" : " (not cascading)", 76 SkipsPointers() ? " (skip pointers)" : "", 77 SkipsReferences() ? " (skip references)" : ""); 78 79 for (size_t i = 0; i < GetCount(); i++) { 80 sstr.Printf(" %s\n", GetExpressionPathAtIndex(i)); 81 } 82 83 sstr.Printf("}"); 84 return std::string(sstr.GetString()); 85 } 86 87 SyntheticChildren::SyntheticChildren(const Flags &flags) : m_flags(flags) {} 88 89 SyntheticChildren::~SyntheticChildren() = default; 90 91 CXXSyntheticChildren::CXXSyntheticChildren( 92 const SyntheticChildren::Flags &flags, const char *description, 93 CreateFrontEndCallback callback) 94 : SyntheticChildren(flags), m_create_callback(std::move(callback)), 95 m_description(description ? description : "") {} 96 97 CXXSyntheticChildren::~CXXSyntheticChildren() = default; 98 99 bool SyntheticChildren::IsScripted() { return false; } 100 101 std::string SyntheticChildren::GetDescription() { return ""; } 102 103 SyntheticChildrenFrontEnd::AutoPointer 104 SyntheticChildren::GetFrontEnd(ValueObject &backend) { 105 return nullptr; 106 } 107 108 std::string CXXSyntheticChildren::GetDescription() { 109 StreamString sstr; 110 sstr.Printf("%s%s%s %s", Cascades() ? "" : " (not cascading)", 111 SkipsPointers() ? " (skip pointers)" : "", 112 SkipsReferences() ? " (skip references)" : "", 113 m_description.c_str()); 114 115 return std::string(sstr.GetString()); 116 } 117 118 uint32_t 119 SyntheticChildrenFrontEnd::CalculateNumChildrenIgnoringErrors(uint32_t max) { 120 auto value_or_err = CalculateNumChildren(max); 121 if (value_or_err) 122 return *value_or_err; 123 LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), value_or_err.takeError(), 124 "{0}"); 125 return 0; 126 } 127 128 lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromExpression( 129 llvm::StringRef name, llvm::StringRef expression, 130 const ExecutionContext &exe_ctx) { 131 ValueObjectSP valobj_sp( 132 ValueObject::CreateValueObjectFromExpression(name, expression, exe_ctx)); 133 if (valobj_sp) 134 valobj_sp->SetSyntheticChildrenGenerated(true); 135 return valobj_sp; 136 } 137 138 lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromAddress( 139 llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, 140 CompilerType type) { 141 ValueObjectSP valobj_sp( 142 ValueObject::CreateValueObjectFromAddress(name, address, exe_ctx, type)); 143 if (valobj_sp) 144 valobj_sp->SetSyntheticChildrenGenerated(true); 145 return valobj_sp; 146 } 147 148 lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromData( 149 llvm::StringRef name, const DataExtractor &data, 150 const ExecutionContext &exe_ctx, CompilerType type) { 151 ValueObjectSP valobj_sp( 152 ValueObject::CreateValueObjectFromData(name, data, exe_ctx, type)); 153 if (valobj_sp) 154 valobj_sp->SetSyntheticChildrenGenerated(true); 155 return valobj_sp; 156 } 157 158 ScriptedSyntheticChildren::FrontEnd::FrontEnd(std::string pclass, 159 ValueObject &backend) 160 : SyntheticChildrenFrontEnd(backend), m_python_class(pclass), 161 m_wrapper_sp(), m_interpreter(nullptr) { 162 if (backend.GetID() == LLDB_INVALID_UID) 163 return; 164 165 TargetSP target_sp = backend.GetTargetSP(); 166 167 if (!target_sp) 168 return; 169 170 m_interpreter = target_sp->GetDebugger().GetScriptInterpreter(); 171 172 if (m_interpreter != nullptr) 173 m_wrapper_sp = m_interpreter->CreateSyntheticScriptedProvider( 174 m_python_class.c_str(), backend.GetSP()); 175 } 176 177 ScriptedSyntheticChildren::FrontEnd::~FrontEnd() = default; 178 179 lldb::ValueObjectSP 180 ScriptedSyntheticChildren::FrontEnd::GetChildAtIndex(uint32_t idx) { 181 if (!m_wrapper_sp || !m_interpreter) 182 return lldb::ValueObjectSP(); 183 184 return m_interpreter->GetChildAtIndex(m_wrapper_sp, idx); 185 } 186 187 bool ScriptedSyntheticChildren::FrontEnd::IsValid() { 188 return (m_wrapper_sp && m_wrapper_sp->IsValid() && m_interpreter); 189 } 190 191 llvm::Expected<uint32_t> 192 ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren() { 193 if (!m_wrapper_sp || m_interpreter == nullptr) 194 return 0; 195 return m_interpreter->CalculateNumChildren(m_wrapper_sp, UINT32_MAX); 196 } 197 198 llvm::Expected<uint32_t> 199 ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren(uint32_t max) { 200 if (!m_wrapper_sp || m_interpreter == nullptr) 201 return 0; 202 return m_interpreter->CalculateNumChildren(m_wrapper_sp, max); 203 } 204 205 lldb::ChildCacheState ScriptedSyntheticChildren::FrontEnd::Update() { 206 if (!m_wrapper_sp || m_interpreter == nullptr) 207 return lldb::ChildCacheState::eRefetch; 208 209 return m_interpreter->UpdateSynthProviderInstance(m_wrapper_sp) 210 ? lldb::ChildCacheState::eReuse 211 : lldb::ChildCacheState::eRefetch; 212 } 213 214 bool ScriptedSyntheticChildren::FrontEnd::MightHaveChildren() { 215 if (!m_wrapper_sp || m_interpreter == nullptr) 216 return false; 217 218 return m_interpreter->MightHaveChildrenSynthProviderInstance(m_wrapper_sp); 219 } 220 221 size_t ScriptedSyntheticChildren::FrontEnd::GetIndexOfChildWithName( 222 ConstString name) { 223 if (!m_wrapper_sp || m_interpreter == nullptr) 224 return UINT32_MAX; 225 return m_interpreter->GetIndexOfChildWithName(m_wrapper_sp, 226 name.GetCString()); 227 } 228 229 lldb::ValueObjectSP ScriptedSyntheticChildren::FrontEnd::GetSyntheticValue() { 230 if (!m_wrapper_sp || m_interpreter == nullptr) 231 return nullptr; 232 233 return m_interpreter->GetSyntheticValue(m_wrapper_sp); 234 } 235 236 ConstString ScriptedSyntheticChildren::FrontEnd::GetSyntheticTypeName() { 237 if (!m_wrapper_sp || m_interpreter == nullptr) 238 return ConstString(); 239 240 return m_interpreter->GetSyntheticTypeName(m_wrapper_sp); 241 } 242 243 std::string ScriptedSyntheticChildren::GetDescription() { 244 StreamString sstr; 245 sstr.Printf("%s%s%s Python class %s", Cascades() ? "" : " (not cascading)", 246 SkipsPointers() ? " (skip pointers)" : "", 247 SkipsReferences() ? " (skip references)" : "", 248 m_python_class.c_str()); 249 250 return std::string(sstr.GetString()); 251 } 252