1# Copyright 2014 the V8 project authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5# Print tagged object. 6define job 7call (void) _v8_internal_Print_Object((void*)($arg0)) 8end 9document job 10Print a v8 JavaScript object 11Usage: job tagged_ptr 12end 13 14# Print content of v8::internal::Handle. 15define jh 16call (void) _v8_internal_Print_Object(*((v8::internal::Object**)($arg0).location_)) 17end 18document jh 19Print content of a v8::internal::Handle 20Usage: jh internal_handle 21end 22 23# Print content of v8::Local handle. 24define jlh 25call (void) _v8_internal_Print_Object(*((v8::internal::Object**)($arg0).val_)) 26end 27document jlh 28Print content of a v8::Local handle 29Usage: jlh local_handle 30end 31 32# Print Code objects containing given PC. 33define jco 34 if $argc == 0 35 call (void) _v8_internal_Print_Code((void*)($pc)) 36 else 37 call (void) _v8_internal_Print_Code((void*)($arg0)) 38 end 39end 40document jco 41Print a v8 Code object from an internal code address 42Usage: jco pc 43end 44 45# Print TransitionTree. 46define jtt 47call (void) _v8_internal_Print_TransitionTree((void*)($arg0)) 48end 49document jtt 50Print the complete transition tree of the given v8 Map. 51Usage: jtt tagged_ptr 52end 53 54# Print JavaScript stack trace. 55define jst 56call (void) _v8_internal_Print_StackTrace() 57end 58document jst 59Print the current JavaScript stack trace 60Usage: jst 61end 62 63# Print TurboFan graph node. 64define pn 65call _v8_internal_Node_Print((void*)($arg0)) 66end 67document pn 68Print a v8 TurboFan graph node 69Usage: pn node_address 70end 71 72# Skip the JavaScript stack. 73define jss 74set $js_entry_sp=v8::internal::Isolate::Current()->thread_local_top()->js_entry_sp_ 75set $rbp=*(void**)$js_entry_sp 76set $rsp=$js_entry_sp + 2*sizeof(void*) 77set $pc=*(void**)($js_entry_sp+sizeof(void*)) 78end 79document jss 80Skip the jitted stack on x64 to where we entered JS last. 81Usage: jss 82end 83 84# Execute a simulator command. 85python 86import gdb 87 88class SimCommand(gdb.Command): 89 """Sim the current program.""" 90 91 def __init__ (self): 92 super (SimCommand, self).__init__ ("sim", gdb.COMMAND_SUPPORT) 93 94 def invoke (self, arg, from_tty): 95 arg_c_string = gdb.Value(arg) 96 cmd_func = gdb.selected_frame().read_var("_v8_internal_Simulator_ExecDebugCommand") 97 cmd_func(arg_c_string) 98 99SimCommand() 100end 101 102# Print stack trace with assertion scopes. 103define bta 104python 105import re 106frame_re = re.compile("^#(\d+)\s*(?:0x[a-f\d]+ in )?(.+) \(.+ at (.+)") 107assert_re = re.compile("^\s*(\S+) = .+<v8::internal::Per\w+AssertScope<v8::internal::(\S*), (false|true)>") 108btl = gdb.execute("backtrace full", to_string = True).splitlines() 109for l in btl: 110 match = frame_re.match(l) 111 if match: 112 print("[%-2s] %-60s %-40s" % (match.group(1), match.group(2), match.group(3))) 113 match = assert_re.match(l) 114 if match: 115 if match.group(3) == "false": 116 prefix = "Disallow" 117 color = "\033[91m" 118 else: 119 prefix = "Allow" 120 color = "\033[92m" 121 print("%s -> %s %s (%s)\033[0m" % (color, prefix, match.group(2), match.group(1))) 122end 123end 124document bta 125Print stack trace with assertion scopes 126Usage: bta 127end 128 129# Search for a pointer inside all valid pages. 130define space_find 131 set $space = $arg0 132 set $current_page = $space->first_page() 133 while ($current_page != 0) 134 printf "# Searching in %p - %p\n", $current_page->area_start(), $current_page->area_end()-1 135 find $current_page->area_start(), $current_page->area_end()-1, $arg1 136 set $current_page = $current_page->next_page() 137 end 138end 139 140define heap_find 141 set $heap = v8::internal::Isolate::Current()->heap() 142 printf "# Searching for %p in old_space ===============================\n", $arg0 143 space_find $heap->old_space() ($arg0) 144 printf "# Searching for %p in map_space ===============================\n", $arg0 145 space_find $heap->map_space() $arg0 146 printf "# Searching for %p in code_space ===============================\n", $arg0 147 space_find $heap->code_space() $arg0 148end 149document heap_find 150Find the location of a given address in V8 pages. 151Usage: heap_find address 152end 153 154# The 'disassembly-flavor' command is only available on i386 and x84_64. 155python 156try: 157 gdb.execute("set disassembly-flavor intel") 158except gdb.error: 159 pass 160end 161set disable-randomization off 162 163# Install a handler whenever the debugger stops due to a signal. It walks up the 164# stack looking for V8_Dcheck / V8_Fatal / OS::DebugBreak frame and moves the 165# frame to the one above it so it's immediately at the line of code that 166# triggered the stop condition. 167python 168def v8_stop_handler(event): 169 frame = gdb.selected_frame() 170 select_frame = None 171 message = None 172 count = 0 173 # Limit stack scanning since the frames we look for are near the top anyway, 174 # and otherwise stack overflows can be very slow. 175 while frame is not None and count < 7: 176 count += 1 177 # If we are in a frame created by gdb (e.g. for `(gdb) call foo()`), gdb 178 # emits a dummy frame between its stack and the program's stack. Abort the 179 # walk if we see this frame. 180 if frame.type() == gdb.DUMMY_FRAME: break 181 182 if frame.name() == 'V8_Dcheck': 183 frame_message = gdb.lookup_symbol('message', frame.block())[0] 184 if frame_message: 185 message = frame_message.value(frame).string() 186 select_frame = frame.older() 187 break 188 if frame.name() is not None and frame.name().startswith('V8_Fatal'): 189 select_frame = frame.older() 190 if frame.name() == 'v8::base::OS::DebugBreak': 191 select_frame = frame.older() 192 frame = frame.older() 193 194 if select_frame is not None: 195 select_frame.select() 196 gdb.execute('frame') 197 if message: 198 print('DCHECK error: {}'.format(message)) 199 200gdb.events.stop.connect(v8_stop_handler) 201end 202 203# Code imported from chromium/src/tools/gdb/gdbinit 204python 205 206import os 207import subprocess 208import sys 209 210compile_dirs = set() 211 212 213def get_current_debug_file_directories(): 214 dir = gdb.execute("show debug-file-directory", to_string=True) 215 dir = dir[ 216 len('The directory where separate debug symbols are searched for is "' 217 ):-len('".') - 1] 218 return set(dir.split(":")) 219 220 221def add_debug_file_directory(dir): 222 # gdb has no function to add debug-file-directory, simulates that by using 223 # `show debug-file-directory` and `set debug-file-directory <directories>`. 224 current_dirs = get_current_debug_file_directories() 225 current_dirs.add(dir) 226 gdb.execute( 227 "set debug-file-directory %s" % ":".join(current_dirs), to_string=True) 228 229 230def newobj_handler(event): 231 global compile_dirs 232 compile_dir = os.path.dirname(event.new_objfile.filename) 233 if not compile_dir: 234 return 235 if compile_dir in compile_dirs: 236 return 237 compile_dirs.add(compile_dir) 238 239 # Add source path 240 gdb.execute("dir %s" % compile_dir) 241 242 # Need to tell the location of .dwo files. 243 # https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html 244 # https://crbug.com/603286#c35 245 add_debug_file_directory(compile_dir) 246 247# Event hook for newly loaded objfiles. 248# https://sourceware.org/gdb/onlinedocs/gdb/Events-In-Python.html 249gdb.events.new_objfile.connect(newobj_handler) 250 251gdb.execute("set environment V8_GDBINIT_SOURCED=1") 252 253end 254