Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kaa Debugger #7

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions src/debug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------------
# debug.py - Debugger for kaa applications
# -----------------------------------------------------------------------------
# kaa.base - The Kaa Application Framework
# Copyright 2013 Dirk Meyer, Jason Tackaberry, et al.
#
# Please see the file AUTHORS for a complete list of authors.
#
# This library is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License version
# 2.1 as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
#
# -----------------------------------------------------------------------------
from __future__ import absolute_import

# python imports
import os
import time
import sys
import struct
import atexit
import socket
import inspect

# kaa.base imports
from .utils import tempfile
from . import nf_wrapper as notifier


socket_listen = None
socket_trace = None

python_distribution = '%s/lib/python%s.%s' % (sys.prefix, sys.version_info.major, sys.version_info.minor)

def socket_unlink():
"""
Delete the debug socket for this application
"""
if os and os.path.exists(tempfile('.debug/%s' % os.getpid())):
os.unlink(tempfile('.debug/%s' % os.getpid()))

def socket_trace_close():
"""
Close the trace socket
"""
global socket_trace
if socket_trace:
print '=== STOP TRACE ==='
sys.settrace(None)
socket_trace.close()
socket_trace = None

def socket_trace_send(frame, event, arg):
"""
Callback for sys.settrace
"""
if event in ('return', 'call'):
filename = frame.f_code.co_filename
if filename.startswith(__file__):
# do not trace the debugging module itself
return
if filename.startswith(python_distribution) and not filename.find('packages') > 0:
# do not trace python core (lib except dist-packages and site-packages)
return
try:
socket_trace.send('\n')
except:
socket_trace_close()
return
if event in ('line', 'call'):
tb = inspect.getframeinfo(frame)
msg = '[%2.2f %s %s:%3d] %s\n' % \
(time.time(), event, tb.filename, tb.lineno, tb.code_context[0].rstrip())
if event == 'call' and tb.code_context[0].strip().startswith('def '):
args = ','.join('%s=%s' % i for i in frame.f_locals.items() if i[0] != 'self')
msg = msg.rstrip() + ' with ' + args + '\n'
try:
socket_trace.send(msg)
except:
socket_trace_close()
return
return socket_trace_send

def new_command(s):
"""
New command from the debugging socket
"""
notifier.socket_remove(s, 0)
cmd = s.recv(struct.unpack('!I', s.recv(4))[0]).strip().split(' ')
if cmd[0] == 'trace':
global socket_trace
if socket_trace:
socket_trace_close()
socket_trace = s
print '=== START TRACE ==='
sys.settrace(socket_trace_send)
if cmd[0] == 'winpdb':
s.send('ok\n')
s.close()
socket_trace_close()
print '=== START WINPDB EMBEDDED DEBUGGER ==='
import rpdb2; rpdb2.start_embedded_debugger('kaa')

def new_connection(s):
"""
New connection on the debugging socket
"""
notifier.socket_add(socket_listen.accept()[0], new_command, 0)
return True

def init():
"""
Set up the debugging module by opening the unix socket
"""
global socket_listen
if socket_listen:
notifier.socket_remove(socket_listen, 0)
else:
atexit.register(socket_unlink)
socket_unlink()
socket_listen = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
socket_listen.bind(tempfile('.debug/%s' % os.getpid()))
socket_listen.listen(1)
notifier.socket_add(socket_listen, new_connection, 0)
5 changes: 5 additions & 0 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
from . import timer
from . import thread

if os.environ.get('KAA_DEBUG', ''):
from . import debug

# get logging object
log = logging.getLogger('kaa.base.core.main')

Expand Down Expand Up @@ -143,6 +146,8 @@ def signal_handler(*args):
signals['sigchld'].connect(reapAllProcesses)

CoreThreading.init(signals, reset)
if os.environ.get('KAA_DEBUG', ''):
debug.init()
signals['init'].emit()
_initialized = True

Expand Down
112 changes: 112 additions & 0 deletions tools/kaa-debugger
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/usr/bin/python
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------------
# kaa-debugger - Debugger for kaa applications
# -----------------------------------------------------------------------------
# kaa.base - The Kaa Application Framework
# Copyright 2013 Dirk Meyer, Jason Tackaberry, et al.
#
# Please see the file AUTHORS for a complete list of authors.
#
# This library is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License version
# 2.1 as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
#
# -----------------------------------------------------------------------------

import sys
import os
import struct
import getopt

import kaa
import kaa.utils

pid = None

def trace(line):
"""
Callback for 'trace'
"""
print line.rstrip()

def winpdb(*args):
"""
Callback for 'winpdb'
"""
print 'The password to enter is \'kaa\''
os.execvp('winpdb', ['winpdb', '-a', pid])

def usage(code):
"""
Print usage on stdout and exit with code
"""
print 'kaa-debugger command'
print ' -t pid trace kaa application'
print ' -w pid use start winpdb to debug'
print ' -l list all running applications'
print
sys.exit(code)

# remove old sockets
for pid in os.listdir(kaa.utils.tempfile('.debug')):
if not os.path.exists(os.path.join('/proc/', pid, 'cmdline')):
os.unlink(kaa.utils.tempfile('.debug/%s' % pid))

try:
# read arguments
opts, args = getopt.getopt(sys.argv[1:], 'twlh', [])
except getopt.GetoptError:
usage(1)

command = ''
for o, a in opts:
if o == '-t':
command = 'trace'
if o == '-w':
command = 'winpdb'
if o == '-l':
for pid in os.listdir(kaa.utils.tempfile('.debug')):
cmd = ' '.join(open(os.path.join('/proc/', pid, 'cmdline')).read().split('\00')).strip()
print pid, cmd
sys.exit(0)
if o == '-h':
usage(0)

if not args or not command:
usage(1)

@kaa.coroutine()
def main():
global pid
s = kaa.Socket()
path = args[0]
if not os.path.exists(path):
path = kaa.utils.tempfile('.debug/%s' % path)
if not os.path.exists(path):
print path, 'not found'
print
usage(1)
pid = os.path.basename(path)
yield s.connect(path)
if command == 'winpdb':
s.signals['readline'].connect(winpdb)
s.write(struct.pack('!I', len('winpdb')))
s.write('winpdb')
if command == 'trace':
s.signals['readline'].connect(trace)
s.write(struct.pack('!I', len('trace')))
s.write('trace')

main()
kaa.main.run()