How to set regex breakpoint for shared library in GDB

Problem

Assume you are running a program under GDB and it is linked to shared library files. Not all the shared libraries are loaded at the beginning when you start the program with GDB. They are loaded when needed. So, how to set a regex breakpoint in a source file that belongs to one of the shared library files?

Solution

  • Setting a normal breakpoint will work if the shared library having that file has already been loaded. You can check the currently loaded shared libraries using the command: info shared

  • If you set a breakpoint for a file which belongs to a shared library that is not yet loaded, GDB will warn you that the breakpoint will only be set once the library is loaded. This is kinda okay.

  • However, if you try to set regex breakpoints (rbreak) that will fail silently if the shared library is not yet loaded. So how to know when is the earliest point when you can set such breakpoints?

  • I find it useful to configure GDB to stop whenever a shared library is loaded. This can be done by setting this option: set stop-on-solib-events 1

  • Now GDB stops every time at the point where one or more shared libraries need to be loaded. If I realize that the shared library I am interested in has now loaded, I run the regex breakpoint command at that point to set the breakpoints. Voila!

Tried with: GDB 7.11.1 and Ubuntu 14.04

Advertisements

Loader not finding shared library in same directory

Problem

I had an executable file that executed correctly on a computer. On a different computer with same setup, the dynamic loader that tries to load the shared libraries required by this executable would fail with this error:

error while loading shared libraries: libmatrixio.so: cannot open shared object file: No such file or directory

The surprising part is that the libmatrixio.so shared library file was always present in the same directory as the executable in both computers! It executed on one, but failed to find that file on another computer!

Solution

It turns out that the dynamic loader ld.so on Linux does not look in the current working directory by default. To make it look in the current directory, you need to add . to LD_LIBRARY_PATH. More information on this can be found in the ld.so manpage, look for LD_LIBRARY_PATH. After making this change to the shell environment variable, the executable loaded correctly on the other computer.

Tried with: Ubuntu 14.04

How to view hierarchy of shared library dependencies using lddtree

Tree of library dependencies shown by lddtree
Tree of library dependencies shown by lddtree

ldd is one of the key tools that should be familiar to all programmers. It shows the list of all shared libraries that an executable binary depends on.

A binary, say ELF file, lists only the immediate shared libraries it depends on in its header. Each of these shared libraries could further depend on other libraries and so on. It would be very useful if you could see the hierarchical tree of these dependencies between the shared libraries. Thankfully, there is a tool that does exactly that named lddtree.

  • It can be installed easily:
$ sudo apt install pax-utils
  • Usage is straightforward:
$ lddtree foo
  • By default, the tool does not show duplicated dependencies. That is, the dependency between a library A and B is shown only once and skipped after that, though it may occur many times. To view all the dependencies, including duplicates:
$ lddtree -a foo

Beware that this can result in a very big tree! This is because dependencies like libc, the ld-linux loader and such will appear for almost all shared libraries.

Note: The Dependency Walker tool does something similar on Windows and can be used as described here.

Tried with: PaX-Utils 0.2.3 and Ubuntu 14.04

Skype error on libGL shared library

Problem

I installed Skype from here using the package for Ubuntu 12.04 Multiarch. When I ran Skype from the Dash, nothing happened. When I ran Skype from the shell, I found that it quit with this error:

$ skype
skype: error while loading shared libraries: libGL.so.1: cannot open shared object file: No such file or directory

Solution

  • Let us check the shared library dependencies of this Skype executable. This actually uses the dynamic linker and loader to compare what is required by the executable with what shared libraries are available in the cache:
$ ldd /usr/bin/skype | grep libGL
libGL.so.1 => not found
libGL.so.1 => not found

So yes, the shared library file is not found.

  • I first checked if the libGL.so.1 was available in the shared library cache:
$ ldconfig -p | grep libGL.so.1
libGL.so.1 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/mesa/libGL.so.1

So, a 64-bit shared library of the required name was present in the cache!

  • I next checked the Skype program itself:
$ file /usr/bin/skype
/usr/bin/skype: ELF 32-bit LSB  shared object, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, stripped

This was a 32-bit executable. Might it require a 32-bit shared library and could this be causing the problem?

  • The 32-bit GL library files and directories updated in cache are controlled by the configuration in /etc/ld.so.conf.d/i386-linux-gnu_GL.conf. This in turn can be easily switched between libraries provided by different providers using update-alternatives:
$ sudo update-alternatives --config i386-linux-gnu_gl_conf

