This is the mail archive of the archer@sourceware.org mailing list for the Archer project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 1/4] 'catch syscall' feature -- Architecture-independentpart


This is the architecture-independent part of the patch.

Regards,

-- 
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil


2008-09-29  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>

	* breakpoint.c (clear_syscall_catchpoints_info): New.
	(insert_catchpoint): Add syscall catchpoint case.
	(insert_bp_location): Add syscall catchpoint for checking.
	(remove_breakpoint): Removing syscall catchpoint.
	(ep_is_catchpoint): Adding syscall catchpoint for checking.
	(print_it_typical): Included syscall catchpoint code for 
	printing.  Also, handle the case of the breakpoint at the
	entrypoint.
	(bpstat_check_location): Add syscall catchpoint handler.
	(bpstat_what): Add the entry breakpoint case.
	(print_one_breakpoint): Add syscall catchpoint and entry
	breakpoint.
	(user_settable_breakpoint): Add syscall catchpoint.
	(breakpoint_address_is_meaningful): Likewise.
	(adjust_breakpoint_address): Likewise.
	(allocate_bp_location): Add syscall catchpoint and entry
	breakpoint.
	(set_raw_breakpoint_without_location): Zeroing fields related
	to syscall catchpoint.
	(create_entry_breakpoint): New.
	(create_syscall_event_catchpoint): New.
	(mention): Add syscall catchpoint and entry breakpoint.
	(catch_syscall_command_1): New.
	(delete_command): Add syscall catchpoint and entry breakpoint.
	(breakpoint_re_set_one): Likewise.
	(disable_command): Add syscall catchpoint.
	(enable_command): Likewise.
	(is_syscall_catchpoint_enabled): New.
	(catch_syscall_enabled): New.
	(catching_syscall_number): New.
	* breakpoint.h (enum bptype): Add syscall catchpoint and entry
	breakpoint types.
	(struct breakpoint): Add field 'syscall_number' (used to know
	which syscall triggered the catchpoint) and
	'syscall_to_be_caught' (used to know which syscall we are trying
	to catch).
	(enum bpstat_what_main_action): Add BPSTAT_WHAT_ENTRY_BREAKPOINT,
	used to identify wheter we hit an entry breakpoint.
	(clear_syscall_catchpoints_info): New.
	(catch_syscall_enabled): New.
	(catching_syscall_number): New.
	(create_entry_breakpoint): New.
	* gdbarch.c: Regenerate.
	* gdbarch.h: Regenerate.
	* gdbarch.sh: Add syscall catchpoint functions to gdbarch.
	(get_syscall_number): New.
	(syscall_name_from_number): New.
	(syscall_number_from_name): New.
	* gdbthread.h (struct thread_info): Add field 'syscall_state',
	used to know if we are calling or returning from a syscall.
	* inf-child.c (inf_child_insert_syscall_catchpoint): New.
	(inf_child_remove_syscall_catchpoint): New.
	(inf_child_target): Assign default values to target_ops.
	* inf-ptrace.c (inf_ptrace_resume): Select the proper request
	to be made for ptrace() considering if we are catching syscalls
	or not.
	* infcmd.c (run_command_1): Clean syscall catchpoint info on every
	run.
	* infrun.c (resume): Add syscall catchpoint and entry breakpoint.
	(deal_with_syscall_event): New.
	(handle_inferior_event): Add syscall entry/return events.  Also,
	add entry breakpoint event.
	(inferior_has_called_syscall): New.
	* target.c (update_current_target): Update/copy functions related to
	syscall catchpoint and entry breakpoint.
	(debug_to_wait): Add syscall catchpoint entry/return events.
	* target.h (struct target_waitstatus): Add syscall number.
	(struct target_ops): Add ops for syscall catchpoint and entry
	breakpoint.
	(inferior_has_called_syscall): New.
	(target_passed_by_entrypoint): New.
	(target_insert_syscall_catchpoint): New.
	(target_remove_syscall_catchpoint): New.
	(target_enable_tracesysgood): New.




diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 6e863d7..7f9cc49 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -404,6 +404,18 @@ set_breakpoint_count (int num)
 		   value_from_longest (builtin_type_int32, (LONGEST) num));
 }
 
+/* Used in run_command to reset syscall catchpoints fields. */
+
+void
+clear_syscall_catchpoints_info (void)
+{
+  struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    if (b->type == bp_catch_syscall)
+      b->syscall_number = UNKNOWN_SYSCALL;
+}
+
 /* Used in run_command to zero the hit count when a new run starts. */
 
 void
@@ -810,6 +822,9 @@ insert_catchpoint (struct ui_out *uo, void *args)
     case bp_catch_exec:
       target_insert_exec_catchpoint (PIDGET (inferior_ptid));
       break;
+    case bp_catch_syscall:
+      target_insert_syscall_catchpoint (PIDGET (inferior_ptid));
+      break;
     default:
       internal_error (__FILE__, __LINE__, _("unknown breakpoint type"));
       break;
@@ -1250,7 +1265,8 @@ Note: automatically using hardware breakpoints for read-only addresses.\n"));
 
   else if (bpt->owner->type == bp_catch_fork
 	   || bpt->owner->type == bp_catch_vfork
-	   || bpt->owner->type == bp_catch_exec)
+	   || bpt->owner->type == bp_catch_exec
+	   || bpt->owner->type == bp_catch_syscall)
     {
       struct gdb_exception e = catch_exception (uiout, insert_catchpoint,
 						bpt->owner, RETURN_MASK_ERROR);
@@ -1708,6 +1724,9 @@ remove_breakpoint (struct bp_location *b, insertion_state_t is)
 	case bp_catch_exec:
 	  val = target_remove_exec_catchpoint (PIDGET (inferior_ptid));
 	  break;
+        case bp_catch_syscall:
+          val = target_remove_syscall_catchpoint (PIDGET (inferior_ptid));
+          break;
 	default:
 	  warning (_("Internal error, %s line %d."), __FILE__, __LINE__);
 	  break;
@@ -1957,7 +1976,8 @@ ep_is_catchpoint (struct breakpoint *ep)
     || (ep->type == bp_catch_unload)
     || (ep->type == bp_catch_fork)
     || (ep->type == bp_catch_vfork)
-    || (ep->type == bp_catch_exec);
+    || (ep->type == bp_catch_exec)
+    || (ep->type == bp_catch_syscall);
 
   /* ??rehrauer: Add more kinds here, as are implemented... */
 }
