This is the mail archive of the cygwin@cygwin.com 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]

Solved, sort of: dumper 1.10 not giving expected stack trace in gdb


Hi all,

I have a suboptimal solution for getting a good stack trace in gdb.

First, DO NOT use dumper as the error_start program. Set CYGWIN='error_start=C:\windows-path-to-gdb\gdb.exe'.

When an abort occurs, gdb will start.

Next, do info thread to find all the threads. Chances are the aborted thread is thread 1. Then do thread 1 to change thread context to the right one:

(gdb) info thread
* 3 thread 3496.0xf54  0x77f75a59 in ntdll!DbgUiConnectToDbg ()
  from /cygdrive/c/WINDOWS/System32/ntdll.dll
 2 thread 3496.0xd6c  0x7ffe0304 in ?? ()
 1 thread 3496.0xe24  0x7ffe0304 in ?? ()
(gdb) thread 1
[Switching to thread 1 (thread 3496.0xe24)]#0  0x7ffe0304 in ?? ()
(gdb) bt
#0  0x7ffe0304 in ?? ()
#1  0x77f5c534 in ntdll!ZwWaitForSingleObject ()
  from /cygdrive/c/WINDOWS/System32/ntdll.dll
#2  0x77e7a62d in WaitForSingleObjectEx ()
  from /cygdrive/c/WINDOWS/system32/KERNEL32.DLL
#3  0x00000778 in ?? ()

Note that the Backtrace Sucks(TM).

Next, take a look at 64 bytes of stack using x/64x $esp:

(gdb) x/64x $esp
0x22fca4:       0x77f5c534      0x77e7a62d      0x00000778      0x00000000
0x22fcb4:       0x0022fccc      0x00000778      0x0000ea60      0x0022fd30
0x22fcc4:       0x77f7d417      0x0022fccc      0xdc3cba00      0xffffffff
0x22fcd4:       0x7ffdf000      0x7ffde000      0x00000014      0x00000001
0x22fce4:       0x00000000      0x00000000      0x00000010      0x0022fcb8
0x22fcf4:       0x0022fd4c      0x0022ff28      0x77e94809      0x77e83ae0
0x22fd04:       0x00000000      0x0022fd58      0x77e7ac21      0x00000778
0x22fd14:       0x0000ea60      0x00000000      0x61073611      0x00000778
0x22fd24:       0x0000ea60      0xffffffff      0x77f59037      0x00000000
0x22fd34:       0x00240000      0x00000000      0x00244348      0x0022fe2c
0x22fd44:       0x0000c000      0x77f5c014      0x00000000      0x00000001
0x22fd54:       0x00000780      0x0022fde8      0x61071c99      0x00000780
0x22fd64:       0x00000001      0x00000000      0x00000000      0x00000000
0x22fd74:       0x0022fd90      0x0000003f      0x00401324      0x0000c000
0x22fd84:       0x0022fd90      0x0000003f      0x00000000      0x61616161
0x22fd94:       0x61416141      0x61616161      0x61126ac0      0x61616161

Also take a look at the current frame pointer via p/x $esp:

(gdb) p/x $ebp
$1 = 0x22fd08

The format of a frame in the stack is as follows:

Current function local vars
    Previous frame pointer <- $ebp
            Return address
     Current function args

We're going to simulate a function return by changing the frame pointer to the previous frame pointer, and the instruction pointer to the return address. In the stack dump, look at what the stack contains at the address of $ebp and $ebp+4:

(gdb) p/x *(int *)$ebp
$2 = 0x22fd58

(gdb) p/x *(int *)($ebp+4)
$3 = 0x77e7ac21

So to simulate a function return, we have to set $ebp to the first value, and $eip to the second value:

(gdb) set $ebp=0x22fd58
(gdb) set $eip=0x77e7ac21
(gdb) bt
#0  0x77e7ac21 in WaitForSingleObject ()
  from /cygdrive/c/WINDOWS/system32/KERNEL32.DLL
#1  0x77f5c534 in ntdll!ZwWaitForSingleObject ()
  from /cygdrive/c/WINDOWS/System32/ntdll.dll
#2  0x77e7a62d in WaitForSingleObjectEx ()
  from /cygdrive/c/WINDOWS/system32/KERNEL32.DLL
#3  0x00000778 in ?? ()

Still, the Backtrace Sucks(TM). So we just repeat the procedure of simulating a function return to move up a frame:

(gdb) p/x *(int *)$ebp
$4 = 0x22fde8
(gdb) p/x *(int *)($ebp+4)
$5 = 0x61071c99
(gdb) set $ebp=0x22fde8
(gdb) set $eip=0x61071c99
(gdb) bt
#0  0x61071c99 in sigpending () from /usr/bin/cygwin1.dll
#1  0x6106f232 in sigprocmask () from /usr/bin/cygwin1.dll
#2  0x6106f3b0 in kill () from /usr/bin/cygwin1.dll
#3  0x6106f2fc in raise () from /usr/bin/cygwin1.dll
#4  0x6106f965 in cygwin1!abort () from /usr/bin/cygwin1.dll
#5  0x00401073 in main () at t.c:5

At last! A backtrace that does not suck. This is the backtrace we're looking for.

NOTE: You cannot use dumper.exe! The reason for this is that gdb will refuse to set registers unless it is running a process. Just looking at a core file is not the same as running a process. Ideally, there should be a way to change the frame without having to run a process, but I haven't found it. That's why you have to run gdb instead of dumper, so that gdb can attach to a running process.

I have also found that when you quit from gdb, the cygwin shell of the original program will hang. You have to three-finger salute your way out of the shell.

For these reasons, I'm labelling my solution as suboptimal.

--Rob


-- 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]