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

Daniel Jacobowitz
2003-04-25T00:27:50Z

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@google.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