Beispiel #1
0
 def __init__(self):
     self.name = None
     self.seq = 0
     self.time = 0
     self.duration = 0
     self.apiId = 0
     self.values = OrderedDict()
     self.modifiedArrays = []
     self.modifiedObjects = []
     self.sensorData = {}
Beispiel #2
0
class Object(object):
  __slots__ = ["id", "ns", "cls", "attrs"]
  
  def __init__(self, id, ns, cls):
    self.id        = id
    self.ns        = ns
    self.cls       = cls
    self.attrs     = OrderedDict()
  
  def __repr__(self):
    attrs = ", ".join(["%s=%s" % (k, v) for k, v in self.attrs.items()])
    return "<%s instance at %s%x %s>" % (self.cls.name, ("%x:" % self.ns if self.ns else ""), self.id, attrs)
    
  def __eq__(self, o):
    try:
      return self.id == o.id and self.cls == o.cls and self.attrs == o.attrs
    except AttributeError:
      return False
      
  def __hash__(self):
    return hash(self.id) ^ hash(self.ns) ^ hash(self.cls) ^ hash(str(self.attrs.items()))
Beispiel #3
0
class Object(object):
    __slots__ = ["id", "ns", "cls", "attrs"]

    def __init__(self, id, ns, cls):
        self.id = id
        self.ns = ns
        self.cls = cls
        self.attrs = OrderedDict()

    def __repr__(self):
        attrs = ", ".join(["%s=%s" % (k, v) for k, v in self.attrs.items()])
        return "<%s instance at %s%x %s>" % (self.cls.name,
                                             ("%x:" % self.ns if self.ns else
                                              ""), self.id, attrs)

    def __eq__(self, o):
        try:
            return self.id == o.id and self.cls == o.cls and self.attrs == o.attrs
        except AttributeError:
            return False

    def __hash__(self):
        return hash(self.id) ^ hash(self.ns) ^ hash(self.cls) ^ hash(
            str(self.attrs.items()))
Beispiel #4
0
 def __init__(self, id, ns, cls):
   self.id        = id
   self.ns        = ns
   self.cls       = cls
   self.attrs     = OrderedDict()
