| # Copyright 2014 the V8 project authors. All rights reserved. | 
 | # Use of this source code is governed by a BSD-style license that can be | 
 | # found in the LICENSE file. | 
 |  | 
 | # Print tagged object. | 
 | define job | 
 | call (void) _v8_internal_Print_Object((void*)($arg0)) | 
 | end | 
 | document job | 
 | Print a v8 JavaScript object | 
 | Usage: job tagged_ptr | 
 | end | 
 |  | 
 | # Print content of v8::internal::Handle. | 
 | define jh | 
 | call (void) _v8_internal_Print_Object(*((v8::internal::Object**)($arg0).location_)) | 
 | end | 
 | document jh | 
 | Print content of a v8::internal::Handle | 
 | Usage: jh internal_handle | 
 | end | 
 |  | 
 | # Print content of v8::Local handle. | 
 | define jlh | 
 | call (void) _v8_internal_Print_Object(*((v8::internal::Object**)($arg0).val_)) | 
 | end | 
 | document jlh | 
 | Print content of a v8::Local handle | 
 | Usage: jlh local_handle | 
 | end | 
 |  | 
 | # Print Code objects containing given PC. | 
 | define jco | 
 | call (void) _v8_internal_Print_Code((void*)($arg0)) | 
 | end | 
 | document jco | 
 | Print a v8 Code object from an internal code address | 
 | Usage: jco pc | 
 | end | 
 |  | 
 | # Print LayoutDescriptor. | 
 | define jld | 
 | call (void) _v8_internal_Print_LayoutDescriptor((void*)($arg0)) | 
 | end | 
 | document jld | 
 | Print a v8 LayoutDescriptor object | 
 | Usage: jld tagged_ptr | 
 | end | 
 |  | 
 | # Print TransitionTree. | 
 | define jtt | 
 | call (void) _v8_internal_Print_TransitionTree((void*)($arg0)) | 
 | end | 
 | document jtt | 
 | Print the complete transition tree of the given v8 Map. | 
 | Usage: jtt tagged_ptr | 
 | end | 
 |  | 
 | # Print JavaScript stack trace. | 
 | define jst | 
 | call (void) _v8_internal_Print_StackTrace() | 
 | end | 
 | document jst | 
 | Print the current JavaScript stack trace | 
 | Usage: jst | 
 | end | 
 |  | 
 | # Print TurboFan graph node. | 
 | define pn | 
 | call _v8_internal_Node_Print((void*)($arg0)) | 
 | end | 
 | document pn | 
 | Print a v8 TurboFan graph node | 
 | Usage: pn node_address | 
 | end | 
 |  | 
 | # Skip the JavaScript stack. | 
 | define jss | 
 | set $js_entry_sp=v8::internal::Isolate::Current()->thread_local_top()->js_entry_sp_ | 
 | set $rbp=*(void**)$js_entry_sp | 
 | set $rsp=$js_entry_sp + 2*sizeof(void*) | 
 | set $pc=*(void**)($js_entry_sp+sizeof(void*)) | 
 | end | 
 | document jss | 
 | Skip the jitted stack on x64 to where we entered JS last. | 
 | Usage: jss | 
 | end | 
 |  | 
 | # Print stack trace with assertion scopes. | 
 | define bta | 
 | python | 
 | import re | 
 | frame_re = re.compile("^#(\d+)\s*(?:0x[a-f\d]+ in )?(.+) \(.+ at (.+)") | 
 | assert_re = re.compile("^\s*(\S+) = .+<v8::internal::Per\w+AssertScope<v8::internal::(\S*), (false|true)>") | 
 | btl = gdb.execute("backtrace full", to_string = True).splitlines() | 
 | for l in btl: | 
 |   match = frame_re.match(l) | 
 |   if match: | 
 |     print("[%-2s] %-60s %-40s" % (match.group(1), match.group(2), match.group(3))) | 
 |   match = assert_re.match(l) | 
 |   if match: | 
 |     if match.group(3) == "false": | 
 |       prefix = "Disallow" | 
 |       color = "\033[91m" | 
 |     else: | 
 |       prefix = "Allow" | 
 |       color = "\033[92m" | 
 |     print("%s -> %s %s (%s)\033[0m" % (color, prefix, match.group(2), match.group(1))) | 
 | end | 
 | end | 
 | document bta | 
 | Print stack trace with assertion scopes | 
 | Usage: bta | 
 | end | 
 |  | 
 | # Search for a pointer inside all valid pages. | 
 | define space_find | 
 |   set $space = $arg0 | 
 |   set $current_page = $space->first_page() | 
 |   while ($current_page != 0) | 
 |     printf "#   Searching in %p - %p\n", $current_page->area_start(), $current_page->area_end()-1 | 
 |     find $current_page->area_start(), $current_page->area_end()-1, $arg1 | 
 |     set $current_page = $current_page->next_page() | 
 |   end | 
 | end | 
 |  | 
 | define heap_find | 
 |   set $heap = v8::internal::Isolate::Current()->heap() | 
 |   printf "# Searching for %p in old_space  ===============================\n", $arg0 | 
 |   space_find $heap->old_space() ($arg0) | 
 |   printf "# Searching for %p in map_space  ===============================\n", $arg0 | 
 |   space_find $heap->map_space() $arg0 | 
 |   printf "# Searching for %p in code_space ===============================\n", $arg0 | 
 |   space_find $heap->code_space() $arg0 | 
 | end | 
 | document heap_find | 
 | Find the location of a given address in V8 pages. | 
 | Usage: heap_find address | 
 | end | 
 |  | 
 | # The 'disassembly-flavor' command is only available on i386 and x84_64. | 
 | python | 
 | try: | 
 |   gdb.execute("set disassembly-flavor intel") | 
 | except gdb.error: | 
 |   pass | 
 | end | 
 | set disable-randomization off | 
 |  | 
 | # Install a handler whenever the debugger stops due to a signal. It walks up the | 
 | # stack looking for V8_Dcheck and moves the frame to the one above it so it's | 
 | # immediately at the line of code that triggered the DCHECK. | 
 | python | 
 | def dcheck_stop_handler(event): | 
 |   frame = gdb.selected_frame() | 
 |   select_frame = None | 
 |   message = None | 
 |   count = 0 | 
 |   # limit stack scanning since they're usually shallow and otherwise stack | 
 |   # overflows can be very slow. | 
 |   while frame is not None and count < 7: | 
 |     count += 1 | 
 |     if frame.name() == 'V8_Dcheck': | 
 |       frame_message = gdb.lookup_symbol('message', frame.block())[0] | 
 |       if frame_message: | 
 |         message = frame_message.value(frame).string() | 
 |       select_frame = frame.older() | 
 |       break | 
 |     if frame.name() is not None and frame.name().startswith('V8_Fatal'): | 
 |       select_frame = frame.older() | 
 |     frame = frame.older() | 
 |  | 
 |   if select_frame is not None: | 
 |     select_frame.select() | 
 |     gdb.execute('frame') | 
 |     if message: | 
 |       print('DCHECK error: {}'.format(message)) | 
 |  | 
 | gdb.events.stop.connect(dcheck_stop_handler) | 
 | end | 
 |  | 
 | # Code imported from chromium/src/tools/gdb/gdbinit | 
 | python | 
 |  | 
 | import os | 
 | import subprocess | 
 | import sys | 
 |  | 
 | compile_dirs = set() | 
 |  | 
 |  | 
 | def get_current_debug_file_directories(): | 
 |   dir = gdb.execute("show debug-file-directory", to_string=True) | 
 |   dir = dir[ | 
 |       len('The directory where separate debug symbols are searched for is "' | 
 |          ):-len('".') - 1] | 
 |   return set(dir.split(":")) | 
 |  | 
 |  | 
 | def add_debug_file_directory(dir): | 
 |   # gdb has no function to add debug-file-directory, simulates that by using | 
 |   # `show debug-file-directory` and `set debug-file-directory <directories>`. | 
 |   current_dirs = get_current_debug_file_directories() | 
 |   current_dirs.add(dir) | 
 |   gdb.execute( | 
 |       "set debug-file-directory %s" % ":".join(current_dirs), to_string=True) | 
 |  | 
 |  | 
 | def newobj_handler(event): | 
 |   global compile_dirs | 
 |   compile_dir = os.path.dirname(event.new_objfile.filename) | 
 |   if not compile_dir: | 
 |     return | 
 |   if compile_dir in compile_dirs: | 
 |     return | 
 |   compile_dirs.add(compile_dir) | 
 |  | 
 |   # Add source path | 
 |   gdb.execute("dir %s" % compile_dir) | 
 |  | 
 |   # Need to tell the location of .dwo files. | 
 |   # https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html | 
 |   # https://crbug.com/603286#c35 | 
 |   add_debug_file_directory(compile_dir) | 
 |  | 
 | # Event hook for newly loaded objfiles. | 
 | # https://sourceware.org/gdb/onlinedocs/gdb/Events-In-Python.html | 
 | gdb.events.new_objfile.connect(newobj_handler) | 
 |  | 
 | gdb.execute("set environment V8_GDBINIT_SOURCED=1") | 
 |  | 
 | end |