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]

[patch/rfc; RFA:testsuite] Revamp store for lval_register and lval_reg_frame_relative


Hello,

The attached patch merges the lval_register and lval_reg_frame_relative store-register code. It now treads lval_register just like lval_reg_frame_relative only the former always applies to the current (inner most) frame.

As a bonus, the merge manages to eliminate any calls to the functions write_register_bytes(), read_register_bytes(), and get_saved_register() in tha file.

But wait, there's more! The patch adds tests to check that GDB can actually store a value correctly in a target register.

And if you test the patch in the next 15 minutes, the merge will also fix the very long standing bug where GDB would occasionally loose the selected frame:
(gdb) up
10 v = v + v;
(gdb) print v
$1 = 10
(gdb) set variable v = 20
(gdb) print v
No symbol "v" in current context.
(gdb) down
Bottom (i.e., innermost) frame selected; you cannot go down.
(gdb) up
10 v = v + v;
(gdb) print v
$2 = 20
The code now restores the selected frame after the frame-cache flush.

I'll look to commit the valops.c patch in a few days (it depends on an earlier frame_register() patch).

Fernando,
the new store.{exp,c} test cases? The tests fail without this patch and pass with the patch applied.

Andrew

2002-11-01  Andrew Cagney  <cagney@redhat.com>

	* valops.c (value_assign): Merge lval_register case into
	lval_reg_frame_relative.  Use frame_register and
	regcache_cooked_write instead of get_saved_register and
	write_register_bytes.  After flushing the register cache, try to
	re-select the selected frame.

Index: testsuite/ChangeLog
2002-11-02  Andrew Cagney  <ac131313@redhat.com>

	* gdb.base/store.exp, gdb.base/store.c: New files.

Index: valops.c
===================================================================
RCS file: /cvs/src/src/gdb/valops.c,v
retrieving revision 1.78
diff -u -r1.78 valops.c
--- valops.c	23 Oct 2002 21:33:07 -0000	1.78
+++ valops.c	3 Nov 2002 04:19:48 -0000
@@ -630,132 +630,120 @@
       }
       break;
 
-    case lval_register:
-      if (VALUE_BITSIZE (toval))
-	{
-	  char buffer[sizeof (LONGEST)];
-	  int len =
-		REGISTER_RAW_SIZE (VALUE_REGNO (toval)) - VALUE_OFFSET (toval);
-
-	  if (len > (int) sizeof (LONGEST))
-	    error ("Can't handle bitfields in registers larger than %d bits.",
-		   (int) sizeof (LONGEST) * HOST_CHAR_BIT);
-
-	  if (VALUE_BITPOS (toval) + VALUE_BITSIZE (toval)
-	      > len * HOST_CHAR_BIT)
-	    /* Getting this right would involve being very careful about
-	       byte order.  */
-	    error ("Can't assign to bitfields that cross register "
-		   "boundaries.");
-
-	  read_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
-			       buffer, len);
-	  modify_field (buffer, value_as_long (fromval),
-			VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
-	  write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
-				buffer, len);
-	}
-      else if (use_buffer)
-	write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
-			      raw_buffer, use_buffer);
-      else
-	{
-	  /* Do any conversion necessary when storing this type to more
-	     than one register.  */
-#ifdef REGISTER_CONVERT_FROM_TYPE
-	  memcpy (raw_buffer, VALUE_CONTENTS (fromval), TYPE_LENGTH (type));
-	  REGISTER_CONVERT_FROM_TYPE (VALUE_REGNO (toval), type, raw_buffer);
-	  write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
-				raw_buffer, TYPE_LENGTH (type));
-#else
-	  write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
-			      VALUE_CONTENTS (fromval), TYPE_LENGTH (type));
-#endif
-	}
-
-      target_changed_event ();
-
-      /* Assigning to the stack pointer, frame pointer, and other
-         (architecture and calling convention specific) registers may
-         cause the frame cache to be out of date.  We just do this
-         on all assignments to registers for simplicity; I doubt the slowdown
-         matters.  */
-      reinit_frame_cache ();
-      break;
-
     case lval_reg_frame_relative:
