lldb_commands.py 3.88 KB
Newer Older
daniel.bevenius's avatar
daniel.bevenius committed
1 2 3 4
# 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.

5 6 7
# Load this file by adding this to your ~/.lldbinit:
# command script import <this_dir>/lldb_commands.py

8 9 10
# for py2/py3 compatibility
from __future__ import print_function

daniel.bevenius's avatar
daniel.bevenius committed
11 12 13
import lldb
import re

14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
#####################
# 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):
  current_frame(debugger).EvaluateExpression(cmd)
  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**)(*{}))")

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 jld(debugger, param, *args):
  """Print a v8 LayoutDescriptor object"""
  ptr_arg_cmd(debugger, 'jld', param,
              "_v8_internal_Print_LayoutDescriptor({})")

def jtt(debugger, param, *args):
  """Print the transition tree of a v8 Map"""
  ptr_arg_cmd(debugger, 'jtt', param, "_v8_internal_Print_TransitionTree({})")

daniel.bevenius's avatar
daniel.bevenius committed
61 62
def jst(debugger, *args):
  """Print the current JavaScript stack trace"""
63
  no_arg_cmd(debugger, "_v8_internal_Print_StackTrace()")
daniel.bevenius's avatar
daniel.bevenius committed
64 65 66

def jss(debugger, *args):
  """Skip the jitted stack on x64 to where we entered JS last"""
67
  frame = current_frame(debugger)
daniel.bevenius's avatar
daniel.bevenius committed
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
  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)>")
84
  thread = current_thread(debugger)
daniel.bevenius's avatar
daniel.bevenius committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
  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)))

111 112 113 114 115
def __lldb_init_module(debugger, dict):
  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))