Beispiel #5
0
    def saveTrace(self,
                  trace,
                  traceFile,
                  dataFileName=None,
                  dataFileFormat="rvct",
                  frameMarkers=[],
                  initFuncName="init",
                  uninitFuncName="uninit",
                  playFuncName="play",
                  playFrameFuncName="playFrame",
                  frameFuncName="frame",
                  arrayPrefix="array",
                  playerArgument="context",
                  insertCopyright=True):
        try:
            library = self.analyzer.project.targets["code"].library
            config = self.analyzer.project.config
        except (AttributeError, KeyError):
            raise RuntimeError("API configuration not found.")

        def arrayId(array):
            assert isinstance(array, Trace.Array)
            return (array.__class__, array.id)

        def objectId(obj):
            assert isinstance(obj, Trace.Object)
            return "%s_%x_%x" % (obj.cls.name.lower(), obj.ns, obj.id)

        task = Task.startTask("c-export", "Formatting source",
                              len(trace.events))
        indent = " " * 3

        # Collect all values for all events
        task = Task.startTask("c-export", "Collecting data", len(trace.events))
        values = []
        [values.extend(e.values.values()) for e in trace.events]

        # Collect arrays
        arrays = OrderedDict([(arrayId(v), v) for v in reversed(values)
                              if isinstance(v, Trace.Array)])

        # Check that the external data format is supported
        if dataFileName:
            assert dataFileName.endswith(
                ".s"), "Unsupported external data file type. Use one of: s"
            assert dataFileFormat in (
                "gcc", "rvct"
            ), "Unsupported external data format. Use one of: gcc, rvct"
            dataFile = open(dataFileName, "w")
        else:
            dataFile = None

        # Calculate maximum sizes of arrays
        arraySizes = dict([(a, 0) for a in arrays.keys()])
        for value in values:
            if isinstance(value, Trace.Array):
                a = arrayId(value)
                arraySizes[a] = max(len(value), arraySizes[a])

        # Figure out the C types of arrays and objects
        classes = {}
        objectTypes = {}
        arrayTypes = {}
        outValueObjects = set()  # Objects that are acquired through a function
        arrayVariants = DefaultDict(list)
        usePersistentArrays = False  # Use arrays whose contents must be kept up to date

        # even after passing them to the API

        def registerObject(event, name, value):
            if not value.cls in classes:
                classes[value.cls] = {}
            function = self.analyzer.lookupFunction(event)
            # Object has already been registered
            if not name or function.parameters[name].isOut:
                outValueObjects.add(value)
            if objectId(value) in classes[value.cls]:
                return
            classes[value.cls][objectId(value)] = value
            for cType, nativeTypeName in library.typeMap.items():
                if cType.name == value.cls.name:
                    objectTypes[value] = cType
                    break
            else:
                self.analyzer.reportWarning("Unknown class: <%s>" %
                                            value.cls.name)
                # Create a fake type name for this class
                objectTypes[value] = value.cls.name

        def registerArray(event, name, value):
            function = self.analyzer.lookupFunction(event)

            if name:
                cType = function.parameters[name].type
            else:
                cType = function.type

            # Extract an essential type for the array discarding all qualifiers and modifiers
            cType = Library.Type(cType.name)

            # Get the real, non-typedef'd type as well
            realType = library.resolveType(cType)

            # If this is a void type, use the original type instead
            if realType.name == "void":
                cType = arrayTypeMap[value.__class__]

            arrayTypes[arrayId(value)] = cType

            # If this is an object array, register the objects too
            if isinstance(value, Trace.ObjectArrayValue):
                for obj in value:
                    registerObject(event, name, obj)

        for event in trace.events:
            # OpenGL needs persistent arrays
            if event.name.startswith("gl"):
                usePersistentArrays = True

            for name, value in event.values.items():
                if isinstance(value, Trace.Object):
                    registerObject(event, name, value)
                elif isinstance(value, Trace.Array):
                    registerArray(event, name, value)

            # Collect the modified arrays for this event
            for array in event.modifiedArrays:
                a = arrayId(array)
                # Only consider the arrays we know about
                if a in arrayTypes:
                    arrayVariants[a].append(array)
            task.step()

        # Count the number of frames
        if frameMarkers:
            frameCount = len(frameMarkers) + 3
        else:
            frameCount = len([
                1 for event in trace.events
                if self.analyzer.lookupFunction(event).isFrameMarker
            ]) + 3

        # Add the header
        print >> traceFile, "/**"
        print >> traceFile, " *  C source generated from %d events (%d frames). " % (
            len(trace.events), frameCount)
        if insertCopyright:
            print >> traceFile, copyrightText
        print >> traceFile, " */"
        print >> traceFile, ""
        print >> traceFile, "/** A macro for copying data into an array */"
        print >> traceFile, "#define LOAD_ARRAY(TO, FROM, LENGTH) \\"
        print >> traceFile, indent, "{ \\"
        print >> traceFile, indent * 2, "int i; \\"
        print >> traceFile, indent * 2, "for (i = 0; i < (LENGTH); i++) \\"
        print >> traceFile, indent * 3, "(TO)[i] = (FROM)[i]; \\"
        print >> traceFile, indent, "}"
        print >> traceFile, ""

        # Insert any additional code specified in the configuration
        if "c_player_code" in config:
            for fileName in config["c_player_code"]:
                f = open(config.getRelativePath(fileName))
                print >> traceFile, f.read()
                f.close()

        # Add the header to the data file if we have one
        if dataFile:
            if dataFileFormat == "gcc":
                print >> dataFile, "#"
                print >> dataFile, "# GNU Assembler data file generated from %d events (%d frames). " % (
                    len(trace.events), frameCount)
                print >> dataFile, "#"
                print >> dataFile, ""
                print >> dataFile, ".section .data"
            else:  # rvct
                print >> dataFile, ";"
                print >> dataFile, "; RVCT Assembler data file generated from %d events (%d frames). " % (
                    len(trace.events), frameCount)
                print >> dataFile, ";"
                print >> dataFile, ""
                print >> dataFile, "    AREA ||.constdata||, DATA, READONLY, ALIGN=2"

        # Introduce objects
        print >> traceFile, "/* Objects */ "
        for objects in classes.values():
            for obj in objects.values():
                print >> traceFile, "static %s %s = (%s)0x%x;" % (
                    objectTypes[obj], objectId(obj), objectTypes[obj], obj.id)
        print >> traceFile, ""
        task.step()

        # Introduce arrays
        print >> traceFile, "/* %d arrays */ " % len(arrays)
        for i, array in enumerate(arrays.values()):
            a = arrayId(array)
            if usePersistentArrays:
                l = arraySizes[a]
                if not l:
                    self.analyzer.reportWarning("Empty array %s" % str(a))
                    l = 1
                print >> traceFile, "static %s %s_%s%d[%d];" % (
                    arrayTypes[a], str(
                        arrayTypes[a]).lower(), arrayPrefix, i, l)
            else:
                print >> traceFile, "static %s* %s_%s%d;" % (
                    arrayTypes[a], str(arrayTypes[a]).lower(), arrayPrefix, i)
        print >> traceFile, ""

        # Introduce unique array data
        print >> traceFile, "/* Array data */ "
        arrayData = []
        arrayMap = {}
        for variants in arrayVariants.values():
            for array in variants:
                # See if an equivalent array is already created
                for j, existingArray in enumerate(arrayData):
                    if existingArray == array and \
                       existingArray.__class__ == array.__class__:
                        arrayMap[id(array)] = j
                        break
                else:
                    arrayMap[id(array)] = len(arrayData)
                    arrayData.append(array)

        if not dataFile:
            # Inline data
            for i, array in enumerate(arrayData):
                if not len(array):
                    continue
                # Object arrays can't be initialized inline
                if isinstance(array, Trace.ObjectArrayValue):
                    print >> traceFile, "static %s %sData%d[%d];" % (
                        arrayTypes[arrayId(array)], arrayPrefix, i, len(array))
                    print >> traceFile, ""
                    continue
                elif usePersistentArrays:
                    print >> traceFile, "static const %s %sData%d[%d] = {" % (
                        arrayTypes[arrayId(array)], arrayPrefix, i, len(array))
                else:
                    print >> traceFile, "static %s %sData%d[%d] = {" % (
                        arrayTypes[arrayId(array)], arrayPrefix, i, len(array))
                print >> traceFile, indent,

                # Figure out the proper qualifier for the array elements
                qualifier = ""
                format = "s"
                if len(array):
                    if isinstance(array, Trace.FloatArrayValue):
                        format = qualifier = "f"
                    elif isinstance(array, Trace.DoubleArrayValue):
                        format = qualifier = "d"
                    elif isinstance(array, Trace.LongArrayValue):
                        format = qualifier = "l"

                for k, value in enumerate(array):
                    value = ("%%%s%s" % (format, qualifier)) % value
                    if k != len(array) - 1:
                        print >> traceFile, "%s," % value,
                        if not (k + 1) % 8:
                            print >> traceFile, ""
                            print >> traceFile, indent,
                    else:
                        print >> traceFile, value
                print >> traceFile, "};"
                print >> traceFile, ""
        else:  # External data
            for i, array in enumerate(arrayData):
                if not len(array):
                    continue
                if usePersistentArrays and not isinstance(
                        array, Trace.ObjectArrayValue):
                    print >> traceFile, "extern const %s %sData%d[%d];" % (
                        arrayTypes[arrayId(array)], arrayPrefix, i, len(array))
                else:
                    print >> traceFile, "extern %s %sData%d[%d];" % (
                        arrayTypes[arrayId(array)], arrayPrefix, i, len(array))

                # Object arrays can't be initialized inline
                if isinstance(array, Trace.ObjectArrayValue):
                    continue

                # Figure out the proper type code for the array elements
                if dataFileFormat == "gcc":
                    print >> dataFile, ".global %sData%d" % (arrayPrefix, i)
                    print >> dataFile, "%sData%d:" % (arrayPrefix, i)
                    if isinstance(array, Trace.FloatArrayValue):
                        typeCode = ".float"
                    elif isinstance(array, Trace.DoubleArrayValue):
                        typeCode = ".double"
                    elif isinstance(array, Trace.LongArrayValue):
                        typeCode = ".quad"
                    elif isinstance(array, Trace.ShortArrayValue):
                        typeCode = ".short"
                    elif isinstance(array, Trace.ByteArrayValue):
                        typeCode = ".byte"
                    elif isinstance(array, Trace.IntegerArrayValue):
                        typeCode = ".int"
                    else:
                        raise RuntimeError("Unknown array type")

                    # Write out the data
                    print >> dataFile, "%s %s" % (typeCode, ", ".join(
                        map(str, array)))
                else:  # rvct
                    print >> dataFile, "GLOBAL %sData%d" % (arrayPrefix, i)
                    print >> dataFile, "%sData%d" % (arrayPrefix, i)
                    if isinstance(array, Trace.FloatArrayValue):
                        typeCode = "DCFS"
                    elif isinstance(array, Trace.DoubleArrayValue):
                        typeCode = "DCFD"
                    elif isinstance(array, Trace.LongArrayValue):
                        typeCode = "DCQ"
                    elif isinstance(array, Trace.ShortArrayValue):
                        typeCode = "DCW"
                    elif isinstance(array, Trace.ByteArrayValue):
                        typeCode = "DCB"
                    elif isinstance(array, Trace.IntegerArrayValue):
                        typeCode = "DCD"
                    else:
                        raise RuntimeError("Unknown array type")

                    # Write out the data
                    prefix = "    %s " % typeCode
                    for j in xrange(0, len(array), 8):
                        values = array[j:j + 8]
                        print >> dataFile, prefix, ",".join(map(str, values))

        # Initialize the objects
        print >> traceFile, "static void %s(void* %s)" % (initFuncName,
                                                          playerArgument)
        print >> traceFile, "{"

        def getObjectAttributeValue(attr):
            if isinstance(attr, Trace.Array):
                # Only strings are supported so far
                assert isinstance(attr, Trace.ByteArrayValue)
                s = "".join((chr(c) for c in attr))
                s = s.replace("\r", "\\r")
                s = s.replace("\t", "\\t")
                s = s.rstrip("\x00")
                lines = s.split("\n")
                return "\n".join(('"%s\\n"' % l for l in lines))
            return str(attr)

        for objects in classes.values():
            for obj in objects.values():
                # If the object has attributes or it wasn't created from a return value, ask the user to create it
                cClass = library.classes.get(obj.cls.name)
                if obj.attrs or (not obj in outValueObjects and cClass
                                 and cClass.overridable):
                    print >> traceFile, indent, "/* %s attributes: %s */" % (
                        obj.cls.name, ", ".join(obj.attrs.keys()))
                    if obj.attrs:
                        attrs = ", ".join(
                            map(getObjectAttributeValue, obj.attrs.values()))
                        print >> traceFile, indent, "%s = create%s%d(%s, %s);" % (
                            objectId(obj), obj.cls.name, len(obj.attrs) + 1,
                            playerArgument, attrs)
                    else:
                        print >> traceFile, indent, "%s = create%s1(%s);" % (
                            objectId(obj), obj.cls.name, playerArgument)
        print >> traceFile, "}"
        print >> traceFile, ""

        # Uninitialize the objects
        print >> traceFile, "static void %s(void* %s)" % (uninitFuncName,
                                                          playerArgument)
        print >> traceFile, "{"
        for objects in classes.values():
            for obj in objects.values():
                # If the object has attributes or it wasn't created from a return value, ask the user to destroy it
                cClass = library.classes.get(obj.cls.name)
                if obj.attrs or (not obj in outValueObjects and cClass
                                 and cClass.overridable):
                    print >> traceFile, indent, "destroy%s2(%s, %s);" % (
                        obj.cls.name, playerArgument, objectId(obj))
        print >> traceFile, "}"
        print >> traceFile, ""

        # Add the events
        task.finish()
        task = Task.startTask("c-export", "Generating source",
                              len(trace.events))
        frameNumber = 0
        frameFunctions = ["%s0" % frameFuncName]
        activeArrays = dict([(a, None) for a in arrays.keys()])

        # Open the frame function
        print >> traceFile, "static void %s0(void* %s)" % (frameFuncName,
                                                           playerArgument)
        print >> traceFile, "{"

        for event in trace.events:
            function = self.analyzer.lookupFunction(event)

            # Modify objects
            for obj in event.modifiedObjects:
                # Check the the object was really modified
                if obj.attrs and obj.attrs != classes[obj.cls][objectId(
                        obj)].attrs:
                    attrs = ", ".join(
                        map(getObjectAttributeValue, obj.attrs.values()))
                    print >> traceFile, indent, "/* %s attributes: %s */" % (
                        obj.cls.name, ", ".join(obj.attrs.keys()))
                    print >>traceFile, indent, "%s = modify%s%d(%s, %s, %s);" % \
                      (objectId(obj), obj.cls.name, len(obj.attrs) + 2, playerArgument, objectId(obj), attrs)
                    classes[obj.cls][objectId(obj)].attrs = obj.attrs

            # Modify arrays
            for array in event.modifiedArrays:
                # Load the correct data into the array
                a = arrayId(array)

                # If this array is not used anywhere, skip it
                if not id(array) in arrayMap:
                    continue

                toArray = arrays.index(a)
                fromArray = arrayMap[id(array)]

                # Don't reload the same data
                if activeArrays[a] == fromArray:
                    continue

                # Ignore empty arrays
                if not len(array):
                    continue

                activeArrays[a] = fromArray
                # Insert new objects directly into the array
                if isinstance(array, Trace.ObjectArrayValue):
                    for i, obj in enumerate(array):
                        print >>traceFile, indent, "%s_%s%d[%d] = %s;" % \
                        (str(arrayTypes[a]).lower(), arrayPrefix, toArray, i, objectId(obj))
                elif usePersistentArrays:
                    print >>traceFile, indent, "LOAD_ARRAY(%s_%s%d, %sData%d, %d);" % \
                      (str(arrayTypes[a]).lower(), arrayPrefix, toArray, arrayPrefix, fromArray, len(array))
                else:
                    print >>traceFile, indent, "%s_%s%d = %sData%d;" % \
                      (str(arrayTypes[a]).lower(), arrayPrefix, toArray, arrayPrefix, fromArray)

            # Collect the arguments
            args = []
            returnValue = None
            for name, value in event.values.items():
                valueType = name and function.parameters[
                    name].type or function.type
                if value is None:
                    value = "(%s)0" % valueType
                elif isinstance(value, Trace.Array):
                    # If this array can be modified by the function, mark it as lost
                    if not valueType.isConstant(
                    ) and value in event.modifiedArrays:
                        a = arrayId(value)
                        activeArrays[a] = None
                    if not value.id:
                        value = "(%s)0" % valueType
                    else:
                        a = arrayId(value)
                        value = "(%s)%s_%s%d" % (valueType, str(
                            arrayTypes[a]).lower(), arrayPrefix,
                                                 arrays.index(a))
                elif isinstance(value, Trace.Object):
                    value = str(objectId(value))
                elif isinstance(value, Trace.UnknownPhrase):
                    value = "(%s)NULL" % valueType
                else:
                    value = StringUtils.decorateValue(library, function, name,
                                                      value)
                    if isinstance(value, Trace.FloatValue):
                        value = str(value) + "f"
                    elif isinstance(value, Trace.DoubleValue):
                        value = str(value) + "d"
                    elif isinstance(value, Trace.LongValue):
                        value = str(value) + "l"

                    # Do a cast if this is actually a pointer parameter (e.g. 'ptr' in glVertexAttribPointer)
                    if name and library.isPointerType(
                            function.parameters[name].type):
                        value = "(%s)%s" % (valueType, value)

                    # If the real C type is unsigned and we have a negative value, do a cast
                    try:
                        if name and "unsigned" in str(
                                library.resolveType(function.parameters[name].
                                                    type)) and int(value) < 0:
                            value = "(%s)%s" % (function.parameters[name].type,
                                                value)
                    except ValueError:
                        # Not an integer
                        pass

                # HACK: eglGetDisplay(0) -> eglGetDisplay(EGL_DEFAULT_DISPLAY)
                if event.name == "eglGetDisplay" and name and str(
                        value) == "0":
                    value = "EGL_DEFAULT_DISPLAY"

                # Make sure we have a meaningful parameter value
                assert len(str(value))

                if name:
                    args.append(str(value))
                else:
                    returnValue = value

            # Truncated event stream?
            if not len(args) == len(function.parameters):
                self.analyzer.reportWarning("Truncated call to %s(%s)" %
                                            (event.name, ", ".join(args)))
                print >> traceFile, indent, "/* truncated call to %s(%s) */" % (
                    event.name, ", ".join(args))
                continue

            # Save the return value if needed
            returnObject = event.values.get(None, None)
            if isinstance(returnObject, Trace.Object):
                print >> traceFile, indent, "%s =" % objectId(returnObject),
            else:
                print >> traceFile, indent,

            args = ", ".join(args)
            print >> traceFile, "%s(%s);" % (event.name, args)

            # Apply modifications to object arrays
            for array in event.modifiedArrays:
                if isinstance(array, Trace.ObjectArrayValue):
                    for i, obj in enumerate(array):
                        a = arrayId(array)
                        fromArray = arrays.index(a)
                        print >>traceFile, indent, "%s = %s_%s%d[%d];" % \
                        (objectId(obj), str(arrayTypes[a]).lower(), arrayPrefix, fromArray, i)

            if (not frameMarkers
                    and function.isFrameMarker) or event in frameMarkers:
                frameNumber += 1
                name = "%s%d" % (frameFuncName, frameNumber)
                print >> traceFile, "}"
                print >> traceFile, ""
                print >> traceFile, "/**"
                print >> traceFile, " *  Frame #%d" % frameNumber
                print >> traceFile, " */"
                print >> traceFile, "static void %s(void* %s)" % (
                    name, playerArgument)
                print >> traceFile, "{"
                frameFunctions.append(name)

            task.step()
        print >> traceFile, "}"
        print >> traceFile, ""

        # Create the playback function
        print >> traceFile, "/**"
        print >> traceFile, " *  Play back all trace frames."
        print >> traceFile, " *  @param %s Optional user data pointer" % (
            playerArgument)
        print >> traceFile, " */"
        print >> traceFile, "static void %s(void* %s)" % (playFuncName,
                                                          playerArgument)
        print >> traceFile, "{"
        print >> traceFile, indent, "%s(%s);" % (initFuncName, playerArgument)
        for name in frameFunctions:
            print >> traceFile, indent, "%s(%s);" % (name, playerArgument)
        print >> traceFile, indent, "%s(%s);" % (uninitFuncName,
                                                 playerArgument)
        print >> traceFile, "}"
        print >> traceFile, ""

        # Create the playback function for single frame playback
        print >> traceFile, "/**"
        print >> traceFile, " *  Play back a single frame of the trace."
        print >> traceFile, " *  @param %s Optional user data pointer" % (
            playerArgument)
        print >> traceFile, " *  @param frame Zero-based number of frame to play"
        print >> traceFile, " *  @returns 1 if the frame number was valid, 0 otherwise"
        print >> traceFile, " */"
        print >> traceFile, "static int %s(void* %s, int frame)" % (
            playFrameFuncName, playerArgument)
        print >> traceFile, "{"
        print >> traceFile, indent, "switch (frame)"
        print >> traceFile, indent, "{"
        print >> traceFile, indent * 2, "case %6d: %s(%s); break;" % (
            0, initFuncName, playerArgument)
        for i, name in enumerate(frameFunctions):
            print >> traceFile, indent * 2, "case %6d: %s(%s); break;" % (
                i + 1, name, playerArgument)
        print >> traceFile, indent * 2, "case %6d: %s(%s); break;" % (
            len(frameFunctions) + 1, uninitFuncName, playerArgument)
        print >> traceFile, indent * 2, "default: return 0;"
        print >> traceFile, indent, "}"
        print >> traceFile, indent, "return 1;"
        print >> traceFile, "}"

        # Close the data file
        if dataFile:
            dataFile.close()

        # All done
        task.finish()
