1 from __future__ import print_function
2 from genEventing import *
3 from genLttngProvider import *
5 import xml.dom.minidom as DOM
6 from utilities import open_for_update, parseExclusionList
8 stdprolog_cpp = """// Licensed to the .NET Foundation under one or more agreements.
9 // The .NET Foundation licenses this file to you under the MIT license.
10 // See the LICENSE file in the project root for more information.
12 /******************************************************************
14 DO NOT MODIFY. AUTOGENERATED FILE.
15 This file is generated using the logic from <root>/src/scripts/genEventPipe.py
17 ******************************************************************/
21 stdprolog_cmake = """#
23 #******************************************************************
25 #DO NOT MODIFY. AUTOGENERATED FILE.
26 #This file is generated using the logic from <root>/src/scripts/genEventPipe.py
28 #******************************************************************
32 eventpipe_dirname = "eventpipe"
34 def generateMethodSignatureEnabled(eventName):
35 return "BOOL EventPipeEventEnabled%s()" % (eventName,)
37 def generateMethodSignatureWrite(eventName, template, extern):
40 if extern: sig_pieces.append('extern "C" ')
41 sig_pieces.append("ULONG EventPipeWriteEvent")
42 sig_pieces.append(eventName)
43 sig_pieces.append("(")
46 sig_pieces.append("\n")
47 fnSig = template.signature
48 for paramName in fnSig.paramlist:
49 fnparam = fnSig.getParam(paramName)
50 wintypeName = fnparam.winType
51 typewName = palDataTypeMapping[wintypeName]
52 winCount = fnparam.count
53 countw = palDataTypeMapping[winCount]
55 if paramName in template.structs:
57 "%sint %s_ElementSize,\n" %
60 sig_pieces.append(lindent)
61 sig_pieces.append(typewName)
63 sig_pieces.append(countw)
65 sig_pieces.append(" ")
66 sig_pieces.append(fnparam.name)
67 sig_pieces.append(",\n")
69 if len(sig_pieces) > 0:
72 sig_pieces.append(")")
73 return ''.join(sig_pieces)
75 def generateClrEventPipeWriteEventsImpl(
76 providerName, eventNodes, allTemplates, extern, exclusionList):
77 providerPrettyName = providerName.replace("Windows-", '')
78 providerPrettyName = providerPrettyName.replace("Microsoft-", '')
79 providerPrettyName = providerPrettyName.replace('-', '_')
82 # EventPipeEvent declaration
83 for eventNode in eventNodes:
84 eventName = eventNode.getAttribute('symbol')
85 WriteEventImpl.append(
86 "EventPipeEvent *EventPipeEvent" +
90 for eventNode in eventNodes:
91 eventName = eventNode.getAttribute('symbol')
92 templateName = eventNode.getAttribute('template')
94 # generate EventPipeEventEnabled function
95 eventEnabledImpl = generateMethodSignatureEnabled(eventName) + """
97 return EventPipeEvent%s->IsEnabled();
101 WriteEventImpl.append(eventEnabledImpl)
103 # generate EventPipeWriteEvent function
107 template = allTemplates[templateName]
111 fnptype.append(generateMethodSignatureWrite(eventName, template, extern))
112 fnptype.append("\n{\n")
113 checking = """ if (!EventPipeEventEnabled%s())
114 return ERROR_SUCCESS;
117 fnptype.append(checking)
119 WriteEventImpl.extend(fnptype)
122 body = generateWriteEventBody(template, providerName, eventName)
123 WriteEventImpl.append(body)
125 WriteEventImpl.append(
126 " EventPipe::WriteEvent(*EventPipeEvent" +
128 ", (BYTE*) nullptr, 0);\n")
130 WriteEventImpl.append("\n return ERROR_SUCCESS;\n}\n\n")
132 # EventPipeProvider and EventPipeEvent initialization
133 callbackName = 'EventPipeEtwCallback' + providerPrettyName
134 if extern: WriteEventImpl.append('extern "C" ')
135 WriteEventImpl.append(
139 WriteEventImpl.append(
140 " EventPipeProvider" +
142 " = EventPipe::CreateProvider(SL(" +
144 "Name), " + callbackName + ");\n")
145 for eventNode in eventNodes:
146 eventName = eventNode.getAttribute('symbol')
147 templateName = eventNode.getAttribute('template')
148 eventKeywords = eventNode.getAttribute('keywords')
149 eventKeywordsMask = generateEventKeywords(eventKeywords)
150 eventValue = eventNode.getAttribute('value')
151 eventVersion = eventNode.getAttribute('version')
152 eventLevel = eventNode.getAttribute('level')
153 eventLevel = eventLevel.replace("win:", "EventPipeEventLevel::")
154 taskName = eventNode.getAttribute('task')
157 for nostackentry in exclusionList.nostack:
158 tokens = nostackentry.split(':')
159 if tokens[2] == eventName:
162 initEvent = """ EventPipeEvent%s = EventPipeProvider%s->AddEvent(%s,%s,%s,%s,%s);
163 """ % (eventName, providerPrettyName, eventValue, eventKeywordsMask, eventVersion, eventLevel, needStack)
165 WriteEventImpl.append(initEvent)
166 WriteEventImpl.append("}")
168 return ''.join(WriteEventImpl)
171 def generateWriteEventBody(template, providerName, eventName):
173 char stackBuffer[%s];
174 char *buffer = stackBuffer;
177 bool fixedBuffer = true;
180 """ % (template.estimated_size, template.estimated_size)
182 fnSig = template.signature
184 for paramName in fnSig.paramlist:
185 parameter = fnSig.getParam(paramName)
187 if paramName in template.structs:
188 size = "(int)%s_ElementSize * (int)%s" % (
189 paramName, parameter.prop)
190 if template.name in specialCaseSizes and paramName in specialCaseSizes[template.name]:
191 size = "(int)(%s)" % specialCaseSizes[template.name][paramName]
193 " success &= WriteToBuffer((const BYTE *)%s, %s, buffer, offset, size, fixedBuffer);" %
195 elif paramName in template.arrays:
196 size = "sizeof(%s) * (int)%s" % (
197 lttngDataTypeMapping[parameter.winType],
199 if template.name in specialCaseSizes and paramName in specialCaseSizes[template.name]:
200 size = "(int)(%s)" % specialCaseSizes[template.name][paramName]
202 " success &= WriteToBuffer((const BYTE *)%s, %s, buffer, offset, size, fixedBuffer);" %
204 elif parameter.winType == "win:GUID":
206 " success &= WriteToBuffer(*%s, buffer, offset, size, fixedBuffer);" %
210 " success &= WriteToBuffer(%s, buffer, offset, size, fixedBuffer);" %
213 code = "\n".join(pack_list) + "\n\n"
215 checking = """ if (!success)
219 return ERROR_WRITE_FAULT;
222 body = " EventPipe::WriteEvent(*EventPipeEvent" + \
223 eventName + ", (BYTE *)buffer, (unsigned int)offset);\n"
230 return header + code + checking + body + footer
235 def generateEventKeywords(eventKeywords):
237 # split keywords if there are multiple
238 allKeywords = eventKeywords.split()
240 for singleKeyword in allKeywords:
241 mask = mask | keywordMap[singleKeyword]
245 def generateEventPipeHelperFile(etwmanifest, eventpipe_directory, extern, dryRun):
246 eventpipehelpersPath = os.path.join(eventpipe_directory, "eventpipehelpers.cpp")
248 print(eventpipehelpersPath)
250 with open_for_update(eventpipehelpersPath) as helper:
251 helper.write(stdprolog_cpp)
264 bool ResizeBuffer(char *&buffer, size_t& size, size_t currLen, size_t newSize, bool &fixedBuffer)
266 newSize = (size_t)(newSize * 1.5);
267 _ASSERTE(newSize > size); // check for overflow
272 char *newBuffer = new (nothrow) char[newSize];
274 if (newBuffer == NULL)
277 memcpy(newBuffer, buffer, currLen);
289 bool WriteToBuffer(const BYTE *src, size_t len, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer)
291 if(!src) return true;
292 if (offset + len > size)
294 if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer))
298 memcpy(buffer + offset, src, len);
303 bool WriteToBuffer(PCWSTR str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer)
305 if(!str) return true;
306 size_t byteCount = (wcslen(str) + 1) * sizeof(*str);
308 if (offset + byteCount > size)
310 if (!ResizeBuffer(buffer, size, offset, size + byteCount, fixedBuffer))
314 memcpy(buffer + offset, str, byteCount);
319 bool WriteToBuffer(const char *str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer)
321 if(!str) return true;
322 size_t len = strlen(str) + 1;
323 if (offset + len > size)
325 if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer))
329 memcpy(buffer + offset, str, len);
336 tree = DOM.parse(etwmanifest)
338 for providerNode in tree.getElementsByTagName('provider'):
339 providerName = providerNode.getAttribute('name')
340 providerPrettyName = providerName.replace("Windows-", '')
341 providerPrettyName = providerPrettyName.replace("Microsoft-", '')
342 providerPrettyName = providerPrettyName.replace('-', '_')
343 if extern: helper.write(
351 if extern: helper.write(
354 helper.write("void InitProvidersAndEvents()\n{\n")
355 for providerNode in tree.getElementsByTagName('provider'):
356 providerName = providerNode.getAttribute('name')
357 providerPrettyName = providerName.replace("Windows-", '')
358 providerPrettyName = providerPrettyName.replace("Microsoft-", '')
359 providerPrettyName = providerPrettyName.replace('-', '_')
360 helper.write(" Init" + providerPrettyName + "();\n")
365 def generateEventPipeImplFiles(
366 etwmanifest, eventpipe_directory, extern, exclusionList, dryRun):
367 tree = DOM.parse(etwmanifest)
369 # Find the src directory starting with the assumption that
370 # A) It is named 'src'
371 # B) This script lives in it
372 src_dirname = os.path.dirname(__file__)
373 while os.path.basename(src_dirname) != "src":
374 src_dirname = os.path.dirname(src_dirname)
376 if os.path.basename(src_dirname) == "":
377 raise IOError("Could not find the Core CLR 'src' directory")
379 for providerNode in tree.getElementsByTagName('provider'):
380 providerName = providerNode.getAttribute('name')
382 providerPrettyName = providerName.replace("Windows-", '')
383 providerPrettyName = providerPrettyName.replace("Microsoft-", '')
384 providerName_File = providerPrettyName.replace('-', '')
385 providerName_File = providerName_File.lower()
386 providerPrettyName = providerPrettyName.replace('-', '_')
387 eventpipefile = os.path.join(eventpipe_directory, providerName_File + ".cpp")
391 with open_for_update(eventpipefile) as eventpipeImpl:
392 eventpipeImpl.write(stdprolog_cpp)
395 #include "{root:s}/vm/common.h"
396 #include "{root:s}/vm/eventpipeprovider.h"
397 #include "{root:s}/vm/eventpipeevent.h"
398 #include "{root:s}/vm/eventpipe.h"
400 #if defined(FEATURE_PAL)
401 #define wcslen PAL_wcslen
404 bool ResizeBuffer(char *&buffer, size_t& size, size_t currLen, size_t newSize, bool &fixedBuffer);
405 bool WriteToBuffer(PCWSTR str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer);
406 bool WriteToBuffer(const char *str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer);
407 bool WriteToBuffer(const BYTE *src, size_t len, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer);
409 template <typename T>
410 bool WriteToBuffer(const T &value, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer)
412 if (sizeof(T) + offset > size)
414 if (!ResizeBuffer(buffer, size, offset, size + sizeof(T), fixedBuffer))
418 memcpy(buffer + offset, (char *)&value, sizeof(T));
423 """.format(root=src_dirname.replace('\\', '/'))
425 eventpipeImpl.write(header)
427 "const WCHAR* %sName = W(\"%s\");\n" % (
433 "EventPipeProvider *EventPipeProvider%s = nullptr;\n" % (
437 templateNodes = providerNode.getElementsByTagName('template')
438 allTemplates = parseTemplateNodes(templateNodes)
439 eventNodes = providerNode.getElementsByTagName('event')
441 generateClrEventPipeWriteEventsImpl(
446 exclusionList) + "\n")
448 def generateEventPipeFiles(
449 etwmanifest, intermediate, extern, exclusionList, dryRun):
450 eventpipe_directory = os.path.join(intermediate, eventpipe_dirname)
451 tree = DOM.parse(etwmanifest)
453 if not os.path.exists(eventpipe_directory):
454 os.makedirs(eventpipe_directory)
456 # generate helper file
457 generateEventPipeHelperFile(etwmanifest, eventpipe_directory, extern, dryRun)
459 # generate all keywords
460 for keywordNode in tree.getElementsByTagName('keyword'):
461 keywordName = keywordNode.getAttribute('name')
462 keywordMask = keywordNode.getAttribute('mask')
463 keywordMap[keywordName] = int(keywordMask, 0)
465 # generate .cpp file for each provider
466 generateEventPipeImplFiles(
479 # parse the command line
480 parser = argparse.ArgumentParser(
481 description="Generates the Code required to instrument eventpipe logging mechanism")
483 required = parser.add_argument_group('required arguments')
484 required.add_argument('--man', type=str, required=True,
485 help='full path to manifest containig the description of events')
486 required.add_argument('--exc', type=str, required=True,
487 help='full path to exclusion list')
488 required.add_argument('--intermediate', type=str, required=True,
489 help='full path to eventprovider intermediate directory')
490 required.add_argument('--nonextern', action='store_true',
491 help='if specified, will generate files to be compiled into the CLR rather than extern' )
492 required.add_argument('--dry-run', action='store_true',
493 help='if specified, will output the names of the generated files instead of generating the files' )
494 args, unknown = parser.parse_known_args(argv)
496 print('Unknown argument(s): ', ', '.join(unknown))
499 sClrEtwAllMan = args.man
500 exclusion_filename = args.exc
501 intermediate = args.intermediate
502 extern = not args.nonextern
503 dryRun = args.dry_run
505 generateEventPipeFiles(sClrEtwAllMan, intermediate, extern, parseExclusionList(exclusion_filename), dryRun)
507 if __name__ == '__main__':
508 return_code = main(sys.argv[1:])
509 sys.exit(return_code)