I found that currently the GL library files provided by /usr/lib/nvidia-352/alt_ld.so.conf, that is, by my NVIDIA drivers was being used. I picked the /usr/lib/i386-linux-gnu/mesa/ld.so.conf which is by MESA. This only sets the symbolic link for the /etc/ld.so.conf.d/i386-linux-gnu_GL.conf from the NVIDIA conf file to the MESA conf file.

  • Next we update the cache so that the NVIDIA library files are removed and the MESA library files are symbolically linked to as the default GL library files:
$ sudo ldconfig
  • Let us check what the cache holds now:
$ ldconfig -p | grep libGL.so.1
libGL.so.1 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/mesa/libGL.so.1
libGL.so.1 (libc6) => /usr/lib/i386-linux-gnu/mesa/libGL.so.1

We can see that we now have an additional entry, which has no architecture specified, but it is for 32-bit by default.

  • Finally, let us check if the shared dependencies of the Skype exectuable are met now:
$ ldd /usr/bin/skype | grep libGL
libGL.so.1 => /usr/lib/i386-linux-gnu/mesa/libGL.so.1 (0xf16b5000)

Yes, they are! I ran Skype after this and it worked fine! 😄

Tried with: Skype 4.3 (multiarch) and Ubuntu 14.04

How to add library directory to ldconfig cache

Problem

ldconfig is a program that is used to maintain the shared library cache. This cache is typically stored in the file /etc/ld.so.cache and is used by the system to map a shared library name to the location of the corresponding shared library file. This is used when a program is executed to find locations of shared libraries that need to be dynamically loaded and linked to the program. By default, the shared library files in /lib, /usr/lib and a few other standard directories are maintained in the cache by ldconfig.

A new program or library might be installed in a non-standard directory, for example in /opt/foobar/lib. Programs that need the shared libraries from this library might fail with this error when executed:

hello-world-program: error while loading shared libraries: libFoobar.so.1: cannot open shared object file: No such file or directory

The libFoobar.so.1 might be located in /opt/foobar/lib, but the system does not know this, so it cannot successfully load and execute the program.

Solution

To fix this problem, we need to add the library directory to the list used by ldconfig. There are two ways to do this: just add to LD_LIBRARY_PATH or rebuild cache.

Add to LD_LIBRARY_PATH

Set this at shell for temporary use or add to the shell initialization file for permanent effect:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/foobar/lib

Rebuild cache

  • Open the /etc/ld.so.conf as sudo and add a new line with the library directory. In this case, we add /opt/foobar/lib.

  • Rerun ldconfig to rebuild the cache:

$ sudo ldconfig
  • Check if the shared library cache now includes the shared libraries from the new directory:
$ ldconfig -p

Your program should now execute without any errors 🙂

Tried with: Ubuntu 14.04

How to add library in Eclipse CDT

The source code of a C/C++ project may need to be linked with an external shared library file. When compiling from the commandline, this is typically linked using the compiler option -l. For example, to link with a library file named libfoobar.so, which is placed in one of the standard library paths, you use the option -lfoobar. As you can see, the lib prefix and the file extension .so do not need to be specified.

Similarly, to add a library file to be linked in Eclipse CDT:

  1. Right-click on the project name in Project Explorer, choose Properties > C/C++ Build > Settings > Tool Settings

  2. Go to Cross G++ Linker > Libraries > Libraries.

  3. Click the + button and add the name of the library file, omit the file extension. For example, to add the library file libfoobar.so, just add foobar. To add multiple library files, add them separately like this.

Tried with: Eclipse 3.7.2, Eclipse CDT 8.0.2 and Ubuntu 12.04 LTS

ELF Library Viewer

Dependency Walker is a popular tool on Windows to view the dependent modules of a EXE or DLL file. ELF Library Viewer is a similar program for Linux. It shows the tree of shared libraries that a program or shared library is dependent on.

The source code of ELF Library Viewer can be downloaded here. It can be compiled easily by typing cmake followed by make.

Tried with: ELF Library Viewer 0.9 and Ubuntu 12.04 LTS

How to view modules loaded by a Python program

The Python program has a useful parameter: -v When Python is launched with this parameter to run a Python program, it prints out all the Python modules and dynamic libraries that are loaded during the executing. This can be useful to see exactly which Python files and shared library files are loaded and in which order. This parameter also prints out the modules as they are cleaned up at the end of program execution.

$ python -v foo.py

Tried with: Python 2.7.3 and Ubuntu 12.04 LTS