首先声名本文中的调试教程需要Android Root环境, 非越狱环境请使用Android Studio
笔者是从iOS开发转到Android的, 所以之前对lldb有一定的了解, 在iOS中我们可以使用debug-server+lldb调试iOS应用,前段时间正好做了一个Android端的native程序, 同样想单步调试一下c++代码,一开始想到使用gdbserver+gdb来调试但弄来弄去, 好像版本不匹配怎么也调不起来. 于是转念一想能不能用lldb呢, 毕竟Android Studio调试JNI使用lldb已经非常流行, 而且AS在逐步淘汰gcc的东西,似乎llvm前途更加光明

前提

要调试的目标程序编译时加了 -g -O0 选项, 只有这样程序才会包含调试信息, 否则你会发现,很多代码中的变量,无法访问, 且没办法看到源码.

准备

1. 获取lldb-server

1.1 从NDK中获得

ndk/21.3.6528147/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/9.0.8/lib/linux/aarch64/lldb-server
NDK中有4个lldb-server, 由于我的设备是64位的, 所以选择aarch64目录下的

1.2 从设备中提取

如果你的手机,曾经使用AS调试过JNI代码的话,看下手机的 /data/local/tmp 目录

adb shell ls -l /data/local/tmp
adb pull /data/local/tmp/lldb-server lldb-server

没有也不用担心, 随便用AS new 一个新工程, 选择Native C++. 然后在cpp文件中打个断点, 调试一下, 手机上自然就有了.

2. 启动lldb-server

将lldb-server放入设备并启动, 或者直接使用 /data/local/tmp/lldb-server就行

$ adb push lldb-server /data/local/tmp/
$ adb shell
cd /data/local/tmp
chmod 755 lldb-server
./lldb-server p --server --listen unix-abstract:///data/local/tmp/debug.sock

3.lldb连接lldb-server

$ lldb
platform list  # 看下lldb可以连接的平台
platform select remote-android
platform status # 查看平台状态
platform connect unix-abstract-connect:///data/local/tmp/debug.sock

注意看下 WorkingDir: /data/local/tmp 说明当前远端工作目录在这儿

调试

方式一

file [target_binary] # 指定将要调试的二进制文件,注意是相对于WorkingDir的路径
br set -f app_core.cpp -l 128 # 意思就是在app_core.cpp的128行处打个断点
run

此时Native程序应该已经启动起来, 如果断点在启动逻辑处, 应该也触发到断点了, 看看~ 多强大, 连代码里的注释都有, 简直不要太方便 😃

Process 6855 stopped
* thread #1, name = 'xxxx', stop reason = breakpoint 1.1
    frame #0: 0x0041343c xxxx`AppCore::run(this=0xf731f000) at app_core.cpp:128:17
   125 	
   126 	    // Initialize config
   127 	    core_server.init_config();
-> 128 	    core.set_reuse(true);
   129 	
   130 	    // 配置xxx

以上这种方式方便调试那种一启动就崩溃的bug, 可以在应用启动前打好断点, 启动时即可触发断点(launch breakpoint).

方式二

假如程序已经运行起来了, 我们可以用attach的方式, 将调试器附到可调试进程中, 并在目标文件打断点, 来调试具体逻辑

file  [target_binary] # 指定将要调试的二进制文件,注意是相对于WorkingDir的路径
platform process list # 查看一直远端的进程, 找到目标进程pid, 或者名称
attach 9053

此时,若附加成功,程序会断住 SIGSTOP, 像这样

Process 9053 stopped
* thread #1, name = 'xxx', stop reason = signal SIGSTOP
    frame #0: 0xf03a38e8 libc.so`__epoll_pwait + 20
libc.so`__epoll_pwait:
->  0xf03a38e8 <+20>: pop    {r4, r5, r6, r7}
    0xf03a38ec <+24>: cmn    r0, #4096
    0xf03a38f0 <+28>: bxls   lr
    0xf03a38f4 <+32>: rsb    r0, r0, #0
  thread #2, name = 'xxx', stop reason = signal SIGSTOP
    frame #0: 0xf03a3834 libc.so`__accept4 + 8
libc.so`__accept4:
->  0xf03a3834 <+8>:  svc    #0x0
    0xf03a3838 <+12>: mov    r7, r12
    0xf03a383c <+16>: cmn    r0, #4096
    0xf03a3840 <+20>: bxls   lr

OK, 现在就是设置断点的时机, 像方式一那样, 打断点, 然后

br set -f app_core.cpp -l 128
continue # 继续运行程序

当触发到断点时, 又可以愉快的调戏你的代码了.

LLDB 命令

lldb使用起来非常的方便, 有什么不会的, 直接在lldb中打help, 所有命令及解释明明白白, 当然你也可以上网扒扒LLDB的命令, 文章无数, 笔者这里列一些常用的命令供参考
lldb命令支持自动补全和简写, 所以上文中的 br = breakpoint. 类似的还有 c = continue. 只要不会和其它命令产生混淆, 使用简写也是完全没问题的, 若有歧义, 聪明的lldb也会友好的给出提示.
b = breakpoint 设置断点
c = continue 继续运行
n = next 下一行
s = step 单步进入
f = finish 跳出

p [var] 打印变量值
var 显示所有局部变量
bt 打印调用栈
up 在调用栈中向上移一帧 older
down 在调用栈中下移一帧 newer

register 查看寄存器
memory 查看内存

参考

LLDB

posted @ 2020-12-18 15:57 Coding&Life 阅读(9528) 评论(3) 推荐(2) 编辑
摘要: 前提条件 如果要调试Android系统库, 先确认AOSP编译时lunch的是eng或userdebug模式, 这样才会有调试工具在 或查看进程中是否存在JDWP线程 基本步骤 # 连接(无线调试需要)adb connect 172.xx.xx.xx# 查看进程IDadb shell ps | gr 阅读全文
posted @ 2020-12-16 17:09 Coding&Life 阅读(1079) 评论(0) 推荐(0) 编辑
摘要: 有时我们用C/C++编写的库,希望可以在Android / iOS上运行, 那么将其编译为Android/iOS的动态或静态库是个不错的选择, 这时就需要用到交叉编译, 意思就是在*nix或win平台编译出arm架构的库. 方法1: 手写编译命令 llvm/prebuilt/<host>/bin/c 阅读全文
posted @ 2020-11-11 11:09 Coding&Life 阅读(3133) 评论(0) 推荐(1) 编辑
摘要: 我的设备是*鱼上淘的Pixel 2, 2015年之后的设备刷写步骤基本一致(Pixel 2XL, Pixel 3, Pixel 3XL, Pixel 4) 上一篇博客讲了如何下载编译AOSP, 但只能编译出模拟器版本, 缺少厂商驱动(没有vendor目录), 不能用来刷机, 因此首先要下载厂商驱动 阅读全文
posted @ 2020-11-10 10:51 Coding&Life 阅读(4247) 评论(1) 推荐(0) 编辑
摘要: 我的环境 Ubuntu 18.04.5 LTS 清华源 https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/ 安装repo, 3种方式 # 1. 无需安装, 下载初始化包中自带最好用# 2. ubuntu apt-getsudo apt-get instal 阅读全文
posted @ 2020-11-09 19:25 Coding&Life 阅读(3647) 评论(0) 推荐(0) 编辑
摘要: Dart数据类型与iOS/Android转换关系表 The following table shows how Dart values are received on the platform side and vice versa: DartJavaKotlinObj-CSwift null nu 阅读全文
posted @ 2020-07-08 23:03 Coding&Life 阅读(2139) 评论(0) 推荐(0) 编辑
摘要: Arm64版: po [NSMethodSignature signatureWithObjCTypes:*((char**)(*((char**)(0x16fd96a40/*换成你的block实例地址*/ + 24))+ 32))] # 或者 po [[NSMethodSignature sign 阅读全文
posted @ 2020-05-25 12:24 Coding&Life 阅读(277) 评论(0) 推荐(0) 编辑
摘要: 本篇为大家带来MAME4iOS版编译打包操作详解 上一篇讲了笔者编译Andriod版MAME模拟器并打包运行的过程,这次分享一下iOS上的编译打包过程。(废话:文章上个月就写好了,我居然一直没点发布 ~_~ ) 环境: Mac OS X 10.14.4 Xcode 10.2.1 iOS分了越狱版和非 阅读全文
posted @ 2020-03-22 14:28 Coding&Life 阅读(4679) 评论(0) 推荐(0) 编辑
摘要: 重新 编译MAME4droid、MAME4all源码 阅读全文
posted @ 2019-12-21 19:40 Coding&Life 阅读(7256) 评论(4) 推荐(1) 编辑
摘要: 1. 安装Frida 首先需要安装Python3, 我下载的是 macOS 64-bit installer 安装(2019/04/26补充,建议用pyenv管理python多版本,同时方便切换。一些系统程序引用系统自带的python,直接安装其它版本有可能造成不确定的问题),因Macbook本机自 阅读全文
posted @ 2019-01-10 17:51 Coding&Life 阅读(4099) 评论(1) 推荐(0) 编辑
点击右上角即可分享
微信分享提示