- Using python script to find symbols in. so library file
- Preparatory knowledge
- Naming rules and storage / search path of Linux dynamic link library
- Search files in Linux
- Linux browsing symbol list in. so library file
- Calling shell commands in Python
- Complete procedure
- Hot Keywords
- Find where is a shared library symbol defined on a live system / list all symbols exported on a system
- How do I find where a symbol is defined among static libraries
- 3 Answers 3
- How to list all externally-undefined symbols of a static library on Linux?
- 2 Answers 2
Using python script to find symbols in. so library file
When encountering a long error, it is usually to link fewer library files when linking. As long as the corresponding library is linked, for example, this error can be fixed by adding — loggershadersystem at compile time.
Therefore, when such errors occur, it is necessary to find out which library file is less linked.
Preparatory knowledge
Naming rules and storage / search path of Linux dynamic link library
The dynamic link library in Linux system is a. so(Shared Object) file. Its default storage locations are / usr/lib / and / lib /.
Its naming rule is generally lib + library name +. So. For example, the library file corresponding to the library ogrrtshadersystem is L ib OgreRTShaderSystem.so . When gcc compiles, the library name is passed in instead of the library file name. For example, if you want to link the library ogrrtshadersystem at compile time, you need to call it in gcc in the following way:
g++ test.cpp -o test -lOgreRTShaderSystem
gcc will look for L in the following order ibOgreRTShaderSystem.so This library file:
- The dynamic library search path specified when compiling the target code;
- Environment variable LD_LIBRARY_PATH: the dynamic library search path specified by path;
- Configuration file / etc/ ld.so.conf Dynamic library search path specified in. D / *;
- Default dynamic library search path / lib;
- The default dynamic library search path is / usr/lib.
Search files in Linux
In Linux, you can use the find command to search for files. Here, take Manjaro system as an example.
The Linux find command is used to find files in the specified directory. Any string before the parameter will be treated as the name of the directory you want to find. If you use this command without setting any parameters, the find command looks for subdirectories and files in the current directory. All the subdirectories and files found will be displayed.
Common parameters include:
- -amin n: read in the last n minutes
- -atime n: files read in the last n days
- -ipath p, -path p: file whose path name matches p, and ipath ignores case
- -name name, -iname name: the file whose name matches name. iname ignores case
- -size n: file size is n unit, b represents 512 byte block, c represents number of characters, k represents kilo bytes, w is two bytes
- -Type c: file of type c
Here we use the — name parameter. We use the following command to find the. so library file starting with libOgre:
find /usr/lib/ -name 'libOgre*.so'
Linux browsing symbol list in. so library file
In Linux, you can use the nm command to list the symbols in the specified library file.
nm is the abbreviation of names. nm command is mainly used to list symbols in some files (in other words, some functions, global variables, etc.).
Here we use the — D(– dynamic) parameter, which is used to display dynamic symbols. This option is only meaningful for dynamic targets, such as shared libraries of a specific type.
For example, find / usr/lib/libOgreBites.so Symbols in:
nm -D /usr/lib/libOgreBites.so
The results are similar to the following:
0000000000046020 B __bss_start U commandWidgetClass U __cxa_allocate_exception U __cxa_atexit U __cxa_begin_catch U __cxa_call_unexpected U __cxa_end_catch w __cxa_finalize U __cxa_free_exception U __cxa_guard_abort U __cxa_guard_acquire U __cxa_guard_release U __cxa_rethrow U __cxa_throw U __dynamic_cast 0000000000046020 D _edata ... ... 0000000000039160 u _ZZNSt8__detail18__to_chars_10_implIjEEvPcjT_E8__digits 00000000000380e0 u _ZZNSt8__detail18__to_chars_10_implImEEvPcjT_E8__digits
You can use grep to find the symbol (_ ZN4Ogre8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE)
nm -D /usr/lib/libOgreBites.so | grep _ZN4Ogre8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE
The results are as follows:
e8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE U _ZN4Ogre8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE
Calling shell commands in Python
In Python, you can call shell commands through the subprocess module. The method is to call the Popen() function directly:
import subprocess child = subprocess.Popen('ls ~ -a', shell=True)
When there is a sequence requirement for the front and back processes, the process of wait() needs to be added to ensure that the latter process starts after the completion of the previous process:
If you want to save the result of running the shell command in subprocess into a variable, you need to specify that the stdout parameter in Popen() is subprocess.PIPE . And use communicate() to get the subprocess.PIPE Read results in:
child = subprocess.Popen('ls ~ -a', shell=True, stdout=subprocess.PIPE) child.wait() result_binary = child.communicate()
The result here is a tuple, the first element of which is a binary string that holds the running result, so it needs to be decoded:
result = result_binary[0].decode("utf-8")
Complete procedure
import subprocess sub = subprocess.Popen('find /usr/lib/ -name \'libOgre*.so\'', shell=True, stdout=subprocess.PIPE) sub.wait() out = sub.communicate() res = out[0].decode("utf-8").split('\n') for item in res: if len(item): tmp_sub = subprocess.Popen('nm -D <> | grep _ZN4Ogre8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE'.format(item), shell=True, stdout=subprocess.PIPE) tmp_sub.wait() tmp = tmp_sub.communicate()[0] if tmp: print('file: <>'.format(item)) print('\t<>'.format(tmp))
find: '/usr/lib/firmware/b43legacy': Permission denied find: '/usr/lib/firmware/b43': Permission denied file: /usr/lib/libOgreRTShaderSystem.so b'00000000000c6fa0 T _ZN4Ogre8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE\n' file: /usr/lib/libOgreBites.so b' U _ZN4Ogre8RTShader15ShaderGenerator15addSceneManagerEPNS_12SceneManagerE\n'
The observation shows that there should be no link ibOgreRTShaderSystem.so .
Posted by sujithnair on Thu, 25 Jun 2020 20:43:02 -0700
Hot Keywords
- Java — 6961
- Database — 2683
- Python — 2616
- Programming — 2419
- Attribute — 2418
- Javascript — 2383
- Spring — 2111
- Android — 2077
- xml — 1972
- Linux — 1818
- JSON — 1764
- network — 1748
- github — 1720
- less — 1676
- MySQL — 1538
- SQL — 1332
- PHP — 1318
- encoding — 1179
- Mobile — 1029
- Apache — 925
Find where is a shared library symbol defined on a live system / list all symbols exported on a system
Basically, this is two questions into one — because if I can list all symbols exported within a system, along with their shared library path, then I could simply grep that output. For kernel symbols, I guess it is somewhat easier — because we can always cat /proc/kallsyms and get a list of all symbols of those modules loaded in memory; then sudo cat /proc/modules will give a list of loaded modules with their addresses, but not the paths where does modules have been loaded from (if they are built as separate, out-of-tree .ko objects) For instance, I try to trace the program kst using ltrace :
$ ltrace kst2 . _ZNK13QGraphicsItem10parentItemEv(0xa1ccdb4, 0, 0xbfe631a8, 0x823652b, 0xbfe63298) = 0xa1ce854 __dynamic_cast(0xa1ce854, 0x839ff00, 0x8306b80, 84, 0xbfe63298) = 0xa1ce800 _ZNK13QGraphicsItem10parentItemEv(0xa1ccdb4, 0x839ff00, 0x8306b80, 84, 0xbfe63298) = 0xa1ce854 __dynamic_cast(0xa1ce854, 0x839ff00, 0x8306b80, 84, 0xbfe63298) = 0xa1ce800 .
. and I would like to know where this _ZNK13QGraphicsItem10parentItemEv resides. So, what to do about shared library symbols? Reading through [gcc-help] Re: finding the library in which symbol is defined.; I tried something like this:
$ find /usr/lib -name '*.so*' -exec nm --print-file-name --defined-only --dynamic <> \; | grep "QGraphicsItem" . /usr/lib/libQtGui.so.4.7.2:00766d70 T _Zls6QDebugN13QGraphicsItem16GraphicsItemFlagE /usr/lib/libQtGui.so.4.7.2:00766aa0 T _Zls6QDebugN13QGraphicsItem18GraphicsItemChangeE /usr/lib/libQtGui.so.4.7.2:00767e80 T _Zls6QDebugP13QGraphicsItem .
. but that gives me additional problems: I don’t really know all the paths which are scanned for shared libraries on my system, so when I first tried find /lib . it didn’t find anything; I find this guessing of directories irksome, just as well as the alternative: scanning the entire root filesystem with find . And also, I seem to hit up *.so’s which cannot be opened by nm (maybe because they are symlinks?), which output a quite a bit of error messages (which I don’t like either). The thing is — ldd (or ld ?) probably performs some of this lookup of symbols, but I tried the respective manpages, and I cannot see a way to «find» any symbol from the command line, without providing some sort of executable file as an argument. Side question — would there a way to use these tools for that? So, what I’m looking for a command line tool, which would behave something like (pseudocode):
$ ./findsymbol '_Zls6QDebugN13QGraphicsItem16GraphicsItemFlagE' symbol found in: /usr/lib/libQtGui.so.4.7.2:00766d70 T _Zls6QDebugN13QGraphicsItem16GraphicsItemFlagE .
. where I don’t specify any directories to search — but which would also handle, e.g. LD_PRELOAD or LD_LIBRARY_PATH ; say if I do:
$ LD_PRELOAD="/path/to/mylib.so" ./findsymbol '*mylib_print*'
. then I’d get the /path/to/mylib.so where the given symbol was defined (given that such a symbol wouldn’t exist in the standard libraries) — and would output «not found» otherwise. And otherwise, ./findsymbol —dumpall could produce a list of all available symbols and their locations seen from a given environment (e.g. a specific bash shell). Does a tool like this exist for Linux?
How do I find where a symbol is defined among static libraries
Suppose you work with a codebase comprising several tools and libraries and you want to port (or resurrect) some component within such codebase but any clue about where symbols lie within the various libs is either lost or will take ages to find out by looking at the code itself (yes improved documentation can avoid such issues but is quite demanding). What is the fastest way to discover in which library you can find symbols used in the code?
3 Answers 3
Assuming a linux box, the nm tool, listing names in library files, comes to the rescue.
It can be used to do an extensive search as follows: one can first find all the libraries available (assuming the project have been successfully compiled without the component you are adding) with a find, then such find can be enclosed in a loop where you call nm on all discovered libraries; the output you then grep for discarding «U» references (undefined symbols, aka where else the symbol is being used). On a single bash line that gives:
for lib in $(find base_path -name \*.a) ; do echo $lib ; nm $lib | grep my_symbol | grep -v " U " ; done
The echo generates a list of all libraries found, which is not so clean since it outputs names of libs not holding the symbol, but it was the fastest way I found to have a direct reference to the library so when you see a:
base_path/component/libA.a 0000000000000080 D my_symbol
You have found your usual suspect.
How to list all externally-undefined symbols of a static library on Linux?
So that I can find out all external symbol dependencies of this library.
2 Answers 2
ld -r -o deleteme.o --whole-archive libfoo.a nm -C --undefined-only deleteme.o # `-C` if you might have C++ archive members rm deleteme.o
extern void two(void); void one()
extern void three(void); void two()
Make a static library libonetwo.a :
$ gcc -Wall -c one.c two.c $ ar rcs libonetwo.a one.o two.o
nm parses the static library as if it were just a commandline list of its members:
$ nm --undefined-only libonetwo.a one.o: U _GLOBAL_OFFSET_TABLE_ U two two.o: U _GLOBAL_OFFSET_TABLE_ U three
So incrementally link them all into a temporary object file:
$ ld -r -o deleteme.o --whole-archive libonetwo.a
Then see the residual undefined symbols of that object file and delete it:
$ nm --undefined-only deleteme.o && rm deleteme.o U _GLOBAL_OFFSET_TABLE_ U three
There is no single command (that I know of) that will do that.
But it’s trivial to construct two commands, one for all undefined, and one for all defined symbols, and then show only the difference between them.
First nm prints only defined symbols. Second nm prints only undefined symbols (which may be defined in another file in the same library).
The comm -13 prints only lines from second nm which do not occur in the output from the first nm .