From: Randolph Chung Date: Fri, 3 Dec 2004 23:59:53 +0000 (+0000) Subject: 2004-12-03 Randolph Chung X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=fe46cd3ab5b2a04cb88f5f34a2d692dc856b3a5a;p=binutils-gdb.git 2004-12-03 Randolph Chung * gdbarch.sh (instruction_nullified): Delete. * gdbarch.c: Regenerate. * gdbarch.h: Regenerate. * hppa-tdep.c (hppa_target_read_pc): Adjust pc if instruction is nullified. (hppa_unwind_pc): Likewise. (hppa_instruction_nullified): Delete. (hppa_gdbarch_init): Don't set instruction_nullified method. * infrun.c (infwait_states): Remove infwait_nullified_state. (handle_inferior_event): Remove handling of infwait_nullified_state. Remove handling of nullified instructions. testsuite/ * gdb.arch/pa-nullify.exp: New file. * gdb.arch/pa-nullify.s: New file. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7e43c8ea400..cbe9c1a5725 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,17 @@ +2004-12-03 Randolph Chung + + * gdbarch.sh (instruction_nullified): Delete. + * gdbarch.c: Regenerate. + * gdbarch.h: Regenerate. + * hppa-tdep.c (hppa_target_read_pc): Adjust pc if instruction is + nullified. + (hppa_unwind_pc): Likewise. + (hppa_instruction_nullified): Delete. + (hppa_gdbarch_init): Don't set instruction_nullified method. + * infrun.c (infwait_states): Remove infwait_nullified_state. + (handle_inferior_event): Remove handling of infwait_nullified_state. + Remove handling of nullified instructions. + 2004-12-03 Mark Kettenis * inf-ttrace.c: Include . diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index efc6bd73361..c277e912eee 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -212,7 +212,6 @@ struct gdbarch gdbarch_smash_text_address_ftype *smash_text_address; gdbarch_software_single_step_ftype *software_single_step; gdbarch_single_step_through_delay_ftype *single_step_through_delay; - gdbarch_instruction_nullified_ftype *instruction_nullified; gdbarch_print_insn_ftype *print_insn; gdbarch_skip_trampoline_code_ftype *skip_trampoline_code; gdbarch_skip_solib_resolver_ftype *skip_solib_resolver; @@ -339,7 +338,6 @@ struct gdbarch startup_gdbarch = 0, /* smash_text_address */ 0, /* software_single_step */ 0, /* single_step_through_delay */ - generic_instruction_nullified, /* instruction_nullified */ 0, /* print_insn */ 0, /* skip_trampoline_code */ generic_skip_solib_resolver, /* skip_solib_resolver */ @@ -437,7 +435,6 @@ gdbarch_alloc (const struct gdbarch_info *info, current_gdbarch->convert_from_func_ptr_addr = convert_from_func_ptr_addr_identity; current_gdbarch->addr_bits_remove = core_addr_identity; current_gdbarch->smash_text_address = core_addr_identity; - current_gdbarch->instruction_nullified = generic_instruction_nullified; current_gdbarch->skip_trampoline_code = generic_skip_trampoline_code; current_gdbarch->skip_solib_resolver = generic_skip_solib_resolver; current_gdbarch->in_solib_return_trampoline = generic_in_solib_return_trampoline; @@ -594,7 +591,6 @@ verify_gdbarch (struct gdbarch *current_gdbarch) /* Skip verify of smash_text_address, invalid_p == 0 */ /* Skip verify of software_single_step, has predicate */ /* Skip verify of single_step_through_delay, has predicate */ - /* Skip verify of instruction_nullified, invalid_p == 0 */ if (current_gdbarch->print_insn == 0) fprintf_unfiltered (log, "\n\tprint_insn"); /* Skip verify of skip_trampoline_code, invalid_p == 0 */ @@ -1199,9 +1195,6 @@ gdbarch_dump (struct gdbarch *current_gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: inner_than = <0x%lx>\n", (long) current_gdbarch->inner_than); - fprintf_unfiltered (file, - "gdbarch_dump: instruction_nullified = <0x%lx>\n", - (long) current_gdbarch->instruction_nullified); #ifdef TARGET_INT_BIT fprintf_unfiltered (file, "gdbarch_dump: TARGET_INT_BIT # %s\n", @@ -3372,23 +3365,6 @@ set_gdbarch_single_step_through_delay (struct gdbarch *gdbarch, gdbarch->single_step_through_delay = single_step_through_delay; } -int -gdbarch_instruction_nullified (struct gdbarch *gdbarch, struct regcache *regcache) -{ - gdb_assert (gdbarch != NULL); - gdb_assert (gdbarch->instruction_nullified != NULL); - if (gdbarch_debug >= 2) - fprintf_unfiltered (gdb_stdlog, "gdbarch_instruction_nullified called\n"); - return gdbarch->instruction_nullified (gdbarch, regcache); -} - -void -set_gdbarch_instruction_nullified (struct gdbarch *gdbarch, - gdbarch_instruction_nullified_ftype instruction_nullified) -{ - gdbarch->instruction_nullified = instruction_nullified; -} - int gdbarch_print_insn (struct gdbarch *gdbarch, bfd_vma vma, struct disassemble_info *info) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index b59f6e76fa0..4ab8ea50afa 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -1227,16 +1227,6 @@ typedef int (gdbarch_single_step_through_delay_ftype) (struct gdbarch *gdbarch, extern int gdbarch_single_step_through_delay (struct gdbarch *gdbarch, struct frame_info *frame); extern void set_gdbarch_single_step_through_delay (struct gdbarch *gdbarch, gdbarch_single_step_through_delay_ftype *single_step_through_delay); -/* On some systems, the PC may be left pointing at an instruction that won't - actually be executed. This is usually indicated by a bit in the PSW. If - we find ourselves in such a state, then we step the target beyond the - nullified instruction before returning control to gdb. - Return non-zero if the processor is about to execute a nullified instruction. */ - -typedef int (gdbarch_instruction_nullified_ftype) (struct gdbarch *gdbarch, struct regcache *regcache); -extern int gdbarch_instruction_nullified (struct gdbarch *gdbarch, struct regcache *regcache); -extern void set_gdbarch_instruction_nullified (struct gdbarch *gdbarch, gdbarch_instruction_nullified_ftype *instruction_nullified); - /* FIXME: cagney/2003-08-28: Need to find a better way of selecting the disassembler. Perhaps objdump can handle it? */ diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 14abd74f8a6..aa0cd62cf25 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -614,12 +614,6 @@ F:=:void:software_single_step:enum target_signal sig, int insert_breakpoints_p:s # Return non-zero if the processor is executing a delay slot and a # further single-step is needed before the instruction finishes. M::int:single_step_through_delay:struct frame_info *frame:frame -# On some systems, the PC may be left pointing at an instruction that won't -# actually be executed. This is usually indicated by a bit in the PSW. If -# we find ourselves in such a state, then we step the target beyond the -# nullified instruction before returning control to gdb. -# Return non-zero if the processor is about to execute a nullified instruction. -m::int:instruction_nullified:struct regcache *regcache:regcache::generic_instruction_nullified::0 # FIXME: cagney/2003-08-28: Need to find a better way of selecting the # disassembler. Perhaps objdump can handle it? f:TARGET_PRINT_INSN:int:print_insn:bfd_vma vma, struct disassemble_info *info:vma, info::0: diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c index 2fc5a391fd1..312e16670c3 100644 --- a/gdb/hppa-tdep.c +++ b/gdb/hppa-tdep.c @@ -1042,6 +1042,8 @@ static CORE_ADDR hppa_target_read_pc (ptid_t ptid) { int flags = read_register_pid (HPPA_FLAGS_REGNUM, ptid); + ULONGEST ipsw = read_register_pid (HPPA_IPSW_REGNUM, ptid); + CORE_ADDR pc; /* The following test does not belong here. It is OS-specific, and belongs in native code. */ @@ -1049,7 +1051,17 @@ hppa_target_read_pc (ptid_t ptid) if (flags & 2) return read_register_pid (31, ptid) & ~0x3; - return read_register_pid (HPPA_PCOQ_HEAD_REGNUM, ptid) & ~0x3; + pc = read_register_pid (HPPA_PCOQ_HEAD_REGNUM, ptid) & ~0x3; + + /* If the current instruction is nullified, then we are effectively + still executing the previous instruction. Pretend we are still + there. This is needed when single stepping; if the nullified instruction + is on a different line, we don't want gdb to think we've stepped onto + that line. */ + if (ipsw & 0x00200000) + pc -= 4; + + return pc; } /* Write out the PC. If currently in a syscall, then also write the new @@ -2185,7 +2197,21 @@ hppa_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) static CORE_ADDR hppa_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) { - return frame_unwind_register_signed (next_frame, HPPA_PCOQ_HEAD_REGNUM) & ~3; + ULONGEST ipsw; + CORE_ADDR pc; + + ipsw = frame_unwind_register_signed (next_frame, HPPA_IPSW_REGNUM); + pc = frame_unwind_register_signed (next_frame, HPPA_PCOQ_HEAD_REGNUM) & ~3; + + /* If the current instruction is nullified, then we are effectively + still executing the previous instruction. Pretend we are still + there. This is needed when single stepping; if the nullified instruction + is on a different line, we don't want gdb to think we've stepped onto + that line. */ + if (ipsw & 0x00200000) + pc -= 4; + + return pc; } /* Instead of this nasty cast, add a method pvoid() that prints out a @@ -2291,22 +2317,6 @@ hppa_pc_requires_run_before_use (CORE_ADDR pc) return (!target_has_stack && (pc & 0xFF000000)); } -static int -hppa_instruction_nullified (struct gdbarch *gdbarch, struct regcache *regcache) -{ - ULONGEST tmp, ipsw, flags; - - regcache_cooked_read (regcache, HPPA_IPSW_REGNUM, &tmp); - ipsw = extract_unsigned_integer (&tmp, - register_size (gdbarch, HPPA_IPSW_REGNUM)); - - regcache_cooked_read (regcache, HPPA_FLAGS_REGNUM, &tmp); - flags = extract_unsigned_integer (&tmp, - register_size (gdbarch, HPPA_FLAGS_REGNUM)); - - return ((ipsw & 0x00200000) && !(flags & 0x2)); -} - /* Return the GDB type object for the "standard" data type of data in register N. */ @@ -2573,7 +2583,6 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_breakpoint_from_pc (gdbarch, hppa_breakpoint_from_pc); set_gdbarch_pseudo_register_read (gdbarch, hppa_pseudo_register_read); - set_gdbarch_instruction_nullified (gdbarch, hppa_instruction_nullified); /* Frame unwind methods. */ set_gdbarch_unwind_dummy_id (gdbarch, hppa_unwind_dummy_id); diff --git a/gdb/infrun.c b/gdb/infrun.c index fcbfd6c79b0..9352229d874 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -870,7 +870,6 @@ enum infwait_states { infwait_normal_state, infwait_thread_hop_state, - infwait_nullified_state, infwait_nonstep_watch_state }; @@ -1263,12 +1262,6 @@ handle_inferior_event (struct execution_control_state *ecs) stepped_after_stopped_by_watchpoint = 0; break; - case infwait_nullified_state: - if (debug_infrun) - printf_unfiltered ("infrun: infwait_nullified_state\n"); - stepped_after_stopped_by_watchpoint = 0; - break; - case infwait_nonstep_watch_state: if (debug_infrun) printf_unfiltered ("infrun: infwait_nonstep_watch_state\n"); @@ -1730,30 +1723,6 @@ handle_inferior_event (struct execution_control_state *ecs) singlestep_breakpoints_inserted_p = 0; } - /* If PC is pointing at a nullified instruction, then step beyond - it before deciding what to do. This is required when we are stepping - through a function where the last instruction is a branch with a - nullified instruction in the delay slot that belongs to the next - line (which may be in a different function altogether). */ - - if (gdbarch_instruction_nullified (current_gdbarch, current_regcache)) - { - if (debug_infrun) - printf_unfiltered ("infrun: instruction nullified\n"); - registers_changed (); - target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); - - /* We may have received a signal that we want to pass to - the inferior; therefore, we must not clobber the waitstatus - in WS. */ - - ecs->infwait_state = infwait_nullified_state; - ecs->waiton_ptid = ecs->ptid; - ecs->wp = &(ecs->tmpstatus); - prepare_to_wait (ecs); - return; - } - /* It may not be necessary to disable the watchpoint to stop over it. For example, the PA can (with some kernel cooperation) single step over a watchpoint without disabling the watchpoint. */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 1a87a090b41..c129cec3a32 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2004-12-03 Randolph Chung + + * gdb.arch/pa-nullify.exp: New file. + * gdb.arch/pa-nullify.s: New file. + 2004-11-30 Randolph Chung * gdb.threads/thread_check.exp: Use ${srcfile} for test program name diff --git a/gdb/testsuite/gdb.arch/pa-nullify.exp b/gdb/testsuite/gdb.arch/pa-nullify.exp new file mode 100644 index 00000000000..4cf5c725876 --- /dev/null +++ b/gdb/testsuite/gdb.arch/pa-nullify.exp @@ -0,0 +1,152 @@ +# Copyright 2004 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# This file is part of the gdb testsuite. + +if $tracelevel { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +# Test handling of nullified instructions for the pa target. + +if ![istarget "hppa*-*-*"] then { + verbose "Skipping hppa nullification tests." + return +} + +set testfile "pa-nullify" +set srcfile ${testfile}.s +set binfile ${objdir}/${subdir}/${testfile} +set gcorefile ${objdir}/${subdir}/${testfile}.gcore + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {}] != "" } { + unsupported "Testcase compile failed." + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# In the first test, we do a "step" on a function whose last instruction +# contains a branch-with-nullify. The instruction in the delay slot belongs +# to the next function. We verify that when we step off the first function +# that we end up back at the caller and not at the second instruction. + +gdb_breakpoint foo +gdb_test "run" "Breakpoint 1, .* in foo.*" "Breakpoint at foo" + +set test "stepi till main" +gdb_test_multiple "stepi" "${test}" { + -re ".*in foo.*$gdb_prompt $" { + send_gdb "stepi\n" + exp_continue -continue_timer + } + -re ".*in bar.*$gdb_prompt $" { + fail $test + } + -re ".*in main.*$gdb_prompt $" { + pass $test + } +} + +# In the second test, we verify that we can get a proper backtrace +# even when we are in a nullified instruction that belongs to the next function. +# We also verify that when stepping over a branch-with-nullify insn that we +# stay on the same insn for two steps. + +proc get_addr_of_sym { sym } { + set addr 0 + global gdb_prompt + global hex + + set test "get address of $sym" + send_gdb "print $sym\n" + gdb_test_multiple "print $sym" $test { + -re ".*($hex) <$sym>.*$gdb_prompt $" { + set addr $expect_out(1,string) + pass $test + } + } + + return $addr +} + +if { ! [ runto_main ] } then { gdb_suppress_tests; } + +set foo [get_addr_of_sym "foo"] +set bar [get_addr_of_sym "bar"] +set foo_last [expr $bar - 4] + +gdb_breakpoint "*$foo_last" + +gdb_test "continue" "Breakpoint \[0-9\]*,.* in foo.*" +gdb_test "backtrace" "in foo.*in main.*" "Backtrace from last insn in foo" +gdb_test "stepi" "in foo.*" "stepi to nullified instruction stays in foo" +gdb_test "backtrace" "in foo.*in main.*" "Backtrace from nullified insn" +gdb_test "stepi" "in main.*" "stepi to main" + +# In the third test, we verify that backtraces from nullified instructions +# work even in coredumps + +proc gen_core { test } { + global gcorefile + global gdb_prompt + set gcore_works 0 + set escapedfilename [string_to_regexp $gcorefile] + + gdb_test_multiple "gcore $gcorefile" "$test: gcore" { + -re "Saved corefile ${escapedfilename}\[\r\n\]+$gdb_prompt $" { + pass "$test: gcore" + set gcore_works 1 + } + -re "Can't create a corefile\[\r\n\]+$gdb_prompt $" { + fail "$test: gcore" + } + } + + return $gcore_works +} + +proc test_core_bt { test } { + global gcorefile + + gdb_test "core $gcorefile" "Core was generated by.*" \ + "$test: load core file" "A program is being debugged already.*" "y" + + gdb_test "backtrace" ".*in foo.*in main.*" "$test: backtrace in gcore" +} + +set test "core at last insn in foo" +if { ! [ runto_main ] } then { gdb_suppress_tests; } +gdb_breakpoint "*$foo_last" +gdb_test "continue" "Breakpoint \[0-9\]*,.* in foo.*" "$test: continue to breakpoint" +if [gen_core $test] { + test_core_bt $test +} + +set test "core at nullified insn" +if { ! [ runto_main ] } then { gdb_suppress_tests; } +gdb_breakpoint "*$foo_last" +gdb_test "continue" "Breakpoint \[0-9\]*,.* in foo.*" "$test: continue to breakpoint" +gdb_test "stepi" ".*in foo.*" "$test: step to nullified instruction" +if [gen_core $test] { + test_core_bt $test +} diff --git a/gdb/testsuite/gdb.arch/pa-nullify.s b/gdb/testsuite/gdb.arch/pa-nullify.s new file mode 100644 index 00000000000..90269b4d7b1 --- /dev/null +++ b/gdb/testsuite/gdb.arch/pa-nullify.s @@ -0,0 +1,59 @@ + .LEVEL 1.1 + .text + .align 4 +.globl foo + .type foo, @function +foo: + .PROC + .CALLINFO FRAME=64,NO_CALLS,SAVE_SP,ENTRY_GR=3 + .ENTRY + copy %r3,%r1 + copy %r30,%r3 + stwm %r1,64(%r30) + stw %r26,-36(%r3) + ldw -36(%r3),%r19 + copy %r19,%r28 + ldo 64(%r3),%r30 + ldwm -64(%r30),%r3 + bv,n %r0(%r2) + .EXIT + .PROCEND + +.globl bar + .type bar, @function +bar: + .PROC + .CALLINFO FRAME=64,NO_CALLS,SAVE_SP,ENTRY_GR=3 + .ENTRY + copy %r3,%r1 + copy %r30,%r3 + stwm %r1,64(%r30) + ldo 64(%r3),%r30 + ldwm -64(%r30),%r3 + bv,n %r0(%r2) + .EXIT + .PROCEND + +.globl main + .type main, @function +main: + .PROC + .CALLINFO FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3 + .ENTRY + stw %r2,-20(%r30) + copy %r3,%r1 + copy %r30,%r3 + stwm %r1,64(%r30) + stw %r26,-36(%r3) + stw %r25,-40(%r3) + ldw -36(%r3),%r26 + bl foo,%r2 + nop + copy %r28,%r19 + copy %r19,%r28 + ldw -20(%r3),%r2 + ldo 64(%r3),%r30 + ldwm -64(%r30),%r3 + bv,n %r0(%r2) + .EXIT + .PROCEND