15

I'm trying to debug an android native app from Android Studio's native debugging using lldb.
My native app contains one libmain.so that is compiled and run by Android Studio and another external libother.so compiled by me. when debugging, I am able to set breakpoints in libmain.so but not libother.so.
Both shared objects are stripped but somehow Android Studio makes lldb know about the unstripped version of libmain.so. I want to do the same for libother.so.

What command do I need to give lldb so that it would load the symbols from an unstripped file on my local machine?
When I do image list I see the main .so with a path the points to its local unstripped version:

/Users/username/Projects/gow/android/AppName/app/build/intermediates/binaries/debug/arm7/obj/armeabi-v7a/libmain.so

and the second .so with a path like /var/folders/3w/5nr95lxx3qvdm2ylb8c8b7500000gn/T/./lldb/module_cache/remote-android/.cache/B5F32653-0000-0000-0000-000000000000/libother.so

How do I make lldb find the unstripped version of libother.so ?
I tried image add and target symbols add but it didn't work.

shoosh
  • 76,898
  • 55
  • 205
  • 325
  • Do you build the app with Gradle? If so, can you share your build file? Also do share your Android.mk file – Laurentiu L. Sep 14 '15 at 09:30
  • I do build it with gradle. The build file is identical to the one that comes with the Teapot example (https://developer.android.com/ndk/samples/sample_teapot.html) The only difference is that in my project I have a folder called "jniLibs" so gradle finds this folder and adds the .so in it to the apk. The Android.mk for building the .so is also a standard one that was used for building with the ndk before the Android Studio support. it uses clang and c++_static (too big to add here). I'm using the latests NDK – shoosh Sep 14 '15 at 13:04
  • Are you debugging on windows? The paths you provided i assume are from Android. There are still some known bugs in NDK; when debugging with LLDB breakpoints do not always work on Windows; if you run into this, you can switch to GDB debugging as a temporary workaround. – Laurentiu L. Sep 14 '15 at 13:08
  • Try configuring a debug buildtype with isDebuggable and isJniDebuggable set to true http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Types – Laurentiu L. Sep 14 '15 at 13:14
  • Debugging from OSX, I tried isDebuggable and isJniDebuggable, both had no effect. – shoosh Sep 14 '15 at 19:37
  • Sorry, the property names for the buildType configuration might actually be debuggable true jniDebuggable true – Laurentiu L. Sep 15 '15 at 10:21
  • I advise you update your answer as you try various things, with the exact changes you do. Perhaps not your case, but more often than you'd think people miss the right solution because of a faulty implementation. Anyone can miss the small stuff at times – Laurentiu L. Sep 15 '15 at 13:53
  • I had good success with this more recent question/answer about the same thing http://stackoverflow.com/a/39797306/1087576 - in Android Studio 2.2.3 it Just Finds It – Tom K Feb 02 '17 at 05:15

4 Answers4

7

The answers in this thread seem to be specific for MacOSX. I am using Linux, so these answers weren't very helpful. After some time I've figured it out, and here is a very simple solution. Before you do "process attach" you should execute the following command:

settings set target.exec-search-paths /path/to/directory/with/unstripped/library/on/host

With this setting lldb has no problems finding the correct version of the library.

BTW, latest versions of Android Studio don't have any problems with external libraries (in fact, the same technique is used to set correct paths all libraries, both "internal" and "external", at least if you're building with Gradle). But if you use standalone lldb, this can be very handy.

To avoid typing it after start of each debugging session you can save this command to file (e.g. lldb.cmd) and then start lldb like this:

