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

Esteemed monks, I pray that you guide me on this quest I'm on, towards enlightenment.

Update:I I added my new findings in the thread below

I'm simply trying to write an inspector that can inspect a perl script with the ptrace call and check what system calls it makes. Below is the C program I've written to trace, but mine is a perl question.

Problem: The perl interpreter is spitting hundreds of system calls from executing a simple print "hello";. I'm guessing it's all extra stuff the interpreter is doing to compile my program

I have two programs. perl_tracer.c and hello.pl. The tracer executes hello.pl via the perl interpreter and gets the output from there at the end. However, I get a total 367 system calls. A variety of sys_rt_sigaction and finally a sys_exit_group. Ideally it should have just said the program made a sys_write call? Right? (for print)

Q : How or what should I do to just trace the perl script I'm running? Is there a way to know where my script execution began?

My target program
####### # hello.pl ######## print "hello";
My tracer :
/* perl_tracer.c This is completed adapted from some stuff I've seen. I'm really not an expert on linux and debugging. */ #include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <sys/user.h> /* For constantsORIG_EAX etc */ #include <sys/reg.h> #include <stdio.h> int pipefd[2]; int main() { int i, status; pid_t child; long orig_eax; long lastcall = 0; pipe(pipefd); child = fork(); if(child == 0) { //pipes so we can get the stdout from the child //doesn't work perfect yet. close(pipefd[0]); dup2(pipefd[1], 1); dup2(pipefd[1], 2); close(pipefd[1]); ptrace(PTRACE_TRACEME, 0, NULL, NULL); execl("/usr/bin/perl", "perl", "hello.pl", NULL ); } else { i = 0; while(1) { wait(&status); if (WIFEXITED(status) || WIFSIGNALED(status)) { break; } orig_eax = ptrace(PTRACE_PEEKUSER,child, 8 * ORIG_RAX,NULL); //We can kill the process if we get a malicious sys call. + /*if (orig_eax == 10){ kill(child, SIGKILL); }*/ printf("%d time system call %ld\n", i++, orig_eax); ptrace(PTRACE_SYSCALL, child, NULL, NULL); lastcall = orig_eax; }//end of while char buffer[1024]; // close the write end of the pipe in the parent close(pipefd[1]); while (read(pipefd[0], buffer, sizeof(buffer)) != 0) {//prints with some garbage at the end. printf("Child says : %.*s", 1024, buffer); } }//end of else. return 0; }

If you've reached here, thanks a ton for reading! :)

Replies are listed 'Best First'.
Re: tracing system calls a perl script is making
by BrowserUk (Patriarch) on May 31, 2013 at 16:38 UTC

    You could add

    INIT{ print "About to start running code\n" } END{ print "Code ending\n"; }

    Anything between those is your program; anything before or after is the interpreter doing its thing.

    See perldoc


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Anything between those is your program

      ...which while block buffered, on my box is optimized into a single write() system call ;-)

      strace perl -le 'INIT{ print "About to start running code" } END{print "code ending"} print "hello"' 2>&1 | less execve("/usr/bin/perl", ["perl", "-le", "INIT{ print \"About to start +runn"...], [/* 51 vars */]) = 0 brk(0) = 0x1bc9000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, +0) = 0x7fc0fdf2f000 ... rt_sigaction(SIGIO, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_sigaction(SIGSYS, NULL, {SIG_DFL, [], 0}, 8) = 0 write(1, "About to start running code\nhell"..., 46About to start runn +ing code hello code ending ) = 46 exit_group(0) = ? +++ exited with 0 +++

      I wished only half of the programs in my linux distro were half as good as the perl optimizer. Not to mention the stuff I am perlpetrating :)

        He can use warn or print STDERR to prevent that.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

      That was a really eloquent solution!

      Unfortunately I think my reading stdout with pipes is flawed! :( I get all the "starting" "hello" and "ending code" just all together after all the 367 system calls and printed.

      And this is because I'm reading the pipes after the program exits

      Any ideas for other approaches?

      Thanks for your answer though! After 1 month of side lining this I realize today my approach is slightly flawed!

        Unfortunately I think my reading stdout with pipes is flawed!

        Not necessarily so. More probably you are "suffering from buffering":

        • printing to the terminal is line buffered
        • printing elsewhere is block buffered

        Try inserting

        $| = 1;

        at the top of your program. See perlvar.

        I get all the "starting" "hello" and "ending code" just all together after all the 367 system calls and printed.

        Replace print with print STDERR ...; (or use warn).


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

      So I rewrote the perl program and the C program to write to the same text file

      I get something like this in my output.txt:

      237 time system call 8 238 time system call 8 239 time system call 5 240 time system call 5 241 time system call 72 242 time system call 72 243 time system call 1 Started #The BEGIN block 244 time system call 1 245 time system call 3 246 time system call 3 247 time system call 2 248 time system call 2 249 time system call 8 250 time system call 8 251 time system call 16 252 time system call 16 253 time system call 8 254 time system call 8 255 time system call 5 256 time system call 5 257 time system call 72 258 time system call 72 259 time system call 1 hello world 260 time system call 1 261 time system call 3 262 time system call 3 .... .... At 400 about I get the END block print and then 3 more system calls before termination

      Unfortunately I don't know now when I should start monitoring the target problem. I want to write something of a generic tracer for any perl script. I thought I would see a pattern in the perl interpreter's system calls but I don't. Any ideas?

        What BrowserUk says - use INIT, not BEGIN, since BEGIN blocks are executed in the compile phase of the perl script.

        I want to write something of a generic tracer for any perl script.

        Why? GNU/Linux has tools for that ready - strace(1), ltrace(1). I suspect an XY problem here. What are you trying to to with that which you are ostensibly trying to do?

        Then, perl is linked against many libraries, and it can well be that most of those syscalls happen inside calls to functions in these libraries. To verify that, you can use ltrace(1), which displays library calls, together with the -S switch to display system calls as well.

        The only thing I would add is that I recommended INIT and END; not BEGIN and END; and that difference may well account for much of your syscall activity, as modules files are read and parsed and memory allocated to accommodate them.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        I cannot help you with that as I don't run *nix.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.