Check out my first novel, midnight's simulacra!

Libc: Difference between revisions

From dankwiki
No edit summary
 
 
(5 intermediate revisions by 2 users not shown)
Line 1: Line 1:
The [[Linux APIs]] page lists the GNU libc versions corresponding to various Linux-specific functionality.
== Determining glibc version ==
== Determining glibc version ==
* From [[C]], use confstr(3) with _CS_GNU_LIBC_VERSION and _CS_GNU_LIBPTHREAD_VERSION.
* From [[C]], use confstr(3) with _CS_GNU_LIBC_VERSION and _CS_GNU_LIBPTHREAD_VERSION.
Line 34: 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. The mtrace(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) $