您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > C/C++/C#

黑盒不黑:跨端 C/C++ 库一键源码调试方案

时间:2022-07-27 15:44:08  来源:  作者:阿里技术

作者:王森(天作)

C/C++ 具有天然的跨平台特性,丰富的构建工具、Native 的性能以及成熟的社区生态,近年来移动端也越来越多的集成了一些使用 C/C++ 开发一些逻辑内聚且对性能要求较高的模块,特别是各类引擎模块例如音视频编解码、RPC 网络库、数据库、神经网络库等。

双向黑盒

但并不完美的是,C/C++ 技术栈在获得上述收益的同时,也使得原本用原生语言进行开发的体验产生了割裂,导致了不小的“隐性成本”,这点 Dropbox 在其分享的一系列 C++ 文章中也有提到。

https://dropbox.tech/mobile/the-not-so-hidden-cost-of-sharing-code-between-IOS-and-Android

C/C++ 工具链和构建环境比较复杂,Makefile、cmake、gn、ninja 等构建工具繁多,对环境的要求极高,因此这些库通常都是以链接后的静态库或者动态库的方式进行二进制分发,App 再进行二次链接之后进行调用。

在模块层和接入层都保障自己 Unit 不出问题的情况下,这一切看似都井井有条。但一旦出现问题需要排查的时候,C/C++ 二进制库对双方来说都是个黑盒:

  1. 对于底层模块开发者来说,代码的调用是在平台代码层,提供出去的二进制没法调试,“破案”就只能靠程序员传统艺能“打日志”的方式了;
  2. 对于业务接入层开发者来说,对方提供的二进制也无法调试,只能看到一行行难以理解的汇编代码,问题只能定位到自己输入输出,无法定位到更深层次的原因。

因此导致出现问题后的排查效率极低,甚至出现过一个问题来来回回排查好几天,影响项目进展。

源代码调试

LLDB 源码调试的原理是根据二进制中的 DWARF 调试信息找到对应源代码路径和行号等信息,在 mach-O 格式文件中,这部分信息存放在 __DWARF 相关的 Section 中,我们可以使用 dwarfdump 命令查看结构化的调试信息,elf 格式文件可以使用 objdump 查看:

 

由于 DWARF 中定义的源码路径本地并不存在,因此 LLDB 并不能进入源码调试模式,这时候要实现本地源码调试有两个方案:

  1. 在本机重新进行源码编译,这样生成的二进制库中定义的源码路径是本地真实存在的,但这又面临编译环境复杂问题;
  2. 免编译调试,想办法将二进制中的源码路径映射成本地真是存在的源码路径,这样不用重新编译也无需替换本地二进制库。

免编译调试

幸运的是 lldb 提供了命令可以修改路径,将二进制中的路径前缀映射到本地的真实路径,因此你可以在 Debug 控制台中输入以下指令实现本地调试:

 

再次点击单步调试后,我们就可以看到熟悉的源码调试界面:

 

但这,还是太麻烦了,首先这个命令不一定记得住,然后是需要从二进制中找到需要映射的路径地址,而且每次重新运行 app 之后又得重新输入一遍;因此,我们利用 lldb 提供的 lldbinit 和 Python/ target=_blank class=infotextkey>Python API,这些步骤都自动化完成,真正实现一键调试体验。

lldbinit 是 LLDB 在启动调试的时候提供给开发者自定义调试命令的接口文件,我们可以在源码根目录下放置一个 lldbinit 用于自定义源码映射的逻辑,于是调试的流程就变成:

 

自动映射源码

增加一个 python 文件,例如 debug.py ,存放在源码目录下,用 Python 实现以下伪代码步骤:

1、通过 Python API 查找指定的 Symbol 调试信息

 

2、约定规则,将 Python 文件默认认为存放在源代码的根目录,这样可以比较方便的获取本地源码路径:

 

 

