曰本美女∴一区二区特级A级黄色大片, 国产亚洲精品美女久久久久久2025, 页岩实心砖-高密市宏伟建材有限公司, 午夜小视频在线观看欧美日韩手机在线,国产人妻奶水一区二区,国产玉足,妺妺窝人体色WWW网站孕妇,色综合天天综合网中文伊,成人在线麻豆网观看

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

反向 Debug 了解一下?揭秘 Java DEBUG 的基本原理

京東云 ? 來源:jf_75140285 ? 作者:jf_75140285 ? 2024-11-25 11:15 ? 次閱讀

Debug 的時候,都遇到過手速太快,直接跳過了自己想調(diào)試的方法、代碼的時候吧……

一旦跳過,可能就得重新執(zhí)行一遍,準備數(shù)據(jù)、重新啟動可能幾分鐘就過去了。

好在IDE 們都很強大,還給你后悔的機會,可以直接刪除某個 Stack Frame,直接返回到之前的狀態(tài),確切的說是返回到之前的某個 Stack Frame,從而實現(xiàn)讓程序“逆向運行”。

wKgaomdD69uABq9tAAb9sMNBUsc682.png

這個 Reset Frame 的能力,可不只是返回上一步,上 N 步也是可以的;選中你期望的那個幀,直接Reset Frame/Drop Frame,可以直接回到調(diào)用棧上的某個棧幀,時間反轉(zhuǎn)!

可惜這玩意也不是那么萬能,畢竟是通過 stack pop 這種操作實現(xiàn),實際上只是給調(diào)用棧棧頂?shù)?N 個 frame pop 出來而已,還談不上是真正的“反向 DEBUG”。

相比之下, GDB 的 Reverse Debugging 就比較強大,真正的 “反向” DEBUG,逆向運行,實現(xiàn)回放。

所以吧在運行過程中,已經(jīng)修改的數(shù)據(jù),比如引用傳遞的方法參數(shù)、變量,一旦修改肯定回退不了,不然真的成時光機了。

這些亂七八糟的調(diào)試功能,都是基于 Java 內(nèi)置的 Debug 體系來實現(xiàn)的。

JAVA DEBUG 體系

Java 提供了一個完整的 Debug 體系 JPDA (Java Platform Debugger Architecture),這個 JPDA 架構(gòu)體系由 3 部分組成:

JVM TI - Java VM Tool Interface

JDWP - Java Debug Wire Protocol

JDI - Java Debug Interface

如果結(jié)合IDE 來看,那么一個完整的 Debug 功能看起來就是這個樣子:

wKgZomdD69yAHuo6AALh88KXiIA805.png

解釋一下這個體系:

JVM TI 是一個 JVM 提供的一個調(diào)試接口,提供了一系列控制 JVM 行為的功能,比如分析、調(diào)試、監(jiān)控、線程分析等等。也就是說,這個接口定義了一系列調(diào)試分析功能,而 JVM 實現(xiàn)了這個接口,從而提供調(diào)試能力。

不過吧,這個接口畢竟是 C++的,調(diào)用起來確實不方便,所以Java 還提供了 JDI 這么個 Java 接口。

JDI 接口使用 JDWP 這個私有的應用層協(xié)議,通過 TCP 和目標 VM 的 JVMTI 接口進行交互。

也可以把簡單這個 JDWP 協(xié)議理解為 JSF/Dubbo 協(xié)議;相當于 IDE 里通過 JDI 這個 SDK,使用 JDWP 協(xié)議調(diào)用遠程 JVMTI 的 RPC 接口,來傳輸調(diào)試時的各種斷點、查看操作。

可能有人會問,搞什么套殼!要什么 JDWP,我直接 JVMTI 調(diào)試不是更香,鏈路越短性能越高!

當然可以,比如 Arthas 里的部分功能,就直接使用了 JVMTI 接口,要什么 JDI!直接 JVMTI 干就完了。

開個玩笑,Arthas 畢竟不是 Debug 工具,人家根本就不用 JDI 接口。而且 JVMTI 的能力也不只是斷點,它的功能非常多:

