1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-08 11:37:04 +09:00
Satori/src/coreclr/scripts/genEventing.py

1179 lines
47 KiB
Python

#
## Licensed to the .NET Foundation under one or more agreements.
## The .NET Foundation licenses this file to you under the MIT license.
#
#
#USAGE:
#Add Events: modify <root>src/vm/ClrEtwAll.man
#Look at the Code in <root>/src/scripts/genLttngProvider.py for using subroutines in this file
#
# Python 2 compatibility
from __future__ import print_function
import os
import sys
import xml.dom.minidom as DOM
from utilities import open_for_update, parseInclusionList
class RuntimeFlavor:
def __init__(self, runtime):
if runtime.lower() == "coreclr":
self.coreclr = True
self.mono = False
self.nativeaot = False
elif runtime.lower() == "mono":
self.coreclr = False
self.mono = True
self.nativeaot = False
elif runtime.lower() == "nativeaot":
self.coreclr = False
self.mono = False
self.nativeaot = True
else:
self.coreclr = True
self.mono = False
self.nativeaot = False
stdprolog="""
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
/******************************************************************
DO NOT MODIFY. AUTOGENERATED FILE.
This file is generated using the logic from <root>/src/scripts/genEventing.py
******************************************************************/
"""
lindent = " "
coreCLRPalDataTypeMapping={
#constructed types
"win:null" :" ",
"win:Int64" :"const int64_t",
"win:ULong" :"const ULONG",
"win:count" :"*",
"win:Struct" :"const void",
#actual spec
"win:GUID" :"const GUID",
"win:AnsiString" :"LPCSTR",
"win:UnicodeString" :"PCWSTR",
"win:Double" :"const double",
"win:Int32" :"const signed int",
"win:Boolean" :"const BOOL",
"win:UInt64" :"const uint64_t",
"win:UInt32" :"const unsigned int",
"win:UInt16" :"const unsigned short",
"win:UInt8" :"const unsigned char",
"win:Pointer" :"const void*",
"win:Binary" :"const BYTE",
}
coreCLREventPipeDataTypeMapping={
"BOOL" : "BOOL",
"LPCGUID" : "LPCGUID",
"UCHAR" : "UCHAR",
"ULONG" : "ULONG",
"ULONGLONG" : "ULONGLONG",
"WCHAR" : "WCHAR",
"BYTE" : "BYTE",
}
coreCLRUserEventDataTypeMapping={
"win:UInt8" : "TraceLoggingUInt8",
"win:UInt16" : "TraceLoggingUInt16",
"win:Int32" : "TraceLoggingInt32",
"win:UInt32" : "TraceLoggingUInt32",
"win:HexInt32" : "TraceLoggingHexInt32",
"win:UInt64" : "TraceLoggingUInt64",
"win:Int64" : "TraceLoggingInt64",
"win:HexInt64" : "TraceLoggingHexInt64",
"win:Pointer" : "TraceLoggingPointer",
"win:Boolean" : "TraceLoggingBoolean",
"win:UnicodeString" : "TraceLoggingString16",
"win:GUID" : "TraceLoggingGuid",
"win:Binary" : "TraceLoggingBinary",
"win:Double" : "TraceLoggingFloat64",
"win:AnsiString" : "TraceLoggingString",
}
coreCLRUserEventLogLevelMapping={
"win:LogAlways" : "0",
"win:Critical" : "1",
"win:Error" : "2",
"win:Warning" : "3",
"win:Informational" : "4",
"win:Verbose" : "5",
}
coreCLRUserEventArrayTypeMapping={
"win:UInt32" : "TraceLoggingUInt32Array",
"win:Binary" : "TraceLoggingUInt8Array",
"win:UInt64" : "TraceLoggingUInt64Array",
}
monoPalDataTypeMapping={
#constructed types
"win:null" :" ",
"win:Int64" :"const int64_t",
"win:ULong" :"const uint32_t",
"win:count" :"*",
"win:Struct" :"const void",
#actual spec
"win:GUID" :"const uint8_t",
"win:AnsiString" :"const char*",
"win:UnicodeString" :"const ep_char8_t*",
"win:Double" :"const double",
"win:Int32" :"const int32_t",
"win:Boolean" :"const bool",
"win:UInt64" :"const uint64_t",
"win:UInt32" :"const uint32_t",
"win:UInt16" :"const uint16_t",
"win:UInt8" :"const uint8_t",
"win:Pointer" :"const void*",
"win:Binary" :"const uint8_t",
}
monoEventPipeDataTypeMapping={
"BOOL" : "bool",
"LPCGUID" : "const uint8_t*",
"UCHAR" : "uint8_t",
"ULONG" : "uint32_t",
"ULONGLONG" : "uint64_t",
"WCHAR" : "wchar_t",
"BYTE" : "uint8_t",
}
aotPalDataTypeMapping={
#constructed types
"win:null" :" ",
"win:Int64" :"const int64_t",
"win:ULong" :"const ULONG",
"win:count" :"*",
"win:Struct" :"const void",
#actual spec
"win:GUID" :"const GUID",
"win:AnsiString" :"LPCSTR",
"win:UnicodeString" :"const WCHAR*",
"win:Double" :"const double",
"win:Int32" :"const signed int",
"win:Boolean" :"const BOOL",
"win:UInt64" :"const uint64_t",
"win:UInt32" :"const unsigned int",
"win:UInt16" :"const unsigned short",
"win:UInt8" :"const unsigned char",
"win:Pointer" :"const void*",
"win:Binary" :"const BYTE",
}
aotEventPipeDataTypeMapping={
"BOOL" : "BOOL",
"LPCGUID" : "const GUID *",
"UCHAR" : "UCHAR",
"ULONG" : "ULONG",
"ULONGLONG" : "ULONGLONG",
"WCHAR" : "WCHAR",
"BYTE" : "BYTE",
}
def getUserEventDataTypeMapping(runtimeFlavor):
if runtimeFlavor.coreclr:
return coreCLRUserEventDataTypeMapping
# elif runtimeFlavor.mono:
# return monoUserEventDataTypeMapping
# elif runtimeFlavor.nativeaot:
# return aotUserEventDataTypeMapping
def getUserEventLogLevelMapping(runtimeFlavor):
if runtimeFlavor.coreclr:
return coreCLRUserEventLogLevelMapping
# elif runtimeFlavor.mono:
# return monoUserEventLogLevelMapping
# elif runtimeFlavor.nativeaot:
# return aotUserEventLogLevelMapping
def getArrayDataTypeMapping(runtimeFlavor):
if runtimeFlavor.coreclr:
return coreCLRUserEventArrayTypeMapping
# elif runtimeFlavor.mono:
# return monoUserEventArrayTypeMapping
# elif runtimeFlavor.nativeaot:
# return aotUserEventArrayTypeMapping
def getEventPipeDataTypeMapping(runtimeFlavor):
if runtimeFlavor.coreclr:
return coreCLREventPipeDataTypeMapping
elif runtimeFlavor.mono:
return monoEventPipeDataTypeMapping
elif runtimeFlavor.nativeaot:
return aotEventPipeDataTypeMapping
def getPalDataTypeMapping(runtimeFlavor):
if runtimeFlavor.coreclr:
return coreCLRPalDataTypeMapping
elif runtimeFlavor.mono:
return monoPalDataTypeMapping
elif runtimeFlavor.nativeaot:
return aotPalDataTypeMapping
def includeProvider(providerName, runtimeFlavor):
if (runtimeFlavor.coreclr or runtimeFlavor.nativeaot) and providerName == "Microsoft-DotNETRuntimeMonoProfiler":
return False
elif runtimeFlavor.nativeaot and (providerName == "Microsoft-Windows-DotNETRuntimeRundown" or providerName == "Microsoft-Windows-DotNETRuntimeStress"):
return False
else:
return True
def includeEvent(inclusionList, providerName, eventName):
if len(inclusionList) == 0:
return True
if providerName in inclusionList and eventName in inclusionList[providerName]:
return True
elif providerName in inclusionList and "*" in inclusionList[providerName]:
return True
elif "*" in inclusionList and eventName in inclusionList["*"]:
return True
elif "*" in inclusionList and "*" in inclusionList["*"]:
return True
else:
return False
def getCoreCLRMonoNativeAotTypeAdaptionDefines():
return """
#ifndef W
#define W(str) L##str
#endif
#ifndef SL
#define SL(str) str
#endif
#ifndef ERROR_SUCCESS
#define ERROR_SUCCESS 0L
#endif
#ifndef ERROR_WRITE_FAULT
#define ERROR_WRITE_FAULT 29L
#endif
"""
# A Template represents an ETW template can contain 1 or more AbstractTemplates
# The AbstractTemplate contains FunctionSignature
# FunctionSignature consist of FunctionParameter representing each parameter in it's signature
def getParamSequenceSize(paramSequence, estimate):
total = 0
pointers = 0
for param in paramSequence:
if param == "win:Int64":
total += 8
elif param == "win:ULong":
total += 4
elif param == "GUID":
total += 16
elif param == "win:Double":
total += 8
elif param == "win:Int32":
total += 4
elif param == "win:Boolean":
total += 4
elif param == "win:UInt64":
total += 8
elif param == "win:UInt32":
total += 4
elif param == "win:UInt16":
total += 2
elif param == "win:UInt8":
total += 1
elif param == "win:Pointer":
if estimate:
total += 8
else:
pointers += 1
elif param == "win:Binary":
total += 1
elif estimate:
if param == "win:AnsiString":
total += 32
elif param == "win:UnicodeString":
total += 64
elif param == "win:Struct":
total += 32
else:
raise Exception("Don't know size for " + param)
if estimate:
return total
return total, pointers
class Template:
def __repr__(self):
return "<Template " + self.name + ">"
def __init__(self, templateName, fnPrototypes, dependencies, structSizes, arrays):
self.name = templateName
self.signature = FunctionSignature()
self.structs = structSizes
self.arrays = arrays
for variable in fnPrototypes.paramlist:
for dependency in dependencies[variable]:
if not self.signature.getParam(dependency):
self.signature.append(dependency, fnPrototypes.getParam(dependency))
def getFnParam(self, name):
return self.signature.getParam(name)
@property
def num_params(self):
return len(self.signature.paramlist)
@property
def estimated_size(self):
total = getParamSequenceSize((self.getFnParam(paramName).winType for paramName in self.signature.paramlist), True)
if total < 32:
total = 32
elif total > 1024:
total = 1024
return total
class FunctionSignature:
def __repr__(self):
return ", ".join(self.paramlist)
def __init__(self):
self.LUT = {} # dictionary of FunctionParameter
self.paramlist = [] # list of parameters to maintain their order in signature
def append(self,variable,fnparam):
self.LUT[variable] = fnparam
self.paramlist.append(variable)
def getParam(self,variable):
return self.LUT.get(variable)
def getLength(self):
return len(self.paramlist)
class FunctionParameter:
def __repr__(self):
return self.name
def __init__(self,winType,name,count,prop):
self.winType = winType #ETW type as given in the manifest
self.name = name #parameter name as given in the manifest
self.prop = prop #any special property as determined by the manifest and developer
#self.count #indicates if the parameter is a pointer
if count == "win:null":
self.count = "win:null"
elif count or winType == "win:GUID" or count == "win:count":
#special case for GUIDS, consider them as structs
self.count = "win:count"
else:
self.count = "win:null"
def getTopLevelElementsByTagName(node,tag):
dataNodes = []
for element in node.getElementsByTagName(tag):
if element.parentNode == node:
dataNodes.append(element)
return dataNodes
ignoredXmlTemplateAttribes = frozenset(["map","outType"])
usedXmlTemplateAttribes = frozenset(["name","inType","count", "length"])
def parseTemplateNodes(templateNodes):
#return values
allTemplates = {}
for templateNode in templateNodes:
structCounts = {}
arrays = {}
templateName = templateNode.getAttribute('tid')
var_Dependencies = {}
fnPrototypes = FunctionSignature()
dataNodes = getTopLevelElementsByTagName(templateNode,'data')
# Validate that no new attributes has been added to manifest
for dataNode in dataNodes:
nodeMap = dataNode.attributes
for attrib in nodeMap.values():
attrib_name = attrib.name
if attrib_name not in ignoredXmlTemplateAttribes and attrib_name not in usedXmlTemplateAttribes:
raise ValueError('unknown attribute: '+ attrib_name + ' in template:'+ templateName)
for dataNode in dataNodes:
variable = dataNode.getAttribute('name')
wintype = dataNode.getAttribute('inType')
#count and length are the same
wincount = dataNode.getAttribute('count')
winlength = dataNode.getAttribute('length');
var_Props = None
var_dependency = [variable]
if winlength:
if wincount:
raise Exception("both count and length property found on: " + variable + "in template: " + templateName)
wincount = winlength
if (wincount.isdigit() and int(wincount) ==1):
wincount = ''
if wincount:
if (wincount.isdigit()):
var_Props = wincount
elif fnPrototypes.getParam(wincount):
var_Props = wincount
var_dependency.insert(0, wincount)
arrays[variable] = wincount
#construct the function signature
if wintype == "win:GUID":
var_Props = "sizeof(GUID)/sizeof(int)"
var_Dependencies[variable] = var_dependency
fnparam = FunctionParameter(wintype,variable,wincount,var_Props)
fnPrototypes.append(variable,fnparam)
structNodes = getTopLevelElementsByTagName(templateNode,'struct')
for structToBeMarshalled in structNodes:
structName = structToBeMarshalled.getAttribute('name')
countVarName = structToBeMarshalled.getAttribute('count')
assert(countVarName == "Count")
assert(countVarName in fnPrototypes.paramlist)
if not countVarName:
raise ValueError("Struct '%s' in template '%s' does not have an attribute count." % (structName, templateName))
names = [x.attributes['name'].value for x in structToBeMarshalled.getElementsByTagName("data")]
types = [x.attributes['inType'].value for x in structToBeMarshalled.getElementsByTagName("data")]
structCounts[structName] = countVarName
var_Dependencies[structName] = [countVarName, structName]
fnparam_pointer = FunctionParameter("win:Struct", structName, "win:count", countVarName)
fnPrototypes.append(structName, fnparam_pointer)
allTemplates[templateName] = Template(templateName, fnPrototypes, var_Dependencies, structCounts, arrays)
return allTemplates
def generateClrallEvents(eventNodes, allTemplates, target_cpp, runtimeFlavor, write_xplatheader, providerName, inclusionList, generatedFileType, user_events):
clrallEvents = []
for eventNode in eventNodes:
eventName = eventNode.getAttribute('symbol')
if not includeEvent(inclusionList, providerName, eventName):
continue
templateName = eventNode.getAttribute('template')
#generate EventEnabled
if includeProvider (providerName, runtimeFlavor):
if not target_cpp:
clrallEvents.append("static ")
if generatedFileType == "header-impl":
clrallEvents.append("inline ")
clrallEvents.append("%s EventEnabled" % (getEventPipeDataTypeMapping(runtimeFlavor)["BOOL"]))
clrallEvents.append(eventName)
clrallEvents.append("(void)")
if generatedFileType == "header":
clrallEvents.append(";\n")
elif generatedFileType == "source-impl-noop":
clrallEvents.append(" { return 0; }\n")
else:
clrallEvents.append(" {return ")
clrallEvents.append("EventPipeEventEnabled" + eventName + "()")
if runtimeFlavor.coreclr or write_xplatheader or runtimeFlavor.nativeaot:
if os.name == 'posix':
if user_events and runtimeFlavor.coreclr:
clrallEvents.append(" || UserEventsEventEnabled" + eventName + "()")
# native AOT does not support non-windows eventing other than via event pipe
if not runtimeFlavor.nativeaot:
clrallEvents.append(" || (XplatEventLogger" +
("::" if target_cpp else "_") +
"IsEventLoggingEnabled() && EventXplatEnabled" +
eventName + "());}\n\n")
else:
clrallEvents.append(";}\n\n")
else:
clrallEvents.append(" || EventXplatEnabled" + eventName + "();}\n\n")
else:
clrallEvents.append(";}\n\n")
#generate FireEtw functions
fnptype = []
fnbody = []
if not target_cpp:
clrallEvents.append("static ")
if not runtimeFlavor.nativeaot:
fnptype.append("inline ")
fnptype.append("%s FireEtw" % (getEventPipeDataTypeMapping(runtimeFlavor)["ULONG"]))
fnptype.append(eventName)
fnptype.append("(\n")
line = []
fnptypeline = []
if templateName:
template = allTemplates[templateName]
fnSig = template.signature
for params in fnSig.paramlist:
fnparam = fnSig.getParam(params)
wintypeName = fnparam.winType
typewName = getPalDataTypeMapping(runtimeFlavor)[wintypeName]
winCount = fnparam.count
countw = getPalDataTypeMapping(runtimeFlavor)[winCount]
if params in template.structs:
fnptypeline.append("%sint %s_ElementSize,\n" % (lindent, params))
fnptypeline.append(lindent)
fnptypeline.append(typewName)
fnptypeline.append(countw)
fnptypeline.append(" ")
fnptypeline.append(fnparam.name)
fnptypeline.append(",\n")
#fnsignature
for params in fnSig.paramlist:
fnparam = fnSig.getParam(params)
if params in template.structs:
line.append(fnparam.name + "_ElementSize")
line.append(", ")
line.append(fnparam.name)
line.append(",")
#remove trailing commas
if len(line) > 0:
del line[-1]
#add activity IDs
fnptypeline.append(lindent)
# source file can't have the parameter initializer
fnptypeline.append("%s ActivityId%s\n" % (getEventPipeDataTypeMapping(runtimeFlavor)["LPCGUID"], " = nullptr," if (target_cpp and (generatedFileType == "header" or generatedFileType == "header-impl")) else ","))
fnptypeline.append(lindent)
fnptypeline.append("%s RelatedActivityId" % (getEventPipeDataTypeMapping(runtimeFlavor)["LPCGUID"]))
if (target_cpp and (generatedFileType == "header" or generatedFileType == "header-impl")):
fnptypeline.append(" = nullptr")
else:
fnptypeline.append("")
fnptype.extend(fnptypeline)
fnptype.append("\n)")
if generatedFileType == "header":
fnptype.append(";\n")
fnptype.append("\n")
elif generatedFileType == "source-impl-noop":
fnptype.append("\n{ return ERROR_SUCCESS; }\n\n")
else: # source-impl
fnptype.append("\n{\n")
fnbody.append(lindent)
fnbody.append("%s status = EventPipeWriteEvent" % (getEventPipeDataTypeMapping(runtimeFlavor)["ULONG"]) + eventName + "(" + ''.join(line))
if len(line) > 0:
fnbody.append(",")
fnbody.append("ActivityId,RelatedActivityId);\n")
if user_events and runtimeFlavor.coreclr:
fnbody.append(lindent)
fnbody.append("status &= UserEventsWriteEvent" + eventName + "(" + ''.join(line))
if len(line) > 0:
fnbody.append(",")
fnbody.append("ActivityId,RelatedActivityId);\n")
if runtimeFlavor.coreclr or write_xplatheader:
fnbody.append(lindent)
fnbody.append("status &= FireEtXplat" + eventName + "(" + ''.join(line) + ");\n")
if runtimeFlavor.nativeaot:
if providerName == "Microsoft-Windows-DotNETRuntime" or providerName == "Microsoft-Windows-DotNETRuntimePrivate":
fnbody.append("#ifndef TARGET_UNIX\n")
fnbody.append(lindent)
fnbody.append("status &= ")
else:
fnbody.append("return ")
fnbody.append("FireEtXplat" + eventName + "(" + ''.join(line) + ");\n")
if providerName == "Microsoft-Windows-DotNETRuntime" or providerName == "Microsoft-Windows-DotNETRuntimePrivate":
fnbody.append("#endif\n")
fnbody.append(lindent)
fnbody.append("return status;\n")
fnbody.append("}\n\n")
clrallEvents.extend(fnptype)
if not (runtimeFlavor.nativeaot and (generatedFileType == "header" or generatedFileType == "source-impl-noop")):
clrallEvents.extend(fnbody)
return ''.join(clrallEvents)
def generateClrXplatEvents(eventNodes, allTemplates, extern, runtimeFlavor):
clrallEvents = []
for eventNode in eventNodes:
eventName = eventNode.getAttribute('symbol')
templateName = eventNode.getAttribute('template')
#generate EventEnabled
if extern: clrallEvents.append('extern "C" ')
clrallEvents.append("%s EventXplatEnabled" % (getEventPipeDataTypeMapping(runtimeFlavor)["BOOL"]))
clrallEvents.append(eventName)
clrallEvents.append("();\n")
#generate FireEtw functions
fnptype = []
fnptypeline = []
if extern: fnptype.append('extern "C" ')
fnptype.append("%s FireEtXplat" % (getEventPipeDataTypeMapping(runtimeFlavor)["ULONG"]))
fnptype.append(eventName)
fnptype.append("(\n")
if templateName:
template = allTemplates[templateName]
fnSig = template.signature
for params in fnSig.paramlist:
fnparam = fnSig.getParam(params)
wintypeName = fnparam.winType
typewName = getPalDataTypeMapping(runtimeFlavor)[wintypeName]
winCount = fnparam.count
countw = getPalDataTypeMapping(runtimeFlavor)[winCount]
if params in template.structs:
fnptypeline.append("%sint %s_ElementSize,\n" % (lindent, params))
fnptypeline.append(lindent)
fnptypeline.append(typewName)
fnptypeline.append(countw)
fnptypeline.append(" ")
fnptypeline.append(fnparam.name)
fnptypeline.append(",\n")
#remove trailing commas
if len(fnptypeline) > 0:
del fnptypeline[-1]
fnptype.extend(fnptypeline)
fnptype.append("\n);\n")
clrallEvents.extend(fnptype)
return ''.join(clrallEvents)
def generateClrEventPipeWriteEvents(eventNodes, allTemplates, extern, target_cpp, runtimeFlavor, providerName, inclusion_list):
clrallEvents = []
for eventNode in eventNodes:
eventName = eventNode.getAttribute('symbol')
if not includeEvent(inclusion_list, providerName, eventName):
continue
templateName = eventNode.getAttribute('template')
#generate EventPipeEventEnabled and EventPipeWriteEvent functions
eventenabled = []
writeevent = []
fnptypeline = []
if extern:eventenabled.append('extern "C" ')
eventenabled.append("%s EventPipeEventEnabled" % (getEventPipeDataTypeMapping(runtimeFlavor)["BOOL"]))
eventenabled.append(eventName)
eventenabled.append("(void);\n")
if extern: writeevent.append('extern "C" ')
writeevent.append("%s EventPipeWriteEvent" % (getEventPipeDataTypeMapping(runtimeFlavor)["ULONG"]))
writeevent.append(eventName)
writeevent.append("(\n")
if templateName:
template = allTemplates[templateName]
fnSig = template.signature
for params in fnSig.paramlist:
fnparam = fnSig.getParam(params)
wintypeName = fnparam.winType
typewName = getPalDataTypeMapping(runtimeFlavor)[wintypeName]
winCount = fnparam.count
countw = getPalDataTypeMapping(runtimeFlavor)[winCount]
if params in template.structs:
fnptypeline.append("%sint %s_ElementSize,\n" % (lindent, params))
fnptypeline.append(lindent)
fnptypeline.append(typewName)
fnptypeline.append(countw)
fnptypeline.append(" ")
fnptypeline.append(fnparam.name)
fnptypeline.append(",\n")
fnptypeline.append(lindent)
fnptypeline.append("%s ActivityId%s\n" % (getEventPipeDataTypeMapping(runtimeFlavor)["LPCGUID"], " = nullptr," if target_cpp else ","))
fnptypeline.append(lindent)
fnptypeline.append("%s RelatedActivityId%s" % (getEventPipeDataTypeMapping(runtimeFlavor)["LPCGUID"], " = nullptr" if target_cpp else ""))
writeevent.extend(fnptypeline)
writeevent.append("\n);\n")
clrallEvents.extend(eventenabled)
clrallEvents.extend(writeevent)
return ''.join(clrallEvents)
def generateClrUserEventsWriteEvents(eventNodes, allTemplates, extern, target_cpp, runtimeFlavor, providerName, inclusion_list):
clrallEvents = []
for eventNode in eventNodes:
eventName = eventNode.getAttribute('symbol')
if not includeEvent(inclusion_list, providerName, eventName):
continue
templateName = eventNode.getAttribute('template')
#generate UserEventsEventEnabled and UserEventsWriteEvent functions
eventenabled = []
writeevent = []
fnptypeline = []
if extern:eventenabled.append('extern "C" ')
eventenabled.append("%s UserEventsEventEnabled" % (getEventPipeDataTypeMapping(runtimeFlavor)["BOOL"]))
eventenabled.append(eventName)
eventenabled.append("(void);\n")
if extern: writeevent.append('extern "C" ')
writeevent.append("%s UserEventsWriteEvent" % (getEventPipeDataTypeMapping(runtimeFlavor)["ULONG"]))
writeevent.append(eventName)
writeevent.append("(\n")
if templateName:
template = allTemplates[templateName]
fnSig = template.signature
for params in fnSig.paramlist:
fnparam = fnSig.getParam(params)
wintypeName = fnparam.winType
typewName = getPalDataTypeMapping(runtimeFlavor)[wintypeName]
winCount = fnparam.count
countw = getPalDataTypeMapping(runtimeFlavor)[winCount]
if params in template.structs:
fnptypeline.append("%sint %s_ElementSize,\n" % (lindent, params))
fnptypeline.append(lindent)
fnptypeline.append(typewName)
fnptypeline.append(countw)
fnptypeline.append(" ")
fnptypeline.append(fnparam.name)
fnptypeline.append(",\n")
fnptypeline.append(lindent)
fnptypeline.append("%s ActivityId%s\n" % (getEventPipeDataTypeMapping(runtimeFlavor)["LPCGUID"], " = nullptr," if target_cpp else ","))
fnptypeline.append(lindent)
fnptypeline.append("%s RelatedActivityId%s" % (getEventPipeDataTypeMapping(runtimeFlavor)["LPCGUID"], " = nullptr" if target_cpp else ""))
writeevent.extend(fnptypeline)
writeevent.append("\n);\n")
clrallEvents.extend(eventenabled)
clrallEvents.extend(writeevent)
return ''.join(clrallEvents)
#generates the dummy header file which is used by the VM as entry point to the logging Functions
def generateclrEtwDummy(eventNodes,allTemplates):
clretmEvents = []
for eventNode in eventNodes:
eventName = eventNode.getAttribute('symbol')
templateName = eventNode.getAttribute('template')
fnptype = []
#generate FireEtw functions
fnptype.append("#define FireEtw")
fnptype.append(eventName)
fnptype.append("(");
line = []
if templateName:
template = allTemplates[templateName]
fnSig = template.signature
for params in fnSig.paramlist:
fnparam = fnSig.getParam(params)
if params in template.structs:
line.append(fnparam.name + "_ElementSize")
line.append(", ")
line.append(fnparam.name)
line.append(", ")
#remove trailing commas
if len(line) > 0:
del line[-1]
fnptype.extend(line)
fnptype.append(") 0\n")
clretmEvents.extend(fnptype)
return ''.join(clretmEvents)
def generateEtmDummyHeader(sClrEtwAllMan,clretwdummy):
if not clretwdummy:
return
tree = DOM.parse(sClrEtwAllMan)
incDir = os.path.dirname(os.path.realpath(clretwdummy))
if not os.path.exists(incDir):
os.makedirs(incDir)
with open_for_update(clretwdummy) as Clretwdummy:
Clretwdummy.write(stdprolog + "\n")
for providerNode in tree.getElementsByTagName('provider'):
templateNodes = providerNode.getElementsByTagName('template')
allTemplates = parseTemplateNodes(templateNodes)
eventNodes = providerNode.getElementsByTagName('event')
#pal: create etmdummy.h
Clretwdummy.write(generateclrEtwDummy(eventNodes, allTemplates) + "\n")
def convertToLevelId(level):
if level == "win:LogAlways":
return 0
if level == "win:Critical":
return 1
if level == "win:Error":
return 2
if level == "win:Warning":
return 3
if level == "win:Informational":
return 4
if level == "win:Verbose":
return 5
raise Exception("unknown level " + level)
def getKeywordsMaskCombined(keywords, keywordsToMask):
mask = 0
for keyword in keywords.split(" "):
if keyword == "":
continue
mask |= keywordsToMask[keyword]
return mask
def updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, user_events_trace_context_typedef, tree, clrallevents, inclusion_list, generatedFileType, user_events):
is_windows = os.name == 'nt'
with open_for_update(clrallevents) as Clrallevents:
Clrallevents.write(stdprolog)
if generatedFileType=="header-impl":
if runtimeFlavor.mono:
Clrallevents.write(getCoreCLRMonoNativeAotTypeAdaptionDefines() + "\n")
if runtimeFlavor.coreclr or write_xplatheader:
Clrallevents.write('#include "clrxplatevents.h"\n')
Clrallevents.write('#include "clreventpipewriteevents.h"\n')
if user_events and runtimeFlavor.coreclr:
Clrallevents.write('#include "clrusereventswriteevents.h"\n')
elif generatedFileType == "header":
Clrallevents.write('#ifndef CLR_ETW_ALL_MAIN_H\n')
Clrallevents.write('#define CLR_ETW_ALL_MAIN_H\n\n')
elif generatedFileType == "source-impl":
Clrallevents.write('#include <common.h>\n')
Clrallevents.write('#include <PalRedhawk.h>\n')
Clrallevents.write('#include "clretwallmain.h"\n')
Clrallevents.write('#include "clreventpipewriteevents.h"\n')
if user_events and runtimeFlavor.coreclr:
Clrallevents.write('#include "clrusereventswriteevents.h"\n')
Clrallevents.write('#ifdef FEATURE_ETW\n')
Clrallevents.write('#include "ClrEtwAll.h"\n')
Clrallevents.write('#endif\n')
Clrallevents.write('\n')
elif generatedFileType == "source-impl-noop":
Clrallevents.write('#include <CommonTypes.h>\n')
Clrallevents.write('#include <CommonMacros.h>\n\n')
Clrallevents.write('#include <PalRedhawk.h>\n\n')
Clrallevents.write('#ifndef ERROR_SUCCESS\n')
Clrallevents.write('#define ERROR_SUCCESS 0L\n')
Clrallevents.write('#endif\n\n')
# define DOTNET_TRACE_CONTEXT depending on the platform
if is_windows and not runtimeFlavor.nativeaot:
Clrallevents.write(eventpipe_trace_context_typedef) # define EVENTPIPE_TRACE_CONTEXT
if runtimeFlavor.coreclr or write_xplatheader:
Clrallevents.write(dotnet_trace_context_typedef_windows + "\n")
else:
Clrallevents.write("\n")
if not is_windows and runtimeFlavor.coreclr:
Clrallevents.write(user_events_trace_context_typedef)
if not is_windows and not write_xplatheader and not runtimeFlavor.nativeaot:
Clrallevents.write(eventpipe_trace_context_typedef) # define EVENTPIPE_TRACE_CONTEXT
Clrallevents.write("\n")
# Hack to write etw specific information to nativeaot
for providerNode in tree.getElementsByTagName('provider'):
providerName = providerNode.getAttribute('name')
templateNodes = providerNode.getElementsByTagName('template')
allTemplates = parseTemplateNodes(templateNodes)
eventNodes = providerNode.getElementsByTagName('event')
#vm header:
Clrallevents.write(generateClrallEvents(eventNodes, allTemplates, target_cpp, runtimeFlavor, write_xplatheader, providerName, inclusion_list, generatedFileType, user_events))
providerName = providerNode.getAttribute('name')
providerSymbol = providerNode.getAttribute('symbol')
eventpipeProviderCtxName = providerSymbol + "_EVENTPIPE_Context"
if is_windows and not (write_xplatheader or runtimeFlavor.nativeaot):
Clrallevents.write(('constexpr ' if target_cpp else 'static const ') + 'EVENTPIPE_TRACE_CONTEXT ' + eventpipeProviderCtxName + ' = { W("' + providerName + '"), 0, false, 0 };\n')
if not is_windows and not write_xplatheader and not runtimeFlavor.nativeaot:
Clrallevents.write('__attribute__((weak)) EVENTPIPE_TRACE_CONTEXT ' + eventpipeProviderCtxName + ' = { W("' + providerName + '"), 0, false, 0 };\n')
if generatedFileType == "header":
Clrallevents.write("#endif // __CLR_ETW_ALL_MAIN_H__\n")
def generatePlatformIndependentFiles(sClrEtwAllMan, incDir, etmDummyFile, extern, write_xplatheader, target_cpp, runtimeFlavor, inclusion_list, user_events):
generateEtmDummyHeader(sClrEtwAllMan,etmDummyFile)
tree = DOM.parse(sClrEtwAllMan)
if not incDir:
return
if not os.path.exists(incDir):
os.makedirs(incDir)
eventpipe_trace_context_typedef = """
#if !defined(EVENTPIPE_TRACE_CONTEXT_DEF)
#define EVENTPIPE_TRACE_CONTEXT_DEF
typedef struct _EVENTPIPE_TRACE_CONTEXT
{
const %s * Name;
%s Level;
bool IsEnabled;
%s EnabledKeywordsBitmask;
} EVENTPIPE_TRACE_CONTEXT, *PEVENTPIPE_TRACE_CONTEXT;
#endif // EVENTPIPE_TRACE_CONTEXT_DEF
""" % (getEventPipeDataTypeMapping(runtimeFlavor)["WCHAR"], getEventPipeDataTypeMapping(runtimeFlavor)["UCHAR"], getEventPipeDataTypeMapping(runtimeFlavor)["ULONGLONG"])
user_events_trace_context_typedef = """
#if !defined(USER_EVENTS_TRACE_CONTEXT_DEF)
#define USER_EVENTS_TRACE_CONTEXT_DEF
typedef struct _USER_EVENTS_TRACE_CONTEXT
{
UCHAR id;
} USER_EVENTS_TRACE_CONTEXT, *PUSER_EVENTS_TRACE_CONTEXT;
#endif // USER_EVENTS_TRACE_CONTEXT_DEF
"""
lttng_trace_context_typedef = """
#if !defined(LTTNG_TRACE_CONTEXT_DEF)
#define LTTNG_TRACE_CONTEXT_DEF
typedef struct _LTTNG_TRACE_CONTEXT
{
WCHAR const * Name;
UCHAR Level;
bool IsEnabled;
ULONGLONG EnabledKeywordsBitmask;
} LTTNG_TRACE_CONTEXT, *PLTTNG_TRACE_CONTEXT;
#endif // LTTNG_TRACE_CONTEXT_DEF
"""
dotnet_trace_context_typedef_windows = """
#if !defined(DOTNET_TRACE_CONTEXT_DEF)
#define DOTNET_TRACE_CONTEXT_DEF
typedef struct _DOTNET_TRACE_CONTEXT
{
PMCGEN_TRACE_CONTEXT EtwProvider;
EVENTPIPE_TRACE_CONTEXT EventPipeProvider;
} DOTNET_TRACE_CONTEXT, *PDOTNET_TRACE_CONTEXT;
#endif // DOTNET_TRACE_CONTEXT_DEF
"""
dotnet_trace_context_typedef_unix = """
#if !defined(DOTNET_TRACE_CONTEXT_DEF)
#define DOTNET_TRACE_CONTEXT_DEF
typedef struct _DOTNET_TRACE_CONTEXT
{
EVENTPIPE_TRACE_CONTEXT EventPipeProvider;
PLTTNG_TRACE_CONTEXT LttngProvider;
USER_EVENTS_TRACE_CONTEXT UserEventsProvider;
} DOTNET_TRACE_CONTEXT, *PDOTNET_TRACE_CONTEXT;
#endif // DOTNET_TRACE_CONTEXT_DEF
"""
is_windows = os.name == 'nt'
# Write the main source(s) for FireETW* functions
# nativeaot requires header and source file to be separated as well as a noop implementation
if runtimeFlavor.nativeaot:
updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, user_events_trace_context_typedef, tree, os.path.join(incDir, "clretwallmain.cpp"), inclusion_list, "source-impl", user_events)
updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, user_events_trace_context_typedef, tree, os.path.join(incDir, "clretwallmain.h"), inclusion_list, "header", user_events)
updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, user_events_trace_context_typedef, tree, os.path.join(incDir, "disabledclretwallmain.cpp"), inclusion_list, "source-impl-noop", user_events)
else:
updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, user_events_trace_context_typedef, tree, os.path.join(incDir, "clretwallmain.h"), inclusion_list, "header-impl", user_events)
if write_xplatheader:
clrproviders = os.path.join(incDir, "clrproviders.h")
with open_for_update(clrproviders) as Clrproviders:
Clrproviders.write("""
typedef struct _EVENT_DESCRIPTOR
{
int const Level;
ULONGLONG const Keyword;
} EVENT_DESCRIPTOR;
""")
if not is_windows and not runtimeFlavor.nativeaot:
Clrproviders.write(eventpipe_trace_context_typedef) # define EVENTPIPE_TRACE_CONTEXT
Clrproviders.write(lttng_trace_context_typedef) # define LTTNG_TRACE_CONTEXT
Clrproviders.write(user_events_trace_context_typedef)
Clrproviders.write(dotnet_trace_context_typedef_unix + "\n")
allProviders = []
nbProviders = 0
for providerNode in tree.getElementsByTagName('provider'):
keywords = []
keywordsToMask = {}
providerName = str(providerNode.getAttribute('name'))
providerSymbol = str(providerNode.getAttribute('symbol'))
nbProviders += 1
nbKeywords = 0
if not is_windows and not runtimeFlavor.nativeaot:
eventpipeProviderCtxName = providerSymbol + "_EVENTPIPE_Context"
Clrproviders.write('__attribute__((weak)) EVENTPIPE_TRACE_CONTEXT ' + eventpipeProviderCtxName + ' = { W("' + providerName + '"), 0, false, 0 };\n')
lttngProviderCtxName = providerSymbol + "_LTTNG_Context"
Clrproviders.write('__attribute__((weak)) LTTNG_TRACE_CONTEXT ' + lttngProviderCtxName + ' = { W("' + providerName + '"), 0, false, 0 };\n')
Clrproviders.write("// Keywords\n");
for keywordNode in providerNode.getElementsByTagName('keyword'):
keywordName = keywordNode.getAttribute('name')
keywordMask = keywordNode.getAttribute('mask')
keywordSymbol = keywordNode.getAttribute('symbol')
Clrproviders.write("#define " + keywordSymbol + " " + keywordMask + "\n")
keywords.append("{ \"" + keywordName + "\", " + keywordMask + " }")
keywordsToMask[keywordName] = int(keywordMask, 16)
nbKeywords += 1
for eventNode in providerNode.getElementsByTagName('event'):
levelName = eventNode.getAttribute('level')
symbolName = eventNode.getAttribute('symbol')
keywords = eventNode.getAttribute('keywords')
level = convertToLevelId(levelName)
Clrproviders.write(("constexpr " if target_cpp else "static const ") + "EVENT_DESCRIPTOR " + symbolName + " = { " + str(level) + ", " + hex(getKeywordsMaskCombined(keywords, keywordsToMask)) + " };\n")
allProviders.append("&" + providerSymbol + "_LTTNG_Context")
# define and initialize runtime providers' DOTNET_TRACE_CONTEXT depending on the platform
if not is_windows and not runtimeFlavor.nativeaot:
Clrproviders.write('#define NB_PROVIDERS ' + str(nbProviders) + '\n')
Clrproviders.write(('constexpr ' if target_cpp else 'static const ') + 'LTTNG_TRACE_CONTEXT * ALL_LTTNG_PROVIDERS_CONTEXT[NB_PROVIDERS] = { ')
Clrproviders.write(', '.join(allProviders))
Clrproviders.write(' };\n')
clreventpipewriteevents = os.path.join(incDir, "clreventpipewriteevents.h")
with open_for_update(clreventpipewriteevents) as Clreventpipewriteevents:
Clreventpipewriteevents.write(stdprolog + "\n")
for providerNode in tree.getElementsByTagName('provider'):
providerName = providerNode.getAttribute('name')
templateNodes = providerNode.getElementsByTagName('template')
allTemplates = parseTemplateNodes(templateNodes)
eventNodes = providerNode.getElementsByTagName('event')
#eventpipe: create clreventpipewriteevents.h
Clreventpipewriteevents.write(generateClrEventPipeWriteEvents(eventNodes, allTemplates, extern, target_cpp, runtimeFlavor, providerName, inclusion_list) + "\n")
if user_events and runtimeFlavor.coreclr:
clrusereventswriteeventsPath = os.path.join(incDir, "clrusereventswriteevents.h")
with open_for_update(clrusereventswriteeventsPath) as clrusereventswriteevents:
clrusereventswriteevents.write(stdprolog + "\n")
for providerNode in tree.getElementsByTagName('provider'):
providerName = providerNode.getAttribute('name')
templateNodes = providerNode.getElementsByTagName('template')
allTemplates = parseTemplateNodes(templateNodes)
eventNodes = providerNode.getElementsByTagName('event')
#user_events: create clrusereventswriteevents.h
clrusereventswriteevents.write(generateClrUserEventsWriteEvents(eventNodes, allTemplates, extern, target_cpp, runtimeFlavor, providerName, inclusion_list) + "\n")
# Write secondary headers for FireEtXplat* and EventPipe* functions
if write_xplatheader:
clrxplatevents = os.path.join(incDir, "clrxplatevents.h")
with open_for_update(clrxplatevents) as Clrxplatevents:
Clrxplatevents.write(stdprolog + "\n")
for providerNode in tree.getElementsByTagName('provider'):
templateNodes = providerNode.getElementsByTagName('template')
allTemplates = parseTemplateNodes(templateNodes)
eventNodes = providerNode.getElementsByTagName('event')
#pal: create clrallevents.h
Clrxplatevents.write(generateClrXplatEvents(eventNodes, allTemplates, extern, runtimeFlavor) + "\n")
import argparse
import sys
def main(argv):
#parse the command line
parser = argparse.ArgumentParser(description="Generates the Code required to instrument LTTtng logging mechanism")
required = parser.add_argument_group('required arguments')
required.add_argument('--man', type=str, required=True,
help='full path to manifest containing the description of events')
required.add_argument('--incdir', type=str, default=None,
help='full path to directory where the header files will be generated')
required.add_argument('--inc', type=str,default="",
help='full path to inclusion list')
required.add_argument('--dummy', type=str,default=None,
help='full path to file that will have dummy definitions of FireEtw functions')
required.add_argument('--runtimeflavor', type=str,default="CoreCLR",
help='runtime flavor')
required.add_argument('--nonextern', action='store_true',
help='if specified, will not generated extern function stub headers' )
required.add_argument('--noxplatheader', action='store_true',
help='if specified, will not write a generated cross-platform header' )
required.add_argument('--userevents', action='store_true',
help='if specified, will emit support for user_events' )
args, unknown = parser.parse_known_args(argv)
if unknown:
print('Unknown argument(s): ', ', '.join(unknown))
return 1
sClrEtwAllMan = args.man
incdir = args.incdir
inclusion_filename = args.inc
etmDummyFile = args.dummy
runtimeFlavor = RuntimeFlavor(args.runtimeflavor)
extern = not args.nonextern
write_xplatheader = not args.noxplatheader
user_events = args.userevents
target_cpp = True
if runtimeFlavor.mono:
extern = False
target_cpp = False
write_xplatheader = False
inclusion_list = parseInclusionList(inclusion_filename)
generatePlatformIndependentFiles(sClrEtwAllMan, incdir, etmDummyFile, extern, write_xplatheader, target_cpp, runtimeFlavor, inclusion_list, user_events)
if __name__ == '__main__':
return_code = main(sys.argv[1:])
sys.exit(return_code)