diff options
author | Daniel Jacobowitz <drow@false.org> | 2010-03-04 13:42:12 +0000 |
---|---|---|
committer | Daniel Jacobowitz <drow@false.org> | 2010-03-04 13:42:12 +0000 |
commit | 50e98be46933386c9ca6c17889230afb217c7e28 (patch) | |
tree | 305ee94fd1ec1fff1b73a1d12ad81d7004eb5c4f | |
parent | 2e3ceee9bd6f5b1006be200faf78b1fdc1e8f4c8 (diff) | |
download | gdb-50e98be46933386c9ca6c17889230afb217c7e28.zip gdb-50e98be46933386c9ca6c17889230afb217c7e28.tar.gz gdb-50e98be46933386c9ca6c17889230afb217c7e28.tar.bz2 |
2010-03-04 Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
* arm-tdep.c (arm_pc_is_thumb): Add heuristic that tries to get
the state right when single stepping.
(arm_get_next_pc_raw, thumb_get_next_pc_raw): New functions.
Get the next PC along with the instruction state.
(thumb_get_next_pc): Remove.
(arm_get_next_pc): Modified to use arm_get_next_pc_raw.
-rw-r--r-- | gdb/ChangeLog | 9 | ||||
-rw-r--r-- | gdb/arm-tdep.c | 119 |
2 files changed, 80 insertions, 48 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 27a749d..b7e028b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,12 @@ +2010-03-04 Matthew Gretton-Dann <matthew.gretton-dann@arm.com> + + * arm-tdep.c (arm_pc_is_thumb): Add heuristic that tries to get + the state right when single stepping. + (arm_get_next_pc_raw, thumb_get_next_pc_raw): New functions. + Get the next PC along with the instruction state. + (thumb_get_next_pc): Remove. + (arm_get_next_pc): Modified to use arm_get_next_pc_raw. + 2010-03-04 Hui Zhu <teawater@gmail.com> * i386-tdep.c (i386_process_record): Change "addr" to "tmpu64". diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index b932c81..80be2cc 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -334,6 +334,9 @@ arm_find_mapping_symbol (CORE_ADDR memaddr, CORE_ADDR *start) return 0; } +static CORE_ADDR arm_get_next_pc_raw (struct frame_info *frame, + CORE_ADDR pc, int insert_bkpt); + /* Determine if the program counter specified in MEMADDR is in a Thumb function. This function should be called for addresses unrelated to any executing frame; otherwise, prefer arm_frame_is_thumb. */ @@ -375,9 +378,29 @@ arm_pc_is_thumb (CORE_ADDR memaddr) target, then trust the current value of $cpsr. This lets "display/i $pc" always show the correct mode (though if there is a symbol table we will not reach here, so it still may not be - displayed in the mode it will be executed). */ + displayed in the mode it will be executed). + + As a further heuristic if we detect that we are doing a single-step we + see what state executing the current instruction ends up with us being + in. */ if (target_has_registers) - return arm_frame_is_thumb (get_current_frame ()); + { + struct frame_info *current_frame = get_current_frame (); + CORE_ADDR current_pc = get_frame_pc (current_frame); + int is_thumb = arm_frame_is_thumb (current_frame); + CORE_ADDR next_pc; + if (memaddr == current_pc) + return is_thumb; + else + { + struct gdbarch *gdbarch = get_frame_arch (current_frame); + next_pc = arm_get_next_pc_raw (current_frame, current_pc, FALSE); + if (memaddr == gdbarch_addr_bits_remove (gdbarch, next_pc)) + return IS_THUMB_ADDR (next_pc); + else + return is_thumb; + } + } /* Otherwise we're out of luck; we assume ARM. */ return 0; @@ -2313,7 +2336,7 @@ thumb_advance_itstate (unsigned int itstate) another breakpoint by our caller. */ static CORE_ADDR -thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc) +thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt) { struct gdbarch *gdbarch = get_frame_arch (frame); struct address_space *aspace = get_frame_address_space (frame); @@ -2325,6 +2348,9 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc) unsigned long offset; ULONGEST status, itstate; + nextpc = MAKE_THUMB_ADDR (nextpc); + pc_val = MAKE_THUMB_ADDR (pc_val); + inst1 = read_memory_unsigned_integer (pc, 2, byte_order_for_code); /* Thumb-2 conditional execution support. There are eight bits in @@ -2363,7 +2389,7 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc) itstate = thumb_advance_itstate (itstate); } - return pc; + return MAKE_THUMB_ADDR (pc); } else if (itstate != 0) { @@ -2381,7 +2407,7 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc) itstate = thumb_advance_itstate (itstate); } - return pc; + return MAKE_THUMB_ADDR (pc); } else if ((itstate & 0x0f) == 0x08) { @@ -2406,7 +2432,8 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc) /* Set a breakpoint on the following instruction. */ gdb_assert ((itstate & 0x0f) != 0); - insert_single_step_breakpoint (gdbarch, aspace, pc); + if (insert_bkpt) + insert_single_step_breakpoint (gdbarch, aspace, pc); cond_negated = (itstate >> 4) & 1; /* Skip all following instructions with the same @@ -2422,7 +2449,7 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc) } while (itstate != 0 && ((itstate >> 4) & 1) == cond_negated); - return pc; + return MAKE_THUMB_ADDR (pc); } } } @@ -2436,9 +2463,9 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc) /* Advance to the next instruction. All the 32-bit instructions share a common prefix. */ if ((inst1 & 0xe000) == 0xe000 && (inst1 & 0x1800) != 0) - return pc + 4; + return MAKE_THUMB_ADDR (pc + 4); else - return pc + 2; + return MAKE_THUMB_ADDR (pc + 2); } /* Otherwise, handle the instruction normally. */ @@ -2453,9 +2480,6 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc) offset = bitcount (bits (inst1, 0, 7)) * INT_REGISTER_SIZE; sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM); nextpc = read_memory_unsigned_integer (sp + offset, 4, byte_order); - nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc); - if (nextpc == pc) - error (_("Infinite loop detected")); } else if ((inst1 & 0xf000) == 0xd000) /* conditional branch */ { @@ -2474,6 +2498,7 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc) /* Default to the next instruction. */ nextpc = pc + 4; + nextpc = MAKE_THUMB_ADDR (nextpc); if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000) { @@ -2566,6 +2591,7 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc) { /* MOV PC or MOVS PC. */ nextpc = get_frame_register_unsigned (frame, bits (inst2, 0, 3)); + nextpc = MAKE_THUMB_ADDR (nextpc); } else if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000) { @@ -2634,10 +2660,6 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc) nextpc = pc_val; else nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6)); - - nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc); - if (nextpc == pc) - error (_("Infinite loop detected")); } else if ((inst1 & 0xf500) == 0xb100) { @@ -2650,12 +2672,20 @@ thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc) else if (!bit (inst1, 11) && reg == 0) nextpc = pc_val + imm; } - return nextpc; } -CORE_ADDR -arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc) +/* Get the raw next address. PC is the current program counter, in + FRAME. INSERT_BKPT should be TRUE if we want a breakpoint set on + the alternative next instruction if there are two options. + + The value returned has the execution state of the next instruction + encoded in it. Use IS_THUMB_ADDR () to see whether the instruction is + in Thumb-State, and gdbarch_addr_bits_remove () to get the plain memory + address. +*/ +static CORE_ADDR +arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt) { struct gdbarch *gdbarch = get_frame_arch (frame); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); @@ -2666,7 +2696,7 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc) CORE_ADDR nextpc; if (arm_frame_is_thumb (frame)) - return thumb_get_next_pc (frame, pc); + return thumb_get_next_pc_raw (frame, pc, insert_bkpt); pc_val = (unsigned long) pc; this_instr = read_memory_unsigned_integer (pc, 4, byte_order_for_code); @@ -2683,10 +2713,7 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc) /* Branch with Link and change to Thumb. */ nextpc = BranchDest (pc, this_instr); nextpc |= bit (this_instr, 24) << 1; - - nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc); - if (nextpc == pc) - error (_("Infinite loop detected")); + nextpc = MAKE_THUMB_ADDR (nextpc); break; } case 0xc: @@ -2722,14 +2749,8 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc) || bits (this_instr, 4, 27) == 0x12fff3) { rn = bits (this_instr, 0, 3); - result = (rn == 15) ? pc_val + 8 + nextpc = (rn == 15) ? pc_val + 8 : get_frame_register_unsigned (frame, rn); - nextpc = (CORE_ADDR) gdbarch_addr_bits_remove - (gdbarch, result); - - if (nextpc == pc) - error (_("Infinite loop detected")); - return nextpc; } @@ -2807,11 +2828,14 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc) result = ~operand2; break; } - nextpc = (CORE_ADDR) gdbarch_addr_bits_remove - (gdbarch, result); - if (nextpc == pc) - error (_("Infinite loop detected")); + /* In 26-bit APCS the bottom two bits of the result are + ignored, and we always end up in ARM state. */ + if (!arm_apcs_32) + nextpc = arm_addr_bits_remove (gdbarch, result); + else + nextpc = result; + break; } @@ -2851,11 +2875,6 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc) } nextpc = (CORE_ADDR) read_memory_integer ((CORE_ADDR) base, 4, byte_order); - - nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc); - - if (nextpc == pc) - error (_("Infinite loop detected")); } } break; @@ -2890,10 +2909,6 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc) + offset), 4, byte_order); } - nextpc = gdbarch_addr_bits_remove - (gdbarch, nextpc); - if (nextpc == pc) - error (_("Infinite loop detected")); } } break; @@ -2902,10 +2917,6 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc) case 0xa: /* branch */ { nextpc = BranchDest (pc, this_instr); - - nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc); - if (nextpc == pc) - error (_("Infinite loop detected")); break; } @@ -2924,6 +2935,18 @@ arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc) return nextpc; } +CORE_ADDR +arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + CORE_ADDR nextpc = + gdbarch_addr_bits_remove (gdbarch, + arm_get_next_pc_raw (frame, pc, TRUE)); + if (nextpc == pc) + error (_("Infinite loop detected")); + return nextpc; +} + /* single_step() is called just before we want to resume the inferior, if we want to single-step it but there is no hardware or kernel single-step support. We find the target of the coming instruction |