News:

Accounts with zero posts and zero activity during the last months will be deleted periodically to fight SPAM!

Main Menu

Stoppable gdb for MacOSX - when?

Started by bnilsson, February 09, 2007, 11:02:09 PM

Previous topic - Next topic

bnilsson

When can we expect a stoppable GDB process from within CB for MacOSX?
I will have to put CB aside and go back to CodeWarrior until this is working.


afb

I'm not sure what the timeline of the wxExecute replacement is... ?

If you can come up with a PID workaround for Mac OS X before then,
it might be doable to add that in a __WXMAC__ block in the meantime.
But the default wxMac implementation will return -1 for the process ID,
regardless of what the real number was when invoking the gdb backend.

Pecan

Quote from: afb on February 10, 2007, 11:20:47 AM
I'm not sure what the timeline of the wxExecute replacement is... ?

If you can come up with a PID workaround for Mac OS X before then,
it might be doable to add that in a __WXMAC__ block in the meantime.
But the default wxMac implementation will return -1 for the process ID,
regardless of what the real number was when invoking the gdb backend.


Something like the following might work. I issue a "ps x" command and capture the output, then scan the output for the program/pid of interest.
In this particular code, I'm looking for the tty (second ps output field) of the sleep command which was started by a "xterm -e sleep 80000" command.

+// ----------------------------------------------------------------------------
+wxString GDB_driver::GetConsoleTty(int ConsolePid)
+// ----------------------------------------------------------------------------
+{
+    // execute the ps -x command  and read PS output to get the /dev/tty field
+
+ unsigned long ConsPid = ConsolePid;
+ wxString psCmd;
+ wxArrayString psOutput;
+ wxArrayString psErrors;
+
+ psCmd << wxT("ps x");
+    m_pDBG->Log(wxString::Format( _("Executing: %s"), psCmd.c_str()) );
+ int result = wxExecute(psCmd, psOutput, psErrors, wxEXEC_SYNC);
+ psCmd.Clear();
+ if (result != 0)
+ {   psCmd << wxT("Result of ps x:") << result;
+        m_pDBG->Log(wxString::Format( _("Execution Error:"), psCmd.c_str()) );
+        return wxEmptyString;
+ }
+
+    wxString ConsTtyStr;
+    wxString ConsPidStr;
+    ConsPidStr << ConsPid;
+    //find task with our unique sleep time
+    wxString uniqueSleepTimeStr;
+    uniqueSleepTimeStr << wxT("sleep ") << 80000 + ::wxGetProcessId();
+    // search the output of "ps pid" command
+    int knt = psOutput.GetCount();
+    for (int i=knt-1; i>-1; --i)
+    {   psCmd = psOutput.Item(i);
+        m_pDBG->Log(wxString::Format( _("PS result: %s"), psCmd.c_str()) );
+        // find the pts/# or tty/# or whatever it's called
+        // by seaching the output for our pid in character
+        // The output of ps looks like:
+        //   PID TTY      STAT   TIME COMMAND
+        // 8779 pts/3    Ss+    0:00 sleep 600000
+        //if (psCmd.Contains(ConsPidStr))
+        if (psCmd.Contains(uniqueSleepTimeStr))
+        {   ConsTtyStr = psCmd.Mid( ConsPidStr.Length()+2);
+            ConsTtyStr = wxT("/dev/")+ConsTtyStr.BeforeFirst(' ');
+            m_pDBG->Log(wxString::Format( _("TTY is[%s]"), ConsTtyStr.c_str()) );
+            return ConsTtyStr;
+        }//if
+    }//for
+
+    knt = psErrors.GetCount();
+    for (int i=0; i<knt; ++i)
+        m_pDBG->Log(wxString::Format( _("PS Error:%s"), psErrors.Item(i).c_str()) );
+    return wxEmptyString;
+}


bnilsson

#3
I wonder...

After a debug session ends, I find the following process with 'ps x':

16989  ??  Z      0:00.00 (gdb-powerpc-appl)

Is this a candidate for the process to be stopped?
If I quit CB it disappears, and it does not appear again until CB is restarted and a new debug session is started and terminated.
I cannot kill it by 'kill -9 16989', nothing happens.
So I guess trying to do the same from within the program would not work either.
Can it be stopped by any other method?


bnilsson

Some more:

When waiting at a breakpoint, 'ps x' shows

18159  ??  S      0:02.62 /usr/libexec/gdb/gdb-powerpc-apple-darwin -nx -fullname -quiet -args bin/Debug/wxProject.app/Contents/MacOS/wxProject

After the debugging is terminated, either by Continue or Stop Debugger, 'ps x' shows

18159  ??  Z      0:00.00 (gdb-powerpc-appl)

apparently a zombie process that I cannot get rid of by command line.

If I do 'kill -9' on the process before it has become a zombie (standing at the breakpoint), it immidiately becomes one (a zombie).
Continuing the debugging after that crashes CB altogether, which is not strange.

Any suggestions would be appreciated.


afb

Since it seems 1.0 didn't happen, I started building for Mac OS X again. (10.4 only at the moment)

Released rev 3656 to BerliOS, but doesn't included patches for Terminal.app or any new for GDB...
I'll see if I can integrate the xterm -> Terminal.app, and maybe something like Pecan's "ps" code.

Pecan

#6
Quote from: afb on March 02, 2007, 10:53:48 AM
Since it seems 1.0 didn't happen, I started building for Mac OS X again. (10.4 only at the moment)

Released rev 3656 to BerliOS, but doesn't included patches for Terminal.app or any new for GDB...
I'll see if I can integrate the xterm -> Terminal.app, and maybe something like Pecan's "ps" code.

Have a look at the following:
1) provides a xterm/terminal for the debuggee
2) fixes crashes during gdb termination
3) allows user to stop debuggee in I/O or loop. User has to hit the stop button twice. Once to stop gdb, then again to kill the debuggee.

I haven't yet figured out a fix for crashes when deleting a breakpoint.


Index: debuggerdriver.cpp
===================================================================
--- debuggerdriver.cpp (revision 3654)
+++ debuggerdriver.cpp (working copy)
@@ -5,6 +5,7 @@
DebuggerDriver::DebuggerDriver(DebuggerGDB* plugin)
     : m_pDBG(plugin),
     m_ProgramIsStopped(true),
+    m_IsStarted(false), //(pecan 2007/3/01)
     m_ChildPID(0),
     m_pBacktrace(0),
     m_pDisassembly(0),
Index: debuggergdb.cpp
===================================================================
--- debuggergdb.cpp (revision 3654)
+++ debuggergdb.cpp (working copy)
@@ -227,12 +227,18 @@
     m_pBreakpointsWindow(0),
     m_pExamineMemoryDlg(0),
     m_pThreadsDlg(0),
-    m_pProject(0)
+    m_pProject(0),
+    m_GDBInputKnt(0)
{
     if(!Manager::LoadResource(_T("debugger.zip")))
     {
         NotifyMissingFile(_T("debugger.zip"));
     }
+    // vars for Linux console //(pecan 2007/2/06)
+    m_bIsConsole = false;
+    m_nConsolePid = 0;
+    m_ConsoleTty = wxEmptyString;
+
}

DebuggerGDB::~DebuggerGDB()
@@ -789,7 +795,11 @@
{
     return !m_State.HasDriver() || m_State.GetDriver()->IsStopped();
}
-
+bool DebuggerGDB::IsStarted() //(pecan 2007/3/01)
+{
+    if (!m_State.HasDriver()) return false;
+    return m_State.GetDriver()->IsStarted();
+}
int DebuggerGDB::Debug()
{
     // if already running, return
@@ -1021,6 +1031,21 @@
     m_State.GetDriver()->Prepare(target && target->GetTargetType() == ttConsoleOnly);
     m_State.ApplyBreakpoints();

+   #ifdef __WXGTK__    //(pecan 2007/2/05)
+    // create xterm and issue tty "/dev/pts/#" to GDB where
+    // # is the tty for the newly created xterm
+    m_bIsConsole = (target && target->GetTargetType() == ttConsoleOnly);
+    if (m_bIsConsole)
+    {
+        if (RunNixConsole() > 0 )
+        {   wxString gdbTtyCmd;
+            gdbTtyCmd << wxT("tty ") << m_ConsoleTty;
+            m_State.GetDriver()->QueueCommand(new DebuggerCmd(m_State.GetDriver(), gdbTtyCmd, true));
+            DebugLog(wxString::Format( _("Queued:[%s]"), gdbTtyCmd.c_str()) );
+        }
+    }//if
+   #endif//def __WXGTK__
+
     // Don't issue 'run' if attaching to a process (Bug #1391904)
     if (m_PidToAttach == 0)
         m_State.GetDriver()->Start(m_BreakOnEntry);
@@ -1503,12 +1528,24 @@

void DebuggerGDB::Stop()
{
+    // m_Process is PipedProcess I/O; m_Pid is debugger pid
     if (m_pProcess && m_Pid)
     {
-        if (IsStopped())
+        //-if (IsStopped()) //no Driver || m_IsStopped
+        //-if (IsStopped() && IsStarted() ) //(pecan 2007/3/01)
+        DebugLog(wxString::Format(wxT("IsStopped:[%d] IsStarted:[%d]"),IsStopped(),IsStarted()));
+        if (IsStarted() ) //(pecan 2007/3/01)
         {
             RunCommand(CMD_STOP);
             m_pProcess->CloseOutput();
+           #ifdef __WXGTK__
+            // kill any linux console //(pecan 2007/2/06)
+            if ( m_bIsConsole && (m_nConsolePid > 0) )
+            {
+                ::wxKill(m_nConsolePid);
+                m_nConsolePid = 0;
+            }
+           #endif
         }
         else
         {
@@ -1521,7 +1558,8 @@
                     _("Debug"), wxOK | wxICON_EXCLAMATION);
             else
         #endif
-            wxKill(pid, wxSIGINT);
+            if (pid > 0)
+                wxKill(pid, wxSIGINT);
         #else
             m_pProcess->CloseOutput();
             wxKillError err = m_pProcess->Kill(m_Pid, wxSIGKILL);
@@ -1909,12 +1947,19 @@

void DebuggerGDB::OnGDBOutput(wxCommandEvent& event)
{
+    ++m_GDBInputKnt;
     wxString msg = event.GetString();
     if (!msg.IsEmpty())
     {
//        Manager::Get()->GetMessageManager()->Log(m_PageIndex, _T("O>>> %s"), msg.c_str());
         ParseOutput(msg);
     }
+    --m_GDBInputKnt;
+    if ( (not m_pProcess) && m_State.HasDriver() && (m_GDBInputKnt==0) )
+    {   m_State.StopDriver();
+        DebugLog(wxT("OnGDBOutput() closed m_State.Driver"));
+    }
+
}

void DebuggerGDB::OnGDBError(wxCommandEvent& event)
@@ -1937,7 +1982,14 @@
//    m_pProcess = 0L;

     ClearActiveMarkFromAllEditors();
-    m_State.StopDriver();
+    // closing the GDB driver here causes crashes because input msgs
+    // are still queued up in OnGDBOutput/ParseOutput //(pecan 2007/2/09)
+    //-m_State.StopDriver();
+    if ( (not m_pProcess) && m_State.HasDriver() && (m_GDBInputKnt==0) )
+    {   m_State.StopDriver();
+        DebugLog(wxT("OnGDBTerminate() closed m_State.Driver"));
+    }
+
     Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("Debugger finished with status %d"), m_LastExitCode);

     if (m_NoDebugInfo)
@@ -2198,3 +2250,95 @@
{
     Configure();
}
+// ----------------------------------------------------------------------------
+int DebuggerGDB::RunNixConsole()
+// ----------------------------------------------------------------------------
+{
+    // start the xterm and put the shell to sleep with -e sleep 80000
+    // fetch the xterm tty so we can issue to gdb a "tty /dev/pts/#"
+    // redirecting program stdin/stdout/stderr to the xterm console.
+
+  #ifndef __WXMSW__
+    wxString cmd;
+    wxString title = wxT("Program Console");
+    m_nConsolePid = 0;
+    // for non-win platforms, use m_ConsoleTerm to run the console app
+    wxString term = Manager::Get()->GetConfigManager(_T("app"))->Read(_T("/console_terminal"), DEFAULT_CONSOLE_TERM);
+    //term.Replace(_T("$TITLE"), _T("'") + _T("*nixConsole") + _T("'"));
+    term.Replace(_T("$TITLE"), _T("'") + title + _T("'"));
+    cmd << term << _T(" ");
+    cmd << wxT("sleep ");
+    cmd << 80000 + ::wxGetProcessId(); //make a unique sleep command
+
+    Manager::Get()->GetMacrosManager()->ReplaceEnvVars(cmd);
+    //Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("Executing: %s"), cmd.c_str() );
+    DebugLog(wxString::Format( _("Executing: %s"), cmd.c_str()) );
+    //start xterm -e sleep {some unique # of seconds}
+    m_nConsolePid = wxExecute(cmd, wxEXEC_ASYNC);
+    if (m_nConsolePid <= 0) return -1;
+
+    // Issue the PS command with to get the /dev/tty device name
+    // First, wait for the xterm to settle down, else PS won't see the sleep task
+    Manager::Yield();
+    ::wxSleep(1);
+    m_ConsoleTty = GetConsoleTty(m_nConsolePid);
+    if (not m_ConsoleTty.IsEmpty() )
+        return m_nConsolePid;
+    // failed to find the console tty
+    DebugLog( wxT("Console Execution error:failed to find console tty."));
+    ::wxKill(m_nConsolePid);
+    m_nConsolePid = 0;
+  #endif//ndef __WWXMSW__
+    return -1;
+}
+// ----------------------------------------------------------------------------
+wxString DebuggerGDB::GetConsoleTty(int ConsolePid)
+// ----------------------------------------------------------------------------
+{
+    // execute the ps -x command  and read PS output to get the /dev/tty field
+
+ unsigned long ConsPid = ConsolePid;
+ wxString psCmd;
+ wxArrayString psOutput;
+ wxArrayString psErrors;
+
+ psCmd << wxT("ps x");
+    DebugLog(wxString::Format( _("Executing: %s"), psCmd.c_str()) );
+ int result = wxExecute(psCmd, psOutput, psErrors, wxEXEC_SYNC);
+ psCmd.Clear();
+ if (result != 0)
+ {   psCmd << wxT("Result of ps x:") << result;
+        DebugLog(wxString::Format( _("Execution Error:"), psCmd.c_str()) );
+        return wxEmptyString;
+ }
+
+    wxString ConsTtyStr;
+    wxString ConsPidStr;
+    ConsPidStr << ConsPid;
+    //find task with our unique sleep time
+    wxString uniqueSleepTimeStr;
+    uniqueSleepTimeStr << wxT("sleep ") << 80000 + ::wxGetProcessId();
+    // search the output of "ps pid" command
+    int knt = psOutput.GetCount();
+    for (int i=knt-1; i>-1; --i)
+    {   psCmd = psOutput.Item(i);
+        DebugLog(wxString::Format( _("PS result: %s"), psCmd.c_str()) );
+        // find the pts/# or tty/# or whatever it's called
+        // by seaching the output or out "ps x" command.
+        // The output of ps looks like:
+        //   PID TTY      STAT   TIME COMMAND
+        // 8779 pts/3    Ss+    0:00 sleep 600000
+        //if (psCmd.Contains(ConsPidStr))
+        if (psCmd.Contains(uniqueSleepTimeStr))
+        {   ConsTtyStr = psCmd.Mid( ConsPidStr.Length()+2);
+            ConsTtyStr = wxT("/dev/")+ConsTtyStr.BeforeFirst(' ');
+            DebugLog(wxString::Format( _("TTY is[%s]"), ConsTtyStr.c_str()) );
+            return ConsTtyStr;
+        }//if
+    }//for
+
+    knt = psErrors.GetCount();
+    for (int i=0; i<knt; ++i)
+        DebugLog(wxString::Format( _("PS Error:%s"), psErrors.Item(i).c_str()) );
+    return wxEmptyString;
+}
Index: gdb_driver.h
===================================================================
--- gdb_driver.h (revision 3654)
+++ gdb_driver.h (working copy)
@@ -86,24 +86,24 @@

         // Seems to be intended to allow step before program has started.
         // Was always false.  HC changed to take value from DebuggerGDB::m_BreakOnEntry.
-        bool m_BreakOnEntry;
-   
+        bool m_BreakOnEntry;
+
         // Seems to be used to issue a InfoProgram command, then continue
         // True after first "Start()", until first break
-        bool m_ManualBreakOnEntry;
+        bool m_ManualBreakOnEntry;

- // Program is "running": after a "run" or a "start", and before "kill" or a "quit"
- bool m_IsStarted;
-
+// // Program is "running": after a "run" or a "start", and before "kill" or a "quit"
+// bool m_IsStarted;
+
         // cursor update flags
         bool m_needsUpdate;
         bool m_forceUpdate;
-
+
         // GDB version
         long m_GDBVersionMajor;
         long m_GDBVersionMinor;
         wxString flavour;
-
+
}; // GDB_driver

#endif // GDB_DRIVER_H
Index: debuggerdriver.h
===================================================================
--- debuggerdriver.h (revision 3654)
+++ debuggerdriver.h (working copy)
@@ -132,6 +132,7 @@

         /** Is the program stopped? */
         virtual bool IsStopped(){ return m_ProgramIsStopped; }
+        virtual bool IsStarted(){ return m_IsStarted; } //(pecan 2007/3/01)
         /** Get debugger cursor. */
         virtual const Cursor& GetCursor() const { return m_Cursor; }
         /** Set child PID (debuggee's). Usually set by debugger commands. */
@@ -162,6 +163,11 @@

         // cursor related
         bool m_ProgramIsStopped;
+        //(pecan 2007/3/01)
+        // moved here from gdb_driver.h
+ // Program is "running": after a "run" or a "start", and before "kill" or a "quit"
+ bool m_IsStarted;
+        ;
         wxString m_LastCursorAddress;
         Cursor m_Cursor;

Index: debuggergdb.h
===================================================================
--- debuggergdb.h (revision 3654)
+++ debuggergdb.h (working copy)
@@ -110,6 +110,7 @@
         int LaunchProcess(const wxString& cmd, const wxString& cwd);
         wxString GetDebuggee(ProjectBuildTarget* target);
         bool IsStopped();
+        bool IsStarted(); //(pecan 2007/3/01)

         void OnUpdateUI(wxUpdateUIEvent& event);
         void OnDebug(wxCommandEvent& event);
@@ -204,7 +205,15 @@
         SearchDirsMap m_SearchDirs;

         int m_HookId; // project loader hook ID
+        int m_GDBInputKnt;

+        // Linux console support
+        int      RunNixConsole();
+        wxString GetConsoleTty(int ConsolePid);
+        bool     m_bIsConsole;
+        int      m_nConsolePid;
+        wxString m_ConsoleTty;
+
DECLARE_EVENT_TABLE()
};

