[Spice-devel] [PATCH v5 30/41] dissector: Handle text formatting of different elements
Frediano Ziglio
fziglio at redhat.com
Fri Aug 7 08:00:59 PDT 2015
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 at redhat.com>
---
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
+ at 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
More information about the Spice-devel
mailing list