mirror of
https://github.com/intel/llvm.git
synced 2026-01-12 10:17:28 +08:00
This patch re-lands #161870 with fixes to the previous test failures. rdar://161834688 Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
222 lines
8.1 KiB
C++
222 lines
8.1 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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 "ScriptedFrameProvider.h"
|
|
#include "Plugins/Process/scripted/ScriptedFrame.h"
|
|
#include "lldb/Core/Debugger.h"
|
|
#include "lldb/Core/PluginManager.h"
|
|
#include "lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h"
|
|
#include "lldb/Interpreter/ScriptInterpreter.h"
|
|
#include "lldb/Target/BorrowedStackFrame.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Target/StackFrame.h"
|
|
#include "lldb/Target/Thread.h"
|
|
#include "lldb/Utility/ScriptedMetadata.h"
|
|
#include "lldb/Utility/Status.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include <cstdint>
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
void ScriptedFrameProvider::Initialize() {
|
|
PluginManager::RegisterPlugin(GetPluginNameStatic(),
|
|
"Provides synthetic frames via scripting",
|
|
nullptr, ScriptedFrameProvider::CreateInstance);
|
|
}
|
|
|
|
void ScriptedFrameProvider::Terminate() {
|
|
PluginManager::UnregisterPlugin(ScriptedFrameProvider::CreateInstance);
|
|
}
|
|
|
|
llvm::Expected<lldb::SyntheticFrameProviderSP>
|
|
ScriptedFrameProvider::CreateInstance(
|
|
lldb::StackFrameListSP input_frames,
|
|
const ScriptedFrameProviderDescriptor &descriptor) {
|
|
if (!input_frames)
|
|
return llvm::createStringError(
|
|
"failed to create scripted frame provider: invalid input frames");
|
|
|
|
Thread &thread = input_frames->GetThread();
|
|
ProcessSP process_sp = thread.GetProcess();
|
|
if (!process_sp)
|
|
return nullptr;
|
|
|
|
if (!descriptor.IsValid())
|
|
return llvm::createStringError(
|
|
"failed to create scripted frame provider: invalid scripted metadata");
|
|
|
|
if (!descriptor.AppliesToThread(thread))
|
|
return nullptr;
|
|
|
|
ScriptInterpreter *script_interp =
|
|
process_sp->GetTarget().GetDebugger().GetScriptInterpreter();
|
|
if (!script_interp)
|
|
return llvm::createStringError("cannot create scripted frame provider: No "
|
|
"script interpreter installed");
|
|
|
|
ScriptedFrameProviderInterfaceSP interface_sp =
|
|
script_interp->CreateScriptedFrameProviderInterface();
|
|
if (!interface_sp)
|
|
return llvm::createStringError(
|
|
"cannot create scripted frame provider: script interpreter couldn't "
|
|
"create Scripted Frame Provider Interface");
|
|
|
|
const ScriptedMetadataSP scripted_metadata = descriptor.scripted_metadata_sp;
|
|
|
|
// If we shouldn't attach a frame provider to this thread, just exit early.
|
|
if (!interface_sp->AppliesToThread(scripted_metadata->GetClassName(),
|
|
thread.shared_from_this()))
|
|
return nullptr;
|
|
|
|
auto obj_or_err = interface_sp->CreatePluginObject(
|
|
scripted_metadata->GetClassName(), input_frames,
|
|
scripted_metadata->GetArgsSP());
|
|
if (!obj_or_err)
|
|
return obj_or_err.takeError();
|
|
|
|
StructuredData::ObjectSP object_sp = *obj_or_err;
|
|
if (!object_sp || !object_sp->IsValid())
|
|
return llvm::createStringError(
|
|
"cannot create scripted frame provider: failed to create valid scripted"
|
|
"frame provider object");
|
|
|
|
return std::make_shared<ScriptedFrameProvider>(input_frames, interface_sp,
|
|
descriptor);
|
|
}
|
|
|
|
ScriptedFrameProvider::ScriptedFrameProvider(
|
|
StackFrameListSP input_frames,
|
|
lldb::ScriptedFrameProviderInterfaceSP interface_sp,
|
|
const ScriptedFrameProviderDescriptor &descriptor)
|
|
: SyntheticFrameProvider(input_frames), m_interface_sp(interface_sp),
|
|
m_descriptor(descriptor) {}
|
|
|
|
ScriptedFrameProvider::~ScriptedFrameProvider() = default;
|
|
|
|
std::string ScriptedFrameProvider::GetDescription() const {
|
|
if (!m_interface_sp)
|
|
return {};
|
|
|
|
return m_interface_sp->GetDescription(m_descriptor.GetName());
|
|
}
|
|
|
|
llvm::Expected<StackFrameSP>
|
|
ScriptedFrameProvider::GetFrameAtIndex(uint32_t idx) {
|
|
if (!m_interface_sp)
|
|
return llvm::createStringError(
|
|
"cannot get stack frame: scripted frame provider not initialized");
|
|
|
|
auto create_frame_from_dict =
|
|
[this](StructuredData::Dictionary *dict,
|
|
uint32_t index) -> llvm::Expected<StackFrameSP> {
|
|
lldb::addr_t pc;
|
|
if (!dict->GetValueForKeyAsInteger("pc", pc))
|
|
return llvm::createStringError(
|
|
"missing 'pc' key from scripted frame dictionary");
|
|
|
|
Address symbol_addr;
|
|
symbol_addr.SetLoadAddress(pc, &GetThread().GetProcess()->GetTarget());
|
|
|
|
const lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
|
|
const bool cfa_is_valid = false;
|
|
const bool artificial = false;
|
|
const bool behaves_like_zeroth_frame = false;
|
|
SymbolContext sc;
|
|
symbol_addr.CalculateSymbolContext(&sc);
|
|
|
|
ThreadSP thread_sp = GetThread().shared_from_this();
|
|
return std::make_shared<StackFrame>(thread_sp, index, index, cfa,
|
|
cfa_is_valid, pc,
|
|
StackFrame::Kind::Synthetic, artificial,
|
|
behaves_like_zeroth_frame, &sc);
|
|
};
|
|
|
|
auto create_frame_from_script_object =
|
|
[this](
|
|
StructuredData::ObjectSP object_sp) -> llvm::Expected<StackFrameSP> {
|
|
Status error;
|
|
if (!object_sp || !object_sp->GetAsGeneric())
|
|
return llvm::createStringError("invalid script object");
|
|
|
|
ThreadSP thread_sp = GetThread().shared_from_this();
|
|
auto frame_or_error = ScriptedFrame::Create(thread_sp, nullptr, nullptr,
|
|
object_sp->GetAsGeneric());
|
|
|
|
if (!frame_or_error) {
|
|
ScriptedInterface::ErrorWithMessage<bool>(
|
|
LLVM_PRETTY_FUNCTION, toString(frame_or_error.takeError()), error);
|
|
return error.ToError();
|
|
}
|
|
|
|
return *frame_or_error;
|
|
};
|
|
|
|
StructuredData::ObjectSP obj_sp = m_interface_sp->GetFrameAtIndex(idx);
|
|
|
|
// None/null means no more frames or error.
|
|
if (!obj_sp || !obj_sp->IsValid())
|
|
return llvm::createStringError("invalid script object returned for frame " +
|
|
llvm::Twine(idx));
|
|
|
|
StackFrameSP synth_frame_sp = nullptr;
|
|
if (StructuredData::UnsignedInteger *int_obj =
|
|
obj_sp->GetAsUnsignedInteger()) {
|
|
uint32_t real_frame_index = int_obj->GetValue();
|
|
if (real_frame_index < m_input_frames->GetNumFrames()) {
|
|
StackFrameSP real_frame_sp =
|
|
m_input_frames->GetFrameAtIndex(real_frame_index);
|
|
synth_frame_sp =
|
|
(real_frame_index == idx)
|
|
? real_frame_sp
|
|
: std::make_shared<BorrowedStackFrame>(real_frame_sp, idx);
|
|
}
|
|
} else if (StructuredData::Dictionary *dict = obj_sp->GetAsDictionary()) {
|
|
// Check if it's a dictionary describing a frame.
|
|
auto frame_from_dict_or_err = create_frame_from_dict(dict, idx);
|
|
if (!frame_from_dict_or_err) {
|
|
return llvm::createStringError(llvm::Twine(
|
|
"couldn't create frame from dictionary at index " + llvm::Twine(idx) +
|
|
": " + toString(frame_from_dict_or_err.takeError())));
|
|
}
|
|
synth_frame_sp = *frame_from_dict_or_err;
|
|
} else if (obj_sp->GetAsGeneric()) {
|
|
// It's a ScriptedFrame object.
|
|
auto frame_from_script_obj_or_err = create_frame_from_script_object(obj_sp);
|
|
if (!frame_from_script_obj_or_err) {
|
|
return llvm::createStringError(
|
|
llvm::Twine("couldn't create frame from script object at index " +
|
|
llvm::Twine(idx) + ": " +
|
|
toString(frame_from_script_obj_or_err.takeError())));
|
|
}
|
|
synth_frame_sp = *frame_from_script_obj_or_err;
|
|
} else {
|
|
return llvm::createStringError(
|
|
llvm::Twine("invalid return type from get_frame_at_index at index " +
|
|
llvm::Twine(idx)));
|
|
}
|
|
|
|
if (!synth_frame_sp)
|
|
return llvm::createStringError(
|
|
llvm::Twine("failed to create frame at index " + llvm::Twine(idx)));
|
|
|
|
synth_frame_sp->SetFrameIndex(idx);
|
|
|
|
return synth_frame_sp;
|
|
}
|
|
|
|
namespace lldb_private {
|
|
void lldb_initialize_ScriptedFrameProvider() {
|
|
ScriptedFrameProvider::Initialize();
|
|
}
|
|
|
|
void lldb_terminate_ScriptedFrameProvider() {
|
|
ScriptedFrameProvider::Terminate();
|
|
}
|
|
} // namespace lldb_private
|