diff options
Diffstat (limited to 'src/scripts/genEventPipe.py')
-rw-r--r-- | src/scripts/genEventPipe.py | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/src/scripts/genEventPipe.py b/src/scripts/genEventPipe.py new file mode 100644 index 0000000000..a00511d95d --- /dev/null +++ b/src/scripts/genEventPipe.py @@ -0,0 +1,495 @@ +from __future__ import print_function +from genXplatEventing import * +from genXplatLttng import * +import os +import xml.dom.minidom as DOM + +stdprolog = """// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************** + +DO NOT MODIFY. AUTOGENERATED FILE. +This file is generated using the logic from <root>/src/scripts/genEventPipe.py + +******************************************************************/ +""" + +stdprolog_cmake = """# +# +#****************************************************************** + +#DO NOT MODIFY. AUTOGENERATED FILE. +#This file is generated using the logic from <root>/src/scripts/genEventPipe.py + +#****************************************************************** +""" + + +def generateClrEventPipeWriteEventsImpl( + providerName, eventNodes, allTemplates, exclusionListFile): + providerPrettyName = providerName.replace("Windows-", '') + providerPrettyName = providerPrettyName.replace("Microsoft-", '') + providerPrettyName = providerPrettyName.replace('-', '_') + WriteEventImpl = [] + + # EventPipeEvent declaration + for eventNode in eventNodes: + eventName = eventNode.getAttribute('symbol') + WriteEventImpl.append( + "EventPipeEvent *EventPipeEvent" + + eventName + + " = nullptr;\n") + + for eventNode in eventNodes: + eventName = eventNode.getAttribute('symbol') + templateName = eventNode.getAttribute('template') + + # generate EventPipeEventEnabled function + eventEnabledImpl = """bool EventPipeEventEnabled%s() +{ + return EventPipeEvent%s->IsEnabled(); +} + +""" % (eventName, eventName) + WriteEventImpl.append(eventEnabledImpl) + + # generate EventPipeWriteEvent function + fnptype = [] + linefnptype = [] + fnptype.append("extern \"C\" ULONG EventPipeWriteEvent") + fnptype.append(eventName) + fnptype.append("(\n") + + if templateName: + template = allTemplates[templateName] + else: + template = None + + if template: + fnSig = template.signature + for paramName in fnSig.paramlist: + fnparam = fnSig.getParam(paramName) + wintypeName = fnparam.winType + typewName = palDataTypeMapping[wintypeName] + winCount = fnparam.count + countw = palDataTypeMapping[winCount] + + if paramName in template.structs: + linefnptype.append( + "%sint %s_ElementSize,\n" % + (lindent, paramName)) + + linefnptype.append(lindent) + linefnptype.append(typewName) + if countw != " ": + linefnptype.append(countw) + + linefnptype.append(" ") + linefnptype.append(fnparam.name) + linefnptype.append(",\n") + + if len(linefnptype) > 0: + del linefnptype[-1] + + fnptype.extend(linefnptype) + fnptype.append(")\n{\n") + checking = """ if (!EventPipeEventEnabled%s()) + return ERROR_SUCCESS; +""" % (eventName) + + fnptype.append(checking) + + WriteEventImpl.extend(fnptype) + + if template: + body = generateWriteEventBody(template, providerName, eventName) + WriteEventImpl.append(body) + else: + WriteEventImpl.append( + " EventPipe::WriteEvent(*EventPipeEvent" + + eventName + + ", nullptr, 0);\n") + + WriteEventImpl.append("\n return ERROR_SUCCESS;\n}\n\n") + + # EventPipeProvider and EventPipeEvent initialization + WriteEventImpl.append( + "extern \"C\" void Init" + + providerPrettyName + + "()\n{\n") + WriteEventImpl.append( + " EventPipeProvider" + + providerPrettyName + + " = EventPipe::CreateProvider(" + + providerPrettyName + + "GUID);\n") + for eventNode in eventNodes: + eventName = eventNode.getAttribute('symbol') + templateName = eventNode.getAttribute('template') + eventKeywords = eventNode.getAttribute('keywords') + eventKeywordsMask = generateEventKeywords(eventKeywords) + eventValue = eventNode.getAttribute('value') + eventVersion = eventNode.getAttribute('version') + eventLevel = eventNode.getAttribute('level') + eventLevel = eventLevel.replace("win:", "EventPipeEventLevel::") + exclusionInfo = parseExclusionList(exclusionListFile) + taskName = eventNode.getAttribute('task') + + initEvent = """ EventPipeEvent%s = EventPipeProvider%s->AddEvent(%s,%s,%s,%s); +""" % (eventName, providerPrettyName, eventValue, eventKeywordsMask, eventVersion, eventLevel) + + WriteEventImpl.append(initEvent) + WriteEventImpl.append("}") + + return ''.join(WriteEventImpl) + + +def generateWriteEventBody(template, providerName, eventName): + header = """ + char stackBuffer[%s]; + char *buffer = stackBuffer; + unsigned int offset = 0; + unsigned int size = %s; + bool fixedBuffer = true; + + bool success = true; +""" % (template.estimated_size, template.estimated_size) + + fnSig = template.signature + pack_list = [] + for paramName in fnSig.paramlist: + parameter = fnSig.getParam(paramName) + + if paramName in template.structs: + size = "(int)%s_ElementSize * (int)%s" % ( + paramName, parameter.prop) + if template.name in specialCaseSizes and paramName in specialCaseSizes[template.name]: + size = "(int)(%s)" % specialCaseSizes[template.name][paramName] + pack_list.append( + " success &= WriteToBuffer((const BYTE *)%s, %s, buffer, offset, size, fixedBuffer);" % + (paramName, size)) + elif paramName in template.arrays: + size = "sizeof(%s) * (int)%s" % ( + lttngDataTypeMapping[parameter.winType], + parameter.prop) + if template.name in specialCaseSizes and paramName in specialCaseSizes[template.name]: + size = "(int)(%s)" % specialCaseSizes[template.name][paramName] + pack_list.append( + " success &= WriteToBuffer((const BYTE *)%s, %s, buffer, offset, size, fixedBuffer);" % + (paramName, size)) + elif parameter.winType == "win:GUID": + pack_list.append( + " success &= WriteToBuffer(*%s, buffer, offset, size, fixedBuffer);" % + (parameter.name,)) + else: + pack_list.append( + " success &= WriteToBuffer(%s, buffer, offset, size, fixedBuffer);" % + (parameter.name,)) + + code = "\n".join(pack_list) + "\n\n" + + checking = """ if (!success) + { + if (!fixedBuffer) + delete[] buffer; + return ERROR_WRITE_FAULT; + }\n\n""" + + body = " EventPipe::WriteEvent(*EventPipeEvent" + \ + eventName + ", (BYTE *)buffer, size);\n" + + footer = """ + if (!fixedBuffer) + delete[] buffer; +""" + + return header + code + checking + body + footer + +providerGUIDMap = {} +providerGUIDMap[ + "{e13c0d23-ccbc-4e12-931b-d9cc2eee27e4}"] = "{0xe13c0d23,0xccbc,0x4e12,{0x93,0x1b,0xd9,0xcc,0x2e,0xee,0x27,0xe4}}" +providerGUIDMap[ + "{A669021C-C450-4609-A035-5AF59AF4DF18}"] = "{0xA669021C,0xC450,0x4609,{0xA0,0x35,0x5A,0xF5,0x9A,0xF4,0xDF,0x18}}" +providerGUIDMap[ + "{CC2BCBBA-16B6-4cf3-8990-D74C2E8AF500}"] = "{0xCC2BCBBA,0x16B6,0x4cf3,{0x89,0x90,0xD7,0x4C,0x2E,0x8A,0xF5,0x00}}" +providerGUIDMap[ + "{763FD754-7086-4dfe-95EB-C01A46FAF4CA}"] = "{0x763FD754,0x7086,0x4dfe,{0x95,0xEB,0xC0,0x1A,0x46,0xFA,0xF4,0xCA}}" + + +def generateGUID(tmpGUID): + return providerGUIDMap[tmpGUID] + +keywordMap = {} + + +def generateEventKeywords(eventKeywords): + mask = 0 + # split keywords if there are multiple + allKeywords = eventKeywords.split() + + for singleKeyword in allKeywords: + mask = mask | keywordMap[singleKeyword] + + return mask + + +def generateEventPipeCmakeFile(etwmanifest, eventpipe_directory): + tree = DOM.parse(etwmanifest) + + with open(eventpipe_directory + "CMakeLists.txt", 'w') as topCmake: + topCmake.write(stdprolog_cmake + "\n") + topCmake.write("""cmake_minimum_required(VERSION 2.8.12.2) + + project(eventpipe) + + set(CMAKE_INCLUDE_CURRENT_DIR ON) + include_directories(${CLR_DIR}/src/vm) + + add_library(eventpipe + STATIC\n""") + + for providerNode in tree.getElementsByTagName('provider'): + providerName = providerNode.getAttribute('name') + providerName = providerName.replace("Windows-", '') + providerName = providerName.replace("Microsoft-", '') + + providerName_File = providerName.replace('-', '') + providerName_File = providerName_File.lower() + + topCmake.write(' "%s.cpp"\n' % (providerName_File)) + topCmake.write(' "eventpipehelpers.cpp"\n') + topCmake.write(""" ) + + # Install the static eventpipe library + install(TARGETS eventpipe DESTINATION lib) + """) + + topCmake.close() + + +def generateEventPipeHelperFile(etwmanifest, eventpipe_directory): + with open(eventpipe_directory + "eventpipehelpers.cpp", 'w') as helper: + helper.write(stdprolog) + helper.write(""" +#include "stdlib.h" + +bool ResizeBuffer(char *&buffer, unsigned int& size, unsigned int currLen, unsigned 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, currLen); + + if (!fixedBuffer) + delete[] buffer; + + buffer = newBuffer; + size = newSize; + fixedBuffer = false; + + return true; +} + +bool WriteToBuffer(const BYTE *src, unsigned int len, char *&buffer, unsigned int& offset, unsigned 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; +} + +bool WriteToBuffer(PCWSTR str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer) +{ + if(!str) return true; + unsigned int byteCount = (PAL_wcslen(str) + 1) * sizeof(*str); + + if (offset + byteCount > size) + { + if (!ResizeBuffer(buffer, size, offset, size + byteCount, fixedBuffer)) + return false; + } + + memcpy(buffer + offset, str, byteCount); + offset += byteCount; + return true; +} + +bool WriteToBuffer(const char *str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer) +{ + if(!str) return true; + unsigned int len = strlen(str) + 1; + if (offset + len > size) + { + if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer)) + return false; + } + + memcpy(buffer + offset, str, len); + offset += len; + return true; +} + +""") + + tree = DOM.parse(etwmanifest) + + for providerNode in tree.getElementsByTagName('provider'): + providerName = providerNode.getAttribute('name') + providerPrettyName = providerName.replace("Windows-", '') + providerPrettyName = providerPrettyName.replace("Microsoft-", '') + providerPrettyName = providerPrettyName.replace('-', '_') + helper.write( + "extern \"C\" void Init" + + providerPrettyName + + "();\n\n") + + helper.write("extern \"C\" void InitProvidersAndEvents()\n{\n") + for providerNode in tree.getElementsByTagName('provider'): + providerName = providerNode.getAttribute('name') + providerPrettyName = providerName.replace("Windows-", '') + providerPrettyName = providerPrettyName.replace("Microsoft-", '') + providerPrettyName = providerPrettyName.replace('-', '_') + helper.write(" Init" + providerPrettyName + "();\n") + helper.write("}") + + helper.close() + + +def generateEventPipeImplFiles( + etwmanifest, eventpipe_directory, exclusionListFile): + tree = DOM.parse(etwmanifest) + coreclrRoot = os.getcwd() + for providerNode in tree.getElementsByTagName('provider'): + providerGUID = providerNode.getAttribute('guid') + providerGUID = generateGUID(providerGUID) + providerName = providerNode.getAttribute('name') + + providerPrettyName = providerName.replace("Windows-", '') + providerPrettyName = providerPrettyName.replace("Microsoft-", '') + providerName_File = providerPrettyName.replace('-', '') + providerName_File = providerName_File.lower() + providerPrettyName = providerPrettyName.replace('-', '_') + eventpipefile = eventpipe_directory + providerName_File + ".cpp" + eventpipeImpl = open(eventpipefile, 'w') + eventpipeImpl.write(stdprolog) + + header = """ +#include \"%s/src/vm/common.h\" +#include \"%s/src/vm/eventpipeprovider.h\" +#include \"%s/src/vm/eventpipeevent.h\" +#include \"%s/src/vm/eventpipe.h\" + +bool ResizeBuffer(char *&buffer, unsigned int& size, unsigned int currLen, unsigned int newSize, bool &fixedBuffer); +bool WriteToBuffer(PCWSTR str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer); +bool WriteToBuffer(const char *str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer); +bool WriteToBuffer(const BYTE *src, unsigned int len, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer); + +template <typename T> +bool WriteToBuffer(const T &value, char *&buffer, unsigned int& offset, unsigned 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; +} + +""" % (coreclrRoot, coreclrRoot, coreclrRoot, coreclrRoot) + + eventpipeImpl.write(header) + eventpipeImpl.write( + "GUID const " + + providerPrettyName + + "GUID = " + + providerGUID + + ";\n") + eventpipeImpl.write( + "EventPipeProvider *EventPipeProvider" + + providerPrettyName + + " = nullptr;\n") + templateNodes = providerNode.getElementsByTagName('template') + allTemplates = parseTemplateNodes(templateNodes) + eventNodes = providerNode.getElementsByTagName('event') + eventpipeImpl.write( + generateClrEventPipeWriteEventsImpl( + providerName, + eventNodes, + allTemplates, + exclusionListFile) + "\n") + eventpipeImpl.close() + + +def generateEventPipeFiles( + etwmanifest, eventpipe_directory, exclusionListFile): + eventpipe_directory = eventpipe_directory + "/" + tree = DOM.parse(etwmanifest) + + if not os.path.exists(eventpipe_directory): + os.makedirs(eventpipe_directory) + + # generate Cmake file + generateEventPipeCmakeFile(etwmanifest, eventpipe_directory) + + # generate helper file + generateEventPipeHelperFile(etwmanifest, eventpipe_directory) + + # generate all keywords + for keywordNode in tree.getElementsByTagName('keyword'): + keywordName = keywordNode.getAttribute('name') + keywordMask = keywordNode.getAttribute('mask') + keywordMap[keywordName] = int(keywordMask, 0) + + # generate .cpp file for each provider + generateEventPipeImplFiles( + etwmanifest, + eventpipe_directory, + exclusionListFile) + +import argparse +import sys + + +def main(argv): + + # parse the command line + parser = argparse.ArgumentParser( + description="Generates the Code required to instrument eventpipe 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') + required.add_argument('--exc', type=str, required=True, + help='full path to exclusion list') + args, unknown = parser.parse_known_args(argv) + if unknown: + print('Unknown argument(s): ', ', '.join(unknown)) + return const.UnknownArguments + + sClrEtwAllMan = args.man + intermediate = args.intermediate + exclusionListFile = args.exc + + generateEventPipeFiles(sClrEtwAllMan, intermediate, exclusionListFile) + +if __name__ == '__main__': + return_code = main(sys.argv[1:]) + sys.exit(return_code) |