Support ws_txt and ws_txt_n attributes. These attributes are there to allow to set specific text based on the values of different elements. For instance a text of a Point structure could explicitly display the coordinated (like "Point (12,32)") instead of just a fixed string (like "Point"). They can be used to output in a single line the features of a structure. Or they can be used to format small array items. They can applied to almost everything from primitives, arrays, structure or even pointers. Signed-off-by: Frediano Ziglio <fziglio@xxxxxxxxxx> --- codegen/dissector_test.c | 28 ++++++ codegen/out_array_raw.txt | 4 +- codegen/out_array_struct.txt | 52 ++++++----- codegen/out_struct1.txt | 13 +-- python_modules/dissector.py | 205 +++++++++++++++++++++++++++++++++++++++---- 5 files changed, 256 insertions(+), 46 deletions(-) diff --git a/codegen/dissector_test.c b/codegen/dissector_test.c index 96b3107..84abacf 100644 --- a/codegen/dissector_test.c +++ b/codegen/dissector_test.c @@ -276,6 +276,34 @@ WS_DLL_PUBLIC proto_tree* proto_item_add_subtree(proto_item *ti, const gint idx) return res; } +WS_DLL_PUBLIC void proto_item_set_end(proto_item *ti, tvbuff_t *tvb, gint end) +{ + assert(tvb); + assert(end >= 0); + if (!ti) + return; + check_item(ti); + tvb_bytes(tvb, 0, end); + assert(ti->finfo->start <= end); + ti->finfo->length = end - ti->finfo->start; + check_item(ti); +} + +WS_DLL_PUBLIC void proto_item_set_text(proto_item *ti, const char *format, ...) +{ + va_list ap; + assert(format); + if (!ti) + return; + + check_item(ti); + va_start(ap, format); + vsnprintf(ti->finfo->rep->representation, sizeof(ti->finfo->rep->representation), + format, ap); + va_end(ap); + check_item(ti); +} + struct all_ti { proto_item ti; diff --git a/codegen/out_array_raw.txt b/codegen/out_array_raw.txt index f276871..31b510c 100644 --- a/codegen/out_array_raw.txt +++ b/codegen/out_array_raw.txt @@ -1,5 +1,3 @@ --- tree --- item - Text: - Name: array - Abbrev: spice2.auto.ArrayRaw_array_array + Text: array diff --git a/codegen/out_array_struct.txt b/codegen/out_array_struct.txt index eb03cd8..53d28ef 100644 --- a/codegen/out_array_struct.txt +++ b/codegen/out_array_struct.txt @@ -1,25 +1,37 @@ --- tree --- item - Text: 0 (0) - Name: dummy - Abbrev: spice2.auto.Dummy_dummy - Type: FT_UINT16 - Base: BASE_DEC + Text: Dummy + --- tree + --- item + Text: 0 (0) + Name: dummy + Abbrev: spice2.auto.Dummy_dummy + Type: FT_UINT16 + Base: BASE_DEC --- item - Text: 1 (0x1) - Name: dummy - Abbrev: spice2.auto.Dummy_dummy - Type: FT_UINT16 - Base: BASE_DEC + Text: Dummy + --- tree + --- item + Text: 1 (0x1) + Name: dummy + Abbrev: spice2.auto.Dummy_dummy + Type: FT_UINT16 + Base: BASE_DEC --- item - Text: 2 (0x2) - Name: dummy - Abbrev: spice2.auto.Dummy_dummy - Type: FT_UINT16 - Base: BASE_DEC + Text: Dummy + --- tree + --- item + Text: 2 (0x2) + Name: dummy + Abbrev: spice2.auto.Dummy_dummy + Type: FT_UINT16 + Base: BASE_DEC --- item - Text: 3 (0x3) - Name: dummy - Abbrev: spice2.auto.Dummy_dummy - Type: FT_UINT16 - Base: BASE_DEC + Text: Dummy + --- tree + --- item + Text: 3 (0x3) + Name: dummy + Abbrev: spice2.auto.Dummy_dummy + Type: FT_UINT16 + Base: BASE_DEC diff --git a/codegen/out_struct1.txt b/codegen/out_struct1.txt index a1d429c..993e77c 100644 --- a/codegen/out_struct1.txt +++ b/codegen/out_struct1.txt @@ -1,7 +1,10 @@ --- tree --- item - Text: 33154 (0x8182) - Name: dummy - Abbrev: spice2.auto.Dummy_dummy - Type: FT_UINT16 - Base: BASE_DEC + Text: Dummy + --- tree + --- item + Text: 33154 (0x8182) + Name: dummy + Abbrev: spice2.auto.Dummy_dummy + Type: FT_UINT16 + Base: BASE_DEC diff --git a/python_modules/dissector.py b/python_modules/dissector.py index 1bcefa3..08adefd 100644 --- a/python_modules/dissector.py +++ b/python_modules/dissector.py @@ -3,6 +3,7 @@ from . import ptypes from . import codegen import re +from contextlib import contextmanager import sys import types @@ -194,6 +195,7 @@ class Destination: self.reuse_scope = scope self.parent_dest = None self.level = Level() + self.index = None def child_sub(self, member, scope): return SubDestination(self, member, scope) @@ -291,7 +293,6 @@ def get_primitive_ft_type(t): # write a field def write_wireshark_field(writer, container, member, t, ws, tree, dest, size, encoding='ENC_LITTLE_ENDIAN', prefix=''): - assert(member and container) size_name = '' @@ -342,7 +343,17 @@ def write_wireshark_field(writer, container, member, t, ws, tree, dest, size, en # read name ws_name = ws.name + + # TODO change entirely to catch flags with same name in different places + # read all forces, check not changed at end dump + if not ws_name: + # write a text only item + if (f_type, base, vals) == ('FT_NONE', 'BASE_NONE', 'NULL'): + stmt = "%sproto_tree_add_text(%s, glb->tvb, offset, %s, \"%s\")" % (prefix, tree, size, desc) + writer.statement(stmt) + return + hf_name = member_hf_name(container, member) ws_name = 'auto.' + hf_name[3:] else: @@ -445,24 +456,46 @@ def write_switch(writer, container, switch, dest, scope): if switch.has_attr("fixedsize"): writer.assign("output", "save_output + %s" % switch.get_fixed_nw_size()) + +def write_array_core(writer, container, member, nelements, array, dest, scope): + element_type = array.element_type + + with writer.index() as index, writer.for_loop(index, nelements) as array_scope: + dest.index = index + if element_type.is_primitive(): + write_member_primitive(writer, container, member, element_type, WSAttributes(element_type, array.item_attrs), dest, scope) + else: + assert(element_type.is_struct()) + write_struct(writer, member, element_type, index, dest, scope) + dest.index = None + def write_array(writer, container, member, nelements, array, dest, scope): assert(container and member) ws = WSAttributes(array, member.attributes) + tree = dest.level.tree element_type = array.element_type + # easy case, binary data if element_type == ptypes.uint8 or element_type == ptypes.int8: - write_wireshark_field(writer, container, member, array, ws, dest.level.tree, dest, nelements, 'ENC_NA') + if not ws.has_txts(): + write_wireshark_field(writer, container, member, array, ws, tree, dest, nelements, 'ENC_NA') + else: + with dest.level: + if not scope.variable_defined(dest.level.ti): + scope.variable_def('proto_item *', dest.level.ti) + write_wireshark_field(writer, container, member, array, ws, tree, dest, nelements, 'ENC_NA', prefix=dest.level.ti + ' = ') + write_ws_formats(writer, ws, dest) writer.increment("offset", nelements) return - with writer.index() as index, writer.for_loop(index, nelements) as array_scope: - if element_type.is_primitive(): - write_member_primitive(writer, container, member, element_type, WSAttributes(element_type, array.item_attrs), dest, scope) - else: - assert(element_type.is_struct()) - write_struct(writer, member, element_type, index, dest, scope) + # just the core + if not ws.desc and not ws.name and not ws.has_txts(): + write_array_core(writer, container, member, nelements, array, dest, scope) + else: + with tree_item(writer, scope, ws, array, dest): + write_array_core(writer, container, member, nelements, array, dest, scope) def write_ptr_function(writer, target_type, container, member, dest, scope): @@ -503,8 +536,15 @@ def write_pointer(writer, container, member, t, dest, scope): assert(t.is_pointer()) if not scope.variable_defined('ptr'): + # TODO correct pointer scope.variable_def('guint32', 'ptr') + + ws = WSAttributes(ptypes.uint32, t.attributes) + if ws.name: + with tree_item(writer, scope, ws, ptypes.uint32, dest, has_subtree=False): + pass read_ptr(writer, t) + with writer.if_block('ptr'): writer.variable_def('guint32', 'save_offset = offset') writer.assign('offset', 'ptr + glb->message_offset') @@ -517,6 +557,117 @@ def write_pointer(writer, container, member, t, dest, scope): writer.assign('offset', 'save_offset') +def get_ws_txt_formats(txt, dest): + if txt is None: + return None + + fmt = txt[0].replace('%%',chr(1)*2).split('%') + if len(fmt) != len(txt): + raise Exception('Wrong number of formatting argument in %s' % fmt) + fmts = [fmt[0]] + s = '' + # parse all fields + for f, fld in list(zip(fmt, txt))[1:]: + s += ', ' + if fld == 'INDEX': + assert dest.index, 'INDEX variable not found' + s += dest.index + else: + s += dest.read_ref(fld) + size = dest.ref_size(fld) + if size > 32: + f = '" G_GINT%d_MODIFIER "' % size + f + fmts.append(f) + fmt = '%'.join(fmts).replace(chr(1), '%') + s = '"%s"' % fmt + s + return s + + +# TODO ugly the fmt part +def write_ws_formats(writer, ws, dest, fmt=None, formats=None): + formats = get_ws_txt_formats(ws.txt, dest) if formats is None else formats + formats_n = get_ws_txt_formats(ws.txt_n, dest) + if not fmt: + fmt = 'proto_item_set_text(%s, %%s)' % dest.level.ti + if formats_n: + assert dest.index, "ws_txt_n specified without an active index" + with writer.if_block('%s != -1' % dest.index, newline=False): + writer.statement(fmt % formats_n) + if formats: + with writer.block(' else ', newline=False): + writer.statement(fmt % formats) + writer.newline() + elif formats: + writer.statement(fmt % formats) + + +# write a new tree +@contextmanager +def tree_item(writer, scope, ws, t, dest, has_subtree=True): + # at enter generate the subtree + size_written = t.is_fixed_nw_size() + size = t.get_fixed_nw_size() if size_written else 1 + need_treeitem = has_subtree or not size_written + def declare_ti(): + if need_treeitem and not scope.variable_defined(dest.level.ti): + scope.variable_def('proto_item *', dest.level.ti) + txt_done = False + if not ws.name: + can_format = False + # TODO ugly + fmt = "proto_tree_add_text(%s, glb->tvb, offset, %s, %%s)" % (dest.level.tree, size) + try: + txt = get_ws_txt_formats(ws.txt, dest) + txt_n = get_ws_txt_formats(ws.txt_n, dest) + can_format = True + except: + pass + if can_format and ws.has_txts() and (txt is not None or ws.desc): + if ws.txt is None and ws.desc: + txt = '"%s"' % ws.desc.replace('%','%%') + if need_treeitem: + declare_ti() + fmt = dest.level.ti + ' = ' + fmt + write_ws_formats(writer, ws, dest, fmt=fmt, formats=txt) + txt_done = True + else: + if not txt_done and ws.has_txts(): + need_treeitem = True + can_format = False + desc = ws.desc + if desc is None and t.is_struct(): + desc = t.name + txt = '"%s"' % desc.replace('%','%%') + if need_treeitem: + declare_ti() + fmt = dest.level.ti + ' = ' + fmt + writer.statement(fmt % txt) + else: + if not txt_done and ws.has_txts(): + need_treeitem = True + prefix = '' + if need_treeitem: + declare_ti() + prefix = dest.level.ti + ' = ' + write_wireshark_field(writer, None, None, t, ws, dest.level.tree, dest, size, 'ENC_LITTLE_ENDIAN', prefix=prefix) + + ti = dest.level.ti + with dest.level: + if has_subtree: + if not scope.variable_defined(dest.level.tree): + scope.variable_def('proto_tree *', dest.level.tree) + ett_name = new_ett(writer) + writer.assign(dest.level.tree, 'proto_item_add_subtree(%s, %s)' % (ti, ett_name)) + + yield scope + + # at exit fix length and write possible text + if not size_written: + writer.statement('proto_item_set_end(%s, glb->tvb, offset)' % dest.level.ti) + if not txt_done and ws.has_txts(): + write_ws_formats(writer, ws, dest) + + def write_struct_func(writer, t, func_name, index): func_name = 'dissect_spice_struct_' + t.name @@ -527,7 +678,11 @@ def write_struct_func(writer, t, func_name, index): writer = writer.function_helper() scope = writer.function(func_name, "guint32", "GlobalInfo *glb _U_, proto_tree *tree _U_, guint32 offset, gint32 index _U_", True) dest = RootDestination(scope) - write_container_parser(writer, t, dest) + dest.index = 'index' + if not t.is_fixed_nw_size() or t.get_fixed_nw_size() != 0: + ws = WSAttributes(t) + with tree_item(writer, scope, ws, t, dest): + write_container_parser(writer, t, dest) writer.statement('return offset') writer.end_block() @@ -536,7 +691,9 @@ def write_struct(writer, member, t, index, dest, scope): if member.has_attr('ws_inline'): dest = dest.child_sub(member.name, scope) - with writer.block() as scope: + dest.index = 'index' + ws = WSAttributes(t, member.attributes) + with writer.block() as scope, tree_item(writer, scope, ws, t, dest): write_container_parser(writer, t, dest) else: func_name = 'dissect_spice_struct_' + t.name @@ -601,19 +758,24 @@ def write_flags(writer, container, member, t, ws, tree, dest): ws_func = WSAttributes(t) own_ti = ws.name != ws_func.name or ws.desc != ws_func.desc or ws.base != ws_func.base - if not own_ti: + if not own_ti and not ws.has_txts(): stmt = write_flags_func(writer, t, ws_func, tree, 'NULL') writer.statement(stmt) return - tree = dest.level.tree + # write reference to allows txt to read it + dest.write_ref(writer, t.get_fixed_nw_size() * 8, member.name, '%s(glb->tvb, offset)' % primitive_read_func(t)) + + # write flags and override texts with writer.block() as scope, dest.level: scope.variable_def('proto_item *', dest.level.ti) - size = t.get_fixed_nw_size() - int_type = ptypes.IntegerType(size*8, False) - write_wireshark_field(writer, container, member, int_type, ws, tree, dest, size, prefix=dest.level.ti + ' = ') + if own_ti: + size = t.get_fixed_nw_size() + int_type = ptypes.IntegerType(size*8, False) + write_wireshark_field(writer, container, member, int_type, ws, tree, dest, size, prefix=dest.level.ti + ' = ') stmt = write_flags_func(writer, t, ws_func, tree, dest.level.ti) - writer.statement(stmt) + writer.assign(dest.level.ti, stmt) + write_ws_formats(writer, ws, dest) def write_member_primitive(writer, container, member, t, ws, dest, scope): @@ -621,13 +783,20 @@ def write_member_primitive(writer, container, member, t, ws, dest, scope): if member.has_attr("bytes_count"): raise NotImplementedError("bytes_count not implemented") - - write_wireshark_field(writer, container, member, t, ws, dest.level.tree, dest, t.get_fixed_nw_size()) if member.has_attr("bytes_count"): dest_var = member.attributes["bytes_count"][0] else: dest_var = member.name dest.write_ref(writer, t.get_fixed_nw_size() * 8, dest_var, '%s(glb->tvb, offset)' % primitive_read_func(t)) + + if not ws.has_txts(): + write_wireshark_field(writer, container, member, t, ws, dest.level.tree, dest, t.get_fixed_nw_size()) + else: + if not scope.variable_defined(dest.level.ti): + scope.variable_def('proto_item *', dest.level.ti) + write_wireshark_field(writer, container, member, t, ws, dest.level.tree, dest, t.get_fixed_nw_size(), prefix=dest.level.ti + ' = ') + write_ws_formats(writer, ws, dest) + writer.increment("offset", t.get_fixed_nw_size()) def write_member(writer, container, member, dest, scope): -- 2.1.0 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel