Remotely debugging android NDK app using VSCode - android

I've tried a number of ways to get this to work but to no avail so far.
My requirements are as follows:
To be able to connect using visual studio code & gdb to a debug-enabled APK process running on an android device
The device should not have to be rooted
I expect full visual debugging of C++ NDK code on that device. Java code would be nice too but C++ is what I'm interested in.
I'm aware that the gdb server must run on the device. A python script in the NDK (ndk-gdb) can copy this to the device and execute it, which then launches its own shell which can be used to set breakpoints, which is useful in a pinch but nowhere near as intuitive as a full GUI.
So, given that the gdb-server is now running on the device, I should be able to connect to it.
I'm trying to use this 'launch.json' debug config in vs-code:
{
"name": "Debug App on Device",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceRoot}",
"program":"${workspaceRoot}\\android-build\\DebugSys\\system\\bin\\app_process64",
"additionalSOLibSearchPath": "${workspaceRoot}\\android-build\\obj\\local\\arm64-v8a",
"miDebuggerServerAddress": "192.168.1.121:5039",
"setupCommands": [{
"text": "set solib-absolute-prefix ${workspaceRoot}/android-build/",
"ignoreFailures": false
}],
"windows": {
"miDebuggerPath": "C:\\Users\\luthe\\AppData\\Local\\Android\\Sdk\\ndk\\23.1.7779620\\prebuilt\\windows-x86_64\\bin\\gdb.exe",
"MIMode": "gdb"
}
},
But running it gives me this error:
(No connection could be made because the target machine actively refused it).
This probably isn't a firewall issue as I'm able to connect to another server I have running, launched by the app in question on port 8080.
Is there an error in my 'launch.json' or am I going about all of this in entirely the wrong way.
Also, would it make sense for my app to launch the gdb server instead or is it better/neutral to have ndk-gdb do it?

In then end, I eschewed lldb in favour of gdb, which ndk-debug can use (for now, they're depreciating it, even though it works and lldb clearly either does not work or requires some setting that it doesn't advertise to work) if you include the 'no_lldb' flag or set 'use_lldb' to 'False' in ndk-gdb.py.
However, if you want visual debugging, you have to not let ndk-dbg.py launch the local gdb client. I've done this by creating a minimal batch file that connects to the phone and this may be useful for people reading this in the future in order to have a clear overview of what's happening on the android device and on the local machine. This script assumes only one device is attached for clarity.
adb shell forward tcp:5039 localfilesystem:/data/user/0/yourorg.yourapp/debug_socket #forward port 5039 to a temporary file called 'debug_socket'. I believe this is called is a 'Unix domain socket'
adb shell run-as yourorg.yourapp rm /data/user/0/yourorg.yourapp/debug_socket #remove the old socket file
adb push libs\arm64-v8a\gdbserver /data/local/tmp/arm64-gdbserver #push the arm64-gdbserver to a temp dir on the device
adb shell run-as yourorg.yourapp "cp /data/local/tmp/arm64-gdbserver /data/user/0/yourorg.yourapp/arm64-gdbserver" #copy the gdbserver to a directory from which it can be run with the privilages of the app you wish to debug
adb shell run-as yourorg.yourapp chmod 700 /data/user/0/yourorg.yourapp/arm64-gdbserver #Ensure 'arm64-gdbserver' is executable
adb shell run-as yourorg.yourapp /data/user/0/yourorg.yourapp/arm64-gdbserver --once +/data/user/0/yourorg.yourapp/debug_socket --attach 1234 #Run gdb server on device, connecting to the societ and the process '1234' (replace with actual PID of your running process)
Where 'yourorg.yourapp' is the name of your org and app and 1234 is the PID of the process to be debugged on your android device.
In visual studio code, you will need to have C++ extensions and gdb debugger extensions installed.
This is the 'launch.json' script that launches gdb locally and connects to the android device. Note that symbols are needed on the client side but not on the android device, so they can stripped if needed.
{
"name": "Debug pilkapel on device",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceRoot}",
"program":"${workspaceRoot}\\android-build\\DebugSys\\system\\bin\\app_process64",
"additionalSOLibSearchPath": "${workspaceRoot}\\android-build\\obj\\local\\arm64-v8a",
"miDebuggerServerAddress": "localhost:5039",
"setupCommands": [
{
"text": "set solib-absolute-prefix ${workspaceRoot}/android-build/",
"ignoreFailures": true
}
],
"windows":
{
"miDebuggerPath": "C:\\Users\\luthe\\AppData\\Local\\Android\\Sdk\\ndk\\23.1.7779620\\prebuilt\\windows-x86_64\\bin\\gdb.exe",
"MIMode": "gdb"
}
}
Also, compiler flags are important for this!
These are the compiler flags I used for the debug build of the library I'm working on:
LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS) -O0 -g -ggdb -gdwarf64
LOCAL_CPPFLAGS += -gfull -fstandalone-debug -Wl -gno-split-dwarf
LOCAL_CPPFLAGS += -fno-unique-internal-linkage-names -fno-direct-access-external-data
LOCAL_CPPFLAGS += -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes
LOCAL_CPPFLAGS += -Wformat -Werror=format-security -fno-limit-debug-info -fPIC
Some of these may be unnecessary for the task at hand, I did really quite a lot of iteration using lldb but nothing worked.
For gdb, I believe it needs -gdwarf-5 as the debugging format (which I gather is the default). When I specified -gdwarf-4 as part of my experimentations, the gdb server ran but breakpoints did not work.

