在Android与iOS中使用LLDB调试Rust程序

2023-05-16

在这里插入图片描述

在Rust中通过println!()打印的日志信息在Xcode中可以显示,但是Android Studio里不显示。所以Android可以使用android_logger实现日志输出。但是开发中仅使用打印日志的方式进行调试还是不够的,我们还需要debug调式。所以有了本篇的内容。

LLDB(Low Level Debugger)是新一代轻量级高性能调试器, 是XcodeAndroid Studio中的默认调试器。相较于Android开发同学,iOS同学更熟悉它。Rust提供了基于LLDB的调试工具链,所以我们就可以借此用来调试Rust程序。

准备工作

首先建议你先阅读Rust库交叉编译以及在Android与iOS中使用这篇内容,了解如何将Rust程序集成进Android或iOS。本篇的例子也是使用此篇的demo。

不论是Android还是iOS,我们本篇的内容都使用CodeLLDB插件进行调试,所以你必须有安装 VS Code和此插件。

在这里插入图片描述

Android

具体操作

注意Android项目中我们需要将调试的so文件配置为不压缩优化,同时注意使用debug生成的so文件。

android {
	...

	packagingOptions{
    	doNotStrip "**/libxxx.so"
	}
}

1.push lldb-server到手机

adb push lldb-server /data/local/tmp/

如果之前你的设备有调式过JNI代码,那么此文件就会存在/data/local/tmp/目录下,可以忽略这一步。同理,如果你没有这个文件,可以新建一个Native C++项目调式一下。
请添加图片描述
或者去ndk中寻找lldb-server文件:

find . -name lldb-server

请添加图片描述
比如我的手机64位的, 所以选择aarch64下的。然后pushlldb-server到手机。

2.启动App,然后获取pid

# 启动App
adb shell am start -a android.intent.action.MAIN -n <package-name>/.<activity-name>
# 获取pid
adb shell pidof <package-name>

3.启动lldb-server

adb shell /data/local/tmp/lldb-server p --server --listen "*:9876"

4.rust项目debug配置

launch.json配置如下,作用是attch到目标进程。

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "attach",
            "name": "Android",
            "pid": "xxx",
            "initCommands": [
                "platform select remote-android",
                "platform connect connect://localhost:9876",
                "file target/aarch64-linux-android/debug/libxxx.so",
            ]
        }
    ]
}
  • pid 按照前面步骤获取的填入。
  • target/aarch64-linux-android/debug/librust_demo.so为调试二进制文件位置,保持与Android项目中的文件一致。

其他部分可以不用修改。然后Debug运行就可以打断点进行调式了。
请添加图片描述

问题

以上其实只适合root设备,否则执行attach xxx时会提示无权限。所以一开始我是使用的模拟器,然后获取root权限进行调试的。

后面看到了Android基础开发实践:如何分析Native Crash这篇gdb调试部分,找到了解决思路。

我们用Android Studio的lldb调试器进行native调试时有如下的输出:

请添加图片描述

从上面可以看出,Android Studio通过cat输出lldb-server并run-as以应用的权限执行cat进行接收,然后将lldb-server写入到app的私有数据目录,紧接着chmod 700增加可执行权限。然后使用同样的方式将一个shell脚本start_lldb_server.sh发送到app数据目录。最后以app的权限运行脚本启动lldb。

其实这个问题仔细想想,为啥as可以不用root就能调试,我们不行。所以就是抄as的作业:

adb shell "cat /data/local/tmp/lldb-server 
| run-as <package-name> sh -c 'cat > /data/data/<package-name>/lldb/bin/lldb-server 
&& chmod 700 /data/data/<package-name>/lldb/bin/lldb-server'"

# 启动lldb-server
adb shell run-as <package-name> ./lldb/bin/lldb-server p --server --listen "*:9876"

如果启动时,报Operation not permitted错误。可以使用unix-abstract方式,start_lldb_server.sh中就是此种方法实现。

adb shell run-as <package-name> ./lldb/bin/lldb-server p --server --listen unix-abstract:///<package-name>/debug.sock

相应的launch.json中的platform connect connect://localhost:9876替换为
platform connect unix-abstract-connect:///<package-name>/debug.sock

当然<package-name>/debug.sock名字随你怎么定义,这里只是给了一个建议格式,避免冲突。

