5e9afd645c
The gdb DCHECK frame skipping automatically skips over all the abort etc. frames to get you to that DCHECK callsite you're actually looking for. However, this is annoying if you tried to call a function with a breakpoint from the gdb prompt; the frame skipping wold skip over your breakpoint back up to the failing DCHECK. Now, we abort the frame walk on dummy frames inserted by gdb execution. Change-Id: I2cf89ea9219374ad7c562c6eb13afe471038b033 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3229376 Commit-Queue: Leszek Swirski <leszeks@chromium.org> Auto-Submit: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Clemens Backes <clemensb@chromium.org> Cr-Commit-Position: refs/heads/main@{#77436}
251 lines
6.8 KiB
Plaintext
251 lines
6.8 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
|
|
if $argc == 0
|
|
call (void) _v8_internal_Print_Code((void*)($pc))
|
|
else
|
|
call (void) _v8_internal_Print_Code((void*)($arg0))
|
|
end
|
|
end
|
|
document jco
|
|
Print a v8 Code object from an internal code address
|
|
Usage: jco pc
|
|
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
|
|
|
|
# Execute a simulator command.
|
|
python
|
|
import gdb
|
|
|
|
class SimCommand(gdb.Command):
|
|
"""Sim the current program."""
|
|
|
|
def __init__ (self):
|
|
super (SimCommand, self).__init__ ("sim", gdb.COMMAND_SUPPORT)
|
|
|
|
def invoke (self, arg, from_tty):
|
|
arg_c_string = gdb.Value(arg)
|
|
cmd_func = gdb.selected_frame().read_var("_v8_internal_Simulator_ExecDebugCommand")
|
|
cmd_func(arg_c_string)
|
|
|
|
SimCommand()
|
|
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 we are in a frame created by gdb (e.g. for `(gdb) call foo()`), gdb
|
|
# emits a dummy frame between its stack and the program's stack. Abort the
|
|
# walk if we see this frame.
|
|
if frame.type() == gdb.DUMMY_FRAME: break
|
|
|
|
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
|