2 ## Licensed to the .NET Foundation under one or more agreements.
3 ## The .NET Foundation licenses this file to you under the MIT license.
4 ## See the LICENSE file in the project root for more information.
8 import xml.dom.minidom as DOM
9 from utilities import open_for_update
13 generatedCodeFileHeader="""// Licensed to the .NET Foundation under one or more agreements.
14 // The .NET Foundation licenses this file to you under the MIT license.
15 // See the LICENSE file in the project root for more information.
17 /**********************************************************************
19 DO NOT MODIFY. AUTOGENERATED FILE.
20 This file is generated by <root>/src/scripts/genRuntimeEventSources.py
22 **********************************************************************/
25 ########################################################################
27 ########################################################################
28 manifestsToGenerate = {
29 "Microsoft-Windows-DotNETRuntime" : "DotNETRuntimeEventSource.cs"
32 providerNameToClassNameMap = {
33 "Microsoft-Windows-DotNETRuntime" : "RuntimeEventSource"
36 manifestTypeToCSharpTypeMap = {
38 "win:UInt16" : "UInt16",
39 "win:UInt32" : "UInt32",
40 "win:UInt64" : "UInt64",
41 "win:Int32" : "Int32",
42 "win:Pointer" : "UIntPtr",
43 "win:UnicodeString" : "string",
44 "win:Binary" : "byte[]",
45 "win:Double" : "double",
46 "win:Boolean" : "bool",
50 overrideEnumBackingTypes = {
51 "Microsoft-Windows-DotNETRuntime" : {
52 "GCSuspendEEReasonMap" : "win:UInt32",
53 "GCRootKindMap" : "win:UInt32"
56 ########################################################################
58 ########################################################################
62 def increaseTabLevel():
66 def decreaseTabLevel():
68 tabText = tabText[:-4]
70 def writeOutput(outputFile, str):
71 outputFile.write(tabText + str)
73 def getCSharpTypeFromManifestType(manifestType):
74 return manifestTypeToCSharpTypeMap[manifestType]
76 def generateEvent(eventNode, providerNode, outputFile, stringTable):
78 # Write the event attribute.
79 writeOutput(outputFile, "[Event("+ eventNode.getAttribute("value") + ", Version = " + eventNode.getAttribute("version") + ", Level = EventLevel." + eventNode.getAttribute("level")[4:])
81 # Not all events have keywords specified, and some have multiple keywords specified.
82 keywords = eventNode.getAttribute("keywords")
84 if " " not in keywords:
85 outputFile.write(", Keywords = Keywords." + keywords)
87 keywords = keywords.split()
88 outputFile.write(", Keywords = ")
89 for keywordIndex in range(len(keywords)):
90 outputFile.write("Keywords." + keywords[keywordIndex])
91 if keywordIndex < (len(keywords) - 1):
92 outputFile.write(" | ")
94 outputFile.write(")]\n")
96 # Get the template for the event.
98 templateKey = eventNode.getAttribute("template")
99 if templateKey is not None:
100 for node in providerNode.getElementsByTagName("templates"):
103 for node in templatesNode.getElementsByTagName("template"):
104 if node.getAttribute("tid") == templateKey:
108 # Write the beginning of the method signature.
109 writeOutput(outputFile, "private void " + eventNode.getAttribute("symbol") + "(")
111 # Write the function signature.
113 if templateNode is not None:
114 argumentNodes = templateNode.childNodes
116 # Calculate the number of arguments.
117 for argumentNode in argumentNodes:
118 if argumentNode.nodeName == "data":
119 if argumentNode.getAttribute("inType") != "win:Binary" and argumentNode.getAttribute("inType") != "win:AnsiString":
123 elif argumentNode.nodeName == "struct":
126 argumentsProcessed = 0
127 for argumentIndex in range(len(argumentNodes)):
128 argumentNode = argumentNodes[argumentIndex]
129 if argumentNode.nodeName == "data":
130 argumentName = argumentNode.getAttribute("name")
131 argumentInType = argumentNode.getAttribute("inType")
133 #### Disable enums until they are needed ####
134 # argumentMap = argumentNode.getAttribute("map")
135 # if not argumentMap:
136 # argumentCSharpType = getCSharpTypeFromManifestType(argumentInType)
138 # argumentCSharpType = argumentMap[:-3]
139 #### Disable enums until they are needed ####
141 argumentCSharpType = getCSharpTypeFromManifestType(argumentInType)
142 outputFile.write(argumentCSharpType + " " + argumentName)
143 argumentsProcessed += 1
144 if argumentsProcessed < argumentCount:
145 outputFile.write(", ")
146 if argumentsProcessed == argumentCount:
149 outputFile.write(")\n")
150 writeOutput(outputFile, "{\n")
152 # Write the call to WriteEvent.
154 writeOutput(outputFile, "WriteEvent(" + eventNode.getAttribute("value"))
156 # Add method parameters.
157 if argumentCount > 0:
158 # A ',' is needed after the event id.
159 outputFile.write(", ")
161 # Write the parameter names to the method call.
162 argumentsProcessed = 0
163 argumentNodes = templateNode.getElementsByTagName("data")
164 for argumentIndex in range(argumentCount):
165 argumentNode = argumentNodes[argumentIndex]
166 argumentName = argumentNode.getAttribute("name")
167 outputFile.write(argumentName)
168 if argumentIndex < (argumentCount - 1):
169 outputFile.write(", ")
171 outputFile.write(");\n")
174 writeOutput(outputFile, "}\n\n")
177 def generateEvents(providerNode, outputFile, stringTable):
179 # Get the events element.
180 for node in providerNode.getElementsByTagName("events"):
184 # Iterate over each event node and process it.
185 for eventNode in eventsNode.getElementsByTagName("event"):
186 generateEvent(eventNode, providerNode, outputFile, stringTable)
188 def generateValueMapEnums(providerNode, outputFile, stringTable, enumTypeMap):
190 # Get the maps element.
191 for node in providerNode.getElementsByTagName("maps"):
195 # Iterate over each map and create an enum out of it.
196 for valueMapNode in mapsNode.getElementsByTagName("valueMap"):
198 # Get the backing type of the enum.
199 typeName = enumTypeMap[valueMapNode.getAttribute("name")]
201 raise ValueError("No mapping from mapName to enum backing type.", valueMapNode.getAttribute("name"))
203 enumType = getCSharpTypeFromManifestType(typeName)
204 writeOutput(outputFile, "public enum " + valueMapNode.getAttribute("name")[:-3] + " : " + enumType + "\n")
205 writeOutput(outputFile, "{\n")
207 for mapNode in valueMapNode.getElementsByTagName("map"):
208 # Each map value has a message, which we should use as the enum value.
209 messageKey = mapNode.getAttribute("message")[9:-1]
210 writeOutput(outputFile, stringTable[messageKey] + " = " + mapNode.getAttribute("value") + ",\n")
212 writeOutput(outputFile, "}\n\n")
214 def generateBitMapEnums(providerNode, outputFile, stringTable, enumTypeMap):
216 # Get the maps element.
217 for node in providerNode.getElementsByTagName("maps"):
221 # Iterate over each map and create an enum out of it.
222 for valueMapNode in mapsNode.getElementsByTagName("bitMap"):
224 # Get the backing type of the enum.
225 typeName = enumTypeMap[valueMapNode.getAttribute("name")]
227 raise ValueError("No mapping from mapName to enum backing type.", valueMapNode.getAttribute("name"))
229 enumType = getCSharpTypeFromManifestType(typeName)
230 writeOutput(outputFile, "[Flags]\n")
231 writeOutput(outputFile, "public enum " + valueMapNode.getAttribute("name")[:-3] + " : " + enumType + "\n")
232 writeOutput(outputFile, "{\n")
234 for mapNode in valueMapNode.getElementsByTagName("map"):
235 # Each map value has a message, which we should use as the enum value.
236 messageKey = mapNode.getAttribute("message")[9:-1]
237 writeOutput(outputFile, stringTable[messageKey] + " = " + mapNode.getAttribute("value") + ",\n")
239 writeOutput(outputFile, "}\n\n")
241 def generateEnumTypeMap(providerNode):
243 providerName = providerNode.getAttribute("name")
244 templatesNodes = providerNode.getElementsByTagName("templates")
245 templatesNode = templatesNodes[0]
246 mapsNodes = providerNode.getElementsByTagName("maps")
248 # Keep a list of mapName -> inType.
249 # This map contains the first inType seen for the specified mapName.
252 # There are a couple of maps that are used by multiple events but have different backing types.
253 # Because only one of the uses will be consumed by EventSource/EventListener we can hack the backing type here
254 # and suppress the warning that we'd otherwise get.
255 overrideTypeMap = dict()
256 if providerName in overrideEnumBackingTypes:
257 overrideTypeMap = overrideEnumBackingTypes[providerName]
259 for mapsNode in mapsNodes:
260 for valueMapNode in mapsNode.getElementsByTagName("valueMap"):
261 mapName = valueMapNode.getAttribute("name")
262 dataNodes = templatesNode.getElementsByTagName("data")
264 # If we've never seen the map used, save its usage with the inType.
265 # If we have seen the map used, make sure that the inType saved previously matches the current inType.
266 for dataNode in dataNodes:
267 if dataNode.getAttribute("map") == mapName:
268 if mapName in overrideTypeMap:
269 typeMap[mapName] = overrideTypeMap[mapName]
270 elif mapName in typeMap and typeMap[mapName] != dataNode.getAttribute("inType"):
271 print("WARNING: Map " + mapName + " is used multiple times with different types. This may cause functional bugs in tracing.")
272 elif not mapName in typeMap:
273 typeMap[mapName] = dataNode.getAttribute("inType")
274 for bitMapNode in mapsNode.getElementsByTagName("bitMap"):
275 mapName = bitMapNode.getAttribute("name")
276 dataNodes = templatesNode.getElementsByTagName("data")
278 # If we've never seen the map used, save its usage with the inType.
279 # If we have seen the map used, make sure that the inType saved previously matches the current inType.
280 for dataNode in dataNodes:
281 if dataNode.getAttribute("map") == mapName:
282 if mapName in overrideTypeMap:
283 typeMap[mapName] = overrideTypeMap[mapName]
284 elif mapName in typeMap and typeMap[mapName] != dataNode.getAttribute("inType"):
285 print("Map " + mapName + " is used multiple times with different types.")
286 elif not mapName in typeMap:
287 typeMap[mapName] = dataNode.getAttribute("inType")
291 def generateKeywordsClass(providerNode, outputFile):
293 # Find the keywords element.
294 for node in providerNode.getElementsByTagName("keywords"):
298 writeOutput(outputFile, "public class Keywords\n")
299 writeOutput(outputFile, "{\n")
302 for keywordNode in keywordsNode.getElementsByTagName("keyword"):
303 writeOutput(outputFile, "public const EventKeywords " + keywordNode.getAttribute("name") + " = (EventKeywords)" + keywordNode.getAttribute("mask") + ";\n")
306 writeOutput(outputFile, "}\n\n")
308 def loadStringTable(manifest):
310 # Create the string table dictionary.
313 # Get the string table element.
314 for node in manifest.getElementsByTagName("stringTable"):
315 stringTableNode = node
318 # Iterate through each string and save it.
319 for stringElem in stringTableNode.getElementsByTagName("string"):
320 stringTable[stringElem.getAttribute("id")] = stringElem.getAttribute("value")
324 def generateEventSources(manifestFullPath, intermediatesDirFullPath):
326 # Open the manifest for reading.
327 manifest = DOM.parse(manifestFullPath)
329 # Load the string table.
330 stringTable = loadStringTable(manifest)
332 # Iterate over each provider that we want to generate an EventSource for.
333 for providerName, outputFileName in manifestsToGenerate.items():
334 for node in manifest.getElementsByTagName("provider"):
335 if node.getAttribute("name") == providerName:
339 if providerNode is None:
340 raise ValueError("Unable to find provider node.", providerName)
342 # Generate a full path to the output file and open the file for open_for_update.
343 outputFilePath = os.path.join(intermediatesDirFullPath, outputFileName)
344 with open_for_update(outputFilePath) as outputFile:
346 # Write the license header.
347 writeOutput(outputFile, generatedCodeFileHeader)
349 # Write the class header.
353 namespace System.Diagnostics.Tracing
356 writeOutput(outputFile, header)
358 writeOutput(outputFile, "[EventSource(Name = \"" + providerName + "\", Guid = \"" + providerNode.getAttribute("guid") + "\")]\n")
359 writeOutput(outputFile, "internal sealed unsafe class " + providerNameToClassNameMap[providerName] + " : EventSource\n")
360 writeOutput(outputFile, "{\n")
363 # Write the keywords class.
364 generateKeywordsClass(providerNode, outputFile)
366 #### Disable enums until they are needed ####
367 # Generate the enum type map.
368 # This determines what the backing type for each enum should be.
369 # enumTypeMap = generateEnumTypeMap(providerNode)
371 # Generate enums for value maps.
372 # generateValueMapEnums(providerNode, outputFile, stringTable, enumTypeMap)
374 # Generate enums for bit maps.
375 # generateBitMapEnums(providerNode, outputFile, stringTable, enumTypeMap)
376 #### Disable enums until they are needed ####
379 generateEvents(providerNode, outputFile, stringTable)
381 # Write the class footer.
383 writeOutput(outputFile, "}\n")
385 writeOutput(outputFile, "}")
389 # Parse command line arguments.
390 parser = argparse.ArgumentParser(
391 description="Generates C# EventSource classes that represent the runtime's native event providers.")
393 required = parser.add_argument_group('required arguments')
394 required.add_argument('--man', type=str, required=True,
395 help='full path to manifest containig the description of events')
396 required.add_argument('--intermediate', type=str, required=True,
397 help='full path to eventprovider intermediate directory')
398 args, unknown = parser.parse_known_args(argv)
400 print('Unknown argument(s): ', ', '.join(unknown))
403 manifestFullPath = args.man
404 intermediatesDirFullPath = args.intermediate
406 # Ensure the intermediates directory exists.
408 os.makedirs(intermediatesDirFullPath)
410 if not os.path.isdir(intermediatesDirFullPath):
413 # Generate event sources.
414 generateEventSources(manifestFullPath, intermediatesDirFullPath)
417 if __name__ == '__main__':
418 return_code = main(sys.argv[1:])
419 sys.exit(return_code)