wKgaomdD692AK-MWAAbr688q4t0961.png

左邊的功能類,提供了各種亂七八糟的功能,比如我們常用的添加一個斷點:

jvmtiError
SetBreakpoint(jvmtiEnv* env,
            jmethodID method,
            jlocation location)

右邊的事件類,可以簡單的理解為回調(diào);還是拿斷點舉例,如果我用上面的 SetBreakpoint 添加了一個斷點,那么當執(zhí)行到該位置時,就會觸發(fā)這個事件:

void JNICALL
Breakpoint(jvmtiEnv *jvmti_env,
            JNIEnv* jni_env,
            jthread thread,
            jmethodID method,
            jlocation location)

JVMTI 的功能非常之多,而 JDI 只是實現(xiàn)了部分 JVMTI 的方法,所以某些專業(yè)的 Profiler 工具,可能會直接使用 JVMTI,從而實現(xiàn)更豐富的診斷分析功能。

遠程調(diào)試與本地調(diào)試

不知道大家有沒有留意過本地 Debug 啟動時的日志:

wKgZomdD69-ACxPvAADllqU4lss011.png

第一行是隱藏了后半段的啟動命令,展開后是這個樣子:

/path/to/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:53631,suspend=y,server=n -javaagent:/path/to/jetbrains/debugger-agent.jar ...

第二行是一個 Connected 日志,意思是使用 socket 連接到遠程 VM 的53631端口

上一段說到,IDE 通過 JDI 接口,使用 JDWP 協(xié)議和目標 VM 的 JVMTI 交互。這里的 53631 端口,就是目標 JVM 暴露出的 JVM TI 的 server 端口。

而第一行里,IDEA 自動給我們加上了 -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:53631 這么一段,這個參數(shù)的意思就是,讓 jvm 以 53631 暴露 jdwp 協(xié)議

小知識,這個 agentlib 可不只是為 jvmti 提供的。它還可以讓 JVM 加載其他的 native lib包,直接“外掛”到你的 jvm 上,下面是“外掛”的參數(shù)格式:

wKgaomdD6-CAOYW2AAEqnSKR9yo953.png

所以吧,上面的描述其實不太嚴謹,更專業(yè)的說法是:

讓 JVM 加載 JDWP 這個 agent 庫,參數(shù)為transport=dt_socket,address=127.0.0.1:53631 ,這個 jdwp agent 庫以 53631 端口提供了 jdwp 協(xié)議的 server。只不過這個 jdwp 是jvm 內(nèi)部的庫,不需要額外的 so/dylib/dll 文件。

如有需要,你完全可以弄個 “datupiao” 的 agentlib,“外掛”到這個 jvm 上,然后在這個 lib 里調(diào)用 JVMTI 接口,然后暴露個端口提供服務(wù)和遠程交互,實現(xiàn)自己的 jdwp!

可能某些老板們注意到了,本地調(diào)試還要127.0.0.1走tcp 交互一遍,那遠程調(diào)試呢?

基于上面的解釋,本地調(diào)試和遠程調(diào)試真的沒啥區(qū)別!或者說,在目前 IDEA/Eclipse 的實現(xiàn)下,不存在本地調(diào)試,都是遠程!只不過一個是 127.0.0.1,一個是遠程的 IP 而已。

在本地調(diào)試時,IDEA 會自動給我們的 JVM 增加 agent 參數(shù),隨機指定一個端口,然后通過 JDI 接口連接,代碼大概長這樣(JDI 的 SDK 在 JDK_HOME/lib/tools.jar ):

Map env = connector.defaultArguments();
env.get("hostname").setValue(hostname);
env.get("port").setValue(port);

VirtualMachine vm = connector.attach(env);

瞅瞅, VirtualMachine 里的就這點方法,能力上比 JVMTI 還是差遠了

List classesByName(String className);

List allClasses();

void redefineClasses(Map classToBytes);

List allThreads();

void suspend();

void resume();

List topLevelThreadGroups();

EventQueue eventQueue();

EventRequestManager eventRequestManager();

VoidValue mirrorOfVoid();