@@ -2278,6 +2298,13 @@ print_it_typical (bpstat bs)
   struct cleanup *old_chain, *ui_out_chain;
   struct breakpoint *b;
   const struct bp_location *bl;
+  /* Used for "catch syscall".
+     
+     This is needed because we want to know in which state a
+     syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
+     or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
+     must print "called syscall" or "returned from syscall". */
+  struct thread_info *th_info = find_thread_pid (inferior_ptid);
   struct ui_stream *stb;
   int bp_temp = 0;  
   stb = ui_out_stream_new (uiout);
@@ -2329,6 +2356,14 @@ print_it_typical (bpstat bs)
       return PRINT_NOTHING;
       break;
 
+    case bp_entry_breakpoint:
+       /* Not sure how we will get here. 
+	 GDB should not stop for these breakpoints.  */
+      internal_error (__FILE__, __LINE__,
+                      _("Entry Breakpoint: gdb should not stop!\n"));
+      return PRINT_NOTHING;
+      break;    
+
     case bp_overlay_event:
       /* By analogy with the thread event, GDB should not stop for these. */
       printf_filtered (_("Overlay Event Breakpoint: gdb should not stop!\n"));
@@ -2375,6 +2410,17 @@ print_it_typical (bpstat bs)
       return PRINT_SRC_AND_LOC;
       break;
 
+    case bp_catch_syscall:
+      annotate_catchpoint (b->number);
+      printf_filtered (_("\nCatchpoint %d (%s syscall '%s ()'), "),
+		       b->number,
+                       (th_info->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY)
+                        ? "called" : "returned from",
+		       gdbarch_syscall_name_from_number (current_gdbarch,
+                                                         b->syscall_number));
+      return PRINT_SRC_AND_LOC;
+      break;
+
     case bp_watchpoint:
     case bp_hardware_watchpoint:
       annotate_watchpoint (b->number);
@@ -2795,7 +2841,8 @@ bpstat_check_location (const struct bp_location *bl, CORE_ADDR bp_addr)
       && b->type != bp_hardware_breakpoint
       && b->type != bp_catch_fork
       && b->type != bp_catch_vfork
-      && b->type != bp_catch_exec)	/* a non-watchpoint bp */
+      && b->type != bp_catch_exec
+      && b->type != bp_catch_syscall)	/* a non-watchpoint bp */
     {
       if (bl->address != bp_addr) 	/* address doesn't match */
 	return 0;
@@ -2869,6 +2916,25 @@ bpstat_check_location (const struct bp_location *bl, CORE_ADDR bp_addr)
       && !inferior_has_execd (inferior_ptid, &b->exec_pathname))
     return 0;
 
+  /* We must check if we are catching specific syscalls in this breakpoint.
+     If we are, then we must guarantee that the called syscall is the same
+     syscall we are catching. */
+  if (b->type == bp_catch_syscall)
+    {
+      int syscall_number;
+      if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
+        return 0;
+      /* Now, checking if the syscall is the same. */
+      if (b->syscall_to_be_caught != CATCHING_ANY_SYSCALL
+          && b->syscall_to_be_caught != syscall_number)
+        /* Not the same. */
+        return 0;
+
+      /* It's the same syscall. We can update the breakpoint struct
+         with the correct information. */
+      b->syscall_number = syscall_number;
+    }
+
   return 1;
 }
 
@@ -3212,6 +3278,9 @@ bpstat_what (bpstat bs)
       /* We caught a shared library event.  */
       catch_shlib_event,
 
+      /* We are in a entry breakpoint. */
+      entry_breakpoint,
+
       /* This is just used to count how many enums there are.  */
       class_last
     };
@@ -3228,6 +3297,7 @@ bpstat_what (bpstat bs)
 #define sr BPSTAT_WHAT_STEP_RESUME
 #define shl BPSTAT_WHAT_CHECK_SHLIBS
 #define shlr BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK
+#define entrybp BPSTAT_WHAT_ENTRY_BREAKPOINT
 
 /* "Can't happen."  Might want to print an error message.
    abort() is not out of the question, but chances are GDB is just
@@ -3272,30 +3342,33 @@ bpstat_what (bpstat bs)
     table[(int) class_last][(int) BPSTAT_WHAT_LAST] =
   {
   /*                              old action */
-  /*       kc    ss    sn    sgl    slr   clr   sr   shl   shlr
+  /*       kc    ss    sn    sgl    slr   clr   sr   shl   shlr   entrybp
    */
 /*no_effect */
-    {kc, ss, sn, sgl, slr, clr, sr, shl, shlr},
+    {kc, ss, sn, sgl, slr, clr, sr, shl, shlr, shlr},
 /*wp_silent */
-    {ss, ss, sn, ss, ss, ss, sr, shl, shlr},
+    {ss, ss, sn, ss, ss, ss, sr, shl, shlr, shlr},
 /*wp_noisy */
-    {sn, sn, sn, sn, sn, sn, sr, shl, shlr},
+    {sn, sn, sn, sn, sn, sn, sr, shl, shlr, shlr},
 /*bp_nostop */
-    {sgl, ss, sn, sgl, slr, slr, sr, shl, shlr},
+    {sgl, ss, sn, sgl, slr, slr, sr, shl, shlr, shlr},
 /*bp_silent */
-    {ss, ss, sn, ss, ss, ss, sr, shl, shlr},
+    {ss, ss, sn, ss, ss, ss, sr, shl, shlr, shlr},
 /*bp_noisy */
-    {sn, sn, sn, sn, sn, sn, sr, shl, shlr},
+    {sn, sn, sn, sn, sn, sn, sr, shl, shlr, shlr},
 /*long_jump */
-    {slr, ss, sn, slr, slr, err, sr, shl, shlr},
+    {slr, ss, sn, slr, slr, err, sr, shl, shlr, shlr},
 /*long_resume */
-    {clr, ss, sn, err, err, err, sr, shl, shlr},
+    {clr, ss, sn, err, err, err, sr, shl, shlr, shlr},
 /*step_resume */
-    {sr, sr, sr, sr, sr, sr, sr, sr, sr},
+    {sr, sr, sr, sr, sr, sr, sr, sr, sr, sr},
 /*shlib */
-    {shl, shl, shl, shl, shl, shl, sr, shl, shlr},
+    {shl, shl, shl, shl, shl, shl, sr, shl, shlr, shl},
 /*catch_shlib */
