vstinner/python-ptrace

ptrace on ARM

vstinner opened this issue · 8 comments

Originally reported by: Peter Saveliev (Bitbucket: svinota, GitHub: svinota)


root@localhost:~# ./strace.py ps
execve(/bin/ps, ['/bin/ps'], [/* 40 vars */]) = 19393
Debugger error: [NotImplementedError]
Traceback (most recent call last):
  File "./strace.py", line 247, in _main
    self.runDebugger()
  File "./strace.py", line 235, in runDebugger
    self.syscallTrace(process)
  File "./strace.py", line 181, in syscallTrace
    self.syscall(process)
  File "./strace.py", line 185, in syscall
    syscall = state.event(self.syscall_options)
  File "/usr/lib/python2.7/dist-packages/ptrace/debugger/syscall_state.py", line 15, in event
    return self.enter(options)
  File "/usr/lib/python2.7/dist-packages/ptrace/debugger/syscall_state.py", line 24, in enter
    self.syscall.enter(regs)
  File "/usr/lib/python2.7/dist-packages/ptrace/syscall/ptrace_syscall.py", line 33, in enter
    argument_values = self.readArgumentValues(regs)
  File "/usr/lib/python2.7/dist-packages/ptrace/syscall/ptrace_syscall.py", line 74, in readArgumentValues
    raise NotImplementedError()
NotImplementedError
Terminate <PtraceProcess #19393>
*** Error in `python': double free or corruption (!prev): 0x02340d90 ***
Aborted
root@localhost:~# cat /proc/cpuinfo
Processor       : ARMv7 Processor rev 9 (v7l)
processor       : 0
BogoMIPS        : 1993.93

processor       : 1
BogoMIPS        : 1993.93

processor       : 2
BogoMIPS        : 1993.93

processor       : 3
BogoMIPS        : 1993.93

Features        : swp half thumb fastmult vfp edsp neon vfpv3 tls
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x2
CPU part        : 0xc09
CPU revision    : 9

Hardware        : cardhu
Revision        : 0000
Serial          : 02458200e04f4300
root@localhost:~#

Platform -- Debian sid on asus transformer pad tf300t, using Android kernel:

root@localhost:~# uname -a
Linux localhost 3.1.10-00003-gb0003ba #1 SMP PREEMPT Fri Dec 28 17:34:15 CST 2012 armv7l GNU/Linux

If ARM platform is not supported, it would be better to raise an exception on import for non-distribution installations AND restrict platforms for distribution packaging.

If it is supported, it would be nice to have it fixed.


Original comment by Victor Stinner (Bitbucket: haypo, GitHub: haypo):


Oh, I don't have access to an ARM device to test python-ptrace. I never tested python-ptrace on ARM. According to the traceback: ptrace() is supported, but not tracing syscalls.

You have to patch PtraceSyscall.readSyscall() and PtraceSyscall.readArgumentValues() for your platform. It's quite easy, you "just" have to find the calling convention for syscalls: where system call arguments are stored? In registers? On the stack?

See for example http://stackoverflow.com/questions/12946958/system-call-in-arm

"Register R8 is used to pass the system call number that is whenever you use a system call through an API, the function being called does not do any specific work. It acts as an interface between the user and the system call system routine.

the registers R9,R10,R11,R12 are used to pass the parameters to the system call. if the system call needs more than 4 parameters then the first 4 are placed on the registers and the others are placed on the stack (This approach can vary with the Compiler being used to compile the kernel)."

Original comment by Peter Saveliev (Bitbucket: svinota, GitHub: svinota):


I will try to take a look, and thanks for hint where to patch the code. But if I fail, I would better give you remote access to my ARM devices :) Ok, we'll see in a week.

Original comment by Peter Saveliev (Bitbucket: svinota, GitHub: svinota):


No progress, and I fear I will not be able to hadle this issue. Not a problem, I will not support ARM for ptrace plugin for some time.

Original comment by hex_m_hell (Bitbucket: hex_m_hell, GitHub: Unknown):


I will buy you a raspberry pi if you will be willing to use it to fix this.

Original comment by Victor Stinner (Bitbucket: haypo, GitHub: haypo):


Ok for the raspberry pi. If you buy me one , I will implement the ARM support.

Original comment by Victor Stinner (Bitbucket: haypo, GitHub: haypo):


Thanks hex_m_hell! I received the Raspberry Pi this morning. I plugged the USB cable to power it, plugged an ethernet cable and... it works!

I made the following changes to port python-ptrace on ARM:

16f3a48
613417e
610608c

PTRACE_SINGLESTEP was implemented in software in the Linux kernel, but it was removed for different reasons.
http://comments.gmane.org/gmane.linux.ports.arm.kernel/105658

HAS_PTRACE_SINGLESTEP should maybe be set to False in ptrace/binding/func.py, but I would prefer that someone else confirms that it doesn't work.

I tried to implement breakpoint using "FE DE FF E7" instruction ("UND" instruction on Linux?), but it looks like the kernel freezes. It looks like debugging is very different from ptrace on Intel. I'm not sure that stack and frame pointer registers are correct.

So please test it!

Original comment by Victor Stinner (Bitbucket: haypo, GitHub: haypo):


Patch for breakpoint which freezes the board:

diff -r 16f3a48a7f5a ptrace/debugger/breakpoint.py
--- a/ptrace/debugger/breakpoint.py Mon Jan 20 17:07:55 2014 +0100
+++ b/ptrace/debugger/breakpoint.py Mon Jan 20 16:24:25 2014 +0000
@@ -2,10 +2,13 @@
 from ptrace import PtraceError
 from logging import info
 from weakref import ref
-from ptrace.cpu_info import CPU_POWERPC, CPU_WORD_SIZE
+from ptrace.cpu_info import CPU_POWERPC, CPU_WORD_SIZE, CPU_ARM
 from ptrace.ctypes_tools import word2bytes
 from ptrace.six import b

+# UND opcode on Linux
+ARM_BREAKPOINT = b('\xFE\xDE\xFF\xE7')
+
 class Breakpoint(object):
     """
     Software breakpoint.
@@ -18,6 +21,8 @@
         self.address = address
         if CPU_POWERPC:
             size = CPU_WORD_SIZE
+        elif CPU_ARM:
+            size = len(ARM_BREAKPOINT) 
         elif size is None:
             size = 1
         self.size = size
@@ -29,6 +34,8 @@
         if CPU_POWERPC:
             # Replace instruction with "TRAP"
             new_bytes = word2bytes(0x0cc00000)
+        elif CPU_ARM:
+            new_bytes = ARM_BREAKPOINT 
         else:
             # Replace instruction with "INT 3"
             new_bytes = b("\xCC") * size

Original comment by Victor Stinner (Bitbucket: haypo, GitHub: haypo):


The new python-ptrace 0.7 release supports ARM. The support is not perfect, but please open new issues for a specific feature. The initial bug was to support strace.py on ARM, it's now implemented.