使用 GDB 更改 JVM 中的变量值

2023-12-14

目前我有一个简单的Java程序:

public class Test {
  public static void main(String[] args) {
    boolean test = true;
    while (test) {
      System.out.println("Hello World");
      try { Thread.sleep(1000); } catch (Exception e) {}
    }
    System.out.println("Bye-bye");
  }
}

它每秒打印“Hello World”。我想使用 gdb 附加到该进程并制作一个内存补丁来停止它并打印“再见”。

我知道GDB可以从其控制台获取创建的VM(JNI_GetCreatedVMs),env对象也可以通过GetEnv的API获得。我怎么能够找出testJVM 中的变量地址并将其设置为 false(这是可选的)以让程序正常退出?不确定 AttachCurrentThread 等 API、HotSpotVirtualMachine 等类、jmap 或 jstack 等工具是否可以提供帮助?

并且没有调试选项,假设简单的程序在生产中运行java -cp . Test.

预先感谢您的任何指导。 :)


附加信息(轨道状态)

  • jmap -dump:file=hex <pid> && jhat hex并浏览http://本地主机:7000;找不到任何参考test(它不是一个对象,只是一个实例class Z)
  • jstack <pid>可以获取主线程的tid(0x7fa412002000)并且jhat hex具有 main 的 java.lang.Thread 对象(0x76ab05c40)
  • java.lang.Thread有一个本地方法start0它调用热点方法JVM_StartThread(hotspot/src/share/vm/prims/jvm.cpp),有一个类JavaThread可能包含线程堆栈中局部变量的内存结构。
  • if private static boolean test = true;; then JNI_GetCreatedJavaVMs ==> jvm, jvm->jvm_api->AttachCurrentThread ==> env, env->env_api->(FindClass, GetStaticFieldID, SetStaticBooleanField) ==> test[true ==> false]

在某些情况下,可以使用 HotSpot Serviceability Agent 获取本地变量地址。我制作了一个示例代理,可以打印带有局部变量信息的扩展堆栈跟踪:

import sun.jvm.hotspot.code.Location;
import sun.jvm.hotspot.code.LocationValue;
import sun.jvm.hotspot.code.NMethod;
import sun.jvm.hotspot.code.ScopeValue;
import sun.jvm.hotspot.code.VMRegImpl;
import sun.jvm.hotspot.debugger.Address;
import sun.jvm.hotspot.debugger.OopHandle;
import sun.jvm.hotspot.interpreter.OopMapCacheEntry;
import sun.jvm.hotspot.oops.Method;
import sun.jvm.hotspot.oops.Oop;
import sun.jvm.hotspot.runtime.CompiledVFrame;
import sun.jvm.hotspot.runtime.InterpretedVFrame;
import sun.jvm.hotspot.runtime.JavaThread;
import sun.jvm.hotspot.runtime.JavaVFrame;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.runtime.VMReg;
import sun.jvm.hotspot.tools.Tool;

import java.util.List;

public class Frames extends Tool {

    @Override
    public void run() {
        for (JavaThread thread = VM.getVM().getThreads().first(); thread != null; thread = thread.next()) {
            System.out.println(thread.getThreadName() + ", id = " + thread.getOSThread().threadId());
            for (JavaVFrame vf = thread.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) {
                dumpFrame(vf);
            }
            System.out.println();
        }
    }

    private void dumpFrame(JavaVFrame vf) {
        Method method = vf.getMethod();
        String className = method.getMethodHolder().getName().asString().replace('/', '.');
        String methodName = method.getName().asString() + method.getSignature().asString();
        System.out.println("  # " + className + '.' + methodName + " @ " + vf.getBCI());

        if (vf.isCompiledFrame()) {
            dumpCompiledFrame(((CompiledVFrame) vf));
        } else {
            dumpInterpretedFrame(((InterpretedVFrame) vf));
        }
    }

