tobias_hofer has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

please share me your wisdom for this case:
I have to write a script which is checking a given
function call sequence like "FunctionZ", "FunctionY",...
against a call stack trace in following textual format:
State: time: memory: Name:
ENTRY: 0.000 0x004e2aa8 FunctionA()
EXIT: 0.000 0x004e2aa8 FunctionA()
ENTRY: 0.000 0x004e3ac8 InitSomething()
ENTRY: 0.000 0x0045760c FunctionZ()
ENTRY: 0.000 0x00455fbd FunctionY()
EXIT: 0.000 0x00455fbd FunctionY()
EXIT: 0.000 0x0045760c FunctionZ()
EXIT: 0.000 0x004e3ac8 InitSomething()
So given the sequence "FunctionZ", "FunctionY" should return true and the sequence "FunctionY", "FunctionZ" should return false.

My Problem is, i am not sure what's the best way for implementing this. I have several ideas. The basis of all ideas is that i read-in the given c-call-stack trace completely and create a data-structure.

This data-structure could be:
#1 A Hash, where all subsequent functioncalls are listed
$->{InitSomething}{FunctionZ}{FunctionY}
Problem here:
  • when i have several calls to "InitSomething" with different subsequent function-calls I have to create additionally arrays for each hash item
  • Data will be doubled, each subsequent function call could be the root of the sequence requested to be matched, thus i have to create a hash item for each sub function call.. i feel by doing this i will end up in hell

  • 2# represent each "ENTRY" sequence in the stack trace as a string. Putting this string in a Hash and check the requested sequence if it is available in the hash.
    Problem here, only a small subset of function could be requested and then it is not working.
    3# Just like 2# but putting all in an array and do a reg-expression withe the requested sequence for each item.
    Problem here: It might be that the sequence wont be matched due to missing function names.
    4# Making a kind of Linked list for each function call where the root-function-call is placed into an hash. Then we search for the sequence in the list.
    Problem: I cannot install in perl the lib for linked lists as i do not have the perl maintenance rights thus i have to create them by myself, not really tricky but also here i fell to end up in hell..

    Maybe someone had a similar problem solved more elegant than my proposals - i hope so! Any help is highly welcome!

    Best regards Tobias
    • Comment on Analyze a C Call-Stack sequence trace and get call sequence from given Function name onwards.

    Replies are listed 'Best First'.
    Re: Analyze a C Call-Stack sequence trace and get call sequence from given Function name onwards.
    by GrandFather (Saint) on Aug 26, 2014 at 11:51 UTC

      How about you try an implementation and see how it pans out? That way at least your teacher can see some progress, and we can see that you've done some work and are more likely to help with actual implementation problems you may have.

      A good implementation would abstract the storage back end so you can get parsing and other front end stuff sorted out without bothering too much about an efficient back end, then if the simple first cut back end is too slow, replace it with something new when you've figured out where the problems are.

      BTW, in Perl linked lists are just arrays. Using the various array functions like push, pop, shift and unshift along with splice you can efficiently manipulate arrays in very much the way you would a linked list.

      Perl is the programming world's equivalent of English
        Thanks, yes, i am currently prototyping. For simplicity i process all pushes to a stack. Once a pop comes in i will store the stack data. Thus i get the stack usage over execution time. By simply appending the functions to each other i can use regex for matching without big effort. In the end it is simpler than expected :-)

        Here my prototype in case of interrest

        package CallStackAnalyzer; use strict; use warnings; use diagnostics; sub new { my $self = { name => 'CallStackAnalyzer', tracefilecontent => undef, stack => [], stacktraces => {}, direction => '', }; bless $self; return $self; } sub TraceFile{ my $self = shift; $self->{tracefilecontent} = shift; _AnalyzeTraceFile($self); } sub _AnalyzeTraceFile{ my $self = shift; my @trace = @{$self->{tracefilecontent}}; foreach my $line (@trace){ if($line=~m/^(ENTRY):\s+\S+\s+\S+\s+(\S+)\(\)/){ push(@{$self->{stack}}, $2) && ($self->{direction} = 'up'); } elsif ($line=~m/^(EXIT):\s+\S+\s+\S+\s+(\S+)\(\)/){ my @stack = $self->{stack}; ($self->{stacktraces}{join('->',@{$self->{stack}})} = \@stack ) && ($self->{direction} = 'down') if( not $self->{direction} eq 'down'); pop(@{$self->{stack}}); } } return ; } 1; package TraceCallStack; use strict; use warnings; use diagnostics; use CallStackAnalyzer; sub Main{ my $trace = open(FH, "CallStack.txt"); my @tracecontent = <FH>; close FH; my $CSA = CallStackAnalyzer->new(); $CSA->TraceFile(\@tracecontent); return; } Main(); 1;
        It works out great. I will add one more interface to do the matching against a collection of functions..
        Many thanks!!!

        Tobias

          Hello tobias_hofer,

          I notice that in sub new, $self->{stack} is assigned [], a reference to an anonymous array; but in sub _AnalyzeTraceFile you have:

          ... my @stack = $self->{stack}; ($self->{stacktraces}{join('->',@{$self->{stack}})} = \@stack ) && ...

          which treats $self->{stack} as an array, not a reference. I think you meant to write this:

          ... my @stack = @{ $self->{stack} }; ($self->{stacktraces}{ join('->', @{$self->{stack}}) } = \@stack) && ...

          Incidentally, while looking at the code I found it useful to add another method to the CallStackAnalyzer package:

          sub print { use Data::Dump; my $self = shift; dd $self; }

          and to call it in sub Main:

          ... $CSA->TraceFile(\@tracecontent); $CSA->print; ...

          Hope that helps,

          Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

    Re: Analyze a C Call-Stack sequence trace and get call sequence from given Function name onwards.
    by Anonymous Monk on Aug 26, 2014 at 12:42 UTC

      The single example you give is trivial to solve*, so I think you haven't described the task completely. What do you want your output to look like? How large are your input files? If there are other calls in between "FunctionZ" and "FunctionY", should it still match? Also I don't understand your point #3 - how do you expect to match function names when they're missing?

      * e.g. /^ENTRY:.*\b\Q$f1()\E\nENTRY:.*\b\Q$f2()\E$/m