Skip to content

Commit

Permalink
[lldb/Plugin] Add artificial stackframe loading in ScriptedThread
Browse files Browse the repository at this point in the history
This patch adds the ability for ScriptedThread to load artificial stack
frames. To do so, the interpreter instance can create a list that will
contain the frame index and its pc address.

Then, when the Scripted Process plugin stops, it will refresh its
Scripted Threads state by invalidating their register context and load
to list from the interpreter object and reconstruct each frame.

This patch also removes all of the default implementation for
`get_stackframes` from the derived ScriptedThread classes, and add the
interface code for the Scripted Thread Interface.

rdar://88721095

Differential Revision: https://reviews.llvm.org/D119388

Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
  • Loading branch information
medismailben committed Feb 16, 2022
1 parent c30742b commit 7066584
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 49 deletions.
4 changes: 2 additions & 2 deletions lldb/examples/python/scripted_process/scripted_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,9 @@ def __init__(idx, cfa, pc, symbol_ctx):
containing for each entry, the frame index, the canonical
frame address, the program counter value for that frame
and a symbol context.
None if the list is empty.
The list can be empty.
"""
return 0
return self.frames

def get_register_info(self):
if self.register_info is None:
Expand Down
3 changes: 3 additions & 0 deletions lldb/include/lldb/Target/StackFrameList.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

namespace lldb_private {

class ScriptedThread;

class StackFrameList {
public:
// Constructors and Destructors
Expand Down Expand Up @@ -86,6 +88,7 @@ class StackFrameList {

protected:
friend class Thread;
friend class ScriptedThread;

bool SetFrameAtIndex(uint32_t idx, lldb::StackFrameSP &frame_sp);

Expand Down
1 change: 1 addition & 0 deletions lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,
void ScriptedProcess::RefreshStateAfterStop() {
// Let all threads recover from stopping and do any clean up based on the
// previous thread state (if any).
m_thread_list.RefreshStateAfterStop();
}

bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) {
Expand Down
68 changes: 68 additions & 0 deletions lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,73 @@ ScriptedThread::CreateRegisterContextForFrame(StackFrame *frame) {
return m_reg_context_sp;
}

bool ScriptedThread::LoadArtificialStackFrames() {
StructuredData::ArraySP arr_sp = GetInterface()->GetStackFrames();

Status error;
if (!arr_sp)
return GetInterface()->ErrorWithMessage<bool>(
LLVM_PRETTY_FUNCTION, "Failed to get scripted thread stackframes.",
error, LLDBLog::Thread);

size_t arr_size = arr_sp->GetSize();
if (arr_size > std::numeric_limits<uint32_t>::max())
return GetInterface()->ErrorWithMessage<bool>(
LLVM_PRETTY_FUNCTION,
llvm::Twine(
"StackFrame array size (" + llvm::Twine(arr_size) +
llvm::Twine(
") is greater than maximum autorized for a StackFrameList."))
.str(),
error, LLDBLog::Thread);

StackFrameListSP frames = GetStackFrameList();

for (size_t idx = 0; idx < arr_size; idx++) {

StructuredData::Dictionary *dict;

if (!arr_sp->GetItemAtIndexAsDictionary(idx, dict) || !dict)
return GetInterface()->ErrorWithMessage<bool>(
LLVM_PRETTY_FUNCTION,
llvm::Twine(
"Couldn't get artificial stackframe dictionary at index (" +
llvm::Twine(idx) + llvm::Twine(") from stackframe array."))
.str(),
error, LLDBLog::Thread);

lldb::addr_t pc;
if (!dict->GetValueForKeyAsInteger("pc", pc))
return ScriptedInterface::ErrorWithMessage<bool>(
LLVM_PRETTY_FUNCTION,
"Couldn't find value for key 'pc' in stackframe dictionary.", error,
LLDBLog::Thread);

Address symbol_addr;
symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget());

lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
bool cfa_is_valid = false;
const bool behaves_like_zeroth_frame = false;
SymbolContext sc;
symbol_addr.CalculateSymbolContext(&sc);

StackFrameSP synth_frame_sp = std::make_shared<StackFrame>(
this->shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc);

if (!frames->SetFrameAtIndex(static_cast<uint32_t>(idx), synth_frame_sp))
return GetInterface()->ErrorWithMessage<bool>(
LLVM_PRETTY_FUNCTION,
llvm::Twine("Couldn't add frame (" + llvm::Twine(idx) +
llvm::Twine(") to ScriptedThread StackFrameList."))
.str(),
error, LLDBLog::Thread);
}

return true;
}

bool ScriptedThread::CalculateStopInfo() {
StructuredData::DictionarySP dict_sp = GetInterface()->GetStopReason();

Expand Down Expand Up @@ -216,6 +283,7 @@ bool ScriptedThread::CalculateStopInfo() {

void ScriptedThread::RefreshStateAfterStop() {
GetRegisterContext()->InvalidateIfNeeded(/*force=*/false);
LoadArtificialStackFrames();
}

lldb::ScriptedThreadInterfaceSP ScriptedThread::GetInterface() const {
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Plugins/Process/scripted/ScriptedThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class ScriptedThread : public lldb_private::Thread {
lldb::RegisterContextSP
CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;

bool LoadArtificialStackFrames();

bool CalculateStopInfo() override;

const char *GetInfo() override { return nullptr; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ ScriptedPythonInterface::GetStatusFromMethod(llvm::StringRef method_name) {
return error;
}

template <>
StructuredData::ArraySP
ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(
python::PythonObject &p, Status &error) {
python::PythonList result_list(python::PyRefType::Borrowed, p.get());
return result_list.CreateStructuredArray();
}

template <>
StructuredData::DictionarySP
ScriptedPythonInterface::ExtractValueFromPythonObject<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
ScriptInterpreterPythonImpl &m_interpreter;
};

template <>
StructuredData::ArraySP
ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(
python::PythonObject &p, Status &error);

template <>
StructuredData::DictionarySP
ScriptedPythonInterface::ExtractValueFromPythonObject<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,14 @@ StructuredData::DictionarySP ScriptedThreadPythonInterface::GetStopReason() {
}

StructuredData::ArraySP ScriptedThreadPythonInterface::GetStackFrames() {
return nullptr;
Status error;
StructuredData::ArraySP arr =
Dispatch<StructuredData::ArraySP>("get_stackframes", error);

if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, arr, error))
return {};

return arr;
}

StructuredData::DictionarySP ScriptedThreadPythonInterface::GetRegisterInfo() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,6 @@ def cleanup():
break
self.assertEqual(idx, int(reg.value, 16))

self.assertTrue(frame.IsArtificial(), "Frame is not artificial")
pc = frame.GetPCAddress().GetLoadAddress(target)
self.assertEqual(pc, 0x0100001b00)
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def get_scripted_thread_plugin(self):
class DummyScriptedThread(ScriptedThread):
def __init__(self, process, args):
super().__init__(process, args)
self.frames.append({"pc": 0x0100001b00 })

def get_thread_id(self) -> int:
return 0x19
Expand All @@ -61,21 +62,6 @@ def get_stop_reason(self) -> Dict[str, Any]:
"signal": signal.SIGINT
} }

def get_stackframes(self):
class ScriptedStackFrame:
def __init__(idx, cfa, pc, symbol_ctx):
self.idx = idx
self.cfa = cfa
self.pc = pc
self.symbol_ctx = symbol_ctx


symbol_ctx = lldb.SBSymbolContext()
frame_zero = ScriptedStackFrame(0, 0x42424242, 0x5000000, symbol_ctx)
self.frames.append(frame_zero)

return self.frame_zero[0:0]

def get_register_context(self) -> str:
return struct.pack(
'21Q', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
Expand All @@ -88,4 +74,4 @@ def __lldb_init_module(debugger, dict):
DummyScriptedProcess.__name__))
else:
print("Name of the class that will manage the scripted process: '%s.%s'"
% (__name__, DummyScriptedProcess.__name__))
% (__name__, DummyScriptedProcess.__name__))
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,6 @@ def get_stop_reason(self) -> Dict[str, Any]:
"signal": signal.SIGTRAP
} }

def get_stackframes(self):
class ScriptedStackFrame:
def __init__(idx, cfa, pc, symbol_ctx):
self.idx = idx
self.cfa = cfa
self.pc = pc
self.symbol_ctx = symbol_ctx


symbol_ctx = lldb.SBSymbolContext()
frame_zero = ScriptedStackFrame(0, 0x42424242, 0x5000000, symbol_ctx)
self.frames.append(frame_zero)

return self.frame_zero[0:0]

def get_register_context(self) -> str:
return None

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,21 +139,6 @@ def get_stop_reason(self) -> Dict[str, Any]:

return stop_reason

def get_stackframes(self):
class ScriptedStackFrame:
def __init__(idx, cfa, pc, symbol_ctx):
self.idx = idx
self.cfa = cfa
self.pc = pc
self.symbol_ctx = symbol_ctx


symbol_ctx = lldb.SBSymbolContext()
frame_zero = ScriptedStackFrame(0, 0x42424242, 0x5000000, symbol_ctx)
self.frames.append(frame_zero)

return self.frame_zero[0:0]

def get_register_context(self) -> str:
if not self.corefile_thread or self.corefile_thread.GetNumFrames() == 0:
return None
Expand Down

0 comments on commit 7066584

Please sign in to comment.