~daisy-pluckers/error-tracker-deployment/test-crashes

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
# Call a program, SIGSEGV it three seconds later, and generate an Apport .crash
# report.
#
# Copyright (C) 2012 Canonical Ltd.
# Author: Martin Pitt <martin.pitt@ubuntu.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.  See http://www.gnu.org/copyleft/gpl.html for
# the full text of the license.

import sys
import subprocess
import argparse
import time
import os
import os.path
import signal
import atexit
import tempfile
import shutil
from glob import glob


import apport

def get_ppid(pid):
    '''Return parent pid of a process'''

    with open('/proc/%i/status' % pid) as f:
        for line in f:
            if line.startswith('PPid:'):
                return int(line.split()[1])
    return None

def gen_crash(reportdir):
    '''Generate initial .crash files in reportdir'''

    env = os.environ.copy()
    env['APPORT_REPORT_DIR'] = reportdir

    gdb = subprocess.Popen(['gdb', '--args'] + sys.argv[1:],
                            #stdout=subprocess.PIPE,
                            #stderr=subprocess.PIPE,
                            stdin=subprocess.PIPE,
                            env=env)
    gdb.stdin.write(b'run\n')
    gdb.stdin.flush()
    time.sleep(3)
    assert gdb.poll() is None, 'process already terminated'

    prog_pids = [int(p) for p in subprocess.check_output(['pidof', sys.argv[1]]).split()]
    prog_pid = None
    # find the one that was launched from our gdb
    for pid in prog_pids:
        if get_ppid(pid) == gdb.pid:
            prog_pid = pid
            break
    assert prog_pid is not None, 'did not find PID of process in gdb'

    # kill our program
    os.kill(prog_pid, signal.SIGSEGV)

    time.sleep(0.5)

    # generate core file
    gdb.stdin.write(('generate-core-file %s/my.core\n' % workdir).encode())
    gdb.stdin.flush()

    subprocess.call(['sync'])

    # generate apport report
    gdb.stdin.write(('shell /usr/share/apport/apport %i 11 0 < %s/my.core\n' %
                     (prog_pid, workdir)).encode())
    gdb.stdin.flush()

    subprocess.call(['sync'])
    time.sleep(2)

    gdb.stdin.write(b'kill\nquit\n')
    gdb.stdin.flush()
    gdb.wait()


#
# main
#

workdir = tempfile.mkdtemp()
atexit.register(shutil.rmtree, workdir)

gen_crash(workdir)

# process crash reports from workdir: add additional information, and write
# back to current directory
for f in glob(os.path.join(workdir, '*.crash')):
    print('--- post-processing %s' % f)
    r = apport.Report()
    with open(f, 'rb') as fd:
        r.load(fd)
    r.add_os_info()
    r.add_gdb_info()
    r.add_package_info()
    r.add_hooks_info(None)

    with open(os.path.basename(f), 'wb') as fd:
        r.write(fd)