From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 6567 invoked by alias); 25 Apr 2007 18:54:59 -0000 Received: (qmail 6553 invoked by uid 22791); 25 Apr 2007 18:54:58 -0000 X-Spam-Check-By: sourceware.org Received: from igw3.br.ibm.com (HELO igw3.br.ibm.com) (32.104.18.26) by sourceware.org (qpsmtpd/0.31) with ESMTP; Wed, 25 Apr 2007 19:54:55 +0100 Received: from mailhub1.br.ibm.com (unknown [9.18.232.109]) by igw3.br.ibm.com (Postfix) with ESMTP id F14BE39015E for ; Wed, 25 Apr 2007 15:47:17 -0300 (BRT) Received: from d24av02.br.ibm.com (d24av02.br.ibm.com [9.18.232.47]) by mailhub1.br.ibm.com (8.13.8/8.13.8/NCO v8.3) with ESMTP id l3PIsaOQ716914 for ; Wed, 25 Apr 2007 15:54:37 -0300 Received: from d24av02.br.ibm.com (loopback [127.0.0.1]) by d24av02.br.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id l3PIrVNN008303 for ; Wed, 25 Apr 2007 15:53:31 -0300 Received: from [9.18.238.71] (dyn531804.br.ibm.com [9.18.238.71] (may be forged)) by d24av02.br.ibm.com (8.12.11.20060308/8.12.11) with ESMTP id l3PIrT1e006401 for ; Wed, 25 Apr 2007 15:53:31 -0300 Subject: [patch] Backtrace prints wrong argument value From: Luis Machado Reply-To: luisgpm@linux.vnet.ibm.com To: gdb-patches@sources.redhat.com Content-Type: multipart/mixed; boundary="=-/o5aO6+N5QFCMezMtmsY" Date: Wed, 25 Apr 2007 19:13:00 -0000 Message-Id: <1177527233.12599.42.camel@localhost> Mime-Version: 1.0 X-Mailer: Evolution 2.6.1 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: 2007-04/txt/msg00343.txt.bz2 --=-/o5aO6+N5QFCMezMtmsY Content-Type: text/plain Content-Transfer-Encoding: 7bit Content-length: 2848 Hi Folks, GDB sometimes acts in an unexpected way while showing backtrace argument values in certain optimized binaries. I'll go through the example: The code used to reproduce this follows: unsigned * __attribute__((noinline)) start_sequence (unsigned * x, unsigned * y) { return (unsigned *)0xdeadbeef; }; unsigned __attribute__((noinline)) gen_movsd (unsigned * operand0, unsigned * operand1) { return *start_sequence(operand0, operand1); } int main(void) { unsigned x, y; x = 13; y = 14; return (int)gen_movsd (&x, &y); } Basically we have two functions, gen_movsd and start_sequence. Since the argument values for those two functions are not really used, GCC optimizes some of them. Loading the binary on GDB, we step through the code until we reach the "start_sequence" function. It shows the following frame info: #0 - start_sequence (x=, y=0xfffff9b1b34) "x" was originally passed on R3, and it's now lost since the same register was used for the return value (0xdeadbeef) of the "start_sequence" function. This is OK. If we call a backtrace on GDB, that's what we have: #0 - start_sequence (x=, y=0xfffff9b1b34) #1 - gen_movsd (operand0=0xdeadbeef, operand1=0xfffff9b1b34) Notice that on frame #1, "operand0" has a "0xdeadbeef" value, which happens to be the return value from the "start_sequence" function from frame #0. This is clearly incorrect. Stepping a little bit further through the code until we exit from "start_sequence" and fall back into "gen_movsd", we have the following as the frame info: #0 - gen_movsd (operand0=, operand1=) This last frame info is just correct, since both values aren't available anymore. What is causing this incorrect value to be printed on frame levels above 0 is an adjustment to the PC on the "frame_unwind_address_in_block" function. The purpose of this adjustment to PC is to make it point to the branch instruction rather than the instruction right after the branch instruction ( this is achieved with a --pc decrement). This breaks the code that finds the right DWARF expression in the location lists for each argument due to an off-by-1 error. Thus, GDB selects the incorrect DWARF expression and shows the wrong value on backtrace. This patch fixes the problem by adjusting the PC to prevent the off-by-1 problem, thus making GDB select the correct DWARF expression. Another point is that the PC decrement operation on "frame_unwind_address_in_block", as it is now, doesn't make sense if the branch instruction is longer than 1 byte. To make sure that PC points to the branch instruction we must go back the length of the last instruction executed. On ppc this length is fixed, but on other architectures it is not. Comments and suggestions are welcome. Best regards, Luis --=-/o5aO6+N5QFCMezMtmsY Content-Disposition: attachment; filename=wrong_backtrace_argument.diff Content-Type: text/x-patch; name=wrong_backtrace_argument.diff; charset=UTF-8 Content-Transfer-Encoding: 7bit Content-length: 1292 2007-04-25 Luis Machado * dwarf2loc.c (loclist_read_variable): Corrected the PC value before calling the find_location_expression function Index: gdb/dwarf2loc.c =================================================================== --- gdb.orig/dwarf2loc.c 2007-04-25 10:29:05.000000000 -0700 +++ gdb/dwarf2loc.c 2007-04-25 11:04:55.000000000 -0700 @@ -528,9 +528,20 @@ gdb_byte *data; size_t size; +/* If the current Frame Level is 0, we pass the unmodified PC, but if the + Frame Level is greater than 0, we must adjust the PC by 1 since it was + decremented by get_frame_address_in_block() to be more intuitive to the + user (to point at the branch instruction rather than the instruction right + after the branch. Due to this adjusting, the Location List has an off-by-1 + error when checking the PC. This could cause wrong argument values to be + shown. */ + data = find_location_expression (dlbaton, &size, - frame ? get_frame_address_in_block (frame) - : 0); + frame ? + (frame_relative_level(frame)? (get_frame_address_in_block(frame) + sizeof(CORE_ADDR)) + : get_frame_address_in_block(frame)) + : 0); + if (data == NULL) { val = allocate_value (SYMBOL_TYPE (symbol)); --=-/o5aO6+N5QFCMezMtmsY--