nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Wireshark - Network traffic analyzer
5 # By Gerald Combs <gerald@wireshark.org>
6 # Copyright 1998 Gerald Combs
7 #
8 # This program is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU General Public License
10 # as published by the Free Software Foundation; either version 2
11 # of the License, or (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #
22 '''\
23 Generate Sysdig event dissector sections from the sysdig sources.
24  
25 Reads driver/event_table.c and driver/ppm_events_public.h and generates
26 corresponding dissection code in packet-sysdig-event.c. Updates are
27 performed in-place in the dissector code.
28  
29 Requires an Internet connection. Assets are loaded from GitHub over HTTPS.
30 '''
31  
32 import os
33 import os.path
34 import re
35 import urllib2
36 import sys
37  
38 sysdig_repo_pfx = 'https://raw.githubusercontent.com/draios/sysdig/0.5.0/'
39  
40 ppm_ev_pub = urllib2.urlopen(sysdig_repo_pfx + 'driver/ppm_events_public.h')
41 ppm_ev_pub_lines = ppm_ev_pub.readlines()
42 ppm_ev_pub.close()
43  
44 ppme_re = re.compile('^\s+PPME_([A-Z0-9_]+_[EX])\s*=\s*([0-9]+)\s*,')
45  
46 event_info_d = {}
47  
48 def get_event_defines():
49 event_d = {}
50 for line in ppm_ev_pub_lines:
51 m = ppme_re.match(line)
52 if m:
53 event_d[int(m.group(2))] = m.group(1)
54 return event_d
55  
56 ppm_ev_table = urllib2.urlopen(sysdig_repo_pfx + 'driver/event_table.c')
57 ppm_ev_table_lines = ppm_ev_table.readlines()
58 ppm_ev_table.close()
59  
60 hf_d = {}
61  
62 event_info_re = re.compile('^\s+/\*\s*PPME_.*\*\/\s*{\s*"([A-Za-z0-9_]+)"\s*,[^,]+,[^,]+,\s*([0-9]+)\s*[,{}]')
63 event_param_re = re.compile('{\s*"([A-Za-z0-9_]+)"\s*,\s*PT_([A-Z0-9_]+)\s*,\s*PF_([A-Z0-9_]+)\s*[,}]')
64  
65 def get_event_names():
66 '''Return a contiguous list of event names. Names are lower case.'''
67 event_name_l = []
68 for line in ppm_ev_table_lines:
69 ei = event_info_re.match(line)
70 if ei:
71 event_name_l.append(ei.group(1))
72 return event_name_l
73  
74 # PT_xxx to FT_xxx
75 pt_to_ft = {
76 'BYTEBUF': 'BYTES',
77 'CHARBUF': 'STRING',
78 'FD': 'INT64',
79 'FSPATH': 'STRING',
80 }
81  
82 def get_event_params():
83 '''Return a list of dictionaries containing event names and parameter info.'''
84 event_param_l = []
85 event_num = 0
86 force_string_l = ['args', 'env']
87 for line in ppm_ev_table_lines:
88 ei = event_info_re.match(line)
89 ep = event_param_re.findall(line)
90 if ei and ep:
91 src_param_count = int(ei.group(2))
92 if len(ep) != src_param_count:
93 err_msg = '{}: found {} parameters. Expected {}. Params: {}'.format(
94 ei.group(1), len(ep), src_param_count, repr(ep))
95 raise NameError(err_msg)
96 for p in ep:
97 if p[0] in force_string_l:
98 param_type = 'STRING'
99 elif p[1] in pt_to_ft:
100 param_type = pt_to_ft[p[1]]
101 elif p[0] == 'flags' and p[1].startswith('INT') and 'HEX' in p[2]:
102 param_type = 'U' + p[1]
103 elif 'INT' in p[1]:
104 # Ints
105 param_type = p[1]
106 else:
107 # Fall back to bytes
108 param_type = 'BYTES'
109  
110 if p[2] == 'NA':
111 if 'INT' in param_type:
112 param_format = 'DEC'
113 else:
114 param_format = 'NONE'
115 elif param_type == 'BYTES':
116 param_format = 'NONE'
117 else:
118 param_format = p[2]
119 param_d = {
120 'event_name': ei.group(1),
121 'event_num': event_num,
122 'param_name': p[0],
123 'param_type': param_type,
124 'param_format': param_format,
125 }
126 event_param_l.append(param_d)
127 if ei:
128 event_num += 1
129 return event_param_l
130  
131 def param_to_hf_name(param):
132 return 'hf_param_{}_{}'.format(param['param_name'], param['param_type'].lower())
133  
134 def param_to_value_string_name(param):
135 return '{}_{}_vals'.format(param['param_name'], param['param_type'].lower())
136  
137 def get_param_desc(param):
138 # Try to coerce event names and parameters into human-friendly
139 # strings.
140 # XXX This could use some work.
141  
142 # Specific descriptions. Event name + parameter name.
143 param_descs = {
144 'accept.queuepct': 'Accept queue per connection',
145 'execve.args': 'Program arguments',
146 'execve.comm': 'Command',
147 'execve.cwd': 'Current working directory',
148 }
149 # General descriptions. Event name only.
150 event_descs = {
151 'ioctl': 'I/O control',
152 }
153  
154 event_name = param['event_name']
155 param_id = '{}.{}'.format(event_name, param['param_name'])
156 if param_id in param_descs:
157 param_desc = param_descs[param_id]
158 elif event_name in event_descs:
159 param_desc = '{}: {}'.format(event_descs[event_name], param['param_name'])
160 else:
161 param_desc = param['param_name']
162 return param_desc
163  
164 def main():
165 # Event list
166 event_d = get_event_defines()
167 event_nums = event_d.keys()
168 event_nums.sort()
169  
170 event_name_l = get_event_names()
171 event_param_l = get_event_params()
172  
173 hf_d = {}
174 for param in event_param_l:
175 hf_name = param_to_hf_name(param)
176 hf_d[hf_name] = param
177  
178 idx_id_to_name = { '': 'no' }
179 parameter_index_l = []
180  
181 for en in range (0, len(event_nums)):
182 param_id = ''
183 param_l = []
184 event_var = event_d[en].lower()
185 for param in event_param_l:
186 if param['event_num'] == en:
187 hf_name = param_to_hf_name(param)
188 param_l.append(hf_name)
189 param_id += ':' + param['param_name'] + '_' + param['param_type']
190  
191 ei_str = ''
192 if param_id not in idx_id_to_name:
193 idx_id_to_name[param_id] = event_var
194 ei_str = 'static const int *{}_indexes[] = {{ &{}, NULL }};'.format(
195 event_var,
196 ', &'.join(param_l)
197 )
198 else:
199 ei_str = '#define {}_indexes {}_indexes'.format(event_var, idx_id_to_name[param_id])
200  
201 parameter_index_l.append(ei_str)
202  
203 dissector_path = os.path.join(os.path.dirname(__file__),
204 '..', 'epan', 'dissectors', 'packet-sysdig-event.c')
205 dissector_f = open(dissector_path, 'r')
206 dissector_lines = list(dissector_f)
207 dissector_f = open(dissector_path, 'w+')
208  
209 # Strip out old content
210 strip_re_l = []
211 strip_re_l.append(re.compile('^static\s+int\s+hf_param_.*;'))
212 strip_re_l.append(re.compile('^#define\s+EVT_STR_[A-Z0-9_]+\s+"[A-Za-z0-9_]+"'))
213 strip_re_l.append(re.compile('^#define\s+EVT_[A-Z0-9_]+\s+[0-9]+'))
214 strip_re_l.append(re.compile('^\s*{\s*EVT_[A-Z0-9_]+\s*,\s*EVT_STR_[A-Z0-9_]+\s*}'))
215 strip_re_l.append(re.compile('^static\s+const\s+int\s+\*\s*[a-z0-9_]+_[ex]_indexes\[\]\s*=\s*\{\s*&hf_param_.*NULL\s*\}\s*;'))
216 strip_re_l.append(re.compile('^\s*#define\s+[a-z0-9_]+_[ex]_indexes\s+[a-z0-9_]+_indexes'))
217 strip_re_l.append(re.compile('^\s*\{\s*EVT_[A-Z0-9_]+_[EX]\s*,\s*[a-z0-9_]+_[ex]_indexes\s*}\s*,'))
218 strip_re_l.append(re.compile('^\s*{\s*&hf_param_.*},')) # Must all be on one line
219  
220 for strip_re in strip_re_l:
221 dissector_lines = [l for l in dissector_lines if not strip_re.search(l)]
222  
223 # Find our value strings
224 value_string_re = re.compile('static\s+const\s+value_string\s+([A-Za-z0-9_]+_vals)')
225 value_string_l = []
226 for line in dissector_lines:
227 vs = value_string_re.match(line)
228 if vs:
229 value_string_l.append(vs.group(1))
230  
231 # Add in new content after comments.
232  
233 header_fields_c = 'Header fields'
234 header_fields_re = re.compile('/\*\s+' + header_fields_c, flags = re.IGNORECASE)
235 header_fields_l = []
236 for hf_name in sorted(hf_d.keys()):
237 header_fields_l.append('static int {} = -1;'.format(hf_name))
238  
239 event_names_c = 'Event names'
240 event_names_re = re.compile('/\*\s+' + event_names_c, flags = re.IGNORECASE)
241 event_names_l = []
242 event_str_l = list(set(event_name_l))
243 event_str_l.sort()
244 for evt_str in event_str_l:
245 event_names_l.append('#define EVT_STR_{0:24s} "{1:s}"'.format(evt_str.upper(), evt_str))
246  
247 event_definitions_c = 'Event definitions'
248 event_definitions_re = re.compile('/\*\s+' + event_definitions_c, flags = re.IGNORECASE)
249 event_definitions_l = []
250 for evt in event_nums:
251 event_definitions_l.append('#define EVT_{0:24s} {1:3d}'.format(event_d[evt], evt))
252  
253 value_strings_c = 'Value strings'
254 value_strings_re = re.compile('/\*\s+' + value_strings_c, flags = re.IGNORECASE)
255 value_strings_l = []
256 for evt in event_nums:
257 evt_num = 'EVT_{},'.format(event_d[evt])
258 evt_str = 'EVT_STR_' + event_name_l[evt].upper()
259 value_strings_l.append(' {{ {0:<32s} {1:s} }},'.format(evt_num, evt_str))
260  
261 parameter_index_c = 'Parameter indexes'
262 parameter_index_re = re.compile('/\*\s+' + parameter_index_c, flags = re.IGNORECASE)
263 # parameter_index_l defined above.
264  
265 event_tree_c = 'Event tree'
266 event_tree_re = re.compile('/\*\s+' + event_tree_c, flags = re.IGNORECASE)
267 event_tree_l = []
268 for evt in event_nums:
269 evt_num = 'EVT_{}'.format(event_d[evt])
270 evt_idx = '{}_indexes'.format(event_d[evt].lower())
271 event_tree_l.append(' {{ {}, {} }},'.format(evt_num, evt_idx))
272  
273 header_field_reg_c = 'Header field registration'
274 header_field_reg_re = re.compile('/\*\s+' + header_field_reg_c, flags = re.IGNORECASE)
275 header_field_reg_l = []
276 for hf_name in sorted(hf_d.keys()):
277 param = hf_d[hf_name]
278 event_name = param['event_name']
279 param_desc = get_param_desc(param)
280 param_name = param['param_name']
281 param_type = param['param_type']
282 param_format = param['param_format']
283 fieldconvert = 'NULL'
284 vs_name = param_to_value_string_name(param)
285 if vs_name in value_string_l and 'INT' in param_type:
286 fieldconvert = 'VALS({})'.format(vs_name)
287 header_field_reg_l.append(' {{ &{}, {{ "{}", "sysdig.param.{}.{}", FT_{}, BASE_{}, {}, 0, NULL, HFILL }} }},'.format(
288 hf_name,
289 param_desc,
290 event_name,
291 param_name,
292 param_type,
293 param_format,
294 fieldconvert
295 ))
296  
297 for line in dissector_lines:
298 fill_comment = None
299 fill_l = []
300  
301 if header_fields_re.match(line):
302 fill_comment = header_fields_c
303 fill_l = header_fields_l
304 elif event_names_re.match(line):
305 fill_comment = event_names_c
306 fill_l = event_names_l
307 elif event_definitions_re.match(line):
308 fill_comment = event_definitions_c
309 fill_l = event_definitions_l
310 elif value_strings_re.match(line):
311 fill_comment = value_strings_c
312 fill_l = value_strings_l
313 elif parameter_index_re.match(line):
314 fill_comment = parameter_index_c
315 fill_l = parameter_index_l
316 elif event_tree_re.match(line):
317 fill_comment = event_tree_c
318 fill_l = event_tree_l
319 elif header_field_reg_re.match(line):
320 fill_comment = header_field_reg_c
321 fill_l = header_field_reg_l
322  
323 if fill_comment is not None:
324 # Write our comment followed by the content
325 print('Generating {}, {:d} lines'.format(fill_comment, len(fill_l)))
326 dissector_f.write('/* {}. Automatically generated by tools/{} */\n'.format(
327 fill_comment,
328 os.path.basename(__file__)
329 ))
330 for line in fill_l:
331 dissector_f.write('{}\n'.format(line))
332 # Fill each section only once
333 del fill_l[:]
334 else:
335 # Existing content
336 dissector_f.write(line)
337  
338 dissector_f.close()
339  
340 #
341 # On with the show
342 #
343  
344 if __name__ == "__main__":
345 sys.exit(main())