您的位置:首页 > 编程语言 > C语言/C++

How C/C++ Debugging Works on Android

2012-06-06 22:19 267 查看
http://mhandroid.wordpress.com/2011/01/25/multithread-cc-debugging-on-emulators-and-rooted-devices-from-android-1-5/

Multithread C/C++ Debugging on Emulators and Rooted Devices from Android 1.5 原文带图

In Android 2.2 Google announced ndk-gdb script which ease the debugging on the device. Later it turns out that it is not capable of debugging any other thread than
the main thread.

In Android 2.3 Google ships fixed setup so you are now finally able to debug multithread application.

In fact multithread debugging is possible at least from Android 1.5. But you have to set up the environment yourself. Due to permissions limitation it is only possible
on rooted devices. But it is possible on emulator as emulator is always rooted!

Here is a small shell script which does everything for you. It will start gdbserver on the device, gdb on PC and connect them together. It will also set up paths
correctly so gdb can find its unstripped libraries on PC while having stripped libraries on the device.

Run this script from your project root directory. You have to modify APP_PACKAGE and ANDROID_TARGET variables to match your project settings. You also need to have
you project compiled in debug mode. This can be done by running ndk-build NDK_DEBUG=1 or by setting android:debuggable=”true” in AndroidManifest.xml and compiling normally.

001

#!/bin/bash

002

# Martin Hejna (c) 2011

003

# martin.hejna@gmail.com

004

# CC-by

005

006

007

## Comment out for quiet run

008

set -x

009

010

# Set those variables to match your application

011

[ "$APP_PACKAGE" ] || APP_PACKAGE="com.example"

012

[ "$ANDROID_TARGET" ] || ANDROID_TARGET="android-9"

013

014

# Set installation paths of SDK and NDK

015

[ "$ANDROID_SDK" ] || ANDROID_SDK="/home/martin/Android/android-sdk-linux_86"

016

[ "$ANDROID_NDK" ] || ANDROID_NDK="/home/martin/Android/android-ndk-r5"

017

018

# adb and gdb executable paths

019

ADB="$ANDROID_SDK"/platform-tools/adb

020

GDB=$ANDROID_NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb

021

022

# Check we are in application root path (the one with AndroidManifest.xml in it)

023

APP_ROOT=`dirname $0`

024

if [ ! -f $APP_ROOT/AndroidManifest.xml ]

025

then

026

echo This script must be run from package root directory

027

echo This is the directory with AndroidManifest.xml in it

028

exit 1

029

fi

030

031

# Path to unstripped versions of native .so libraries

032

UNSTRIPPED_SO_LIB="$APP_ROOT/obj/local/armeabi"

033

APP_PROCESS=$UNSTRIPPED_SO_LIB/app_process

034

APP_LIBC_SO=$UNSTRIPPED_SO_LIB/libc.so

035

if [ ! -d $UNSTRIPPED_SO_LIB ]; then

036

echo Error: Directory $UNSTRIPPED_SO_LIB does not exist

037

exit 1

038

fi

039

040

# Use cgdb if available

041

if which cgdb > /dev/null

042

then GDB_CMD="cgdb -d $GDB --"

043

else GDB_CMD=$GDB

044

fi

045

046

# We use same port number on pc and on device

047

DEBUG_PORT=5039

048

049

# File with gdb setup instructions (executed when gdb starts)

050

[ "$GDB_SETUP" ] || GDB_SETUP="/tmp/gdb.setup"

051

052

053

# Generate setup file for gdb with appropriate paths to symbols

054

function gdb_setup()

055

{

056

cat <<EOF >$GDB_SETUP

057

set solib-search-path $UNSTRIPPED_SO_LIB:$ANDROID_NDK/platforms/$ANDROID_TARGET/arch-arm/usr/lib

058

directory $ANDROID_NDK/platforms/$ANDROID_TARGET/arch-arm/usr/include $APP_ROOT/jni $ANDROID_NDK/sources/cxx-stl/system

059

## set solib-absolute-prefix $ANDROID_NDK/platforms/$ANDROID_TARGET/arch-arm/usr/lib

060

061

file $APP_PROCESS

062

target remote :$DEBUG_PORT

063

064

# Probably not needed. Uncomment if you have problems with watchdogs

065

## set variable gDvm.nativeDebuggerActive=true

066

EOF

067

}

