Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: "Maciej W. Rozycki" <macro@codesourcery.com>
To: <gdb-patches@sourceware.org>
Subject: Re: [PATCH] microMIPS support (Linux signal trampolines)
Date: Fri, 18 May 2012 21:32:00 -0000	[thread overview]
Message-ID: <alpine.DEB.1.10.1205171611090.11227@tp.orcam.me.uk> (raw)
In-Reply-To: <alpine.DEB.1.10.1204241843340.19835@tp.orcam.me.uk>

Hi,

On Tue, 24 Apr 2012, Maciej W. Rozycki wrote:

>  Here's a change that adds support for debugging binaries containing 
> microMIPS code.  There's not much to say about it except that it works. ;)  

 And with the update below it works even better. :)

 The necessity for this change was revealed in the course of investigation 
related to my recent ISA bit submission.  It adds support for Linux signal 
trampolines encoded with the microMIPS instruction set.  Such trampolines 
are used by the Linux kernel if compiled as a microMIPS binary (even if 
the binary run/debugged itself contains no microMIPS code at all).  Until 
recently the reliability of such kernel binaries was not good enough for 
regression testing as they would typically not get through at all.  
Therefore the need for this change was not covered and escaped testing.  
It was revealed by code inspection.

 To see if we need to check whether the execution mode selected matches 
the given trampoline I have checked what the bit patterns of all the 
trampoline sequences decode to in the opposite instruction set.  This 
produced useless or at least unusual code in most cases, for example:

microMIPS/EB, o32 sigreturn, decoded as MIPS:
	30401017 	andi	zero,v0,0x1017
	00008b7c 	dsll32	s1,zero,0xd

MIPS/EL, o32 sigreturn, decoded as microMIPS:
	1017 2402 	addi	zero,s7,9218
	000c 0000 	sll	zero,t0,0x0

However in some corner cases reasonable code can mimic a trampoline, for 
example:

MIPS/EB, n32 rt_sigreturn, decoded as microMIPS:
	2402      	sll	s0,s0,1
	1843 0000 	sb	v0,0(v1)
	000c 0f3c 	jr	t0

-- here the first instruction is a 16-bit one making things nastier even 
as there are some other microMIPS instructions whose first 16-bit halfword 
is 0x000c and therefore matches this whole trampoline pattern.

 To overcome this problem I have decided the signal trampoline unwinder 
has to ask the platform backend whether it can apply a given trampoline 
pattern to the code location being concerned or not.  Anticipating the 
acceptance of the ISA bit proposal I decided the handler not to merely be 
a predicate, but also to be able to provide an adjusted PC if required.  
I decided that returning zero will mean that the trampoline pattern is not 
applicable and any other value is the adjusted PC to use; a handler may 
return the value requested if the trampoline pattern and the PC requested 
as-is are both accepted.

 This changes the semantics of the trampoline unwinder a bit in that the 
zero PC now has a special value.  I think this should be safe as a NULL 
pointer is generally supposed to be invalid.  Let me know if you think 
that could cause any troubles (the zero PC serves as a frame chain 
termination mark in some ABIs, including the MIPS ABI; I have a vague 
recollection that it is actually already caught elsewhere, but couldn't 
track that place down easily).

 A corresponding change will be required to the ISA bit proposal that I 
shall send separately -- the signal trampoline unwinder is a piece of 
generic code that interpretes the instruction stream (hopefully this is 
the only such place across GDB), so it has to see the ISA bit stripped off 
which the change below doesn't do for obvious reasons.

 Also obviously, if the ISA bit was stripped off from the PC as execution 
stopped in an actual trampoline, then we'll never have a chance to know 
that we stopped in the microMIPS mode in the first place as the trampoline 
will not have any symbol information associated and by now the ISA bit has 
been lost.  Which really means the change below will only make sense once 
the ISA bit proposal has got in.

 I'll be pushing this update through testing now.  I don't expect any 
problems, the change is mostly mechanical (as noted before microMIPS 
instructions, similarly to MIPS16 ones, are sequences of halfwords, hence 
the different arrangement of the instruction patterns used; POOL32A is the 
name of the major opcode the SYSCALL instruction is assigned to, that 
takes the upper six bits and happens to be all-zeros, the rest of the 
halfword is the SYSCALL immediate "argument" that is all-zeros too).

 Given that this change touches generic parts, the note about the ISA bit 
above, and that the original microMIPS change has worked correctly for 
many months now (especially given that microMIPS Linux kernel binaries may 
have only recently become usable), I decided I would be treating these two 
patches as separate and will therefore commit the microMIPS patch in its 
original form straight away.

 Meanwhile I'll be happy to answer any questions.

2011-05-18  Maciej W. Rozycki  <macro@codesourcery.com>

	gdb/
	* tramp-frame.h (tramp_frame): Add validate member.
	* tramp-frame.c (tramp_frame_start): Validate trampoline before
	scanning.
	* mips-linux-tdep.c (MICROMIPS_INST_LI_V0): New macro.
	(MICROMIPS_INST_POOL32A, MICROMIPS_INST_SYSCALL): Likewise.
	(mips_linux_o32_sigframe): Initialize validate member.
	(mips_linux_o32_rt_sigframe): Likewise.
	(mips_linux_n32_rt_sigframe): Likewise.
	(mips_linux_n64_rt_sigframe): Likewise.
	(micromips_linux_o32_sigframe): New variable.
	(micromips_linux_o32_rt_sigframe): Likewise.
	(micromips_linux_n32_rt_sigframe): Likewise.
	(micromips_linux_n64_rt_sigframe): Likewise.
	(mips_linux_o32_sigframe_init): Handle microMIPS trampolines.
	(mips_linux_n32n64_sigframe_init): Likewise.
	(mips_linux_sigframe_validate): New function.
	(micromips_linux_sigframe_validate): Likewise.
	(mips_linux_init_abi): Install microMIPS trampoline unwinders.

  Maciej

gdb-micromips-linux-sigtramp.diff
Index: gdb-fsf-trunk-quilt/gdb/mips-linux-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mips-linux-tdep.c	2012-05-18 19:46:29.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mips-linux-tdep.c	2012-05-18 20:41:04.625560181 +0100
@@ -800,6 +800,14 @@ static void mips_linux_n32n64_sigframe_i
 					     struct trad_frame_cache *this_cache,
 					     CORE_ADDR func);
 
+static CORE_ADDR mips_linux_sigframe_validate (const struct tramp_frame *self,
+					       struct frame_info *this_frame,
+					       CORE_ADDR pc);
+
+static CORE_ADDR micromips_linux_sigframe_validate (const struct tramp_frame *self,
+						    struct frame_info *this_frame,
+						    CORE_ADDR pc);
+
 #define MIPS_NR_LINUX 4000
 #define MIPS_NR_N64_LINUX 5000
 #define MIPS_NR_N32_LINUX 6000
@@ -815,6 +823,10 @@ static void mips_linux_n32n64_sigframe_i
 #define MIPS_INST_LI_V0_N32_RT_SIGRETURN 0x24020000 + MIPS_NR_N32_rt_sigreturn
 #define MIPS_INST_SYSCALL 0x0000000c
 
+#define MICROMIPS_INST_LI_V0 0x3040
+#define MICROMIPS_INST_POOL32A 0x0000
+#define MICROMIPS_INST_SYSCALL 0x8b7c
+
 static const struct tramp_frame mips_linux_o32_sigframe = {
   SIGTRAMP_FRAME,
   4,
@@ -823,7 +835,8 @@ static const struct tramp_frame mips_lin
     { MIPS_INST_SYSCALL, -1 },
     { TRAMP_SENTINEL_INSN, -1 }
   },
-  mips_linux_o32_sigframe_init
+  mips_linux_o32_sigframe_init,
+  mips_linux_sigframe_validate
 };
 
 static const struct tramp_frame mips_linux_o32_rt_sigframe = {
@@ -833,7 +846,8 @@ static const struct tramp_frame mips_lin
     { MIPS_INST_LI_V0_RT_SIGRETURN, -1 },
     { MIPS_INST_SYSCALL, -1 },
     { TRAMP_SENTINEL_INSN, -1 } },
