You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
362 lines
11 KiB
362 lines
11 KiB
from __future__ import print_function
|
|
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 if self.t is not None else None
|
|
|
|
def getNext(self):
|
|
return TracebackFancy(self.t.tb_next)
|
|
|
|
def __str__(self):
|
|
if self.t is 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 is not None or self.etype is not None or self.evalue is not 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 if self.c is not None else 0
|
|
|
|
def getFilename(self):
|
|
return self.c.co_filename if self.c is not None else ""
|
|
|
|
def getVariables(self):
|
|
return self.c.co_varnames if self.c is not None else []
|
|
|
|
def getName(self):
|
|
return self.c.co_name if self.c is not None else ""
|
|
|
|
def getFileName(self):
|
|
return self.c.co_filename if self.c is not None else ""
|
|
|
|
|
|
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 if self.f is not None else 0
|
|
|
|
def getCodeInformation(self):
|
|
return CodeFancy(self.f.f_code) if self.f is not None else None
|
|
|
|
def getExceptionInfo(self):
|
|
return ExceptionFancy(self.f) if self.f is not None else None
|
|
|
|
def getName(self):
|
|
return self.getCodeInformation().getName() if self.f is not None else ""
|
|
|
|
def getFileName(self):
|
|
return self.getCodeInformation().getFileName() if self.f is not None else ""
|
|
|
|
def getLocals(self):
|
|
return self.f.f_locals if self.f is not None else {}
|
|
|
|
def getArgumentInfo(self):
|
|
return ArgsFancy(
|
|
self.f, inspect.getargvalues(
|
|
self.f)) if self.f is not None else None
|
|
|
|
|
|
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 is None:
|
|
return None
|
|
if event == "call":
|
|
call_retval = tracer_impl.callEvent(FrameFancy(frame))
|
|
if not call_retval:
|
|
return None
|
|
return the_tracer_entrypoint
|
|
elif event == "line":
|
|
line_retval = tracer_impl.lineEvent(FrameFancy(frame))
|
|
if not line_retval:
|
|
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 not exception_retval:
|
|
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()) + " in " + frame.getFileName())
|
|
|
|
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()))
|
|
|
|
# the same functionality as LoggingTracer, but with a little more
|
|
# lldb-specific smarts
|
|
|
|
|
|
class LLDBAwareTracer:
|
|
|
|
def callEvent(self, frame):
|
|
if frame.getName() == "<module>":
|
|
return
|
|
if frame.getName() == "run_one_line":
|
|
print("call run_one_line(%s)" % (frame.getArgumentInfo().getArgs()["input_string"]))
|
|
return
|
|
if "Python.framework" in frame.getFileName():
|
|
print("call into Python at " + frame.getName())
|
|
return
|
|
if frame.getName() == "__init__" and frame.getCaller().getName(
|
|
) == "run_one_line" and frame.getCaller().getLineNumber() == 101:
|
|
return False
|
|
strout = "call " + frame.getName()
|
|
if (frame.getCaller().getFileName() == ""):
|
|
strout += " from LLDB - args are "
|
|
args = frame.getArgumentInfo().getArgs()
|
|
for arg in args:
|
|
if arg == "dict" or arg == "internal_dict":
|
|
continue
|
|
strout = strout + ("%s = %s " % (arg, args[arg]))
|
|
else:
|
|
strout += " from " + frame.getCaller().getName() + " @ " + \
|
|
str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
|
|
print(strout)
|
|
|
|
def lineEvent(self, frame):
|
|
if frame.getName() == "<module>":
|
|
return
|
|
if frame.getName() == "run_one_line":
|
|
print("running run_one_line(%s) @ %s" % (frame.getArgumentInfo().getArgs()["input_string"], frame.getLineNumber()))
|
|
return
|
|
if "Python.framework" in frame.getFileName():
|
|
print("running into Python at " + frame.getName() + " @ " + str(frame.getLineNumber()))
|
|
return
|
|
strout = "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + \
|
|
" locals are "
|
|
if (frame.getCaller().getFileName() == ""):
|
|
locals = frame.getLocals()
|
|
for local in locals:
|
|
if local == "dict" or local == "internal_dict":
|
|
continue
|
|
strout = strout + ("%s = %s " % (local, locals[local]))
|
|
else:
|
|
strout = strout + str(frame.getLocals())
|
|
strout = strout + " in " + frame.getFileName()
|
|
print(strout)
|
|
|
|
def returnEvent(self, frame, retval):
|
|
if frame.getName() == "<module>":
|
|
return
|
|
if frame.getName() == "run_one_line":
|
|
print("return from run_one_line(%s) return value is %s" % (frame.getArgumentInfo().getArgs()["input_string"], retval))
|
|
return
|
|
if "Python.framework" in frame.getFileName():
|
|
print("return from Python at " + frame.getName() + " return value is " + str(retval))
|
|
return
|
|
strout = "return from " + frame.getName() + " return value is " + \
|
|
str(retval) + " locals are "
|
|
if (frame.getCaller().getFileName() == ""):
|
|
locals = frame.getLocals()
|
|
for local in locals:
|
|
if local == "dict" or local == "internal_dict":
|
|
continue
|
|
strout = strout + ("%s = %s " % (local, locals[local]))
|
|
else:
|
|
strout = strout + str(frame.getLocals())
|
|
strout = strout + " in " + frame.getFileName()
|
|
print(strout)
|
|
|
|
def exceptionEvent(self, frame, exception):
|
|
if frame.getName() == "<module>":
|
|
return
|
|
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.items():
|
|
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()
|