xref: /aosp_15_r20/art/test/jvmti-common/Breakpoint.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker package art;
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Executable;
20*795d594fSAndroid Build Coastguard Worker import java.util.HashSet;
21*795d594fSAndroid Build Coastguard Worker import java.util.Set;
22*795d594fSAndroid Build Coastguard Worker import java.util.Objects;
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker public class Breakpoint {
25*795d594fSAndroid Build Coastguard Worker   public static class Manager {
26*795d594fSAndroid Build Coastguard Worker     public static class BP {
27*795d594fSAndroid Build Coastguard Worker       public final Executable method;
28*795d594fSAndroid Build Coastguard Worker       public final long location;
29*795d594fSAndroid Build Coastguard Worker 
BP(Executable method)30*795d594fSAndroid Build Coastguard Worker       public BP(Executable method) {
31*795d594fSAndroid Build Coastguard Worker         this(method, getStartLocation(method));
32*795d594fSAndroid Build Coastguard Worker       }
33*795d594fSAndroid Build Coastguard Worker 
BP(Executable method, long location)34*795d594fSAndroid Build Coastguard Worker       public BP(Executable method, long location) {
35*795d594fSAndroid Build Coastguard Worker         this.method = method;
36*795d594fSAndroid Build Coastguard Worker         this.location = location;
37*795d594fSAndroid Build Coastguard Worker       }
38*795d594fSAndroid Build Coastguard Worker 
39*795d594fSAndroid Build Coastguard Worker       @Override
equals(Object other)40*795d594fSAndroid Build Coastguard Worker       public boolean equals(Object other) {
41*795d594fSAndroid Build Coastguard Worker         return (other instanceof BP) &&
42*795d594fSAndroid Build Coastguard Worker             method.equals(((BP)other).method) &&
43*795d594fSAndroid Build Coastguard Worker             location == ((BP)other).location;
44*795d594fSAndroid Build Coastguard Worker       }
45*795d594fSAndroid Build Coastguard Worker 
46*795d594fSAndroid Build Coastguard Worker       @Override
toString()47*795d594fSAndroid Build Coastguard Worker       public String toString() {
48*795d594fSAndroid Build Coastguard Worker         return method.toString() + " @ " + getLine();
49*795d594fSAndroid Build Coastguard Worker       }
50*795d594fSAndroid Build Coastguard Worker 
51*795d594fSAndroid Build Coastguard Worker       @Override
hashCode()52*795d594fSAndroid Build Coastguard Worker       public int hashCode() {
53*795d594fSAndroid Build Coastguard Worker         return Objects.hash(method, location);
54*795d594fSAndroid Build Coastguard Worker       }
55*795d594fSAndroid Build Coastguard Worker 
getLine()56*795d594fSAndroid Build Coastguard Worker       public int getLine() {
57*795d594fSAndroid Build Coastguard Worker         try {
58*795d594fSAndroid Build Coastguard Worker           LineNumber[] lines = getLineNumberTable(method);
59*795d594fSAndroid Build Coastguard Worker           int best = -1;
60*795d594fSAndroid Build Coastguard Worker           for (LineNumber l : lines) {
61*795d594fSAndroid Build Coastguard Worker             if (l.location > location) {
62*795d594fSAndroid Build Coastguard Worker               break;
63*795d594fSAndroid Build Coastguard Worker             } else {
64*795d594fSAndroid Build Coastguard Worker               best = l.line;
65*795d594fSAndroid Build Coastguard Worker             }
66*795d594fSAndroid Build Coastguard Worker           }
67*795d594fSAndroid Build Coastguard Worker           return best;
68*795d594fSAndroid Build Coastguard Worker         } catch (Exception e) {
69*795d594fSAndroid Build Coastguard Worker           return -1;
70*795d594fSAndroid Build Coastguard Worker         }
71*795d594fSAndroid Build Coastguard Worker       }
72*795d594fSAndroid Build Coastguard Worker     }
73*795d594fSAndroid Build Coastguard Worker 
74*795d594fSAndroid Build Coastguard Worker     private Set<BP> breaks = new HashSet<>();
75*795d594fSAndroid Build Coastguard Worker 
setBreakpoints(BP... bs)76*795d594fSAndroid Build Coastguard Worker     public void setBreakpoints(BP... bs) {
77*795d594fSAndroid Build Coastguard Worker       for (BP b : bs) {
78*795d594fSAndroid Build Coastguard Worker         if (breaks.add(b)) {
79*795d594fSAndroid Build Coastguard Worker           Breakpoint.setBreakpoint(b.method, b.location);
80*795d594fSAndroid Build Coastguard Worker         }
81*795d594fSAndroid Build Coastguard Worker       }
82*795d594fSAndroid Build Coastguard Worker     }
setBreakpoint(Executable method, long location)83*795d594fSAndroid Build Coastguard Worker     public void setBreakpoint(Executable method, long location) {
84*795d594fSAndroid Build Coastguard Worker       setBreakpoints(new BP(method, location));
85*795d594fSAndroid Build Coastguard Worker     }
86*795d594fSAndroid Build Coastguard Worker 
clearBreakpoints(BP... bs)87*795d594fSAndroid Build Coastguard Worker     public void clearBreakpoints(BP... bs) {
88*795d594fSAndroid Build Coastguard Worker       for (BP b : bs) {
89*795d594fSAndroid Build Coastguard Worker         if (breaks.remove(b)) {
90*795d594fSAndroid Build Coastguard Worker           Breakpoint.clearBreakpoint(b.method, b.location);
91*795d594fSAndroid Build Coastguard Worker         }
92*795d594fSAndroid Build Coastguard Worker       }
93*795d594fSAndroid Build Coastguard Worker     }
clearBreakpoint(Executable method, long location)94*795d594fSAndroid Build Coastguard Worker     public void clearBreakpoint(Executable method, long location) {
95*795d594fSAndroid Build Coastguard Worker       clearBreakpoints(new BP(method, location));
96*795d594fSAndroid Build Coastguard Worker     }
97*795d594fSAndroid Build Coastguard Worker 
clearAllBreakpoints()98*795d594fSAndroid Build Coastguard Worker     public void clearAllBreakpoints() {
99*795d594fSAndroid Build Coastguard Worker       clearBreakpoints(breaks.toArray(new BP[0]));
100*795d594fSAndroid Build Coastguard Worker     }
101*795d594fSAndroid Build Coastguard Worker   }
102*795d594fSAndroid Build Coastguard Worker 
startBreakpointWatch(Class<?> methodClass, Executable breakpointReached, Thread thr)103*795d594fSAndroid Build Coastguard Worker   public static void startBreakpointWatch(Class<?> methodClass,
104*795d594fSAndroid Build Coastguard Worker                                           Executable breakpointReached,
105*795d594fSAndroid Build Coastguard Worker                                           Thread thr) {
106*795d594fSAndroid Build Coastguard Worker     startBreakpointWatch(methodClass, breakpointReached, false, thr);
107*795d594fSAndroid Build Coastguard Worker   }
108*795d594fSAndroid Build Coastguard Worker 
109*795d594fSAndroid Build Coastguard Worker   /**
110*795d594fSAndroid Build Coastguard Worker    * Enables the trapping of breakpoint events.
111*795d594fSAndroid Build Coastguard Worker    *
112*795d594fSAndroid Build Coastguard Worker    * If allowRecursive == true then breakpoints will be sent even if one is currently being handled.
113*795d594fSAndroid Build Coastguard Worker    */
startBreakpointWatch(Class<?> methodClass, Executable breakpointReached, boolean allowRecursive, Thread thr)114*795d594fSAndroid Build Coastguard Worker   public static native void startBreakpointWatch(Class<?> methodClass,
115*795d594fSAndroid Build Coastguard Worker                                                  Executable breakpointReached,
116*795d594fSAndroid Build Coastguard Worker                                                  boolean allowRecursive,
117*795d594fSAndroid Build Coastguard Worker                                                  Thread thr);
stopBreakpointWatch(Thread thr)118*795d594fSAndroid Build Coastguard Worker   public static native void stopBreakpointWatch(Thread thr);
119*795d594fSAndroid Build Coastguard Worker 
120*795d594fSAndroid Build Coastguard Worker   public static final class LineNumber implements Comparable<LineNumber> {
121*795d594fSAndroid Build Coastguard Worker     public final long location;
122*795d594fSAndroid Build Coastguard Worker     public final int line;
123*795d594fSAndroid Build Coastguard Worker 
LineNumber(long loc, int line)124*795d594fSAndroid Build Coastguard Worker     private LineNumber(long loc, int line) {
125*795d594fSAndroid Build Coastguard Worker       this.location = loc;
126*795d594fSAndroid Build Coastguard Worker       this.line = line;
127*795d594fSAndroid Build Coastguard Worker     }
128*795d594fSAndroid Build Coastguard Worker 
equals(Object other)129*795d594fSAndroid Build Coastguard Worker     public boolean equals(Object other) {
130*795d594fSAndroid Build Coastguard Worker       return other instanceof LineNumber && ((LineNumber)other).line == line &&
131*795d594fSAndroid Build Coastguard Worker           ((LineNumber)other).location == location;
132*795d594fSAndroid Build Coastguard Worker     }
133*795d594fSAndroid Build Coastguard Worker 
compareTo(LineNumber other)134*795d594fSAndroid Build Coastguard Worker     public int compareTo(LineNumber other) {
135*795d594fSAndroid Build Coastguard Worker       int v = Integer.valueOf(line).compareTo(Integer.valueOf(other.line));
136*795d594fSAndroid Build Coastguard Worker       if (v != 0) {
137*795d594fSAndroid Build Coastguard Worker         return v;
138*795d594fSAndroid Build Coastguard Worker       } else {
139*795d594fSAndroid Build Coastguard Worker         return Long.valueOf(location).compareTo(Long.valueOf(other.location));
140*795d594fSAndroid Build Coastguard Worker       }
141*795d594fSAndroid Build Coastguard Worker     }
142*795d594fSAndroid Build Coastguard Worker   }
143*795d594fSAndroid Build Coastguard Worker 
setBreakpoint(Executable m, long loc)144*795d594fSAndroid Build Coastguard Worker   public static native void setBreakpoint(Executable m, long loc);
setBreakpoint(Executable m, LineNumber l)145*795d594fSAndroid Build Coastguard Worker   public static void setBreakpoint(Executable m, LineNumber l) {
146*795d594fSAndroid Build Coastguard Worker     setBreakpoint(m, l.location);
147*795d594fSAndroid Build Coastguard Worker   }
148*795d594fSAndroid Build Coastguard Worker 
clearBreakpoint(Executable m, long loc)149*795d594fSAndroid Build Coastguard Worker   public static native void clearBreakpoint(Executable m, long loc);
clearBreakpoint(Executable m, LineNumber l)150*795d594fSAndroid Build Coastguard Worker   public static void clearBreakpoint(Executable m, LineNumber l) {
151*795d594fSAndroid Build Coastguard Worker     clearBreakpoint(m, l.location);
152*795d594fSAndroid Build Coastguard Worker   }
153*795d594fSAndroid Build Coastguard Worker 
getLineNumberTableNative(Executable m)154*795d594fSAndroid Build Coastguard Worker   private static native Object[] getLineNumberTableNative(Executable m);
getLineNumberTable(Executable m)155*795d594fSAndroid Build Coastguard Worker   public static LineNumber[] getLineNumberTable(Executable m) {
156*795d594fSAndroid Build Coastguard Worker     Object[] nativeTable = getLineNumberTableNative(m);
157*795d594fSAndroid Build Coastguard Worker     long[] location = (long[])(nativeTable[0]);
158*795d594fSAndroid Build Coastguard Worker     int[] lines = (int[])(nativeTable[1]);
159*795d594fSAndroid Build Coastguard Worker     if (lines.length != location.length) {
160*795d594fSAndroid Build Coastguard Worker       throw new Error("Lines and locations have different lengths!");
161*795d594fSAndroid Build Coastguard Worker     }
162*795d594fSAndroid Build Coastguard Worker     LineNumber[] out = new LineNumber[lines.length];
163*795d594fSAndroid Build Coastguard Worker     for (int i = 0; i < lines.length; i++) {
164*795d594fSAndroid Build Coastguard Worker       out[i] = new LineNumber(location[i], lines[i]);
165*795d594fSAndroid Build Coastguard Worker     }
166*795d594fSAndroid Build Coastguard Worker     return out;
167*795d594fSAndroid Build Coastguard Worker   }
168*795d594fSAndroid Build Coastguard Worker 
getStartLocation(Executable m)169*795d594fSAndroid Build Coastguard Worker   public static native long getStartLocation(Executable m);
170*795d594fSAndroid Build Coastguard Worker 
locationToLine(Executable m, long location)171*795d594fSAndroid Build Coastguard Worker   public static int locationToLine(Executable m, long location) {
172*795d594fSAndroid Build Coastguard Worker     try {
173*795d594fSAndroid Build Coastguard Worker       Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m);
174*795d594fSAndroid Build Coastguard Worker       int best = -1;
175*795d594fSAndroid Build Coastguard Worker       for (Breakpoint.LineNumber l : lines) {
176*795d594fSAndroid Build Coastguard Worker         if (l.location > location) {
177*795d594fSAndroid Build Coastguard Worker           break;
178*795d594fSAndroid Build Coastguard Worker         } else {
179*795d594fSAndroid Build Coastguard Worker           best = l.line;
180*795d594fSAndroid Build Coastguard Worker         }
181*795d594fSAndroid Build Coastguard Worker       }
182*795d594fSAndroid Build Coastguard Worker       return best;
183*795d594fSAndroid Build Coastguard Worker     } catch (Exception e) {
184*795d594fSAndroid Build Coastguard Worker       return -1;
185*795d594fSAndroid Build Coastguard Worker     }
186*795d594fSAndroid Build Coastguard Worker   }
187*795d594fSAndroid Build Coastguard Worker 
lineToLocation(Executable m, int line)188*795d594fSAndroid Build Coastguard Worker   public static long lineToLocation(Executable m, int line) throws Exception {
189*795d594fSAndroid Build Coastguard Worker     try {
190*795d594fSAndroid Build Coastguard Worker       Breakpoint.LineNumber[] lines = Breakpoint.getLineNumberTable(m);
191*795d594fSAndroid Build Coastguard Worker       for (Breakpoint.LineNumber l : lines) {
192*795d594fSAndroid Build Coastguard Worker         if (l.line == line) {
193*795d594fSAndroid Build Coastguard Worker           return l.location;
194*795d594fSAndroid Build Coastguard Worker         }
195*795d594fSAndroid Build Coastguard Worker       }
196*795d594fSAndroid Build Coastguard Worker       throw new Exception("Unable to find line " + line + " in " + m);
197*795d594fSAndroid Build Coastguard Worker     } catch (Exception e) {
198*795d594fSAndroid Build Coastguard Worker       throw new Exception("Unable to get line number info for " + m, e);
199*795d594fSAndroid Build Coastguard Worker     }
200*795d594fSAndroid Build Coastguard Worker   }
201*795d594fSAndroid Build Coastguard Worker }
202*795d594fSAndroid Build Coastguard Worker 
203