* src/gdb/target.h: Remove all tests for already defined
[deliverable/binutils-gdb.git] / gdb / breakpoint.c
index 5a909c8105882dd7906faf4310ced2385bb0b57a..35db0f375d141ed51b046160179d4288c471b7b3 100644 (file)
@@ -25,6 +25,7 @@
 #include "symtab.h"
 #include "frame.h"
 #include "breakpoint.h"
+#include "tracepoint.h"
 #include "gdbtypes.h"
 #include "expression.h"
 #include "gdbcore.h"
 #include "wrapper.h"
 #include "valprint.h"
 
+/* readline include files */
+#include "readline/readline.h"
+#include "readline/history.h"
+
+/* readline defines this.  */
+#undef savestring
+
 #include "mi/mi-common.h"
 
 /* Arguments to pass as context to some catch command handlers.  */
@@ -191,6 +199,21 @@ static int is_hardware_watchpoint (struct breakpoint *bpt);
 
 static void insert_breakpoint_locations (void);
 
+static void tracepoints_info (char *, int);
+
+static void delete_trace_command (char *, int);
+
+static void enable_trace_command (char *, int);
+
+static void disable_trace_command (char *, int);
+
+static void trace_pass_command (char *, int);
+
+/* Flag indicating that a command has proceeded the inferior past the
+   current breakpoint.  */
+
+static int breakpoint_proceeded;
+
 static const char *
 bpdisp_text (enum bpdisp disp)
 {
@@ -309,6 +332,12 @@ static int overlay_events_enabled;
             B ? (TMP=B->global_next, 1): 0;    \
             B = TMP)
 
+/* Iterator for tracepoints only.  */
+
+#define ALL_TRACEPOINTS(B)  \
+  for (B = breakpoint_chain; B; B = B->next)  \
+    if ((B)->type == bp_tracepoint)
+
 /* Chains of all breakpoints defined.  */
 
 struct breakpoint *breakpoint_chain;
@@ -324,6 +353,10 @@ VEC(bp_location_p) *moribund_locations = NULL;
 
 int breakpoint_count;
 
+/* Number of last tracepoint made.  */
+
+int tracepoint_count;
+
 /* Return whether a breakpoint is an active enabled breakpoint.  */
 static int
 breakpoint_enabled (struct breakpoint *b)
@@ -1024,6 +1057,11 @@ should_be_inserted (struct bp_location *bpt)
   if (!bpt->enabled || bpt->shlib_disabled || bpt->duplicate)
     return 0;
 
+  /* Tracepoints are inserted by the target at a time of its choosing,
+     not by us.  */
+  if (bpt->owner->type == bp_tracepoint)
+    return 0;
+
   return 1;
 }
 
@@ -1888,28 +1926,51 @@ int
 breakpoint_thread_match (CORE_ADDR pc, ptid_t ptid)
 {
   const struct bp_location *bpt;
-  int thread;
-
-  thread = pid_to_thread_id (ptid);
-
+  /* The thread and task IDs associated to PTID, computed lazily.  */
+  int thread = -1;
+  int task = 0;
+  
   ALL_BP_LOCATIONS (bpt)
     {
       if (bpt->loc_type != bp_loc_software_breakpoint
          && bpt->loc_type != bp_loc_hardware_breakpoint)
        continue;
 
-      if ((breakpoint_enabled (bpt->owner)
-          || bpt->owner->enable_state == bp_permanent)
-         && bpt->address == pc
-         && (bpt->owner->thread == -1 || bpt->owner->thread == thread))
+      if (!breakpoint_enabled (bpt->owner)
+         && bpt->owner->enable_state != bp_permanent)
+       continue;
+
+      if (bpt->address != pc)
+       continue;
+
+      if (bpt->owner->thread != -1)
        {
-         if (overlay_debugging 
-             && section_is_overlay (bpt->section) 
-             && !section_is_mapped (bpt->section))
-           continue;           /* unmapped overlay -- can't be a match */
-         else
-           return 1;
+         /* This is a thread-specific breakpoint.  Check that ptid
+            matches that thread.  If thread hasn't been computed yet,
+            it is now time to do so.  */
+         if (thread == -1)
+           thread = pid_to_thread_id (ptid);
+         if (bpt->owner->thread != thread)
+           continue;
        }
+
+      if (bpt->owner->task != 0)
+        {
+         /* This is a task-specific breakpoint.  Check that ptid
+            matches that task.  If task hasn't been computed yet,
+            it is now time to do so.  */
+         if (task == 0)
+           task = ada_get_task_number (ptid);
+         if (bpt->owner->task != task)
+           continue;
+        }
+
+      if (overlay_debugging 
+         && section_is_overlay (bpt->section) 
+         && !section_is_mapped (bpt->section))
+       continue;           /* unmapped overlay -- can't be a match */
+
+      return 1;
     }
 
   return 0;
@@ -2083,6 +2144,26 @@ bpstat_clear_actions (bpstat bs)
     }
 }
 
