From 47f5a3ea9afeaade0295022c7e01fdc54401ef9f Mon Sep 17 00:00:00 2001 From: Itamar Date: Sun, 19 Feb 2023 22:52:52 +0200 Subject: [PATCH] HackStudio: Add 'pause debuggee' button This button sends a SIGSTOP to the debugged process, which pauses it. The debuggee can be resumed with the 'continue' button. --- Base/res/icons/16x16/debug-pause.png | Bin 0 -> 4979 bytes .../HackStudio/Debugger/DebugInfoWidget.cpp | 27 ++++++++++++++---- .../HackStudio/Debugger/DebugInfoWidget.h | 8 +++++- .../DevTools/HackStudio/Debugger/Debugger.cpp | 4 +++ .../DevTools/HackStudio/Debugger/Debugger.h | 2 ++ .../DevTools/HackStudio/HackStudioWidget.cpp | 6 ++-- Userland/Libraries/LibDebug/DebugSession.cpp | 5 ++++ Userland/Libraries/LibDebug/DebugSession.h | 3 +- 8 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 Base/res/icons/16x16/debug-pause.png diff --git a/Base/res/icons/16x16/debug-pause.png b/Base/res/icons/16x16/debug-pause.png new file mode 100644 index 0000000000000000000000000000000000000000..a93a815ea314f3a81a5c8de02983f4ca10a0933a GIT binary patch literal 4979 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s-B&$LqN`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsH_Ei(L2Eg6Ge5&1W1+D_gDl!WQHk9G^dFPsyAm@ssM9c`itB z8)kMb>(cSs__F@L#54VvGuI@aFK!cQI{I{y_nd_*?ylSOF6Hj7_x#@i^va6;41Ab0 zZ!d1U`+vjay)KJ*&faIaw99|WYnP(xn!VgdW>4tMc$LdP<(tEy+bnMxKTVs)>-jjB zYia%_*_kiC8GnBEh3of2%SBaZlVua%IVBZ}-()=Tr*q<-DLpSuWT)#b+Ob*YV8Dd* zQmgeWF3C=%{&V%#%#pI)KD&CG%zM3}@FxYQmX|sI%X2zc`lBp$`R-%o-|`-}y;%3_ zv$@;ljYV!^H(94xz44qII-Bbcm($s$R~e!l&NRpcov;*YTeMm`YT?Z+Znvc_JiFK| zv!-MQ#BT~>bvb^wpyg0Zqu*dp<4;f%#D>5KXmkF78~x@M8zUbfyJ}zq!>Yf%-7 zuX7($@`}=g`|LmROsFfmmSM!k7OVcPneQD>evjX?eMe_^zB?rSU#~bV=(}QZ{~p`q zwP*J)+$C|l?4iyo(KmKy%FnK;{CCsVTU-6Zw8asqdG z_1e$9bSY@o?W>iC+7|`nPdWDO!3ytLGv<7JviniSA@OT-HhosPF{k8hgTU>YZ)g3Q z-!N`E%D1Vm@|G&ENY?C=-)FSFcR%9Hb~kNe)yC;Nw#z*$v0S@eG2nLcchBA>Ggs_P z`!(Uk%ni4N{cN|*h>AV8ZrS2FZUs8Jk0$jkD7~}k#^F`=cG+1sFR$LXWBHAJ$E(qf1!|f%+EM8*KSPycllf$ z=Z%`iA79t)Wz5+Z{%HQCKXsk!zZ&0fD!e}7z1X+^4)rAqI{5de{9}v@{HP*n{IQ9F zfw3ji**U<|*%?+yFfdfishw!+ao9oTXne5i#4cy!4i2_8eqt`JGF!P^R|sUahROQq z{cTd?_3Y|i{2;2}L-NK~4<4;q-Mm_Xqpo4cE(^_F9-aTQxpb3kEZ!a8UEROCydgl_ z@a{Va_L9RJCw-hT<=h&t*!2PeZ5@d`nrF~ zeU{K+1FolQ-P1m_F)N0vA~a$mPvZhzr9^N0sC7ftm#C)|A`XkYJD zvouz3^?6Et8M_>RI^9a{{VbNgHze_F^(XPRO~+0dUC-oG>T}g`Y-14>6$xx=)>zA? zX*Ow#{O6DSCVz}}h7^e&Jh8FCs6>O;{)haZch}DO`c-%?l(_Ko(JpyqhwFL)>vz5T zzVY=n|Aq&~1*u#9Je4x|>{+#SscT=uzT5|ob}e05ec&nIh5sp9(=JVDGHH$BtFT|3 ze~RH@^n&!Wuh;JEzs#=S8mpSu(CnOG;(znC-TQZW@88}xKKrkZp_aR7_2&onI~W*v zr7}YzN+NuHtdjF{^%7I^lT!66atjzhz{b9!ATc>RwL~E)H9a%WR_Xoj{Yna%DYi=C zroINg16w1-Ypui3%0DIeEoa6}C!XbFK1< ztw6&1N(x{lCE2!05xxNm&iO^D3MP6cdIq|#6`5s5N_JcdHbp6ERzWUqP$P;`(rlG7 zN=gc>^!3Zj%k|2Q_413-^$jg8E%gnI^o@*ki&D~bi!1X=5-W7`ij_e|K+JGSElw`V zEGWs$&r<-InV6JcT4JlD#HFC105!ZKx4_pIZhT%bG!&BabM-3{3-k^34D@qz^^tWH zm$;Ud;MY+cQdy9yACy|0Us{x$>ROhXSE7t;L`pJTe?e(c4%j;>$@-}|sky0nCB^!N zdWI-gx_kNtz;%FvAU!j;0IaJbw*WGG*3n{!oMgpJu@#c2ia91qf#cBwM-V7v(0F*eYe_CZ?zA7v!abB|rgg zi4>2_;*$KLN;`0h2IrgL)Itakk_B=y!BPqe;ACr+m<+L`II%1>1?)5hm{f8`VqSV` zimehfLBYf`u|$@oL2`;^lA)Qdi9uSLu1S(BaeJ zCFO}lsgCKXc_p?=?wPp-VBaWcfP+#KRdsnrDkz)`jEr>+jC2hxLyU~9j4iB;47Cl6 ztPBj4^dVlf(Ff&fn2&ArF~S6*0I3+T<5GZ#1-ZD{aoOmD%OX&@1Thd)F3=J~gnPbVsSb-L4q~npc7l$|C>BK{|i4(WE5UHtyjuGf=7athlk DebugInfoWidget::init_toolbar() Debugger::the().set_requested_debugger_action(Debugger::DebuggerAction::SourceStepOut); }); + m_pause_action = GUI::Action::create("Pause", {}, TRY(Gfx::Bitmap::load_from_file("/res/icons/16x16/debug-pause.png"sv)), [](auto&) { + Debugger::the().stop_debuggee(); + }); + m_toolbar->add_action(*m_continue_action); m_toolbar->add_action(*m_singlestep_action); m_toolbar->add_action(*m_step_in_action); m_toolbar->add_action(*m_step_out_action); + m_toolbar->add_action(*m_pause_action); - set_debug_actions_enabled(false); + set_debug_actions_enabled(false, {}); return {}; } @@ -193,12 +198,22 @@ void DebugInfoWidget::program_stopped() m_registers_view->set_model({}); } -void DebugInfoWidget::set_debug_actions_enabled(bool enabled) +void DebugInfoWidget::set_debug_actions_enabled(bool enabled, Optional state) { - m_continue_action->set_enabled(enabled); - m_singlestep_action->set_enabled(enabled); - m_step_in_action->set_enabled(enabled); - m_step_out_action->set_enabled(enabled); + if (!enabled) { + m_continue_action->set_enabled(false); + m_singlestep_action->set_enabled(false); + m_step_in_action->set_enabled(false); + m_step_out_action->set_enabled(false); + m_pause_action->set_enabled(false); + return; + } + + m_continue_action->set_enabled(state == DebugActionsState::DebuggeeStopped); + m_singlestep_action->set_enabled(state == DebugActionsState::DebuggeeStopped); + m_step_in_action->set_enabled(state == DebugActionsState::DebuggeeStopped); + m_step_out_action->set_enabled(state == DebugActionsState::DebuggeeStopped); + m_pause_action->set_enabled(state == DebugActionsState::DebuggeeRunning); } } diff --git a/Userland/DevTools/HackStudio/Debugger/DebugInfoWidget.h b/Userland/DevTools/HackStudio/Debugger/DebugInfoWidget.h index 11759c649d..e08b23dfae 100644 --- a/Userland/DevTools/HackStudio/Debugger/DebugInfoWidget.h +++ b/Userland/DevTools/HackStudio/Debugger/DebugInfoWidget.h @@ -29,7 +29,12 @@ public: void update_state(Debug::ProcessInspector&, PtraceRegisters const&); void program_stopped(); - void set_debug_actions_enabled(bool enabled); + + enum class DebugActionsState { + DebuggeeRunning, + DebuggeeStopped, + }; + void set_debug_actions_enabled(bool enabled, Optional); Function on_backtrace_frame_selection; @@ -51,6 +56,7 @@ private: RefPtr m_singlestep_action; RefPtr m_step_in_action; RefPtr m_step_out_action; + RefPtr m_pause_action; }; } diff --git a/Userland/DevTools/HackStudio/Debugger/Debugger.cpp b/Userland/DevTools/HackStudio/Debugger/Debugger.cpp index b1a97bae4c..2ab1a0cbc8 100644 --- a/Userland/DevTools/HackStudio/Debugger/Debugger.cpp +++ b/Userland/DevTools/HackStudio/Debugger/Debugger.cpp @@ -314,5 +314,9 @@ void Debugger::set_requested_debugger_action(DebuggerAction action) pthread_cond_signal(continue_cond()); pthread_mutex_unlock(continue_mutex()); } +void Debugger::stop_debuggee() +{ + return m_debug_session->stop_debuggee(); +} } diff --git a/Userland/DevTools/HackStudio/Debugger/Debugger.h b/Userland/DevTools/HackStudio/Debugger/Debugger.h index eafd7382ba..656d2983c4 100644 --- a/Userland/DevTools/HackStudio/Debugger/Debugger.h +++ b/Userland/DevTools/HackStudio/Debugger/Debugger.h @@ -64,6 +64,8 @@ public: void set_child_setup_callback(Function()> callback) { m_child_setup_callback = move(callback); } + void stop_debuggee(); + private: class DebuggingState { public: diff --git a/Userland/DevTools/HackStudio/HackStudioWidget.cpp b/Userland/DevTools/HackStudio/HackStudioWidget.cpp index 71d9eb486c..aa8b5be432 100644 --- a/Userland/DevTools/HackStudio/HackStudioWidget.cpp +++ b/Userland/DevTools/HackStudio/HackStudioWidget.cpp @@ -1055,7 +1055,7 @@ void HackStudioWidget::initialize_debugger() if (m_current_editor_in_execution) m_current_editor_in_execution->editor().set_execution_position(source_position.value().line_number - 1); m_debug_info_widget->update_state(*Debugger::the().session(), regs); - m_debug_info_widget->set_debug_actions_enabled(true); + m_debug_info_widget->set_debug_actions_enabled(true, DebugInfoWidget::DebugActionsState::DebuggeeStopped); m_disassembly_widget->update_state(*Debugger::the().session(), regs); HackStudioWidget::reveal_action_tab(*m_debug_info_widget); }); @@ -1065,7 +1065,7 @@ void HackStudioWidget::initialize_debugger() }, [this]() { GUI::Application::the()->event_loop().deferred_invoke([this] { - m_debug_info_widget->set_debug_actions_enabled(false); + m_debug_info_widget->set_debug_actions_enabled(true, DebugInfoWidget::DebugActionsState::DebuggeeRunning); if (m_current_editor_in_execution) m_current_editor_in_execution->editor().clear_execution_position(); }); @@ -1073,7 +1073,7 @@ void HackStudioWidget::initialize_debugger() }, [this]() { GUI::Application::the()->event_loop().deferred_invoke([this] { - m_debug_info_widget->set_debug_actions_enabled(false); + m_debug_info_widget->set_debug_actions_enabled(false, {}); if (m_current_editor_in_execution) m_current_editor_in_execution->editor().clear_execution_position(); m_debug_info_widget->program_stopped(); diff --git a/Userland/Libraries/LibDebug/DebugSession.cpp b/Userland/Libraries/LibDebug/DebugSession.cpp index 7ad41b67db..451d4a17a2 100644 --- a/Userland/Libraries/LibDebug/DebugSession.cpp +++ b/Userland/Libraries/LibDebug/DebugSession.cpp @@ -510,4 +510,9 @@ void DebugSession::update_loaded_libs() }); } +void DebugSession::stop_debuggee() +{ + kill(pid(), SIGSTOP); +} + } diff --git a/Userland/Libraries/LibDebug/DebugSession.h b/Userland/Libraries/LibDebug/DebugSession.h index 8997cea5dc..70b7ce43d3 100644 --- a/Userland/Libraries/LibDebug/DebugSession.h +++ b/Userland/Libraries/LibDebug/DebugSession.h @@ -100,6 +100,7 @@ public: Syscall, }; void continue_debuggee(ContinueType type = ContinueType::FreeRun); + void stop_debuggee(); // Returns the wstatus result of waitpid() int continue_debuggee_and_wait(ContinueType type = ContinueType::FreeRun); @@ -169,7 +170,7 @@ void DebugSession::run(DesiredInitialDebugeeState initial_debugee_state, Callbac // FIXME: This check actually only checks whether the debuggee // stopped because it hit a breakpoint/syscall/is in single stepping mode or not - if (WSTOPSIG(wstatus) != SIGTRAP) { + if (WSTOPSIG(wstatus) != SIGTRAP && WSTOPSIG(wstatus) != SIGSTOP) { callback(DebugBreakReason::Exited, Optional()); m_is_debuggee_dead = true; return true;