3、然后需要找到调试信息中存储的路径与本地路径之间的前缀映射关系,可以通过遍历路径目录的方式逐级查找本地对应的源码是否存在:

 

4、再调用 lldb 命令将源码路径映射到本地路径:

 

5、以上替换的主要逻辑实现,需要通过一个 lldbinit 将这个方法添加给 lldb 运行时,我们可以通过添加 stop-hook 的方式让上述脚本自动运行:

 

工程改造

最后,通过一些简单的工程改造,便可以将调试应用到 Android 和 iOS 的日常开发环境中:

  1. 编译参数增加变量调试信息,大部分情况下不需要处理,但基于不同工具链或编译参数构建的二进制库中,有的缺少了 变量 的调试信息(通过 dwarfdump 可以查看是否存在 DW_TAG_variable 信息),导致在单步调试的过程中无法打印或者查看变量,只需要编译参数中增加或修改 -gfull 即可;
  2. DoNotStrip,Android 工程中,为了包大小通常会将 so strip 掉调试信息,因此在 Debug 环境下,可以将 so 改造成 DoNotStrip。

最后

通过这几十行的脚本,让 C/C++ 二进制库在各平台上能够使用默认的 IDE 快速进行源码调试,有助于提升问题排查效率和打破上下游边界。

除了应用在 C/C++ 模块,以上原理同样适用于 Swift 或者 ObjC、Rust 等其他任何能够生成 DWARF 调试信息并支持使用 lldb 调试的语言。

附上实现源码:

  • lldbinit:

 

  • debug.py:

 



Tags:黑盒   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
黑盒不黑:跨端 C/C++ 库一键源码调试方案
作者:王森(天作)C/C++ 具有天然的跨平台特性,丰富的构建工具、Native 的性能以及成熟的社区生态,近年来移动端也越来越多的集成了一些使用 C/C++ 开发一些逻辑内聚且对性能要求...【详细内容】
2022-07-27  Search: 黑盒  点击:(435)  评论:(0)  加入收藏
超适合新手的黑盒测试用例设计方法
等价类划分法1.1概念等价类划分法就是把程序的输入域划分成若干个部分(子集),然后从每个部分中选取少数代表性数据作为测试用例。每一类的代表性数据在测试中的作用等价于这一...【详细内容】
2022-02-17  Search: 黑盒  点击:(234)  评论:(0)  加入收藏
只需一个小黑盒,轻松搭建个人云盘,共享数据更安全
现在大家需要共享文件、备份资料时,首先想到的往往是某通讯APP和某网盘,但在安全性和可靠性上,这两大行业龙头表现却很糟糕,特别是在很多办公场合里,使用这种第三方软件也很臃肿,...【详细内容】
2020-12-22  Search: 黑盒  点击:(311)  评论:(0)  加入收藏
机器学习模型的黑盒公平性测试
论文摘要任何给定的人工智能系统都不能被接受,除非它的可信度被证明。值得信赖的人工智能系统的一个重要特征是没有算法偏见。“个体歧视”存在于给定个体与另一个体仅在“...【详细内容】
2020-06-21  Search: 黑盒  点击:(545)  评论:(0)  加入收藏
快看看你车上有没有?赶紧扔掉这种“黑盒子”,又有人中招!
飞机上必须有黑匣子来记录飞机的飞行数据但是汽车附近如果发现“黑匣子”那就得赶紧扔掉!这是骗子出来“冲业绩”了!近日,广东佛山顺德区警方接到市民胡女士报警称其将奔驰小汽...【详细内容】
2020-05-18  Search: 黑盒  点击:(417)  评论:(0)  加入收藏
▌简易百科推荐
C++中的外部模板及其在当前编译文件中的实例化
在C++中,模板是一种泛型编程的工具,它允许程序员以一种类型无关的方式编写代码。然而,模板的一个常见问题是它们会导致编译时间增加,特别是在大型项目中,当多个源文件包含相同的...【详细内容】
2024-04-11  鲨鱼编程  微信公众号  Tags:C++   点击:(12)  评论:(0)  加入收藏
C++常见避坑指南
C++ 从入门到放弃?本文主要总结了在C++开发或review过程中常见易出错点做了归纳总结,希望借此能增进大家对C++的了解,减少编程出错,提升工作效率,也可以作为C++开发的避坑攻略。...【详细内容】
2024-04-03  腾讯技术工程    Tags:C++   点击:(8)  评论:(0)  加入收藏
C++ 之父反驳白宫警告:自诞生第一天起,C++ 的目标就一直是提高安全性
整理 | 郑丽媛上个月,美国白宫国家网络主任办公室(ONCD)在一份主题为《回到基础构件:通往安全软件之路》的 19 页 PDF 报告中,呼吁开发人员停止使用容易出现内存安全漏洞的编程语...【详细内容】
2024-03-25    CSDN  Tags:C++   点击:(11)  评论:(0)  加入收藏
八个 C++ 开源项目,帮助初学者进阶成长
通过参与或阅读开源项目的源代码,你可以获得丰富的实践机会。实际的项目代码比简单的教程更具挑战性,可以帮助你深入理解 C++ 的各种概念和技术。1.ThreadPool一个简单的 C++1...【详细内容】
2024-03-22  AI让生活更美好  微信公众号  Tags:C++   点击:(27)  评论:(0)  加入收藏
C# 中15个值得收藏的开源项目推荐
在开源的世界里,C# 编程语言也占有一席之地。这些开源项目涵盖了多个领域,从框架、库到工具,它们为C#开发者提供了丰富的资源和工具,帮助他们更高效地开发、测试和部署应用程序...【详细内容】
2024-03-20  程序员编程日记  微信公众号  Tags:C#   点击:(33)  评论:(0)  加入收藏
C#异步编程:Task.Run vs. async-await,掌握基础与高级用法
概述:C#中的异步编程有两主要方式:Task.Run用于在后台线程执行同步操作,而async-await更适用于清晰表达异步流程。基础用法展示了它们的简单应用,高级用法则演示了它们的结合使...【详细内容】
2024-03-09  架构师老卢  今日头条  Tags:C#   点击:(34)  评论:(0)  加入收藏
C++多线程编程:解锁性能与并发的奥秘
今天我们将深入探讨C++中的多线程编程,揭示多线程如何解锁性能潜力,提高程序的并发性能。什么是多线程?在计算机科学中,多线程是指一个进程(程序的执行实例)中的多个线程同时执行...【详细内容】
2024-02-03     AI让生活更美好  Tags:C++   点击:(76)  评论:(0)  加入收藏
C++代码优化攻略
今天我们将深入探讨C++性能优化的世界。在当今软件开发的浪潮中,高性能的代码是必不可少的。无论是开发桌面应用、移动应用,还是嵌入式系统,性能都是关键。1. 选择合适的数据结...【详细内容】
2024-01-26  AI让生活更美好  微信公众号  Tags:C++   点击:(129)  评论:(0)  加入收藏
C# 线程本地存储为什么线程间值不一样
为什么用 ThreadStatic 标记的字段,只有第一个线程拿到了初始值,其他线程都是默认值,让我能不能帮他解答一下,尼玛,我也不是神仙什么都懂,既然问了,那我试着帮他解答一下,也给后面类...【详细内容】
2024-01-26  一线码农聊技术  微信公众号  Tags:C#   点击:(80)  评论:(0)  加入收藏
C++质数检测器的设计与实现​
质数,作为数学中的一个基本概念,一直以其独特的性质吸引着众多研究者和爱好者。质数是指大于1的自然数中,除了1和它本身以外不再有其他因数的数。在实际应用中,质数检测也扮演着...【详细内容】
2024-01-15  鲨鱼编程  微信公众号  Tags:C++   点击:(124)  评论:(0)  加入收藏
站内最新
站内热门
站内头条