comp.lang.ada
 help / color / mirror / Atom feed
* Injecting trace code under GNAT
@ 2013-07-17  7:33 wrostek
  2013-07-17  8:00 ` Georg Bauhaus
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: wrostek @ 2013-07-17  7:33 UTC (permalink / raw)


Hi forum,

I'm starting new to a fairly large GNAT project. 

Is the GNAT environment providing help to inject trace code
on entry/exit of each subroutine? 

It doesn't matter if it is a one go over the whole codebase
or by pre-processing prior to each compilation.

I need to hook into my own routines to optimize things for
perfomance reasons. 

thanks in advance
Wolfagng R.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Injecting trace code under GNAT
  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
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: Georg Bauhaus @ 2013-07-17  8:00 UTC (permalink / raw)


On 17.07.13 09:33, wrostek wrote:
> Hi forum,
>
> I'm starting new to a fairly large GNAT project.
>
> Is the GNAT environment providing help to inject trace code
> on entry/exit of each subroutine?
>
> It doesn't matter if it is a one go over the whole codebase
> or by pre-processing prior to each compilation.
>
> I need to hook into my own routines to optimize things for
> perfomance reasons.

If it is about measuring relative performance of subprograms,
then one good approximation is kcachegrind.
(With compiler switch -fno-inline in particular).

If you can target the JVM using JGNAT, too, then this target
might allow injecting something.

The -fprofile* compiler switches might be interesting.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Injecting trace code under GNAT
  2013-07-17  7:33 Injecting trace code under GNAT wrostek
  2013-07-17  8:00 ` Georg Bauhaus
@ 2013-07-17  8:15 ` Niklas Holsti
  2013-07-17 23:38 ` Randy Brukardt
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Niklas Holsti @ 2013-07-17  8:15 UTC (permalink / raw)


On 13-07-17 10:33 , wrostek wrote:
> Hi forum,
> 
> I'm starting new to a fairly large GNAT project. 
> 
> Is the GNAT environment providing help to inject trace code
> on entry/exit of each subroutine? 
> 
> It doesn't matter if it is a one go over the whole codebase
> or by pre-processing prior to each compilation.
> 
> I need to hook into my own routines to optimize things for
> perfomance reasons. 

It seems that GNAT can be used with gprof:

http://gcc.gnu.org/onlinedocs/gcc-4.8.1/gnat_ugn_unw/Profiling-an-Ada-Program-using-gprof.html

For something more advanced, you could try the RapiTime tool,
http://www.rapitasystems.com/products/RapiTime.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
      .      @       .

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Injecting trace code under GNAT
  2013-07-17  8:00 ` Georg Bauhaus
@ 2013-07-17  8:40   ` wrostek
  0 siblings, 0 replies; 10+ messages in thread
From: wrostek @ 2013-07-17  8:40 UTC (permalink / raw)


Thank you both for your quick feedback

...
> If it is about measuring relative performance of subprograms,
> 
> then one good approximation is kcachegrind.
> 
> (With compiler switch -fno-inline in particular).
No, it's about understanding the program flow.
I'm very much preferring tracing over debugging. 
Means instrumenting code with minor impact on runtime.

Of course this is bulk data and needs specific care.

As an example I trace simple IDs and only integer values
to shared memory and stream it to disk by another process.
All formatting is off-line. This way I can inject a fairly
huge number of traces by low runtime penalties. My personal
taste is to accept up to ~3% runtime increase but have
this trace all time available. This did help me a lot in the
past to speed up turn-around time for error analysis.

But I'm aware that this approach isn't accepted by everybody ;)   


> 
> 
> 
> If you can target the JVM using JGNAT, too, then this target
> 
> might allow injecting something.
Yes, in my Java days there was this nice API interface
to the JVM to hook methods in. 

> 
> 
> 
> The -fprofile* compiler switches might be interesting.


I will elaborate all your proposals.

