From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 25672 invoked by alias); 23 Sep 2005 19:34:35 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 25168 invoked by uid 22791); 23 Sep 2005 19:34:05 -0000 Received: from nevyn.them.org (HELO nevyn.them.org) (66.93.172.17) by sourceware.org (qpsmtpd/0.30-dev) with ESMTP; Fri, 23 Sep 2005 19:34:05 +0000 Received: from drow by nevyn.them.org with local (Exim 4.52) id 1EItJ5-0002Ew-FR; Fri, 23 Sep 2005 15:34:03 -0400 Date: Fri, 23 Sep 2005 19:34:00 -0000 From: Daniel Jacobowitz To: gdb-patches@sourceware.org Cc: Kevin Buettner , Andrew Cagney Subject: RFC: Make PowerPC backtraces more robust Message-ID: <20050923193403.GA7146@nevyn.them.org> Mail-Followup-To: gdb-patches@sourceware.org, Kevin Buettner , Andrew Cagney Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.8i X-SW-Source: 2005-09/txt/msg00200.txt.bz2 The PowerPC ABI is pretty explicit about the layout of the stack: if there is a stack frame, the LR gets saved right after the backchain. Various bits of handwritten assembly that I've surveyed honor this convention, as does GCC. This patch takes advantage of that to handle backtraces in a couple of cases that would otherwise be impossible. This patch helps when there's no symbols available (-> frame_func_unwind returns 0, skip_prologue does nothing), or where GDB can not handle a prologue (e.g. assembly stubs which have a fast path which does not set up a stack frame, falling back to a slow path which does). It adds a simple heuristic: if the prologue analyzer did not find a stack frame or a saved link register, then take a look at this frame's LR. If it points to the same address as the current PC, or if we can see that it definitively points to somewhere in the current function, then we know that the unwound LR is wrong, and/or the function really does have a frame. If neither of those were true, the function would be recursive without a stack frame. So in this case, assume the ABI-mandated backchain and saved LR. We can't guess at saved registers, but having the stack is a big improvement over not. It seems to work very well. I've regression tested it on powerpc64-linux and manually checked some improved cases on powerpc-linux. Comments? OK? -- Daniel Jacobowitz CodeSourcery, LLC 2005-09-23 Daniel Jacobowitz * rs6000-tdep.c (rs6000_frame_cache): Handle misdetected frameless functions. Index: rs6000-tdep.c =================================================================== RCS file: /big/fsf/rsync/src/src/gdb/rs6000-tdep.c,v retrieving revision 1.243 diff -u -p -r1.243 rs6000-tdep.c --- rs6000-tdep.c 19 Sep 2005 17:38:03 -0000 1.243 +++ rs6000-tdep.c 23 Sep 2005 18:26:39 -0000 @@ -2852,6 +2852,7 @@ rs6000_frame_cache (struct frame_info *n struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); struct rs6000_framedata fdata; int wordsize = tdep->wordsize; + CORE_ADDR func, pc; if ((*this_cache) != NULL) return (*this_cache); @@ -2859,35 +2860,56 @@ rs6000_frame_cache (struct frame_info *n (*this_cache) = cache; cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); - skip_prologue (frame_func_unwind (next_frame), frame_pc_unwind (next_frame), - &fdata); + func = frame_func_unwind (next_frame); + pc = frame_pc_unwind (next_frame); + skip_prologue (func, pc, &fdata); + + /* Figure out the parent's stack pointer. */ + + /* NOTE: cagney/2002-04-14: The ->frame points to the inner-most + address of the current frame. Things might be easier if the + ->frame pointed to the outer-most address of the frame. In + the mean time, the address of the prev frame is used as the + base address of this frame. */ + cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM); + + /* If the function appears to be frameless, check a couple of likely + indicators that we have simply failed to find the frame setup. + Two common cases of this are missing symbols (i.e. + frame_func_unwind returns the wrong address or 0), and assembly + stubs which have a fast exit path but set up a frame on the slow + path. + + If the LR appears to return to this function, then presume that + we have an ABI compliant frame that we failed to find. */ + if (fdata.frameless && fdata.lr_offset == 0) + { + CORE_ADDR saved_lr; + int make_frame = 0; + + func = frame_func_unwind (next_frame); + saved_lr = frame_unwind_register_unsigned (next_frame, + tdep->ppc_lr_regnum); + if (func == 0 && saved_lr == pc) + make_frame = 1; + else if (func != 0) + { + CORE_ADDR saved_func = get_pc_function_start (saved_lr); + if (func == saved_func) + make_frame = 1; + } - /* If there were any saved registers, figure out parent's stack - pointer. */ - /* The following is true only if the frame doesn't have a call to - alloca(), FIXME. */ - - if (fdata.saved_fpr == 0 - && fdata.saved_gpr == 0 - && fdata.saved_vr == 0 - && fdata.saved_ev == 0 - && fdata.lr_offset == 0 - && fdata.cr_offset == 0 - && fdata.vr_offset == 0 - && fdata.ev_offset == 0) - cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM); - else - { - /* NOTE: cagney/2002-04-14: The ->frame points to the inner-most - address of the current frame. Things might be easier if the - ->frame pointed to the outer-most address of the frame. In - the mean time, the address of the prev frame is used as the - base address of this frame. */ - cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM); - if (!fdata.frameless) - /* Frameless really means stackless. */ - cache->base = read_memory_addr (cache->base, wordsize); + if (make_frame) + { + fdata.frameless = 0; + fdata.lr_offset = wordsize; + } } + + if (!fdata.frameless) + /* Frameless really means stackless. */ + cache->base = read_memory_addr (cache->base, wordsize); + trad_frame_set_value (cache->saved_regs, SP_REGNUM, cache->base); /* if != -1, fdata.saved_fpr is the smallest number of saved_fpr.