-
Notifications
You must be signed in to change notification settings - Fork 54
Description
The sample source code is shown below. The output implies that the second bp=p.createBreakpoint(breakpoint_address) doesn't work.(Version: 0.9.9)
import subprocess
from ptrace.debugger import PtraceDebugger, ProcessExit
from ptrace.debugger.memory_mapping import readProcessMappings
if __name__=="__main__":
debugger = PtraceDebugger()
conn = subprocess.Popen(["./helloworld"])
p = debugger.addProcess(conn.pid, is_attached=False)
p.attach()
breakpoint_address = 0x405CD0 # Replace with actual address
bp=p.createBreakpoint(breakpoint_address)
print(list(hex(ele) for ele in debugger.dict[conn.pid].breakpoints.keys()))
p.removeBreakpoint(bp)
print(list(hex(ele) for ele in debugger.dict[conn.pid].breakpoints.keys()))
bp=p.createBreakpoint(breakpoint_address)
print(list(hex(ele) for ele in debugger.dict[conn.pid].breakpoints.keys()))
output:
['0x405cd0']
[]
[]
Traceback (most recent call last):
File "ptracebug.py", line 17, in <module>
p.removeBreakpoint(bp)
File "/root/miniconda3/lib/python3.8/site-packages/ptrace/debugger/process.py", line 759, in removeBreakpoint
del self.breakpoints[breakpoint.address]
KeyError: 4218064
Exception ignored in: <function Breakpoint.__del__ at 0x7f714e311430>
Traceback (most recent call last):
File "/root/miniconda3/lib/python3.8/site-packages/ptrace/debugger/breakpoint.py", line 64, in __del__
File "/root/miniconda3/lib/python3.8/site-packages/ptrace/debugger/breakpoint.py", line 55, in desinstall
File "/root/miniconda3/lib/python3.8/site-packages/ptrace/debugger/process.py", line 759, in removeBreakpoint
KeyError: 4218064
I viewed the source code and find something confusing. PtraceProcess.removeBreakpoint calls Breakpoint.del, Breakpoint.del calls Breakpoint.desinstall and Breakpoint.desinstall calls PtraceProcess.removeBreakpoint...
INFINITE RECURSION! No wonder there's is an (ignored) exception.
ptrace/debugger/process.py
class PtraceProcess(object):
#...
def removeBreakpoint(self, breakpoint):
del self.breakpoints[breakpoint.address]
#...
ptrace/debugger/breakpoint.py
class Breakpoint(object):
#...
def desinstall(self, set_ip=False):
"""
Remove the breakpoint from the associated process. If set_ip is True,
restore the instruction pointer to the address of the breakpoint.
"""
if not self._installed:
return
self._installed = False
info("Desinstall %s" % self)
process = self.process()
if not process:
return
if process.running:
process.writeBytes(self.address, self.old_bytes)
if set_ip:
process.setInstrPointer(self.address)
process.removeBreakpoint(self)
#...
def __del__(self):
try:
self.desinstall(False)
except PtraceError:
pass
To deal with it, i suggest using (set or list) instead of dictionary to record active breakpoints(ptrace/debugger/process.py, Line 162). In the dictionary, the key and the value.address are bound to be the same, so there is redundant information in the data structure.