docker swarm
This commit is contained in:
@ -0,0 +1,253 @@
|
||||
# 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 / V8_Fatal / OS::DebugBreak frame and moves the
|
||||
# frame to the one above it so it's immediately at the line of code that
|
||||
# triggered the stop condition.
|
||||
python
|
||||
def v8_stop_handler(event):
|
||||
frame = gdb.selected_frame()
|
||||
select_frame = None
|
||||
message = None
|
||||
count = 0
|
||||
# Limit stack scanning since the frames we look for are near the top anyway,
|
||||
# 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()
|
||||
if frame.name() == 'v8::base::OS::DebugBreak':
|
||||
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(v8_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
|
@ -0,0 +1,134 @@
|
||||
# Copyright 2017 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.
|
||||
|
||||
# Load this file by adding this to your ~/.lldbinit:
|
||||
# command script import <this_dir>/lldb_commands.py
|
||||
|
||||
# for py2/py3 compatibility
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
import lldb
|
||||
|
||||
#####################
|
||||
# Helper functions. #
|
||||
#####################
|
||||
def current_thread(debugger):
|
||||
return debugger.GetSelectedTarget().GetProcess().GetSelectedThread()
|
||||
|
||||
def current_frame(debugger):
|
||||
return current_thread(debugger).GetSelectedFrame()
|
||||
|
||||
def no_arg_cmd(debugger, cmd):
|
||||
cast_to_void_expr = '(void) {}'.format(cmd)
|
||||
evaluate_result = current_frame(debugger).EvaluateExpression(cast_to_void_expr)
|
||||
# When a void function is called the return value type is 0x1001 which
|
||||
# is specified in http://tiny.cc/bigskz. This does not indicate
|
||||
# an error so we check for that value below.
|
||||
kNoResult = 0x1001
|
||||
error = evaluate_result.GetError()
|
||||
if error.fail and error.value != kNoResult:
|
||||
print("Failed to evaluate command {} :".format(cmd))
|
||||
print(error.description)
|
||||
else:
|
||||
print("")
|
||||
|
||||
def ptr_arg_cmd(debugger, name, param, cmd):
|
||||
if not param:
|
||||
print("'{}' requires an argument".format(name))
|
||||
return
|
||||
param = '(void*)({})'.format(param)
|
||||
no_arg_cmd(debugger, cmd.format(param))
|
||||
|
||||
#####################
|
||||
# lldb commands. #
|
||||
#####################
|
||||
def job(debugger, param, *args):
|
||||
"""Print a v8 heap object"""
|
||||
ptr_arg_cmd(debugger, 'job', param, "_v8_internal_Print_Object({})")
|
||||
|
||||
def jlh(debugger, param, *args):
|
||||
"""Print v8::Local handle value"""
|
||||
ptr_arg_cmd(debugger, 'jlh', param,
|
||||
"_v8_internal_Print_Object(*(v8::internal::Object**)({}.val_))")
|
||||
|
||||
def jco(debugger, param, *args):
|
||||
"""Print the code object at the given pc (default: current pc)"""
|
||||
if not param:
|
||||
param = str(current_frame(debugger).FindRegister("pc").value)
|
||||
ptr_arg_cmd(debugger, 'jco', param, "_v8_internal_Print_Code({})")
|
||||
|
||||
def jtt(debugger, param, *args):
|
||||
"""Print the transition tree of a v8 Map"""
|
||||
ptr_arg_cmd(debugger, 'jtt', param, "_v8_internal_Print_TransitionTree({})")
|
||||
|
||||
def jst(debugger, *args):
|
||||
"""Print the current JavaScript stack trace"""
|
||||
no_arg_cmd(debugger, "_v8_internal_Print_StackTrace()")
|
||||
|
||||
def jss(debugger, *args):
|
||||
"""Skip the jitted stack on x64 to where we entered JS last"""
|
||||
frame = current_frame(debugger)
|
||||
js_entry_sp = frame.EvaluateExpression(
|
||||
"v8::internal::Isolate::Current()->thread_local_top()->js_entry_sp_;") \
|
||||
.GetValue()
|
||||
sizeof_void = frame.EvaluateExpression("sizeof(void*)").GetValue()
|
||||
rbp = frame.FindRegister("rbp")
|
||||
rsp = frame.FindRegister("rsp")
|
||||
pc = frame.FindRegister("pc")
|
||||
rbp = js_entry_sp
|
||||
rsp = js_entry_sp + 2 *sizeof_void
|
||||
pc.value = js_entry_sp + sizeof_void
|
||||
|
||||
def bta(debugger, *args):
|
||||
"""Print stack trace with assertion scopes"""
|
||||
func_name_re = re.compile("([^(<]+)(?:\(.+\))?")
|
||||
assert_re = re.compile(
|
||||
"^v8::internal::Per\w+AssertType::(\w+)_ASSERT, (false|true)>")
|
||||
thread = current_thread(debugger)
|
||||
for frame in thread:
|
||||
functionSignature = frame.GetDisplayFunctionName()
|
||||
if functionSignature is None:
|
||||
continue
|
||||
functionName = func_name_re.match(functionSignature)
|
||||
line = frame.GetLineEntry().GetLine()
|
||||
sourceFile = frame.GetLineEntry().GetFileSpec().GetFilename()
|
||||
if line:
|
||||
sourceFile = sourceFile + ":" + str(line)
|
||||
|
||||
if sourceFile is None:
|
||||
sourceFile = ""
|
||||
print("[%-2s] %-60s %-40s" % (frame.GetFrameID(),
|
||||
functionName.group(1),
|
||||
sourceFile))
|
||||
match = assert_re.match(str(functionSignature))
|
||||
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)))
|
||||
|
||||
def setup_source_map_for_relative_paths(debugger):
|
||||
# Copied from Chromium's tools/lldb/lldbinit.py.
|
||||
# When relative paths are used for debug symbols, lldb cannot find source
|
||||
# files. Set up a source map to point to V8's root.
|
||||
this_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
source_dir = os.path.join(this_dir, os.pardir)
|
||||
|
||||
debugger.HandleCommand(
|
||||
'settings set target.source-map ../.. ' + source_dir)
|
||||
|
||||
|
||||
def __lldb_init_module(debugger, dict):
|
||||
setup_source_map_for_relative_paths(debugger)
|
||||
debugger.HandleCommand('settings set target.x86-disassembly-flavor intel')
|
||||
for cmd in ('job', 'jlh', 'jco', 'jld', 'jtt', 'jst', 'jss', 'bta'):
|
||||
debugger.HandleCommand(
|
||||
'command script add -f lldb_commands.{} {}'.format(cmd, cmd))
|
Reference in New Issue
Block a user