Skip to content

Commit b77e264

Browse files
authored
Fix native Windows adapter broken after detach (#1050)
1 parent 134e0b2 commit b77e264

2 files changed

Lines changed: 75 additions & 17 deletions

File tree

core/adapters/windowsnativeadapter.cpp

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -238,23 +238,6 @@ bool WindowsNativeAdapter::Detach()
238238
// Wake up the debug thread if it's waiting
239239
m_debugCondition.notify_one();
240240

241-
// Remove all breakpoints before detaching
242-
{
243-
std::lock_guard<std::mutex> lock(m_breakpointsMutex);
244-
for (auto& bp : m_breakpoints)
245-
{
246-
if (bp.isActive)
247-
RemoveBreakpointInternal(bp.address);
248-
}
249-
m_breakpoints.clear();
250-
}
251-
252-
if (!DebugActiveProcessStop(m_processId))
253-
{
254-
LogError("Failed to detach from process: %d", GetLastError());
255-
return false;
256-
}
257-
258241
if (m_debugThread.joinable())
259242
m_debugThread.join();
260243

@@ -563,7 +546,16 @@ void WindowsNativeAdapter::DebugLoop()
563546

564547
if (m_shouldStop)
565548
{
549+
RemoveAllBreakpoints();
566550
ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);
551+
552+
// DebugActiveProcessStop must be called from the same thread that started debugging
553+
if (!DebugActiveProcessStop(m_processId))
554+
{
555+
LogWarn("DebugActiveProcessStop failed (error %d) -- killing target", GetLastError());
556+
TerminateProcess(m_processHandle, 1);
557+
}
558+
567559
break;
568560
}
569561
}
@@ -588,6 +580,19 @@ void WindowsNativeAdapter::DebugLoop()
588580
ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, continueStatus);
589581
}
590582

583+
// If we exited the loop due to m_shouldStop while the target was running (not stopped at a
584+
// breakpoint), we still need to detach. The stopped-at-breakpoint case is handled inside the loop.
585+
if (m_shouldStop && m_activelyDebugging)
586+
{
587+
RemoveAllBreakpoints();
588+
589+
if (!DebugActiveProcessStop(m_processId))
590+
{
591+
LogWarn("DebugActiveProcessStop failed (error %d) -- killing target", GetLastError());
592+
TerminateProcess(m_processHandle, 1);
593+
}
594+
}
595+
591596
m_activelyDebugging = false;
592597
}
593598

@@ -1569,6 +1574,58 @@ bool WindowsNativeAdapter::RemoveBreakpoint(const ModuleNameAndOffset& breakpoin
15691574
}
15701575

15711576

1577+
void WindowsNativeAdapter::RemoveAllBreakpoints()
1578+
{
1579+
// Remove software breakpoints
1580+
{
1581+
std::lock_guard<std::mutex> lock(m_breakpointsMutex);
1582+
for (auto& bp : m_breakpoints)
1583+
{
1584+
if (bp.isActive)
1585+
RemoveBreakpointInternal(bp.address);
1586+
}
1587+
m_breakpoints.clear();
1588+
}
1589+
1590+
// Remove hardware breakpoints from all threads
1591+
{
1592+
std::lock_guard<std::mutex> lock(m_hwBreakpointsMutex);
1593+
for (const auto& hwbp : m_hardwareBreakpoints)
1594+
{
1595+
if (hwbp.isActive)
1596+
{
1597+
for (auto& [tid, handle] : m_threads)
1598+
{
1599+
if (!handle)
1600+
continue;
1601+
if (m_isTargetWow64)
1602+
{
1603+
WOW64_CONTEXT ctx {};
1604+
ctx.ContextFlags = WOW64_CONTEXT_DEBUG_REGISTERS;
1605+
if (Wow64GetThreadContext(handle, &ctx))
1606+
{
1607+
if (ClearHardwareBreakpointInContext(ctx, hwbp.drIndex))
1608+
Wow64SetThreadContext(handle, &ctx);
1609+
}
1610+
}
1611+
else
1612+
{
1613+
CONTEXT ctx {};
1614+
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
1615+
if (GetThreadContext(handle, &ctx))
1616+
{
1617+
if (ClearHardwareBreakpointInContext(ctx, hwbp.drIndex))
1618+
SetThreadContext(handle, &ctx);
1619+
}
1620+
}
1621+
}
1622+
}
1623+
}
1624+
m_hardwareBreakpoints.clear();
1625+
}
1626+
}
1627+
1628+
15721629
bool WindowsNativeAdapter::RemoveBreakpointInternal(uint64_t address)
15731630
{
15741631
// Find the breakpoint to get the original byte

core/adapters/windowsnativeadapter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ namespace BinaryNinjaDebugger {
154154
bool ApplyBreakpoint(uint64_t address, unsigned long id);
155155
bool RemoveBreakpointInternal(uint64_t address);
156156
void ApplyPendingBreakpoints();
157+
void RemoveAllBreakpoints();
157158
bool ApplyHardwareBreakpointsToThread(HANDLE threadHandle);
158159
int FindFreeDebugRegister();
159160
bool SetHardwareBreakpointInContext(CONTEXT& ctx, int drIndex, uint64_t address, DebugBreakpointType type, size_t size);

0 commit comments

Comments
 (0)