This is the mail archive of the gdb-patches@sourceware.org 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]

[rfc] [02/18] Cell multi-arch: Per-frame architecture infrastructure


Hello,

this is the second major infrastructure: per-frame architecture.

This patch should be pretty much straight-forward: it replaced the
current dummy implementation of get_frame_arch with actually storing
a gdbarch for each frame.  This gets set during frame unwinding:
for the sentinel frame, the architecture of the register cache is
used; when unwinding, a new "prev_arch" member of "struct frame_unwind"
is called to determine the architecture of the previous frame.  (The
default is the same as the current frame.)

In order to make architecture changes visible to the user, this patch
also introduces a new "enum frame_type" value ARCH_FRAME; such frames
get displayed as "<cross-architecture call>" during a backtrace.  To 
use this, you'd install a unwinder of frame type ARCH_FRAME with a
non-NULL prev_arch implementation.

(If it makes more sense on other platforms, you can also have NORMAL_FRAME
unwinders with non-NULL prev_arch -- this way you will not see the extra
frame during backtrace.)

In addition, there are a couple of related changes:

- select_frame resets current_gdbarch to the architecture of the 
  selected frame.  (This can go once we're fully rid of current_gdbarch.)

- A couple of unwinder-related functions used get_frame_arch on THIS
  frame and assumed this was also the architecture of the PREV frame.
  That assumption is true today, but actually incorrect now that we
  have real per-frame architecture.  This patch changes those locations
  to use frame_arch_unwind instead.

Bye,
Ulrich


ChangeLog:

	* frame.h (frame_arch_unwind): New.
	* frame-unwind.h (frame_prev_arch_ftype): New type.
	(struct frame_unwind): New member prev_arch.
	* frame.c (struct frame_info): New member prev_arch.
	(frame_arch_unwind): New function.
	(get_frame_arch): Reimplement in terms of frame_arch_unwind.
	* sentinel-frame.c (sentinel_frame_prev_arch): New function.
	(sentinel_frame_unwinder): Install it.

	* frame.c (select_frame): Reset current_gdbarch.

	* frame.c (frame_pc_unwind): Use frame_arch_unwind instead
	of get_frame_arch.
	(frame_unwind_register_value): Likewise.
	(frame_unwind_register_signed): Likewise.
	(frame_unwind_register_unsigned): Likewise.
	* frame-unwind.c (frame_unwind_got_optimized): Likewise.
	(frame_unwind_got_register): Likewise.
	(frame_unwind_got_constant): Likewise.
	(frame_unwind_got_bytes): Likewise.
	(frame_unwind_got_address): Likewise.

	* frame.h (enum frame_type): New value ARCH_FRAME.
	* frame.c (fprint_frame_type): Handle ARCH_FRAME.
	* stack.c (print_frame_info): Likewise.


Index: src/gdb/frame.c
===================================================================
--- src.orig/gdb/frame.c
+++ src/gdb/frame.c
@@ -75,6 +75,13 @@ struct frame_info
   void *prologue_cache;
   const struct frame_unwind *unwind;
 
+  /* Cached copy of the previous frame's architecture.  */
+  struct
+  {
+    int p;
+    struct gdbarch *arch;
+  } prev_arch;
+
   /* Cached copy of the previous frame's resume address.  */
   struct {
     int p;
@@ -190,6 +197,9 @@ fprint_frame_type (struct ui_file *file,
     case SIGTRAMP_FRAME:
       fprintf_unfiltered (file, "SIGTRAMP_FRAME");
       return;
+    case ARCH_FRAME:
+      fprintf_unfiltered (file, "ARCH_FRAME");
+      return;
     default:
       fprintf_unfiltered (file, "<unknown type>");
       return;
@@ -459,7 +469,7 @@ frame_pc_unwind (struct frame_info *this
   if (!this_frame->prev_pc.p)
     {
       CORE_ADDR pc;
-      if (gdbarch_unwind_pc_p (get_frame_arch (this_frame)))
+      if (gdbarch_unwind_pc_p (frame_arch_unwind (this_frame)))
 	{
 	  /* The right way.  The `pure' way.  The one true way.  This
 	     method depends solely on the register-unwind code to
@@ -477,7 +487,7 @@ frame_pc_unwind (struct frame_info *this
 	     frame.  This is all in stark contrast to the old
 	     FRAME_SAVED_PC which would try to directly handle all the
 	     different ways that a PC could be unwound.  */
-	  pc = gdbarch_unwind_pc (get_frame_arch (this_frame), this_frame);
+	  pc = gdbarch_unwind_pc (frame_arch_unwind (this_frame), this_frame);
 	}
       else
 	internal_error (__FILE__, __LINE__, _("No unwind_pc method"));
@@ -647,17 +657,18 @@ get_frame_register (struct frame_info *f
 struct value *
 frame_unwind_register_value (struct frame_info *frame, int regnum)
 {
+  struct gdbarch *gdbarch;
   struct value *value;
 
   gdb_assert (frame != NULL);
+  gdbarch = frame_arch_unwind (frame);
 
   if (frame_debug)
     {
       fprintf_unfiltered (gdb_stdlog, "\
 { frame_unwind_register_value (frame=%d,regnum=%d(%s),...) ",
 			  frame->level, regnum,
-			  user_reg_map_regnum_to_name
-			    (get_frame_arch (frame), regnum));
+			  user_reg_map_regnum_to_name (gdbarch, regnum));
     }
 
   /* Find the unwinder.  */
@@ -692,7 +703,7 @@ frame_unwind_register_value (struct fram
 
 	      fprintf_unfiltered (gdb_stdlog, " bytes=");
 	      fprintf_unfiltered (gdb_stdlog, "[");
-	      for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++)
+	      for (i = 0; i < register_size (gdbarch, regnum); i++)
 		fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
 	      fprintf_unfiltered (gdb_stdlog, "]");
 	    }
@@ -715,7 +726,7 @@ frame_unwind_register_signed (struct fra
 {
   gdb_byte buf[MAX_REGISTER_SIZE];
   frame_unwind_register (frame, regnum, buf);
-  return extract_signed_integer (buf, register_size (get_frame_arch (frame),
+  return extract_signed_integer (buf, register_size (frame_arch_unwind (frame),
 						     regnum));
 }
 
@@ -730,7 +741,7 @@ frame_unwind_register_unsigned (struct f
 {
   gdb_byte buf[MAX_REGISTER_SIZE];
   frame_unwind_register (frame, regnum, buf);
-  return extract_unsigned_integer (buf, register_size (get_frame_arch (frame),
+  return extract_unsigned_integer (buf, register_size (frame_arch_unwind (frame),
 						       regnum));
 }
 
@@ -1046,6 +1057,8 @@ select_frame (struct frame_info *fi)
      source language of this frame, and switch to it if desired.  */
   if (fi)
     {
+      current_gdbarch = get_frame_arch (fi);
+
       /* We retrieve the frame's symtab by using the frame PC.  However
          we cannot use the frame PC as-is, because it usually points to
          the instruction following the "call", which is sometimes the
@@ -1771,12 +1784,42 @@ safe_frame_unwind_memory (struct frame_i
   return !target_read_memory (addr, buf, len);
 }
 
-/* Architecture method.  */
+/* Architecture methods.  */
 
 struct gdbarch *
 get_frame_arch (struct frame_info *this_frame)
 {
-  return current_gdbarch;
+  return frame_arch_unwind (this_frame->next);
+}
+
+struct gdbarch *
+frame_arch_unwind (struct frame_info *next_frame)
+{
+  if (!next_frame->prev_arch.p)
+    {
+      struct gdbarch *arch;
+
+      if (next_frame->unwind == NULL)
+	next_frame->unwind
+	  = frame_unwind_find_by_frame (next_frame,
+					&next_frame->prologue_cache);
+
+      if (next_frame->unwind->prev_arch != NULL)
+	arch = next_frame->unwind->prev_arch (next_frame,
+					      &next_frame->prologue_cache);
+      else
+	arch = get_frame_arch (next_frame);
+
+      next_frame->prev_arch.arch = arch;
+      next_frame->prev_arch.p = 1;
+      if (frame_debug)
+	fprintf_unfiltered (gdb_stdlog,
+			    "{ frame_arch_unwind (next_frame=%d) -> %s }\n",
+			    next_frame->level,
+			    gdbarch_bfd_arch_info (arch)->printable_name);
+    }
+
+  return next_frame->prev_arch.arch;
 }
 
 /* Stack pointer methods.  */
Index: src/gdb/frame.h
===================================================================
--- src.orig/gdb/frame.h
+++ src/gdb/frame.h
@@ -180,6 +180,8 @@ enum frame_type
   /* In a signal handler, various OSs handle this in various ways.
      The main thing is that the frame may be far from normal.  */
   SIGTRAMP_FRAME,
+  /* Fake frame representing a cross-architecture call.  */
+  ARCH_FRAME,
   /* Sentinel or registers frame.  This frame obtains register values
      direct from the inferior's registers.  */
   SENTINEL_FRAME
@@ -518,6 +520,7 @@ extern int safe_frame_unwind_memory (str
 /* Return this frame's architecture.  */
 
 extern struct gdbarch *get_frame_arch (struct frame_info *this_frame);
+extern struct gdbarch *frame_arch_unwind (struct frame_info *next_frame);
 
 
 /* Values for the source flag to be used in print_frame_info_base().  */
Index: src/gdb/frame-unwind.c
===================================================================
--- src.orig/gdb/frame-unwind.c
+++ src/gdb/frame-unwind.c
@@ -126,7 +126,7 @@ default_frame_sniffer (const struct fram
 struct value *
 frame_unwind_got_optimized (struct frame_info *frame, int regnum)
 {
-  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch *gdbarch = frame_arch_unwind (frame);
   struct value *reg_val;
 
   reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
@@ -149,7 +149,7 @@ frame_unwind_got_register (struct frame_
 struct value *
 frame_unwind_got_memory (struct frame_info *frame, int regnum, CORE_ADDR addr)
 {
-  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch *gdbarch = frame_arch_unwind (frame);
 
   return value_at_lazy (register_type (gdbarch, regnum), addr);
 }
@@ -161,7 +161,7 @@ struct value *
 frame_unwind_got_constant (struct frame_info *frame, int regnum,
 			   ULONGEST val)
 {
-  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch *gdbarch = frame_arch_unwind (frame);
   struct value *reg_val;
 
   reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
@@ -173,7 +173,7 @@ frame_unwind_got_constant (struct frame_
 struct value *
 frame_unwind_got_bytes (struct frame_info *frame, int regnum, gdb_byte *buf)
 {
-  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch *gdbarch = frame_arch_unwind (frame);
   struct value *reg_val;
 
   reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
@@ -189,7 +189,7 @@ struct value *
 frame_unwind_got_address (struct frame_info *frame, int regnum,
 			  CORE_ADDR addr)
 {
-  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch *gdbarch = frame_arch_unwind (frame);
   struct value *reg_val;
 
   reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
Index: src/gdb/frame-unwind.h
===================================================================
--- src.orig/gdb/frame-unwind.h
+++ src/gdb/frame-unwind.h
@@ -121,6 +121,13 @@ typedef struct value * (frame_prev_regis
 typedef void (frame_dealloc_cache_ftype) (struct frame_info *self,
 					  void *this_cache);
 
+/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
+   use THIS frame, and implicitly the NEXT frame's register unwind
+   method, return PREV frame's architecture.  */
+
+typedef struct gdbarch *(frame_prev_arch_ftype) (struct frame_info *this_frame,
+						 void **this_prologue_cache);
+
 struct frame_unwind
 {
   /* The frame's type.  Should this instead be a collection of
@@ -133,6 +140,7 @@ struct frame_unwind
   const struct frame_data *unwind_data;
   frame_sniffer_ftype *sniffer;
   frame_dealloc_cache_ftype *dealloc_cache;
+  frame_prev_arch_ftype *prev_arch;
 };
 
 /* Register a frame unwinder, _prepending_ it to the front of the
Index: src/gdb/sentinel-frame.c
===================================================================
--- src.orig/gdb/sentinel-frame.c
+++ src/gdb/sentinel-frame.c
@@ -76,11 +76,23 @@ sentinel_frame_this_id (struct frame_inf
   internal_error (__FILE__, __LINE__, _("sentinel_frame_this_id called"));
 }
 
+static struct gdbarch *
+sentinel_frame_prev_arch (struct frame_info *this_frame,
+			  void **this_prologue_cache)
+{
+  struct frame_unwind_cache *cache = *this_prologue_cache;
+  return get_regcache_arch (cache->regcache);
+}
+
 const struct frame_unwind sentinel_frame_unwinder =
 {
   SENTINEL_FRAME,
   sentinel_frame_this_id,
-  sentinel_frame_prev_register
+  sentinel_frame_prev_register,
+  NULL,
+  NULL,
+  NULL,
+  sentinel_frame_prev_arch,
 };
 
 const struct frame_unwind *const sentinel_frame_unwind = &sentinel_frame_unwinder;
Index: src/gdb/stack.c
===================================================================
--- src.orig/gdb/stack.c
+++ src/gdb/stack.c
@@ -473,7 +473,8 @@ print_frame_info (struct frame_info *fra
   int location_print;
 
   if (get_frame_type (frame) == DUMMY_FRAME
-      || get_frame_type (frame) == SIGTRAMP_FRAME)
+      || get_frame_type (frame) == SIGTRAMP_FRAME
+      || get_frame_type (frame) == ARCH_FRAME)
     {
       struct cleanup *uiout_cleanup
 	= make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
@@ -506,6 +507,10 @@ print_frame_info (struct frame_info *fra
 	  annotate_signal_handler_caller ();
           ui_out_field_string (uiout, "func", "<signal handler called>");
         }
+      else if (get_frame_type (frame) == ARCH_FRAME)
+        {
+          ui_out_field_string (uiout, "func", "<cross-architecture call>");
+	}
       ui_out_text (uiout, "\n");
       annotate_frame_end ();
 
-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com


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