aboutsummaryrefslogtreecommitdiff
path: root/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp')
-rw-r--r--source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp374
1 files changed, 240 insertions, 134 deletions
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
index 8e2cfb5570d9..c49feb07200e 100644
--- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
@@ -13,13 +13,18 @@
#include "lldb/Core/ConstString.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Log.h"
+#include "lldb/Core/Mangled.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@@ -43,68 +48,26 @@ ItaniumABILanguageRuntime::CouldHaveDynamicValue (ValueObject &in_value)
return in_value.GetCompilerType().IsPossibleDynamicType (NULL, check_cxx, check_objc);
}
-bool
-ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,
- lldb::DynamicValueType use_dynamic,
- TypeAndOrName &class_type_or_name,
- Address &dynamic_address,
- Value::ValueType &value_type)
+TypeAndOrName
+ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress(ValueObject &in_value, lldb::addr_t original_ptr,
+ lldb::addr_t vtable_load_addr)
{
- // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0
- // in the object. That will point to the "address point" within the vtable (not the beginning of the
- // vtable.) We can then look up the symbol containing this "address point" and that symbol's name
- // demangled will contain the full class name.
- // The second pointer above the "address point" is the "offset_to_top". We'll use that to get the
- // start of the value object which holds the dynamic type.
- //
-
- class_type_or_name.Clear();
- value_type = Value::ValueType::eValueTypeScalar;
-
- // Only a pointer or reference type can have a different dynamic and static type:
- if (CouldHaveDynamicValue (in_value))
+ if (m_process && vtable_load_addr != LLDB_INVALID_ADDRESS)
{
- // First job, pull out the address at 0 offset from the object.
- AddressType address_type;
- lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type);
- if (original_ptr == LLDB_INVALID_ADDRESS)
- return false;
-
- ExecutionContext exe_ctx (in_value.GetExecutionContextRef());
-
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
-
- char memory_buffer[16];
- DataExtractor data(memory_buffer, sizeof(memory_buffer),
- process->GetByteOrder(),
- process->GetAddressByteSize());
- size_t address_byte_size = process->GetAddressByteSize();
- Error error;
- size_t bytes_read = process->ReadMemory (original_ptr,
- memory_buffer,
- address_byte_size,
- error);
- if (!error.Success() || (bytes_read != address_byte_size))
- {
- return false;
- }
-
- lldb::offset_t offset = 0;
- lldb::addr_t vtable_address_point = data.GetAddress (&offset);
-
- if (offset == 0)
- return false;
-
- // Now find the symbol that contains this address:
-
- SymbolContext sc;
- Address address_point_address;
- if (target && !target->GetSectionLoadList().IsEmpty())
+ // Find the symbol that contains the "vtable_load_addr" address
+ Address vtable_addr;
+ Target &target = m_process->GetTarget();
+ if (!target.GetSectionLoadList().IsEmpty())
{
- if (target->GetSectionLoadList().ResolveLoadAddress (vtable_address_point, address_point_address))
+ if (target.GetSectionLoadList().ResolveLoadAddress(vtable_load_addr, vtable_addr))
{
- target->GetImages().ResolveSymbolContextForAddress (address_point_address, eSymbolContextSymbol, sc);
+ // See if we have cached info for this type already
+ TypeAndOrName type_info = GetDynamicTypeInfo(vtable_addr);
+ if (type_info)
+ return type_info;
+
+ SymbolContext sc;
+ target.GetImages().ResolveSymbolContextForAddress(vtable_addr, eSymbolContextSymbol, sc);
Symbol *symbol = sc.symbol;
if (symbol != NULL)
{
@@ -119,52 +82,56 @@ ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,
name);
// We are a C++ class, that's good. Get the class name and look it up:
const char *class_name = name + strlen(vtable_demangled_prefix);
- class_type_or_name.SetName (class_name);
+ type_info.SetName(class_name);
const bool exact_match = true;
TypeList class_types;
-
+
uint32_t num_matches = 0;
// First look in the module that the vtable symbol came from
// and look for a single exact match.
+ llvm::DenseSet<SymbolFile *> searched_symbol_files;
if (sc.module_sp)
{
num_matches = sc.module_sp->FindTypes (sc,
ConstString(class_name),
exact_match,
1,
+ searched_symbol_files,
class_types);
}
-
+
// If we didn't find a symbol, then move on to the entire
// module list in the target and get as many unique matches
// as possible
if (num_matches == 0)
{
- num_matches = target->GetImages().FindTypes (sc,
- ConstString(class_name),
- exact_match,
- UINT32_MAX,
- class_types);
+ num_matches = target.GetImages().FindTypes(sc, ConstString(class_name), exact_match,
+ UINT32_MAX, searched_symbol_files, class_types);
}
-
+
lldb::TypeSP type_sp;
if (num_matches == 0)
{
if (log)
log->Printf("0x%16.16" PRIx64 ": is not dynamic\n", original_ptr);
- return false;
+ return TypeAndOrName();
}
if (num_matches == 1)
{
type_sp = class_types.GetTypeAtIndex(0);
- if (log)
- log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 "}, type-name='%s'\n",
- original_ptr,
- in_value.GetTypeName().AsCString(),
- type_sp->GetID(),
- type_sp->GetName().GetCString());
-
- class_type_or_name.SetTypeSP(class_types.GetTypeAtIndex(0));
+ if (type_sp)
+ {
+ if (ClangASTContext::IsCXXClassType(type_sp->GetForwardCompilerType()))
+ {
+ if (log)
+ log->Printf("0x%16.16" PRIx64
+ ": static-type = '%s' has dynamic type: uid={0x%" PRIx64
+ "}, type-name='%s'\n",
+ original_ptr, in_value.GetTypeName().AsCString(), type_sp->GetID(),
+ type_sp->GetName().GetCString());
+ type_info.SetTypeSP(type_sp);
+ }
+ }
}
else if (num_matches > 1)
{
@@ -191,7 +158,7 @@ ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,
type_sp = class_types.GetTypeAtIndex(i);
if (type_sp)
{
- if (ClangASTContext::IsCXXClassType(type_sp->GetFullCompilerType ()))
+ if (ClangASTContext::IsCXXClassType(type_sp->GetForwardCompilerType()))
{
if (log)
log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, picking this one: uid={0x%" PRIx64 "}, type-name='%s'\n",
@@ -199,74 +166,112 @@ ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,
in_value.GetTypeName().AsCString(),
type_sp->GetID(),
type_sp->GetName().GetCString());
- class_type_or_name.SetTypeSP(type_sp);
- break;
+ type_info.SetTypeSP(type_sp);
}
}
}
-
- if (i == num_matches)
- {
- if (log)
- log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, didn't find a C++ match\n",
- original_ptr,
- in_value.GetTypeName().AsCString());
- return false;
- }
- }
-
- // There can only be one type with a given name,
- // so we've just found duplicate definitions, and this
- // one will do as well as any other.
- // We don't consider something to have a dynamic type if
- // it is the same as the static type. So compare against
- // the value we were handed.
- if (type_sp)
- {
- if (ClangASTContext::AreTypesSame (in_value.GetCompilerType(),
- type_sp->GetFullCompilerType ()))
- {
- // The dynamic type we found was the same type,
- // so we don't have a dynamic type here...
- return false;
- }
- // The offset_to_top is two pointers above the address.
- Address offset_to_top_address = address_point_address;
- int64_t slide = -2 * ((int64_t) target->GetArchitecture().GetAddressByteSize());
- offset_to_top_address.Slide (slide);
-
- Error error;
- lldb::addr_t offset_to_top_location = offset_to_top_address.GetLoadAddress(target);
-
- size_t bytes_read = process->ReadMemory (offset_to_top_location,
- memory_buffer,
- address_byte_size,
- error);
-
- if (!error.Success() || (bytes_read != address_byte_size))
- {
- return false;
- }
-
- offset = 0;
- int64_t offset_to_top = data.GetMaxS64(&offset, process->GetAddressByteSize());
-
- // So the dynamic type is a value that starts at offset_to_top
- // above the original address.
- lldb::addr_t dynamic_addr = original_ptr + offset_to_top;
- if (!target->GetSectionLoadList().ResolveLoadAddress (dynamic_addr, dynamic_address))
+ if (log && i == num_matches)
{
- dynamic_address.SetRawAddress(dynamic_addr);
+ log->Printf("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic "
+ "types, didn't find a C++ match\n",
+ original_ptr, in_value.GetTypeName().AsCString());
}
- return true;
}
+ if (type_info)
+ SetDynamicTypeInfo(vtable_addr, type_info);
+ return type_info;
}
}
}
}
}
-
+ return TypeAndOrName();
+}
+
+bool
+ItaniumABILanguageRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic,
+ TypeAndOrName &class_type_or_name, Address &dynamic_address,
+ Value::ValueType &value_type)
+{
+ // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0
+ // in the object. That will point to the "address point" within the vtable (not the beginning of the
+ // vtable.) We can then look up the symbol containing this "address point" and that symbol's name
+ // demangled will contain the full class name.
+ // The second pointer above the "address point" is the "offset_to_top". We'll use that to get the
+ // start of the value object which holds the dynamic type.
+ //
+
+ class_type_or_name.Clear();
+ value_type = Value::ValueType::eValueTypeScalar;
+
+ // Only a pointer or reference type can have a different dynamic and static type:
+ if (CouldHaveDynamicValue(in_value))
+ {
+ // First job, pull out the address at 0 offset from the object.
+ AddressType address_type;
+ lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type);
+ if (original_ptr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ ExecutionContext exe_ctx(in_value.GetExecutionContextRef());
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (process == nullptr)
+ return false;
+
+ Error error;
+ const lldb::addr_t vtable_address_point = process->ReadPointerFromMemory(original_ptr, error);
+
+ if (!error.Success() || vtable_address_point == LLDB_INVALID_ADDRESS)
+ {
+ return false;
+ }
+
+ class_type_or_name = GetTypeInfoFromVTableAddress(in_value, original_ptr, vtable_address_point);
+
+ if (class_type_or_name)
+ {
+ TypeSP type_sp = class_type_or_name.GetTypeSP();
+ // There can only be one type with a given name,
+ // so we've just found duplicate definitions, and this
+ // one will do as well as any other.
+ // We don't consider something to have a dynamic type if
+ // it is the same as the static type. So compare against
+ // the value we were handed.
+ if (type_sp)
+ {
+ if (ClangASTContext::AreTypesSame(in_value.GetCompilerType(), type_sp->GetForwardCompilerType()))
+ {
+ // The dynamic type we found was the same type,
+ // so we don't have a dynamic type here...
+ return false;
+ }
+
+ // The offset_to_top is two pointers above the vtable pointer.
+ const uint32_t addr_byte_size = process->GetAddressByteSize();
+ const lldb::addr_t offset_to_top_location = vtable_address_point - 2 * addr_byte_size;
+ // Watch for underflow, offset_to_top_location should be less than vtable_address_point
+ if (offset_to_top_location >= vtable_address_point)
+ return false;
+ const int64_t offset_to_top =
+ process->ReadSignedIntegerFromMemory(offset_to_top_location, addr_byte_size, INT64_MIN, error);
+
+ if (offset_to_top == INT64_MIN)
+ return false;
+ // So the dynamic type is a value that starts at offset_to_top
+ // above the original address.
+ lldb::addr_t dynamic_addr = original_ptr + offset_to_top;
+ if (!process->GetTarget().GetSectionLoadList().ResolveLoadAddress(dynamic_addr, dynamic_address))
+ {
+ dynamic_address.SetRawAddress(dynamic_addr);
+ }
+ return true;
+ }
+ }
+ }
+
return class_type_or_name.IsEmpty() == false;
}
@@ -336,12 +341,94 @@ ItaniumABILanguageRuntime::CreateInstance (Process *process, lldb::LanguageType
return NULL;
}
+class CommandObjectMultiwordItaniumABI_Demangle : public CommandObjectParsed
+{
+public:
+ CommandObjectMultiwordItaniumABI_Demangle (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "demangle",
+ "Demangle a C++ mangled name.",
+ "language cplusplus demangle")
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData index_arg;
+
+ // Define the first (and only) variant of this arg.
+ index_arg.arg_type = eArgTypeSymbol;
+ index_arg.arg_repetition = eArgRepeatPlus;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (index_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectMultiwordItaniumABI_Demangle() override = default;
+
+protected:
+ bool
+ DoExecute(Args& command, CommandReturnObject &result) override
+ {
+ bool demangled_any = false;
+ bool error_any = false;
+ for (size_t i = 0; i < command.GetArgumentCount(); i++)
+ {
+ auto arg = command.GetArgumentAtIndex(i);
+ if (arg && *arg)
+ {
+ ConstString mangled_cs(arg);
+
+ // the actual Mangled class should be strict about this, but on the command line
+ // if you're copying mangled names out of 'nm' on Darwin, they will come out with
+ // an extra underscore - be willing to strip this on behalf of the user
+ // This is the moral equivalent of the -_/-n options to c++filt
+ if (mangled_cs.GetStringRef().startswith("__Z"))
+ mangled_cs.SetCString(arg+1);
+
+ Mangled mangled(mangled_cs, true);
+ if (mangled.GuessLanguage() == lldb::eLanguageTypeC_plus_plus)
+ {
+ ConstString demangled(mangled.GetDisplayDemangledName(lldb::eLanguageTypeC_plus_plus));
+ demangled_any = true;
+ result.AppendMessageWithFormat("%s ---> %s\n", arg, demangled.GetCString());
+ }
+ else
+ {
+ error_any = true;
+ result.AppendErrorWithFormat("%s is not a valid C++ mangled name\n", arg);
+ }
+ }
+ }
+
+ result.SetStatus(error_any ? lldb::eReturnStatusFailed :
+ (demangled_any ? lldb::eReturnStatusSuccessFinishResult : lldb::eReturnStatusSuccessFinishNoResult));
+ return result.Succeeded();
+ }
+};
+
+class CommandObjectMultiwordItaniumABI : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordItaniumABI(CommandInterpreter &interpreter)
+ : CommandObjectMultiword(interpreter, "cplusplus", "Commands for operating on the C++ language runtime.",
+ "cplusplus <subcommand> [<subcommand-options>]")
+ {
+ LoadSubCommand ("demangle", CommandObjectSP (new CommandObjectMultiwordItaniumABI_Demangle (interpreter)));
+ }
+
+ ~CommandObjectMultiwordItaniumABI() override = default;
+};
+
void
ItaniumABILanguageRuntime::Initialize()
{
PluginManager::RegisterPlugin (GetPluginNameStatic(),
"Itanium ABI for the C++ language",
- CreateInstance);
+ CreateInstance,
+ [] (CommandInterpreter& interpreter) -> lldb::CommandObjectSP {
+ return CommandObjectSP(new CommandObjectMultiwordItaniumABI(interpreter));
+ });
}
void
@@ -408,6 +495,7 @@ ItaniumABILanguageRuntime::CreateExceptionResolver (Breakpoint *bkpt, bool catch
exception_names.size(),
eFunctionNameTypeBase,
eLanguageTypeUnknown,
+ 0,
eLazyBoolNo));
return resolver_sp;
@@ -510,3 +598,21 @@ ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP sto
m_cxx_exception_bp_sp->GetID());
}
+
+TypeAndOrName
+ItaniumABILanguageRuntime::GetDynamicTypeInfo(const lldb_private::Address &vtable_addr)
+{
+ std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex);
+ DynamicTypeCache::const_iterator pos = m_dynamic_type_map.find(vtable_addr);
+ if (pos == m_dynamic_type_map.end())
+ return TypeAndOrName();
+ else
+ return pos->second;
+}
+
+void
+ItaniumABILanguageRuntime::SetDynamicTypeInfo(const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info)
+{
+ std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex);
+ m_dynamic_type_map[vtable_addr] = type_info;
+}