From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 14415 invoked by alias); 20 Jul 2009 11:18:10 -0000 Received: (qmail 14405 invoked by uid 22791); 20 Jul 2009 11:18:09 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL,BAYES_00,SARE_MSGID_LONG40,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mail-bw0-f205.google.com (HELO mail-bw0-f205.google.com) (209.85.218.205) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 20 Jul 2009 11:18:02 +0000 Received: by bwz1 with SMTP id 1so1786978bwz.24 for ; Mon, 20 Jul 2009 04:17:59 -0700 (PDT) MIME-Version: 1.0 Received: by 10.103.198.20 with SMTP id a20mr2167024muq.63.1248088678609; Mon, 20 Jul 2009 04:17:58 -0700 (PDT) Date: Mon, 20 Jul 2009 11:18:00 -0000 Message-ID: <74fef6df0907200417q503ca457m642ebab9d953edb@mail.gmail.com> Subject: _r_debug_state getting screwed on x86_64 ? From: Mathieu Lacage To: gdb@sourceware.org Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-IsSubscribed: yes Mailing-List: contact gdb-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-owner@sourceware.org X-SW-Source: 2009-07/txt/msg00135.txt.bz2 hi, I have an adhoc _r_debug_state function in my elf loader: static void _r_debug_state (void) { // GDB // the debugger will put a breakpoint here. } on x86_64, this code compiles to: 0000000000007564 <_r_debug_state>: 7564: 55 push %rbp 7565: 48 89 e5 mov %rsp,%rbp 7568: c9 leaveq 7569: c3 retq I invoke this function to notify gdb that I do have a valid linkmap ready to be parsed and I get the following events: 34 g_vdl.breakpoint (); (gdb) disas $rip $rip+20 Dump of assembler code from 0x7ffff7df75dc to 0x7ffff7df75f0: 0x00007ffff7df75dc : mov 0x206b5d(%rip),%rax # 0x7ffff7ffe140 0x00007ffff7df75e3 : mov 0x10(%rax),%rax 0x00007ffff7df75e7 : callq *%rax 0x00007ffff7df75e9 : leaveq 0x00007ffff7df75ea : retq 0x00007ffff7df75eb: nop 0x00007ffff7df75ec : push %rbp 0x00007ffff7df75ed : mov %rsp,%rbp End of assembler dump. (gdb) ni 0x00007ffff7df75e3 34 g_vdl.breakpoint (); (gdb) 0x00007ffff7df75e7 34 g_vdl.breakpoint (); (gdb) x/1gx $rsp 0x7fffffffe018: 0x00007fffffffe1a8 ----------- Ok, before calling, the stack contains this value for a local variable (gdb) disas _r_debug_state Dump of assembler code for function _r_debug_state: 0x00007ffff7df7564 <_r_debug_state+0>: push %rbp 0x00007ffff7df7565 <_r_debug_state+1>: mov %rsp,%rbp 0x00007ffff7df7568 <_r_debug_state+4>: leaveq 0x00007ffff7df7569 <_r_debug_state+5>: retq End of assembler dump. (gdb) si warning: Temporarily disabling breakpoints for unloaded shared library "../ldso" Stopped due to shared library event -------------- Ok, now, I did hit the breakpoint at the start of _r_debug_state and gdb has indeed read the linkmap --------------- (gdb) 0x00007ffff7df7565 in _r_debug_state () at gdb.c:9 9 { (gdb) disas _r_debug_state Dump of assembler code for function _r_debug_state: 0x00007ffff7df7564 <_r_debug_state+0>: int3 0x00007ffff7df7565 <_r_debug_state+1>: mov %rsp,%rbp 0x00007ffff7df7568 <_r_debug_state+4>: leaveq 0x00007ffff7df7569 <_r_debug_state+5>: retq End of assembler dump. (gdb) ------------ and, yes, we can see the gdb int3 instruction in the function. ------------- (gdb) p $rsp $3 = (void *) 0x7fffffffe010 (gdb) x/1gx $rsp 0x7fffffffe010: 0x00007ffff7df75e9 ------------- yep, the stack has grown downward by 8 bytes: we can see the return address pushed there (gdb) ni 0x00007ffff7df7565 in _r_debug_state () at gdb.c:9 9 { --------------- Ok, I have now executed theoretically the initial push %rbp (gdb) x/1gx $rsp 0x7fffffffe010: 0x00007ffff7df75e9 -------------- but my stack pointer did not change ? (gdb) ni 12 } gdb) p $rbp $5 = (void *) 0x7fffffffe010 ------------ %rbp before executing the leaveq (gdb) ni 0x00007ffff7df7569 in _r_debug_state () at gdb.c:12 12 } (gdb) p $rbp $6 = (void *) 0x7ffff7df75e9 ------------ %rbp has been changed, but, well, it's been set to the return _address_ pushed by the initial call, not to the value which should have been saved by push %rbp (gdb) si 0x00007fffffffe1a8 in ?? () (gdb) ------------ and now, the code jumps into what it thinks is the return address but it's garbage :/ The problem appears to be that the initial push %rbp which is the first instruction of the function is not being really executed so, when we leave the body of the function, leaveq pops the return value instead of poping the frame pointer. I never observed this problem on ia32 systems so, I wonder what could be wrong here: could it be really that gdb did clobber the initial push %rbp in _r_debug_state with an int3 and never executed the original push ? Mathieu -- Mathieu Lacage