    private void dumpCompiledFrame(CompiledVFrame vf) {
        if (vf.getScope() == null) {
            return;
        }

        NMethod nm = vf.getCode();
        System.out.println("    * code=[" + nm.codeBegin() + "-" + nm.codeEnd() + "], pc=" + vf.getFrame().getPC());

        List locals = vf.getScope().getLocals();
        for (int i = 0; i < locals.size(); i++) {
            ScopeValue sv = (ScopeValue) locals.get(i);
            if (!sv.isLocation()) continue;

            Location loc = ((LocationValue) sv).getLocation();
            Address addr = null;
            String regName = "";

            if (loc.isRegister()) {
                int reg = loc.getRegisterNumber();
                addr = vf.getRegisterMap().getLocation(new VMReg(reg));
                regName = ":" + VMRegImpl.getRegisterName(reg);
            } else if (loc.isStack() && !loc.isIllegal()) {
                addr = vf.getFrame().getUnextendedSP().addOffsetTo(loc.getStackOffset());
            }

            String value = getValue(addr, loc.getType());
            System.out.println("    [" + i + "] " + addr + regName + " = " + value);
        }
    }

    private void dumpInterpretedFrame(InterpretedVFrame vf) {
        Method method = vf.getMethod();
        int locals = (int) (method.isNative() ? method.getSizeOfParameters() : method.getMaxLocals());
        OopMapCacheEntry oopMask = method.getMaskFor(vf.getBCI());

        for (int i = 0; i < locals; i++) {
            Address addr = vf.getFrame().addressOfInterpreterFrameLocal(i);
            String value = getValue(addr, oopMask.isOop(i) ? Location.Type.OOP : Location.Type.NORMAL);
            System.out.println("    [" + i + "] " + addr + " = " + value);
        }
    }

    private String getValue(Address addr, Location.Type type) {
        if (type == Location.Type.INVALID || addr == null) {
            return "(invalid)";
        } else if (type == Location.Type.OOP) {
            return "(oop) " + getOopName(addr.getOopHandleAt(0));
        } else if (type == Location.Type.NARROWOOP) {
            return "(narrow_oop) " + getOopName(addr.getCompOopHandleAt(0));
        } else if (type == Location.Type.NORMAL) {
            return "(int) 0x" + Integer.toHexString(addr.getJIntAt(0));
        } else {
            return "(" + type + ") 0x" + Long.toHexString(addr.getJLongAt(0));
        }
    }

    private String getOopName(OopHandle hadle) {
        if (hadle == null) {
            return "null";
        }
        Oop oop = VM.getVM().getObjectHeap().newOop(hadle);
        return oop.getKlass().getName().asString();
    }

    public static void main(String[] args) throws Exception {
        new Frames().execute(args);
    }
}

运行它:

java -cp $JAVA_HOME/lib/sa-jdi.jar:. Frames PID

这将附加到 Java 进程PID并打印堆栈跟踪,例如

