From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22186 invoked by alias); 24 Apr 2003 22:31:54 -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 22176 invoked from network); 24 Apr 2003 22:31:52 -0000 Received: from unknown (HELO 216-239-45-4.google.com) (216.239.45.4) by sources.redhat.com with SMTP; 24 Apr 2003 22:31:52 -0000 Received: from moma.corp.google.com (moma.corp.google.com [10.3.0.12]) by 216-239-45-4.google.com (8.12.9/8.12.3) with ESMTP id h3OMVqFw017563 for ; Thu, 24 Apr 2003 15:31:52 -0700 Received: from dhcp357.corp.google.com (dhcp357.corp.google.com [10.3.7.103]) by moma.corp.google.com (8.12.9/8.12.3) with ESMTP id h3OMVqiC028771 for ; Thu, 24 Apr 2003 15:31:52 -0700 Received: from dhcp357.corp.google.com (colins@localhost) by dhcp357.corp.google.com (8.10.2/8.10.2) with ESMTP id h3OMVqM13587 for ; Thu, 24 Apr 2003 15:31:52 -0700 Message-Id: <200304242231.h3OMVqM13587@dhcp357.corp.google.com> To: gdb-patches@sources.redhat.com Subject: patch for printing 64-bit values in i386 registers; STABS format Date: Fri, 25 Apr 2003 00:27:00 -0000 From: Colin Smith X-SW-Source: 2003-04/txt/msg00478.txt.bz2 * Description of bug: On i386 with STABS debug format, if the debug info for a function indicates that a long long variable is held in a register, for example %ebx, GDB will assume that the other register follows the first one in gdb register number order. But GDB register numbering and GCC register numbering do not correspond. The patch fixes this by offering a new macro that will compute the "next" register given the first one in the event a value is spread across multiple registers. We implement this macro in the i386 case. * Changelog Entry 2003-04-24 Colin Smith * findvar.c (value_from_register): use new NEXT_LOCAL_REGNUM to find follow-on registers for values larger than one register, in the STABS case. Implemented in tm-i386.h and i386-tdep.c. * Example code that provokes the bug: #include //using namespace std; typedef long long uint64; inline uint64 g(uint64 v, uint64 w) { cout << v << ' ' << w << endl; ++w; return v-w; } int k = 3; main() { uint64 v = 0x1111111122222222; if (v > 0) { uint64 u = 0xaaaaaaaabbbbbbbb; for (int i = 0; i < k; ++i) v = g(u+v,v); } } ... compile with gcc (2.95.x), -O0, -g; set breakpoint on 'g', run, 'print w', note that value is incorrect; do 'i addr w', see that it's supposed to be in %ebx, do 'i regi' and see that GDB thinks that the value is in %esp:%ebx, when in fact it's in %esi:%ebx. * Text of Patch. diff -cpr gdb-orig/gdb/config/i386/tm-i386.h gdb/gdb/config/i386/tm-i386.h *** gdb-orig/gdb/config/i386/tm-i386.h Thu Apr 24 15:27:35 2003 --- gdb/gdb/config/i386/tm-i386.h Thu Apr 24 13:06:52 2003 *************** *** 22,27 **** --- 22,36 ---- #ifndef TM_I386_H #define TM_I386_H 1 + /* This macro maps between GCC and GDB's register ordering. This is + used when fetching quantities larger than one register out of the + register file: GDB's register ordering is not indicative of the + order in which these registers would have been allocated by the + compiler. */ + + #define NEXT_LOCAL_REGNUM(regnum) \ + i386_next_local_regnum (regnum) + #define GDB_MULTI_ARCH GDB_MULTI_ARCH_PARTIAL /* FIXME: kettenis/2000-06-12: These do not belong here. */ diff -cpr gdb-orig/gdb/findvar.c gdb/gdb/findvar.c *** gdb-orig/gdb/findvar.c Thu Apr 24 15:27:32 2003 --- gdb/gdb/findvar.c Thu Apr 24 12:29:06 2003 *************** *** 46,51 **** --- 46,62 ---- you lose #endif + /* GCC's register ordering (the ordering it will follow when + allocating 64-bit quantities among multiple registers) is not + necessarily the same as GDB's register numbering. In the event + that these orderings don't agree, a config file can specify + an alternate implementation of this macro. (This case occurs + on gcc2 x i386, for example.) */ + + #ifndef NEXT_LOCAL_REGNUM + #define NEXT_LOCAL_REGNUM(regnum) ((regnum)+1) + #endif + LONGEST extract_signed_integer (const void *addr, int len) { *************** value_from_register (struct type *type, *** 735,744 **** } else #endif /* GDB_TARGET_IS_H8500 */ for (local_regnum = regnum; value_bytes_copied < len; (value_bytes_copied += REGISTER_RAW_SIZE (local_regnum), ! ++local_regnum)) { get_saved_register (value_bytes + value_bytes_copied, &optim, --- 746,756 ---- } else #endif /* GDB_TARGET_IS_H8500 */ + for (local_regnum = regnum; value_bytes_copied < len; (value_bytes_copied += REGISTER_RAW_SIZE (local_regnum), ! local_regnum = NEXT_LOCAL_REGNUM (local_regnum))) { get_saved_register (value_bytes + value_bytes_copied, &optim, diff -cpr gdb-orig/gdb/i386-tdep.c gdb/gdb/i386-tdep.c *** gdb-orig/gdb/i386-tdep.c Thu Apr 24 15:27:33 2003 --- gdb/gdb/i386-tdep.c Thu Apr 24 12:59:01 2003 *************** static char *i386_register_names[] = *** 58,63 **** --- 58,86 ---- "mxcsr" }; + int + i386_next_local_regnum (int reg) + { + /* Interpretation of the following table: because + next_reg_map[regnum(ebx)] == regnum(esi), esi + follows ebx in multi-register data allocation + according to GCC. No register follows esp, since + esp is dedicated to another important function ;-) */ + + /* eax ecx edx ebx esp ebp esi edi */ + static int next_reg_map [] = { 2, 3, 1, 6, -1, 4, 7, 5 }; + int n; + + if (reg >= 0 && reg < 8) + if ((n = next_reg_map[reg]) >= 0) + return n; + + /* Give up: we'll have to try gdb's standard algorithm. We've + done no harm, though. */ + + return reg+1; + } + /* MMX registers. */ static char *i386_mmx_names[] =