+    case lval_register:
       {
+	struct frame_id old_frame;
 	/* value is stored in a series of registers in the frame
 	   specified by the structure.  Copy that value out, modify
 	   it, and copy it back in.  */
-	int amount_to_copy = (VALUE_BITSIZE (toval) ? 1 : TYPE_LENGTH (type));
-	int reg_size = REGISTER_RAW_SIZE (VALUE_FRAME_REGNUM (toval));
-	int byte_offset = VALUE_OFFSET (toval) % reg_size;
-	int reg_offset = VALUE_OFFSET (toval) / reg_size;
 	int amount_copied;
-
-	/* Make the buffer large enough in all cases.  */
-	/* FIXME (alloca): Not safe for very large data types. */
-	char *buffer = (char *) alloca (amount_to_copy
-					+ sizeof (LONGEST)
-					+ MAX_REGISTER_RAW_SIZE);
-
+	int amount_to_copy;
+	char *buffer;
+	int value_reg;
+	int reg_offset;
+	int byte_offset;
 	int regno;
 	struct frame_info *frame;
 
+	/* Since modifying a register can trash the frame chain, we
+           save the old frame and then restore the new frame
+           afterwards.  */
+	get_frame_id (selected_frame, &old_frame);
+
 	/* Figure out which frame this is in currently.  */
-	for (frame = get_current_frame ();
-	     frame && FRAME_FP (frame) != VALUE_FRAME (toval);
-	     frame = get_prev_frame (frame))
-	  ;
+	if (VALUE_LVAL (toval) == lval_register)
+	  {
+	    frame = get_current_frame ();
+	    value_reg = VALUE_REGNO (toval);
+	  }
+	else
+	  {
+	    for (frame = get_current_frame ();
+		 frame && FRAME_FP (frame) != VALUE_FRAME (toval);
+		 frame = get_prev_frame (frame))
+	      ;
+	    value_reg = VALUE_FRAME_REGNUM (toval);
+	  }
 
 	if (!frame)
 	  error ("Value being assigned to is no longer active.");
 
-	amount_to_copy += (reg_size - amount_to_copy % reg_size);
+	/* Locate the first register that falls in the value that
+           needs to be transfered.  Compute the offset of the value in
+           that register.  */
+	{
+	  int offset;
+	  for (reg_offset = value_reg, offset = 0;
+	       offset + REGISTER_RAW_SIZE (reg_offset) <= VALUE_OFFSET (toval);
+	       reg_offset++);
+	  byte_offset = VALUE_OFFSET (toval) - offset;
+	}
+
+	/* Compute the number of register aligned values that need to
+           be copied.  */
+	if (VALUE_BITSIZE (toval))
+	  amount_to_copy = byte_offset + 1;
+	else
+	  amount_to_copy = byte_offset + TYPE_LENGTH (type);
+
+	/* And a bounce buffer.  Be slightly over generous.  */
+	buffer = (char *) alloca (amount_to_copy
+				  + MAX_REGISTER_RAW_SIZE);
 
-	/* Copy it out.  */
-	for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset,
-	      amount_copied = 0);
+	/* Copy it in.  */
+	for (regno = reg_offset, amount_copied = 0;
 	     amount_copied < amount_to_copy;
-	     amount_copied += reg_size, regno++)
+	     amount_copied += REGISTER_RAW_SIZE (regno), regno++)
 	  {
-	    get_saved_register (buffer + amount_copied,
-				(int *) NULL, (CORE_ADDR *) NULL,
-				frame, regno, (enum lval_type *) NULL);
+	    frame_register_read (frame, regno, buffer + amount_copied);
 	  }
-
+	
 	/* Modify what needs to be modified.  */
 	if (VALUE_BITSIZE (toval))
