DEBUGINFOD_FIND_*(3)

πŸ’– DEBUGINFOD_FIND_*(3) πŸ’–

okay bestie, welcome to the Library Functions Manual, where we're talking about the debuginfod_find_* girlies β€” the whole lil family of functions that go ask a debuginfod server "hey can u hand me this file pls πŸ₯Ί". Lowkey iconic, highkey useful, let's get into it.


✨ NAME ✨

debuginfod_find_debuginfo β€” request debuginfo from debuginfod


🌸 SYNOPSIS 🌸

#include <elfutils/debuginfod.h>

Link with -ldebuginfod.

πŸŽ€ CONNECTION HANDLE πŸŽ€

debuginfod_client *debuginfod_begin(void);
void debuginfod_end(debuginfod_client *client);

πŸ” LOOKUP FUNCTIONS πŸ”

int debuginfod_find_debuginfo(debuginfod_client *client,
                              const unsigned char *build_id,
                              int build_id_len,
                              char ** path);
int debuginfod_find_executable(debuginfod_client *client,
                               const unsigned char *build_id,
                               int build_id_len,
                               char ** path);
int debuginfod_find_source(debuginfod_client *client,
                           const unsigned char *build_id,
                           int build_id_len,
                           const char *filename,
                           char ** path);
int debuginfod_find_section(debuginfod_client *client,
                            const unsigned char *build_id,
                            int build_id_len,
                            const char * section,
                            char ** path);
int debuginfod_find_metadata(debuginfod_client *client,
                             const char *key,
                             const char *value,
                             char ** path);

πŸ’« OPTIONAL FUNCTIONS πŸ’«

typedef int (*debuginfod_progressfn_t)(debuginfod_client *client,
                                       long a, long b);
void debuginfod_set_progressfn(debuginfod_client *client,
                               debuginfod_progressfn_t progressfn);
int debuginfod_default_progressfn(debuginfod_client *client,
                                  long a, long b);
void debuginfod_set_verbose_fd(debuginfod_client *client,
                               int fd);
void debuginfod_set_user_data(debuginfod_client *client,
                              void *data);
void* debuginfod_get_user_data(debuginfod_client *client);
const char* debuginfod_get_url(debuginfod_client *client);
int debuginfod_add_http_header(debuginfod_client *client,
                               const char* header);
const char* debuginfod_get_headers(debuginfod_client *client);

🌈 DESCRIPTION 🌈

So first things first: debuginfod_begin() makes you a debuginfod_client connection handle, and you're gonna pass that handle into literally every other call on this page. When you're done and you want all the state and storage yeeted into the void, you call debuginfod_end() on that handle. Cleanup era πŸ’…

Then the lookups. debuginfod_find_debuginfo(), debuginfod_find_executable(), and debuginfod_find_source() go query the debuginfod server URLs sitting inside $DEBUGINFOD_URLS (more on that below πŸ‘‡) for the debuginfo, executable, or source file matching the build_id you gave them. That build_id should be a pointer to either a null-terminated lowercase hex string or a raw binary blob. If build_id is a hex string, then build_id_len should be 0. Otherwise, build_id_len should be however many bytes are in the binary blob. fr fr, that's the whole rule.

Now debuginfod_find_source() is extra and also needs a filename, because it's gotta know which source file you mean. That filename should be an absolute path that includes the compilation directory of the CU associated with the source file. The tea here: relative path names show up all the time in the DWARF file's source directory, but those paths are relative to each individual compilation unit AT_comp_dir path, and yet one executable is made up of multiple CUs. So to disambiguate, debuginfod expects source queries to prefix relative path names with the CU compilation-directory, followed by a mandatory "/".

Note: the caller may or may not elide ../ or /./ or extraneous /// sorts of path components in the directory names. debuginfod accepts both forms. Specifically, debuginfod canonicalizes path names according to RFC3986 section 5.2.4 (Remove Dot Segments), plus reducing any // to / in the path.

Next up, debuginfod_find_section() queries the debuginfod server URLs in $DEBUGINFOD_URLS for the binary contents of an ELF/DWARF section contained in a debuginfo or executable file with the given build_id. Your section argument should be the name of the ELF/DWARF section you want. And heads up: if a server does not support section queries, debuginfod_find_section may query the server for the debuginfo and/or executable with that build_id in order to retrieve and extract the section. Sneaky but valid 🫢

Then debuginfod_find_metadata() queries all the debuginfod server URLs in $DEBUGINFOD_URLS for metadata for all matches of a given key/value query against files in their indexes. The resulting file is a JSON document. Peep the debuginfod-find(1) man page for examples of the supported types of key/value queries and their JSON results. πŸ‘‘

