~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/skiboot/external/fwts/generate-fwts-olog

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python2
 
2
#
 
3
# Copyright 2016 Jeremy Kerr <jk@ozlabs.org>
 
4
#
 
5
# Licensed under the Apache License, Version 2.0 (the "License");
 
6
# you may not use this file except in compliance with the License.
 
7
# You may obtain a copy of the License at
 
8
#
 
9
#       http://www.apache.org/licenses/LICENSE-2.0
 
10
#
 
11
# Unless required by applicable law or agreed to in writing, software
 
12
# distributed under the License is distributed on an "AS IS" BASIS,
 
13
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 
14
# implied.
 
15
# See the License for the specific language governing permissions and
 
16
# limitations under the License.
 
17
 
 
18
import os.path
 
19
import re
 
20
import sys
 
21
import string
 
22
import json
 
23
import argparse
 
24
from pyparsing import Regex, Literal, Word, Combine, OneOrMore, QuotedString, \
 
25
         lineno
 
26
 
 
27
json_params = {
 
28
    'indent': 1,
 
29
    'sort_keys': True,
 
30
    'separators': (',', ': '),
 
31
}
 
32
 
 
33
def create_parser():
 
34
    # Match a C-style comment starting with two *s
 
35
    comment = Regex(r'/\*\*(?P<content>.*?)\*/', re.DOTALL)
 
36
 
 
37
    # Match an @fwts-<tag> annotation (within the comment), plus the proceeding
 
38
    # text
 
39
    annotation = Regex(r'@fwts-(?P<tag>\w+)\W+(?P<text>.*?)(?=@fwts-|\Z)',
 
40
                re.DOTALL)
 
41
 
 
42
    # Match the following prlog() call
 
43
    log_call = (Literal("prlog") +
 
44
                Literal('(').suppress() +
 
45
                Word(string.letters + string.digits + '_') +
 
46
                Literal(',').suppress() +
 
47
                Combine(OneOrMore(QuotedString('"')), adjacent=False) +
 
48
                (Literal(')') | Literal(',')).suppress()
 
49
               )
 
50
 
 
51
    pattern = comment + log_call
 
52
    pattern.setWhitespaceChars(string.whitespace + '\n')
 
53
 
 
54
    def comment_action(tok):
 
55
        patterns = {}
 
56
        for result in annotation.scanString(tok['content']):
 
57
            patterns.update(result[0][0])
 
58
        return patterns
 
59
 
 
60
    def annotation_action(tok):
 
61
        return {
 
62
            tok['tag']: cleanup_content(tok['text'])
 
63
        }
 
64
 
 
65
    comment.setParseAction(comment_action)
 
66
    annotation.setParseAction(annotation_action)
 
67
    pattern.parseWithTabs()
 
68
 
 
69
    return pattern
 
70
 
 
71
def find_sources(dirname):
 
72
    sources = []
 
73
 
 
74
    def is_source(fname):
 
75
        return fname.endswith('.c')
 
76
 
 
77
    def add_fn(s, dname, fnames):
 
78
        s.extend([ os.path.join(dname, fname)
 
79
                         for fname in fnames if is_source(fname) ])
 
80
 
 
81
    os.path.walk(dirname, add_fn, sources)
 
82
    return sources
 
83
 
 
84
def cleanup_content(content):
 
85
    comment_prefix_re = re.compile(r'^\s*\*\s*', re.MULTILINE)
 
86
    whitespace_re = re.compile(r'\s+')
 
87
 
 
88
    content = comment_prefix_re.sub(' ', content)
 
89
    content = whitespace_re.sub(' ', content)
 
90
    return content.strip()
 
91
 
 
92
def warn(loc, message):
 
93
    print >>sys.stderr, 'WARNING:%s:%d: %s' % (loc[0], loc[1], message)
 
94
 
 
95
def log_level_to_fwts(level):
 
96
    level_map = {
 
97
        'PR_EMERG':     'LOG_LEVEL_CRITICAL',
 
98
        'PR_ALERT':     'LOG_LEVEL_CRITICAL',
 
99
        'PR_CRIT':      'LOG_LEVEL_CRITICAL',
 
100
        'PR_ERR':       'LOG_LEVEL_CRITICAL',
 
101
        'PR_WARNING':   'LOG_LEVEL_HIGH',
 
102
        'PR_NOTICE':    'LOG_LEVEL_MEDIUM',
 
103
        'PR_PRINTF':    'LOG_LEVEL_MEDIUM',
 
104
    }
 
105
    return level_map.get(level, 'LOG_LEVEL_LOW')
 
106
 
 
107
def message_to_pattern(loc, msg):
 
108
    """ Convert a C printf()-style template to a pattern suitable for fwts """
 
109
 
 
110
    # Somewhat-simplified match for a %-template
 
