bool DbgGdb::Interrupt() { if ( m_debuggeePid > 0 ) { m_observer->UpdateAddLine( wxString::Format( wxT( "Interrupting debugee process: %ld" ), m_debuggeePid ) ); #ifdef __WXMSW__ if ( !GetIsRemoteDebugging() && DebugBreakProcessFunc ) { // we have DebugBreakProcess HANDLE process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, ( DWORD )m_debuggeePid ); BOOL res = DebugBreakProcessFunc( process ); CloseHandle(process); return res == TRUE; } if ( GetIsRemoteDebugging() ) { // We need to send GDB a Ctrl-C event. Using DebugBreakProcess just leaves // it unresponsive. return GenerateConsoleCtrlEvent( CTRL_C_EVENT, 0 ); } // on Windows version < XP we need to find a solution for interrupting the // debuggee process return false; #else kill( m_debuggeePid, SIGINT ); return true; #endif } else { ::wxMessageBox(_("Can't interrupt debuggee process: I don't know its PID!"), wxT("CodeLite")); } return false; }
void DbgGdb::DoCleanup() { #ifdef __WXMSW__ if(GetIsRemoteDebugging()) { SetConsoleCtrlHandler((PHANDLER_ROUTINE)SigHandler, FALSE); FreeConsole(); // Disconnect any existing console window. } #endif wxDELETE(m_gdbProcess); SetIsRecording(false); m_reverseDebugging = false; m_goingDown = false; m_attachedMode = false; SetIsRemoteDebugging(false); SetIsRemoteExtended(false); EmptyQueue(); m_gdbOutputArr.Clear(); m_bpList.clear(); m_debuggeeProjectName.Clear(); // Clear any bufferd output m_gdbOutputIncompleteLine.Clear(); // Free allocated console for this session m_consoleFinder.FreeConsole(); }
bool DbgGdb::DoInitializeGdb(const std::vector<BreakpointInfo> &bpList, const wxArrayString &cmds) { //place breakpoint at first line #ifdef __WXMSW__ ExecuteCmd(wxT("set new-console on")); #endif ExecuteCmd(wxT("set unwindonsignal on")); if (m_info.enablePendingBreakpoints) { ExecuteCmd(wxT("set breakpoint pending on")); } if (m_info.catchThrow) { ExecuteCmd(wxT("catch throw")); } #ifdef __WXMSW__ if (m_info.debugAsserts) { ExecuteCmd(wxT("break assert")); } #endif ExecuteCmd(wxT("set width 0")); ExecuteCmd(wxT("set height 0")); ExecuteCmd(wxT("set print pretty on")); // pretty printing // Number of elements to show for arrays (including strings) wxString sizeCommand; sizeCommand << wxT("set print elements ") << m_info.maxDisplayStringSize; ExecuteCmd( sizeCommand ); // set the project startup commands for (size_t i=0; i<cmds.GetCount(); i++) { ExecuteCmd(cmds.Item(i)); } // keep the list of breakpoints m_bpList = bpList; if(GetIsRemoteDebugging() == false) // When remote debugging, apply the breakpoints after we connect the // gdbserver SetBreakpoints(); if (m_info.breakAtWinMain) { //try also to set breakpoint at WinMain WriteCommand(wxT("-break-insert main"), NULL); } return true; }
void DbgGdb::GetDebugeePID(const wxString& line) { if(m_debuggeePid == wxNOT_FOUND) { if(GetIsRemoteDebugging()) { m_debuggeePid = m_gdbProcess->GetPid(); } else { static wxRegEx reDebuggerPidWin(wxT("New Thread ([0-9]+)\\.(0[xX][0-9a-fA-F]+)")); static wxRegEx reGroupStarted(wxT("id=\"([0-9]+)\"")); static wxRegEx reSwitchToThread(wxT("Switching to process ([0-9]+)")); // test for the debuggee PID // in the line with the following pattern: // =thread-group-started,id="i1",pid="15599" if(m_debuggeePid < 0 && !line.IsEmpty()) { wxString debuggeePidStr; if(line.Contains(wxT("=thread-group-started")) && reGroupStarted.Matches(line)) { debuggeePidStr = reGroupStarted.GetMatch(line, 1); } else if(line.Contains(wxT("=thread-group-created")) && reGroupStarted.Matches(line)) { debuggeePidStr = reGroupStarted.GetMatch(line, 1); } else if(reDebuggerPidWin.Matches(line)) { debuggeePidStr = reDebuggerPidWin.GetMatch(line, 1); } else if(reSwitchToThread.Matches(line)) { debuggeePidStr = reSwitchToThread.GetMatch(line, 1); } if(!debuggeePidStr.IsEmpty()) { long iPid(0); if(debuggeePidStr.ToLong(&iPid)) { m_debuggeePid = iPid; wxString msg; msg << wxT(">> Debuggee process ID: ") << m_debuggeePid; m_observer->UpdateAddLine(msg); // Now there's a known pid, the debugger can be interrupted to let any to-be-disabled bps be // disabled. So... m_observer->DebuggerPidValid(); } } } } } }
bool DbgGdb::Run(const wxString &args, const wxString &comm) { if ( !GetIsRemoteDebugging() ) { // add handler for this command return WriteCommand(wxT("-exec-run ") + args, new DbgCmdHandlerAsyncCmd(m_observer)); } else { // attach to the remote gdb server wxString cmd; //cmd << wxT("-target-select remote ") << comm << wxT(" ") << args; cmd << wxT("target remote ") << comm << wxT(" ") << args; return WriteCommand(cmd, new DbgCmdHandlerRemoteDebugging(m_observer, this)); } }
bool DbgGdb::Run(const wxString& args, const wxString& comm) { if(!GetIsRemoteDebugging()) { // add handler for this command wxString setArgsCommands; setArgsCommands << wxT("-exec-arguments ") << args; if(!WriteCommand(setArgsCommands, NULL)) return false; return WriteCommand(wxT("-exec-run "), new DbgCmdHandlerExecRun(m_observer, this)); } else { // attach to the remote gdb server wxString cmd; // cmd << wxT("-target-select remote ") << comm << wxT(" ") << args; if(GetIsRemoteExtended()) cmd << wxT("target extended-remote ") << comm << wxT(" ") << args; else cmd << wxT("target remote ") << comm << wxT(" ") << args; return WriteCommand(cmd, new DbgCmdHandlerRemoteDebugging(m_observer, this)); } }
bool DbgGdb::Start( const DebugSessionInfo& si) { //set the environment variables EnvSetter env( m_env, NULL, m_debuggeeProjectName ); wxString dbgExeName; if ( ! DoLocateGdbExecutable( si.debuggerPath, dbgExeName ) ) { return false; } wxString cmd; #if defined (__WXGTK__) || defined (__WXMAC__) cmd << dbgExeName; if ( !si.ttyName.IsEmpty() ) { cmd << wxT( " --tty=" ) << si.ttyName; } cmd << wxT( " --interpreter=mi " ) << si.exeName; #else cmd << dbgExeName << wxT( " --interpreter=mi " ) << si.exeName; #endif m_debuggeePid = wxNOT_FOUND; m_attachedMode = false; m_observer->UpdateAddLine( wxString::Format( wxT( "Current working dir: %s" ), wxGetCwd().c_str() ) ); m_observer->UpdateAddLine( wxString::Format( wxT( "Launching gdb from : %s" ), si.cwd.c_str() ) ); m_observer->UpdateAddLine( wxString::Format( wxT( "Starting debugger : %s" ), cmd.c_str() ) ); #ifdef __WXMSW__ // When using remote debugging on Windows we need a console window, as this is the only // mechanism to send a Ctrl-C event and signal a SIGINT to interrupt the target. bool needs_console = GetIsRemoteDebugging() | m_info.showTerminal; #else bool needs_console = m_info.showTerminal; #endif m_gdbProcess = CreateAsyncProcess( this, cmd, // show console? needs_console ? IProcessCreateConsole : IProcessCreateDefault, si.cwd ); if ( !m_gdbProcess ) { return false; } #ifdef __WXMSW__ if ( GetIsRemoteDebugging() ) { // This doesn't really make sense, but AttachConsole fails without it... AllocConsole(); FreeConsole(); // Disconnect any existing console window. if ( !AttachConsole( m_gdbProcess->GetPid() ) ) m_observer->UpdateAddLine( wxString::Format(wxT("AttachConsole returned error %d"), GetLastError())); // We can at least make the window invisible if the user doesn't want to see it. if ( !m_info.showTerminal ) SetWindowPos(GetConsoleWindow(), HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW); // Finally we ignore SIGINT so we don't get killed by our own signal signal(SIGINT, SIG_IGN); } #endif m_gdbProcess->SetHardKill( true ); DoInitializeGdb( si ); return true; }
// Initialization stage bool DbgGdb::DoInitializeGdb(const DebugSessionInfo& sessionInfo) { m_goingDown = false; m_internalBpId = wxNOT_FOUND; #ifdef __WXMSW__ ExecuteCmd( wxT( "set new-console on" ) ); #endif ExecuteCmd( wxT( "set unwindonsignal on" ) ); wxString breakinsertcmd(wxT("-break-insert ")); if ( m_info.enablePendingBreakpoints ) { ExecuteCmd( wxT( "set breakpoint pending on" ) ); breakinsertcmd << wxT("-f "); } if ( m_info.catchThrow ) { ExecuteCmd( wxT( "catch throw" ) ); } #ifdef __WXMSW__ if ( m_info.debugAsserts ) { ExecuteCmd( wxT( "break assert" ) ); } #endif ExecuteCmd( wxT( "set width 0" ) ); ExecuteCmd( wxT( "set height 0" ) ); // Number of elements to show for arrays (including strings) wxString sizeCommand; sizeCommand << wxT( "set print elements " ) << m_info.maxDisplayStringSize; ExecuteCmd( sizeCommand ); // set the project startup commands for ( size_t i=0; i<sessionInfo.cmds.GetCount(); i++ ) { ExecuteCmd( sessionInfo.cmds.Item( i ) ); } // keep the list of breakpoints m_bpList = sessionInfo.bpList; bool setBreakpointsAfterMain( m_info.applyBreakpointsAfterProgramStarted ); if( GetIsRemoteDebugging() == false && !setBreakpointsAfterMain ) { // When remote debugging, apply the breakpoints after we connect the // gdbserver SetBreakpoints(); } else if( setBreakpointsAfterMain && m_bpList.empty() == false ) { // Place an 'internal' breakpoint at main. Once this breakpoint is hit // set all breakpoints and remove the 'internal' one. // Then 'continue', unless the user has said he actually _wants_ to break at main WriteCommand( breakinsertcmd + wxT("-t main"), new DbgFindMainBreakpointIdHandler( m_observer, this ) ); } if (m_info.breakAtWinMain) { // Set a breakpoint at WinMain // Use a temporary one, so that it isn't duplicated in future sessions WriteCommand( breakinsertcmd + wxT("-t main"), NULL ); // Flag that we've done this. DbgFindMainBreakpointIdHandler::ProcessOutput uses this // to decide whether or not to 'continue' after setting BPs after main() SetShouldBreakAtMain(true); } else { SetShouldBreakAtMain(false); // Needs explicitly to be set, in case the user has just changed his options } // Enable python based pretty printing? if ( sessionInfo.enablePrettyPrinting ) { WriteCommand( wxT( "-enable-pretty-printing" ), NULL ); } // Add the additional search paths for(size_t i=0; i<sessionInfo.searchPaths.GetCount(); ++i) { wxString dirCmd; wxString path = sessionInfo.searchPaths.Item(i); path.Trim().Trim(false); if ( path.Contains(" ") ) { path.Prepend('"').Append('"'); } dirCmd << "-environment-directory " << path; WriteCommand( dirCmd, NULL ); } return true; }
void DbgGdb::Poke() { static wxRegEx reCommand(wxT("^([0-9]{8})")); //poll the debugger output wxString line; if ( !m_gdbProcess || m_gdbOutputArr.IsEmpty() ) { return; } if (m_debuggeePid == wxNOT_FOUND) { if (GetIsRemoteDebugging()) { m_debuggeePid = m_gdbProcess->GetPid(); } else { std::vector<long> children; ProcUtils::GetChildren(m_gdbProcess->GetPid(), children); std::sort(children.begin(), children.end()); if (children.empty() == false) { m_debuggeePid = children.at(0); } if (m_debuggeePid != wxNOT_FOUND) { wxString msg; msg << wxT("Debuggee process ID: ") << m_debuggeePid; m_observer->UpdateAddLine(msg); } } } while ( DoGetNextLine( line ) ) { // For string manipulations without damaging the original line read wxString tmpline ( line ); StripString( tmpline ); tmpline.Trim().Trim(false); if (m_info.enableDebugLog) { //Is logging enabled? if (line.IsEmpty() == false && !tmpline.StartsWith(wxT(">")) ) { wxString strdebug(wxT("DEBUG>>")); strdebug << line; m_observer->UpdateAddLine(strdebug); } } if (reConnectionRefused.Matches(line)) { StripString(line); #ifdef __WXGTK__ m_consoleFinder.FreeConsole(); #endif m_observer->UpdateAddLine(line); m_observer->UpdateGotControl(DBG_EXITED_NORMALLY); return; } if( tmpline.StartsWith(wxT(">")) ) { // Shell line, probably user command line continue; } if (line.StartsWith(wxT("~")) || line.StartsWith(wxT("&"))) { // lines starting with ~ are considered "console stream" message // and are important to the CLI handler bool consoleStream(false); if ( line.StartsWith(wxT("~")) ) { consoleStream = true; } // Filter out some gdb error lines... if (FilterMessage(line)) { continue; } StripString( line ); // If we got a valid "CLI Handler" instead of writing the output to // the output view, concatenate it into the handler buffer if ( GetCliHandler() && consoleStream ) { GetCliHandler()->Append( line ); } else if ( consoleStream ) { // log message m_observer->UpdateAddLine( line ); } } else if (reCommand.Matches(line)) { //not a gdb message, get the command associated with the message wxString id = reCommand.GetMatch(line, 1); if ( GetCliHandler() && GetCliHandler()->GetCommandId() == id ) { // probably the "^done" message of the CLI command GetCliHandler()->ProcessOutput( line ); SetCliHandler( NULL ); // we are done processing the CLI } else { //strip the id from the line line = line.Mid(8); DoProcessAsyncCommand(line, id); } } else if (line.StartsWith(wxT("^done")) || line.StartsWith(wxT("*stopped"))) { //Unregistered command, use the default AsyncCommand handler to process the line DbgCmdHandlerAsyncCmd cmd(m_observer); cmd.ProcessOutput(line); } else { //Unknow format, just log it if( m_info.enableDebugLog && !FilterMessage(line)) { m_observer->UpdateAddLine(line); } } } }