Ok, so I still can't debug but I can now at least run the debug server and connect to it. It seems there's a problem with my symbol file for my C++ .so library which I'm trying to resolve here
The process I've used to run this on the device is this:
adb shell forward tcp:5039 localfilesystem:/data/user/0/totga.anthracite/debug_socket
adb shell run-as totga.anthracite rm /data/user/0/totga.anthracite/debug_socket
adb shell run-as totga.anthracite /data/user/0/totga.anthracite/arm64-lldb-server gdbserver unix:///data/user/0/totga.anthracite/debug_socket --attach 1234
where '1234' is the process ID on the device
and 'totga.anthracite' is my package name. You need to copy the 'arm64-lldb-server' to the data directory indicated (I'd run this step beforehand) and also remember to delete the 'debug_socket' file - that was messing things up before.
On the VSCode side, add something like this to 'launch.json'
{
"name": "Debug android app on device",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceRoot}",
"program":"${workspaceRoot}\\android-build\\DebugSys\\system\\bin\\app_process64",
"additionalSOLibSearchPath": "${workspaceRoot}\\android-build\\obj\\local\\arm64-v8a",
"miDebuggerServerAddress": "localhost:5039",
"setupCommands": [
{
"text": "set solib-absolute-prefix ${workspaceRoot}/android-build/",
"ignoreFailures": true
}
],
"windows": {
"miDebuggerPath": "${ANDROID_NDK_HOME}/prebuilt/windows-x86_64\\bin\\gdb.exe",
"MIMode": "gdb"
}
}
This should connect but, if like me you have no symbols, you still can't debug. Hopefully once that issue is resolved, this will work and I'll be able to debug native C++ code on an android device.

Related

ndk-gdb cannot find gdb.setup but it is there under x86