-    {shlr, shlr, shlr, shlr, shlr, shlr, sr, shlr, shlr}
+    {shlr, shlr, shlr, shlr, shlr, shlr, sr, shlr, shlr, shlr},
+/* entry_breakpoint */
+    {entrybp, entrybp, entrybp, entrybp, entrybp, entrybp, sr, entrybp,
+      entrybp, entrybp}
   };
 
 #undef kc
@@ -3309,6 +3382,7 @@ bpstat_what (bpstat bs)
 #undef ts
 #undef shl
 #undef shlr
+#undef entrybp
   enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING;
   struct bpstat_what retval;
 
@@ -3396,6 +3470,7 @@ bpstat_what (bpstat bs)
 	case bp_catch_fork:
 	case bp_catch_vfork:
 	case bp_catch_exec:
+        case bp_catch_syscall:
 	  if (bs->stop)
 	    {
 	      if (bs->print)
@@ -3414,6 +3489,12 @@ bpstat_what (bpstat bs)
 	  bs_class = bp_silent;
 	  retval.call_dummy = 1;
 	  break;
+        case bp_entry_breakpoint:
+          if (bs->stop)
+            bs_class = entry_breakpoint;
+          else
+            bs_class = no_effect;
+          break;
 	}
       current_action = table[(int) bs_class][(int) current_action];
     }
@@ -3577,7 +3658,9 @@ print_one_breakpoint_location (struct breakpoint *b,
     {bp_catch_unload, "catch unload"},
     {bp_catch_fork, "catch fork"},
     {bp_catch_vfork, "catch vfork"},
-    {bp_catch_exec, "catch exec"}
+    {bp_catch_exec, "catch exec"},
+    {bp_catch_syscall, "catch syscall"},
+    {bp_entry_breakpoint, "entry breakpoint"}
   };
   
   static char bpenables[] = "nynny";
@@ -3743,6 +3826,23 @@ print_one_breakpoint_location (struct breakpoint *b,
 	  }
 	break;
 
+      case bp_catch_syscall:
+	/* Field 4, the address, is omitted (which makes the columns
+	   not line up too nicely with the headers, but the effect
+	   is relatively readable).  */
+	if (addressprint)
+	  ui_out_field_skip (uiout, "addr");
+	annotate_field (5);
+        ui_out_text (uiout, "syscall \"");
+        if (b->syscall_number != UNKNOWN_SYSCALL)
+          ui_out_field_string (uiout, "what",
+                       gdbarch_syscall_name_from_number (current_gdbarch,
+                                                         b->syscall_number));
+        else
+            ui_out_field_string (uiout, "what", "<unknown syscall>");
+        ui_out_text (uiout, "\" ");
+	break;
+
       case bp_breakpoint:
       case bp_hardware_breakpoint:
       case bp_until:
@@ -3755,6 +3855,7 @@ print_one_breakpoint_location (struct breakpoint *b,
       case bp_shlib_event:
       case bp_thread_event:
       case bp_overlay_event:
+      case bp_entry_breakpoint:
 	if (addressprint)
 	  {
 	    annotate_field (4);
@@ -3944,6 +4045,7 @@ user_settable_breakpoint (const struct breakpoint *b)
 	  || b->type == bp_catch_fork
 	  || b->type == bp_catch_vfork
 	  || b->type == bp_catch_exec
+          || b->type == bp_catch_syscall
 	  || b->type == bp_hardware_breakpoint
 	  || b->type == bp_watchpoint
 	  || b->type == bp_read_watchpoint
@@ -4150,6 +4252,7 @@ set_default_breakpoint (int valid, CORE_ADDR addr, struct symtab *symtab,
       bp_hardware_watchpoint
       bp_read_watchpoint
       bp_access_watchpoint
+      bp_catch_syscall
       bp_catch_exec
       bp_catch_fork
       bp_catch_vork */
@@ -4163,6 +4266,7 @@ breakpoint_address_is_meaningful (struct breakpoint *bpt)
 	  && type != bp_hardware_watchpoint
 	  && type != bp_read_watchpoint
 	  && type != bp_access_watchpoint
+          && type != bp_catch_syscall
 	  && type != bp_catch_exec
 	  && type != bp_catch_fork
 	  && type != bp_catch_vfork);
@@ -4282,7 +4386,8 @@ adjust_breakpoint_address (CORE_ADDR bpaddr, enum bptype bptype)
            || bptype == bp_access_watchpoint
            || bptype == bp_catch_fork
            || bptype == bp_catch_vfork
-           || bptype == bp_catch_exec)
+           || bptype == bp_catch_exec
+	   || bptype == bp_catch_syscall)
     {
       /* Watchpoints and the various bp_catch_* eventpoints should not
          have their addresses modified.  */
@@ -4333,6 +4438,7 @@ allocate_bp_location (struct breakpoint *bpt, enum bptype bp_type)
     case bp_watchpoint_scope:
     case bp_call_dummy:
     case bp_shlib_event:
+    case bp_entry_breakpoint:
     case bp_thread_event:
     case bp_overlay_event:
     case bp_catch_load:
@@ -4351,6 +4457,7 @@ allocate_bp_location (struct breakpoint *bpt, enum bptype bp_type)
     case bp_catch_fork:
     case bp_catch_vfork:
     case bp_catch_exec:
+    case bp_catch_syscall:
       loc->loc_type = bp_loc_other;
       break;
     default:
@@ -4396,6 +4503,8 @@ set_raw_breakpoint_without_location (enum bptype bptype)
   b->triggered_dll_pathname = NULL;
   b->forked_inferior_pid = null_ptid;
   b->exec_pathname = NULL;
+  b->syscall_to_be_caught = CATCHING_ANY_SYSCALL;
+  b->syscall_number = UNKNOWN_SYSCALL;
   b->ops = NULL;
   b->condition_not_parsed = 0;
 
@@ -4618,6 +4727,31 @@ disable_overlay_breakpoints (void)
     }
 }
 
