Index: gdb/gdbarch.sh =================================================================== RCS file: /cvs/src/src/gdb/gdbarch.sh,v retrieving revision 1.550 diff -u -p -r1.550 gdbarch.sh --- gdb/gdbarch.sh 21 Nov 2012 00:29:54 -0000 1.550 +++ gdb/gdbarch.sh 11 Dec 2012 20:13:20 -0000 @@ -798,6 +798,10 @@ M:void:record_special_symbol:struct objf # Get architecture-specific system calls information from registers. M:LONGEST:get_syscall_number:ptid_t ptid:ptid +# Return number of bytes the architecture may increment PC after +# syscall. +M:int:syscall_pc_increment:const struct frame_info *frame:frame + # SystemTap related fields and functions. # Prefix used to mark an integer constant on the architecture's assembly Index: gdb/gdbarch.h =================================================================== RCS file: /cvs/src/src/gdb/gdbarch.h,v retrieving revision 1.449 diff -u -p -r1.449 gdbarch.h --- gdb/gdbarch.h 21 Nov 2012 00:29:54 -0000 1.449 +++ gdb/gdbarch.h 11 Dec 2012 20:13:20 -0000 @@ -611,7 +611,7 @@ extern void set_gdbarch_addr_bits_remove FIXME/cagney/2001-01-18: The logic is backwards. It should be asking if the target can single step. If not, then implement single step using breakpoints. - A return value of 1 means that the software_single_step breakpoints + A return value of 1 means that the software_single_step breakpoints were inserted; 0 means they were not. */ extern int gdbarch_software_single_step_p (struct gdbarch *gdbarch); @@ -998,6 +998,15 @@ typedef LONGEST (gdbarch_get_syscall_num 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); +/* Return number of bytes the architecture may increment PC after + syscall. */ + +extern int gdbarch_syscall_pc_increment_p (struct gdbarch *gdbarch); + +typedef int (gdbarch_syscall_pc_increment_ftype) (struct gdbarch *gdbarch, const struct frame_info *frame); +extern int gdbarch_syscall_pc_increment (struct gdbarch *gdbarch, const struct frame_info *frame); +extern void set_gdbarch_syscall_pc_increment (struct gdbarch *gdbarch, gdbarch_syscall_pc_increment_ftype *syscall_pc_increment); + /* SystemTap related fields and functions. Prefix used to mark an integer constant on the architecture's assembly For example, on x86 integer constants are written as: Index: gdb/gdbarch.c =================================================================== RCS file: /cvs/src/src/gdb/gdbarch.c,v retrieving revision 1.501 diff -u -p -r1.501 gdbarch.c --- gdb/gdbarch.c 21 Nov 2012 00:29:54 -0000 1.501 +++ gdb/gdbarch.c 11 Dec 2012 20:13:20 -0000 @@ -263,6 +263,7 @@ struct gdbarch gdbarch_get_siginfo_type_ftype *get_siginfo_type; gdbarch_record_special_symbol_ftype *record_special_symbol; gdbarch_get_syscall_number_ftype *get_syscall_number; + gdbarch_syscall_pc_increment_ftype *syscall_pc_increment; const char * stap_integer_prefix; const char * stap_integer_suffix; const char * stap_register_prefix; @@ -431,6 +432,7 @@ struct gdbarch startup_gdbarch = 0, /* get_siginfo_type */ 0, /* record_special_symbol */ 0, /* get_syscall_number */ + 0, /* syscall_pc_increment */ 0, /* stap_integer_prefix */ 0, /* stap_integer_suffix */ 0, /* stap_register_prefix */ @@ -731,6 +733,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of get_siginfo_type, has predicate. */ /* Skip verify of record_special_symbol, has predicate. */ /* Skip verify of get_syscall_number, has predicate. */ + /* Skip verify of syscall_pc_increment, has predicate. */ /* Skip verify of stap_integer_prefix, invalid_p == 0 */ /* Skip verify of stap_integer_suffix, invalid_p == 0 */ /* Skip verify of stap_register_prefix, invalid_p == 0 */ @@ -1345,6 +1348,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s "gdbarch_dump: static_transform_name = <%s>\n", host_address_to_string (gdbarch->static_transform_name)); fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_syscall_pc_increment_p() = %d\n", + gdbarch_syscall_pc_increment_p (gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: syscall_pc_increment = <%s>\n", + host_address_to_string (gdbarch->syscall_pc_increment)); + fprintf_unfiltered (file, "gdbarch_dump: target_desc = %s\n", host_address_to_string (gdbarch->target_desc)); fprintf_unfiltered (file, @@ -3890,6 +3899,30 @@ set_gdbarch_get_syscall_number (struct g gdbarch->get_syscall_number = get_syscall_number; } +int +gdbarch_syscall_pc_increment_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->syscall_pc_increment != NULL; +} + +int +gdbarch_syscall_pc_increment (struct gdbarch *gdbarch, const struct frame_info *frame) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->syscall_pc_increment != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_syscall_pc_increment called\n"); + return gdbarch->syscall_pc_increment (gdbarch, frame); +} + +void +set_gdbarch_syscall_pc_increment (struct gdbarch *gdbarch, + gdbarch_syscall_pc_increment_ftype syscall_pc_increment) +{ + gdbarch->syscall_pc_increment = syscall_pc_increment; +} + const char * gdbarch_stap_integer_prefix (struct gdbarch *gdbarch) { Index: gdb/arm-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/arm-tdep.c,v retrieving revision 1.373 diff -u -p -r1.373 arm-tdep.c --- gdb/arm-tdep.c 21 Nov 2012 00:29:54 -0000 1.373 +++ gdb/arm-tdep.c 11 Dec 2012 20:13:21 -0000 @@ -5242,6 +5242,31 @@ arm_software_single_step (struct frame_i next_pc = arm_get_next_pc (frame, get_frame_pc (frame)); arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc); + if (gdbarch_syscall_pc_increment_p (gdbarch)) + { + /* Some OS-es will increment pc to differentiate success vs + * error returning from a sys call. */ + const int inc = gdbarch_syscall_pc_increment (gdbarch, frame); + const enum bfd_endian byte_order_for_code + = gdbarch_byte_order_for_code (gdbarch); + const LONGEST this_pc = get_frame_pc (frame); + LONGEST insn, mask, match; + + if (arm_frame_is_thumb (frame)) + { + mask = 0xff000000; + match = 0xdf000000; + } + else + { + mask = 0x0f000000; + match = 0x0f000000; + } + if (safe_read_memory_integer (this_pc, 4, byte_order_for_code, &insn) + && (insn & mask) == match) + arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc + inc); + } + return 1; }