1.binary instrumentation: 二进制执行文件插桩简介
2.什么是插桩测试测试插桩插桩程序设计
3.程序插桩分类
4.字节码插桩(四): AST
5.ASM 框架字节码插桩的常见用法
6.实战|Java 测试覆盖率 Jacoco 插桩的不同形式总结和踩坑记录
binary instrumentation: 二进制执行文件插桩简介
在二进制层面对执行文件进行插桩,能够摆脱对源码和编译器的源码依赖,广泛应用于测试、软件函数收集、插桩测试测试插桩无用函数检测等领域。源码静态插桩(static instrumentation)利用此方法在二进制层面实现代码覆盖分析,软件ida 源码无需编译器支持,插桩测试测试插桩能够达到极高的源码代码覆盖率,避免编译器优化对桩指令的软件影响,且不受编程语言、插桩测试测试插桩编译器差异的源码限制。静态插桩灵活且强大,软件能覆盖大部分场景,插桩测试测试插桩包括异常处理等复杂逻辑。源码静态插桩工具如bcov,软件能够对二进制代码进行代码覆盖率分析,通过在关键位置插入探针,控制流转移至跳板(trampoline),执行相关操作后,再返回原路径。bcov扩展ELF文件,插入代码段与数据段,用于跳板逻辑与覆盖率数据存储。在原始代码位置插入跳转指令,跳转至跳板,跳板中修改覆盖率数据,执行原始代码块指令。通过分析运行后的数据段,可以了解哪些代码被执行过。inline hook原理与trampoline hook相似,用于替换函数开头指令,转移执行流,执行所需逻辑后,回调执行原始指令,再跳转回原路径。inline hook处理时需注意被覆盖指令的跳转、函数执行体、寄存器变量污染等问题。动态插桩在运行时利用工具收集信息,对性能影响较小,源码解析大全适用于不依赖编程语言、编译器、操作系统的软件层面实现。动态插桩通过虚拟机实现,指令经过虚拟机处理,插桩相对容易。关于动态插桩的详细内容,已有文章进行深入讨论,感兴趣者可参考阅读。
什么是插桩程序设计
插桩程序设计是一种软件调试技术。 插桩程序设计的主要目的是为软件的调试和测试提供便利。具体来说,插桩程序设计是通过在目标程序中插入一些额外的代码段,即“桩”,以实现对程序运行时的某些特定行为或状态的监控和记录。这些插入的桩代码通常包含用于收集运行数据、追踪程序执行路径、验证程序逻辑等功能。 详细解释如下: 1. 插桩程序设计的核心思想:在软件开发过程中,为了确保软件的质量和性能,需要进行各种测试和调试。插桩程序设计是一种增强测试手段的技术。它通过插入额外的代码,帮助开发者了解程序在运行时的情况,从而找出潜在的错误和性能瓶颈。 2. 插桩的具体实现:插桩的实现方式有多种,包括静态插桩和动态插桩。静态插桩是在源代码阶段进行,直接在源代码中插入监控代码,然后编译生成目标程序。动态插桩则是在程序运行时,通过工具将桩代码注入到目标程序的运行过程中。这些桩代码可以监控程序的执行流程、调用外部函数、记录变量值等。 3. 应用与优势:插桩程序设计广泛应用于各种软件系统中,特别是在系统级软件、嵌入式系统以及性能要求较高的应用中。它能够帮助开发者准确了解程序的企业源码视频行为,从而进行针对性的优化和调试。此外,通过插桩,还可以实现一些特殊的监控功能,如内存泄露检测、性能分析、故障排查等。 总的来说,插桩程序设计是一种有效的软件调试和测试技术,它通过插入额外的代码来监控和记录程序的运行状况,从而帮助开发者发现和解决潜在的问题。程序插桩分类
程序插桩技术是一种通过在被测程序中插入探针来获取控制流和数据流信息的测试手段。其分类主要依据探针插入的时间点,分为目标代码插桩和源代码插桩。
目标代码插桩是在程序运行时进行的,它依赖于对目标代码的分析,确定需要插入探针的特定位置。由于目标代码格式与操作系统相关,与特定编程语言和版本关系不大,这使得它在内存监控等应用场景中广泛应用。然而,由于目标代码缺乏完整的语法和语义信息,对代码词法语法分析的要求较高,因此在覆盖测试工具中,通常采用源代码插桩,以确保插桩的准确性和针对性。
源代码插桩则是在编译前进行,它对源文件进行词法和语法分析,确保插桩的精确执行。这种方法能够提供高精度的插桩,针对性强。但同时,源代码插桩需要直接操作源代码,增加了工作量,并且随着编程语言和版本的变化,可能需要对插桩代码进行相应的调整。在本文中,我们将主要讨论的程序插桩形式是指源代码插桩,它在测试中的简图app源码应用更为广泛和深入。
字节码插桩(四): AST
在Android开发过程中,通过AndroidStudio生成Bean对象通常借助注解自动生成getter/setter方法、equals()和hashCode()方法,遵循驼式命名规则,确保类(或接口)名称首字母大写,方法名称首字母小写,类或实例变量同样遵循驼式命名法,首字母小写,常量全部由大写字母或下划线构成,且首字符不能是下划线。那么,编译器如何解析这些不规范的命名方式呢?这里涉及到一个关键的字节码插桩技术——AST(Abstract Syntax Tree)。
AST(Abstract Syntax Tree)是编译器对源代码进行初步加工后得到的结果,是一个树形结构表示的源代码。在Java编译过程中,编译流程大致分为三个阶段:第一阶段解析源文件为语法树;第二阶段调用注解处理器(APT模块),处理生成的新源文件;第三阶段将语法树转换为类文件。利用操作AST可以实现修改源代码的功能。
在代码实现层面,APT(Annotation Processing Tool)与AST结合使用,允许在编译期进行代码生成、代码检查或代码转换。AST操作属于编译器级别,对程序运行没有影响,效率相对其他AOP(Aspect-Oriented Programming)技术更高。
AST操作常见API包括但不限于:访问节点类型、获取节点子节点、设置节点属性等。在Android开发中,AST的应用场景广泛,特别是在代码规范检查方面。例如,Android Lint是一个静态代码检查工具,其内部已经封装了AST,用于扫描和检查Android工程代码,发现潜在问题,提醒程序员及时修正,提高代码质量。
在开发Linter工具时,源码求小数需求包括禁止日志输出、使用Toast、资源文件命名规范、避免自建线程等。开发步骤涉及创建Java工程、配置Gradle、创建Detector(负责扫描代码发现问题并报告)、实现Id类型检查、检查message.obtain()调用、避免创建Thread、序列化内部类检查、禁用系统Log/System.out日志等。
通过自定义IssueRegistry提供需要被检测的Issue列表,声明Lint-Registry属性并在build.gradle中声明,完成自定义Lint编码部分。利用AST,开发者可以有效地实现代码规范检查,提高代码质量,降低潜在错误,提升开发效率。
综上所述,AST在Android开发中扮演着重要角色,不仅能够辅助编译器完成解析任务,还能在代码编写阶段进行静态分析,帮助开发者遵守代码规范,提升代码质量。利用AST结合Linter工具,可以有效地提高开发效率,降低维护成本,确保代码的健壮性和可维护性。
ASM 框架字节码插桩的常见用法
ASM 是一款 Java 字节码操作工具,允许开发者在不修改源代码的情况下,以字节码形式创建类、修改类属性和方法,常用于开发辅助框架。在 Android 开发中,通过字节码插桩技术,实现热修复、事件监听、埋点等功能,与 Gradle 插件协同使用。ASM API 可以从官网下载,包含从4.0到最新版本的所有 jar 包,同时,JDK 内置 asm API,而 Gradle 内置 API 适用于 Android 开发。建议在 Android Studio 安装 ASM 相关插件,以便更高效地使用字节码技术。
ASM 的常见使用场景包括生成完整类、修改现有类、方法注入和方法调用注入。
生成完整类时,建议使用 `ClassWriter` 的 `COMPUTE_FRAMES|COMPUTE_MAXS` 参数,自动更新操作数栈和方法调用帧计算。生成类后,可打包供他人使用,实现面向字节码编程。
修改类时,可以增加属性、删除或修改方法,如新增 `phone` 字段,删除 `testA` 方法,修改 `testC` 方法访问权限,新增 `getPhone` 方法。修改后,生成的类文件可替换原文件,重新打包入 jar。
方法注入时,通过 ASM 代码避开构造方法,注入新的方法调用,增加特定功能,如调用 `Tool.useTool()` 方法。
ASM 功能强大,支持丰富的字节码操作。更多细节和高级用法参见官方文档和 GitHub 仓库,为开发者提供了灵活、强大的字节码编程手段。
实战|Java 测试覆盖率 Jacoco 插桩的不同形式总结和踩坑记录
本文为霍格沃兹测试学院优秀学员对 Jacoco 的总结和对使用过程中可能遇到的坑点记录。测试开发进阶学习,文末加群。一、概述
测试覆盖率是老生常谈的话题。本文主要关注Java后端的测试覆盖率。由于历史原因,公司基本不做单元测试(UT),因此我们更关心手工执行、接口执行(人工使用Postman等)、接口自动化、WebUI自动化对应用系统的覆盖度。
尽管Jacoco已流行多年,各种文档和帖子描述得很详细,但大多数文章都是针对特定形式的总结和使用方法。负责整个公司项目的覆盖率任务的人们需要一一研究和应对,经历多次入坑、出坑。
今年上半年负责公司不同类型的项目覆盖率统计技术的适配,对不同形式的项目有了一定的了解,记录下来,希望对他人有所帮助。本文由个人能力有限、表达能力有限所写,如有错误,欢迎指正。
二、投入覆盖率之前的思路
了解了Jacoco的部分机制,知道它提供了许多强大的功能,以满足不同形式的项目需求。Jacoco提供了API,可以屏蔽不同类型项目带来的困扰。
官方API示例地址:Jacoco.org/Jacoco/trunk...
使用API进行操作的好处包括:
屏蔽不同方式的构建部署。若想将此功能集成到平台中,API无疑是很好的方式。只需将Jacoco插桩到测试服务器上,暴露TCP IP和端口,剩余提取代码执行数据、生成覆盖率报告,就可以统一方式执行。Jacoco官方提供了Maven插件方式、Ant的XML方式,均有对应的dump和report进行覆盖率数据的dump和报告生成。三、项目梳理
公司是个老牌公司,项目杂乱无章,技术五花八门,至今仍有使用JDK6的项目。影响Jacoco使用过程的因素可能包括:
JDK版本:公司使用JDK6、7、8,JDK6是个分水岭,其他版本基本可用JDK8适配。构建方式:Maven构建、ANT构建,也有使用Gradle的可能。启动方式:Java -jar启动、通过命令行启动、使用Tomcat启动WAR包(打包方式灵活)。部署场景:线上部署、测试部署、开发部署可能采用不同方式,开发者多倾向于使用插件方式启动,因为快速且集成IDE。四、Jacoco插桩的本质
Jacoco介入部署过程的本质是插桩,可以是编译时插桩或运行时插桩。选择on-the-fly模式。
本质在于,在应用启动过程中,让Jacoco相关工具介入部署过程,即介入class文件的加载,在加载class时动态改变字节码结构,插入Jacoco的探针。以TCPserver方式进行插桩,应用启动时在端口上开启TCP服务,接收执行覆盖率信息并保存。提供API连接TCP服务,进行覆盖率数据的dump操作。
五、不同形式的插桩配置
介入启动过程需要一个jar包:Jacocoagent.jar。配置需要介入的jar包路径、过滤class文件、TCPserver端口号、访问地址等。针对不同启动方式,需要在相应的启动参数中加入配置,如在java命令、war包启动、Maven命令、ANT构建、Java -jar启动时加入相应的配置参数。
六、注意事项汇总
在配置过程中,需注意端口管理、变量作用域、代码适配性等问题,确保配置的正确性和兼容性。
七、说给想做平台的你
对于想做增量覆盖率的平台,需要自动化配置,集成devops平台,规划端口,使用API进行数据收集,确保不同启动方式的兼容性。
八、一些坑
在配置Ant构建时,确保compile阶段配置正确,避免数据无法注入。在多服务器部署负载均衡时,需要循环连接不同服务器的IP:port进行数据收集。确保编译环境的一致性,可以使用sftp下载代码。注意数据的及时保存和收集,防止覆盖率数据丢失或不准确。
九、补充API相关代码覆盖率数据的获取
可以封装覆盖率数据生成报告时所需的属性,如数据文件、源码、class文件等,生成报告时自动获取这些信息。若需要具体实现代码示例或获取更多代码,请参阅GitHub仓库。
十、总结
本文是对Java端覆盖率探索的细化总结,参考了相关资料和课程。期待与大家分享和探讨,共同进步。
简述源代码插桩是在程序执行前还是执行后完成的?原因是什么?
源代码插桩是在程序执行前完成的。这是因为源代码插桩需要在程序正式执行之前对代码进行修改,插入额外的代码逻辑,以实现特定的目的。如果插桩是在程序执行后完成,那么程序已经开始执行了,此时无法再对其代码进行修改。
在进行源代码插桩时,通常需要使用特定的工具或库,例如LLVM、Valgrind等。这些工具一般通过静态分析、抽象语法树(AST)等技术,在代码编译期间将插桩代码嵌入到源代码中。经过这些修改后的源代码,才会被编译成可以执行的二进制文件。
因此,源代码插桩必须在程序正式执行之前进行。在运行时进行代码修改或注入,通常是通过动态链接库或Hook技术实现,而不是通过源代码插桩完成的。