+int
+create_entry_breakpoint ()
+{
+  CORE_ADDR taddr, entry_addr;
+  struct breakpoint *b;
+
+  taddr = entry_point_address ();
+  /* Make certain that the address points at real code, and not a
+     function descriptor.  */
+  entry_addr = gdbarch_convert_from_func_ptr_addr (current_gdbarch, taddr,
+                                                   &current_target);
+
+  /* Setting the breakpoint */
+  b = create_internal_breakpoint (entry_addr, bp_entry_breakpoint);
+
+  b->enable_state = bp_enabled;
+  b->disposition = disp_del;
+  /* addr_string has to be used or breakpoint_re_set will delete me. */
+  b->addr_string = xstrprintf ("AT_ENTRY (0x%s)", paddr (entry_addr));
+
+  update_global_location_list (1);
+
+  return 1;
+}
+
 struct breakpoint *
 create_thread_event_breakpoint (CORE_ADDR address)
 {
@@ -4817,6 +4951,31 @@ create_exec_event_catchpoint (int tempflag, char *cond_string)
   mention (b);
 }
 
+static void
+create_syscall_event_catchpoint (int tempflag, int syscall_number)
+{
+  struct symtab_and_line sal;
+  struct breakpoint *b;
+  int thread = -1;		/* All threads. */
+
+  init_sal (&sal);
+
+  b = set_raw_breakpoint (sal, bp_catch_syscall);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  b->cond_string = NULL;
+  b->thread = thread;
+  b->syscall_to_be_caught = syscall_number;
+  /* We still don't know the syscall that will be caught :-). */
+  b->syscall_number = UNKNOWN_SYSCALL;
+  b->addr_string = NULL;
+  b->enable_state = bp_enabled;
+  b->disposition = tempflag ? disp_del : disp_donttouch;
+  update_global_location_list (1);
+
+  mention (b);
+}
+
 static int
 hw_breakpoint_used_count (void)
 {
@@ -5034,6 +5193,16 @@ mention (struct breakpoint *b)
 	printf_filtered (_("Catchpoint %d (exec)"),
 			 b->number);
 	break;
+      case bp_catch_syscall:
+        if (b->syscall_to_be_caught != CATCHING_ANY_SYSCALL)
+          printf_filtered (_("Catchpoint %d (syscall '%s ()')"),
+                           b->number,
+                           gdbarch_syscall_name_from_number (current_gdbarch,
+                                                    b->syscall_to_be_caught));
+        else
+          printf_filtered (_("Catchpoint %d (syscall)"),
+                           b->number);
+	break;
 
       case bp_until:
       case bp_finish:
@@ -5045,6 +5214,7 @@ mention (struct breakpoint *b)
       case bp_shlib_event:
       case bp_thread_event:
       case bp_overlay_event:
+      case bp_entry_breakpoint:
 	break;
       }
 
@@ -6795,6 +6965,36 @@ catch_ada_exception_command (char *arg, int from_tty,
                                    from_tty);
 }
 
+/* Implement the "catch syscall" command. */
+
+static void
+catch_syscall_command_1 (char *arg, int from_tty, struct cmd_list_element *command)
+{
+  int tempflag;
+  int syscall_number = CATCHING_ANY_SYSCALL;
+
+  tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+
+  ep_skip_leading_whitespace (&arg);
+
+  /* The allowed syntax is:
+     catch syscall
+     catch syscall <name>
+
+     Let's check if there's a syscall name. */
+
+  if (arg != NULL)
+    {
+      syscall_number = gdbarch_syscall_number_from_name (current_gdbarch,
+                                                         (const char *) arg);
+      if (syscall_number == UNKNOWN_SYSCALL)
+        error (_("Invalid syscall name '%s'."), arg);
+    }
+
+  /* Now let's create the catchpoint */
+  create_syscall_event_catchpoint (tempflag, syscall_number);
+}
+
 /* Implement the "catch assert" command.  */
 
 static void
@@ -7312,6 +7512,7 @@ delete_command (char *arg, int from_tty)
 	    b->type != bp_shlib_event &&
 	    b->type != bp_thread_event &&
 	    b->type != bp_overlay_event &&
+            b->type != bp_entry_breakpoint &&
 	    b->number >= 0)
 	  {
 	    breaks_to_delete = 1;
@@ -7329,6 +7530,7 @@ delete_command (char *arg, int from_tty)
 		b->type != bp_shlib_event &&
 		b->type != bp_thread_event &&
 		b->type != bp_overlay_event &&
+                b->type != bp_entry_breakpoint &&
 		b->number >= 0)
 	      delete_breakpoint (b);
 	  }
@@ -7620,6 +7822,7 @@ breakpoint_re_set_one (void *bint)
     case bp_catch_fork:
     case bp_catch_vfork:
     case bp_catch_exec:
+    case bp_catch_syscall:
       break;
 
     default:
@@ -7639,6 +7842,9 @@ breakpoint_re_set_one (void *bint)
 	 Once it is set up, we do not want to touch it.  */
     case bp_thread_event:
 
+      /* Same for this one */
+    case bp_entry_breakpoint:
+
       /* Keep temporary breakpoints, which can be encountered when we step
          over a dlopen call and SOLIB_ADD is resetting the breakpoints.
          Otherwise these should have been blown away via the cleanup chain
@@ -7893,6 +8099,7 @@ disable_command (char *args, int from_tty)
       case bp_catch_fork:
       case bp_catch_vfork:
       case bp_catch_exec:
+      case bp_catch_syscall:
       case bp_hardware_breakpoint:
       case bp_watchpoint:
       case bp_hardware_watchpoint:
@@ -8027,6 +8234,7 @@ enable_command (char *args, int from_tty)
       case bp_catch_fork:
       case bp_catch_vfork:
       case bp_catch_exec:
+      case bp_catch_syscall:
       case bp_hardware_breakpoint:
       case bp_watchpoint:
       case bp_hardware_watchpoint:
@@ -8209,6 +8417,45 @@ single_step_breakpoint_inserted_here_p (CORE_ADDR pc)
   return 0;
 }
 
+/* Returns 0 if 'bp' is NOT a syscall catchpoint,
+   non-zero otherwise. */
+static int
+is_syscall_catchpoint_enabled (struct breakpoint *bp)
+{
+  if (bp->type == bp_catch_syscall
+      && bp->enable_state != bp_disabled
+      && bp->enable_state != bp_call_disabled)
+    return 1;
+  else
+    return 0;
+}
+
+int
+catch_syscall_enabled (void)
+{
+  struct breakpoint *bp;
+
+  ALL_BREAKPOINTS (bp)
+    if (is_syscall_catchpoint_enabled (bp))
+      return 1;
+
+  return 0;
+}
+
+int
+catching_syscall_number (int syscall_number)
+{
+  struct breakpoint *bp;
+
+  ALL_BREAKPOINTS (bp)
+    if (is_syscall_catchpoint_enabled (bp))
+      if (bp->syscall_to_be_caught == syscall_number
+          || bp->syscall_to_be_caught == CATCHING_ANY_SYSCALL)
+        return 1;
+
+  return 0;
+}
+
 
 /* This help string is used for the break, hbreak, tbreak and thbreak commands.
    It is defined as a macro to prevent duplication.
@@ -8549,6 +8796,12 @@ With an argument, catch only exceptions with the given name."),
 		     catch_exec_command_1,
 		     CATCH_PERMANENT,
 		     CATCH_TEMPORARY);
+  add_catch_command ("syscall", _("\
+Catch calls to syscalls.\n\
+With an argument, catch only calls of that syscall."),
+                     catch_syscall_command_1,
+                     CATCH_PERMANENT,
+                     CATCH_TEMPORARY);
   add_catch_command ("load", _("\
 Catch library loads.\n\
 With an argument, catch only loads of that library."),
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index db6e972..bc3de7f 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -33,6 +33,11 @@ struct block;
 
 #define	BREAKPOINT_MAX	16
 
+
+/* A number to represent wether we are catching any syscalls. */
+
+#define CATCHING_ANY_SYSCALL (-1)
+
 /* Type of breakpoint. */
 /* FIXME In the future, we should fold all other breakpoint-like things into
    here.  This includes:
@@ -127,6 +132,14 @@ enum bptype
     bp_catch_fork,
     bp_catch_vfork,
     bp_catch_exec,
+
+    /* This is not really a breakpoint, but the catchpoint which implements
+       the "catch syscall" functionality. */
+    bp_catch_syscall,
+
+    /* This type is used to signal an internal breakpoint located at
+       the AT_ENTRY address. */
+    bp_entry_breakpoint,
   };
 
 /* States of enablement of breakpoint. */
