nexmon – Blame information for rev 1
?pathlinks?
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()) |