mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 13:46:07 +00:00

Add the ability to get a C++ vtable ValueObject from another ValueObject. This patch adds the ability to ask a ValueObject for a ValueObject that represents the virtual function table for a C++ class. If the ValueObject is not a C++ class with a vtable, a valid ValueObject value will be returned that contains an appropriate error. If it is successful a valid ValueObject that represents vtable will be returned. The ValueObject that is returned will have a name that matches the demangled value for a C++ vtable mangled name like "vtable for <class-name>". It will have N children, one for each virtual function pointer. Each child's value is the function pointer itself, the summary is the symbolication of this function pointer, and the type will be a valid function pointer from the debug info if there is debug information corresponding to the virtual function pointer. The vtable SBValue will have the following: - SBValue::GetName() returns "vtable for <class>" - SBValue::GetValue() returns a string representation of the vtable address - SBValue::GetSummary() returns NULL - SBValue::GetType() returns a type appropriate for a uintptr_t type for the current process - SBValue::GetLoadAddress() returns the address of the vtable adderess - SBValue::GetValueAsUnsigned(...) returns the vtable address - SBValue::GetNumChildren() returns the number of virtual function pointers in the vtable - SBValue::GetChildAtIndex(...) returns a SBValue that represents a virtual function pointer The child SBValue objects that represent a virtual function pointer has the following values: - SBValue::GetName() returns "[%u]" where %u is the vtable function pointer index - SBValue::GetValue() returns a string representation of the virtual function pointer - SBValue::GetSummary() returns a symbolicated respresentation of the virtual function pointer - SBValue::GetType() returns the function prototype type if there is debug info, or a generic funtion prototype if there is no debug info - SBValue::GetLoadAddress() returns the address of the virtual function pointer - SBValue::GetValueAsUnsigned(...) returns the virtual function pointer - SBValue::GetNumChildren() returns 0 - SBValue::GetChildAtIndex(...) returns invalid SBValue for any index Examples of using this API via python: ``` (lldb) script vtable = lldb.frame.FindVariable("shape_ptr").GetVTable() (lldb) script vtable vtable for Shape = 0x0000000100004088 { [0] = 0x0000000100003d20 a.out`Shape::~Shape() at main.cpp:3 [1] = 0x0000000100003e4c a.out`Shape::~Shape() at main.cpp:3 [2] = 0x0000000100003e7c a.out`Shape::area() at main.cpp:4 [3] = 0x0000000100003e3c a.out`Shape::optional() at main.cpp:7 } (lldb) script c = vtable.GetChildAtIndex(0) (lldb) script c (void ()) [0] = 0x0000000100003d20 a.out`Shape::~Shape() at main.cpp:3 ```
88 lines
3.3 KiB
C++
88 lines
3.3 KiB
C++
//===-- CXXFunctionPointer.cpp---------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/DataFormatters/CXXFunctionPointer.h"
|
|
|
|
#include "lldb/Core/ValueObject.h"
|
|
#include "lldb/Target/ABI.h"
|
|
#include "lldb/Target/SectionLoadList.h"
|
|
#include "lldb/Target/Target.h"
|
|
#include "lldb/Utility/Stream.h"
|
|
#include "lldb/lldb-enumerations.h"
|
|
|
|
#include <string>
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace lldb_private::formatters;
|
|
|
|
bool lldb_private::formatters::CXXFunctionPointerSummaryProvider(
|
|
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
|
|
std::string destination;
|
|
StreamString sstr;
|
|
AddressType func_ptr_address_type = eAddressTypeInvalid;
|
|
addr_t func_ptr_address = valobj.GetPointerValue(&func_ptr_address_type);
|
|
if (func_ptr_address != 0 && func_ptr_address != LLDB_INVALID_ADDRESS) {
|
|
switch (func_ptr_address_type) {
|
|
case eAddressTypeInvalid:
|
|
case eAddressTypeFile:
|
|
case eAddressTypeHost:
|
|
break;
|
|
|
|
case eAddressTypeLoad: {
|
|
ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
|
|
|
|
Address so_addr;
|
|
Target *target = exe_ctx.GetTargetPtr();
|
|
if (target && !target->GetSectionLoadList().IsEmpty()) {
|
|
target->GetSectionLoadList().ResolveLoadAddress(func_ptr_address,
|
|
so_addr);
|
|
if (so_addr.GetSection() == nullptr) {
|
|
// If we have an address that doesn't correspond to any symbol,
|
|
// it might have authentication bits. Strip them & see if it
|
|
// now points to a symbol -- if so, do the SymbolContext lookup
|
|
// based on the stripped address.
|
|
// If we find a symbol with the ptrauth bits stripped, print the
|
|
// raw value into the stream, and replace the Address with the
|
|
// one that points to a symbol for a fuller description.
|
|
if (Process *process = exe_ctx.GetProcessPtr()) {
|
|
if (ABISP abi_sp = process->GetABI()) {
|
|
addr_t fixed_addr = abi_sp->FixCodeAddress(func_ptr_address);
|
|
if (fixed_addr != func_ptr_address) {
|
|
Address test_address;
|
|
test_address.SetLoadAddress(fixed_addr, target);
|
|
if (test_address.GetSection() != nullptr) {
|
|
int addrsize = target->GetArchitecture().GetAddressByteSize();
|
|
sstr.Printf("actual=0x%*.*" PRIx64 " ", addrsize * 2,
|
|
addrsize * 2, fixed_addr);
|
|
so_addr = test_address;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (so_addr.IsValid()) {
|
|
so_addr.Dump(&sstr, exe_ctx.GetBestExecutionContextScope(),
|
|
Address::DumpStyleResolvedDescription,
|
|
Address::DumpStyleSectionNameOffset);
|
|
}
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
if (sstr.GetSize() > 0) {
|
|
if (valobj.GetValueType() == lldb::eValueTypeVTableEntry)
|
|
stream.PutCString(sstr.GetData());
|
|
else
|
|
stream.Printf("(%s)", sstr.GetData());
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|