-  mips_linux_o32_sigframe_init
+  mips_linux_o32_sigframe_init,
+  mips_linux_sigframe_validate
 };
 
 static const struct tramp_frame mips_linux_n32_rt_sigframe = {
@@ -844,7 +858,8 @@ static const struct tramp_frame mips_lin
     { MIPS_INST_SYSCALL, -1 },
     { TRAMP_SENTINEL_INSN, -1 }
   },
-  mips_linux_n32n64_sigframe_init
+  mips_linux_n32n64_sigframe_init,
+  mips_linux_sigframe_validate
 };
 
 static const struct tramp_frame mips_linux_n64_rt_sigframe = {
@@ -855,7 +870,63 @@ static const struct tramp_frame mips_lin
     { MIPS_INST_SYSCALL, -1 },
     { TRAMP_SENTINEL_INSN, -1 }
   },
-  mips_linux_n32n64_sigframe_init
+  mips_linux_n32n64_sigframe_init,
+  mips_linux_sigframe_validate
+};
+
+static const struct tramp_frame micromips_linux_o32_sigframe = {
+  SIGTRAMP_FRAME,
+  2,
+  {
+    { MICROMIPS_INST_LI_V0, -1 },
+    { MIPS_NR_sigreturn, -1 },
+    { MICROMIPS_INST_POOL32A, -1 },
+    { MICROMIPS_INST_SYSCALL, -1 },
+    { TRAMP_SENTINEL_INSN, -1 }
+  },
+  mips_linux_o32_sigframe_init,
+  micromips_linux_sigframe_validate
+};
+
+static const struct tramp_frame micromips_linux_o32_rt_sigframe = {
+  SIGTRAMP_FRAME,
+  2,
+  {
+    { MICROMIPS_INST_LI_V0, -1 },
+    { MIPS_NR_rt_sigreturn, -1 },
+    { MICROMIPS_INST_POOL32A, -1 },
+    { MICROMIPS_INST_SYSCALL, -1 },
+    { TRAMP_SENTINEL_INSN, -1 } },
+  mips_linux_o32_sigframe_init,
+  micromips_linux_sigframe_validate
+};
+
+static const struct tramp_frame micromips_linux_n32_rt_sigframe = {
+  SIGTRAMP_FRAME,
+  2,
+  {
+    { MICROMIPS_INST_LI_V0, -1 },
+    { MIPS_NR_N32_rt_sigreturn, -1 },
+    { MICROMIPS_INST_POOL32A, -1 },
+    { MICROMIPS_INST_SYSCALL, -1 },
+    { TRAMP_SENTINEL_INSN, -1 }
+  },
+  mips_linux_n32n64_sigframe_init,
+  micromips_linux_sigframe_validate
+};
+
+static const struct tramp_frame micromips_linux_n64_rt_sigframe = {
+  SIGTRAMP_FRAME,
+  2,
+  {
+    { MICROMIPS_INST_LI_V0, -1 },
+    { MIPS_NR_N64_rt_sigreturn, -1 },
+    { MICROMIPS_INST_POOL32A, -1 },
+    { MICROMIPS_INST_SYSCALL, -1 },
+    { TRAMP_SENTINEL_INSN, -1 }
+  },
+  mips_linux_n32n64_sigframe_init,
+  micromips_linux_sigframe_validate
 };
 
 /* *INDENT-OFF* */