111
    template_re = re.compile(
 
112
            '%(?P<flag>[-#0 +]*)'
 
113
            '(?P<width>(?:[0-9]*|\*))?'
 
114
            '(?P<precision>\.*(?:[1-9][0-9]*|\*))?'
 
115
            '(?:hh|h|ll|l|L|j|z|t)?'
 
116
            '(?P<conversion>[a-zA-Z%])')
 
117
    global is_regex
 
118
    is_regex = False
 
119
 
 
120
    def expand_template(match):
 
121
        global is_regex
 
122
        c = match.group('conversion').lower()
 
123
        if c == '%':
 
124
            return '%'
 
125
        is_regex = True
 
126
        if c in ['d', 'i', 'u']:
 
127
            return '[0-9]+'
 
128
        elif c == 'o':
 
129
            return '[0-7]+'
 
130
        elif c == 'x':
 
131
            return '[0-9a-f]+'
 
132
        elif c == 'p':
 
133
            return '(0x[0-9a-f]+|nil)'
 
134
        elif c == 's':
 
135
            return '.*'
 
136
        else:
 
137
            warn(loc, "Unknown template conversion '%s'" % match.group(0))
 
138
            return '.*'
 
139
 
 
140
    escape_re = re.compile(r'\\(?P<char>.)', re.DOTALL)
 
141
    def expand_escape(match):
 
142
        global is_regex
 
143
        c = match.group('char')
 
144
        if c == 'n':
 
145
            return '\n'
 
146
        elif c in ['\\', '"']:
 
147
            return c
 
148
        else:
 
149
            warn(loc, "Unhandled escape sequence '%s'" % match.group(0))
 
150
            is_regex = True
 
151
            return '.'
 
152
 
 
153
    pattern = template_re.sub(expand_template, msg)
 
154
    pattern = escape_re.sub(expand_escape, pattern)
 
155
    pattern = pattern.strip()
 
156
 
 
157
    compare_mode = "string"
 
158
    if is_regex:
 
159
        compare_mode = "regex"
 
160
 
 
161
    return (compare_mode, pattern)
 
162
 
 
163
def parse_patterns(parser, fname):
 
164
    patterns = []
 
165
    data = open(fname).read()
 
166
    i = 1
 
167
    for result in parser.scanString(data):
 
168
        (token, loc, _) = result
 
169
        (annotations, logfn, level, msg) = token
 
170
 
 
171
        loc = (fname, lineno(loc, data))
 
172
 
 
173
        if logfn != 'prlog':
 
174
            warn(loc, "unknown log output function '%s'" % logfn)
 
175
 
 
176
        compare_mode, pattern_str = message_to_pattern(loc, msg)
 
177
 
 
178
        pattern = {
 
179
            'log_level': log_level_to_fwts(level),
 
180
            'compare_mode': compare_mode,
 
181
            'pattern': pattern_str,
 
182
        }
 
183
 
 
184
        pattern.update(annotations)
 
185
 
 
186
        if not 'label' in pattern:
 
187
            warn(loc, "missing label")
 
188
            pattern['label'] = '%s:%d' % (fname, i)
 
189
            i += 1
 
190
 
 
191
        if not 'advice' in pattern:
 
192
            warn(loc, "missing advice")
 
193
 
 
194
        allowed_data = ['compare_mode', 'log_level',
 
195
                        'pattern', 'advice', 'label']
 
196
        extras = set(pattern.keys()) - set(allowed_data)
 
197
        if extras:
 
198
            warn(loc, "unknown pattern annotation: %s" %
 
199
                    ','.join([ "'%s'" % e for e in extras]))
 
200
            for e in extras:
 
201
                del pattern[e]
 
202
 
 
203
        patterns.append(pattern)
 
204
 
 
205
    return patterns
 
206
 
 
207
if __name__ == '__main__':
 
208
    argparser = argparse.ArgumentParser(
 
209
            description='Generate FWTS olog definitions from the skiboot '
 
210
                        'source tree')
 
211
    argparser.add_argument('directories', metavar='DIR', nargs='*',
 
212
            help='path to source files (default .)', default=['.'])
 
213
    argparser.add_argument('--output', '-o', metavar='FILE',
 
214
            type=argparse.FileType('w'), default=sys.stdout,
 
215
            help='output to FILE (default to stdout)', nargs='?')
 
216
    args = argparser.parse_args()
 
217
 
 
218
    sources = []
 
219
    for directory in args.directories:
 
220
        sources.extend(find_sources(directory))
 
221
 
 
222
    parser = create_parser()
 
223
    patterns = []
 
224
    for source in sources:
 
225
        patterns.extend(parse_patterns(parser, source))
 
226
 
 
227
    data = {'olog_error_warning_patterns': patterns}
 
228
 
 
229
    args.output.write(json.dumps(data, **json_params) + '\n')
 
230