Skip to content

Commit

Permalink
Make the Attach operation async
Browse files Browse the repository at this point in the history
  • Loading branch information
xusheng6 committed Apr 11, 2023
1 parent c288ea1 commit 873cc9e
Show file tree
Hide file tree
Showing 14 changed files with 146 additions and 37 deletions.
7 changes: 5 additions & 2 deletions api/debuggerapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ namespace BinaryNinjaDebuggerAPI {

// target control
bool Launch();
bool LaunchAndWait();
BNDebugStopReason LaunchAndWait();
bool Execute();
void Restart();
void Quit();
Expand All @@ -497,7 +497,8 @@ namespace BinaryNinjaDebuggerAPI {
// Convenience function, either launch the target process or connect to a remote, depending on the selected
// adapter
void LaunchOrConnect();
bool Attach(uint32_t pid);
bool Attach();
DebugStopReason AttachAndWait();

bool Go();
bool StepInto(BNFunctionGraphType il = NormalFunctionGraph);
Expand Down Expand Up @@ -528,6 +529,7 @@ namespace BinaryNinjaDebuggerAPI {
std::string GetWorkingDirectory();
bool GetRequestTerminalEmulator();
std::string GetCommandLineArguments();
int32_t GetPIDAttach();

void SetInputFile(const std::string& path);
void SetExecutablePath(const std::string& path);
Expand All @@ -536,6 +538,7 @@ namespace BinaryNinjaDebuggerAPI {
void SetRemoteHost(const std::string& host);
void SetRemotePort(uint32_t port);
void SetRequestTerminalEmulator(bool requested);
void SetPIDAttach(int32_t pid);

std::vector<DebugBreakpoint> GetBreakpoints();
void DeleteBreakpoint(uint64_t address);
Expand Down
25 changes: 22 additions & 3 deletions api/debuggercontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ bool DebuggerController::Launch()
}


bool DebuggerController::LaunchAndWait()
DebugStopReason DebuggerController::LaunchAndWait()
{
return BNDebuggerLaunchAndWait(m_object);
}
Expand Down Expand Up @@ -351,12 +351,19 @@ void DebuggerController::LaunchOrConnect()
}


bool DebuggerController::Attach(uint32_t pid)
bool DebuggerController::Attach()
{
return BNDebuggerAttach(m_object, pid);
return BNDebuggerAttach(m_object);
}


DebugStopReason DebuggerController::AttachAndWait()
{
return BNDebuggerAttachAndWait(m_object);
}



bool DebuggerController::StepInto(BNFunctionGraphType il)
{
return BNDebuggerStepInto(m_object, il);
Expand Down Expand Up @@ -472,6 +479,12 @@ uint32_t DebuggerController::GetRemotePort()
}


int32_t DebuggerController::GetPIDAttach()
{
return BNDebuggerGetPIDAttach(m_object);
}


std::string DebuggerController::GetInputFile()
{
char* path = BNDebuggerGetInputFile(m_object);
Expand Down Expand Up @@ -562,6 +575,12 @@ void DebuggerController::SetRemotePort(uint32_t port)
}


void DebuggerController::SetPIDAttach(int32_t port)
{
BNDebuggerSetPIDAttach(m_object, port);
}


void DebuggerController::SetRequestTerminalEmulator(bool requested)
{
BNDebuggerSetRequestTerminalEmulator(m_object, requested);
Expand Down
8 changes: 6 additions & 2 deletions api/ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ extern "C"
enum BNDebuggerAdapterOperation
{
DebugAdapterLaunch,
DebugAdapterAttach,
DebugAdapterGo,
DebugAdapterStepInto,
DebugAdapterStepOver,
Expand Down Expand Up @@ -352,7 +353,7 @@ extern "C"

// target control
DEBUGGER_FFI_API bool BNDebuggerLaunch(BNDebuggerController* controller);
DEBUGGER_FFI_API bool BNDebuggerLaunchAndWait(BNDebuggerController* controller);
DEBUGGER_FFI_API BNDebugStopReason BNDebuggerLaunchAndWait(BNDebuggerController* controller);
DEBUGGER_FFI_API bool BNDebuggerExecute(BNDebuggerController* controller);
DEBUGGER_FFI_API void BNDebuggerRestart(BNDebuggerController* controller);
DEBUGGER_FFI_API void BNDebuggerQuit(BNDebuggerController* controller);
Expand All @@ -363,7 +364,8 @@ extern "C"
DEBUGGER_FFI_API void BNDebuggerDetach(BNDebuggerController* controller);
// Convenience function, either launch the target process or connect to a remote, depending on the selected adapter
DEBUGGER_FFI_API void BNDebuggerLaunchOrConnect(BNDebuggerController* controller);
DEBUGGER_FFI_API bool BNDebuggerAttach(BNDebuggerController* controller, uint32_t pid);
DEBUGGER_FFI_API bool BNDebuggerAttach(BNDebuggerController* controller);
DEBUGGER_FFI_API BNDebugStopReason BNDebuggerAttachAndWait(BNDebuggerController* controller);

DEBUGGER_FFI_API bool BNDebuggerGo(BNDebuggerController* controller);
DEBUGGER_FFI_API bool BNDebuggerStepInto(BNDebuggerController* controller, BNFunctionGraphType il);
Expand Down Expand Up @@ -391,6 +393,7 @@ extern "C"

DEBUGGER_FFI_API char* BNDebuggerGetRemoteHost(BNDebuggerController* controller);
DEBUGGER_FFI_API uint32_t BNDebuggerGetRemotePort(BNDebuggerController* controller);
DEBUGGER_FFI_API int32_t BNDebuggerGetPIDAttach(BNDebuggerController* controller);
DEBUGGER_FFI_API char* BNDebuggerGetInputFile(BNDebuggerController* controller);
DEBUGGER_FFI_API char* BNDebuggerGetExecutablePath(BNDebuggerController* controller);
DEBUGGER_FFI_API char* BNDebuggerGetWorkingDirectory(BNDebuggerController* controller);
Expand All @@ -399,6 +402,7 @@ extern "C"

DEBUGGER_FFI_API void BNDebuggerSetRemoteHost(BNDebuggerController* controller, const char* host);
DEBUGGER_FFI_API void BNDebuggerSetRemotePort(BNDebuggerController* controller, uint32_t port);
DEBUGGER_FFI_API void BNDebuggerSetPIDAttach(BNDebuggerController* controller, int32_t pid);
DEBUGGER_FFI_API void BNDebuggerSetInputFile(BNDebuggerController* controller, const char* path);
DEBUGGER_FFI_API void BNDebuggerSetExecutablePath(BNDebuggerController* controller, const char* path);
DEBUGGER_FFI_API void BNDebuggerSetWorkingDirectory(BNDebuggerController* controller, const char* path);
Expand Down
32 changes: 28 additions & 4 deletions api/python/debuggercontroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -795,13 +795,21 @@ def launch_or_connect(self) -> None:
"""
dbgcore.BNDebuggerLaunchOrConnect(self.handle)

def attach(self, pid: int) -> bool:
def attach(self) -> bool:
"""
Attach to a running process by its PID
Attach to a running process
:param pid: the PID of the process to attach to
The PID of the target process must be set via DebuggerState.pid_attach
"""
return dbgcore.BNDebuggerAttach(self.handle, pid)
return dbgcore.BNDebuggerAttach(self.handle)

def attach_and_wait(self) -> bool:
"""
Attach to a running process and wait until all debugger events are processed
The PID of the target process must be set via DebuggerState.pid_attach
"""
return dbgcore.BNDebuggerAttachAndWait(self.handle)

def go(self) -> bool:
"""
Expand Down Expand Up @@ -1065,6 +1073,22 @@ def remote_port(self) -> int:
def remote_port(self, port: int) -> None:
dbgcore.BNDebuggerSetRemotePort(self.handle, port)

@property
def pid_attach(self) -> int:
"""
The PID to attach to. (read/write)
``pid_attach`` is only useful for connecting to a running process using PID.
:getter: returns the remote port
:setter: sets the remote port
"""
return dbgcore.BNDebuggerGetPIDAttach(self.handle)

@remote_port.setter
def pid_attach(self, pid: int) -> None:
dbgcore.BNDebuggerSetPIDAttach(self.handle, pid)

@property
def executable_path(self) -> str:
"""
Expand Down
5 changes: 3 additions & 2 deletions cli/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,8 @@ int main(int argc, const char* argv[])
uint32_t pid = std::stoi(argv[3]);
if (pid == 0)
return -1;
if (!debugger->Attach(pid))
debugger->SetPIDAttach(pid);
if (!debugger->AttachAndWait())
return -1;
}

Expand Down Expand Up @@ -561,7 +562,7 @@ int main(int argc, const char* argv[])
}
else if (input == "r")
{
[[maybe_unused]] bool result = debugger->Launch();
[[maybe_unused]] bool result = debugger->LaunchAndWait();
}
else if (input == "force_go")
{
Expand Down
6 changes: 3 additions & 3 deletions core/adapters/lldbadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ bool LldbAdapter::Attach(std::uint32_t pid)
if (!m_target.IsValid())
{
DebuggerEvent event;
event.type = ErrorEventType;
event.type = LaunchFailureEventType;
event.data.errorData.shortError = fmt::format("LLDB failed to attach to target.");
event.data.errorData.error =
fmt::format("LLDB failed to attach to target with \"{}\"", err.GetCString() ? err.GetCString() : "");
Expand All @@ -288,7 +288,7 @@ bool LldbAdapter::Attach(std::uint32_t pid)
if (!m_process.IsValid() || (m_process.GetState() == StateType::eStateInvalid) || err.Fail())
{
DebuggerEvent event;
event.type = ErrorEventType;
event.type = LaunchFailureEventType;
event.data.errorData.shortError = fmt::format("LLDB failed to attach to target.");
event.data.errorData.error =
fmt::format("LLDB Failed to attach to target with \"{}\"", err.GetCString() ? err.GetCString() : "");
Expand All @@ -299,7 +299,7 @@ bool LldbAdapter::Attach(std::uint32_t pid)
// LLDB event listener does not get an event when the attach operation completes, so we must send an event here.
// This is NOT needed for Connect(), since LLDB event listener sends an event in that case.
DebuggerEvent dbgevt;
dbgevt.type = TargetStoppedEventType;
dbgevt.type = AdapterStoppedEventType;
dbgevt.data.targetStoppedData.reason = InitialBreakpoint;
PostDebuggerEvent(dbgevt);
return true;
Expand Down
40 changes: 33 additions & 7 deletions core/debuggercontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,21 +147,43 @@ DebugStopReason DebuggerController::LaunchAndWait()
}


bool DebuggerController::Attach(int32_t pid)
bool DebuggerController::Attach()
{
std::unique_lock<std::recursive_mutex> lock(m_targetControlMutex);
std::thread([&]() { AttachAndWait(); }).detach();
return true;
}


DebugStopReason DebuggerController::AttachAndWaitInternal()
{
DebuggerEvent event;
event.type = LaunchEventType;
PostDebuggerEvent(event);

NotifyEvent(AttachEventType);
if (!CreateDebugAdapter())
return false;
return InternalError;

m_inputFileLoaded = false;
m_initialBreakpointSeen = false;
m_initialBreakpointSeen = false;
m_state->MarkDirty();
if (!CreateDebuggerBinaryView())
return false;
return InternalError;

return ExecuteAdapterAndWait(DebugAdapterAttach);
}


DebugStopReason DebuggerController::AttachAndWait()
{
if (!m_targetControlMutex.try_lock())
return InternalError;

auto reason = AttachAndWaitInternal();
if (!m_userRequestedBreak && (reason != ProcessExited) && (reason != InternalError))
NotifyStopped(reason);

return m_adapter->Attach(pid);
m_targetControlMutex.unlock();
return reason;
}


Expand Down Expand Up @@ -749,6 +771,7 @@ void DebuggerController::Connect()
m_initialBreakpointSeen = false;
m_state->MarkDirty();
m_state->SetConnectionStatus(DebugAdapterConnectingStatus);
CreateDebuggerBinaryView();
NotifyEvent(ConnectEventType);

bool ok = m_adapter->Connect(m_state->GetRemoteHost(), m_state->GetRemotePort());
Expand Down Expand Up @@ -1747,6 +1770,9 @@ DebugStopReason DebuggerController::ExecuteAdapterAndWait(const DebugAdapterOper
case DebugAdapterLaunch:
resumeOK = Execute();
break;
case DebugAdapterAttach:
resumeOK = m_adapter->Attach(m_state->GetPIDAttach());
break;
default:
break;
}
Expand Down
18 changes: 10 additions & 8 deletions core/debuggercontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ namespace BinaryNinjaDebugger {
// Low-level internal synchronous APIs. They resume the target and wait for the adapter to stop.
// They do NOT dispatch the debugger event callbacks. Higher-level APIs must take care of notifying
// the callbacks.
DebugStopReason LaunchAndWaitInternal();
DebugStopReason AttachAndWaitInternal();
DebugStopReason PauseAndWaitInternal();
DebugStopReason GoAndWaitInternal();
DebugStopReason StepIntoAndWaitInternal();
Expand Down Expand Up @@ -207,25 +209,21 @@ namespace BinaryNinjaDebugger {
bool SetIP(uint64_t address);

// target control
DebugStopReason LaunchAndWait();
DebugStopReason LaunchAndWaitInternal();
bool Launch();
bool Execute();
void Restart();
void Quit();
void QuitAndWait();
void Connect();
bool ConnectToDebugServer();
bool DisconnectDebugServer();
void Detach();
void DetachAndWait();
// Convenience function, either launch the target process or connect to a remote, depending on the selected
// adapter
void LaunchOrConnect();
bool Attach(int32_t pid);
bool Attach();

// Asynchronous APIs.
bool Launch();
void Detach();
bool Go();
void Quit();
bool StepInto(BNFunctionGraphType il = NormalFunctionGraph);
bool StepOver(BNFunctionGraphType il = NormalFunctionGraph);
bool StepReturn();
Expand All @@ -235,12 +233,16 @@ namespace BinaryNinjaDebugger {
DebugStopReason ExecuteAdapterAndWait(const DebugAdapterOperation operation);

// Synchronous APIs
DebugStopReason LaunchAndWait();
DebugStopReason GoAndWait();
DebugStopReason AttachAndWait();
DebugStopReason StepIntoAndWait(BNFunctionGraphType il = NormalFunctionGraph);
DebugStopReason StepOverAndWait(BNFunctionGraphType il = NormalFunctionGraph);
DebugStopReason StepReturnAndWait();
DebugStopReason RunToAndWait(const std::vector<uint64_t>& remoteAddresses);
DebugStopReason PauseAndWait();
void DetachAndWait();
void QuitAndWait();

// getters
DebugAdapter* GetAdapter() { return m_adapter; }
Expand Down
6 changes: 6 additions & 0 deletions core/debuggerstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -936,3 +936,9 @@ void DebuggerState::SetRequestTerminalEmulator(bool requested)
m_requestTerminalEmulator = requested;
m_controller->NotifyEvent(DebuggerSettingsChangedEvent);
}


void DebuggerState::SetPIDAttach(int32_t pid)
{
m_pidAttach = pid;
}
3 changes: 3 additions & 0 deletions core/debuggerstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ namespace BinaryNinjaDebugger {
std::string m_commandLineArgs;
std::string m_remoteHost;
uint32_t m_remotePort = 0;
int32_t m_pidAttach = 0;
bool m_requestTerminalEmulator;
std::string m_adapterType;
std::vector<std::string> m_availableAdapters;
Expand Down Expand Up @@ -192,6 +193,7 @@ namespace BinaryNinjaDebugger {
std::string GetRemoteHost() const { return m_remoteHost; }
uint32_t GetRemotePort() const { return m_remotePort; }
bool GetRequestTerminalEmulator() const { return m_requestTerminalEmulator; }
int32_t GetPIDAttach() const { return m_pidAttach; }

void SetAdapterType(const std::string& adapter);
void SetExecutablePath(const std::string& path);
Expand All @@ -201,6 +203,7 @@ namespace BinaryNinjaDebugger {
void SetRemoteHost(const std::string& host);
void SetRemotePort(uint32_t port);
void SetRequestTerminalEmulator(bool requested);
void SetPIDAttach(int32_t pid);

// This is the center hub for adding and deleting breakpoints. It is called from DebugView, the CLI, the
// DebugBreakpointsWidget, and the planned C++/Python API.
Expand Down
Loading

0 comments on commit 873cc9e

Please sign in to comment.