[Spice-devel,v4,11/41] dissector: Add code to handle destination variable

Submitted by Frediano Ziglio on July 23, 2015, 3:54 p.m.

Details

Message ID 1437666898-27863-12-git-send-email-fziglio@redhat.com
State New
Headers show

Not browsing as part of any series.

Commit Message

Frediano Ziglio July 23, 2015, 3:54 p.m.
Add some classes to be able to store retrieved data from structure
and messages.
The idea is to generate code dynamically when variable are read.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
---
 python_modules/dissector.py | 104 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 103 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/python_modules/dissector.py b/python_modules/dissector.py
index ea13033..10da2e7 100644
--- a/python_modules/dissector.py
+++ b/python_modules/dissector.py
@@ -67,6 +67,106 @@  def write_parser_helpers(writer):
     writer.writeln('#endif')
     writer.newline()
 
+# generate code to declare a variable only when needed
+# code is generated only when we read the reference
+class Reference:
+    def __init__(self, writer, name):
+        self.defined = False
+        self.written = False
+        self.name = name
+        # create a subwriter to write code to read variable only once
+        self.writer = writer.get_subwriter()
+
+    def write(self, size, value, scope):
+        if not size in (8, 16, 32, 64):
+            raise Exception('Unknown size %d for %s' % (size, self.name))
+        assert(not self.defined or (value, size) == (self.value, self.size))
+        if not self.defined:
+            self.value = value
+            self.size = size
+            self.scope = scope
+            self.defined = True
+
+    def read(self):
+        # variable not yet defined
+        assert(self.defined)
+        if not self.written:
+            assert(not self.scope.variable_defined(self.name))
+            t = { 8: 'guint32', 16: 'guint32', 32: 'guint32', 64: 'guint64' }[self.size]
+            self.scope.variable_def(t, self.name)
+            self.writer.assign(self.name, self.value)
+            self.written = True
+        return self.name
+
+class Level:
+    def __init__(self, n=0):
+        self.level = n
+    def __enter__(self):
+        self.level += 1
+    def __exit__(self, exc_type, exc_value, traceback):
+        self.level -= 1
+    def __getattr__(self, name):
+        if not name in {'tree', 'ti'}:
+            raise Exception('Not possible to get name %s' % name)
+        return name if self.level == 0 else name + str(self.level)
+
+# represent part of a destination to write to
+# for instance if we are parsing a structure dest represent that structure output
+class Destination:
+    def __init__(self, scope):
+        self.refs = {}
+        self.is_helper = False
+        self.reuse_scope = scope
+        self.parent_dest = None
+        self.level = Level()
+
+    def child_sub(self, member, scope):
+        return SubDestination(self, member, scope)
+
+    def declare(self, writer):
+        return writer.optional_block(self.reuse_scope)
+
+    def is_toplevel(self):
+        return self.parent_dest == None and not self.is_helper
+
+    def read_ref(self, member):
+        return self.get_ref(member).read()
+
+    def write_ref(self, writer, size, member, value):
+        ref = self.get_ref(member, writer)
+        ref.write(size, value, self.reuse_scope)
+
+    def ref_size(self, member):
+        return self.get_ref(member).size
+
+class RootDestination(Destination):
+    def __init__(self, scope):
+        Destination.__init__(self, scope)
+        self.base_var = "fld"
+
+    def get_ref(self, member, writer=None):
+        name = (self.base_var + "." + member).replace('.', '__')
+        if name in self.refs:
+            return self.refs[name]
+        if not writer:
+            raise Exception('trying to read a reference to %s' % member)
+        self.refs[name] = ref = Reference(writer, name)
+        return ref
+
+    def declare(self, writer):
+        return writer.no_block(self.reuse_scope)
+
+class SubDestination(Destination):
+    def __init__(self, parent_dest, member, scope):
+        Destination.__init__(self, scope)
+        self.parent_dest = parent_dest
+        self.member = member
+        self.level = parent_dest.level
+
+    def get_ref(self, member, writer=None):
+        return self.parent_dest.get_ref(self.member + "." + member, writer)
+
+
 def write_msg_parser(writer, message, server):
     msg_name = message.c_name()
     function_name = "dissect_spice_%s_%s" % ('server' if server else 'client', msg_name)
@@ -81,7 +181,9 @@  def write_msg_parser(writer, message, server):
     writer.ifdef(message)
     parent_scope = writer.function(function_name,
                                    "guint32",
-                                   "GlobalInfo *glb _U_, proto_tree *tree0 _U_, guint32 offset", True)
+                                   "GlobalInfo *glb _U_, proto_tree *tree _U_, guint32 offset", True)
+
+    dest = RootDestination(parent_scope)
 
     writer.statement("return offset")
     writer.end_block()