Skip to content

Commit

Permalink
thread suspend /resume support
Browse files Browse the repository at this point in the history
active thread indicator

remove log messages for thread suspend /resume

always expand current thread
  • Loading branch information
op2786 authored and xusheng6 committed Dec 13, 2022
1 parent 73b2b5e commit 5372a0f
Show file tree
Hide file tree
Showing 16 changed files with 783 additions and 195 deletions.
3 changes: 3 additions & 0 deletions api/debuggerapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ namespace BinaryNinjaDebuggerAPI {
{
std::uint32_t m_tid {};
std::uintptr_t m_rip {};
bool m_isFrozen {};

DebugThread() {}
DebugThread(std::uint32_t tid) : m_tid(tid) {}
Expand Down Expand Up @@ -452,6 +453,8 @@ namespace BinaryNinjaDebuggerAPI {
DebugThread GetActiveThread();
void SetActiveThread(const DebugThread& thread);
std::vector<DebugFrame> GetFramesOfThread(uint32_t tid);
bool SuspendThread(std::uint32_t tid);
bool ResumeThread(std::uint32_t tid);

std::vector<DebugModule> GetModules();
std::vector<DebugRegister> GetRegisters();
Expand Down
13 changes: 13 additions & 0 deletions api/debuggercontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ std::vector<DebugThread> DebuggerController::GetThreads()
DebugThread thread;
thread.m_rip = threads[i].m_rip;
thread.m_tid = threads[i].m_tid;
thread.m_isFrozen = threads[i].m_isFrozen;
result.push_back(thread);
}
BNDebuggerFreeThreads(threads, count);
Expand Down Expand Up @@ -150,6 +151,18 @@ void DebuggerController::SetActiveThread(const DebugThread& thread)
}


bool DebuggerController::SuspendThread(std::uint32_t tid)
{
return BNDebuggerSuspendThread(m_object, tid);
}


bool DebuggerController::ResumeThread(std::uint32_t tid)
{
return BNDebuggerResumeThread(m_object, tid);
}


std::vector<DebugFrame> DebuggerController::GetFramesOfThread(uint32_t tid)
{
size_t count;
Expand Down
4 changes: 4 additions & 0 deletions api/ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ extern "C"
{
uint32_t m_tid;
uint64_t m_rip;
bool m_isFrozen;
};

struct BNDebugFrame
Expand Down Expand Up @@ -227,6 +228,7 @@ extern "C"
// This event is only emitted when the value of a register is modified explicitly (e.g., using Python API,
// in the register widget, etc.). It is not emitted when the target executes and then stops.
RegisterChangedEvent,
ThreadStateChangedEvent,
};


Expand Down Expand Up @@ -319,6 +321,8 @@ extern "C"

DEBUGGER_FFI_API BNDebugThread BNDebuggerGetActiveThread(BNDebuggerController* controller);
DEBUGGER_FFI_API void BNDebuggerSetActiveThread(BNDebuggerController* controller, BNDebugThread thread);
DEBUGGER_FFI_API bool BNDebuggerSuspendThread(BNDebuggerController* controller, uint32_t tid);
DEBUGGER_FFI_API bool BNDebuggerResumeThread(BNDebuggerController* controller, uint32_t tid);

DEBUGGER_FFI_API BNDebugFrame* BNDebuggerGetFramesOfThread(
BNDebuggerController* controller, uint32_t tid, size_t* count);
Expand Down
18 changes: 18 additions & 0 deletions api/python/debuggercontroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,24 @@ def active_thread(self) -> DebugThread:
def active_thread(self, thread: DebugThread) -> None:
dbgcore.BNDebuggerSetActiveThread(self.handle, dbgcore.BNDebugThread(thread.tid, thread.rip))

def suspend_thread(self, tid: int) -> bool:
"""
Suspends a thread by thread id.
:param tid: thread id
:return:
"""
return dbgcore.BNDebuggerSuspendThread(self.handle, tid)

def resume_thread(self, tid: int) -> bool:
"""
Resumes a thread by thread id.
:param tid: thread id
:return:
"""
return dbgcore.BNDebuggerResumeThread(self.handle, tid)

@property
def modules(self) -> List[DebugModule]:
"""
Expand Down
16 changes: 16 additions & 0 deletions core/adapters/dbgengadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,22 @@ bool DbgEngAdapter::SetActiveThreadId(std::uint32_t tid)
return true;
}


bool DbgEngAdapter::SuspendThread(std::uint32_t tid)
{
std::string suspendCmd = fmt::format("~{}f", tid);
InvokeBackendCommand(suspendCmd);
return true;
}

bool DbgEngAdapter::ResumeThread(std::uint32_t tid)
{
std::string resumeCmd = fmt::format("~{}u", tid);
InvokeBackendCommand(resumeCmd);
return true;
}


DebugBreakpoint DbgEngAdapter::AddBreakpoint(const std::uintptr_t address, unsigned long breakpoint_flags)
{
IDebugBreakpoint2* debug_breakpoint {};
Expand Down
3 changes: 3 additions & 0 deletions core/adapters/dbgengadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ namespace BinaryNinjaDebugger {

std::vector<DebugFrame> GetFramesOfThread(uint32_t tid) override;

bool SuspendThread(std::uint32_t tid) override;
bool ResumeThread(std::uint32_t tid) override;

void ApplyBreakpoints();

std::string GetDbgEngPath(const std::string& arch = "x64");
Expand Down
35 changes: 34 additions & 1 deletion core/adapters/lldbadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,39 @@ bool LldbAdapter::SetActiveThreadId(std::uint32_t tid)
}


bool LldbAdapter::SuspendThread(std::uint32_t tid)
{
SBError error;
SBThread thread = m_process.GetThreadByID(tid);
if (!thread.IsValid())
return false;

if (!thread.Suspend(error))
return false;

if (!error.Success())
return false;

return true;
}

bool LldbAdapter::ResumeThread(std::uint32_t tid)
{
SBError error;
SBThread thread = m_process.GetThreadByID(tid);
if (!thread.IsValid())
return false;

if (!thread.Resume(error))
return false;

if (!error.Success())
return false;

return true;
}


std::vector<DebugFrame> LldbAdapter::GetFramesOfThread(uint32_t tid)
{
size_t threadCount = m_process.GetNumThreads();
Expand Down Expand Up @@ -1509,4 +1542,4 @@ bool LldbAdapter::DisconnectDebugServer()
// Otherwise, launching the target (on the host) would not work after disconnecting from a debug server.
[[maybe_unused]] auto error = m_debugger.SetCurrentPlatform("host");
return true;
}
}
3 changes: 3 additions & 0 deletions core/adapters/lldbadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ namespace BinaryNinjaDebugger {

bool SetActiveThreadId(std::uint32_t tid) override;

bool SuspendThread(std::uint32_t tid) override;
bool ResumeThread(std::uint32_t tid) override;

std::vector<DebugFrame> GetFramesOfThread(uint32_t tid) override;

DebugBreakpoint AddBreakpoint(const std::uintptr_t address, unsigned long breakpoint_type) override;
Expand Down
5 changes: 5 additions & 0 deletions core/debugadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ namespace BinaryNinjaDebugger {
{
std::uint32_t m_tid {};
std::uintptr_t m_rip {};
bool m_isFrozen {};

DebugThread() {}

Expand Down Expand Up @@ -211,6 +212,10 @@ namespace BinaryNinjaDebugger {

virtual bool SetActiveThreadId(std::uint32_t tid) = 0;

virtual bool SuspendThread(std::uint32_t tid) = 0;

virtual bool ResumeThread(std::uint32_t tid) = 0;

virtual std::vector<DebugFrame> GetFramesOfThread(std::uint32_t tid);

virtual DebugBreakpoint AddBreakpoint(const std::uintptr_t address, unsigned long breakpoint_type = 0) = 0;
Expand Down
27 changes: 27 additions & 0 deletions core/debuggercontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,33 @@ void DebuggerController::SetActiveThread(const DebugThread& thread)
}


bool DebuggerController::SuspendThread(std::uint32_t tid)
{
auto result = m_state->GetThreads()->SuspendThread(tid);
if (!result)
return false;

DebuggerEvent event;
event.type = ThreadStateChangedEvent;
PostDebuggerEvent(event);

return result;
}

bool DebuggerController::ResumeThread(std::uint32_t tid)
{
auto result = m_state->GetThreads()->ResumeThread(tid);
if (!result)
return false;

DebuggerEvent event;
event.type = ThreadStateChangedEvent;
PostDebuggerEvent(event);

return result;
}


std::vector<DebugFrame> DebuggerController::GetFramesOfThread(uint64_t tid)
{
return m_state->GetThreads()->GetFramesOfThread(tid);
Expand Down
2 changes: 2 additions & 0 deletions core/debuggercontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ namespace BinaryNinjaDebugger {
void SetActiveThread(const DebugThread& thread);
std::vector<DebugThread> GetAllThreads();
std::vector<DebugFrame> GetFramesOfThread(uint64_t tid);
bool SuspendThread(std::uint32_t tid);
bool ResumeThread(std::uint32_t tid);

// modules
std::vector<DebugModule> GetAllModules();
Expand Down
85 changes: 78 additions & 7 deletions core/debuggerstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,9 @@ DebuggerThreads::DebuggerThreads(DebuggerState* state) : m_state(state)
void DebuggerThreads::MarkDirty()
{
m_dirty = true;
m_threads.clear();
m_frames.clear();
// clearing these here corrupts thread state updating in ::Update() below
// m_threads.clear();
// m_frames.clear();
// TODO: consider also caching the last active thread
}

Expand All @@ -196,11 +197,24 @@ void DebuggerThreads::Update()
if (!adapter)
return;

m_threads.clear();
m_frames.clear();

m_threads = adapter->GetThreadList();
for (const DebugThread thread : m_threads)
m_frames[thread.m_tid] = adapter->GetFramesOfThread(thread.m_tid);
std::vector<DebugThread> newThreads = adapter->GetThreadList();
for (auto thread = newThreads.begin(); thread != newThreads.end(); thread++)
{
m_frames[thread->m_tid] = adapter->GetFramesOfThread(thread->m_tid);

// update thread states in new thread list
auto oldThread = std::find_if(m_threads.begin(), m_threads.end(), [&](DebugThread const& t) {
return t.m_tid == thread->m_tid;
});

if (oldThread != m_threads.end() && thread->m_isFrozen != oldThread->m_isFrozen)
thread->m_isFrozen = oldThread->m_isFrozen;
}

m_threads.clear();
m_threads = newThreads;

m_dirty = false;
}
Expand Down Expand Up @@ -253,6 +267,63 @@ std::vector<DebugFrame> DebuggerThreads::GetFramesOfThread(uint32_t tid)
}


bool DebuggerThreads::SuspendThread(std::uint32_t tid)
{
if (!m_state)
return false;

DebugAdapter* adapter = m_state->GetAdapter();
if (!adapter)
return false;

auto thread = std::find_if(m_threads.begin(), m_threads.end(), [&](DebugThread const& t) {
return t.m_tid == tid;
});

if (thread == m_threads.end())
return false;


if (thread->m_isFrozen)
return true;

auto result = adapter->SuspendThread(tid);
if (!result)
return false;

thread->m_isFrozen = true;

return true;
}

bool DebuggerThreads::ResumeThread(std::uint32_t tid)
{
if (!m_state)
return false;

DebugAdapter* adapter = m_state->GetAdapter();
if (!adapter)
return false;

auto thread = std::find_if(m_threads.begin(), m_threads.end(), [&](DebugThread const& t) {
return t.m_tid == tid;
});

if (thread == m_threads.end())
return false;

if (!thread->m_isFrozen)
return true;

auto result = adapter->ResumeThread(tid);
if (!result)
return false;

thread->m_isFrozen = false;

return true;
}

DebuggerModules::DebuggerModules(DebuggerState* state) : m_state(state)
{
MarkDirty();
Expand Down Expand Up @@ -324,7 +395,7 @@ DebugModule DebuggerModules::GetModuleForAddress(uint64_t remoteAddress)
{
// This is slighlty different from the Python implementation, which finds the largest module start that is
// smaller than the remoteAddress.
//if ((module.m_address <= remoteAddress) && (remoteAddress < module.m_address + module.m_size))
// if ((module.m_address <= remoteAddress) && (remoteAddress < module.m_address + module.m_size))
// return module;
if ((module.m_address <= remoteAddress) && (module.m_address > closestAddress))
{
Expand Down
2 changes: 2 additions & 0 deletions core/debuggerstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ namespace BinaryNinjaDebugger {
bool IsDirty() const { return m_dirty; }
std::vector<DebugThread> GetAllThreads();
std::vector<DebugFrame> GetFramesOfThread(uint32_t tid);
bool SuspendThread(std::uint32_t tid);
bool ResumeThread(std::uint32_t tid);
};


Expand Down
13 changes: 13 additions & 0 deletions core/ffi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ BNDebugThread* BNDebuggerGetThreads(BNDebuggerController* controller, size_t* si
{
results[i].m_tid = threads[i].m_tid;
results[i].m_rip = threads[i].m_rip;
results[i].m_isFrozen = threads[i].m_isFrozen;
}

return results;
Expand Down Expand Up @@ -242,6 +243,18 @@ void BNDebuggerSetActiveThread(BNDebuggerController* controller, BNDebugThread t
}


bool BNDebuggerSuspendThread(BNDebuggerController* controller, uint32_t tid)
{
return controller->object->SuspendThread(tid);
}


bool BNDebuggerResumeThread(BNDebuggerController* controller, uint32_t tid)
{
return controller->object->ResumeThread(tid);
}


BNDebugFrame* BNDebuggerGetFramesOfThread(BNDebuggerController* controller, uint32_t tid, size_t* count)
{
std::vector<DebugFrame> frames = controller->object->GetFramesOfThread(tid);
Expand Down
Loading

0 comments on commit 5372a0f

Please sign in to comment.