Cocos2d-x 3.7.1 + ndk r10e project on Mac trying to debug in Eclipse. Days pass and the errors keep coming...
I can build and run using cocos compile and cocos run with -p android -m debug --ndk-mode NDK_DEBUG=1 from the terminal in proj.android.
My app runs Ok (eventually) on my x86 emulator no problem.
Typing 'ndk-gdb' in the terminal from ./proj.android and I get the error
ERROR: Could not find gdb.setup under ./libs/
BUT the file gdb.setup (and gdbserver & libcocos2dcpp.so) can be seen in ./proj.android/libs/x86 !?
My AndroidManifest.xml includes android:debuggable="true"
My jni/Application.mk includes APP_ABI := x86 (only)
If anyone can tell me how I can diagnose or fix this problem then I guess I owe them a beer (in Yorkshire btw)
UPDATE: I have tried running up GDB using the --verbose flag. The output shows
Using gdb setup init: ./libs/armeabi/gdb.setup
Using app out directory: ./obj/local/armeabi
Guess I need to change to settings/init file somewhere??
I ran into the same problem. It seems something changed in recent version of Android Build tools.
The trick is:
ERROR: Could not find gdb.setup under ./libs/
It expects gdb.setup is in the directory libs but NOT libs/armeabi
so the simple workground is to copy gdb.setup and gdbserver from "libs/cpu" to "libs" and it works like a magic!
This is a bug caused by adb from android sdk.Issue 191085: ndk-gdb issue - Could not find gdb.setup under ./libs/ (even though it's there)
Currently previewl channel's adb whose version is 1.0.35 still has the same problem.
Without revert adb to 1.0.31.A simple workaround would be modify ndk-gdb a little: change the line if [ $? = 0 ]; then which is below adb_var_shell BCFILES run-as $PACKAGE_NAME /system/bin/sh -c "ls lib/*.bc" to if [ $? = 1 ]; then

How do I build Libgdx.so from source for Android with gdb tracing enabled?

I have setup a debug ROM on an Android device, and enabled the DDMS Native Heap in search for a libgdx memory leak.
I now have a trace, but no source code attached to follow the lead.
I downloaded libgdx source code.
How do I build it enabling gdb tracing so I can follow the code referenced by the trace ?
Update:
I built the debug .so libgdx from source
To do this, I modified the file:
libgdx/gdx/jni/build-android32.xml
Adding to the compile-natives target
I also added APP_OPTIM := debug to the Application.mk in the same folder
And added '-g' to the Android.mk file in the same folder:
LOCAL_CFLAGS := -g $(LOCAL_C_INCLUDES:%=-I%) -O2 -Wall -D__ANDROID__
This, indeed, produces a dbg libgdx.so dynamic library place in
libgdx/gdx/libs/armeabi
Although I am getting closer, I still cannot get the name of the function that is loading memory.
I am using arm-linux-androideabi-addr2line and the Hex address of the function, but it prints
??
Download the Android Source and build it.
Point DDMS to the libs with debug symbols. On the command line:
export ANDROID_SYMBOLS=$ANDROID_SOURCE/out/target/product/flo/symbols/system/lib
Note that $ANDROID_SOURCE refers to the location where you built the Android source.
start DDMS from that shell
$ddms
Now you should see the native traces on ddms.
I also built libgdx from source and added $LIBGDX_SOURCE/libgdx/gdx/obj/local/armeabi/libgdx.so
to $ANDROID_SOURCE/out/target/product/flo/symbols/system/lib to see the method names for libgdx.so.
Preliminaries
You need to set the device to debug memory
adb root
adb shell setprop libc.debug.malloc 1
adb shell stop
adb shell start
The device must be rooted or with a dbg ROM.

Function: selinux_android_load_priority [0], There is no sepolicy file

I have 2 errors in logcat.
Function: selinux_android_load_priority [0], There is no sepolicy file
04-11 10:58:13.837: E/SELinux(10101): Function: selinux_android_load_priority , loading version is VE=SEPF_SGH-I337M_4.3_0022
It's not fatal, my app seems to be fine.
Any idea what is the cause, and how do I fix it? Just can have Error Logs in my app!
I don't know how to get rid of those messages. But they do prevent the Android NDK ndk-gdb script from working. I found this question while searching for a way to get the debugger working after getting this error:
ERROR: Could not setup network redirection to gdbserver?
Maybe using --port=<port> to use a different TCP port might help?
This seems to be an issue with some phones - possibly Samsung phones, or at least the one that I am working with is a Samsung Galaxy Note 2. Certain commands (such as run-as) come with these selinux warning messages in stderr output.
The ndk-gdb script parses output from shell commands run on a device to determine facts like the path of the data directory for the package that it is debugging. The selinux messages interfere with that collection. To fix that problem, edit $NDK_HOME/ndk-gdb and make this change:
diff --git a/ndk-gdb b/ndk-gdb
index 537808e..c8561e5 100755
--- a/ndk-gdb
+++ b/ndk-gdb
## -620,7 +620,7 ## else
fi
# Find the <dataDir> of the package on the device
-adb_var_shell2 DATA_DIR run-as $PACKAGE_NAME /system/bin/sh -c pwd
+adb_var_shell DATA_DIR "run-as $PACKAGE_NAME /system/bin/sh -c pwd 2>/dev/null"
if [ $? != 0 -o -z "$DATA_DIR" ] ; then
echo "ERROR: Could not extract package's data directory. Are you sure that"
echo " your installed application is debuggable?"

How to compile C into an executable binary file and run it in Android from Android Shell?

I have a Device on which I installed Android Gingerbread 2.3.4
Here i want to run C executable file on android device
I am able to run android NDK application on this Device and it runs perfect.
But I want to run only one hello.c executable file on the Device.
/* #includes #defines ... */
int main(){
// Do something when this is executed
return 0;
}
Is there any way to compile this file with Android NDK tool chain so I can run this file's executable?
I found one thing here but this is not working for me. I am using Android NDK, Revision 7b for Linux.
There is no directory structure like this.
First, let me say that my answer is dependent on your using NDK r7b (it'll work for r7c as well) on Linux (change paths appropriately for other systems).
Edit: Last tested with NDK r8e on Linux and Nexus 4 with adb from SDK Platform-Tools Rev 18 on Windows 7 (latest as of 2013-07-25) without root access.
Yet Another Edit: Please read this question for altering my instruction for native binaries that need to run on Android 5.0(Lollypop) and later.
Go to $NDK_ROOT (The topmost folder of NDK zip when unzipped).
Copy $NDK_ROOT/samples/hello-jni directory as $NDK_ROOT/sources/hello-world.
Go to $NDK_ROOT/sources/hello-world.
Edit AndroidManifest.xml to give the application an appropriate name (This is optional).
Go to $NDK_ROOT/sources/hello-world/jni. This is where the source code is.
Edit hello-jni.c, remove all the code, and put in your hello world code. Mine is:#include
int main( int argc, char* argv[])
{
printf("Hello, World!");
return 0;
}
Edit Android.mk and change the line include $(BUILD_SHARED_LIBRARY) to include $(BUILD_EXECUTABLE). You can also change the LOCAL_MODULE line to the name you want for your executable(default is hello-jni)
Go back to $NDK_ROOT/sources/hello-world
Run ../../ndk-build to create the executable.
Copy it from $NDK_ROOT/sources/hello-jni/libs/armeabi/hello-jni to /data/local/tmp on the Android device and change it's permissions to 755 (rwxr-xr-x). If you changed the LOCAL_MODULE line in $NDK_ROOT/sources/hello-world/jni/Android.mk, the executable name will be the new value of LOCAL_MODULE instead of hello-jni. (All this is done via adb from the Android SDK.)
Execute the binary with full path as /data/local/tmp/hello-jni, or whatever you named it to.
And you're done( and free to start on the documentation in $NDK_ROOT/docs to get a better idea of what to do).
The best/easiest place to put a executable is /data/local. You'll also need to chmod the binary as executable. Often you'll also need to do this in two steps to get the binary from /sdcard/ to /data/local:
$ adb push mybin /sdcard/
$ adb shell
$ cp /sdcard/mybin /data/local/mybin
$ cd /data/local
$ chmod 751 mybin
Caveats:
Not all systems have cp. You can use cat if this is the case:
$ cat /sdcard/mybin > /data/local/mybin
Some systems don't allow write in /data/local for the "shell" user. Try /data/local/tmp
the "/sdcard" location is not executable, meaning that any file there is not executable at all.
the only way to "adb push" executable would be to put them in "/data/local", which should be writable for adb, and allow execution for anyone.
I recently had the same problem on a new nexus-5. I'd like to add that /data/local was not writable by the user ("shell", uid 2000) I got with adb shell. But putting the executable in the subdirectory /data/local/tmp/ worked fine.
In a nutshell,
First, to cross-compile your C code from your host machine, use NDK toolchain with sysroot option and position independent option -fPIE -pie.
$NDKROOT/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-gcc \
--sysroot=$NDKROOT/platforms/android-22/arch-arm64 -fPIE -pie main.c -o main
the arch part arrch64 or arch-arm64, the toolchain version part 4.9, platform version part android-22, and the binary format for your host machine darwin-x86_64 may vary by your environment.
Second, push your binary under /data/local/tmp and execute it from adb shell.

Debugging Android NDK native apps

I'm trying to debug and step through an Android application that segfaults. I've tried ndk-gdb, but with little luck. I've also referred to Android NDK Debugging without being able to debug my app.
When I try ndk-gdb --start, and I get:
$ ndk-gdb --start --verbose
Android NDK installation path: /opt/android-ndk-r7
Using default adb command: /opt/android-sdk-linux/platform-tools/adb
ADB version found: Android Debug Bridge version 1.0.29
Using final ADB command: '/opt/android-sdk-linux/platform-tools/adb'
Using auto-detected project path: .
Found package name: com.example.native_plasma
ABIs targetted by application: armeabi armeabi-v7a
Device API Level: 10
Device CPU ABIs: armeabi-v7a armeabi
Compatible device ABI: armeabi-v7a
Found debuggable flag: true
Found device gdbserver: /data/data/com.example.native_plasma/lib/gdbserver
Using gdb setup init: ./libs/armeabi-v7a/gdb.setup
Using toolchain prefix: /opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-
Using app out directory: ./obj/local/armeabi-v7a
Found data directory: '/data/data/com.example.native_plasma'
Found first launchable activity: android.app.NativeActivity
Launching activity: com.example.native_plasma/android.app.NativeActivity
## COMMAND: /opt/android-sdk-linux/platform-tools/adb shell am start -n com.example.native_plasma/android.app.NativeActivity
Starting: Intent { cmp=com.example.native_plasma/android.app.NativeActivity }
## COMMAND: /opt/android-sdk-linux/platform-tools/adb shell sleep 2
Found running PID: 0
ERROR: Could not extract PID of application on device/emulator.
Weird, this probably means one of these:
- The installed package does not match your current manifest.
- The application process was terminated.
Try using the --verbose option and look at its output for details.
This indicates that the application segfaulted more less, but I don't know how to set a breakpoint here since gdb never actually gives a prompt.
I also tried this command:
$ ../../toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-addr2line -f -e libs/armeabi/libnative-plasma.so
bedb2330
??
??:0
I have debug symbols I believe.
ndk-build -B V=1 APP_OPTIM=debug
Android.mk in jni/ has LOCAL_CFLAGS := -g
ant debug
I've also ndk-build NDK_DEBUG=1 but I still get where it looks like I don't have debug symbols.
Here's an image of the stack trace. It doesn't get any more informative:
Well NDK_DEBUG=1 and debuggable flag in manifest set to true are required. When you build the app,in your project/libs/armeabi, there should be a gdb.setup file. There is symbol search path there, check whether it is valid. And did you try this:
ndk-gdb --start --verbose --force
And looks like you are getting a null pointer exception.
In latest versions of NDK and Eclipse plug-in you can right click on package and choose Debug as -> Android Native Application
Make sure that you load your native library in either a launchable activity or in your Application class. Otherwise it wouldn't work and you'll get the following error No symbol table is loaded. Use the "file" command..
For example in Application class:
import android.app.Application;
public class MyApp extends Application {
static {
System.loadLibrary("Name");
}
public static native int doSomething();
}
Name is the name of your library (.so file) without the lib part.
I resolved putting --nowait option to the shell command:
ndk-gdb --start --verbose --nowait

Categories

Resources