优化

在第四步中,我们需要每次手动替换pid,这还是比较麻烦的。我们可以优化一下这里,动态获取pid。

创建tasks.json文件,输入以下内容:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "get pid",
            "type": "shell",
            "command": "adb shell pidof <package-name> | tr -d '\n' > ${workspaceRoot}/pid.txt"
        }
    ]
}

作用是获取pid,然后写入到pid.txt文件中。

launch.json修改如下:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "attach",
            "name": "Attach",
            "pid": "${input:pid}",
            "preLaunchTask": "get pid",
            "initCommands": [
                "platform select remote-android",
                "platform connect connect://localhost:9876",
                "file target/aarch64-linux-android/debug/libxxx.so",
            ]
        }
    ],
    "inputs": [
        {
            "id": "pid",
            "type": "command",
            "command": "extension.commandvariable.file.content",
            "args": {
                "fileName": "${workspaceFolder}/pid.txt"
            }
        }
    ]
}

运行时,读取pid.txt文件内容作为pid。

  • 注意这里使用extension.commandvariable.file.content需要vs code安装Command Variable插件。
  • 目前这种方式的问题是会先读取文件中的pid,早于get pid的执行。所以需要运行第二次才可以拿到正确的pid。但由于pid只要app不杀死就不会变动,所以问题不大。

Android虽然可以通过上述方法实现调试Rust代码,但毕竟没有as直接支持来的方便。目前来说,聊胜于无。

iOS

iOS整体比Android简单方便很多,首先和Android一样需要用debug静态库包(cargo lipo命令)。然后在 Frameworks,Libraries,and Embedded ContentLibrary Search Paths 配置libxxx.a
请添加图片描述
我用的模拟器,所以这里选择x86_64-apple-ios文件夹下的。

launch.json配置如下:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "attach",
            "name": "iOS",
            "program": "RustDemo",
        },
    ]
}

这里是根据App名称连接的,RustDemo就是这个的demo的名称。

启动App,然后debug就好了。
请添加图片描述
是不是非常简单。

参考

  • 使用GDB/LLDB调试Android的Rust程序
  • Android基础开发实践:如何分析Native Crash
  • LLDB调试Android Native程序
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在Android与iOS中使用LLDB调试Rust程序 的相关文章

随机推荐

  • Jetpack Compose 从入门到入门(二)

    开始布局部分 这部分我个人感觉没有必要每个组件 属性都详细说到 xff0c 否则篇幅会很长 建立起Compose中的组件与 Android Views的一个对应关系就够了 具体还是需要在实际的使用中去熟悉 1 Column 子元素按竖直顺序
  • Jetpack Compose 从入门到入门(三)

    本篇开始介绍Jetpack Compose 中的修饰符Modifier 修饰符可以用来执行以下操作 xff1a 更改可组合项的大小 布局 行为和外观 添加信息 xff0c 如无障碍标签 处理用户输入 添加高级互动 xff0c 如使元素可点击
  • 【操作系统】Linux系统中直接优化提升CPU性能(已解决)

    文章目录 问题 xff1a 服务器CPU没有调用最高性能 xff0c 导致跑算法的时候处理速度慢一 BIOS方法二 终端直接设置CPU调节器方法1 查看当前CPU调节器2 安装各种依赖库3 最后安装cpufrequtis工具包并设置CPU调
  • Jetpack Compose 从入门到入门(四)

    本篇开始介绍Jetpack Compose 中常用的组件 有一部分之前的文章中也出现过 xff0c 今天详细说明一下 1 Text 日常最常用的应该就是显示文字 xff0c 所以有必要说一下Text控件 首先源码如下 xff1a span
  • Jetpack Compose 从入门到入门(五)

    应用中的状态是指可以随时间变化的任何值 这是一个非常宽泛的定义 xff0c 从 Room 数据库到类的变量 xff0c 全部涵盖在内 由于Compose是声明式UI xff0c 会根据状态变化来更新UI xff0c 因此状态的处理至关重要
  • Jetpack Compose 从入门到入门(六)

    本篇说说Compose中的Canvas 1 Canvas span class token annotation builtin 64 Composable span span class token keyword fun span sp
  • Jetpack Compose 从入门到入门(七)

    本篇进入Compose 动画部分 1 动画预览 在本系列第一篇中我们提到过 xff0c 64 Preview可以帮我们实现UI的预览功能 xff0c 简单的交互和播放动画 在Android Studio Bumblebee xff08 大黄
  • Android 12 变更及适配攻略

    这几个月有点忙 xff0c 一年一篇的适配文章来的有点晚了 但其实也还好 xff0c 因为我们项目也是下半年才适配 我这边也是提前调研踩坑 xff0c 评估一下工作量 这个时间点也完全跟得上Google Play的审核要求 xff08 11
  • Jetpack Compose 从入门到入门(八)

    接着上一篇的动画部分 xff0c 本篇主要是自定义动画与Animatable AnimationSpec 上一篇中 xff0c 出现了多次animationSpec属性 xff0c 它是用来自定义动画规范的 例如 xff1a span cl
  • Jetpack Compose 从入门到入门(九)

    本篇是Compose的手势部分 点击 添加clickable修饰符就可以轻松实现元素的点击 此外它还提供无障碍功能 xff0c 并在点按时显示水波纹效果 span class token annotation builtin 64 Comp
  • 记参加 2022 Google开发者大会

    前几天有幸参加了2022年Google 开发者大会 Google Developer Summit xff0c 上一次参加Google开发者大会还是2019年 这期间因为众所周知的原因 xff0c 开发者大会都改为了线上举办 和上次相比可以
  • Jetpack Compose 从入门到入门(十)

    本篇介绍如何将Jetpack Compose 添加到已有应用中 xff0c 毕竟大多数情况都是在现有项目中使用 Jetpack Compose 旨在配合既有的基于 View 的界面构造方式一起使用 如果您要构建新应用 xff0c 最好的选择
  • Flutter状态管理之Riverpod 2.0

    两年前分享过一篇Flutter状态管理之Riverpod xff0c 当时riverpod的版本还是0 8 0 xff08 后来文章更新到0 14版本 xff09 当时提到过有一些不足之处 xff1a 毕竟诞生不久 xff0c 它还不能保证
  • Python:元组和字典简述

    目录 1 列表的方法2 for循环遍历列表2 1 语法2 2 range 函数 3 元组3 1 元组的基本概念3 2 元组的创建3 3 元组的解包3 3 1 号在解包中的用法 4 字典4 1 字典的基本概念4 2 字典的使用4 2 1 字典
  • 七种常见软件开发模型

    目录 瀑布模型 xff08 面向文档的软件开发模型 xff09 演化模型 螺旋模型 增量模型 构件组装模型 统一过程 xff08 up xff09 xff08 迭代的软件过程 xff0c 以架构为中心 xff09 敏捷开发模型 瀑布模型 x
  • IP安全策略:只允许指定IP连接远程桌面,限制IP登录

    一 xff0c 新建IP安全策略 WIN 43 R打开运行对话框 xff0c 输入gpedit msc进入组策略编辑器 依次打开 本地计算机 策略 计算机配置 Windows设置 安全设置 IP安全策略 在 本地计算机上 在右面的空白处右击
  • 2022年终总结

    不知不觉就到了年末 xff0c 感叹时间过的真快 我自己坚持写了七年多的博客 xff0c 但这其实是我第一次去写年终总结 也不知道怎么写 xff0c 就简单聊聊 写博客的初衷就是个人收获 xff0c 学习的记录 xff0c 分享出来如果能帮
  • Rust库交叉编译以及在Android与iOS中使用

    本篇是关于交叉编译Rust库 xff0c 生成Android和iOS的二进制文件 xff08 so与a文件 xff09 xff0c 以及简单的集成使用 1 环境 系统 xff1a macOS 13 0 M1 Pro xff0c Window
  • 利用Rust与Flutter开发一款小工具

    1 起因 起因是年前看到了一篇Rust 43 iOS amp Android xff5c 未入门也能用来造轮子 xff1f 的文章 xff0c 作者使用Rust做了个实时查看埋点的工具 其中作者的一段话给了我启发 xff1a 无论是 Loo
  • 在Android与iOS中使用LLDB调试Rust程序

    在Rust中通过println 打印的日志信息在Xcode中可以显示 xff0c 但是Android Studio里不显示 所以Android可以使用android logger实现日志输出 但是开发中仅使用打印日志的方式进行调试还是不够的