main, id = 30920
  # java.lang.Thread.sleep(J)V @ 0
  # Test.main([Ljava/lang/String;)V @ 15
    [0] 0x00007f075a857918 = (oop) [Ljava/lang/String;
    [1] 0x00007f075a857910 = (int) 0x1
    [2] 0x00007f075a857908 = (int) 0x0

Here main是Java线程名称;30920是本机线程ID;@ 15是字节码索引。

线路[1] 0x00007f075a857910 = (int) 0x1意味着局部变量 #1 位于地址 0x00007f075a857910 且值为 1。这正是您感兴趣的变量。

局部变量信息对于解释方法来说是可靠的,但对于编译方法来说并不总是可靠的。但是,已编译的方法将有一个额外的行,其中包含代码的地址,因此您可以在 gdb 中反汇编和检查它。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 GDB 更改 JVM 中的变量值 的相关文章

  • java.lang.NoClassDefFoundError:org.apache.batik.dom.svg.SVGDOMImplementation

    我在链接到我的 Android LibGDX 项目的 Apache Batik 库时遇到了奇怪的问题 但让我们从头开始 在 IntelliJ Idea 中我有一个项目 其中包含三个模块 Main Android 和 Desktop 我强调的
  • 如何为最终用户方便地启动Java GUI程序

    用户想要从以下位置启动 Java GUI 应用程序Windows 以及一些额外的 JVM 参数 例如 javaw Djava util logging config file logging properties jar MyGUI jar
  • Java new Date() 打印

    刚刚学习 Java 我知道这可能听起来很愚蠢 但我不得不问 System out print new Date 我知道参数中的任何内容都会转换为字符串 最终值是 new Date 返回对 Date 对象的引用 那么它是如何打印这个的呢 Mo
  • Java EE:如何获取我的应用程序的 URL?

    在 Java EE 中 如何动态检索应用程序的完整 URL 例如 如果 URL 是 localhost 8080 myapplication 我想要一个可以简单地将其作为字符串或其他形式返回给我的方法 我正在运行 GlassFish 作为应
  • 在画布上绘图

    我正在编写一个 Android 应用程序 它可以在视图的 onDraw 事件上直接绘制到画布上 我正在绘制一些涉及单独绘制每个像素的东西 为此我使用类似的东西 for int x 0 x lt xMax x for int y 0 y lt
  • 如何找到给定字符串的最长重复子串

    我是java新手 我被分配寻找字符串的最长子字符串 我在网上研究 似乎解决这个问题的好方法是实现后缀树 请告诉我如何做到这一点或者您是否有任何其他解决方案 请记住 这应该是在 Java 知识水平较低的情况下完成的 提前致谢 附 测试仪字符串
  • Final字段的线程安全

    假设我有一个 JavaBeanUser这是从另一个线程更新的 如下所示 public class A private final User user public A User user this user user public void
  • Android MediaExtractor seek() 对 MP3 音频文件的准确性

    我在使用 Android 时无法在eek 上获得合理的准确度MediaExtractor 对于某些文件 例如this one http www archive org download emma solo librivox emma 01
  • 加速代码 - 3D 数组

    我正在尝试提高我编写的一些代码的速度 我想知道从 3d 整数数组访问数据的效率如何 我有一个数组 int cube new int 10 10 10 我用价值观填充其中 然后我访问这些值数千次 我想知道 由于理论上所有 3d 数组都存储在内
  • 磁模拟

    假设我在 n m 像素的 2D 表面上有 p 个节点 我希望这些节点相互吸引 使得它们相距越远吸引力就越强 但是 如果两个节点之间的距离 比如 d A B 小于某个阈值 比如 k 那么它们就会开始排斥 谁能让我开始编写一些关于如何随时间更新
  • Java按日期升序对列表对象进行排序[重复]

    这个问题在这里已经有答案了 我想按一个参数对对象列表进行排序 其日期格式为 YYYY MM DD HH mm 按升序排列 我找不到正确的解决方案 在 python 中使用 lambda 很容易对其进行排序 但在 Java 中我遇到了问题 f
  • 在两个活动之间传输数据[重复]

    这个问题在这里已经有答案了 我正在尝试在两个不同的活动之间发送和接收数据 我在这个网站上看到了一些其他问题 但没有任何问题涉及保留头等舱的状态 例如 如果我想从 A 类发送一个整数 X 到 B 类 然后对整数 X 进行一些操作 然后将其发送
  • JRE 系统库 [WebSphere v6.1 JRE](未绑定)

    将项目导入 Eclipse 后 我的构建路径中出现以下错误 JRE System Library WebSphere v6 1 JRE unbound 谁知道怎么修它 右键单击项目 特性 gt Java 构建路径 gt 图书馆 gt JRE
  • 如何在控制器、服务和存储库模式中使用 DTO

    我正在遵循控制器 服务和存储库模式 我只是想知道 DTO 在哪里出现 控制器应该只接收 DTO 吗 我的理解是您不希望外界了解底层域模型 从领域模型到 DTO 的转换应该发生在控制器层还是服务层 在今天使用 Spring MVC 和交互式
  • AWS 无法从 START_OBJECT 中反序列化 java.lang.String 实例

    我创建了一个 Lambda 函数 我想在 API 网关的帮助下通过 URL 访问它 我已经把一切都设置好了 我还创建了一个application jsonAPI Gateway 中的正文映射模板如下所示 input input params
  • 如何从终端运行处理应用程序

    我目前正在使用加工 http processing org对于一个小项目 但是我不喜欢它附带的文本编辑器 我使用 vim 编写所有代码 我找到了 pde 文件的位置 并且我一直在从 vim 中编辑它们 然后重新打开它们并运行它们 重新加载脚
  • Android 中麦克风的后台访问

    是否可以通过 Android 手机上的后台应用程序 服务 持续监控麦克风 我想做的一些想法 不断聆听背景中的声音信号 收到 有趣的 音频信号后 执行一些网络操作 如果前台应用程序需要的话 后台应用程序必须能够智能地放弃对麦克风的访问 除非可
  • 如何从指定日期获取上周五的日期? [复制]

    这个问题在这里已经有答案了 如何找出上一个 上一个 星期五 或指定日期的任何其他日期的日期 public getDateOnDay Date date String dayName 我不会给出答案 先自己尝试一下 但是 也许这些提示可以帮助
  • 捕获的图像分辨率太大

    我在做什么 我允许用户捕获图像 将其存储到 SD 卡中并上传到服务器 但捕获图像的分辨率为宽度 4608 像素和高度 2592 像素 现在我想要什么 如何在不影响质量的情况下获得小分辨率图像 例如我可以获取或设置捕获的图像分辨率为原始图像分
  • java.lang.IllegalStateException:驱动程序可执行文件的路径必须由 webdriver.chrome.driver 系统属性设置 - Similiar 不回答

    尝试学习 Selenium 我打开了类似的问题 但似乎没有任何帮助 我的代码 package seleniumPractice import org openqa selenium WebDriver import org openqa s

随机推荐

  • 使用服务帐户进行 Google Admin SDK 身份验证

    我的团队目前正在开发一个应用程序 以使用 Admin SDK 在 GCP 中列出我公司的域用户 以实现入职和离职目的 我们使用服务帐户来执行此操作 并且我们已经添加了admin directory user readonly范围 在 Goo
  • Primefaces 文件上传,将文件拖放到 p:fileUpload 页面任意位置之外

    在primefaces文件上传中 FileUpload组件本身就是放置区 我想创建多个拖放区 例如 如果用户将文件拖放到任何其他 div 或表上 Primefaces 文件上传组件应该选择该拖放区 我尝试手动触发 primefaces 上传
  • React:使用危险的SetInnerHTML插入时脚本标签不起作用

    我正在尝试使用React中的dangerouslySetInnerHTML属性将从我的服务器发送的html设置为在div内显示 我里面还有 script 标签 并使用该 html 中定义的函数 我在 JSFiddle 中制作了错误示例her
  • Oracle ODBC:SQL_HANDLE_ENV 上的驱动程序 SQLAllocHandle 失败

    我收到消息 Oracle ODBC SQL HANDLE ENV 上的驱动程序的 SQLAllocHandle 失败 当尝试在 Excel 中打开 Oracle 连接时 我正在通过 citrix 在虚拟机中工作 您能否给出提示为什么会出现以
  • for 循环括号内的两个分号

    我正在自定义在互联网上找到的代码 它是Adafruit 推文收据 我无法理解代码的很多部分 但最令我困惑的是括号内有两个分号的 for 循环 boolean jsonParse int depth byte endChar int c i
  • 如何在 Propel 中使用 MySQL 函数

    我想选择 1 个月或更晚的记录 查询是 SELECT FROM foobar WHERE created at gt DATE SUB curdate INTERVAL 1 MONTH 在 Symfony 中使用 Propel 我会 c 新
  • 无法使用 vba vlookup 查找日期

    我有一个 Excel 工作表 其中 A 列包含日期 B 列包含相应的日期 例如 A2 01 01 14 且 B2 星期三 依此类推 我尝试使用示例 vba 代码检索 B2 中的日期 但我不断收到错误消息 运行时错误 1004 无法获取wor
  • 即使不打开设置应用程序,是否可以将 Settings.bundle 中的设置设为默认值

    我有一个带有 settings bundle 的 iPhone 应用程序 可以处理我的应用程序的各种设置 我可以在 root plist 文件中设置默认值 使用 DefaultValue 属性 但这些值仅在用户第一次打开设置应用程序时使用
  • SICP 3.52 延迟 CDR

    练习3 52 define sum 0 define accum x set sum x sum sum 1 define seq stream map accum stream enumerate interval 1 20 2 defi
  • 在 php 中打印到 Zebra 打印机

    正在寻找使用 RAW 端口 9100 从 php 网页打印到 zebra IP 打印机的正确代码 有谁知道这是否可行 我需要将 ZPL 格式输出的字符串直接发送到 ZM400 标签打印机 我到处搜索 找到的最接近的是 使用php直接打印到网
  • 如何使下拉菜单自动完成消失 onblur 或单击 jquery 外部?

    下面是被调用以在搜索框中显示自动完成功能的函数 我希望自动完成功能在模糊或单击搜索框外部时消失 请告诉我应该在此函数中添加什么以使自动完成功能消失点击外面时向下消失 function hideLoader sub cont fadeIn 1
  • password_hash 到底是如何工作的?

    我试图理解密码哈希值充分以便能够向审核员解释 根据我对答案的寻找 我了解到password hash 函数是一个包装器crypt 在阅读 PHP 手册时预定义常量我看到它使用PASSWORD BCRYPT作为默认整数值 基本上它使用CRYP
  • PDO SQLite查询零结果问题

    我环顾四周 但似乎找不到任何有关此的信息 我不确定这是我的代码的问题还是内存 SQLite 数据库和 PDO 的已知问题 基本上 在将单行插入内存 SQLite 数据库表后 我希望与插入项不匹配的查询返回零行 但是 以下代码给出了一行 fa
  • 是否可以将 DataTable 作为 TextBox 中的 AutoCompleteSource? (C#)

    是否可以将 DataTable 作为 TextBox 中的 AutoCompleteSource C Jared 是正确的 如果不进行一些操作 就无法直接绑定 以下是使用 LINQ 数据集扩展检索字段作为自动完成源的示例 DataTable
  • Windows MIrror 驱动程序 远程显示驱动程序 VNC 服务器 Windows 8

    我正在开发远程桌面服务器的驱动程序 像 UltraVNC 内部协议 之类的东西 首先我发现 Windows 8 不支持镜像驱动程序 作为远程显示驱动程序的 DDI 的唯一子集 1 这是否意味着我需要为 Windows 8 实施远程显示驱动程
  • JavaScript:输入按键

    早上好 I am using java script in each page to trigger the Enter key press Event inside the textbox It is working fine Now i
  • 通过 Azure Powershell 设置 Azure 网站的主机名

    我正在尝试使用 PowerShell 将主机分配给 Azure 网站实例 我已验证要添加的域 主机是否有效 甚至转到 Azure 门户以验证其将新域识别为有效 但由于某种原因 下面的脚本没有像我认为应该的那样设置主机名 当我在为主机名设置新
  • 在运行时自动从 PowerShell 作业中提取数据

    当我试图做一些很可能超出 PowerShell 范围的事情时 我似乎遇到了障碍 我有一个主窗体脚本 它协调了我的大部分功能 但我需要另一个脚本来打开侦听器 system Net Sockets Udpclient Receive 并在整个程
  • 在 AWS Lambda 上安装新字体

    我正在 AWS Lambda 上安装 Imagemagick 但 Imagemagick 通常使用的字体似乎未预安装 如何添加其他字体 以下是我刚刚使用 pandoc xelatex 在 AWS Lambda 上处理自定义字体的工作 我假设
  • 使用 GDB 更改 JVM 中的变量值

    目前我有一个简单的Java程序 public class Test public static void main String args boolean test true while test System out println He