+/* Called when a command is about to proceed the inferior.  */
+
+static void
+breakpoint_about_to_proceed (void)
+{
+  if (!ptid_equal (inferior_ptid, null_ptid))
+    {
+      struct thread_info *tp = inferior_thread ();
+
+      /* Allow inferior function calls in breakpoint commands to not
+        interrupt the command list.  When the call finishes
+        successfully, the inferior will be standing at the same
+        breakpoint as if nothing happened.  */
+      if (tp->in_infcall)
+       return;
+    }
+
+  breakpoint_proceeded = 1;
+}
+
 /* Stub for cleaning up our state if we error-out of a breakpoint command */
 static void
 cleanup_executing_breakpoints (void *ignore)
@@ -2387,6 +2468,7 @@ print_it_typical (bpstat bs)
     case bp_step_resume:
     case bp_watchpoint_scope:
     case bp_call_dummy:
+    case bp_tracepoint:
     default:
       result = PRINT_UNKNOWN;
       break;
@@ -2630,9 +2712,15 @@ watchpoint_check (void *p)
         that the watchpoint frame couldn't be found by frame_find_by_id()
         because the current PC is currently in an epilogue.  Calling
         gdbarch_in_function_epilogue_p() also when fr == NULL fixes that. */
-      if ((!within_current_scope || fr == get_current_frame ())
-          && gdbarch_in_function_epilogue_p (current_gdbarch, read_pc ()))
-       return WP_VALUE_NOT_CHANGED;
+      if (!within_current_scope || fr == get_current_frame ())
+       {
+         struct frame_info *frame = get_current_frame ();
+         struct gdbarch *frame_arch = get_frame_arch (frame);
+         CORE_ADDR frame_pc = get_frame_pc (frame);
+
+         if (gdbarch_in_function_epilogue_p (frame_arch, frame_pc))
+           return WP_VALUE_NOT_CHANGED;
+       }
       if (fr && within_current_scope)
        /* If we end up stopping, the current frame will get selected
           in normal_stop.  So this call to select_frame won't affect
@@ -3288,6 +3376,13 @@ bpstat_what (bpstat bs)
          bs_class = bp_silent;
          retval.call_dummy = 1;
          break;
+       case bp_tracepoint:
+         /* Tracepoint hits should not be reported back to GDB, and
+            if one got through somehow, it should have been filtered
+            out already.  */
+         internal_error (__FILE__, __LINE__,
+                         _("bpstat_what: bp_tracepoint encountered"));
+         break;
        }
       current_action = table[(int) bs_class][(int) current_action];
     }
@@ -3387,6 +3482,7 @@ print_one_breakpoint_location (struct breakpoint *b,
     {bp_thread_event, "thread events"},
     {bp_overlay_event, "overlay events"},
     {bp_catchpoint, "catchpoint"},
+    {bp_tracepoint, "tracepoint"},
   };
   
   static char bpenables[] = "nynny";