If path is not NULL and the query succeeds, path gets set to the path of the file in the cache. And important: the caller must free() this value. Don't ghost it, bestie, free it.

The URLs in $DEBUGINFOD_URLS may be queried in parallel. As soon as a debuginfod server begins transferring the target file, all of the connections to the other servers are closed. First one to show up wins, the rest get left on read πŸ’€

One more thing β€” a client handle should be used from only one thread at a time. But you can reuse a handle for a whole series of lookups, which can improve performance because it retains connections and caches. Reuse queen ✨


🎯 RETURN VALUE 🎯

debuginfod_begin returns the debuginfod_client handle to use with all the other calls. On error, NULL will be returned and errno will be set. Bestie check that errno.

If a find family function is successful, the resulting file is saved to the client cache and a file descriptor to that file is returned. That file descriptor points to the beginning of the file. The caller needs to close() this descriptor. Otherwise, a negative error code is returned. No vibes, just numbers 😭


πŸ’« OPTIONAL FUNCTIONS πŸ’«

A small number of optional functions are available to tune or query the operation of the debuginfod client. Cute lil extras πŸŽ€

πŸ“Š PROGRESS CALLBACK πŸ“Š

Since the debuginfod_find_*() functions may block for seconds or longer, a progress callback function gets called periodically β€” if you configured one with debuginfod_set_progressfn(). That function sets a new progress callback function (or NULL) for the client handle.

The callback you give it gets called from the context of each thread that's invoking any of the other lookup functions. It receives two numeric parameters that, if you think of them as a numerator a and a denominator b, together represent a completion fraction a/b. The denominator may be zero initially, until a quantity such as an exact download size becomes known. So like, don't divide by it, babe 😭

The progress callback function is also the supported way to interrupt the download operation. (The library does not modify or trigger signals.) The progress callback must return 0 to continue the work, or any other value to stop work as soon as possible. Consequently, the debuginfod_find_*() function will likely return with an error, but might still succeed. Yeah, "might still succeed" β€” the chaos is real.

debuginfod_default_progressfn() is the progress callback function set by the debuginfod client library when the DEBUGINFOD_PROGRESS environment variable is set and no progressfn is explicitly set. For more information see DEBUGINFOD_PROGRESS below. Custom progress callback functions may call debuginfod_default_progressfn() directly to report download status. Convenient ✨

πŸ—£οΈ VERBOSE OUTPUT πŸ—£οΈ

The debuginfod_find_*() functions may use several techniques to retrieve the requested files β€” through the cache, or through one or multiple servers or file URLs. To show how a query is handled, debuginfod_set_verbose_fd() can be used to set a particular file descriptor on which verbose output is given about the query steps and eventual errors encountered. Basically it narrates the whole thing to a fd of your choice 🫢

πŸ‘€ USER DATA POINTER πŸ‘€

A single void * pointer associated with the connection handle may be set any time via debuginfod_set_user_data(), and retrieved via debuginfod_get_user_data(). The value is undefined if unset.

πŸ”— URL πŸ”—

The URL of the current or most recent outgoing download, if known, may be retrieved via debuginfod_get_url() from the progressfn callback, or afterwards. It may be NULL. The resulting string is owned by the library, and must not be modified or freed. The caller should copy it if it is needed beyond the release of the client object.

πŸ“¨ HTTP HEADER πŸ“¨

Before each lookup function is initiated, a client application may add HTTP request headers. These are reset after each lookup function. debuginfod_add_http_header() may be called with strings of the form "Header: value". These strings are copied by the library. A zero return value indicates success, but out-of-memory conditions may result in a non-zero -ENOMEM. If the string is in the wrong form, -EINVAL will be returned. So format it right or get clowned.

$DEBUGINFOD_HEADERS_FILE specifies a file to supply headers to outgoing requests. Each non-whitespace line of this file is handled as if debuginfod_add_http_header() were called on the contents.

Note that the current debuginfod-client library implementation uses libcurl, but you shouldn't rely on that fact. Don't use this function for replacing any standard headers, except for the User-Agent mentioned below. You can use this function to add authorization information for access control, or to provide optional headers to the server for logging purposes.

By default, the library adds a descriptive User-Agent: header to outgoing requests. If the client application adds a header with the same name, this default is suppressed. You overrode it, so it steps aside πŸ’…

During or after a lookup, a client application may call debuginfod_get_headers() to gather the subset of HTTP response headers received from the current or most recent debuginfod server. Only those headers prefixed with X-DEBUGINFOD (case-insensitive) are kept. They are returned as a single string, with each "header: value" terminated with a \n (not \r\n as in HTTP). It may be NULL. The resulting string is owned by the library, and must not be modified or freed. The caller should copy the returned string if it is needed beyond the release of the client object.