-	  modify_field (buffer + byte_offset,
-			value_as_long (fromval),
-			VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+	  {
+	    modify_field (buffer + byte_offset,
+			  value_as_long (fromval),
+			  VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+	  }
 	else if (use_buffer)
-	  memcpy (buffer + byte_offset, raw_buffer, use_buffer);
+	  {
+	    memcpy (buffer + VALUE_OFFSET (toval), raw_buffer, use_buffer);
+	  }
 	else
-	  memcpy (buffer + byte_offset, VALUE_CONTENTS (fromval),
-		  TYPE_LENGTH (type));
+	  {
+	    memcpy (buffer + byte_offset, VALUE_CONTENTS (fromval),
+		    TYPE_LENGTH (type));
+	    /* Do any conversion necessary when storing this type to
+	       more than one register.  */
+#ifdef REGISTER_CONVERT_FROM_TYPE
+	    REGISTER_CONVERT_FROM_TYPE (value_reg, type,
+					(buffer + byte_offset));
+#endif
+	  }
 
-	/* Copy it back.  */
-	for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset,
-	      amount_copied = 0);
+	/* Copy it out.  */
+	for (regno = reg_offset, amount_copied = 0;
 	     amount_copied < amount_to_copy;
-	     amount_copied += reg_size, regno++)
+	     amount_copied += REGISTER_RAW_SIZE (regno), regno++)
 	  {
 	    enum lval_type lval;
 	    CORE_ADDR addr;
 	    int optim;
-
+	    int realnum;
+	    
 	    /* Just find out where to put it.  */
-	    get_saved_register ((char *) NULL,
-				&optim, &addr, frame, regno, &lval);
-
+	    frame_register (frame, regno, &optim, &lval, &addr, &realnum,
+			    NULL);
+	    
 	    if (optim)
 	      error ("Attempt to assign to a value that was optimized out.");
 	    if (lval == lval_memory)
-	      write_memory (addr, buffer + amount_copied, reg_size);
+	      write_memory (addr, buffer + amount_copied,
+			    REGISTER_RAW_SIZE (regno));
 	    else if (lval == lval_register)
-	      write_register_bytes (addr, buffer + amount_copied, reg_size);
+	      regcache_cooked_write (current_regcache, realnum,
+				     (buffer + amount_copied));
 	    else
 	      error ("Attempt to assign to an unmodifiable value.");
 	  }
@@ -763,10 +751,31 @@
 	if (register_changed_hook)
 	  register_changed_hook (-1);
 	target_changed_event ();
+
+	/* Assigning to the stack pointer, frame pointer, and other
+	   (architecture and calling convention specific) registers
+	   may cause the frame cache to be out of date.  We just do
+	   this on all assignments to registers for simplicity; I
+	   doubt the slowdown matters.  */
+	reinit_frame_cache ();
+
+	/* Having destoroyed the frame cache, restore the selected
+           frame.  */
+	/* FIXME: cagney/2002-11-02: There has to be a better way of
+           doing this.  Instead of constantly saving/restoring the
+           frame.  Why not create a get_selected_frame() function
+           that, having saved the selected frame's ID can
+           automatically re-find the previously selected frame
+           automatically.  */
+	{
+	  struct frame_info *fi = frame_find_by_id (old_frame);
+	  if (fi != NULL)
+	    select_frame (fi);
+	}
       }
       break;
-
-
+      
+      
     default:
       error ("Left operand of assignment is not an lvalue.");
     }
