Check out my first novel, midnight's simulacra!
Libc: Difference between revisions
No edit summary |
|||
(3 intermediate revisions by the same user not shown) | |||
Line 35: | Line 35: | ||
same name contained in libraries that have already been loaded. | same name contained in libraries that have already been loaded. | ||
This flag is not specified in POSIX.1-2001.</pre> | This flag is not specified in POSIX.1-2001.</pre> | ||
==Generating a stack trace== | |||
The <tt>backtrace</tt>, <tt>backtrace_symbols</tt> and <tt>backtrace_symbols_fd</tt> glibc calls can be used to generate a stack trace from within a program. | |||
* <tt>backtrace</tt> generates a list of addresses | |||
* <tt>backtrace_symbols</tt>, given the output of <tt>backtrace</tt>, will populate its argv-style return value with any symbols it can look up | |||
In order to extract symbols, appropriate binaries must: | |||
* not be stripped (or linked with -s), | |||
* be linked with -rdynamic/--export-dynamic, and | |||
* provide frame pointers (none for inlined code, omitted with most [[gcc]] optimization levels) | |||
==Using an alternate Glibc== | |||
Acquire the glibc sources, create a build directory, and run <tt>configure</tt> from that build directory. You are advised to run with <tt>--prefix=/usr</tt>, and then install to an alternative directory using e.g. <tt>make install DESTDIR=$HOME/glibc</tt>. Use <tt>--with-headers</tt> to specify kernel headers: | |||
<pre> | |||
[schwarzgerat](0) $ pwd | |||
/home/dank/src/glibc/build | |||
[schwarzgerat](0) $ ../configure --prefix=/usr --with-headers=/usr/src/linux-headers-5.7.7nlb/include/generated/uapi/ | |||
</pre> | |||
So you've installed a local build of Glibc to, say, $HOME/glibc, eh? | |||
Trying to run with <tt>LD_LIBRARY_PATH=$HOME/glibc/lib</tt> will result in all dynamically-linked executables segfaulting immediately. That's because they're using a mismatched loader. Try running the correct loader directly to sanity-check your library install, e.g.: | |||
<pre> | |||
[schwarzgerat](0) $ /bin/echo | |||
Segmentation fault (core dumped) | |||
[schwarzgerat](139) $ ~/glibc/lib/ld-linux-x86-64.so.2 /bin/echo this will work | |||
this will work | |||
[schwarzgerat](0) $ | |||
</pre> |
Latest revision as of 16:22, 5 July 2020
The Linux APIs page lists the GNU libc versions corresponding to various Linux-specific functionality.
Determining glibc version
- From C, use confstr(3) with _CS_GNU_LIBC_VERSION and _CS_GNU_LIBPTHREAD_VERSION.
- libdank provides confstr_dyn(), a convenience wrapper
- On the command line, getconf(1) can be used:
- getconf GNU_LIBC_VERSION, getconf GNU_LIBPTHREAD_VERSION
Memory Utilities
- What is mudflap? FIXME
- Memory traces: if code calls
mtrace()
, then the environment variable MALLOC_TRACE is checked for a filename. If this file can be written to/created, it'll be truncated, and hooks will be installed so that all allocations and deallocations are dumped to the file. Themtrace(1)
tool (part of glibc) can then be used to generate human-readable output from this file, especially if the source code is available. - Heap consistency checking: A less efficient allocation system can be used, which detects certain classes of errors. Link with -lmcheck, or call
mcheck(3)
prior to any allocations, or define MALLOC_CHECK_ to be 1 (to print a warning) or 2 (to generate SIGABRT).mprobe(3)
is available in this mode, which upon invocation performs extra checks on specified blocks. - Statistics:
mallinfo(3)
can be called at any time to collect statistics from the allocator. Beware: this function returns a large struct on the stack (unless its prototype is ever changed), and can thus be incredibly slow!
Dynamic Symbols
- dlopen(3dl) is since glibc 2.2 extended by the RTLD_NODELETE and RTLD_NOLOAD directives. From the man page:
RTLD_NODELETE (since glibc 2.2) Do not unload the library during dlclose(). Consequently, the library’s static variables are not reinitialized if the library is reloaded with dlopen() at a later time. This flag is not specified in POSIX.1-2001. RTLD_NOLOAD (since glibc 2.2) Don’t load the library. This can be used to test if the library is already resident (dlopen() returns NULL if it is not, or the library’s handle if it is resident). This flag can also be used to promote the flags on a library that is already loaded. For example, a library that was previously loaded with RTLD_LOCAL can be re-opened with RTLD_NOLOAD | RTLD_GLOBAL. This flag is not specified in POSIX.1-2001.
- dlopen(3dl) is since glibc 2.3.4 extended by the RTLD_DEEPBIND flag. From the man page:
RTLD_DEEPBIND (since glibc 2.3.4) Place the lookup scope of the symbols in this library ahead of the global scope. This means that a self-contained library will use its own symbols in preference to global symbols with the same name contained in libraries that have already been loaded. This flag is not specified in POSIX.1-2001.
Generating a stack trace
The backtrace, backtrace_symbols and backtrace_symbols_fd glibc calls can be used to generate a stack trace from within a program.
- backtrace generates a list of addresses
- backtrace_symbols, given the output of backtrace, will populate its argv-style return value with any symbols it can look up
In order to extract symbols, appropriate binaries must:
- not be stripped (or linked with -s),
- be linked with -rdynamic/--export-dynamic, and
- provide frame pointers (none for inlined code, omitted with most gcc optimization levels)
Using an alternate Glibc
Acquire the glibc sources, create a build directory, and run configure from that build directory. You are advised to run with --prefix=/usr, and then install to an alternative directory using e.g. make install DESTDIR=$HOME/glibc. Use --with-headers to specify kernel headers:
[schwarzgerat](0) $ pwd /home/dank/src/glibc/build [schwarzgerat](0) $ ../configure --prefix=/usr --with-headers=/usr/src/linux-headers-5.7.7nlb/include/generated/uapi/
So you've installed a local build of Glibc to, say, $HOME/glibc, eh?
Trying to run with LD_LIBRARY_PATH=$HOME/glibc/lib will result in all dynamically-linked executables segfaulting immediately. That's because they're using a mismatched loader. Try running the correct loader directly to sanity-check your library install, e.g.:
[schwarzgerat](0) $ /bin/echo Segmentation fault (core dumped) [schwarzgerat](139) $ ~/glibc/lib/ld-linux-x86-64.so.2 /bin/echo this will work this will work [schwarzgerat](0) $