Replace compGetMemArray uses
[platform/upstream/coreclr.git] / src / scripts / genRuntimeEventSources.py
1 #
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.
5 #
6
7 import os
8 import xml.dom.minidom as DOM
9 from utilities import open_for_update
10 import argparse
11 import sys
12
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.
16
17 /**********************************************************************
18
19 DO NOT MODIFY. AUTOGENERATED FILE.
20 This file is generated by <root>/src/scripts/genRuntimeEventSources.py
21
22 **********************************************************************/
23 """
24
25 ########################################################################
26 # START CONFIGURATION
27 ########################################################################
28 manifestsToGenerate = {
29     "Microsoft-Windows-DotNETRuntime" : "DotNETRuntimeEventSource.cs"
30 }
31
32 providerNameToClassNameMap = {
33     "Microsoft-Windows-DotNETRuntime" : "RuntimeEventSource"
34 }
35
36 manifestTypeToCSharpTypeMap = {
37     "win:UInt8" : "byte",
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",
47     "win:GUID" : "Guid",
48 }
49
50 overrideEnumBackingTypes = {
51     "Microsoft-Windows-DotNETRuntime" : {
52         "GCSuspendEEReasonMap" : "win:UInt32",
53         "GCRootKindMap" : "win:UInt32"
54     }
55 }
56 ########################################################################
57 # END CONFIGURATION
58 ########################################################################
59
60 tabText = ""
61
62 def increaseTabLevel():
63     global tabText
64     tabText += "    "
65
66 def decreaseTabLevel():
67     global tabText
68     tabText = tabText[:-4]
69
70 def writeOutput(outputFile, str):
71     outputFile.write(tabText + str)
72
73 def getCSharpTypeFromManifestType(manifestType):
74     return manifestTypeToCSharpTypeMap[manifestType]
75
76 def generateEvent(eventNode, providerNode, outputFile, stringTable):
77
78     # Write the event attribute.
79     writeOutput(outputFile, "[Event("+ eventNode.getAttribute("value") + ", Version = " + eventNode.getAttribute("version") + ", Level = EventLevel." + eventNode.getAttribute("level")[4:])
80     
81     # Not all events have keywords specified, and some have multiple keywords specified.
82     keywords = eventNode.getAttribute("keywords")
83     if keywords:
84         if " " not in keywords:
85             outputFile.write(", Keywords = Keywords." + keywords)
86         else:
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(" | ")
93
94     outputFile.write(")]\n")
95
96     # Get the template for the event.
97     templateNode = None
98     templateKey = eventNode.getAttribute("template")
99     if templateKey is not None:
100         for node in providerNode.getElementsByTagName("templates"):
101             templatesNode = node
102             break
103         for node in templatesNode.getElementsByTagName("template"):
104             if node.getAttribute("tid") == templateKey:
105                 templateNode = node
106                 break
107
108     # Write the beginning of the method signature.
109     writeOutput(outputFile, "private void " + eventNode.getAttribute("symbol") + "(")
110
111     # Write the function signature.
112     argumentCount = 0
113     if templateNode is not None:
114         argumentNodes = templateNode.childNodes
115
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":
120                     argumentCount += 1
121                 else:
122                     break
123             elif argumentNode.nodeName == "struct":
124                 break
125
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")
132
133                 #### Disable enums until they are needed ####
134                 # argumentMap = argumentNode.getAttribute("map")
135                 # if not argumentMap:
136                 #     argumentCSharpType = getCSharpTypeFromManifestType(argumentInType)
137                 # else:
138                 #     argumentCSharpType = argumentMap[:-3]
139                 #### Disable enums until they are needed ####
140
141                 argumentCSharpType = getCSharpTypeFromManifestType(argumentInType)
142                 outputFile.write(argumentCSharpType + " " + argumentName)
143                 argumentsProcessed += 1
144                 if argumentsProcessed < argumentCount:
145                     outputFile.write(", ")
146             if argumentsProcessed == argumentCount:
147                 break
148
149     outputFile.write(")\n")
150     writeOutput(outputFile, "{\n")
151
152     # Write the call to WriteEvent.
153     increaseTabLevel()
154     writeOutput(outputFile, "WriteEvent(" + eventNode.getAttribute("value"))
155
156     # Add method parameters.
157     if argumentCount > 0:
158         # A ',' is needed after the event id.
159         outputFile.write(", ")
160
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(", ")
170
171     outputFile.write(");\n")
172     decreaseTabLevel()
173
174     writeOutput(outputFile, "}\n\n")
175
176
177 def generateEvents(providerNode, outputFile, stringTable):
178
179     # Get the events element.
180     for node in providerNode.getElementsByTagName("events"):
181         eventsNode = node
182         break
183
184     # Iterate over each event node and process it.
185     for eventNode in eventsNode.getElementsByTagName("event"):
186         generateEvent(eventNode, providerNode, outputFile, stringTable)
187
188 def generateValueMapEnums(providerNode, outputFile, stringTable, enumTypeMap):
189
190     # Get the maps element.
191     for node in providerNode.getElementsByTagName("maps"):
192         mapsNode = node
193         break
194
195     # Iterate over each map and create an enum out of it.
196     for valueMapNode in mapsNode.getElementsByTagName("valueMap"):
197
198         # Get the backing type of the enum.
199         typeName = enumTypeMap[valueMapNode.getAttribute("name")]
200         if typeName is None:
201             raise ValueError("No mapping from mapName to enum backing type.", valueMapNode.getAttribute("name"))
202
203         enumType = getCSharpTypeFromManifestType(typeName)
204         writeOutput(outputFile, "public enum " + valueMapNode.getAttribute("name")[:-3] + " : " + enumType + "\n")
205         writeOutput(outputFile, "{\n")
206         increaseTabLevel()
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")
211         decreaseTabLevel()
212         writeOutput(outputFile, "}\n\n")
213
214 def generateBitMapEnums(providerNode, outputFile, stringTable, enumTypeMap):
215
216     # Get the maps element.
217     for node in providerNode.getElementsByTagName("maps"):
218         mapsNode = node
219         break
220
221     # Iterate over each map and create an enum out of it.
222     for valueMapNode in mapsNode.getElementsByTagName("bitMap"):
223
224         # Get the backing type of the enum.
225         typeName = enumTypeMap[valueMapNode.getAttribute("name")]
226         if typeName is None:
227             raise ValueError("No mapping from mapName to enum backing type.", valueMapNode.getAttribute("name"))
228
229         enumType = getCSharpTypeFromManifestType(typeName)
230         writeOutput(outputFile, "[Flags]\n")
231         writeOutput(outputFile, "public enum " + valueMapNode.getAttribute("name")[:-3] + " : " + enumType + "\n")
232         writeOutput(outputFile, "{\n")
233         increaseTabLevel()
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")
238         decreaseTabLevel()
239         writeOutput(outputFile, "}\n\n")
240
241 def generateEnumTypeMap(providerNode):
242
243     providerName = providerNode.getAttribute("name")
244     templatesNodes = providerNode.getElementsByTagName("templates")
245     templatesNode = templatesNodes[0]
246     mapsNodes = providerNode.getElementsByTagName("maps")
247
248     # Keep a list of mapName -> inType.
249     # This map contains the first inType seen for the specified mapName.
250     typeMap = dict()
251
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]
258
259     for mapsNode in mapsNodes:
260         for valueMapNode in mapsNode.getElementsByTagName("valueMap"):
261             mapName = valueMapNode.getAttribute("name")
262             dataNodes = templatesNode.getElementsByTagName("data")
263
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")
277
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")
288
289     return typeMap
290
291 def generateKeywordsClass(providerNode, outputFile):
292
293     # Find the keywords element.
294     for node in providerNode.getElementsByTagName("keywords"):
295         keywordsNode = node
296         break;
297
298     writeOutput(outputFile, "public class Keywords\n")
299     writeOutput(outputFile, "{\n")
300     increaseTabLevel()
301
302     for keywordNode in keywordsNode.getElementsByTagName("keyword"):
303         writeOutput(outputFile, "public const EventKeywords " + keywordNode.getAttribute("name") + " = (EventKeywords)" + keywordNode.getAttribute("mask") + ";\n")
304
305     decreaseTabLevel()
306     writeOutput(outputFile, "}\n\n")
307
308 def loadStringTable(manifest):
309
310     # Create the string table dictionary.
311     stringTable = dict()
312
313     # Get the string table element.
314     for node in manifest.getElementsByTagName("stringTable"):
315         stringTableNode = node
316         break
317
318     # Iterate through each string and save it.
319     for stringElem in stringTableNode.getElementsByTagName("string"):
320         stringTable[stringElem.getAttribute("id")] = stringElem.getAttribute("value")
321
322     return stringTable
323
324 def generateEventSources(manifestFullPath, intermediatesDirFullPath):
325
326     # Open the manifest for reading.
327     manifest = DOM.parse(manifestFullPath)
328
329     # Load the string table.
330     stringTable = loadStringTable(manifest)
331
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:
336                 providerNode = node
337                 break
338
339         if providerNode is None:
340             raise ValueError("Unable to find provider node.", providerName)
341
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:
345
346             # Write the license header.
347             writeOutput(outputFile, generatedCodeFileHeader)
348
349             # Write the class header.
350             header = """
351 using System;
352
353 namespace System.Diagnostics.Tracing
354 {
355 """
356             writeOutput(outputFile, header)
357             increaseTabLevel()
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")
361             increaseTabLevel()
362
363             # Write the keywords class.
364             generateKeywordsClass(providerNode, outputFile)
365
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)
370
371             # Generate enums for value maps.
372             # generateValueMapEnums(providerNode, outputFile, stringTable, enumTypeMap)
373
374             # Generate enums for bit maps.
375             # generateBitMapEnums(providerNode, outputFile, stringTable, enumTypeMap)
376             #### Disable enums until they are needed ####
377
378             # Generate events.
379             generateEvents(providerNode, outputFile, stringTable)
380
381             # Write the class footer.
382             decreaseTabLevel()
383             writeOutput(outputFile, "}\n")
384             decreaseTabLevel()
385             writeOutput(outputFile, "}")
386
387 def main(argv):
388
389     # Parse command line arguments.
390     parser = argparse.ArgumentParser(
391         description="Generates C# EventSource classes that represent the runtime's native event providers.")
392
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)
399     if unknown:
400         print('Unknown argument(s): ', ', '.join(unknown))
401         return 1
402
403     manifestFullPath = args.man
404     intermediatesDirFullPath = args.intermediate
405
406     # Ensure the intermediates directory exists.
407     try:
408         os.makedirs(intermediatesDirFullPath)
409     except OSError:
410         if not os.path.isdir(intermediatesDirFullPath):
411             raise
412
413     # Generate event sources.
414     generateEventSources(manifestFullPath, intermediatesDirFullPath)
415     return 0
416
417 if __name__ == '__main__':
418     return_code = main(sys.argv[1:])
419     sys.exit(return_code)