summaryrefslogtreecommitdiff
path: root/block-grep
blob: 5d10f7261a2597646faf4cd6efe86733f8c229cf (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
#!/usr/bin/env python
# Searches block separated by multiple newlines.
# Originally written for filtering ASAN (LSan) reports.
#
# Example usage:
# ASAN_OPTIONS=log_path=$PWD/leak wireshark
# block-grep leak.1337 -e dbus -v | block-grep -e Direct

import argparse
import re
import sys

def is_leaked(lines):
    return 'Objects leaked above:' in lines

def parse_file(f, match_func):
    lines = ''
    last_matched = ''
    def handle_lines():
        nonlocal last_matched
        if match_func(lines):
            sys.stdout.write(lines)
            # Uncomment if you want to see the leaked objects too
            #last_matched = lines
        elif last_matched:
            # If the previous block had a matching "Indirect leak of x bytes"
            # and this block is its related "Objects leaked above", write it too
            if  'irect leak of ' in last_matched and is_leaked(lines):
               sys.stdout.write(lines)
            last_matched = ''
    for line in f:
        lines += line
        if line.strip('\r\n'):
            continue

        handle_lines()
        lines = ''
    handle_lines()

parser = argparse.ArgumentParser()
parser.add_argument('-e', '--regexp', dest='pattern')
parser.add_argument('-i', '--ignore-case', action='store_true')
parser.add_argument('-v', '--invert-match', action='store_true')
parser.add_argument('file', nargs='*')

def main():
    args = parser.parse_args()
    files = args.file
    if not args.pattern:
        if not files:
            parser.error('Missing pattern option')
        pattern = files.pop(0)
    else:
        pattern = args.pattern

    if not files:
        files = ['-']

    flags = 0
    if args.ignore_case:
        flags |= re.IGNORECASE
    pattern = re.compile(pattern, flags)

    match_func = lambda lines: pattern.search(lines)
    if args.invert_match:
        match_func = lambda lines: not pattern.search(lines) and not is_leaked(lines)

    for filename in files:
        if filename == '-':
            parse_file(sys.stdin, match_func)
        else:
            parse_file(open(filename, 'r'), match_func)

if __name__ == '__main__':
    try:
        main()
    except (KeyboardInterrupt, BrokenPipeError):
        pass