From: "Edgar E. Iglesias" <[email protected]>

Signed-off-by: Edgar E. Iglesias <[email protected]>
---
 sysdeps/linux-gnu/mipsel/arch.h  |    1 +
 sysdeps/linux-gnu/mipsel/trace.c |  164 ++++++++++++++++++++++++++++++++++++++
 sysdeps/linux-gnu/trace.c        |    2 +-
 3 files changed, 166 insertions(+), 1 deletions(-)

diff --git a/sysdeps/linux-gnu/mipsel/arch.h b/sysdeps/linux-gnu/mipsel/arch.h
index cfb5a4d..23fe167 100644
--- a/sysdeps/linux-gnu/mipsel/arch.h
+++ b/sysdeps/linux-gnu/mipsel/arch.h
@@ -42,6 +42,7 @@ struct arch_ltelf_data {
 #define ARCH_HAVE_GET_SYMINFO
 #define ARCH_HAVE_DYNLINK_DONE
 #define ARCH_HAVE_ADD_PLT_ENTRY
+#define ARCH_HAVE_ATOMIC_SINGLESTEP
 
 #define ARCH_HAVE_LIBRARY_SYMBOL_DATA
 enum mips_plt_type
diff --git a/sysdeps/linux-gnu/mipsel/trace.c b/sysdeps/linux-gnu/mipsel/trace.c
index c55ff32..1143397 100644
--- a/sysdeps/linux-gnu/mipsel/trace.c
+++ b/sysdeps/linux-gnu/mipsel/trace.c
@@ -5,6 +5,7 @@
 #include <signal.h>
 #include <sys/ptrace.h>
 #include <asm/ptrace.h>
+#include <assert.h>
 
 #include "backend.h"
 #include "common.h"
@@ -93,6 +94,169 @@ syscall_p(Process *proc, int status, int *sysnum) {
        }
        return 0;
 }