Index: testsuite/gdb.base/store.c
===================================================================
RCS file: testsuite/gdb.base/store.c
diff -N testsuite/gdb.base/store.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/store.c	3 Nov 2002 04:20:29 -0000
@@ -0,0 +1,250 @@
+/* Check that GDB can correctly update a value, living in a register,
+   in the target.  This pretty much relies on the compiler taking heed
+   of requests for values to be stored in registers.  */
+
+static char
+add_char (register char u, register char v)
+{
+  return u + v;
+}
+
+static short
+add_short (register short u, register short v)
+{
+  return u + v;
+}
+
+static int
+add_int (register int u, register int v)
+{
+  return u + v;
+}
+
+static long
+add_long (register long u, register long v)
+{
+  return u + v;
+}
+
+static float
+add_float (register float u, register float v)
+{
+  return u + v;
+}
+
+static double
+add_double (register double u, register double v)
+{
+  return u + v;
+}
+
+/* */
+
+static char
+wack_char (register char u, register char v)
+{
+  register char l = u;
+  l = add_char (l, v);
+  return l;
+}
+
+static short
+wack_short (register short u, register short v)
+{
+  register short l = u;
+  l = add_short (l, v);
+  return l;
+}
+
+static int
+wack_int (register int u, register int v)
+{
+  register int l = u;
+  l = add_int (l, v);
+  return l;
+}
+
+static long
+wack_long (register long u, register long v)
+{
+  register long l = u;
+  l = add_long (l, v);
+  return l;
+}
+
+static float
+wack_float (register float u, register float v)
+{
+  register float l = u;
+  l = add_float (l, v);
+  return l;
+}
+
+static double
+wack_double (register double u, register double v)
+{
+  register double l = u;
+  l = add_double (l, v);
+  return l;
+}
+
+struct s_1 { short s[1]; } z_1, s_1;
+struct s_2 { short s[2]; } z_2, s_2;
+struct s_3 { short s[3]; } z_3, s_3;
+struct s_4 { short s[4]; } z_4, s_4;
+
+static struct s_1
+add_struct_1 (struct s_1 s)
+{
+  int i;
+  for (i = 0; i < sizeof (s) / sizeof (s.s[0]); i++)
+    {
+      s.s[i] = s.s[i] + s.s[i];
+    }
+  return s;
+}
+
+static struct s_2
+add_struct_2 (struct s_2 s)
+{
+  int i;
+  for (i = 0; i < sizeof (s) / sizeof (s.s[0]); i++)
+    {
+      s.s[i] = s.s[i] + s.s[i];
+    }
+  return s;
+}
+
+static struct s_3
+add_struct_3 (struct s_3 s)
+{
+  int i;
+  for (i = 0; i < sizeof (s) / sizeof (s.s[0]); i++)
+    {
+      s.s[i] = s.s[i] + s.s[i];
+    }
+  return s;
+}
+
+static struct s_4
+add_struct_4 (struct s_4 s)
+{
+  int i;
+  for (i = 0; i < sizeof (s) / sizeof (s.s[0]); i++)
+    {
+      s.s[i] = s.s[i] + s.s[i];
+    }
+  return s;
+}
+
+static struct s_1
+wack_struct_1 (void)
+{
+  int i; register struct s_1 u = z_1;
+  for (i = 0; i < sizeof (s_1) / sizeof (s_1.s[0]); i++) { s_1.s[i] = i + 1; }
+  u = add_struct_1 (u);
+  return u;
+}
+
+static struct s_2
+wack_struct_2 (void)
+{
+  int i; register struct s_2 u = z_2;
+  for (i = 0; i < sizeof (s_2) / sizeof (s_2.s[0]); i++) { s_2.s[i] = i + 1; }
+  u = add_struct_2 (u);
+  return u;
+}
+
+static struct s_3
+wack_struct_3 (void)
+{
+  int i; register struct s_3 u = z_3;
+  for (i = 0; i < sizeof (s_3) / sizeof (s_3.s[0]); i++) { s_3.s[i] = i + 1; }
+  u = add_struct_3 (u);
+  return u;
+}
+
+static struct s_4
+wack_struct_4 (void)
+{
+  int i; register struct s_4 u = z_4;
+  for (i = 0; i < sizeof (s_4) / sizeof (s_4.s[0]); i++) { s_4.s[i] = i + 1; }
+  u = add_struct_4 (u);
+  return u;
+}
+
+/* */
+
+struct f_1 {unsigned i:1;unsigned j:1;unsigned k:1; } f_1 = {1,1,1}, F_1;
+struct f_2 {unsigned i:2;unsigned j:2;unsigned k:2; } f_2 = {1,1,1}, F_2;
+struct f_3 {unsigned i:3;unsigned j:3;unsigned k:3; } f_3 = {1,1,1}, F_3;
+struct f_4 {unsigned i:4;unsigned j:4;unsigned k:4; } f_4 = {1,1,1}, F_4;
+
+static struct f_1
+wack_field_1 (void)
+{
+  register struct f_1 u = f_1;
+  return u;
+}
+
+static struct f_2
+wack_field_2 (void)
+{
+  register struct f_2 u = f_2;
+  return u;
+}
+
+static struct f_3
+wack_field_3 (void)
+{
+  register struct f_3 u = f_3;
+  return u;
+}
+
+static struct f_4
+wack_field_4 (void)
+{
+  register struct f_4 u = f_4;
+  return u;
+}
+
+/* */
+
+int
+main ()
+{
+  /* These calls are for current frame test.  */
+  wack_char (1, 2);
+  wack_short (1, 2);
+  wack_int (1, 2);
+  wack_long (1, 2);
+  wack_float (1, 2);
+  wack_double (1, 2);
+
+  /* These calls are for up frame.  */
+  wack_char (1, 2);
+  wack_short (1, 2);
+  wack_int (1, 2);
+  wack_long (1, 2);
+  wack_float (1, 2);
+  wack_double (1, 2);
+
+  /* These calls are for current frame test.  */
+  wack_struct_1 ();
+  wack_struct_2 ();
+  wack_struct_3 ();
+  wack_struct_4 ();
+  
+  /* These calls are for up frame.  */
+  wack_struct_1 ();
+  wack_struct_2 ();
+  wack_struct_3 ();
+  wack_struct_4 ();
+  
+  wack_field_1 ();
+  wack_field_2 ();
+  wack_field_3 ();
+  wack_field_4 ();
+
+  return 0;
+}
Index: testsuite/gdb.base/store.exp
===================================================================
RCS file: testsuite/gdb.base/store.exp
diff -N testsuite/gdb.base/store.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/store.exp	3 Nov 2002 04:20:29 -0000
@@ -0,0 +1,171 @@
+# Copyright 2002 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@gnu.org
+
+if $tracelevel {
+    strace $tracelevel
+}
+
+#
+# test running programs
+#
+set prms_id 0
+set bug_id 0
+
+set testfile "store"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+     gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
+}
+
+if [get_compiler_info ${binfile}] {
+    return -1;
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+#
+# set it up at a breakpoint so we can play with the variable values
+#
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint"
+    continue
+}
+
+#
+
+proc check_set { t old new add } {
+    global gdb_prompt
+    gdb_test "tbreak wack_${t}"
+    gdb_test "continue" "register ${t} l = u;" "continue set ${t}"
+    gdb_test "next" "l = add_${t} .l, v.;" "next ${t}"
+    gdb_test "print l" " = ${old}" "print old ${t}"
+    gdb_test "set variable l = 4"
+    gdb_test "print l" " = ${new}" "print new ${t}"
+    gdb_test "next" "return l;"
+    gdb_test "print l" " = ${add}" "print add ${t}"
+}
+
+check_set "char" "1 ..001." "4 ..004." "6 ..006."
+check_set "short" "1" "4" "6"
+check_set "int" "1" "4" "6"
+check_set "long" "1" "4" "6"
+check_set "float" "1" "4" "6"
+check_set "double" "1" "4" "6"
+
+#
+
+proc up_set { t old new } {
+    global gdb_prompt
+    gdb_test "tbreak add_${t}"
+    gdb_test "continue" "return u . v;" "continue up ${t}"
+    gdb_test "up" "l = add_${t} .l, v.;" "up ${t}"
+    gdb_test "print l" " = ${old}" "print old up ${t}"
+    gdb_test "set variable l = 4"
+    gdb_test "print l" " = ${new}" "print new up ${t}"
+}
+
+up_set "char" "1 ..001." "4 ..004."
+up_set "short" "1" "4"
+up_set "int" "1" "4"
+up_set "long" "1" "4"
+up_set "float" "1" "4"
+up_set "double" "1" "4"
+
+#
+
+proc check_struct { t old new } {
+    global gdb_prompt
+    gdb_test "tbreak wack_struct_${t}"
+    gdb_test "continue" "int i; register struct s_${t} u = z_${t};" \
+	    "continue set struct ${t}"
+    gdb_test "next 2" "add_struct_${t} .u.;"
+    gdb_test "print u" " = ${old}" "old check struct ${t}"
+    gdb_test "set variable u = s_${t}"
+    gdb_test "print u" " = ${new}" "new check struct ${t}"
+}
+
+check_struct "1" "{s = {0}}" "{s = {1}}"
+check_struct "2" "{s = {0, 0}}" "{s = {1, 2}}"
+check_struct "3" "{s = {0, 0, 0}}" "{s = {1, 2, 3}}"
+check_struct "4" "{s = {0, 0, 0, 0}}" "{s = {1, 2, 3, 4}}"
+
+proc up_struct { t old new } {
+    global gdb_prompt
+    gdb_test "tbreak add_struct_${t}"
+    gdb_test "continue" "for .i = 0; i < sizeof .s. / sizeof .s.s.0..; i..." \
+	    "continue up struct ${t}"
+    gdb_test "up" "u = add_struct_${t} .u.;" "up struct ${t}"
+    gdb_test "print u" " = ${old}" "old up struct ${t}"
+    gdb_test "set variable u = s_${t}"
+    gdb_test "print u" " = ${new}" "new up struct ${t}"
+}
+
+up_struct "1" "{s = {0}}" "{s = {1}}"
+up_struct "2" "{s = {0, 0}}" "{s = {1, 2}}"
+up_struct "3" "{s = {0, 0, 0}}" "{s = {1, 2, 3}}"
+up_struct "4" "{s = {0, 0, 0, 0}}" "{s = {1, 2, 3, 4}}"
+
+#
+
+proc check_field { t } {
+    global gdb_prompt
+    gdb_test "tbreak wack_field_${t}"
+    gdb_test "continue" "register struct f_${t} u = f_${t};" \
+	    "continue field ${t}"
+    gdb_test "next" "return u;" "next field ${t}"
+
+    gdb_test "print u" " = {i = 1, j = 1, k = 1}" "old field ${t}"
+    gdb_test "set variable u = F_${t}"
+    gdb_test "print u" " = {i = 0, j = 0, k = 0}" "new field ${t}"
+
+    gdb_test "set variable u = F_${t}, u.i = f_${t}.i"
+    gdb_test "print u" " = {i = 1, j = 0, k = 0}" "f_${t}.i"
+
+    gdb_test "set variable u = F_${t}, u.j = f_${t}.j"
+    gdb_test "print u" " = {i = 0, j = 1, k = 0}" "f_${t}.j"
+
+    gdb_test "set variable u = F_${t}, u.k = f_${t}.k"
+    gdb_test "print u" " = {i = 0, j = 0, k = 1}" "f_${t}.k"
+
+    gdb_test "set variable u = f_${t}, u.i = F_${t}.i"
+    gdb_test "print u" " = {i = 0, j = 1, k = 1}" "F_${t}.i"
+
+    gdb_test "set variable u = f_${t}, u.j = F_${t}.j"
+    gdb_test "print u" " = {i = 1, j = 0, k = 1}" "F_${t}.j"
+
+    gdb_test "set variable u = f_${t}, u.k = F_${t}.k"
+    gdb_test "print u" " = {i = 1, j = 1, k = 0}" "F_${t}.k"
+
+}
+
+check_field 1
+check_field 2
+check_field 3
+check_field 4
+
+#
+
+# WANTED: A fairly portable way of convincing the compiler to split a
+# value across memory and registers.
+

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