SA's JStack vs JDK's JSt
2017-06-27 本文已影响24人
andersonoy
-
Linux Signals
-
Standard Signals
Linux supports the standard signals listed below. Several signal
numbers are architecture-dependent, as indicated in the "Value"
column. (Where three values are given, the first one is usually
valid for alpha and sparc, the middle one for x86, arm, and most
other architectures, and the last one for mips.- table
- Signal Value Action Comment
- SIGKILL 9 Term Kill signal
- SIGSTOP 17,19,23 Stop Stop process
- table
-
signal.h
- partial
-
define SIGQUIT 3
-
define SIGKILL 9
-
define SIGSTOP 19
-
- partial
-
Signal Descriptions
- SIGKILL
- The SIGKILL signal forces the process to stop executing immediately. The program cannot ignore this signal. This process does not get to clean-up either.
- SIGQUIT
- This is like SIGINT with the ability to make the process produce a core dump.
- SIGSTOP
- This signal makes the operating system pause a process's execution. The process cannot ignore the signal.
- SIGKILL
-
kill -l (kill -9 pid)
- SIGQUIT
- SIGKILL
- SIGSTOP
-
-
References
-
ptrace
- process trace
- The ptrace() system call provides a means by which one process (the
"tracer") may observe and control the execution of another process
(the "tracee"), and examine and change the tracee's memory and
registers. It is primarily used to implement breakpoint debugging
and system call tracing. - long ptrace(enum __ptrace_request request,
pid_t pid, 指示ptrace要跟踪的进程
void *addr, 指示要监控的内存地址
void *data);存放读取出的或者要写入的数据- PTRACE_ATTACH
- Attach to the process specified in pid, making it a tracee of
the calling process. The tracee is sent a SIGSTOP, but will
not necessarily have stopped by the completion of this call;
use waitpid(2) to wait for the tracee to stop. See the
"Attaching and detaching" subsection for additional
information. (addr and data are ignored.)
- Attach to the process specified in pid, making it a tracee of
- ptrace(PTRACE_ATTACH, pid, 0, 0);
- PTRACE_ATTACH
- 你是否曾经想过怎样才能拦截系统调用?你是否曾经想过通过修改一下系统调用的参数来耍一把内核?你是否想过调试器是怎样把一个进程停下来,然后把控制权转移给你的?如果你以为这些都是通过复杂的内核编程来实现的,那你就错了,事实上,Linux 提供了一种很优雅的方式来实现上述所有行为:ptrace 系统调用。ptrace 提供了一种机制使得父进程可以观察和控制子进程的执行过程,ptrace 还可以检查和修改该子进程的可执行文件在内存中的镜像及该子进程所使用的寄存器中的值。这种用法通常来说,主要用于实现对进程插入断点和跟踪子进程的系统调用。
- ptrace函数可能会让人们觉得很奇特,因为它居然可以检测和修改一个运行中的程序。这种技术主要是在调试器和系统调用跟踪程序中使用。它使程序员可以在用户级别做更多有意思的事情。已经有过很多在用户级别下扩展操作系统得尝试,比如UFO,一个用户级别的文件系统扩展,它使用ptrace来实现一些安全机制。
- 进程状态TASK_TRACED用以表示当前进程因为被父进程跟踪而被系统停止
- gdb是我们调试程序的利器,strace可以方便的帮助我们记录进程所执行的系统调用 都是基于ptrace实现的;
-
References
-
proc
- process information pseudo-filesystem
- Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。
proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。
它以文件系统的方式为访问系统内核数据的操作提供接口 - The proc filesystem is a pseudo-filesystem which provides an
interface to kernel data structures. It is commonly mounted at
/proc. Most of it is read-only, but some files allow kernel
variables to be changed. - Files and directories
- /proc/[pid]
- There is a numerical subdirectory for each running process; the subdirectory is named by the process ID.
- /proc/[pid]/maps
- A file containing the currently mapped memory regions and their access permissions
- The format of the file is
address perms offset dev inode pathname
00400000-00452000 r-xp 00000000 08:02 173521 /usr/bin/dbus-daemon
00651000-00652000 r--p 00051000 08:02 173521 /usr/bin/dbus-daemon00652000-00655000 rw-p 00052000 08:02 173521 /usr/bin/dbus-daemon 00e03000-00e24000 rw-p 00000000 00:00 0 [heap] 00e24000-011f7000 rw-p 00000000 00:00 0 [heap] ... 35b1800000-35b1820000 r-xp 00000000 08:02 135522 /usr/lib64/ld-2.15.so 35b1a1f000-35b1a20000 r--p 0001f000 08:02 135522 /usr/lib64/ld-2.15.so 35b1a20000-35b1a21000 rw-p 00020000 08:02 135522 /usr/lib64/ld-2.15.so 35b1a21000-35b1a22000 rw-p 00000000 00:00 0 35b1c00000-35b1dac000 r-xp 00000000 08:02 135870 /usr/lib64/libc-2.15.so 35b1dac000-35b1fac000 ---p 001ac000 08:02 135870 /usr/lib64/libc-2.15.so 35b1fac000-35b1fb0000 r--p 001ac000 08:02 135870 /usr/lib64/libc-2.15.so 35b1fb0000-35b1fb2000 rw-p 001b0000 08:02 135870 /usr/lib64/libc-2.15.so ... f2c6ff8c000-7f2c7078c000 rw-p 00000000 00:00 0 [stack:986] ... 7fffb2c0d000-7fffb2c2e000 rw-p 00000000 00:00 0 [stack] 7fffb2d48000-7fffb2d49000 r-xp 00000000 00:00 0 [vdso]
-
References
-
HotSpot Serviceability Agent
- JStack
- HotSpot Serviceability Agent?简单来讲SA就是HotSpot提供的一套JavaAPI,通过这套API我们可以获取一个目标JVM的运行时信息,这套API的代码在$JAVA_HOME/lib/sa-jdi.jar中,源码的话是在hotspot工程的agent目录下: openjdk/hotspot/agent/***
- 介绍SA中的一个工具jstack。咦,jstack,好眼熟,是的,在JDK自带的工具中也有一个jstack,我们平时用的也都是它。在SA中也有一个JStack,二者实现的机制完全不一样
- JDK's JStack (openjdk/jdk/src/share/classes/sun/tools/jstack/JStack.java)
- 在jdk工程下发现了sun.tools.jstack.JStack,应该就是jstack命令的源码了。我们来跑下试下。这个类是在$JAVA_HOME/lib/tools.jar中。先把环境变量配置好
- 2132是通过jps命令看到的另一个Java进程的pid
- java sun.tools.jstack.JStack 2132
- 上面已经说到了两个jstack实现的机制是完全不一样的,SA中的jstack当然是通过SA的机制实现的,那么JDK中的jstack又是通过什么机制呢?其实是通过了另一个HotSpot提供的,Dynamic Attach机制(跟SA二者都是HotSpot的私有机制,不是JVM标准),具体这个机制是怎么实现的,这里暂不展开,有兴趣的同学可以看看笨神博客还有官方文档。
- SA's JStack (openjdk/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JStack.java)
- java sun.jvm.hotspot.tools.JStack 2132
- 看上去还是JDK自带的jstack输出友好一点。
- 加上-Dsun.jvm.hotspot.bugspot.BugSpotAgent.DEBUG=true选项会多输出一行,SA's JVMDI,这个又是什么鬼?暂不深究哈,还有SA的实现机制,留待后续再作探讨。
- JDK's JStack实现分析
- This class is the main class for the JStack utility. It parses its arguments and decides if the command should be executed by the SA JStack tool or by obtained the thread dump from a target process using the VM attach mechanism
if (useSA) {//使用SA runJStackTool(mixed, locks, params); - runJStackTool(){//反射调用 // JStack tool also takes -m and -l arguments Class cl = Class.forName("sun.jvm.hotspot.tools.JStack", true, ClassLoader.getSystemClassLoader()); Method m = cl.getDeclaredMethod("main", { String[].class }); m.invoke(null, { args }); } } else { runThreadDump(pid, params); - runThreadDump(){ // Attach to pid and perform a thread dump VirtualMachine vm = VirtualMachine.attach(pid); // Cast to HotSpotVirtualMachine as this is implementation specific method. InputStream in = ((HotSpotVirtualMachine)vm).remoteDataDump((Object[])args); //读取n = in.read(b); vm.detach(); } }
- 哪些情况下使用SA's JStack?
- -F
- -m
- Next we check the parameter count. If there are two parameters we assume core file and executable so we use SA.
- 参数的值不能匹配数字[0-9]+ //If we can't parse it as a pid then it must be debug server
- SA non-supported
- jstack [-l] <pid> to connect to running process
- -l long listing. Prints additional information about locks
- -h or -help to print this help message
- jstack [-l] <pid> to connect to running process
- SA supported
- jstack -F [-m] [-l] <pid> to connect to a hung process
- jstack [-m] [-l] <executable> <core> to connect to a core file
- jstack [-m] [-l] [server_id@]<remote server IP or hostname> to connect to a remote debug server
- -F to force a thread dump. Use when jstack <pid> does not respond process is hung
- -m to print both java and native frames (mixed mode)
- This class is the main class for the JStack utility. It parses its arguments and decides if the command should be executed by the SA JStack tool or by obtained the thread dump from a target process using the VM attach mechanism
- SA's JStack实现分析
- 官方文档对其实现机制有以下描述
- SA consists mostly of Java classes but it contains a small amount of native code to read raw bits from processes and core files.
- On Linux, SA uses a mix of /proc and ptrace (mostly the latter) to read bits from a process. For core files, SA parses ELF files directly.
- 在Linux平台上,是使用了/proc和ptrace
- 1.SA工具的基类是Tool,通过调用start方法启动,该方法里面会new一个BugSpotAgent,并且attach到目标VM上面
- 先来看是怎么attach到目标进程的
// attach to a process/thread specified by "pid"
static bool ptrace_attach(pid_t pid) {
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {//这里调用了系统调用ptrace!!!
print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid);
return false;
} else {
return ptrace_waitpid(pid);
}
}
- rslt = ptrace(PTRACE_PEEKDATA, ph->pid, aligned_addr, 0);//读取数据
- 后面的太复杂,有兴趣的看看http://blog.csdn.net/kisimple/article/details/46496721 - 总结一下,
- 通过/proc/[pid]/maps读取ELF文件,保存符号表
- 通过符号表读取HotSpotVM中localHotSpotVMStructs,localHotSpotVMTypes等变量的地址
- 使用ptrace读取上述变量的值
- 这两个变量值包含了SA需要用到的HotSpotVM中的数据的元信息(类型信息,字段offset,地址等)
- 有了这些元信息就可以使用ptrace读取目标VM上这些数据的值
- 官方文档对其实现机制有以下描述
- JStack
-
References
-
Java Attach Api 实现分析
- The Attach API is a Sun Microsystems extension that provides a mechanism to attach to a Java™ virtual machine. A tool written in the Java Language, uses this API to attach to a target virtual machine and load its tool agent into that virtual machine. For example, a management console might have a management agent which it uses to obtain management information from instrumented objects in a virtual machine. If the management console is required to manage an application that is running in a virtual machine that does not include the management agent, then this API can be used to attach to the target virtual machine and load the agent.
-
References