Beispiel #6
0
  def saveTrace(self, trace, traceFile, 
                dataFileName       = None,
                dataFileFormat     = "rvct",
                frameMarkers       = [], 
                initFuncName       = "init",
                uninitFuncName     = "uninit",
                playFuncName       = "play",
                playFrameFuncName  = "playFrame",
                frameFuncName      = "frame",
                arrayPrefix        = "array",
                playerArgument     = "context",
                insertCopyright    = True):
    try:
      library = self.analyzer.project.targets["code"].library
      config  = self.analyzer.project.config
    except (AttributeError, KeyError):
      raise RuntimeError("API configuration not found.")

    def arrayId(array):
      assert isinstance(array, Trace.Array)
      return (array.__class__, array.id)

    def objectId(obj):
      assert isinstance(obj, Trace.Object)
      return "%s_%x_%x" % (obj.cls.name.lower(), obj.ns, obj.id)
      
    task   = Task.startTask("c-export", "Formatting source", len(trace.events))
    indent = " " * 3
    
    # Collect all values for all events
    task = Task.startTask("c-export", "Collecting data", len(trace.events))
    values = []
    [values.extend(e.values.values()) for e in trace.events]

    # Collect arrays
    arrays        = OrderedDict([(arrayId(v), v) for v in reversed(values) if isinstance(v, Trace.Array)])
    
    # Check that the external data format is supported
    if dataFileName:
      assert dataFileName.endswith(".s"), "Unsupported external data file type. Use one of: s"
      assert dataFileFormat in ("gcc", "rvct"), "Unsupported external data format. Use one of: gcc, rvct"
      dataFile = open(dataFileName, "w")
    else:
      dataFile = None

    # Calculate maximum sizes of arrays
    arraySizes = dict([(a, 0) for a in arrays.keys()])
    for value in values:
      if isinstance(value, Trace.Array):
        a = arrayId(value)
        arraySizes[a] = max(len(value), arraySizes[a])
    
    # Figure out the C types of arrays and objects
    classes             = {}
    objectTypes         = {}
    arrayTypes          = {}
    outValueObjects     = set()     # Objects that are acquired through a function
    arrayVariants       = DefaultDict(list)
    usePersistentArrays = False     # Use arrays whose contents must be kept up to date
                                    # even after passing them to the API

    def registerObject(event, name, value):
      if not value.cls in classes:
        classes[value.cls] = {}
      function = self.analyzer.lookupFunction(event)
      # Object has already been registered
      if not name or function.parameters[name].isOut:
        outValueObjects.add(value)
      if objectId(value) in classes[value.cls]:
        return
      classes[value.cls][objectId(value)] = value
      for cType, nativeTypeName in library.typeMap.items():
        if cType.name == value.cls.name:
          objectTypes[value] = cType
          break
      else:
        self.analyzer.reportWarning("Unknown class: <%s>" % value.cls.name)
        # Create a fake type name for this class
        objectTypes[value] = value.cls.name

    def registerArray(event, name, value):
      function = self.analyzer.lookupFunction(event)
      
      if name:
        cType = function.parameters[name].type
      else:
        cType = function.type
      
      # Extract an essential type for the array discarding all qualifiers and modifiers
      cType = Library.Type(cType.name)
      
      # Get the real, non-typedef'd type as well
      realType = library.resolveType(cType)
      
      # If this is a void type, use the original type instead
      if realType.name == "void":
        cType = arrayTypeMap[value.__class__]
        
      arrayTypes[arrayId(value)] = cType

      # If this is an object array, register the objects too
      if isinstance(value, Trace.ObjectArrayValue):
        for obj in value:
          registerObject(event, name, obj)

    for event in trace.events:
      # OpenGL needs persistent arrays
      if event.name.startswith("gl"):
        usePersistentArrays = True

      for name, value in event.values.items():
        if isinstance(value, Trace.Object):
          registerObject(event, name, value)
        elif isinstance(value, Trace.Array):
          registerArray(event, name, value)
      
      # Collect the modified arrays for this event
      for array in event.modifiedArrays:
        a = arrayId(array)
        # Only consider the arrays we know about
        if a in arrayTypes:
          arrayVariants[a].append(array)
      task.step()
      
    # Count the number of frames
    if frameMarkers:
      frameCount = len(frameMarkers) + 3
    else:
      frameCount = len([1 for event in trace.events if self.analyzer.lookupFunction(event).isFrameMarker]) + 3
      
    # Add the header
    print >>traceFile, "/**"
    print >>traceFile, " *  C source generated from %d events (%d frames). " % (len(trace.events), frameCount)
    if insertCopyright:
        print >>traceFile, copyrightText
    print >>traceFile, " */"
    print >>traceFile, ""
    print >>traceFile, "/** A macro for copying data into an array */"
    print >>traceFile, "#define LOAD_ARRAY(TO, FROM, LENGTH) \\"
    print >>traceFile, indent, "{ \\"
    print >>traceFile, indent * 2, "int i; \\"
    print >>traceFile, indent * 2, "for (i = 0; i < (LENGTH); i++) \\"
    print >>traceFile, indent * 3, "(TO)[i] = (FROM)[i]; \\"
    print >>traceFile, indent, "}"
    print >>traceFile, ""
    
    # Insert any additional code specified in the configuration
    if "c_player_code" in config:
      for fileName in config["c_player_code"]:
        f = open(config.getRelativePath(fileName))
        print >>traceFile, f.read()
        f.close()

    # Add the header to the data file if we have one
    if dataFile:
      if dataFileFormat == "gcc":
        print >>dataFile, "#"
        print >>dataFile, "# GNU Assembler data file generated from %d events (%d frames). " % (len(trace.events), frameCount)
        print >>dataFile, "#"
        print >>dataFile, ""
        print >>dataFile, ".section .data"
      else: # rvct
        print >>dataFile, ";"
        print >>dataFile, "; RVCT Assembler data file generated from %d events (%d frames). " % (len(trace.events), frameCount)
        print >>dataFile, ";"
        print >>dataFile, ""
        print >>dataFile, "    AREA ||.constdata||, DATA, READONLY, ALIGN=2"

    # Introduce objects
    print >>traceFile, "/* Objects */ "
    for objects in classes.values():
      for obj in objects.values():
        print >>traceFile, "static %s %s = (%s)0x%x;" % (objectTypes[obj], objectId(obj), objectTypes[obj], obj.id)
    print >>traceFile, ""
    task.step()
    
    # Introduce arrays
    print >>traceFile, "/* %d arrays */ " % len(arrays)
    for i, array in enumerate(arrays.values()):
      a = arrayId(array)
      if usePersistentArrays:
        l = arraySizes[a]
        if not l:
          self.analyzer.reportWarning("Empty array %s" % str(a))
          l = 1
        print >>traceFile, "static %s %s_%s%d[%d];" % (arrayTypes[a], str(arrayTypes[a]).lower(), arrayPrefix, i, l)
      else:
        print >>traceFile, "static %s* %s_%s%d;" % (arrayTypes[a], str(arrayTypes[a]).lower(), arrayPrefix, i)
    print >>traceFile, ""

    # Introduce unique array data
    print >>traceFile, "/* Array data */ "
    arrayData = []
    arrayMap  = {}
    for variants in arrayVariants.values():
      for array in variants:
        # See if an equivalent array is already created
        for j, existingArray in enumerate(arrayData):
          if existingArray == array and \
             existingArray.__class__ == array.__class__:
            arrayMap[id(array)] = j
            break
        else:
          arrayMap[id(array)] = len(arrayData)
          arrayData.append(array)

    if not dataFile:
      # Inline data
      for i, array in enumerate(arrayData):
        if not len(array):
          continue
        # Object arrays can't be initialized inline
        if isinstance(array, Trace.ObjectArrayValue):
          print >>traceFile, "static %s %sData%d[%d];" % (arrayTypes[arrayId(array)], arrayPrefix, i, len(array))
          print >>traceFile, ""
          continue
        elif usePersistentArrays:
          print >>traceFile, "static const %s %sData%d[%d] = {" % (arrayTypes[arrayId(array)], arrayPrefix, i, len(array))
        else:
          print >>traceFile, "static %s %sData%d[%d] = {" % (arrayTypes[arrayId(array)], arrayPrefix, i, len(array))
        print >>traceFile, indent,
        
        # Figure out the proper qualifier for the array elements
        qualifier = ""
        format    = "s"
        if len(array):
          if isinstance(array, Trace.FloatArrayValue):
            format = qualifier = "f"
          elif isinstance(array, Trace.DoubleArrayValue):
            format = qualifier = "d"
          elif isinstance(array, Trace.LongArrayValue):
            format = qualifier = "l"
      
        for k, value in enumerate(array):
          value = ("%%%s%s" % (format, qualifier)) % value
          if k != len(array) - 1:
            print >>traceFile, "%s," % value,
            if not (k + 1) % 8:
              print >>traceFile, ""
              print >>traceFile, indent,
          else:
            print >>traceFile, value
        print >>traceFile, "};"
        print >>traceFile, ""
    else: # External data
      for i, array in enumerate(arrayData):
        if not len(array):
          continue
        if usePersistentArrays and not isinstance(array, Trace.ObjectArrayValue):
          print >>traceFile, "extern const %s %sData%d[%d];" % (arrayTypes[arrayId(array)], arrayPrefix, i, len(array))
        else:
          print >>traceFile, "extern %s %sData%d[%d];" % (arrayTypes[arrayId(array)], arrayPrefix, i, len(array))
        
        # Object arrays can't be initialized inline
        if isinstance(array, Trace.ObjectArrayValue):
          continue

        # Figure out the proper type code for the array elements
        if dataFileFormat == "gcc":
          print >>dataFile,  ".global %sData%d" % (arrayPrefix, i)
          print >>dataFile,  "%sData%d:" % (arrayPrefix, i)
          if isinstance(array, Trace.FloatArrayValue):
            typeCode = ".float"
          elif isinstance(array, Trace.DoubleArrayValue):
            typeCode = ".double"
          elif isinstance(array, Trace.LongArrayValue):
            typeCode = ".quad"
          elif isinstance(array, Trace.ShortArrayValue):
            typeCode = ".short"
          elif isinstance(array, Trace.ByteArrayValue):
            typeCode = ".byte"
          elif isinstance(array, Trace.IntegerArrayValue):
            typeCode = ".int"
          else:
            raise RuntimeError("Unknown array type")

          # Write out the data
          print >>dataFile, "%s %s" % (typeCode, ", ".join(map(str, array)))
        else: # rvct
          print >>dataFile, "GLOBAL %sData%d" % (arrayPrefix, i)
          print >>dataFile, "%sData%d" % (arrayPrefix, i)
          if isinstance(array, Trace.FloatArrayValue):
            typeCode = "DCFS"
          elif isinstance(array, Trace.DoubleArrayValue):
            typeCode = "DCFD"
          elif isinstance(array, Trace.LongArrayValue):
            typeCode = "DCQ"
          elif isinstance(array, Trace.ShortArrayValue):
            typeCode = "DCW"
          elif isinstance(array, Trace.ByteArrayValue):
            typeCode = "DCB"
          elif isinstance(array, Trace.IntegerArrayValue):
            typeCode = "DCD"
          else:
            raise RuntimeError("Unknown array type")

          # Write out the data
          prefix = "    %s " % typeCode
          for j in xrange(0, len(array), 8):
            values = array[j:j + 8]
            print >>dataFile, prefix, ",".join(map(str, values))

    # Initialize the objects
    print >>traceFile, "static void %s(void* %s)" % (initFuncName, playerArgument)
    print >>traceFile, "{"

    def getObjectAttributeValue(attr):
      if isinstance(attr, Trace.Array):
        # Only strings are supported so far
        assert isinstance(attr, Trace.ByteArrayValue)
        s = "".join((chr(c) for c in attr))
        s = s.replace("\r", "\\r")
        s = s.replace("\t", "\\t")
        s = s.rstrip("\x00")
        lines = s.split("\n")
        return "\n".join(('"%s\\n"' % l for l in lines))
      return str(attr)

    for objects in classes.values():
      for obj in objects.values():
        # If the object has attributes or it wasn't created from a return value, ask the user to create it
        cClass = library.classes.get(obj.cls.name)
        if obj.attrs or (not obj in outValueObjects and cClass and cClass.overridable):
          print >>traceFile, indent, "/* %s attributes: %s */" % (obj.cls.name, ", ".join(obj.attrs.keys()))
          if obj.attrs:
            attrs = ", ".join(map(getObjectAttributeValue, obj.attrs.values()))
            print >>traceFile, indent, "%s = create%s%d(%s, %s);" % (objectId(obj), obj.cls.name, len(obj.attrs) + 1, playerArgument, attrs)
          else:
            print >>traceFile, indent, "%s = create%s1(%s);" % (objectId(obj), obj.cls.name, playerArgument)
    print >>traceFile, "}"
    print >>traceFile, ""

    # Uninitialize the objects
    print >>traceFile, "static void %s(void* %s)" % (uninitFuncName, playerArgument)
    print >>traceFile, "{"
    for objects in classes.values():
      for obj in objects.values():
        # If the object has attributes or it wasn't created from a return value, ask the user to destroy it
        cClass = library.classes.get(obj.cls.name)
        if obj.attrs or (not obj in outValueObjects and cClass and cClass.overridable):
          print >>traceFile, indent, "destroy%s2(%s, %s);" % (obj.cls.name, playerArgument, objectId(obj))
    print >>traceFile, "}"
    print >>traceFile, ""
            
    # Add the events
    task.finish()
    task = Task.startTask("c-export", "Generating source", len(trace.events))
    frameNumber = 0
    frameFunctions = ["%s0" % frameFuncName]
    activeArrays = dict([(a, None) for a in arrays.keys()])

    # Open the frame function
    print >>traceFile, "static void %s0(void* %s)" % (frameFuncName, playerArgument)
    print >>traceFile, "{"
    
    for event in trace.events:
      function = self.analyzer.lookupFunction(event)
      
      # Modify objects
      for obj in event.modifiedObjects:
        # Check the the object was really modified
        if obj.attrs and obj.attrs != classes[obj.cls][objectId(obj)].attrs:
          attrs = ", ".join(map(getObjectAttributeValue, obj.attrs.values()))
          print >>traceFile, indent, "/* %s attributes: %s */" % (obj.cls.name, ", ".join(obj.attrs.keys()))
          print >>traceFile, indent, "%s = modify%s%d(%s, %s, %s);" % \
            (objectId(obj), obj.cls.name, len(obj.attrs) + 2, playerArgument, objectId(obj), attrs)
          classes[obj.cls][objectId(obj)].attrs = obj.attrs

      # Modify arrays
      for array in event.modifiedArrays:
        # Load the correct data into the array
        a            = arrayId(array)
        
        # If this array is not used anywhere, skip it
        if not id(array) in arrayMap:
          continue
        
        toArray      = arrays.index(a)
        fromArray    = arrayMap[id(array)]

        # Don't reload the same data        
        if activeArrays[a] == fromArray:
          continue
          
        # Ignore empty arrays
        if not len(array):
          continue
        
        activeArrays[a] = fromArray
        # Insert new objects directly into the array
        if isinstance(array, Trace.ObjectArrayValue):
          for i, obj in enumerate(array):
            print >>traceFile, indent, "%s_%s%d[%d] = %s;" % \
            (str(arrayTypes[a]).lower(), arrayPrefix, toArray, i, objectId(obj))
        elif usePersistentArrays:
          print >>traceFile, indent, "LOAD_ARRAY(%s_%s%d, %sData%d, %d);" % \
            (str(arrayTypes[a]).lower(), arrayPrefix, toArray, arrayPrefix, fromArray, len(array))
        else:
          print >>traceFile, indent, "%s_%s%d = %sData%d;" % \
            (str(arrayTypes[a]).lower(), arrayPrefix, toArray, arrayPrefix, fromArray)
      
      # Collect the arguments
      args        = []      
      returnValue = None
      for name, value in event.values.items():
        valueType = name and function.parameters[name].type or function.type
        if value is None:
          value = "(%s)0" % valueType
        elif isinstance(value, Trace.Array):
          # If this array can be modified by the function, mark it as lost
          if not valueType.isConstant() and value in event.modifiedArrays:
            a = arrayId(value)
            activeArrays[a] = None
          if not value.id:
            value = "(%s)0" % valueType
          else:
            a         = arrayId(value)
            value     = "(%s)%s_%s%d" % (valueType, str(arrayTypes[a]).lower(), arrayPrefix, arrays.index(a))
        elif isinstance(value, Trace.Object):
          value = str(objectId(value))
        elif isinstance(value, Trace.UnknownPhrase):
          value = "(%s)NULL" % valueType
        else:
          value = StringUtils.decorateValue(library, function, name, value)
          if isinstance(value, Trace.FloatValue):
            value = str(value) + "f"
          elif isinstance(value, Trace.DoubleValue):
            value = str(value) + "d"
          elif isinstance(value, Trace.LongValue):
            value = str(value) + "l"

          # Do a cast if this is actually a pointer parameter (e.g. 'ptr' in glVertexAttribPointer)
          if name and library.isPointerType(function.parameters[name].type):
            value = "(%s)%s" % (valueType, value)

          # If the real C type is unsigned and we have a negative value, do a cast
          try:
            if name and "unsigned" in str(library.resolveType(function.parameters[name].type)) and int(value) < 0:
              value = "(%s)%s" % (function.parameters[name].type, value)
          except ValueError:
            # Not an integer
            pass

        # HACK: eglGetDisplay(0) -> eglGetDisplay(EGL_DEFAULT_DISPLAY)
        if event.name == "eglGetDisplay" and name and str(value) == "0":
          value = "EGL_DEFAULT_DISPLAY"

        # Make sure we have a meaningful parameter value
        assert len(str(value))
        
        if name:
          args.append(str(value))
        else:
          returnValue = value
          
      # Truncated event stream?
      if not len(args) == len(function.parameters):
        self.analyzer.reportWarning("Truncated call to %s(%s)" % (event.name, ", ".join(args)))
        print >>traceFile, indent, "/* truncated call to %s(%s) */" % (event.name, ", ".join(args))
        continue

      # Save the return value if needed
      returnObject = event.values.get(None, None)
      if isinstance(returnObject, Trace.Object):
        print >>traceFile, indent, "%s =" % objectId(returnObject),
      else:
        print >>traceFile, indent,

      args = ", ".join(args)
      print >>traceFile, "%s(%s);" % (event.name, args)

      # Apply modifications to object arrays
      for array in event.modifiedArrays:
        if isinstance(array, Trace.ObjectArrayValue):
          for i, obj in enumerate(array):
            a = arrayId(array)
            fromArray = arrays.index(a)
            print >>traceFile, indent, "%s = %s_%s%d[%d];" % \
            (objectId(obj), str(arrayTypes[a]).lower(), arrayPrefix, fromArray, i)

      if (not frameMarkers and function.isFrameMarker) or event in frameMarkers:
        frameNumber += 1
        name = "%s%d" % (frameFuncName, frameNumber)
        print >>traceFile, "}"
        print >>traceFile, ""
        print >>traceFile, "/**"
        print >>traceFile, " *  Frame #%d" % frameNumber
        print >>traceFile, " */"
        print >>traceFile, "static void %s(void* %s)" % (name, playerArgument)
        print >>traceFile, "{"
        frameFunctions.append(name)
      
      task.step()
    print >>traceFile, "}"
    print >>traceFile, ""

    # Create the playback function
    print >>traceFile, "/**"
    print >>traceFile, " *  Play back all trace frames."
    print >>traceFile, " *  @param %s Optional user data pointer" % (playerArgument)
    print >>traceFile, " */"
    print >>traceFile, "static void %s(void* %s)" % (playFuncName, playerArgument)
    print >>traceFile, "{"
    print >>traceFile, indent, "%s(%s);" % (initFuncName, playerArgument)
    for name in frameFunctions:
      print >>traceFile, indent, "%s(%s);" % (name, playerArgument)
    print >>traceFile, indent, "%s(%s);" % (uninitFuncName, playerArgument)
    print >>traceFile, "}"
    print >>traceFile, ""

    # Create the playback function for single frame playback
    print >>traceFile, "/**"
    print >>traceFile, " *  Play back a single frame of the trace."
    print >>traceFile, " *  @param %s Optional user data pointer" % (playerArgument)
    print >>traceFile, " *  @param frame Zero-based number of frame to play"
    print >>traceFile, " *  @returns 1 if the frame number was valid, 0 otherwise"
    print >>traceFile, " */"
    print >>traceFile, "static int %s(void* %s, int frame)" % (playFrameFuncName, playerArgument)
    print >>traceFile, "{"
    print >>traceFile, indent, "switch (frame)"
    print >>traceFile, indent, "{"
    print >>traceFile, indent * 2, "case %6d: %s(%s); break;" % (0, initFuncName, playerArgument)
    for i, name in enumerate(frameFunctions):
      print >>traceFile, indent * 2, "case %6d: %s(%s); break;" % (i + 1, name, playerArgument)
    print >>traceFile, indent * 2, "case %6d: %s(%s); break;" % (len(frameFunctions) + 1, uninitFuncName, playerArgument)
    print >>traceFile, indent * 2, "default: return 0;"
    print >>traceFile, indent, "}"
    print >>traceFile, indent, "return 1;"
    print >>traceFile, "}"
    
    # Close the data file
    if dataFile:
      dataFile.close()
    
    # All done
    task.finish()
Beispiel #7
0
 def __init__(self, id, ns, cls):
     self.id = id
     self.ns = ns
     self.cls = cls
     self.attrs = OrderedDict()