How can I set a breakpoint to a native library load event in Android?
I would assume that setting a breakpoint on dlopen() would be a good starting point, however, the gdb cannot find the dlopen function even when the symbols for libc.so and /system/bin/linker are loaded.
It also looks like Android is using some special format of the .so files, as the nm tool does not report the dlopen() location either.
Is there any workaround for the problem or an Android-specific .so dump tool that can help locating the function address by its name so that I can set a breakpoint manually?
Edit:
What I’m trying to do is to set a breakpoint that should trigger when ANY native library is loaded, i.e. when any code (not even in my libraries) calls the dlopen() function.
The problem is that Android GDB does not support pending breakpoints. My scenario is like this:
- I start my app and halt it.
- The app is resumed and it loads my native library.
- My function is called from the library (only once when the app is loaded).
If I set a breakpoint after #1, it won’t work as the library is still not there and android-gdb won’t be able to rebind it. If I let the program run, then halt it again and set a breakpoint, I’m already past #3, so that the breakpoint will be useless.
I’m trying to work around it by setting a breakpoint to dlopen() at #1 and then when it hits and loads the library (i.e. #2) I will set the actual breakpoint.
Using the normal ARM nm and objdump has no help. NM’ing the libc.so shows that dlopen() is undefined:
00016188 T dlmemalign
U dlopen
00016338 T dlpvalloc
The /system/bin/linker binary physically contains the dlopen text (first byte of .rodata section), however nm shows the following text:
arm-linux-androideabi-nm.exe: linker: No symbols
Disassembling it with objdump gives no symbol names.
Googling around for android sources revealed this source file:
http://dexandroid.googlecode.com/svn/trunk/bionic/linker/dlfcn.c
It looks like dlopen() is indeed defined inside /system/bin/linker, but it is using some non-standard symbol resolution mechanism (at least, based on the first comment):
/* This file hijacks the symbols stubbed out in libdl.so. */
So, coming back to the question, how can I set a breakpoint into dlopen() to set the actual breakpoint just when the library is loaded?
Usually any arm objdump should work, but there will be one in your ndk directory.
Even a non-arm readelf may work.
I’m not sure why you expect to find dlopen() in the library, unless it is explicitly using that to open another library – normally, one would think it would be called from libdvm.so at any rate I belive the implemention is in libdl.so (having a version of grep built for android is a very useful thing – you can find strings in the lib directory, though if you want to find if they are imports or exports you probably need to adb pull and objdump the files of interest).
If you are trying to breakpoint the library file being loaded, you might try implementing one of the static initializer functions (either C-level or the jni on load one) and putting a breakpoint there.
EDIT:
It turns out that objdump for arm does not decode the linkage via the plt used for symbols imported from shared libraries, though it does for some other platforms like x86. This can make it very hard to make any sense of binaries which are stripped of debugging symbols, as you would expect from the system libs on the devices. I was able to patch the binutils sources to do this for arm. Eventually I hope to submit that somewhere, but in the meantime source of the patched version is available at https://github.com/cstratton/binutils-android-decodeplt
I put an objdump binary in a prebuilt-linux-x86/ directory though I don’t know how portable that will be.