This is the mail archive of the
gdb@sourceware.org
mailing list for the GDB project.
Re: Interrupting a running program
- From: Roland Puntaier <Roland dot Puntaier at br-automation dot com>
- To: "Roberto Saltini" <house dot 83 at gmail dot com>
- Cc: gdb at sourceware dot org
- Date: Thu, 17 Apr 2008 13:59:08 +0200
- Subject: 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;
}