Process process();

再回來看看 IDEA 中獨立的遠程調(diào)試,配置好之后,紅框里的信息會提示你 ,遠程的 JVM 需增加這一段啟動參數(shù),而且支持多個版本 JDK 的格式,CV 大法就能直接用。

wKgZomdD6-CAFWzPAAHEdznUmT4345.png

-agentlib 和 -javaagent

有些細心的同學可能發(fā)現(xiàn)了,IDEA 默認的啟動腳本里,同時配置了 -agentlib 和 -javaagent。

-javaagent:/path/to/jetbrains/debugger-agent.jar 

這個 debugger-agent吧,其實也沒干啥事,只是對 JDK 內(nèi)置的一些線程做了些增強,輔助 IDEA 的 debug 功能,支持一些異步的調(diào)試。

wKgaomdD6-KAfwr8AAyvMfA8bTM822.png

agentlib、javaagent 這倆兄弟,定位其實很像,都是加載自定義的代碼。

不過區(qū)別在于,agentlib 是加載 native lib,需要c/cpp 去寫,相當于外掛自己的代碼在 jvm 上,可以為所欲為,比如在 agentlib 里調(diào)用上面說的 JVMTI 。

而 javaagent 是用 java 寫的,可以直接用上層的 Instrumentation API,做一些類的增強轉(zhuǎn)換之類,這也是大多數(shù) APM Agent、Profiler Agent實現(xiàn)的基本原理。

Arthas 的玩法

Arthas 的核心入口,其實還是 javaagent,支持靜態(tài)加載和動態(tài)加載兩種玩法。

靜態(tài)沒啥好說的,啟動腳本里增加一個-javaagent:/tmp/test/arthas-agent.jar,然后為所欲為。

wKgZomdD6-SAOD_NAAE7RdOEjg4491.png

動態(tài)的叫 attach,使用 Java 提供的 VirtualMachine 就可以實現(xiàn)運行時添加 -javaagent,效果一樣:

VirtualMachine virtualMachine = VirtualMachine.attach(virtualMachineDescriptor);
virtualMachine.loadAgent(agentPath, agentArgs);

這個 Agent 在 JVM 里啟動了一個TCP server,用于收發(fā) Arthas Client 的各種 trace、watch 、Dashboard 等指令,然后通過 Instrumentation 增強Class 插入代碼、或者直接調(diào)用某些 Java API,實現(xiàn)各種功能。

注意到了嗎?Arthas 可以直接下載一個 jar 包,java -jar 就能連上。

其實吧,它這個直接啟動的 jar 包,是一個 boot 包,啟動之后把亂七八糟的 jar 都下載下來。接著動態(tài) attach 的方式,連接到本機指定進程號的 JVM,然后再為所欲為。

在 3.5 版本之后,Arthas 還新增了一個 vmtool 命令,這個命令可以直接獲取內(nèi)存中的指定對象實例。

$ vmtool --action getInstances --className java.lang.String --limit 10
@String[][
    @String[com/taobao/arthas/core/shell/session/Session],
    @String[com.taobao.arthas.core.shell.session.Session],
    @String[com/taobao/arthas/core/shell/session/Session],
    @String[com/taobao/arthas/core/shell/session/Session],
    @String[com/taobao/arthas/core/shell/session/Session.class],
    @String[com/taobao/arthas/core/shell/session/Session.class],
    @String[com/taobao/arthas/core/shell/session/Session.class],
    @String[com/],
    @String[java/util/concurrent/ConcurrentHashMap$ValueIterator],
    @String[java/util/concurrent/locks/LockSupport],
]

直接獲取內(nèi)存對象,這玩意只靠 Instrumentation API 可做不到。Arthas 搞了個騷操作,直接 JNI 調(diào)用自定義 lib,用過 cpp 直接調(diào)用了 JVMTI 的 API,融合了 Instrumentation 和 JVMTI 的能力,這下是真的為所欲為了!

#include 
#include 
#include 
#include 
#include "arthas_VmTool.h" // under target/native/javah/

static jvmtiEnv *jvmti;

...

