From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10663 invoked by alias); 16 Mar 2012 12:02:32 -0000 Received: (qmail 10437 invoked by uid 22791); 16 Mar 2012 12:02:30 -0000 X-SWARE-Spam-Status: No, hits=-5.8 required=5.0 tests=AWL,BAYES_00,KAM_STOCKGEN,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,TW_BJ,TW_DB,TW_FD,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 16 Mar 2012 12:02:13 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q2GC2CA6027816 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 16 Mar 2012 08:02:12 -0400 Received: from host2.jankratochvil.net (ovpn-116-16.ams2.redhat.com [10.36.116.16]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id q2GC289Q006956 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO) for ; Fri, 16 Mar 2012 08:02:11 -0400 Date: Fri, 16 Mar 2012 12:02:00 -0000 From: Jan Kratochvil To: gdb-patches@sourceware.org Subject: [patch] Stop runaway unwinding on stripped executables Message-ID: <20120316120207.GA10006@host2.jankratochvil.net> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2012-03/txt/msg00602.txt.bz2 Hi, this situation came from the real world out there: # inferior has symbols echo 'main(){pause();}'|gcc -x c -; ./a.out& gdb -p $! -ex bt #0 0x00007f9dc4d4f0d0 in __pause_nocancel () at ../sysdeps/unix/syscall-template.S:82 #1 0x00000000004004ea in main () (gdb) q PROBLEM: -------- # -s: inferior has no symbols echo 'main(){pause();}'|gcc -x c - -s; ./a.out& gdb -p $! -ex bt #0 0x00007f274fd5a0d0 in __pause_nocancel () at ../sysdeps/unix/syscall-template.S:82 #1 0x00000000004004ea in ?? () #2 0x00007f274fcc1735 in __libc_start_main (main=0x4004dc, ...) at libc-start.c:226 #3 0x00000000004003f9 in ?? () #4 0x00007fffdbdec7a8 in ?? () #5 0x000000000000001c in ?? () #6 0x0000000000000001 in ?? () #7 0x00007fffdbdede72 in ?? () #8 0x0000000000000000 in ?? () (gdb) q --- In reality this backtrace can be much longer confusing the people thinking they have wrong backtrace; it is correctly unwound, it is just runaway unwinding garbage. # -s, now with the fix below: #0 0x00007f1b912b80d0 in __pause_nocancel () at ../sysdeps/unix/syscall-template.S:82 #1 0x00000000004004ea in ?? () #2 0x00007f1b9121f735 in __libc_start_main (main=0x4004dc, argc=1, ubp_av=0x7fff150f9038, init=, fini=, rtld_fini=, stack_end=0x7fff150f9028) at libc-start.c:226 # inferior has symbols, with set backtrace past-main echo 'main(){pause();}'|gcc -x c -; ./a.out& ./gdb -nx -p $! -ex 'set backtrace past-main' -ex bt #0 0x00007f8930f090d0 in __pause_nocancel () at ../sysdeps/unix/syscall-template.S:82 #1 0x00000000004004ea in main () ^^^^^^^ Both addresses were unwound above but not printed. #2 0x00007f8930e70735 in __libc_start_main (main=0x4004dc
, ...) at libc-start.c:226 #3 0x00000000004003f9 in _start () ^^^^^^^^^ Both addresses were unwound above but not printed. GDB needs to know at least size of "_start" for inside_entry_func but without symbols it knows neither. (gdb) q One can see that with stripped inferior (-s) GDB cannot even stop at the entry symbol as "_start" is also missing there. I find the patch safe enough, if we want to stop at "main" and we see "__libc_start_main" there is no chance "main" would be seen anymore. Sure this whole patch has no effect with "set backtrace past-main". I do not think a testcase makes sense, it would just duplicate the C code logic in TCL being untested if "__libc_start_main" is not found. No regressions on {x86_64,x86_64-m32,i686}-fedora17-linux-gnu. Thanks, Jan gdb/ 2012-03-16 Jan Kratochvil Stop runaway unwinding of stripped executables. * frame.c: Include objfiles.h. (past_main_func): New function. (get_prev_frame): Call it besides inside_main_func. --- a/gdb/frame.c +++ b/gdb/frame.c @@ -43,7 +43,8 @@ #include "gdbthread.h" #include "block.h" #include "inline-frame.h" -#include "tracepoint.h" +#include "tracepoint.h" +#include "objfiles.h" static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame); static struct frame_info *get_prev_frame_raw (struct frame_info *this_frame); @@ -1856,6 +1857,43 @@ inside_main_func (struct frame_info *this_frame) return maddr == get_frame_func (this_frame); } +/* Is this (non-sentinel) frame verified to be after (missed) "main"() + function? This is a safety stop of runaway unwinding on stripped + executables missing both "main" and "_start" (entry) symbols when + "set backtrace past-main on" in in use. */ + +static int +past_main_func (struct frame_info *this_frame) +{ + struct objfile *objfile; + + ALL_OBJFILES (objfile) + { + struct minimal_symbol *msymbol; + CORE_ADDR maddr; + + if (objfile->separate_debug_objfile_backlink) + continue; + + if (strcmp (lbasename (objfile->name), "libc.so.6") != 0) + continue; + + msymbol = lookup_minimal_symbol ("__libc_start_main", NULL, objfile); + if (msymbol == NULL) + continue; + + /* Make certain that the code, and not descriptor, address is + returned. */ + maddr = gdbarch_convert_from_func_ptr_addr (get_frame_arch (this_frame), + SYMBOL_VALUE_ADDRESS (msymbol), + ¤t_target); + if (maddr == get_frame_func (this_frame)) + return 1; + } + + return 0; +} + /* Test whether THIS_FRAME is inside the process entry point function. */ static int @@ -1904,7 +1942,7 @@ get_prev_frame (struct frame_info *this_frame) && get_frame_type (this_frame) == NORMAL_FRAME && !backtrace_past_main && frame_pc_p - && inside_main_func (this_frame)) + && (inside_main_func (this_frame) || past_main_func (this_frame))) /* Don't unwind past main(). Note, this is done _before_ the frame has been marked as previously unwound. That way if the user later decides to enable unwinds past main(), that will