2011-06-30 11:52:00 +00:00
|
|
|
# Copyright 2011 the V8 project authors. All rights reserved.
|
|
|
|
# Redistribution and use in source and binary forms, with or without
|
|
|
|
# modification, are permitted provided that the following conditions are
|
|
|
|
# met:
|
|
|
|
#
|
|
|
|
# * Redistributions of source code must retain the above copyright
|
|
|
|
# notice, this list of conditions and the following disclaimer.
|
|
|
|
# * Redistributions in binary form must reproduce the above
|
|
|
|
# copyright notice, this list of conditions and the following
|
|
|
|
# disclaimer in the documentation and/or other materials provided
|
|
|
|
# with the distribution.
|
|
|
|
# * Neither the name of Google Inc. nor the names of its
|
|
|
|
# contributors may be used to endorse or promote products derived
|
|
|
|
# from this software without specific prior written permission.
|
|
|
|
#
|
|
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
2019-02-19 08:28:26 +00:00
|
|
|
# for py2/py3 compatibility
|
|
|
|
from __future__ import print_function
|
|
|
|
|
2015-07-21 09:28:34 +00:00
|
|
|
import re
|
2017-11-24 16:13:54 +00:00
|
|
|
import tempfile
|
|
|
|
import os
|
|
|
|
import subprocess
|
|
|
|
import time
|
2019-02-19 08:28:26 +00:00
|
|
|
import gdb
|
2011-06-30 11:52:00 +00:00
|
|
|
|
|
|
|
kSmiTag = 0
|
|
|
|
kSmiTagSize = 1
|
|
|
|
kSmiTagMask = (1 << kSmiTagSize) - 1
|
|
|
|
|
|
|
|
|
|
|
|
kHeapObjectTag = 1
|
|
|
|
kHeapObjectTagSize = 2
|
|
|
|
kHeapObjectTagMask = (1 << kHeapObjectTagSize) - 1
|
|
|
|
|
|
|
|
|
|
|
|
kFailureTag = 3
|
|
|
|
kFailureTagSize = 2
|
|
|
|
kFailureTagMask = (1 << kFailureTagSize) - 1
|
|
|
|
|
|
|
|
|
|
|
|
kSmiShiftSize32 = 0
|
|
|
|
kSmiValueSize32 = 31
|
|
|
|
kSmiShiftBits32 = kSmiTagSize + kSmiShiftSize32
|
|
|
|
|
|
|
|
|
|
|
|
kSmiShiftSize64 = 31
|
|
|
|
kSmiValueSize64 = 32
|
|
|
|
kSmiShiftBits64 = kSmiTagSize + kSmiShiftSize64
|
|
|
|
|
|
|
|
|
|
|
|
kAllBits = 0xFFFFFFFF
|
|
|
|
kTopBit32 = 0x80000000
|
|
|
|
kTopBit64 = 0x8000000000000000
|
|
|
|
|
|
|
|
|
|
|
|
t_u32 = gdb.lookup_type('unsigned int')
|
|
|
|
t_u64 = gdb.lookup_type('unsigned long long')
|
|
|
|
|
|
|
|
|
|
|
|
def has_smi_tag(v):
|
|
|
|
return v & kSmiTagMask == kSmiTag
|
|
|
|
|
|
|
|
|
|
|
|
def has_failure_tag(v):
|
|
|
|
return v & kFailureTagMask == kFailureTag
|
|
|
|
|
|
|
|
|
|
|
|
def has_heap_object_tag(v):
|
|
|
|
return v & kHeapObjectTagMask == kHeapObjectTag
|
|
|
|
|
|
|
|
|
|
|
|
def raw_heap_object(v):
|
|
|
|
return v - kHeapObjectTag
|
|
|
|
|
|
|
|
|
|
|
|
def smi_to_int_32(v):
|
|
|
|
v = v & kAllBits
|
|
|
|
if (v & kTopBit32) == kTopBit32:
|
|
|
|
return ((v & kAllBits) >> kSmiShiftBits32) - 2147483648
|
|
|
|
else:
|
|
|
|
return (v & kAllBits) >> kSmiShiftBits32
|
|
|
|
|
|
|
|
|
|
|
|
def smi_to_int_64(v):
|
|
|
|
return (v >> kSmiShiftBits64)
|
|
|
|
|
|
|
|
|
|
|
|
def decode_v8_value(v, bitness):
|
|
|
|
base_str = 'v8[%x]' % v
|
|
|
|
if has_smi_tag(v):
|
|
|
|
if bitness == 32:
|
|
|
|
return base_str + (" SMI(%d)" % smi_to_int_32(v))
|
|
|
|
else:
|
|
|
|
return base_str + (" SMI(%d)" % smi_to_int_64(v))
|
|
|
|
elif has_failure_tag(v):
|
|
|
|
return base_str + " (failure)"
|
|
|
|
elif has_heap_object_tag(v):
|
|
|
|
return base_str + (" H(0x%x)" % raw_heap_object(v))
|
|
|
|
else:
|
|
|
|
return base_str
|
|
|
|
|
|
|
|
|
|
|
|
class V8ValuePrinter(object):
|
|
|
|
"Print a v8value."
|
|
|
|
def __init__(self, val):
|
|
|
|
self.val = val
|
|
|
|
def to_string(self):
|
|
|
|
if self.val.type.sizeof == 4:
|
|
|
|
v_u32 = self.val.cast(t_u32)
|
|
|
|
return decode_v8_value(int(v_u32), 32)
|
|
|
|
elif self.val.type.sizeof == 8:
|
|
|
|
v_u64 = self.val.cast(t_u64)
|
|
|
|
return decode_v8_value(int(v_u64), 64)
|
|
|
|
else:
|
|
|
|
return 'v8value?'
|
|
|
|
def display_hint(self):
|
|
|
|
return 'v8value'
|
|
|
|
|
|
|
|
|
|
|
|
def v8_pretty_printers(val):
|
|
|
|
lookup_tag = val.type.tag
|
|
|
|
if lookup_tag == None:
|
|
|
|
return None
|
|
|
|
elif lookup_tag == 'v8value':
|
|
|
|
return V8ValuePrinter(val)
|
|
|
|
return None
|
|
|
|
gdb.pretty_printers.append(v8_pretty_printers)
|
|
|
|
|
|
|
|
|
|
|
|
def v8_to_int(v):
|
|
|
|
if v.type.sizeof == 4:
|
|
|
|
return int(v.cast(t_u32))
|
|
|
|
elif v.type.sizeof == 8:
|
|
|
|
return int(v.cast(t_u64))
|
|
|
|
else:
|
|
|
|
return '?'
|
|
|
|
|
2011-09-01 11:28:10 +00:00
|
|
|
|
2011-06-30 11:52:00 +00:00
|
|
|
def v8_get_value(vstring):
|
|
|
|
v = gdb.parse_and_eval(vstring)
|
|
|
|
return v8_to_int(v)
|
|
|
|
|
|
|
|
|
|
|
|
class V8PrintObject (gdb.Command):
|
|
|
|
"""Prints a v8 object."""
|
|
|
|
def __init__ (self):
|
|
|
|
super (V8PrintObject, self).__init__ ("v8print", gdb.COMMAND_DATA)
|
|
|
|
def invoke (self, arg, from_tty):
|
|
|
|
v = v8_get_value(arg)
|
|
|
|
gdb.execute('call __gdb_print_v8_object(%d)' % v)
|
|
|
|
V8PrintObject()
|
2015-05-27 13:48:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
class FindAnywhere (gdb.Command):
|
|
|
|
"""Search memory for the given pattern."""
|
|
|
|
MAPPING_RE = re.compile(r"^\s*\[\d+\]\s+0x([0-9A-Fa-f]+)->0x([0-9A-Fa-f]+)")
|
2015-06-18 11:56:50 +00:00
|
|
|
LIVE_MAPPING_RE = re.compile(r"^\s+0x([0-9A-Fa-f]+)\s+0x([0-9A-Fa-f]+)")
|
2015-05-27 13:48:56 +00:00
|
|
|
def __init__ (self):
|
|
|
|
super (FindAnywhere, self).__init__ ("find-anywhere", gdb.COMMAND_DATA)
|
2015-06-18 11:56:50 +00:00
|
|
|
def find (self, startAddr, endAddr, value):
|
|
|
|
try:
|
|
|
|
result = gdb.execute(
|
|
|
|
"find 0x%s, 0x%s, %s" % (startAddr, endAddr, value),
|
|
|
|
to_string = True)
|
|
|
|
if result.find("not found") == -1:
|
2016-07-03 07:09:18 +00:00
|
|
|
print(result)
|
2015-06-18 11:56:50 +00:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
2015-05-27 13:48:56 +00:00
|
|
|
def invoke (self, value, from_tty):
|
|
|
|
for l in gdb.execute("maint info sections", to_string = True).split('\n'):
|
|
|
|
m = FindAnywhere.MAPPING_RE.match(l)
|
|
|
|
if m is None:
|
|
|
|
continue
|
2015-06-18 11:56:50 +00:00
|
|
|
self.find(m.group(1), m.group(2), value)
|
|
|
|
for l in gdb.execute("info proc mappings", to_string = True).split('\n'):
|
|
|
|
m = FindAnywhere.LIVE_MAPPING_RE.match(l)
|
|
|
|
if m is None:
|
|
|
|
continue
|
|
|
|
self.find(m.group(1), m.group(2), value)
|
|
|
|
|
2015-05-27 13:48:56 +00:00
|
|
|
FindAnywhere()
|
2017-11-24 16:13:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Redirect(gdb.Command):
|
|
|
|
"""Redirect the subcommand's stdout to a temporary file.
|
|
|
|
|
|
|
|
Usage: redirect subcommand...
|
|
|
|
Example:
|
|
|
|
redirect job 0x123456789
|
|
|
|
redirect x/1024xg 0x12345678
|
|
|
|
|
|
|
|
If provided, the generated temporary file is directly openend with the
|
|
|
|
GDB_EXTERNAL_EDITOR environment variable.
|
|
|
|
"""
|
|
|
|
def __init__(self):
|
|
|
|
super(Redirect, self).__init__("redirect", gdb.COMMAND_USER)
|
|
|
|
|
|
|
|
def invoke(self, subcommand, from_tty):
|
2020-03-03 09:43:48 +00:00
|
|
|
old_stdout = gdb.execute(
|
|
|
|
"p (int)dup(1)", to_string=True).split("=")[-1].strip()
|
2017-11-24 16:13:54 +00:00
|
|
|
try:
|
|
|
|
time_suffix = time.strftime("%Y%m%d-%H%M%S")
|
|
|
|
fd, file = tempfile.mkstemp(suffix="-%s.gdbout" % time_suffix)
|
|
|
|
try:
|
|
|
|
# Temporaily redirect stdout to the created tmp file for the
|
|
|
|
# duration of the subcommand.
|
2020-03-03 09:43:48 +00:00
|
|
|
gdb.execute('p (int)dup2(open("%s", 1), 1)' % file, to_string=True)
|
2017-11-24 16:13:54 +00:00
|
|
|
# Execute subcommand non interactively.
|
|
|
|
result = gdb.execute(subcommand, from_tty=False, to_string=True)
|
|
|
|
# Write returned string results to the temporary file as well.
|
|
|
|
with open(file, 'a') as f:
|
|
|
|
f.write(result)
|
|
|
|
# Open generated result.
|
|
|
|
if 'GDB_EXTERNAL_EDITOR' in os.environ:
|
|
|
|
open_cmd = os.environ['GDB_EXTERNAL_EDITOR']
|
|
|
|
print("Opening '%s' with %s" % (file, open_cmd))
|
|
|
|
subprocess.call([open_cmd, file])
|
|
|
|
else:
|
|
|
|
print("Open output:\n %s '%s'" % (os.environ['EDITOR'], file))
|
|
|
|
finally:
|
|
|
|
# Restore original stdout.
|
2020-03-03 09:43:48 +00:00
|
|
|
gdb.execute("p (int)dup2(%s, 1)" % old_stdout, to_string=True)
|
2017-11-24 16:13:54 +00:00
|
|
|
# Close the temporary file.
|
|
|
|
os.close(fd)
|
|
|
|
finally:
|
|
|
|
# Close the originally duplicated stdout descriptor.
|
2020-03-03 09:43:48 +00:00
|
|
|
gdb.execute("p (int)close(%s)" % old_stdout, to_string=True)
|
2017-11-24 16:13:54 +00:00
|
|
|
|
|
|
|
Redirect()
|