Wolfgang R.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Injecting trace code under GNAT
  2013-07-17  7:33 Injecting trace code under GNAT wrostek
  2013-07-17  8:00 ` Georg Bauhaus
  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
  4 siblings, 0 replies; 10+ messages in thread
From: Randy Brukardt @ 2013-07-17 23:38 UTC (permalink / raw)


"wrostek" <wolfgang.rostek@gmx.de> wrote in message 
news:07cb9baf-902c-4870-bfd1-aa8018e9d5c5@googlegroups.com...
> Hi forum,
>
> I'm starting new to a fairly large GNAT project.
>
> Is the GNAT environment providing help to inject trace code
> on entry/exit of each subroutine?
>
> It doesn't matter if it is a one go over the whole codebase
> or by pre-processing prior to each compilation.

There was a tool for doing such preprocessing that was created during the 
very early days of Ada, and it was found in one of the repositories. (I 
remember it because we used it as the basis for an in-house tool for 
coverage analysis.) You might look in the on-line version of the old ASE 
cd-roms (lots of very old software that still might be useful for 
something): http://archive.adaic.com/ase/

                               Randy. 


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Injecting trace code under GNAT
  2013-07-17  7:33 Injecting trace code under GNAT wrostek
                   ` (2 preceding siblings ...)
  2013-07-17 23:38 ` Randy Brukardt
@ 2013-07-18  6:03 ` J-P. Rosen
  2013-07-23  6:59 ` wrostek
  4 siblings, 0 replies; 10+ messages in thread
From: J-P. Rosen @ 2013-07-18  6:03 UTC (permalink / raw)


Le 17/07/2013 09:33, wrostek a écrit :

> Is the GNAT environment providing help to inject trace code
> on entry/exit of each subroutine? 
> 
You might be interested in package Debug
(http://www.adalog.fr/compo2.htm#Debug). It provides a very
sophisticated tracing facility, but no automatic insertion of trace calls.


-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Injecting trace code under GNAT
  2013-07-17  7:33 Injecting trace code under GNAT wrostek
                   ` (3 preceding siblings ...)
  2013-07-18  6:03 ` J-P. Rosen
@ 2013-07-23  6:59 ` wrostek
  2013-07-23 13:43   ` Marc C
  4 siblings, 1 reply; 10+ messages in thread
From: wrostek @ 2013-07-23  6:59 UTC (permalink / raw)


Sorry all. I thought I was under email notification and didn't
see the latest comments. Thanks for these links.

Thinking about the features I need it should have been quite
simple to write a quick and dirty parsing by hand.

This would give me more flexibility in instrumenting the
code in different sections. Mixing between generated and
hand written trace statements could be easier this way
as well.

I decided to go with python and learn a bit more this
language along the script.

It took me 2 days and works quite well for me. Here my
experiences.

Looking at the subroutine structure I thought it must
be quite easy to extract begin, end and return tokens.

Almost through the implementation I encountered a wrong
assumption of mine that the subroutine designatore must
be repeated in the end-clause. A shame that this is
optional (had in mind that this is one of the nice
things Ada forces to have readable printouts) ;) But 
fortunately only 5 places had to be fixed to have
it all over the place now.

Half a day it took me to enhance parsing for more 
sophisticated structures. (it covers only things
seen in my code base) 

In the end there were 3 locations remaining where the
effort isn't justified to enhance the parsing further.
One is a task body and two places where keywords are
part of a variable/attribute. Here I use an IGNORE_ON/
IGNORE_OFF comment to skip them. I'll need the ignore 
anyway in the future.

The script comes to some 800 lines. It is filtering
200 package bodies and 300 kloc. For now it is injecting
a null statement but passes the compiler.

Wolfgang R.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Injecting trace code under GNAT
  2013-07-23  6:59 ` wrostek
@ 2013-07-23 13:43   ` Marc C
  2013-07-23 15:44     ` wrostek
  0 siblings, 1 reply; 10+ messages in thread
From: Marc C @ 2013-07-23 13:43 UTC (permalink / raw)


On Tuesday, July 23, 2013 1:59:57 AM UTC-5, wrostek wrote:

> The script comes to some 800 lines. It is filtering
> 200 package bodies and 300 kloc. For now it is injecting
> a null statement but passes the compiler.

I think a lot of people would be interested in the functionality of this script. Kindly post it when you get a chance, even if it's just a quick & dirty version.

Thanks!

Marc

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Injecting trace code under GNAT
  2013-07-23 13:43   ` Marc C
@ 2013-07-23 15:44     ` wrostek
  2013-07-24  9:10       ` wrostek
  0 siblings, 1 reply; 10+ messages in thread
From: wrostek @ 2013-07-23 15:44 UTC (permalink / raw)


Hi Marc

yes I can do so. But it needs a least a bit of adapting correct names and
comments. Otherwise I will get blamed all over the place. That doesn't mean
it will become nice;)

I'm no longer in the office but I can cleanup and attach it tomorrow.

Wolfgang R.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Injecting trace code under GNAT
  2013-07-23 15:44     ` wrostek
@ 2013-07-24  9:10       ` wrostek
  0 siblings, 0 replies; 10+ messages in thread
From: wrostek @ 2013-07-24  9:10 UTC (permalink / raw)


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)


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2013-07-24  9:10 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox