12b45fdf00
The macro pn ensures that TurboFan nodes can be easily printed in gdb, even in release builds where Node::Print is sometimes not available (because all uses have been inlined). This CL also modifies the print function to deal gracefully with nullptr input nodes, which is helpful for debugging. Change-Id: Ib5f58aa13b719c8390826bc89dfe21cf58586de5 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1672941 Reviewed-by: Georg Neis <neis@chromium.org> Reviewed-by: Tamer Tas <tmrts@chromium.org> Commit-Queue: Sigurd Schneider <sigurds@chromium.org> Cr-Commit-Position: refs/heads/master@{#62422}
227 lines
6.1 KiB
Plaintext
227 lines
6.1 KiB
Plaintext
# 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
|
|
|
|
set disassembly-flavor intel
|
|
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 < 5:
|
|
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
|