Procházet zdrojové kódy

Enable support for ETW events on xplat via LTTng

Running build.sh with the --lttng flag will generate ETW-like event emitting
functions that produce LTTng events. This means that you can get improved
diagnostics on non-windows platforms like so:

```bash
./build.sh --lttng # + whatever other flags
lttng create mySession
lttng enable-event -u "JScript:*" # or more specific events specified in the ETW manifest
lttng start
out/Release/ch script.js
lttng stop
lttng view
```
Jimmy Thomson před 8 roky
rodič
revize
6756e7d8fb

+ 16 - 0
CMakeLists.txt

@@ -495,5 +495,21 @@ add_definitions(
     -DNO_PAL_MINMAX
     -DPAL_STDCPP_COMPAT
     )
+
+if (ENABLE_JS_LTTNG_SH)
+    unset(ENABLE_JS_LTTNG_SH CACHE)
+    include_directories (
+      ${CMAKE_CURRENT_SOURCE_DIR}/out/lttng
+    )
+    add_subdirectory ($ENV{TARGET_PATH}/lttng ${CMAKE_CURRENT_BINARY_DIR}/lttng)
+
+    add_definitions(
+      -DENABLE_JS_ETW
+      -DENABLE_JS_LTTNG
+    )
+    set(USE_LTTNG "1")
+endif()
+
 add_subdirectory (lib)
+
 add_subdirectory (bin)

+ 1 - 1
bin/GCStress/StubExternalApi.cpp

@@ -21,7 +21,7 @@ void ConfigParserAPI::DisplayInitialOutput(__in LPWSTR moduleName)
     Output::Print(_u("INIT: DLL Path   : %s\n"), moduleName);
 }
 
