13#include "clang/AST/RecordLayout.h"
23 "::`RTTI Complete Object Locator'";
27 name.consume_front(
"const ");
40 if (!suffix.consume_front(
"{for `") || !suffix.consume_back(
"'}"))
43 suffix.split(components,
"'s `");
54 std::optional<int64_t> offset_to_top =
61 if (!
m_process->GetTarget().ResolveLoadAddress(dynamic_addr, dynamic_address))
84 llvm::StringRef symbol_name =
87 LLDB_LOG(log,
"{0:x16}: '{1}' is not a valid vtable symbol",
95 bool any_found =
false;
104 "static-type = '{0}' has dynamic type: uid={1:x}, type-name='{2}'",
105 in_value.
GetTypeName(), type_sp->GetID(), type_sp->GetName());
119 llvm::SmallVector<llvm::StringRef, 2> vtable_components;
120 class_type_or_name =
GetTypeInfo(in_value, vtable_info, vtable_components);
121 if (!class_type_or_name) {
122 LLDB_LOG(log,
"{0:x16}: failed to get type info",
129 LLDB_LOG(log,
"{0:x16}: failed to get type info (no compiler type)",
138 LLDB_LOG(log,
"{0:x16}: {1} is not a complete type",
143 LLDB_LOG(log,
"{0:x16}: {1} is not a complete type",
150 LLDB_LOG(log,
"{0:x16}: in type is the same as the dynamic type",
156 std::scoped_lock<std::mutex> g(
m_mutex);
162 std::scoped_lock<std::mutex> g(
m_mutex);
165 return offset_to_top_it->second;
179 llvm::StringRef strategy =
"RTTI";
188 "{0:x16}: [{1}] '{2}' has offset {3} in '{4}'",
195 std::scoped_lock<std::mutex> g(
m_mutex);
211 const uint32_t addr_byte_size =
m_process->GetAddressByteSize();
213 vtable_load_addr - addr_byte_size;
215 if (complete_object_locator_load_addr >= vtable_load_addr)
220 llvm::Expected<lldb::addr_t> rtti_locator_base_load_addr =
221 m_process->ReadPointerFromMemory(complete_object_locator_load_addr);
222 if (!rtti_locator_base_load_addr ||
225 "Failed to read address of RTTI complete object locator at "
227 complete_object_locator_load_addr);
232 Address rtti_locator_base_addr;
233 if (!
m_process->GetTarget().ResolveLoadAddress(*rtti_locator_base_load_addr,
234 rtti_locator_base_addr)) {
236 "Failed to resolve load address of RTTI complete object "
237 "locator at {1:x16}: {0}",
238 *rtti_locator_base_load_addr);
244 if (symbol ==
nullptr)
250 LLDB_LOG(log,
"Found RTTI complete object locator: {0:x16}",
251 *rtti_locator_base_load_addr);
258 constexpr uint32_t int_size = 4;
262 Address offset_from_top_addr = rtti_locator_base_addr;
263 offset_from_top_addr.
Slide(int_size);
267 offset_from_top_addr, int_size, INT64_MIN,
error);
268 if (offset_from_top == INT64_MIN ||
error.Fail()) {
270 "Failed to read 'offset from top' from RTTI complete object "
271 "locator at {1:x16}: {0}",
276 return offset_from_top;
281static std::optional<size_t>
283 const clang::CXXRecordDecl *haystack,
284 const clang::CXXRecordDecl *target_base,
285 const llvm::ArrayRef<llvm::StringRef> checkpoints) {
287 const clang::CXXRecordDecl *decl;
290 std::optional<size_t> offset;
292 llvm::ArrayRef<llvm::StringRef> checkpoints;
294 bool found_target =
false;
299 std::deque<BaseEntry> bases;
300 bases.emplace_back(BaseEntry{
307 std::string base_name;
308 for (
const clang::CXXBaseSpecifier &base : haystack->vbases()) {
309 const clang::CXXRecordDecl *base_decl = llvm::cast<clang::CXXRecordDecl>(
310 base.getType()->castAs<clang::RecordType>()->getDecl());
313 if (!checkpoints.empty()) {
314 base_name = base_decl->getDeclName().getAsString();
315 if (base_name == checkpoints.back())
317 }
else if (base_decl == target_base) {
323 bases.emplace_back(BaseEntry{
330 while (!bases.empty()) {
331 BaseEntry current = bases.front();
333 (!current.found_target || !current.checkpoints.empty()) &&
334 "if we found the target we should only need to check the checkpoints");
336 const clang::ASTRecordLayout &record_layout =
337 ast.getASTRecordLayout(current.decl);
339 for (
const clang::CXXBaseSpecifier &base : current.decl->bases()) {
340 if (base.isVirtual())
343 const clang::CXXRecordDecl *base_decl = llvm::cast<clang::CXXRecordDecl>(
344 base.getType()->castAs<clang::RecordType>()->getDecl());
345 bool found_target = base_decl == target_base || current.found_target;
346 std::optional<size_t> offset = current.offset;
348 *offset += record_layout.getBaseClassOffset(base_decl).getQuantity();
350 if (!current.checkpoints.empty()) {
351 base_name = base_decl->getDeclName().getAsString();
352 if (base_name == current.checkpoints.back()) {
354 if (found_target && current.checkpoints.size() == 1)
359 bases.emplace_back(BaseEntry{
362 current.checkpoints.drop_back(),
367 }
else if (found_target) {
371 bases.emplace_back(BaseEntry{
387 llvm::ArrayRef<llvm::StringRef> vtable_components) {
392 clang::CXXRecordDecl *in_decl =
394 clang::CXXRecordDecl *target_decl =
396 if (!in_decl || !target_decl) {
397 LLDB_LOG(log,
"{0:x16}: types are not record types (in={1}, target={2})",
405 LLDB_LOG(log,
"{0:x16}: '{1}' and '{2}' are from different type systems",
407 in_decl->getDeclName().getAsString(),
408 target_decl->getDeclName().getAsString());
413 ts->getASTContext(), target_decl, in_decl, vtable_components);
415 LLDB_LOG(log,
"{0:x16}: failed to find offset of '{1}' in '{2}'",
417 in_decl->getDeclName().getAsString(),
418 target_decl->getDeclName().getAsString());
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
#define LLDB_LOG_ERROR(log, error,...)
static std::optional< size_t > GetOffsetOfBaseFromAST(clang::ASTContext &ast, const clang::CXXRecordDecl *haystack, const clang::CXXRecordDecl *target_base, const llvm::ArrayRef< llvm::StringRef > checkpoints)
Try to find the offset of target_base inside haystack while visiting all checkpoints.
static bool SplitVTableComponents(llvm::StringRef demangled, llvm::SmallVectorImpl< llvm::StringRef > &components)
static const llvm::StringRef s_rtti_complete_object_locator_indicator
static const llvm::StringRef s_vtable_demangled_indicator
static llvm::StringRef StripDemangledVTableSuffix(llvm::StringRef demangled)
A section + offset based address class.
lldb::addr_t GetLoadAddress(Target *target) const
Get the load address.
void SetRawAddress(lldb::addr_t addr)
bool Slide(int64_t offset)
lldb::addr_t GetOffset() const
Get the section relative offset value.
bool IsSectionOffset() const
Check if an address is section offset.
Symbol * CalculateSymbolContextSymbol() const
CommonABIRuntime(Process *process)
void SetDynamicTypeInfo(const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info)
lldb::TypeSP LookupTypeByName(llvm::StringRef type_name, lldb::ModuleSP preferred_module, bool &any_found) const
Find a type by its name, preferably in preferred_module.
TypeAndOrName GetDynamicTypeInfo(const lldb_private::Address &vtable_addr)
Generic representation of a type in a programming language.
TypeSystemSPWrapper GetTypeSystem() const
Accessors.
lldb::opaque_compiler_type_t GetOpaqueQualType() const
ConstString GetTypeName(bool BaseOnly=false) const
CompilerType GetPointeeType() const
If this type is a pointer type, return the type that the pointer points to, else return an invalid ty...
bool GetCompleteType() const
Type Completion.
bool IsPointerOrReferenceType(CompilerType *pointee_type=nullptr) const
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
const char * GetCString() const
Get the string value as a C string.
A class that handles mangled names.
ConstString GetDemangledName() const
Demangled name get accessor.
bool GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, const LanguageRuntime::VTableInfo &vtable_info, TypeAndOrName &class_type_or_name, Address &dynamic_address) override
std::optional< int64_t > GetOffsetToTopFromAST(const CompilerType &in_type, ValueObject &in_value, const CompilerType &dyn_type, const LanguageRuntime::VTableInfo &vtable_info, llvm::ArrayRef< llvm::StringRef > vtable_components)
OffsetToTopCache m_offset_to_top_map
std::optional< int64_t > GetOffsetToTopFromRTTI(const LanguageRuntime::VTableInfo &vtable_info, const CompilerType &dynamic_type)
std::optional< int64_t > GetOffsetToTop(ValueObject &in_value, TypeAndOrName &class_type_or_name, const LanguageRuntime::VTableInfo &vtable_info)
bool IsVTableSymbol(Mangled &mangled) const override
MicrosoftABIRuntime(Process *process)
TypeAndOrName GetTypeInfo(ValueObject &in_value, const LanguageRuntime::VTableInfo &vtable_info, llvm::SmallVectorImpl< llvm::StringRef > &vtable_components)
A plug-in interface definition class for debugging a process.
lldb::ModuleSP CalculateSymbolContextModule() override
ConstString GetName() const
int64_t ReadSignedIntegerFromMemory(const Address &addr, size_t integer_byte_size, int64_t fail_value, Status &error, bool force_live_memory=false)
Sometimes you can find the name of the type corresponding to an object, but we don't have debug infor...
void SetName(ConstString type_name)
CompilerType GetCompilerType() const
void SetTypeSP(lldb::TypeSP type_sp)
A TypeSystem implementation based on Clang.
static bool AreTypesSame(CompilerType type1, CompilerType type2, bool ignore_qualifiers=false)
static clang::CXXRecordDecl * GetAsCXXRecordDecl(lldb::opaque_compiler_type_t type)
virtual ConstString GetTypeName()
CompilerType GetCompilerType()
AddrAndType GetPointerValue()
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
std::shared_ptr< lldb_private::Type > TypeSP
std::shared_ptr< lldb_private::TypeSystemClang > TypeSystemClangSP
Symbol * symbol
Address of the vtable's virtual function table.