@@ -455,6 +468,21 @@ struct breakpoint
        triggered.  */
     char *exec_pathname;
 
+    /* Syscall number used for the 'catch syscall' feature.
+       If no syscall has been called, its value is UNKNOWN_SYSCALL.
+       Otherwise, it holds the system call number in the target.
+
+       This field is only valid immediately after this catchpoint has
+       triggered.  */
+    int syscall_number;
+
+    /* This field is used when we are "filtering" the syscalls
+       (i.e., when the user types "catch syscall <SYSCALL_NAME>".
+
+       It stores the syscall number in case we are in the "filter mode",
+       or CATCHING_ANY_SYSCALL otherwise. */
+    int syscall_to_be_caught;
+
     /* Methods associated with this breakpoint.  */
     struct breakpoint_ops *ops;
 
@@ -536,6 +564,10 @@ enum bpstat_what_main_action
        resume out of the dynamic linker's callback, stop and print.  */
     BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK,
 
+    /* This internal breakpoint is used syscall catchpoints only after the
+       shell and the dynamic linker have already ran. */
+    BPSTAT_WHAT_ENTRY_BREAKPOINT,
+
     /* This is just used to keep track of how many enums there are.  */
     BPSTAT_WHAT_LAST
   };
@@ -805,6 +837,8 @@ extern void enable_watchpoints_after_interactive_call_stop (void);
 extern enum command_control_type commands_from_control_command
   (char *arg, struct command_line *cmd);
 
+extern void clear_syscall_catchpoints_info (void);
+
 extern void clear_breakpoint_hit_counts (void);
 
 extern int get_number (char **);
@@ -884,4 +918,26 @@ extern int breakpoints_always_inserted_mode (void);
    in our opinion won't ever trigger.  */
 extern void breakpoint_retire_moribund (void);
 
+/* Checks if we are catching syscalls or not.
+   Returns 0 if not, greater than 0 if we are. */
+extern int catch_syscall_enabled (void);
+
+/* Checks if we are catching syscalls with the specific
+   syscall_number. Used for "filtering" the catchpoints.
+   Returns 0 if not, greater than 0 if we are. */
+extern int catching_syscall_number (int syscall_number);
+
+/* Function used to set an internal breakpoint at the AT_ENTRY
+   (a.k.a. the entry point of the inferior).
+
+   This is currently needed for us to know when to start setting
+   up catchpoints for syscalls in the inferior. If we don't do that,
+   then we would set a "catch syscall" too early, which would
+   catch syscalls from ld.so and/or libc (and we don't want that).
+
+   Returns zero if there was an error setting this breakpoint,
+   or 1 if everything went OK. */
+extern int create_entry_breakpoint (void);
+
+
 #endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index aa9a455..f4b3dec 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -240,6 +240,9 @@ struct gdbarch
   gdbarch_target_signal_from_host_ftype *target_signal_from_host;
   gdbarch_target_signal_to_host_ftype *target_signal_to_host;
   gdbarch_record_special_symbol_ftype *record_special_symbol;
+  gdbarch_get_syscall_number_ftype *get_syscall_number;
+  gdbarch_syscall_name_from_number_ftype *syscall_name_from_number;
+  gdbarch_syscall_number_from_name_ftype *syscall_number_from_name;
 };
 

@@ -371,6 +374,9 @@ struct gdbarch startup_gdbarch =
   default_target_signal_from_host,  /* target_signal_from_host */
   default_target_signal_to_host,  /* target_signal_to_host */
   0,  /* record_special_symbol */
+  0,  /* get_syscall_number */
+  0,  /* syscall_name_from_number */
+  0,  /* syscall_number_from_name */
   /* startup_gdbarch() */
 };
 
@@ -623,6 +629,9 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of target_signal_from_host, invalid_p == 0 */
   /* Skip verify of target_signal_to_host, invalid_p == 0 */
   /* Skip verify of record_special_symbol, has predicate */
+  /* Skip verify of get_syscall_number, has predicate */
+  /* Skip verify of syscall_name_from_number, has predicate */
+  /* Skip verify of syscall_number_from_name, has predicate */
   buf = ui_file_xstrdup (log, &dummy);
   make_cleanup (xfree, buf);
   if (strlen (buf) > 0)
@@ -832,6 +841,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
                       "gdbarch_dump: get_longjmp_target = <0x%lx>\n",
                       (long) gdbarch->get_longjmp_target);
   fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_get_syscall_number_p() = %d\n",
