CrackOps
Interview PrepTracksLinuxAWS LabSoonInterview RoomSoon
Sign inStart free
CrackOps

Interview prep for the people who keep production up.

[email protected]
ProductInterview PrepTracksDashboardInterview Room
RolesDevOpsSREPlatformCloud
CompanyAboutContactPrivacyTerms
© CrackOps
Linux / Debugging & Diagnostics / ltrace

ltrace

Trace the library calls a program makes

Advanceddebugginglibrariesptrace

ltrace shows the calls a program makes into shared libraries such as libc: getenv, fopen, malloc, strcmp and friends, with arguments and return values. It answers questions strace can't, like which environment variable a binary looks for or which string it compares your input against.

Syntaxltrace [-f] [-c] [-S] [-tt] [-e FILTER] [-s N] [-o FILE] { COMMAND [ARG]... | -p PID }

Watch it run

You want to know what settings a program looks up at startup without reading its source code.

devops@devops-lab: ~ — zsh — 96×28
➜ ~
Step 1 of 2
ltrace -e getenv ls /tmp

Each line is caller->function(arguments) = return value. ls checks for LS_BLOCK_SIZE, QUOTING_STYLE, TZ and more: nil means the variable isn't set. Every one of these is a knob you can turn without touching the code.

Anatomy of a command

$
commandltrace

The library-call tracer. Like strace, it controls the program through ptrace.

How it works

ltrace reads the program's ELF dynamic symbol table (.dynsym and .dynstr) to learn which library functions it imports. It starts the program under ptrace and plants breakpoint instructions (int3) on the PLT stubs, the small trampolines every call into a shared library goes through. When a breakpoint fires, the kernel stops the program and ltrace decodes the arguments using prototypes from /usr/share/ltrace/*.conf (it knows getenv takes a string, fopen two strings). It then sets a breakpoint on the return address to catch the return value. Statically linked binaries, including most Go programs, have no dynamic symbol table, so there is nothing to trace. Each traced call costs several context switches, so ltrace is slower than strace. -S adds system calls to the same output.

Options you'll actually use

-e FILTEROnly these functions: getenv+fopen, or 'malloc*' patterns, or -e '@libssl.so*'
-cCount calls and time per function, printed as a table at exit
-SAlso show system calls (prefixed SYS_), mixed with library calls
-fFollow child processes created by fork
-p PIDAttach to a running process (needs root on Ubuntu)
-tt / -TTimestamp each call / show time spent inside each call
-s NMaximum string length to print (default 32)
-n NIndent nested calls by N spaces, to see who calls whom
-o FILEWrite the trace to FILE instead of stderr
-x PATTERNAlso trace internal (non-PLT) functions matching the pattern

Common mistakes

ltrace ./myapp on a Go, Rust-musl or other static binary and assuming it does nothing

Static binaries have no PLT or dynamic symbol table, so ltrace has nothing to hook; the program's work is invisible to it.

file ./myapp to check, then strace -f for syscalls or perf record for CPU
Running ltrace without -e on a real service

You get hundreds of thousands of strlen, memcpy and malloc calls and the program slows to a crawl.

ltrace -e getenv+fopen+connect ... or ltrace -c for a summary
Reading ltrace -c times as the real cost of each function

Every traced call pays for breakpoints and context switches; the overhead (tens of µs) dwarfs a strlen that takes nanoseconds.

Use -c for call counts; use perf to measure real CPU time

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Find which environment variables the date command reads.

  2. 2

    Count the library calls made by 'ls -l ~/app' and find the most frequent one.

  3. 3

    Show both library calls and system calls for 'cat ~/app/README.md' (or any file in ~/app), limited to fopen/open-style calls.

Related commands

straceTrace the system calls a process makesgdbDebug crashes, core dumps and hung processesperfProfile where CPU time goes, kernel and user spaceenvShow the environment, or run a command with a changed one
PreviousstraceNextlsof
Linux / Debugging & Diagnostics / ltrace

ltrace

Trace the library calls a program makes

Advanceddebugginglibrariesptrace

ltrace shows the calls a program makes into shared libraries such as libc: getenv, fopen, malloc, strcmp and friends, with arguments and return values. It answers questions strace can't, like which environment variable a binary looks for or which string it compares your input against.

Syntaxltrace [-f] [-c] [-S] [-tt] [-e FILTER] [-s N] [-o FILE] { COMMAND [ARG]... | -p PID }

Watch it run

You want to know what settings a program looks up at startup without reading its source code.

devops@devops-lab: ~ — zsh — 96×28
➜ ~
Step 1 of 2
ltrace -e getenv ls /tmp

Each line is caller->function(arguments) = return value. ls checks for LS_BLOCK_SIZE, QUOTING_STYLE, TZ and more: nil means the variable isn't set. Every one of these is a knob you can turn without touching the code.

Anatomy of a command

$
commandltrace

The library-call tracer. Like strace, it controls the program through ptrace.

How it works

ltrace reads the program's ELF dynamic symbol table (.dynsym and .dynstr) to learn which library functions it imports. It starts the program under ptrace and plants breakpoint instructions (int3) on the PLT stubs, the small trampolines every call into a shared library goes through. When a breakpoint fires, the kernel stops the program and ltrace decodes the arguments using prototypes from /usr/share/ltrace/*.conf (it knows getenv takes a string, fopen two strings). It then sets a breakpoint on the return address to catch the return value. Statically linked binaries, including most Go programs, have no dynamic symbol table, so there is nothing to trace. Each traced call costs several context switches, so ltrace is slower than strace. -S adds system calls to the same output.

Options you'll actually use

-e FILTEROnly these functions: getenv+fopen, or 'malloc*' patterns, or -e '@libssl.so*'
-cCount calls and time per function, printed as a table at exit
-SAlso show system calls (prefixed SYS_), mixed with library calls
-fFollow child processes created by fork
-p PIDAttach to a running process (needs root on Ubuntu)
-tt / -TTimestamp each call / show time spent inside each call
-s NMaximum string length to print (default 32)
-n NIndent nested calls by N spaces, to see who calls whom
-o FILEWrite the trace to FILE instead of stderr
-x PATTERNAlso trace internal (non-PLT) functions matching the pattern

Common mistakes

ltrace ./myapp on a Go, Rust-musl or other static binary and assuming it does nothing

Static binaries have no PLT or dynamic symbol table, so ltrace has nothing to hook; the program's work is invisible to it.

file ./myapp to check, then strace -f for syscalls or perf record for CPU
Running ltrace without -e on a real service

You get hundreds of thousands of strlen, memcpy and malloc calls and the program slows to a crawl.

ltrace -e getenv+fopen+connect ... or ltrace -c for a summary
Reading ltrace -c times as the real cost of each function

Every traced call pays for breakpoints and context switches; the overhead (tens of µs) dwarfs a strlen that takes nanoseconds.

Use -c for call counts; use perf to measure real CPU time

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Find which environment variables the date command reads.

  2. 2

    Count the library calls made by 'ls -l ~/app' and find the most frequent one.

  3. 3

    Show both library calls and system calls for 'cat ~/app/README.md' (or any file in ~/app), limited to fopen/open-style calls.

Related commands

straceTrace the system calls a process makesgdbDebug crashes, core dumps and hung processesperfProfile where CPU time goes, kernel and user spaceenvShow the environment, or run a command with a changed one
PreviousstraceNextlsof