+
+/* Based on GDB code.  */
+#define mips32_op(x) (x >> 26)
+#define itype_op(x) (x >> 26)
+#define itype_rs(x) ((x >> 21) & 0x1f)
+#define itype_rt(x) ((x >> 16) & 0x1f)
+#define itype_immediate(x) (x & 0xffff)
+
+#define jtype_op(x) (x >> 26)
+#define jtype_target(x) (x & 0x03ffffff)
+
+#define rtype_op(x) (x >> 26)
+#define rtype_rs(x) ((x >> 21) & 0x1f)
+#define rtype_rt(x) ((x >> 16) & 0x1f)
+#define rtype_rd(x) ((x >> 11) & 0x1f)
+#define rtype_shamt(x) ((x >> 6) & 0x1f)
+#define rtype_funct(x) (x & 0x3f)
+
+static int32_t
+mips32_relative_offset (uint32_t inst)
+{
+  return ((itype_immediate (inst) ^ 0x8000) - 0x8000) << 2;
+}
+
+int mips_next_pcs(struct Process *proc, uint32_t pc, uint32_t *newpc)
+{
+       uint32_t inst, rx;
+       int op;
+       int rn;
+       int nr = 0;
+
+       inst = ptrace(PTRACE_PEEKTEXT, proc->pid, pc, 0);
+
+       if ((inst & 0xe0000000) != 0) {
+               /* Check for branches.  */
+               if (itype_op (inst) >> 2 == 5) {
+                       /* BEQL, BNEL, BLEZL, BGTZL: bits 0101xx */
+                       op = (itype_op (inst) & 0x03);
+                       switch (op)
+                       {
+                       case 0: /* BEQL */
+                       case 1: /* BNEL */
+                       case 2: /* BLEZL */
+                       case 3: /* BGTZL */
+                               newpc[nr++] = pc + 8;
+                               newpc[nr++] = pc + 4 +
+                                       mips32_relative_offset (inst);
+                               break;
+                       default:
+                               newpc[nr++] = pc + 4;
+                               break;
+                       }
+               } else if (itype_op (inst) == 17 && itype_rs (inst) == 8) {
+                       /* Step over the branch.  */
+                       newpc[nr++] = pc + 8;
+                       newpc[nr++] = pc + mips32_relative_offset (inst) + 4;
+               } else {
+                       newpc[nr++] = pc + 4;
+               }
+       } else {
+               /* Further subdivide into SPECIAL, REGIMM and other.  */
+               switch (op = itype_op (inst) & 0x07)
+               {
+               case 0:
+                       op = rtype_funct (inst);
+                       switch (op)
+                       {
+                       case 8: /* JR  */
+                       case 9: /* JALR  */
+                               rn = rtype_rs (inst);
+
+                               rx = ptrace(PTRACE_PEEKUSER,proc->pid, rn, 0);
+                               newpc[nr++] = rx;
+                               break;
+                       default:
+                       case 12:        /* SYSCALL  */
+                               newpc[nr++] = pc + 4;
+                               break;
+                       }
+                       break;
+               case 1:
+                       op = itype_rt (inst);
+                       switch (op)
+                       {
+                               case 0:
+                               case 1:
+                               case 2:
+                               case 3:
+                               case 16:
+                               case 17:
+                               case 18:
+                               case 19:
+                                       newpc[nr++] = pc + 8;
+                                       newpc[nr++] = pc + 4 +
+                                               mips32_relative_offset(inst);
+                                       break;
+                               default:
+                                       newpc[nr++] = pc + 4;
+                                       break;
+                       }
+                       break;
+               case 2: /* J  */
+               case 3: /* JAL  */
+                       rx = jtype_target (inst) << 2;
+                       /* Upper four bits get never changed...  */
+                       newpc[nr++] = rx + ((pc + 4) & ~0x0fffffff);
+                       break;
+               default:
+               case 4:
+               case 5:
+               case 6:
+               case 7:
+                       /* Step over the branch.  */
+                       newpc[nr++] = pc + 8;
+                       newpc[nr++] = pc + mips32_relative_offset (inst) + 4;
+                       break;
+               }
+       }
+       if (nr <= 0 || nr > 2)
+               goto fail;
+       if (nr == 2) {
+               if (newpc[1] == 0)
+                       goto fail;
+       }
+       if (newpc[0] == 0)
+               goto fail;
+
+       assert(nr == 1 || nr == 2);
+       return nr;
+
+fail:
+       printf("nr=%d pc=%x\n", nr, pc);
+       printf("pc=%x %x\n", newpc[0], newpc[1]);
+       return 0;
+}
+
+int
+arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
+                      int (*add_cb)(void *addr, void *data),
+                      void *add_cb_data)
+{
+       uint32_t pc = (uint32_t) get_instruction_pointer(proc);
+       uint32_t newpcs[2];
+       int nr;
+
+       nr = mips_next_pcs(proc, pc, newpcs);
+
+       while (nr--) {
+               arch_addr_t baddr = (void *) newpcs[nr];
+               /* Not sure what to do here. We've already got a bp.  */
+               if (dict_find_entry(proc->breakpoints, baddr)) {
+                       fprintf(stderr, "skip %p %p\n", baddr, add_cb_data);
+                       continue;
+               }
+
+               if (add_cb(baddr, add_cb_data) < 0)
+                       return -1;
+       }
+
+       ptrace(PTRACE_SYSCALL, proc->pid, 0, 0);
+       return 0;
+}
+
 /**
    \param type Function/syscall call or return.
    \param proc The process that had an event.
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
index 0829bdb..cdc4062 100644
--- a/sysdeps/linux-gnu/trace.c
+++ b/sysdeps/linux-gnu/trace.c
@@ -930,7 +930,7 @@ continue_after_breakpoint(Process *proc, struct breakpoint 
*sbp)
        if (sbp->enabled == 0) {
                continue_process(proc->pid);
        } else {
-#if defined __sparc__  || defined __ia64___ || defined __mips__
+#if defined __sparc__  || defined __ia64___
                /* we don't want to singlestep here */
                continue_process(proc->pid);
 #else
-- 
1.7.8.6


_______________________________________________
Ltrace-devel mailing list
[email protected]
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/ltrace-devel

Reply via email to