1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

ltrace - Linux Debugging Utility Tutorial

Discussion in 'Linux' started by Trinity, Sep 16, 2012.

  1. Trinity

    Trinity New Member

    Joined:
    Nov 23, 2011
    Messages:
    28
    Likes Received:
    11
    Trophy Points:
    0
    Occupation:
    Software Engineer
    'ltrace' is another Linux Utility similar to 'strace'. However, ltrace lists all the library calls being called in an executable or a running process. Its name itself comes from library-call tracing. This tool is very useful for debugging user-space applications to determine which library call is failing. It is also capable of receiving signals for segmentation faults, etc.

    Using ltrace



    One does NOT need any root privileges to run ltrace.

    Using ltrace to debug an application executable
    Code:
    ltrace ./executable <parameters>
    
    Using ltrace to debug a running process
    Code:
    ltrace -p <PID>
    
    Here is an example usage of ltrace along with its output for a rare command 'time'
    Code:
    rupali@ubuntu:~/source$ ltrace time
    __libc_start_main(0x8048a50, 1, 0xbfc806e4, 0x8049890, 0x8049880 <unfinished ...>
    getenv("TIME")                                                                                           = NULL
    getopt_long(1, 0xbfc806e4, "+af:o:pqvV", 0x0804c0a0, NULL)                                               = -1
    __fprintf_chk(0x7b6980, 1, 0x8049948, 0xbfc81dce, 0Usage: time [-apvV] [-f format] [-o file] [--append] [--verbose]
           [--portability] [--format=format] [--output=file] [--version]
           [--quiet] [--help] command [arg...]
    )                                                     = 177
    exit(1 <unfinished ...>
    +++ exited (status 1) +++
    
    Notice the familiar library calls along with their parameters and return values in the output.

    Refer ltrace man page for details to run ltrace with various other options offered. Man page can be found by typing
    Code:
    man ltrace
    
    or through this link.

    Debugging with ltrace



    The ltrace utility is most useful for debugging user-space application programs as the bugs could be surfaced out seeing the dynamic records of the library calls. Here, let us take an scenario where we'll see what kind of errors we see and how we debug while using ltrace.

    Lets take a sample program.
    This program has a bug, and I suggest you not to even try to find the bug in this program on your own. Let ltrace help us to find the bug, as that is what we are here to learn. :)
    Code:
    1.  #include <stdio.h>
    2.  #include <unistd.h>
    3. 
    4.  int main()
    5.  {
    6.     FILE *fp = fopen("rfile.txt", "w+");
    7.     fprintf(fp+1, "Invalid Write\n");
    8.     fclose(fp);
    9.     return 0;
    10. }
    
    Lets compile and run it.
    Code:
    rupali@ubuntu:~/source$ gcc file.c -Wall -o file
    rupali@ubuntu:~/source$./file
    Segmentation fault (core dumped)
    
    Oh, that is a segmentation fault. Lets use ltrace to debug and see what is happening.
    Code:
    rupali@ubuntu:~/source$ltrace ./file
     __libc_start_main(0x8048454, 1, 0xbfc19db4, 0x80484c0, 0x8048530 <unfinished ...>
     fopen("rfile.txt", "w+")                          = 0x9160008
     fwrite("Invalid Write\n", 1, 14, 0x916009c <unfinished ...>
     --- SIGSEGV (Segmentation fault) ---
     +++ killed by SIGSEGV +++
    
    The first line states the libc function call 'main()', with its parameters and it terminated unfinished. Since we saw the segmentation fault, so unfinished main() aligns with our understanding.

    Next line has listed the fopen() call to open 'rfile.txt' in write plus mode and returning a valid file pointer address.
    Moving on to the next library call, we have fwrite which is unfinished. Here is the bug because of which program crashed. So focusing on this call and analyzing, notice the file pointer containing the address in fwrite() call doesnt match the one in fopen() call. Hence, the crash. The program is trying to write onto a file using file pointer which is invalid following a SIGSEGV signal.
    Getting back to our program, the bug is in line 7 of our program where the file pointer being passed to the fprintf() call is tampered. So, we just found the bug.

    Here is the corrected code
    Code:
    1.  #include <stdio.h>
    2.  #include <unistd.h>
    3. 
    4.  int main()
    5.  {
    6.     FILE *fp = fopen("rfile.txt", "w+");
    7.     fprintf(fp, "Invalid Write\n");
    8.     fclose(fp);
    9.     return 0;
    10. }
    
    In the example, we had taken a simple straight-forward program. Imagine, if it was a complicated huge program for some considerable data, ltrace output would had been much efficient to debug than re-checking each line of source or adding various printf's.

    Conclusion



    Now we know how to use ltrace for debugging applications. For more better intricate functionalities like breakpoints, stepping through, etc use GDB. However, most of the bugs can be resolved using ltrace/strace by knowing and analysing the calls and their success and failure errors.
     

Share This Page