+                      gdbarch_get_syscall_number_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: get_syscall_number = <0x%lx>\n",
+                      (long) gdbarch->get_syscall_number);
+  fprintf_unfiltered (file,
                       "gdbarch_dump: have_nonsteppable_watchpoint = %s\n",
                       plongest (gdbarch->have_nonsteppable_watchpoint));
   fprintf_unfiltered (file,
@@ -1051,6 +1066,18 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
                       "gdbarch_dump: static_transform_name = <0x%lx>\n",
                       (long) gdbarch->static_transform_name);
   fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_syscall_name_from_number_p() = %d\n",
+                      gdbarch_syscall_name_from_number_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: syscall_name_from_number = <0x%lx>\n",
+                      (long) gdbarch->syscall_name_from_number);
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_syscall_number_from_name_p() = %d\n",
+                      gdbarch_syscall_number_from_name_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: syscall_number_from_name = <0x%lx>\n",
+                      (long) gdbarch->syscall_number_from_name);
+  fprintf_unfiltered (file,
                       "gdbarch_dump: target_desc = %s\n",
                       plongest ((long) gdbarch->target_desc));
   fprintf_unfiltered (file,
@@ -3237,6 +3264,78 @@ set_gdbarch_record_special_symbol (struct gdbarch *gdbarch,
   gdbarch->record_special_symbol = record_special_symbol;
 }
 
+int
+gdbarch_get_syscall_number_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->get_syscall_number != NULL;
+}
+
+LONGEST
+gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->get_syscall_number != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_number called\n");
+  return gdbarch->get_syscall_number (gdbarch, ptid);
+}
+
+void
+set_gdbarch_get_syscall_number (struct gdbarch *gdbarch,
+                                gdbarch_get_syscall_number_ftype get_syscall_number)
+{
+  gdbarch->get_syscall_number = get_syscall_number;
+}
+
+int
+gdbarch_syscall_name_from_number_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->syscall_name_from_number != NULL;
+}
+
+const char *
+gdbarch_syscall_name_from_number (struct gdbarch *gdbarch, int syscall_number)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->syscall_name_from_number != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_syscall_name_from_number called\n");
+  return gdbarch->syscall_name_from_number (gdbarch, syscall_number);
+}
+
+void
+set_gdbarch_syscall_name_from_number (struct gdbarch *gdbarch,
+                                      gdbarch_syscall_name_from_number_ftype syscall_name_from_number)
+{
+  gdbarch->syscall_name_from_number = syscall_name_from_number;
+}
+
+int
+gdbarch_syscall_number_from_name_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->syscall_number_from_name != NULL;
+}
+
+int
+gdbarch_syscall_number_from_name (struct gdbarch *gdbarch, const char *syscall_name)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->syscall_number_from_name != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_syscall_number_from_name called\n");
+  return gdbarch->syscall_number_from_name (gdbarch, syscall_name);
+}
+
+void
+set_gdbarch_syscall_number_from_name (struct gdbarch *gdbarch,
+                                      gdbarch_syscall_number_from_name_ftype syscall_number_from_name)
+{
+  gdbarch->syscall_number_from_name = syscall_number_from_name;
+}
+
 
 /* Keep a registry of per-architecture data-pointers required by GDB
    modules. */
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index bc8298d..a2b4468 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -811,6 +811,37 @@ typedef void (gdbarch_record_special_symbol_ftype) (struct gdbarch *gdbarch, str
 extern void gdbarch_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile, asymbol *sym);
 extern void set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, gdbarch_record_special_symbol_ftype *record_special_symbol);
 
+/* Functions for the 'catch syscall' feature.
+   Get architecture-specific system calls information from registers. */
+
+extern int gdbarch_get_syscall_number_p (struct gdbarch *gdbarch);
+
+typedef LONGEST (gdbarch_get_syscall_number_ftype) (struct gdbarch *gdbarch, ptid_t ptid);
+extern LONGEST gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid);
+extern void set_gdbarch_get_syscall_number (struct gdbarch *gdbarch, gdbarch_get_syscall_number_ftype *get_syscall_number);
+
+/* Translate a syscall number to its corresponding name. */
+
+extern int gdbarch_syscall_name_from_number_p (struct gdbarch *gdbarch);
+
+typedef const char * (gdbarch_syscall_name_from_number_ftype) (struct gdbarch *gdbarch, int syscall_number);
+extern const char * gdbarch_syscall_name_from_number (struct gdbarch *gdbarch, int syscall_number);
+extern void set_gdbarch_syscall_name_from_number (struct gdbarch *gdbarch, gdbarch_syscall_name_from_number_ftype *syscall_name_from_number);
+
+/* Translate a syscall name to its corresponding number.
+  
+   This function must return the syscall number if found, or
+   UNKNOWN_SYSCALL if not found. */
+
+extern int gdbarch_syscall_number_from_name_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_syscall_number_from_name_ftype) (struct gdbarch *gdbarch, const char *syscall_name);
+extern int gdbarch_syscall_number_from_name (struct gdbarch *gdbarch, const char *syscall_name);
+extern void set_gdbarch_syscall_number_from_name (struct gdbarch *gdbarch, gdbarch_syscall_number_from_name_ftype *syscall_number_from_name);
+
+/* Definition for an unknown syscall, used basically in error-cases. */
+#define UNKNOWN_SYSCALL (-1)
+
 extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
 

diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 0c513a5..684bb8c 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -707,6 +707,20 @@ m:int:target_signal_to_host:enum target_signal ts:ts::default_target_signal_to_h
 
 # Record architecture-specific information from the symbol table.
 M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym
+
+# Functions for the 'catch syscall' feature.
+
+# Get architecture-specific system calls information from registers.
+M:LONGEST:get_syscall_number:ptid_t ptid:ptid
+
+# Translate a syscall number to its corresponding name.
+M:const char *:syscall_name_from_number:int syscall_number:syscall_number
+
+# Translate a syscall name to its corresponding number.
+#
+# This function must return the syscall number if found, or
+# UNKNOWN_SYSCALL if not found.
+M:int:syscall_number_from_name:const char *syscall_name:syscall_name
 EOF
 }
 
@@ -888,6 +902,9 @@ done
 # close it off
 cat <<EOF
 
+/* Definition for an unknown syscall, used basically in error-cases. */
+#define UNKNOWN_SYSCALL (-1)
+
 extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
 

diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 0fb53fb..85245ca 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -170,6 +170,13 @@ struct thread_info
 
   /* Private data used by the target vector implementation.  */
   struct private_thread_info *private;
