Android emulator中C代码的调试——gdb/gdbservers时遇到的坑

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android emulator中C代码的调试——gdb/gdbservers时遇到的坑相关的知识,希望对你有一定的参考价值。

版权声明:本文为博主原创文章,未经博主允许不得转载。

 

先写个helloworld吧,在android源码树中创建文件夹external/helloworld,加入文件:

// helloworld.c
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** arv)
{
    printf("Hello world~\n"); 
    return 0;
}
# Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := helloworld
LOCAL_CFLAGS += -march=armv4
LOCAL_SRC_FILES := $(call all-subdir-c-files)
include $(BUILD_EXECUTABLE)

执行

$ mmm external/helloworld

生成可执行文件。

  • 启动模拟器并将待调试的文件上传到模拟器/data目录,(注意要传带调试信息的)
$ emulator&
$ adb push out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/LINKED/helloworld /data
  • 把gdbserver上传到模拟器
$ adb push prebuilts/misc/android-arm/gdbserver /data

我的平台是Mac OSX,在不同的平台下gdbserver的位置可能会不同。不过我发现在emulator的system/bin下面是有gdbserver的,所以如果不传,用这个默认的应该也可以。

  • 在设备上通过gdbserver启动Native程序
$ adb shell gdbserver :1234 /data/helloworld
  • 在远程调试机器上把本地tcp端口forward到设备的tcp端口
$ adb forward tcp:1234 tcp:1234
  • 在远程调试机器上运行gdb
$ ./prebuilts/gcc/darwin-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androideabi-gdb out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/LINKED/helloworld

gdb的路径会因平台而不同,helloworld要保证和模拟器上被调试的是同一个可执行程序。

  • 接下来是gdb的具体调试命令
(gdb) target remote :1234    # 连接到emulator的gdbserver
Remote debugging using :1234
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
Cannot access memory at address 0x0
0xb3446658 in ?? ()
(gdb) b main
Breakpoint 1 at 0xb34665cc: file external/helloworld/helloworld.c, line 6.
(gdb) c
Continuing.
warning: Could not load shared library symbols for 5 libraries, e.g. /system/bin/linker.
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?

Breakpoint 1, main (argc=1, arv=0xbe8c5ba4) at external/helloworld/helloworld.c:6
6        printf("Hello world~\n");
(gdb) n
5    {
(gdb) info sharedlibrary
From        To          Syms Read   Shared Object Library
                        No          /system/bin/linker
                        No          /system/lib/libc++.so
                        No          /system/lib/libc.so
                        No          /system/lib/libm.so
                        No          /system/lib/libnetd_client.so
(gdb) set solib-absolute-prefix out/target/product/generic/symbols/
Reading symbols from out/target/product/generic/symbols/system/bin/linker...done.
Loaded symbols for out/target/product/generic/symbols/system/bin/linker
Reading symbols from out/target/product/generic/symbols/system/lib/libc++.so...done.
Loaded symbols for out/target/product/generic/symbols/system/lib/libc++.so
Reading symbols from out/target/product/generic/symbols/system/lib/libc.so...done.
Loaded symbols for out/target/product/generic/symbols/system/lib/libc.so
Reading symbols from out/target/product/generic/symbols/system/lib/libm.so...done.
Loaded symbols for out/target/product/generic/symbols/system/lib/libm.so
Reading symbols from out/target/product/generic/symbols/system/lib/libnetd_client.so...done.
Loaded symbols for out/target/product/generic/symbols/system/lib/libnetd_client.so
(gdb) info sharedlibrary
From        To          Syms Read   Shared Object Library
0xb3445e20  0xb345af18  Yes         out/target/product/generic/symbols/system/bin/linker
0xb33bc920  0xb34032d8  Yes         out/target/product/generic/symbols/system/lib/libc++.so
0xb331c8d0  0xb33685ac  Yes         out/target/product/generic/symbols/system/lib/libc.so
0xb32e8e30  0xb3300450  Yes         out/target/product/generic/symbols/system/lib/libm.so
0xb32bcb08  0xb32be914  Yes         out/target/product/generic/symbols/system/lib/libnetd_client.so
(gdb)……

这部分命令是纯调试功夫了,可是我遇到的大坑就在这!上面的顺序是连接到emulator、设置断点、continue断住、设置动态库搜索路径、开始调试……


 

说一下我遇到的坑及现象。我认为连接设备、设置搜索路径这些都属于环境的搭建和配置,所以都放到了前面执行。next了两步就收到了signal,说是非法指令:

(gdb) target remote :1234
Remote debugging using :1234
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
Cannot access memory at address 0x0
0xb1df5658 in ?? ()
(gdb) set solib-absolute-prefix out/target/product/generic/symbols/
Reading symbols from out/target/product/generic/symbols/system/bin/linker...done.
Loaded symbols for out/target/product/generic/symbols/system/bin/linker
(gdb) n
33      bl __linker_init
(gdb) n

Program received signal SIGILL, Illegal instruction.
notify_gdb_of_load (info=0xbed759d8) at bionic/linker/linker.cpp:194
194      rtld_db_dlactivity();
(gdb) l
189      rtld_db_dlactivity();
190
191      insert_soinfo_into_debug_map(info);
192
193      _r_debug.r_state = r_debug::RT_CONSISTENT;
194      rtld_db_dlactivity();
195    }
196
197    static void notify_gdb_of_unload(soinfo* info) {
198      if (info->is_main_executable()) {
(gdb)

此时还没有碰到helloworld就挂了,list查看当前的位置在bionic/linker/linker.cpp:194。

google了好多地儿,有的说这是Android4.1.2的一bug,这类文章大多是2012年的,而且号称是已经fix掉了(http://code.google.com/p/android/issues/detail?id=40941)。还有的地儿出主意说现在这一行上断住,然后修改PC寄存器(http://visualgdb.com/android/linker-sigill/)我看signal的位置是由arm指令跳转到thumb指令,我试过,修改之后又冒出别的问题。我是用的是Android官方6.0.1_r11正式版的代码数,不应该有这么严重的问题。

后来请教别的同事,发现他的操作就能完成完整的调试。跟我操作上最明显的差别就是他每次都会换一个映射端口,怀疑是用过的端口再次映射会出问题。然后我反复回溯他的调试过程,发现真正的原因在于gdb命令的执行过程——不要过早地设定so路径。

以上是关于Android emulator中C代码的调试——gdb/gdbservers时遇到的坑的主要内容,如果未能解决你的问题,请参考以下文章

MacBook Pro中的Android Emulator中没有播放音频

Android emulator启动模拟器

android: ADB错误“more than one device and emulator”

Android模拟器(emulator)设置代理

Android Emulator 无法连接到 React-Native 远程调试器 - 连接时超时

VS2015 使用 Visual Studio Emulator For Android 调试无法命中断点的解决办法?