Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
add_lldb_library(lldbPluginCPPRuntime
add_lldb_library(lldbPluginCPPRuntime PLUGIN
CommandObjectCPlusPlus.cpp
CPPLanguageRuntime.cpp
ItaniumABIRuntime.cpp
VerboseTrapFrameRecognizer.cpp

LINK_LIBS
lldbBreakpoint
lldbCore
lldbInterpreter
lldbPluginTypeSystemClang
lldbSymbol
lldbTarget
lldbValueObject
CLANG_LIBS
clangCodeGen
)

add_subdirectory(ItaniumABI)
#add_subdirectory(MicrosoftABI)
185 changes: 185 additions & 0 deletions lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <memory>

#include "CPPLanguageRuntime.h"
#include "CommandObjectCPlusPlus.h"
#include "VerboseTrapFrameRecognizer.h"

#include "llvm/ADT/StringRef.h"
Expand All @@ -36,6 +37,8 @@
using namespace lldb;
using namespace lldb_private;

LLDB_PLUGIN_DEFINE_ADV(CPPLanguageRuntime, CPPRuntime)

static ConstString g_this = ConstString("this");
// Artificial coroutine-related variables emitted by clang.
static ConstString g_promise = ConstString("__promise");
Expand Down Expand Up @@ -491,3 +494,185 @@ bool CPPLanguageRuntime::IsSymbolARuntimeThunk(const Symbol &symbol) {
return mangled_name.starts_with("_ZTh") || mangled_name.starts_with("_ZTv") ||
mangled_name.starts_with("_ZTc");
}

bool CPPLanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
const bool check_cxx = true;
const bool check_objc = false;
return in_value.GetCompilerType().IsPossibleDynamicType(nullptr, check_cxx,
check_objc);
}

bool CPPLanguageRuntime::GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &dynamic_address,
Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) {
class_type_or_name.Clear();
value_type = Value::ValueType::Scalar;

if (!CouldHaveDynamicValue(in_value))
return false;

return m_itanium_runtime.GetDynamicTypeAndAddress(
in_value, use_dynamic, class_type_or_name, dynamic_address, value_type,
*m_process);
}

TypeAndOrName
CPPLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) {
CompilerType static_type(static_value.GetCompilerType());
Flags static_type_flags(static_type.GetTypeInfo());

TypeAndOrName ret(type_and_or_name);
if (type_and_or_name.HasType()) {
// The type will always be the type of the dynamic object. If our parent's
// type was a pointer, then our type should be a pointer to the type of the
// dynamic object. If a reference, then the original type should be
// okay...
CompilerType orig_type = type_and_or_name.GetCompilerType();
CompilerType corrected_type = orig_type;
if (static_type_flags.AllSet(eTypeIsPointer))
corrected_type = orig_type.GetPointerType();
else if (static_type_flags.AllSet(eTypeIsReference))
corrected_type = orig_type.GetLValueReferenceType();
ret.SetCompilerType(corrected_type);
} else {
// If we are here we need to adjust our dynamic type name to include the
// correct & or * symbol
std::string corrected_name(type_and_or_name.GetName().GetCString());
if (static_type_flags.AllSet(eTypeIsPointer))
corrected_name.append(" *");
else if (static_type_flags.AllSet(eTypeIsReference))
corrected_name.append(" &");
// the parent type should be a correctly pointer'ed or referenc'ed type
ret.SetCompilerType(static_type);
ret.SetName(corrected_name.c_str());
}
return ret;
}

LanguageRuntime *
CPPLanguageRuntime::CreateInstance(Process *process,
lldb::LanguageType language) {
if (language == eLanguageTypeC_plus_plus ||
language == eLanguageTypeC_plus_plus_03 ||
language == eLanguageTypeC_plus_plus_11 ||
language == eLanguageTypeC_plus_plus_14)
return new CPPLanguageRuntime(process);
else
return nullptr;
}

void CPPLanguageRuntime::Initialize() {
PluginManager::RegisterPlugin(
GetPluginNameStatic(), "C++ language runtime", CreateInstance,
[](CommandInterpreter &interpreter) -> lldb::CommandObjectSP {
return CommandObjectSP(new CommandObjectCPlusPlus(interpreter));
});
}

