summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorNikola Valerjev <nikola@ghs.com>2005-12-10 11:59:15 +0000
committerRussell King <rmk+kernel@arm.linux.org.uk>2005-12-10 11:59:15 +0000
commit22f975f4ffa707ea24507f6899bb9f5a1ff034bc (patch)
treeb82d3d97110b8f5c9d80dfca36d38be98498fd5a /arch
parent5b35193f5868da5e63f5b4cfe8fbcf9f10fe65cd (diff)
downloadlinux-3.10-22f975f4ffa707ea24507f6899bb9f5a1ff034bc.tar.gz
linux-3.10-22f975f4ffa707ea24507f6899bb9f5a1ff034bc.tar.bz2
linux-3.10-22f975f4ffa707ea24507f6899bb9f5a1ff034bc.zip
[ARM] 3200/1: Singlestep over ARM BX and BLX instructions using ptrace fix
Patch from Nikola Valerjev Single stepping an application using ptrace() fails over ARM instructions BX and BLX. Steps to reproduce: Compile and link the following files main.c ----- void foo(); int main() { foo(); return 0; } foo.s ----- .text .globl foo foo: BX LR Using ptrace() functionality, run to main(), and start singlestepping. Singlestep over \"BX LR\" instruction won\'t transfer the control back to main, but run the code to completion. This problems seems to be in the function get_branch_address() in arch/arm/kernel/ptrace.c. The function doesn\'t seem to recognize BX and BLX instructions as branches. BX and BLX instructions can be used to convert from ARM to Thumb mode if the target address has the low bit set. However, they are also perfectly legal in the ARM only mode. Although other things in the kernel seem to indicate that only ARM mode is accepted (and not Thumb), many compilers will generate BX and BLX instructions even when generating ARM only code. Signed-off-by: Nikola Valerjev <nikola@ghs.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/kernel/ptrace.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 9a340e790da..2b84f78d7b0 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -242,6 +242,15 @@ get_branch_address(struct task_struct *child, unsigned long pc, unsigned long in
*/
long aluop1, aluop2, ccbit;
+ if ((insn & 0x0fffffd0) == 0x012fff10) {
+ /*
+ * bx or blx
+ */
+ alt = get_user_reg(child, insn & 15);
+ break;
+ }
+
+
if ((insn & 0xf000) != 0xf000)
break;