From: wrostek <wolfgang.rostek@gmx.de>
Subject: Re: Injecting trace code under GNAT
Date: Wed, 24 Jul 2013 02:10:30 -0700 (PDT)
Date: 2013-07-24T02:10:30-07:00 [thread overview]
Message-ID: <7119a808-0f52-4f2a-8b8e-76f13410a968@googlegroups.com> (raw)
In-Reply-To: <e15d1198-151b-4194-8b8e-3c0d0c157fd3@googlegroups.com>
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 <working_dir>\n" + \
"Filter Ada subroutines and inject trace code.\n" + \
"Refer to the script header info for details.\n" + \
"<working_dir> 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)
prev parent reply other threads:[~2013-07-24 9:10 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-17 7:33 Injecting trace code under GNAT wrostek
2013-07-17 8:00 ` Georg Bauhaus
2013-07-17 8:40 ` wrostek
2013-07-17 8:15 ` Niklas Holsti
2013-07-17 23:38 ` Randy Brukardt
2013-07-18 6:03 ` J-P. Rosen
2013-07-23 6:59 ` wrostek
2013-07-23 13:43 ` Marc C
2013-07-23 15:44 ` wrostek
2013-07-24 9:10 ` wrostek [this message]
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox