Slide 1

Slide 1 text

Java Debugging Internals @yardenlaif

Slide 2

Slide 2 text

2 Who Am I? • Software Engineer at Rookout • Background in low level C programming in linux IOT environments • Java, Go, Ruby • C#, Python, JavaScript, C++

Slide 3

Slide 3 text

Non Breaking Breakpoints 3

Slide 4

Slide 4 text

Non Breaking Breakpoints 4

Slide 5

Slide 5 text

jdb -attach 8000 java -agentlib:jdwp= transport=dt_socket,server=y, suspend=n,address=*:8000 myApp JDB - The Java Debugger 5 JVM MyApp Debugger CLI

Slide 6

Slide 6 text

JPDA - Java Platform Debugging Architecture The Java Platform Debugger Architecture (JPDA) consists of three interfaces designed for use by debuggers in development environments for desktop systems. - Oracle Documentation 6

Slide 7

Slide 7 text

JPDA - Java Platform Debugging Architecture ● JDI - Java Debug Interface ● JDWP - Java Debug Wire Protocol ● JVMTI - Java Virtual Machine Tool Interface 7

Slide 8

Slide 8 text

JDI - Java Debug Interface ● High level Java API ● Inspect & Control ● Connect remotely 8

Slide 9

Slide 9 text

JDI - Java Debug Interface ● Add breakpoint ○ createBreakpointRequest ● Collect data ○ visibleVariables ○ getArgumentValues ○ frames ● Continue program ○ resume 9

Slide 10

Slide 10 text

Using JDI ● No availability during collection ● Zero control or visibility ● Easy to make mistakes ● Single instance debugging 10

Slide 11

Slide 11 text

JPDA - Java Platform Debugging Architecture ● JDI - Java Debug Interface ● JDWP - Java Debug Wire Protocol ● JVMTI - Java Virtual Machine Tool Interface 11

Slide 12

Slide 12 text

JDWP - Java Debug Wire Protocol ● A protocol ● Used for communication between a debugger and the JVM which it debugs 12 JVM MyApp Debugger CLI JDWP

Slide 13

Slide 13 text

Using JDWP ● No availability during collection ● Zero control or visibility ● Easy to make mistakes ● Single instance debugging ● Managing multiple clients and connecting to multiple servers 13

Slide 14

Slide 14 text

JPDA - Java Platform Debugging Architecture ● JDI - Java Debug Interface ● JDWP - Java Debug Wire Protocol ● JVMTI - Java Virtual Machine Tool Interface 14

Slide 15

Slide 15 text

JVMTI - Java Virtual Machine Tool Interface ● Native programming interface ● Interacts directly with the JVM ● Inspect & Control 15

Slide 16

Slide 16 text

JVMTI - Java Virtual Machine Tool Interface ● SetBreakpoint ● SetEventNotificationMode ○ Breakpoint ● GetLocalObject ○ jobject 16

Slide 17

Slide 17 text

JVMTI - Get Stack Trace /* Get Stack Trace */ err = (*jvmti)->GetStackTrace(jvmti, thr, 0, 5, &frames, &count); if (err != JVMTI_ERROR_NONE) { printf("(GetThreadInfo) Error expected: %d, got: %d\n", JVMTI_ERROR_NONE, err); describe(err); printf("\n"); } printf("Number of records filled: %d\n", count); if (err == JVMTI_ERROR_NONE && count >=1) { char *methodName; methodName = "yet_to_call()"; char *declaringClassName; jclass declaring_class; int i=0; printf("Exception Stack Trace\n"); printf("=====================\n"); printf("Stack Trace Depth: %d\n", count); for ( i=0; i < count; i++) { err = (*jvmti)->GetMethodName(jvmti, frames[i].method, &methodName, NULL, NULL); if (err == JVMTI_ERROR_NONE) { err = (*jvmti)->GetMethodDeclaringClass(jvmti, frames[i].method, &declaring_class); err = (*jvmti)->GetClassSignature(jvmti, declaring_class, &declaringClassName, NULL); if (err == JVMTI_ERROR_NONE) { printf("at method %s() in class %s\n", methodName, declaringClassName); } } } } 17 *A lot of code*

Slide 18

Slide 18 text

Java - Get Stack Trace Thread.currentThread().getStackTrace() 18

Slide 19

Slide 19 text

Using JVMTI ● Incredibly Complex ● Native vulnerabilities ● Not portable ● Bugs are catastrophic 19

Slide 20

Slide 20 text

20 Newer? Simpler? Full control? In-process? Unbreakable?

Slide 21

Slide 21 text

Requirements 21 ● Don’t break ● Predictability ● Availability ● Performance ● Security and compliance ● Multi-instance debugging

Slide 22

Slide 22 text

Thread 2: Client Connection public Response Process(Request req) { String id = req.GetID(); if (isExistingUser(id)) { return new Response("User exists!"); } // Create new user... } Requirements 22 ● Don’t break ● Availability Thread 1: Server Client Connection Thread 3: Client Connection public Response Process(Request req) { String id = req.GetID(); if (isExistingUser(id)) { return new Response("User exists!"); } // Create new user... } Thread 2: Client Connection public Response Process(Request req) { String id = req.GetID(); if (isExistingUser(id)) { return new Response("User exists!"); } // Create new user... }

Slide 23

Slide 23 text

-agentlib:jdwp address=*:8000 transport=dt_socket server=y suspend=n Break It Down java -agentlib:jdwp=transport=dt_socket,server=y, suspend=n,address=*:8000 myApp 23

Slide 24

Slide 24 text

Java Agents 24

Slide 25

Slide 25 text

Java Agents 25 JVM MyApp Java Agent java.lang.Instrument API

Slide 26

Slide 26 text

Sample Program 26 1| public class HelloWorld { 2| public static void main(String[] args) { 3| while(true) { 4| System.out.println("Hello, World!"); 5| } 6| } 7| }

Slide 27

Slide 27 text

Sample Program 27 ● Build HelloWorld to JAR ● Run: java -jar HelloWorld.jar ● Output: Hello, World! Hello, World! ...

Slide 28

Slide 28 text

Java Agent - Premain 28 public class JavaAgent { public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { System.out.println("Hello, JavaSummit!"); } }

Slide 29

Slide 29 text

Java Agent - Premain 29 public class JavaAgent { public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { System.out.println("Hello, JavaSummit!"); } }

Slide 30

Slide 30 text

Java Agent - Premain 30 public class JavaAgent { public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { System.out.println("Hello, JavaSummit!"); } }

Slide 31

Slide 31 text

Java Agent - Premain 31 public class JavaAgent { public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { System.out.println("Hello, JavaSummit!"); } }

Slide 32

Slide 32 text

Java Agent - Premain 32 ● Build JavaAgent to JAR ● Run with java agent: java -javaagent:JavaAgent.jar -jar HelloWorld.jar ● Output: Hello, JavaSummit! Hello, World! ...

Slide 33

Slide 33 text

Java Agent - ClassFileTransformer 33 JVM Compiler Code Bytecode

Slide 34

Slide 34 text

Java Agent - ClassFileTransformer 34 JVM 32 | … 33 | new Item() 34 | … Class Loader Get Item class bytecode Return Item class bytecode

Slide 35

Slide 35 text

Java Agent - ClassFileTransformer 35 JVM 32 | … 33 | new Item() 34 | … Class Loader Get Item class bytecode Return Item class bytecode Class File Transformer Return transformed Item class bytecode

Slide 36

Slide 36 text

Java Agent - ClassFileTransformer 36 public class JavaAgent { public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { System.out.println("Hello, JavaSummit!"); } } ● void addTransformer(ClassFileTransformer transformer);

Slide 37

Slide 37 text

Java Agent - ClassFileTransformer 37 public class DebugTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {

Slide 38

Slide 38 text

Java Agent - ClassFileTransformer 38 public class DebugTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {

Slide 39

Slide 39 text

Java Agent - ClassFileTransformer 39 public class DebugTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {

Slide 40

Slide 40 text

Open Source Bytecode Manipulation Tools BCEL ASM 40

Slide 41

Slide 41 text

Bytecode Abstraction 41 ● AbstractInsnNode ○ JumpInsnNode ○ MethodInsnNode ○ VarInsnNode ● InsnList instructions

Slide 42

Slide 42 text

Bytecode Manipulation 42 byte[] addPrintCall(byte[] classfileBuffer) { // Add call to System.out.println("Transformed!") // Return transformed bytecode }

Slide 43

Slide 43 text

Java Agent - ClassFileTransformer 43 public class DebugTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { if (className.contains("HelloWorld")) { return addPrintCall(classfileBuffer); } return classfileBuffer; } }

Slide 44

Slide 44 text

Java Agent - ClassFileTransformer 44 public class DebugTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { if (className.contains("HelloWorld")) { return addPrintCall(classfileBuffer); } return classfileBuffer; } }

Slide 45

Slide 45 text

Java Agent - Premain 45 public class JavaAgent { public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { DebugTransformer transformer = new DebugTransformer(); instrumentation.addTransformer(transformer); } }

Slide 46

Slide 46 text

Java Agent - Premain 46 public class JavaAgent { public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { DebugTransformer transformer = new DebugTransformer(); instrumentation.addTransformer(transformer); } }

Slide 47

Slide 47 text

Java Agent - Premain 47 ● Build JavaAgent to JAR ● Run with java agent: java -javaagent:JavaAgent.jar -jar HelloWorld.jar ● Output: Transformed! Hello, World! Hello, World! ...

Slide 48

Slide 48 text

Non-Breaking Breakpoints!

Slide 49

Slide 49 text

Profiling Interpreter C2 C1 Profiling Profiling Interpreter C2 C1 Profiling JVM Execution Engine 49

Slide 50

Slide 50 text

Add Breakpoint 50 public void Breakpoint(Object[] locals) { System.out.println("Breakpoint hit!"); for (Object local : locals) { System.out.println(local); } }

Slide 51

Slide 51 text

Add Breakpoint 51 byte[] addBreakpoint(byte[] classfileBuffer, int lineno) { // Find where to insert Breakpoint call // Push local variables onto stack // Insert call to Breakpoint // Return transformed bytecode }

Slide 52

Slide 52 text

Add Breakpoint 52 byte[] addBreakpoint(byte[] classfileBuffer, int lineno) { // Find where to insert Breakpoint call // Push local variables onto stack // Insert call to Breakpoint // Return transformed bytecode }

Slide 53

Slide 53 text

Add Breakpoint 53 byte[] addBreakpoint(byte[] classfileBuffer, int lineno) { // Find where to insert Breakpoint call // Push local variables onto stack // Insert call to Breakpoint // Return transformed bytecode }

Slide 54

Slide 54 text

Add Breakpoint 54 byte[] addBreakpoint(byte[] classfileBuffer, int lineno) { // Find where to insert Breakpoint call // Push local variables onto stack // Insert call to Breakpoint // Return transformed bytecode }

Slide 55

Slide 55 text

Add Breakpoint 55 byte[] addBreakpoint(byte[] classfileBuffer, int lineno) { // Find where to insert Breakpoint call // Push local variables onto stack // Insert call to Breakpoint // Return transformed bytecode }

Slide 56

Slide 56 text

Sample Program 56 1| public class HelloWorld { 2| public static void main(String[] args) { 3| while(true) { 4| System.out.println("Hello, World!"); 5| } 6| } 7| }

Slide 57

Slide 57 text

Java Agent - ClassFileTransformer 57 public class DebugTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { if (className.contains("HelloWorld")) { return addBreakpoint(classfileBuffer, 4); } return classfileBuffer; } }

Slide 58

Slide 58 text

Java Agent - Premain 58 ● Build JavaAgent to JAR ● Run with java agent: java -javaagent:JavaAgent.jar -jar HelloWorld.jar ● Output: Breakpoint hit! [Ljava.lang.Object;@3d075dc0 Hello, World! ...

Slide 59

Slide 59 text

59 What if the class has already been loaded?

Slide 60

Slide 60 text

Magic Instrumentation 60 void redefineClasses(ClassDefinition... definitions) void retransformClasses(Class... classes)

Slide 61

Slide 61 text

Putting it all together 61 ● Transform on demand ● Add call to breakpoint function ● Access locals as objects

Slide 62

Slide 62 text

62 Putting it all together

Slide 63

Slide 63 text

Thank You @yardenlaif rookout.com