diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index a2b0d39..e0bfd21 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,11 @@
+2016-02-07  Marcin KoÅ›cielnicki  <koriakin@0x04.net>
+
+	* gdbarch.c: Regenerate.
+	* gdbarch.h: Regenerate.
+	* gdbarch.sh: Add supply_pseudo_pc hook.
+	* tracefile.c (tracefile_fetch_registers): When PC is a pseudo,
+	ask gdbarch to handle guessed PC via the new hook.
+
 2016-02-04  Yao Qi  <yao.qi@linaro.org>
 
 	* remote.c (remote_wait_as): Set rs->waiting_for_stop_reply to
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 4143744..b323d44 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -181,6 +181,7 @@ struct gdbarch
   int char_signed;
   gdbarch_read_pc_ftype *read_pc;
   gdbarch_write_pc_ftype *write_pc;
+  gdbarch_supply_pseudo_pc_ftype *supply_pseudo_pc;
   gdbarch_virtual_frame_pointer_ftype *virtual_frame_pointer;
   gdbarch_pseudo_register_read_ftype *pseudo_register_read;
   gdbarch_pseudo_register_read_value_ftype *pseudo_register_read_value;
@@ -523,6 +524,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
     gdbarch->char_signed = 1;
   /* Skip verify of read_pc, has predicate.  */
   /* Skip verify of write_pc, has predicate.  */
+  /* Skip verify of supply_pseudo_pc, has predicate.  */
   /* Skip verify of virtual_frame_pointer, invalid_p == 0 */
   /* Skip verify of pseudo_register_read, has predicate.  */
   /* Skip verify of pseudo_register_read_value, has predicate.  */
@@ -1366,6 +1368,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
                       "gdbarch_dump: static_transform_name = <%s>\n",
                       host_address_to_string (gdbarch->static_transform_name));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_supply_pseudo_pc_p() = %d\n",
+                      gdbarch_supply_pseudo_pc_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: supply_pseudo_pc = <%s>\n",
+                      host_address_to_string (gdbarch->supply_pseudo_pc));
+  fprintf_unfiltered (file,
                       "gdbarch_dump: syscalls_info = %s\n",
                       host_address_to_string (gdbarch->syscalls_info));
   fprintf_unfiltered (file,
@@ -1821,6 +1829,30 @@ set_gdbarch_write_pc (struct gdbarch *gdbarch,
   gdbarch->write_pc = write_pc;
 }
 
+int
+gdbarch_supply_pseudo_pc_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->supply_pseudo_pc != NULL;
+}
+
+void
+gdbarch_supply_pseudo_pc (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR val)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->supply_pseudo_pc != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_supply_pseudo_pc called\n");
+  gdbarch->supply_pseudo_pc (regcache, val);
+}
+
+void
+set_gdbarch_supply_pseudo_pc (struct gdbarch *gdbarch,
+                              gdbarch_supply_pseudo_pc_ftype supply_pseudo_pc)
+{
+  gdbarch->supply_pseudo_pc = supply_pseudo_pc;
+}
+
 void
 gdbarch_virtual_frame_pointer (struct gdbarch *gdbarch, CORE_ADDR pc, int *frame_regnum, LONGEST *frame_offset)
 {
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 3fadcd1..bbb0ba3 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -239,6 +239,17 @@ typedef void (gdbarch_write_pc_ftype) (struct regcache *regcache, CORE_ADDR val)
 extern void gdbarch_write_pc (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR val);
 extern void set_gdbarch_write_pc (struct gdbarch *gdbarch, gdbarch_write_pc_ftype *write_pc);
 
+/* Supply given PC into an empty regcache.  Used for tracepoints where
+   no registers have been collected, but there's only one location,
+   allowing us to guess the PC value.  Only used on targets where PC
+   is a pseudo-register - otherwise PC is supplied directly. */
+
+extern int gdbarch_supply_pseudo_pc_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_supply_pseudo_pc_ftype) (struct regcache *regcache, CORE_ADDR val);
+extern void gdbarch_supply_pseudo_pc (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR val);
+extern void set_gdbarch_supply_pseudo_pc (struct gdbarch *gdbarch, gdbarch_supply_pseudo_pc_ftype *supply_pseudo_pc);
+
 /* Function for getting target's idea of a frame pointer.  FIXME: GDB's
    whole scheme for dealing with "frames" and "frame pointers" needs a
    serious shakedown. */
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 4ac6b90..346dc3a 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -417,6 +417,11 @@ v:int:char_signed:::1:-1:1
 #
 F:CORE_ADDR:read_pc:struct regcache *regcache:regcache
 F:void:write_pc:struct regcache *regcache, CORE_ADDR val:regcache, val
+# Supply given PC into an empty regcache.  Used for tracepoints where
+# no registers have been collected, but there's only one location,
+# allowing us to guess the PC value.  Only used on targets where PC
+# is a pseudo-register - otherwise PC is supplied directly.
+F:void:supply_pseudo_pc:struct regcache *regcache, CORE_ADDR val:regcache, val
 # Function for getting target's idea of a frame pointer.  FIXME: GDB's
 # whole scheme for dealing with "frames" and "frame pointers" needs a
 # serious shakedown.
diff --git a/gdb/tracefile.c b/gdb/tracefile.c
index fef4ed9..e3d7b0e 100644
--- a/gdb/tracefile.c
+++ b/gdb/tracefile.c
@@ -396,16 +396,18 @@ tracefile_fetch_registers (struct regcache *regcache, int regno)
      as the address of the tracepoint.  */
   pc_regno = gdbarch_pc_regnum (gdbarch);
 
-  /* XXX This guessing code below only works if the PC register isn't
-     a pseudo-register.  The value of a pseudo-register isn't stored
-     in the (non-readonly) regcache -- instead it's recomputed
-     (probably from some other cached raw register) whenever the
-     register is read.  This guesswork should probably move to some
-     higher layer.  */
-  if (pc_regno < 0 || pc_regno >= gdbarch_num_regs (gdbarch))
+  if (pc_regno < 0)
     return;
 
-  if (regno == -1 || regno == pc_regno)
+  /* We try to guess PC if:
+
+     1) We want all registers, or
+     2) PC is a real register, and we want exactly it, or
+     3) PC is a pseudo register (we don't know which real register it
+	corresponds to, so let's try to play safe).  */
+
+  if (regno == -1 || regno == pc_regno ||
+      pc_regno >= gdbarch_num_regs (gdbarch))
     {
       struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
       gdb_byte *regs;
@@ -429,11 +431,23 @@ tracefile_fetch_registers (struct regcache *regcache, int regno)
 	      return;
 	    }
 
-	  regs = (gdb_byte *) alloca (register_size (gdbarch, pc_regno));
-	  store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
-				  gdbarch_byte_order (gdbarch),
-				  tp->base.loc->address);
-	  regcache_raw_supply (regcache, pc_regno, regs);
+	  if (pc_regno >= gdbarch_num_regs (gdbarch))
+	    {
+	      /* PC is a pseudo, let gdbarch deal with that.  If it doesn't
+		 know how, just bail.  */
+	      if (gdbarch_supply_pseudo_pc_p (gdbarch))
+		gdbarch_supply_pseudo_pc (gdbarch, regcache,
+						     tp->base.loc->address);
+	    }
+	  else
+	    {
+	      /* PC is a real register.  */
+	      regs = (gdb_byte *) alloca (register_size (gdbarch, pc_regno));
+	      store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
+				      gdbarch_byte_order (gdbarch),
+				      tp->base.loc->address);
+	      regcache_raw_supply (regcache, pc_regno, regs);
+	    }
 	}
     }
 }