void CPPLanguageRuntime::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}

llvm::Expected<LanguageRuntime::VTableInfo>
CPPLanguageRuntime::GetVTableInfo(ValueObject &in_value, bool check_type) {
return m_itanium_runtime.GetVTableInfo(in_value, check_type);
}

BreakpointResolverSP
CPPLanguageRuntime::CreateExceptionResolver(const BreakpointSP &bkpt,
bool catch_bp, bool throw_bp) {
return CreateExceptionResolver(bkpt, catch_bp, throw_bp, false);
}

BreakpointResolverSP
CPPLanguageRuntime::CreateExceptionResolver(const BreakpointSP &bkpt,
bool catch_bp, bool throw_bp,
bool for_expressions) {
std::vector<const char *> exception_names;
m_itanium_runtime.AppendExceptionBreakpointFunctions(
exception_names, catch_bp, throw_bp, for_expressions);

BreakpointResolverSP resolver_sp(new BreakpointResolverName(
bkpt, exception_names.data(), exception_names.size(),
eFunctionNameTypeBase, eLanguageTypeUnknown, 0, eLazyBoolNo));

return resolver_sp;
}

lldb::SearchFilterSP CPPLanguageRuntime::CreateExceptionSearchFilter() {
Target &target = m_process->GetTarget();

FileSpecList filter_modules;
m_itanium_runtime.AppendExceptionBreakpointFilterModules(filter_modules,
target);
return target.GetSearchFilterForModuleList(&filter_modules);
}

lldb::BreakpointSP CPPLanguageRuntime::CreateExceptionBreakpoint(
bool catch_bp, bool throw_bp, bool for_expressions, bool is_internal) {
Target &target = m_process->GetTarget();
FileSpecList filter_modules;
BreakpointResolverSP exception_resolver_sp =
CreateExceptionResolver(nullptr, catch_bp, throw_bp, for_expressions);
SearchFilterSP filter_sp(CreateExceptionSearchFilter());
const bool hardware = false;
const bool resolve_indirect_functions = false;
return target.CreateBreakpoint(filter_sp, exception_resolver_sp, is_internal,
hardware, resolve_indirect_functions);
}

void CPPLanguageRuntime::SetExceptionBreakpoints() {
if (!m_process)
return;

const bool catch_bp = false;
const bool throw_bp = true;
const bool is_internal = true;
const bool for_expressions = true;

// For the exception breakpoints set by the Expression parser, we'll be a
// little more aggressive and stop at exception allocation as well.

if (m_cxx_exception_bp_sp) {
m_cxx_exception_bp_sp->SetEnabled(true);
} else {
m_cxx_exception_bp_sp = CreateExceptionBreakpoint(
catch_bp, throw_bp, for_expressions, is_internal);
if (m_cxx_exception_bp_sp)
m_cxx_exception_bp_sp->SetBreakpointKind("c++ exception");
}
}

void CPPLanguageRuntime::ClearExceptionBreakpoints() {
if (!m_process)
return;

if (m_cxx_exception_bp_sp) {
m_cxx_exception_bp_sp->SetEnabled(false);
}
}

bool CPPLanguageRuntime::ExceptionBreakpointsAreSet() {
return m_cxx_exception_bp_sp && m_cxx_exception_bp_sp->IsEnabled();
}

bool CPPLanguageRuntime::ExceptionBreakpointsExplainStop(
lldb::StopInfoSP stop_reason) {
if (!m_process)
return false;

if (!stop_reason || stop_reason->GetStopReason() != eStopReasonBreakpoint)
return false;

uint64_t break_site_id = stop_reason->GetValue();
return m_process->GetBreakpointSiteList().StopPointSiteContainsBreakpoint(
break_site_id, m_cxx_exception_bp_sp->GetID());
}

