Home | History | Annotate | Download | only in tools
      1 # Copyright 2017 the V8 project authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 # Load this file by adding this to your ~/.lldbinit:
      6 # command script import <this_dir>/lldb_commands.py
      7 
      8 import lldb
      9 import re
     10 
     11 #####################
     12 # Helper functions. #
     13 #####################
     14 def current_thread(debugger):
     15   return debugger.GetSelectedTarget().GetProcess().GetSelectedThread()
     16 
     17 def current_frame(debugger):
     18   return current_thread(debugger).GetSelectedFrame()
     19 
     20 def no_arg_cmd(debugger, cmd):
     21   current_frame(debugger).EvaluateExpression(cmd)
     22   print("")
     23 
     24 def ptr_arg_cmd(debugger, name, param, cmd):
     25   if not param:
     26     print("'{}' requires an argument".format(name))
     27     return
     28   param = '(void*)({})'.format(param)
     29   no_arg_cmd(debugger, cmd.format(param))
     30 
     31 #####################
     32 # lldb commands.    #
     33 #####################
     34 def job(debugger, param, *args):
     35   """Print a v8 heap object"""
     36   ptr_arg_cmd(debugger, 'job', param, "_v8_internal_Print_Object({})")
     37 
     38 def jlh(debugger, param, *args):
     39   """Print v8::Local handle value"""
     40   ptr_arg_cmd(debugger, 'jlh', param,
     41               "_v8_internal_Print_Object(*(v8::internal::Object**)(*{}))")
     42 
     43 def jco(debugger, param, *args):
     44   """Print the code object at the given pc (default: current pc)"""
     45   if not param:
     46     param = str(current_frame(debugger).FindRegister("pc").value)
     47   ptr_arg_cmd(debugger, 'jco', param, "_v8_internal_Print_Code({})")
     48 
     49 def jld(debugger, param, *args):
     50   """Print a v8 LayoutDescriptor object"""
     51   ptr_arg_cmd(debugger, 'jld', param,
     52               "_v8_internal_Print_LayoutDescriptor({})")
     53 
     54 def jtt(debugger, param, *args):
     55   """Print the transition tree of a v8 Map"""
     56   ptr_arg_cmd(debugger, 'jtt', param, "_v8_internal_Print_TransitionTree({})")
     57 
     58 def jst(debugger, *args):
     59   """Print the current JavaScript stack trace"""
     60   no_arg_cmd(debugger, "_v8_internal_Print_StackTrace()")
     61 
     62 def jss(debugger, *args):
     63   """Skip the jitted stack on x64 to where we entered JS last"""
     64   frame = current_frame(debugger)
     65   js_entry_sp = frame.EvaluateExpression(
     66       "v8::internal::Isolate::Current()->thread_local_top()->js_entry_sp_;") \
     67        .GetValue()
     68   sizeof_void = frame.EvaluateExpression("sizeof(void*)").GetValue()
     69   rbp = frame.FindRegister("rbp")
     70   rsp = frame.FindRegister("rsp")
     71   pc = frame.FindRegister("pc")
     72   rbp = js_entry_sp
     73   rsp = js_entry_sp + 2 *sizeof_void
     74   pc.value = js_entry_sp + sizeof_void
     75 
     76 def bta(debugger, *args):
     77   """Print stack trace with assertion scopes"""
     78   func_name_re = re.compile("([^(<]+)(?:\(.+\))?")
     79   assert_re = re.compile(
     80       "^v8::internal::Per\w+AssertType::(\w+)_ASSERT, (false|true)>")
     81   thread = current_thread(debugger)
     82   for frame in thread:
     83     functionSignature = frame.GetDisplayFunctionName()
     84     if functionSignature is None:
     85       continue
     86     functionName = func_name_re.match(functionSignature)
     87     line = frame.GetLineEntry().GetLine()
     88     sourceFile = frame.GetLineEntry().GetFileSpec().GetFilename()
     89     if line:
     90       sourceFile = sourceFile + ":" + str(line)
     91 
     92     if sourceFile is None:
     93       sourceFile = ""
     94     print("[%-2s] %-60s %-40s" % (frame.GetFrameID(),
     95                                   functionName.group(1),
     96                                   sourceFile))
     97     match = assert_re.match(str(functionSignature))
     98     if match:
     99       if match.group(3) == "false":
    100         prefix = "Disallow"
    101         color = "\033[91m"
    102       else:
    103         prefix = "Allow"
    104         color = "\033[92m"
    105       print("%s -> %s %s (%s)\033[0m" % (
    106           color, prefix, match.group(2), match.group(1)))
    107 
    108 def __lldb_init_module(debugger, dict):
    109   debugger.HandleCommand('settings set target.x86-disassembly-flavor intel')
    110   for cmd in ('job', 'jlh', 'jco', 'jld', 'jtt', 'jst', 'jss', 'bta'):
    111     debugger.HandleCommand(
    112       'command script add -f lldb_commands.{} {}'.format(cmd, cmd))
    113