strace traces syscalls. ltrace traces library calls — malloc, free, strcpy, pthread_mutex_lock, etc. I’ve been conflating them for years.

When strace shows nothing interesting but something is still wrong, ltrace sometimes shows the problem:

ltrace -p $PID

Example use case: a process was segfaulting, strace showed a successful read, then a SIGSEGV. ltrace revealed a strcpy(dst, src) where dst was NULL — the null check was missing in user code, not a syscall issue. Problem found in 30 seconds.

Caveats:

  • ltrace only works on dynamically linked binaries. Static binaries are opaque to it.
  • Overhead is worse than strace. Every library call gets intercepted. Don’t use it on hot paths without sampling.
  • Doesn’t follow across execve by default. Use -f if you care about child processes.

Worth knowing about for the rare times strace isn’t enough.

Also: modern alternative is bpftrace with uprobe on library entry points. More powerful, slightly scarier syntax. For casual debugging, ltrace is still the fastest thing to reach for.