068

069

# Get pid of the process (first one if there are more of them)

070

function get_pid_on_device()

071

{

072

$ADB shell ps | grep "$@" | awk '{print $2; exit}'

073

}

074

075

076

#############################################################################

077

## Main entry

078

############################################################################

079

080

081

# Restart adb server. Uncomment if you have problems with adb being stuck

082

## $ADB kill-server

083

084

# Get the app_process and libc.so from the device

085

# Always download and overwrite those files to be sure we have correct ones

086

$ADB pull /system/bin/app_process $APP_PROCESS

087

$ADB pull /system/lib/libc.so $APP_LIBC_SO

088

089

# Set up port forwarding for gdb and gdbserver

090

if $ADB forward tcp:$DEBUG_PORT tcp:$DEBUG_PORT

091

then :

092

else

093

echo Failed to setup tcp forwarding for port $DEBUG_PORT

094

echo Is the device running?

095

exit 1

096

fi

097

098

# Get pid of the process

099

APP_PID=`get_pid_on_device "$APP_PACKAGE"`

100

if [ -z $APP_PID ]

101

then

102

echo "$APP_PACKAGE is not running"

103

exit 1

104

fi

105

106

# Kill any prior gdbserver

107

GDBSERV_PID=`get_pid_on_device gdbserver`

108

if [ -n "$GDBSERV_PID" ]

109

then

110

$ADB shell kill $GDBSERV_PID

111

sleep 1

112

fi

113

114

# Start gdbserver and attach it to our application

115

$ADB shell gdbserver :$DEBUG_PORT --attach $APP_PID &

116

sleep 2

117

118

# Invoke gdb and feed it with setup commands to set up path to libraries

119

gdb_setup

120

$GDB_CMD -x $GDB_SETUP

121

rm -f $GDB_SETUP

Have fun!

----------------------------------------------------------------------------------------------------------

