mirror of
https://github.com/nodejs/node.git
synced 2025-05-15 05:00:15 +00:00

PR-URL: https://github.com/nodejs/node/pull/54077 Reviewed-By: Jiawen Geng <technicalcute@gmail.com> Reviewed-By: Richard Lau <rlau@redhat.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
233 lines
7.4 KiB
Python
233 lines
7.4 KiB
Python
# 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, print_error=True):
|
|
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
|
|
result = evaluate_result.GetError()
|
|
is_success = not result.fail or result.value == kNoResult
|
|
if not is_success:
|
|
if print_error:
|
|
print("Failed to evaluate command {} :".format(cmd))
|
|
print(result.description)
|
|
else:
|
|
print("")
|
|
return (is_success, result, cmd)
|
|
|
|
|
|
def ptr_arg_cmd(debugger, name, param, cmd, print_error=True):
|
|
if not param:
|
|
print("'{}' requires an argument".format(name))
|
|
return (False, None, "")
|
|
param = '(void*)({})'.format(param)
|
|
return no_arg_cmd(debugger, cmd.format(param), print_error)
|
|
|
|
|
|
def print_handle(debugger, command_name, param, print_func):
|
|
value = current_frame(debugger).EvaluateExpression(param)
|
|
error = value.GetError()
|
|
if error.fail:
|
|
print("Error evaluating {}\n{}".format(param, error))
|
|
return (False, error, "")
|
|
# Attempt to print, ignoring visualizers if they are enabled
|
|
result = print_func(value.GetNonSyntheticValue())
|
|
if not result[0]:
|
|
print("{} cannot print a value of type {}".format(command_name,
|
|
value.type.name))
|
|
return result
|
|
|
|
|
|
def print_direct(debugger, command_name, value):
|
|
CMD = "_v8_internal_Print_Object((v8::internal::Address*)({}))"
|
|
return ptr_arg_cmd(debugger, command_name, value, CMD.format(value))
|
|
|
|
|
|
def print_indirect(debugger, command_name, value):
|
|
CMD = "_v8_internal_Print_Object(*(v8::internal::Object**)({}))"
|
|
return ptr_arg_cmd(debugger, command_name, value, CMD.format(value))
|
|
|
|
|
|
V8_LLDB_COMMANDS = []
|
|
|
|
|
|
def lldbCommand(fn):
|
|
V8_LLDB_COMMANDS.append(fn.__name__)
|
|
return fn
|
|
|
|
|
|
#####################
|
|
# lldb commands. #
|
|
#####################
|
|
|
|
@lldbCommand
|
|
def job(debugger, param, *args):
|
|
"""Print a v8 heap object"""
|
|
ptr_arg_cmd(debugger, 'job', param, "_v8_internal_Print_Object({})")
|
|
|
|
|
|
@lldbCommand
|
|
def jh(debugger, param, *args):
|
|
"""Print v8::internal::(Maybe)?(Direct|Indirect)?Handle value"""
|
|
|
|
def print_func(value):
|
|
# Indirect handles contain a location_.
|
|
field = value.GetValueForExpressionPath(".location_")
|
|
if field.IsValid():
|
|
return print_indirect(debugger, 'jh', field.value)
|
|
# Direct handles contain a obj_.
|
|
field = value.GetValueForExpressionPath(".obj_")
|
|
if field.IsValid():
|
|
return print_indirect(debugger, 'jh', field.value)
|
|
# We don't know how to print this...
|
|
return (False, None, "")
|
|
|
|
return print_handle(debugger, 'jh', param, print_func)
|
|
|
|
|
|
@lldbCommand
|
|
def jlh(debugger, param, *args):
|
|
"""Print v8::(Maybe)?Local value"""
|
|
|
|
def print_func(value):
|
|
# After https://crrev.com/c/4335544, v8::MaybeLocal contains a local_.
|
|
field = value.GetValueForExpressionPath(".local_")
|
|
if field.IsValid():
|
|
value = field
|
|
# After https://crrev.com/c/4335544, v8::Local contains a location_.
|
|
field = value.GetValueForExpressionPath(".location_")
|
|
if field.IsValid():
|
|
return print_indirect(debugger, 'jlh', field.value)
|
|
# Before https://crrev.com/c/4335544, v8::Local contained a val_.
|
|
field = value.GetValueForExpressionPath(".val_")
|
|
if field.IsValid():
|
|
return print_indirect(debugger, 'jlh', field.value)
|
|
# With v8_enable_direct_local=true, v8::Local contains a ptr_.
|
|
field = value.GetValueForExpressionPath(".ptr_")
|
|
if field.IsValid():
|
|
return print_direct(debugger, 'jlh', field.value)
|
|
# We don't know how to print this...
|
|
return (False, None, "")
|
|
|
|
return print_handle(debugger, 'jlh', param, print_func)
|
|
|
|
|
|
@lldbCommand
|
|
def jl(debugger, param, *args):
|
|
"""Print v8::Local handle value"""
|
|
return jlh(debugger, param, *args)
|
|
|
|
|
|
@lldbCommand
|
|
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({})")
|
|
|
|
|
|
@lldbCommand
|
|
def jtt(debugger, param, *args):
|
|
"""Print the transition tree of a v8 Map"""
|
|
ptr_arg_cmd(debugger, 'jtt', param, "_v8_internal_Print_TransitionTree({})")
|
|
|
|
|
|
@lldbCommand
|
|
def jst(debugger, *args):
|
|
"""Print the current JavaScript stack trace"""
|
|
no_arg_cmd(debugger, "_v8_internal_Print_StackTrace()")
|
|
|
|
|
|
@lldbCommand
|
|
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
|
|
|
|
|
|
@lldbCommand
|
|
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 V8_LLDB_COMMANDS:
|
|
debugger.HandleCommand(
|
|
'command script add -f lldb_commands.{} {}'.format(cmd, cmd))
|