`
caoxudong818
  • 浏览: 45769 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Serviceability 简介 —— tools

    博客分类:
  • sa
 
阅读更多

前文中提到,$JAVA_HOME/bin下有一些工具也是通过SA实现的,本文就对SA中tools包下的工具做简单介绍。

 

tools包下一个主要的类是sun.jvm.hotspot.tools.Tool。使用SA实现的工具类大部分都是继承自此类。子类通过覆盖run方法来实现自定义的功能。例如,类sun.jvm.hotspot.tools.JInfo在run方法中确定是打印系统属性还是打印虚拟机参数:

 

public void run() {
        Tool tool = null;
        switch (mode) {
        case MODE_FLAGS:
            printVMFlags();
            return;
        case MODE_SYSPROPS:
            tool = new SysPropsDumper();
            break;
        case MODE_BOTH: {
            tool = new Tool() {
                    public void run() {
                        Tool sysProps = new SysPropsDumper();
                        sysProps.setAgent(getAgent());
                        System.out.println("Java System Properties:");
                        System.out.println();
                        sysProps.run();
                        System.out.println();
                        System.out.println("VM Flags:");
                        printVMFlags();
                        System.out.println();
                    }
                };
            }
            break;

        default:
            usage();
            break;
        }
        tool.setAgent(getAgent());
        tool.run();
    }

 

 

在使用的时候,一般会是如下情况:

  1. 启动Java,调用子类的main方法;
  2. 子类做一些初步的处理;
  3. 调用sun.jvm.hotspot.tools.Tool类的start方法,传入相应的命令行参数;
  4. 在start方法中根据接收的参数判断要使用何种调式类型;
  5. 根据不同的调式类型使用不同的attach(不知道还用什么词比较好)策略;
  6. 调用子类实现的run方法。
  7. 调用 sun.jvm.hotspot.tools.Tool类的 方法,一般用于从目标JVM中detach

所以,如果想自己编写调试工具的话,只需要继承Tool类,实现run方法,再调用类似下面的代码(以FinalizerInfo类为例)即可:

 

public static void main(String[] args) {
        FinalizerInfo finfo = new FinalizerInfo();
        finfo.start(args);
        finfo.stop();
    }

 

下面看一下Tool类是如何进行调试的。

在Tool类中,定义了3中调试类型,分别是:

 

   // debugeeType is one of constants below
   protected static final int DEBUGEE_PID    = 0;
   protected static final int DEBUGEE_CORE   = 1;
   protected static final int DEBUGEE_REMOTE = 2;
 

针对不同的调式类型所使用的attach代码:

switch (debugeeType) {
    case DEBUGEE_PID:
        err.println("Attaching to process ID " + pid + ", please wait...");
        agent.attach(pid);
        break;

    case DEBUGEE_CORE:
         err.println("Attaching to core " + coreFileName + " from executable " + executableName + ", please wait...");
         agent.attach(executableName, coreFileName);
         break;

     case DEBUGEE_REMOTE:
         err.println("Attaching to remote server " + remoteServer + ", please wait...");
         agent.attach(remoteServer);
         break;
}

 

 

由上面的代码中可以看到,调式功能主要是通过agent进行的,该变量是一个sun.jvm.hotspot.bugspot.BugSpotAgent类的实例。

 

OpenJDK 写道
This class wraps the basic functionality for connecting to the target process or debug server. It makes it simple to start up the debugging system.

This agent (as compared to the HotSpotAgent) can connect to and interact with arbitrary processes. If the target process happens to be a HotSpot JVM, the Java debugging features of the Serviceability Agent are enabled.

Further, if the Serviceability Agent's JVMDI module is loaded into the target VM, interaction with the live Java program is possible, specifically the catching of exceptions and setting of breakpoints.

The BugSpot debugger requires that the underlying Debugger support C/C++ debugging via the CDebugger interface.

 

该类的主要功能是简化对JVM的调试。它可以对任意目标进行调试,若目标进行是HotSpot JVM,则启用SA。若目标JVM载入了JVMDI模块,则可以与Java程序进行交互。

 

在该类中,调试功能(如加断点、挂起线程、恢复线程运行、挂起目标JVM等)都是通过sun.jvm.hotspot.livejvm.ServiceabilityAgentJVMDIModule类完成的。当然,使用ServiceabilityAgentJVMDIModule类的前提是目标JVM是HotSpot,并且启用了SA的JVMDI模块。例如下面添加断点的代码:

 

/** Toggle a Java breakpoint at the given location. */
    public synchronized ServiceabilityAgentJVMDIModule.BreakpointToggleResult
    toggleJavaBreakpoint(String srcFileName, String pkgName, int lineNo) {
        if (!canInteractWithJava()) {
            throw new DebuggerException("Could not connect to SA's JVMDI module; can not toggle Java breakpoints");
        }
        return jvmdi.toggleBreakpoint(srcFileName, pkgName, lineNo);
    }

 

 

ServiceabilityAgentJVMDIModule类是一个Java语言级的交互式调试工具。

 

/** Provides Java programming language-level interaction with a live
    Java HotSpot VM via the use of the SA's JVMDI module. This is an
    experimental mechanism. The BugSpot debugger should be converted
    to use the JVMDI/JDWP-based JDI implementation for live process
    interaction once the JDI binding for the SA is complete. */

 

其中,VM与SA交互部分的数据有:

 

// Values in target process
  // Events sent from VM to SA
  private CIntegerAccessor saAttached;
  private CIntegerAccessor saEventPending;
  private CIntegerAccessor saEventKind;
  // Exception events
  private JNIHandleAccessor saExceptionThread;
  private JNIHandleAccessor saExceptionClass;
  private JNIid             saExceptionMethod;
  private CIntegerAccessor  saExceptionLocation;
  private JNIHandleAccessor saExceptionException;
  private JNIHandleAccessor saExceptionCatchClass;
  private JNIid             saExceptionCatchMethod;
  private CIntegerAccessor  saExceptionCatchLocation;
  // Breakpoint events
  private JNIHandleAccessor saBreakpointThread;
  private JNIHandleAccessor saBreakpointClass;
  private JNIid             saBreakpointMethod;
  private CIntegerAccessor  saBreakpointLocation;
  // Commands sent by the SA to the VM
  private int               SA_CMD_SUSPEND_ALL;
  private int               SA_CMD_RESUME_ALL;
  private int               SA_CMD_TOGGLE_BREAKPOINT;
  private int               SA_CMD_BUF_SIZE;
  private CIntegerAccessor  saCmdPending;
  private CIntegerAccessor  saCmdType;
  private CIntegerAccessor  saCmdResult;
  private CStringAccessor   saCmdResultErrMsg;
  // Toggle breakpoint command arguments
  private CStringAccessor   saCmdBkptSrcFileName;
  private CStringAccessor   saCmdBkptPkgName;
  private CIntegerAccessor  saCmdBkptLineNumber;
  private CIntegerAccessor  saCmdBkptResWasError;
  private CIntegerAccessor  saCmdBkptResLineNumber;
  private CIntegerAccessor  saCmdBkptResBCI;
  private CIntegerAccessor  saCmdBkptResWasSet;
  private CStringAccessor   saCmdBkptResMethodName;
  private CStringAccessor   saCmdBkptResMethodSig;
 

在继续对ServiceabilityAgentJVMDIModule类进行介绍之前,先说一个这里常用到的类sun.jvm.hotspot.debugger.Address。该类是在调试过程中对地址进行访问的底层抽象接口,简单的理解话,就当作是指针地址好了。你可以在使用CLHSDB的过程中看到很多数据后面都会跟着一个类似于“0x32bf4978”这样的数,这个就是地址,Address类对这个进行了封装,便于在Java中进行访问和操作,提供了对地址的加、减、比较和位运算,以及获取、设置指定地址内容等操作。例如:

 

public long       getCIntegerAt      (long offset, long numBytes, boolean isUnsigned)
    throws UnmappedAddressException, UnalignedAddressException;
/** Sets a C integer numBytes in size at the specified offset. Note
      that there is no "unsigned" flag for the accessor since the
      value will not be sign-extended; the number of bytes are simply
      copied from the value into the target address space. */
  public void setCIntegerAt(long offset, long numBytes, long value);
/** This throws an UnsupportedOperationException if this address happens
      to actually be an OopHandle, because interior object pointers
      are not allowed. Negative offsets are allowed and handle the
      subtraction case. */
  public Address    addOffsetTo        (long offset) throws UnsupportedOperationException;
/** This throws an UnsupportedOperationException if this address happens
      to actually be an OopHandle. Performs a logical "and" operation
      of the bits of the address and the mask (least significant bits
      of the Address and the mask are aligned) and returns the result
      as an Address. Returns null if the result was zero. */
  public Address    andWithMask(long mask) throws UnsupportedOperationException;

 

当然,在使用Address过程中,会有一些需要注意的地方:

 

  • 地址是不可变的(immutable),但其指向的内容是可变的,可以理解为const void* point;
  • 如果当前的调试目标是一个核心转储文件(core dump),则不可以修改地址指向的内容;
  • C/C++中的地址一般由无符号整数表示,而Java中不存在无符号原生类型,所以以原始地址数据(例如0x32bf4978)为参数的方法中,都是以long型代替。相应的,对地址进行运行时,也需要注意类型的处理。

下面以Linux平台为例进行说明。在Linux上,Address类是实现类是sun.jvm.hotspot.debugger.linux.LinuxAddress。在该类中,对地址指向的数据的读取操作是通过sun.jvm.hotspot.debugger.linux.LinuxDebugger类完成的,而写操作目前还未实现,调用方法时会抛异常。对sun.jvm.hotspot.debugger.linux.LinuxDebugger类的说明并不是本文的目的,就此打住,后续的文章中再谈。

 

现在回到ServiceabilityAgentJVMDIModule类,在前面提到的SA与VM交互的数据中,其类型基本上都是对Address的封装。这里有个奇怪的问题,在挂起VM线程的suspend方法中,会调用sun.jvm.hotspot.livejvm.CIntegerAccessor类的setValue方法,而这个方法实现是通过调用Address类的setCIntegerAt方法完成的。从目前看到的Address的实现类(包括LinuxAddressWindbgAddressDbxAddressDummyAddressRemoteAddressProcAddress)看,setValue方法都会抛出异常(Win32Address类除外)。

 

ServiceabilityAgentJVMDIModule类的suspend方法:

 

/** Suspend all Java threads in the target VM. Throws
      DebuggerException if the VM disconnected. */
  public void suspend() {
    saCmdType.setValue(SA_CMD_SUSPEND_ALL);
    saCmdPending.setValue(1);
    waitForCommandCompletion();
    suspended = true;
  }

 

CIntegerAccessor类的setValue方法:

 

void setValue(long value) {
    addr.setCIntegerAt(0, numBytes, value);
  }
 

 

LinuxAddress类setCIntegerAt方法:

 

// Mutators -- not implemented for now (FIXME)
  public void setCIntegerAt(long offset, long numBytes, long value) {
    throw new DebuggerException("Unimplemented");
  }

 

只有Win32Address类中,通过Win32Debugger接口提供对setCIntegerAt方法的实现,在该接口的实现类Win32DebuggerLocal的父类DebuggerBase类中的writeCInteger方法中会做相应的检查,包括字节对齐和相应成员对象是否存在的检查。在最终实现上,是通过Win32DebuggerLocalwriteBytesToProcess方法完成的。

 

Win32Address类的setCIntegerAt方法:

 

public void setCIntegerAt(long offset, long numBytes, long value) {
    debugger.writeCInteger(addr + offset, numBytes, value);
  }

 

 

DebuggerBase类的writeCInteger方法:

 

public void writeCInteger(long address, long numBytes, long value)
    throws UnmappedAddressException, UnalignedAddressException {
    checkConfigured();
    utils.checkAlignment(address, numBytes);
    byte[] data = utils.cIntegerToData(numBytes, value);
    writeBytes(address, numBytes, data);
  }

 

 

Win32DebuggerLocal类的writeBytesToProcess方法:

 

public synchronized void writeBytesToProcess(long startAddress, long numBytes, byte[] data)
    throws UnmappedAddressException, DebuggerException {
    try {
      printToOutput("poke 0x" + Long.toHexString(startAddress) +
                    " |");
      writeIntToOutput((int) numBytes);
      writeToOutput(data, 0, (int) numBytes);
      printlnToOutput("");
      if (!in.parseBoolean()) {
        throw new UnmappedAddressException(startAddress);
      }
    } catch (IOException e) {
      throw new DebuggerException(e);
    }
  }

 

到这里就是将内容发送到输出中,至于内容中“poke”是个啥玩意,还不清楚,需要后续跟进一些调试器的知识。这里的输出应该是与本地程序之间建立的socket连接:

 

 /** Connects to the debug server, setting up out and in streams. */
  private void connectToDebugServer() throws IOException {
    // Try for a short period of time to connect to debug server; time out
    // with failure if didn't succeed
    debuggerSocket = null;
    long endTime = System.currentTimeMillis() + SHORT_TIMEOUT;

    while ((debuggerSocket == null) && (System.currentTimeMillis() < endTime)) {
      try {
        // FIXME: this does not work if we are on a DHCP machine which
        // did not get an IP address this session. It appears to use
        // an old cached address and the connection does not actually
        // succeed. Must file a bug.
        // debuggerSocket = new Socket(InetAddress.getLocalHost(), PORT);
        debuggerSocket = new Socket(InetAddress.getByName("127.0.0.1"), PORT);
        debuggerSocket.setTcpNoDelay(true);
      }
      catch (IOException e) {
        // Swallow IO exceptions while attempting connection
        debuggerSocket = null;
        try {
          // Don't swamp the CPU
          Thread.sleep(750);
        }
        catch (InterruptedException ex) {
        }
      }
    }

    if (debuggerSocket == null) {
      // Failed to connect because of timeout
      throw new DebuggerException("Timed out while attempting to connect to debug server (please start SwDbgSrv.exe)");
    }

    out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(debuggerSocket.getOutputStream(), "US-ASCII")), true);
    rawOut = new DataOutputStream(new BufferedOutputStream(debuggerSocket.getOutputStream()));
    in = new InputLexer(new BufferedInputStream(debuggerSocket.getInputStream()));
  }
 

说到这里,有个问题,难道只有win32下可以进行调试么?那么,这个方法会不会有问题呢?到底有没有调用ServiceabilityAgentJVMDIModule类的suspend方法呢?现在手边没有开发环境,等配置好后,再通过btrace查一下。

 

to be continued......

分享到:
评论

相关推荐

    鸿蒙关于js与serviceAbility交互的Demo讲解

    接下来,我们转向Java端,创建`serviceAbility.java`文件,这里定义Service Ability的行为。我们需要实现`onRemoteRequest()`方法,根据接收到的动作来判断是订阅还是取消订阅的请求。在处理这些请求时,我们可以...

    Reliability, Availability and Serviceability on Linux.pdf

    在探讨Linux系统中的可靠性(Reliability)、可用性(Availability)和服务性(Serviceability),简称RAS特性时,首先需要明确RAS概念的由来及其在Linux环境下的应用。 RAS最初是IBM为衡量大型机(mainframe)的...

    IBM 小型机 P770 P780更换 I/O柜电源

    如果日志没有报出故障电源具体位置,可以从 Serviceability——Hardware-——Exchange FRU 中查找故障电源模块的信息。 五、结论 更换 I/O 柜电源是一个复杂的过程,需要经过详细的诊断和检查。在执行更换操作前,...

    ServiceAbilityDemo.zip

    ServiceAbilityDemo.zip是一个关于华为鸿蒙操作系统(HarmonyOS)中的ServiceAbility开发示例的压缩包。ServiceAbility是鸿蒙系统中的一种核心组件,用于实现应用程序间的后台服务交互。在这个示例中,开发者可以学习...

    Service实现通知,判断通知栏是否已打开

    在Android应用开发中,服务(Service)是一种在后台运行,不与用户交互的组件。它常用于执行长时间的任务,如播放音乐、网络通信等。在本主题中,我们将深入探讨如何利用Service来实现通知功能,并检测通知栏是否...

    Java Performance Companion(Addison,2016)

    Using HotSpot VM Serviceability Agent to analyze, triage, and resolve diverse HotSpot VM issues Troubleshooting out of memory errors, Java level deadlocks, and HotSpot VM crashes Extending the ...

    IBMSystemp5最新产品简介updateV35.pptx

    在"IBM System p5 最新产品简介updateV35.pptx"中,主要介绍了UNIX计算的发展趋势、IBM System p5的技术优势以及具体的产品家族和热点产品。 首先,UNIX计算经历了三个阶段:工作站阶段、单一服务器阶段和系统整合...

    jdk-9.0.1_doc-all 最新版

    Defines the implementation of the HotSpot Serviceability Agent. jdk.httpserver Defines the JDK-specific HTTP server API. jdk.incubator.httpclient Defines the high-level HTTP and WebSocket API. jdk....

    IBM System p5最新产品简介--updateV35.pptx

    此产品系列是IBM在技术领域的创新体现,尤其是在RAS(Reliability, Availability, Serviceability)特性、性能优势以及服务器整合方面。 首先,我们来看UNIX计算的发展趋势。从第四页的内容可以看出,UNIX计算经历...

    hllvm.借HSDB来探索HotSpot VM的运行时数据1

    【描述】:本篇文章旨在探讨Java内存模型中不同类型的变量——包括静态变量t1、实例变量t2和局部变量t3——在HotSpot VM中的存储位置。我们将借助HSDB(HotSpot Serviceability Agent的调试器)来探索实际运行时的...

    PPR(Post Package Repair)功能简介

    **RAS(Reliability, Availability, and Serviceability)**是一套旨在提升内存系统可靠性的技术体系。将PPR纳入RAS体系中,使其成为一种有效的修复手段,对于提高内存系统的整体可靠性至关重要。 - **修复策略**: ...

    NetApp EF560 用户操作手册

    《NetApp EF560 用户操作手册》是针对NetApp公司的一款高性能全闪存存储阵列——EF560的设计和操作进行详细阐述的技术报告。该文档旨在为销售工程师、合作伙伴、服务提供商以及最终用户提供一个了解EF560系统特性的...

    HPBCS产品介绍.pptx

    本文件主要介绍了HPBCS中的核心组件——下一代 Integrity 服务器(Next Generation Integrity Systems, NGIS)。NGIS是惠普基于Itanium处理器的高端服务器平台,它为运行关键业务应用提供了高可用性、可扩展性和安全...

    DAOS技术手册.docx

    1. RAS:Reliability, Availability & Serviceability,用于提供高可靠性和可用性。 2. RDMA/RMA:Remote (Direct) Memory Access,用于提供高性能和低延迟的存储。 3. HLC:Hybrid Logical Clock,用于提供高效的...

    Fujitsu(富士通)发布全新SPARC64 Ⅶ4核处理器.pdf

    标题提及的"Fujitsu(富士通)发布全新SPARC64 Ⅶ4核处理器"是关于富士通公司推出的一款高性能处理器——SPARC64 Ⅶ4。这款处理器设计用于高端计算平台,拥有四个内核和八条线程,最大频率可达2.52GHz,相较于上一代...

    品质内涵、全面品质管理与ISO 9000品保系统简介(ppt 76页).pptx

    6. 服务性(Serviceability):服务的速度、价格竞争性和维修便利性。 7. 美学(Aesthetics):产品的外观、感觉和感官体验。 8. 意识到的品质(Perceived Quality):基于品牌、广告等无形因素对品质的主观评价。 ...

    BSEN1993-1-12-2007Eurocode3—designofsteelstructures

    It complies with the principles and requirements for the safety and serviceability of structures, the basis of their design and verification that are given in EN 1990 – Basis of structural design....

    linux集群 heartbeat应用

    Linux-HA的全称是High-Availability Linux,这个开源项目的目标是:通过社区开发者的共同努力,提供一个增强linux可靠性(reliability)、可用性(availability)和可服务性(serviceability)(RAS)的群集解决方案...

    RAS32&amp;16再剖析

    在信息技术领域,RAS(Reliability, Availability, and Serviceability)是衡量系统稳定性和可维护性的重要指标,广泛应用于高性能计算、数据中心以及企业级服务器等领域。RAS32和RAS16是两个与RAS相关的概念,它们...

Global site tag (gtag.js) - Google Analytics