1 //===-- ValueObjectVTable.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/Core/ValueObjectVTable.h" 10 #include "lldb/Core/Module.h" 11 #include "lldb/Core/ValueObjectChild.h" 12 #include "lldb/Symbol/Function.h" 13 #include "lldb/Target/Language.h" 14 #include "lldb/Target/LanguageRuntime.h" 15 #include "lldb/lldb-defines.h" 16 #include "lldb/lldb-enumerations.h" 17 #include "lldb/lldb-forward.h" 18 #include "lldb/lldb-private-enumerations.h" 19 20 using namespace lldb; 21 using namespace lldb_private; 22 23 class ValueObjectVTableChild : public ValueObject { 24 public: 25 ValueObjectVTableChild(ValueObject &parent, uint32_t func_idx, 26 uint64_t addr_size) 27 : ValueObject(parent), m_func_idx(func_idx), m_addr_size(addr_size) { 28 SetFormat(eFormatPointer); 29 SetName(ConstString(llvm::formatv("[{0}]", func_idx).str())); 30 } 31 32 ~ValueObjectVTableChild() override = default; 33 34 std::optional<uint64_t> GetByteSize() override { return m_addr_size; }; 35 36 llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override { 37 return 0; 38 }; 39 40 ValueType GetValueType() const override { return eValueTypeVTableEntry; }; 41 42 bool IsInScope() override { 43 if (ValueObject *parent = GetParent()) 44 return parent->IsInScope(); 45 return false; 46 }; 47 48 protected: 49 bool UpdateValue() override { 50 SetValueIsValid(false); 51 m_value.Clear(); 52 ValueObject *parent = GetParent(); 53 if (!parent) { 54 m_error.SetErrorString("owning vtable object not valid"); 55 return false; 56 } 57 58 addr_t parent_addr = parent->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); 59 if (parent_addr == LLDB_INVALID_ADDRESS) { 60 m_error.SetErrorString("invalid vtable address"); 61 return false; 62 } 63 64 ProcessSP process_sp = GetProcessSP(); 65 if (!process_sp) { 66 m_error.SetErrorString("no process"); 67 return false; 68 } 69 70 TargetSP target_sp = GetTargetSP(); 71 if (!target_sp) { 72 m_error.SetErrorString("no target"); 73 return false; 74 } 75 76 // Each `vtable_entry_addr` points to the function pointer. 77 addr_t vtable_entry_addr = parent_addr + m_func_idx * m_addr_size; 78 addr_t vfunc_ptr = 79 process_sp->ReadPointerFromMemory(vtable_entry_addr, m_error); 80 if (m_error.Fail()) { 81 m_error.SetErrorStringWithFormat( 82 "failed to read virtual function entry 0x%16.16" PRIx64, 83 vtable_entry_addr); 84 return false; 85 } 86 87 88 // Set our value to be the load address of the function pointer in memory 89 // and our type to be the function pointer type. 90 m_value.SetValueType(Value::ValueType::LoadAddress); 91 m_value.GetScalar() = vtable_entry_addr; 92 93 // See if our resolved address points to a function in the debug info. If 94 // it does, then we can report the type as a function prototype for this 95 // function. 96 Function *function = nullptr; 97 Address resolved_vfunc_ptr_address; 98 target_sp->ResolveLoadAddress(vfunc_ptr, resolved_vfunc_ptr_address); 99 if (resolved_vfunc_ptr_address.IsValid()) 100 function = resolved_vfunc_ptr_address.CalculateSymbolContextFunction(); 101 if (function) { 102 m_value.SetCompilerType(function->GetCompilerType().GetPointerType()); 103 } else { 104 // Set our value's compiler type to a generic function protoype so that 105 // it displays as a hex function pointer for the value and the summary 106 // will display the address description. 107 108 // Get the original type that this vtable is based off of so we can get 109 // the language from it correctly. 110 ValueObject *val = parent->GetParent(); 111 auto type_system = target_sp->GetScratchTypeSystemForLanguage( 112 val ? val->GetObjectRuntimeLanguage() : eLanguageTypeC_plus_plus); 113 if (type_system) { 114 m_value.SetCompilerType( 115 (*type_system)->CreateGenericFunctionPrototype().GetPointerType()); 116 } else { 117 consumeError(type_system.takeError()); 118 } 119 } 120 121 // Now read our value into m_data so that our we can use the default 122 // summary provider for C++ for function pointers which will get the 123 // address description for our function pointer. 124 if (m_error.Success()) { 125 const bool thread_and_frame_only_if_stopped = true; 126 ExecutionContext exe_ctx( 127 GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped)); 128 m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get()); 129 } 130 SetValueDidChange(true); 131 SetValueIsValid(true); 132 return true; 133 }; 134 135 CompilerType GetCompilerTypeImpl() override { 136 return m_value.GetCompilerType(); 137 }; 138 139 const uint32_t m_func_idx; 140 const uint64_t m_addr_size; 141 142 private: 143 // For ValueObject only 144 ValueObjectVTableChild(const ValueObjectVTableChild &) = delete; 145 const ValueObjectVTableChild & 146 operator=(const ValueObjectVTableChild &) = delete; 147 }; 148 149 ValueObjectSP ValueObjectVTable::Create(ValueObject &parent) { 150 return (new ValueObjectVTable(parent))->GetSP(); 151 } 152 153 ValueObjectVTable::ValueObjectVTable(ValueObject &parent) 154 : ValueObject(parent) { 155 SetFormat(eFormatPointer); 156 } 157 158 std::optional<uint64_t> ValueObjectVTable::GetByteSize() { 159 if (m_vtable_symbol) 160 return m_vtable_symbol->GetByteSize(); 161 return std::nullopt; 162 } 163 164 llvm::Expected<uint32_t> ValueObjectVTable::CalculateNumChildren(uint32_t max) { 165 if (UpdateValueIfNeeded(false)) 166 return m_num_vtable_entries <= max ? m_num_vtable_entries : max; 167 return 0; 168 } 169 170 ValueType ValueObjectVTable::GetValueType() const { return eValueTypeVTable; } 171 172 ConstString ValueObjectVTable::GetTypeName() { 173 if (m_vtable_symbol) 174 return m_vtable_symbol->GetName(); 175 return ConstString(); 176 } 177 178 ConstString ValueObjectVTable::GetQualifiedTypeName() { return GetTypeName(); } 179 180 ConstString ValueObjectVTable::GetDisplayTypeName() { 181 if (m_vtable_symbol) 182 return m_vtable_symbol->GetDisplayName(); 183 return ConstString(); 184 } 185 186 bool ValueObjectVTable::IsInScope() { return GetParent()->IsInScope(); } 187 188 ValueObject *ValueObjectVTable::CreateChildAtIndex(size_t idx) { 189 return new ValueObjectVTableChild(*this, idx, m_addr_size); 190 } 191 192 bool ValueObjectVTable::UpdateValue() { 193 m_error.Clear(); 194 m_flags.m_children_count_valid = false; 195 SetValueIsValid(false); 196 m_num_vtable_entries = 0; 197 ValueObject *parent = GetParent(); 198 if (!parent) { 199 m_error.SetErrorString("no parent object"); 200 return false; 201 } 202 203 ProcessSP process_sp = GetProcessSP(); 204 if (!process_sp) { 205 m_error.SetErrorString("no process"); 206 return false; 207 } 208 209 const LanguageType language = parent->GetObjectRuntimeLanguage(); 210 LanguageRuntime *language_runtime = process_sp->GetLanguageRuntime(language); 211 212 if (language_runtime == nullptr) { 213 m_error.SetErrorStringWithFormat( 214 "no language runtime support for the language \"%s\"", 215 Language::GetNameForLanguageType(language)); 216 return false; 217 } 218 219 // Get the vtable information from the language runtime. 220 llvm::Expected<LanguageRuntime::VTableInfo> vtable_info_or_err = 221 language_runtime->GetVTableInfo(*parent, /*check_type=*/true); 222 if (!vtable_info_or_err) { 223 m_error = vtable_info_or_err.takeError(); 224 return false; 225 } 226 227 TargetSP target_sp = GetTargetSP(); 228 const addr_t vtable_start_addr = 229 vtable_info_or_err->addr.GetLoadAddress(target_sp.get()); 230 231 m_vtable_symbol = vtable_info_or_err->symbol; 232 if (!m_vtable_symbol) { 233 m_error.SetErrorStringWithFormat( 234 "no vtable symbol found containing 0x%" PRIx64, vtable_start_addr); 235 return false; 236 } 237 238 // Now that we know it's a vtable, we update the object's state. 239 SetName(GetTypeName()); 240 241 // Calculate the number of entries 242 if (!m_vtable_symbol->GetByteSizeIsValid()) { 243 m_error.SetErrorStringWithFormat( 244 "vtable symbol \"%s\" doesn't have a valid size", 245 m_vtable_symbol->GetMangled().GetDemangledName().GetCString()); 246 return false; 247 } 248 249 m_addr_size = process_sp->GetAddressByteSize(); 250 const addr_t vtable_end_addr = 251 m_vtable_symbol->GetLoadAddress(target_sp.get()) + 252 m_vtable_symbol->GetByteSize(); 253 m_num_vtable_entries = (vtable_end_addr - vtable_start_addr) / m_addr_size; 254 255 m_value.SetValueType(Value::ValueType::LoadAddress); 256 m_value.GetScalar() = parent->GetAddressOf(); 257 auto type_system_or_err = 258 target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC_plus_plus); 259 if (type_system_or_err) { 260 m_value.SetCompilerType( 261 (*type_system_or_err)->GetBasicTypeFromAST(eBasicTypeUnsignedLong)); 262 } else { 263 consumeError(type_system_or_err.takeError()); 264 } 265 SetValueDidChange(true); 266 SetValueIsValid(true); 267 return true; 268 } 269 270 CompilerType ValueObjectVTable::GetCompilerTypeImpl() { return CompilerType(); } 271 272 ValueObjectVTable::~ValueObjectVTable() = default; 273