summaryrefslogtreecommitdiff
path: root/src/scripts
diff options
context:
space:
mode:
authorBrian Robbins <brianrob@microsoft.com>2018-05-16 18:59:51 -0700
committerGitHub <noreply@github.com>2018-05-16 18:59:51 -0700
commit0fbd0f535e566bcde591701adc2de51ee0f020af (patch)
tree0f9ad83b02b124bae036fe45fd659a146f63221e /src/scripts
parenta8d40ac8362bacd98f7fa422190fe66916e040e8 (diff)
downloadcoreclr-0fbd0f535e566bcde591701adc2de51ee0f020af.tar.gz
coreclr-0fbd0f535e566bcde591701adc2de51ee0f020af.tar.bz2
coreclr-0fbd0f535e566bcde591701adc2de51ee0f020af.zip
Generate EventSources Representing DotNETRuntime Eventing Providers (#18007)
Diffstat (limited to 'src/scripts')
-rw-r--r--src/scripts/genRuntimeEventSources.py419
-rw-r--r--src/scripts/scripts.pyproj38
2 files changed, 457 insertions, 0 deletions
diff --git a/src/scripts/genRuntimeEventSources.py b/src/scripts/genRuntimeEventSources.py
new file mode 100644
index 0000000000..5795a4d22a
--- /dev/null
+++ b/src/scripts/genRuntimeEventSources.py
@@ -0,0 +1,419 @@
+#
+## Licensed to the .NET Foundation under one or more agreements.
+## The .NET Foundation licenses this file to you under the MIT license.
+## See the LICENSE file in the project root for more information.
+#
+
+import os
+import xml.dom.minidom as DOM
+from utilities import open_for_update
+import argparse
+import sys
+
+generatedCodeFileHeader="""// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/**********************************************************************
+
+DO NOT MODIFY. AUTOGENERATED FILE.
+This file is generated by <root>/src/scripts/genRuntimeEventSources.py
+
+**********************************************************************/
+"""
+
+########################################################################
+# START CONFIGURATION
+########################################################################
+manifestsToGenerate = {
+ "Microsoft-Windows-DotNETRuntime" : "DotNETRuntimeEventSource.cs"
+}
+
+providerNameToClassNameMap = {
+ "Microsoft-Windows-DotNETRuntime" : "RuntimeEventSource"
+}
+
+manifestTypeToCSharpTypeMap = {
+ "win:UInt8" : "byte",
+ "win:UInt16" : "UInt16",
+ "win:UInt32" : "UInt32",
+ "win:UInt64" : "UInt64",
+ "win:Int32" : "Int32",
+ "win:Pointer" : "UIntPtr",
+ "win:UnicodeString" : "string",
+ "win:Binary" : "byte[]",
+ "win:Double" : "double",
+ "win:Boolean" : "bool",
+ "win:GUID" : "Guid",
+}
+
+overrideEnumBackingTypes = {
+ "Microsoft-Windows-DotNETRuntime" : {
+ "GCSuspendEEReasonMap" : "win:UInt32",
+ "GCRootKindMap" : "win:UInt32"
+ }
+}
+########################################################################
+# END CONFIGURATION
+########################################################################
+
+tabText = ""
+
+def increaseTabLevel():
+ global tabText
+ tabText += " "
+
+def decreaseTabLevel():
+ global tabText
+ tabText = tabText[:-4]
+
+def writeOutput(outputFile, str):
+ outputFile.write(tabText + str)
+
+def getCSharpTypeFromManifestType(manifestType):
+ return manifestTypeToCSharpTypeMap[manifestType]
+
+def generateEvent(eventNode, providerNode, outputFile, stringTable):
+
+ # Write the event attribute.
+ writeOutput(outputFile, "[Event("+ eventNode.getAttribute("value") + ", Version = " + eventNode.getAttribute("version") + ", Level = EventLevel." + eventNode.getAttribute("level")[4:])
+
+ # Not all events have keywords specified, and some have multiple keywords specified.
+ keywords = eventNode.getAttribute("keywords")
+ if keywords:
+ if " " not in keywords:
+ outputFile.write(", Keywords = Keywords." + keywords)
+ else:
+ keywords = keywords.split()
+ outputFile.write(", Keywords = ")
+ for keywordIndex in range(len(keywords)):
+ outputFile.write("Keywords." + keywords[keywordIndex])
+ if keywordIndex < (len(keywords) - 1):
+ outputFile.write(" | ")
+
+ outputFile.write(")]\n")
+
+ # Get the template for the event.
+ templateNode = None
+ templateKey = eventNode.getAttribute("template")
+ if templateKey is not None:
+ for node in providerNode.getElementsByTagName("templates"):
+ templatesNode = node
+ break
+ for node in templatesNode.getElementsByTagName("template"):
+ if node.getAttribute("tid") == templateKey:
+ templateNode = node
+ break
+
+ # Write the beginning of the method signature.
+ writeOutput(outputFile, "private void " + eventNode.getAttribute("symbol") + "(")
+
+ # Write the function signature.
+ argumentCount = 0
+ if templateNode is not None:
+ argumentNodes = templateNode.childNodes
+
+ # Calculate the number of arguments.
+ for argumentNode in argumentNodes:
+ if argumentNode.nodeName == "data":
+ if argumentNode.getAttribute("inType") != "win:Binary" and argumentNode.getAttribute("inType") != "win:AnsiString":
+ argumentCount += 1
+ else:
+ break
+ elif argumentNode.nodeName == "struct":
+ break
+
+ argumentsProcessed = 0
+ for argumentIndex in range(len(argumentNodes)):
+ argumentNode = argumentNodes[argumentIndex]
+ if argumentNode.nodeName == "data":
+ argumentName = argumentNode.getAttribute("name")
+ argumentInType = argumentNode.getAttribute("inType")
+
+ #### Disable enums until they are needed ####
+ # argumentMap = argumentNode.getAttribute("map")
+ # if not argumentMap:
+ # argumentCSharpType = getCSharpTypeFromManifestType(argumentInType)
+ # else:
+ # argumentCSharpType = argumentMap[:-3]
+ #### Disable enums until they are needed ####
+
+ argumentCSharpType = getCSharpTypeFromManifestType(argumentInType)
+ outputFile.write(argumentCSharpType + " " + argumentName)
+ argumentsProcessed += 1
+ if argumentsProcessed < argumentCount:
+ outputFile.write(", ")
+ if argumentsProcessed == argumentCount:
+ break
+
+ outputFile.write(")\n")
+ writeOutput(outputFile, "{\n")
+
+ # Write the call to WriteEvent.
+ increaseTabLevel()
+ writeOutput(outputFile, "WriteEvent(" + eventNode.getAttribute("value"))
+
+ # Add method parameters.
+ if argumentCount > 0:
+ # A ',' is needed after the event id.
+ outputFile.write(", ")
+
+ # Write the parameter names to the method call.
+ argumentsProcessed = 0
+ argumentNodes = templateNode.getElementsByTagName("data")
+ for argumentIndex in range(argumentCount):
+ argumentNode = argumentNodes[argumentIndex]
+ argumentName = argumentNode.getAttribute("name")
+ outputFile.write(argumentName)
+ if argumentIndex < (argumentCount - 1):
+ outputFile.write(", ")
+
+ outputFile.write(");\n")
+ decreaseTabLevel()
+
+ writeOutput(outputFile, "}\n\n")
+
+
+def generateEvents(providerNode, outputFile, stringTable):
+
+ # Get the events element.
+ for node in providerNode.getElementsByTagName("events"):
+ eventsNode = node
+ break
+
+ # Iterate over each event node and process it.
+ for eventNode in eventsNode.getElementsByTagName("event"):
+ generateEvent(eventNode, providerNode, outputFile, stringTable)
+
+def generateValueMapEnums(providerNode, outputFile, stringTable, enumTypeMap):
+
+ # Get the maps element.
+ for node in providerNode.getElementsByTagName("maps"):
+ mapsNode = node
+ break
+
+ # Iterate over each map and create an enum out of it.
+ for valueMapNode in mapsNode.getElementsByTagName("valueMap"):
+
+ # Get the backing type of the enum.
+ typeName = enumTypeMap[valueMapNode.getAttribute("name")]
+ if typeName is None:
+ raise ValueError("No mapping from mapName to enum backing type.", valueMapNode.getAttribute("name"))
+
+ enumType = getCSharpTypeFromManifestType(typeName)
+ writeOutput(outputFile, "public enum " + valueMapNode.getAttribute("name")[:-3] + " : " + enumType + "\n")
+ writeOutput(outputFile, "{\n")
+ increaseTabLevel()
+ for mapNode in valueMapNode.getElementsByTagName("map"):
+ # Each map value has a message, which we should use as the enum value.
+ messageKey = mapNode.getAttribute("message")[9:-1]
+ writeOutput(outputFile, stringTable[messageKey] + " = " + mapNode.getAttribute("value") + ",\n")
+ decreaseTabLevel()
+ writeOutput(outputFile, "}\n\n")
+
+def generateBitMapEnums(providerNode, outputFile, stringTable, enumTypeMap):
+
+ # Get the maps element.
+ for node in providerNode.getElementsByTagName("maps"):
+ mapsNode = node
+ break
+
+ # Iterate over each map and create an enum out of it.
+ for valueMapNode in mapsNode.getElementsByTagName("bitMap"):
+
+ # Get the backing type of the enum.
+ typeName = enumTypeMap[valueMapNode.getAttribute("name")]
+ if typeName is None:
+ raise ValueError("No mapping from mapName to enum backing type.", valueMapNode.getAttribute("name"))
+
+ enumType = getCSharpTypeFromManifestType(typeName)
+ writeOutput(outputFile, "[Flags]\n")
+ writeOutput(outputFile, "public enum " + valueMapNode.getAttribute("name")[:-3] + " : " + enumType + "\n")
+ writeOutput(outputFile, "{\n")
+ increaseTabLevel()
+ for mapNode in valueMapNode.getElementsByTagName("map"):
+ # Each map value has a message, which we should use as the enum value.
+ messageKey = mapNode.getAttribute("message")[9:-1]
+ writeOutput(outputFile, stringTable[messageKey] + " = " + mapNode.getAttribute("value") + ",\n")
+ decreaseTabLevel()
+ writeOutput(outputFile, "}\n\n")
+
+def generateEnumTypeMap(providerNode):
+
+ providerName = providerNode.getAttribute("name")
+ templatesNodes = providerNode.getElementsByTagName("templates")
+ templatesNode = templatesNodes[0]
+ mapsNodes = providerNode.getElementsByTagName("maps")
+
+ # Keep a list of mapName -> inType.
+ # This map contains the first inType seen for the specified mapName.
+ typeMap = dict()
+
+ # There are a couple of maps that are used by multiple events but have different backing types.
+ # Because only one of the uses will be consumed by EventSource/EventListener we can hack the backing type here
+ # and suppress the warning that we'd otherwise get.
+ overrideTypeMap = dict()
+ if providerName in overrideEnumBackingTypes:
+ overrideTypeMap = overrideEnumBackingTypes[providerName]
+
+ for mapsNode in mapsNodes:
+ for valueMapNode in mapsNode.getElementsByTagName("valueMap"):
+ mapName = valueMapNode.getAttribute("name")
+ dataNodes = templatesNode.getElementsByTagName("data")
+
+ # If we've never seen the map used, save its usage with the inType.
+ # If we have seen the map used, make sure that the inType saved previously matches the current inType.
+ for dataNode in dataNodes:
+ if dataNode.getAttribute("map") == mapName:
+ if mapName in overrideTypeMap:
+ typeMap[mapName] = overrideTypeMap[mapName]
+ elif mapName in typeMap and typeMap[mapName] != dataNode.getAttribute("inType"):
+ print("WARNING: Map " + mapName + " is used multiple times with different types. This may cause functional bugs in tracing.")
+ elif not mapName in typeMap:
+ typeMap[mapName] = dataNode.getAttribute("inType")
+ for bitMapNode in mapsNode.getElementsByTagName("bitMap"):
+ mapName = bitMapNode.getAttribute("name")
+ dataNodes = templatesNode.getElementsByTagName("data")
+
+ # If we've never seen the map used, save its usage with the inType.
+ # If we have seen the map used, make sure that the inType saved previously matches the current inType.
+ for dataNode in dataNodes:
+ if dataNode.getAttribute("map") == mapName:
+ if mapName in overrideTypeMap:
+ typeMap[mapName] = overrideTypeMap[mapName]
+ elif mapName in typeMap and typeMap[mapName] != dataNode.getAttribute("inType"):
+ print("Map " + mapName + " is used multiple times with different types.")
+ elif not mapName in typeMap:
+ typeMap[mapName] = dataNode.getAttribute("inType")
+
+ return typeMap
+
+def generateKeywordsClass(providerNode, outputFile):
+
+ # Find the keywords element.
+ for node in providerNode.getElementsByTagName("keywords"):
+ keywordsNode = node
+ break;
+
+ writeOutput(outputFile, "public class Keywords\n")
+ writeOutput(outputFile, "{\n")
+ increaseTabLevel()
+
+ for keywordNode in keywordsNode.getElementsByTagName("keyword"):
+ writeOutput(outputFile, "public const EventKeywords " + keywordNode.getAttribute("name") + " = (EventKeywords)" + keywordNode.getAttribute("mask") + ";\n")
+
+ decreaseTabLevel()
+ writeOutput(outputFile, "}\n\n")
+
+def loadStringTable(manifest):
+
+ # Create the string table dictionary.
+ stringTable = dict()
+
+ # Get the string table element.
+ for node in manifest.getElementsByTagName("stringTable"):
+ stringTableNode = node
+ break
+
+ # Iterate through each string and save it.
+ for stringElem in stringTableNode.getElementsByTagName("string"):
+ stringTable[stringElem.getAttribute("id")] = stringElem.getAttribute("value")
+
+ return stringTable
+
+def generateEventSources(manifestFullPath, intermediatesDirFullPath):
+
+ # Open the manifest for reading.
+ manifest = DOM.parse(manifestFullPath)
+
+ # Load the string table.
+ stringTable = loadStringTable(manifest)
+
+ # Iterate over each provider that we want to generate an EventSource for.
+ for providerName, outputFileName in manifestsToGenerate.items():
+ for node in manifest.getElementsByTagName("provider"):
+ if node.getAttribute("name") == providerName:
+ providerNode = node
+ break
+
+ if providerNode is None:
+ raise ValueError("Unable to find provider node.", providerName)
+
+ # Generate a full path to the output file and open the file for open_for_update.
+ outputFilePath = os.path.join(intermediatesDirFullPath, outputFileName)
+ with open_for_update(outputFilePath) as outputFile:
+
+ # Write the license header.
+ writeOutput(outputFile, generatedCodeFileHeader)
+
+ # Write the class header.
+ header = """
+using System;
+
+namespace System.Diagnostics.Tracing
+{
+"""
+ writeOutput(outputFile, header)
+ increaseTabLevel()
+ writeOutput(outputFile, "[EventSource(Name = \"" + providerName + "\", Guid = \"" + providerNode.getAttribute("guid") + "\")]\n")
+ writeOutput(outputFile, "internal sealed unsafe class " + providerNameToClassNameMap[providerName] + " : EventSource\n")
+ writeOutput(outputFile, "{\n")
+ increaseTabLevel()
+
+ # Write the keywords class.
+ generateKeywordsClass(providerNode, outputFile)
+
+ #### Disable enums until they are needed ####
+ # Generate the enum type map.
+ # This determines what the backing type for each enum should be.
+ # enumTypeMap = generateEnumTypeMap(providerNode)
+
+ # Generate enums for value maps.
+ # generateValueMapEnums(providerNode, outputFile, stringTable, enumTypeMap)
+
+ # Generate enums for bit maps.
+ # generateBitMapEnums(providerNode, outputFile, stringTable, enumTypeMap)
+ #### Disable enums until they are needed ####
+
+ # Generate events.
+ generateEvents(providerNode, outputFile, stringTable)
+
+ # Write the class footer.
+ decreaseTabLevel()
+ writeOutput(outputFile, "}\n")
+ decreaseTabLevel()
+ writeOutput(outputFile, "}")
+
+def main(argv):
+
+ # Parse command line arguments.
+ parser = argparse.ArgumentParser(
+ description="Generates C# EventSource classes that represent the runtime's native event providers.")
+
+ required = parser.add_argument_group('required arguments')
+ required.add_argument('--man', type=str, required=True,
+ help='full path to manifest containig the description of events')
+ required.add_argument('--intermediate', type=str, required=True,
+ help='full path to eventprovider intermediate directory')
+ args, unknown = parser.parse_known_args(argv)
+ if unknown:
+ print('Unknown argument(s): ', ', '.join(unknown))
+ return 1
+
+ manifestFullPath = args.man
+ intermediatesDirFullPath = args.intermediate
+
+ # Ensure the intermediates directory exists.
+ try:
+ os.makedirs(intermediatesDirFullPath)
+ except OSError:
+ if not os.path.isdir(intermediatesDirFullPath):
+ raise
+
+ # Generate event sources.
+ generateEventSources(manifestFullPath, intermediatesDirFullPath)
+ return 0
+
+if __name__ == '__main__':
+ return_code = main(sys.argv[1:])
+ sys.exit(return_code)
diff --git a/src/scripts/scripts.pyproj b/src/scripts/scripts.pyproj
new file mode 100644
index 0000000000..c0b7bef641
--- /dev/null
+++ b/src/scripts/scripts.pyproj
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{9d304b80-696f-4873-85ca-cbd2fdb900af}</ProjectGuid>
+ <ProjectHome />
+ <StartupFile>genRuntimeEventSources.py</StartupFile>
+ <SearchPath />
+ <WorkingDirectory>.</WorkingDirectory>
+ <OutputPath>.</OutputPath>
+ <ProjectTypeGuids>{888888a0-9f3d-457c-b088-3a5042f75d52}</ProjectTypeGuids>
+ <LaunchProvider>Standard Python launcher</LaunchProvider>
+ <InterpreterId>Global|PythonCore|2.7</InterpreterId>
+ <CommandLineArguments>--man c:\src\coreclr\src\vm\clretwall.man --intermediate c:\work\runtimeeventsource</CommandLineArguments>
+ <EnableNativeCodeDebugging>False</EnableNativeCodeDebugging>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)' == 'Debug'" />
+ <PropertyGroup Condition="'$(Configuration)' == 'Release'" />
+ <PropertyGroup>
+ <VisualStudioVersion Condition=" '$(VisualStudioVersion)' == '' ">10.0</VisualStudioVersion>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="check-definitions.py" />
+ <Compile Include="genDummyProvider.py" />
+ <Compile Include="genEtwProvider.py" />
+ <Compile Include="genEventing.py" />
+ <Compile Include="genEventPipe.py" />
+ <Compile Include="genLttngProvider.py" />
+ <Compile Include="genRuntimeEventSources.py" />
+ <Compile Include="pgocheck.py" />
+ <Compile Include="utilities.py" />
+ </ItemGroup>
+ <ItemGroup>
+ <InterpreterReference Include="Global|PythonCore|2.7" />
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets" />
+</Project> \ No newline at end of file