diff --git a/thermosphere/src/debug_manager.c b/thermosphere/src/debug_manager.c index b01cf054b..510475d82 100644 --- a/thermosphere/src/debug_manager.c +++ b/thermosphere/src/debug_manager.c @@ -124,6 +124,12 @@ void debugManagerSetReportingEnabled(bool enabled) atomic_store(&g_debugManager.reportingEnabled, enabled); } +bool debugManagerHasDebugEvent(u32 coreId) +{ + bool isPaused = debugManagerIsCorePaused(coreId); + return isPaused && g_debugManager.debugEventInfos[coreId].type != DBGEVENT_NONE; +} + void debugManagerPauseCores(u32 coreList) { u64 flags = maskIrq(); @@ -161,7 +167,7 @@ u32 debugManagerGetPausedCoreList(void) return atomic_load(&g_debugManager.pausedCoreList); } -DebugEventInfo *debugManagerGetCoreDebugEvent(u32 coreId) +DebugEventInfo *debugManagerGetDebugEvent(u32 coreId) { return &g_debugManager.debugEventInfos[coreId]; } @@ -217,7 +223,7 @@ void debugManagerBreakCores(u32 coreList) if (coreList & ~BIT(coreId)) { generateSgiForList(ThermosphereSgi_ReportDebuggerBreak, coreList & ~BIT(coreId)); } - if ((coreList & BIT(coreId)) && !debugManagerIsCorePaused(coreId)) { + if ((coreList & BIT(coreId)) && !debugManagerHasDebugEvent(coreId)) { debugManagerReportEvent(DBGEVENT_DEBUGGER_BREAK); } diff --git a/thermosphere/src/debug_manager.h b/thermosphere/src/debug_manager.h index 2f2d7df0d..d41287f64 100644 --- a/thermosphere/src/debug_manager.h +++ b/thermosphere/src/debug_manager.h @@ -57,6 +57,9 @@ void debugManagerSetReportingEnabled(bool enabled); // Hypervisor interrupts will be serviced during the pause-wait bool debugManagerHandlePause(void); +DebugEventInfo *debugManagerGetDebugEvent(u32 coreId); +bool debugManagerHasDebugEvent(u32 coreId); + // Note: these functions are not reentrant EXCEPT debugPauseCores(1 << currentCoreId) // "Pause" makes sure all cores reaches the pause function before proceeding. // "Unpause" doesn't synchronize, it just makes sure the core resumes & that "pause" can be called again. @@ -68,7 +71,6 @@ void debugManagerSetSteppingRange(u32 coreId, uintptr_t startAddr, uintptr_t end u32 debugManagerGetPausedCoreList(void); -DebugEventInfo *debugManagerGetCoreDebugEvent(u32 coreId); void debugManagerReportEvent(DebugEventType type, ...); diff --git a/thermosphere/src/gdb/context.c b/thermosphere/src/gdb/context.c index 7a0b6440f..1e7e935e6 100644 --- a/thermosphere/src/gdb/context.c +++ b/thermosphere/src/gdb/context.c @@ -191,7 +191,7 @@ void GDB_AttachToContext(GDBContext *ctx) GDB_BreakAllCores(ctx); - DebugEventInfo *info = debugManagerGetCoreDebugEvent(currentCoreCtx->coreId); + DebugEventInfo *info = debugManagerGetDebugEvent(currentCoreCtx->coreId); info->preprocessed = true; info->handled = true; ctx->lastDebugEvent = info; diff --git a/thermosphere/src/gdb/context.h b/thermosphere/src/gdb/context.h index 23cbfb691..c3f4e3c6a 100644 --- a/thermosphere/src/gdb/context.h +++ b/thermosphere/src/gdb/context.h @@ -115,3 +115,8 @@ static inline bool GDB_IsAttached(GDBContext *ctx) { return ctx->state == GDB_STATE_ATTACHED; } + +static inline bool GDB_IsNonStop(GDBContext *ctx) +{ + return (ctx->flags & GDB_FLAG_NONSTOP) != 0; +} diff --git a/thermosphere/src/gdb/debug.c b/thermosphere/src/gdb/debug.c index ad341dbff..9b2c2bfe2 100644 --- a/thermosphere/src/gdb/debug.c +++ b/thermosphere/src/gdb/debug.c @@ -196,7 +196,7 @@ int GDB_SendStopReply(GDBContext *ctx, const DebugEventInfo *info, bool asNotifi } case DBGEVENT_OUTPUT_STRING: { - if (!(ctx->flags & GDB_FLAG_NONSTOP)) { + if (!GDB_IsNonStop(ctx)) { uintptr_t addr = info->outputString.address; size_t remaining = info->outputString.size; size_t sent = 0; @@ -235,9 +235,6 @@ int GDB_SendStopReply(GDBContext *ctx, const DebugEventInfo *info, bool asNotifi } else if (asNotification) { return GDB_SendNotificationPacket(ctx, buf, strlen(buf)); } else { - if (!(ctx->flags & GDB_FLAG_NONSTOP)) { - GDB_MarkDebugEventAcked(ctx, info); - } return GDB_SendPacket(ctx, buf, strlen(buf)); } } @@ -273,7 +270,7 @@ int GDB_TrySignalDebugEvent(GDBContext *ctx, DebugEventInfo *info) // Are we still paused & has the packet not been handled & are we allowed to send on our own? if (shouldSignal && !ctx->sendOwnDebugEventDisallowed && !info->handled && debugManagerIsCorePaused(info->coreId)) { - bool nonStop = (ctx->flags & GDB_FLAG_NONSTOP) != 0; + bool nonStop = GDB_IsNonStop(ctx); info->handled = true; // Full-stop mode: stop other cores @@ -296,14 +293,14 @@ int GDB_TrySignalDebugEvent(GDBContext *ctx, DebugEventInfo *info) void GDB_BreakAllCores(GDBContext *ctx) { - if (ctx->flags & GDB_FLAG_NONSTOP) { + if (GDB_IsNonStop(ctx)) { debugManagerBreakCores(ctx->attachedCoreList); } else { // Break all cores too, but mark everything but the first has handled debugManagerBreakCores(ctx->attachedCoreList); u32 rem = ctx->attachedCoreList & ~BIT(currentCoreCtx->coreId); FOREACH_BIT (tmp, coreId, rem) { - DebugEventInfo *info = debugManagerGetCoreDebugEvent(coreId); + DebugEventInfo *info = debugManagerGetDebugEvent(coreId); info->handled = true; info->preprocessed = true; } @@ -324,7 +321,7 @@ GDB_DECLARE_VERBOSE_HANDLER(Stopped) if (remaining != 0) { // Send one more debug event (marking it as handled) u32 coreId = __builtin_ctz(remaining); - DebugEventInfo *info = debugManagerGetCoreDebugEvent(coreId); + DebugEventInfo *info = debugManagerGetDebugEvent(coreId); if (GDB_PreprocessDebugEvent(ctx, info)) { ctx->sendOwnDebugEventDisallowed = true; @@ -342,8 +339,7 @@ GDB_DECLARE_VERBOSE_HANDLER(Stopped) GDB_DECLARE_HANDLER(GetStopReason) { - bool nonStop = (ctx->flags & GDB_FLAG_NONSTOP) != 0; - if (!nonStop) { + if (!GDB_IsNonStop(ctx)) { // Full-stop: return GDB_SendStopReply(ctx, ctx->lastDebugEvent, false); } else { @@ -384,9 +380,9 @@ GDB_DECLARE_HANDLER(ContinueOrStepDeprecated) char cmd = ctx->commandData[-1]; // This deprecated command should not be permitted in non-stop mode - if (ctx->flags & GDB_FLAG_NONSTOP) { + /*if (GDB_IsNonStop(ctx)) { return GDB_ReplyErrno(ctx, EPERM); - } + }*/ if(cmd == 'C' || cmd == 'S') { // Check the presence of the two-digit signature, even if we ignore it. @@ -544,7 +540,7 @@ GDB_DECLARE_VERBOSE_HANDLER(Continue) // "Note: In non-stop mode, a thread is considered running until GDB acknowledges // an asynchronous stop notification for it with the ‘vStopped’ packet (see Remote Non-Stop)." - u32 mask = ctx->acknowledgedDebugEventCoreList; + u32 mask = GDB_IsNonStop(ctx) ? ctx->acknowledgedDebugEventCoreList : ctx->attachedCoreList; debugManagerSetSingleStepCoreList(stepCoreList & mask); debugManagerBreakCores(stopCoreList & ~mask); diff --git a/thermosphere/src/irq.c b/thermosphere/src/irq.c index 9f1b69141..09823914c 100644 --- a/thermosphere/src/irq.c +++ b/thermosphere/src/irq.c @@ -221,6 +221,7 @@ void handleIrqException(ExceptionStackFrame *frame, bool isLowerEl, bool isA32) bool isGuestInterrupt = false; bool isMaintenanceInterrupt = false; bool isPaused = false; + bool hasDebugEvent = false; switch (irqId) { case ThermosphereSgi_ExecuteFunction: @@ -237,7 +238,6 @@ void handleIrqException(ExceptionStackFrame *frame, bool isLowerEl, bool isA32) // See bottom halves // Because exceptions (other debug events) are handling w/ interrupts off, if // we get there, there's no race condition possible with debugManagerReportEvent - isPaused = debugManagerIsCorePaused(currentCoreCtx->coreId); break; case GIC_IRQID_MAINTENANCE: isMaintenanceInterrupt = true; @@ -274,12 +274,15 @@ void handleIrqException(ExceptionStackFrame *frame, bool isLowerEl, bool isA32) recursiveSpinlockUnlock(&g_irqManager.lock); + isPaused = debugManagerIsCorePaused(currentCoreCtx->coreId); + hasDebugEvent = debugManagerHasDebugEvent(currentCoreCtx->coreId); + if (irqId == ThermosphereSgi_ReportDebuggerBreak) DEBUG("debug event=%d\n", (int)debugManagerGetDebugEvent(currentCoreCtx->coreId)->type); // Bottom half part if (transportIface != NULL) { exceptionEnterInterruptibleHypervisorCode(); unmaskIrq(); transportInterfaceIrqHandlerBottomHalf(transportIface); - } else if (irqId == ThermosphereSgi_ReportDebuggerBreak && !isPaused) { + } else if (irqId == ThermosphereSgi_ReportDebuggerBreak && !hasDebugEvent) { debugManagerReportEvent(DBGEVENT_DEBUGGER_BREAK); } else if (irqId == ThermosphereSgi_DebuggerContinue && isPaused) { debugManagerUnpauseCores(BIT(currentCoreCtx->coreId));