Update README.linux
[deliverable/titan.core.git] / etc / scripts / stacklogger.pl
1 ###############################################################################
2 # Copyright (c) 2000-2014 Ericsson Telecom AB
3 # All rights reserved. This program and the accompanying materials
4 # are made available under the terms of the Eclipse Public License v1.0
5 # which accompanies this distribution, and is available at
6 # http://www.eclipse.org/legal/epl-v10.html
7 ###############################################################################
8 #!/usr/bin/perl
9 #############################################################
10 # The gdb cannot load the symbol table for compiler. That is why this script was written.
11 # This script creates logs for the stack.
12 # The following parameters can be used:
13 # 1st parameter : ON or OFF. ON makes the changes for Makefiles and creates the logger C++ files.
14 # The OFF sets mandatory the -R flag. The cleaning is always recursive.
15 # 2nd parameter : -R. Optional. If set the search for files is recursive in directory structure.
16 # 3d parameter : a directory or file name under titan. This sript now is only for compiler2.
17 # 4th parameter : -L main or -L all. Optional. Omitting it, the all is used default.
18 # The main logs only between the program function main entry and exit.
19 # The following parameters shall be set to restore all the changes: OFF -R subdir
20 # where subdir is a directory name directly under titan.
21 # The logfile is placed into ../titan/stacklogger directory. The format: stack_logger_MM_DD_YYYY.log.
22 # The date is the one when the script generated the changes in the source code.
23 # examples:
24 # perl stacklogger.pl ON -R compiler2 -L main
25 # perl stacklogger.pl ON -R compiler2 -L all
26 # perl stacklogger.pl OFF -R compiler2
27 ##############################################################
28 use 5.010;
29 use strict;
30 use warnings;
31 use Cwd;
32 use File::Copy;
33 use File::Basename;
34 use POSIX qw(strftime);
35
36 my $topdir;
37 my $path;
38 my $loggerdir;
39 my $pathtomain;
40 my $set = 0; # default off
41 my $recursive = 0; # default non recursive iteration
42 my $loglevel = 1; # this means: -L all
43 my $cwd = cwd();
44 #weird name not to macth for any string in C++ file
45 my $macroname = "STACK_LOGGER_2014_BL67";
46 my $loggerdirname = "stacklogger";
47
48 &processArgs ( \$topdir, \$path, \$loggerdir, \$pathtomain, \$set, \$recursive, \$loglevel );
49 my @dirs;
50 &getDirs ( $path, \@dirs );
51
52 my @files;
53 &getFiles ( $path, \@files );
54
55 if ( $set )
56 {
57 &setLogger;
58 }
59 else
60 {
61 &resetLogger;
62 }
63 chdir $cwd;
64 ############################################################
65 sub setLogger # switches the logger on
66 {
67 &add_objects_to_target_makes ( @dirs );
68 &add_dir_to_top_make;
69 &create_logger_files ( $loggerdir );
70 &insert_include ( @files );
71 &insert_logger_macro ( @files );
72 }
73 ############################################################
74 sub resetLogger # switches the logger off
75 {
76 &remove_logger_macro ( @files );
77 &remove_include ( @files );
78 &delete_logger_files ( $loggerdir );
79 &restore_make ( $path );
80 &delete_dep_files ( $path );
81 if ( -d $loggerdir && ( $pathtomain eq $path )) { rmdir $loggerdir or die ( "$loggerdir cannot be deleted\n"); }
82 }
83 ############################################################
84 sub insert_logger_macro # inserts the logger macro in the files
85 {
86 my @files = @_; #all the files where the logger macros are to be written
87 for my $file (@files)
88 {
89 remove_logger_macro ( $file );
90 open ( FILE, "<", $file ) or die ( "failed to open file: $file\n" );
91 my @lines = <FILE>;
92 close FILE ;
93 my $arrSize = scalar @lines;
94 my $countline = 0;
95 my $moreline = "";
96
97 open ( FILE, ">", $file ) or die ( "failed to open file: $file\n" );
98 for my $line (@lines)
99 {
100 my $temp = $line;
101 # regex for for '::'
102 my $regex1 = qr/.*[:]{2}.*/s;
103 my $found = $line =~ $regex1;
104 if ( $found || ( $moreline ne "" ))
105 {
106 $moreline = append_and_check ( $moreline, $line );
107 }
108 else
109 {
110 print FILE $line;
111 }
112 }
113 close FILE;
114 }
115 }
116 ############################################################
117 sub remove_logger_macro # removes the logger macros from the files
118 {
119 my @files = @_; #all the files where the logger macros are to be written
120 for my $file (@files)
121 {
122 open ( FILE, "<", $file ) or die ( "failed to open file: $file\n" );
123 my @lines = <FILE>;
124 close FILE ;
125 my $arrSize = scalar @lines;
126
127 open ( FILE, ">", $file ) or die ( "failed to open file: $file\n" );
128 for my $line (@lines)
129 {
130 $line =~ s/$macroname//;
131 print FILE $line;
132 }
133 close FILE;
134 }
135 }
136 ############################################################
137 sub append_and_check # appends the next line to $moreline if the pattern was not found
138 { # it searches through more lines
139 my $origline = $_[1]; # the next line to be examined and/or append
140 # remove C++ style comment
141 my $cppcomment = qr/\/{2}.*/s;
142 my $ccomment = qr/\/\*.*\*\//s;
143 # valid function definition
144 my $regex2 = qr/.*[:]{2}[A-Za-z0-9_~\s]+[(].*[)][^;}]*[{]/s;
145 # found ';' it cannot be a function definition
146 my $regex3 = qr/.*[:]{2}.+[;].*/s;
147 chomp ($_[1]);
148 my $append = $_[1];
149 # remove cpp comment
150 $append =~ s/$cppcomment//;
151 my $string = $_[0] . $append;
152 # remove c comment
153 $string =~ s/$ccomment//;
154 my $found = ($string =~ $regex2);
155 if ( $found )
156 {
157 $string = "";
158 $origline =~ s/\{/\{$macroname/;
159 }
160 print FILE $origline;
161 my $invalid = ($string =~ $regex3);
162 if ( $invalid )
163 {
164 $string = "";
165 }
166 return $string;
167 }
168 ############################################################
169 sub add_dir_to_top_make # the directory of the stacklogger will be added to Makefile in the {top} dir
170 {
171 my $replace = ":= " . $loggerdirname . " ";
172 # the compiler2 pattern is fix the stacklogger shall be written in this line to the first place
173 #ALLDIRS := **insert here** common compiler2 repgen xsdconvert
174 my $search = qr/^[\s]*ALLDIRS[\s]*:=.*compiler2/s;
175 my $makefile = $topdir . "Makefile";
176 open ( FILE, "<", $makefile ) or die ( "failed to open file: $makefile\n" );
177 my @list = <FILE>;
178 close FILE;
179 my @found = grep /$loggerdirname/, @list;
180 if ( @found == 0 )
181 {
182 my $newfile = $topdir . "Makefile.orig";
183 if ( -f $newfile ) { unlink $newfile; }
184 copy ( $makefile, $newfile ) or die ( "File cannot be copied." );
185 open ( FILE, ">", $makefile ) or die ( "failed to open file: $makefile\n" );
186 my $count = 0;
187 for my $i ( 0 .. $#list )
188 {
189 if ( $list[$i] =~ $search )
190 {
191 $list[$i] =~ s/:=/$replace/;
192 $list[$i] =~ s/ {2,}/ /; # 2 spaces are replaced to 1, if there is any
193 $count += 1;
194 }
195 print FILE $list[$i];
196 }
197 close FILE;
198 if ( $count != 1) { die ( "The Makefile in $topdir seems to have been changed.\nPlease redesign the regex in sub add_dir_to_top_make.\n" ); }
199 }
200 }
201 ############################################################
202 sub add_objects_to_target_makes #changes the Makefiles to be compiled
203 {
204 my @dirs = @_; # the target and its subdirectories
205 if ( ! grep {/$pathtomain$/} @dirs )
206 {
207 push ( @dirs, $pathtomain );
208 }
209 my $date = strftime "%m_%d_%Y", localtime;
210 my $object = ".o";
211 my $objectfilename = "stack_logger_" . $date . $object;
212 my $insert = "
213 CPPFLAGS += -I$loggerdir
214 COMPILER_COMMON_OBJECTS += $loggerdir/$objectfilename
215 MFGEN_COMMON_OBJECTS += $loggerdir/$objectfilename
216 TCOV2LCOV_COMMON_OBJECTS += $loggerdir/$objectfilename
217 ";
218 my $insertsubdir = "
219 CPPFLAGS += -I$loggerdir
220 ";
221 my $search = qr/^SUBDIRS :=/s;
222 for my $dir ( @dirs )
223 {
224 my $makefile = $dir . "Makefile";
225 open ( FILE, "<", $makefile ) or die ( "failed to open file: $makefile\n" );
226 my @list = <FILE>;
227 close FILE;
228 my @found = grep /$loggerdir/, @list;
229 if ( @found == 0 )
230 {
231 my $newfile = $dir . "Makefile.orig";
232 if ( -f $newfile ) { unlink $newfile; }
233 copy ( $makefile, $newfile ) or die ( "File cannot be copied." );
234 open ( FILE, ">", $makefile ) or die ( "failed to open file: $makefile\n" );
235 my $count = 0;
236 for my $i ( 0 .. $#list )
237 {
238 if ( $list[$i] =~ $search )
239 {
240 if ( $dir eq $pathtomain )
241 {
242 print FILE $insert ;
243 }
244 else
245 {
246 print FILE $insertsubdir ;
247 }
248 $count += 1;
249 }
250 print FILE $list[$i];
251 }
252 close FILE;
253 if ( $count != 1) { die ( "The Makefile in $dir seems to have been changed.\nPlease redesign the regex in sub add_objects_to_target_makes.\n" ); }
254 }
255 }
256 }
257 ############################################################
258 sub restore_make #restores the original Makefiles
259 {
260 my $path = $_[0]; #path to target directory
261 if ( $path eq $pathtomain )
262 {
263 $recursive = 1;
264 &getDirs ( $path, \@dirs );
265 }
266 else
267 {
268 push ( @dirs, $path );
269 }
270 for my $dir ( @dirs )
271 {
272 my $origmakefile = $dir . "Makefile.orig";
273 if ( -f $origmakefile )
274 {
275 my $makefile = $dir . "Makefile";
276 unlink $makefile;
277 rename ( $origmakefile, $makefile ) or die ( "File cannot be renamed." );
278 }
279 }
280 if ( $path eq $pathtomain )
281 {
282 &restore_make ( $topdir );
283 }
284 }
285 ############################################################
286 sub create_logger_files # creates the .hh the .cc and the Makefile for the stacklogger
287 { # these files are C++ construct which at construction and destruction creates a logentry for the function contained
288 my $dir = $_[0]; # path to directory where the logger files are to be created
289 &delete_logger_files ( $dir );
290 chdir $dir;
291 my $guard = $macroname . "_H";
292 my $logger_header =
293 "#ifndef $guard
294 #define $guard
295 #include <stdio.h>
296 #define $macroname EntryRaiiObject obj ## __LINE__ (__FUNCTION__ , __FILE__);
297 class EntryRaiiObject {
298 public:
299 EntryRaiiObject (const char* func, const char* file);
300 ~EntryRaiiObject ();
301 int doLog ();
302 private:
303 const char* func_;
304 const char* file_;
305 static unsigned int level;
306 };
307
308 class FH
309 {
310 public:
311 static FILE* getHandler ();
312 ~FH ();
313 private:
314 FH () {};
315 FH (const FH&) {};
316 private:
317 static FILE* fh;
318 static const char* file_name;
319 };
320
321 #endif //$guard";
322
323 my $date = strftime "%m_%d_%Y", localtime;
324 my $headerfilename = "stack_logger_" . $date . ".hh";
325 my $logfilename = "stack_logger_" . $date . ".log";
326 open(FILE, ">", $headerfilename) or die ( "failed to open file: $headerfilename\n" );
327 print FILE $logger_header;
328 close FILE;
329 my $printlog = "";
330 if ( $loglevel == 0 )
331 {
332 $printlog = "if (!doLog()) { return; }";
333 }
334 my $logger =
335 "#include \"$headerfilename\"
336 #include <stdlib.h>
337 #include <string.h>
338 FILE* FH::fh = 0;
339 const char* FH::file_name = \"$dir/$logfilename\";
340 unsigned int EntryRaiiObject::level = 0;
341 EntryRaiiObject::EntryRaiiObject (const char* func, const char* file) : func_(func), file_(file)
342 {
343 $printlog
344 ++level;
345 fprintf ( FH::getHandler(), \"%*u %s - Entry - %s\\n\", level, level, func_, file_);
346 fflush (FH::getHandler());
347 }
348 EntryRaiiObject::~EntryRaiiObject ()
349 {
350 $printlog
351 fprintf( FH::getHandler(), \"%*u %s - Exit - %s\\n\", level, level, func_, file_);
352 fflush (FH::getHandler());
353 --level;
354 }
355 int EntryRaiiObject::doLog ()
356 {
357 static int count = 0;
358 if (strcmp ( func_ , \"main\") == 0)
359 {
360 if ( count % 2 )
361 {
362 return count++ % 2;
363 }
364 else
365 {
366 return ++count % 2;
367 }
368 }
369 return count % 2;
370 }
371
372 FILE* FH::getHandler ()
373 {
374 if ( !fh)
375 {
376 fh = fopen (file_name, \"w\");
377 if ( !fh )
378 {
379 printf (\"Failed to open file: %s\", file_name);
380 exit (1);
381 }
382 }
383 return fh;
384 }
385
386 FH::~FH ()
387 {
388 fclose (fh);
389 }
390 ";
391 my $extension = ".cc";
392 my $bodyfilename = "stack_logger_" . $date . $extension;
393 open ( FILE, ">", $bodyfilename ) or die ( "failed to open file: $bodyfilename\n" );
394 print FILE $logger;
395 close FILE;
396 my $make =
397 "TOP := ..
398 include \$(TOP)/Makefile.cfg
399 SOURCES := $bodyfilename
400 HEADERS := \$(SOURCES:.cc=.hh)
401 OBJECTS := \$(SOURCES:.cc=.o)
402
403 all run : \$(OBJECTS)
404
405 install: all
406
407 include ../Makefile.genrules
408 ";
409
410 open ( FILE, ">", "Makefile" ) or die ( "failed to open file: Makefile\n" );
411 print FILE $make;
412 close FILE;
413 }
414 ############################################################
415 sub insert_include # inserts the header file include of the stacklogger for every files touched
416 {
417 my @files = @_; # all files for inserting the header
418 # if found previuos Include then update
419 my $regex = qr/#include <stack_logger_*/;
420 for my $includefilenamein (@files)
421 {
422 my $date = strftime "%m_%d_%Y", localtime;
423 my $includefilename = "stack_logger_" . $date . ".hh";
424 my $include = "#include <$includefilename>\n";
425 my $includefilenameout = "$includefilenamein.new" ;
426 open ( IN, "<", $includefilenamein) or die ( "failed to open file: $includefilenamein\n" );
427 open ( OUT, ">", $includefilenameout) or die ( "failed to open file: $includefilenameout\n" );
428 my $first_line = <IN>;
429 if ( $first_line !~ $regex )
430 {
431 print OUT $include;
432 print OUT $first_line;
433 }
434 else
435 {
436 print OUT $include;
437 }
438 while( <IN> )
439 {
440 print OUT $_;
441 }
442 close IN;
443 close OUT;
444 unlink $includefilenamein;
445 rename $includefilenameout, $includefilenamein;
446 }
447 }
448 ############################################################
449 sub remove_include # removes the header file include of the stacklogger from files
450 {
451 my @files = @_; # all files where the include is to be removed from
452 # if found previuos Include then update
453 my $regex = qr/#include <stack_logger_*/;
454
455 for my $file (@files)
456 {
457 open ( FILE, "<", $file) or die ( "failed to open file: $file\n" );
458 my @lines = <FILE>;
459 close FILE;
460 my $start = 0;
461 open ( FILE, ">", $file) or die ( "failed to open file: $file\n" );
462 while ( $lines[$start] =~ $regex )
463 {
464 $start += 1;
465 }
466 for my $i ( $start .. $#lines )
467 {
468 print FILE $lines[$i];
469 }
470 close FILE;
471 }
472 }
473 ############################################################
474 sub getFiles # collects the .cc files recursively from the path given
475 {
476 my($path) = $_[0]; # the target path
477 if ( -f $path )
478 {
479 push ( @files, $path );
480 return ;
481 }
482 #append a trailing / if it's not there
483 $path .= '/' if($path !~ /\/$/);
484 #loop through the files contained in the directory
485 for my $eachFile (glob($path . '*'))
486 {
487 # if the file is a directory
488 if ( -d $eachFile && $recursive )
489 {
490 # pass the directory to the routine
491 getFiles ( $eachFile, \@files );
492 }
493 else
494 {
495 my $regex = qr/.+\.cc$/s;
496 my $cpp = ($eachFile =~ $regex);
497 if ( $cpp )
498 {
499 push ( @files, $eachFile );
500 }
501 }
502 }
503 }
504 ############################################################
505 sub getDirs # collects the directories recursively from the path given
506 {
507 my($path) = $_[0]; # the target path
508 if ( -f $path )
509 {
510 my $dir = dirname ( $path );
511 $dir .= '/' if($dir !~ /\/$/);
512 push ( @dirs, $dir );
513 return;
514 }
515 #append a trailing / if it's not there
516 $path .= '/' if($path !~ /\/$/);
517 push ( @dirs, $path );
518 #loop through the files contained in the directory
519 for my $eachFile (glob($path . '*'))
520 {
521 # if the file is a directory
522 if ( -d $eachFile && $recursive )
523 {
524 # pass the directory to the routine
525 getDirs ( $eachFile, \@dirs );
526 }
527 }
528 }
529 ############################################################
530 sub delete_dep_files # deletes the dependency files that breaks the recompilation
531 {
532 my($path) = $_[0]; # the target path
533 if ( -f $path ) { return; }
534 #append a trailing / if it's not there
535 $path .= '/' if($path !~ /\/$/);
536 #loop through the files contained in the directory
537 for my $eachFile (glob($path . '*'))
538 {
539 # if the file is a directory
540 if ( -d $eachFile )
541 {
542 # pass the directory to the routine
543 delete_dep_files ( $eachFile );
544 }
545 else
546 {
547 my $regex = qr/.+\.d$/s;
548 my $dep = ($eachFile =~ $regex);
549 if ( $dep )
550 {
551 unlink $eachFile;
552 }
553 }
554 }
555 }
556 ############################################################
557 sub delete_logger_files # removes the logger files and their directory
558 {
559 if ( $path ne $pathtomain) { return;}
560 my ($logpath) = $_[0];
561 $logpath .= '/' if($logpath !~ /\/$/);
562 for my $file (glob($logpath . '*'))
563 {
564 if ( -f $file )
565 {
566 unlink $file;
567 }
568 }
569 }
570 ############################################################
571 sub getMainDir # defines the directory where the main.cc is to be found
572 {
573 my $dir = $_[0] ; # the target directory
574 $dir =~ s/\/$//;
575 my $enddir = $topdir;
576 $enddir =~ s/\/$//;
577 if ( -f $dir ) { $dir = dirname ( $dir ); } # if it is file, get the containing dir
578 while ( $enddir ne $dir )
579 {
580 opendir ( DIR, $dir ) or die $!;
581 my @dir = grep { /main.cc/ } readdir DIR;
582 if ( @dir == 0 )
583 {
584 $dir = dirname ( $dir ) ; # get the parent
585 }
586 else
587 {
588 return $dir . "/";
589 }
590 }
591 die ( "There was no main.cc in the path given and in their parent directories up to titan\n");
592 }
593 ############################################################
594 sub processArgs #( \$topdir, \$path, \$loggerdir, \$target, \$set, \$recursive, \$loglevel )
595 {
596 my @messages;
597 $messages[0] = "\nUsage: perl stacklogger.pl ON|OFF [ -R ] compiler2 | pathto/file \n";
598 $messages[1] = "ON switches on the stack logger\n";
599 $messages[2] = "OFF removes the stack logger\n";
600 $messages[3] = "-R optional: recursive handling the path given\n";
601 $messages[4] = "/pathto/file accept only a filename with extension .cc\n";
602 $messages[5] = "compiler2 accept only the directory name within titan\n";
603 $messages[6] = "-L main or -L all, sets the log level\n";
604 $messages[7] = "Correct usage of the ";
605 my $numArgs = $#ARGV + 1;
606
607 if ( $numArgs < 1 && $numArgs > 5 )
608 {
609 print @messages;
610 }
611 if (( uc ( $ARGV[0] ) ne "ON" ) && ( uc ( $ARGV[0] ) ne "OFF" ))
612 {
613 print $messages[7] . "first parameter :\n";
614 print $messages[1];
615 print $messages[2];
616 die;
617 }
618
619 if ((( $numArgs == 3 ) || ( $numArgs == 5 )) && ($ARGV[1] ne "-R" ))
620 {
621 print $messages[7] . "second parameter :\n";
622 print $messages[3] ;
623 die;
624 }
625
626 if (( $numArgs > 3 ) && ( $ARGV[1] eq "-R" ) ||
627 ( $numArgs > 2 ) && ( $ARGV[1] ne "-R" ))
628 {
629 my $logarg1 = 3;
630 my $logarg2 = 4;
631 if ( $ARGV[1] ne "-R" )
632 {
633 $logarg1 -= 1;
634 $logarg2 -= 1;
635 }
636 if (( $ARGV[$logarg1] ne "-L" ) || (( uc ( $ARGV[$logarg2] ) ne "MAIN" ) && ( uc ( $ARGV[$logarg2] ) ne "ALL" )))
637 {
638 print $messages[7] . "the log level :\n";
639 print $messages[6];
640 die;
641 }
642 if ( uc $ARGV[$logarg2] eq "MAIN" )
643 {
644 $loglevel = 0;
645 }
646 }
647
648 if ( $numArgs > 1 )
649 {
650 my $ttcn3_dir = $ENV{TTCN3_DIR};
651 if ( defined ( $ttcn3_dir))
652 { # the top dir is ../titan/
653 $ttcn3_dir =~ s/.*\/titan\K.+//;
654 $topdir = $path = $ttcn3_dir . "/";
655 my $index = 2;
656 if ( $ARGV[1] ne "-R" ) { $index -= 1; }
657 $path = $path . $ARGV[$index] ;
658 $path =~ s/\/\//\//; # replace // to /
659 unless ( -d $path || -f $path ) { die ( "$path neither file nor directory\n" ) ;}
660 if ( -d $path ) {$path .= "/"; }
661 $pathtomain = &getMainDir ( $path );
662 }
663 else { die ( "Error: environment variable TTCN3_DIR is not defined\n" ); }
664 }
665
666 if (( $numArgs >= 3 ) && ( $ARGV[1] eq "-R" ) && ( -f $path ))
667 {
668 die ( "recursive iteration is only for directories\n" );
669 }
670
671 $loggerdir = $topdir . $loggerdirname;
672 if ( uc ( $ARGV[0] ) eq "ON" )
673 {
674 $set = 1;
675 unless ( -d $loggerdir )
676 { # Create a directory
677 mkdir ( $loggerdir, 0770 ) or die ("can't create: $loggerdir\n");
678 }
679 }
680
681 if (( $numArgs >= 3 ) && ( $ARGV[1] eq "-R" ))
682 {
683 $recursive = 1;
684 }
685 }
686 ############################################################
This page took 0.056362 seconds and 5 git commands to generate.