ltrace Library Tracer

ltrace cheatsheet — trace shared library calls made by a program. ltrace ./myprogram, ltrace -e malloc+free, ltrace -p PID. Debug library-level issues on Linux.

6 min read

What it is

ltrace is a dynamic library call tracer for Linux that intercepts and records calls made by a program to shared libraries. You reach for it when you want to understand how a program interacts with the system’s libraries, debugging library-related issues, or reverse-engineering.

Installation

Linux

sudo apt update && sudo apt install ltrace
# or
sudo yum install ltrace
# or
sudo dnf install ltrace

macOS

ltrace is not natively available on macOS. You can install it via Homebrew, but its functionality might be limited due to differences in dynamic linking mechanisms:

brew install ltrace

Windows

ltrace is not available for Windows. Tools like ProcMon from Sysinternals provide similar functionality.

Core Concepts

  • Dynamic Linking: ltrace works by intercepting calls to functions within shared libraries (like libc, libm, etc.) that are dynamically linked by the target executable. When the program runs, ltrace hooks into these calls before they reach the actual library functions and records them.
  • System Calls vs. Library Calls: ltrace specifically traces library calls, not system calls. For system calls, use strace.

Commands / Usage

Basic Tracing

  • Trace all library calls for a command:

    ltrace ls -l /tmp
    

    Explanation: Executes ls -l /tmp and shows all library calls it makes.

  • Trace a specific program:

    ltrace /usr/bin/firefox
    

    Explanation: Starts firefox and traces all its library calls.

Filtering Calls

  • Trace specific libraries:

    ltrace -l 'libc.so*' ls -l
    

    Explanation: Traces only calls to functions within libraries whose names start with libc.so.

  • Trace specific functions:

    ltrace -e 'printf|puts' date
    

    Explanation: Traces only calls to the printf and puts functions.

  • Trace functions in a specific library:

    ltrace -l 'libcrypto.so*' -e 'RAND_bytes' /usr/bin/openssl rand -hex 16
    

    Explanation: Traces only the RAND_bytes function within libcrypto.so (and its variants) when running the openssl command.

  • Exclude specific libraries:

    ltrace -L 'libdl.so*' bash
    

    Explanation: Traces all library calls made by bash except those in libdl.so.

  • Exclude specific functions:

    ltrace -e '!free' free_program
    

    Explanation: Traces all library calls made by free_program except for calls to the free function.

Output Control

  • Show time of day for each call:

    ltrace -T uptime
    

    Explanation: Adds the time of day to the output for each traced call.

  • Show time spent in each call:

    ltrace -t sleep 5
    

    Explanation: Measures and displays the time spent within each library call.

  • Show relative time spent in each call:

    ltrace -tt sleep 5
    

    Explanation: Displays the time spent within each call with microsecond precision.

  • Show absolute timestamp for each call:

    ltrace -ttt sleep 5
    

    Explanation: Displays the absolute timestamp of each call with microsecond precision.

  • Print return values:

    ltrace -r echo "Hello"
    

    Explanation: Appends the return value of each library call to its output line.

  • Print function arguments:

    ltrace -a 10 printf "Hello, %s!\n" "World"
    

    Explanation: Prints the first 10 characters of string arguments to library calls.

  • Follow child processes (fork, vfork, clone):

    ltrace -f ./my_multiprocess_app
    

    Explanation: Traces library calls made by the main process and any child processes it creates.

  • Output to a file:

    ltrace -o ltrace.log ./my_program
    

    Explanation: Redirects all ltrace output to the file ltrace.log instead of stderr.

  • Show library names:

    ltrace -L ls -l
    

    Explanation: Prefixes each traced call with the name of the library it originates from.

  • Set maximum string length to print:

    ltrace -s 128 ./my_program
    

    Explanation: Limits string arguments and return values to 128 characters.

Attaching to Running Processes

  • Attach to a running process by PID:

    ltrace -p 12345
    

    Explanation: Attaches ltrace to the process with PID 12345 and traces its library calls.

  • Detach from a process:

    ltrace -p 12345 -D
    

    Explanation: Detaches ltrace from the process with PID 12345 without terminating the process.

Intercepting Specific Libraries and Functions

  • Trace all calls to malloc and free:

    ltrace -e malloc=libc,free=libc ./my_allocator_test
    

    Explanation: Traces only malloc and free calls originating from libc.

  • Trace all functions starting with send:

    ltrace -e 'send*' ./my_network_client
    

    Explanation: Traces all library functions whose names begin with send.

  • Trace calls to pthread_create:

    ltrace -e pthread_create ./my_threaded_app
    

    Explanation: Traces only calls to the pthread_create function.

Library Path Configuration

  • Specify library path to search for shared libraries:
    ltrace -p /opt/my_libs/libmy.so -e my_custom_function ./my_app
    
    Explanation: Instructs ltrace to look for shared libraries in /opt/my_libs when resolving symbols.

Common Patterns

  • Finding which library a function belongs to:

    ltrace -l 'libc.so*' -e 'strchr' /bin/bash
    

    Explanation: Shows calls to strchr and explicitly prefixes them with libc.so (if that’s where it’s found), helping to confirm its origin.

  • Debugging memory allocation issues:

    ltrace -e 'malloc|calloc|realloc|free' ./my_program
    

    Explanation: Isolates all memory management calls to pinpoint potential leaks or incorrect usage.

  • Understanding network communication:

    ltrace -l 'libcurl.so*' -e 'curl_*' ./my_curl_script
    

    Explanation: Focuses on libcurl calls to debug network requests.

  • Tracing configuration file parsing:

    ltrace -e 'fopen|fread|fclose' ./my_config_reader
    

    Explanation: Monitors file I/O operations related to configuration file handling.

  • Saving trace output for later analysis:

    ltrace -o trace.out ./my_slow_app
    

    Explanation: Captures the entire trace to trace.out for detailed review without cluttering the terminal.

  • Tracing a process that’s already running and stuck:

    sudo ltrace -p <PID>
    

    Explanation: Attaches to a frozen process to see what library call it might be waiting on.

Gotchas

  • ltrace vs. strace: Remember ltrace traces library calls, while strace traces system calls. If you’re seeing a lot of read, write, open, close, you’re likely looking at system calls, and strace is the tool you need. ltrace intercepts calls like printf, fopen, malloc, socket, etc., which are often wrappers around system calls.
  • Static Binaries: ltrace will not work on statically linked executables because they do not rely on shared libraries.
  • Security Restrictions: Some security mechanisms (like seccomp) or complex library loading scenarios might interfere with ltrace’s ability to intercept calls.
  • Performance Overhead: Tracing can significantly slow down the execution of the target program, especially for programs that make a very large number of library calls. Use filtering (-e, -l) to reduce overhead.
  • Interpreted Languages: ltrace primarily targets native code. Tracing applications written in interpreted languages (like Python, Ruby, Node.js) might not yield the expected results for the language’s internal operations, though it might trace calls made by the interpreter itself or C extensions.
  • Complex Argument Types: ltrace might struggle to perfectly represent complex data structures passed as arguments or return values. It often shows them as hexadecimal or truncated representations.
  • Child Processes: By default, ltrace does not trace child processes. You need the -f flag to follow them.
  • Root Privileges: Attaching to processes owned by other users or system processes often requires root privileges (sudo ltrace).