[Tizen] Implement detecting of sanitized libraries
[platform/upstream/coreclr.git] / src / scripts / genLttngProvider.py
1 ##
2 ## Licensed to the .NET Foundation under one or more agreements.
3 ## The .NET Foundation licenses this file to you under the MIT license.
4 ## See the LICENSE file in the project root for more information.
5 ##
6 ##  Sample LTTng Instrumentation code that is generated:
7 ##
8 ## HEADER:
9 ## #define GCFinalizersEnd_TRACEPOINT_ARGS \
10 ##TP_ARGS(\
11 ##        const unsigned int ,Count\
12 ##)
13 ##TRACEPOINT_EVENT_CLASS(
14 ##    DotNETRuntime,
15 ##    GCFinalizersEnd,
16 ##    GCFinalizersEnd_TRACEPOINT_ARGS,
17 ##     TP_FIELDS(
18 ##        ctf_integer(unsigned int, Count, Count)
19 ##    )
20 ##)
21 ##
22 ##CPP :
23 ##
24 ##extern "C" BOOL  EventXplatEnabledGCFinalizersEnd(){ return TRUE;}
25 ##extern "C" ULONG  FireEtXplatGCFinalizersEnd(
26 ##                  const unsigned int Count
27 ##)
28 ##{
29 ##  ULONG Error = ERROR_WRITE_FAULT;
30 ##    if (!EventXplatEnabledGCFinalizersEnd()){ return ERROR_SUCCESS;}
31 ##
32 ##
33 ##     tracepoint(
34 ##        DotNETRuntime,
35 ##        GCFinalizersEnd,
36 ##        Count
37 ##        );
38 ##        Error = ERROR_SUCCESS;
39 ##
40 ##return Error;
41 ##}
42 ##
43 ###define GCFinalizersEndT_TRACEPOINT_INSTANCE(name) \
44 ##TRACEPOINT_EVENT_INSTANCE(\
45 ##    DotNETRuntime,\
46 ##    GCFinalizersEnd,\
47 ##    name ,\
48 ##    GCFinalizersEnd_TRACEPOINT_ARGS \
49 ##)
50 #
51
52 import os
53 from genEventing import *
54 from utilities import open_for_update
55
56 stdprolog="""
57 // Licensed to the .NET Foundation under one or more agreements.
58 // The .NET Foundation licenses this file to you under the MIT license.
59 // See the LICENSE file in the project root for more information.
60
61 /******************************************************************
62
63 DO NOT MODIFY. AUTOGENERATED FILE.
64 This file is generated using the logic from <root>/src/scripts/genLttngProvider.py
65
66 ******************************************************************/
67 """
68
69 specialCaseSizes = { "BulkType" : { "Values" : "Values_ElementSize" }, "GCBulkRootCCW" : { "Values" : "Values_ElementSize" }, "GCBulkRCW" : { "Values" : "Values_ElementSize" }, "GCBulkRootStaticVar" : { "Values" : "Values_ElementSize" } }
70
71 lttngDataTypeMapping ={
72         #constructed types
73         "win:null"          :" ",
74         "win:Int64"         :"const __int64",
75         "win:ULong"         :"const ULONG",
76         "win:count"         :"*",
77         "win:Struct"        :"const BYTE *",
78         #actual spec
79         "win:GUID"          :"const int",
80         "win:AnsiString"    :"const char*",
81         "win:UnicodeString" :"const char*",
82         "win:Double"        :"const double",
83         "win:Int32"         :"const signed int",
84         "win:Boolean"       :"const BOOL",
85         "win:UInt64"        :"const unsigned __int64",
86         "win:UInt32"        :"const unsigned int",
87         "win:UInt16"        :"const unsigned short",
88         "win:UInt8"         :"const unsigned char",
89         "win:Pointer"       :"const size_t",
90         "win:Binary"        :"const BYTE"
91         }
92
93 ctfDataTypeMapping ={
94         #constructed types
95         "win:Int64"         :"ctf_integer",
96         "win:ULong"         :"ctf_integer",
97         "win:count"         :"ctf_sequence",
98         "win:Struct"        :"ctf_sequence",
99         #actual spec
100         "win:GUID"          :"ctf_sequence",
101         "win:AnsiString"    :"ctf_string",
102         "win:UnicodeString" :"ctf_string",
103         "win:Double"        :"ctf_float",
104         "win:Int32"         :"ctf_integer",
105         "win:Boolean"       :"ctf_integer",
106         "win:UInt64"        :"ctf_integer",
107         "win:UInt32"        :"ctf_integer",
108         "win:UInt16"        :"ctf_integer",
109         "win:UInt8"         :"ctf_integer",  #actually a character
110         "win:Pointer"       :"ctf_integer",
111         "win:Binary"        :"ctf_sequence"
112         }
113
114 MAX_LTTNG_ARGS = 9
115
116 def shouldPackTemplate(template):
117     return template.num_params > MAX_LTTNG_ARGS or len(template.structs) > 0 or len(template.arrays) > 0
118
119 def generateArgList(template):
120     header = "TP_ARGS( \\\n"
121     footer = ")\n"
122
123     if "MethodILToNative" in template.name:
124         pass
125
126     if shouldPackTemplate(template):
127         args  = "        const unsigned int, length, \\\n"
128         args += "        const char *, __data__ \\\n"
129
130     else:
131         fnSig = template.signature
132         args = []
133         for params in fnSig.paramlist:
134             fnparam     = fnSig.getParam(params)
135             wintypeName = fnparam.winType
136             typewName   = lttngDataTypeMapping[wintypeName]
137             winCount    = fnparam.count
138             countw      = lttngDataTypeMapping[winCount]
139
140             arg = "        " + typewName
141             if countw != " ":
142                 arg += countw
143             arg += ", " + fnparam.name
144             args.append(arg)
145         args = ", \\\n".join(args) + " \\\n"
146
147     return header + args + footer
148
149
150 def generateFieldList(template):
151     header = "    " + " TP_FIELDS(\n"
152     footer = "\n    )\n)\n"
153
154     if shouldPackTemplate(template):
155         field_list  = "        ctf_integer(ULONG, length, length)\n"
156         field_list += "        ctf_sequence(char, __data__, __data__, ULONG, length)"
157
158     else:
159         fnSig = template.signature
160         field_list = []
161         for params in fnSig.paramlist:
162             fnparam     = fnSig.getParam(params)
163             wintypeName = fnparam.winType
164             winCount    = fnparam.count
165             countw      = lttngDataTypeMapping[winCount]
166             typewName   = lttngDataTypeMapping[wintypeName].replace("const ","")
167
168             field_body  = None
169             ctf_type    = None
170             varname     = fnparam.name
171
172             if fnparam.prop:
173                 #this is an explicit struct treat as a sequence
174                 ctf_type = "ctf_sequence"
175                 sizeofseq = fnparam.prop
176                 field_body = ", ".join((typewName, varname, varname, "size_t", sizeofseq))
177
178             else:
179                 ctf_type = ctfDataTypeMapping[wintypeName]
180                 if ctf_type == "ctf_string":
181                     field_body = ", ".join((varname, varname))
182
183                 elif ctf_type == "ctf_integer" or ctf_type == "ctf_float":
184                     field_body = ", ".join((typewName, varname, varname))
185
186                 elif ctf_type == "ctf_sequence":
187                     raise Exception("ctf_sequence needs to have its memory expilicitly laid out")
188
189                 else:
190                     raise Exception("no such ctf intrinsic called: " +  ctf_type)
191
192             field_list.append("        %s(%s)" % (ctf_type, field_body))
193
194         field_list = "\n".join(field_list)
195
196     return header + field_list + footer
197
198 def generateLttngHeader(providerName, allTemplates, eventNodes):
199     lTTngHdr = []
200     for templateName in allTemplates:
201         template = allTemplates[templateName]
202         fnSig   = allTemplates[templateName].signature
203
204         lTTngHdr.append("\n#define " + templateName + "_TRACEPOINT_ARGS \\\n")
205
206 #TP_ARGS
207         tp_args = generateArgList(template)
208         lTTngHdr.append(tp_args)
209
210 #TP_EVENT_CLASS
211         lTTngHdr.append("TRACEPOINT_EVENT_CLASS(\n")
212         lTTngHdr.append("    " + providerName + ",\n")
213         lTTngHdr.append("    " + templateName + ",\n")
214         lTTngHdr.append("    " + templateName + "_TRACEPOINT_ARGS,\n")
215
216 #TP_FIELDS
217         tp_fields = generateFieldList(template)
218         lTTngHdr.append(tp_fields)
219
220 # Macro for defining event instance
221         lTTngHdr.append("\n#define " + templateName)
222         lTTngHdr.append("""T_TRACEPOINT_INSTANCE(name) \\
223 TRACEPOINT_EVENT_INSTANCE(\\
224 """)
225         lTTngHdr.append("    "+providerName + ",\\\n")
226         lTTngHdr.append("    " + templateName + ",\\\n")
227         lTTngHdr.append("    name ,\\\n")
228         lTTngHdr.append("    " + templateName + "_TRACEPOINT_ARGS \\\n)")
229
230
231
232 #add an empty template node to just specify the event name in the event stream
233     lTTngHdr.append("\n\nTRACEPOINT_EVENT_CLASS(\n")
234     lTTngHdr.append("    " + providerName + ",\n")
235     lTTngHdr.append("    emptyTemplate ,\n")
236     lTTngHdr.append("""    TP_ARGS(),
237     TP_FIELDS()
238 )
239 #define T_TRACEPOINT_INSTANCE(name) \\
240 TRACEPOINT_EVENT_INSTANCE(\\
241 """)
242     lTTngHdr.append("    " + providerName + ",\\\n")
243     lTTngHdr.append("    emptyTemplate,\\\n")
244
245     lTTngHdr.append("""    name ,\\
246     TP_ARGS()\\
247 )""")
248 #end of empty template
249 # create the event instance in headers
250     lTTngHdr.append("\n")
251
252     for eventNode in eventNodes:
253         eventName    = eventNode.getAttribute('symbol');
254         templateName = eventNode.getAttribute('template');
255
256         if not eventName :
257             raise Exception(eventNode + " event does not have a symbol")
258         if not templateName:
259             lTTngHdr.append("T_TRACEPOINT_INSTANCE(")
260             lTTngHdr.append(eventName +")\n")
261             continue
262
263         subevent = templateName.replace(templateName,'')
264         lTTngHdr.append(templateName)
265         lTTngHdr.append("T_TRACEPOINT_INSTANCE(")
266         lTTngHdr.append(eventName + subevent + ")\n")
267
268     lTTngHdr.append("\n#endif /* LTTNG_CORECLR_H")
269     lTTngHdr.append(providerName + " */\n")
270     lTTngHdr.append("#include <lttng/tracepoint-event.h>")
271
272     return ''.join(lTTngHdr)
273
274
275 def generateMethodBody(template, providerName, eventName):
276     #emit code to init variables convert unicode to ansi string
277     result = []
278
279     if template is None:
280         return "\n    do_tracepoint(%s, %s);\n" % (providerName, eventName)
281
282     fnSig = template.signature
283
284     for paramName in fnSig.paramlist:
285         fnparam     = fnSig.getParam(paramName)
286         paramname   = fnparam.name
287
288         if fnparam.winType == "win:UnicodeString":
289             result.append("    INT " + paramname + "_path_size = -1;\n")
290             result.append("    PathCharString " + paramname + "_PS;\n")
291             result.append("    INT " + paramname + "_full_name_path_size")
292             result.append(" = (wcslen(" + paramname + ") + 1)*sizeof(WCHAR);\n")
293             result.append("    CHAR* " + paramname + "_full_name = ")
294             result.append(paramname + "_PS.OpenStringBuffer(" + paramname + "_full_name_path_size );\n")
295             result.append("    if (" + paramname + "_full_name == NULL )")
296             result.append("    { return ERROR_WRITE_FAULT; }\n")
297
298     result.append("\n")
299
300     #emit tracepoints
301     fnSig   = template.signature
302
303     if not shouldPackTemplate(template):
304         linefnbody = ["    do_tracepoint(%s,\n        %s" % (providerName, eventName)]
305
306         for params in fnSig.paramlist:
307             fnparam     = fnSig.getParam(params)
308             wintypeName = fnparam.winType
309             winCount    = fnparam.count
310             paramname   = fnparam.name
311             ctf_type    = ctfDataTypeMapping.get(winCount)
312
313             line = "        "
314             if not ctf_type:
315                 ctf_type    = ctfDataTypeMapping[wintypeName]
316
317             if ctf_type == "ctf_string" and wintypeName == "win:UnicodeString":
318                 #emit code to convert unicode to ansi string
319
320                 result.append("    " + paramname+ "_path_size = WideCharToMultiByte( CP_ACP, 0, ")
321                 result.append(paramname + ", -1, ")
322                 result.append(paramname + "_full_name, ")
323                 result.append(paramname + "_full_name_path_size, NULL, NULL );\n")
324
325                 result.append("    _ASSERTE(" +paramname+ "_path_size < " )
326                 result.append(paramname + "_full_name_path_size );\n    ")
327
328                 result.append(paramname + "_PS.CloseBuffer(" + paramname + "_path_size );\n")
329                 result.append("    if( " + paramname + "_path_size == 0 ){ return ERROR_INVALID_PARAMETER; }\n")
330
331                 line += paramname + "_full_name"
332                 linefnbody.append(line)
333                 continue
334
335             elif ctf_type == "ctf_sequence" or wintypeName == "win:Pointer":
336                 line += "(" + lttngDataTypeMapping[wintypeName]
337                 if not lttngDataTypeMapping[winCount] == " ":
338                     line += lttngDataTypeMapping[winCount]
339
340                 line += ") "
341                 linefnbody.append(line + paramname)
342
343             else:
344                 linefnbody.append(line + paramname)
345
346         linefnbody = ",\n".join(linefnbody) + ");\n"
347         result.append(linefnbody)
348         return ''.join(result)
349
350     else:
351         header = """
352     char stackBuffer[%s];
353     char *buffer = stackBuffer;
354     size_t offset = 0;
355     size_t size = %s;
356     bool fixedBuffer = true;
357
358     bool success = true;
359 """ % (template.estimated_size, template.estimated_size)
360         footer = """
361     if (!fixedBuffer)
362         delete[] buffer;
363 """
364
365         pack_list = []
366         for paramName in fnSig.paramlist:
367             parameter = fnSig.getParam(paramName)
368
369             if paramName in template.structs:
370                 size = "(int)%s_ElementSize * (int)%s" % (paramName, parameter.prop)
371                 if template.name in specialCaseSizes and paramName in specialCaseSizes[template.name]:
372                     size = "(int)(%s)" % specialCaseSizes[template.name][paramName]
373                 pack_list.append("    success &= WriteToBuffer((const BYTE *)%s, %s, buffer, offset, size, fixedBuffer);" % (paramName, size))
374             elif paramName in template.arrays:
375                 size = "sizeof(%s) * (int)%s" % (lttngDataTypeMapping[parameter.winType], parameter.prop)
376                 if template.name in specialCaseSizes and paramName in specialCaseSizes[template.name]:
377                     size = "(int)(%s)" % specialCaseSizes[template.name][paramName]
378                 pack_list.append("    success &= WriteToBuffer((const BYTE *)%s, %s, buffer, offset, size, fixedBuffer);" % (paramName, size))
379             elif parameter.winType == "win:GUID":
380                 pack_list.append("    success &= WriteToBuffer(*%s, buffer, offset, size, fixedBuffer);" % (parameter.name,))
381             else:
382                 pack_list.append("    success &= WriteToBuffer(%s, buffer, offset, size, fixedBuffer);" % (parameter.name,))
383
384         code = "\n".join(pack_list) + "\n\n"
385         tracepoint = """    if (!success)
386     {
387         if (!fixedBuffer)
388             delete[] buffer;
389         return ERROR_WRITE_FAULT;
390     }
391
392     do_tracepoint(%s, %s, offset, buffer);\n""" % (providerName, eventName)
393
394         return header + code + tracepoint + footer
395
396
397
398
399
400 def generateLttngTpProvider(providerName, eventNodes, allTemplates):
401     lTTngImpl = []
402     for eventNode in eventNodes:
403         eventName    = eventNode.getAttribute('symbol')
404         templateName = eventNode.getAttribute('template')
405         #generate EventXplatEnabled
406         lTTngImpl.append("extern \"C\" BOOL  EventXplatEnabled%s(){ return tracepoint_enabled(%s, %s); }\n\n" % (eventName, providerName, eventName))
407         #generate FireEtw functions
408         fnptype = []
409         linefnptype = []
410         fnptype.append("extern \"C\" ULONG  FireEtXplat")
411         fnptype.append(eventName)
412         fnptype.append("(\n")
413
414
415         if templateName:
416             template = allTemplates[templateName]
417         else:
418             template = None
419
420         if template:
421             fnSig   = template.signature
422             for paramName in fnSig.paramlist:
423                 fnparam     = fnSig.getParam(paramName)
424                 wintypeName = fnparam.winType
425                 typewName   = palDataTypeMapping[wintypeName]
426                 winCount    = fnparam.count
427                 countw      = palDataTypeMapping[winCount]
428
429                 if paramName in template.structs:
430                     linefnptype.append("%sint %s_ElementSize,\n" % (lindent, paramName))
431
432                 linefnptype.append(lindent)
433                 linefnptype.append(typewName)
434                 if countw != " ":
435                     linefnptype.append(countw)
436
437                 linefnptype.append(" ")
438                 linefnptype.append(fnparam.name)
439                 linefnptype.append(",\n")
440
441             if len(linefnptype) > 0 :
442                 del linefnptype[-1]
443
444         fnptype.extend(linefnptype)
445         fnptype.append(")\n{\n")
446         lTTngImpl.extend(fnptype)
447
448         #start of fn body
449         lTTngImpl.append("    if (!EventXplatEnabled%s())\n" % (eventName,))
450         lTTngImpl.append("        return ERROR_SUCCESS;\n")
451
452         result = generateMethodBody(template, providerName, eventName)
453         lTTngImpl.append(result)
454
455         lTTngImpl.append("\n    return ERROR_SUCCESS;\n}\n\n")
456
457     return ''.join(lTTngImpl)
458
459
460
461 def generateLttngFiles(etwmanifest,eventprovider_directory, dryRun):
462
463     eventprovider_directory = eventprovider_directory + "/"
464     tree                    = DOM.parse(etwmanifest)
465
466     #keep these relative
467     tracepointprovider_directory =  "tracepointprovider"
468     lttng_directory              =  "lttng"
469
470     lttngevntprovPre             = lttng_directory + "/eventprov"
471     lttngevntprovTpPre           = lttng_directory + "/traceptprov"
472
473     if not os.path.exists(eventprovider_directory):
474         os.makedirs(eventprovider_directory)
475
476     if not os.path.exists(eventprovider_directory + lttng_directory):
477         os.makedirs(eventprovider_directory + lttng_directory)
478
479     if not os.path.exists(eventprovider_directory + tracepointprovider_directory):
480         os.makedirs(eventprovider_directory + tracepointprovider_directory)
481
482 # Generate Lttng specific instrumentation
483     for providerNode in tree.getElementsByTagName('provider'):
484
485         providerName = providerNode.getAttribute('name')
486         providerName = providerName.replace("Windows-",'')
487         providerName = providerName.replace("Microsoft-",'')
488
489         providerName_File = providerName.replace('-','')
490         providerName_File = providerName_File.lower()
491         providerName      = providerName.replace('-','_')
492
493         lttngevntheadershortname = "tp" + providerName_File +".h"
494         lttngevntheader          = eventprovider_directory + "lttng/" + lttngevntheadershortname
495         lttngevntprov            = eventprovider_directory + lttngevntprovPre + providerName_File + ".cpp"
496         lttngevntprovTp          = eventprovider_directory + lttngevntprovTpPre + providerName_File +".cpp"
497
498         templateNodes = providerNode.getElementsByTagName('template')
499         eventNodes = providerNode.getElementsByTagName('event')
500         allTemplates  = parseTemplateNodes(templateNodes)
501
502         if dryRun:
503             print(lttngevntheader)
504             print(lttngevntprov)
505             print(lttngevntprovTp)
506         else:
507             with open_for_update(lttngevntheader) as lttnghdr_file:
508                 lttnghdr_file.write(stdprolog + "\n")
509                 lttnghdr_file.write("""
510 #include "palrt.h"
511 #include "pal.h"
512
513 #undef TRACEPOINT_PROVIDER
514
515 """)
516
517                 lttnghdr_file.write("#define TRACEPOINT_PROVIDER " + providerName + "\n")
518                 lttnghdr_file.write("""
519
520 #undef TRACEPOINT_INCLUDE
521 """)
522
523                 lttnghdr_file.write("#define TRACEPOINT_INCLUDE \"./" + lttngevntheadershortname + "\"\n\n")
524
525                 lttnghdr_file.write("#if !defined(LTTNG_CORECLR_H" + providerName + ") || defined(TRACEPOINT_HEADER_MULTI_READ)\n\n")
526                 lttnghdr_file.write("#define LTTNG_CORECLR_H" + providerName + "\n")
527
528                 lttnghdr_file.write("\n#include <lttng/tracepoint.h>\n\n")
529
530                 lttnghdr_file.write(generateLttngHeader(providerName,allTemplates,eventNodes) + "\n")
531
532             with open_for_update(lttngevntprov) as lttngimpl_file:
533                 lttngimpl_file.write(stdprolog + "\n")
534                 lttngimpl_file.write("""
535 #define TRACEPOINT_DEFINE
536 #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE
537
538 #include "stdlib.h"
539 #include "pal_mstypes.h"
540 #include "pal_error.h"
541 #include "pal.h"
542 #define PAL_free free
543 #define PAL_realloc realloc
544 #include "pal/stackstring.hpp"
545 """)
546                 lttngimpl_file.write("#include \"" + lttngevntheadershortname + "\"\n\n")
547
548                 lttngimpl_file.write("""#ifndef tracepoint_enabled
549
550 extern "C" bool XplatEventLoggerIsEnabled();
551
552 #define tracepoint_enabled(provider, name) XplatEventLoggerIsEnabled()
553 #define do_tracepoint tracepoint
554 #endif
555
556 #define wcslen PAL_wcslen
557
558 bool ResizeBuffer(char *&buffer, size_t& size, size_t currLen, size_t newSize, bool &fixedBuffer);
559 bool WriteToBuffer(PCWSTR str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer);
560 bool WriteToBuffer(const char *str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer);
561 bool WriteToBuffer(const BYTE *src, size_t len, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer);
562
563 template <typename T>
564 bool WriteToBuffer(const T &value, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer)
565 {
566     if (sizeof(T) + offset > size)
567     {
568         if (!ResizeBuffer(buffer, size, offset, size + sizeof(T), fixedBuffer))
569             return false;
570     }
571
572     memcpy(buffer + offset, (char *)&value, sizeof(T));
573     offset += sizeof(T);
574     return true;
575 }
576
577 """)
578                 lttngimpl_file.write(generateLttngTpProvider(providerName,eventNodes,allTemplates) + "\n")
579
580             with open_for_update(lttngevntprovTp) as tpimpl_file:
581                 tpimpl_file.write(stdprolog + "\n")
582
583                 tpimpl_file.write("\n#define TRACEPOINT_CREATE_PROBES\n")
584
585                 tpimpl_file.write("#include \"./"+lttngevntheadershortname + "\"\n")
586
587 import argparse
588 import sys
589
590 def main(argv):
591
592     #parse the command line
593     parser = argparse.ArgumentParser(description="Generates the Code required to instrument LTTtng logging mechanism")
594
595     required = parser.add_argument_group('required arguments')
596     required.add_argument('--man',  type=str, required=True,
597                                     help='full path to manifest containig the description of events')
598     required.add_argument('--intermediate', type=str, required=True,
599                                     help='full path to eventprovider  intermediate directory')
600     required.add_argument('--dry-run', action='store_true',
601                                     help='if specified, will output the names of the generated files instead of generating the files' )
602     args, unknown = parser.parse_known_args(argv)
603     if unknown:
604         print('Unknown argument(s): ', ', '.join(unknown))
605         return 1
606
607     sClrEtwAllMan     = args.man
608     intermediate      = args.intermediate
609     dryRun            = args.dry_run
610
611     generateLttngFiles(sClrEtwAllMan,intermediate, dryRun)
612
613 if __name__ == '__main__':
614     return_code = main(sys.argv[1:])
615     sys.exit(return_code)