btrace: identify cpu
[deliverable/binutils-gdb.git] / gdb / btrace.c
index c7932bb33081348caaa435597636cacfdccafe6a..72e85670d1ddb2c7c2ca98d08fcde228c2e56651 100644 (file)
@@ -330,20 +330,18 @@ ftrace_find_caller (struct btrace_function *bfun,
    tail calls ending with a jump).  */
 
 static struct btrace_function *
-ftrace_find_call (struct gdbarch *gdbarch, struct btrace_function *bfun)
+ftrace_find_call (struct btrace_function *bfun)
 {
   for (; bfun != NULL; bfun = bfun->up)
     {
       struct btrace_insn *last;
-      CORE_ADDR pc;
 
       /* We do not allow empty function segments.  */
       gdb_assert (!VEC_empty (btrace_insn_s, bfun->insn));
 
       last = VEC_last (btrace_insn_s, bfun->insn);
-      pc = last->pc;
 
-      if (gdbarch_insn_is_call (gdbarch, pc))
+      if (last->iclass == BTRACE_INSN_CALL)
        break;
     }
 
@@ -355,8 +353,7 @@ ftrace_find_call (struct gdbarch *gdbarch, struct btrace_function *bfun)
    MFUN and FUN are the symbol information we have for this function.  */
 
 static struct btrace_function *
-ftrace_new_return (struct gdbarch *gdbarch,
-                  struct btrace_function *prev,
+ftrace_new_return (struct btrace_function *prev,
                   struct minimal_symbol *mfun,
                   struct symbol *fun)
 {
@@ -391,7 +388,7 @@ ftrace_new_return (struct gdbarch *gdbarch,
         wrong or that the call is simply not included in the trace.  */
 
       /* Let's search for some actual call.  */
-      caller = ftrace_find_call (gdbarch, prev->up);
+      caller = ftrace_find_call (prev->up);
       if (caller == NULL)
        {
          /* There is no call in PREV's back trace.  We assume that the
@@ -454,8 +451,7 @@ ftrace_new_switch (struct btrace_function *prev,
    Return the chronologically latest function segment, never NULL.  */
 
 static struct btrace_function *
-ftrace_update_function (struct gdbarch *gdbarch,
-                       struct btrace_function *bfun, CORE_ADDR pc)
+ftrace_update_function (struct btrace_function *bfun, CORE_ADDR pc)
 {
   struct bound_minimal_symbol bmfun;
   struct minimal_symbol *mfun;
@@ -485,24 +481,29 @@ ftrace_update_function (struct gdbarch *gdbarch,
 
   if (last != NULL)
     {
-      CORE_ADDR lpc;
+      switch (last->iclass)
+       {
+       case BTRACE_INSN_RETURN:
+         return ftrace_new_return (bfun, mfun, fun);
 
-      lpc = last->pc;
+       case BTRACE_INSN_CALL:
+         /* Ignore calls to the next instruction.  They are used for PIC.  */
+         if (last->pc + last->size == pc)
+           break;
 
-      /* Check for returns.  */
-      if (gdbarch_insn_is_ret (gdbarch, lpc))
-       return ftrace_new_return (gdbarch, bfun, mfun, fun);
+         return ftrace_new_call (bfun, mfun, fun);
 
-      /* Check for calls.  */
-      if (gdbarch_insn_is_call (gdbarch, lpc))
-       {
-         int size;
+       case BTRACE_INSN_JUMP:
+         {
+           CORE_ADDR start;
 
-         size = gdb_insn_length (gdbarch, lpc);
+           start = get_pc_function_start (pc);
 
-         /* Ignore calls to the next instruction.  They are used for PIC.  */
-         if (lpc + size != pc)
-           return ftrace_new_call (bfun, mfun, fun);
+           /* If we can't determine the function for PC, we treat a jump at
+              the end of the block as tail call.  */
+           if (start == 0 || start == pc)
+             return ftrace_new_tailcall (bfun, mfun, fun);
+         }
        }
     }
 
@@ -514,24 +515,6 @@ ftrace_update_function (struct gdbarch *gdbarch,
                    ftrace_print_function_name (bfun),
                    ftrace_print_filename (bfun));
 
-      if (last != NULL)
-       {
-         CORE_ADDR start, lpc;
-
-         start = get_pc_function_start (pc);
-
-         /* If we can't determine the function for PC, we treat a jump at
-            the end of the block as tail call.  */
-         if (start == 0)
-           start = pc;
-
-         lpc = last->pc;
-
-         /* Jumps indicate optimized tail calls.  */
-         if (start == pc && gdbarch_insn_is_jump (gdbarch, lpc))
-           return ftrace_new_tailcall (bfun, mfun, fun);
-       }
-
       return ftrace_new_switch (bfun, mfun, fun);
     }
 
@@ -574,29 +557,51 @@ ftrace_update_lines (struct btrace_function *bfun, CORE_ADDR pc)
 /* Add the instruction at PC to BFUN's instructions.  */
 
 static void
-ftrace_update_insns (struct btrace_function *bfun, CORE_ADDR pc)
+ftrace_update_insns (struct btrace_function *bfun,
+                    const struct btrace_insn *insn)
 {
-  struct btrace_insn *insn;
-
-  insn = VEC_safe_push (btrace_insn_s, bfun->insn, NULL);
-  insn->pc = pc;
+  VEC_safe_push (btrace_insn_s, bfun->insn, insn);
 
   if (record_debug > 1)
     ftrace_debug (bfun, "update insn");
 }
 
+/* Classify the instruction at PC.  */
+
+static enum btrace_insn_class
+ftrace_classify_insn (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  volatile struct gdb_exception error;
+  enum btrace_insn_class iclass;
+
+  iclass = BTRACE_INSN_OTHER;
+  TRY_CATCH (error, RETURN_MASK_ERROR)
+    {
+      if (gdbarch_insn_is_call (gdbarch, pc))
+       iclass = BTRACE_INSN_CALL;
+      else if (gdbarch_insn_is_ret (gdbarch, pc))
+       iclass = BTRACE_INSN_RETURN;
+      else if (gdbarch_insn_is_jump (gdbarch, pc))
+       iclass = BTRACE_INSN_JUMP;
+    }
+
+  return iclass;
+}
+
 /* Compute the function branch trace from BTS trace.  */
 
 static void
-btrace_compute_ftrace_bts (struct btrace_thread_info *btinfo,
+btrace_compute_ftrace_bts (struct thread_info *tp,
                           const struct btrace_data_bts *btrace)
 {
+  struct btrace_thread_info *btinfo;
   struct btrace_function *begin, *end;
   struct gdbarch *gdbarch;
   unsigned int blk;
   int level;
 
   gdbarch = target_gdbarch ();
+  btinfo = &tp->btrace;
   begin = btinfo->begin;
   end = btinfo->end;
   level = begin != NULL ? -btinfo->level : INT_MAX;
@@ -614,6 +619,8 @@ btrace_compute_ftrace_bts (struct btrace_thread_info *btinfo,
 
       for (;;)
        {
+         volatile struct gdb_exception error;
+         struct btrace_insn insn;
          int size;
 
          /* We should hit the end of the block.  Warn if we went too far.  */
@@ -624,7 +631,7 @@ btrace_compute_ftrace_bts (struct btrace_thread_info *btinfo,
              break;
            }
 
-         end = ftrace_update_function (gdbarch, end, pc);
+         end = ftrace_update_function (end, pc);
          if (begin == NULL)
            begin = end;
 
@@ -633,16 +640,22 @@ btrace_compute_ftrace_bts (struct btrace_thread_info *btinfo,
          if (blk != 0)
            level = min (level, end->level);
 
-         ftrace_update_insns (end, pc);
+         size = 0;
+         TRY_CATCH (error, RETURN_MASK_ERROR)
+           size = gdb_insn_length (gdbarch, pc);
+
+         insn.pc = pc;
+         insn.size = size;
+         insn.iclass = ftrace_classify_insn (gdbarch, pc);
+
+         ftrace_update_insns (end, &insn);
          ftrace_update_lines (end, pc);
 
          /* We're done once we pushed the instruction at the end.  */
          if (block->end == pc)
            break;
 
-         size = gdb_insn_length (gdbarch, pc);
-
-         /* Make sure we terminate if we fail to compute the size.  */
+         /* We can't continue if we fail to compute the size.  */
          if (size <= 0)
            {
              warning (_("Recorded trace may be incomplete around %s."),
@@ -676,8 +689,7 @@ btrace_compute_ftrace_bts (struct btrace_thread_info *btinfo,
    a thread given by BTINFO.  */
 
 static void
-btrace_compute_ftrace (struct btrace_thread_info *btinfo,
-                      struct btrace_data *btrace)
+btrace_compute_ftrace (struct thread_info *tp, struct btrace_data *btrace)
 {
   DEBUG ("compute ftrace");
 
@@ -687,7 +699,7 @@ btrace_compute_ftrace (struct btrace_thread_info *btinfo,
       return;
 
     case BTRACE_FORMAT_BTS:
-      btrace_compute_ftrace_bts (btinfo, &btrace->variant.bts);
+      btrace_compute_ftrace_bts (tp, &btrace->variant.bts);
       return;
     }
 
@@ -718,7 +730,7 @@ btrace_add_pc (struct thread_info *tp)
   block->begin = pc;
   block->end = pc;
 
-  btrace_compute_ftrace (&tp->btrace, &btrace);
+  btrace_compute_ftrace (tp, &btrace);
 
   do_cleanups (cleanup);
 }
@@ -964,7 +976,7 @@ btrace_fetch (struct thread_info *tp)
   if (!btrace_data_empty (&btrace))
     {
       btrace_clear_history (btinfo);
-      btrace_compute_ftrace (btinfo, &btrace);
+      btrace_compute_ftrace (tp, &btrace);
     }
 
   do_cleanups (cleanup);
This page took 0.028503 seconds and 4 git commands to generate.