@@ -3513,6 +3609,7 @@ print_one_breakpoint_location (struct breakpoint *b,
       case bp_shlib_event:
       case bp_thread_event:
       case bp_overlay_event:
+      case bp_tracepoint:
        if (opts.addressprint)
          {
            annotate_field (4);
@@ -3531,12 +3628,20 @@ print_one_breakpoint_location (struct breakpoint *b,
        break;
       }
 
-  if (!part_of_multiple && b->thread != -1)
+  if (!part_of_multiple)
     {
-      /* FIXME: This seems to be redundant and lost here; see the
-        "stop only in" line a little further down. */
-      ui_out_text (uiout, " thread ");
-      ui_out_field_int (uiout, "thread", b->thread);
+      if (b->thread != -1)
+       {
+         /* FIXME: This seems to be redundant and lost here; see the
+            "stop only in" line a little further down. */
+         ui_out_text (uiout, " thread ");
+         ui_out_field_int (uiout, "thread", b->thread);
+       }
+      else if (b->task != 0)
+       {
+         ui_out_text (uiout, " task ");
+         ui_out_field_int (uiout, "task", b->task);
+       }
     }
   
   ui_out_text (uiout, "\n");
@@ -3557,7 +3662,10 @@ print_one_breakpoint_location (struct breakpoint *b,
          because the condition is an internal implementation detail
          that we do not want to expose to the user.  */
       annotate_field (7);
-      ui_out_text (uiout, "\tstop only if ");
+      if (b->type == bp_tracepoint)
+       ui_out_text (uiout, "\ttrace only if ");
+      else
+       ui_out_text (uiout, "\tstop only if ");
       ui_out_field_string (uiout, "cond", b->cond_string);
       ui_out_text (uiout, "\n");
     }
@@ -3609,6 +3717,34 @@ print_one_breakpoint_location (struct breakpoint *b,
       do_cleanups (script_chain);
     }
 
+  if (!part_of_multiple && b->pass_count)
+    {
+      annotate_field (10);
+      ui_out_text (uiout, "\tpass count ");
+      ui_out_field_int (uiout, "pass", b->pass_count);
+      ui_out_text (uiout, " \n");
+    }
+
+  if (!part_of_multiple && b->step_count)
+    {
+      annotate_field (11);
+      ui_out_text (uiout, "\tstep count ");
+      ui_out_field_int (uiout, "step", b->step_count);
+      ui_out_text (uiout, " \n");
+    }
+
+  if (!part_of_multiple && b->actions)
+    {
+      struct action_line *action;
+      annotate_field (12);
+      for (action = b->actions; action; action = action->next)
+       {
+         ui_out_text (uiout, "      A\t");
+         ui_out_text (uiout, action->action);
+         ui_out_text (uiout, "\n");
+       }
+    }
+
   if (ui_out_is_mi_like_p (uiout) && !part_of_multiple)
     {
       if (b->addr_string)
@@ -3699,6 +3835,7 @@ user_settable_breakpoint (const struct breakpoint *b)
   return (b->type == bp_breakpoint
          || b->type == bp_catchpoint
          || b->type == bp_hardware_breakpoint
+         || b->type == bp_tracepoint
          || b->type == bp_watchpoint
          || b->type == bp_read_watchpoint
          || b->type == bp_access_watchpoint
@@ -4077,6 +4214,7 @@ allocate_bp_location (struct breakpoint *bpt)
   switch (bpt->type)
     {
     case bp_breakpoint:
+    case bp_tracepoint:
     case bp_until:
     case bp_finish:
     case bp_longjmp:
@@ -4166,7 +4304,8 @@ static void
 set_breakpoint_location_function (struct bp_location *loc)
 {
   if (loc->owner->type == bp_breakpoint
-      || loc->owner->type == bp_hardware_breakpoint)
+      || loc->owner->type == bp_hardware_breakpoint
+      || loc->owner->type == bp_tracepoint)
     {
       find_pc_partial_function (loc->address, &(loc->function_name), 
                                NULL, NULL);
@@ -4441,7 +4580,9 @@ disable_breakpoints_in_shlibs (void)
        becomes enabled, or the duplicate is removed, gdb will try to insert
        all breakpoints.  If we don't set shlib_disabled here, we'll try
        to insert those breakpoints and fail.  */
-    if (((b->type == bp_breakpoint) || (b->type == bp_hardware_breakpoint))
+    if (((b->type == bp_breakpoint)
+        || (b->type == bp_hardware_breakpoint)
+        || (b->type == bp_tracepoint))
        && !loc->shlib_disabled
 #ifdef PC_SOLIB
        && PC_SOLIB (loc->address)
@@ -4477,28 +4618,22 @@ disable_breakpoints_in_unloaded_shlib (struct so_list *solib)
     struct breakpoint *b = loc->owner;
     if ((loc->loc_type == bp_loc_hardware_breakpoint
         || loc->loc_type == bp_loc_software_breakpoint)
-       && !loc->shlib_disabled)
+       && !loc->shlib_disabled
+       && (b->type == bp_breakpoint || b->type == bp_hardware_breakpoint)
+       && solib_contains_address_p (solib, loc->address))
       {
-#ifdef PC_SOLIB
-       char *so_name = PC_SOLIB (loc->address);
-#else
-       char *so_name = solib_name_from_address (loc->address);
-#endif
-       if (so_name && !strcmp (so_name, solib->so_name))
-          {
-           loc->shlib_disabled = 1;
-           /* At this point, we cannot rely on remove_breakpoint
-              succeeding so we must mark the breakpoint as not inserted
-              to prevent future errors occurring in remove_breakpoints.  */
-           loc->inserted = 0;
-           if (!disabled_shlib_breaks)
-             {
-               target_terminal_ours_for_output ();
-               warning (_("Temporarily disabling breakpoints for unloaded shared library \"%s\""),
-                         so_name);
-             }
-           disabled_shlib_breaks = 1;
+       loc->shlib_disabled = 1;
+       /* At this point, we cannot rely on remove_breakpoint
+          succeeding so we must mark the breakpoint as not inserted
+          to prevent future errors occurring in remove_breakpoints.  */
+       loc->inserted = 0;
+       if (!disabled_shlib_breaks)
+         {
+           target_terminal_ours_for_output ();
+           warning (_("Temporarily disabling breakpoints for unloaded shared library \"%s\""),
+                    solib->so_name);
          }
+       disabled_shlib_breaks = 1;
       }
   }
 }
@@ -4977,6 +5112,16 @@ mention (struct breakpoint *b)
        printf_filtered (_("Hardware assisted breakpoint %d"), b->number);
        say_where = 1;
        break;
+      case bp_tracepoint:
+       if (ui_out_is_mi_like_p (uiout))
+         {
+           say_where = 0;
+           break;
+         }
+       printf_filtered (_("Tracepoint"));
+       printf_filtered (_(" %d"), b->number);
+       say_where = 1;
+       break;
 
       case bp_until:
       case bp_finish:
@@ -5094,7 +5239,7 @@ static void
 create_breakpoint (struct symtabs_and_lines sals, char *addr_string,
                   char *cond_string,
                   enum bptype type, enum bpdisp disposition,
-                  int thread, int ignore_count, 
+                  int thread, int task, int ignore_count, 
                   struct breakpoint_ops *ops, int from_tty, int enabled)
 {
   struct breakpoint *b = NULL;
@@ -5126,6 +5271,7 @@ create_breakpoint (struct symtabs_and_lines sals, char *addr_string,
          set_breakpoint_count (breakpoint_count + 1);
          b->number = breakpoint_count;
          b->thread = thread;
+         b->task = task;
   
          b->cond_string = cond_string;
          b->ignore_count = ignore_count;
@@ -5304,7 +5450,7 @@ static void
 create_breakpoints (struct symtabs_and_lines sals, char **addr_string,
                    char *cond_string,
                    enum bptype type, enum bpdisp disposition,
-                   int thread, int ignore_count, 
+                   int thread, int task, int ignore_count, 
                    struct breakpoint_ops *ops, int from_tty,
                    int enabled)
 {
@@ -5316,10 +5462,8 @@ create_breakpoints (struct symtabs_and_lines sals, char **addr_string,
 
       create_breakpoint (expanded, addr_string[i],
                         cond_string, type, disposition,
-                        thread, ignore_count, ops, from_tty, enabled);
+                        thread, task, ignore_count, ops, from_tty, enabled);
     }
-
-  update_global_location_list (1);
 }
 
 /* Parse ARG which is assumed to be a SAL specification possibly
@@ -5423,7 +5567,7 @@ do_captured_parse_breakpoint (struct ui_out *ui, void *data)
    If no thread is found, *THREAD is set to -1.  */
 static void 
 find_condition_and_thread (char *tok, CORE_ADDR pc, 
-                          char **cond_string, int *thread)
+                          char **cond_string, int *thread, int *task)
 {
   *cond_string = NULL;
   *thread = -1;
@@ -5466,6 +5610,18 @@ find_condition_and_thread (char *tok, CORE_ADDR pc,
          if (!valid_thread_id (*thread))
            error (_("Unknown thread %d."), *thread);
        }
+      else if (toklen >= 1 && strncmp (tok, "task", toklen) == 0)
+       {
+         char *tmptok;
+
+         tok = end_tok + 1;
+         tmptok = tok;
+         *task = strtol (tok, &tok, 0);
+         if (tok == tmptok)
+           error (_("Junk after task keyword."));
+         if (!valid_task_id (*task))
+           error (_("Unknown task %d\n"), *task);
+       }
       else
        error (_("Junk at end of arguments."));
     }
@@ -5484,7 +5640,7 @@ find_condition_and_thread (char *tok, CORE_ADDR pc,
 static void
 break_command_really (char *arg, char *cond_string, int thread,
                      int parse_condition_and_thread,
-                     int tempflag, int hardwareflag, 
+                     int tempflag, int hardwareflag, int traceflag,
                      int ignore_count,
                      enum auto_boolean pending_break_support,
                      struct breakpoint_ops *ops,
@@ -5504,6 +5660,8 @@ break_command_really (char *arg, char *cond_string, int thread,
   int i;
   int pending = 0;
   int not_found = 0;
+  enum bptype type_wanted;
+  int task = 0;
 
   sals.sals = NULL;
   sals.nelts = 0;
@@ -5592,6 +5750,10 @@ break_command_really (char *arg, char *cond_string, int thread,
   if (!pending)
     breakpoint_sals_to_pc (&sals, addr_start);
 
+  type_wanted = (traceflag
+                ? bp_tracepoint
+                : (hardwareflag ? bp_hardware_breakpoint : bp_breakpoint));
+
   /* Verify that condition can be parsed, before setting any
      breakpoints.  Allocate a separate condition expression for each
      breakpoint. */
@@ -5605,7 +5767,8 @@ break_command_really (char *arg, char *cond_string, int thread,
                re-parse it in context of each sal.  */
             cond_string = NULL;
             thread = -1;
-            find_condition_and_thread (arg, sals.sals[0].pc, &cond_string, &thread);
+            find_condition_and_thread (arg, sals.sals[0].pc, &cond_string,
+                                       &thread, &task);
             if (cond_string)
                 make_cleanup (xfree, cond_string);
         }
@@ -5618,11 +5781,9 @@ break_command_really (char *arg, char *cond_string, int thread,
                 make_cleanup (xfree, cond_string);
             }
         }
-      create_breakpoints (sals, addr_string, cond_string,
-                         hardwareflag ? bp_hardware_breakpoint 
-                         : bp_breakpoint,
+      create_breakpoints (sals, addr_string, cond_string, type_wanted,
                          tempflag ? disp_del : disp_donttouch,
-                         thread, ignore_count, ops, from_tty, enabled);
+                         thread, task, ignore_count, ops, from_tty, enabled);
     }
   else
     {
@@ -5631,9 +5792,7 @@ break_command_really (char *arg, char *cond_string, int thread,
 
       make_cleanup (xfree, copy_arg);
 
-      b = set_raw_breakpoint_without_location (hardwareflag 
-                                              ? bp_hardware_breakpoint 
-                                              : bp_breakpoint);
+      b = set_raw_breakpoint_without_location (type_wanted);
       set_breakpoint_count (breakpoint_count + 1);
       b->number = breakpoint_count;
       b->thread = -1;
@@ -5645,7 +5804,6 @@ break_command_really (char *arg, char *cond_string, int thread,
       b->ops = ops;
       b->enable_state = enabled ? bp_enabled : bp_disabled;
 
-      update_global_location_list (1);
       mention (b);
     }
   
@@ -5657,6 +5815,9 @@ break_command_really (char *arg, char *cond_string, int thread,
   discard_cleanups (breakpoint_chain);
   /* But cleanup everything else. */
   do_cleanups (old_chain);
+
+  /* error call may happen here - have BREAKPOINT_CHAIN already discarded.  */
+  update_global_location_list (1);
 }
 
 /* Set a breakpoint. 
@@ -5674,7 +5835,7 @@ break_command_1 (char *arg, int flag, int from_tty)
 
   break_command_really (arg, 
                        NULL, 0, 1 /* parse arg */,
-                       tempflag, hardwareflag,
+                       tempflag, hardwareflag, 0 /* traceflag */,
                        0 /* Ignore count */,
                        pending_break_support, 
                        NULL /* breakpoint_ops */,
@@ -5691,7 +5852,7 @@ set_breakpoint (char *address, char *condition,
 {
   break_command_really (address, condition, thread,
                        0 /* condition and thread are valid.  */,
-                       tempflag, hardwareflag,
+                       tempflag, hardwareflag, 0 /* traceflag */,
                        ignore_count,
                        pending 
                        ? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE,
@@ -5735,7 +5896,12 @@ resolve_sal_pc (struct symtab_and_line *sal)
       /* If this SAL corresponds to a breakpoint inserted using
          a line number, then skip the function prologue if necessary.  */
       if (sal->explicit_line)
-        skip_prologue_sal (sal);
+       {
+         /* Preserve the original line number.  */
+         int saved_line = sal->line;
+         skip_prologue_sal (sal);
+         sal->line = saved_line;
+       }
     }
 
   if (sal->section == 0 && sal->symtab != NULL)
@@ -6471,7 +6637,7 @@ print_exception_catchpoint (struct breakpoint *b)
     breakpoint_adjustment_warning (b->loc->requested_address,
                                   b->loc->address,
                                   b->number, 1);
-  bp_temp = b->loc->owner->disposition == disp_del;
+  bp_temp = b->disposition == disp_del;
   ui_out_text (uiout, 
               bp_temp ? "Temporary catchpoint "
                       : "Catchpoint ");
@@ -6518,7 +6684,7 @@ print_mention_exception_catchpoint (struct breakpoint *b)
   int bp_temp;
   int bp_throw;
 
-  bp_temp = b->loc->owner->disposition == disp_del;
+  bp_temp = b->disposition == disp_del;
   bp_throw = strstr (b->addr_string, "throw") != NULL;
   ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ")
                              : _("Catchpoint "));
@@ -6549,7 +6715,7 @@ handle_gnu_v3_exceptions (int tempflag, char *cond_string,
 
   break_command_really (trigger_func_name, cond_string, -1,
                        0 /* condition and thread are valid.  */,
-                       tempflag, 0,
+                       tempflag, 0, 0,
                        0,
                        AUTO_BOOLEAN_TRUE /* pending */,
                        &gnu_v3_exception_catchpoint_ops, from_tty,
@@ -7409,6 +7575,7 @@ breakpoint_re_set_one (void *bint)
       return 0;
     case bp_breakpoint:
     case bp_hardware_breakpoint:
+    case bp_tracepoint:
       if (b->addr_string == NULL)
        {
          /* Anything without a string can't be re-set. */
@@ -7461,11 +7628,14 @@ breakpoint_re_set_one (void *bint)
        {
          char *cond_string = 0;
          int thread = -1;
+         int task = 0;
+
          find_condition_and_thread (s, sals.sals[0].pc, 
-                                    &cond_string, &thread);
+                                    &cond_string, &thread, &task);
          if (cond_string)
            b->cond_string = cond_string;
          b->thread = thread;
+         b->task = task;
          b->condition_not_parsed = 0;
        }
       expanded = expand_line_sal_maybe (sals.sals[0]);
@@ -7774,6 +7944,7 @@ disable_command (char *args, int from_tty)
                 bpt->number);
        continue;
       case bp_breakpoint:
+      case bp_tracepoint:
       case bp_catchpoint:
       case bp_hardware_breakpoint:
       case bp_watchpoint:
@@ -7866,6 +8037,7 @@ enable_command (char *args, int from_tty)
                 bpt->number);
        continue;
       case bp_breakpoint:
+      case bp_tracepoint:
       case bp_catchpoint:
       case bp_hardware_breakpoint:
       case bp_watchpoint:
@@ -8049,6 +8221,324 @@ single_step_breakpoint_inserted_here_p (CORE_ADDR pc)
   return 0;
 }
 
+/* Tracepoint-specific operations.  */
+
+/* Set tracepoint count to NUM.  */
+static void
+set_tracepoint_count (int num)
+{
+  tracepoint_count = num;
+  set_internalvar (lookup_internalvar ("tpnum"),
+                  value_from_longest (builtin_type_int32, (LONGEST) num));
+}
+
+void
+trace_command (char *arg, int from_tty)
+{
+  break_command_really (arg, 
+                       NULL, 0, 1 /* parse arg */,
+                       0 /* tempflag */, 0 /* hardwareflag */,
+                       1 /* traceflag */,
+                       0 /* Ignore count */,
+                       pending_break_support, 
+                       NULL,
+                       from_tty,
+                       1 /* enabled */);
+  set_tracepoint_count (breakpoint_count);
+}
+
+/* Print information on tracepoint number TPNUM_EXP, or all if
+   omitted.  */
+
+static void
+tracepoints_info (char *tpnum_exp, int from_tty)
+{
+  struct breakpoint *b;
+  int tps_to_list = 0;
+
+  /* In the no-arguments case, say "No tracepoints" if none found.  */
+  if (tpnum_exp == 0)
+    {
+      ALL_TRACEPOINTS (b)
+      {
+       if (b->number >= 0)
+         {
+           tps_to_list = 1;
+           break;
+         }
+      }
+      if (!tps_to_list)
+       {
+         ui_out_message (uiout, 0, "No tracepoints.\n");
+         return;
+       }
+    }
+
+  /* Otherwise be the same as "info break".  */
+  breakpoints_info (tpnum_exp, from_tty);
+}
+
+/* The 'enable trace' command enables tracepoints.  
+   Not supported by all targets.  */
+static void
+enable_trace_command (char *args, int from_tty)
+{
+  enable_command (args, from_tty);
+}
+
+/* The 'disable trace' command disables tracepoints.  
+   Not supported by all targets.  */
+static void
+disable_trace_command (char *args, int from_tty)
+{
+  disable_command (args, from_tty);
+}
+
+/* Remove a tracepoint (or all if no argument) */
+static void
+delete_trace_command (char *arg, int from_tty)
+{
+  struct breakpoint *b, *temp;
+
+  dont_repeat ();
+
+  if (arg == 0)
+    {
+      int breaks_to_delete = 0;
+
+      /* Delete all breakpoints if no argument.
+         Do not delete internal or call-dummy breakpoints, these
+         have to be deleted with an explicit breakpoint number argument.  */
+      ALL_TRACEPOINTS (b)
+      {
+       if (b->number >= 0)
+         {
+           breaks_to_delete = 1;
+           break;
+         }
+      }
+
+      /* Ask user only if there are some breakpoints to delete.  */
+      if (!from_tty
+         || (breaks_to_delete && query (_("Delete all tracepoints? "))))
+       {
+         ALL_BREAKPOINTS_SAFE (b, temp)
+         {
+           if (b->type == bp_tracepoint &&
+               b->number >= 0)
+             delete_breakpoint (b);
+         }
+       }
+    }
+  else
+    map_breakpoint_numbers (arg, delete_breakpoint);
+}
+
+/* Set passcount for tracepoint.
+
+   First command argument is passcount, second is tracepoint number.
+   If tracepoint number omitted, apply to most recently defined.
+   Also accepts special argument "all".  */
+
+static void
+trace_pass_command (char *args, int from_tty)
+{
+  struct breakpoint *t1 = (struct breakpoint *) -1, *t2;
+  unsigned int count;
+  int all = 0;
+
+  if (args == 0 || *args == 0)
+    error (_("passcount command requires an argument (count + optional TP num)"));
+
+  count = strtoul (args, &args, 10);   /* Count comes first, then TP num. */
+
+  while (*args && isspace ((int) *args))
+    args++;
+
+  if (*args && strncasecmp (args, "all", 3) == 0)
+    {
+      args += 3;                       /* Skip special argument "all".  */
+      all = 1;
+      if (*args)
+       error (_("Junk at end of arguments."));
+    }
+  else
+    t1 = get_tracepoint_by_number (&args, 1, 1);
+
+  do
+    {
+      if (t1)
+       {
+         ALL_TRACEPOINTS (t2)
+           if (t1 == (struct breakpoint *) -1 || t1 == t2)
+             {
+               t2->pass_count = count;
+               observer_notify_tracepoint_modified (t2->number);
+               if (from_tty)
+                 printf_filtered (_("Setting tracepoint %d's passcount to %d\n"),
+                                  t2->number, count);
+             }
+         if (! all && *args)
+           t1 = get_tracepoint_by_number (&args, 1, 0);
+       }
+    }
+  while (*args);
+}
+
+struct breakpoint *
+get_tracepoint (int num)
+{
+  struct breakpoint *t;
+
+  ALL_TRACEPOINTS (t)
+    if (t->number == num)
+      return t;
+
+  return NULL;
+}
+
+/* Utility: parse a tracepoint number and look it up in the list.
+   If MULTI_P is true, there might be a range of tracepoints in ARG.
+   if OPTIONAL_P is true, then if the argument is missing, the most
+   recent tracepoint (tracepoint_count) is returned.  */
+struct breakpoint *
+get_tracepoint_by_number (char **arg, int multi_p, int optional_p)
+{
+  extern int tracepoint_count;
+  struct breakpoint *t;
+  int tpnum;
+  char *instring = arg == NULL ? NULL : *arg;
+
+  if (arg == NULL || *arg == NULL || ! **arg)
+    {
+      if (optional_p)
+       tpnum = tracepoint_count;
+      else
+       error_no_arg (_("tracepoint number"));
+    }
+  else
+    tpnum = multi_p ? get_number_or_range (arg) : get_number (arg);
+
+  if (tpnum <= 0)
+    {
+      if (instring && *instring)
+       printf_filtered (_("bad tracepoint number at or near '%s'\n"), 
+                        instring);
+      else
+       printf_filtered (_("Tracepoint argument missing and no previous tracepoint\n"));
+      return NULL;
+    }
+
+  ALL_TRACEPOINTS (t)
+    if (t->number == tpnum)
+    {
+      return t;
+    }
+
+  /* FIXME: if we are in the middle of a range we don't want to give
+     a message.  The current interface to get_number_or_range doesn't
+     allow us to discover this.  */
+  printf_unfiltered ("No tracepoint number %d.\n", tpnum);
+  return NULL;
+}
+
+/* save-tracepoints command */
+static void
+tracepoint_save_command (char *args, int from_tty)
+{
+  struct breakpoint *tp;
+  int any_tp = 0;
+  struct action_line *line;
+  FILE *fp;
+  char *i1 = "    ", *i2 = "      ";
+  char *indent, *actionline, *pathname;
+  char tmp[40];
+  struct cleanup *cleanup;
+
+  if (args == 0 || *args == 0)
+    error (_("Argument required (file name in which to save tracepoints)"));
+
+  /* See if we have anything to save.  */
+  ALL_TRACEPOINTS (tp)
+  {
+    any_tp = 1;
+    break;
+  }
+  if (!any_tp)
+    {
+      warning (_("save-tracepoints: no tracepoints to save."));
+      return;
+    }
+
+  pathname = tilde_expand (args);
+  cleanup = make_cleanup (xfree, pathname);
+  if (!(fp = fopen (pathname, "w")))
+    error (_("Unable to open file '%s' for saving tracepoints (%s)"),
+          args, safe_strerror (errno));
+  make_cleanup_fclose (fp);
+  
+  ALL_TRACEPOINTS (tp)
+  {
+    if (tp->addr_string)
+      fprintf (fp, "trace %s\n", tp->addr_string);
+    else
+      {
+       sprintf_vma (tmp, tp->loc->address);
+       fprintf (fp, "trace *0x%s\n", tmp);
+      }
+
+    if (tp->pass_count)
+      fprintf (fp, "  passcount %d\n", tp->pass_count);
+
+    if (tp->actions)
+      {
+       fprintf (fp, "  actions\n");
+       indent = i1;
+       for (line = tp->actions; line; line = line->next)
+         {
+           struct cmd_list_element *cmd;
+
+           QUIT;               /* allow user to bail out with ^C */
+           actionline = line->action;
+           while (isspace ((int) *actionline))
+             actionline++;
+
+           fprintf (fp, "%s%s\n", indent, actionline);
+           if (*actionline != '#')     /* skip for comment lines */
+             {
+               cmd = lookup_cmd (&actionline, cmdlist, "", -1, 1);
+               if (cmd == 0)
+                 error (_("Bad action list item: %s"), actionline);
+               if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
+                 indent = i2;
+               else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
+                 indent = i1;
+             }
+         }
+      }
+  }
+  do_cleanups (cleanup);
+  if (from_tty)
+    printf_filtered (_("Tracepoints saved to file '%s'.\n"), args);
+  return;
+}
+
+/* Create a vector of all tracepoints.  */
+
+VEC(breakpoint_p) *
+all_tracepoints ()
+{
+  VEC(breakpoint_p) *tp_vec = 0;
+  struct breakpoint *tp;
+
+  ALL_TRACEPOINTS (tp)
+  {
+    VEC_safe_push (breakpoint_p, tp_vec, tp);
+  }
+
+  return tp_vec;
+}
+
 \f
 /* This help string is used for the break, hbreak, tbreak and thbreak commands.
    It is defined as a macro to prevent duplication.
@@ -8111,6 +8601,8 @@ _initialize_breakpoint (void)
      before a breakpoint is set.  */
   breakpoint_count = 0;
 
+  tracepoint_count = 0;
+
   add_com ("ignore", class_breakpoint, ignore_command, _("\
 Set ignore-count of breakpoint number N to COUNT.\n\
 Usage is `ignore N COUNT'."));
@@ -8440,6 +8932,58 @@ hardware.)"),
 
   can_use_hw_watchpoints = 1;
 
+  /* Tracepoint manipulation commands.  */
+
+  c = add_com ("trace", class_breakpoint, trace_command, _("\
+Set a tracepoint at specified line or function.\n\
+\n"
+BREAK_ARGS_HELP ("trace") "\n\
+Do \"help tracepoints\" for info on other tracepoint commands."));
+  set_cmd_completer (c, location_completer);
+
+  add_com_alias ("tp", "trace", class_alias, 0);
+  add_com_alias ("tr", "trace", class_alias, 1);
+  add_com_alias ("tra", "trace", class_alias, 1);
+  add_com_alias ("trac", "trace", class_alias, 1);
+
+  add_info ("tracepoints", tracepoints_info, _("\
+Status of tracepoints, or tracepoint number NUMBER.\n\
+Convenience variable \"$tpnum\" contains the number of the\n\
+last tracepoint set."));
+
+  add_info_alias ("tp", "tracepoints", 1);
+
+  add_cmd ("tracepoints", class_trace, delete_trace_command, _("\
+Delete specified tracepoints.\n\
+Arguments are tracepoint numbers, separated by spaces.\n\
+No argument means delete all tracepoints."),
+          &deletelist);
+
+  c = add_cmd ("tracepoints", class_trace, disable_trace_command, _("\
+Disable specified tracepoints.\n\
+Arguments are tracepoint numbers, separated by spaces.\n\
+No argument means disable all tracepoints."),
+          &disablelist);
+  deprecate_cmd (c, "disable");
+
+  c = add_cmd ("tracepoints", class_trace, enable_trace_command, _("\
+Enable specified tracepoints.\n\
+Arguments are tracepoint numbers, separated by spaces.\n\
+No argument means enable all tracepoints."),
+          &enablelist);
+  deprecate_cmd (c, "enable");
+
+  add_com ("passcount", class_trace, trace_pass_command, _("\
+Set the passcount for a tracepoint.\n\
+The trace will end when the tracepoint has been passed 'count' times.\n\
+Usage: passcount COUNT TPNUM, where TPNUM may also be \"all\";\n\
+if TPNUM is omitted, passcount refers to the last tracepoint defined."));
+
+  c = add_com ("save-tracepoints", class_trace, tracepoint_save_command, _("\
+Save current tracepoint definitions as a script.\n\
+Use the 'source' command in another debug session to restore them."));
+  set_cmd_completer (c, filename_completer);
+
   add_prefix_cmd ("breakpoint", class_maintenance, set_breakpoint_cmd, _("\
 Breakpoint specific settings\n\
 Configure various breakpoint-specific variables such as\n\
@@ -8498,4 +9042,6 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
                           &breakpoint_show_cmdlist);
   
   automatic_hardware_breakpoints = 1;
+
+  observer_attach_about_to_proceed (breakpoint_about_to_proceed);
 }
This page took 0.035305 seconds and 4 git commands to generate.