• Android系统中调试动态链接库so文件的步骤


    原文:http://blog.wjmjimmie.cn/archives/154.html

    Android系统中调试动态链接库.so文件的步骤

    (于2010年8月5日更新,提示可用gdbtui调试,以及调试动态链接库有时遇到的调试问题,在第3.2节和第4节增加)

    参考文章:
    gdbserver调试共享库 http://www.limodev.cn/blog/archives/393
    android中c/c++程序的调试(eclipse) http://xy0811.spaces.live.com/blog/cns!F8AECD2A067A6B17!1480.entry#

    参考代码:(文件内容见最下面)
    ~/mydroid/android-1.6_r2/development/self/HelloWorld/Android.mk
    ~/mydroid/android-1.6_r2/development/self/HelloWorld/HelloWorld.c
    ~/mydroid/android-1.6_r2/development/self/libtest/Android.mk
    ~/mydroid/android-1.6_r2/development/self/libtest/libtest.h
    ~/mydroid/android-1.6_r2/development/self/libtest/libtest.c

    使用的平台:
    系统平台:ubuntu10.4 LTS
    源代码版本:Android 1.6r2
    Emulator平台:Android 1.6(SDK是Android2.2,这个版本没大关系了)

    注:编译Android略过,编译目标是默认的generic release版,若需要调试dalvikvm等系统自带程序,最好编译debug版本。
    (以下默认shell都已执行过 $ source build/envsetup.sh)
    更改debug版的命令是:

    tapas

    (选择device debug generic eng)
    (小提示:执行“lunch 2”命令,可以将Android编译目标更改为编译主机程序,编译的dalvikvm可以直接在ubuntu下运行,某种情况下还是很有用的)

    0. 准备工作
    启动模拟器

    emulator -avd aaa

    在Android源代码根目录执行

    source build/envsetup.sh

    1. 使用没有被strip版本的执行文件HelloWorld和libtest.so
    在Android源代码根目录下依次执行

    make libtest
    make HelloWorld

    没有被strip的版本所在位置是
    ~/mydroid/android-1.6_r2/out/target/product/generic/symbols/system/bin/HelloWorld
    ~/mydroid/android-1.6_r2/out/target/product/generic/symbols/system/lib/libtest.so

    将HelloWorld push到/data/bin/目录下,将libtest.so push到/system/lib/目录下

    $ adb push ~/mydroid/android-1.6_r2/out/target/product/generic/symbols/system/bin/HelloWorld /data/bin/
    $ adb remount
    $ adb push ~/mydroid/android-1.6_r2/out/target/product/generic/symbols/system/lib/libtest.so /system/lib/

    2. 启动gdbserver
    Android1.6模拟器中自带gdbserver程序,在Android模拟器中执行如下命令:

    gdbserver :1234 /data/bin/HelloWorld

    正常的话结果应该是:(不正常的话就自己查吧)

    Process /data/bin/HelloWorld created; pid = 206
    Listening on port 1234

    不要忘记上面的pid,忘记了就ps呗

    3. 启动arm-eabi-gdb进行调试连接

    3.1 首先设置模拟器端口转发:

    adb forward tcp:1234 tcp:1234

    3.2 启动arm-eabi-gdb:(android源代码prebuild目录下有相应文件,有多个版本,没查有什么区别,我用的是4.4)
    (2010/08/05+:用arm-eabi-gdbtui调试也可,只是上下左右方向键是用来控制源代码显示的。另外,有些程序不需要第5步就可以调试动态链接库,目前不知道为什么,但要在gdb中调用set solib相关的两个命令(参照3.3节),并且是绝对路经,其实之前用相对路径没有效果。进入动态链接库调试时可以使用n,尽管显示代码位置会到处乱跳,但在关键函数处倒也正确。)

    ~/mydroid/android-1.6_r2/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi-gdb ~/mydroid/android-1.6_r2/out/target/product/generic/symbols/system/bin/HelloWorld

    启动后会显示:

    GNU gdb 6.6
    Copyright (C) 2006 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type "show copying" to see the conditions.
    There is absolutely no warranty for GDB.  Type "show warranty" for details.
    This GDB was configured as "--host=i686-pc-linux-gnu --target=arm-elf-linux"...

    3.3 首先执行set solib-×××的两个命令:(可选,只调试HelloWorld及其动态库的话不执行也无碍,最好是绝对路径,用自动扩展的写法可能不行)

    (gdb) set solib-absolute-prefix /home/j/mydroid/android-1.6_r2/out/target/product/generic/symbols/
    (gdb) set solib-search-path /home/j/mydroid/android-1.6_r2/out/target/product/generic/symbols/system/lib/

    3.4 连接gdbserver调试:

    (gdb) target remote :1234

    成功的话会显示:

    __dl__start () at bionic/linker/arch/arm/begin.S:35
    35      mov r0, sp
    Current language:  auto; currently asm

    如果没执行set solib-×××的两个命令会显示如下信息,但没关系

    warning: Unable to find dynamic linker breakpoint function.
    GDB will be unable to debug shared library initializers
    and track explicitly loaded dynamic code.
    0xb0000100 in ?? ()

    4. 进行gdb调试
    首先执行两个命令:

    (gdb) b main
    (gdb) c

    这是调试会停在HelloWorld.c的main函数处,提示信息如下:

    Continuing.
    Error while mapping shared library sections:
    libc.so: No such file or directory.
    Error while mapping shared library sections:
    libstdc++.so: No such file or directory.
    Error while mapping shared library sections:
    libm.so: No such file or directory.
    Error while mapping shared library sections:
    libtest.so: No such file or directory.
    Breakpoint 1, main ()
    at /home/j/mydroid/android-1.6_r2/development/self/HelloWorld/HelloWorld.c:6
    6       printf("main 1");
    Current language:  auto; currently c

    最后几行表示调试正常,如果你编的debug版的Android,前几行会显示加载动态库成功,但也不能直接进入动态链接库进行调试的:)至少我这里不能。
    (2010/08/05+:这个时候可以通过info share来判断。执行info share命令会显示当前动态链接库加载的内存地址,若显示的地址与第5节获得的地址相同,则说明可以调试动态链接库,并且应该可以用n命令,若不同,则请尝试第5节的办法。)

    这时你可以通过基本的gdb调试命令进行调试:

    (gdb) n     (执行下一条)
    (gdb) b 10  (在第10行设断点)
    (gdb) list  (显示源代码信息)
    (gdb) c (继续至下一断点或结束)

    (注:其实我不了解gdb调试,还是google一下比较好)

    若你在func()处执行s命令进入func()函数体,就会提示错误,也无法进行正常调试了,如何调,请继续下一节—

    5. 加载动态库so文件进行调试
    这部分的工作参考 gdbserver调试共享库 这篇文章就可以了,不过我还是重复一下Android平台的步骤:

    5.1 查看动态链接库加载的内存地址

    adb shell cat /proc/206/maps

    结果中会有如下几行:

    00009000-0000a000 rwxp 00001000 1f:01 712        /data/bin/HelloWorld
    40000000-40008000 r-xs 00000000 00:07 186        /dev/ashmem/system_properties (deleted)
    80000000-80001000 r-xp 00000000 1f:00 713        /system/lib/libtest.so
    80001000-80002000 rwxp 00001000 1f:00 713        /system/lib/libtest.so
    afc00000-afc21000 r-xp 00000000 1f:00 478        /system/lib/libm.so

    记录下80000000这个地址。

    5.2 查看动态链接库libtest.so中text段的偏移地

    ./prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi-objdump -h ~/mydroid/android-1.6_r2/out/target/product/generic/symbols/system/lib/libtest.so |grep .text

    结果显示为:

    5 .text         00000034  00000344  00000344  00000344  2**2

    记录00000344这个地址。

    5.3 在gdb中加载动态链接库
    在gdb命令行执行如下命令:(其中0×80000344是80000000+00000344=80000344)

    (gdb) add-symbol-file /home/j/mydroid/android-1.6_r2/out/target/product/generic/symbols/system/lib/libtest.so 0x80000344

    5.4 进入动态链接库进行调试
    有两种进入动态链接库进行调试的方式:

    5.4.1 通过s命令进入
    设置断点在func()函数被调用处:

    (gdb) b 10
    (gdb) c

    当调试停在HelloWorld.c的第十行时,执行s命令:

    Breakpoint 2, main ()
    at /home/j/mydroid/android-1.6_r2/development/self/HelloWorld/HelloWorld.c:10
    10          func();
    (gdb) s

    这时就会显示libtest.c的代码,执行list命令进行查看:

    func () at /home/j/mydroid/android-1.6_r2/development/self/libtest/libtest.c:3
    3   void func(){
    (gdb) list
    1   #include "stdio.h"
    2   #include "libtest.h"
    3   void func(){
    4       printf("libtest 1");
    5       printf("Hello, This is a function in libtest!");
    6       printf("libtest 2");
    7   }

    5.4.2 通过设置断点进

    在libtest.c中设置断点:

    (gdb) b libtest.c:5
    Breakpoint 3 at 0x80000352: file /home/j/mydroid/android-1.6_r2/development/self/libtest/libtest.c, line 5.
    (gdb) c
    Continuing.
    Breakpoint 3, func ()
    at /home/j/mydroid/android-1.6_r2/development/self/libtest/libtest.c:5
    5       printf("Hello, This is a function in libtes

    t!”);

    如此,就可以进行了动态链接库的调试了。

    注意:我在使用时,在进入到动态链接库中调试时无法使用n命令,可以使用c finish b等命令。

    下面这两个页面有改进的调试:
    用gdbserver调试共享库(改进版) http://blog.csdn.net/absurd/archive/2007/09/20/1793646.aspx
    gdbserver调试共享库(终结版) http://www.limodev.cn/blog/archives/477

    参考文章:
    gdbserver调试共享库 http://www.limodev.cn/blog/archives/393
    android中c/c++程序的调试(eclipse) http://xy0811.spaces.live.com/blog/cns!F8AECD2A067A6B17!1480.entry#

    附文件内容:

    ./HelloWorld/Android.mk

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    LOCAL_PATH:= $(call my-dir)
    include $(CLEAR_VARS)

    LOCAL_SRC_FILES := 
    HelloWorld.c

    LOCAL_MODULE:= HelloWorld

    LOCAL_SHARED_LIBRARIES += 
    libtest

    include $(BUILD_EXECUTABLE)

    ./HelloWorld/HelloWorld.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #include "stdio.h"
    #include "../libtest/libtest.h"

    int main()
    {
    printf("main 1");
    int a=10;
    while(a--){
    printf("while 1");
    func();
    printf("while 2");
    };
    printf("Hello Androidn");
    printf("main 2");
    }

    ./libtest/Android.mk

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    LOCAL_PATH:= $(call my-dir)
    include $(CLEAR_VARS)

    LOCAL_PRELINK_MODULE := false

    LOCAL_SRC_FILES := 
    libtest.c

    LOCAL_MODULE:= libtest

    include $(BUILD_SHARED_LIBRARY)

    ./libtest/libtest.h

    1
    void func();

    ./libtest/libtest.c

    1
    2
    3
    4
    5
    6
    7
    #include "stdio.h"
    #include "libtest.h"
    void func(){
    printf("libtest 1");
    printf("Hello, This is a function in libtest!");
    printf("libtest 2");
    }
    阅读(476) | 评论(0) | 转发(0) |
    给主人留下些什么吧!~~
    评论热议
  • 相关阅读:
    以证书的方式登录ssh
    JSPatch在MAC下的使用
    sqlite3使用备忘
    iOS模拟器录屏转gif神器
    UINavigationController + UIScrollView组合,视图尺寸的设置探秘(三)
    UINavigationController + UIScrollView组合,视图尺寸的设置探秘(二)
    UINavigationController + UIScrollView组合,视图尺寸的设置探秘(一)
    内容可循环重用的ScrollView
    关于Logger
    Git入门操作
  • 原文地址:https://www.cnblogs.com/black/p/5171695.html
Copyright © 2020-2023  润新知