This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: patch for printing 64-bit values in i386 registers; STABS format


Hey, Mark, this sounds very much like a change you proposed.  What ever
happened to that patch?

On Thu, Apr 24, 2003 at 03:31:52PM -0700, Colin Smith wrote:
> 
> * 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  <colins at google dot com>
> 
> 	* 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 <iostream>
>     //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[] =
> 

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]