[Lldb-commits] [lldb] r181343 - First iteration of a Python tracer module
Enrico Granata
egranata at apple.com
Tue May 7 12:49:59 PDT 2013
Author: enrico
Date: Tue May 7 14:49:59 2013
New Revision: 181343
URL: http://llvm.org/viewvc/llvm-project?rev=181343&view=rev
Log:
First iteration of a Python tracer module
This module uses Python's sys.settrace() mechanism so setup a hook that can log every significant operation
This is a first step in providing a good debugging experience of Python embedded in LLDB
This module comprises an OO infrastructure that wraps Python's tracing and inspecting mechanisms, plus a very simple logging tracer
Output from this tracer looks like:
call print_keyword_args from <module> @ 243 args are kwargs are {'first_name': 'John', 'last_name': 'Doe'}
running print_keyword_args @ 228 locals are {'kwargs': {'first_name': 'John', 'last_name': 'Doe'}}
running print_keyword_args @ 229 locals are {'key': 'first_name', 'value': 'John', 'kwargs': {'first_name': 'John', 'last_name': 'Doe'}}
first_name = John
running print_keyword_args @ 228 locals are {'key': 'first_name', 'value': 'John', 'kwargs': {'first_name': 'John', 'last_name': 'Doe'}}
running print_keyword_args @ 229 locals are {'key': 'last_name', 'value': 'Doe', 'kwargs': {'first_name': 'John', 'last_name': 'Doe'}}
last_name = Doe
running print_keyword_args @ 228 locals are {'key': 'last_name', 'value': 'Doe', 'kwargs': {'first_name': 'John', 'last_name': 'Doe'}}
return from print_keyword_args value is None locals are {'key': 'last_name', 'value': 'Doe', 'kwargs': {'first_name': 'John', 'last_name': 'Doe'}}
Added:
lldb/trunk/examples/python/pytracer.py
Added: lldb/trunk/examples/python/pytracer.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/examples/python/pytracer.py?rev=181343&view=auto
==============================================================================
--- lldb/trunk/examples/python/pytracer.py (added)
+++ lldb/trunk/examples/python/pytracer.py Tue May 7 14:49:59 2013
@@ -0,0 +1,249 @@
+import sys
+import inspect
+from collections import OrderedDict
+
+class TracebackFancy:
+ def __init__(self,traceback):
+ self.t = traceback
+
+ def getFrame(self):
+ return FrameFancy(self.t.tb_frame)
+
+ def getLineNumber(self):
+ return self.t.tb_lineno
+
+ def getNext(self):
+ return TracebackFancy(self.t.tb_next)
+
+ def __str__(self):
+ if self.t == None:
+ return ""
+ str_self = "%s @ %s" % (self.getFrame().getName(), self.getLineNumber())
+ return str_self + "\n" + self.getNext().__str__()
+
+class ExceptionFancy:
+ def __init__(self,frame):
+ self.etraceback = frame.f_exc_traceback
+ self.etype = frame.exc_type
+ self.evalue = frame.f_exc_value
+
+ def __init__(self,tb,ty,va):
+ self.etraceback = tb
+ self.etype = ty
+ self.evalue = va
+
+ def getTraceback(self):
+ return TracebackFancy(self.etraceback)
+
+ def __nonzero__(self):
+ return self.etraceback != None or self.etype != None or self.evalue != None
+
+ def getType(self):
+ return str(self.etype)
+
+ def getValue(self):
+ return self.evalue
+
+class CodeFancy:
+ def __init__(self,code):
+ self.c = code
+
+ def getArgCount(self):
+ return self.c.co_argcount
+
+ def getFilename(self):
+ return self.c.co_filename
+
+ def getVariables(self):
+ return self.c.co_varnames
+
+ def getName(self):
+ return self.c.co_name
+
+class ArgsFancy:
+ def __init__(self,frame,arginfo):
+ self.f = frame
+ self.a = arginfo
+
+ def __str__(self):
+ args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs()
+ ret = ""
+ count = 0
+ size = len(args)
+ for arg in args:
+ ret = ret + ("%s = %s" % (arg, args[arg]))
+ count = count + 1
+ if count < size:
+ ret = ret + ", "
+ if varargs:
+ if size > 0:
+ ret = ret + " "
+ ret = ret + "varargs are " + str(varargs)
+ if kwargs:
+ if size > 0:
+ ret = ret + " "
+ ret = ret + "kwargs are " + str(kwargs)
+ return ret
+
+ def getNumArgs(wantVarargs = False, wantKWArgs=False):
+ args, varargs, keywords, values = self.a
+ size = len(args)
+ if varargs and wantVarargs:
+ size = size+len(self.getVarArgs())
+ if keywords and wantKWArgs:
+ size = size+len(self.getKWArgs())
+ return size
+
+ def getArgs(self):
+ args, _, _, values = self.a
+ argWValues = OrderedDict()
+ for arg in args:
+ argWValues[arg] = values[arg]
+ return argWValues
+
+ def getVarArgs(self):
+ _, vargs, _, _ = self.a
+ if vargs:
+ return self.f.f_locals[vargs]
+ return ()
+
+ def getKWArgs(self):
+ _, _, kwargs, _ = self.a
+ if kwargs:
+ return self.f.f_locals[kwargs]
+ return {}
+
+class FrameFancy:
+ def __init__(self,frame):
+ self.f = frame
+
+ def getCaller(self):
+ return FrameFancy(self.f.f_back)
+
+ def getLineNumber(self):
+ return self.f.f_lineno
+
+ def getCodeInformation(self):
+ return CodeFancy(self.f.f_code)
+
+ def getExceptionInfo(self):
+ return ExceptionFancy(self.f)
+
+ def getName(self):
+ return self.f.f_code.co_name
+
+ def getLocals(self):
+ return self.f.f_locals
+
+ def getArgumentInfo(self):
+ return ArgsFancy(self.f,inspect.getargvalues(self.f))
+
+class TracerClass:
+ def callEvent(self,frame):
+ pass
+
+ def lineEvent(self,frame):
+ pass
+
+ def returnEvent(self,frame,retval):
+ pass
+
+ def exceptionEvent(self,frame,exception,value,traceback):
+ pass
+
+ def cCallEvent(self,frame,cfunct):
+ pass
+
+ def cReturnEvent(self,frame,cfunct):
+ pass
+
+ def cExceptionEvent(self,frame,cfunct):
+ pass
+
+tracer_impl = TracerClass()
+
+
+def the_tracer_entrypoint(frame,event,args):
+ if tracer_impl == None:
+ return None
+ if event == "call":
+ call_retval = tracer_impl.callEvent(FrameFancy(frame))
+ if call_retval == False:
+ return None
+ return the_tracer_entrypoint
+ elif event == "line":
+ line_retval = tracer_impl.lineEvent(FrameFancy(frame))
+ if line_retval == False:
+ return None
+ return the_tracer_entrypoint
+ elif event == "return":
+ tracer_impl.returnEvent(FrameFancy(frame),args)
+ elif event == "exception":
+ exty,exva,extb = args
+ exception_retval = tracer_impl.exceptionEvent(FrameFancy(frame),ExceptionFancy(extb,exty,exva))
+ if exception_retval == False:
+ return None
+ return the_tracer_entrypoint
+ elif event == "c_call":
+ tracer_impl.cCallEvent(FrameFancy(frame),args)
+ elif event == "c_return":
+ tracer_impl.cReturnEvent(FrameFancy(frame),args)
+ elif event == "c_exception":
+ tracer_impl.cExceptionEvent(FrameFancy(frame),args)
+ return None
+
+def enable(t=None):
+ global tracer_impl
+ if t:
+ tracer_impl = t
+ sys.settrace(the_tracer_entrypoint)
+
+def disable():
+ sys.settrace(None)
+
+class LoggingTracer:
+ def callEvent(self,frame):
+ print "call " + frame.getName() + " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
+
+ def lineEvent(self,frame):
+ print "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " + str(frame.getLocals())
+
+ def returnEvent(self,frame,retval):
+ print "return from " + frame.getName() + " value is " + str(retval) + " locals are " + str(frame.getLocals())
+
+ def exceptionEvent(self,frame,exception):
+ print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber())
+ print "tb: " + str(exception.getTraceback())
+
+def f(x,y=None):
+ if x > 0:
+ return 2 + f(x-2)
+ return 35
+
+def g(x):
+ return 1.134 / x
+
+def print_keyword_args(**kwargs):
+ # kwargs is a dict of the keyword args passed to the function
+ for key, value in kwargs.iteritems():
+ print "%s = %s" % (key, value)
+
+def total(initial=5, *numbers, **keywords):
+ count = initial
+ for number in numbers:
+ count += number
+ for key in keywords:
+ count += keywords[key]
+ return count
+
+if __name__ == "__main__":
+ enable(LoggingTracer())
+ f(5)
+ f(5,1)
+ print_keyword_args(first_name="John", last_name="Doe")
+ total(10, 1, 2, 3, vegetables=50, fruits=100)
+ try:
+ g(0)
+ except:
+ pass
+ disable()
More information about the lldb-commits
mailing list