GDB Ctrl-C Interrupt Fails WORKAROUND

Kyle McKay kylem@qualcomm.com
Thu Jun 15 17:53:00 GMT 2006


On 15 Jun 2006 11:04:56 -0400, Christopher Faylor wrote:
> >Lacking the ability to interrupt a running program severely limits
> >gdb's usefulness.  Fortunately there's a workaround available.
>
> Yep.  Use a console window.

Maybe I haven't been clear.  THIS DOES NOT WORK.

Compile the below hellowin.c program with the m$ visual C compiler.   
Start it up using gdb.  Run it, press CTRL-C, NOTHING HAPPENS.

/* BEGIN hellowin.c */

/* compile with "cl -o hellowin.exe hellowin.c user32.lib" */

#include <windows.h>
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR  
lpCmdLine,
                    int nCmdShow)
{
     MessageBox(NULL, "Hello, world!", "", MB_OK);
     return 0;
}

/* END hellowin.c */

Now if you have such a program compiled with the m$ compiler for  
which you do not have the source and such a program is loading a DLL  
plugin built with cygwin that you're trying to debug then CTRL-C WILL  
NEVER WORK no matter how many console windows you get out.

A console window is also not an option when debugging via a remote X  
session or ssh.

On 15 Jun 2006 10:43:23 -0400 , Igor Peshansky wrote:
> Does "kill -INT <cygwin_pid>" work?

No.

> The workaround would be even better if you didn't need a separate  
> program.
> How about submitting a patch for Cygwin's "kill" (with a new signal,
> SIGDBG or SIGDEBUG)?  CGF, would you consider such a patch?

That would be nice, for both kill and killall.  I provided the very  
simple source code in my original message (and included again in this  
one for your convenience) so anyone could use it right away or make a  
patch if they like.  The relevant code is:

HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD) 
winpid_proc_id);
if (proc != NULL) {DebugBreakProcess(proc); CloseHandle(proc);}

On 15 Jun 2006 01:28:59 -0700 , clayne at anodized dot wrote:
> BTW Kyle, you can extend your program greatly by using process  
> enumeration
> coupled with strcmp on the image name to find the pid based on a  
> string and
> automatically signal it.

Yes, or you could just use the below two-line shell script:

#!/bin/sh
ps -W | grep "$1" | awk '{print $1}' | xargs -n 1 debugbreak

> But honestly I don't think this program should be needed in the  
> first place.

Neither do I.   gdb was not usable for me previously.  The console  
window option DOES NOT WORK when the program loading the cygwin-built  
DLL was compiled with m$ visual C.  It is also a non-solution for ssh  
users and remote X users.

Here is the simple debugbreak.c source again.

Kyle

/* BEGIN debugbreak.c */
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif

#if _WIN32_WINNT < 0x0501
#error Must target Windows NT 5.0.1 or later for DebugBreakProcess
#endif

#include <Windows.h>
#include <stddef.h>
#include <stdlib.h>

/* Compile with this line:

gcc -o debugbreak -mno-cygwin -mthreads debugbreak.c

*/

static char errbuffer[256];

static const char *geterrstr(DWORD errcode)
{
     size_t skip = 0;
     DWORD chars;
     chars = FormatMessage(
         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
         NULL, errcode, 0, errbuffer, sizeof(errbuffer)-1, 0);
     errbuffer[sizeof(errbuffer)-1] = 0;
     if (chars) {
         while (errbuffer[chars-1] == '\r' || errbuffer[chars-1] ==  
'\n') {
             errbuffer[--chars] = 0;
         }
     }
     if (chars && errbuffer[chars-1] == '.') errbuffer[--chars] = 0;
     if (chars >= 2 && errbuffer[0] == '%' && errbuffer[1] >= '0'
         && errbuffer[1] <= '9')
     {
         skip = 2;
         while (chars > skip && errbuffer[skip] == ' ') ++skip;
         if (chars >= skip+2 && errbuffer[skip] == 'i'
             && errbuffer[skip+1] == 's')
         {
             skip += 2;
             while (chars > skip && errbuffer[skip] == ' ') ++skip;
         }
     }
     if (chars > skip && errbuffer[skip] >= 'A' && errbuffer[skip] <=  
'Z') {
         errbuffer[skip] += 'a' - 'A';
     }
     return errbuffer+skip;
}

int main(int argc, char *argv[])
{
     HANDLE proc;
     unsigned proc_id = 0;
     BOOL break_result;

     if (argc != 2) {
         printf("Usage: debugbreak process_id_number\n");
         return 1;
     }
     proc_id = (unsigned) strtol(argv[1], NULL, 0);
     if (proc_id == 0) {
         printf("Invalid process id %u\n", proc_id);
         return 1;
     }
     proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)proc_id);
     if (proc == NULL) {
         DWORD lastError = GetLastError();
         printf("Failed to open process %u\n", proc_id);
         printf("Error code is %lu (%s)\n", (unsigned long)lastError,
             geterrstr(lastError));
         return 1;
     }
     break_result = DebugBreakProcess(proc);
     if (!break_result) {
         DWORD lastError = GetLastError();
         printf("Failed to debug break process %u\n", proc_id);
         printf("Error code is %lu (%s)\n", (unsigned long)lastError,
             geterrstr(lastError));
         CloseHandle(proc);
         return 1;
     }
     printf("DebugBreak sent successfully to process id %u\n", proc_id);
     CloseHandle(proc);
     return 0;
}

/* END debugbreak.c */

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/



More information about the Cygwin mailing list