How C/C++ Debugging Works on Android(http://mhandroid.wordpress.com/2011/01/25/how-cc-debugging-works-on-android/)

Posted on January 25, 2011

How debugging of C/C++ code works on Android? Nothing special actually. Gdb itself has a feature for remote debugging.

Note: For this article I am using Android NDK, r5. The behavior of ndk-build and ndk-gdb commands can be different in other versions.

Basic setup

You simply run gdbserver on the device and let it attach to some process. Gdbserver acts as a remote debugger which is commanded by gdb itself. This step is pretty
easy and is done by some variant of

gdbserver :5039 --attach 123

where 5039 is a TCP port number to which gdb will connect and 123 is a PID of process we want to debug.

The next step is to run gdb client and connect it to the gdbserver on the device. You need to start gdb with command

gdb app_process

where app_process is Android binary which you need to copy from Android device to your PC. This binary is some kind of loader and lies in /system/bin/app_process
file on the device (or in the emulator).

After you start gdb you connect it with the gdbserver by this command (ran from gdb shell)

target remote :5039

Because you are usually running Android device connected through USB and not normal TCP/IP network (or you are running Android emulator) you have to set up TCP port
forwarding in advance. This is done by command

adb forward tcp:5039 tcp:5039

which you have to execute before starting gdb. This command will handle all connection requests to port 5039 on PC to the device on the same port.

And this is all.

Debug symbols

You typically compile your .so library with debug symbols. But it makes good sense to strip those symbols off before uploading your binary to the Android device.
Binary will be smaller (which means faster installation time of the apk package), will occupy less memory and will run faster. So you upload stripped version of your libraries to the Android device and keep unstripped versions on your PC.

To tell gdb the path to the unstripped libraries run this command from gdb shell

set solib-search-path obj/local/armeabi

You can enter more paths and separate them by colon (:) character.

There is a difference between debug symbols and code optimization. Code optimization allows changing the code flow or removing some dead-code and unused variables.
While debug symbols bind machine code together with appropriate lines in the source code. Usually you build a binary with debug symbols and no code optimization for debugging and another binary without debug symbols and with some code optimization for release.
But you can use debug symbols together with code optimization. In this case some variables will be missing and some lines of code will be probably jumped over but in general you can debug this way.

Android ndk-build command always produce binaries (your libnative.so files) with debug symbols and place them in obj/local/armeabi subdirectory of your project. Then
it strips off debug symbols and place stripped version in the final .apk (and thus in the device). ndk-gdb script uses this set solib-search-path command to point gdb to the unstripped binary so you can see your position in the source code. You can find the
set solib-search-path command in obj/local/armeabi/gdb.setup file.

If you have android:debuggable=”true” in your AndroidManifest.xml or if you run ndk-build with NDK_DEBUG=1 argument then ndk-build will produce binaries with no code
optimization. Otherwise code optimization will be used.

Sources

Gdb needs to have access to your source files. Otherwise it cannot show you the source code as it is executed. You can configure directory with your source files
by command

directory jni

You can enter more paths and separate them by space. Take a look into obj/local/armeabi/gdb.setup file for example.

How ndk-gdb and friends works

If you are using Android NDK, r5 and Android 2.3 device you can use ndk-gdb script which does everything for you.

If you have android:debuggable=”true” in your AndroidManifest.xml then ndk-build will add the gdbserver into your .apk package. This gdbserver will be started by
ndk-gdb and also all the other steps will be set up by this script.

Important caveat

Because gdbserver is attached to the already running process (as opposed to situation where process would be started by gdbserver) it can miss some code execution
which take place soon after the application start. There is no easy solution to this.

I usually write some endless while loop and then change the control variable after gdb is fully started. For example

1

int i = 0

2

while (!i) {

3

a++;

4

}

After ndk-gdb starts gdb session I can set breakpoints appropriately and change value of i variable by command

set var i=1

and then continue in application execution by gdb command c.

Multithread debug problem

It is well-known problem that ndk-gdb shipped with Android NDK, r4b used on Android 2.2 device was only able to hit the breakpoint on the main thread. If you set
breakpoint on any other thread gdb session will crash.

Every time new thread is created libc will call _thread_created_hook() function (which has empty body). The purpose of this function is that gdb will set breakpoint
on this function and thus will know that new thread was created. Gdb will then keep database of existing threads. Because of this gdb needs to have access to the libc.so file to figure out address of the _thread_created_hook() function.

Android NDK, r5 contains ndk-gdb which copies the file libc.so from the device (or emulator) and stores it in obj/local/armeabi subdirectory of your project. Also
gdbserver included in this ndk is compiled with libthread_db support. Both those two things are missing in Android NDK, r4b.

Links

Description of multithreading debug bug.
http://code.google.com/p/android/issues/detail?id=9713
Android NDK, r5
http://dl.google.com/android/ndk/android-ndk-r5-linux-x86.tar.bz2
Android ndk main page
http://developer.android.com/sdk/ndk/index.html
---------------------------------------------------------------------------------------------------------------
http://mhandroid.wordpress.com/2011/01/23/using-eclipse-for-android-cc-debugging/ 原文带图

Using Eclipse for Android C/C++ Debugging

Posted on January 23, 2011

Yes. You can use Eclipse for debugging of C/C++ code. I personally prefer cgdb but if you want to debug in Eclipse here is how.

See my previous spot how to set up cgdb debugger if you think it will suit you.

See my blog spot how to set up Eclipse for compiling and editing C/C++ code.

0) Prerequisities

You need Eclipse with CDT installed.

See my previous spot how to do it.

You also need Android ndk. Download it from http://developer.android.com/sdk/ndk/index.html and unpack it somewhere.