lldb::ValueObjectSP
CPPLanguageRuntime::GetExceptionObjectForThread(lldb::ThreadSP thread_sp) {
return m_itanium_runtime.GetExceptionObjectForThread(std::move(thread_sp),
*m_process);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "llvm/ADT/StringMap.h"

#include "ItaniumABIRuntime.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/lldb-private.h"
Expand Down Expand Up @@ -42,6 +43,19 @@ class CPPLanguageRuntime : public LanguageRuntime {

static char ID;

static void Initialize();

static void Terminate();

static lldb_private::LanguageRuntime *
CreateInstance(Process *process, lldb::LanguageType language);

static llvm::StringRef GetPluginNameStatic() {
return "cpp-language-runtime";
}

llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }

bool isA(const void *ClassID) const override {
return ClassID == &ID || LanguageRuntime::isA(ClassID);
}
Expand Down Expand Up @@ -81,15 +95,55 @@ class CPPLanguageRuntime : public LanguageRuntime {

bool IsSymbolARuntimeThunk(const Symbol &symbol) override;

protected:
// Classes that inherit from CPPLanguageRuntime can see and modify these
CPPLanguageRuntime(Process *process);
llvm::Expected<LanguageRuntime::VTableInfo>
GetVTableInfo(ValueObject &in_value, bool check_type) override;

bool GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address, Value::ValueType &value_type,
llvm::ArrayRef<uint8_t> &local_buffer) override;

TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) override;

bool CouldHaveDynamicValue(ValueObject &in_value) override;

void SetExceptionBreakpoints() override;

void ClearExceptionBreakpoints() override;

bool ExceptionBreakpointsAreSet() override;

bool ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) override;

lldb::BreakpointResolverSP
CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp,
bool throw_bp) override;

lldb::SearchFilterSP CreateExceptionSearchFilter() override;

lldb::ValueObjectSP
GetExceptionObjectForThread(lldb::ThreadSP thread_sp) override;

private:
CPPLanguageRuntime(Process *process);

lldb::BreakpointResolverSP
CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp,
bool throw_bp, bool for_expressions);

lldb::BreakpointSP CreateExceptionBreakpoint(bool catch_bp, bool throw_bp,
bool for_expressions,
bool is_internal);

using OperatorStringToCallableInfoMap =
llvm::StringMap<CPPLanguageRuntime::LibCppStdFunctionCallableInfo>;

OperatorStringToCallableInfoMap CallableLookupCache;

lldb::BreakpointSP m_cxx_exception_bp_sp;
ItaniumABIRuntime m_itanium_runtime;
};

} // namespace lldb_private
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//===----------------------------------------------------------------------===//
//
// 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 "CommandObjectCPlusPlus.h"

#include "lldb/Core/Mangled.h"
#include "lldb/Interpreter/CommandReturnObject.h"

using namespace lldb;
using namespace lldb_private;

CommandObjectCPlusPlusDemangle::CommandObjectCPlusPlusDemangle(
CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "demangle",
"Demangle a C++ mangled name.",
"language cplusplus demangle [<mangled-name> ...]") {
AddSimpleArgumentList(eArgTypeSymbol, eArgRepeatPlus);
}

void CommandObjectCPlusPlusDemangle::DoExecute(Args &command,
CommandReturnObject &result) {
bool demangled_any = false;
bool error_any = false;
for (auto &entry : command.entries()) {
if (entry.ref().empty())
continue;

// 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
auto name = entry.ref();
if (name.starts_with("__Z"))
name = name.drop_front();

Mangled mangled(name);
if (mangled.GuessLanguage() == lldb::eLanguageTypeC_plus_plus) {
ConstString demangled(mangled.GetDisplayDemangledName());
demangled_any = true;
result.AppendMessageWithFormat("%s ---> %s\n", entry.c_str(),
demangled.GetCString());
} else {
error_any = true;
result.AppendErrorWithFormat("%s is not a valid C++ mangled name\n",
entry.ref().str().c_str());
}
}

result.SetStatus(
error_any ? lldb::eReturnStatusFailed
: (demangled_any ? lldb::eReturnStatusSuccessFinishResult
: lldb::eReturnStatusSuccessFinishNoResult));
}

CommandObjectCPlusPlus::CommandObjectCPlusPlus(CommandInterpreter &interpreter)
: CommandObjectMultiword(
interpreter, "cplusplus",
"Commands for operating on the C++ language runtime.",
"cplusplus <subcommand> [<subcommand-options>]") {
LoadSubCommand("demangle", CommandObjectSP(new CommandObjectCPlusPlusDemangle(
interpreter)));
}
Loading
Loading