--- a/js/src/gdb/mozilla/unwind.py
+++ b/js/src/gdb/mozilla/unwind.py
@@ -9,23 +9,16 @@ from mozilla.ExecutableAllocator import
# For ease of use in Python 2, we use "long" instead of "int"
# everywhere.
try:
long
except NameError:
long = int
-# The Python 3 |map| built-in works lazily, but in Python 2 we need
-# itertools.imap to get this.
-try:
- from itertools import imap
-except ImportError:
- imap = map
-
_have_unwinder = True
try:
from gdb.unwinder import Unwinder
except ImportError:
_have_unwinder = False
# We need something here; it doesn't matter what as no unwinder
# will ever be instantiated.
Unwinder = object
@@ -144,16 +137,33 @@ class FrameSymbol(object):
self.val = val
def symbol(self):
return self.sym
def value(self):
return self.val
+# Get the filename of a JSScript; or return None if this isn't
+# possible.
+def jsscript_filename(script, cache):
+ obj = script['sourceObject_']['value']
+ # Verify that this is a ScriptSource object.
+ # FIXME should also deal with wrappers here.
+ nativeobj = obj.cast(cache.NativeObject)
+ # See bug 987069 and despair. At least this
+ # approach won't give exceptions.
+ class_name = nativeobj['group_']['value']['clasp_']['name'].string("ISO-8859-1")
+ if class_name != "ScriptSource":
+ return None
+ scriptsourceobj = (nativeobj + 1).cast(cache.HeapSlot)[cache.SOURCE_SLOT]
+ scriptsource = scriptsourceobj['value']['data']['asBits'] << 1
+ scriptsource = scriptsource.cast(cache.ScriptSource)
+ return scriptsource['filename_']['mTuple']['mFirstA'].string()
+
# This represents a single JIT frame for the purposes of display.
# That is, the frame filter creates instances of this when it sees a
# JIT frame in the stack.
class JitFrameDecorator(FrameDecorator):
def __init__(self, base, info, cache):
super(JitFrameDecorator, self).__init__(base)
self.info = info
self.cache = cache
@@ -194,28 +204,19 @@ class JitFrameDecorator(FrameDecorator):
def filename(self):
this_frame = self.info["this_frame"]
if this_frame is not None:
if gdb.types.has_field(this_frame.type.target(), "calleeToken_"):
[function, script] = self._decode_jitframe(this_frame)
if script is not None:
obj = script['sourceObject_']['value']
- # Verify that this is a ScriptSource object.
- # FIXME should also deal with wrappers here.
- nativeobj = obj.cast(self.cache.NativeObject)
- # See bug 987069 and despair. At least this
- # approach won't give exceptions.
- class_name = nativeobj['group_']['value']['clasp_']['name'].string("ISO-8859-1")
- if class_name != "ScriptSource":
- return FrameDecorator.filename(self)
- scriptsourceobj = (nativeobj + 1).cast(self.cache.HeapSlot)[self.cache.SOURCE_SLOT]
- scriptsource = scriptsourceobj['value']['data']['asBits'] << 1
- scriptsource = scriptsource.cast(self.cache.ScriptSource)
- return scriptsource['filename_']['mTuple']['mFirstA'].string()
+ scriptfile = jsscript_filename(script, self.cache)
+ if scriptfile is not None:
+ return scriptfile
return FrameDecorator.filename(self)
def frame_args(self):
this_frame = self.info["this_frame"]
if this_frame is None:
return FrameDecorator.frame_args(self)
if not gdb.types.has_field(this_frame.type.target(), "numActualArgs_"):
return FrameDecorator.frame_args(self)
@@ -237,40 +238,83 @@ class JitFrameDecorator(FrameDecorator):
# anything better to do.
if i == 0:
name = 'this'
else:
name = 'arg%d' % i
result.append(FrameSymbol(name, args_ptr[i]))
return result
+# A frame decorator representing a single interpreter frame.
+class InterpreterFrameDecorator(FrameDecorator):
+ def __init__(self, base, iframe, cache):
+ super(InterpreterFrameDecorator, self).__init__(base)
+ self.iframe = iframe
+ self.cache = cache
+
+ def function(self):
+ return "<<<<" + FrameDecorator.function(self) + ">>>>"
+
+ def filename(self):
+ scriptfile = jsscript_filename(self.iframe['script_'], self.cache)
+ if scriptfile is not None:
+ return scriptfile
+ return FrameDecorator.filename(self)
+
+ def line(self):
+ # We can't yet compute the line number. Return None so that
+ # we don't end up sending the line number from the base frame.
+ return None
+
+ # def frame_args(self):
+ # pass
+
+# Yield a succession of synthetic interpreter frames for the given
+# frame. |frame| must be a FrameDecorator representing a call to the
+# Interpret function.
+def get_interpreter_frames(frame, cache):
+ try:
+ activation = frame.inferior_frame().read_var("activation")
+ iframe = activation['regs_']['fp_']
+ except gdb.error:
+ # maybe the activation wasn't initialized yet. This can
+ # happen if we stop in its block but before its declaration.
+ yield frame
+ return
+ while long(iframe) != 0:
+ x = InterpreterFrameDecorator(frame, iframe, cache)
+ yield x
+ iframe = iframe['prev_']
+
# A frame filter for SpiderMonkey.
class SpiderMonkeyFrameFilter(object):
# |state_holder| is either None, or an instance of
# SpiderMonkeyUnwinder. If the latter, then this class will
# reference the |unwinder_state| attribute to find the current
# unwinder state.
def __init__(self, cache, state_holder):
self.name = "SpiderMonkey"
self.enabled = True
self.priority = 100
self.state_holder = state_holder
self.cache = cache
- def maybe_wrap_frame(self, frame):
- if self.state_holder is None or self.state_holder.unwinder_state is None:
- return frame
- base = frame.inferior_frame()
- info = self.state_holder.unwinder_state.get_frame(base)
- if info is None:
- return frame
- return JitFrameDecorator(frame, info, self.cache)
-
def filter(self, frame_iter):
- return imap(self.maybe_wrap_frame, frame_iter)
+ for frame in frame_iter:
+ if self.state_holder is not None and self.state_holder.unwinder_state is not None:
+ base = frame.inferior_frame()
+ info = self.state_holder.unwinder_state.get_frame(base)
+ if info is not None:
+ yield JitFrameDecorator(frame, info, self.cache)
+ continue
+ if frame.function() == "Interpret(JSContext*, js::RunState&)":
+ for iframe in get_interpreter_frames(frame, self.cache):
+ yield iframe
+ else:
+ yield frame
# A frame id class, as specified by the gdb unwinder API.
class SpiderMonkeyFrameId(object):
def __init__(self, sp, pc):
self.sp = sp
self.pc = pc
# This holds all the state needed during a given unwind. Each time a