| 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(x: path); |
| 33 | else |
| 34 | m_expression_paths.push_back(x: 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 | llvm::Expected<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(s1: name_cstr, s2: expr_cstr)) |
| 66 | return i; |
| 67 | } |
| 68 | } |
| 69 | } |
| 70 | return llvm::createStringError(Fmt: "Type has no child named '%s'" , |
| 71 | Vals: name.AsCString()); |
| 72 | } |
| 73 | |
| 74 | std::string TypeFilterImpl::GetDescription() { |
| 75 | StreamString sstr; |
| 76 | sstr.Printf(format: "%s%s%s {\n" , Cascades() ? "" : " (not cascading)" , |
| 77 | SkipsPointers() ? " (skip pointers)" : "" , |
| 78 | SkipsReferences() ? " (skip references)" : "" ); |
| 79 | |
| 80 | for (size_t i = 0; i < GetCount(); i++) { |
| 81 | sstr.Printf(format: " %s\n" , GetExpressionPathAtIndex(i)); |
| 82 | } |
| 83 | |
| 84 | sstr.Printf(format: "}" ); |
| 85 | return std::string(sstr.GetString()); |
| 86 | } |
| 87 | |
| 88 | SyntheticChildren::SyntheticChildren(const Flags &flags) : m_flags(flags) {} |
| 89 | |
| 90 | SyntheticChildren::~SyntheticChildren() = default; |
| 91 | |
| 92 | CXXSyntheticChildren::CXXSyntheticChildren( |
| 93 | const SyntheticChildren::Flags &flags, const char *description, |
| 94 | CreateFrontEndCallback callback) |
| 95 | : SyntheticChildren(flags), m_create_callback(std::move(callback)), |
| 96 | m_description(description ? description : "" ) {} |
| 97 | |
| 98 | CXXSyntheticChildren::~CXXSyntheticChildren() = default; |
| 99 | |
| 100 | bool SyntheticChildren::IsScripted() { return false; } |
| 101 | |
| 102 | std::string SyntheticChildren::GetDescription() { return "" ; } |
| 103 | |
| 104 | SyntheticChildrenFrontEnd::AutoPointer |
| 105 | SyntheticChildren::GetFrontEnd(ValueObject &backend) { |
| 106 | return nullptr; |
| 107 | } |
| 108 | |
| 109 | std::string CXXSyntheticChildren::GetDescription() { |
| 110 | StreamString sstr; |
| 111 | sstr.Printf(format: "%s%s%s %s" , Cascades() ? "" : " (not cascading)" , |
| 112 | SkipsPointers() ? " (skip pointers)" : "" , |
| 113 | SkipsReferences() ? " (skip references)" : "" , |
| 114 | m_description.c_str()); |
| 115 | |
| 116 | return std::string(sstr.GetString()); |
| 117 | } |
| 118 | |
| 119 | uint32_t |
| 120 | SyntheticChildrenFrontEnd::CalculateNumChildrenIgnoringErrors(uint32_t max) { |
| 121 | auto value_or_err = CalculateNumChildren(max); |
| 122 | if (value_or_err) |
| 123 | return *value_or_err; |
| 124 | LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), value_or_err.takeError(), |
| 125 | "{0}" ); |
| 126 | return 0; |
| 127 | } |
| 128 | |
| 129 | lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromExpression( |
| 130 | llvm::StringRef name, llvm::StringRef expression, |
| 131 | const ExecutionContext &exe_ctx) { |
| 132 | ValueObjectSP valobj_sp( |
| 133 | ValueObject::CreateValueObjectFromExpression(name, expression, exe_ctx)); |
| 134 | if (valobj_sp) |
| 135 | valobj_sp->SetSyntheticChildrenGenerated(true); |
| 136 | return valobj_sp; |
| 137 | } |
| 138 | |
| 139 | lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromAddress( |
| 140 | llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, |
| 141 | CompilerType type, bool do_deref) { |
| 142 | ValueObjectSP valobj_sp(ValueObject::CreateValueObjectFromAddress( |
| 143 | name, address, exe_ctx, type, do_deref)); |
| 144 | if (valobj_sp) |
| 145 | valobj_sp->SetSyntheticChildrenGenerated(true); |
| 146 | return valobj_sp; |
| 147 | } |
| 148 | |
| 149 | lldb::ValueObjectSP SyntheticChildrenFrontEnd::( |
| 150 | llvm::StringRef name, const DataExtractor &data, |
| 151 | const ExecutionContext &exe_ctx, CompilerType type) { |
| 152 | ValueObjectSP valobj_sp( |
| 153 | ValueObject::CreateValueObjectFromData(name, data, exe_ctx, type)); |
| 154 | if (valobj_sp) |
| 155 | valobj_sp->SetSyntheticChildrenGenerated(true); |
| 156 | return valobj_sp; |
| 157 | } |
| 158 | |
| 159 | ScriptedSyntheticChildren::FrontEnd::FrontEnd(std::string pclass, |
| 160 | ValueObject &backend) |
| 161 | : SyntheticChildrenFrontEnd(backend), m_python_class(pclass), |
| 162 | m_wrapper_sp(), m_interpreter(nullptr) { |
| 163 | if (backend.GetID() == LLDB_INVALID_UID) |
| 164 | return; |
| 165 | |
| 166 | TargetSP target_sp = backend.GetTargetSP(); |
| 167 | |
| 168 | if (!target_sp) |
| 169 | return; |
| 170 | |
| 171 | m_interpreter = target_sp->GetDebugger().GetScriptInterpreter(); |
| 172 | |
| 173 | if (m_interpreter != nullptr) |
| 174 | m_wrapper_sp = m_interpreter->CreateSyntheticScriptedProvider( |
| 175 | class_name: m_python_class.c_str(), valobj: backend.GetSP()); |
| 176 | } |
| 177 | |
| 178 | ScriptedSyntheticChildren::FrontEnd::~FrontEnd() = default; |
| 179 | |
| 180 | lldb::ValueObjectSP |
| 181 | ScriptedSyntheticChildren::FrontEnd::GetChildAtIndex(uint32_t idx) { |
| 182 | if (!m_wrapper_sp || !m_interpreter) |
| 183 | return lldb::ValueObjectSP(); |
| 184 | |
| 185 | return m_interpreter->GetChildAtIndex(implementor: m_wrapper_sp, idx); |
| 186 | } |
| 187 | |
| 188 | bool ScriptedSyntheticChildren::FrontEnd::IsValid() { |
| 189 | return (m_wrapper_sp && m_wrapper_sp->IsValid() && m_interpreter); |
| 190 | } |
| 191 | |
| 192 | llvm::Expected<uint32_t> |
| 193 | ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren() { |
| 194 | if (!m_wrapper_sp || m_interpreter == nullptr) |
| 195 | return 0; |
| 196 | return m_interpreter->CalculateNumChildren(implementor: m_wrapper_sp, UINT32_MAX); |
| 197 | } |
| 198 | |
| 199 | llvm::Expected<uint32_t> |
| 200 | ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren(uint32_t max) { |
| 201 | if (!m_wrapper_sp || m_interpreter == nullptr) |
| 202 | return 0; |
| 203 | return m_interpreter->CalculateNumChildren(implementor: m_wrapper_sp, max); |
| 204 | } |
| 205 | |
| 206 | lldb::ChildCacheState ScriptedSyntheticChildren::FrontEnd::Update() { |
| 207 | if (!m_wrapper_sp || m_interpreter == nullptr) |
| 208 | return lldb::ChildCacheState::eRefetch; |
| 209 | |
| 210 | return m_interpreter->UpdateSynthProviderInstance(implementor: m_wrapper_sp) |
| 211 | ? lldb::ChildCacheState::eReuse |
| 212 | : lldb::ChildCacheState::eRefetch; |
| 213 | } |
| 214 | |
| 215 | bool ScriptedSyntheticChildren::FrontEnd::MightHaveChildren() { |
| 216 | if (!m_wrapper_sp || m_interpreter == nullptr) |
| 217 | return false; |
| 218 | |
| 219 | return m_interpreter->MightHaveChildrenSynthProviderInstance(implementor: m_wrapper_sp); |
| 220 | } |
| 221 | |
| 222 | llvm::Expected<size_t> |
| 223 | ScriptedSyntheticChildren::FrontEnd::GetIndexOfChildWithName(ConstString name) { |
| 224 | if (!m_wrapper_sp || m_interpreter == nullptr) |
| 225 | return llvm::createStringError(Fmt: "Type has no child named '%s'" , |
| 226 | Vals: name.AsCString()); |
| 227 | return m_interpreter->GetIndexOfChildWithName(implementor: m_wrapper_sp, |
| 228 | child_name: name.GetCString()); |
| 229 | } |
| 230 | |
| 231 | lldb::ValueObjectSP ScriptedSyntheticChildren::FrontEnd::GetSyntheticValue() { |
| 232 | if (!m_wrapper_sp || m_interpreter == nullptr) |
| 233 | return nullptr; |
| 234 | |
| 235 | return m_interpreter->GetSyntheticValue(implementor: m_wrapper_sp); |
| 236 | } |
| 237 | |
| 238 | ConstString ScriptedSyntheticChildren::FrontEnd::GetSyntheticTypeName() { |
| 239 | if (!m_wrapper_sp || m_interpreter == nullptr) |
| 240 | return ConstString(); |
| 241 | |
| 242 | return m_interpreter->GetSyntheticTypeName(implementor: m_wrapper_sp); |
| 243 | } |
| 244 | |
| 245 | std::string ScriptedSyntheticChildren::GetDescription() { |
| 246 | StreamString sstr; |
| 247 | sstr.Printf(format: "%s%s%s Python class %s" , Cascades() ? "" : " (not cascading)" , |
| 248 | SkipsPointers() ? " (skip pointers)" : "" , |
| 249 | SkipsReferences() ? " (skip references)" : "" , |
| 250 | m_python_class.c_str()); |
| 251 | |
| 252 | return std::string(sstr.GetString()); |
| 253 | } |
| 254 | |