🧚 MACROS 🧚

⭐ DEBUGINFOD_SONAME ⭐

Defined to the string that could be passed to dlopen(3) if the library is loaded at runtime, for example:

void *debuginfod_so = dlopen(DEBUGINFOD_SONAME, RTLD_LAZY);

πŸ”’ SECURITY πŸ”’

If IMA signature(s) are available from the RPMs that contain requested files, then debuginfod will extract those signatures into response headers, and debuginfod_find_*() will perform verification upon the files. Validation policy is controlled via tags inserted into $DEBUGINFOD_URLS. By default, debuginfod_find_*() acts in ignore mode. So it's just vibing unless you tell it otherwise 🫢

If accessed across HTTP rather than HTTPS, the network should be trustworthy. Authentication information through the internal libcurl library is not currently enabled, except for the basic plaintext http[s]://userid:password@hostname/ style. (The debuginfod server does not perform authentication, but a front-end proxy server could.) Read that twice, bestie, it matters.

πŸ’€ ERRORS πŸ’€

okay bestie, real talk β€” this list is not the whole story. Like, it's not comprehensive at all. Error codes can also come from calls to various C Library functions, so if you see something that's not here, don't come for me, it probably wandered in from libc. πŸ™ˆ

  • EACCESS β€” access to the resource located at the URL was denied. nope, not for you, babes. 🚫
  • ECONNREFUSED β€” couldn't connect to the remote host. Also gets returned when an HTTPS connection couldn't be verified (aka bad certificate) β€” the vibe check on that cert did not pass. 😭
  • ECONNRESET β€” couldn't send or receive network data. the connection said "and I oop" and left. πŸ’€
  • EHOSTUNREACH β€” couldn't resolve the remote host. it's giving "who?? never heard of her." πŸ‘»
  • EINVAL β€” one or more arguments are incorrectly formatted. specifically: build_id may be too long (greater than 256 characters), filename may be empty, or a debuginfod URL is malformed. girl, fix your args. ✨
  • EIO β€” couldn't write the data received from the server to the local file. πŸ’Ύ
  • EMLINK β€” too many HTTP redirects. she kept passing the aux, we never got anywhere. πŸ”
  • ENETUNREACH β€” couldn't initialize the network connection. 🌐
  • ENOENT β€” couldn't find the resource located at the URL. lowkey the most common one, and often it means a debuginfod server was successfully contacted but the server just couldn't find the target file. so close yet so far bestie. 🫢
  • ENOMEM β€” the system can't allocate resources. memory said "I'm full." 🍽️
  • ENOSYS β€” $DEBUGINFOD_URLS is not defined. she's not configured, she's not showing up, periodt.
  • ETIME β€” the query failed due to timeout. $DEBUGINFOD_TIMEOUT and $DEBUGINFOD_MAXTIME are the ones controlling this. ⏰
  • EF2BIG β€” the query got aborted because the file requested was too big. $DEBUGINFOD_MAXSIZE controls this one. 🐘
  • EBADMSG β€” the file content failed IMA verification against a known signer certificate. πŸ“œ
  • ENOKEY β€” the file content failed IMA verification because the signer certificate is missing. πŸ”‘
  • ENODATA β€” the file content failed IMA verification because of a missing signature. ✍️
heads up: everything below is generic info. Some debuginfod clients may internally override the defaults listed here. iykyk. πŸ’…