+
+  /* Signal wether we are in a SYSCALL_ENTRY or
+     in a SYSCALL_RETURN event.
+     Values:
+     - TARGET_WAITKIND_SYSCALL_ENTRY
+     - TARGET_WAITKIND_SYSCALL_RETURN */
+  int syscall_state;
 };
 
 /* Create an empty thread list, or empty the existing one.  */
diff --git a/gdb/inf-child.c b/gdb/inf-child.c
index 8da25f4..058cb34 100644
--- a/gdb/inf-child.c
+++ b/gdb/inf-child.c
@@ -144,6 +144,21 @@ inf_child_remove_exec_catchpoint (int pid)
   return 0;
 }
 
+static void
+inf_child_insert_syscall_catchpoint (int pid)
+{
+  /* This version of Unix doesn't support notification of syscall
+     events.  */
+}
+
+static int
+inf_child_remove_syscall_catchpoint (int pid)
+{
+  /* This version of Unix doesn't support notification of syscall
+     events.  */
+  return 0;
+}
+
 static int
 inf_child_can_run (void)
 {
@@ -187,6 +202,8 @@ inf_child_target (void)
   t->to_follow_fork = inf_child_follow_fork;
   t->to_insert_exec_catchpoint = inf_child_insert_exec_catchpoint;
   t->to_remove_exec_catchpoint = inf_child_remove_exec_catchpoint;
+  t->to_insert_syscall_catchpoint = inf_child_insert_syscall_catchpoint;
+  t->to_remove_syscall_catchpoint = inf_child_remove_syscall_catchpoint;
   t->to_can_run = inf_child_can_run;
   t->to_pid_to_exec_file = inf_child_pid_to_exec_file;
   t->to_stratum = process_stratum;
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index 57af79a..65e7acd 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -355,13 +355,19 @@ static void
 inf_ptrace_resume (ptid_t ptid, int step, enum target_signal signal)
 {
   pid_t pid = ptid_get_pid (ptid);
-  int request = PT_CONTINUE;
+  int request;
 
   if (pid == -1)
     /* Resume all threads.  Traditionally ptrace() only supports
        single-threaded processes, so simply resume the inferior.  */
     pid = ptid_get_pid (inferior_ptid);
 
+  if (target_passed_by_entrypoint () > 0
+      && catch_syscall_enabled () > 0)
+    request = PT_SYSCALL;
+  else
+    request = PT_CONTINUE;
+
   if (step)
     {
       /* If this system does not support PT_STEP, a higher level
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 6ed6341..09d4d9b 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -450,6 +450,11 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main)
   init_wait_for_inferior ();
   clear_breakpoint_hit_counts ();
 
+  /* If we already caught a syscall catchpoint, then reset its
+     syscall_number information because we are starting all over
+     again. */
+  clear_syscall_catchpoints_info ();
+
   /* Clean up any leftovers from other runs.  Some other things from
      this function should probably be moved into target_pre_inferior.  */
   target_pre_inferior (from_tty);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 4b4df8f..9c5efef 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -964,7 +964,7 @@ a command like `return' or `jump' to continue execution."));
         }
     }
 
-  /* If there were any forks/vforks/execs that were caught and are
+  /* If there were any forks/vforks/execs/syscalls that were caught and are
      now to be followed, then do so.  */
   switch (pending_follow.kind)
     {
@@ -980,6 +980,11 @@ a command like `return' or `jump' to continue execution."));
       pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
       break;
 
+    case TARGET_WAITKIND_SYSCALL_ENTRY:
+    case TARGET_WAITKIND_SYSCALL_RETURN:
+      pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
+      break;
+
     default:
       break;
     }
@@ -1386,7 +1391,7 @@ init_wait_for_inferior (void)
 
   breakpoint_init_inferior (inf_starting);
 
-  /* The first resume is not following a fork/vfork/exec. */
+  /* The first resume is not following a fork/vfork/exec/syscall. */
   pending_follow.kind = TARGET_WAITKIND_SPURIOUS;	/* I.e., none. */
 
   clear_proceed_status ();
@@ -1831,6 +1836,50 @@ ensure_not_running (void)
     error_is_running ();
 }
 
+/* Auxiliary function that handles syscall entry/return events.
+   It returns 1 if the inferior should keep going (and GDB
+   should ignore the event), or 0 if the event deserves to be
+   processed. */
+static int
+deal_with_syscall_event (struct execution_control_state *ecs)
+{
+  int syscall_number = gdbarch_get_syscall_number (current_gdbarch,
+                                                   ecs->ptid);
+  if (catch_syscall_enabled () > 0
+      && catching_syscall_number (syscall_number) > 0)
+    {
+      ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP;
+      pending_follow.kind = ecs->ws.kind;
+
+      if (!ptid_equal (ecs->ptid, inferior_ptid))
+        {
+          context_switch (ecs->ptid);
+          reinit_frame_cache ();
+        }
+
+      stop_pc = read_pc ();
+
+      ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+
+      ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
+
+      /* If no catchpoint triggered for this, then keep going.  */
+      if (ecs->random_signal)
+        {
+          ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
+          keep_going (ecs);
+          return 1;
+        }
+      return 0;
+    }
+  else
+    {
+      resume (0, TARGET_SIGNAL_0);
+      prepare_to_wait (ecs);
+      return 1;
+    }
+}
+
 /* Given an execution control state that has been freshly filled in
    by an event from the inferior, figure out what it means and take
    appropriate action.  */
@@ -2119,9 +2168,11 @@ handle_inferior_event (struct execution_control_state *ecs)
     case TARGET_WAITKIND_SYSCALL_ENTRY:
       if (debug_infrun)
         fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n");
-      resume (0, TARGET_SIGNAL_0);
-      prepare_to_wait (ecs);
-      return;
+      /* Getting the current syscall number */
+      if (deal_with_syscall_event (ecs) != 0)
+        return;
+      goto process_event_stop_test;
+      break;
 
       /* Before examining the threads further, step this thread to
          get it entirely out of the syscall.  (We get notice of the
@@ -2131,9 +2182,10 @@ handle_inferior_event (struct execution_control_state *ecs)
     case TARGET_WAITKIND_SYSCALL_RETURN:
       if (debug_infrun)
         fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_RETURN\n");
-      target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);
-      prepare_to_wait (ecs);
-      return;
+      if (deal_with_syscall_event (ecs) != 0)
+        return;
+      goto process_event_stop_test;
+      break;
 
     case TARGET_WAITKIND_STOPPED:
       if (debug_infrun)
@@ -2951,6 +3003,16 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
 	}
 	break;
 
+      case BPSTAT_WHAT_ENTRY_BREAKPOINT:
+        /* We hit the AT_ENTRY breakpoint, and now we have to enable
+           the PTRACE_O_TRACESYSGOOD option in the inferior *if* we
+           are catching syscalls. */
+        if (debug_infrun)
+          fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_ENTRY_BREAKPOINT\n");
+        target_enable_tracesysgood (ecs->ptid);
+        ecs->event_thread->stepping_over_breakpoint = 1;
+        break;
+
       case BPSTAT_WHAT_LAST:
 	/* Not a real code, but listed here to shut up gcc -Wall.  */
 
@@ -4563,6 +4625,25 @@ inferior_has_execd (ptid_t pid, char **execd_pathname)
   return 1;
 }
 
+int
+inferior_has_called_syscall (ptid_t pid, int *syscall_number)
+{
+  struct target_waitstatus last;
+  ptid_t last_ptid;
+
+  get_last_target_status (&last_ptid, &last);
+
+  if (last.kind != TARGET_WAITKIND_SYSCALL_ENTRY &&
+      last.kind != TARGET_WAITKIND_SYSCALL_RETURN)
+    return 0;
+
+  if (!ptid_equal (last_ptid, pid))
+    return 0;
+
+  *syscall_number = last.value.syscall_number;
+  return 1;
+}
+
 /* Oft used ptids */
 ptid_t null_ptid;
 ptid_t minus_one_ptid;
diff --git a/gdb/target.c b/gdb/target.c
index a509c17..39a92b5 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -426,6 +426,10 @@ update_current_target (void)
       /* Do not inherit to_follow_fork.  */
       INHERIT (to_insert_exec_catchpoint, t);
       INHERIT (to_remove_exec_catchpoint, t);
+      INHERIT (to_passed_by_entrypoint, t);
+      INHERIT (to_insert_syscall_catchpoint, t);
+      INHERIT (to_remove_syscall_catchpoint, t);
+      INHERIT (to_enable_tracesysgood, t);
       INHERIT (to_has_exited, t);
       INHERIT (to_mourn_inferior, t);
       INHERIT (to_can_run, t);
@@ -581,9 +585,21 @@ update_current_target (void)
   de_fault (to_insert_exec_catchpoint,
 	    (void (*) (int))
 	    tcomplain);
+  de_fault (to_passed_by_entrypoint,
+            (int (*) (void))
+            tcomplain);
   de_fault (to_remove_exec_catchpoint,
 	    (int (*) (int))
 	    tcomplain);
+  de_fault (to_insert_syscall_catchpoint,
+	    (void (*) (int))
+	    tcomplain);
+  de_fault (to_remove_syscall_catchpoint,
+	    (int (*) (int))
+	    tcomplain);
+  de_fault (to_enable_tracesysgood,
+            (void (*) (ptid_t))
+            tcomplain);
   de_fault (to_has_exited,
 	    (int (*) (int, int, int *))
 	    return_zero);
@@ -2532,6 +2548,12 @@ debug_to_wait (ptid_t ptid, struct target_waitstatus *status)
     case TARGET_WAITKIND_EXECD:
       fprintf_unfiltered (gdb_stdlog, "execd\n");
       break;
+    case TARGET_WAITKIND_SYSCALL_ENTRY:
+      fprintf_unfiltered (gdb_stdlog, "entered syscall\n");
+      break;
+    case TARGET_WAITKIND_SYSCALL_RETURN:
+      fprintf_unfiltered (gdb_stdlog, "exited syscall\n");
+      break;
     case TARGET_WAITKIND_SPURIOUS:
       fprintf_unfiltered (gdb_stdlog, "spurious\n");
       break;
diff --git a/gdb/target.h b/gdb/target.h
index 067c031..6e379d3 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -135,14 +135,15 @@ struct target_waitstatus
   {
     enum target_waitkind kind;
 
-    /* Forked child pid, execd pathname, exit status or signal number.  */
+    /* Forked child pid, execd pathname, exit status, signal number or
+       syscall name. */
     union
       {
 	int integer;
 	enum target_signal sig;
 	ptid_t related_pid;
 	char *execd_pathname;
-	int syscall_id;
+	int syscall_number;
       }
     value;
   };
@@ -393,6 +394,10 @@ struct target_ops
     int (*to_follow_fork) (struct target_ops *, int);
     void (*to_insert_exec_catchpoint) (int);
     int (*to_remove_exec_catchpoint) (int);
+    int (*to_passed_by_entrypoint) (void);
+    void (*to_insert_syscall_catchpoint) (int);
+    int (*to_remove_syscall_catchpoint) (int);
+    void (*to_enable_tracesysgood) (ptid_t);
     int (*to_has_exited) (int, int, int *);
     void (*to_mourn_inferior) (void);
     int (*to_can_run) (void);
@@ -708,6 +713,8 @@ extern int inferior_has_vforked (ptid_t pid, ptid_t *child_pid);
 
 extern int inferior_has_execd (ptid_t pid, char **execd_pathname);
 
+extern int inferior_has_called_syscall (ptid_t pid, int *syscall_number);
+
 /* From exec.c */
 
 extern void print_section_info (struct target_ops *, bfd *);
@@ -867,6 +874,24 @@ int target_follow_fork (int follow_child);
 #define target_remove_exec_catchpoint(pid) \
      (*current_target.to_remove_exec_catchpoint) (pid)
 
+/* Has the inferior already passed through its entrypoint? */
+#define target_passed_by_entrypoint() \
+     (*current_target.to_passed_by_entrypoint) ()
+
+/* Syscall catch functions */
+
+#define target_insert_syscall_catchpoint(pid) \
+     (*current_target.to_insert_syscall_catchpoint) (pid)
+
+#define target_remove_syscall_catchpoint(pid) \
+     (*current_target.to_remove_syscall_catchpoint) (pid)
+
+/* Enable PTRACE_O_TRACESYSGOOD in the inferior.
+   This is mainly used for the "catch syscall" feature. */
+
+#define target_enable_tracesysgood(ptid) \
+     (*current_target.to_enable_tracesysgood) (ptid)
+
 /* Returns TRUE if PID has exited.  And, also sets EXIT_STATUS to the
    exit code of PID, if any.  */
 



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]