diff options
| author | Jiri Moskovcak <jmoskovc@redhat.com> | 2009-06-02 17:06:39 +0200 |
|---|---|---|
| committer | Jiri Moskovcak <jmoskovc@redhat.com> | 2009-06-02 17:06:39 +0200 |
| commit | 8024b6ca0335cb59f737769f2e573435e32dd155 (patch) | |
| tree | a7aa3da017f04b56191fa2d93fd22096e269eef0 | |
| parent | 8966e621a0809d2109133f180db6a23bb4335843 (diff) | |
| download | abrt-8024b6ca0335cb59f737769f2e573435e32dd155.tar.gz abrt-8024b6ca0335cb59f737769f2e573435e32dd155.tar.xz abrt-8024b6ca0335cb59f737769f2e573435e32dd155.zip | |
New hook for python apps
- minor fixes in python analyzer
| -rw-r--r-- | lib/Plugins/Python.cpp | 72 | ||||
| -rw-r--r-- | lib/Plugins/Python.h | 2 | ||||
| -rw-r--r-- | src/Hooks/Makefile.am | 13 | ||||
| -rw-r--r-- | src/Hooks/abrt_exception_handler.py.in | 333 | ||||
| -rw-r--r-- | src/Hooks/pyhook.conf | 1 | ||||
| -rw-r--r-- | src/Hooks/sitecustomize.py | 30 |
6 files changed, 403 insertions, 48 deletions
diff --git a/lib/Plugins/Python.cpp b/lib/Plugins/Python.cpp index dcf78fa..f58a6c9 100644 --- a/lib/Plugins/Python.cpp +++ b/lib/Plugins/Python.cpp @@ -1,54 +1,25 @@ #include "Python.h" #include "DebugDump.h" -#include <sstream> -#include <iomanip> -#include <nss.h> -#include <sechash.h> -#include <prinit.h> +#include <fstream> +#include "ABRTException.h" #define FILENAME_BACKTRACE "backtrace" +#define PYHOOK_CONFIG "/etc/abrt/pyhook.conf" -std::string CAnalyzerPython::CreateHash(const std::string& pInput) -{ - std::string ret = ""; - HASHContext* hc; - unsigned char hash[SHA1_LENGTH]; - unsigned int len; - - hc = HASH_Create(HASH_AlgSHA1); - if (!hc) - { - throw std::string("CAnalyzerPython::CreateHash(): cannot initialize hash."); - } - HASH_Begin(hc); - HASH_Update(hc, reinterpret_cast<const unsigned char*>(pInput.c_str()), pInput.length()); - HASH_End(hc, hash, &len, sizeof(hash)); - HASH_Destroy(hc); - - unsigned int ii; - std::stringstream ss; - for (ii = 0; ii < len; ii++) - ss << std::setw(2) << std::setfill('0') << std::hex << (hash[ii]&0xff); - - return ss.str(); -} - -std::string CAnalyzerPython::GetLocalUUID(const std::string& pDebugDumpDir) +std::string CAnalyzerPython::CreateHash(const std::string& pDebugDumpDir) { + std::string uuid; CDebugDump dd; - std::string executable; - std::string package; - std::string backtrace; dd.Open(pDebugDumpDir); - dd.LoadText(FILENAME_EXECUTABLE, executable); - dd.LoadText(FILENAME_PACKAGE, package); - dd.LoadText(FILENAME_BACKTRACE, backtrace); + dd.LoadText("uuid", uuid); dd.Close(); + return uuid; +} - // TODO: get independent backtrace - - return CreateHash(package + executable + backtrace ); +std::string CAnalyzerPython::GetLocalUUID(const std::string& pDebugDumpDir) +{ + return CreateHash(pDebugDumpDir); } std::string CAnalyzerPython::GetGlobalUUID(const std::string& pDebugDumpDir) { @@ -57,16 +28,23 @@ std::string CAnalyzerPython::GetGlobalUUID(const std::string& pDebugDumpDir) void CAnalyzerPython::Init() { - // TODO: Copy abrt exception handler to proper place - if (NSS_NoDB_Init(NULL) != SECSuccess) - { - throw std::string("CAnalyzerPython::Init(): cannot initialize NSS library."); - } + std::ofstream fOutPySiteCustomize; + fOutPySiteCustomize.open(PYHOOK_CONFIG); + if (fOutPySiteCustomize.is_open()) + { + fOutPySiteCustomize << "enabled = yes" << std::endl; + fOutPySiteCustomize.close(); + } } - void CAnalyzerPython::DeInit() { // TODO: remove copied abrt exception handler - NSS_Shutdown(); + std::ofstream fOutPySiteCustomize; + fOutPySiteCustomize.open(PYHOOK_CONFIG); + if (fOutPySiteCustomize.is_open()) + { + fOutPySiteCustomize << "enabled = no" << std::endl; + fOutPySiteCustomize.close(); + } } diff --git a/lib/Plugins/Python.h b/lib/Plugins/Python.h index 620ba37..3c23e08 100644 --- a/lib/Plugins/Python.h +++ b/lib/Plugins/Python.h @@ -23,7 +23,7 @@ PLUGIN_INFO(ANALYZER, "Python", "0.0.1", "Simple Python analyzer plugin.", - "zprikryl@redhat.com", + "zprikryl@redhat.com, jmoskovc@redhat.com", "https://fedorahosted.org/abrt/wiki"); diff --git a/src/Hooks/Makefile.am b/src/Hooks/Makefile.am index 88361c6..2bb2e25 100644 --- a/src/Hooks/Makefile.am +++ b/src/Hooks/Makefile.am @@ -5,3 +5,16 @@ hookCCpp_SOURCES = CCpp.cpp hookCCpp_LDADD = ../../lib/Utils/libABRTUtils.la hookCCpp_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../../lib/Utils \ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" + +python_PYTHON = sitecustomize.py abrt_exception_handler.py + +EXTRA_DIST = pyhook.conf + +# FIXME: remove hardcoded path +pyhookconfdir = /etc/abrt +dist_pyhookconf_DATA = pyhook.conf + +CLEANFILES := $(notdir $(wildcard *~)) $(notdir $(wildcard *\#)) $(notdir $(wildcard \.\#*)) $(notdir $(wildcard *.pyc)) + +install-data-local: + sed s,@DEBUG_DUMP_DIR@,$(DEBUG_DUMPS_DIR),g abrt_exception_handler.py.in > abrt_exception_handler.py diff --git a/src/Hooks/abrt_exception_handler.py.in b/src/Hooks/abrt_exception_handler.py.in new file mode 100644 index 0000000..4283f3b --- /dev/null +++ b/src/Hooks/abrt_exception_handler.py.in @@ -0,0 +1,333 @@ +# -*- coding: utf-8 -*- +## Copyright (C) 2001-2005 Red Hat, Inc. +## Copyright (C) 2001-2005 Harald Hoyer <harald@redhat.com> +## Copyright (C) 2009 Jiri Moskovcak <jmoskovc@redhat.com> + +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. + +## This program 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 General Public License for more details. + +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +""" +Module for a userfriendly exception handling + +Example code: + +import sys + +from exception import action, error, exitcode, installExceptionHandler + +installExceptionHandler("test", "1.0", gui=0, debug=0) + +def exception_function(): + action("Trying to divide by zero") + + try: + local_var_1 = 1 + local_var_2 = 0 + # test exception raised to show the effect + local_var_3 = local_var_1 / local_var_2 + except: + error("Does not seem to work!? :-)") + exitcode(15) + raise + +""" +import sys +import os +import syslog +# abrt lib for saving debugdumps +import ABRTUtils + +from rhpl.translate import _ + + +__DUMPHASH = {} +# FIXME: do length limits on obj dumps. +def __dump_class(instance, fd, level=0): + "dumps all classes" + import types + # protect from loops + if not __DUMPHASH.has_key(instance): + __DUMPHASH[instance] = True + else: + fd.write("Already dumped\n") + return + if (instance.__class__.__dict__.has_key("__str__") or + instance.__class__.__dict__.has_key("__repr__")): + fd.write("%s\n" % (instance,)) + return + fd.write("%s instance, containing members:\n" % + (instance.__class__.__name__)) + pad = ' ' * ((level) * 2) + for key, value in instance.__dict__.items(): + if type(value) == types.ListType: + fd.write("%s%s: [" % (pad, key)) + first = 1 + for item in value: + if not first: + fd.write(", ") + else: + first = 0 + if type(item) == types.InstanceType: + __dump_class(item, fd, level + 1) + else: + fd.write("%s" % (item,)) + fd.write("]\n") + elif type(value) == types.DictType: + fd.write("%s%s: {" % (pad, key)) + first = 1 + for k, v in value.items(): + if not first: + fd.write(", ") + else: + first = 0 + if type(k) == types.StringType: + fd.write("'%s': " % (k,)) + else: + fd.write("%s: " % (k,)) + if type(v) == types.InstanceType: + __dump_class(v, fd, level + 1) + else: + fd.write("%s" % (v,)) + fd.write("}\n") + elif type(value) == types.InstanceType: + fd.write("%s%s: " % (pad, key)) + __dump_class(value, fd, level + 1) + else: + fd.write("%s%s: %s\n" % (pad, key, value)) + +def write_dump(pid, tb_uuid, tb): + import time + ttime = int(time.time()) + # localstatedir + #dir_name = "/home/jmoskovc/.local/abrt/var/cache/abrt/pyhook-%s-%s" % (ttime , pid) + dir_name = "@DEBUG_DUMP_DIR@/pyhook-%s-%s" % (ttime , pid) + dd = ABRTUtils.CDebugDump() + try: + #os.mkdir(dir_name) + dd.Create(dir_name) + except Exception, e: + syslog.syslog("abrt: Cannot create dir %s" % dir_name) + return + # save executable + fexecutable = open("%s/executable" % dir_name, "w") + if sys.argv[0]: + fexecutable.write(os.path.abspath(sys.argv[0])) + else: + fexecutable.write("Exception raised from python shell") + fexecutable.close() + # save coredump + coredump = open("%s/backtrace" % dir_name, "w") + coredump.write(tb) + coredump.close() + # save uuid + uuid = open("%s/uuid" % dir_name, "w") + uuid.write(tb_uuid) + uuid.close() + # save cmdline + cmdline = open("%s/cmdline" % dir_name, "w") + cmdline.write(open("/proc/%s/cmdline" % pid).read().replace('\x00',' ')) + cmdline.close() + # save uid + uid = open("%s/uid" % dir_name, "w") + uid.write(open("/proc/%s/loginuid" % pid).readlines()[0]) + uid.close() + # save analyzer + analyzer = open("%s/analyzer" % dir_name, "w") + analyzer.write("Python") + analyzer.close() + dd.Close() + +def __dump_exception(out, text, tracebk): + 'write a traceback to "out"' + + out.write(text) + + trace = tracebk + while trace.tb_next: + trace = trace.tb_next + frame = trace.tb_frame + out.write ("\nLocal variables in innermost frame:\n") + try: + for (key, value) in frame.f_locals.items(): + out.write ("%s: %s\n" % (key, value)) + except: + pass + + +def __exception_window(title, text, component_name): + pass + +__ACTION_STR = "" +def action(what): + """Describe what you want to do actually. + what - string + """ + global __ACTION_STR # pylint: disable-msg=W0603 + __ACTION_STR = what + +__ERROR_STR = "" +def error(what): + """Describe what went wrong with a userfriendly text. + what - string + """ + global __ERROR_STR # pylint: disable-msg=W0603 + __ERROR_STR = what + +__EXITCODE = 10 +def exitcode(num): + """The exitcode, with which the exception handling routine should call + sys.exit(). + num - int(exitcode) + """ + global __EXITCODE # pylint: disable-msg=W0603 + __EXITCODE = int(num) + +# +# handleMyException function +# +def handleMyException((etype, value, tb)): + """ + The exception handling function. + + progname - the name of the application + version - the version of the application + """ + + # restore original exception handler + sys.excepthook = sys.__excepthook__ # pylint: disable-msg=E1101 + + import os.path + import md5 + import traceback + + syslog.syslog("abrt: Pyhook: Detected unhandled exception in %s " % sys.argv[0]) + elist = traceback.format_exception (etype, value, tb) + tblast = traceback.extract_tb(tb, limit=None) + if len(tblast): + tblast = tblast[len(tblast)-1] + extxt = traceback.format_exception_only(etype, value) + text = "" + text = text + "Summary: TB" + if tblast and len(tblast) > 3: + ll = [] + ll.extend(tblast[:3]) + ll[0] = os.path.basename(tblast[0]) + tblast = ll + + m = md5.new() + ntext = "" + for t in tblast: + ntext += str(t) + ":" + m.update(str(t)) + + tb_uuid = str(m.hexdigest())[:8] + text += tb_uuid + " " + ntext + + text += extxt[0] + text += "\n" + text += "".join(elist) + + trace = tb + while trace.tb_next: + trace = trace.tb_next + frame = trace.tb_frame + text += ("\nLocal variables in innermost frame:\n") + try: + for (key, value) in frame.f_locals.items(): + text += "%s: %s\n" % (key, value) + except: + pass + + # add coredump saving + print text + write_dump(os.getpid(), tb_uuid, text) + sys.exit(__EXITCODE) + +def installExceptionHandler(debug = 1): + """ + Install the exception handling function. + + progname - the name of the application + version - the version of the application + debug - show the full traceback (with "Save to file" in GUI) + """ + # FIXME: only root can write ddump :( + if os.getuid() == 0: + sys.excepthook = lambda etype, value, tb: \ + handleMyException((etype, value, tb)) + +if __name__ == '__main__': + def _exception_function(): + action("Trying to divide by zero") + + try: + local_var_1 = 1 + local_var_2 = 0 + # test exception raised to show the effect + local_var_3 = local_var_1 / local_var_2 # pylint: disable-msg=W0612 + except: + error("Does not seem to work!? :-)") + exitcode(15) + raise + + def _usage(): + print """%s [-dgh] [--debug] [--gui] [--help] + -d, --debug + Show the whole backtrace + + -h, --help + Display this message""" % (sys.argv[0]) + + import getopt + __debug = 1 + + installExceptionHandler(__debug) + + __debug = 0 + + class BadUsage(Exception): + "exception for a bad command line usage" + + try: + __opts, __args = getopt.getopt(sys.argv[1:], "dgh", + [ + "debug", + "help", + "gui", + ]) + + for __opt, __val in __opts: + if __opt == '-d' or __opt == '--debug': + __debug = 1 + continue + + if __opt == '-g' or __opt == '--gui': + __gui = 1 + continue + + if __opt == '-h' or __opt == '--help': + _usage() + sys.exit(0) + + except (getopt.error, BadUsage): + _usage() + sys.exit(1) + + installExceptionHandler(__debug) + + _exception_function() + sys.exit(0) + + +__author__ = "Harald Hoyer <harald@redhat.com>" diff --git a/src/Hooks/pyhook.conf b/src/Hooks/pyhook.conf new file mode 100644 index 0000000..731debb --- /dev/null +++ b/src/Hooks/pyhook.conf @@ -0,0 +1 @@ +enabled = yes diff --git a/src/Hooks/sitecustomize.py b/src/Hooks/sitecustomize.py new file mode 100644 index 0000000..5e7b524 --- /dev/null +++ b/src/Hooks/sitecustomize.py @@ -0,0 +1,30 @@ +config = None +conf = {} +try: + config = open("/etc/abrt/pyhook.conf","r") +except: + #silently ignore if file doesn't exist + pass + +try: + if config: + # we expect config in form + # key = value + # Enabled = yes + # this should strip + line = config.readline().lower().replace(' ','').strip('\n').split('=') + conf[line[0]] = line[1] +except: + # ignore silently everything, because we don't want to bother user if this hook doesn't work + pass + +if conf.has_key("enabled"): + if conf["enabled"] == "yes": + try: + from abrt_exception_handler import * + + installExceptionHandler(debug = 1) + except Exception, e: + # FIXME don't print anything, write it to some log file + print e + pass
\ No newline at end of file |
