From patchwork Tue Nov 4 19:03:08 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 3576 Received: (qmail 4717 invoked by alias); 4 Nov 2014 19:03:19 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 4573 invoked by uid 89); 4 Nov 2014 19:03:18 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Tue, 04 Nov 2014 19:03:16 +0000 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id sA4J3EOf004005 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Tue, 4 Nov 2014 14:03:15 -0500 Received: from brno.lan (ovpn01.gateway.prod.ext.ams2.redhat.com [10.39.146.11]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id sA4J3Bm3026910 for ; Tue, 4 Nov 2014 14:03:13 -0500 From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH 1/3] add a default method for gdbarch_skip_permanent_breakpoint Date: Tue, 4 Nov 2014 19:03:08 +0000 Message-Id: <1415127790-15091-2-git-send-email-palves@redhat.com> In-Reply-To: <1415127790-15091-1-git-send-email-palves@redhat.com> References: <1415127790-15091-1-git-send-email-palves@redhat.com> breakpoint.c uses gdbarch_breakpoint_from_pc to determine whether a breakpoint location points at a permanent breakpoint: static int bp_loc_is_permanent (struct bp_location *loc) { ... addr = loc->address; bpoint = gdbarch_breakpoint_from_pc (loc->gdbarch, &addr, &len); ... if (target_read_memory (loc->address, target_mem, len) == 0 && memcmp (target_mem, bpoint, len) == 0) retval = 1; ... So I think we should default the gdbarch_skip_permanent_breakpoint hook to advancing the PC by the length of the breakpoint instruction, as determined by gdbarch_breakpoint_from_pc. I believe that simple implementation does the right thing for most architectures. If there's an oddball architecture where that doesn't work, then it should override the hook, just like it should be overriding the hook if there was no default anyway. The only two implementation of skip_permanent_breakpoint are i386_skip_permanent_breakpoint, for x86, and hppa_skip_permanent_breakpoint, for PA-RISC/HP-UX The x86 implementation is trivial, and can clearly be replaced by the new default. I don't know about the HP-UX one though, I know almost nothing about PA. It may well be advancing the PC ends up being equivalent. Otherwise, it must be that "jump $pc_after_bp" doesn't work either... Tested on x86_64 Fedora 20. gdb/ 2014-11-04 Pedro Alves * arch-utils.c (default_skip_permanent_breakpoint): New function. * arch-utils.h (default_skip_permanent_breakpoint): New declaration. * gdbarch.sh (skip_permanent_breakpoint): Now an 'f' function. Install default_skip_permanent_breakpoint as default method. * i386-tdep.c (i386_skip_permanent_breakpoint): Delete function. (i386_gdbarch_init): Don't install it. * infrun.c (resume): Assume there's always a gdbarch_skip_permanent_breakpoint implementation. --- gdb/arch-utils.c | 13 ++++++++++++- gdb/arch-utils.h | 8 ++++++++ gdb/gdbarch.c | 13 ++----------- gdb/gdbarch.h | 2 -- gdb/gdbarch.sh | 2 +- gdb/i386-tdep.c | 15 --------------- gdb/infrun.c | 8 +------- 7 files changed, 24 insertions(+), 37 deletions(-) diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index 41cf828..a2e76de 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -826,7 +826,18 @@ int default_insn_is_jump (struct gdbarch *gdbarch, CORE_ADDR addr) return 0; } -/* */ +void +default_skip_permanent_breakpoint (struct regcache *regcache) +{ + struct gdbarch *gdbarch = get_regcache_arch (regcache); + CORE_ADDR current_pc = regcache_read_pc (regcache); + const gdb_byte *bp_insn; + int bp_len; + + bp_insn = gdbarch_breakpoint_from_pc (gdbarch, ¤t_pc, &bp_len); + current_pc += bp_len; + regcache_write_pc (regcache, current_pc); +} /* -Wmissing-prototypes */ extern initialize_file_ftype _initialize_gdbarch_utils; diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h index a609662..1f5dd55 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -178,4 +178,12 @@ extern int default_insn_is_jump (struct gdbarch *, CORE_ADDR); /* Do-nothing version of vsyscall_range. Returns false. */ extern int default_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range); + +/* Default way to advance the PC to the next instruction in order to + skip a permanent breakpoint. Increments the PC by the size of a + software breakpoint instruction, as determined with + gdbarch_breakpoint_from_pc. This matches how the breakpoints + module determines whether a breakpoint is permanent. */ +extern void default_skip_permanent_breakpoint (struct regcache *regcache); + #endif diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 2984358..bd53acc 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -393,6 +393,7 @@ gdbarch_alloc (const struct gdbarch_info *info, gdbarch->elf_make_msymbol_special = default_elf_make_msymbol_special; gdbarch->coff_make_msymbol_special = default_coff_make_msymbol_special; gdbarch->register_reggroup_p = default_register_reggroup_p; + gdbarch->skip_permanent_breakpoint = default_skip_permanent_breakpoint; gdbarch->displaced_step_hw_singlestep = default_displaced_step_hw_singlestep; gdbarch->displaced_step_fixup = NULL; gdbarch->displaced_step_free_closure = NULL; @@ -581,7 +582,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of gcore_bfd_target, has predicate. */ /* Skip verify of vtable_function_descriptors, invalid_p == 0 */ /* Skip verify of vbit_in_delta, invalid_p == 0 */ - /* Skip verify of skip_permanent_breakpoint, has predicate. */ + /* Skip verify of skip_permanent_breakpoint, invalid_p == 0 */ /* Skip verify of max_insn_length, has predicate. */ /* Skip verify of displaced_step_copy_insn, has predicate. */ /* Skip verify of displaced_step_hw_singlestep, invalid_p == 0 */ @@ -1190,9 +1191,6 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) "gdbarch_dump: skip_main_prologue = <%s>\n", host_address_to_string (gdbarch->skip_main_prologue)); fprintf_unfiltered (file, - "gdbarch_dump: gdbarch_skip_permanent_breakpoint_p() = %d\n", - gdbarch_skip_permanent_breakpoint_p (gdbarch)); - fprintf_unfiltered (file, "gdbarch_dump: skip_permanent_breakpoint = <%s>\n", host_address_to_string (gdbarch->skip_permanent_breakpoint)); fprintf_unfiltered (file, @@ -3465,13 +3463,6 @@ set_gdbarch_vbit_in_delta (struct gdbarch *gdbarch, gdbarch->vbit_in_delta = vbit_in_delta; } -int -gdbarch_skip_permanent_breakpoint_p (struct gdbarch *gdbarch) -{ - gdb_assert (gdbarch != NULL); - return gdbarch->skip_permanent_breakpoint != NULL; -} - void gdbarch_skip_permanent_breakpoint (struct gdbarch *gdbarch, struct regcache *regcache) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index f5330c2..5cd4197 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -829,8 +829,6 @@ extern void set_gdbarch_vbit_in_delta (struct gdbarch *gdbarch, int vbit_in_delt /* Advance PC to next instruction in order to skip a permanent breakpoint. */ -extern int gdbarch_skip_permanent_breakpoint_p (struct gdbarch *gdbarch); - typedef void (gdbarch_skip_permanent_breakpoint_ftype) (struct regcache *regcache); extern void gdbarch_skip_permanent_breakpoint (struct gdbarch *gdbarch, struct regcache *regcache); extern void set_gdbarch_skip_permanent_breakpoint (struct gdbarch *gdbarch, gdbarch_skip_permanent_breakpoint_ftype *skip_permanent_breakpoint); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 5442799..d9b55c2 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -699,7 +699,7 @@ v:int:vtable_function_descriptors:::0:0::0 v:int:vbit_in_delta:::0:0::0 # Advance PC to next instruction in order to skip a permanent breakpoint. -F:void:skip_permanent_breakpoint:struct regcache *regcache:regcache +f:void:skip_permanent_breakpoint:struct regcache *regcache:regcache:default_skip_permanent_breakpoint:default_skip_permanent_breakpoint::0 # The maximum length of an instruction on this architecture in bytes. V:ULONGEST:max_insn_length:::0:0 diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index 8387c72..83956bf 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -4523,18 +4523,6 @@ i386_fetch_pointer_argument (struct frame_info *frame, int argi, return read_memory_unsigned_integer (sp + (4 * (argi + 1)), 4, byte_order); } -static void -i386_skip_permanent_breakpoint (struct regcache *regcache) -{ - CORE_ADDR current_pc = regcache_read_pc (regcache); - - /* On i386, breakpoint is exactly 1 byte long, so we just - adjust the PC in the regcache. */ - current_pc += 1; - regcache_write_pc (regcache, current_pc); -} - - #define PREFIX_REPZ 0x01 #define PREFIX_REPNZ 0x02 #define PREFIX_LOCK 0x04 @@ -8566,9 +8554,6 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_iterate_over_regset_sections (gdbarch, i386_iterate_over_regset_sections); - set_gdbarch_skip_permanent_breakpoint (gdbarch, - i386_skip_permanent_breakpoint); - set_gdbarch_fast_tracepoint_valid_at (gdbarch, i386_fast_tracepoint_valid_at); diff --git a/gdb/infrun.c b/gdb/infrun.c index b950b74..4c4f03b 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -2075,13 +2075,7 @@ resume (int step, enum gdb_signal sig) breakpoints can't be removed. So we have to test for it here. */ if (breakpoint_here_p (aspace, pc) == permanent_breakpoint_here) { - if (gdbarch_skip_permanent_breakpoint_p (gdbarch)) - gdbarch_skip_permanent_breakpoint (gdbarch, regcache); - else - error (_("\ -The program is stopped at a permanent breakpoint, but GDB does not know\n\ -how to step past a permanent breakpoint on this architecture. Try using\n\ -a command like `return' or `jump' to continue execution.")); + gdbarch_skip_permanent_breakpoint (gdbarch, regcache); } /* If we have a breakpoint to step over, make sure to do a single