1 # 2 # Copyright 2015 Google, Inc. All Rights Reserved. 3 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 # 5 # This code is free software; you can redistribute it and/or modify it 6 # under the terms of the GNU General Public License version 2 only, as 7 # published by the Free Software Foundation. This particular file is 8 # subject to the "Classpath" exception as provided in the LICENSE file 9 # that accompanied this code. 10 # 11 # This code is distributed in the hope that it will be useful, but WITHOUT 12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 # version 2 for more details (a copy is included in the LICENSE file that 15 # accompanied this code). 16 # 17 # You should have received a copy of the GNU General Public License version 18 # 2 along with this work; if not, write to the Free Software Foundation, 19 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 # 21 # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 # or visit www.oracle.com if you need additional information or have any 23 # questions. 24 # 25 26 """Frame unwinder and frame filter to display Java frames in GDB backtraces. 27 28 How to use it 29 * Copy this file into the directory containing libjvm.so under the name 30 libjvm.so-gdb.py (it should be jre/lib/amd64/{client,server}/ in the JDK 31 installation directory. 32 * Use GDB 7.9 (as of 26-Feb-2015, not released yet). 33 * Enable autoloading in your GDB setup. 34 35 This is prototype code, DO NOT COMMIT. 36 TODO: 37 * Move platform-dependent part into per-platform module and arrange this 38 script to import the corresponding platform module dynamically. 39 * Provide build machinery. 40 * Add tests that load this module into GDB and verify it traverses various 41 HotSpot structures correctly. 42 """ 43 44 import itertools 45 import re 46 import traceback 47 import gdb 48 49 from gdb.FrameDecorator import FrameDecorator 50 from gdb.sniffer import Sniffer 51 52 53 def _init_jvm(): 54 """Initializes JVM if necessary and returns it.""" 55 inferior = gdb.selected_inferior().pid 56 if inferior in jvms: 57 return jvms[inferior] 58 59 try: 60 for objfile in gdb.objfiles(): 61 if not objfile.filename.endswith("libjvm.so"): 62 continue 63 # NOTE: gdb.parse_and_eval() cannot be called here: it fiddles 64 # with frame chain, so if _init_jvm is called from the sniffer, 65 # we can get into trouble. Fortunately, gdb.lookup_global_symbol 66 # does not fiddle with the frame chain. 67 init_symbol = gdb.lookup_global_symbol("Universe::_fully_initialized", 68 gdb.SYMBOL_VAR_DOMAIN) 69 if (init_symbol is not None and init_symbol.is_valid() 70 and init_symbol.value()): 71 # if False: 72 jvms[inferior] = Jvm() 73 FrameFilter() 74 return jvms[inferior] 75 else: 76 return None 77 except (AttributeError, NameError, RuntimeError): 78 print(traceback.format_exc()) 79 80 return None 81 82 83 class Jdk8Amd64Sniffer(Sniffer): 84 """Inferior-specific sniffer class.""" 85 86 amd64_rbp_num = 6 87 amd64_rsp_num = 7 88 amd64_rip_num = 16 89 CALL_STUB_START = None 90 CALL_STUB_END = None 91 92 def __init__(self): 93 super(Jdk8Amd64Sniffer, self).__init__("jdk8-amd64-sniffer") 94 self.initializing_jvm = False 95 96 def __call__(self, sniffer_info): 97 """GDB Sniffer for the frames created by the JVM.""" 98 # print "->Sniffer.sniff\n" 99 if self.initializing_jvm: 100 return None 101 102 self.initializing_jvm = True 103 result = self._sniff(sniffer_info) 104 self.initializing_jvm = False 105 return result 106 107 def _sniff(self, sniffer_info): 108 """TODO.""" 109 jvm = _init_jvm() 110 if jvm is None: 111 return None 112 113 if Jdk8Amd64Sniffer.CALL_STUB_START is None: 114 Jdk8Amd64Sniffer.CALL_STUB_START = gdb.parse_and_eval( 115 "StubRoutines::_call_stub_entry") 116 # NOTE(asmundak): assume that StubRoutines::_catch_exception_entry 117 # is initialized immediately after _call_stub_entry 118 Jdk8Amd64Sniffer.CALL_STUB_END = gdb.parse_and_eval( 119 "StubRoutines::_catch_exception_entry") 120 r_pc = sniffer_info.read_register(Jdk8Amd64Sniffer.amd64_rip_num) 121 if jvm.in_interpreter(r_pc): 122 return self.unwind_interpreted_frame(jvm, sniffer_info) 123 elif jvm.code_cache.contains(r_pc): 124 return self.unwind_compiled_frame(jvm, sniffer_info) 125 return None 126 127 def unwind_interpreted_frame(self, jvm, sniffer_info): 128 """Unwind interpreted frame.""" 129 jvm_frame = self.create_jvm_frame(jvm, sniffer_info) 130 if jvm_frame is None: 131 return None 132 jvm_java_frame = jvm.locate_java_vframe(jvm_frame) 133 if jvm_java_frame is None: 134 print("Error: cannot find VFrame for the interpreted code at %s." 135 " FP=%s is probably incorrect\n" % 136 (hexstr(jvm_frame.machine_frame.pc), 137 hexstr(jvm_frame.machine_frame.fp))) 138 return None 139 if not isinstance(jvm_java_frame, JvmInterpretedFrame): 140 print("Error: expected vframe for the interpreter at %s\n" % 141 hexstr(jvm_frame.machine_frame.pc)) 142 return None 143 144 next_frame = jvm_java_frame.machine_frame.sender() 145 if _debug > 0: 146 machine_frame = jvm_frame.machine_frame 147 self.print_unwind_result( 148 "INTR", machine_frame, next_frame.fp, next_frame.unextended_sp, 149 next_frame.pc) 150 151 return ((( Jdk8Amd64Sniffer.amd64_rbp_num, next_frame.fp), 152 ( Jdk8Amd64Sniffer.amd64_rip_num, next_frame.pc), 153 ( Jdk8Amd64Sniffer.amd64_rsp_num, next_frame.unextended_sp)), 154 ( Jdk8Amd64Sniffer.amd64_rsp_num, Jdk8Amd64Sniffer.amd64_rip_num)) 155 156 def unwind_compiled_frame(self, jvm, sniffer_info): 157 """Unwinds compiled frame.""" 158 jvm_frame = self.create_jvm_frame(jvm, sniffer_info) 159 machine_frame = jvm_frame.machine_frame 160 p_code_blob = jvm.code_cache.find_blob_unsafe(machine_frame.pc) 161 if p_code_blob is None: 162 return None 163 if jvm.is_instance_of(p_code_blob, "nmethod"): 164 jvm_java_frame = jvm.locate_java_vframe(jvm_frame) 165 if jvm_java_frame is not None: 166 next_machine_frame = jvm_java_frame.machine_frame.sender() 167 next_fp = next_machine_frame.fp 168 next_sp = next_machine_frame.unextended_sp 169 next_pc = next_machine_frame.pc 170 else: 171 next_sp = machine_frame.sp + CodeBlob(jvm, p_code_blob).frame_size 172 next_fp = jvm.char_ptr_at(next_sp - 2 * jvm.pointer_size) 173 next_pc = jvm.char_ptr_at(next_sp - jvm.pointer_size) 174 else: 175 next_pc = machine_frame.sender_pc 176 next_fp = machine_frame.link 177 next_sp = machine_frame.sender_sp 178 179 if _debug > 0: 180 self.print_unwind_result("COMP", machine_frame, next_fp, next_sp, next_pc) 181 182 return ((( Jdk8Amd64Sniffer.amd64_rbp_num, next_fp), 183 ( Jdk8Amd64Sniffer.amd64_rip_num, next_pc), 184 ( Jdk8Amd64Sniffer.amd64_rsp_num, next_sp)), 185 ( Jdk8Amd64Sniffer.amd64_rsp_num, Jdk8Amd64Sniffer.amd64_rip_num)) 186 187 def create_jvm_frame(self, jvm, sniffer_info): 188 """Creates JVM frame from the sniffer info.""" 189 lwp_id = gdb.selected_thread().ptid[1] 190 java_thread = jvm.find_thread(lwp_id) 191 r_fp = sniffer_info.read_register(Jdk8Amd64Sniffer.amd64_rbp_num) 192 r_pc = sniffer_info.read_register(Jdk8Amd64Sniffer.amd64_rip_num) 193 r_sp = sniffer_info.read_register(Jdk8Amd64Sniffer.amd64_rsp_num) 194 if java_thread is None: 195 print("Frame(PC=%s, FP=%s, SP=%s): cannot locate Java thread for " 196 "thread with LWP_ID=%d" % 197 (hexstr(r_pc), hexstr(r_fp), hexstr(r_sp), lwp_id)) 198 return None 199 return jvm.make_vframe(java_thread, r_fp, r_sp, r_pc) 200 201 def print_unwind_result(self, title, mframe, next_fp, next_sp, next_pc): 202 print("\n%s FP %s SP %s PC %s\n" 203 " FP %s SP %s PC %s" % 204 (title, 205 hexstr(mframe.fp), hexstr(mframe.sp), hexstr(mframe.pc), 206 hexstr(next_fp), hexstr(next_sp), hexstr(next_pc))) 207 208 209 class FrameFilter(object): 210 """Frame Filter for Java.""" 211 212 def __init__(self): 213 self.name = "Java" 214 self.priority = 100 215 self.enabled = True 216 gdb.frame_filters[self.name] = self 217 218 def filter(self, frame_iter): 219 frame_iter = itertools.imap(JavaFrameDecorator, frame_iter) 220 return frame_iter 221 222 223 class JavaFrameDecorator(FrameDecorator): 224 """FrameDecorator that can handle the frames generated by the OpenJDK JVM. 225 226 """ 227 BLOBS = ( 228 ("AdapterBlob", "<AdapterBlob>"), 229 ("BufferBlob", "<StubRoutines>"), 230 ("DeoptimizationBlob", "<DeoptimizationStub>"), 231 ("ExceptionBlob", "<ExceptionStub>"), 232 ("MethodHandlesAdapterBlob", "<MethodHandles adapters>"), 233 ("RuntimeStub", "<RuntimeStub>"), 234 ("SafepointBlob", "<SafepointStub>"), 235 ("SingletonBlob", "<SingletonStub"), 236 ("UncommonTrapBlob", "<UncommonTrapStub>") 237 ) 238 239 def __init__(self, fobj): 240 super(JavaFrameDecorator, self).__init__(fobj) 241 self.fobj = fobj 242 self.is_java_frame = None 243 244 def function(self): 245 return (self.java_method if self.check_java_frame() 246 else super(JavaFrameDecorator, self).function()) 247 248 def filename(self): 249 return (self.java_filename if self.check_java_frame() 250 else super(JavaFrameDecorator, self).filename()) 251 252 def line(self): 253 return (self.java_line if self.check_java_frame() 254 else super(JavaFrameDecorator, self).line()) 255 256 def frame_args(self): 257 return (self.args if self.check_java_frame() 258 else super(JavaFrameDecorator, self).frame_args()) 259 260 def check_java_frame(self): 261 if self.is_java_frame is not None: 262 return self.is_java_frame 263 264 self.is_java_frame = False 265 jvm = _init_jvm() 266 if jvm is None: 267 return self.is_java_frame 268 269 frame = self.fobj.inferior_frame() 270 r_pc = frame.read_register("pc") 271 if jvm.in_interpreter(r_pc): 272 self.process_interpreted_frame(jvm, frame) 273 elif jvm.code_cache.contains(r_pc): 274 self.process_compiled_frame(jvm, frame) 275 return self.is_java_frame 276 277 def process_interpreted_frame(self, jvm, frame): 278 jvm_frame = self.make_jvm_frame(jvm, frame) 279 if jvm_frame is None: 280 return 281 machine_frame = jvm_frame.machine_frame 282 jvm_java_frame = jvm.locate_java_vframe(jvm_frame) 283 if jvm_java_frame is None: 284 print("Error: cannot find VFrame for the interpreted code at %s." 285 " FP=%s is probably incorrect\n" % 286 (hexstr(machine_frame.pc), hexstr(machine_frame.fp))) 287 return 288 if not isinstance(jvm_java_frame, JvmInterpretedFrame): 289 print("Error: expected vframe for the interpreter at %s\n" % 290 hexstr(machine_frame.pc)) 291 return 292 # TODO(asmundak): check SP and FP alignment 293 method = jvm_java_frame.method 294 tag = "N" if method.is_native else "I" 295 self.java_method = "%s.%s#%s" % ( 296 method.klass_fqname, method.name.string(), tag) 297 source_file_name = method.method_holder.source_file_name 298 if source_file_name is not None: 299 self.java_filename = source_file_name.string() 300 self.java_line = method.line_number_from_bci(jvm_java_frame.bci) 301 self.is_java_frame = True 302 self.build_java_frame_args(jvm_java_frame, method) 303 return 304 305 def process_compiled_frame(self, jvm, frame): 306 p_code_blob = jvm.code_cache.find_blob_unsafe(frame.read_register("pc")) 307 if p_code_blob is None: 308 return 309 self.java_filename = None 310 self.java_line = None 311 if jvm.is_instance_of(p_code_blob, "nmethod"): 312 jvm_frame = self.make_jvm_frame(jvm, frame) 313 if jvm_frame is None: 314 return 315 method = Method(jvm, p_code_blob.cast(jvm.t_nmethod_ptr)["_method"]) 316 self.java_method = "%s.%s#C" % ( 317 method.klass_fqname, method.name.string()) 318 source_file_name = method.method_holder.source_file_name 319 if source_file_name is not None: 320 self.java_filename = source_file_name.string() 321 self.java_line = method.line_number_from_bci(jvm_frame.bci) 322 self.build_java_frame_args(jvm_frame, method) 323 else: 324 self.java_method = "<Unknown code blob>" 325 for (klass, stub_name) in JavaFrameDecorator.BLOBS: 326 if jvm.is_instance_of(p_code_blob, klass): 327 self.java_method = stub_name 328 break 329 self.args = [] 330 self.is_java_frame = True 331 return 332 333 def make_jvm_frame(self, jvm, frame): 334 r_pc = frame.read_register("pc") 335 r_fp = frame.read_register("rbp") 336 r_sp = frame.read_register("sp") 337 lwp_id = gdb.selected_thread().ptid[1] 338 java_thread = jvm.find_thread(lwp_id) 339 if java_thread is None: 340 print("Frame(PC=%s, FP=%s, SP=%s): cannot locate Java thread for " 341 "thread with LWP_ID=%d" % 342 (hexstr(r_pc), hexstr(r_fp), hexstr(r_sp), lwp_id)) 343 return None 344 return jvm.make_vframe(java_thread, r_fp, r_sp, r_pc) 345 346 def build_java_frame_args(self, jvm_java_frame, method): 347 self.args = ArgumentsAndLocals(jvm_java_frame, method).arguments 348 349 350 class SymbolValueWrapper(object): 351 """An item of a collection returned by FrameDecorator.frame_args.""" 352 353 def __init__(self, symbol, value=None): 354 self._symbol = symbol 355 self._value = value 356 357 def symbol(self): 358 return self._symbol 359 360 def value(self): 361 return self._value 362 363 364 class Jvm(object): 365 """OpenJDK JVM state. 366 367 """ 368 369 # Type sizes, in stack units 370 BOOLEAN_SIZE = 1 371 CHAR_SIZE = 1 372 FLOAT_SIZE = 1 373 DOUBLE_SIZE = 2 374 BYTE_SIZE = 1 375 SHORT_SIZE = 1 376 INT_SIZE = 1 377 LONG_SIZE = 2 378 OBJECT_SIZE = 1 379 ARRAY_SIZE = 1 380 381 def __init__(self): 382 self.hs_version_string = gdb.parse_and_eval( 383 "Abstract_VM_Version::_s_vm_release").string() 384 match = re.match("^(\\d+)", self.hs_version_string) 385 if match: 386 self.hs_version = int(match.group(1)) 387 else: 388 self.hs_version = None 389 self.stub_queue = gdb.parse_and_eval("AbstractInterpreter::_code") 390 self.code_cache = CodeCache(self) 391 self.min_obj_alignment_in_bytes = gdb.parse_and_eval( 392 "ObjectAlignmentInBytes") 393 self.is_compressed_oops_enabled = gdb.parse_and_eval("UseCompressedOops") 394 self.invocation_entry_bci = gdb.parse_and_eval("InvocationEntryBci") 395 396 self.t_array_oop = gdb.lookup_type("arrayOopDesc").pointer() 397 self.t_bool = gdb.lookup_type("bool") 398 self.t_char_ptr = gdb.lookup_type("unsigned char").pointer() 399 self.t_char_ptr_ptr = self.t_char_ptr.pointer() 400 self.t_codeblob_ptr = gdb.lookup_type("CodeBlob").pointer() 401 self.t_double_ptr = gdb.lookup_type("double").pointer() 402 self.t_float_ptr = gdb.lookup_type("float").pointer() 403 self.t_int = gdb.lookup_type("int") 404 self.t_int_ptr = self.t_int.pointer() 405 self.t_int_ptr_ptr = self.t_int_ptr.pointer() 406 self.t_long_ptr = gdb.lookup_type("long").pointer() 407 self.t_short_ptr = gdb.lookup_type("short").pointer() 408 self.t_u2ptr = gdb.lookup_type("unsigned short").pointer() 409 self.t_ulong = gdb.lookup_type("unsigned long") 410 self.t_void_ptr = gdb.lookup_type("void").pointer() 411 self.t_local_variable_table_element_ptr = gdb.lookup_type( 412 "LocalVariableTableElement").pointer() 413 self.t_metadata_ptr_ptr = gdb.lookup_type("Metadata").pointer().pointer() 414 self.t_method_ptr = gdb.lookup_type("Method").pointer() 415 self.t_narrow_oop = gdb.lookup_type("narrowOop") 416 self.t_narrow_oop_ptr = self.t_narrow_oop.pointer() 417 self.t_nmethod_ptr = gdb.lookup_type("nmethod").pointer() 418 self.t_obj_array_oop = gdb.lookup_type("objArrayOopDesc").pointer() 419 self.t_obj_array_klass_ptr = gdb.lookup_type("ObjArrayKlass").pointer() 420 self.t_oop = gdb.lookup_type("oop") 421 self.t_oop_ptr = self.t_oop.pointer() 422 self.t_instance_klass_ptr = gdb.lookup_type("InstanceKlass").pointer() 423 self.t_klass_ptr = gdb.lookup_type("Klass").pointer() 424 self.t_pcdesc_ptr = gdb.lookup_type("PcDesc").pointer() 425 self.t_symbol_ptr = gdb.lookup_type("Symbol").pointer() 426 self.t_symbol_ptr_ptr = self.t_symbol_ptr.pointer() 427 self.t_type_array_oop = gdb.lookup_type("typeArrayOopDesc").pointer() 428 429 self.oop_size = gdb.parse_and_eval("oopSize") 430 self.const_method_oop_desc_size = gdb.lookup_type("ConstMethod").sizeof 431 self.heap_word_size = gdb.parse_and_eval("HeapWordSize") 432 self.pointer_size = self.t_char_ptr.sizeof 433 self.narrow_oop_base = gdb.parse_and_eval("Universe::_narrow_oop._base") 434 self.narrow_oop_shift = gdb.parse_and_eval("Universe::_narrow_oop._shift") 435 self.narrow_klass_base = gdb.parse_and_eval("Universe::_narrow_klass._base") 436 self.narrow_klass_shift = gdb.parse_and_eval( 437 "Universe::_narrow_klass._shift") 438 439 self.fields_straddle = gdb.parse_and_eval("FieldInfo::field_slots") 440 self.fields_name_offset = gdb.parse_and_eval("FieldInfo::name_index_offset") 441 442 self.vm_symbols = gdb.parse_and_eval("vmSymbols::_symbols") 443 self.vm_symbols_first_sid = gdb.parse_and_eval("vmSymbols::FIRST_SID") 444 self.vm_symbols_sid_limit = gdb.parse_and_eval("vmSymbols::SID_LIMIT") 445 446 self.symbol_table = SymbolTable(self) 447 448 self.cpp_class_vtable_cache = {} 449 self.known_klasses = {} 450 for (klass_name, klass_class) in ( 451 ("InstanceKlass", InstanceKlass), 452 ("ArrayKlass", ArrayKlass), 453 ("TypeArrayKlass", TypeArrayKlass), 454 ("ObjArrayKlass", ObjArrayKlass), 455 ("InstanceMirrorKlass", InstanceMirrorKlass), 456 ("InstanceRefKlass", InstanceRefKlass), 457 ("InstanceClassLoaderKlass", InstanceClassLoaderKlass)): 458 vtable_address = self.vtable_address(klass_name) 459 if vtable_address is None: 460 raise RuntimeError("Initialization failed") 461 self.known_klasses[long(vtable_address)] = klass_class 462 463 self.object_heap = VmObjectHeap(self) 464 465 @property 466 def is_debugging(self): 467 return False 468 469 @property 470 def is_core(self): 471 # TODO(asmundak): Should be true if neither C1 nor C2 are present. 472 return False 473 474 def find_thread(self, lwpid): 475 """Returns an address of a thread with given LwpID.""" 476 p_thread = gdb.parse_and_eval("Threads::_thread_list") 477 while p_thread != 0: 478 if lwpid == p_thread["_osthread"]["_thread_id"]: 479 return p_thread 480 p_thread = p_thread["_next"] 481 return None 482 483 def make_vframe(self, java_thread, r_fp, r_sp, r_pc): 484 machine_frame = MachineFrame(self, fp=r_fp, sp=r_sp, pc=r_pc) 485 if machine_frame.find_cb() is None: 486 raise RuntimeError("Cannot find code blob for the frame with FP=%s, " 487 "SP=%s, PC=%s" % 488 (hexstr(r_fp), hexstr(r_sp), hexstr(r_pc))) 489 return machine_frame.vframe(java_thread, True, True) 490 491 def locate_java_vframe(self, vframe): 492 """TODO.""" 493 if vframe is None: 494 return None 495 if vframe.is_java_vframe: 496 return vframe 497 imprecise = False 498 if self.is_debugging: 499 imprecise = vframe.maybe_imprecise_dbg 500 sender_vframe = vframe.sender(imprecise) 501 while sender_vframe is not None: 502 if sender_vframe.is_java_vframe: 503 break 504 next_vframe = sender_vframe.sender(imprecise) 505 if (sender_vframe.machine_frame.unextended_sp >= 506 next_vframe.machine_frame.unextended_sp): 507 return None 508 sender_vframe = next_vframe 509 return sender_vframe 510 511 def align_object_size(self, size): 512 return ((size + self.min_obj_alignment_in_bytes -1) & 513 -self.min_obj_alignment_in_bytes) 514 515 def is_instance_of(self, ptr, cpp_class_name): 516 return (ptr.cast(self.t_char_ptr_ptr).dereference() == 517 self.cpp_vtable(cpp_class_name)) 518 519 def vtable_address(self, cpp_class_name): 520 vtable_expr = "&_ZTV%d%s" % (len(cpp_class_name), cpp_class_name) 521 try: 522 return (gdb.parse_and_eval(vtable_expr).cast(self.t_char_ptr) + 523 2 * self.t_char_ptr.sizeof) 524 except gdb.error: 525 print("%s: cannot find vtable" % cpp_class_name) 526 return None 527 528 def cpp_vtable(self, cpp_class_name): 529 if cpp_class_name not in self.cpp_class_vtable_cache: 530 self.cpp_class_vtable_cache[cpp_class_name] = ( 531 self.vtable_address(cpp_class_name)) 532 return self.cpp_class_vtable_cache[cpp_class_name] 533 534 def in_interpreter(self, pc): 535 stub_start = self.stub_queue["_stub_buffer"] 536 return (pc >= stub_start and 537 pc < stub_start + self.stub_queue["_buffer_limit"]) 538 539 def char_ptr_at(self, ptr): 540 return ptr.cast(self.t_char_ptr_ptr).dereference() 541 542 def decode_narrow_klass(self, narrow_klass): 543 """Returns the address of the Klass instance.""" 544 return self.narrow_klass_base.cast(self.t_ulong) + ( 545 narrow_klass.cast(self.t_ulong) << self.narrow_klass_shift).cast( 546 self.t_klass_ptr) 547 548 def decode_narrow_oop(self, narrow_oop): 549 """Returns oop.""" 550 return self.narrow_oop_base.cast(self.t_ulong) + ( 551 narrow_oop.cast(self.t_ulong) << self.narrow_oop_shift).cast( 552 self.t_oop) 553 554 def new_klass(self, klass_address): 555 """Klass factory. 556 557 Figures out which sublclass of JVM Klass resides at a given address and 558 return the instance of the corresponding Python's subclass of Klass. 559 560 Args: 561 klass_address: points to JVM's Klass instance 562 Returns: 563 an instance of Klass subclass. 564 Raises: 565 RuntimeError: if cannot handle. 566 """ 567 if klass_address is None: 568 return None 569 vtable = long(klass_address.cast(self.t_char_ptr_ptr).dereference()) 570 if vtable in self.known_klasses: 571 cls = self.known_klasses[vtable] 572 return cls(self, klass_address) 573 raise RuntimeError("%s does not point to known Klass subclass" % 574 hexstr(klass_address)) 575 576 def new_oop(self, object_pointer): 577 """Oop factory. 578 579 Figures out what kind of oop resides at a given address and returns an 580 instance of the corresponding Python's Oop subclass. 581 582 Args: 583 object_pointer: the pointer to oopDesc. 584 Returns: 585 an instance of Oop subclass. 586 Raises: 587 RuntimeError. 588 """ 589 if self.is_compressed_oops_enabled: 590 klass_pointer = self.decode_narrow_klass( 591 object_pointer["_metadata"]["_compressed_klass"]) 592 else: 593 klass_pointer = object_pointer["_metadata"]["_klass"] 594 return self.new_klass(klass_pointer).new_oop(object_pointer) 595 596 def symbol_at(self, index): 597 """Returns 'global' symbol at a given index.""" 598 if index < self.vm_symbols_first_sid or index >= self.vm_symbols_sid_limit: 599 raise IndexError("%d out of range [%d..%d)" % 600 (index, self.vm_symbols_first_sid, 601 self.vm_symbols_sid_limit)) 602 return Symbol(self, self.vm_symbols[index]) 603 604 def oop_value(self, oop): 605 """Oop's printable value.""" 606 klass = oop.klass 607 if klass.name.string() == "java/lang/String": 608 value_field = oop.klass.find_field("value", "[C") 609 if value_field is not None: 610 chars = oop.obj_field(value_field.offset) 611 return (chars.char_base.cast(self.t_char_ptr) 612 .string("utf-16", "replace", 2 * chars.length)) 613 elif isinstance(oop, ObjArrayOop): 614 element_klass = klass.element_klass 615 if element_klass.name.string() == "java/lang/String": 616 return ("string1", "string2") 617 return oop.address.cast(self.t_void_ptr) 618 619 620 class SymbolTable(object): 621 """Mirrors JVM's SymbolTable. 622 623 See src/share/vm/classfile/symbolTable.{hpp, cpp} 624 """ 625 626 def __init__(self, jvm): 627 self.jvm = jvm 628 self.symbol_table = gdb.parse_and_eval("SymbolTable::_the_table") 629 self.t_entry = gdb.lookup_type("IntptrHashtableEntry").pointer() 630 631 def verify(self): 632 """Debugging: verifies symbol table is correct.""" 633 buckets = self.symbol_table["_buckets"] 634 bucket_count = self.symbol_table["_table_size"] 635 for i in range(bucket_count): 636 entry = buckets[i]["_entry"].cast(self.t_entry) 637 while entry != 0: 638 sym = Symbol(self.jvm, entry["_literal"].cast(self.jvm.t_symbol_ptr)) 639 sym_string = sym.string() 640 h1 = entry["_hash"] 641 h2 = self._hash_symbol_name(sym_string) 642 if h1 != h2: 643 print("Warning: symbol's '%s' table entry has value %08x," 644 " should be %08x. Symbol is unreachable" % (sym_string, h1, h2)) 645 elif i != (h1 % bucket_count): 646 print("Warning symbol '%s' is in bucket #%d, should be in #%d" % 647 (sym_string, i, (h1 % bucket_count))) 648 entry = entry["_next"].cast(self.t_entry) 649 650 def probe_symbol(self, symbol_name): 651 """Finds symbol with given name.""" 652 hash_value = self._hash_symbol_name(symbol_name) 653 bucket_index = hash_value % self.symbol_table["_table_size"] 654 entry = self.symbol_table["_buckets"][bucket_index]["_entry"].cast( 655 self.t_entry) 656 while entry != 0: 657 if entry["_hash"] == hash_value: 658 sym = Symbol(self.jvm, entry["_literal"].cast(self.jvm.t_symbol_ptr)) 659 if symbol_name == sym.string(): 660 return sym 661 entry = entry["_next"].cast(self.t_entry) 662 return None 663 664 def _hash_symbol_name(self, symbol_name): 665 h = 0L 666 for c in symbol_name: 667 h = 31 * h + ord(c) 668 return h & 0xFFFFFFFFL 669 670 671 class VmObject(object): 672 """TODO.""" 673 674 def __init__(self, jvm, address): 675 self.jvm = jvm 676 self.address = address 677 678 679 class Oop(VmObject): 680 """Corresponds to JVM's oopDesc class. 681 682 See src/share/vm/oops/oop.{hpp,cpp}. 683 """ 684 685 def __init__(self, jvm, address): 686 super(Oop, self).__init__(jvm, address) 687 688 def __repr__(self): 689 return "%s, klass=%s" % (self.address, self.klass) 690 691 @property 692 def klass(self): 693 meta = self.address["_metadata"] 694 klass_address = (self.jvm.decode_narrow_klass(meta["_compressed_klass"]) 695 if self.jvm.is_compressed_oops_enabled 696 else meta["_klass"]) 697 return self.jvm.new_klass(klass_address) 698 699 def obj_field(self, offset): 700 """Fetches a field at a given offset. A field is an oop.""" 701 address = self.address.cast(self.jvm.t_char_ptr) + offset 702 if self.jvm.is_compressed_oops_enabled: 703 oop_address = self.jvm.decode_narrow_oop( 704 address.cast(self.jvm.t_narrow_oop_ptr).dereference()) 705 else: 706 oop_address = address.cast(self.jvm.t_oop_ptr).dereference() 707 return self.jvm.new_oop(oop_address) 708 709 710 class ArrayOop(Oop): 711 """Abstract baseclass for all arrays. 712 713 The layout of ArrayOops is: 714 markOop 715 Klass* 32 bits if compressed but declared 64 in LP64. 716 length shares klass memory or allocated after declared fields. 717 718 See See src/share/vm/oops/arrayOop.{hpp,cpp}. 719 """ 720 721 def __init__(self, jvm, address): 722 super(ArrayOop, self).__init__(jvm, address) 723 724 @property 725 def length_address(self): 726 if self.jvm.is_compressed_oops_enabled: 727 return ((self.address["_metadata"]["_compressed_klass"].address+1) 728 .cast(self.jvm.t_int_ptr)) 729 else: 730 return ((self.address.cast(self.jvm.t_oop) + 1) 731 .cast(self.jvm.t_int_ptr)) 732 733 @property 734 def length(self): 735 return self.length_address.dereference() 736 737 738 class ObjArrayOop(ArrayOop): 739 """An array containing oops. 740 741 See src/share/vm/oops/objArrayOop.{hpp,cpp}. 742 """ 743 744 def __init__(self, jvm, address): 745 super(ObjArrayOop, self).__init__(jvm, address) 746 747 748 class TypeArrayOop(ArrayOop): 749 """An array containing basic types (non oop elements). 750 751 It is used for arrays of {characters, singles, doubles, bytes, shorts, 752 integers, longs}. 753 See src/share/vm/oops/typeArrayOop.{hpp,cpp} 754 """ 755 756 def __init(self, jvm, address): 757 super(TypeArrayOop, self).__init__(jvm, address) 758 759 @property 760 def basic_type(self): 761 return None 762 763 @property 764 def char_base(self): 765 return (self.length_address + 1).cast(self.jvm.t_u2ptr) 766 767 768 def hexstr(addr): 769 if addr is None: 770 return "NULL" 771 return "0x%x" % addr.cast(gdb.lookup_type("long")) 772 773 774 class CodeBlob(VmObject): 775 """Superclass for all entries in the CodeCache. 776 777 See src/share/vm/code/codeBlob.{hpp, cpp}. 778 """ 779 780 def __init__(self, jvm, address): 781 super(CodeBlob, self).__init__(jvm, address) 782 783 def __repr__(self): 784 return "%s" % self.address.dereference() 785 786 @property 787 def frame_size(self): 788 return self.jvm.pointer_size * self.address["_frame_size"] 789 790 @property 791 def header_begin(self): 792 return self.address.cast(self.jvm.t_char_ptr) 793 794 @property 795 def code_begin(self): 796 return self.header_begin + self.address["_code_offset"] 797 798 799 class NMethod(CodeBlob): 800 """Compiled code versions of Java methods. 801 802 See src/share/vm/code/nmethod.{hpp,cpp}. 803 """ 804 805 def __init__(self, jvm, address): 806 super(NMethod, self).__init__(jvm, address) 807 808 @property 809 def method(self): 810 return Method(self.jvm, self.address["_method"]) 811 812 def is_deopt_pc(self, pc): 813 return self.is_deopt_entry(pc) or self.is_deopt_mh_entry(pc) 814 815 def is_deopt_mh_entry(self, pc): 816 return pc == self.deopt_mh_handler_begin 817 818 def is_deopt_entry(self, pc): 819 return pc == self.deopt_handler_begin 820 821 def is_method_handle_return(self, pc): 822 pcdesc = self.pcdesc_at(pc) 823 if pcdesc is not None: 824 return pcdesc.is_method_handle_invoke 825 return False 826 827 @property 828 def deopt_handler_begin(self): 829 return self.header_begin + self.address["_deoptimize_offset"] 830 831 @property 832 def deopt_mh_handler_begin(self): 833 return self.header_begin + self.address["_deoptimize_mh_offset"] 834 835 @property 836 def scopes_data_begin(self): 837 return self.header_begin + self.address["_scopes_data_offset"] 838 839 @property 840 def oops_begin(self): 841 return (self.header_begin + 842 self.address["_oops_offset"]).cast(self.jvm.t_oop_ptr) 843 844 def oops_size(self): 845 return self.address["_metadata_offset"] - self.address["_oops_offset"] 846 847 @property 848 def metadata_begin(self): 849 return (self.header_begin + 850 self.address["_metadata_offset"]).cast(self.jvm.t_metadata_ptr_ptr) 851 852 @property 853 def metadata_size(self): 854 return (self.address["_scopes_data_offset"] - 855 self.address["_metadata_offset"]) 856 857 def scope_desc_near_dbg(self, pc): 858 pc_desc = self.pcdesc_near_dbg(pc) 859 if pc_desc is None: 860 return None 861 return ScopeDesc(self, pc_desc.scope_decode_offset, 862 pc_desc.obj_decode_offset, pc_desc.reexecute) 863 864 def pcdesc_near_dbg(self, pc_needle): 865 """TODO.""" 866 best_guess_pc_desc = None 867 best_distance = 0 868 pc_needle_offset = pc_needle - self.code_begin 869 for p_pcdesc in self.scopes_pcs(): 870 distance = pc_needle_offset - p_pcdesc["_pc_offset"] 871 if best_guess_pc_desc is None or (distance >= 0 and 872 distance < best_distance): 873 best_guess_pc_desc = p_pcdesc 874 best_distance = distance 875 if best_guess_pc_desc is not None: 876 return PcDesc(self.jvm, best_guess_pc_desc) 877 return None 878 879 def pcdesc_at(self, pc): 880 """TODO.""" 881 pc_offset = pc - self.code_begin 882 for p_pcdesc in self.scopes_pcs(): 883 if pc_offset == p_pcdesc["_pc_offset"]: 884 return PcDesc(self.jvm, p_pcdesc) 885 return None 886 887 def scopes_pcs(self): 888 p_pcdesc = ( 889 self.header_begin + self.address["_scopes_pcs_offset"]).cast( 890 self.jvm.t_pcdesc_ptr) 891 p_pcdesc_end = ( 892 self.header_begin + self.address["_dependencies_offset"]).cast( 893 self.jvm.t_pcdesc_ptr) 894 while p_pcdesc < p_pcdesc_end: 895 yield p_pcdesc 896 p_pcdesc += 1 897 898 def oop_at(self, i): 899 if i == 0: 900 return None 901 if i < 0 or i >= self.oops_size: 902 raise RuntimeError("%s: index %d out of bounds" % (self, i)) 903 return (self.oops_begin + i - 1).dereference 904 905 def method_at(self, i): 906 return Method(self.jvm, self.metadata_at(i).cast(self.jvm.t_char_ptr)) 907 908 def metadata_at(self, i): 909 if i == 0: 910 return None 911 if i < 0 or i >= self.metadata_size: 912 raise RuntimeError("%s: index %d out of bounds" % (self, i)) 913 return (self.metadata_begin + i - 1).dereference() 914 915 @property 916 def orig_pc_offset(self): 917 return self.address["_orig_pc_offset"] 918 919 920 class CodeCache(object): 921 """Various pieces of generated code. 922 923 (e.g., compiled java methods, runtime stubs, transition frames, etc.) 924 The entries in the CodeCache are all CodeBlob's. 925 See src/share/vm/code/codeCache.{hpp,cpp} 926 """ 927 928 def __init__(self, jvm): 929 self.jvm = jvm 930 self.heap = CodeHeap(jvm, gdb.parse_and_eval("CodeCache::_heap")) 931 932 def contains(self, pc): 933 return self.heap.contains(pc) 934 935 def find_blob_unsafe(self, pc): 936 """Returns CodeBlob containing given PC.""" 937 return self.heap.find_start(pc) 938 939 def find_blob(self, pc): 940 code_blob = self.find_blob_unsafe(pc) 941 if code_blob is None: 942 return None 943 if self.jvm.is_debugging: 944 return code_blob 945 # Assert.that(!(code_blob.isZombie() || code_blob.isLockedByVM()) 946 return code_blob 947 948 949 class CodeHeap(object): 950 """Memory for the CodeCache. 951 952 See src/share/vm/memory/heap.{hpp,cpp}. 953 """ 954 955 def __init__(self, jvm, address): 956 self.jvm = jvm 957 self.p_code_heap = address 958 959 def contains(self, pc): 960 mem = self.p_code_heap["_memory"] 961 return mem["_low"] <= pc and pc < mem["_high"] 962 963 def find_start(self, pc): 964 if not self.contains(pc): 965 return None 966 p_heap_block = self.block_start(pc) 967 if p_heap_block is None: 968 return None 969 if p_heap_block["_header"]["_used"]: 970 return (p_heap_block+1).cast(self.jvm.t_char_ptr) 971 return None 972 973 def block_start(self, pc): 974 """Locates HeapBlock containing given address.""" 975 memory_low = self.p_code_heap["_memory"]["_low"].cast(self.jvm.t_char_ptr) 976 shift_value = self.p_code_heap["_log2_segment_size"] 977 seg_nr = (pc - memory_low) >> shift_value 978 seg_nr = (pc - memory_low) >> shift_value 979 b = self.p_code_heap["_segmap"]["_low"].cast(self.jvm.t_char_ptr) 980 count = (b + seg_nr).dereference() 981 if count == 255: 982 return None 983 while count > 0: 984 seg_nr -= count 985 count = (b + seg_nr).dereference() 986 ptr = memory_low + (seg_nr << shift_value) 987 return ptr.cast(gdb.lookup_type("HeapBlock").pointer()) 988 989 990 class VmObjectHeap(object): 991 """TODO.""" 992 993 def __init__(self, jvm): 994 self.jvm = jvm 995 self.narrow_oop_base = gdb.parse_and_eval("Universe::_narrow_oop._base") 996 self.narrow_oop_shift = gdb.parse_and_eval("Universe::_narrow_oop._shift") 997 return 998 999 def decode_narrow_oop(self, narrow_oop): 1000 return self.narrow_oop_base + (narrow_oop << self.narrow_oop_shift) 1001 1002 def metadata_for(self, ptr): 1003 if ptr is None or ptr == 0: 1004 return None 1005 hs_type = self.jvm.types.dynamic_type_for_address(ptr, self.metadata_t) 1006 if hs_type is None: 1007 raise RuntimeError("%s does does not point to an instance of %s" % 1008 (ptr, self.metadata_t.name)) 1009 return self.metadata_subclasses[hs_type.name](self.jvm, ptr) 1010 1011 1012 class FieldInfo(object): 1013 """Field information. 1014 1015 Obtained from the contents in an element of the _fields array of 1016 an InstanceKlass. 1017 """ 1018 1019 FIELDINFO_TAG_MASK = 0x0003 1020 FIELDINFO_TAG_OFFSET = 0x0001 1021 1022 def __init__(self, klass, index): 1023 self.klass = klass 1024 self.jvm = klass.jvm 1025 self.index = index 1026 fields = klass.address["_fields"]["_data"] 1027 base = index * 6 1028 self.access_flags = fields[base] 1029 self.name_index = fields[base+1] 1030 self.signature_index = fields[base+2] 1031 self.initval_index = fields[base+3] 1032 self.low_packed_offset = fields[base+4] 1033 self.high_packed_offset = fields[base+5] 1034 1035 @property 1036 def name(self): 1037 if self.access_flags & ClassConstants.JVM_ACC_FIELD_INTERNAL == 0: 1038 return self.klass.constants.symbol_at(self.name_index) 1039 else: 1040 return self.jvm.symbol_at(self.name_index) 1041 1042 @property 1043 def signature(self): 1044 if self.access_flags & ClassConstants.JVM_ACC_FIELD_INTERNAL == 0: 1045 return self.klass.constants.symbol_at(self.signature_index) 1046 else: 1047 return self.jvm.symbol_at(self.signature_index) 1048 1049 @property 1050 def offset(self): 1051 if (self.low_packed_offset & FieldInfo.FIELDINFO_TAG_MASK == 1052 FieldInfo.FIELDINFO_TAG_OFFSET): 1053 return (self.low_packed_offset + (self.high_packed_offset<<16)) >> 2 1054 else: 1055 raise RuntimeError("Bad field offset for %s", self) 1056 1057 1058 class Metadata(VmObject): 1059 """Reflects share/vm/oops/metadata.hpp.""" 1060 1061 def __init__(self, jvm, address): 1062 super(Metadata, self).__init__(jvm, address) 1063 1064 1065 class Klass(Metadata): 1066 """Mirrors JVM's Klass. 1067 1068 See src/share/vm/oops/klass.{hpp,cpp}. 1069 """ 1070 1071 def __init__(self, jvm, address): 1072 super(Klass, self).__init__(jvm, address) 1073 1074 @property 1075 def name(self): 1076 return Symbol(self.jvm, self.address["_name"]) 1077 1078 @property 1079 def superclass(self): 1080 return self.jvm.new_klass(self.address["_super"]) 1081 1082 1083 class ArrayKlass(Klass): 1084 """Abstract base class of all array classes.""" 1085 1086 def __init__(self, jvm, address): 1087 super(ArrayKlass, self).__init__(jvm, address) 1088 1089 1090 class TypeArrayKlass(ArrayKlass): 1091 """Klass for base types array.""" 1092 1093 def __init__(self, jvm, address): 1094 super(TypeArrayKlass, self).__init__(jvm, address) 1095 1096 def new_oop(self, address): 1097 return TypeArrayOop(self.jvm, 1098 address.cast(self.jvm.t_type_array_oop)) 1099 1100 1101 class ObjArrayKlass(ArrayKlass): 1102 """Klass for object arrays.""" 1103 1104 def __init__(self, jvm, address): 1105 super(ObjArrayKlass, self).__init__( 1106 jvm, address.cast(jvm.t_obj_array_klass_ptr)) 1107 1108 def new_oop(self, address): 1109 return ObjArrayOop(self.jvm, 1110 address.cast(self.jvm.t_obj_array_oop)) 1111 1112 @property 1113 def element_klass(self): 1114 return self.jvm.new_klass(self.address["_element_klass"]) 1115 1116 1117 class InstanceKlass(Klass): 1118 """VM level representation of a Java class.""" 1119 1120 def __init__(self, jvm, address): 1121 super(InstanceKlass, self).__init__( 1122 jvm, address.cast(jvm.t_instance_klass_ptr)) 1123 1124 def __repr__(self): 1125 return "%s" % self.address.dereference() 1126 1127 def new_oop(self, address): 1128 return Oop(self.jvm, address.cast(self.jvm.t_oop)) 1129 1130 @property 1131 def source_file_name(self): 1132 return self.constants.symbol_at(self.address["_source_file_name_index"]) 1133 1134 @property 1135 def methods(self): 1136 return MethodArray(self.jvm, self.address["_methods"]) 1137 1138 def method_with_idnum(self, idnum): 1139 """TODO.""" 1140 m = None 1141 methods = self.methods 1142 if idnum < methods.length: 1143 m = methods.at(idnum) 1144 if m is None or m.method_idnum != idnum: 1145 for i in range(methods.length): 1146 m = methods.at(i) 1147 if m.method_idnum == idnum: 1148 break 1149 return m 1150 1151 @property 1152 def constants(self): 1153 return ConstantPool(self.jvm, self.address["_constants"]) 1154 1155 def find_field(self, field_name, field_signature): 1156 1157 """Finds field. 1158 1159 Finds field according to JVM spec 5.4.3.2, returns the klass in 1160 which the field is defined (convenience routine). 1161 1162 Args: 1163 field_name: Field name symbol. 1164 field_signature: Signature encoding field type. 1165 1166 Returns: 1167 FieldInfo or None 1168 """ 1169 symbols = self.jvm.symbol_table 1170 name_symbol = symbols.probe_symbol(field_name) 1171 signature_symbol = symbols.probe_symbol(field_signature) 1172 if name_symbol is None or signature_symbol is None: 1173 return None 1174 return self.find_field_by_symbol(name_symbol, signature_symbol) 1175 1176 def find_field_by_symbol(self, name_symbol, signature_symbol): 1177 f = self.find_local_field(name_symbol, signature_symbol) 1178 if f is None: 1179 f = self.find_interface_field(name_symbol, signature_symbol) 1180 if f is None: 1181 superclass = self.superclass 1182 if superclass is not None: 1183 f = superclass.find_field_by_symbol(name_symbol, signature_symbol) 1184 return f 1185 1186 def find_local_field(self, name_symbol, signature_symbol): 1187 for i in range(self.java_fields_count): 1188 field = FieldInfo(self, i) 1189 if (name_symbol == field.name and 1190 signature_symbol == field.signature): 1191 return field 1192 return None 1193 1194 def find_interface_field(self, name_symbol, signature_symbol): 1195 """TODO.""" 1196 local_interfaces = self.address["_local_interfaces"] 1197 for i in range(0, local_interfaces["_length"]): 1198 intf = self.jvm.new_klass(local_interfaces["_data"][i]) 1199 f = intf.find_local_field(name_symbol, signature_symbol) 1200 if f is None: 1201 f = intf.find_interface_field(name_symbol, signature_symbol) 1202 if f is not None: 1203 return f 1204 return None 1205 1206 @property 1207 def java_fields_count(self): 1208 return self.address["_java_fields_count"] 1209 1210 1211 class InstanceMirrorKlass(InstanceKlass): 1212 """A specialized InstanceKlass for java.lang.Class instances. 1213 1214 See src/share/vm/oops/instanceMirrorKlass.{hpp,cpp} 1215 """ 1216 1217 def __init__(self, jvm, address): 1218 super(InstanceMirrorKlass, self).__init__(jvm, address) 1219 1220 1221 class InstanceRefKlass(InstanceKlass): 1222 """A specialized InstanceKlass for subclasses of java/lang/ref/Reference. 1223 1224 See src/share/vm/oops/instanceRefKlass.{hpp,cpp}. 1225 """ 1226 1227 def __init__(self, jvm, address): 1228 super(InstanceRefKlass, self).__init__(jvm, address) 1229 1230 1231 class InstanceClassLoaderKlass(InstanceKlass): 1232 """A specialization of the InstanceKlass. 1233 1234 See src/share/vm/oops/instanceClassLoaderKlass.{hpp,cpp}. 1235 """ 1236 1237 def __init__(self, jvm, address): 1238 super(InstanceClassLoaderKlass, self).__init__(jvm, address) 1239 1240 1241 class Method(Metadata): 1242 """Represents Java method. 1243 1244 See src/share/vm/oops/method.{hpp,cpp} 1245 """ 1246 1247 def __init__(self, jvm, address): 1248 super(Method, self).__init__(jvm, address) 1249 1250 def __repr__(self): 1251 return "%s" % self.address.dereference() 1252 1253 @property 1254 def name(self): 1255 return self.constants.symbol_at(self.address["_constMethod"]["_name_index"]) 1256 1257 @property 1258 def klass_fqname(self): 1259 return self.method_holder.name.string().replace("/", ".") 1260 1261 @property 1262 def const_method(self): 1263 return ConstMethod(self.jvm, self.address["_constMethod"]) 1264 1265 @property 1266 def constants(self): 1267 return ConstantPool(self.jvm, self.address["_constMethod"]["_constants"]) 1268 1269 @property 1270 def method_holder(self): 1271 return InstanceKlass( 1272 self.jvm, self.address["_constMethod"]["_constants"]["_pool_holder"]) 1273 1274 @property 1275 def is_native(self): 1276 return self.access_flags & ClassConstants.JVM_ACC_NATIVE != 0 1277 1278 @property 1279 def is_static(self): 1280 return self.access_flags & ClassConstants.JVM_ACC_STATIC != 0 1281 1282 @property 1283 def access_flags(self): 1284 return self.address["_access_flags"].cast(self.jvm.t_int) 1285 1286 @property 1287 def size_of_parameters(self): 1288 return self.const_method.size_of_parameters 1289 1290 @property 1291 def signature(self): 1292 return self.constants.symbol_at(self.const_method.signature_index) 1293 1294 @property 1295 def has_local_variable_table(self): 1296 return self.const_method.has_localvariable_table 1297 1298 @property 1299 def first_local_variable_ptr(self): 1300 return self.const_method.first_local_variable_ptr 1301 1302 @property 1303 def localvariable_table_length(self): 1304 return self.const_method.localvariable_table_length 1305 1306 @property 1307 def method_idnum(self): 1308 return self.address["_constMethod"]["_method_idnum"] 1309 1310 def line_number_from_bci(self, bci): 1311 return self.const_method.line_number_from_bci(bci) 1312 1313 def bci_from(self, bcx): 1314 return bcx - self.const_method.code_base 1315 1316 @property 1317 def max_locals(self): 1318 return self.const_method.max_locals 1319 1320 def mask_for(self, _): 1321 # entry = OopMapCacheEntry() 1322 # entry.fill(this, bci) 1323 # return entry 1324 return None 1325 1326 1327 class MethodData(Metadata): 1328 """TODO.""" 1329 1330 def __init__(self, jvm, address): 1331 super(MethodData, self).__init__(jvm, address) 1332 1333 1334 class ConstMethod(VmObject): 1335 """Represents portions of a Java method which do not vary. 1336 1337 See src/share/vm/oops/constMethod.{hpp,cpp}. 1338 """ 1339 1340 HAS_LINENUMBER_TABLE = None 1341 1342 def __init__(self, jvm, address): 1343 super(ConstMethod, self).__init__(jvm, address) 1344 if ConstMethod.HAS_LINENUMBER_TABLE is None: 1345 ConstMethod.init_constants() 1346 self._is_native = None 1347 1348 def __repr__(self): 1349 return "%s" % self.address 1350 1351 @classmethod 1352 def init_constants(cls): 1353 """TODO.""" 1354 t_int = gdb.lookup_type("int") 1355 ConstMethod.HAS_LINENUMBER_TABLE = gdb.parse_and_eval( 1356 "ConstMethod::_has_linenumber_table").cast(t_int) 1357 ConstMethod.HAS_LOCALVARIABLE_TABLE = gdb.parse_and_eval( 1358 "ConstMethod::_has_localvariable_table").cast(t_int) 1359 ConstMethod.HAS_CHECKED_EXCEPTIONS = gdb.parse_and_eval( 1360 "ConstMethod::_has_checked_exceptions").cast(t_int) 1361 ConstMethod.HAS_EXCEPTION_TABLE = gdb.parse_and_eval( 1362 "ConstMethod::_has_exception_table").cast(t_int) 1363 ConstMethod.HAS_METHOD_PARAMETERS = gdb.parse_and_eval( 1364 "ConstMethod::_has_method_parameters").cast(t_int) 1365 ConstMethod.HAS_GENERIC_SIGNATURE = gdb.parse_and_eval( 1366 "ConstMethod::_has_generic_signature").cast(t_int) 1367 ConstMethod.HAS_METHOD_ANNOTATIONS = gdb.parse_and_eval( 1368 "ConstMethod::_has_method_annotations").cast(t_int) 1369 ConstMethod.HAS_PARAMETER_ANNOTATIONS = gdb.parse_and_eval( 1370 "ConstMethod::_has_parameter_annotations").cast(t_int) 1371 ConstMethod.HAS_TYPE_ANNOTATIONS = gdb.parse_and_eval( 1372 "ConstMethod::_has_type_annotations").cast(t_int) 1373 ConstMethod.HAS_DEFAULT_ANNOTATIONS = gdb.parse_and_eval( 1374 "ConstMethod::_has_default_annotations").cast(t_int) 1375 ConstMethod.EXCEPTION_TABLE_STRIDE = gdb.lookup_type( 1376 "ExceptionTableElement").sizeof 1377 ConstMethod.CHECKED_EXCEPTION_STRIDE = gdb.lookup_type( 1378 "CheckedExceptionElement").sizeof 1379 ConstMethod.LOCALVARIABLE_TABLE_STRIDE = gdb.lookup_type( 1380 "LocalVariableTableElement").sizeof 1381 1382 @property 1383 def name_index(self): 1384 return self.address["_name_index"] 1385 1386 @property 1387 def signature_index(self): 1388 return self.address["_signature_index"] 1389 1390 @property 1391 def constants(self): 1392 return ConstantPool(self.jvm, self.address["_constants"]) 1393 1394 def line_number_from_bci(self, bci_needle): 1395 """TODO.""" 1396 1397 if self.is_native or not self.has_line_number_table: 1398 return None 1399 best_bci = -1 1400 best_line = -1 1401 for (bci, line) in self.compressed_line_numbers(): 1402 # print "Read bci=%d, line=%d" % (bci, line) 1403 if bci == bci_needle: 1404 return line if line >= 0 else None 1405 if bci < bci_needle and bci > best_bci: 1406 best_bci = bci 1407 best_line = line 1408 return best_line if best_line >= 0 else None 1409 1410 def compressed_line_numbers(self): 1411 stream = CompressedStream(self.code_end) 1412 bci = 0 1413 line = 0 1414 while True: 1415 byte = stream.read_byte() 1416 if byte == 0: 1417 return 1418 if byte == 255: 1419 bci += stream.read_signed_int() 1420 line += stream.read_signed_int() 1421 else: 1422 bci += byte >> 3 1423 line += byte & 7 1424 yield bci, line 1425 1426 @property 1427 def is_native(self): 1428 if self._is_native is None: 1429 self._is_native = self.method.is_native 1430 return self._is_native 1431 1432 @property 1433 def method(self): 1434 klass = InstanceKlass(self.jvm, self.address["_constants"]["_pool_holder"]) 1435 return klass.method_with_idnum(self.address["_method_idnum"]) 1436 1437 @property 1438 def has_line_number_table(self): 1439 return self.address["_flags"] & ConstMethod.HAS_LINENUMBER_TABLE 1440 1441 @property 1442 def has_localvariable_table(self): 1443 return self.address["_flags"] & ConstMethod.HAS_LOCALVARIABLE_TABLE 1444 1445 @property 1446 def has_exception_table(self): 1447 return self.address["_flags"] & ConstMethod.HAS_EXCEPTION_TABLE 1448 1449 @property 1450 def has_checked_exceptions(self): 1451 return self.address["_flags"] & ConstMethod.HAS_CHECKED_EXCEPTIONS 1452 1453 @property 1454 def has_method_parameters(self): 1455 return self.address["_flags"] & ConstMethod.HAS_METHOD_PARAMETERS 1456 1457 @property 1458 def has_generic_signature(self): 1459 return self.address["_flags"] & ConstMethod.HAS_GENERIC_SIGNATURE 1460 1461 @property 1462 def has_method_annotations(self): 1463 return self.address["_flags"] & ConstMethod.HAS_METHOD_ANNOTATIONS 1464 1465 @property 1466 def has_parameter_annotations(self): 1467 return self.address["_flags"] & ConstMethod.HAS_PARAMETER_ANNOTATIONS 1468 1469 @property 1470 def has_type_annotations(self): 1471 return self.address["_flags"] & ConstMethod.HAS_TYPE_ANNOTATIONS 1472 1473 @property 1474 def has_default_annotations(self): 1475 return self.address["_flags"] & ConstMethod.HAS_DEFAULT_ANNOTATIONS 1476 1477 @property 1478 def first_local_variable_ptr(self): 1479 return self.localvariable_table_start.cast( 1480 self.jvm.t_local_variable_table_element_ptr) 1481 1482 @property 1483 def last_u2_element_address(self): 1484 """TODO.""" 1485 offset = 0 1486 if self.has_method_annotations: 1487 offset += 1 1488 if self.has_parameter_annotations: 1489 offset += 1 1490 if self.has_type_annotations: 1491 offset += 1 1492 if self.has_default_annotations: 1493 offset += 1 1494 return self.const_method_end - offset * self.jvm.t_char_ptr.sizeof - 2 1495 1496 @property 1497 def method_parameters_length_addr(self): 1498 if self.has_generic_signature: 1499 return self.last_u2_element_address - 2 1500 else: 1501 return self.last_u2_element_address 1502 1503 @property 1504 def checked_exceptions_length_addr(self): 1505 if self.has_method_parameters: 1506 return self.method_parameters_start - 2 1507 elif self.has_generic_signature: 1508 return self.last_u2_element_address - 2 1509 else: 1510 return self.last_u2_element_address 1511 1512 @property 1513 def exception_table_length_addr(self): 1514 if self.has_checked_exceptions: 1515 return self.checked_exceptions_address - 2 1516 elif self.has_method_parameters: 1517 return self.method_parameters_start - 2 1518 elif self.has_generic_signature: 1519 return self.last_u2_element_address - 2 1520 else: 1521 return self.last_u2_element_address 1522 1523 @property 1524 def localvariable_table_length_addr(self): 1525 if self.has_exception_table: 1526 return self.exception_table_start - 2 1527 elif self.has_checked_exceptions: 1528 return self.checked_exceptions_start - 2 1529 elif self.has_method_parameters: 1530 return self.method_parameters_start - 2 1531 elif self.has_generic_signature: 1532 return self.last_u2_element_address - 2 1533 else: 1534 return self.last_u2_element_address 1535 1536 def count_to_address(self, count_address, stride): 1537 count = count_address.cast(self.jvm.t_u2ptr).dereference() 1538 return count_address - count * stride 1539 1540 @property 1541 def checked_exceptions_start(self): 1542 return self.count_to_address(self.checked_exceptions_length_addr, 1543 ConstMethod.CHECKED_EXCEPTION_STRIDE) 1544 1545 @property 1546 def localvariable_table_start(self): 1547 return self.count_to_address(self.localvariable_table_length_addr, 1548 ConstMethod.LOCALVARIABLE_TABLE_STRIDE) 1549 1550 @property 1551 def exception_table_start(self): 1552 return self.count_to_address(self.exception_table_length_addr, 1553 ConstMethod.EXCEPTION_TABLE_STRIDE) 1554 1555 @property 1556 def localvariable_table_length(self): 1557 return self.localvariable_table_length_addr.cast( 1558 self.jvm.t_u2ptr).dereference() 1559 1560 @property 1561 def code_base(self): 1562 return (self.address + 1).cast(self.jvm.t_char_ptr) 1563 1564 @property 1565 def code_size(self): 1566 return self.address["_code_size"] 1567 1568 @property 1569 def code_end(self): 1570 return self.code_base + self.code_size 1571 1572 @property 1573 def size_of_parameters(self): 1574 return self.address["_size_of_parameters"] 1575 1576 @property 1577 def max_locals(self): 1578 return self.address["_max_locals"] 1579 1580 @property 1581 def const_method_end(self): 1582 return (self.address.cast(self.jvm.t_int_ptr_ptr) + 1583 self.address["_constMethod_size"]).cast(self.jvm.t_char_ptr) 1584 1585 1586 class ConstantPool(Metadata): 1587 """Class constants as described in the class file. 1588 1589 See src/share/vm/oops/constantPool.{hpp,cpp}. 1590 """ 1591 1592 def __init__(self, jvm, address): 1593 super(ConstantPool, self).__init__(jvm, address) 1594 1595 def __repr__(self): 1596 return "%s" % self.address.dereference() 1597 1598 def symbol_at(self, index): 1599 base = (self.address + 1).cast(self.jvm.t_symbol_ptr_ptr) 1600 if index < 0 or index >= self.length: 1601 raise RuntimeError("%s: index %d out of bounds" % (self, index)) 1602 return Symbol(self.jvm, (base + index).dereference()) 1603 1604 @property 1605 def length(self): 1606 return self.jvm.align_object_size(self.address["_length"]) 1607 1608 @property 1609 def pool_holder(self): 1610 return InstanceKlass(self.jvm, self.address["_pool_holder"]) 1611 1612 @property 1613 def header_size(self): 1614 return self.address.dereference().type.sizeof / self.jvm.heap_word_size 1615 1616 1617 class MethodArray(VmObject): 1618 """TODO.""" 1619 1620 def __init__(self, jvm, address): 1621 super(MethodArray, self).__init__(jvm, address) 1622 1623 def __repr__(self): 1624 return "%s" % self.address 1625 1626 def at(self, i): 1627 if i < 0 or i >= self.length: 1628 raise RuntimeError("%s index %d out of bounds" % (self, i)) 1629 return Method(self.jvm, self.address["_data"][i]) 1630 1631 @property 1632 def length(self): 1633 return self.address["_length"] 1634 1635 1636 class Symbol(VmObject): 1637 """A canonicalized string. 1638 1639 See src/share/vm/oops/symbol.{hpp,cpp}. 1640 """ 1641 1642 def __init__(self, jvm, address): 1643 super(Symbol, self).__init__(jvm, address) 1644 1645 def __repr__(self): 1646 return "%s" % self.address.dereference() 1647 1648 def __eq__(self, other): 1649 return self.string() == other.string() 1650 1651 def string(self): 1652 return self.address["_body"].string( 1653 "utf-8", "replace", self.address["_length"]) 1654 1655 1656 class MachineFrame(object): 1657 """A frame represents a physical stack frame (an activation). 1658 1659 Frames can be C or Java frames, and the Java frames can be 1660 interpreted or compiled. In contrast, vframes represent 1661 source-level activations, so that one physical frame can 1662 correspond to multiple source level frames because of inlining. 1663 1664 For the X64, the layout of the machine frame is as follows (lowest addr 1665 on top): 1666 [expression stack ] * <- sp 1667 [monitors ] \ 1668 ... | monitor block size 1669 [monitors ] / 1670 [monitor block size ] 1671 [byte code index/pointr] = bcx() bcx_offset 1672 [pointer to locals ] = locals() locals_offset 1673 [constant pool cache ] = cache() cache_offset 1674 [methodData ] = mdp() mdx_offset 1675 [methodOop ] = method() method_offset 1676 [last sp ] = last_sp() last_sp_offset 1677 [old stack pointer ] (sender_sp) sender_sp_offset 1678 [old frame pointer ] <- fp = link() 1679 [return pc ] 1680 [oop temp ] (only for native calls) 1681 [locals and parameters ] 1682 <- sender sp 1683 1684 This class mirrors sun.jvm.hotspot.runtime.Frame in SA. 1685 """ 1686 1687 def __init__(self, jvm, fp=None, sp=None, pc=None, unextended_sp=None): 1688 self.jvm = jvm 1689 self.fp = fp 1690 self.sp = sp 1691 self.pc = (pc if pc is not None 1692 else jvm.char_ptr_at(sp - jvm.pointer_size)) 1693 self.unextended_sp = sp if unextended_sp is None else unextended_sp 1694 # Adjust unextended SP. 1695 self.deoptimized = False 1696 p_nmethod = self.find_cb() 1697 if p_nmethod is not None and jvm.is_instance_of(p_nmethod, "nmethod"): 1698 nmethod = NMethod(jvm, p_nmethod.cast(jvm.t_nmethod_ptr)) 1699 if nmethod.is_deopt_mh_entry(self.pc): 1700 self.unextended_sp = self.fp 1701 elif nmethod.is_deopt_entry(self.pc): 1702 self.pc = jvm.char_ptr_at( 1703 self.unextended_sp + nmethod.orig_pc_offset) 1704 self.deoptimized = True 1705 elif nmethod.is_method_handle_return(self.pc): 1706 self.unextended_sp = self.fp 1707 1708 def __repr__(self): 1709 return ("FP %s, SP %s, PC %s" % 1710 (hexstr(self.fp), hexstr(self.sp), hexstr(self.pc))) 1711 1712 def vframe(self, java_thread, use_find_unsafe, allow_imprecise): 1713 """TODO.""" 1714 1715 if self.is_interpreted: 1716 return JvmInterpretedFrame(self, java_thread) 1717 1718 if use_find_unsafe: 1719 p_code_blob = self.jvm.code_cache.find_blob_unsafe(self.pc) 1720 else: 1721 p_code_blob = self.find_cb() 1722 if self.jvm.is_instance_of(p_code_blob, "nmethod"): 1723 nmethod = NMethod(self.jvm, p_code_blob.cast(self.jvm.t_nmethod_ptr)) 1724 if allow_imprecise: 1725 scope_desc = nmethod.scope_desc_near_dbg(self.pc) 1726 else: 1727 scope_desc = nmethod.scope_desc_at(self.pc) 1728 return JvmCompiledFrame(self, java_thread, 1729 scope_desc, allow_imprecise) 1730 if self.is_runtime_frame: 1731 return self.sender().make_vframe(java_thread, use_find_unsafe, 1732 allow_imprecise) 1733 return JvmExternalFrame(self, java_thread, allow_imprecise) 1734 1735 def find_cb(self): 1736 return self.jvm.code_cache.find_blob(self.pc) 1737 1738 def sender(self, code_blob=None): 1739 """Returns MachineFrame instance for the frame that called this one.""" 1740 # From sun.jvm.hotspot.runtime.x86.X86Frame.sender(): 1741 # Default is we don't have to follow them. The sender_for_xxx 1742 # will update it accordingly. 1743 # register_map.setIncludeArgumentOops(false) 1744 if self.is_interpreted: 1745 return self.sender_for_interpreter_frame() 1746 if code_blob is None: 1747 p_code_blob = self.find_cb() 1748 if p_code_blob is None: 1749 raise RuntimeError("Cannot find code blob for the frame %s" % self) 1750 return self.sender_for_compiled_frame( 1751 CodeBlob(self.jvm, p_code_blob.cast(self.jvm.t_codeblob_ptr))) 1752 1753 def sender_for_interpreter_frame(self): 1754 return MachineFrame(self.jvm, fp=self.link, sp=self.sender_sp, 1755 pc=self.sender_pc, 1756 unextended_sp=self.slot_value(-1)) 1757 1758 def sender_for_compiled_frame(self, code_blob): 1759 next_sp = self.unextended_sp + code_blob.frame_size 1760 next_pc = self.jvm.char_ptr_at(next_sp - self.jvm.pointer_size) 1761 next_fp = self.jvm.char_ptr_at(next_sp - 2 * self.jvm.pointer_size) 1762 if _debug > 0: 1763 print("Sender for %s: FP=%s, SP=%s, PC=%x" % 1764 (self, hexstr(next_fp), hexstr(next_sp), next_pc)) 1765 return MachineFrame(self.jvm, fp=next_fp, sp=next_sp, pc=next_pc) 1766 1767 def real_sender(self): 1768 next_machine_frame = self.sender() 1769 if self.jvm.is_core: 1770 return next_machine_frame 1771 while next_machine_frame.is_runtime_frame: 1772 next_machine_frame = next_machine_frame.sender() 1773 return next_machine_frame 1774 1775 @property 1776 def is_interpreted(self): 1777 return self.jvm.in_interpreter(self.pc) 1778 1779 @property 1780 def is_runtime_frame(self): 1781 p_code_blob = self.find_cb() 1782 if p_code_blob is None: 1783 return False 1784 return self.jvm.is_instance_of(p_code_blob, "RuntimeStub") 1785 1786 @property 1787 def is_first_frame(self): 1788 # TODO(asmundak): implement 1789 return False 1790 1791 @property 1792 def interpreter_frame_method(self): 1793 return self.slot_value(-3).cast(self.jvm.t_method_ptr) 1794 1795 @property 1796 def interpreter_frame_bci(self): 1797 bcp = self.slot_value(-7) 1798 p_const_method = self.interpreter_frame_method["_constMethod"] 1799 if bcp >= 0 and bcp < p_const_method["_code_size"]: 1800 return bcp.cast(self.jvm.t_int) 1801 return (bcp - self.jvm.const_method_oop_desc_size - 1802 p_const_method.cast(self.jvm.t_char_ptr)).cast(self.jvm.t_int) 1803 1804 @property 1805 def interpreter_frame_locals(self): 1806 return self.slot_value(-6) 1807 1808 @property 1809 def sender_pc(self): 1810 return self.slot_value(1) 1811 1812 @property 1813 def link(self): 1814 return self.slot_value(0) 1815 1816 @property 1817 def sender_sp(self): 1818 return self.fp + 2 * self.jvm.pointer_size 1819 1820 def slot_value(self, slot): 1821 return self.jvm.char_ptr_at(self.fp + slot * self.jvm.pointer_size) 1822 1823 1824 class JvmFrame(object): 1825 """TODO.""" 1826 1827 def __init__(self, machine_frame, java_thread): 1828 self.machine_frame = machine_frame 1829 self.java_thread = java_thread 1830 1831 @property 1832 def is_java_vframe(self): 1833 return False 1834 1835 def sender(self, imprecise): 1836 if self.machine_frame.is_first_frame: 1837 return None 1838 next_machine_frame = self.machine_frame.real_sender() 1839 if next_machine_frame.is_first_frame: 1840 return None 1841 return next_machine_frame.vframe(self.java_thread, 1842 self.machine_frame.jvm.is_debugging, 1843 imprecise) 1844 1845 1846 class JvmCompiledFrame(JvmFrame): 1847 """JVM frame for the JIT-compiled method. 1848 1849 see src/share/vm/runtime/vframe_hp.{hpp,cpp}. 1850 """ 1851 1852 def __init__(self, machine_frame, java_thread, scope_desc, 1853 allow_imprecise): 1854 super(JvmCompiledFrame, self).__init__(machine_frame, java_thread) 1855 self.scope_desc = scope_desc 1856 self.allow_imprecise = allow_imprecise 1857 1858 @property 1859 def is_java_vframe(self): 1860 return True 1861 1862 @property 1863 def local_variables(self): 1864 """TODO.""" 1865 if self.scope_desc is None: 1866 return None 1867 if _debug > 0: 1868 for scope_value in self.scope_desc.locals(): 1869 print(scope_value) 1870 1871 result = [] 1872 heap = self.machine_frame.jvm.object_heap 1873 for scope_value in self.scope_desc.locals(): 1874 if scope_value.is_location and scope_value.location_is_onstack: 1875 result.append(self.machine_frame.unextended_sp + 1876 scope_value.location_stack_offset) 1877 else: 1878 result.append(None) 1879 if (scope_value.is_location and scope_value.location_is_onstack and 1880 scope_value.location_value_is_oop): 1881 oop = self.machine_frame.jvm.char_ptr_at(result[-1]) 1882 if _debug > 0: 1883 print("local: (%s, %s@%s)" % 1884 (scope_value, heap.klass_name_for_oop_handle(oop), result[-1])) 1885 else: 1886 if _debug > 0: 1887 print("local: %s" % (scope_value)) 1888 return StackValueCollection(self.machine_frame.jvm.object_heap, result) 1889 1890 @property 1891 def bci(self): 1892 raw_bci = 0 if self.scope_desc is None else self.scope_desc.bci 1893 return (0 if raw_bci == self.machine_frame.jvm.invocation_entry_bci 1894 else raw_bci) 1895 1896 1897 class JvmInterpretedFrame(JvmFrame): 1898 """JVM frame for the interpreted method. 1899 1900 See src/share/vm/runtime/vframe.{hpp,cpp}. 1901 """ 1902 1903 def __init__(self, machine_frame, java_thread): 1904 super(JvmInterpretedFrame, self).__init__(machine_frame, java_thread) 1905 1906 def __repr__(self): 1907 return "JvmInterpretedFrame(%s)" % self.machine_frame 1908 1909 @property 1910 def is_java_vframe(self): 1911 return True 1912 1913 @property 1914 def method(self): 1915 return Method(self.machine_frame.jvm, 1916 self.machine_frame.interpreter_frame_method) 1917 1918 @property 1919 def bci(self): 1920 return self.machine_frame.interpreter_frame_bci 1921 1922 @property 1923 def local_variables(self): 1924 """TODO.""" 1925 m = self.method 1926 length = m.max_locals if not m.is_native else m.size_of_parameters 1927 result = [] 1928 # oop_mask = m.mask_for(self.bci) 1929 for i in range(length): 1930 result.append(self.address_of_local_at(i)) 1931 # print "locals[%d] = %s" % (i, hexstr(result[i])) 1932 return StackValueCollection(m.jvm.object_heap, result) 1933 1934 def address_of_local_at(self, i): 1935 return (self.machine_frame.interpreter_frame_locals - 1936 i * self.machine_frame.jvm.pointer_size) 1937 1938 1939 class JvmExternalFrame(JvmFrame): 1940 """TODO(asmundak): what is it? 1941 1942 See src/share/vm/runtime/vframe.{hpp,cpp}. 1943 """ 1944 1945 def __init__(self, machine_frame, java_thread, allow_imprecise): 1946 super(JvmExternalFrame, self).__init__(machine_frame, java_thread) 1947 self.allow_imprecise = allow_imprecise 1948 1949 1950 class ArgumentsAndLocals(object): 1951 """Contains variables from the current java frame.""" 1952 1953 def __init__(self, jvm_java_frame, method): 1954 self.jvm = jvm_java_frame.machine_frame.jvm 1955 self.jvm_java_frame = jvm_java_frame 1956 method_signature = method.signature.string() 1957 self.args = [] 1958 first_arg = 0 if method.is_static else Jvm.OBJECT_SIZE 1959 arg_count = method.size_of_parameters 1960 if arg_count + first_arg == 0: 1961 return 1962 1963 # If debuginfo is present, build an array of local variable names so 1964 # that that can be shown in the argument list. 1965 if method.has_local_variable_table: 1966 lv_table = method.first_local_variable_ptr 1967 slot_name = [0] * int(method.localvariable_table_length) 1968 for i in range(len(slot_name)): 1969 slot_name[int(lv_table[i]["slot"])] = int(lv_table[i]["name_cp_index"]) 1970 if _debug > 0: 1971 self.print_localvariable_table(method) 1972 else: 1973 slot_name = None 1974 1975 local_variables = jvm_java_frame.local_variables 1976 if first_arg > 0: 1977 # TODO(asmundak): this object should be 1978 # local_variables.object_at(0, method.klass_fqname), 1979 # but it does not work. 1980 self.args.append(SymbolValueWrapper( 1981 "this", local_variables.object_at(0, method.klass_fqname))) 1982 1983 arg_slot = first_arg 1984 arg_nr = 0 1985 for (arg_type, arg_word_size, klass_name) in ArgumentIterator( 1986 method_signature): 1987 arg_name = None 1988 if slot_name is not None: 1989 name_cp_index = slot_name[arg_slot] 1990 if name_cp_index != 0: 1991 arg_name = method.constants.symbol_at(name_cp_index).string() 1992 local_index = first_arg + arg_nr 1993 if local_variables is None or not local_variables.exists_at(local_index): 1994 # TODO(asmundak): should set it to some kind of predefined 1995 # "optimized out" value. Add it to Python API 1996 value = 0 1997 else: 1998 if arg_type == "B": 1999 value = local_variables.byte_at(local_index) 2000 elif arg_type == "C": 2001 value = local_variables.char_at(local_index) 2002 elif arg_type == "D": 2003 value = local_variables.double_at(local_index) 2004 elif arg_type == "F": 2005 value = local_variables.float_at(local_index) 2006 elif arg_type == "I": 2007 value = local_variables.int_at(local_index) 2008 elif arg_type == "J": 2009 value = local_variables.long_at(local_index) 2010 elif arg_type == "S": 2011 value = local_variables.short_at(local_index) 2012 elif arg_type == "Z": 2013 value = local_variables.bool_at(local_index) 2014 elif arg_type == "L": 2015 if arg_name is None: 2016 arg_name = re.sub("/", ".", klass_name) 2017 value = local_variables.object_at(local_index, klass_name) 2018 elif arg_type == "[": 2019 value = local_variables.array_at(local_index, klass_name) 2020 if arg_name is None: 2021 arg_name = self.make_arg_name(arg_type, klass_name) 2022 self.args.append(SymbolValueWrapper(arg_name, value)) 2023 arg_slot += arg_word_size 2024 arg_nr += 1 2025 2026 def make_arg_name(self, arg_type, klass_name): 2027 """Returns arg name. 2028 2029 Args: 2030 arg_type: type letter ('B'/'C'/'D'/etc. to basic types, 'L' for classes, 2031 '[' for arrays) 2032 klass_name: class name if arg_type is 'L' or '[' 2033 Returns: 2034 argument name 2035 """ 2036 if arg_type == "L": 2037 return klass_name.replace("/", ".") 2038 elif arg_type == "[": 2039 return self.make_arg_name(klass_name[0], klass_name[1:]) + "[]" 2040 else: 2041 return { 2042 "B": "byte", "C": "char", "D": "double", "F": "float", 2043 "I": "int", "J": "long", "S": "short", "Z": "boolean" 2044 }[klass_name[0]] 2045 2046 def print_localvariable_table(self, method): 2047 print 2048 lv_table = method.first_local_variable_ptr 2049 cp = method.constants 2050 for i in range(method.localvariable_table_length): 2051 lve = lv_table[i] 2052 print("%s\t%d" % 2053 (cp.symbol_at(lve["name_cp_index"]).string(), lv_table[i]["slot"])) 2054 2055 @property 2056 def arguments(self): 2057 return self.args 2058 2059 2060 class ArgumentIterator(object): 2061 """Iterate over signature string tokens.""" 2062 2063 def __init__(self, signature_string): 2064 # Sanity check: signature always starts with '(' and contains ')' 2065 if not (signature_string[0] == "(" and signature_string.find(")") > 0): 2066 raise RuntimeError("Bad signature string '%s'" % signature_string) 2067 2068 self.signature_string = signature_string 2069 2070 def __iter__(self): 2071 i = 1 2072 while i < len(self.signature_string): 2073 c = self.signature_string[i] 2074 i += 1 2075 if c == ")": 2076 return 2077 if c == "B": 2078 yield "B", Jvm.BYTE_SIZE, None 2079 elif c == "C": 2080 yield "C", Jvm.CHAR_SIZE, None 2081 elif c == "D": 2082 yield "D", Jvm.DOUBLE_SIZE, None 2083 elif c == "F": 2084 yield "F", Jvm.FLOAT_SIZE, None 2085 elif c == "I": 2086 yield "I", Jvm.INT_SIZE, None 2087 elif c == "J": 2088 yield "J", Jvm.LONG_SIZE, None 2089 elif c == "S": 2090 yield "S", Jvm.SHORT_SIZE, None 2091 elif c == "Z": 2092 yield "Z", Jvm.BOOLEAN_SIZE, None 2093 elif c == "V": 2094 raise RuntimeError("Bad argument type V at offset %d in %s" % 2095 (i - 1, self.signature_string)) 2096 elif c == "L": 2097 end = self.signature_string.index(";", i) 2098 klass_name = self.signature_string[i : end] 2099 i = end + 1 2100 yield "L", Jvm.OBJECT_SIZE, klass_name 2101 elif c == "[": 2102 while True: 2103 c = self.signature_string[i] 2104 i += 1 2105 if (c < "0" or c > "9") and c != "[": 2106 break 2107 start = i 2108 if c == "L": 2109 end = self.signature_string.index(";", start) 2110 klass_name = self.signature_string[start : end] 2111 i = end + 1 2112 else: 2113 klass_name = None 2114 i += 1 2115 yield "[", Jvm.ARRAY_SIZE, klass_name 2116 2117 2118 class ClassConstants(object): 2119 """ClassFile constants.""" 2120 JVM_ACC_PUBLIC = 0x0001 2121 JVM_ACC_PRIVATE = 0x0002 2122 JVM_ACC_PROTECTED = 0x0004 2123 JVM_ACC_STATIC = 0x0008 2124 JVM_ACC_FINAL = 0x0010 2125 JVM_ACC_SYNCHRONIZED = 0x0020 2126 JVM_ACC_SUPER = 0x0020 2127 JVM_ACC_VOLATILE = 0x0040 2128 JVM_ACC_BRIDGE = 0x0040 2129 JVM_ACC_TRANSIENT = 0x0080 2130 JVM_ACC_VARARGS = 0x0080 2131 JVM_ACC_NATIVE = 0x0100 2132 JVM_ACC_INTERFACE = 0x0200 2133 JVM_ACC_ABSTRACT = 0x0400 2134 JVM_ACC_STRICT = 0x0800 2135 JVM_ACC_SYNTHETIC = 0x1000 2136 JVM_ACC_ANNOTATION = 0x2000 2137 JVM_ACC_ENUM = 0x4000 2138 JVM_ACC_FIELD_ACCESS_WATCHED = 0x2000 2139 JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x8000 2140 JVM_ACC_FIELD_INTERNAL = 0x0400 2141 JVM_ACC_FIELD_STABLE = 0x0020 2142 JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x0800 2143 2144 2145 class CompressedStream(object): 2146 """An interface to serialize basic types. 2147 2148 See src/share/vm/code/compressedStream.{hpp,cpp}. 2149 """ 2150 2151 H = 64 # Number of high codes 2152 L = 192 # Number of low codes 2153 2154 def __init__(self, address): 2155 self.position = address 2156 2157 def read_byte(self): 2158 b = self.position.dereference() 2159 self.position += 1 2160 return b & 255 2161 2162 def read_signed_int(self): 2163 return self.decode_sign(self.read_int()) 2164 2165 def read_int(self): 2166 # This encoding, called UNSIGNED5, is taken from J2SE Pack200. 2167 # It assumes that most values have lots of leading zeroes. 2168 # Very small values, in the range [0..191], code in one byte. 2169 # Any 32-bit value (including negatives) can be coded, in 2170 # up to five bytes. The grammar is: 2171 # low_byte = [0..191] 2172 # high_byte = [192..255] 2173 # any_byte = low_byte | high_byte 2174 # coding = low_byte 2175 # | high_byte low_byte 2176 # | high_byte high_byte low_byte 2177 # | high_byte high_byte high_byte low_byte 2178 # | high_byte high_byte high_byte high_byte any_byte 2179 # Each high_byte contributes six bits of payload. 2180 # The encoding is one-to-one (except for integer overflow) 2181 # and easy to parse and unparse. 2182 value = self.read_byte() 2183 if value < CompressedStream.L: 2184 return value 2185 shift = 0 2186 while True: 2187 byte = self.read_byte() 2188 shift += 6 2189 value += (byte << 6) 2190 if byte < CompressedStream.L or shift >= 24: 2191 return value 2192 2193 def encode_sign(self, value): 2194 return (value << 1) ^ ((value >> 31) & 1) 2195 2196 def decode_sign(self, value): 2197 return ((value >> 1) & 0x7FFFFFFF) ^ -(value & 1) 2198 2199 2200 class PcDesc(VmObject): 2201 """Maps an offset from start of nmethod to the source scope and BCI. 2202 2203 See src/share/vm/code/pcDesc.{hpp,cpp}. 2204 """ 2205 2206 REEXECUTE = None 2207 2208 @classmethod 2209 def init_constants(cls): 2210 t_int = gdb.lookup_type("int") 2211 PcDesc.REEXECUTE = gdb.parse_and_eval( 2212 "PcDesc::PCDESC_reexecute").cast(t_int) 2213 PcDesc.IS_METHOD_HANDLE_INVOKE = gdb.parse_and_eval( 2214 "PcDesc::PCDESC_is_method_handle_invoke") 2215 2216 def __init__(self, jvm, address): 2217 super(PcDesc, self).__init__(jvm, address) 2218 if PcDesc.REEXECUTE is None: 2219 PcDesc.init_constants() 2220 2221 @property 2222 def pc_offset(self): 2223 return self.address["_pc_offset"] 2224 2225 @property 2226 def scope_decode_offset(self): 2227 return self.address["_scope_decode_offset"] 2228 2229 @property 2230 def obj_decode_offset(self): 2231 return self.address["_obj_decode_offset"] 2232 2233 @property 2234 def reexecute(self): 2235 return self.address["_flags"] & PcDesc.REEXECUTE 2236 2237 @property 2238 def is_method_handle_invoke(self): 2239 return self.address["_flags"] & PcDesc.IS_METHOD_HANDLE_INVOKE 2240 2241 def real_pc(self, nmethod): 2242 return self.pc_offset + nmethod.code_begin 2243 2244 2245 class ScopeDesc(object): 2246 """Scope description. 2247 2248 ScopeDescs contain information that make source-level debugging of nmethods 2249 possible: each ScopeDesc describes a method activation. 2250 See share/vm/code/scopeDesc.{hpp,cpp}. 2251 """ 2252 2253 def __init__(self, nmethod, decode_offset, object_decode_offset, 2254 reexecute): 2255 self.nmethod = nmethod 2256 self.decode_offset = decode_offset 2257 self.objects = self.decode_object_values(object_decode_offset) 2258 self.reexecute = reexecute 2259 stream = DebugInfoStream(nmethod, self.decode_offset) 2260 self.sender_decode_offset = stream.read_int() 2261 self.method = Method(nmethod.jvm, stream.read_method()) 2262 self.bci = stream.read_bci() 2263 self.locals_decode_offset = stream.read_int() 2264 self.expressions_decode_offset = stream.read_int() 2265 self.monitors_decode_offset = stream.read_int() 2266 2267 def locals(self): 2268 stream = DebugInfoStream(self.nmethod, self.locals_decode_offset) 2269 count = stream.read_int() 2270 if _debug > 0: 2271 print("Debug info stream at %s, nmethod %s with %d items" % 2272 (hexstr(stream.position), hexstr(self.nmethod.address), count)) 2273 for _ in range(count): 2274 yield ScopeValue.read_from(stream) 2275 2276 def decode_object_values(self, _): 2277 return [] 2278 2279 2280 class ScopeValue(object): 2281 """The value of a variable/expression in a scope. 2282 2283 See src/share/vm/code/debugInfo.{hpp,cpp}. 2284 """ 2285 2286 LOCATION_CODE = 0 2287 CONSTANT_INT_CODE = 1 2288 CONSTANT_OOP_CODE = 2 2289 CONSTANT_LONG_CODE = 3 2290 CONSTANT_DOUBLE_CODE = 4 2291 CONSTANT_OBJECT_CODE = 5 2292 CONSTANT_OBJECT_ID_CODE = 6 2293 VALUE_NAMES = ("location", "int", "oop", "long", "double", 2294 "object", "object_id") 2295 2296 @classmethod 2297 def read_from(cls, stream): 2298 """TODO.""" 2299 tag = stream.read_int() 2300 if tag == ScopeValue.LOCATION_CODE: 2301 value = stream.read_int() 2302 elif tag == ScopeValue.CONSTANT_INT_CODE: 2303 value = stream.read_signed_int() 2304 elif tag == ScopeValue.CONSTANT_OOP_CODE: 2305 value = stream.read_oop_handle() 2306 elif tag == ScopeValue.CONSTANT_LONG_CODE: 2307 value = stream.read_long() 2308 elif tag == ScopeValue.CONSTANT_DOUBLE_CODE: 2309 value = stream.read_double() 2310 elif tag == ScopeValue.CONSTANT_OBJECT_CODE: 2311 value = stream.read_object_value() 2312 elif tag == ScopeValue.CONSTANT_OBJECT_ID_CODE: 2313 value = stream.get_cached_object() 2314 else: 2315 raise RuntimeError("Unexpected tag %d" % tag) 2316 return cls(tag, value) 2317 2318 def __init__(self, tag, value): 2319 self.tag = tag 2320 self.value = value 2321 2322 def __repr__(self): 2323 if self.tag == ScopeValue.LOCATION_CODE: 2324 loc_type = ("invalid", "normal", "oop", "int_in_long", "lng", 2325 "float_in_dbl", "dbl", "addr", "narrowoop" 2326 )[int(self.value & 0x0F)] 2327 if self.value & 0x10 == 0: 2328 # Location on stack 2329 return "Location(%s at +0x%x)" % (loc_type, (self.value >> 5) << 2) 2330 else: 2331 return "Location(%s in register %d)" % (loc_type, self.value >> 5) 2332 2333 return "ScopeValue(%s, %s)" % (ScopeValue.VALUE_NAMES[int(self.tag)], 2334 self.value) 2335 2336 @property 2337 def is_location(self): 2338 return self.tag == ScopeValue.LOCATION_CODE 2339 2340 @property 2341 def location_is_onstack(self): 2342 return (self.is_location and (self.value & 0x10 == 0) and 2343 self.value & 0x0f != 0) 2344 2345 @property 2346 def location_value_is_oop(self): 2347 return self.is_location and (self.value & 0x0f == 2) 2348 2349 @property 2350 def location_stack_offset(self): 2351 if self.is_location and self.location_is_onstack: 2352 return (self.value >> 5) << 2 2353 return None 2354 2355 @property 2356 def location_register_number(self): 2357 if self.is_location and not self.location_is_onstack: 2358 return self.value >> 5 2359 return None 2360 2361 2362 class ObjectValue(ScopeValue): 2363 """An object eliminated by escape analysis. 2364 2365 See src/share/vm/code/debugInfo.{hpp,cpp}. 2366 """ 2367 2368 def __init__(self, tag, value): 2369 super(ObjectValue, self).__init__(tag, value) 2370 self.klass = None 2371 self.fields = [] 2372 2373 def __repr__(self): 2374 return "ObjectValue(%d)" % self.value 2375 2376 def read_object(self, stream): 2377 self.klass = ObjectValue.read_from(stream) 2378 count = stream.read_int() 2379 for _ in range(count): 2380 self.fields.append(self.read_from(stream)) 2381 2382 2383 class DebugInfoStream(CompressedStream): 2384 """Serialize debug information. 2385 2386 See src/share/vm/code/debugInfo.hpp. 2387 """ 2388 2389 def __init__(self, nmethod, offset): 2390 super(DebugInfoStream, self).__init__( 2391 nmethod.scopes_data_begin + offset) 2392 self.nmethod = nmethod 2393 self.object_pool = {} 2394 self.invocation_entry_bci = gdb.parse_and_eval("InvocationEntryBci") 2395 2396 def read_oop_handle(self): 2397 i = self.read_int() 2398 return self.nmethod.oop_at(i) 2399 2400 def read_object_value(self): 2401 obj_id = self.read_int() 2402 result = ObjectValue(ScopeValue.OBJECT_CODE, obj_id) 2403 result.read_object(self) 2404 self.object_pool[result.value] = result 2405 2406 def read_bci(self): 2407 return self.invocation_entry_bci + self.read_int() 2408 2409 def get_cached_object(self): 2410 obj_id = self.read_int() 2411 return self.object_pool[obj_id] 2412 2413 def read_method(self): 2414 return self.nmethod.method_at(self.read_int()) 2415 2416 2417 class StackValueCollection(object): 2418 """See src/share/vm/runtime/stackValueCollection.{hpp,cpp}.""" 2419 2420 def __init__(self, object_heap, addresses): 2421 self.object_heap = object_heap 2422 self.jvm = object_heap.jvm 2423 self.addresses = addresses 2424 2425 def exists_at(self, i): 2426 return self.addresses[i] is not None 2427 2428 def byte_at(self, i): 2429 return self.addresses[i].cast(self.jvm.t_char_ptr).dereference() 2430 2431 def char_at(self, i): 2432 return self.addresses[i].cast(self.jvm.t_char_ptr).dereference() 2433 2434 def double_at(self, i): 2435 return self.addresses[i].cast(self.jvm.t_double_ptr).dereference() 2436 2437 def float_at(self, i): 2438 return self.addresses[i].cast(self.jvm.t_float_ptr).dereference() 2439 2440 def int_at(self, i): 2441 return self.addresses[i].cast(self.jvm.t_int_ptr).dereference() 2442 2443 def long_at(self, i): 2444 return self.addresses[i].cast(self.jvm.t_long_ptr).dereference() 2445 2446 def short_at(self, i): 2447 return self.addresses[i].cast(self.jvm.t_short_ptr).dereference() 2448 2449 def bool_at(self, i): 2450 v = self.addresses[i].cast(self.jvm.t_char_ptr).dereference() 2451 return gdb.Value(v != 0).cast(self.jvm.t_bool) 2452 2453 def object_at(self, i, klass_name): 2454 """An object at a given slot. 2455 2456 Args: 2457 i: slot. 2458 klass_name: object's expected class name. 2459 2460 Returns: 2461 String if the object has suitable external representation or void pointer 2462 (oop). 2463 """ 2464 if self.addresses[i] is None: 2465 return None 2466 oop_location = self.addresses[i].cast(self.jvm.t_oop_ptr) 2467 if oop_location is None: 2468 return None 2469 oop = oop_location.dereference() 2470 return self.jvm.oop_value(self.jvm.new_oop(oop)) 2471 2472 def array_at(self, i, klass_name): 2473 """An object array at a given slot. 2474 2475 Args: 2476 i: slot number 2477 klass_name: expected klass name 2478 Returns: 2479 oop 2480 """ 2481 if self.addresses[i] is None: 2482 return None 2483 oop_location = self.addresses[i].cast(self.jvm.t_oop_ptr) 2484 if oop_location is None: 2485 return None 2486 oop = oop_location.dereference() 2487 return self.jvm.oop_value(self.jvm.new_oop(oop)) 2488 2489 2490 class BadOopError(Exception): 2491 """TODO.""" 2492 2493 2494 _debug = 0 2495 jvms = {} 2496 if _debug > 0: 2497 print("Loaded Java frame filter") 2498 gdb.sniffer.register_sniffer(gdb.current_progspace(), Jdk8Amd64Sniffer())