summaryrefslogtreecommitdiffstats
path: root/src/Hooks/abrt_exception_handler.py.in
blob: 89f301324df9ebbe9d461c394aac16cbb57f2ca8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# -*- 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
"""

import sys
import os
import syslog
import subprocess


def write_dump(pid, tb):
    executable = "Exception raised from python shell"
    if sys.argv[0]:
        # FIXME: is this reliable?!
        # what if argv[0] is relative and we chdir'ed somewhere
        # during execution?
        executable = os.path.abspath(sys.argv[0])

    command = ["/usr/libexec/abrt-hook-python"]
    command.append("--pid=%s" % pid)
    command.append("--executable=%s" % executable)

    helper = subprocess.Popen(command, stdin=subprocess.PIPE)
    helper.communicate(tb)
    helper.wait()


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
    # ignore uncaught ctrl-c
    if etype == KeyboardInterrupt:
        return sys.__excepthook__(etype, value, tb)

    try:
        import os.path
        import traceback

        # "-c" appears in this case:
        # $ python -c 'import sys; print "argv0 is:%s" % sys.argv[0]'
        # argv0 is:-c
        if sys.argv[0] and sys.argv[0] != "-c":
            syslog.syslog("abrt: detected unhandled Python exception in %s" % sys.argv[0])
        else: # interactive Python etc
            syslog.syslog("abrt: detected unhandled Python exception")

        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)
        if tblast and len(tblast) > 3:
            ll = []
            ll.extend(tblast[:3])
            ll[0] = os.path.basename(tblast[0])
            tblast = ll

        ntext = ""
        for t in tblast:
            ntext += str(t) + ":"

        text = 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, val) in frame.f_locals.items():
                text += "%s: %s\n" % (key, repr(val))
        except:
            pass

        # add coredump saving
        write_dump(os.getpid(), text)

    except:
        # silently ignore any error in this hook,
        # to not interfere with the python scripts
        pass

    return sys.__excepthook__(etype, value, tb)


def installExceptionHandler():
    """
    Install the exception handling function.
    """
    sys.excepthook = lambda etype, value, tb: handleMyException((etype, value, tb))


if __name__ == '__main__':
    # test exception raised to show the effect
    div0 = 1 / 0 # pylint: disable-msg=W0612
    sys.exit(0)


__author__ = "Harald Hoyer <harald@redhat.com>"