/examples/python/pytracer.py

https://gitlab.com/jorjpimm/lldb
Python | 328 lines | 269 code | 57 blank | 2 comment | 88 complexity | 26f908b0996d63a7db574b5b08539f64 MD5 | raw file
  1. import sys
  2. import inspect
  3. from collections import OrderedDict
  4. class TracebackFancy:
  5. def __init__(self,traceback):
  6. self.t = traceback
  7. def getFrame(self):
  8. return FrameFancy(self.t.tb_frame)
  9. def getLineNumber(self):
  10. return self.t.tb_lineno if self.t != None else None
  11. def getNext(self):
  12. return TracebackFancy(self.t.tb_next)
  13. def __str__(self):
  14. if self.t == None:
  15. return ""
  16. str_self = "%s @ %s" % (self.getFrame().getName(), self.getLineNumber())
  17. return str_self + "\n" + self.getNext().__str__()
  18. class ExceptionFancy:
  19. def __init__(self,frame):
  20. self.etraceback = frame.f_exc_traceback
  21. self.etype = frame.exc_type
  22. self.evalue = frame.f_exc_value
  23. def __init__(self,tb,ty,va):
  24. self.etraceback = tb
  25. self.etype = ty
  26. self.evalue = va
  27. def getTraceback(self):
  28. return TracebackFancy(self.etraceback)
  29. def __nonzero__(self):
  30. return self.etraceback != None or self.etype != None or self.evalue != None
  31. def getType(self):
  32. return str(self.etype)
  33. def getValue(self):
  34. return self.evalue
  35. class CodeFancy:
  36. def __init__(self,code):
  37. self.c = code
  38. def getArgCount(self):
  39. return self.c.co_argcount if self.c != None else 0
  40. def getFilename(self):
  41. return self.c.co_filename if self.c != None else ""
  42. def getVariables(self):
  43. return self.c.co_varnames if self.c != None else []
  44. def getName(self):
  45. return self.c.co_name if self.c != None else ""
  46. def getFileName(self):
  47. return self.c.co_filename if self.c != None else ""
  48. class ArgsFancy:
  49. def __init__(self,frame,arginfo):
  50. self.f = frame
  51. self.a = arginfo
  52. def __str__(self):
  53. args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs()
  54. ret = ""
  55. count = 0
  56. size = len(args)
  57. for arg in args:
  58. ret = ret + ("%s = %s" % (arg, args[arg]))
  59. count = count + 1
  60. if count < size:
  61. ret = ret + ", "
  62. if varargs:
  63. if size > 0:
  64. ret = ret + " "
  65. ret = ret + "varargs are " + str(varargs)
  66. if kwargs:
  67. if size > 0:
  68. ret = ret + " "
  69. ret = ret + "kwargs are " + str(kwargs)
  70. return ret
  71. def getNumArgs(wantVarargs = False, wantKWArgs=False):
  72. args, varargs, keywords, values = self.a
  73. size = len(args)
  74. if varargs and wantVarargs:
  75. size = size+len(self.getVarArgs())
  76. if keywords and wantKWArgs:
  77. size = size+len(self.getKWArgs())
  78. return size
  79. def getArgs(self):
  80. args, _, _, values = self.a
  81. argWValues = OrderedDict()
  82. for arg in args:
  83. argWValues[arg] = values[arg]
  84. return argWValues
  85. def getVarArgs(self):
  86. _, vargs, _, _ = self.a
  87. if vargs:
  88. return self.f.f_locals[vargs]
  89. return ()
  90. def getKWArgs(self):
  91. _, _, kwargs, _ = self.a
  92. if kwargs:
  93. return self.f.f_locals[kwargs]
  94. return {}
  95. class FrameFancy:
  96. def __init__(self,frame):
  97. self.f = frame
  98. def getCaller(self):
  99. return FrameFancy(self.f.f_back)
  100. def getLineNumber(self):
  101. return self.f.f_lineno if self.f != None else 0
  102. def getCodeInformation(self):
  103. return CodeFancy(self.f.f_code) if self.f != None else None
  104. def getExceptionInfo(self):
  105. return ExceptionFancy(self.f) if self.f != None else None
  106. def getName(self):
  107. return self.getCodeInformation().getName() if self.f != None else ""
  108. def getFileName(self):
  109. return self.getCodeInformation().getFileName() if self.f != None else ""
  110. def getLocals(self):
  111. return self.f.f_locals if self.f != None else {}
  112. def getArgumentInfo(self):
  113. return ArgsFancy(self.f,inspect.getargvalues(self.f)) if self.f != None else None
  114. class TracerClass:
  115. def callEvent(self,frame):
  116. pass
  117. def lineEvent(self,frame):
  118. pass
  119. def returnEvent(self,frame,retval):
  120. pass
  121. def exceptionEvent(self,frame,exception,value,traceback):
  122. pass
  123. def cCallEvent(self,frame,cfunct):
  124. pass
  125. def cReturnEvent(self,frame,cfunct):
  126. pass
  127. def cExceptionEvent(self,frame,cfunct):
  128. pass
  129. tracer_impl = TracerClass()
  130. def the_tracer_entrypoint(frame,event,args):
  131. if tracer_impl == None:
  132. return None
  133. if event == "call":
  134. call_retval = tracer_impl.callEvent(FrameFancy(frame))
  135. if call_retval == False:
  136. return None
  137. return the_tracer_entrypoint
  138. elif event == "line":
  139. line_retval = tracer_impl.lineEvent(FrameFancy(frame))
  140. if line_retval == False:
  141. return None
  142. return the_tracer_entrypoint
  143. elif event == "return":
  144. tracer_impl.returnEvent(FrameFancy(frame),args)
  145. elif event == "exception":
  146. exty,exva,extb = args
  147. exception_retval = tracer_impl.exceptionEvent(FrameFancy(frame),ExceptionFancy(extb,exty,exva))
  148. if exception_retval == False:
  149. return None
  150. return the_tracer_entrypoint
  151. elif event == "c_call":
  152. tracer_impl.cCallEvent(FrameFancy(frame),args)
  153. elif event == "c_return":
  154. tracer_impl.cReturnEvent(FrameFancy(frame),args)
  155. elif event == "c_exception":
  156. tracer_impl.cExceptionEvent(FrameFancy(frame),args)
  157. return None
  158. def enable(t=None):
  159. global tracer_impl
  160. if t:
  161. tracer_impl = t
  162. sys.settrace(the_tracer_entrypoint)
  163. def disable():
  164. sys.settrace(None)
  165. class LoggingTracer:
  166. def callEvent(self,frame):
  167. print "call " + frame.getName() + " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
  168. def lineEvent(self,frame):
  169. print "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " + str(frame.getLocals()) + " in " + frame.getFileName()
  170. def returnEvent(self,frame,retval):
  171. print "return from " + frame.getName() + " value is " + str(retval) + " locals are " + str(frame.getLocals())
  172. def exceptionEvent(self,frame,exception):
  173. print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber())
  174. print "tb: " + str(exception.getTraceback())
  175. # the same functionality as LoggingTracer, but with a little more lldb-specific smarts
  176. class LLDBAwareTracer:
  177. def callEvent(self,frame):
  178. if frame.getName() == "<module>":
  179. return
  180. if frame.getName() == "run_one_line":
  181. print "call run_one_line(%s)" % (frame.getArgumentInfo().getArgs()["input_string"])
  182. return
  183. if "Python.framework" in frame.getFileName():
  184. print "call into Python at " + frame.getName()
  185. return
  186. if frame.getName() == "__init__" and frame.getCaller().getName() == "run_one_line" and frame.getCaller().getLineNumber() == 101:
  187. return False
  188. strout = "call " + frame.getName()
  189. if (frame.getCaller().getFileName() == ""):
  190. strout += " from LLDB - args are "
  191. args = frame.getArgumentInfo().getArgs()
  192. for arg in args:
  193. if arg == "dict" or arg == "internal_dict":
  194. continue
  195. strout = strout + ("%s = %s " % (arg,args[arg]))
  196. else:
  197. strout += " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
  198. print strout
  199. def lineEvent(self,frame):
  200. if frame.getName() == "<module>":
  201. return
  202. if frame.getName() == "run_one_line":
  203. print "running run_one_line(%s) @ %s" % (frame.getArgumentInfo().getArgs()["input_string"],frame.getLineNumber())
  204. return
  205. if "Python.framework" in frame.getFileName():
  206. print "running into Python at " + frame.getName() + " @ " + str(frame.getLineNumber())
  207. return
  208. strout = "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are "
  209. if (frame.getCaller().getFileName() == ""):
  210. locals = frame.getLocals()
  211. for local in locals:
  212. if local == "dict" or local == "internal_dict":
  213. continue
  214. strout = strout + ("%s = %s " % (local,locals[local]))
  215. else:
  216. strout = strout + str(frame.getLocals())
  217. strout = strout + " in " + frame.getFileName()
  218. print strout
  219. def returnEvent(self,frame,retval):
  220. if frame.getName() == "<module>":
  221. return
  222. if frame.getName() == "run_one_line":
  223. print "return from run_one_line(%s) return value is %s" % (frame.getArgumentInfo().getArgs()["input_string"],retval)
  224. return
  225. if "Python.framework" in frame.getFileName():
  226. print "return from Python at " + frame.getName() + " return value is " + str(retval)
  227. return
  228. strout = "return from " + frame.getName() + " return value is " + str(retval) + " locals are "
  229. if (frame.getCaller().getFileName() == ""):
  230. locals = frame.getLocals()
  231. for local in locals:
  232. if local == "dict" or local == "internal_dict":
  233. continue
  234. strout = strout + ("%s = %s " % (local,locals[local]))
  235. else:
  236. strout = strout + str(frame.getLocals())
  237. strout = strout + " in " + frame.getFileName()
  238. print strout
  239. def exceptionEvent(self,frame,exception):
  240. if frame.getName() == "<module>":
  241. return
  242. print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber())
  243. print "tb: " + str(exception.getTraceback())
  244. def f(x,y=None):
  245. if x > 0:
  246. return 2 + f(x-2)
  247. return 35
  248. def g(x):
  249. return 1.134 / x
  250. def print_keyword_args(**kwargs):
  251. # kwargs is a dict of the keyword args passed to the function
  252. for key, value in kwargs.iteritems():
  253. print "%s = %s" % (key, value)
  254. def total(initial=5, *numbers, **keywords):
  255. count = initial
  256. for number in numbers:
  257. count += number
  258. for key in keywords:
  259. count += keywords[key]
  260. return count
  261. if __name__ == "__main__":
  262. enable(LoggingTracer())
  263. f(5)
  264. f(5,1)
  265. print_keyword_args(first_name="John", last_name="Doe")
  266. total(10, 1, 2, 3, vegetables=50, fruits=100)
  267. try:
  268. g(0)
  269. except:
  270. pass
  271. disable()