175_fields_=(176# NOTE: Expand out the user regs struct so177# we can make one call to _rctx_Import178("regs",user_regs_i386),179("u_fpvalid",c_ulong),180("u_tsize",c_ulong),181("u_dsize",c_ulong),182("u_ssize",c_ulong),183("start_code",c_ulong),184("start_stack",c_ulong),185("signal",c_ulong),186("reserved",c_ulong),187("u_ar0",c_void_p),188("u_fpstate",c_void_p),189("magic",c_ulong),190("u_comm",c_char*32),191("debug0",c_ulong),192("debug1",c_ulong),193("debug2",c_ulong),194("debug3",c_ulong),195("debug4",c_ulong),196("debug5",c_ulong),197("debug6",c_ulong),198("debug7",c_ulong),199)

253"""254 A utility to open (if necissary) and seek the memfile255 """256ifself.memfd==None:257self.memfd=libc.open("/proc/%d/mem"%self.pid,O_RDWR|O_LARGEFILE,0755)258259x=libc.lseek64(self.memfd,offset,0)

263"""264 A *much* faster way of reading memory that the 4 bytes265 per syscall allowed by ptrace266 """267self.setupMemFile(address)268# Use ctypes cause python implementation is teh ghey269buf=create_string_buffer(size)270x=libc.read(self.memfd,addressof(buf),size)271ifx!=size:272#libc.perror('libc.read %d (size: %d)' % (x,size))273raiseException("reading from invalid memory %s (%d returned)"%(hex(address),x))274# We have to slice cause ctypes "helps" us by adding a null byte...275returnbuf.raw

305# Very similar to posix, but not306# quite close enough...307self.execing=True308cmdlist=e_cli.splitargs(cmdline)309os.stat(cmdlist[0])310pid=os.fork()311312ifpid==0:313v_posix.ptrace(v_posix.PT_TRACE_ME,0,0,0)314# Make sure our parent gets some cycles315time.sleep(0.1)316os.execv(cmdlist[0],cmdlist)317sys.exit(-1)318319ifv_posix.ptrace(PT_ATTACH,pid,0,0)!=0:320raiseException("PT_ATTACH failed! linux platformExec")321322self.pthreads=[pid,]323self.setMeta("ExeName",self._findExe(pid))324returnpid

372# Blocking wait once...373pid,status=os.waitpid(-1,0x40000002)374self.setMeta("ThreadId",pid)375# Stop the rest of the threads... 376# why is linux debugging so Ghetto?!?!377ifnotself.stepping:# If we're stepping, only do the one378fortidinself.pthreads:379iftid==pid:380continue381try:382# We use SIGSTOP here because they can't mask it.383os.kill(tid,signal.SIGSTOP)384os.waitpid(tid,0x40000002)385exceptException,e:386print"WARNING TID is invalid %d %s"%(tid,e)387returnpid,status

391cmd=v_posix.PT_CONTINUE392ifself.getMode("Syscall",False):393cmd=PT_SYSCALL394pid=self.getPid()395sig=self.getCurrentSignal()396ifsig==None:397sig=0398# Only deliver signals to the main thread399ifv_posix.ptrace(cmd,pid,0,sig)!=0:400libc.perror('ptrace PT_CONTINUE failed for pid %d'%pid)401raiseException("ERROR ptrace failed for pid %d"%pid)402403fortidinself.pthreads:404iftid==pid:405continue406ifv_posix.ptrace(cmd,tid,0,0)!=0:407pass

424"""425 Do the work for attaching a thread. This must be *under*426 attachThread() so callers in notifiers may call it (because427 it's also gotta be thread wrapped).428 """429ifnotattached:430ifv_posix.ptrace(PT_ATTACH,tid,0,0)!=0:431raiseException("ERROR ptrace attach failed for thread %d"%tid)432433# We may have already revcieved the stop signal434ifnotself._stopped_cache.pop(tid,None):435os.waitpid(tid,0x40000002)436437self.setupPtraceOptions(tid)438self.pthreads.append(tid)

462# Skim some linux specific events before passing to posix463tid,status=event464ifos.WIFSTOPPED(status):465sig=status>>8# Cant use os.WSTOPSIG() here...466#print('STOPPED: %d %d %.8x %d' % (self.pid, tid, status, sig))467468# Ok... this is a crazy little state engine that tries469# to account for the discrepancies in how linux posts470# signals to the debugger...471472# Thread Creation:473# In each case below, the kernel may deliver474# any of the 3 signals in any order... ALSO475# (and more importantly) *if* the kernel sends476# SIGSTOP to the thread first, the debugger477# will get a SIGSTOP *instead* of SIG_LINUX_CLONE478# ( this will go back and forth on *ONE BOX* with479# the same kernel version... Finally squished it480# because it presents more frequently ( 1 in 10 )481# on my new ARM linux dev board. WTF?!1?!one?!? )482#483# Case 1 (SIG_LINUX_CLONE):484# debugger gets SIG_LINUX CLONE as expected485# and can then use ptrace(PT_GETEVENTMSG)486# to get new TID and attach as normal487# Case 2 (SIGSTOP delivered to thread)488# Thread is already stoped and attached but489# parent debugger doesn't know yet. We add490# the tid to the stopped_cache so when the491# kernel gets around to telling the debugger492# we don't wait on him again.493# Case 3 (SIGSTOP delivered to debugger)494# In both case 2 and case 3, this will cause495# the SIG_LINUX_CLONE to be skipped. Either496# way, we should head down into thread attach.497# ( The thread may be already stopped )498ifsig==SIG_LINUX_SYSCALL:499self.fireNotifiers(vtrace.NOTIFY_SYSCALL)500501elifsig==SIG_LINUX_EXIT:502503ecode=self.getPtraceEvent()>>8504505iftid==self.getPid():506self._fireExit(ecode)507self.platformDetach()508509else:510self.detachThread(tid,ecode)511512elifsig==SIG_LINUX_CLONE:513# Handle a new thread here!514newtid=self.getPtraceEvent()515#print('CLONE (new tid: %d)' % newtid)516self.attachThread(newtid,attached=True)517518elifsig==signal.SIGSTOPandtid!=self.pid:519#print('OMG IM THE NEW THREAD! %d' % tid)520# We're not even a real event right now...521self.runAgain()522self._stopped_cache[tid]=True523524elifsig==signal.SIGSTOP:525# If we are still 'exec()'ing, we havent hit the SIGTRAP526# yet ( so our process info is still python, lets skip it )527ifself.execing:528self._stopped_hack=True529self.setupPtraceOptions(tid)530self.runAgain()531532elifself._stopped_hack:533newtid=self.getPtraceEvent(tid)534#print("WHY DID WE GET *ANOTHER* STOP?: %d" % tid)535#print('PTRACE EVENT: %d' % newtid)536self.attachThread(newtid,attached=True)537538else:# on first attach...539self._stopped_hack=True540self.setupPtraceOptions(tid)541self.handlePosixSignal(sig)542543#FIXME eventually implement child catching!544else:545self.handlePosixSignal(sig)546547return548549v_posix.PosixMixin.platformProcessEvent(self,event)

800# See notes below about insanity...801ifself._step_cleanup!=None:802[self.writeMemory(bva,bytes)for(bva,bytes)inself._step_cleanup]803self._step_cleanup=None804returnv_base.TracerBase._fireStep(self)

812# This is a total rediculous hack to account813# for the fact that the arm platform couldn't814# be bothered to implement single stepping in815# the stupid hardware...816817self.stepping=True818819pc=self.getProgramCounter()820op=self.parseOpcode(pc)821822branches=op.getBranches(self)823ifnotbranches:824raiseException('''825 The branches for the instruction %r were not decoded correctly. This means that826 we cant properly predict the possible next instruction executions in a way that allows us827 to account for the STUPID INSANE FACT THAT THERE IS NO HARDWARE SINGLE STEP CAPABILITY ON828 ARM (non-realtime or JTAG anyway). We *would* have written invalid instructions to each829 of those locations and cleaned them up before you ever knew anything was amiss... which is830 how we pretend arm can single step... even though IT CANT. (please tell visi...)831 '''%op)832833# Save the memory at the branches for later834# restoration in the _fireStep callback.835836self._step_cleanup=[]837forbva,bflagsinop.getBranches(self):838self._step_cleanup.append((bva,self.readMemory(bva,4)))839self.writeMemory(bva,arm_break_le)840841tid=self.getMeta('ThreadId')842843ifv_posix.ptrace(v_posix.PT_CONTINUE,tid,0,0)!=0:844raiseException("ERROR ptrace failed for tid %d"%tid)