BACKTRACE(3)

πŸ“¦ version 15.1, in freebsd 14.5, freebsd 15.1

✨ BACKTRACE(3) ✨

okay so bestie, you know how when your program face-plants and you're like "where even WAS I" β€” that's literally what this is for πŸ’… this is the LIBRARY situation: it lives in library β€œlibexecinfo”, not in libc, and we'll get to why later (spoiler: it's a whole thing).

It's the Library Functions Manual page, and honestly? iconic behaviour.


πŸŽ€ SYNOPSIS πŸŽ€

like, the receipts, exactly as they are:

#include <execinfo.h>

size_t
backtrace(void **addrlist, size_t len);

char **
backtrace_symbols(void * const *addrlist, size_t len);

int
backtrace_symbols_fd(void * const *addrlist, size_t len, int fd);

char **
backtrace_symbols_fmt(void * const *addrlist, size_t len,
    const char *fmt);

int
backtrace_symbols_fd_fmt(void * const *addrlist, size_t len, int fd,
    const char *fmt);

🌸 DESCRIPTION 🌸

the main character: backtrace()

so backtrace() takes that array pointed to by addrlist and fills it with the program counter values for each frame it can see, all the way up to len frames. and then it tells you how many frames it actually found β€” which, plot twist, can be fewer than len 😭. that number is the return value. slay.

backtrace_symbols_fmt() β€” the glow-up

this one takes an array of addresses that backtrace() already filled in (addrlist, len elements) and uses fmt to make them look cute. the formatting characters you can use are, and I'm quoting the vibes exactly here:

  • a β€” the numeric address of each element, printed the way %p would do it.
  • n β€” the name of the nearest function symbol (smaller than the address element), figured out by dladdr(3) if the symbol was dynamic, or looked up in the executable if static and the /proc filesystem is available to determine the executable path. iykyk.
  • d β€” the difference between the symbol address and the address element, printed using 0x%tx.
  • D β€” the difference between the symbol address and the address element, printed using +0x%tx if non-zero, or nothing at all if it's zero. zero erasure, honestly 🫢
  • f β€” the filename of the symbol, as determined by dladdr(3).

the array of formatted strings comes back as one contiguous memory address, which means you can free the whole thing with a single free(3). one free, one vibe. πŸ¦‹

backtrace_symbols()

this is literally backtrace_symbols_fmt() with the format argument set to %a <%n%D> at %f. that's it. that's the whole thing.

the _fd girlies: backtrace_symbols_fd() and backtrace_symbols_fd_fmt()

same as the non-_fd functions, except instead of handing you back an array of strings, they print a new-line separated array of strings into fd. and they return 0 on success, -1 on failure. no array, just vibes into a file descriptor πŸ’Œ


πŸ’– RETURN VALUES πŸ’–

  • backtrace() returns the number of elements that actually got filled in the backtrace.
  • backtrace_symbols() and backtrace_symbols_fmt() return a string array on success, and NULL on failure β€” and they set errno while they're at it.
  • also, heads up: diagnostic output may also be produced by the ELF symbol lookup functions. not me getting extra output I didn't ask for πŸ™ˆ

⭐ SEE ALSO ⭐

go read those, bestie, they're the supporting cast πŸŽ€


🌈 HISTORY 🌈

the backtrace() library of functions first appeared in NetBSD 7.0 and FreeBSD 10.0. vintage. lowkey a pioneer.


πŸ’€ BUGS πŸ’€

  1. Errors should not be printed but communicated to the caller differently. yeah. that one. it's giving "we know, we know" 😭
  2. Because these functions use elf(3) this is a separate library instead of being part of libc/libutil, so that no library dependencies are introduced. it's called boundaries, look it up πŸ’…
  3. The Linux versions of the functions (there are no _fmt variants) use int instead of size_t arguments. not the _fmt variants existing on Linux. not them changing the types. we don't talk about it. πŸ’€
fr fr though β€” if you're relying on the exact return values here, check your platform, because that last one will absolutely bite you.

and that's the page! 🫢 this one shipped with Debian, dated December 12, 2015 β€” so yeah, she's a 2015 icon and she's still serving. mwah πŸ’‹

πŸ“¦ where this page comes from