🌈 ENVIRONMENT VARIABLES 🌈

  • $TMPDIR β€” points to a file system to be used for temporary files. the default is /tmp. πŸ—‚οΈ
  • $DEBUGINFOD_URLS β€” this one is a whole moment, okay. It contains a list of URL prefixes for trusted debuginfod instances, and alternate URL prefixes are separated by space. This environment variable may be set by /etc/profile.d scripts reading /etc/debuginfod/*.urls files.

She can also contain policy-defining tags which dictate the response policy for verifying per-file IMA signatures in RPMs. Since the space-separated list is read left to right, when you hit a tag, every subsequent URL up to the next tag gets handled using that specified policy. All URLs before the first tag use the default policy, ima:ignore. for example:

DEBUGINFOD_URLS="https://foo.com ima:enforcing https://bar.ca http://localhost:8002/ ima:ignore https://baz.org"

So in that little lineup, foo.com and baz.org use the default ignore policy, while bar.ca and localhost use an enforcing policy. The policy tag may be one of the following:

  • ima:enforcing β€” every downloaded file requires a valid signature, fully protecting integrity. she does not play about security. πŸ”’
  • ima:ignore β€” skips verification altogether, providing no protection. living dangerously, no notes. πŸ™ˆ

Alerts of validation failure will be directed as specified in $DEBUGINFOD_VERBOSE.

  • $DEBUGINFOD_CACHE_PATH β€” governs the location of the cache where downloaded files and cache-control files are kept. The default directory is chosen based on other environment variables, see below. πŸ‘€
  • $DEBUGINFOD_PROGRESS β€” governs the default progress function. If set, and if a progressfn is not explicitly set, then the library will configure a default progressfn. This function will append a simple progress message periodically to stderr. The default is no progress function output. πŸ“Š
  • $DEBUGINFOD_VERBOSE β€” governs the default file descriptor for verbose output. If set, and if a verbose fd is not explicitly set, then the verbose output will be produced on STDERR_FILENO. πŸ—£οΈ
  • $DEBUGINFOD_RETRY_LIMIT β€” governs the default limit of retry attempts. If a query failed with an errno other than ENOENT, will initiate several attempts within the limit. πŸ”
  • $DEBUGINFOD_TIMEOUT β€” governs the download commencing timeout, in seconds, for each debuginfod HTTP connection. A server is skipped if it either fails to establish a connection within the timeout or fails to provide at least 100K of data within the timeout. The default is 90 seconds. (Zero or negative means "no timeout".) ⏳
  • $DEBUGINFOD_MAXTIME β€” dictates how long the client will wait to complete the download of a file found on a server, in seconds. It is best used to ensure that a file is downloaded quickly or be rejected. The default is 0 (infinite time). πŸ•°οΈ
  • $DEBUGINFOD_MAXSIZE β€” dictates the maximum size of a file to download, in bytes. This is best used if the user would like to ensure only small files are downloaded. A value of 0 causes no consideration for size, and the client may attempt to download a file of any size. The default is 0 (infinite size). 🐜
  • $DEBUGINFOD_HEADERS_FILE β€” points to a file that supplies headers to outbound HTTP requests, one per line. The header lines shouldn't end with CRLF, unless that's the system newline convention. Whitespace-only lines are skipped. πŸ“¨
  • $DEBUGINFOD_IMA_CERT_PATH β€” contains a list of absolute directory paths holding X.509 certificates for RPM per-file IMA-verification. Alternate paths are separated by colons. πŸŽ€

πŸŽ€ CACHE πŸŽ€

Before each query, the debuginfod client library checks whether there's a need to clean the cache. If it's time to clean, the library traverses the cache directory and removes downloaded debuginfo-related artifacts and newly empty directories β€” but only if they have not been accessed recently. spring cleaning but make it automated. 🧹

Control files live directly under the cache directory. They contain simple decimal numbers that set cache-related configuration parameters. If the files do not exist, the client library creates the files with the default parameter values as content. πŸ’…

After each query, the debuginfod client library deposits newly received files into a directory & file that is named based on the build-id. A failed query is also cached by a special file. The naming convention used for these artifacts is deliberately undocumented. mysterious. iconic. do not ask. 🀫

  • $XDG_CACHE_HOME/debuginfod_client/ β€” default cache directory, if $XDG_CACHE_HOME is set. ✨
  • $HOME/.cache/debuginfod_client/ β€” default cache directory, if $XDG_CACHE_HOME is not set. πŸ’–
  • $HOME/.debuginfod_client_cache/ β€” deprecated cache directory, used only if preexisting. she's retired but still around. πŸͺ¦

and now the control files, bestie:

  • cache_clean_interval_s β€” gives the interval between cache cleaning rounds, in seconds. The default is 86400, one day. 0 means "immediately". 🧽
  • max_unused_age_s β€” sets how long unaccessed debuginfo-related files are retained, in seconds. The default is 604800, one week. 0 means "immediately". πŸ“…
  • cache_miss_s β€” sets how long to remember a query failure, in seconds. New queries for the same artifacts within this time window are short-circuited (returning an immediate failure instead of sending a new query to servers). This accelerates queries that probably would still fail. The default is 600, 10 minutes. 0 means "forget immediately". πŸ’­
  • metadata_retention_s β€” sets how long to remember the results of a metadata query. New queries for the same artifacts within this time window are short-circuited (repeating the same results). This accelerates queries that would probably have the same results. The default is 3600, 1 hour. 0 means "do not retain". πŸ“

πŸ‘€ SEE ALSO πŸ‘€

  • debuginfod(8) β€” go read her too, she's the whole ecosystem bestie 🫢

and that's the whole page, periodt. the footer at the very bottom just signs off with the page's own name, DEBUGINFOD_FIND_*(3) β€” she really said "I am the moment." πŸ’…βœ¨ go forth and debug, you ate. πŸ¦‹

πŸ“¦ where this page comes from