2 # -*- coding: utf-8 -*-
4 # Wireshark - Network traffic analyzer
5 # By Gerald Combs <gerald@wireshark.org>
6 # Copyright 1998 Gerald Combs
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.
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.
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.
23 Generate Sysdig event dissector sections from the sysdig sources.
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.
29 Requires an Internet connection. Assets are loaded from GitHub over HTTPS.
38 sysdig_repo_pfx = 'https://raw.githubusercontent.com/draios/sysdig/0.5.0/'
40 ppm_ev_pub = urllib2.urlopen(sysdig_repo_pfx + 'driver/ppm_events_public.h')
41 ppm_ev_pub_lines = ppm_ev_pub.readlines()
44 ppme_re = re.compile('^\s+PPME_([A-Z0-9_]+_[EX])\s*=\s*([0-9]+)\s*,')
48 def get_event_defines():
50 for line in ppm_ev_pub_lines:
51 m = ppme_re.match(line)
53 event_d[int(m.group(2))] = m.group(1)
56 ppm_ev_table = urllib2.urlopen(sysdig_repo_pfx + 'driver/event_table.c')
57 ppm_ev_table_lines = ppm_ev_table.readlines()
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*[,}]')
65 def get_event_names():
66 '''Return a contiguous list of event names. Names are lower case.'''
68 for line in ppm_ev_table_lines:
69 ei = event_info_re.match(line)
71 event_name_l.append(ei.group(1))
82 def get_event_params():
83 '''Return a list of dictionaries containing event names and parameter info.'''
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)
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)
97 if p[0] in force_string_l:
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]
111 if 'INT' in param_type:
114 param_format = 'NONE'
115 elif param_type == 'BYTES':
116 param_format = 'NONE'
120 'event_name': ei.group(1),
121 'event_num': event_num,
123 'param_type': param_type,
124 'param_format': param_format,
126 event_param_l.append(param_d)
131 def param_to_hf_name(param):
132 return 'hf_param_{}_{}'.format(param['param_name'], param['param_type'].lower())
134 def param_to_value_string_name(param):
135 return '{}_{}_vals'.format(param['param_name'], param['param_type'].lower())
137 def get_param_desc(param):
138 # Try to coerce event names and parameters into human-friendly
140 # XXX This could use some work.
142 # Specific descriptions. Event name + parameter name.
144 'accept.queuepct': 'Accept queue per connection',
145 'execve.args': 'Program arguments',
146 'execve.comm': 'Command',
147 'execve.cwd': 'Current working directory',
149 # General descriptions. Event name only.
151 'ioctl': 'I/O control',
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'])
161 param_desc = param['param_name']
166 event_d = get_event_defines()
167 event_nums = event_d.keys()
170 event_name_l = get_event_names()
171 event_param_l = get_event_params()
174 for param in event_param_l:
175 hf_name = param_to_hf_name(param)
176 hf_d[hf_name] = param
178 idx_id_to_name = { '': 'no' }
179 parameter_index_l = []
181 for en in range (0, len(event_nums)):
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']
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(
199 ei_str = '#define {}_indexes {}_indexes'.format(event_var, idx_id_to_name[param_id])
201 parameter_index_l.append(ei_str)
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+')
209 # Strip out old content
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
220 for strip_re in strip_re_l:
221 dissector_lines = [l for l in dissector_lines if not strip_re.search(l)]
223 # Find our value strings
224 value_string_re = re.compile('static\s+const\s+value_string\s+([A-Za-z0-9_]+_vals)')
226 for line in dissector_lines:
227 vs = value_string_re.match(line)
229 value_string_l.append(vs.group(1))
231 # Add in new content after comments.
233 header_fields_c = 'Header fields'
234 header_fields_re = re.compile('/\*\s+' + header_fields_c, flags = re.IGNORECASE)
236 for hf_name in sorted(hf_d.keys()):
237 header_fields_l.append('static int {} = -1;'.format(hf_name))
239 event_names_c = 'Event names'
240 event_names_re = re.compile('/\*\s+' + event_names_c, flags = re.IGNORECASE)
242 event_str_l = list(set(event_name_l))
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))
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))
253 value_strings_c = 'Value strings'
254 value_strings_re = re.compile('/\*\s+' + value_strings_c, flags = re.IGNORECASE)
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))
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.
265 event_tree_c = 'Event tree'
266 event_tree_re = re.compile('/\*\s+' + event_tree_c, flags = re.IGNORECASE)
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))
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(
297 for line in dissector_lines:
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
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(
328 os.path.basename(__file__)
331 dissector_f.write('{}\n'.format(line))
332 # Fill each section only once
336 dissector_f.write(line)
344 if __name__ == "__main__":