extern "C"
JNIEXPORT jobjectArray JNICALL
Java_arthas_VmTool_getInstances0(JNIEnv *env, jclass thisClass, jclass klass, jint limit) {
    jlong tag = getTag();
    limitCounter.init(limit);
    jvmtiError error = jvmti->IterateOverInstancesOfClass(klass, JVMTI_HEAP_OBJECT_EITHER,
                                               HeapObjectCallback, &tag);
    if (error) {
        printf("ERROR: JVMTI IterateOverInstancesOfClass failed!%un", error);
        return NULL;
    }

    jint count = 0;
    jobject *instances;
    error = jvmti->GetObjectsWithTags(1, &tag, &count, &instances, NULL);
    if (error) {
        printf("ERROR: JVMTI GetObjectsWithTags failed!%un", error);
        return NULL;
    }

    jobjectArray array = env->NewObjectArray(count, klass, NULL);
    //添加元素到數(shù)組
    for (int i = 0; i < count; i++) {
        env-?>SetObjectArrayElement(array, i, instances[i]);
    }
    jvmti->Deallocate(reinterpret_cast(instances));
    return array;
}

總結(jié)

Debug 基于 JDPA 體系

IDE 直接接入 JDPA 體系中的 JDI 接口完成

JDI 通過 JDWP 協(xié)議,調(diào)用遠程 VM 的 JVMTI 接口

JDWP 是通過 agentlib 加載的,agentlib 算是一個 native 的靜態(tài)“外掛”接口

javaagent 是 JAVA 層面的“外掛”接口,用過 Instrumentation API(Java)實現(xiàn)各種功能,主要用于APM、Profiler 工具

如果你想,在 javaagent 里調(diào)用功能更豐富的 JVMTI 也不是不行。

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • JAVA
    +關(guān)注

    關(guān)注

    20

    文章

    2983

    瀏覽量

    106618
  • IDE
    IDE
    +關(guān)注

    關(guān)注

    0

    文章

    346

    瀏覽量

    47389
  • DEBUG
    +關(guān)注

    關(guān)注

    3

    文章

    94

    瀏覽量

    20333
