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