./lldb -S lldb.cmd
Aleksei Petrenko
  • 6,698
  • 10
  • 53
  • 87
  • It seems this does not to work in AS 2.2.2 (also running under Linux). `lldb` is using the libraries stored in `.lldb/module_cache/...` (I can see that in `image list`) which don't contain debug symbols. I've put the exec-search-path under `LLDB Startup Commands` in `Run/Debug Configuration`. The path itself points to `{abs_path_to_project}/app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a` as this directory contains shared libraries with debug symbols. Any ideas on what I'm doing wrong here? – Krzysztof Kansy Nov 16 '16 at 10:57
  • I don't know about `LLDB startup commands`, never used it. Can you just type it manually, does it work? Do libraries appear on your `image list`? – Aleksei Petrenko Nov 21 '16 at 15:42
  • 1
    Sorry, it turned out my libraries were not build properly for debug, your answer worked for me after fixing build process. Thank you. – Krzysztof Kansy Nov 22 '16 at 15:42
  • May you send link with documentation about this (and others) setting? – magrif Aug 22 '22 at 19:55
4

use the "target.source-map" setting

(lldb) settings list target.source-map
source-map -- Source path remappings used to track the change of location between a source file when built, and where it exists on the current system. It consists of an array of duples, the first element of each duple is some part (starting at the root) of the path to the file when it was built, and the second is where the remainder of the original build hierarchy is rooted on the local system. Each element of the array is checked in order and the first one that results in a match wins.

i.e.

settings set target.source-map /build_src /source

where the building environment is under /build_src and the.dSYM files (symbols) are copied under /source

EDIT:

Binaries are often stripped after being built and packaged into a release. If your build systems saves an unstripped executable a path to this executable can be provided using the key DBGSymbolRichExecutable

You can write a shell command that will be given a UUID value and is expected to return a plist with certain keys that specify where the binary is.

You can enable the shell script using:

% defaults write com.apple.DebugSymbols DBGShellCommands /path/to/shellscript

Your shell script will be invoked with a UUID string value like "23516BE4-29BE-350C-91C9-F36E7999F0F1". The shell script can respond with a plist in the following format:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" 
"http://www.apple.com/DTDs/PropertyList-1.0.dtd";>
<plist version="1.0">
<dict>
        <key>23516BE4-29BE-350C-91C9-F36E7999F0F1</key>
        <dict>
                <key>DBGArchitecture</key>
                <string>i386</string>
                <key>DBGBuildSourcePath</key>
                <string>/path/to/build/sources</string>
                <key>DBGSourcePath</key>
                <string>/path/to/actual/sources</string>
                <key>DBGDSYMPath</key>
                <string>/path/to/foo.dSYM/Contents/Resources/DWARF/foo</string>
                <key>DBGSymbolRichExecutable</key>
                <string>/path/to/unstripped/exectuable</string>
        </dict>
        <key>A40597AA-5529-3337-8C09-D8A014EB1578</key>
        <dict>
                <key>DBGArchitecture</key>
                <string>x86_64</string>
                .....
        </dict>
</dict>
</plist>

for more details please see:

http://lldb.llvm.org/symbols.html

https://www.mail-archive.com/lldb-dev@cs.uiuc.edu/msg01142.html

EDIT 2:

Terminal command to print an executable's build UUID

$ xcrun dwarfdump --uuid <PATH_TO_APP_EXECUTABLE>

source

Pat
  • 2,670
  • 18
  • 27
3

For completeness, what I ended up doing is
- add -Wl,--build-id=sha1 to the LOCAL_LDFLAGS in the Android.mk of libmain.so
- add a symlink from /Users/username/Projects/gow/android/AppName/app/build/intermediates/binaries/debug/arm7/obj/armeabi-v7a/ to the unstripped shared object.

That allowed Android-Studio's LLDB to find the unstripped .so, correctly present its symbols and allowed me to add breakpoints in libmain.so code.

shoosh
  • 76,898
  • 55
  • 205
  • 325
1

I've found that this issue occurs when a shared library does not contain the .note.gnu.build-id section. This section contains an unique ID of the file. To create this section it is needed to pass the --build-id switch to the LD linker.

After addition of the build-id to my shared library LLDB started to use un-stripped version of the library and successfully loaded its debug information.

Jusid
  • 936
  • 7
  • 8