您的位置:首页 > 移动开发 > Android开发

Why your Android NDK breakpoints might fail and how to fix them

2014-11-09 22:44 585 查看


Why your Android NDK breakpoints might fail and how to fix them


Ivan
Shcherbakov, 1 Nov 2013 CPOL





   4.86 (5 votes)
Rate this:vote
1vote
2vote
3vote
4vote
5
 
This article explains why the breakpoints in native Android code might fail and how to fix them


Overview

This article shows why your breakpoints in native Android code might fail and how to fix them.


Introduction

First of all, let's get an overview of the structure of a typical Android app containing native code:



The app code is stored inside a .apk file that is essentially a Zip archive containing the classes.dex file (with all the Java code) and one
or more native libraries in the lib\<EABI name> subdirectory. The typical lifecycle of an application with native code is the following:

The Android OS loads the Java code and starts executing it
The Java code calls 
System.loadLibrary()
 to load a native library.
The Java code starts calling functions from the native code.
Each native library exists in two versions:

 A "full" version debugging information that associates code addresses inside the library with source files and lines. This version resides in obj\local\armeabi under
your project directory.
A "stripped" version without the debugging information that resides in libs\armeabi and gets packaged into the APK file.
While the Android device runs the smaller "stripped" version of the library, the GDB debugger needs the larger "non-stripped" version to map source files into addresses and vice versa:




Setting breakpoints 

When you set a breakpoint on a given line of a source file, the GDB debugger needs to perform certain computations before the breakpoint can be physically created and starts triggering. Assume libNative1 is loaded at address 0x10000 and
the user is setting a breakpoint in line 24 of c:\main.cpp. GDB will do the following before it can set a breakpoint:

GDB starts searching all loaded libraries for the file called "c:\main.cpp". In this example the Android OS only reports the libNative1.so library.
GDB looks inside obj\local\armeabi for a file called libNative1.so which is the "non-stripped"
version of the library containing the debug information. GDB reads the symbol table from it and finds c:\main.cpp inside it.
Based on the symbol table GDB computes that line 24 corresponds to offset +0x2. It adds 0x2 to the load address of libNative1.so (0x10000)
and sets the breakpoint at 0x10002.
If any of the three steps fail, the breakpoint will not be created, or will be created wrongly and will never be hit. The next section explains how to diagnose and fix the related problems.


Diagnosing the problems

This section provides detailed instructions how to check for the most common problems with breakpoints caused by non-standard configurations or missing files:

A. Ensure that the library is loaded

First thing to do is to determine if the native library has been actually loaded and if GDB knows about it. It is done by running the "info shared" command in GDB:



The output from the info shared command should include three important lines:

Loaded symbols for "linker"
Loaded symbols for "libc.so"
Loaded symbols for all native libraries you want to debug.
Here's an example of those lines:


 Collapse | Copy
Code
From       To         Syms Read       Shared Object Library
No com.visualgdb.example.MyAndroidApp
0xb0001000 0xb00069d0 Yes C:/.../AndroidBinaryCache/.../linker
0x40073300 0x400a12fc Yes C:/.../AndroidBinaryCache/.../libc.so
0x5148fccc 0x51491198 Yes E:/.../obj/local/armeabi/libMyAndroidApp.so

If some of the libraries are not present, you can force GDB to manually reload the symbols by running the following command in GDB:


 Collapse | Copy
Code
sharedlibrary

If your .so library (e.g., libMyAndroidApp.so) is listed, but the symbols are not loaded ("Syms read" states "no"), GDB was not able to find a non-stripped version of the library. To fix it please
run the "show solib-search-path" command in GDB:



The obj/local/armeabi directory of your project should be present among the reported directories and it should contain the .so file with symbols.
If not, copy the correct .so file into a directory listed here and rerun the "sharedlibrary" command.

You can alternatively force GDB to search additional directories for the .so file using the set solib-search-pathcommand.

If your .so library is not present in the list, it has not been loaded by the Java code yet. Please ensure that
System.loadLibrary()
 is
called from your Java code and that it succeeds without any Java exceptions.

B. Ensure that you are using correct file paths

A common cause of many breakpoint problems is a configuration when the directories using for building and debugging your project are different. E.g., if the library was compiled from c:\projects and
then the sources were moved to d:\projects, setting a breakpoint in d:\projects\main.cpp will fail, as GDB will not acceptc:\projects\main.cpp as
a substitute.

Those problems can be diagnosed by looking into the source file lists and comparing them with the file used to set a breakpoint. First of all, remove your breakpoint, try setting your breakpoint again and watch what GDB command is issued by your IDE:



The -break-insert command used to set a breakpoint will specify a path to your source file.

Run the "info sources" command to see the source files discovered by GDB:



Copy the output of the command to the clipboard (Ctrl-A, Ctrl-C), paste it into a text editor and search for the source file you are trying to debug (e.g., MyAndroidApp.c):



If the file is not present in the list, you have loaded a wrong version of the .so file (see previous section). If the file is present, but the path is different from the one used in -break-insert command,
you have found the cause of your problem. Rebuild your app using the new path, or move the file back to an old location so that the path used for creating breakpoints matches the path reported by the "info sources" command.

Note that GDB requires the file path to be EXACTLY the same as reported by "info sources", including double slash before "jni".

C. Recheck file versions and do a clean build

If your breakpoints are set, but never hit, there is probably a mismatch between the .so file version loaded into the Android application and the .so file
version used by GDB to compute addresses from source lines. The most common cause for it is the bug in the Android loader that loads the armeabi library instead of the armeabi-v7aversion.
If you suspect this to happen, change your build configuration to build either armeabi, or armeabi-v7aplatform, but not both at the same time
and rebuild your application.


License

This article, along with any associated source code and files, is licensed under The
Code Project Open License (CPOL)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