*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / arm-linux-tdep.c
index 682054c44b4c9dfa52aa72d412be1e41628b4135..aa7d0af2b15176393a56cb060cd51b7d9929f587 100644 (file)
@@ -630,6 +630,82 @@ arm_linux_regset_from_core_section (struct gdbarch *gdbarch,
   return NULL;
 }
 
+/* Copy the value of next pc of sigreturn and rt_sigrturn into PC,
+   and return 1.  Return 0 if it is not a rt_sigreturn/sigreturn
+   syscall.  */
+static int
+arm_linux_sigreturn_return_addr (struct frame_info *frame,
+                                unsigned long svc_number,
+                                CORE_ADDR *pc)
+{
+  /* Is this a sigreturn or rt_sigreturn syscall?  */
+  if (svc_number == 119 || svc_number == 173)
+    {
+      if (get_frame_type (frame) == SIGTRAMP_FRAME)
+       {
+         *pc = frame_unwind_caller_pc (frame);
+         return 1;
+       }
+    }
+  return 0;
+}
+
+/* When FRAME is at a syscall instruction, return the PC of the next
+   instruction to be executed.  */
+
+static CORE_ADDR
+arm_linux_syscall_next_pc (struct frame_info *frame)
+{
+  CORE_ADDR pc = get_frame_pc (frame);
+  CORE_ADDR return_addr = 0;
+  int is_thumb = arm_frame_is_thumb (frame);
+  ULONGEST svc_number = 0;
+  int is_sigreturn = 0;
+
+  if (is_thumb)
+    {
+      svc_number = get_frame_register_unsigned (frame, 7);
+    }
+  else
+    {
+      struct gdbarch *gdbarch = get_frame_arch (frame);
+      enum bfd_endian byte_order_for_code = 
+       gdbarch_byte_order_for_code (gdbarch);
+      unsigned long this_instr = 
+       read_memory_unsigned_integer (pc, 4, byte_order_for_code);
+
+      unsigned long svc_operand = (0x00ffffff & this_instr);
+      if (svc_operand)  /* OABI.  */
+       {
+         svc_number = svc_operand - 0x900000;
+       }
+      else /* EABI.  */
+       {
+         svc_number = get_frame_register_unsigned (frame, 7);
+       }
+    }
+
+  is_sigreturn = arm_linux_sigreturn_return_addr (frame, svc_number, 
+                                                 &return_addr);
+
+  if (is_sigreturn)
+    return return_addr;
+  
+  if (is_thumb)
+    {
+      return_addr = pc + 2;
+      /* Addresses for calling Thumb functions have the bit 0 set.  */
+      return_addr |= 1;
+    }
+  else
+    {
+      return_addr = pc + 4;
+    }
+
+  return return_addr;
+}
+
+
 /* Insert a single step breakpoint at the next executed instruction.  */
 
 static int
@@ -688,8 +764,11 @@ arm_linux_copy_svc (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
                    struct regcache *regs, struct displaced_step_closure *dsc)
 {
   CORE_ADDR from = dsc->insn_addr;
+  CORE_ADDR return_to = 0;
+
   struct frame_info *frame;
   unsigned int svc_number = displaced_read_reg (regs, from, 7);
+  int is_sigreturn = 0;
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: copying Linux svc insn %.8lx\n",
@@ -697,13 +776,10 @@ arm_linux_copy_svc (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
 
   frame = get_current_frame ();
 
-  /* Is this a sigreturn or rt_sigreturn syscall?  Note: these are only useful
-     for EABI.  */
-  if (svc_number == 119 || svc_number == 173)
+  is_sigreturn = arm_linux_sigreturn_return_addr(frame, svc_number,
+                                                &return_to);
+  if (is_sigreturn)
     {
-      if (get_frame_type (frame) == SIGTRAMP_FRAME)
-       {
-         CORE_ADDR return_to;
          struct symtab_and_line sal;
 
          if (debug_displaced)
@@ -711,7 +787,6 @@ arm_linux_copy_svc (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
              "sigreturn/rt_sigreturn SVC call. PC in frame = %lx\n",
              (unsigned long) get_frame_pc (frame));
 
-         return_to = frame_unwind_caller_pc (frame);
          if (debug_displaced)
            fprintf_unfiltered (gdb_stdlog, "displaced: unwind pc = %lx. "
              "Setting momentary breakpoint.\n", (unsigned long) return_to);
@@ -743,7 +818,7 @@ arm_linux_copy_svc (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
       else if (debug_displaced)
        fprintf_unfiltered (gdb_stdlog, "displaced: sigreturn/rt_sigreturn "
                            "SVC call not in signal trampoline frame\n");
-    }
+    
 
   /* Preparation: If we detect sigreturn, set momentary breakpoint at resume
                  location, else nothing.
@@ -946,6 +1021,9 @@ arm_linux_init_abi (struct gdbarch_info info,
   set_gdbarch_displaced_step_free_closure (gdbarch,
                                           simple_displaced_step_free_closure);
   set_gdbarch_displaced_step_location (gdbarch, displaced_step_at_entry_point);
+
+
+  tdep->syscall_next_pc = arm_linux_syscall_next_pc;
 }
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */
This page took 0.024604 seconds and 4 git commands to generate.