--- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -1028,7 +1028,9 @@ update_watchpoint (struct breakpoint *b, int reparse) addr = value_address (v); len = TYPE_LENGTH (value_type (v)); type = hw_write; - if (b->type == bp_read_watchpoint) + if (v == val_chain && value_lazy (v)) + type = hw_mmap; + else if (b->type == bp_read_watchpoint) type = hw_read; else if (b->type == bp_access_watchpoint) type = hw_access; @@ -1287,9 +1289,17 @@ Note: automatically using hardware breakpoints for read-only addresses.\n")); watchpoints. It's not clear that it's necessary... */ && bpt->owner->disposition != disp_del_at_next_stop) { - val = target_insert_watchpoint (bpt->address, - bpt->length, - bpt->watchpoint_type); + if (bpt->watchpoint_type == hw_mmap) + { + struct inferior *inf = current_inferior (); + + inf->trap_syscalls = 1; + val = 0; + } + else + val = target_insert_watchpoint (bpt->address, + bpt->length, + bpt->watchpoint_type); bpt->inserted = (val != -1); } @@ -1796,8 +1806,11 @@ remove_breakpoint (struct bp_location *b, insertion_state_t is) struct value *n; b->inserted = (is == mark_inserted); - val = target_remove_watchpoint (b->address, b->length, - b->watchpoint_type); + if (b->watchpoint_type == hw_mmap) + val = 0; + else + val = target_remove_watchpoint (b->address, b->length, + b->watchpoint_type); /* Failure to remove any of the hardware watchpoints comes here. */ if ((is == mark_uninserted) && (b->inserted)) @@ -2783,6 +2796,25 @@ watchpoints_triggered (struct target_waitstatus *ws) return 1; } +void +mmap_watchpoints_triggered (void) +{ + struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (b->type == bp_hardware_watchpoint) + { + struct bp_location *loc; + + for (loc = b->loc; loc; loc = loc->next) + if (loc->watchpoint_type == hw_mmap) + { + b->watchpoint_triggered = watch_triggered_yes; + break; + } + } +} + /* Possible return values for watchpoint_check (this can't be an enum because of check_errors). */ /* The watchpoint has been deleted. */ @@ -6333,7 +6365,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty) struct symtab_and_line sal; struct expression *exp; struct block *exp_valid_block; - struct value *val, *mark; + struct value *val, *mark, *result; struct frame_info *frame; char *exp_start = NULL; char *exp_end = NULL; @@ -6423,7 +6455,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty) exp_valid_block = innermost_block; mark = value_mark (); - fetch_watchpoint_value (exp, &val, NULL, NULL); + fetch_watchpoint_value (exp, &val, &result, NULL); if (val != NULL) release_value (val); @@ -6455,7 +6487,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty) mem_cnt = can_use_hardware_watchpoint (val); if (mem_cnt == 0 && bp_type != bp_hardware_watchpoint) error (_("Expression cannot be implemented with read/access watchpoint.")); - if (mem_cnt != 0) + if (mem_cnt != 0 || !val) { i = hw_watchpoint_used_count (bp_type, &other_type_used); target_resources_ok = @@ -6470,7 +6502,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty) /* Change the type of breakpoint to an ordinary watchpoint if a hardware watchpoint could not be set. */ - if (!mem_cnt || target_resources_ok <= 0) + if ((!mem_cnt && val) || target_resources_ok <= 0) bp_type = bp_watchpoint; frame = block_innermost_frame (exp_valid_block); --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -167,7 +167,8 @@ enum target_hw_bp_type hw_write = 0, /* Common HW watchpoint */ hw_read = 1, /* Read HW watchpoint */ hw_access = 2, /* Access HW watchpoint */ - hw_execute = 3 /* Execute HW breakpoint */ + hw_execute = 3, /* Execute HW breakpoint */ + hw_mmap = 4 /* Memory area gets mmap(2)ed. */ }; @@ -912,6 +913,8 @@ extern int deprecated_remove_raw_breakpoint (struct gdbarch *, void *); target. */ int watchpoints_triggered (struct target_waitstatus *); +extern void mmap_watchpoints_triggered (void); + /* Update BUF, which is LEN bytes read from the target address MEMADDR, by replacing any memory breakpoints with their shadowed contents. */ void breakpoint_restore_shadows (gdb_byte *buf, ULONGEST memaddr, --- a/gdb/gdb_ptrace.h +++ b/gdb/gdb_ptrace.h @@ -92,6 +92,11 @@ # endif #endif +#ifndef PT_SYSCALL +# define PT_SYSCALL 24 /* Continue and stop at the next (return from) + syscall. */ +#endif + /* Not all systems support attaching and detaching. */ #ifndef PT_ATTACH --- a/gdb/inf-ptrace.c +++ b/gdb/inf-ptrace.c @@ -339,7 +339,9 @@ inf_ptrace_resume (struct target_ops *ops, single-threaded processes, so simply resume the inferior. */ pid = ptid_get_pid (inferior_ptid); - if (step) + if (step == 2) + request = PT_SYSCALL; + else if (step) { /* If this system does not support PT_STEP, a higher level function will have called single_step() to transmute the step --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -425,6 +425,8 @@ struct inferior /* Private data used by the target vector implementation. */ struct private_inferior *private; + + unsigned trap_syscalls : 1; }; /* Create an empty inferior list, or empty the existing one. */ --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1211,7 +1211,7 @@ a command like `return' or `jump' to continue execution.")); } /* Do we need to do it the hard way, w/temp breakpoints? */ - if (step) + if (step == 1) step = maybe_software_singlestep (gdbarch, pc); if (should_resume) @@ -1380,6 +1380,7 @@ clear_proceed_status (void) inferior = current_inferior (); inferior->stop_soon = NO_STOP_QUIETLY; + inferior->trap_syscalls = 0; } stop_after_trap = 0; @@ -1478,6 +1479,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) struct thread_info *tp; CORE_ADDR pc; int oneproc = 0; + struct inferior *inf; /* If we're stopped at a fork/vfork, follow the branch set by the "set follow-fork-mode" command; otherwise, we'll just proceed @@ -1640,8 +1642,10 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step) /* Reset to normal state. */ init_infwait_state (); + inf = current_inferior (); + /* Resume inferior. */ - resume (oneproc || step || bpstat_should_step (), tp->stop_signal); + resume (oneproc || step || bpstat_should_step () ? 1 : (inf->trap_syscalls ? 2 : 0), tp->stop_signal); /* Wait for it to stop (if not standalone) and in any case decode why it stopped, and act accordingly. */ @@ -3052,6 +3056,15 @@ targets should add new threads to the thread list themselves in non-stop mode.") else stopped_by_watchpoint = watchpoints_triggered (&ecs->ws); + if (ecs->ws.kind == TARGET_WAITKIND_STOPPED + && ecs->ws.value.sig == TARGET_SIGNAL_TRAP) + { + struct inferior *inferior = current_inferior (); + + if (inferior->trap_syscalls) + mmap_watchpoints_triggered (); + } + /* If necessary, step over this watchpoint. We'll be back to display it in a moment. */ if (stopped_by_watchpoint --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -1654,6 +1654,22 @@ resume_set_callback (struct lwp_info *lp, void *data) return 0; } +static const char * +step_string (int step) +{ + switch (step) + { + case 0: + return "PTRACE_CONT"; + case 1: + return "PTRACE_SINGLESTEP"; + case 2: + return "PTRACE_SYSCALL"; + default: + gdb_assert (0); + } +} + static void linux_nat_resume (struct target_ops *ops, ptid_t ptid, int step, enum target_signal signo) @@ -1770,7 +1786,7 @@ linux_nat_resume (struct target_ops *ops, if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, "LLR: %s %s, %s (resume event thread)\n", - step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT", + step_string (step), target_pid_to_str (ptid), signo ? strsignal (signo) : "0"); @@ -2672,8 +2688,7 @@ linux_nat_filter_event (int lwpid, int status, int options) if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, "LLW: %s %s, 0, 0 (discard SIGSTOP)\n", - lp->step ? - "PTRACE_SINGLESTEP" : "PTRACE_CONT", + step_string (lp->step), target_pid_to_str (lp->ptid)); lp->stopped = 0; @@ -2702,8 +2717,7 @@ linux_nat_filter_event (int lwpid, int status, int options) if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, "LLW: %s %s, 0, 0 (discard SIGINT)\n", - lp->step ? - "PTRACE_SINGLESTEP" : "PTRACE_CONT", + step_string (lp->step), target_pid_to_str (lp->ptid)); lp->stopped = 0; @@ -2841,7 +2855,7 @@ retry: if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, "LLW: %s %s, 0, 0 (expect SIGSTOP)\n", - lp->step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT", + step_string (lp->step), target_pid_to_str (lp->ptid)); lp->stopped = 0; gdb_assert (lp->resumed); @@ -3024,8 +3038,7 @@ retry: if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, "LLW: %s %s, %s (preempt 'handle')\n", - lp->step ? - "PTRACE_SINGLESTEP" : "PTRACE_CONT", + step_string (lp->step), target_pid_to_str (lp->ptid), signo ? strsignal (signo) : "0"); lp->stopped = 0;