[Tizen] Implement detecting of sanitized libraries
[platform/upstream/coreclr.git] / src / scripts / genEventPipe.py
1 from __future__ import print_function
2 from genEventing import *
3 from genLttngProvider import *
4 import os
5 import xml.dom.minidom as DOM
6 from utilities import open_for_update, parseExclusionList
7
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.
11
12 /******************************************************************
13
14 DO NOT MODIFY. AUTOGENERATED FILE.
15 This file is generated using the logic from <root>/src/scripts/genEventPipe.py
16
17 ******************************************************************/
18
19 """
20
21 stdprolog_cmake = """#
22 #
23 #******************************************************************
24
25 #DO NOT MODIFY. AUTOGENERATED FILE.
26 #This file is generated using the logic from <root>/src/scripts/genEventPipe.py
27
28 #******************************************************************
29
30 """
31
32 eventpipe_dirname = "eventpipe"
33
34 def generateMethodSignatureEnabled(eventName):
35     return "BOOL EventPipeEventEnabled%s()" % (eventName,)
36
37 def generateMethodSignatureWrite(eventName, template, extern):
38     sig_pieces = []
39
40     if extern: sig_pieces.append('extern "C" ')
41     sig_pieces.append("ULONG EventPipeWriteEvent")
42     sig_pieces.append(eventName)
43     sig_pieces.append("(")
44
45     if template:
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]
54
55             if paramName in template.structs:
56                 sig_pieces.append(
57                     "%sint %s_ElementSize,\n" %
58                     (lindent, paramName))
59
60             sig_pieces.append(lindent)
61             sig_pieces.append(typewName)
62             if countw != " ":
63                 sig_pieces.append(countw)
64
65             sig_pieces.append(" ")
66             sig_pieces.append(fnparam.name)
67             sig_pieces.append(",\n")
68
69         if len(sig_pieces) > 0:
70             del sig_pieces[-1]
71
72     sig_pieces.append(")")
73     return ''.join(sig_pieces)
74
75 def generateClrEventPipeWriteEventsImpl(
76         providerName, eventNodes, allTemplates, extern, exclusionList):
77     providerPrettyName = providerName.replace("Windows-", '')
78     providerPrettyName = providerPrettyName.replace("Microsoft-", '')
79     providerPrettyName = providerPrettyName.replace('-', '_')
80     WriteEventImpl = []
81
82     # EventPipeEvent declaration
83     for eventNode in eventNodes:
84         eventName = eventNode.getAttribute('symbol')
85         WriteEventImpl.append(
86             "EventPipeEvent *EventPipeEvent" +
87             eventName +
88             " = nullptr;\n")
89
90     for eventNode in eventNodes:
91         eventName = eventNode.getAttribute('symbol')
92         templateName = eventNode.getAttribute('template')
93
94         # generate EventPipeEventEnabled function
95         eventEnabledImpl = generateMethodSignatureEnabled(eventName) + """
96 {
97     return EventPipeEvent%s->IsEnabled();
98 }
99
100 """ % eventName
101         WriteEventImpl.append(eventEnabledImpl)
102
103         # generate EventPipeWriteEvent function
104         fnptype = []
105
106         if templateName:
107             template = allTemplates[templateName]
108         else:
109             template = None
110
111         fnptype.append(generateMethodSignatureWrite(eventName, template, extern))
112         fnptype.append("\n{\n")
113         checking = """    if (!EventPipeEventEnabled%s())
114         return ERROR_SUCCESS;
115 """ % (eventName)
116
117         fnptype.append(checking)
118
119         WriteEventImpl.extend(fnptype)
120
121         if template:
122             body = generateWriteEventBody(template, providerName, eventName)
123             WriteEventImpl.append(body)
124         else:
125             WriteEventImpl.append(
126                 "    EventPipe::WriteEvent(*EventPipeEvent" +
127                 eventName +
128                 ", (BYTE*) nullptr, 0);\n")
129
130         WriteEventImpl.append("\n    return ERROR_SUCCESS;\n}\n\n")
131
132     # EventPipeProvider and EventPipeEvent initialization
133     callbackName = 'EventPipeEtwCallback' + providerPrettyName
134     if extern: WriteEventImpl.append('extern "C" ')
135     WriteEventImpl.append(
136         "void Init" +
137         providerPrettyName +
138         "()\n{\n")
139     WriteEventImpl.append(
140         "    EventPipeProvider" +
141         providerPrettyName +
142         " = EventPipe::CreateProvider(SL(" +
143         providerPrettyName +
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')
155
156         needStack = "true"
157         for nostackentry in exclusionList.nostack:
158             tokens = nostackentry.split(':')
159             if tokens[2] == eventName:
160                 needStack = "false"
161
162         initEvent = """    EventPipeEvent%s = EventPipeProvider%s->AddEvent(%s,%s,%s,%s,%s);
163 """ % (eventName, providerPrettyName, eventValue, eventKeywordsMask, eventVersion, eventLevel, needStack)
164
165         WriteEventImpl.append(initEvent)
166     WriteEventImpl.append("}")
167
168     return ''.join(WriteEventImpl)
169
170
171 def generateWriteEventBody(template, providerName, eventName):
172     header = """
173     char stackBuffer[%s];
174     char *buffer = stackBuffer;
175     size_t offset = 0;
176     size_t size = %s;
177     bool fixedBuffer = true;
178
179     bool success = true;
180 """ % (template.estimated_size, template.estimated_size)
181
182     fnSig = template.signature
183     pack_list = []
184     for paramName in fnSig.paramlist:
185         parameter = fnSig.getParam(paramName)
186
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]
192             pack_list.append(
193                 "    success &= WriteToBuffer((const BYTE *)%s, %s, buffer, offset, size, fixedBuffer);" %
194                 (paramName, size))
195         elif paramName in template.arrays:
196             size = "sizeof(%s) * (int)%s" % (
197                 lttngDataTypeMapping[parameter.winType],
198                 parameter.prop)
199             if template.name in specialCaseSizes and paramName in specialCaseSizes[template.name]:
200                 size = "(int)(%s)" % specialCaseSizes[template.name][paramName]
201             pack_list.append(
202                 "    success &= WriteToBuffer((const BYTE *)%s, %s, buffer, offset, size, fixedBuffer);" %
203                 (paramName, size))
204         elif parameter.winType == "win:GUID":
205             pack_list.append(
206                 "    success &= WriteToBuffer(*%s, buffer, offset, size, fixedBuffer);" %
207                 (parameter.name,))
208         else:
209             pack_list.append(
210                 "    success &= WriteToBuffer(%s, buffer, offset, size, fixedBuffer);" %
211                 (parameter.name,))
212
213     code = "\n".join(pack_list) + "\n\n"
214
215     checking = """    if (!success)
216     {
217         if (!fixedBuffer)
218             delete[] buffer;
219         return ERROR_WRITE_FAULT;
220     }\n\n"""
221
222     body = "    EventPipe::WriteEvent(*EventPipeEvent" + \
223         eventName + ", (BYTE *)buffer, (unsigned int)offset);\n"
224
225     footer = """
226     if (!fixedBuffer)
227         delete[] buffer;
228 """
229
230     return header + code + checking + body + footer
231
232
233 keywordMap = {}
234
235 def generateEventKeywords(eventKeywords):
236     mask = 0
237     # split keywords if there are multiple
238     allKeywords = eventKeywords.split()
239
240     for singleKeyword in allKeywords:
241         mask = mask | keywordMap[singleKeyword]
242
243     return mask
244
245 def generateEventPipeHelperFile(etwmanifest, eventpipe_directory, extern, dryRun):
246     eventpipehelpersPath = os.path.join(eventpipe_directory, "eventpipehelpers.cpp")
247     if dryRun:
248         print(eventpipehelpersPath)
249     else:
250         with open_for_update(eventpipehelpersPath) as helper:
251             helper.write(stdprolog_cpp)
252             helper.write("""
253 #include "common.h"
254 #include <stdlib.h>
255 #include <string.h>
256
257 #ifndef FEATURE_PAL
258 #include <windef.h>
259 #include <crtdbg.h>
260 #else
261 #include "pal.h"
262 #endif //FEATURE_PAL
263
264 bool ResizeBuffer(char *&buffer, size_t& size, size_t currLen, size_t newSize, bool &fixedBuffer)
265 {
266     newSize = (size_t)(newSize * 1.5);
267     _ASSERTE(newSize > size); // check for overflow
268
269     if (newSize < 32)
270         newSize = 32;
271
272     char *newBuffer = new (nothrow) char[newSize];
273
274     if (newBuffer == NULL)
275         return false;
276
277     memcpy(newBuffer, buffer, currLen);
278
279     if (!fixedBuffer)
280         delete[] buffer;
281
282     buffer = newBuffer;
283     size = newSize;
284     fixedBuffer = false;
285
286     return true;
287 }
288
289 bool WriteToBuffer(const BYTE *src, size_t len, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer)
290 {
291     if(!src) return true;
292     if (offset + len > size)
293     {
294         if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer))
295             return false;
296     }
297
298     memcpy(buffer + offset, src, len);
299     offset += len;
300     return true;
301 }
302
303 bool WriteToBuffer(PCWSTR str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer)
304 {
305     if(!str) return true;
306     size_t byteCount = (wcslen(str) + 1) * sizeof(*str);
307
308     if (offset + byteCount > size)
309     {
310         if (!ResizeBuffer(buffer, size, offset, size + byteCount, fixedBuffer))
311             return false;
312     }
313
314     memcpy(buffer + offset, str, byteCount);
315     offset += byteCount;
316     return true;
317 }
318
319 bool WriteToBuffer(const char *str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer)
320 {
321     if(!str) return true;
322     size_t len = strlen(str) + 1;
323     if (offset + len > size)
324     {
325         if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer))
326             return false;
327     }
328
329     memcpy(buffer + offset, str, len);
330     offset += len;
331     return true;
332 }
333
334 """)
335
336             tree = DOM.parse(etwmanifest)
337
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(
344                     'extern "C" '
345                 )
346                 helper.write(
347                     "void Init" +
348                     providerPrettyName +
349                     "();\n\n")
350
351             if extern: helper.write(
352                 'extern "C" '
353             )
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")
361             helper.write("}")
362
363         helper.close()
364
365 def generateEventPipeImplFiles(
366         etwmanifest, eventpipe_directory, extern, exclusionList, dryRun):
367     tree = DOM.parse(etwmanifest)
368
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)
375
376         if os.path.basename(src_dirname) == "":
377             raise IOError("Could not find the Core CLR 'src' directory")
378
379     for providerNode in tree.getElementsByTagName('provider'):
380         providerName = providerNode.getAttribute('name')
381
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")
388         if dryRun:
389             print(eventpipefile)
390         else:
391             with open_for_update(eventpipefile) as eventpipeImpl:
392                 eventpipeImpl.write(stdprolog_cpp)
393
394                 header = """
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"
399
400 #if defined(FEATURE_PAL)
401 #define wcslen PAL_wcslen
402 #endif
403
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);
408
409 template <typename T>
410 bool WriteToBuffer(const T &value, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer)
411 {{
412     if (sizeof(T) + offset > size)
413     {{
414         if (!ResizeBuffer(buffer, size, offset, size + sizeof(T), fixedBuffer))
415             return false;
416     }}
417
418     memcpy(buffer + offset, (char *)&value, sizeof(T));
419     offset += sizeof(T);
420     return true;
421 }}
422
423 """.format(root=src_dirname.replace('\\', '/'))
424
425                 eventpipeImpl.write(header)
426                 eventpipeImpl.write(
427                     "const WCHAR* %sName = W(\"%s\");\n" % (
428                         providerPrettyName,
429                         providerName
430                     )
431                 )
432                 eventpipeImpl.write(
433                     "EventPipeProvider *EventPipeProvider%s = nullptr;\n" % (
434                         providerPrettyName,
435                     )
436                 )
437                 templateNodes = providerNode.getElementsByTagName('template')
438                 allTemplates = parseTemplateNodes(templateNodes)
439                 eventNodes = providerNode.getElementsByTagName('event')
440                 eventpipeImpl.write(
441                     generateClrEventPipeWriteEventsImpl(
442                         providerName,
443                         eventNodes,
444                         allTemplates,
445                         extern,
446                         exclusionList) + "\n")
447
448 def generateEventPipeFiles(
449         etwmanifest, intermediate, extern, exclusionList, dryRun):
450     eventpipe_directory = os.path.join(intermediate, eventpipe_dirname)
451     tree = DOM.parse(etwmanifest)
452
453     if not os.path.exists(eventpipe_directory):
454         os.makedirs(eventpipe_directory)
455
456     # generate helper file
457     generateEventPipeHelperFile(etwmanifest, eventpipe_directory, extern, dryRun)
458
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)
464
465     # generate .cpp file for each provider
466     generateEventPipeImplFiles(
467         etwmanifest,
468         eventpipe_directory,
469         extern,
470         exclusionList,
471         dryRun
472     )
473
474 import argparse
475 import sys
476
477 def main(argv):
478
479     # parse the command line
480     parser = argparse.ArgumentParser(
481         description="Generates the Code required to instrument eventpipe logging mechanism")
482
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)
495     if unknown:
496         print('Unknown argument(s): ', ', '.join(unknown))
497         return 1
498
499     sClrEtwAllMan = args.man
500     exclusion_filename = args.exc
501     intermediate = args.intermediate
502     extern = not args.nonextern
503     dryRun            = args.dry_run
504
505     generateEventPipeFiles(sClrEtwAllMan, intermediate, extern, parseExclusionList(exclusion_filename), dryRun)
506
507 if __name__ == '__main__':
508     return_code = main(sys.argv[1:])
509     sys.exit(return_code)