-#ifdef ENABLE_JS_ETW
+#if defined(ENABLE_JS_ETW) && !defined(ENABLE_JS_LTTNG)
 void EtwCallbackApi::OnSessionChange(ULONG /* controlCode */, PVOID /* callbackContext */)
 {
     // Does nothing

+ 17 - 1
build.sh

@@ -52,6 +52,7 @@ PRINT_USAGE() {
     echo "     --libs-only       Do not build CH and GCStress"
     echo "     --lto             Enables LLVM Full LTO"
     echo "     --lto-thin        Enables LLVM Thin LTO - xcode 8+ or clang 3.9+"
+    echo "     --lttng           Enables LTTng support for ETW events"
     echo "     --static          Build as static library. Default: shared library"
     echo "     --sanitize=CHECKS Build with clang -fsanitize checks,"
     echo "                       e.g. undefined,signed-integer-overflow."
@@ -104,6 +105,7 @@ OS_LINUX=0
 OS_APT_GET=0
 OS_UNIX=0
 LTO=""
+LTTNG=""
 TARGET_OS=""
 ENABLE_CC_XPLAT_TRACE=""
 WB_CHECK=
@@ -230,6 +232,11 @@ while [[ $# -gt 0 ]]; do
         HAS_LTO=1
         ;;
 
+    --lttng)
+        LTTNG="-DENABLE_JS_LTTNG_SH=1"
+        HAS_LTTNG=1
+        ;;
+    
     -n | --ninja)
         CMAKE_GEN="-G Ninja"
         MAKE=ninja
@@ -516,6 +523,15 @@ else
         exit 1
     fi
 fi
+export TARGET_PATH
+
+if [[ $HAS_LTTNG == 1 ]]; then
+    CHAKRACORE_ROOT=`dirname $0`
+    python $CHAKRACORE_ROOT/tools/lttng.py --man $CHAKRACORE_ROOT/manifests/Microsoft-Scripting-Chakra-Instrumentation.man --intermediate $TARGET_PATH/intermediate
+    mkdir -p $TARGET_PATH/lttng
+    (diff -q $TARGET_PATH/intermediate/lttng/jscriptEtw.h $TARGET_PATH/lttng/jscriptEtw.h && echo "jscriptEtw.h up to date; skipping") || cp $TARGET_PATH/intermediate/lttng/* $TARGET_PATH/lttng/
+fi
+
 
 BUILD_DIRECTORY="${TARGET_PATH}/${BUILD_TYPE:0}"
 echo "Build path: ${BUILD_DIRECTORY}"
@@ -602,7 +618,7 @@ fi
 
 echo Generating $BUILD_TYPE makefiles
 echo $EXTRA_DEFINES
-cmake $CMAKE_GEN $CC_PREFIX $ICU_PATH $LTO $STATIC_LIBRARY $ARCH $TARGET_OS \
+cmake $CMAKE_GEN $CC_PREFIX $ICU_PATH $LTO $LTTNG $STATIC_LIBRARY $ARCH $TARGET_OS \
     $ENABLE_CC_XPLAT_TRACE $EXTRA_DEFINES -DCMAKE_BUILD_TYPE=$BUILD_TYPE $SANITIZE $NO_JIT $INTL_ICU \
     $WITHOUT_FEATURES $WB_FLAG $WB_ARGS $CMAKE_EXPORT_COMPILE_COMMANDS $LIBS_ONLY_BUILD\
     $VALGRIND $BUILD_RELATIVE_DIRECTORY

+ 12 - 0
lib/CMakeLists.txt

@@ -14,6 +14,10 @@ if(CAN_BUILD_WABT)
     set(wabt_includes ${CHAKRACORE_SOURCE_DIR}/lib/wabt)
 endif()
 
+if (USE_LTTNG)
+    set(lttng_objects $<TARGET_OBJECTS:Chakra.LTTng>)
+endif()
+
 add_library (ChakraCoreStatic STATIC
   ChakraCoreStatic.cpp
   $<TARGET_OBJECTS:Chakra.Pal>
@@ -38,8 +42,16 @@ add_library (ChakraCoreStatic STATIC
   $<TARGET_OBJECTS:Chakra.Parser>
   ${wasm_objects}
   ${wabt_objects}
+  ${lttng_objects}
 )
 
+if(USE_LTTNG)
+    target_link_libraries(ChakraCoreStatic
+      -llttng-ust
+      -ldl
+    )
+endif()
+
 if(CC_TARGET_OS_OSX)
   target_link_libraries(ChakraCoreStatic
     "-framework CoreFoundation"

+ 3 - 1
lib/Common/Core/EtwTraceCore.cpp

@@ -6,6 +6,7 @@
 #include "Core/EtwTraceCore.h"
 
 #ifdef ENABLE_JS_ETW
+#ifndef ENABLE_JS_LTTNG
 extern "C" {
     ETW_INLINE
         VOID EtwCallback(
@@ -64,4 +65,5 @@ void EtwTraceCore::UnRegister()
     }
 }
 
-#endif
+#endif // !ENABLE_JS_LTTNG
+#endif // ENABLE_JS_ETW

+ 5 - 0
lib/Common/Core/EtwTraceCore.h

@@ -47,6 +47,10 @@
 #define JS_ETW(s) s
 #define IS_JS_ETW(s) s
 
+#ifdef ENABLE_JS_LTTNG
+#include "jscriptEtw.h"
+
+#else
 // C-style callback
 extern "C" {
     void EtwCallback(
@@ -87,6 +91,7 @@ public:
 
     static bool s_registered;
 };
+#endif // ENABLE_JS_LTTNG
 
 #else
 #define GCETW(e, ...)

+ 5 - 3
lib/Common/Memory/Recycler.cpp

@@ -5968,7 +5968,8 @@ Recycler::ThreadProc()
     }
 #endif
 
-#ifdef ENABLE_JS_ETW
+#if defined(ENABLE_JS_ETW) && ! defined(ENABLE_JS_LTTNG)
+    // LTTng has no concept of EventActivityIdControl
     // Create an ETW ActivityId for this thread, to help tools correlate ETW events we generate
     GUID activityId = { 0 };
     auto eventActivityIdControlResult = EventActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_SET_ID, &activityId);
@@ -6536,7 +6537,8 @@ RecyclerParallelThread::StaticThreadProc(LPVOID lpParameter)
             dllHandle = NULL;
         }
 #endif
-#ifdef ENABLE_JS_ETW
+#if defined(ENABLE_JS_ETW) && ! defined(ENABLE_JS_LTTNG)
+        // LTTng has no concept of EventActivityIdControl
         // Create an ETW ActivityId for this thread, to help tools correlate ETW events we generate
         GUID activityId = { 0 };
         auto eventActivityIdControlResult = EventActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_SET_ID, &activityId);
@@ -8757,4 +8759,4 @@ template char* Recycler::AllocZeroWithAttributesInlined<RecyclerVisitedHostTrace
 template char* Recycler::AllocZeroWithAttributesInlined<RecyclerVisitedHostFinalizableBits, /* nothrow = */true>(size_t);
 template char* Recycler::AllocZeroWithAttributesInlined<RecyclerVisitedHostTracedBits, /* nothrow = */true>(size_t);
 template char* Recycler::AllocZeroWithAttributesInlined<LeafBit, /* nothrow = */true>(size_t);
-#endif
+#endif

+ 1 - 1
lib/Jsrt/JsrtHelper.cpp

@@ -143,7 +143,7 @@ void JsrtCallbackState::ObjectBeforeCallectCallbackWrapper(JsObjectBeforeCollect
             ConfigParser::ParseOnModuleLoad(parser, mod);
         }
 
-    #ifdef ENABLE_JS_ETW
+    #if defined(ENABLE_JS_ETW) && !defined(ENABLE_JS_LTTNG)
         EtwTrace::Register();
     #endif
     #ifdef VTUNE_PROFILING

+ 7 - 1
lib/Runtime/Base/EtwTrace.cpp

@@ -10,6 +10,7 @@
 
 using namespace Js;
 
+#ifndef ENABLE_JS_LTTNG
 //
 // This C style callback is invoked by ETW when a trace session is started/stopped
 // by an ETW controller for the Jscript and MSHTML providers.
@@ -47,6 +48,7 @@ void EtwCallbackApi::OnSessionChange(ULONG controlCode, PVOID callbackContext)
         }
     }
 }
+#endif
 
 //
 // Registers the ETW provider - this is usually done on Jscript DLL load
@@ -54,7 +56,9 @@ void EtwCallbackApi::OnSessionChange(ULONG controlCode, PVOID callbackContext)
 //
 void EtwTrace::Register()
 {
+#ifndef ENABLE_JS_LTTNG
     EtwTraceCore::Register();
+#endif
 
 #ifdef TEST_ETW_EVENTS
     TestEtwEventSink::Load();
@@ -66,8 +70,10 @@ void EtwTrace::Register()
 //
 void EtwTrace::UnRegister()
 {
+#ifndef ENABLE_JS_LTTNG
     EtwTraceCore::UnRegister();
-
+#endif
+    
 #ifdef TEST_ETW_EVENTS
     TestEtwEventSink::Unload();
 #endif

+ 755 - 0
tools/lttng.py

@@ -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)