@@ -942,7 +1013,8 @@ mips_linux_o32_sigframe_init (const stru
   const struct mips_regnum *regs = mips_regnum (gdbarch);
   CORE_ADDR regs_base;
 
-  if (self == &mips_linux_o32_sigframe)
+  if (self == &mips_linux_o32_sigframe
+      || self == &micromips_linux_o32_sigframe)
     sigcontext_base = frame_sp + SIGFRAME_SIGCONTEXT_OFFSET;
   else
     sigcontext_base = frame_sp + RTSIGFRAME_SIGCONTEXT_OFFSET;
@@ -1107,7 +1179,8 @@ mips_linux_n32n64_sigframe_init (const s
   CORE_ADDR sigcontext_base;
   const struct mips_regnum *regs = mips_regnum (gdbarch);
 
-  if (self == &mips_linux_n32_rt_sigframe)
+  if (self == &mips_linux_n32_rt_sigframe
+      || self == &micromips_linux_n32_rt_sigframe)
     sigcontext_base = frame_sp + N32_SIGFRAME_SIGCONTEXT_OFFSET;
   else
     sigcontext_base = frame_sp + N64_SIGFRAME_SIGCONTEXT_OFFSET;
@@ -1151,6 +1224,22 @@ mips_linux_n32n64_sigframe_init (const s
   trad_frame_set_id (this_cache, frame_id_build (frame_sp, func));
 }
 
+static CORE_ADDR
+mips_linux_sigframe_validate (const struct tramp_frame *self,
+			      struct frame_info *this_frame,
+			      CORE_ADDR pc)
+{
+  return mips_pc_is_mips (pc) ? pc : 0;
+}
+
+static CORE_ADDR
+micromips_linux_sigframe_validate (const struct tramp_frame *self,
+				   struct frame_info *this_frame,
+				   CORE_ADDR pc)
+{
+  return mips_pc_is_micromips (get_frame_arch (this_frame), pc) ? pc : 0;
+}
+
 /* Implement the "write_pc" gdbarch method.  */
 
 static void
@@ -1254,6 +1343,9 @@ mips_linux_init_abi (struct gdbarch_info
 	                                mips_linux_get_longjmp_target);
 	set_solib_svr4_fetch_link_map_offsets
 	  (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+	tramp_frame_prepend_unwinder (gdbarch, &micromips_linux_o32_sigframe);
+	tramp_frame_prepend_unwinder (gdbarch,
+				      &micromips_linux_o32_rt_sigframe);
 	tramp_frame_prepend_unwinder (gdbarch, &mips_linux_o32_sigframe);
 	tramp_frame_prepend_unwinder (gdbarch, &mips_linux_o32_rt_sigframe);
 	set_xml_syscall_file_name ("syscalls/mips-o32-linux.xml");
@@ -1269,6 +1361,8 @@ mips_linux_init_abi (struct gdbarch_info
 	   except that the quiet/signalling NaN bit is reversed (GDB
 	   does not distinguish between quiet and signalling NaNs).  */
 	set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
+	tramp_frame_prepend_unwinder (gdbarch,
+				      &micromips_linux_n32_rt_sigframe);
 	tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n32_rt_sigframe);
 	set_xml_syscall_file_name ("syscalls/mips-n32-linux.xml");
 	break;
@@ -1283,6 +1377,8 @@ mips_linux_init_abi (struct gdbarch_info
 	   except that the quiet/signalling NaN bit is reversed (GDB
 	   does not distinguish between quiet and signalling NaNs).  */
 	set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
+	tramp_frame_prepend_unwinder (gdbarch,
+				      &micromips_linux_n64_rt_sigframe);
 	tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n64_rt_sigframe);
 	set_xml_syscall_file_name ("syscalls/mips-n64-linux.xml");
 	break;
Index: gdb-fsf-trunk-quilt/gdb/tramp-frame.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/tramp-frame.c	2012-02-24 15:23:42.000000000 +0000
+++ gdb-fsf-trunk-quilt/gdb/tramp-frame.c	2012-05-18 20:03:53.775469792 +0100
@@ -87,6 +87,12 @@ tramp_frame_start (const struct tramp_fr
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int ti;
 
+  /* Check if we can use this trampoline.  */
+  if (tramp->validate)
+    pc = tramp->validate (tramp, this_frame, pc);
+  if (pc == 0)
+    return 0;
+
   /* Search through the trampoline for one that matches the
      instruction sequence around PC.  */
   for (ti = 0; tramp->insn[ti].bytes != TRAMP_SENTINEL_INSN; ti++)
Index: gdb-fsf-trunk-quilt/gdb/tramp-frame.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/tramp-frame.h	2012-02-24 15:23:42.000000000 +0000
+++ gdb-fsf-trunk-quilt/gdb/tramp-frame.h	2012-05-18 19:56:11.745630232 +0100
@@ -69,6 +69,12 @@ struct tramp_frame
 		struct frame_info *this_frame,
 		struct trad_frame_cache *this_cache,
 		CORE_ADDR func);
+  /* Check if the tramp-frame is valid for the PC requested.  Return
+     the address to check the instruction sequence against if so,
+     otherwise zero.  If this is NULL, then any PC is valid.  */
+  CORE_ADDR (*validate) (const struct tramp_frame *self,
+			 struct frame_info *this_frame,
+			 CORE_ADDR pc);
 };
 
 void tramp_frame_prepend_unwinder (struct gdbarch *gdbarch,


  parent reply	other threads:[~2012-05-18 21:32 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-04-24 21:18 [PATCH] microMIPS support Maciej W. Rozycki
2012-04-25  6:20 ` Eli Zaretskii
2012-04-26 13:54   ` Maciej W. Rozycki
2012-04-26 14:14     ` Eli Zaretskii
2012-04-26 18:03       ` Maciej W. Rozycki
2012-04-26 20:39         ` Eli Zaretskii
2012-04-27 18:16           ` Maciej W. Rozycki
2012-04-27 18:24             ` Eli Zaretskii
     [not found]               ` <alpine.DEB.1.10.1204302334520.19835@tp.orcam.me.uk>
2012-05-02 16:39                 ` Eli Zaretskii
2012-05-17 15:07                   ` Maciej W. Rozycki
2012-05-17 16:10                     ` Eli Zaretskii
2012-05-18 23:13                       ` Maciej W. Rozycki
2012-05-19  8:20                         ` Eli Zaretskii
2012-04-25 13:13 ` Yao Qi
2012-04-25 15:57   ` Maciej W. Rozycki
2012-04-25 15:54 ` Joel Brobecker
2012-04-25 17:18   ` Maciej W. Rozycki
2012-04-25 18:12     ` Joel Brobecker
2012-04-25 18:27       ` Maciej W. Rozycki
2012-04-26 18:38 ` Jan Kratochvil
2012-04-26 19:04   ` Maciej W. Rozycki
2012-04-26 19:29     ` Jan Kratochvil
2012-04-26 21:59       ` Maciej W. Rozycki
2012-04-27  7:11         ` Jan Kratochvil
2012-04-27 15:14           ` Maciej W. Rozycki
2012-04-27 15:29             ` Pedro Alves
2012-04-27 15:46               ` Maciej W. Rozycki
2012-04-27 15:54             ` Tom Tromey
2012-05-18 23:53     ` Maciej W. Rozycki
2012-05-18 21:32 ` Maciej W. Rozycki [this message]
2012-05-18 22:25   ` [PATCH] microMIPS support (Linux signal trampolines) Mark Kettenis
2012-05-21 14:33     ` Maciej W. Rozycki
2012-06-11 10:32       ` [PING][PATCH] " Maciej W. Rozycki
2014-09-28 11:12       ` [PATCH] " Maciej W. Rozycki
2014-10-06  0:46         ` [PING][PATCH] " Maciej W. Rozycki
2014-10-13 12:24           ` [PING^2][PATCH] " Maciej W. Rozycki
2014-10-20 17:01             ` [PING^3][PATCH] " Maciej W. Rozycki
2014-11-03 16:04               ` [PING^4][PATCH] " Maciej W. Rozycki
2014-11-16  8:58         ` [PATCH] " Joel Brobecker
2014-12-03 21:00           ` Maciej W. Rozycki
2012-05-18 23:47 ` [PATCH] microMIPS support Maciej W. Rozycki
2012-05-19  8:52   ` Eli Zaretskii
2012-05-22  0:07     ` Maciej W. Rozycki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=alpine.DEB.1.10.1205171611090.11227@tp.orcam.me.uk \
    --to=macro@codesourcery.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox