如何编写自己的Java / Scala调试器

通过这篇文章,我们将探讨Java / Scala调试器的编写和工作方式。 诸如Windows的WinDbg或Linux / Unix的gdb之类的本机调试器通过操作系统直接提供给它们的钩子来获取其强大功能,以监视和操纵外部进程的状态。 JVM充当OS之上的抽象层,它提供了自己的独立体系结构来调试字节码。 blog_MyDebugger2

该框架及其API是完全开放的,有文档的和可扩展的,这意味着您可以轻松编写自己的调试器。 该框架的当前设计由两个主要部分组成-JDWP协议和JVMTI API层。 每种方法都有其自己的一套优点和最佳用例。

JDWP协议

Java调试器有线协议通常用于在网络上使用二进制消息在调试器和被调试进程之间传递请求和接收事件(例如线程状态或异常的更改)。 该体系结构背后的概念是在两者之间建立尽可能多的隔离。 这是为了减少让调试器在目标代码运行时改变其执行的海森堡效应(物理学家维尔纳,而不是友好的Meth Cooking Walt )。

从目标进程中删除尽可能多的调试器逻辑也有助于确保已调试VM状态的更改(例如“停止世界” GC或OutOfMemoryErrors)不会影响调试器本身。 为了简化操作,JDK附带了JDI (Java调试器接口),该接口提供了协议的完整调试器端实现,并具有连接,分离,监视和操纵目标VM的状态的能力。

例如,该协议与Eclipse的调试器使用的协议相同。 如果查看在IDE调试时传递给Java进程的命令行参数,您会注意到Eclipse传递给它的其他参数(-agentlib:jdwp = transport = dt_socket,…)来启用JVM调试,并且还会建立发送请求和事件的端口。

JVMTI API

现代JVM调试器体系结构中的第二个关键组件是一组本机API,涵盖了与JVM操作相关的广泛领域,称为JVM工具接口 (即JVMTI)。 与JDWP不同,JVMTI被设计为一组C / C ++ API,并且具有JVM动态加载利用API提供的命令的预编译库(例如.dll或.so)的机制。

这种方法与JDWP的不同之处在于,它实际上在目标进程内部执行调试器。 这增加了调试器在性能和稳定性方面影响应用程序代码的可能性。 但是,关键优势在于能够以近乎实时的方式直接与JVM交互。

由于JVMTI提供了一组功能强大的低级API集,所以我认为有必要进一步深入研究并解释其工作原理,以及可以使用它进行哪些出色的工作。 可通过JDK随附的jvmti.h获得API标头。

编写调试器库

编写自己的调试器需要使用C ++创建本机OS库。 在这种情况下,您的“主要”功能看起来像–

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void*)

当您的调试器代理由JVM加载时,该函数将由JVM调用。 传递给您的日益重要的JavaVM指针将为您提供与JVM对话所需的一切。 它引入了JavaVM :: GetEnv方法中可用的jvmtiEnv类,该类使您能够通过功能和事件的概念与JVMTI层进行交互。

JVMTI功能

编写调试器的关键方面之一是要特别注意调试器代码对目标进程的影响。 这对于本机调试器库尤其重要,在该库中,代码与应用程序非常紧密地运行。 为了帮助您更好地控制调试器如何影响代码的执行,JVMTI规范引入了功能概念。

在编写调试器时,您可以提前告诉JVM您打算使用哪些API命令或事件集(即设置断点,挂起线程等)。 这使JVM可以提前为此做准备,并使您可以更好地控制调试器的运行时开销。 这种方法还使来自不同供应商的JVM能够以编程方式告诉您整个JVMTI规范中当前支持哪些API命令。

并非所有能力都是平等的 。 某些功能的性能开销相对较小。 其他有趣的,如can_generate_exception_events接收回调时异常的代码抛出,或用于接收回调时获取锁定can_generate_monitor_events,付出更高的成本。 原因是它们阻止JVM在JIT编译期间完全优化代码,并可能迫使JVM在运行时进入解释模式。

其他功能,例如can_generate_field_modification_events用于在设置目标对象字段(即设置监视)时接收通知,其成本甚至更高,从而使代码执行速度大大降低。 即使JVM支持同时加载多个本机库,HotSpot中的某些功能(例如can_suspend用于挂起和恢复线程)也只能一次声明一个库。

构建Takipi的生产调试器时,我们面临的最困难的部分之一就是提供类似的功能,而又不会产生这种开销(在以后的文章中会介绍更多)。

设置回调 。 收到一组功能后,下一步就是设置回调,JVM将调用这些回调以让您知道实际发生的时间。 这些回调中的每一个都会提供有关发生的事件的相当深的信息。 例如,对于异常回调,此信息将包括引发异常的字节码位置,线程,异常对象以及是否以及将在何处捕获该异常。

void JNICALL ExceptionCallback(jvmtiEnv *jvmti,JNIEnv *jni, jthread thread, jmethodID method,jlocation location, jobject exception,jmethodID catch_method, jlocation catch_location)

重要的是要注意,功能的开销有时分为两部分。 第一部分仅是通过启用它来完成的,因为这将导致JIT编译器以不同的方式编译事物,从而产生对代码进行调用的潜力。 第二部分是在您实际安装回调函数时出现的,因为它会使JVM在运行时选择优化程度较低的执行路径,通过该路径它可以调用您的代码,并带来解析和传递的额外开销。您有意义的数据。

断点和手表 。 您的调试器可以提供在运行时检查特定状态的熟悉功能,例如SetBreakpoint可以通知JVM暂停执行特定字节代码指令,或者SetFieldModificationWatch可以在修改字段时暂停执行。 到那时,您可以使用其他补充功能,例如GetStackTraceGetThreadInfo来了解有关您当前在代码中的位置的更多信息并将其报告。

如下所示的大多数JVMTI函数都使用称为jmethodID和jclass的抽象句柄来引用类和方法(如果您曾经编写过Java Native Interface代码,则应该很熟悉)。 提供了诸如GetMethodNameGetClassSignature之类的附加功能,以帮助您从类的常量池中获取实际的符号名称。 然后,您可以使用它们以可读格式记录数据或将其呈现在UI中,就像我们每天在IDE中看到的那样。

附加调试器

编写调试器库后,下一步就是将其附加到JVM。 有几种方法可以做到–

1.连接JDWP 。 如果要编写基于JDWP的调试器,则需要以– agentlib:jdwp = transport = dt_socket,suspend = y,address = localhost:<port>的形式向调试对象添加启动参数以通过线路启用调试。 这些参数详细说明了调试器和目标(在本例中为套接字)之间的通信形式,以及是否以挂起模式启动调试对象。

2.附加JVMTI库 。 JVM通过传递给debuggee进程并指向您的库在磁盘上的位置的agentpath命令行参数加载JVMTI库。

另一种方法是将代理程序命令行参数附加到全局JAVA_TOOL_OPTIONS环境变量,该环境变量将由每个新JVM拾取,并且其值会自动附加到其现有参数列表中。

3.远程连接 。 附加调试器的另一种方法是使用远程附加API 。 这个简单而强大的API使您可以将代理附加到正在运行的JVM进程,而无需使用任何命令行参数启动它们。 不利的一面是您将无法使用通常需要的某些功能,例如can_generate_exception_events ,因为这些功能仅在VM启动时才需要-遗憾的是,调试器有些麻烦了。

您可以下载Takipi的生产调试器,以在此处查看其中的一些方法。

参考: 如何从我们的JCG合作伙伴 Tal Weiss在Takipi博客上编写自己的Java / Scala调试器 。

翻译自: https://www.javacodegeeks.com/2013/09/how-to-write-your-own-java-scala-debugger.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/367868.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件测试bug文档模板,软件bug测试记录模板

软件bug测试记录模板 XXX软件bug测试记录表 文档编号&#xff1a; 背景信息 项目名称 测试目的 硬件环境 软件环境 测试时间 测试人员 测试说明 1、严重等级&#xff1a; A-Crash(崩溃的)&#xff1a;由于程序所引起的死机、非法退出、死循环&#xff1b;数据库发生死锁&#x…

Java即时编译:不仅仅是一个流行词

最近的Java生产性能问题迫使我重新审视并真正欣赏Java VM即时&#xff08;JIT&#xff09;编译器。 大多数Java开发人员和支持人员都听说过这种JVM运行时性能优化&#xff0c;但是有多少人真正理解并欣赏它的好处&#xff1f; 本文将与您分享在添加新的虚拟服务器&#xff08…

win10设置计算机关机时间,教你windows10电脑怎么设置定时关机

今天小编教你windows10电脑怎么设置定时关机&#xff0c;相信大家都有过这样的经历吧!那就是有时开着电脑玩累了,躺在床上睡了一会&#xff0c;结果醒来的时候发现睡了比较久&#xff0c;且还不愿意下床关电脑怎么办&#xff0c;其实我们可设置定时关机&#xff0c;有需要的用户…

Android内存优化9 内存检测工具3 MAT比Menmery Monitor更强大

在Android性能优化第&#xff08;一&#xff09;篇---基本概念中讲了JAVA的四大引用&#xff0c;讲了一下GCRoot&#xff0c;第二篇Memory Monitor检测内存泄露仅仅说了Menmery Monitor的使用&#xff0c;这篇博客谈一下MAT来寻找内存泄露&#xff0c;相对来说&#xff0c;Memo…

计算机三种引用方式,单元格的引用方式有哪几种

EXCEL单元格的引用包括绝对引用、相对引用和混合引用三种。单元格引用是Excel中的术语&#xff0c;指用单元格在表中的坐标位置的标识。是计算机基础的重要学习内容。1、绝对引用&#xff1a;单元格中的绝对单元格引用(例如$F$6)总是在指定位置引用单元格F6。如果公式所在单元格…

linux上php指向mysql_linux环境下 php如何配置mysql

展开全部Linux下配置安装PHP环境参考别人的做法,遇到问题上网查,下面就是安装步骤.一、安装Apache2.2.221、到官网下636f707962616964757a686964616f31333339666133载 http://httpd.apache.org/download.cgi2、解压tar -zxvf httpd-2.2.22.tar.gz3、建立目标文件夹(注意以下所有…

Java 7 Swing:创建半透明和成形的Windows

Java 7 Swing支持具有透明和非矩形形状的窗口。 以下屏幕截图显示了创建的不透明度为75&#xff05;的圆形窗口。 您可以通过在JFrame上使用setOpacity方法更改其不透明度来创建半透明窗口。 请注意&#xff0c;只有底层操作系统支持时&#xff0c;您才能创建半透明窗口。 另外…

mac mysql创建本地数据库_【mac】配置本地数据库

1.【安装数据库】brew 安装mysql -- brew install mysql安装成功后在命令行敲入 which mysql 查看安装路径2.【配置数据库】如果直接打mysql会报错&#xff0c;需要将mysql添加到环境变量&#xff0c;具体方法参阅后台学习-环境变量检查mysql是否启动 ps -ef | grep mysqld开启…

糖豆人维修服务器多长时间,服务器不稳定的《糖豆人》凭啥还这么火?只因做到了这三点...

8月4日&#xff0c;《糖豆人&#xff1a;终极淘汰赛》在steam平台上线&#xff0c;不到一周的时间直接登上steam畅销榜第六位。这款看起来似乎并不具备3A制作级别的游戏&#xff0c;到底是怎么获得了这么多玩家的追捧和青睐的呢&#xff1f;不妨跟着汇智妹一起看看这款游戏到底…

虚拟机游戏获取服务器地址,vue获取服务器地址

vue获取服务器地址 内容精选换一换Atlas 500 Pro 智能边缘服务器(型号 3000)安装上架、服务器基础参数配置、安装操作系统等操作请参见《Atlas 500 Pro 智能边缘服务器 用户指南(型号 3000)》&#xff0c;安装操作系统完成后&#xff0c;配置业务网口IP地址&#xff0c;请参见配…

使用Selenium和HTML中的动态ID进行Java测试

Selenium最酷的方面之一是&#xff0c;您不仅可以使用网站进行录制&#xff0c;还可以将其实际用作junit测试。 首先&#xff0c;我将在Firefox中安装Selenium&#xff08;因为这是正式版本&#xff09;并进行快速测试。 重要的是要注意&#xff0c;Selenium将为您提供多种不同…

查看表空间名称、大小、使用大小、剩余大小和使用率

查看表空间名称、大小、使用大小、剩余大小和使用率&#xff1a; SELECT a.tablespace_name "表空间名称", total / (1024 * 1024) "表空间大小(M)", free / (1024 * 1024) "表空间剩余大小(M)", (total - free) / (1024 * 1024 ) "表空…

编译安装PHP-7.2.8

一 下载并软件包 wget http://124.205.69.169/files/A218000006E9730A/cn2.php.net/distributions/php-7.2.8.tar.gz tar xf php-7.2.8.tar.gz cd php-7.2.8 二 安装依赖程序 yum -y install pcre pcre-devel openssl openssl-devel libicu-devel gcc gcc-c autoconf libjpeg l…

常用操作符

2 1. 转换类型数据&#xff0c;可以先定义一个数据&#xff0c;然后在采用调用的方法进行转换。 2. 进行查看相关数据&#xff0c;使用type类型数据进行查看&#xff0c;例如&#xff1a;type(**),然后就可以查到所属的类型了。但是对于单个字符来说&#xff0c;例如红线方…

重要通知,事关校营宝新老用户,敬请知悉!

尊敬的校营宝用户&#xff0c;感谢您选择校营宝培训学校管理系统&#xff0c;我们的发展离不开您的支持鼓励&#xff0c;只要您选择校营宝&#xff0c;就是我们的终身客户&#xff0c;我们承诺给您终身的售后咨询服务&#xff01; 校营宝培训学校管理系统是面向校外艺术类培训…

从条纹边框的实现谈盒子模型

类似下面这个图形&#xff0c;只使用一个标签&#xff0c;可以有多少种实现方式&#xff1a;(不考虑兼容性的情况下) 假设我们的单标签为 div : 定义如下通用 CSS: div{ position:relative; width: 180px; height: 180px; } NO.1 方案一&#xff1a;div上是棕色背景&#xf…

Android_(游戏)打飞机04:绘画敌机、添加子弹

(游戏)打飞机01&#xff1a;前言  传送门 (游戏)打飞机02&#xff1a;游戏背景滚动  传送门 (游戏)打飞机03&#xff1a;控制玩家飞机   传送门 (游戏)打飞机04&#xff1a;绘画敌机、添加子弹   传送门 (游戏)打飞机05&#xff1a;处理子弹&#xff0c;击中敌机&am…

关于HTML5本地持久化存储的Web SQL、Local Storage、Cookies技术

在浏览器客户端记录一些信息&#xff0c;有三种常用的Web数据持久化存储的方式&#xff0c;分别是Web SQL、Local Storage、Cookies。Web SQL作为html5本地数据库&#xff0c;可通过一套API来操纵客户端的数据库&#xff08;关系数据库&#xff09;&#xff0c;下面是支持浏览器…

死锁

7.1 系统模型 定义&#xff1a;多个进程竞争一定数量的资源&#xff0c;某个进程申请资源&#xff0c;若此时该资源不可用&#xff0c;则进程进入等待状态。若所申请的资源被其他等待进程占用&#xff0c;则该等待进程可能再也不法改变其状态。 进程使用资源的顺序&#xff1a;…

mysql lepus_MySQL 监控软件lepus天兔

概述类别版本操作系统Centos 7.4数据库版本MySQL 5.6.49天兔版本lepus 3.7依赖软件1.MySQL 5.0及以上(必须,用来存储监控系统采集的数据)2.Apache 2.2及以上 (必须,WEB服务器运行服务器)3.PHP 5.3以上 (必须,提供WEB界面支持)4.Python2 (必须,推荐2.6及以上版本,执行数据采集和…