|
|
@@ -0,0 +1,755 @@
|
|
|
+#-------------------------------------------------------------------------------------------------------
|
|
|
+# Copyright (C) Microsoft. All rights reserved.
|
|
|
+# Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
|
|
+#-------------------------------------------------------------------------------------------------------
|
|
|
+import xml.dom.minidom as DOM
|
|
|
+
|
|
|
+lttngDataTypeMapping = {
|
|
|
+ "win:null" :" ",
|
|
|
+ "win:Int64" :"const __int64",
|
|
|
+ "win:ULong" :"const unsigned long",
|
|
|
+ "win:count" :"*",
|
|
|
+ "win:Struct" :"const char *",
|
|
|
+ "win:GUID" :"const int",
|
|
|
+ "win:AnsiString" :"const char*",
|
|
|
+ "win:UnicodeString" :"const char*",
|
|
|
+ "win:Double" :"const double",
|
|
|
+ "win:Int32" :"const signed int",
|
|
|
+ "win:HexInt32" :"const signed int",
|
|
|
+ "win:Boolean" :"const bool",
|
|
|
+ "win:UInt64" :"const unsigned __int64",
|
|
|
+ "win:UInt32" :"const unsigned int",
|
|
|
+ "win:UInt16" :"const unsigned short",
|
|
|
+ "win:UInt8" :"const unsigned char",
|
|
|
+ "win:Int8" :"const char",
|
|
|
+ "win:Pointer" :"const uintptr_t",
|
|
|
+ "win:Binary" :"const char"
|
|
|
+}
|
|
|
+
|
|
|
+ctfDataTypeMapping = {
|
|
|
+ "win:Int64" :"ctf_integer",
|
|
|
+ "win:HexInt64" :"ctf_integer_hex",
|
|
|
+ "win:ULong" :"ctf_integer",
|
|
|
+ "win:count" :"ctf_sequence",
|
|
|
+ "win:Struct" :"ctf_sequence",
|
|
|
+ "win:GUID" :"ctf_sequence",
|
|
|
+ "win:AnsiString" :"ctf_string",
|
|
|
+ "win:UnicodeString" :"ctf_string",
|
|
|
+ "win:Double" :"ctf_float",
|
|
|
+ "win:Int32" :"ctf_integer",
|
|
|
+ "win:HexInt32" :"ctf_integer_hex",
|
|
|
+ "win:Boolean" :"ctf_integer",
|
|
|
+ "win:UInt64" :"ctf_integer",
|
|
|
+ "win:UInt32" :"ctf_integer",
|
|
|
+ "win:UInt16" :"ctf_integer",
|
|
|
+ "win:HexInt16" :"ctf_integer_hex",
|
|
|
+ "win:UInt8" :"ctf_integer", #actually a character
|
|
|
+ "win:Int8" :"ctf_integer", #actually a character
|
|
|
+ "win:Pointer" :"ctf_integer",
|
|
|
+ "win:Binary" :"ctf_sequence",
|
|
|
+ "xs:string" :"ctf_string",
|
|
|
+ "xs:unsignedLong" :"ctf_integer",
|
|
|
+ "xs:unsignedInt" :"ctf_integer"
|
|
|
+}
|
|
|
+
|
|
|
+palDataTypeMapping ={
|
|
|
+ "win:null" :" ",
|
|
|
+ "win:Int64" :"const __int64",
|
|
|
+ "win:ULong" :"const unsigned long",
|
|
|
+ "win:count" :"*",
|
|
|
+ "win:Struct" :"const void",
|
|
|
+ "win:GUID" :"const GUID",
|
|
|
+ "win:AnsiString" :"LPCSTR",
|
|
|
+ "win:UnicodeString" :"PCWSTR",
|
|
|
+ "win:Double" :"const double",
|
|
|
+ "win:Int32" :"const signed int",
|
|
|
+ "win:HexInt32" :"const signed int",
|
|
|
+ "win:Boolean" :"const bool",
|
|
|
+ "win:UInt64" :"const unsigned __int64",
|
|
|
+ "win:UInt32" :"const unsigned int",
|
|
|
+ "win:UInt16" :"const unsigned short",
|
|
|
+ "win:UInt8" :"const unsigned char",
|
|
|
+ "win:Int8" :"const char",
|
|
|
+ "win:Pointer" :"const void*",
|
|
|
+ "win:Binary" :"const char"
|
|
|
+ }
|
|
|
+
|
|
|
+MAX_LTTNG_ARGS = 10
|
|
|
+
|
|
|
+def getParamSequenceSize(paramSequence, estimate):
|
|
|
+ total = 0
|
|
|
+ pointers =0
|
|
|
+ for param in paramSequence:
|
|
|
+ if param in ["win:Int64", "win:UInt64", "win:Double"]:
|
|
|
+ total += 8
|
|
|
+ elif param in ["win:ULong", "win:Int32", "win:Boolean",]:
|
|
|
+ total += 4
|
|
|
+ elif param == "GUID":
|
|
|
+ total += 16
|
|
|
+ elif param in ["win:UInt16"]:
|
|
|
+ total += 2
|
|
|
+ elif param in ["win:Uint8", "win:Binary"]:
|
|
|
+ total += 1
|
|
|
+ elif param == "win:Pointer":
|
|
|
+ if estimate:
|
|
|
+ total += 8
|
|
|
+ else:
|
|
|
+ pointers += 1
|
|
|
+ elif estimate:
|
|
|
+ if param in ["win:AnsiString", "win:Struct"]:
|
|
|
+ total += 32
|
|
|
+ elif param in ["win:UnicodeString"]:
|
|
|
+ total += 64
|
|
|
+ else:
|
|
|
+ raise Exception ("Don't know size of " + param)
|
|
|
+
|
|
|
+ if estimate:
|
|
|
+ return total
|
|
|
+
|
|
|
+ return total, pointers
|
|
|
+
|
|
|
+class Template:
|
|
|
+ def __repr__(self):
|
|
|
+ return "<Template " + self.name + " />"
|
|
|
+
|
|
|
+ def __init__(self, name, prototypes, dependencies, structCounts, arrayCounts):
|
|
|
+ self.name = name
|
|
|
+ self.signature = FunctionSignature()
|
|
|
+ self.structCounts = structCounts
|
|
|
+ self.arrayCounts = arrayCounts
|
|
|
+
|
|
|
+ for variable in prototypes.paramList:
|
|
|
+ for dependency in dependencies[variable]:
|
|
|
+ if not self.signature.getParam(dependency):
|
|
|
+ self.signature.append(dependency, prototypes.getParam(dependency))
|
|
|
+ @property
|
|
|
+ def num_params(self):
|
|
|
+ return len(self.signature.paramList)
|
|
|
+
|
|
|
+ def getParam(self, name):
|
|
|
+ return self.signature.getParam(name)
|
|
|
+
|
|
|
+ @property
|
|
|
+ def estimatedSize(self):
|
|
|
+ total = getParamSequenceSize((self.getParam(paramName).winType for paramName in self.signature.paramList), True)
|
|
|
+
|
|
|
+ if total < 32:
|
|
|
+ return 32
|
|
|
+ elif total > 1024:
|
|
|
+ return 1024
|
|
|
+ return total
|
|
|
+
|
|
|
+class FunctionSignature:
|
|
|
+ def __repr__(self):
|
|
|
+ return ', '.join(self.paramList)
|
|
|
+
|
|
|
+ def __init__(self):
|
|
|
+ self.LUT = {}
|
|
|
+ self.paramList = []
|
|
|
+
|
|
|
+ def append(self, variable, param):
|
|
|
+ self.LUT[variable] = param
|
|
|
+ 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, outType, length):
|
|
|
+ self.winType = winType
|
|
|
+ self.outType = outType
|
|
|
+ self.name = name
|
|
|
+ self.length = length
|
|
|
+ self.count = "win:null"
|
|
|
+ if winType == "win:GUID" or count == "win:count":
|
|
|
+ self.count = "win:count"
|
|
|
+
|
|
|
+ignoredXmlAttributes = frozenset(["map"])
|
|
|
+usedXmlAttributes = frozenset(["name", "inType", "count", "length", "outType"])
|
|
|
+knownXmlAttributes = ignoredXmlAttributes | usedXmlAttributes
|
|
|
+
|
|
|
+def checkKnownAttributes(nodes, templateName):
|
|
|
+ for node in nodes:
|
|
|
+ nodeMap = node.attributes
|
|
|
+ for attribute in nodeMap.values():
|
|
|
+ if attribute.name not in knownXmlAttributes:
|
|
|
+ raise ValueError('Unknown attribute: ' + attribute.name + ' in template ' + templateName)
|
|
|
+
|
|
|
+def getTopLevelElementsByTagName(node, tag):
|
|
|
+ return [e for e in node.getElementsByTagName(tag) if e.parentNode == node]
|
|
|
+
|
|
|
+def parseTemplateNodes(templateNodes):
|
|
|
+ templates = {}
|
|
|
+
|
|
|
+ for templateNode in templateNodes:
|
|
|
+ templateName = templateNode.getAttribute('tid')
|
|
|
+ dataNodes = getTopLevelElementsByTagName(templateNode, 'data')
|
|
|
+
|
|
|
+ checkKnownAttributes(dataNodes, templateName)
|
|
|
+
|
|
|
+ functionPrototypes = FunctionSignature()
|
|
|
+
|
|
|
+ arrayCounts = {}
|
|
|
+ structCounts = {}
|
|
|
+ var_Dependencies = {}
|
|
|
+
|
|
|
+ for dataNode in dataNodes:
|
|
|
+ variable = dataNode.getAttribute('name')
|
|
|
+ wintype = dataNode.getAttribute('inType')
|
|
|
+ outType = dataNode.getAttribute('outType')
|
|
|
+
|
|
|
+ wincount = dataNode.getAttribute('count')
|
|
|
+ winLength = dataNode.getAttribute('length')
|
|
|
+
|
|
|
+ var_dependency = [variable]
|
|
|
+ if winLength:
|
|
|
+ if wincount:
|
|
|
+ raise Exception("Both count and length properties found on " + variable + " in template " + templateName)
|
|
|
+
|
|
|
+ if wincount.isdigit() and int(wincount) == 1:
|
|
|
+ wincount = ''
|
|
|
+
|
|
|
+ if wincount:
|
|
|
+ if wincount.isdigit():
|
|
|
+ raise Exception("Expect constant count to be length")
|
|
|
+ elif functionPrototypes.getParam(wincount):
|
|
|
+ var_dependency.insert(0, wincount)
|
|
|
+ arrayCounts[variable] = wincount
|
|
|
+
|
|
|
+
|
|
|
+ var_Dependencies[variable] = var_dependency
|
|
|
+ functionParameter = FunctionParameter(wintype, variable, wincount, outType, winLength)
|
|
|
+ functionPrototypes.append(variable, functionParameter)
|
|
|
+
|
|
|
+ structNodes = getTopLevelElementsByTagName(templateNode, 'struct')
|
|
|
+
|
|
|
+ for structNode in structNodes:
|
|
|
+ structName = structNode.getAttribute('name')
|
|
|
+ countName = structNode.getAttribute('count')
|
|
|
+
|
|
|
+ assert(countName in functionPrototypes.paramList)
|
|
|
+
|
|
|
+ #childData = structNode.getElementsByTagName("data")
|
|
|
+ #names = [x.attributes['name'].value for x in childData]
|
|
|
+ #types = [x.attributes['inType'].value for x in childData]
|
|
|
+
|
|
|
+ structCounts[structName] = countName
|
|
|
+ var_Dependencies[structName] = [countName, structName]
|
|
|
+ functionParameterPointer = FunctionParameter("win:Struct", structName, "win:count", None, None)
|
|
|
+ functionPrototypes.append(structName, functionParameterPointer)
|
|
|
+
|
|
|
+ templates[templateName] = Template(templateName, functionPrototypes, var_Dependencies, structCounts, arrayCounts)
|
|
|
+
|
|
|
+ return templates
|
|
|
+
|
|
|
+def shouldPackTemplate(template):
|
|
|
+ return template.num_params > MAX_LTTNG_ARGS or len(template.structCounts) > 0 or len(template.arrayCounts) > 0
|
|
|
+
|
|
|
+def generateArgList(template):
|
|
|
+ # Construct a TP_ARGS macro call, as defined in another macro, e.g.
|
|
|
+ #
|
|
|
+ # TP_ARGS( \
|
|
|
+ # int, my_integer_arg, \
|
|
|
+ # char*, my_string_arg \
|
|
|
+ # )
|
|
|
+ header = "TP_ARGS( \\\n"
|
|
|
+ footer = "\\\n)"
|
|
|
+
|
|
|
+ args = []
|
|
|
+
|
|
|
+ if shouldPackTemplate(template):
|
|
|
+ args.append(" const unsigned int, length")
|
|
|
+ args.append(" const char *, __data__")
|
|
|
+ else:
|
|
|
+ signature = template.signature
|
|
|
+ for param in signature.paramList:
|
|
|
+ functionParam = signature.getParam(param)
|
|
|
+ wintypeName = functionParam.winType
|
|
|
+ mappedType = lttngDataTypeMapping[wintypeName]
|
|
|
+ winCount = functionParam.count
|
|
|
+ mappedCount = lttngDataTypeMapping[winCount]
|
|
|
+
|
|
|
+ arg = " " + mappedType
|
|
|
+ if mappedCount != " ":
|
|
|
+ arg += mappedCount
|
|
|
+ elif functionParam.length:
|
|
|
+ arg += "*"
|
|
|
+ arg += ", " + functionParam.name
|
|
|
+
|
|
|
+ args.append(arg)
|
|
|
+
|
|
|
+ return header + ", \\\n".join(args) + footer
|
|
|
+
|
|
|
+def generateFieldList(template):
|
|
|
+ # Construct a TP_FIELDS macro call, e.g.
|
|
|
+ # TP_FIELDS(
|
|
|
+ # ctf_string(my_string_field, my_string_arg)
|
|
|
+ # ctf_integer(int, my_integer_field, my_integer_arg)
|
|
|
+ # )
|
|
|
+ header = " " + " TP_FIELDS(\n"
|
|
|
+ footer = "\n )"
|
|
|
+
|
|
|
+ fieldList = []
|
|
|
+
|
|
|
+ if shouldPackTemplate(template):
|
|
|
+ fieldList.append(" ctf_integer(unsigned long, length, length)")
|
|
|
+ fieldList.append(" ctf_sequence(char, __data__, __data__, unsigned long, length)")
|
|
|
+ else:
|
|
|
+ signature = template.signature
|
|
|
+ for param in signature.paramList:
|
|
|
+ functionParam = signature.getParam(param)
|
|
|
+ wintypeName = functionParam.winType
|
|
|
+ winCount = functionParam.count
|
|
|
+ mappedCount = lttngDataTypeMapping[winCount]
|
|
|
+ mappedType = lttngDataTypeMapping[wintypeName].replace("const ", "")
|
|
|
+
|
|
|
+ if functionParam.outType:
|
|
|
+ wintypeName = functionParam.outType
|
|
|
+
|
|
|
+ ctf_type = None
|
|
|
+ field_body = None
|
|
|
+ varname = functionParam.name
|
|
|
+
|
|
|
+ if param in template.structCounts or param in template.arrayCounts:
|
|
|
+ # This is a struct, treat as a sequence
|
|
|
+ countVar = template.structCounts.get(param, template.arrayCounts.get(param))
|
|
|
+ ctf_type = "ctf_sequence"
|
|
|
+ field_body = ", ".join((mappedType, varname, varname, "size_t", functionParam.prop))
|
|
|
+ elif functionParam.length:
|
|
|
+ ctf_type = "ctf_sequence"
|
|
|
+ field_body = ", ".join((mappedType, varname, varname, "size_t", functionParam.length))
|
|
|
+ else:
|
|
|
+ ctf_type = ctfDataTypeMapping[wintypeName]
|
|
|
+ if ctf_type == "ctf_string":
|
|
|
+ field_body = ", ".join((varname, varname))
|
|
|
+ elif ctf_type == "ctf_integer" or ctf_type == "ctf_integer_hex" or ctf_type == "ctf_float":
|
|
|
+ field_body = ", ".join((mappedType, varname, varname))
|
|
|
+ elif ctf_type == "ctf_sequence":
|
|
|
+ raise Exception("ctf_sequence needs special handling: " + template.name + " " + param)
|
|
|
+ else:
|
|
|
+ raise Exception("Unhandled ctf intrinsic: " + ctf_type)
|
|
|
+
|
|
|
+# fieldList.append("// " + wintypeName)
|
|
|
+ fieldList.append(" %s(%s)" % (ctf_type, field_body))
|
|
|
+
|
|
|
+ return header + "\n".join(fieldList) + footer
|
|
|
+
|
|
|
+def generateLttngHeader(providerName, lttngEventHeaderShortName, templates, events):
|
|
|
+ headerLines = []
|
|
|
+
|
|
|
+ headerLines.append("")
|
|
|
+ headerLines.append("#ifdef __int64")
|
|
|
+ headerLines.append("#if TARGET_64")
|
|
|
+ headerLines.append("#undef __int64")
|
|
|
+ headerLines.append("#else")
|
|
|
+ headerLines.append("#error \"Linux and OSX builds only support 64bit platforms\"")
|
|
|
+ headerLines.append("#endif // TARGET_64")
|
|
|
+ headerLines.append("#endif // __int64")
|
|
|
+ headerLines.append("#undef TRACEPOINT_PROVIDER")
|
|
|
+ headerLines.append("#undef TRACEPOINT_INCLUDE")
|
|
|
+ headerLines.append("")
|
|
|
+ headerLines.append("#define TRACEPOINT_PROVIDER " + providerName + "\n")
|
|
|
+ headerLines.append("#define TRACEPOINT_INCLUDE \"./" + lttngEventHeaderShortName + "\"\n\n")
|
|
|
+
|
|
|
+ headerLines.append("#if !defined(LTTNG_CHAKRA_H" + providerName + ") || defined(TRACEPOINT_HEADER_MULTI_READ)\n\n")
|
|
|
+ headerLines.append("#define LTTNG_CHAKRA_H" + providerName +"\n")
|
|
|
+
|
|
|
+ headerLines.append("\n#include <lttng/tracepoint.h>\n\n")
|
|
|
+
|
|
|
+
|
|
|
+ for templateName in templates:
|
|
|
+ template = templates[templateName]
|
|
|
+ functionSignature = template.signature
|
|
|
+
|
|
|
+ headerLines.append("")
|
|
|
+ headerLines.append("#define " + templateName + "_TRACEPOINT_ARGS \\")
|
|
|
+
|
|
|
+ tracepointArgs = generateArgList(template)
|
|
|
+ headerLines.append(tracepointArgs)
|
|
|
+
|
|
|
+ headerLines.append("TRACEPOINT_EVENT_CLASS(")
|
|
|
+ headerLines.append(" " + providerName + ",")
|
|
|
+ headerLines.append(" " + templateName + ",")
|
|
|
+ headerLines.append(" " + templateName + "_TRACEPOINT_ARGS,")
|
|
|
+ tracepointFields = generateFieldList(template)
|
|
|
+ headerLines.append(tracepointFields)
|
|
|
+ headerLines.append(")")
|
|
|
+
|
|
|
+ headerLines.append("#define " + templateName + "T_TRACEPOINT_INSTANCE(name) \\")
|
|
|
+ headerLines.append("TRACEPOINT_EVENT_INSTANCE(\\")
|
|
|
+ headerLines.append(" " + providerName + ",\\")
|
|
|
+ headerLines.append(" " + templateName + ",\\")
|
|
|
+ headerLines.append(" name,\\")
|
|
|
+ headerLines.append(" " + templateName + "_TRACEPOINT_ARGS \\")
|
|
|
+ headerLines.append(")")
|
|
|
+
|
|
|
+ headerLines.append("")
|
|
|
+ headerLines.append("")
|
|
|
+ headerLines.append("TRACEPOINT_EVENT_CLASS(")
|
|
|
+ headerLines.append(" " + providerName + ",")
|
|
|
+ headerLines.append(" emptyTemplate,")
|
|
|
+ headerLines.append(" TP_ARGS(),")
|
|
|
+ headerLines.append(" TP_FIELDS()")
|
|
|
+ headerLines.append(")")
|
|
|
+ headerLines.append("#define T_TRACEPOINT_INSTANCE(name) \\")
|
|
|
+ headerLines.append("TRACEPOINT_EVENT_INSTANCE(\\")
|
|
|
+ headerLines.append(" " + providerName + ",\\")
|
|
|
+ headerLines.append(" emptyTemplate,\\")
|
|
|
+ headerLines.append(" name,\\")
|
|
|
+ headerLines.append(" TP_ARGS()\\")
|
|
|
+ headerLines.append(")")
|
|
|
+
|
|
|
+ headerLines.append("")
|
|
|
+
|
|
|
+ for eventNode in events:
|
|
|
+ eventName = eventNode.getAttribute('symbol')
|
|
|
+ templateName = eventNode.getAttribute('template')
|
|
|
+
|
|
|
+ if not eventName:
|
|
|
+ raise Exception(eventNode + " event does not have a symbol")
|
|
|
+ if not templateName:
|
|
|
+ headerLines.append("T_TRACEPOINT_INSTANCE(" + eventName + ")")
|
|
|
+ continue
|
|
|
+
|
|
|
+ headerLines.append(templateName + "T_TRACEPOINT_INSTANCE(" + eventName + ")")
|
|
|
+
|
|
|
+ headerLines.append("#endif /* LTTNG_CHAKRA_H" + providerName + " */")
|
|
|
+ headerLines.append("#include <lttng/tracepoint-event.h>")
|
|
|
+
|
|
|
+ return "\n".join(headerLines)
|
|
|
+
|
|
|
+def generateMethodBody(template, providerName, eventName):
|
|
|
+ # Convert from ETW's windows types to LTTng compatiable types
|
|
|
+
|
|
|
+ methodBody = [""]
|
|
|
+
|
|
|
+ functionSignature = template.signature
|
|
|
+
|
|
|
+ if not shouldPackTemplate(template):
|
|
|
+ invocation = ["do_tracepoint(" + providerName, eventName]
|
|
|
+
|
|
|
+ for paramName in functionSignature.paramList:
|
|
|
+ functionParam = functionSignature.getParam(paramName)
|
|
|
+ wintypeName = functionParam.winType
|
|
|
+ winCount = functionParam.count
|
|
|
+
|
|
|
+ ctf_type = None
|
|
|
+
|
|
|
+ if functionParam.outType:
|
|
|
+ ctf_type = ctfDataTypeMapping.get(functionParam.outType)
|
|
|
+ else:
|
|
|
+ ctf_Type = ctfDataTypeMapping.get(winCount)
|
|
|
+
|
|
|
+ if not ctf_type:
|
|
|
+ ctf_type = ctfDataTypeMapping[wintypeName]
|
|
|
+
|
|
|
+ if ctf_type == "ctf_string" and wintypeName == "win:UnicodeString":
|
|
|
+ # Convert wchar unicode string to utf8
|
|
|
+ if functionParam.length:
|
|
|
+ methodBody.append("utf8::WideToNarrow " + paramName + "_converter(" + paramName + ", " + functionParam.length + ");")
|
|
|
+ else:
|
|
|
+ methodBody.append("utf8::WideToNarrow " + paramName + "_converter(" + paramName + ");")
|
|
|
+ invocation.append(paramName + "_converter")
|
|
|
+# elif ctf_type == "ctf_sequence" or wintypeName == "win:Pointer":
|
|
|
+ elif wintypeName == "win:Pointer":
|
|
|
+ invocation.append("(" + lttngDataTypeMapping[wintypeName] + lttngDataTypeMapping[winCount] + ")" + paramName)
|
|
|
+ else:
|
|
|
+ invocation.append(paramName)
|
|
|
+
|
|
|
+ methodBody.append(",\n ".join(invocation) + ");")
|
|
|
+ else:
|
|
|
+ # Packing results into buffer
|
|
|
+ methodBody.append("char stackBuffer[" + str(template.estimatedSize) + "];")
|
|
|
+ methodBody.append("char *buffer = stackBuffer;")
|
|
|
+ methodBody.append("int offset = 0;")
|
|
|
+ methodBody.append("int size = " + str(template.estimatedSize) + ";")
|
|
|
+ methodBody.append("bool fixedBuffer = true;")
|
|
|
+ methodBody.append("bool success = true;")
|
|
|
+
|
|
|
+ for paramName in functionSignature.paramList:
|
|
|
+ functionParameter = functionSignature.getParam(paramName)
|
|
|
+
|
|
|
+ if paramName in template.structCounts:
|
|
|
+ size = "(unsigned int)" + paramName + "_ElementSize * (unsigned int)" + template.structCounts[paramName]
|
|
|
+ methodBody.append("success &= WriteToBuffer((const char *)" + paramName + ", " + size + ", buffer, offset, size, fixedBuffer);")
|
|
|
+ elif paramName in template.arrayCounts:
|
|
|
+ size = "sizeof(" + lttngDataTypeMapping[functionParameter.winType] + ") * (unsigned int)" + template.arrayCounts[paramName]
|
|
|
+ methodBody.append("success &= WriteToBuffer((const char *)" + paramName + ", " + size + ", buffer, offset, size, fixedBuffer);")
|
|
|
+ elif functionParameter.winType == "win:GUID":
|
|
|
+ methodBody.append("success &= WriteToBuffer(*" + paramName + ", buffer, offset, size, fixedBuffer);")
|
|
|
+ else:
|
|
|
+ methodBody.append("success &= WriteToBuffer(" + paramName + ", buffer, offset, size, fixedBuffer);")
|
|
|
+
|
|
|
+ methodBody.append("if (!success)")
|
|
|
+ methodBody.append("{")
|
|
|
+ methodBody.append(" if (!fixedBuffer) delete[] buffer;")
|
|
|
+ methodBody.append(" return ERROR_WRITE_FAULT;")
|
|
|
+ methodBody.append("}")
|
|
|
+ methodBody.append("do_tracepoint(" + providerName + ", " + eventName + ", offset, buffer);")
|
|
|
+ methodBody.append("if (!fixedBuffer) delete[] buffer;")
|
|
|
+
|
|
|
+ return "\n ".join(methodBody) + "\n"
|
|
|
+
|
|
|
+def generateMethodSignature(template):
|
|
|
+ if not template:
|
|
|
+ return ""
|
|
|
+
|
|
|
+ functionSignature = template.signature
|
|
|
+ lineFunctionPrototype = []
|
|
|
+ for paramName in functionSignature.paramList:
|
|
|
+ functionParameter = functionSignature.getParam(paramName)
|
|
|
+ wintypeName = functionParameter.winType
|
|
|
+ mappedType = palDataTypeMapping[wintypeName]
|
|
|
+ winCount = functionParameter.count
|
|
|
+ mappedCount = palDataTypeMapping[winCount]
|
|
|
+
|
|
|
+ if paramName in template.structCounts:
|
|
|
+ lineFunctionPrototype.append(" int " + paramName + "_ElementSize")
|
|
|
+ # lineFunctionPrototype.append("// " + wintypeName + " " + str(functionParameter.length))
|
|
|
+ lineFunctionPrototype.append(
|
|
|
+ " " + mappedType
|
|
|
+ + (mappedCount if mappedCount != " " else "*" if functionParameter.length and not wintypeName in ["win:UnicodeString", "win:AnsiString"] else "")
|
|
|
+ + " "
|
|
|
+ + functionParameter.name)
|
|
|
+ return ",\n".join(lineFunctionPrototype)
|
|
|
+
|
|
|
+
|
|
|
+def generateLttngTracepointProvider(providerName, lttngHeader, templates, events):
|
|
|
+ providerLines = [];
|
|
|
+
|
|
|
+ providerLines.append("#define TRACEPOINT_DEFINE")
|
|
|
+ providerLines.append("#ifndef CHAKRA_STATIC_LIBRARY")
|
|
|
+ providerLines.append("#define TRACEPOINT_PROBE_DYNAMIC_LINKAGE")
|
|
|
+ providerLines.append("#endif")
|
|
|
+ providerLines.append("#include \"stdlib.h\"")
|
|
|
+ providerLines.append("#include \"Common.h\"")
|
|
|
+ providerLines.append("#include \"Codex/Utf8Helper.h\"")
|
|
|
+
|
|
|
+ providerLines.append("#include \"" + lttngHeader + "\"\n\n")
|
|
|
+ providerLines.append("#ifndef tracepoint_enabled")
|
|
|
+ providerLines.append("#define tracepoint_enabled(provider, name) 1")
|
|
|
+ providerLines.append("#define do_tracepoint tracepoint")
|
|
|
+ providerLines.append("#endif")
|
|
|
+
|
|
|
+ providerLines.append("""
|
|
|
+bool ResizeBuffer(char *&buffer, int&size, int currentLength, int newSize, bool &fixedBuffer)
|
|
|
+{
|
|
|
+ newSize *= 1.5;
|
|
|
+ _ASSERTE(newSize > size); // Check for overflow
|
|
|
+
|
|
|
+ if (newSize < 32)
|
|
|
+ {
|
|
|
+ newSize = 32;
|
|
|
+ }
|
|
|
+
|
|
|
+ char *newBuffer = new char[newSize];
|
|
|
+ memcpy(newBuffer, buffer, currentLength);
|
|
|
+
|
|
|
+ if (!fixedBuffer)
|
|
|
+ {
|
|
|
+ delete[] buffer;
|
|
|
+ }
|
|
|
+
|
|
|
+ buffer = newBuffer;
|
|
|
+ size = newSize;
|
|
|
+ fixedBuffer = false;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+bool WriteToBuffer(const char * src, int len, char *&buffer, int &offset, int &size, bool &fixedBuffer)
|
|
|
+{
|
|
|
+ if (!src)
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (offset + len > size)
|
|
|
+ {
|
|
|
+ if (!ResizeBuffer(buffer, size, offset, size+len, fixedBuffer))
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ memcpy(buffer + offset, src, len);
|
|
|
+ offset += len;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+template <typename T>
|
|
|
+bool WriteToBuffer(const T &value, char *&buffer, int&offset, int&size, bool &fixedBuffer)
|
|
|
+{
|
|
|
+ if (sizeof(T) + offset > size)
|
|
|
+ {
|
|
|
+ if (!ResizeBuffer(buffer, size, offset, size + sizeof(T), fixedBuffer))
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ *(T *)(buffer + offset) = value;
|
|
|
+ offset += sizeof(T);
|
|
|
+ return true;
|
|
|
+}
|
|
|
+""")
|
|
|
+
|
|
|
+ for eventNode in events:
|
|
|
+ eventName = eventNode.getAttribute('symbol')
|
|
|
+ templateName = eventNode.getAttribute('template')
|
|
|
+
|
|
|
+ providerLines.append("extern \"C\" bool EventXplatEnabled%s(){ return tracepoint_enabled(%s, %s);}"
|
|
|
+ % (eventName, providerName, eventName))
|
|
|
+ providerLines.append("")
|
|
|
+
|
|
|
+ template = None
|
|
|
+ if templateName:
|
|
|
+ template = templates[templateName]
|
|
|
+
|
|
|
+ providerLines.append("extern \"C\" unsigned long FireEtXplat" + eventName + "(")
|
|
|
+ providerLines.append(generateMethodSignature(template))
|
|
|
+ providerLines.append(")")
|
|
|
+ providerLines.append("{")
|
|
|
+ providerLines.append(" if (!EventXplatEnabled" + eventName + "())")
|
|
|
+ providerLines.append(" return ERROR_SUCCESS;")
|
|
|
+
|
|
|
+ if template:
|
|
|
+ providerLines.append(generateMethodBody(template, providerName, eventName))
|
|
|
+ else:
|
|
|
+ providerLines.append(" do_tracepoint(" + providerName + ", " + eventName +");")
|
|
|
+
|
|
|
+ providerLines.append("")
|
|
|
+ providerLines.append(" return ERROR_SUCCESS;")
|
|
|
+ providerLines.append("}")
|
|
|
+ providerLines.append("")
|
|
|
+
|
|
|
+ return "\n".join(providerLines)
|
|
|
+
|
|
|
+def generateEtwHeader(templates, events):
|
|
|
+ headerLines = []
|
|
|
+
|
|
|
+ headerLines.append("#include \"pal.h\"")
|
|
|
+ headerLines.append("")
|
|
|
+
|
|
|
+ for event in events:
|
|
|
+ eventName = event.getAttribute('symbol')
|
|
|
+ templateName = event.getAttribute('template')
|
|
|
+
|
|
|
+ template = None
|
|
|
+ if templateName:
|
|
|
+ template = templates[templateName]
|
|
|
+
|
|
|
+ callArgs = []
|
|
|
+ if template:
|
|
|
+ functionSignature = template.signature
|
|
|
+ for param in functionSignature.paramList:
|
|
|
+ if param in template.structCounts:
|
|
|
+ callArgs.append(param + "_ElementSize")
|
|
|
+ callArgs.append(param)
|
|
|
+
|
|
|
+ headerLines.append("extern \"C\" bool EventXplatEnabled" + eventName +"();")
|
|
|
+ headerLines.append("inline bool EventEnabled" + eventName +"() { return EventXplatEnabled" + eventName + "();}")
|
|
|
+ headerLines.append("")
|
|
|
+ headerLines.append("extern \"C\" unsigned long FireEtXplat" + eventName +" (")
|
|
|
+ headerLines.append(generateMethodSignature(template))
|
|
|
+ headerLines.append(");")
|
|
|
+ headerLines.append("inline unsigned long EventWrite" + eventName + "(")
|
|
|
+ headerLines.append(generateMethodSignature(template))
|
|
|
+ headerLines.append(")")
|
|
|
+ headerLines.append("{")
|
|
|
+ headerLines.append(" return FireEtXplat" + eventName + "(" + ", ".join(callArgs) + ");")
|
|
|
+ headerLines.append("}")
|
|
|
+ headerLines.append("")
|
|
|
+
|
|
|
+
|
|
|
+ return "\n".join(headerLines)
|
|
|
+
|
|
|
+def generateCmakeFile(providerName):
|
|
|
+ cmakeLines = []
|
|
|
+ cmakeLines.append("project(Chakra.LTTng)")
|
|
|
+ cmakeLines.append("")
|
|
|
+ cmakeLines.append("add_compile_options(-fPIC)")
|
|
|
+ cmakeLines.append("")
|
|
|
+ cmakeLines.append("add_library (Chakra.LTTng OBJECT")
|
|
|
+ cmakeLines.append(" eventprovider" + providerName + ".cpp")
|
|
|
+ cmakeLines.append(" tracepointprovider" + providerName + ".cpp")
|
|
|
+ cmakeLines.append(")")
|
|
|
+
|
|
|
+ return "\n".join(cmakeLines)
|
|
|
+
|
|
|
+def generateLttngFiles(manifest, providerDirectory):
|
|
|
+ import os
|
|
|
+ tree = DOM.parse(manifest)
|
|
|
+
|
|
|
+ if not os.path.exists(providerDirectory):
|
|
|
+ os.makedirs(providerDirectory)
|
|
|
+
|
|
|
+ if not os.path.exists(providerDirectory + "/lttng"):
|
|
|
+ os.makedirs(providerDirectory + "/lttng")
|
|
|
+
|
|
|
+ for providerNode in tree.getElementsByTagName("provider"):
|
|
|
+ providerName = providerNode.getAttribute("name")
|
|
|
+ providerName = providerName.replace("Microsoft-", "")
|
|
|
+
|
|
|
+ providerNameFile = providerName.lower()
|
|
|
+
|
|
|
+ lttngEventHeaderShortName = "tp" + providerNameFile + ".h"
|
|
|
+ lttngEventHeaderPath = providerDirectory + "/lttng/" + lttngEventHeaderShortName
|
|
|
+ lttngEventProvider = providerDirectory + "/lttng/eventprovider" + providerNameFile + ".cpp"
|
|
|
+ lttngEventProviderTrace = providerDirectory + "/lttng/tracepointprovider" + providerNameFile + ".cpp"
|
|
|
+ lttngEtwHeaderFile = providerDirectory + "/lttng/" + providerNameFile + "Etw.h"
|
|
|
+ lttngCmakeFile = providerDirectory + "/lttng/CMakeLists.txt"
|
|
|
+
|
|
|
+ lttngHeader = open(lttngEventHeaderPath, "w")
|
|
|
+ lttngImplementation = open(lttngEventProvider, "w")
|
|
|
+ lttngTraceImplementation = open(lttngEventProviderTrace, "w")
|
|
|
+ lttngEtwHeader = open(lttngEtwHeaderFile, "w")
|
|
|
+ lttngCmake = open(lttngCmakeFile, "w")
|
|
|
+
|
|
|
+ # Create the lttng implementation
|
|
|
+ lttngTraceImplementation.write("#define TRACEPOINT_CREATE_PROBES\n")
|
|
|
+ lttngTraceImplementation.write("#include \"./"+lttngEventHeaderShortName+"\"\n")
|
|
|
+ lttngTraceImplementation.close()
|
|
|
+
|
|
|
+ # Create the lttng header
|
|
|
+
|
|
|
+ templateNodes = providerNode.getElementsByTagName('template')
|
|
|
+ eventNodes = providerNode.getElementsByTagName('event')
|
|
|
+
|
|
|
+ allTemplates = parseTemplateNodes(templateNodes)
|
|
|
+
|
|
|
+ lttngHeader.write(generateLttngHeader(providerName, lttngEventHeaderShortName, allTemplates, eventNodes))
|
|
|
+ lttngHeader.close();
|
|
|
+
|
|
|
+ lttngImplementation.write(generateLttngTracepointProvider(providerName, lttngEventHeaderShortName, allTemplates, eventNodes))
|
|
|
+ lttngImplementation.close();
|
|
|
+
|
|
|
+ lttngEtwHeader.write(generateEtwHeader(allTemplates, eventNodes))
|
|
|
+ lttngEtwHeader.close()
|
|
|
+
|
|
|
+ # Note: This in particular assumes that there is only one ETW provider
|
|
|
+ lttngCmake.write(generateCmakeFile(providerNameFile))
|
|
|
+ lttngCmake.close()
|
|
|
+
|
|
|
+if __name__ == '__main__':
|
|
|
+ import argparse
|
|
|
+ import sys
|
|
|
+
|
|
|
+ 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 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(sys.argv[1:])
|
|
|
+ if unknown:
|
|
|
+ print('Unknown argument(s): ', ', '.join(unknown))
|
|
|
+ sys.exit(1)
|
|
|
+
|
|
|
+ generateLttngFiles(args.man, args.intermediate)
|
|
|
+ sys.exit(0)
|