收藏 人收藏

    評論

    相關(guān)推薦
    熱點推薦

    詳解Java DEBUG基本原理

    Debug 的時候,都遇到過手速太快,直接跳過了自己想調(diào)試的方法、代碼的時候吧……
    的頭像 發(fā)表于 01-05 10:10 ?1595次閱讀
    詳解<b class='flag-5'>Java</b> <b class='flag-5'>DEBUG</b>的<b class='flag-5'>基本原理</b>

    先來認識一下正激的基本原理

    我們先來認識一下正激的基本原理,如圖所示:正激在原邊加正向電壓 MOS 管導通時,副邊的輸出符合變壓器原理,即:Vs = n* VinVs :變壓器副邊輸出電壓n:匝比 = Ns/NpVin:輸入電壓由上式可知正激拓撲不難理解。* 注意:原邊還有個繞組稱為復位繞組,副邊有
    發(fā)表于 12-31 06:18

    DEBUG程序的使用

    實 驗   DEBUG程序的使用 、 實驗目的 1. 學習使用DEBUG程序的各種命令
    發(fā)表于 09-28 23:10 ?7489次閱讀

    Vivado+FPGA:如何使用Debug Cores(ILA)在線調(diào)試

    在Vivado下在線調(diào)試是利用ILA進行的,Xilinx官方給出了個視頻,演示了如何使用Vivado的debug cores,下面我根據(jù)這個官方視頻的截圖的來演示一下: 官方的視頻使用的軟件版本為
    發(fā)表于 02-08 08:52 ?2918次閱讀

    Vivado中使用debug工具步驟與調(diào)試技巧

    在ISE中稱為ChipScope而Vivado中就稱為in system debug。下面就介紹Vivado中如何使用debug工具。 Debug分為3個階段: 1. 探測信號:在設(shè)計中標志想要查看的信號 2. 布局布線:給包含
    發(fā)表于 11-17 14:05 ?6.2w次閱讀
    Vivado中使用<b class='flag-5'>debug</b>工具步驟與調(diào)試技巧

    STM32調(diào)試DEBUG時需要了解那些知識相關(guān)資料概述

    學習STM32開發(fā),肯定少不了DEBUG調(diào)試這步驟。那么,本文帶你了解一下這個調(diào)試相關(guān)的知識。本文以STM
    的頭像 發(fā)表于 11-11 11:39 ?7233次閱讀
    STM32調(diào)試<b class='flag-5'>DEBUG</b>時需要<b class='flag-5'>了解</b>那些知識相關(guān)資料概述

    關(guān)于Vivado中三種操作Debug的方式

    Vivado中提供了多種Debug的操作方式,下面就來總結(jié)一下: 1. 代碼中例化ILA IP核 第種,直接例化ILA IP核: 需要探測多少個信號,信號的位寬是多少,直接選擇即可: 下面界面可以
    的頭像 發(fā)表于 11-11 17:07 ?1.1w次閱讀
    關(guān)于Vivado中三種操作<b class='flag-5'>Debug</b>的方式

    含淚Debug:STM32與ESP32 SPI通信避坑

    最近搞了一下ESP32與STM32之間的SPI通信,這路曲曲折折耗費了很長時間,下面我把我的debug踩坑經(jīng)歷奉獻出了,希望大家不要fanwo
    發(fā)表于 12-24 19:07 ?37次下載
    含淚<b class='flag-5'>Debug</b>:STM32與ESP32 SPI通信避坑

    STM32(Cortex-M)內(nèi)核DEBUG調(diào)試接口知識

    學習STM32開發(fā),肯定少不了debug調(diào)試這步驟。那么,本文帶你了解一下這個調(diào)試相關(guān)的知識。
    發(fā)表于 02-08 16:02 ?9次下載
    STM32(Cortex-M)內(nèi)核<b class='flag-5'>DEBUG</b>調(diào)試接口知識

    debug 吞吐量的辦法

    Debug 網(wǎng)絡(luò)質(zhì)量的時候,我們般會關(guān)注兩個因素:延遲和吞吐量(帶寬)。延遲比較好驗證,Ping 一下或者 mtr[1] 一下就能看出來。這篇文章分享
    的頭像 發(fā)表于 08-23 09:17 ?1103次閱讀

    debug 吞吐量的辦法

    Debug 網(wǎng)絡(luò)質(zhì)量的時候,我們般會關(guān)注兩個因素:延遲和吞吐量(帶寬)。延遲比較好驗證,Ping 一下或者 mtr[1] 一下就能看出來。這篇文章分享
    的頭像 發(fā)表于 09-02 09:36 ?1004次閱讀

    IAR中 Debug 和 Release有何區(qū)別

    ; ? Release, 即發(fā)布版本,或者說最終釋放版本。 ? 在些項目中,會出現(xiàn)Debug 和 Release兩個版本,比如: ? IAR EWARM: ? VS: ? 些初學者可能會問,
    的頭像 發(fā)表于 05-22 10:54 ?3813次閱讀
    IAR中 <b class='flag-5'>Debug</b> 和 Release有何區(qū)別

    一下電荷泵升壓的基本原理

    電荷泵基于個物理學的基本原理:在閉合電路中來回流動的電荷不會消失。
    的頭像 發(fā)表于 08-15 15:38 ?3840次閱讀
    講<b class='flag-5'>一下</b>電荷泵升壓的<b class='flag-5'>基本原理</b>

    OpenCV4.8在Debug模式滾動條錯誤問題解決與原因查找

    不同的是他在Debug模式執(zhí)行的而我在Release模式執(zhí)行的。
    的頭像 發(fā)表于 10-23 10:19 ?650次閱讀
    OpenCV4.8在<b class='flag-5'>Debug</b>模式<b class='flag-5'>下</b>滾動條錯誤問題解決與原因查找

    了解矢量網(wǎng)絡(luò)分析的基本原理

    了解矢量網(wǎng)絡(luò)分析的基本原理
    發(fā)表于 11-02 15:11 ?1次下載