glibc/manual/dynlink.texi
Florian Weimer f8d8b1b1e6 aarch64: Enhanced CPU diagnostics for ld.so
This prints some information from struct cpu_features, and the midr_el1
and dczid_el0 system register contents on every CPU.

Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
2024-04-08 16:48:55 +02:00

548 lines
22 KiB
Plaintext

@node Dynamic Linker
@c @node Dynamic Linker, Internal Probes, Threads, Top
@c %MENU% Loading programs and shared objects.
@chapter Dynamic Linker
@cindex dynamic linker
@cindex dynamic loader
The @dfn{dynamic linker} is responsible for loading dynamically linked
programs and their dependencies (in the form of shared objects). The
dynamic linker in @theglibc{} also supports loading shared objects (such
as plugins) later at run time.
Dynamic linkers are sometimes called @dfn{dynamic loaders}.
@menu
* Dynamic Linker Invocation:: Explicit invocation of the dynamic linker.
* Dynamic Linker Introspection:: Interfaces for querying mapping information.
@end menu
@node Dynamic Linker Invocation
@section Dynamic Linker Invocation
@cindex program interpreter
When a dynamically linked program starts, the operating system
automatically loads the dynamic linker along with the program.
@Theglibc{} also supports invoking the dynamic linker explicitly to
launch a program. This command uses the implied dynamic linker
(also sometimes called the @dfn{program interpreter}):
@smallexample
sh -c 'echo "Hello, world!"'
@end smallexample
This command specifies the dynamic linker explicitly:
@smallexample
ld.so /bin/sh -c 'echo "Hello, world!"'
@end smallexample
Note that @command{ld.so} does not search the @env{PATH} environment
variable, so the full file name of the executable needs to be specified.
The @command{ld.so} program supports various options. Options start
@samp{--} and need to come before the program that is being launched.
Some of the supported options are listed below.
@table @code
@item --list-diagnostics
Print system diagnostic information in a machine-readable format.
@xref{Dynamic Linker Diagnostics}.
@end table
@menu
* Dynamic Linker Diagnostics:: Obtaining system diagnostic information.
@end menu
@node Dynamic Linker Diagnostics
@subsection Dynamic Linker Diagnostics
@cindex diagnostics (dynamic linker)
The @samp{ld.so --list-diagnostics} produces machine-readable
diagnostics output. This output contains system data that affects the
behavior of @theglibc{}, and potentially application behavior as well.
The exact set of diagnostic items can change between releases of
@theglibc{}. The output format itself is not expected to change
radically.
The following table shows some example lines that can be written by the
diagnostics command.
@table @code
@item dl_pagesize=0x1000
The system page size is 4096 bytes.
@item env[0x14]="LANG=en_US.UTF-8"
This item indicates that the 21st environment variable at process
startup contains a setting for @code{LANG}.
@item env_filtered[0x22]="DISPLAY"
The 35th environment variable is @code{DISPLAY}. Its value is not
included in the output for privacy reasons because it is not recognized
as harmless by the diagnostics code.
@item path.prefix="/usr"
This means that @theglibc{} was configured with @code{--prefix=/usr}.
@item path.system_dirs[0x0]="/lib64/"
@itemx path.system_dirs[0x1]="/usr/lib64/"
The built-in dynamic linker search path contains two directories,
@code{/lib64} and @code{/usr/lib64}.
@end table
@menu
* Dynamic Linker Diagnostics Format:: Format of ld.so output.
* Dynamic Linker Diagnostics Values:: Data contain in ld.so output.
@end menu
@node Dynamic Linker Diagnostics Format
@subsubsection Dynamic Linker Diagnostics Format
As seen above, diagnostic lines assign values (integers or strings) to a
sequence of labeled subscripts, separated by @samp{.}. Some subscripts
have integer indices associated with them. The subscript indices are
not necessarily contiguous or small, so an associative array should be
used to store them. Currently, all integers fit into the 64-bit
unsigned integer range. Every access path to a value has a fixed type
(string or integer) independent of subscript index values. Likewise,
whether a subscript is indexed does not depend on previous indices (but
may depend on previous subscript labels).
A syntax description in ABNF (RFC 5234) follows. Note that
@code{%x30-39} denotes the range of decimal digits. Diagnostic output
lines are expected to match the @code{line} production.
@c ABNF-START
@smallexample
HEXDIG = %x30-39 / %x61-6f ; lowercase a-f only
ALPHA = %x41-5a / %x61-7a / %x7f ; letters and underscore
ALPHA-NUMERIC = ALPHA / %x30-39 / "_"
DQUOTE = %x22 ; "
; Numbers are always hexadecimal and use a 0x prefix.
hex-value-prefix = %x30 %x78
hex-value = hex-value-prefix 1*HEXDIG
; Strings use octal escape sequences and \\, \".
string-char = %x20-21 / %x23-5c / %x5d-7e ; printable but not "\
string-quoted-octal = %x30-33 2*2%x30-37
string-quoted = "\" ("\" / DQUOTE / string-quoted-octal)
string-value = DQUOTE *(string-char / string-quoted) DQUOTE
value = hex-value / string-value
label = ALPHA *ALPHA-NUMERIC
index = "[" hex-value "]"
subscript = label [index]
line = subscript *("." subscript) "=" value
@end smallexample
@node Dynamic Linker Diagnostics Values
@subsubsection Dynamic Linker Diagnostics Values
As mentioned above, the set of diagnostics may change between
@theglibc{} releases. Nevertheless, the following table documents a few
common diagnostic items. All numbers are in hexadecimal, with a
@samp{0x} prefix.
@table @code
@item dl_dst_lib=@var{string}
The @code{$LIB} dynamic string token expands to @var{string}.
@cindex HWCAP (diagnostics)
@item dl_hwcap=@var{integer}
@itemx dl_hwcap2=@var{integer}
The HWCAP and HWCAP2 values, as returned for @code{getauxval}, and as
used in other places depending on the architecture.
@cindex page size (diagnostics)
@item dl_pagesize=@var{integer}
The system page size is @var{integer} bytes.
@item dl_platform=@var{string}
The @code{$PLATFORM} dynamic string token expands to @var{string}.
@item dso.libc=@var{string}
This is the soname of the shared @code{libc} object that is part of
@theglibc{}. On most architectures, this is @code{libc.so.6}.
@item env[@var{index}]=@var{string}
@itemx env_filtered[@var{index}]=@var{string}
An environment variable from the process environment. The integer
@var{index} is the array index in the environment array. Variables
under @code{env} include the variable value after the @samp{=} (assuming
that it was present), variables under @code{env_filtered} do not.
@item path.prefix=@var{string}
This indicates that @theglibc{} was configured using
@samp{--prefix=@var{string}}.
@item path.sysconfdir=@var{string}
@Theglibc{} was configured (perhaps implicitly) with
@samp{--sysconfdir=@var{string}} (typically @code{/etc}).
@item path.system_dirs[@var{index}]=@var{string}
These items list the elements of the built-in array that describes the
default library search path. The value @var{string} is a directory file
name with a trailing @samp{/}.
@item path.rtld=@var{string}
This string indicates the application binary interface (ABI) file name
of the run-time dynamic linker.
@item version.release="stable"
@itemx version.release="development"
The value @code{"stable"} indicates that this build of @theglibc{} is
from a release branch. Releases labeled as @code{"development"} are
unreleased development versions.
@cindex version (diagnostics)
@item version.version="@var{major}.@var{minor}"
@itemx version.version="@var{major}.@var{minor}.9000"
@Theglibc{} version. Development releases end in @samp{.9000}.
@cindex auxiliary vector (diagnostics)
@item auxv[@var{index}].a_type=@var{type}
@itemx auxv[@var{index}].a_val=@var{integer}
@itemx auxv[@var{index}].a_val_string=@var{string}
An entry in the auxiliary vector (specific to Linux). The values
@var{type} (an integer) and @var{integer} correspond to the members of
@code{struct auxv}. If the value is a string, @code{a_val_string} is
used instead of @code{a_val}, so that values have consistent types.
The @code{AT_HWCAP} and @code{AT_HWCAP2} values in this output do not
reflect adjustment by @theglibc{}.
@item uname.sysname=@var{string}
@itemx uname.nodename=@var{string}
@itemx uname.release=@var{string}
@itemx uname.version=@var{string}
@itemx uname.machine=@var{string}
@itemx uname.domain=@var{string}
These Linux-specific items show the values of @code{struct utsname}, as
reported by the @code{uname} function. @xref{Platform Type}.
@item aarch64.cpu_features.@dots{}
These items are specific to the AArch64 architectures. They report data
@theglibc{} uses to activate conditionally supported features such as
BTI and MTE, and to select alternative function implementations.
@item aarch64.processor[@var{index}].@dots{}
These are additional items for the AArch64 architecture and are
described below.
@item aarch64.processor[@var{index}].requested=@var{kernel-cpu}
The kernel is told to run the subsequent probing on the CPU numbered
@var{kernel-cpu}. The values @var{kernel-cpu} and @var{index} can be
distinct if there are gaps in the process CPU affinity mask. This line
is not included if CPU affinity mask information is not available.
@item aarch64.processor[@var{index}].observed=@var{kernel-cpu}
This line reports the kernel CPU number @var{kernel-cpu} on which the
probing code initially ran. If the CPU number cannot be obtained,
this line is not printed.
@item aarch64.processor[@var{index}].observed_node=@var{node}
This reports the observed NUMA node number, as reported by the
@code{getcpu} system call. If this information cannot be obtained, this
line is not printed.
@item aarch64.processor[@var{index}].midr_el1=@var{value}
The value of the @code{midr_el1} system register on the processor
@var{index}. This line is only printed if the kernel indicates that
this system register is supported.
@item aarch64.processor[@var{index}].dczid_el0=@var{value}
The value of the @code{dczid_el0} system register on the processor
@var{index}.
@cindex CPUID (diagnostics)
@item x86.cpu_features.@dots{}
These items are specific to the i386 and x86-64 architectures. They
reflect supported CPU features and information on cache geometry, mostly
collected using the CPUID instruction.
@item x86.processor[@var{index}].@dots{}
These are additional items for the i386 and x86-64 architectures, as
described below. They mostly contain raw data from the CPUID
instruction. The probes are performed for each active CPU for the
@code{ld.so} process, and data for different probed CPUs receives a
uniqe @var{index} value. Some CPUID data is expected to differ from CPU
core to CPU core. In some cases, CPUs are not correctly initialized and
indicate the presence of different feature sets.
@item x86.processor[@var{index}].requested=@var{kernel-cpu}
The kernel is told to run the subsequent probing on the CPU numbered
@var{kernel-cpu}. The values @var{kernel-cpu} and @var{index} can be
distinct if there are gaps in the process CPU affinity mask. This line
is not included if CPU affinity mask information is not available.
@item x86.processor[@var{index}].observed=@var{kernel-cpu}
This line reports the kernel CPU number @var{kernel-cpu} on which the
probing code initially ran. If the CPU number cannot be obtained,
this line is not printed.
@item x86.processor[@var{index}].observed_node=@var{node}
This reports the observed NUMA node number, as reported by the
@code{getcpu} system call. If this information cannot be obtained, this
line is not printed.
@item x86.processor[@var{index}].cpuid_leaves=@var{count}
This line indicates that @var{count} distinct CPUID leaves were
encountered. (This reflects internal @code{ld.so} storage space, it
does not directly correspond to @code{CPUID} enumeration ranges.)
@item x86.processor[@var{index}].ecx_limit=@var{value}
The CPUID data extraction code uses a brute-force approach to enumerate
subleaves (see the @samp{.subleaf_eax} lines below). The last
@code{%rcx} value used in a CPUID query on this probed CPU was
@var{value}.
@item x86.processor[@var{index}].cpuid.eax[@var{query_eax}].eax=@var{eax}
@itemx x86.processor[@var{index}].cpuid.eax[@var{query_eax}].ebx=@var{ebx}
@itemx x86.processor[@var{index}].cpuid.eax[@var{query_eax}].ecx=@var{ecx}
@itemx x86.processor[@var{index}].cpuid.eax[@var{query_eax}].edx=@var{edx}
These lines report the register contents after executing the CPUID
instruction with @samp{%rax == @var{query_eax}} and @samp{%rcx == 0} (a
@dfn{leaf}). For the first probed CPU (with a zero @var{index}), only
leaves with non-zero register contents are reported. For subsequent
CPUs, only leaves whose register contents differs from the previously
probed CPUs (with @var{index} one less) are reported.
Basic and extended leaves are reported using the same syntax. This
means there is a large jump in @var{query_eax} for the first reported
extended leaf.
@item x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].eax=@var{eax}
@itemx x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].ebx=@var{ebx}
@itemx x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].ecx=@var{ecx}
@itemx x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].edx=@var{edx}
This is similar to the leaves above, but for a @dfn{subleaf}. For
subleaves, the CPUID instruction is executed with @samp{%rax ==
@var{query_eax}} and @samp{%rcx == @var{query_ecx}}, so the result
depends on both register values. The same rules about filtering zero
and identical results apply.
@item x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].until_ecx=@var{ecx_limit}
Some CPUID results are the same regardless the @var{query_ecx} value.
If this situation is detected, a line with the @samp{.until_ecx}
selector ins included, and this indicates that the CPUID register
contents is the same for @code{%rcx} values between @var{query_ecx}
and @var{ecx_limit} (inclusive).
@item x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].ecx_query_mask=0xff
This line indicates that in an @samp{.until_ecx} range, the CPUID
instruction preserved the lowested 8 bits of the input @code{%rcx} in
the output @code{%rcx} registers. Otherwise, the subleaves in the range
have identical values. This special treatment is necessary to report
compact range information in case such copying occurs (because the
subleaves would otherwise be all different).
@item x86.processor[@var{index}].xgetbv.ecx[@var{query_ecx}]=@var{result}
This line shows the 64-bit @var{result} value in the @code{%rdx:%rax}
register pair after executing the XGETBV instruction with @code{%rcx}
set to @var{query_ecx}. Zero values and values matching the previously
probed CPU are omitted. Nothing is printed if the system does not
support the XGETBV instruction.
@end table
@node Dynamic Linker Introspection
@section Dynamic Linker Introspection
@Theglibc{} provides various functions for querying information from the
dynamic linker.
@deftypefun {int} dlinfo (void *@var{handle}, int @var{request}, void *@var{arg})
@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
@standards{GNU, dlfcn.h}
This function returns information about @var{handle} in the memory
location @var{arg}, based on @var{request}. The @var{handle} argument
must be a pointer returned by @code{dlopen} or @code{dlmopen}; it must
not have been closed by @code{dlclose}.
On success, @code{dlinfo} returns 0 for most request types; exceptions
are noted below. If there is an error, the function returns @math{-1},
and @code{dlerror} can be used to obtain a corresponding error message.
The following operations are defined for use with @var{request}:
@vtable @code
@item RTLD_DI_LINKMAP
The corresponding @code{struct link_map} pointer for @var{handle} is
written to @code{*@var{arg}}. The @var{arg} argument must be the
address of an object of type @code{struct link_map *}.
@item RTLD_DI_LMID
The namespace identifier of @var{handle} is written to
@code{*@var{arg}}. The @var{arg} argument must be the address of an
object of type @code{Lmid_t}.
@item RTLD_DI_ORIGIN
The value of the @code{$ORIGIN} dynamic string token for @var{handle} is
written to the character array starting at @var{arg} as a
null-terminated string.
This request type should not be used because it is prone to buffer
overflows.
@item RTLD_DI_SERINFO
@itemx RTLD_DI_SERINFOSIZE
These requests can be used to obtain search path information for
@var{handle}. For both requests, @var{arg} must point to a
@code{Dl_serinfo} object. The @code{RTLD_DI_SERINFOSIZE} request must
be made first; it updates the @code{dls_size} and @code{dls_cnt} members
of the @code{Dl_serinfo} object. The caller should then allocate memory
to store at least @code{dls_size} bytes and pass that buffer to a
@code{RTLD_DI_SERINFO} request. This second request fills the
@code{dls_serpath} array. The number of array elements was returned in
the @code{dls_cnt} member in the initial @code{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
@code{RTLD_DI_SERINFOSIZE} and @code{RTLD_DI_SERINFO} requests.
@item RTLD_DI_TLS_DATA
This request writes the address of the TLS block (in the current thread)
for the shared object identified by @var{handle} to @code{*@var{arg}}.
The argument @var{arg} must be the address of an object of type
@code{void *}. A null pointer is written if the object does not have
any associated TLS block.
@item RTLD_DI_TLS_MODID
This request writes the TLS module ID for the shared object @var{handle}
to @code{*@var{arg}}. The argument @var{arg} must be the address of an
object of type @code{size_t}. The module ID is zero if the object
does not have an associated TLS block.
@item RTLD_DI_PHDR
This request writes the address of the program header array to
@code{*@var{arg}}. The argument @var{arg} must be the address of an
object of type @code{const ElfW(Phdr) *} (that is,
@code{const Elf32_Phdr *} or @code{const Elf64_Phdr *}, as appropriate
for the current architecture). For this request, the value returned by
@code{dlinfo} is the number of program headers in the program header
array.
@end vtable
The @code{dlinfo} function is a GNU extension.
@end deftypefun
The remainder of this section documents the @code{_dl_find_object}
function and supporting types and constants.
@deftp {Data Type} {struct dl_find_object}
@standards{GNU, dlfcn.h}
This structure contains information about a main program or loaded
object. The @code{_dl_find_object} function uses it to return
result data to the caller.
@table @code
@item unsigned long long int dlfo_flags
Currently unused and always 0.
@item 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.
@item void *dlfo_map_end
The end address of the mapping.
@item struct link_map *dlfo_link_map
This member contains a pointer to the link map of the object.
@item void *dlfo_eh_frame
This member contains a pointer to the exception handling data of the
object. See @code{DLFO_EH_SEGMENT_TYPE} below.
@end table
This structure is a GNU extension.
@end deftp
@deftypevr Macro int DLFO_STRUCT_HAS_EH_DBASE
@standards{GNU, dlfcn.h}
On most targets, this macro is defined as @code{0}. If it is defined to
@code{1}, @code{struct dl_find_object} contains an additional member
@code{dlfo_eh_dbase} of type @code{void *}. It is the base address for
@code{DW_EH_PE_datarel} DWARF encodings to this location.
This macro is a GNU extension.
@end deftypevr
@deftypevr Macro int DLFO_STRUCT_HAS_EH_COUNT
@standards{GNU, dlfcn.h}
On most targets, this macro is defined as @code{0}. If it is defined to
@code{1}, @code{struct dl_find_object} contains an additional member
@code{dlfo_eh_count} of type @code{int}. It is the number of exception
handling entries in the EH frame segment identified by the
@code{dlfo_eh_frame} member.
This macro is a GNU extension.
@end deftypevr
@deftypevr Macro int DLFO_EH_SEGMENT_TYPE
@standards{GNU, dlfcn.h}
On targets using DWARF-based exception unwinding, this macro expands to
@code{PT_GNU_EH_FRAME}. This indicates that @code{dlfo_eh_frame} in
@code{struct dl_find_object} points to the @code{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.
@end deftypevr
@deftypefun {int} _dl_find_object (void *@var{address}, struct dl_find_object *@var{result})
@standards{GNU, dlfcn.h}
@safety{@mtsafe{}@assafe{}@acsafe{}}
On success, this function returns 0 and writes about the object
surrounding the address to @code{*@var{result}}. On failure, -1 is
returned.
The @var{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, @code{_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 @var{address} is greater than or equal to
@code{@var{result}->dlfo_map_start} and less than
@code{@var{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 @var{address} in
@code{@var{result}->dlfo_eh_frame}. If the platform uses DWARF
unwinding information, this is the in-memory address of the
@code{PT_GNU_EH_FRAME} segment. See @code{DLFO_EH_SEGMENT_TYPE} above.
In case @var{address} resides in an object that lacks unwinding information,
the function still returns 0, but sets @code{@var{result}->dlfo_eh_frame}
to a null pointer.
@code{_dl_find_object} itself is thread-safe. However, if the
application invokes @code{dlclose} for the object that contains
@var{address} concurrently with @code{_dl_find_object} or after the call
returns, accessing the unwinding data for that object or the link map
(through @code{@var{result}->dlfo_link_map}) is not safe. Therefore, the
application needs to ensure by other means (e.g., by convention) that
@var{address} remains a valid code address while the unwinding
information is processed.
This function is a GNU extension.
@end deftypefun
@c FIXME these are undocumented:
@c dladdr
@c dladdr1
@c dlclose
@c dlerror
@c dlmopen
@c dlopen
@c dlsym
@c dlvsym