diff options
author | Victor "Nate" Graf <nategraf1@gmail.com> | 2017-12-20 18:07:52 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-20 18:07:52 -0800 |
commit | 7524d72d4f0f634fe5407280b83c25181dc8c556 (patch) | |
tree | 119c7edbbd7b3a0aec47d55334d52d1471e3a3da /src/scripts | |
parent | 9891c8ba8f84ff646455b4493447295c591665f4 (diff) | |
download | coreclr-7524d72d4f0f634fe5407280b83c25181dc8c556.tar.gz coreclr-7524d72d4f0f634fe5407280b83c25181dc8c556.tar.bz2 coreclr-7524d72d4f0f634fe5407280b83c25181dc8c556.zip |
Enable EventPipe across Unix and Windows (#14772)
* [squashed] most work complete to enable EventPipe on Windows
* Eventpipe now builds on Windows
* Ensure evevntpipe is intialized on Windows
* Resolve the location of python from build.cmd
* Ensure eventing files are generated when needed
* moving linkage declaration to cmake
* create new event from constructor
* enable FEATURE_EVENT_TRACE and FEATURE_PERF_TRACE everywhere
* [WIP] checkpoint in fixing contarct errors
* add another possible python location
* Fix double delete bug in EventPipeConfiguration destructor
* Fix typo in function name
* Revert changes to .gitgnore
* bump to netstandard1.6 in preperation for new version of TraceEvent
* Revert changes to groovy files
* revert changes to perf-prep scripts
* add common.h and use nothrow
* Fix issue which was causing double delete of configprovider
* Add new test utilizing TraceEvent
* Remove accidentally added local directory reference
* Add comment to explain the addition of misc/tracepointprovider.cpp
* Add back sys.exit(0) and refactor
* Change conditional to be more direct
* Better handle NULL config
* Initialize m_deleteDefered
* Eliminate obsolete field
* Fix spelling error
* Fix nits
* Make smaple progiler timing functions easier to read
* Move projects back to netstandard1.4
* Incomplete improvements to EventPipeTrace test
* Add event integrity checks to test
* Clean up some left over code
* Add EventSource based test
* Remove unused PAL tests on Windows
* Fix Linux build breaks
* Minor changes to CMake files
* Remove //HACK for hack that was previously removed
* Fix formatting and negate a #ifdef
* Add conditional to ensure PERFTRACING is not enabled without EVENT_TRACE
* Take lock on EventPipeProvider and EventPipeConfiguration destruction
* Load winmm.dll at runtime
* Change function name and compile conditions
* Move typedef into #ifndef
* Use the correct config in setup
* Change lifecycle managment of EventPipeConfiguration's configuration provider
* Enable EventPipe tests pri0 and disable broken tests
* Replace python3 only error with python2 compatable one
* Make common.csproj build pri0
* Change TraceEvent version to 2.0.2 to match published verison
* Address cross build failure
* Remove use of undefined variable
* Add crossgen fix to .cmd
* Use more specific types to avoid marshalling errors
* Use Assert-style statements and remove one check
* Fix cross arch build
* Fix flipped branch
* Bring build.cmd changes to build.sh
* Fix cmake writing
* Revert "Bring build.cmd changes to build.sh"
This reverts commit 893c6492548d8bc9859ebba5b1b810aa630fac63.
* remove stdlib.h
* Fix out of order null check
Diffstat (limited to 'src/scripts')
-rw-r--r-- | src/scripts/Utilities.py | 49 | ||||
-rw-r--r-- | src/scripts/check-definitions.py | 24 | ||||
-rw-r--r-- | src/scripts/genDummyProvider.py | 211 | ||||
-rw-r--r-- | src/scripts/genEtwProvider.py | 312 | ||||
-rw-r--r-- | src/scripts/genEventPipe.py | 313 | ||||
-rw-r--r-- | src/scripts/genEventing.py (renamed from src/scripts/genXplatEventing.py) | 387 | ||||
-rw-r--r-- | src/scripts/genLttngProvider.py (renamed from src/scripts/genXplatLttng.py) | 228 | ||||
-rw-r--r-- | src/scripts/genWinEtw.py | 125 | ||||
-rw-r--r-- | src/scripts/utilities.py | 106 |
9 files changed, 1082 insertions, 673 deletions
diff --git a/src/scripts/Utilities.py b/src/scripts/Utilities.py deleted file mode 100644 index c1ceec8e9f..0000000000 --- a/src/scripts/Utilities.py +++ /dev/null @@ -1,49 +0,0 @@ -from filecmp import dircmp -import shutil -import os - -def walk_recursively_and_update(dcmp): - #for different Files Copy from right to left - for name in dcmp.diff_files: - srcpath = dcmp.right + "/" + name - destpath = dcmp.left + "/" + name - print("Updating %s" % (destpath)) - if os.path.isfile(srcpath): - shutil.copyfile(srcpath, destpath) - else : - raise Exception("path: " + srcpath + "is neither a file or folder") - - #copy right only files - for name in dcmp.right_only: - srcpath = dcmp.right + "/" + name - destpath = dcmp.left + "/" + name - print("Updating %s" % (destpath)) - if os.path.isfile(srcpath): - shutil.copyfile(srcpath, destpath) - elif os.path.isdir(srcpath): - shutil.copytree(srcpath, destpath) - else : - raise Exception("path: " + srcpath + "is neither a file or folder") - - #delete left only files - for name in dcmp.left_only: - path = dcmp.left + "/" + name - print("Deleting %s" % (path)) - if os.path.isfile(path): - os.remove(path) - elif os.path.isdir(path): - shutil.rmtree(path) - else : - raise Exception("path: " + path + "is neither a file or folder") - - #call recursively - for sub_dcmp in dcmp.subdirs.values(): - walk_recursively_and_update(sub_dcmp) - -def UpdateDirectory(destpath,srcpath): - - print("Updating %s with %s" % (destpath,srcpath)) - if not os.path.exists(destpath): - os.makedirs(destpath) - dcmp = dircmp(destpath,srcpath) - walk_recursively_and_update(dcmp) diff --git a/src/scripts/check-definitions.py b/src/scripts/check-definitions.py index 59b309a3e6..4f1026d4ef 100644 --- a/src/scripts/check-definitions.py +++ b/src/scripts/check-definitions.py @@ -33,18 +33,17 @@ debug = 0 # For the native part, return the sorted definition array. def loadDefinitionFile(filename): result = [] + try: - f = open(filename, 'r') - except: + with open(filename, 'r') as f: + for line in f: + line = line.strip() + if line: + result.append(line) + except IOError: + # If cmake was not used, this script won't work, and that's ok sys.exit(0) - # if cmake was not used (because of skipnative or systems that do not use cmake), this script won't work. - - for line in f: - theLine = line.rstrip("\r\n").strip() - if (len(theLine) > 0): - result.append(theLine) - f.close() result = sorted(result) return result @@ -108,9 +107,10 @@ def getDiff(arrNative, arrManaged): def printPotentiallyCritical(arrDefinitions, referencedFilename, arrIgnore): - f = open(referencedFilename, 'r') - content = f.read() - f.close() + content = None + with open(referencedFilename, 'r') as f: + content = f.read() + for keyword in arrDefinitions: skip = 0 diff --git a/src/scripts/genDummyProvider.py b/src/scripts/genDummyProvider.py new file mode 100644 index 0000000000..0704554263 --- /dev/null +++ b/src/scripts/genDummyProvider.py @@ -0,0 +1,211 @@ +## +## 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. +## +## This script exists to create a dummy implementaion of the eventprovider +## interface from a manifest file +## +## The intended use if for platforms which support event pipe +## but do not have a an eventing platform to recieve report events + +import os +from genEventing import * +from utilities import open_for_update + +stdprolog_cpp=""" +// 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/genDummyProvider.py + +******************************************************************/ +""" +stdprolog_cmake=""" +# +# +#****************************************************************** + +#DO NOT MODIFY. AUTOGENERATED FILE. +#This file is generated using the logic from <root>/src/scripts/genDummyProvider.py + +#****************************************************************** +""" + +def trimProvName(name): + name = name.replace("Windows-",'') + name = name.replace("Microsoft-",'') + name = name.replace('-','_') + return name + +def escapeProvFilename(name): + name = name.replace('_','') + name = name.lower() + return name + +def generateDummyProvider(providerName, eventNodes, allTemplates, extern): + impl = [] + for eventNode in eventNodes: + eventName = eventNode.getAttribute('symbol') + templateName = eventNode.getAttribute('template') + + #generate EventXplatEnabled + if extern: impl.append('extern "C" ') + impl.append("BOOL EventXplatEnabled%s(){ return FALSE; }\n\n" % (eventName,)) + + #generate FireEtw functions + fnptype = [] + linefnptype = [] + if extern: fnptype.append('extern "C" ') + fnptype.append("ULONG FireEtXplat") + 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") + impl.extend(fnptype) + + #start of fn body + impl.append(" return ERROR_SUCCESS;\n") + impl.append("}\n\n") + + return ''.join(impl) + +def generateDummyFiles(etwmanifest, out_dirname, extern): + tree = DOM.parse(etwmanifest) + + #keep these relative + dummy_directory = "dummy" + dummyevntprovPre = os.path.join(dummy_directory, "eventprov") + + if not os.path.exists(out_dirname): + os.makedirs(out_dirname) + + if not os.path.exists(os.path.join(out_dirname, dummy_directory)): + os.makedirs(os.path.join(out_dirname, dummy_directory)) + + # Cmake + with open_for_update(os.path.join(out_dirname, "CMakeLists.txt")) as cmake: + cmake.write(stdprolog_cmake + "\n") + cmake.write("\ncmake_minimum_required(VERSION 2.8.12.2)\n") + if extern: cmake.write("\nproject(eventprovider)\n") + cmake.write(""" + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +if(FEATURE_PAL) + add_definitions(-DPAL_STDCPP_COMPAT=1) + include_directories(${COREPAL_SOURCE_DIR}/inc/rt) +endif(FEATURE_PAL) +include_directories(dummy) + +""") + if extern: cmake.write("add_library") + else: cmake.write("add_library_clr") + cmake.write("""(eventprovider + STATIC\n""") + + for providerNode in tree.getElementsByTagName('provider'): + providerName = trimProvName(providerNode.getAttribute('name')) + providerName_File = escapeProvFilename(providerName) + + cmake.write(' "%s%s.cpp"\n' % (dummyevntprovPre, providerName_File)) + + cmake.write(")") + if extern: cmake.write(""" + +# Install the static eventprovider library +install(TARGETS eventprovider DESTINATION lib) +""") + + # Dummy Instrumentation + for providerNode in tree.getElementsByTagName('provider'): + providerName = trimProvName(providerNode.getAttribute('name')) + providerName_File = escapeProvFilename(providerName) + + dummyevntprov = os.path.join(out_dirname, dummyevntprovPre + providerName_File + ".cpp") + + with open_for_update(dummyevntprov) as impl: + impl.write(stdprolog_cpp + "\n") + + impl.write(""" +#ifdef PLATFORM_UNIX +#include "pal_mstypes.h" +#include "pal_error.h" +#include "pal.h" +#define PAL_free free +#define PAL_realloc realloc +#include "pal/stackstring.hpp" +#endif + + +""") + + templateNodes = providerNode.getElementsByTagName('template') + eventNodes = providerNode.getElementsByTagName('event') + + allTemplates = parseTemplateNodes(templateNodes) + + #create the implementation of eventing functions : dummyeventprov*.cp + impl.write(generateDummyProvider(providerName, eventNodes, allTemplates, extern) + "\n") + +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 containig the description of events') + required.add_argument('--intermediate', type=str, required=True, + help='full path to eventprovider intermediate directory') + required.add_argument('--nonextern', action='store_true', + help='if specified, will generate files to be compiled into the CLR rather than externaly' ) + args, unknown = parser.parse_known_args(argv) + if unknown: + print('Unknown argument(s): ', ', '.join(unknown)) + return 1 + + sClrEtwAllMan = args.man + intermediate = args.intermediate + extern = not args.nonextern + + generateDummyFiles(sClrEtwAllMan, intermediate, extern) + +if __name__ == '__main__': + return_code = main(sys.argv[1:]) + sys.exit(return_code)
\ No newline at end of file diff --git a/src/scripts/genEtwProvider.py b/src/scripts/genEtwProvider.py new file mode 100644 index 0000000000..fc9d43800f --- /dev/null +++ b/src/scripts/genEtwProvider.py @@ -0,0 +1,312 @@ +## +## 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. +## +## This script generates the interface to ETW using MC.exe + +import os +from os import path +import shutil +import re +import sys +import argparse +import subprocess +import xml.dom.minidom as DOM +from genEventing import parseTemplateNodes +from utilities import open_for_update + +macroheader_filename = "etwmacros.h" +mcheader_filename = "ClrEtwAll.h" +clrxplat_filename = "clrxplatevents.h" +etw_dirname = "etw" +replacements = [ + (r"EventEnabled", "EventXplatEnabled"), + (r"\bPVOID\b", "void*") +] + +stdprolog_cpp=""" +// 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/genEtwProvider.py + +******************************************************************/ +""" +stdprolog_cmake=""" +# +# +#****************************************************************** + +#DO NOT MODIFY. AUTOGENERATED FILE. +#This file is generated using the logic from <root>/src/scripts/genEtwProvider.py + +#****************************************************************** +""" + +def genProviderInterface(manifest, intermediate): + provider_dirname = os.path.join(intermediate, etw_dirname) + + if not os.path.exists(provider_dirname): + os.makedirs(provider_dirname) + + cmd = ['mc.exe', '-h', provider_dirname, '-r', provider_dirname, '-b', '-co', '-um', '-p', 'FireEtXplat', manifest] + subprocess.check_call(cmd) + + header_text = None + with open(path.join(provider_dirname, mcheader_filename), 'r') as mcheader_file: + header_text = mcheader_file.read() + + for pattern, replacement in replacements: + header_text = re.sub(pattern, replacement, header_text) + + with open_for_update(path.join(provider_dirname, mcheader_filename)) as mcheader_file: + mcheader_file.write(header_text) + +def genCmake(intermediate): + # Top level Cmake + + with open_for_update(os.path.join(intermediate, "CMakeLists.txt")) as cmake_file: + cmake_file.write(stdprolog_cmake) + cmake_file.write(""" +project(eventprovider) + +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +include_directories({0}) + +add_library_clr(eventprovider + STATIC + "{0}/{1}" + "{0}/{2}" +) + +#set_target_properties(eventprovider PROPERTIES LINKER_LANGUAGE Hxx) +""".format(etw_dirname, macroheader_filename, "ClrEtwAll.cpp")) + +def genXplatHeader(intermediate): + with open_for_update(path.join(intermediate, clrxplat_filename)) as header_file: + header_file.write(""" +#ifndef _CLR_XPLAT_EVENTS_H_ +#define _CLR_XPLAT_EVENTS_H_ + +#include "{0}/{1}" +#include "{0}/{2}" + +#endif //_CLR_XPLAT_EVENTS_H_ +""".format(etw_dirname, macroheader_filename, mcheader_filename)) + + +class EventExclusions: + def __init__(self): + self.nostack = set() + self.explicitstack = set() + self.noclrinstance = set() + +def parseExclusionList(exclusion_filename): + with open(exclusion_filename,'r') as ExclusionFile: + exclusionInfo = EventExclusions() + + for line in ExclusionFile: + line = line.strip() + + #remove comments + if not line or line.startswith('#'): + continue + + tokens = line.split(':') + #entries starting with nomac are ignored + if "nomac" in tokens: + continue + + if len(tokens) > 5: + raise Exception("Invalid Entry " + line + "in "+ exclusion_filename) + + eventProvider = tokens[2] + eventTask = tokens[1] + eventSymbol = tokens[4] + + if eventProvider == '': + eventProvider = "*" + if eventTask == '': + eventTask = "*" + if eventSymbol == '': + eventSymbol = "*" + entry = eventProvider + ":" + eventTask + ":" + eventSymbol + + if tokens[0].lower() == "nostack": + exclusionInfo.nostack.add(entry) + if tokens[0].lower() == "stack": + exclusionInfo.explicitstack.add(entry) + if tokens[0].lower() == "noclrinstanceid": + exclusionInfo.noclrinstance.add(entry) + + return exclusionInfo + +def getStackWalkBit(eventProvider, taskName, eventSymbol, stackSet): + for entry in stackSet: + tokens = entry.split(':') + + if len(tokens) != 3: + raise Exception("Error, possible error in the script which introduced the enrty "+ entry) + + eventCond = tokens[0] == eventProvider or tokens[0] == "*" + taskCond = tokens[1] == taskName or tokens[1] == "*" + symbolCond = tokens[2] == eventSymbol or tokens[2] == "*" + + if eventCond and taskCond and symbolCond: + return False + return True + +#Add the miscelaneous checks here +def checkConsistency(manifest, exclusion_filename): + tree = DOM.parse(manifest) + exclusionInfo = parseExclusionList(exclusion_filename) + for providerNode in tree.getElementsByTagName('provider'): + + stackSupportSpecified = {} + eventNodes = providerNode.getElementsByTagName('event') + templateNodes = providerNode.getElementsByTagName('template') + eventProvider = providerNode.getAttribute('name') + allTemplates = parseTemplateNodes(templateNodes) + + for eventNode in eventNodes: + taskName = eventNode.getAttribute('task') + eventSymbol = eventNode.getAttribute('symbol') + eventTemplate = eventNode.getAttribute('template') + eventValue = int(eventNode.getAttribute('value')) + clrInstanceBit = getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.noclrinstance) + sLookupFieldName = "ClrInstanceID" + sLookupFieldType = "win:UInt16" + + if clrInstanceBit and allTemplates.get(eventTemplate): + # check for the event template and look for a field named ClrInstanceId of type win:UInt16 + fnParam = allTemplates[eventTemplate].getFnParam(sLookupFieldName) + + if not(fnParam and fnParam.winType == sLookupFieldType): + raise Exception(exclusion_filename + ":No " + sLookupFieldName + " field of type " + sLookupFieldType + " for event symbol " + eventSymbol) + + # If some versions of an event are on the nostack/stack lists, + # and some versions are not on either the nostack or stack list, + # then developer likely forgot to specify one of the versions + + eventStackBitFromNoStackList = getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.nostack) + eventStackBitFromExplicitStackList = getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.explicitstack) + sStackSpecificityError = exclusion_filename + ": Error processing event :" + eventSymbol + "(ID" + str(eventValue) + "): This file must contain either ALL versions of this event or NO versions of this event. Currently some, but not all, versions of this event are present\n" + + if not stackSupportSpecified.get(eventValue): + # Haven't checked this event before. Remember whether a preference is stated + if ( not eventStackBitFromNoStackList) or ( not eventStackBitFromExplicitStackList): + stackSupportSpecified[eventValue] = True + else: + stackSupportSpecified[eventValue] = False + else: + # We've checked this event before. + if stackSupportSpecified[eventValue]: + # When we last checked, a preference was previously specified, so it better be specified here + if eventStackBitFromNoStackList and eventStackBitFromExplicitStackList: + raise Exception(sStackSpecificityError) + else: + # When we last checked, a preference was not previously specified, so it better not be specified here + if ( not eventStackBitFromNoStackList) or ( not eventStackBitFromExplicitStackList): + raise Exception(sStackSpecificityError) + +def genEtwMacroHeader(manifest, exclusion_filename, intermediate): + provider_dirname = os.path.join(intermediate, etw_dirname) + + if not os.path.exists(provider_dirname): + os.makedirs(provider_dirname) + + tree = DOM.parse(manifest) + numOfProviders = len(tree.getElementsByTagName('provider')) + nMaxEventBytesPerProvider = 64 + + exclusionInfo = parseExclusionList(exclusion_filename) + + with open_for_update(os.path.join(provider_dirname, macroheader_filename)) as header_file: + header_file.write(stdprolog_cpp + "\n") + + header_file.write("#define NO_OF_ETW_PROVIDERS " + str(numOfProviders) + "\n") + header_file.write("#define MAX_BYTES_PER_ETW_PROVIDER " + str(nMaxEventBytesPerProvider) + "\n") + header_file.write("EXTERN_C __declspec(selectany) const BYTE etwStackSupportedEvents[NO_OF_ETW_PROVIDERS][MAX_BYTES_PER_ETW_PROVIDER] = \n{\n") + + for providerNode in tree.getElementsByTagName('provider'): + stackSupportedEvents = [0]*nMaxEventBytesPerProvider + eventNodes = providerNode.getElementsByTagName('event') + eventProvider = providerNode.getAttribute('name') + + for eventNode in eventNodes: + taskName = eventNode.getAttribute('task') + eventSymbol = eventNode.getAttribute('symbol') + eventTemplate = eventNode.getAttribute('template') + eventTemplate = eventNode.getAttribute('template') + eventValue = int(eventNode.getAttribute('value')) + eventIndex = eventValue // 8 + eventBitPositionInIndex = eventValue % 8 + + eventStackBitFromNoStackList = int(getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.nostack)) + eventStackBitFromExplicitStackList = int(getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.explicitstack)) + + # Shift those bits into position. For the explicit stack list, swap 0 and 1, so the eventValue* variables + # have 1 in the position iff we should issue a stack for the event. + eventValueUsingNoStackListByPosition = (eventStackBitFromNoStackList << eventBitPositionInIndex) + eventValueUsingExplicitStackListByPosition = ((1 - eventStackBitFromExplicitStackList) << eventBitPositionInIndex) + + # Commit the values to the in-memory array that we'll dump into the header file + stackSupportedEvents[eventIndex] = stackSupportedEvents[eventIndex] | eventValueUsingNoStackListByPosition; + if eventStackBitFromExplicitStackList == 0: + stackSupportedEvents[eventIndex] = stackSupportedEvents[eventIndex] | eventValueUsingExplicitStackListByPosition + + # print the bit array + line = [] + line.append("\t{") + for elem in stackSupportedEvents: + line.append(str(elem)) + line.append(", ") + + del line[-1] + line.append("},") + header_file.write(''.join(line) + "\n") + header_file.write("};\n") + +def genFiles(manifest, intermediate, exclusion_filename): + if not os.path.exists(intermediate): + os.makedirs(intermediate) + + genProviderInterface(manifest, intermediate) + genEtwMacroHeader(manifest, exclusion_filename, intermediate) + genXplatHeader(intermediate) + + +def main(argv): + #parse the command line + parser = argparse.ArgumentParser(description="Generates the Code required to instrument ETW 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('--exc', type=str, required=True, + help='full path to exclusion list') + required.add_argument('--intermediate', type=str, required=True, + help='full path to eventprovider intermediate directory') + args, unknown = parser.parse_known_args(argv) + if unknown: + print('Unknown argument(s): ', ', '.join(unknown)) + return 1 + + manifest = args.man + exclusion_filename = args.exc + intermediate = args.intermediate + + checkConsistency(manifest, exclusion_filename) + genFiles(manifest, intermediate, exclusion_filename) + +if __name__ == '__main__': + return_code = main(sys.argv[1:]) + sys.exit(return_code)
\ No newline at end of file diff --git a/src/scripts/genEventPipe.py b/src/scripts/genEventPipe.py index 8a970794c0..96755ea459 100644 --- a/src/scripts/genEventPipe.py +++ b/src/scripts/genEventPipe.py @@ -1,10 +1,11 @@ from __future__ import print_function -from genXplatEventing import * -from genXplatLttng import * +from genEventing import * +from genLttngProvider import * import os import xml.dom.minidom as DOM +from utilities import open_for_update -stdprolog = """// Licensed to the .NET Foundation under one or more agreements. +stdprolog_cpp = """// 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. @@ -14,6 +15,7 @@ DO NOT MODIFY. AUTOGENERATED FILE. This file is generated using the logic from <root>/src/scripts/genEventPipe.py ******************************************************************/ + """ stdprolog_cmake = """# @@ -24,11 +26,54 @@ stdprolog_cmake = """# #This file is generated using the logic from <root>/src/scripts/genEventPipe.py #****************************************************************** + """ +eventpipe_dirname = "eventpipe" + +def generateMethodSignatureEnabled(eventName): + return "BOOL EventPipeEventEnabled%s()" % (eventName,) + +def generateMethodSignatureWrite(eventName, template, extern): + sig_pieces = [] + + if extern: sig_pieces.append('extern "C" ') + sig_pieces.append("ULONG EventPipeWriteEvent") + sig_pieces.append(eventName) + sig_pieces.append("(") + + if template: + sig_pieces.append("\n") + 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: + sig_pieces.append( + "%sint %s_ElementSize,\n" % + (lindent, paramName)) + + sig_pieces.append(lindent) + sig_pieces.append(typewName) + if countw != " ": + sig_pieces.append(countw) + + sig_pieces.append(" ") + sig_pieces.append(fnparam.name) + sig_pieces.append(",\n") + + if len(sig_pieces) > 0: + del sig_pieces[-1] + + sig_pieces.append(")") + return ''.join(sig_pieces) def generateClrEventPipeWriteEventsImpl( - providerName, eventNodes, allTemplates, exclusionListFile): + providerName, eventNodes, allTemplates, extern): providerPrettyName = providerName.replace("Windows-", '') providerPrettyName = providerPrettyName.replace("Microsoft-", '') providerPrettyName = providerPrettyName.replace('-', '_') @@ -47,54 +92,24 @@ def generateClrEventPipeWriteEventsImpl( templateName = eventNode.getAttribute('template') # generate EventPipeEventEnabled function - eventEnabledImpl = """bool EventPipeEventEnabled%s() + eventEnabledImpl = generateMethodSignatureEnabled(eventName) + """ { return EventPipeEvent%s->IsEnabled(); } -""" % (eventName, 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") + fnptype.append(generateMethodSignatureWrite(eventName, template, extern)) + fnptype.append("\n{\n") checking = """ if (!EventPipeEventEnabled%s()) return ERROR_SUCCESS; """ % (eventName) @@ -115,8 +130,9 @@ def generateClrEventPipeWriteEventsImpl( WriteEventImpl.append("\n return ERROR_SUCCESS;\n}\n\n") # EventPipeProvider and EventPipeEvent initialization + if extern: WriteEventImpl.append('extern "C" ') WriteEventImpl.append( - "extern \"C\" void Init" + + "void Init" + providerPrettyName + "()\n{\n") WriteEventImpl.append( @@ -134,7 +150,6 @@ def generateClrEventPipeWriteEventsImpl( 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); @@ -150,8 +165,8 @@ def generateWriteEventBody(template, providerName, eventName): header = """ char stackBuffer[%s]; char *buffer = stackBuffer; - unsigned int offset = 0; - unsigned int size = %s; + size_t offset = 0; + size_t size = %s; bool fixedBuffer = true; bool success = true; @@ -198,7 +213,7 @@ def generateWriteEventBody(template, providerName, eventName): }\n\n""" body = " EventPipe::WriteEvent(*EventPipeEvent" + \ - eventName + ", (BYTE *)buffer, offset);\n" + eventName + ", (BYTE *)buffer, (unsigned int)offset);\n" footer = """ if (!fixedBuffer) @@ -221,20 +236,23 @@ def generateEventKeywords(eventKeywords): return mask -def generateEventPipeCmakeFile(etwmanifest, eventpipe_directory): +def generateEventPipeCmakeFile(etwmanifest, eventpipe_directory, extern): 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) + with open_for_update(os.path.join(eventpipe_directory, "CMakeLists.txt")) as cmake_file: + cmake_file.write(stdprolog_cmake) + cmake_file.write("cmake_minimum_required(VERSION 2.8.12.2)\n") + if extern: cmake_file.write("\nproject(eventpipe)\n") + cmake_file.write(""" - project(eventpipe) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +include_directories(${CLR_DIR}/src/vm) - set(CMAKE_INCLUDE_CURRENT_DIR ON) - include_directories(${CLR_DIR}/src/vm) - - add_library(eventpipe - STATIC\n""") +""") + if extern: cmake_file.write("add_library") + else: cmake_file.write("add_library_clr") + cmake_file.write("""(eventpipe + STATIC\n""") for providerNode in tree.getElementsByTagName('provider'): providerName = providerNode.getAttribute('name') @@ -244,34 +262,41 @@ def generateEventPipeCmakeFile(etwmanifest, eventpipe_directory): providerName_File = providerName.replace('-', '') providerName_File = providerName_File.lower() - topCmake.write(' "%s.cpp"\n' % (providerName_File)) - topCmake.write(' "eventpipehelpers.cpp"\n') - topCmake.write(""" ) - - add_dependencies(eventpipe GeneratedEventingFiles) - - # Install the static eventpipe library - install(TARGETS eventpipe DESTINATION lib) - """) - - topCmake.close() + cmake_file.write(' "%s/%s.cpp"\n' % (eventpipe_dirname, providerName_File)) + cmake_file.write(' "%s/eventpipehelpers.cpp"\n)' % (eventpipe_dirname,)) + if extern: cmake_file.write(""" +# Install the static eventpipe library +install(TARGETS eventpipe DESTINATION lib) +""") -def generateEventPipeHelperFile(etwmanifest, eventpipe_directory): - with open(eventpipe_directory + "eventpipehelpers.cpp", 'w') as helper: - helper.write(stdprolog) +def generateEventPipeHelperFile(etwmanifest, eventpipe_directory, extern): + with open_for_update(os.path.join(eventpipe_directory, "eventpipehelpers.cpp")) as helper: + helper.write(stdprolog_cpp) helper.write(""" -#include "stdlib.h" - -bool ResizeBuffer(char *&buffer, unsigned int& size, unsigned int currLen, unsigned int newSize, bool &fixedBuffer) +#include "common.h" +#include <stdlib.h> +#include <string.h> + +#ifndef FEATURE_PAL +#include <windef.h> +#include <crtdbg.h> +#else +#include "pal.h" +#endif //FEATURE_PAL + +bool ResizeBuffer(char *&buffer, size_t& size, size_t currLen, size_t newSize, bool &fixedBuffer) { - newSize *= 1.5; + newSize = (size_t)(newSize * 1.5); _ASSERTE(newSize > size); // check for overflow if (newSize < 32) newSize = 32; - char *newBuffer = new char[newSize]; + char *newBuffer = new (nothrow) char[newSize]; + + if (newBuffer == NULL) + return false; memcpy(newBuffer, buffer, currLen); @@ -285,7 +310,7 @@ bool ResizeBuffer(char *&buffer, unsigned int& size, unsigned int currLen, unsig return true; } -bool WriteToBuffer(const BYTE *src, unsigned int len, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer) +bool WriteToBuffer(const BYTE *src, size_t len, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer) { if(!src) return true; if (offset + len > size) @@ -299,10 +324,10 @@ bool WriteToBuffer(const BYTE *src, unsigned int len, char *&buffer, unsigned in return true; } -bool WriteToBuffer(PCWSTR str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer) +bool WriteToBuffer(PCWSTR str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer) { if(!str) return true; - unsigned int byteCount = (PAL_wcslen(str) + 1) * sizeof(*str); + size_t byteCount = (wcslen(str) + 1) * sizeof(*str); if (offset + byteCount > size) { @@ -315,10 +340,10 @@ bool WriteToBuffer(PCWSTR str, char *&buffer, unsigned int& offset, unsigned int return true; } -bool WriteToBuffer(const char *str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer) +bool WriteToBuffer(const char *str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer) { if(!str) return true; - unsigned int len = strlen(str) + 1; + size_t len = strlen(str) + 1; if (offset + len > size) { if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer)) @@ -339,12 +364,18 @@ bool WriteToBuffer(const char *str, char *&buffer, unsigned int& offset, unsigne providerPrettyName = providerName.replace("Windows-", '') providerPrettyName = providerPrettyName.replace("Microsoft-", '') providerPrettyName = providerPrettyName.replace('-', '_') + if extern: helper.write( + 'extern "C" ' + ) helper.write( - "extern \"C\" void Init" + + "void Init" + providerPrettyName + "();\n\n") - helper.write("extern \"C\" void InitProvidersAndEvents()\n{\n") + if extern: helper.write( + 'extern "C" ' + ) + helper.write("void InitProvidersAndEvents()\n{\n") for providerNode in tree.getElementsByTagName('provider'): providerName = providerNode.getAttribute('name') providerPrettyName = providerName.replace("Windows-", '') @@ -355,11 +386,20 @@ bool WriteToBuffer(const char *str, char *&buffer, unsigned int& offset, unsigne helper.close() - def generateEventPipeImplFiles( - etwmanifest, eventpipe_directory, exclusionListFile): + etwmanifest, eventpipe_directory, extern): tree = DOM.parse(etwmanifest) - coreclrRoot = os.getcwd() + + # Find the src directory starting with the assumption that + # A) It is named 'src' + # B) This script lives in it + src_dirname = os.path.dirname(__file__) + while os.path.basename(src_dirname) != "src": + src_dirname = os.path.dirname(src_dirname) + + if os.path.basename(src_dirname) == "": + raise IOError("Could not find the Core CLR 'src' directory") + for providerNode in tree.getElementsByTagName('provider'): providerName = providerNode.getAttribute('name') @@ -368,74 +408,77 @@ def generateEventPipeImplFiles( 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) + eventpipefile = os.path.join(eventpipe_directory, providerName_File + ".cpp") + with open_for_update(eventpipefile) as eventpipeImpl: + eventpipeImpl.write(stdprolog_cpp) + + header = """ +#include "{root:s}/vm/common.h" +#include "{root:s}/vm/eventpipeprovider.h" +#include "{root:s}/vm/eventpipeevent.h" +#include "{root:s}/vm/eventpipe.h" - 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\" +#if defined(FEATURE_PAL) +#define wcslen PAL_wcslen +#endif -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); +bool ResizeBuffer(char *&buffer, size_t& size, size_t currLen, size_t newSize, bool &fixedBuffer); +bool WriteToBuffer(PCWSTR str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer); +bool WriteToBuffer(const char *str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer); +bool WriteToBuffer(const BYTE *src, size_t len, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer); template <typename T> -bool WriteToBuffer(const T &value, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer) -{ +bool WriteToBuffer(const T &value, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer) +{{ if (sizeof(T) + offset > size) - { - if (!ResizeBuffer(buffer, size, offset, size + sizeof(T), fixedBuffer)) - return false; - } + {{ + if (!ResizeBuffer(buffer, size, offset, size + sizeof(T), fixedBuffer)) + return false; + }} *(T *)(buffer + offset) = value; offset += sizeof(T); return true; -} +}} -""" % (coreclrRoot, coreclrRoot, coreclrRoot, coreclrRoot) +""".format(root=src_dirname.replace('\\', '/')) - eventpipeImpl.write(header) - eventpipeImpl.write( - "const WCHAR* %sName = W(\"%s\");\n" % ( - providerPrettyName, - providerName + eventpipeImpl.write(header) + eventpipeImpl.write( + "const WCHAR* %sName = W(\"%s\");\n" % ( + providerPrettyName, + providerName + ) ) - ) - eventpipeImpl.write( - "EventPipeProvider *EventPipeProvider%s = nullptr;\n" % ( - providerPrettyName, + eventpipeImpl.write( + "EventPipeProvider *EventPipeProvider%s = nullptr;\n" % ( + providerPrettyName, + ) ) - ) - templateNodes = providerNode.getElementsByTagName('template') - allTemplates = parseTemplateNodes(templateNodes) - eventNodes = providerNode.getElementsByTagName('event') - eventpipeImpl.write( - generateClrEventPipeWriteEventsImpl( - providerName, - eventNodes, - allTemplates, - exclusionListFile) + "\n") - eventpipeImpl.close() + templateNodes = providerNode.getElementsByTagName('template') + allTemplates = parseTemplateNodes(templateNodes) + eventNodes = providerNode.getElementsByTagName('event') + eventpipeImpl.write( + generateClrEventPipeWriteEventsImpl( + providerName, + eventNodes, + allTemplates, + extern) + "\n") def generateEventPipeFiles( - etwmanifest, eventpipe_directory, exclusionListFile): - eventpipe_directory = eventpipe_directory + "/" + etwmanifest, intermediate, extern): + eventpipe_directory = os.path.join(intermediate, eventpipe_dirname) tree = DOM.parse(etwmanifest) if not os.path.exists(eventpipe_directory): os.makedirs(eventpipe_directory) - # generate Cmake file - generateEventPipeCmakeFile(etwmanifest, eventpipe_directory) + # generate CMake file + generateEventPipeCmakeFile(etwmanifest, intermediate, extern) # generate helper file - generateEventPipeHelperFile(etwmanifest, eventpipe_directory) + generateEventPipeHelperFile(etwmanifest, eventpipe_directory, extern) # generate all keywords for keywordNode in tree.getElementsByTagName('keyword'): @@ -447,12 +490,12 @@ def generateEventPipeFiles( generateEventPipeImplFiles( etwmanifest, eventpipe_directory, - exclusionListFile) + extern + ) import argparse import sys - def main(argv): # parse the command line @@ -464,19 +507,19 @@ def main(argv): 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') + required.add_argument('--nonextern', action='store_true', + help='if specified, will generate files to be compiled into the CLR rather than extern' ) args, unknown = parser.parse_known_args(argv) if unknown: print('Unknown argument(s): ', ', '.join(unknown)) - return const.UnknownArguments + return 1 sClrEtwAllMan = args.man intermediate = args.intermediate - exclusionListFile = args.exc + extern = not args.nonextern - generateEventPipeFiles(sClrEtwAllMan, intermediate, exclusionListFile) + generateEventPipeFiles(sClrEtwAllMan, intermediate, extern) if __name__ == '__main__': return_code = main(sys.argv[1:]) - sys.exit(return_code) + sys.exit(return_code)
\ No newline at end of file diff --git a/src/scripts/genXplatEventing.py b/src/scripts/genEventing.py index 4c9ce873b7..d6d6afbb90 100644 --- a/src/scripts/genXplatEventing.py +++ b/src/scripts/genEventing.py @@ -6,7 +6,7 @@ # #USAGE: #Add Events: modify <root>src/vm/ClrEtwAll.man -#Look at the Code in <root>/src/scripts/genXplatLttng.py for using subroutines in this file +#Look at the Code in <root>/src/scripts/genLttngProvider.py for using subroutines in this file # # Python 2 compatibility @@ -14,6 +14,7 @@ from __future__ import print_function import os import xml.dom.minidom as DOM +from utilities import open_for_update stdprolog=""" // Licensed to the .NET Foundation under one or more agreements. @@ -23,7 +24,7 @@ stdprolog=""" /****************************************************************** DO NOT MODIFY. AUTOGENERATED FILE. -This file is generated using the logic from <root>/src/scripts/genXplatEventing.py +This file is generated using the logic from <root>/src/scripts/genEventing.py ******************************************************************/ """ @@ -34,7 +35,7 @@ stdprolog_cmake=""" #****************************************************************** #DO NOT MODIFY. AUTOGENERATED FILE. -#This file is generated using the logic from <root>/src/scripts/genXplatEventing.py +#This file is generated using the logic from <root>/src/scripts/genEventing.py #****************************************************************** """ @@ -260,7 +261,7 @@ def parseTemplateNodes(templateNodes): 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")] @@ -305,8 +306,8 @@ def generateClrallEvents(eventNodes,allTemplates): typewName = palDataTypeMapping[wintypeName] winCount = fnparam.count countw = palDataTypeMapping[winCount] - - + + if params in template.structs: fnptypeline.append("%sint %s_ElementSize,\n" % (lindent, params)) @@ -321,7 +322,7 @@ def generateClrallEvents(eventNodes,allTemplates): for params in fnSig.paramlist: fnparam = fnSig.getParam(params) - if params in template.structs: + if params in template.structs: line.append(fnparam.name + "_ElementSize") line.append(", ") @@ -349,20 +350,23 @@ def generateClrallEvents(eventNodes,allTemplates): return ''.join(clrallEvents) -def generateClrXplatEvents(eventNodes, allTemplates): +def generateClrXplatEvents(eventNodes, allTemplates, extern): clrallEvents = [] for eventNode in eventNodes: eventName = eventNode.getAttribute('symbol') templateName = eventNode.getAttribute('template') #generate EventEnabled - clrallEvents.append("extern \"C\" BOOL EventXplatEnabled") + if extern: clrallEvents.append('extern "C" ') + clrallEvents.append("BOOL EventXplatEnabled") clrallEvents.append(eventName) clrallEvents.append("();\n") + #generate FireEtw functions fnptype = [] fnptypeline = [] - fnptype.append("extern \"C\" ULONG FireEtXplat") + if extern: fnptype.append('extern "C" ') + fnptype.append("ULONG FireEtXplat") fnptype.append(eventName) fnptype.append("(\n") @@ -377,7 +381,7 @@ def generateClrXplatEvents(eventNodes, allTemplates): winCount = fnparam.count countw = palDataTypeMapping[winCount] - + if params in template.structs: fnptypeline.append("%sint %s_ElementSize,\n" % (lindent, params)) @@ -398,7 +402,7 @@ def generateClrXplatEvents(eventNodes, allTemplates): return ''.join(clrallEvents) -def generateClrEventPipeWriteEvents(eventNodes, allTemplates): +def generateClrEventPipeWriteEvents(eventNodes, allTemplates, extern): clrallEvents = [] for eventNode in eventNodes: eventName = eventNode.getAttribute('symbol') @@ -409,11 +413,13 @@ def generateClrEventPipeWriteEvents(eventNodes, allTemplates): writeevent = [] fnptypeline = [] - eventenabled.append("extern \"C\" bool EventPipeEventEnabled") + if extern:eventenabled.append('extern "C" ') + eventenabled.append("BOOL EventPipeEventEnabled") eventenabled.append(eventName) eventenabled.append("();\n") - writeevent.append("extern \"C\" ULONG EventPipeWriteEvent") + if extern: writeevent.append('extern "C" ') + writeevent.append("ULONG EventPipeWriteEvent") writeevent.append(eventName) writeevent.append("(\n") @@ -554,63 +560,70 @@ def generateSanityTest(sClrEtwAllMan,testDir): cmake_file = testDir + "/CMakeLists.txt" test_cpp = "clralltestevents.cpp" testinfo = testDir + "/testinfo.dat" - Cmake_file = open(cmake_file,'w') - Test_cpp = open(testDir + "/" + test_cpp,'w') - Testinfo = open(testinfo,'w') #CMake File: - Cmake_file.write(stdprolog_cmake) - Cmake_file.write(""" - cmake_minimum_required(VERSION 2.8.12.2) - set(CMAKE_INCLUDE_CURRENT_DIR ON) - set(SOURCES - """) - Cmake_file.write(test_cpp) - Cmake_file.write(""" - ) - include_directories(${GENERATED_INCLUDE_DIR}) + with open_for_update(cmake_file) as Cmake_file: + Cmake_file.write(stdprolog_cmake) + Cmake_file.write(""" +cmake_minimum_required(VERSION 2.8.12.2) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(SOURCES +""") + Cmake_file.write(test_cpp) + Cmake_file.write(""" + ) +include_directories(${GENERATED_INCLUDE_DIR}) + +if(FEATURE_PAL) include_directories(${COREPAL_SOURCE_DIR}/inc/rt) +endif(FEATURE_PAL) + +add_executable(eventprovidertest + ${SOURCES} + ) +set(EVENT_PROVIDER_DEPENDENCIES "") +set(EVENT_PROVIDER_LINKER_OTPTIONS "") +if(FEATURE_EVENT_TRACE) + add_definitions(-DFEATURE_EVENT_TRACE=1) + list(APPEND EVENT_PROVIDER_DEPENDENCIES + eventprovider + ) + if(CLR_CMAKE_PLATFORM_LINUX) + list(APPEND EVENT_PROVIDER_DEPENDENCIES + coreclrtraceptprovider + ) + endif(CLR_CMAKE_PLATFORM_LINUX) + list(APPEND EVENT_PROVIDER_LINKER_OTPTIONS + ${EVENT_PROVIDER_DEPENDENCIES} + ) +endif(FEATURE_EVENT_TRACE) + +add_dependencies(eventprovidertest ${EVENT_PROVIDER_DEPENDENCIES} coreclrpal) +target_link_libraries(eventprovidertest + coreclrpal + ${EVENT_PROVIDER_LINKER_OTPTIONS} + ) +""") + + + with open_for_update(testinfo) as Testinfo: + Testinfo.write(""" +Copyright (c) Microsoft Corporation. All rights reserved. +# - add_executable(eventprovidertest - ${SOURCES} - ) - set(EVENT_PROVIDER_DEPENDENCIES "") - set(EVENT_PROVIDER_LINKER_OTPTIONS "") - if(FEATURE_EVENT_TRACE) - add_definitions(-DFEATURE_EVENT_TRACE=1) - list(APPEND EVENT_PROVIDER_DEPENDENCIES - coreclrtraceptprovider - eventprovider - ) - list(APPEND EVENT_PROVIDER_LINKER_OTPTIONS - ${EVENT_PROVIDER_DEPENDENCIES} - ) - - endif(FEATURE_EVENT_TRACE) - - add_dependencies(eventprovidertest ${EVENT_PROVIDER_DEPENDENCIES} coreclrpal) - target_link_libraries(eventprovidertest - coreclrpal - ${EVENT_PROVIDER_LINKER_OTPTIONS} - ) - """) - Testinfo.write(""" - Copyright (c) Microsoft Corporation. All rights reserved. - # - - Version = 1.0 - Section = EventProvider - Function = EventProvider - Name = PAL test for FireEtW* and EventEnabled* functions - TYPE = DEFAULT - EXE1 = eventprovidertest - Description - =This is a sanity test to check that there are no crashes in Xplat eventing - """) +Version = 1.0 +Section = EventProvider +Function = EventProvider +Name = PAL test for FireEtW* and EventEnabled* functions +TYPE = DEFAULT +EXE1 = eventprovidertest +Description = This is a sanity test to check that there are no crashes in Xplat eventing +""") #Test.cpp - Test_cpp.write(stdprolog) - Test_cpp.write(""" + with open_for_update(testDir + "/" + test_cpp) as Test_cpp: + Test_cpp.write(stdprolog) + Test_cpp.write(""" /*===================================================================== ** ** Source: clralltestevents.cpp @@ -619,7 +632,9 @@ def generateSanityTest(sClrEtwAllMan,testDir): ** ** **===================================================================*/ +#if FEATURE_PAL #include <palsuite.h> +#endif //FEATURE_PAL #include <clrxplatevents.h> typedef struct _Struct1 { @@ -646,39 +661,42 @@ int win_Int32 = 12; BYTE* win_Binary =(BYTE*)var21 ; int __cdecl main(int argc, char **argv) { - +#if defined(FEATURE_PAL) /* Initialize the PAL. */ if(0 != PAL_Initialize(argc, argv)) { - return FAIL; + return FAIL; } +#endif ULONG Error = ERROR_SUCCESS; #if defined(FEATURE_EVENT_TRACE) Trace("\\n Starting functional eventing APIs tests \\n"); """) - Test_cpp.write(generateClralltestEvents(sClrEtwAllMan)) - Test_cpp.write(""" -/* Shutdown the PAL. - */ - - if (Error != ERROR_SUCCESS) - { - Fail("One or more eventing Apis failed\\n "); - return FAIL; - } - Trace("\\n All eventing APIs were fired succesfully \\n"); + Test_cpp.write(generateClralltestEvents(sClrEtwAllMan)) + Test_cpp.write(""" + + if (Error != ERROR_SUCCESS) + { + Fail("One or more eventing Apis failed\\n "); + return FAIL; + } + Trace("\\n All eventing APIs were fired succesfully \\n"); #endif //defined(FEATURE_EVENT_TRACE) - PAL_Terminate(); - return PASS; - } +#if defined(FEATURE_PAL) + +/* Shutdown the PAL. +*/ + + PAL_Terminate(); +#endif + return PASS; + } """) - Cmake_file.close() - Test_cpp.close() Testinfo.close() def generateEtmDummyHeader(sClrEtwAllMan,clretwdummy): @@ -693,19 +711,17 @@ def generateEtmDummyHeader(sClrEtwAllMan,clretwdummy): if not os.path.exists(incDir): os.makedirs(incDir) - Clretwdummy = open(clretwdummy,'w') - 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") + with open_for_update(clretwdummy) as Clretwdummy: + Clretwdummy.write(stdprolog + "\n") - Clretwdummy.close() + 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 generatePlformIndependentFiles(sClrEtwAllMan,incDir,etmDummyFile): +def generatePlatformIndependentFiles(sClrEtwAllMan, incDir, etmDummyFile, extern): generateEtmDummyHeader(sClrEtwAllMan,etmDummyFile) tree = DOM.parse(sClrEtwAllMan) @@ -717,152 +733,43 @@ def generatePlformIndependentFiles(sClrEtwAllMan,incDir,etmDummyFile): if not os.path.exists(incDir): os.makedirs(incDir) - clrallevents = incDir + "/clretwallmain.h" - clrxplatevents = incDir + "/clrxplatevents.h" - clreventpipewriteevents = incDir + "/clreventpipewriteevents.h" - - Clrallevents = open(clrallevents,'w') - Clrxplatevents = open(clrxplatevents,'w') - Clreventpipewriteevents = open(clreventpipewriteevents,'w') + # Write the main header for FireETW* functions + clrallevents = os.path.join(incDir, "clretwallmain.h") + with open_for_update(clrallevents) as Clrallevents: + Clrallevents.write(stdprolog) + Clrallevents.write(""" +#include "clrxplatevents.h" +#include "clreventpipewriteevents.h" - Clrallevents.write(stdprolog + "\n") - Clrxplatevents.write(stdprolog + "\n") - Clreventpipewriteevents.write(stdprolog + "\n") +""") + for providerNode in tree.getElementsByTagName('provider'): + templateNodes = providerNode.getElementsByTagName('template') + allTemplates = parseTemplateNodes(templateNodes) + eventNodes = providerNode.getElementsByTagName('event') - Clrallevents.write("\n#include \"clrxplatevents.h\"\n") - Clrallevents.write("#include \"clreventpipewriteevents.h\"\n\n") - - for providerNode in tree.getElementsByTagName('provider'): - templateNodes = providerNode.getElementsByTagName('template') - allTemplates = parseTemplateNodes(templateNodes) - eventNodes = providerNode.getElementsByTagName('event') - #vm header: - Clrallevents.write(generateClrallEvents(eventNodes, allTemplates) + "\n") + #vm header: + Clrallevents.write(generateClrallEvents(eventNodes, allTemplates) + "\n") - #pal: create clrallevents.h - Clrxplatevents.write(generateClrXplatEvents(eventNodes, allTemplates) + "\n") - #eventpipe: create clreventpipewriteevents.h - Clreventpipewriteevents.write(generateClrEventPipeWriteEvents(eventNodes, allTemplates) + "\n") + # Write secondary headers for FireEtXplat* and EventPipe* functions + clrxplatevents = os.path.join(incDir, "clrxplatevents.h") + clreventpipewriteevents = os.path.join(incDir, "clreventpipewriteevents.h") + with open_for_update(clrxplatevents) as Clrxplatevents: + with open_for_update(clreventpipewriteevents) as Clreventpipewriteevents: + Clrxplatevents.write(stdprolog + "\n") + Clreventpipewriteevents.write(stdprolog + "\n") - Clrxplatevents.close() - Clrallevents.close() - Clreventpipewriteevents.close() + for providerNode in tree.getElementsByTagName('provider'): + templateNodes = providerNode.getElementsByTagName('template') + allTemplates = parseTemplateNodes(templateNodes) + eventNodes = providerNode.getElementsByTagName('event') -class EventExclusions: - def __init__(self): - self.nostack = set() - self.explicitstack = set() - self.noclrinstance = set() - -def parseExclusionList(exclusionListFile): - ExclusionFile = open(exclusionListFile,'r') - exclusionInfo = EventExclusions() - - for line in ExclusionFile: - line = line.strip() - - #remove comments - if not line or line.startswith('#'): - continue - - tokens = line.split(':') - #entries starting with nomac are ignored - if "nomac" in tokens: - continue - - if len(tokens) > 5: - raise Exception("Invalid Entry " + line + "in "+ exclusionListFile) - - eventProvider = tokens[2] - eventTask = tokens[1] - eventSymbol = tokens[4] - - if eventProvider == '': - eventProvider = "*" - if eventTask == '': - eventTask = "*" - if eventSymbol == '': - eventSymbol = "*" - entry = eventProvider + ":" + eventTask + ":" + eventSymbol - - if tokens[0].lower() == "nostack": - exclusionInfo.nostack.add(entry) - if tokens[0].lower() == "stack": - exclusionInfo.explicitstack.add(entry) - if tokens[0].lower() == "noclrinstanceid": - exclusionInfo.noclrinstance.add(entry) - ExclusionFile.close() - - return exclusionInfo - -def getStackWalkBit(eventProvider, taskName, eventSymbol, stackSet): - for entry in stackSet: - tokens = entry.split(':') - - if len(tokens) != 3: - raise Exception("Error, possible error in the script which introduced the enrty "+ entry) - - eventCond = tokens[0] == eventProvider or tokens[0] == "*" - taskCond = tokens[1] == taskName or tokens[1] == "*" - symbolCond = tokens[2] == eventSymbol or tokens[2] == "*" - - if eventCond and taskCond and symbolCond: - return False - return True - -#Add the miscelaneous checks here -def checkConsistency(sClrEtwAllMan,exclusionListFile): - tree = DOM.parse(sClrEtwAllMan) - exclusionInfo = parseExclusionList(exclusionListFile) - for providerNode in tree.getElementsByTagName('provider'): + #pal: create clrallevents.h + Clrxplatevents.write(generateClrXplatEvents(eventNodes, allTemplates, extern) + "\n") - stackSupportSpecified = {} - eventNodes = providerNode.getElementsByTagName('event') - templateNodes = providerNode.getElementsByTagName('template') - eventProvider = providerNode.getAttribute('name') - allTemplates = parseTemplateNodes(templateNodes) + #eventpipe: create clreventpipewriteevents.h + Clreventpipewriteevents.write(generateClrEventPipeWriteEvents(eventNodes, allTemplates, extern) + "\n") - for eventNode in eventNodes: - taskName = eventNode.getAttribute('task') - eventSymbol = eventNode.getAttribute('symbol') - eventTemplate = eventNode.getAttribute('template') - eventValue = int(eventNode.getAttribute('value')) - clrInstanceBit = getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.noclrinstance) - sLookupFieldName = "ClrInstanceID" - sLookupFieldType = "win:UInt16" - - if clrInstanceBit and allTemplates.get(eventTemplate): - # check for the event template and look for a field named ClrInstanceId of type win:UInt16 - fnParam = allTemplates[eventTemplate].getFnParam(sLookupFieldName) - - if not(fnParam and fnParam.winType == sLookupFieldType): - raise Exception(exclusionListFile + ":No " + sLookupFieldName + " field of type " + sLookupFieldType + " for event symbol " + eventSymbol) - - # If some versions of an event are on the nostack/stack lists, - # and some versions are not on either the nostack or stack list, - # then developer likely forgot to specify one of the versions - - eventStackBitFromNoStackList = getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.nostack) - eventStackBitFromExplicitStackList = getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.explicitstack) - sStackSpecificityError = exclusionListFile + ": Error processing event :" + eventSymbol + "(ID" + str(eventValue) + "): This file must contain either ALL versions of this event or NO versions of this event. Currently some, but not all, versions of this event are present\n" - - if not stackSupportSpecified.get(eventValue): - # Haven't checked this event before. Remember whether a preference is stated - if ( not eventStackBitFromNoStackList) or ( not eventStackBitFromExplicitStackList): - stackSupportSpecified[eventValue] = True - else: - stackSupportSpecified[eventValue] = False - else: - # We've checked this event before. - if stackSupportSpecified[eventValue]: - # When we last checked, a preference was previously specified, so it better be specified here - if eventStackBitFromNoStackList and eventStackBitFromExplicitStackList: - raise Exception(sStackSpecificityError) - else: - # When we last checked, a preference was not previously specified, so it better not be specified here - if ( not eventStackBitFromNoStackList) or ( not eventStackBitFromExplicitStackList): - raise Exception(sStackSpecificityError) import argparse import sys @@ -874,28 +781,28 @@ def main(argv): 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('--exc', type=str, required=True, - help='full path to exclusion list') required.add_argument('--inc', type=str, default=None, help='full path to directory where the header files will be generated') required.add_argument('--dummy', type=str,default=None, help='full path to file that will have dummy definitions of FireEtw functions') required.add_argument('--testdir', type=str, default=None, help='full path to directory where the test assets will be deployed' ) + required.add_argument('--nonextern', action='store_true', + help='if specified, will not generated extern function stub headers' ) args, unknown = parser.parse_known_args(argv) if unknown: print('Unknown argument(s): ', ', '.join(unknown)) - return const.UnknownArguments + return 1 sClrEtwAllMan = args.man - exclusionListFile = args.exc incdir = args.inc etmDummyFile = args.dummy testDir = args.testdir + extern = not args.nonextern + + generatePlatformIndependentFiles(sClrEtwAllMan, incdir, etmDummyFile, extern) + generateSanityTest(sClrEtwAllMan, testDir) - checkConsistency(sClrEtwAllMan, exclusionListFile) - generatePlformIndependentFiles(sClrEtwAllMan,incdir,etmDummyFile) - generateSanityTest(sClrEtwAllMan,testDir) if __name__ == '__main__': return_code = main(sys.argv[1:]) - sys.exit(return_code) + sys.exit(return_code)
\ No newline at end of file diff --git a/src/scripts/genXplatLttng.py b/src/scripts/genLttngProvider.py index 9959895f5a..382cb74675 100644 --- a/src/scripts/genXplatLttng.py +++ b/src/scripts/genLttngProvider.py @@ -50,7 +50,8 @@ # import os -from genXplatEventing import * +from genEventing import * +from utilities import open_for_update stdprolog=""" // Licensed to the .NET Foundation under one or more agreements. @@ -60,7 +61,7 @@ stdprolog=""" /****************************************************************** DO NOT MODIFY. AUTOGENERATED FILE. -This file is generated using the logic from <root>/src/scripts/genXplatLttng.py +This file is generated using the logic from <root>/src/scripts/genLttngProvider.py ******************************************************************/ """ @@ -70,7 +71,7 @@ stdprolog_cmake=""" #****************************************************************** #DO NOT MODIFY. AUTOGENERATED FILE. -#This file is generated using the logic from <root>/src/scripts/genXplatLttng.py +#This file is generated using the logic from <root>/src/scripts/genLttngProvider.py #****************************************************************** """ @@ -159,7 +160,7 @@ def generateArgList(template): def generateFieldList(template): header = " " + " TP_FIELDS(\n" footer = "\n )\n)\n" - + if shouldPackTemplate(template): field_list = " ctf_integer(ULONG, length, length)\n" field_list += " ctf_sequence(char, __data__, __data__, ULONG, length)" @@ -209,7 +210,7 @@ def generateLttngHeader(providerName, allTemplates, eventNodes): for templateName in allTemplates: template = allTemplates[templateName] fnSig = allTemplates[templateName].signature - + lTTngHdr.append("\n#define " + templateName + "_TRACEPOINT_ARGS \\\n") #TP_ARGS @@ -289,7 +290,7 @@ def generateMethodBody(template, providerName, eventName): return "\n do_tracepoint(%s, %s);\n" % (providerName, eventName) fnSig = template.signature - + for paramName in fnSig.paramlist: fnparam = fnSig.getParam(paramName) paramname = fnparam.name @@ -298,7 +299,7 @@ def generateMethodBody(template, providerName, eventName): result.append(" INT " + paramname + "_path_size = -1;\n") result.append(" PathCharString " + paramname + "_PS;\n") result.append(" INT " + paramname + "_full_name_path_size") - result.append(" = (PAL_wcslen(" + paramname + ") + 1)*sizeof(WCHAR);\n") + result.append(" = (wcslen(" + paramname + ") + 1)*sizeof(WCHAR);\n") result.append(" CHAR* " + paramname + "_full_name = ") result.append(paramname + "_PS.OpenStringBuffer(" + paramname + "_full_name_path_size );\n") result.append(" if (" + paramname + "_full_name == NULL )") @@ -308,7 +309,7 @@ def generateMethodBody(template, providerName, eventName): #emit tracepoints fnSig = template.signature - + if not shouldPackTemplate(template): linefnbody = [" do_tracepoint(%s,\n %s" % (providerName, eventName)] @@ -360,8 +361,8 @@ def generateMethodBody(template, providerName, eventName): header = """ char stackBuffer[%s]; char *buffer = stackBuffer; - int offset = 0; - int size = %s; + size_t offset = 0; + size_t size = %s; bool fixedBuffer = true; bool success = true; @@ -401,7 +402,7 @@ def generateMethodBody(template, providerName, eventName): do_tracepoint(%s, %s, offset, buffer);\n""" % (providerName, eventName) return header + code + tracepoint + footer - + @@ -420,7 +421,7 @@ def generateLttngTpProvider(providerName, eventNodes, allTemplates): fnptype.append(eventName) fnptype.append("(\n") - + if templateName: template = allTemplates[templateName] else: @@ -489,7 +490,7 @@ def generateLttngFiles(etwmanifest,eventprovider_directory): os.makedirs(eventprovider_directory + tracepointprovider_directory) #Top level Cmake - with open(eventprovider_directory + "CMakeLists.txt", 'w') as topCmake: + with open_for_update(eventprovider_directory + "CMakeLists.txt") as topCmake: topCmake.write(stdprolog_cmake + "\n") topCmake.write("""cmake_minimum_required(VERSION 2.8.12.2) @@ -514,7 +515,7 @@ def generateLttngFiles(etwmanifest,eventprovider_directory): providerName_File = providerName_File.lower() topCmake.write(' "%s%s.cpp"\n' % (lttngevntprovPre, providerName_File)) - + topCmake.write(' "%shelpers.cpp"\n' % (lttngevntprovPre,)) topCmake.write(""") add_subdirectory(tracepointprovider) @@ -525,7 +526,7 @@ def generateLttngFiles(etwmanifest,eventprovider_directory): #TracepointProvider Cmake - with open(eventprovider_directory + tracepointprovider_directory + "/CMakeLists.txt", 'w') as tracepointprovider_Cmake: + with open_for_update(eventprovider_directory + tracepointprovider_directory + "/CMakeLists.txt") as tracepointprovider_Cmake: tracepointprovider_Cmake.write(stdprolog_cmake + "\n") tracepointprovider_Cmake.write("""cmake_minimum_required(VERSION 2.8.12.2) @@ -562,7 +563,7 @@ def generateLttngFiles(etwmanifest,eventprovider_directory): install_clr(coreclrtraceptprovider) """) - with open(eventprovider_directory + lttng_directory + "/eventprovhelpers.cpp", 'w') as helper: + with open_for_update(eventprovider_directory + lttng_directory + "/eventprovhelpers.cpp") as helper: helper.write(""" #include "palrt.h" #include "pal.h" @@ -572,72 +573,81 @@ def generateLttngFiles(etwmanifest,eventprovider_directory): #include <new> #include <memory.h> -bool ResizeBuffer(char *&buffer, int& size, int currLen, int newSize, bool &fixedBuffer) +#define wcslen PAL_wcslen + +bool ResizeBuffer(char *&buffer, size_t& size, size_t currLen, size_t newSize, bool &fixedBuffer) { - newSize *= 1.5; - _ASSERTE(newSize > size); // check for overflow + newSize = (size_t)(newSize * 1.5); + _ASSERTE(newSize > size); // check for overflow if (newSize < 32) newSize = 32; - char *newBuffer = new char[newSize]; + // We can't use coreclr includes here so we use std::nothrow + // rather than the coreclr version + char *newBuffer = new (std::nothrow) char[newSize]; - memcpy(newBuffer, buffer, currLen); + if (newBuffer == NULL) + return false; - if (!fixedBuffer) - delete[] buffer; + memcpy(newBuffer, buffer, currLen); - buffer = newBuffer; - size = newSize; - fixedBuffer = false; + if (!fixedBuffer) + delete[] buffer; - return true; + buffer = newBuffer; + size = newSize; + fixedBuffer = false; + + return true; } -bool WriteToBuffer(const BYTE *src, int len, char *&buffer, int& offset, int& size, bool &fixedBuffer) +bool WriteToBuffer(const BYTE *src, size_t len, char *&buffer, size_t& offset, size_t& 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; + 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, int& offset, int& size, bool &fixedBuffer) +bool WriteToBuffer(PCWSTR str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer) { - if (!str) return true; - 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; + if(!str) return true; + size_t byteCount = (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, int& offset, int& size, bool &fixedBuffer) +bool WriteToBuffer(const char *str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer) { - if (!str) return true; - 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; -}""") + if(!str) return true; + size_t 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; +} + +""") # Generate Lttng specific instrumentation for providerNode in tree.getElementsByTagName('provider'): @@ -650,24 +660,19 @@ bool WriteToBuffer(const char *str, char *&buffer, int& offset, int& size, bool providerName_File = providerName_File.lower() providerName = providerName.replace('-','_') - lttngevntheadershortname = "tp" + providerName_File +".h"; + lttngevntheadershortname = "tp" + providerName_File +".h" lttngevntheader = eventprovider_directory + "lttng/" + lttngevntheadershortname lttngevntprov = eventprovider_directory + lttngevntprovPre + providerName_File + ".cpp" lttngevntprovTp = eventprovider_directory + lttngevntprovTpPre + providerName_File +".cpp" - lTTngHdr = open(lttngevntheader, 'w') - lTTngImpl = open(lttngevntprov, 'w') - lTTngTpImpl = open(lttngevntprovTp, 'w') - - lTTngHdr.write(stdprolog + "\n") - lTTngImpl.write(stdprolog + "\n") - lTTngTpImpl.write(stdprolog + "\n") - - lTTngTpImpl.write("\n#define TRACEPOINT_CREATE_PROBES\n") + templateNodes = providerNode.getElementsByTagName('template') + eventNodes = providerNode.getElementsByTagName('event') + allTemplates = parseTemplateNodes(templateNodes) - lTTngTpImpl.write("#include \"./"+lttngevntheadershortname + "\"\n") - lTTngHdr.write(""" + with open_for_update(lttngevntheader) as lttnghdr_file: + lttnghdr_file.write(stdprolog + "\n") + lttnghdr_file.write(""" #include "palrt.h" #include "pal.h" @@ -675,20 +680,24 @@ bool WriteToBuffer(const char *str, char *&buffer, int& offset, int& size, bool """) - lTTngHdr.write("#define TRACEPOINT_PROVIDER " + providerName + "\n") - lTTngHdr.write(""" + lttnghdr_file.write("#define TRACEPOINT_PROVIDER " + providerName + "\n") + lttnghdr_file.write(""" #undef TRACEPOINT_INCLUDE """) - lTTngHdr.write("#define TRACEPOINT_INCLUDE \"./" + lttngevntheadershortname + "\"\n\n") + lttnghdr_file.write("#define TRACEPOINT_INCLUDE \"./" + lttngevntheadershortname + "\"\n\n") + + lttnghdr_file.write("#if !defined(LTTNG_CORECLR_H" + providerName + ") || defined(TRACEPOINT_HEADER_MULTI_READ)\n\n") + lttnghdr_file.write("#define LTTNG_CORECLR_H" + providerName + "\n") - lTTngHdr.write("#if !defined(LTTNG_CORECLR_H" + providerName + ") || defined(TRACEPOINT_HEADER_MULTI_READ)\n\n") - lTTngHdr.write("#define LTTNG_CORECLR_H" + providerName + "\n") + lttnghdr_file.write("\n#include <lttng/tracepoint.h>\n\n") - lTTngHdr.write("\n#include <lttng/tracepoint.h>\n\n") + lttnghdr_file.write(generateLttngHeader(providerName,allTemplates,eventNodes) + "\n") - lTTngImpl.write(""" + with open_for_update(lttngevntprov) as lttngimpl_file: + lttngimpl_file.write(stdprolog + "\n") + lttngimpl_file.write(""" #define TRACEPOINT_DEFINE #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE @@ -700,48 +709,43 @@ bool WriteToBuffer(const char *str, char *&buffer, int& offset, int& size, bool #define PAL_realloc realloc #include "pal/stackstring.hpp" """) - lTTngImpl.write("#include \"" + lttngevntheadershortname + "\"\n\n") + lttngimpl_file.write("#include \"" + lttngevntheadershortname + "\"\n\n") - lTTngImpl.write("""#ifndef tracepoint_enabled + lttngimpl_file.write("""#ifndef tracepoint_enabled #define tracepoint_enabled(provider, name) TRUE #define do_tracepoint tracepoint #endif +#define wcslen PAL_wcslen -bool ResizeBuffer(char *&buffer, int& size, int currLen, int newSize, bool &fixedBuffer); -bool WriteToBuffer(PCWSTR str, char *&buffer, int& offset, int& size, bool &fixedBuffer); -bool WriteToBuffer(const char *str, char *&buffer, int& offset, int& size, bool &fixedBuffer); -bool WriteToBuffer(const BYTE *src, int len, char *&buffer, int& offset, int& size, bool &fixedBuffer); +bool ResizeBuffer(char *&buffer, size_t& size, size_t currLen, size_t newSize, bool &fixedBuffer); +bool WriteToBuffer(PCWSTR str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer); +bool WriteToBuffer(const char *str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer); +bool WriteToBuffer(const BYTE *src, size_t len, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer); template <typename T> -bool WriteToBuffer(const T &value, char *&buffer, int& offset, int& size, bool &fixedBuffer) +bool WriteToBuffer(const T &value, char *&buffer, size_t& offset, size_t& 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; + 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; } """) + lttngimpl_file.write(generateLttngTpProvider(providerName,eventNodes,allTemplates) + "\n") - templateNodes = providerNode.getElementsByTagName('template') - eventNodes = providerNode.getElementsByTagName('event') - - allTemplates = parseTemplateNodes(templateNodes) - #generate the header - lTTngHdr.write(generateLttngHeader(providerName,allTemplates,eventNodes) + "\n") + with open_for_update(lttngevntprovTp) as tpimpl_file: + tpimpl_file.write(stdprolog + "\n") - #create the implementation of eventing functions : lttngeventprov*.cp - lTTngImpl.write(generateLttngTpProvider(providerName,eventNodes,allTemplates) + "\n") + tpimpl_file.write("\n#define TRACEPOINT_CREATE_PROBES\n") - lTTngHdr.close() - lTTngImpl.close() - lTTngTpImpl.close() + tpimpl_file.write("#include \"./"+lttngevntheadershortname + "\"\n") import argparse import sys @@ -759,7 +763,7 @@ def main(argv): args, unknown = parser.parse_known_args(argv) if unknown: print('Unknown argument(s): ', ', '.join(unknown)) - return const.UnknownArguments + return 1 sClrEtwAllMan = args.man intermediate = args.intermediate @@ -768,4 +772,4 @@ def main(argv): if __name__ == '__main__': return_code = main(sys.argv[1:]) - sys.exit(return_code) + sys.exit(return_code)
\ No newline at end of file diff --git a/src/scripts/genWinEtw.py b/src/scripts/genWinEtw.py deleted file mode 100644 index aa75f680cd..0000000000 --- a/src/scripts/genWinEtw.py +++ /dev/null @@ -1,125 +0,0 @@ - -## 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. -# - -import os -from genXplatEventing import * - -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/genWinEtw.py - -******************************************************************/ - -""" -import argparse -import sys -import xml.dom.minidom as DOM - -def generateEtwMacroHeader(sClrEtwAllMan, sExcludeFile,macroHeader,inHeader): - tree = DOM.parse(sClrEtwAllMan) - numOfProviders = len(tree.getElementsByTagName('provider')) - nMaxEventBytesPerProvider = 64 - - exclusionInfo = parseExclusionList(sExcludeFile) - incDir = os.path.dirname(os.path.realpath(macroHeader)) - if not os.path.exists(incDir): - os.makedirs(incDir) - - outHeader = open(macroHeader,'w') - outHeader.write(stdprolog + "\n") - - outHeader.write("#include \"" + os.path.basename(inHeader) + '"\n') - outHeader.write("#define NO_OF_ETW_PROVIDERS " + str(numOfProviders) + "\n") - outHeader.write("#define MAX_BYTES_PER_ETW_PROVIDER " + str(nMaxEventBytesPerProvider) + "\n") - outHeader.write("EXTERN_C __declspec(selectany) const BYTE etwStackSupportedEvents[NO_OF_ETW_PROVIDERS][MAX_BYTES_PER_ETW_PROVIDER] = \n{\n") - - for providerNode in tree.getElementsByTagName('provider'): - stackSupportedEvents = [0]*nMaxEventBytesPerProvider - eventNodes = providerNode.getElementsByTagName('event') - eventProvider = providerNode.getAttribute('name') - - for eventNode in eventNodes: - taskName = eventNode.getAttribute('task') - eventSymbol = eventNode.getAttribute('symbol') - eventTemplate = eventNode.getAttribute('template') - eventTemplate = eventNode.getAttribute('template') - eventValue = int(eventNode.getAttribute('value')) - eventIndex = eventValue // 8 - eventBitPositionInIndex = eventValue % 8 - - eventStackBitFromNoStackList = int(getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.nostack)) - eventStackBitFromExplicitStackList = int(getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.explicitstack)) - - # Shift those bits into position. For the explicit stack list, swap 0 and 1, so the eventValue* variables - # have 1 in the position iff we should issue a stack for the event. - eventValueUsingNoStackListByPosition = (eventStackBitFromNoStackList << eventBitPositionInIndex) - eventValueUsingExplicitStackListByPosition = ((1 - eventStackBitFromExplicitStackList) << eventBitPositionInIndex) - - # Commit the values to the in-memory array that we'll dump into the header file - stackSupportedEvents[eventIndex] = stackSupportedEvents[eventIndex] | eventValueUsingNoStackListByPosition; - if eventStackBitFromExplicitStackList == 0: - stackSupportedEvents[eventIndex] = stackSupportedEvents[eventIndex] | eventValueUsingExplicitStackListByPosition - - # print the bit array - line = [] - line.append("\t{") - for elem in stackSupportedEvents: - line.append(str(elem)) - line.append(", ") - - del line[-1] - line.append("},") - outHeader.write(''.join(line) + "\n") - outHeader.write("};\n") - - outHeader.close() - - -def generateEtwFiles(sClrEtwAllMan, exclusionListFile, etmdummyHeader, macroHeader, inHeader): - - checkConsistency(sClrEtwAllMan, exclusionListFile) - generateEtmDummyHeader(sClrEtwAllMan, etmdummyHeader) - generateEtwMacroHeader(sClrEtwAllMan, exclusionListFile, macroHeader, inHeader) - -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 containig the description of events') - required.add_argument('--exc', type=str, required=True, - help='full path to exclusion list') - required.add_argument('--eventheader', type=str, required=True, - help='full path to the header file') - required.add_argument('--macroheader', type=str, required=True, - help='full path to the macro header file') - required.add_argument('--dummy', type=str, required=True, - help='full path to file that will have dummy definitions of FireEtw functions') - - args, unknown = parser.parse_known_args(argv) - if unknown: - print('Unknown argument(s): ', ', '.join(unknown)) - return const.UnknownArguments - - sClrEtwAllMan = args.man - exclusionListFile = args.exc - inHeader = args.eventheader - macroHeader = args.macroheader - etmdummyHeader = args.dummy - - generateEtwFiles(sClrEtwAllMan, exclusionListFile, etmdummyHeader, macroHeader, inHeader) - -if __name__ == '__main__': - return_code = main(sys.argv[1:]) - sys.exit(return_code) diff --git a/src/scripts/utilities.py b/src/scripts/utilities.py new file mode 100644 index 0000000000..6898bb7542 --- /dev/null +++ b/src/scripts/utilities.py @@ -0,0 +1,106 @@ +from filecmp import dircmp +from hashlib import sha256 +from io import StringIO +import shutil +import os + +class WrappedStringIO(StringIO): + """A wrapper around StringIO to allow writing str objects""" + def write(self, s): + if isinstance(s, str): + s = unicode(s) + super(WrappedStringIO, self).write(s) + +class UpdateFileWriter: + """A file-like context object which will only write to a file if the result would be different + + Attributes: + filename (str): The name of the file to update + stream (WrappedStringIO): The file-like stream provided upon context enter + + Args: + filename (str): Sets the filename attribute + """ + filemode = 'w' + + def __init__(self, filename): + self.filename = filename + self.stream = None + + def __enter__(self): + self.stream = WrappedStringIO() + return self.stream + + def __exit__(self, exc_type, exc_value, traceback): + if exc_value is None: + new_content = self.stream.getvalue() + new_hash = sha256() + cur_hash = sha256() + + try: + with open(self.filename, 'r') as fstream: + cur_hash.update(fstream.read()) + file_found = True + except IOError: + file_found = False + + if file_found: + new_hash.update(new_content) + update = new_hash.digest() != cur_hash.digest() + else: + update = True + + if update: + with open(self.filename, 'w') as fstream: + fstream.write(new_content) + + self.stream.close() + +def open_for_update(filename): + return UpdateFileWriter(filename) + +def walk_recursively_and_update(dcmp): + #for different Files Copy from right to left + for name in dcmp.diff_files: + srcpath = dcmp.right + "/" + name + destpath = dcmp.left + "/" + name + print("Updating %s" % (destpath)) + if os.path.isfile(srcpath): + shutil.copyfile(srcpath, destpath) + else : + raise Exception("path: " + srcpath + "is neither a file or folder") + + #copy right only files + for name in dcmp.right_only: + srcpath = dcmp.right + "/" + name + destpath = dcmp.left + "/" + name + print("Updating %s" % (destpath)) + if os.path.isfile(srcpath): + shutil.copyfile(srcpath, destpath) + elif os.path.isdir(srcpath): + shutil.copytree(srcpath, destpath) + else : + raise Exception("path: " + srcpath + "is neither a file or folder") + + #delete left only files + for name in dcmp.left_only: + path = dcmp.left + "/" + name + print("Deleting %s" % (path)) + if os.path.isfile(path): + os.remove(path) + elif os.path.isdir(path): + shutil.rmtree(path) + else : + raise Exception("path: " + path + "is neither a file or folder") + + #call recursively + for sub_dcmp in dcmp.subdirs.values(): + walk_recursively_and_update(sub_dcmp) + +def UpdateDirectory(destpath,srcpath): + + print("Updating %s with %s" % (destpath,srcpath)) + if not os.path.exists(destpath): + os.makedirs(destpath) + dcmp = dircmp(destpath,srcpath) + walk_recursively_and_update(dcmp) |