1) In Eclipse open your Android project which contains C/C++ code that you want to debug.

For this tutorial I’ve created simple MyAndroidProject.

2) Set android:debuggable=”true”. Set android:targetSdkVersion=”9″.

android:debuggable is a property of <application> tag in your AndroidManifest.xml. You can set it either directly in xml or in Application tab as in the screenshot.

android:targetSdkVersion=”9″ is a property of <uses-sdk> tag in your AndroidManifest.xml. You can set it either directly in xml or in Manifest tab as in the screenshot.

3) Run your application in debug mode and try to run ndk-gdb from console

To run application in debug mode press debug button (green bug/spider button in toolbox). In console go to your project directory and run ndk-gdb. It should succeed.
If it fails you have to resolve the problem. Running ndk-gdb does not only ensure us that we are doing everything right so far, but also creates app_process, gdb.setup and libc.so files in obj/local/armeabi/ subdirectory of our project. Those files will be
needed in later steps.

4) Create C/C++ debug configuration

Click on combo-box like down arrow next to debug button. Pop-up menu will appear and then select Debug Configurations…

In Debug Configurations window select C/C++ Application and press New button as advised on the right pane.

5) Set name of the debug configuration, and fill information on Main tab.

Select Standard Create Process Launcher by clicking on the blue Select other… link at the bottom of the window.

In C/C++ Application entry fill the path to the app_process binary which is located in obj/local/armeabi/ subdirectory of your project.

6) Click on Debugger tab and fill information about debugger.

Choose gdbserver Debugger as a Debugger.

It’s good idea to set initial breakpoint to some function but Android projects do not contain main function so fill some appropriate function name in Stop on startup
field (I filled Java_com_example_map_MyAndroidProject_doSomething but you can see only Java_com_exam on the screenshot).

Set path to GDB debugger. The debugger is distributed with the Android ndk. Its located at toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb.

Set path to GDB command line. This path should point to obj/local/armeabi/gdb2.setup file inside your project. You don’t have gdb2.setup file there yet but you will
create one in a while.

7) Click on the Connection tab (so you are in Debugger->Connection section of your C/C++ debug configuration) and fill information about connecting gdb with gdbserver.

Choose TCP as a type of connection and choose 5039 as a Port number.

8) Finally click Apply to save all the information about your C/C++ debug configuration.

This will save your new C/C++ debug configuration. Later, when running your application in debug mode you can choose in combo box associated with Debug button what
debug configuration you want to use. Now you have two debug configurations. Android Java one which was created automatically for you when you’ve created Android project. And C/C++ one you’ve just created.

9) Go to the obj/local/armeabi/ subdirectory of your project and copy gdb.setup file to gdb2.setup file. Remove target remote :5039 line from gdb2.setup.

Eclipse don’t like target remote :5039 line in gdb setup file because it wants to enter this command internally (that is why you configured port 5039 in the previous
step). Because the gdb.setup file is recreated by ndk scripts you have to copy it to the gdb2.setup and point Eclipse to the gdb2.setup file (we did this in step 6).

10) Go to the directory with Android ndk and copy ndk-gdb to ndk-gdb-eclipse. Remove execution of gdb command from ndk-gdb-eclipse.

Original content of ndk-gdb (Android NDK, r5):

578

if [ -n "$OPTION_EXEC" ] ; then

579

cat $OPTION_EXEC >> $GDBSETUP

580

fi

581

$GDBCLIENT -x `native_path $GDBSETUP`

Content of ndk-gdb-eclipse:

578

if [ -n "$OPTION_EXEC" ] ; then

579

cat $OPTION_EXEC >> $GDBSETUP

580

fi

581

## $GDBCLIENT -x `native_path $GDBSETUP`

Eclipse will run the gdb binary itself. So we have to remove the execution of gdb from ndk-gdb. To save original content it is good idea to copy the ndk-gdb to ndk-gdb-eclipse.

11) Now you are done. Put breakpoint in Java code after the execution of System.loadLibrary() and start your application in Debug mode.

Start your application in debug mode by clicking on Debug button. It will automatically choose Android debug mode. Later you will have to take care to choose Android
Java debugging configuration by clicking on combo arrow associated with the debug button.

The reason that breakpoint should be after System.loadLibrary() call is that our C/C++ code will be already loaded in that point and we can set breakpoints in it.

12) When execution reach the breakpoint run ndk-gdb-eclipse from your project directory and start debugging in C/C++ debug mode.

Go to the directory with your project and run ndk-gdb-eclipse. This will start server-part of the debugging infrastructure. Now click on the combo arrow associated
with the debug button in Eclipse and choose Debug Configurations… Choose your C/C++ debug configuration and click Debug button.

The C/C++ debug configuration will be added to recently used debug configurations so later you don’t have to walk into the Debug Configurations… window again and
you can choose between Android Java debug configuration and C/C++ debug configuration by just clicking on the combo arrow associated with debug button in Eclipse. However always make sure which debug configuration you are about to execute as this is where
mistakes happen very often (at least for me).

After you’ve started C/C++ debug configuration click Resume button (or press F8). The application should resume its run and stop on C/C++ breakpoint (if you have
one).

13) Now you are debugging the C/C++ code. Have fun!

Try to set some breakpoints in C/C++ code, etc.

Note on running ndk-gdb-eclipse

You have to run ndk-gdb-eclipse every time before starting C/C++ debug session. This script starts the gdbserver binary on device/emulator so gdb (run by Eclipse)
can connect to it.

I made several attempts to force Eclipse to run ndk-gdb-eclipse script itself on start of C/C++ debug session. The most logical point is to write small script which
will run ndk-gdb-eclipse without parameters (or with –force parameter) and then run gdb from Android ndk toolchain with all the parameters. This script can be used as GDB debugger command in the Debugger tab. But even if this script (and ndk-gdb-eclipse inside)
was run successfully, the resulting connection of gdb and gdbserver always broke apart.

Final note and thanks!

This tutorial is heavily inspired by Sequoyah Project native debug tutorial. See http://www.eclipse.org/sequoyah/documentation/native_debug.php
Many thanks to you guys.

---------------------------------------------------------------------------------------------------------------
http://mhandroid.wordpress.com/2011/01/23/using-cgdb-with-ndk-debug-and-cgdb-tutorial/ 原文带图

Using cgdb with ndk-debug (and cgdb tutorial)

Posted on January 23, 2011

Android ndk (http://developer.android.com/sdk/ndk/index.html) comes with ndk-gdb command that starts gdb debugger and connects it to Android application.

cgdb (http://cgdb.sourceforge.net/) is superior console front-end to gdb so it seems logical to use it for debugging of Android applications. Following modification
of ndk-gdb script will cause that cgdb will be invoked instead of gdb.

Original ndk-gdb (Android NDK, r5):

569

# Now launch the appropriate gdb client with the right init commands

570

#

571

GDBCLIENT=${TOOLCHAIN_PREFIX}gdb

572

GDBSETUP=$APP_OUT/gdb.setup

Modified ndk-gdb (originally from Android NDK, r5) which uses cgdb instead of gdb:

569

# Now launch the appropriate gdb client with the right init commands

570

#

571

GDBCLIENT="cgdb -d ${TOOLCHAIN_PREFIX}gdb --"

572

GDBSETUP=$APP_OUT/gdb.setup

Now if you run ndk-gdb you will get cgdb front-end.

Small cgdb tutorial

In cgdb you can have focus either on source window (part with the source text) or gdb window.

To switch from source window to gdb press i.

To switch from gdb window to source press esc.

Commands you can use in source window:

arrows — scroll the text

space — set or delete breakpoint

o — open source file

i — switch focus to gdb window

- — make source window 1 line smaller

= — make source window 1 line bigger

Commands you can use in gdb window:

n — next instruction. Will not dive into subfunctions

s — step. Will dive into subfunctions

c — continue

b — set breakpoint

bt — show call stack (backtrace)

info threads — show information about running threads

info breakpoints — show information about breakpoints

pgup, pgdown — scroll the content of gdb window

esc — switch focus to source windows

Full cgdb documentation is at http://cgdb.sourceforge.net/docs/cgdb-no-split.html
Full gdb documentation is at http://www.gnu.org/software/gdb/documentation/
Have fun!

---------------------------------------------------------------------------------------------------------------
http://mhandroid.wordpress.com/2011/01/23/using-eclipse-for-android-cc-development/ 原文带图

Programming in C/C++ on Android is just awesome! This tutorial shows how to setup Eclipse for using C/C++ together with Java in Android projects.

0) Prerequisities

You need to have Google ADT (Android Development Tools) installed. See http://developer.android.com/sdk/eclipse-adt.html how to do it.

You also need Android ndk. Download it from http://developer.android.com/sdk/ndk/index.html and unpack it somewhere.

1) Install CDT (C/C++ Development Tools) into Eclipse.

