def setUp(self): # Create a configuration self.config = Config.Config() self.config["library"] = "testlib" # Create a basic library for testing self.library = Library.Library("test") voidType = Library.Type("void") intType = Library.Type("int") f = Library.Function("func1", voidType) p = Library.Parameter("parameter", intType) f.parameters[p.name] = p self.library.functions[f.name] = f f = Library.Function("func2", intType) p1 = Library.Parameter("p1", intType) p2 = Library.Parameter("p2", intType) f.parameters[p1.name] = p1 f.parameters[p2.name] = p2 self.library.functions[f.name] = f # Register some types self.library.typeMap["int"] = "int" self.library.typeMap["void"] = "void" # Define platform properties self.platform = SymbianPlatform(self.config)
def testGlTracerGeneration(self): # Parse the preprocessed GL header l = Library.Library("GL", "libgles_cm_orig.dll") l.merge(Parser.parseSource(open("data/gl-cpp.h").read())) l.merge(Parser.parseSource(open("data/egl-cpp.h").read())) defFile = open("data/opengles11u.def").read() for function, ordinal in Parser.parseDefFile(defFile): if function in l.functions: l.functions[function].ordinal = ordinal # Add a custom function hook customSource = """ GLenum xglGetError(void) { wtf(); } """ l.merge(Parser.parseSource(customSource)) T = Library.Type # GL types l.typeMap[T("GLenum")] = "int" l.typeMap[T("GLint")] = "int" l.typeMap[T("GLintptr")] = "int" l.typeMap[T("GLuint")] = "int" l.typeMap[T("GLboolean")] = "int" l.typeMap[T("GLbitfield")] = "int" l.typeMap[T("GLsizei")] = "int" l.typeMap[T("GLsizeiptr")] = "int" l.typeMap[T("GLfixed")] = "int" l.typeMap[T("GLclampx")] = "int" l.typeMap[T("GLubyte")] = "byte" l.typeMap[T("GLshort")] = "short" l.typeMap[T("GLclampf")] = "float" l.typeMap[T("GLfloat")] = "float" l.typeMap[T("void")] = "void" # EGL types l.typeMap[T("EGLboolean")] = "int" l.typeMap[T("EGLint")] = "int" l.typeMap[T("EGLDisplay")] = "int" l.typeMap[T("EGLSurface")] = "int" l.typeMap[T("EGLContext")] = "int" l.typeMap[T("EGLConfig")] = "int" l.typeMap[T("EGLBoolean")] = "int" l.typeMap[T("NativeDisplayType")] = "int" l.typeMap[T("NativeWindowType")] = "pointer" l.typeMap[T("NativePixmapType")] = "pointer" # Mark eglTerminate as a terminator l.functions["eglTerminate"].isTerminator = True g = TracerGenerator(self.config, self.platform, [l]) g.generate(open("generator_test_output.txt", "w"))
def processEvent(self, event, implicitStateValue = None): assert event.name in self.library.functions, "Function not found in library: %s" % event.name function = self.library.functions[event.name] stateModifiers = [] def getStatePathForValue(name): if name is None: relation = function.retStateRelation else: relation = function.parameters[name].stateRelation if relation: try: return relation.path except AttributeError: # The copy relation does it this way return relation.destPath # Sort the values by their state paths (shortest first) values = event.values.items() values.sort(cmp = lambda v1, v2: cmp(getStatePathForValue(v1[0]), getStatePathForValue(v2[0]))) for name, value in values: # Get the state path if name is None: relation = function.retStateRelation else: relation = function.parameters[name].stateRelation if self.decorateValues: value = StringUtils.decorateValue(self.library, function, name, value) # Write the state value if relation and self._updateState(event, relation, value): stateModifiers.append(name) for relation in function.stateRelations: if isinstance(relation, Library.StateRelationModify): if implicitStateValue is None: # Use a special placeholder value for completely unknown state values self._updateState(event, relation, ImplicitStateValue()) else: # When we know the exact value, this relation becomes a "set" relation self._updateState(event, Library.StateRelationSet(relation.path), implicitStateValue) elif relation.__class__ in (Library.StateRelationSet, Library.StateRelationGet, Library.StateRelationCopy): self._updateState(event, relation, None) else: raise RuntimeError("Unknown state relation: %s" % relation) if self.collectEffectiveEvents and self.isStateAccessingEvent(event): self.effectiveEvents.add(event) return stateModifiers
def testDefFile(self): l = Parser.parseSource(testHeader) # FIXME: hardcode the function pointer since we don't parse those yet l.functions["funcPointer"] = Library.Function("funcPointer", "void") for function, ordinal in Parser.parseDefFile(testDefFile): l.functions[function].ordinal = ordinal # check that all ordinals were read for f in l.functions.values(): assert f.ordinal is not None # check overlapping ordinals in input try: Parser.parseDefFile(testBadDefFile) self.fail("ValueError not raised.") except ValueError: pass
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)
def parseSource(source): """ Parses the given source string and adds all found functions to the library. @param header: Source text @returns: A library containing the parsed functions """ task = Task.startTask("parser", "Parsing type declarations", len(source)) library = Library() # Read the type definitions typedefs = [] for match, pos, l in typedefDecl.scanString(source): task.updateProgress(pos) # Map enumerations to integers if match[0] == "enum": name = match[-1] type = Type("int") for i, e in enumerate(match[1]): enumeration, value = e if value is None: value = i type.addSymbolicConstant(enumeration, value) library.constants[enumeration] = value else: name, type = match[0] library.typeDefs[Type(name)] = type task.finish() # Read preprocessor constants task = Task.startTask("parser", "Parsing preprocessor constants", len(source)) for match, pos, l in preprocessorCommand.scanString(source): task.updateProgress(pos) # Only look for #define if match.command != "define": continue # Only accept integral constants try: value = parseInteger(None, None, [match.value]) except ValueError: continue library.constants[match.name] = value task.finish() def where(pos): return "Line %d, column %s" % (lineno(pos, source), col(pos, source)) task = Task.startTask("parser", "Parsing functions", len(source)) for match, pos, l in function.scanString(source): task.updateProgress(pos) name, type = match.name[0] if not name: continue f = Function(name, type) f.language = "c" for name, type in match.args: if not name or not type: continue f.parameters[name] = Parameter(name, type) # Grab the code if any if match.body: f.body = match.body library.functions[f.name] = f task.finish() return library
def prepare(self): # Shorthand for various objects config = self.config lib = self.library # Parse the sources for fileName in config.get("apiheaders", []): Log.notice("Parsing functions from '%s'." % fileName) source = self.parserTool.readSource(fileName) newLib = Parser.parseSource(source) for f in newLib.functions.values(): f.headerName = fileName for f in newLib.functions.values(): Log.debug("%s %s(%s)" % (f.type, f.name, ", ".join( ["%s %s" % (t.type, p) for p, t in f.parameters.items()]))) if not newLib.functions: Log.warn("No new functions found.") else: Log.notice("%d functions found." % len(newLib.functions)) lib.merge(newLib) # Load the hooks self.parserTool.loadHooks() def parseBool(s): return bool(int(s)) # Read the typemap for typeDecl, mapping in self.config.types.items(): attrs = self.config.types[typeDecl].attrs name, type = Parser.parseVariableDeclaration(typeDecl + " dummy") assert name == "dummy" # If this is a class mapping, create the class if it doesn't already exist if mapping == "object": if not mapping in self.library.classes: cls = Library.Class(type) if "namespace" in attrs: cls.namespacePath = attrs["namespace"].split(".") self.library.classes[type] = cls # Patch the default decoration hint into all matching types if "decorationhint" in attrs: for function in self.library.functions.values(): for t in [p.type for p in function.parameters.values() ] + [function.type]: if t == type: t.decorationHint = attrs["decorationhint"] self.library.typeMap[type] = str(mapping) # Patch in some function-specific attributes for function in config.functions.keys(): if not function in lib.functions: self.fail( "Attributes specified for non-existent function '%s'." % function) attrs = config.functions[function].attrs if "terminator" in attrs: lib.functions[function].isTerminator = parseBool( attrs["terminator"]) if "generate" in attrs: lib.functions[function].generate = parseBool(attrs["generate"]) if "runtimestate" in attrs: lib.functions[function].runtimeStateTracking = parseBool( attrs["runtimestate"]) if "framemarker" in attrs: lib.functions[function].isFrameMarker = parseBool( attrs["framemarker"]) if "staticlinkage" in attrs: lib.functions[function].staticLinkage = parseBool( attrs["staticlinkage"]) if "rendercall" in attrs: lib.functions[function].isRenderCall = parseBool( attrs["rendercall"]) if "passthrough" in attrs: lib.functions[function].passthrough = parseBool( attrs["passthrough"]) if not isinstance(config.functions[function], Config.Group): self.fail( "Syntax error: State map definition for function '%s' is missing braces." % function) # Argument to state mapping reservedNames = ["@return", "@modify", "@set", "@get", "@copy"] funcAttrs = attrs for arg, parameter in config.functions[function].items(): # Check that this is a valid parameter if not arg in reservedNames and not arg in lib.functions[ function].parameters: self.fail( "State mapping for nonexistent parameter '%s' of function '%s' specified." % (arg, function)) if arg in ["@copy"] and parseBool( funcAttrs.get("runtimestate", "0")): Log.warn( "Function %s state relation %s not implemented for runtime state tracking." % (function, arg)) # Read the parameter-specific attributes attrs = config.functions[function][arg].attrs if "decoration" in attrs: lib.functions[function].parameters[arg].decoration = attrs[ "decoration"] if "decorationhint" in attrs: lib.functions[function].parameters[ arg].decorationHint = attrs["decorationhint"] if "out" in attrs: lib.functions[function].parameters[arg].isOut = parseBool( attrs["out"]) if "object_class" in attrs: # Create a function-local type so that this parameter type is an object only for this function if arg == "@return": type = lib.functions[function].type else: type = lib.functions[function].parameters[arg].type # Override the type's name so that it will refer to the new object class # while still using the original C type under the hood newType = copy.deepcopy(type) newType.isObject = True newType.name = attrs["object_class"] if arg == "@return": lib.functions[function].type = newType else: lib.functions[function].parameters[arg].type = newType # Check that this class exists classType = Library.Type(attrs["object_class"]) if not classType in self.library.classes: self.fail("Undefined object class '%s'." % classType) # Do we have a meta type? if "metatype" in config.functions[function][arg]: metaGroup = config.functions[function][arg].metatype try: metaType = Library.MetaType(metaGroup.attrs["class"]) except KeyError: self.fail( "Meta type for parameter '%s' does not define class." % arg) # Is this an array parameter? if metaType.name == "array": metaType.values["size"] = Library.MetaValue( "size", metaGroup.attrs.get("size", 1)) if "type" in metaGroup.attrs: metaType.values["type"] = Library.MetaValue( "type", metaGroup.attrs["type"]) if metaGroup.attrs["type"] == "object": if not "object_class" in metaGroup.attrs: self.fail( "Required metatype attribute object_class missing" ) metaType.values[ "object_class"] = Library.MetaValue( "object_class", metaGroup.attrs["object_class"]) # How about an image parameter? elif metaType.name == "image": metaType.values["stride"] = Library.MetaValue( "stride", metaGroup.attrs.get("stride", "width")) metaType.values["height"] = Library.MetaValue( "height", metaGroup.attrs.get("height", "height")) metaType.values["components"] = Library.MetaValue( "components", metaGroup.attrs.get("components", "1")) metaType.values["type"] = Library.MetaValue( "type", metaGroup.attrs.get("type", "byte")) else: self.fail("Unknown meta type class '%s'." % metaclass) Log.debug("Meta type: %s.%s: %s" % (function, arg, metaType.name)) # Get the conditions for different meta values if isinstance(metaGroup, Config.List): for item in metaGroup: predicate = item.attrs["condition"] predicateValue = item.attrs["value"] result = item.attrs["result"] metaType.values[item].addPredicate( predicate, predicateValue, result) Log.debug( "Meta type condition: If %s is %s, then %s = %s" % (predicate, predicateValue, item, result)) elif isinstance(metaGroup, Config.Group): Log.error( "Meta type variations for parameter '%s' represented in a group instead of a list." % arg) # Record the meta type lib.functions[function].parameters[arg].metaType = metaType # Is this a short-hand state mapping? try: path = parameter.split(".") except AttributeError: # Try the expanded form of a nested attribute set try: path = ( config.functions[function][arg].state).split(".") except AttributeError: path = [] # Check that we even have a state structure if path and not "state" in config: Log.warn("State structure not defined.") continue # Parse special state mapping relations relation = None checkPaths = [] if arg == "@copy": relation = Library.StateRelationCopy( attrs["src"].split("."), attrs["dest"].split(".")) checkPaths = [relation.sourcePath, relation.destPath] elif arg == "@get": relation = Library.StateRelationGet(path) checkPaths = [relation.path] elif arg == "@set": relation = Library.StateRelationSet(path) checkPaths = [relation.path] elif arg == "@modify": relation = Library.StateRelationModify(path) checkPaths = [relation.path] # Empty mapping? elif not "".join(path): continue if relation: for path in checkPaths: if traverseStatePath(config, path) is None: self.fail( "Relation state path '%s' for function '%s' does not exist." % (".".join(path), function)) Log.debug("State relation: %s %s" % (function, relation)) lib.functions[function].stateRelations.append(relation) continue Log.debug("State mapping: %s.%s -> %s" % (function, arg, ".".join(path))) # Determine the parameter type type = None if arg == "@return": type = lib.functions[function].type else: type = lib.functions[function].parameters[arg].type # If this is a runtime mapping, check that the parameter is of a supported type if lib.functions[function].runtimeStateTracking and type and \ lib.getNativeType(type) in ["float", "double"]: self.fail( "Values of type '%s' can not be saved to the runtime state tree" % type) continue node = traverseStatePath(config, path) if node is None: self.fail( "State path '%s' for function '%s' does not exist." % (".".join(path), function)) # Save the mapping if arg == "@return": lib.functions[ function].retStateRelation = Library.StateRelationSet( path) else: lib.functions[function].parameters[ arg].stateRelation = Library.StateRelationSet(path)
def loadSymbolMap(self): config = self.config lib = self.library demangler = Tools.SymbolDecoder(config) # Set default library name if "library" in config: for function in lib.functions.values(): function.libName = config.library # Read in the export ordinals if "deffiles" in config: for defFile in config.deffiles: for function, ordinal in Parser.parseDefFile( open(config.getRelativePath(defFile)).read()): if function in lib.functions: lib.functions[function].exportOrdinal = ordinal Log.debug("%s is exported at %d" % (function, ordinal)) # The function was not found in the library, so let's check whether it is a C++ symbol elif demangler.isMangled(function): function = demangler.decode(function) if function in lib.functions: # Save the ordinal and mark the function as C++ lib.functions[function].exportOrdinal = ordinal lib.functions[function].language = "c++" Log.debug("%s is exported at %d" % (function, ordinal)) # Read the link ordinals and DLL information if "symbol_map" in config: defaultLibName = None for fileName, libName in config.symbol_map.items(): if fileName == "default": defaultLibName = libName continue # Is it a .DEF file if fileName.endswith(".def"): for function, ordinal in Parser.parseDefFile( open(config.getRelativePath(fileName)).read()): if function in lib.functions: lib.functions[function].ordinal = ordinal lib.functions[function].libName = libName Log.debug("%s is at %s:%d" % (function, libName, ordinal)) # The function was not found in the library, so let's check whether it is a C++ symbol elif demangler.isMangled(function): function = demangler.decode(function) if function in lib.functions: # Save the ordinal and mark the function as C++ lib.functions[function].ordinal = ordinal lib.functions[function].libName = libName lib.functions[function].language = "c++" Log.debug("%s is at %s:%d" % (function, libName, ordinal)) else: # it's a header file assert fileName.endswith(".h") for function in lib.functions.values(): if function.headerName == fileName: function.libName = libName # Generate passthrough functions for internal symbols if defaultLibName: assert self.project.platform.requireOrdinals, "Default symbol mapping can only be used in platforms that use symbol ordinals" assert "max_internal_ordinal" in config, "max_internal_ordinal must be defined when using a default symbol mapping" ordinals = range(1, int(config["max_internal_ordinal"]) + 1) for function in lib.functions.values(): if function.exportOrdinal in ordinals: ordinals.remove(function.exportOrdinal) for ordinal in ordinals: name = "_trInternal%d" % ordinal f = Library.Function(name, Library.Type("void")) f.language = "c" f.ordinal = ordinal f.exportOrdinal = ordinal f.libName = defaultLibName lib.functions[name] = f Log.debug("%s is at %s:%d" % (name, defaultLibName, ordinal))
def create(project, options, args): """Create a new Tracy project. [config file] [targets]""" if not args or len(args) < 1: fail("Configuration file name missing.") configName = args[0] targetNames = args[1:] # Load the configuration file project.config.loadFile(configName) for path in project.config.paths: Resource.paths.append(path) config = project.config try: # Create the platform and read it's configuration if it exists. platform = Platform.platforms[options.platform](config) except KeyError: fail("No such platform. Use one of %s" % ", ".join(Platform.platforms.keys())) projectName = config.name.lower() Log.notice( heading("Creating Tracy project '%s' for %s" % (projectName, platform.name))) # Initialize the project lib = Library.Library(name=config.name) project.library = lib project.platform = platform def prepareTarget(targetName): if targetName in project.targets: return if not targetName in Target.targets: fail("Bad target name '%s'." % targetName) return targetClass = Target.targets[targetName] for dep in targetClass.dependencies: if not dep in project.targets: prepareTarget(dep) Log.notice("Preparing target %d of %d: %s." % (len(project.targets) + 1, len(targetNames), targetName)) target = targetClass(project) target.prepare() target.validate() project.targets[targetName] = target # Prepare the targets if not targetNames: targetNames = Target.targets.keys() for targetName in targetNames: prepareTarget(targetName) # Save the project projectPath = options.output and options.output or ("%s.tcy" % projectName) project.save(projectPath) Log.notice("Tracy project '%s' saved to '%s'." % (projectName, projectPath))