Index: gdb_driver.cpp
===================================================================
--- gdb_driver.cpp (revision 3654)
+++ gdb_driver.cpp (working copy)
@@ -55,7 +55,7 @@
     : DebuggerDriver(plugin),
     m_BreakOnEntry(false),
     m_ManualBreakOnEntry(false),
- m_IsStarted(false),
+// m_IsStarted(false), //(pecan 2007/3/01)
     m_GDBVersionMajor(0),
     m_GDBVersionMinor(0)
{


afb

#7
Thanks, maybe parts of it can be adapted...

I'm using: /bin/ps -o ppid,pid,command

afb



Pecan

#10
Quote from: afb on March 02, 2007, 04:42:35 PM
Here is a first hack: http://www.algonet.se/~afb/wx/codeblocks-macgdbpid.patch

"if (psLine.StartsWith(mypidStr) " may not work.
I've noticed that when the output has longer and shorter length pids,
some pids may have a variable number of blanks before the pid.

And thanks for the "ps -o" idea. I've found that "ps x -o" is safer though. It appears that, on ubuntu at least, some output is skipped on "ps -o" and I miss finding the correct TTY for the console.




afb

#11
Quote from: Pecan on March 02, 2007, 07:04:37 PM
"if (psLine.StartsWith(mypidStr) " may not work.
I've noticed that when the output has longer and shorter length pids,
some pids may have a variable number of blanks before the pid.

You are right, it does - needs to be trimmed first, thanks!

Edit: patch updated