Choose Help->Install New Software… from the main menu.

Choose http://download.eclipse.org/releases/galileo as the source site. If you have another Eclipse release than Galileo choose the appropriate url.

Click Next, Accept licences and finish the installation process.

2) In Eclipse create Android project to which you want to add C/C++ code (if you already don’t have one).

For this tutorial I’ve created simple MyAndroidProject.

3) In file manager create jni/ directory in your project directory and place your C/C++ sources file here. Also put here Android.mk file which is a makefile that
tells Android build-system how to build your files.

Take a look into Android ndk docs/ANDROID-MK.html file how to create one.

Simple example of Android.mk file:

01

LOCAL_PATH := $(call my-dir)

02

03

include $(CLEAR_VARS)

04

05

LOCAL_LDLIBS := -llog

06

07

LOCAL_MODULE := native

08

LOCAL_SRC_FILES := native.c

09

10

include $(BUILD_SHARED_LIBRARY)

4) Refresh (F5) directories in Package Explorer to see jni directory here. Open your .c/.cpp file.

Your .c/.cpp file (native.c in my case) contains a lot of syntax errors which are not truly syntax errors. This is because Eclipse threats the project as a pure Java
project. We have to convert the project into mixed Java & C/C++ project.

5) Press Ctrl+n (or choose File->New->Other… from main menu) and select Convert to a C/C++ Project.

This will convert your project into a mixed Java & C/C++ project rather than into pure C/C++ project (the name of the function is misleading).

Click Next. Then choose your project and below choose Makefile project and – Other Toolchain –. Click Finish.

After doing this Eclipse will ask you if you want to switch to C/C++ perspective. Choose Yes because otherwise you wouldn’t be able to set C/C++ build preferences.

6) Click on your project with right button and select Properties or press Alt+Enter

Properties windows will appear. Here you have to configure use of ndk-build instead of make all command and set proper include paths.

7) Choose C/C++ Build and configure ndk-build as a build command

In Builder settings fill ndk-build into Build command entry. You have to uncheck Use default build command. You also need to have ndk-build script in your PATH.

In Behaviour setting uncheck clean (ndk-build cleans project automatically on build and does not support separate clean command) and clear all text from build (ndk-build
does not accept all as a parameter.

Click Apply to save settings.

8) Choose C/C++ General->Paths and Symbols and configure include path

In Includes tab choose GNU C or GNU C++ and click Add… button. Add path to include directory which is located in platforms/android-4/arch/arm/usr/include subdirectory
of place where you’ve unpacked Android ndk. Include path depends on target for which you are compiling (android-4 in my case — i.e. Android 1.6).

Finally click Apply and OK and that is all. Now you can use all Eclipse power for editing your C/C++ sources. If you click Run or Debug Eclipse will compile C/C++
code as well as Java code and run it on device/emulator. However you will not be able to debug C/C++ code.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: