Dynamic Linker Introspection (The GNU C Library)

### 37.3 Dynamic Linker Introspection ¶

The GNU C Library provides various facilities for querying information from the dynamic linker.

Data Type: struct link_map ¶

  A link map is associated with the main executable and each shared object. Some fields of the link map are accessible to applications and exposed through the `struct link_map`. Applications must not modify the link map directly.

  Pointers to link maps can be obtained from the `_r_debug` variable, from the `RTLD_DI_LINKMAP` request for `dlinfo`, and from the `_dl_find_object` function. See below for details.

  `l_addr` ¶

    This field contains the load address of the object. This is the offset that needs to be applied to unrelocated addresses in the object image (as stored on disk) to form an address that can be used at run time for accessing data or running code. For position-dependent executables, the load address is typically zero, and no adjustment is required. For position-independent objects, the `l_addr` field usually contains the address of the object’s ELF header in the process image. However, this correspondence is not guaranteed because the ELF header might not be mapped at all, and the ELF file as stored on disk might use zero as the lowest virtual address. Due to the second variable, values of the `l_addr` field do not necessarily uniquely identify a shared object.

    On Linux, to obtain the lowest loaded address of the main program, use `getauxval` to obtain the `AT_PHDR` and `AT_PHNUM` values for the current process. Alternatively, call ‘`dlinfo (_r_debug.r_map, &phdr)`’ to obtain the number of program headers, and the address of the program header array will be stored in phdr (of type `const ElfW(Phdr) *`, as explained below). These values allow processing the array of program headers and the address information in the `PT_LOAD` entries among them. This works even when the program was started with an explicit loader invocation.

  `l_name`

    For a shared object, this field contains the file name that the the GNU C Library dynamic loader used when opening the object. This can be a relative path (relative to the current directory at process start, or if the object was loaded later, via `dlopen` or `dlmopen`). Symbolic links are not necessarily resolved.

    For the main executable, `l_name` is ‘`""`’ (the empty string). (The main executable is not loaded by the GNU C Library, so its file name is not available.) On Linux, the main executable is available as `/proc/self/exe` (unless an explicit loader invocation was used to start the program). The file name `/proc/self/exe` continues to resolve to the same file even if it is moved within or deleted from the file system. Its current location can be read using `readlink`. See Symbolic Links. (Although `/proc/self/exe` is not actually a symbol link, it is only presented as one.) Note that `/proc` may not be mounted, in which case `/proc/self/exe` is not available.

    If an explicit loader invocation is used (such as ‘`ld.so /usr/bin/emacs`’), the `/proc/self/exe` approach does not work because the file name refers to the dynamic linker `ld.so`, and not the `/usr/bin/emacs` program. An approximation to the executable path is still available in the `info.dli_fname` member after calling ‘`dladdr (_r_debug.r_map->l_ld, &info)`’. Note that this could be a relative path, and it is supplied by the process that created the current process, not the kernel, so it could be inaccurate.

  `l_ld`

    This is a pointer to the ELF dynamic segment, an array of tag/value pairs that provide various pieces of information that the dynamic linking process uses. On most architectures, addresses in the dynamic segment are relocated at run time, but on some architectures and in some run-time configurations, it is necessary to add the `l_addr` field value to obtain a proper address.

  `l_prev`
  `l_next`

    These fields are used to maintain a double-linked linked list of all link maps within one `dlmopen` namespace. Note that there is currently no thread-safe way to iterate over this list. The callback-based `dl_iterate_phdr` interface can be used instead.

Portability note: It is not possible to create a `struct link_map` object and pass a pointer to a function that expects a `struct link_map *` argument. Only link map pointers initially supplied by the GNU C Library are permitted as arguments. In current versions of the GNU C Library, handles returned by `dlopen` and `dlmopen` are pointers to link maps. However, this is not a portable assumption, and may even change in future versions of the GNU C Library. To obtain the link map associated with a handle, see `dlinfo` and `RTLD_DI_LINKMAP` below. If a function accepts both `dlopen`/`dlmopen` handles and `struct link_map` pointers in its `void *` argument, that is documented explicitly.

#### 37.3.1 Querying information for loaded objects ¶

The `dlinfo` function provides access to internal information associated with `dlopen`/`dlmopen` handles and link maps.

Function: `int` dlinfo `(void *handle, int request, void *arg)` ¶

  | MT-Safe | AS-Unsafe corrupt | AC-Unsafe corrupt | See POSIX Safety Concepts.

  This function returns information about handle in the memory location arg, based on request. The handle argument must be a pointer returned by `dlopen` or `dlmopen`; it must not have been closed by `dlclose`. Alternatively, handle can be a `struct link_map *` value for a link map of an object that has not been closed.

  On success, `dlinfo` returns 0 for most request types; exceptions are noted below. If there is an error, the function returns -1, and `dlerror` can be used to obtain a corresponding error message.

  The following operations are defined for use with request:

  `RTLD_DI_LINKMAP` ¶

    The corresponding `struct link_map` pointer for handle is written to `*arg`. The arg argument must be the address of an object of type `struct link_map *`.

  `RTLD_DI_LMID` ¶

    The namespace identifier of handle is written to `*arg`. The arg argument must be the address of an object of type `Lmid_t`.

  `RTLD_DI_ORIGIN_PATH` ¶

    The `$ORIGIN` dynamic string token pointer for handle is written to `*arg`. The arg argument must be the address of a `const char *`. If the `$ORIGIN` could not be determined, the function still returns 0 but writes a null pointer to `*arg`. The returned string is only valid as long as the corresponding handle is valid. Accessing it after `dlclose` has been called for the corresponding handle is undefined behavior.

  `RTLD_DI_ORIGIN` ¶

    The value of the `$ORIGIN` dynamic string token for handle is written to the character array starting at arg as a null-terminated string.

    This request type should not be used because it is prone to buffer overflows. Instead, `RTLD_DI_ORIGIN_PATH` described above should be used.

  `RTLD_DI_SERINFO` ¶
  `RTLD_DI_SERINFOSIZE` ¶

    These requests can be used to obtain search path information for handle. For both requests, arg must point to a `Dl_serinfo` object. The `RTLD_DI_SERINFOSIZE` request must be made first; it updates the `dls_size` and `dls_cnt` members of the `Dl_serinfo` object. The caller should then allocate memory to store at least `dls_size` bytes and pass that buffer to a `RTLD_DI_SERINFO` request. This second request fills the `dls_serpath` array. The number of array elements was returned in the `dls_cnt` member in the initial `RTLD_DI_SERINFOSIZE` request. The caller is responsible for freeing the allocated buffer.

    This interface is prone to buffer overflows in multi-threaded processes because the required size can change between the `RTLD_DI_SERINFOSIZE` and `RTLD_DI_SERINFO` requests.

  `RTLD_DI_TLS_DATA` ¶

    This request writes the address of the TLS block (in the current thread) for the shared object identified by handle to `*arg`. The argument arg must be the address of an object of type `void *`. A null pointer is written if the object does not have any associated TLS block.

  `RTLD_DI_TLS_MODID` ¶

    This request writes the TLS module ID for the shared object handle to `*arg`. The argument arg must be the address of an object of type `size_t`. The module ID is zero if the object does not have an associated TLS block.

  `RTLD_DI_PHDR` ¶

    This request writes the address of the program header array to `*arg`. The argument arg must be the address of an object of type `const ElfW(Phdr) *` (that is, `const Elf32_Phdr *` or `const Elf64_Phdr *`, as appropriate for the current architecture). For this request, the value returned by `dlinfo` is the number of program headers in the program header array.

  The `dlinfo` function is a GNU extension.

The remainder of this section documents the `_dl_find_object` function and supporting types and constants.

Data Type: struct dl_find_object ¶

  This structure contains information about a main program or loaded object. The `_dl_find_object` function uses it to return result data to the caller.

  `unsigned long long int dlfo_flags`

    Bit zero signals if SFrame stack data is valid. See `DLFO_FLAG_SFRAME` below.

  `void *dlfo_map_start`

    The start address of the inspected mapping. This information comes from the program header, so it follows its convention, and the address is not necessarily page-aligned.

  `void *dlfo_map_end`

    The end address of the mapping.

  `struct link_map *dlfo_link_map`

    This member contains a pointer to the link map of the object.

  `void *dlfo_eh_frame`

    This member contains a pointer to the exception handling data of the object. See `DLFO_EH_SEGMENT_TYPE` below.

  `void *dlfo_sframe`

    This member points to the SFrame stack trace data associated with the object. It is valid only when `DLFO_FLAG_SFRAME` is set in `dlfo_flags`; otherwise, it may be null or undefined.

  This structure is a GNU extension.

Macro: `int` DLFO_STRUCT_HAS_EH_DBASE ¶

  On most targets, this macro is defined as `0`. If it is defined to `1`, `struct dl_find_object` contains an additional member `dlfo_eh_dbase` of type `void *`. It is the base address for `DW_EH_PE_datarel` DWARF encodings to this location.

  This macro is a GNU extension.

Macro: `int` DLFO_STRUCT_HAS_EH_COUNT ¶

  On most targets, this macro is defined as `0`. If it is defined to `1`, `struct dl_find_object` contains an additional member `dlfo_eh_count` of type `int`. It is the number of exception handling entries in the EH frame segment identified by the `dlfo_eh_frame` member.

  This macro is a GNU extension.

Macro: `int` DLFO_EH_SEGMENT_TYPE ¶

  On targets using DWARF-based exception unwinding, this macro expands to `PT_GNU_EH_FRAME`. This indicates that `dlfo_eh_frame` in `struct dl_find_object` points to the `PT_GNU_EH_FRAME` segment of the object. On targets that use other unwinding formats, the macro expands to the program header type for the unwinding data.

  This macro is a GNU extension.

Function: `int` _dl_find_object `(void *address, struct dl_find_object *result)` ¶

  | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

  On success, this function returns 0 and writes about the object surrounding the address to `*result`. On failure, -1 is returned.

  The address can be a code address or data address. On architectures using function descriptors, no attempt is made to decode the function descriptor. Depending on how these descriptors are implemented, `_dl_find_object` may return the object that defines the function descriptor (and not the object that contains the code implementing the function), or fail to find any object at all.

  On success address is greater than or equal to `result->dlfo_map_start` and less than `result->dlfo_map_end`, that is, the supplied code address is located within the reported mapping.

  This function returns a pointer to the unwinding information for the object that contains the program code address in `result->dlfo_eh_frame`. If the platform uses DWARF unwinding information, this is the in-memory address of the `PT_GNU_EH_FRAME` segment. See `DLFO_EH_SEGMENT_TYPE` above. In case address resides in an object that lacks unwinding information, the function still returns 0, but sets `result->dlfo_eh_frame` to a null pointer.

  `_dl_find_object` itself is thread-safe. However, if the application invokes `dlclose` for the object that contains address concurrently with `_dl_find_object` or after the call returns, accessing the unwinding data for that object or the link map (through `result->dlfo_link_map`) is not safe. Therefore, the application needs to ensure by other means (e.g., by convention) that address remains a valid code address while the unwinding information is processed.

  This function is a GNU extension.

The following flag masks are defined for use with `dlfo_flags`:

`DLFO_FLAG_SFRAME`

  A bit mask used to signal that the object contains SFrame data. See `dlfo_sframe` above.