From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,FREEMAIL_FROM autolearn=unavailable autolearn_force=no version=3.4.4 X-Received: by 10.66.249.193 with SMTP id yw1mr7546746pac.26.1374657030257; Wed, 24 Jul 2013 02:10:30 -0700 (PDT) X-Received: by 10.49.63.162 with SMTP id h2mr131846qes.26.1374657030171; Wed, 24 Jul 2013 02:10:30 -0700 (PDT) Path: border1.nntp.dca3.giganews.com!border2.nntp.dca3.giganews.com!border4.nntp.dca.giganews.com!border2.nntp.dca.giganews.com!nntp.giganews.com!qx7no52674300pbc.1!news-out.google.com!b2ni84402pby.1!nntp.google.com!qx7no52674298pbc.1!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail Newsgroups: comp.lang.ada Date: Wed, 24 Jul 2013 02:10:30 -0700 (PDT) In-Reply-To: Complaints-To: groups-abuse@google.com Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=194.15.135.12; posting-account=GxWvNgoAAAAH4SakIxF38Jkeu4kDHb6i NNTP-Posting-Host: 194.15.135.12 References: <07cb9baf-902c-4870-bfd1-aa8018e9d5c5@googlegroups.com> <38da123d-4b6d-4f93-a013-11bb5b1e2727@googlegroups.com> <727e9cb2-b0df-4838-85e3-bf1f97e08d18@googlegroups.com> User-Agent: G2/1.0 MIME-Version: 1.0 Message-ID: <7119a808-0f52-4f2a-8b8e-76f13410a968@googlegroups.com> Subject: Re: Injecting trace code under GNAT From: wrostek Injection-Date: Wed, 24 Jul 2013 09:10:30 +0000 Content-Type: text/plain; charset=ISO-8859-1 X-Original-Bytes: 26914 Xref: number.nntp.dca.giganews.com comp.lang.ada:182666 Date: 2013-07-24T02:10:30-07:00 List-Id: Here we are. I hope it will survive formatting issues. Wolfgang R. ------------------------------------------------------- #!/usr/bin/python ####################################################################### # This script is a very simple approach parsing and # adding trace statements to each entry/exit of a subroutine. # # Some more background is discussed here # https://groups.google.com/forum/#!topic/comp.lang.ada/vSNunYeX6GY # # It is by no way intended to be a complete useful parser rather than # a good bad example for students not coding this way. I will admit. # My only excuse is that it fits +my+ needs, my time budget and my # limited knowledge of python. # # The script is relying on the subroutine denominator repeated in the # end-clause. Don't read any further if this isn't given in your codebase. # # It will modify the source code files in the working directory given # by the mandatory single parameter! Be careful to not check them in # and use this tmp directory for creating patched executables only. # # The script will not change line numbers but modify within the same # line. If the injected trace statement reports its line number this # will be identical to the unmodified file. # # I assume to run on Unix and having access to /tmp. # # The script will probably fail the first time and tweaking for your # needs is needed. But do not try to go beyond the complexity this # simple script is able to handle. As an example only one nested # subroutine level is supported. # # Here my iterations to fix problems in the script # # ./inject_ada /my/path/to/tmp/dir > ~/x # # tail -3 ~/x # ... # ERROR: not cleared by end of file package: ... // not ok # # // look how far we got # egrep -Hn "processing file" /tmp/x_ada # # // open the failed file (/tmp/x_ada) and the log (~/x) # # // From my experience it is better to check the failed file top down. # // If the parser assumes to open a level 2 subroutine (look for first 'level2') # // then the subroutine (or lines) before this point are a good candidate # // having trouble. # // The extensive trace of the script has given me a good turnaround time # // tracking down the problem. ####################################################################### from sys import exit import sys import string import os, glob import shutil def trace() : return True def exttrace() : return True and trace() #################################################################### ## we handle parsing a subroutine by a large number of globals ## (this might be better moved to classes later) ## ## top frame stack storage area _subroutineIdentifierFound = False _subroutineNameFound = False _subroutineIsFound = False _subroutineBeginFound = False _subroutineEndFound = False _subroutineEndSemicolonFound = False _subroutineIsFunction = False # procedure or function _subroutineName = '' _paramBracketCount = 0 tmp_filename = '/tmp/_x_ada' tmp_file = open(tmp_filename, 'w') currentLineOrig = '' currentLineOut = '' outputModifiedLine = False currentLineWoComment = '' # lower case currentColumnIndex = 0 # status (must all be reset) subroutineIdentifierFound = False subroutineNameFound = False subroutineIsFound = False subroutineBeginFound = False subroutineEndFound = False subroutineEndSemicolonFound = False subroutineIsFunction = False # procedure or function paramBracketCount = 0 # we are on the second level? is_sub_frame = False # we are inside an IGNORE_ section ignore_active = False # for use by inject_xxx() packageName = '' subroutineName = '' curr_line_num = 0 # statistics inject_count = 1 ## ## end globals #################################################################### def clear_status() : global subroutineIdentifierFound global subroutineNameFound global subroutineIsFound global subroutineBeginFound global subroutineEndFound global subroutineEndSemicolonFound global paramBracketCount if exttrace() : print 'clear_status()' subroutineIdentifierFound = False subroutineNameFound = False subroutineIsFound = False subroutineBeginFound = False subroutineEndFound = False subroutineEndSemicolonFound = False paramBracketCount = 0 return def push_frame() : global _subroutineIdentifierFound global _subroutineNameFound global _subroutineIsFound global _subroutineBeginFound global _subroutineEndFound global _subroutineEndSemicolonFound global _subroutineIsFunction # procedure or function global _subroutineName global _paramBracketCount global subroutineIdentifierFound global subroutineNameFound global subroutineIsFound global subroutineBeginFound global subroutineEndFound global subroutineEndSemicolonFound global subroutineIsFunction # procedure or function global subroutineName global paramBracketCount if exttrace() : print 'push_frame()' _subroutineIdentifierFound = subroutineIdentifierFound _subroutineNameFound = subroutineNameFound _subroutineIsFound = subroutineIsFound _subroutineBeginFound = subroutineBeginFound _subroutineEndFound = subroutineEndFound _subroutineEndSemicolonFound = subroutineEndSemicolonFound _subroutineIsFunction = subroutineIsFunction # procedure or function _subroutineName = subroutineName _paramBracketCount = paramBracketCount subroutineIdentifierFound = False subroutineNameFound = False subroutineIsFound = False subroutineBeginFound = False subroutineEndFound = False subroutineEndSemicolonFound = False subroutineName = '' paramBracketCount = 0 return def pop_frame() : global _subroutineIdentifierFound global _subroutineNameFound global _subroutineIsFound global _subroutineBeginFound global _subroutineEndFound global _subroutineEndSemicolonFound global _subroutineIsFunction # procedure or function global _subroutineName global _paramBracketCount global subroutineIdentifierFound global subroutineNameFound global subroutineIsFound global subroutineBeginFound global subroutineEndFound global subroutineEndSemicolonFound global subroutineIsFunction # procedure or function global subroutineName global paramBracketCount if exttrace() : print 'pop_frame()' subroutineIdentifierFound = _subroutineIdentifierFound subroutineNameFound = _subroutineNameFound subroutineIsFound = _subroutineIsFound subroutineBeginFound = _subroutineBeginFound subroutineEndFound = _subroutineEndFound subroutineEndSemicolonFound = _subroutineEndSemicolonFound subroutineIsFunction = _subroutineIsFunction # procedure or function subroutineName = _subroutineName paramBracketCount = _paramBracketCount return # are we inside a parameter block? def isInsideParam() : global paramBracketCount return paramBracketCount > 0 # ignore sections between IGNORE_ON/IGNORE_OFF def check_ignore() : global currentLineOrig global ignore_active index = currentLineOrig.find('IGNORE_ON') if index >= 0 : if ignore_active : print 'FATAL: ignore is activate already while active request' exit(1) if exttrace() : print 'ignore activated' ignore_active = True index = currentLineOrig.find('IGNORE_OFF') if index >= 0 : if not ignore_active : print 'FATAL: ignore is not active while deactivate request' exit(1) if exttrace() : print 'ignore deactivated' ignore_active = False return def check_for_new() : global currentLineWoComment global currentColumnIndex global is_sub_frame if exttrace() : print 'check_for_new()' # special case for package packageIndex = currentLineWoComment[currentColumnIndex:].find('package ') if packageIndex >= 0 : return # special case for vars newIndex = currentLineWoComment[currentColumnIndex:].find('new_') if newIndex >= 0 : return newIndex = currentLineWoComment[currentColumnIndex:].find('new') if newIndex >= 0 : if exttrace() : print 'new found' clear_status() if is_sub_frame : pop_frame() is_sub_frame = False return def check_for_separate() : global currentLineWoComment global currentColumnIndex global is_sub_frame if exttrace() : print 'check_for_separate()' separateIndex = currentLineWoComment[currentColumnIndex:].find('separate') if separateIndex >= 0 : if exttrace() : print 'separate found' clear_status() if is_sub_frame : pop_frame() is_sub_frame = False return def check_for_semicolon() : global currentLineWoComment global currentColumnIndex global subroutineEndSemicolonFound if exttrace() : print 'check_for_semicolon()' semicolonIndex = currentLineWoComment[currentColumnIndex:].find(';') if semicolonIndex >= 0 : if exttrace() : print 'semicolon found' subroutineEndSemicolonFound = True return def handle_semicolon() : global subroutineEndSemicolonFound global subroutineIdentifierFound global subroutineIsFound global is_sub_frame if exttrace() : print 'handle_semicolon()' if not subroutineIdentifierFound : return if isInsideParam() : return if subroutineIsFound : return check_for_semicolon() if subroutineIdentifierFound and not subroutineIsFound and subroutineEndSemicolonFound : if exttrace() : print 'clear by semicolon found()' clear_status() if is_sub_frame : pop_frame() is_sub_frame = False return # do we have a local subroutine? def handle_second_level_entry() : global currentLineWoComment global currentColumnIndex global is_sub_frame global subroutineIdentifierFound subroutineIdentifierP = 'procedure' subroutineIdentifierF = 'function' if exttrace() : print 'handle_second_level...' if currentColumnIndex >= len(currentLineWoComment) : if exttrace() : print '...handle_second_level -1-' return if exttrace() : print 'currentColumnIndex: ' + str(currentColumnIndex) # we assume a blank after subroutine token myIndex = currentLineWoComment[currentColumnIndex:].find(subroutineIdentifierP + ' ') if myIndex >= 0 : if trace() : print 'token found: procedure -level2-' push_frame() subroutineIsFunction = False currentColumnIndex = myIndex currentColumnIndex += len(subroutineIdentifierP) else : myIndex = currentLineWoComment[currentColumnIndex:].find(subroutineIdentifierF + ' ') if myIndex >= 0 : if trace() : print 'token found: function -level2-' push_frame() subroutineIsFunction = True currentColumnIndex = myIndex currentColumnIndex += len(subroutineIdentifierF) if exttrace() : print 'myindex: ' + str(myIndex) if exttrace() : print 'currentColumnIndex: ' + str(currentColumnIndex) if myIndex >= 0 : if exttrace() : print 'is_sub_frame = True' is_sub_frame = True subroutineIdentifierFound = True find_identifier() if exttrace() : print '...handle_second_level -e-' return # remove and ignore parameter block def strip_parameters() : global currentLineWoComment global paramBracketCount currIndex = 0 # forward while currIndex < len(currentLineWoComment) : if isInsideParam() : if currentLineWoComment[currIndex] == ')' : currentLineWoComment = currentLineWoComment[0:currIndex] + " " + currentLineWoComment[currIndex+1:] paramBracketCount -= 1 else : if currentLineWoComment[currIndex] == '(' : paramBracketCount += 1 if isInsideParam() : currentLineWoComment = currentLineWoComment[0:currIndex] + " " + currentLineWoComment[currIndex+1:] currIndex += 1 # backward currIndex = len(currentLineWoComment) - 1 while currIndex >= 0 : if isInsideParam(): if currentLineWoComment[currIndex] == '(' : currentLineWoComment = currentLineWoComment[0:currIndex] + " " + currentLineWoComment[currIndex+1:] paramBracketCount -= 1 else : if currentLineWoComment[currIndex] == ')' : paramBracketCount += 1 if isInsideParam() : currentLineWoComment = currentLineWoComment[0:currIndex] + " " + currentLineWoComment[currIndex+1:] currIndex -= 1 if exttrace() : print '...strip_parameters >' + currentLineWoComment + '<' return # we assume it is allowed injecting at the beginning of first line def inject_with() : global outputModifiedLine global currentLineOrig global currentLineOut # remove this to do something useful if True : return if exttrace() : print 'inject_with' outputModifiedLine = True currentLineOut = 'with text_io; use text_io; ' + currentLineOrig return def inject_begin() : global outputModifiedLine global currentLineWoComment global currentLineOut global inject_count outputModifiedLine = True inject_count += 1 currentLineOut = currentLineWoComment + ' null; ' if exttrace() : print 'inject_begin >' + currentLineOut + '<' return def inject_end() : global outputModifiedLine global currentLineWoComment global currentLineOut global inject_count outputModifiedLine = True inject_count += 1 currentLineOut = 'null; ' + currentLineWoComment if exttrace() : print 'inject_end >' + currentLineOut + '<' return def find_end() : global subroutineEndFound global currentLineWoComment global currentColumnIndex global subroutineName global is_sub_frame subroutineEnd = 'end' subroutineReturn = 'return' if exttrace() : print 'find_end...' if currentColumnIndex >= len(currentLineWoComment) : if exttrace() : print '...find_end -1-' return if exttrace() : print 'currentColumnIndex: ' + str(currentColumnIndex) if subroutineEndFound : print 'ERROR: must not come to this line' return # we are inside a subroutine body and may have optional returns returnIndex = currentLineWoComment[currentColumnIndex:].find(subroutineReturn + ' ') if returnIndex < 0 : returnIndex = currentLineWoComment[currentColumnIndex:].find(subroutineReturn + ';') if returnIndex < 0 : returnIndex = currentLineWoComment[currentColumnIndex:].find(subroutineReturn + '(') if returnIndex > 0 : returnIndex = currentLineWoComment[currentColumnIndex:].find(' ' + subroutineReturn) if returnIndex >= 0 : returnIndex += 1 if returnIndex >= 0 : if trace() : print 'token found: return' currentColumnIndex = returnIndex currentColumnIndex += len(subroutineReturn) inject_end() find_end() # we may have something still on the line if exttrace() : print '...find_end -2-' return nameIndex = currentLineWoComment[currentColumnIndex:].find(' ' + subroutineName) if nameIndex < 0 : if exttrace() : print '...find_end -3-' return endIndex = currentLineWoComment[currentColumnIndex:].find(subroutineEnd + ' ') if endIndex >= 0 : testIndex = endIndex + len(subroutineEnd) while testIndex < nameIndex : if currentLineWoComment[testIndex] != ' ' : if exttrace() : print 'not blank between end and name' if exttrace() : print '...find_end -4-' return testIndex += 1 if trace() : print 'token found: end' subroutineEndFound = True currentColumnIndex = endIndex currentColumnIndex += len(subroutineEnd) inject_end() clear_status() if is_sub_frame : pop_frame() is_sub_frame = False if exttrace() : print '...find_end -e-' return def find_begin() : global subroutineBeginFound global currentLineWoComment global currentColumnIndex subroutineBegin = 'begin' if exttrace() : print 'find_begin...' if currentColumnIndex >= len(currentLineWoComment) : if exttrace() : print '...find_begin -1-' return if exttrace() : print 'currentColumnIndex: ' + str(currentColumnIndex) if subroutineBeginFound : find_end() if exttrace() : print '...find_begin -2-' return beginIndex = currentLineWoComment[currentColumnIndex:].find(subroutineBegin) if beginIndex >= 0 : if beginIndex + len(subroutineBegin) < len(currentLineWoComment) : beginIndex2 = currentLineWoComment[currentColumnIndex:].find(subroutineBegin + ' ') if beginIndex2 < 0 : if exttrace() : print '...find_begin -3-' return if trace() : print 'token found: begin' subroutineBeginFound = True currentColumnIndex = beginIndex currentColumnIndex += len(subroutineBegin) inject_begin() find_end() if exttrace() : print '...find_begin -e-' return def find_is() : global subroutineIsFound global currentLineWoComment global currentColumnIndex subroutineIs = 'is' if exttrace() : print 'find_is...' if currentColumnIndex >= len(currentLineWoComment) : if exttrace() : print '...find_is -1-' return if exttrace() : print 'currentColumnIndex: ' + str(currentColumnIndex) if not subroutineIsFound : strip_parameters() if isInsideParam() : return if subroutineIsFound : check_for_new() check_for_separate() if subroutineIsFound : find_begin() if exttrace() : print '...find_is -2-' return isIndex = currentLineWoComment[currentColumnIndex:].find(subroutineIs) if isIndex > 0 : isIndex2 = currentLineWoComment[currentColumnIndex:].find(' is') if isIndex2 < 0 : if exttrace() : print '...find_is -3-' return if isIndex >= 0 : if trace() : print 'token found: is' subroutineIsFound = True currentColumnIndex = isIndex currentColumnIndex += len(subroutineIs) check_for_new() check_for_separate() if subroutineIsFound : find_begin() if exttrace() : print '...find_is -e-' return def find_name() : global subroutineNameFound global currentLineWoComment global subroutineName global currentColumnIndex if exttrace() : print 'find_name...' if currentColumnIndex >= len(currentLineWoComment) : if exttrace() : print '...find_name -1-' return if exttrace() : print 'currentColumnIndex: ' + str(currentColumnIndex) if subroutineNameFound : find_is() if exttrace() : print '...find_name -2-' return myIndex1 = -1 while currentColumnIndex < len(currentLineWoComment) : if ' ' == currentLineWoComment[currentColumnIndex] : currentColumnIndex += 1 continue else : myIndex1 = currentColumnIndex break if myIndex1 < 0 : if exttrace() : print '...find_name -3-' return myIndex2 = len(currentLineWoComment) while currentColumnIndex < len(currentLineWoComment) : if ' ' != currentLineWoComment[currentColumnIndex] \ and '(' != currentLineWoComment[currentColumnIndex] \ and chr(31) < currentLineWoComment[currentColumnIndex]: currentColumnIndex += 1 continue else : myIndex2 = currentColumnIndex break subroutineName = currentLineWoComment[myIndex1:myIndex2] subroutineNameFound = True if trace() : print 'subroutine name >' + subroutineName + '<' find_is() if exttrace() : print '...find_name -e-' return # lookup the subroutine identifier def find_identifier() : global subroutineIdentifierFound global currentLineWoComment global subroutineIsFunction global currentColumnIndex subroutineIdentifierP = 'procedure' subroutineIdentifierF = 'function' if exttrace() : print 'find_identifier...' if currentColumnIndex >= len(currentLineWoComment) : if exttrace() : print '...line end' return if exttrace() : print 'currentColumnIndex: ' + str(currentColumnIndex) if subroutineIdentifierFound : handle_second_level_entry() if subroutineIdentifierFound : find_name() if exttrace() : print '...find_identifier -1-' return # we assume one blank after the identifier (and no immmediate line break) myIndex = currentLineWoComment[currentColumnIndex:].find(subroutineIdentifierP + ' ') if myIndex >= 0 : if trace() : print 'token found: procedure' subroutineIsFunction = False currentColumnIndex = myIndex currentColumnIndex += len(subroutineIdentifierP) else : myIndex = currentLineWoComment[currentColumnIndex:].find(subroutineIdentifierF + ' ') if myIndex >= 0 : if trace() : print 'token found: function' subroutineIsFunction = True currentColumnIndex = myIndex currentColumnIndex += len(subroutineIdentifierF) if exttrace() : print 'myindex: ' + str(myIndex) if exttrace() : print 'currentColumnIndex: ' + str(currentColumnIndex) if myIndex >= 0 : subroutineIdentifierFound = True find_name() if exttrace() : print '...find_identifier -e-' return def process_file(src_name): global tmp_file global currentLineWoComment global currentLineOrig global currentLineOut global currentColumnIndex global curr_line_num global outputModifiedLine global packageName global subroutineIdentifierFound global is_sub_frame global ignore_active global subroutineEndSemicolonFound if exttrace() : print 'process_file...' # reset curr_line_num = 0 is_sub_frame = False ignore_active = False myfile = open(src_name) # extract package name index_underscore = src_name.rfind('.'); index_slash = src_name.rfind('/'); packageName = src_name[index_slash+1:index_underscore] if trace() : print 'packageName >' + packageName + '<' # process all lines while 1: line = myfile.readline() if len(line) == 0 : break curr_line_num += 1 # without \n currentLineOrig = line[:-1] # reset outputModifiedLine = False if curr_line_num == 1 : inject_with() check_ignore() if ignore_active : if exttrace() : print '[' + str(curr_line_num) + ']' + ' ignore_active ' tmp_file.write(line) continue ## handle comment part hyphen_index = currentLineOrig.find('--') # strip comment and lower case the string to work on if hyphen_index >= 0 : currentLineWoComment = currentLineOrig[:hyphen_index].lower() else : currentLineWoComment = currentLineOrig.lower() if exttrace() : print '[' + str(curr_line_num) + ']' + ' >' + currentLineWoComment + '<' currentColumnIndex = 0 subroutineEndSemicolonFound = False find_identifier() handle_semicolon() if outputModifiedLine : if trace() : print 'modified line >' + currentLineOut + '<' tmp_file.write(currentLineOut) else : tmp_file.write(currentLineOrig) tmp_file.write('\n') # while 1 myfile.close() if subroutineIdentifierFound : if exttrace() : print 'ERROR: not cleared by end of file package: ' + packageName exit(1) if exttrace() : print '...process_file' return # iterate all Ada package bodies def process_files(working_path): global tmp_file global tmp_filename processed_files_count = 0 if exttrace() : print 'process_files...' for currentFile in glob.glob( os.path.join(working_path, '*') ): if os.path.isdir(currentFile): if exttrace() : print 'got a directory: ' + currentFile process_files(currentFile) for currentFile in glob.glob( os.path.join(working_path, '*.ada') ): # drop specs if currentFile.find('_.ada') >= 0 : continue if trace() : print "processing file: " + currentFile tmp_file = open(tmp_filename, 'w') process_file(currentFile) tmp_file.close() shutil.copyfile(tmp_filename, currentFile) processed_files_count += 1 if trace() : print '...process_files processed_files_count: ' + str(processed_files_count) return ####################################################################### ## init ####################################################################### use = "\nUsage : ./inject_ada \n" + \ "Filter Ada subroutines and inject trace code.\n" + \ "Refer to the script header info for details.\n" + \ " The directory root to do the conversion.\n" + \ " NOTE: The content of this directory gets modified!\n\n" if len(sys.argv) != 2 : print use exit(0) working_path = sys.argv[1] if trace() : print 'working_path: ' + working_path ####################################################################### ## main ####################################################################### process_files(working_path) exit(0)