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:
ltraceworks by intercepting calls to functions within shared libraries (likelibc,libm, etc.) that are dynamically linked by the target executable. When the program runs,ltracehooks into these calls before they reach the actual library functions and records them. - System Calls vs. Library Calls:
ltracespecifically traces library calls, not system calls. For system calls, usestrace.
Commands / Usage
Basic Tracing
-
Trace all library calls for a command:
ltrace ls -l /tmpExplanation: Executes
ls -l /tmpand shows all library calls it makes. -
Trace a specific program:
ltrace /usr/bin/firefoxExplanation: Starts
firefoxand traces all its library calls.
Filtering Calls
-
Trace specific libraries:
ltrace -l 'libc.so*' ls -lExplanation: Traces only calls to functions within libraries whose names start with
libc.so. -
Trace specific functions:
ltrace -e 'printf|puts' dateExplanation: Traces only calls to the
printfandputsfunctions. -
Trace functions in a specific library:
ltrace -l 'libcrypto.so*' -e 'RAND_bytes' /usr/bin/openssl rand -hex 16Explanation: Traces only the
RAND_bytesfunction withinlibcrypto.so(and its variants) when running theopensslcommand. -
Exclude specific libraries:
ltrace -L 'libdl.so*' bashExplanation: Traces all library calls made by
bashexcept those inlibdl.so. -
Exclude specific functions:
ltrace -e '!free' free_programExplanation: Traces all library calls made by
free_programexcept for calls to thefreefunction.
Output Control
-
Show time of day for each call:
ltrace -T uptimeExplanation: Adds the time of day to the output for each traced call.
-
Show time spent in each call:
ltrace -t sleep 5Explanation: Measures and displays the time spent within each library call.
-
Show relative time spent in each call:
ltrace -tt sleep 5Explanation: Displays the time spent within each call with microsecond precision.
-
Show absolute timestamp for each call:
ltrace -ttt sleep 5Explanation: 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_appExplanation: Traces library calls made by the main process and any child processes it creates.
-
Output to a file:
ltrace -o ltrace.log ./my_programExplanation: Redirects all
ltraceoutput to the fileltrace.loginstead of stderr. -
Show library names:
ltrace -L ls -lExplanation: Prefixes each traced call with the name of the library it originates from.
-
Set maximum string length to print:
ltrace -s 128 ./my_programExplanation: Limits string arguments and return values to 128 characters.
Attaching to Running Processes
-
Attach to a running process by PID:
ltrace -p 12345Explanation: Attaches
ltraceto the process with PID12345and traces its library calls. -
Detach from a process:
ltrace -p 12345 -DExplanation: Detaches
ltracefrom the process with PID12345without terminating the process.
Intercepting Specific Libraries and Functions
-
Trace all calls to
mallocandfree:ltrace -e malloc=libc,free=libc ./my_allocator_testExplanation: Traces only
mallocandfreecalls originating fromlibc. -
Trace all functions starting with
send:ltrace -e 'send*' ./my_network_clientExplanation: Traces all library functions whose names begin with
send. -
Trace calls to
pthread_create:ltrace -e pthread_create ./my_threaded_appExplanation: Traces only calls to the
pthread_createfunction.
Library Path Configuration
- Specify library path to search for shared libraries:
Explanation: Instructsltrace -p /opt/my_libs/libmy.so -e my_custom_function ./my_appltraceto look for shared libraries in/opt/my_libswhen resolving symbols.
Common Patterns
-
Finding which library a function belongs to:
ltrace -l 'libc.so*' -e 'strchr' /bin/bashExplanation: Shows calls to
strchrand explicitly prefixes them withlibc.so(if that’s where it’s found), helping to confirm its origin. -
Debugging memory allocation issues:
ltrace -e 'malloc|calloc|realloc|free' ./my_programExplanation: Isolates all memory management calls to pinpoint potential leaks or incorrect usage.
-
Understanding network communication:
ltrace -l 'libcurl.so*' -e 'curl_*' ./my_curl_scriptExplanation: Focuses on
libcurlcalls to debug network requests. -
Tracing configuration file parsing:
ltrace -e 'fopen|fread|fclose' ./my_config_readerExplanation: Monitors file I/O operations related to configuration file handling.
-
Saving trace output for later analysis:
ltrace -o trace.out ./my_slow_appExplanation: Captures the entire trace to
trace.outfor 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
ltracevs.strace: Rememberltracetraces library calls, whilestracetraces system calls. If you’re seeing a lot ofread,write,open,close, you’re likely looking at system calls, andstraceis the tool you need.ltraceintercepts calls likeprintf,fopen,malloc,socket, etc., which are often wrappers around system calls.- Static Binaries:
ltracewill 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 withltrace’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:
ltraceprimarily 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:
ltracemight 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,
ltracedoes not trace child processes. You need the-fflag to follow them. - Root Privileges: Attaching to processes owned by other users or system processes often requires root privileges (
sudo ltrace).