This is the mail archive of the cygwin mailing list for the Cygwin 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: GDB Ctrl-C Interrupt Fails WORKAROUND


On 15 Jun 2006 13:57:14 -0400, Christopher Faylor wrote:
On Cygwin, gdb is the debugger for programs produced by gcc.  You are
not going to be able to read many (any?) symbols for programs produced
by other compilers so there really isn't much of a reason to use gdb
to debug non-gcc-produced programs.

Apparently you did not see my previous comments about this:


On 15 Jun 2006 10:38:57 -0700, Kyle McKay wrote:
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.

DLLs built with gcc cannot be interrupted with CTRL-C when they are loaded by programs built with other compilers.


In any event, at least we're getting details now beyond the "CTRL-C
doesn't work with gdb".

Or these comments about using a console window:


On 15 Jun 2006 10:38:57 -0700, Kyle McKay wrote:
It is also a non-solution for ssh users and remote X users.

CTRL-C also appears to be used by the X windows ddd break button. Doesn't work there either.


However, in all these cases the debugbreak (debugbreak.c) utility can provide a usable, if awkward, workaround.

For example, build the loopdll.dll and runloop.exe from the following sources using the gcc and m$ compilers as indicated:

/* BEGIN loopdll.c */
/* Compile with cygwin gcc -o loopdll.dll -g -mno-cygwin -mthreads - mdll loopdll.c */
#include <Windows.h>
extern __declspec(dllexport) void Looper(void);
__declspec(dllexport) void Looper(void)
{
for (;;)
{
/* do nothing except eat CPU */
}
}
/* END loopdll.c */


/* BEGIN runloop.c */
#include <Windows.h>
#include <stddef.h>
/* Compile with m$ cl -o runloop.exe runloop.c */
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nCmdShow)
{
    FARPROC loopfunc;
    HMODULE lib = LoadLibrary("loopdll.dll");
    if (lib != NULL) {
        loopfunc = GetProcAddress(lib, "Looper");
        if (loopfunc != NULL) {
            (*((void(*)())loopfunc))();
        }
        FreeLibrary(lib);
    }
    return 0;
}
/* END runloop.c */

Then type gdb runloop.exe (making sure loopdll.dll is located in the current directory along with runloop.exe) followed by run. Do this from a CONSOLE window without tty set. Now try CTRL-C. Doesn't work. Build the debugbreak utility and then type this at a cygwin bash prompt while gdb is stuck:

./debugbreak `ps -W | grep runloop | awk '{print $1}'`

gdb will regain control. Type "list Looper" or "break Looper" and you will see that indeed you can use gdb to debug with symbols in this case, set breakpoints, etc. However CTRL-C is useless for interrupting the running program.

This is not a contrived example. It mirrors the situation found when attempting to use the cygwin environment to build DLL plugins (and debug them) for commercial windows applications for which you do not have the source and which were not built using cygwin. (Note that this example can also be used to demonstrate that having "set stop-on- solib-events 1" active in gdb before typing run does NOT cause gdb to regain control when loopdll.dll is first loaded.)

Kyle

P.S. (Here is debugbreak.c again to build debugbreak for use with this example:)

/* 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/


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