This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Interrupting a running program


Hi,

gdb-owner@sourceware.org wrote on 2008/04/17 12:10:23:

> Hello,
> I am emulating a program written for an embedded system. This means I
> have a main which loop continuosly.
> Problem with gdb is that if I run the program I lose gdb input console
> and threfor I am not able to interrupt the program execution or insert
> a break point.
> How could I solve my problem?
> Thank you.
> 
> -- 
> Saltini Roberto


I had the same problem. I suppose you use Windows with MinGW. If Yes, then 
the following might help you.
I interpret the CLI, because there is also a console interface and the 
user should get from GDB what he is used, i.e. the CLI output.

(I must say that I did not go into depth to find out how this is possible 
with MI and also I don't know whether MI provides a solution to the 
problem, 
that gdb is not responsive while the inferior is running. Maybe someone 
else can tell you that. 
I did also not test the possibilities of libmigdb about which was posted 
here recently.)

One can send
        GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
to GDB, but this works only from a console application. For this reason I 
made a Console Wrapper that calls the function as a response to a windows 
event.
Futher down are the sources. They are based on sources I found in the 
internet.

I use GDB 6.6 and still had a problem that GDB hanged after Ctrl-C. The 
solution can be found in 
http://www.cygwin.com/ml/gdb/2007-08/msg00181.html.

When GDB is interrupted the gdbserver is abandoned and it must start 
listening again maintaining its internal state and queuing breakpoints 
that might come in the meantime.
When GDB reconnects its remote commands like setting new BPs must be 
executed, but resume on the inferior can only be made if no BPs are 
queued.
Instead queued BPs must be return to GDB.

Hope this helps. Cheers.


Console Wrapper Sources:

#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from 
Windows headers
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>

//this is an adaptation of 
http://www.codeproject.com/threads/RTconsole.asp.

#define SLEEP_TIME 50 // reactivity: sleep time to wait for subprocess to 
output some more data

CONST COORD origin = { 0, 0 };

// we should have been spawned using SW_HIDE, so our console window is not 
visible
int main(int argc, char* argv[])
{
        // get pipe/console to output to
        HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
        DWORD dwDummy;

        if (argc < 4) 
        {
                _tprintf(__TEXT("Usage: %s (InheritableEventHandle for 
CtrlC|0) (InheritableEventHandle for Terminate|0) (CommandLineToSpawn)\n"
), argv[0]);
                return(0);
        }

        TCHAR commandLine[1024] = { 0 };
        for (int x = 3; x < argc; x++) 
        {
                strcat_s(commandLine, argv[x]); 
                strcat_s(commandLine, __TEXT(" ")); 
        }

        HANDLE evtCtrlC = (HANDLE)atol(argv[1]);
        HANDLE evtTerminate = (HANDLE)atol(argv[2]);
        if (evtCtrlC!=0)
                ResetEvent(evtCtrlC);
        if (evtTerminate!=0)
                ResetEvent(evtTerminate);

        // prepare the console window & inherited screen buffer
        SECURITY_ATTRIBUTES sa;
        sa.nLength = sizeof(sa);
        sa.lpSecurityDescriptor = NULL;
        sa.bInheritHandle = TRUE;
        HANDLE hConsole = 
CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,&sa,CONSOLE_TEXTMODE_BUFFER,NULL);
        FillConsoleOutputCharacter(hConsole, '\0', MAXLONG, origin, 
&dwDummy); // fill screen buffer with zeroes
        SetConsoleActiveScreenBuffer(hConsole);

        // start the subprocess
        PROCESS_INFORMATION pi;
        STARTUPINFO si;
        ZeroMemory(&si, sizeof(STARTUPINFO));
        si.cb = sizeof(STARTUPINFO);
        si.dwFlags = STARTF_FORCEOFFFEEDBACK; // we don't want the "app 
starting" cursor
        // all other default options are already good : we want subprocess 
to share the same console and to inherit our STD handles
        if (!CreateProcess(NULL, commandLine, NULL, NULL, TRUE, 0, NULL, 
NULL, &si, &pi))
        {
                CloseHandle(hConsole);
                return -2;
        }
        CloseHandle(pi.hThread); // always close the hThread after a 
CreateProcess

        SetConsoleCtrlHandler(NULL, TRUE);//only let gdb handle CTRL-C

        COORD lastpos = { 0, 0 };
        CONSOLE_SCREEN_BUFFER_INFO csbi;
        bool exitNow = false;
        do
        {
                if (WaitForSingleObject(pi.hProcess, 0) != WAIT_TIMEOUT)
                        exitNow = true; // exit after this last iteration

                // get screen buffer state
                GetConsoleScreenBufferInfo(hConsole, &csbi);

                int lineWidth = csbi.dwSize.X;
 
                if ((csbi.dwCursorPosition.X == lastpos.X) && 
(csbi.dwCursorPosition.Y == lastpos.Y))
                {
                     HANDLE handles[2];
                     handles[0] = evtCtrlC;
                     handles[1] = evtTerminate;
                     DWORD wait_res = 
WaitForMultipleObjects(2,handles,FALSE,SLEEP_TIME);
                     if (wait_res==WAIT_OBJECT_0) 
                     {
                        GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
                     }
                     else if (wait_res==WAIT_OBJECT_0+1)
                     {
                         TerminateProcess(pi.hProcess,0);
                     }
                     else if (wait_res != WAIT_TIMEOUT)
                        Sleep(SLEEP_TIME);
                }
                else
                {
                        DWORD count = 
(csbi.dwCursorPosition.Y-lastpos.Y)*lineWidth+csbi.dwCursorPosition.X-lastpos.X;
                        // read newly output characters starting from last 
cursor position
                        LPTSTR buffer = (LPTSTR) LocalAlloc(0, count*
sizeof(TCHAR));
                        ReadConsoleOutputCharacter(hConsole, buffer, 
count, lastpos, &count);
                        // fill screen buffer with zeroes
                        FillConsoleOutputCharacter(hConsole, '\0', count, 
lastpos, &dwDummy);
 
                        SetThreadPriority(GetCurrentThread(), 
THREAD_PRIORITY_TIME_CRITICAL);
                        lastpos = csbi.dwCursorPosition;
                        GetConsoleScreenBufferInfo(hConsole, &csbi);
                        if ((csbi.dwCursorPosition.X == lastpos.X) && 
(csbi.dwCursorPosition.Y == lastpos.Y))
                        { // text cursor did not move since this 
treatment, hurry to reset it to home
                                SetConsoleCursorPosition(hConsole, 
origin);
                                lastpos = origin;
                        }
                        SetThreadPriority(GetCurrentThread(), 
THREAD_PRIORITY_NORMAL);

                        // scan screen buffer and transmit character to 
real output handle
                        LPTSTR scan = buffer;
                        do
                        {
                                if (*scan)
                                {
                                        DWORD len = 1;
                                        while (scan[len] && (len < count))
                                                len++;
                                        WriteFile(hOutput, scan, len, 
&dwDummy, NULL);
                                        scan += len;
                                        count -= len;
                                }
                                else
                                {
                                        DWORD len = 1;
                                        while (!scan[len] && (len < 
count))
                                                len++;
                                        scan += len;
                                        count -= len;
                                        len = (len+lineWidth-1)/lineWidth;
                                        for (;len;len--)
                                                WriteFile(hOutput, "\r\n", 
2, &dwDummy, NULL);
                                }
                        } while (count);
                        //FlushFileBuffers(hOutput); // seems unnecessary
                        LocalFree(buffer);
                }
                // loop until end of subprocess
        } while (!exitNow);

        SetConsoleCtrlHandler(NULL, FALSE);
 
        CloseHandle(hConsole);
 
        // release subprocess handle
        DWORD exitCode;
        if (!GetExitCodeProcess(pi.hProcess, &exitCode))
                exitCode = -3;
        CloseHandle(pi.hProcess); 
        return exitCode;
}





Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]