Beispiel #1
0
def asio_stacktrace(wh, limit=None):
    """Produce a list of async frames by following a WaitHandle's parent chain.
    The stacktrace ends at the WaitHandle::join().

    The whole chain is walked even if `limit' is provided---the return
    stacktrace will have `limit' or fewer entries if there were `limit' or
    fewer frames, and `limit' + 1 frames otherwise, where the last frame is the
    WaitHandle::join().
    """
    stacktrace = []
    count = 0

    for wh in WaitHandle(wh).chain():
        resumable = wh.resumable()

        if resumable is None:
            continue

        if limit is None or count < limit:
            stacktrace.append(frame.create_resumable(count, resumable))
        count += 1

    ar = asio_context(wh['m_contextIdx'])['m_savedFP']

    if ar != nullptr():
        stacktrace.append(frame.create_php(idx=count, ar=ar))

    return stacktrace
Beispiel #2
0
def asio_stacktrace(wh, limit=None):
    """Produce a list of async frames by following a WaitHandle's parent chain.
    The stacktrace ends at the WaitHandle::join().

    The whole chain is walked even if `limit' is provided---the return
    stacktrace will have `limit' or fewer entries if there were `limit' or
    fewer frames, and `limit' + 1 frames otherwise, where the last frame is the
    WaitHandle::join().
    """
    stacktrace = []
    count = 0

    for wh in WaitHandle(wh).chain():
        resumable = wh.resumable()

        if resumable is None:
            continue

        if limit is None or count < limit:
            stacktrace.append(frame.create_resumable(count, resumable))
        count += 1

    ar = asio_context(wh['m_contextIdx'])['m_savedFP']

    if ar != nullptr():
        stacktrace.append(frame.create_php(idx=count, ar=ar))

    return stacktrace
Beispiel #3
0
    def invoke(self, args, from_tty):
        argv = parse_argv(args)

        if len(argv) > 2:
            print('Usage: walkfp [fp] [rip]')
            return

        fp_type = T('uintptr_t').pointer()

        try:
            arch = gdb.newest_frame().architecture().name()
        except:
            arch = 'i386:x86-64'

        frame_reg = '$x29' if arch == 'aarch64' else '$rbp'
        pc_reg = '$pc' if arch == 'aarch64' else '$rip'

        fp = (argv[0] if len(argv) >= 1 else
              gdb.parse_and_eval(frame_reg)).cast(fp_type)
        rip = (argv[1] if len(argv) == 2 else gdb.parse_and_eval(pc_reg)).cast(
            T('uintptr_t'))

        i = 0
        fp = (fp, rip)

        while fp:
            rip = fp[1]
            fp = fp[0].cast(fp_type)

            try:
                if frame.is_jitted(fp, rip):
                    ar_type = T('HPHP::ActRec').pointer()
                    print(
                        frame.stringify(
                            frame.create_php(idx=i,
                                             ar=fp.cast(ar_type),
                                             rip=rip)))
                else:
                    print(
                        frame.stringify(
                            frame.create_native(idx=i,
                                                fp=fp,
                                                rip=rip,
                                                name=_function_for(rip))))
            except:
                print(
                    frame.stringify(frame.create_native(idx=i, fp=fp,
                                                        rip=rip)))

            i += 1
Beispiel #4
0
    def invoke(self, args, from_tty):
        argv = parse_argv(args)

        if len(argv) > 2:
            print('Usage: walkfp [fp] [rip]')
            return

        fp_type = T('uintptr_t').pointer()
        fp = gdb.parse_and_eval('$rbp').cast(fp_type)
        rip = gdb.parse_and_eval('$rip').cast(T('uintptr_t'))

        if len(argv) >= 1:
            fp = argv[0].cast(fp_type)

            if len(argv) == 2:
                rip = argv[1].cast(T('uintptr_t'))

        i = 0
        fp = (fp, rip)

        while fp:
            rip = fp[1]
            fp = fp[0].cast(fp_type)

            try:
                if frame.is_jitted(fp, rip):
                    ar_type = T('HPHP::ActRec').pointer()
                    print(
                        frame.stringify(
                            frame.create_php(idx=i,
                                             ar=fp.cast(ar_type),
                                             rip=rip)))
                else:
                    print(
                        frame.stringify(
                            frame.create_native(idx=i,
                                                fp=fp,
                                                rip=rip,
                                                name=_function_for(rip))))
            except:
                print(
                    frame.stringify(frame.create_native(idx=i, fp=fp,
                                                        rip=rip)))

            i += 1
Beispiel #5
0
    def invoke(self, args, from_tty):
        argv = parse_argv(args)

        if len(argv) > 2:
            print('Usage: walkfp [fp] [rip]')
            return

        fp_type = T('uintptr_t').pointer()

        try:
            arch = gdb.newest_frame().architecture().name()
        except:
            arch = 'i386:x86-64'

        frame_reg = '$x29' if arch == 'aarch64' else '$rbp'
        pc_reg = '$pc' if arch == 'aarch64' else '$rip'

        fp = (argv[0] if len(argv) >= 1 else
              gdb.parse_and_eval(frame_reg)).cast(fp_type)
        rip = (argv[1] if len(argv) == 2 else
               gdb.parse_and_eval(pc_reg)).cast(T('uintptr_t'))

        i = 0
        fp = (fp, rip)

        while fp:
            rip = fp[1]
            fp = fp[0].cast(fp_type)

            try:
                if frame.is_jitted(fp, rip):
                    ar_type = T('HPHP::ActRec').pointer()
                    print(frame.stringify(frame.create_php(
                        idx=i, ar=fp.cast(ar_type), rip=rip)))
                else:
                    print(frame.stringify(frame.create_native(
                        idx=i, fp=fp, rip=rip, name=_function_for(rip))))
            except:
                print(frame.stringify(frame.create_native(idx=i, fp=fp, rip=rip)))

            i += 1
Beispiel #6
0
    def invoke(self, args, from_tty):
        argv = parse_argv(args)

        if len(argv) > 2:
            print('Usage: walkfp [fp] [rip]')
            return

        fp_type = T('uintptr_t').pointer()
        fp = gdb.parse_and_eval('$rbp').cast(fp_type)
        rip = gdb.parse_and_eval('$rip').cast(T('uintptr_t'))

        if len(argv) >= 1:
            fp = argv[0].cast(fp_type)

            if len(argv) == 2:
                rip = argv[1].cast(T('uintptr_t'))

        i = 0
        fp = (fp, rip)

        while fp:
            rip = fp[1]
            fp = fp[0].cast(fp_type)

            try:
                if frame.is_jitted(fp, rip):
                    ar_type = T('HPHP::ActRec').pointer()
                    print(frame.stringify(frame.create_php(
                        idx=i, ar=fp.cast(ar_type), rip=rip)))
                else:
                    print(frame.stringify(frame.create_native(
                        idx=i, fp=fp, rip=rip, name=_function_for(rip))))
            except:
                print(frame.stringify(frame.create_native(idx=i, fp=fp, rip=rip)))

            i += 1
Beispiel #7
0
    def invoke(self, args, from_tty):
        argv = parse_argv(args)

        if len(argv) > 1:
            print('Usage: walkstk [fp]')
            return

        # Set fp = $rbp.
        fp_type = T('uintptr_t').pointer()
        fp = gdb.parse_and_eval('$rbp').cast(fp_type)
        if len(argv) == 1:
            fp = argv[0].cast(fp_type)[0]

        # Set rip = $rip.
        rip_type = T('uintptr_t')
        rip = gdb.parse_and_eval('$rip').cast(rip_type)
        if len(argv) == 1:
            rip = argv[0].cast(fp_type)[1]

        # Find the starting native frame.
        native_frame = gdb.newest_frame()

        while (native_frame is not None and rip != native_frame.pc()):
            native_frame = native_frame.older()

        if native_frame is None:
            if len(argv) == 0:
                print('walkstk: Unknown error: corrupt stack?')
            else:
                print('walkstk: Invalid frame pointer')
            return

        # Get the address and value of `mcg', the global MCGenerator pointer.
        # For some reason, gdb doesn't have debug info about the symbol, so we
        # can't use V(); probably this is because we declare it extern "C" (and
        # maybe also because we do so in a namespace).
        mcg_type = T('HPHP::jit::MCGenerator').pointer()
        mcg_addr = gdb.parse_and_eval('&::mcg').cast(mcg_type.pointer())
        mcg = mcg_addr.dereference()

        # Set the bounds of the TC.
        try:
            tc_base = mcg['code']['m_base']
            tc_end = tc_base + mcg['code']['m_codeSize']
        except:
            # We can't access `mcg' for whatever reason.  Assume that the TC is
            # above the data section, but restricted to low memory.
            tc_base = mcg_addr.cast(T('uintptr_t'))
            tc_end = 0x100000000

        i = 0

        # Make a fake frame for our `fp' and `rip'.  This lets us pop a frame
        # at the top of the loop, which makes it easier to include the final
        # frame.
        fp = (fp, rip)

        while fp:
            rip = fp[1]
            fp = fp[0].cast(fp_type)

            in_tc = rip >= tc_base and rip < tc_end

            # Try to get the PHP function name from the ActRec at %fp if we're
            # executing in the TC.
            if in_tc:
                ar_type = T('HPHP::ActRec').pointer()
                try:
                    print(
                        frame.stringify(
                            frame.create_php(idx=i + 1,
                                             ar=fp.cast(ar_type),
                                             rip=rip)))
                except gdb.MemoryError:
                    print(
                        frame.stringify(
                            frame.create_native(idx=i + 1,
                                                fp=fp,
                                                rip=rip,
                                                native_frame=native_frame)))

            # Pop native frames until we hit our caller's rip.
            else:
                frames = []

                while (native_frame is not None
                       and fp[1] != native_frame.pc()):
                    frames.append(
                        frame.create_native(idx=i,
                                            fp='{inline frame}',
                                            rip=rip,
                                            native_frame=native_frame))

                    i += 1
                    native_frame = native_frame.older()

                if frames:
                    # Associate the frame pointer with the un-inlined frame.
                    frames[-1]['fp'] = str(fp)

                for f in frames:
                    print(frame.stringify(f))
Beispiel #8
0
    def invoke(self, args, from_tty):
        argv = parse_argv(args)

        if len(argv) > 1:
            print('Usage: walkstk [fp]')
            return

        # Bail early if the custom unwinder has not been set up.
        if not unwind.try_unwinder_init():
            print('walkstk: Could not initialize the HHVM unwinder.')

        # Find the starting native frame.
        native_frame = gdb.newest_frame()
        if native_frame is None:
            print('walkstk: Cannot find any frames: corrupt stack?')
            return

        # Set fp = $rbp, rip = $rip.
        fp_type = T('uintptr_t').pointer()
        fp = native_frame.read_register('rbp').cast(fp_type)
        rip = native_frame.pc()

        if len(argv) == 1:
            # Start walking the stack from the user-provided `fp'.
            fp = argv[0].cast(fp_type)[0]
            rip = argv[0].cast(fp_type)[1]

            # Try to find a corresponding native frame.
            while (native_frame is not None and rip != native_frame.pc()):
                native_frame = native_frame.older()

        i = 0

        # Make a fake frame for our `fp' and `rip'.  This lets us pop a frame
        # at the top of the loop, which makes it easier to include the final
        # frame.
        fp = (fp, rip)

        while fp:
            rip = fp[1]
            fp = fp[0].cast(fp_type)

            # Try to get the PHP function name from the ActRec at `fp' if we're
            # executing in the TC.
            if frame.is_jitted(fp, rip):
                ar_type = T('HPHP::ActRec').pointer()
                try:
                    print(
                        frame.stringify(
                            frame.create_php(idx=i,
                                             ar=fp.cast(ar_type),
                                             rip=rip)))
                except gdb.MemoryError:
                    print(
                        frame.stringify(
                            frame.create_native(idx=i,
                                                fp=fp,
                                                rip=rip,
                                                native_frame=native_frame)))

                if native_frame is not None:
                    native_frame = native_frame.older()
                i += 1

            else:
                if native_frame is None:
                    # If we couldn't find a native frame, then `walkstk' was
                    # invoked with a non-native `fp' argument.  Now that we
                    # don't seem to be in the TC, try to find the corresponding
                    # native frame.
                    native_frame = gdb.newest_frame()
                    while (native_frame is not None
                           and rip != native_frame.pc()):
                        native_frame = native_frame.older()

                if native_frame is not None:
                    # Pop native frames until we hit our caller's rip.
                    frames = []

                    while (native_frame is not None
                           and (fp == 0x0 or fp[1] != native_frame.pc())):
                        frames.append(
                            frame.create_native(idx=i,
                                                fp='{inline frame}',
                                                rip=native_frame.pc(),
                                                native_frame=native_frame))

                        native_frame = native_frame.older()
                        i += 1

                    if frames:
                        # Associate the frame pointer with the un-inlined frame.
                        frames[-1]['fp'] = str(fp)

                    for f in frames:
                        print(frame.stringify(f))
                else:
                    # We only hit this case if gdb undercounted the TC's
                    # frames---which shouldn't happen unless the custom
                    # unwinder (or gdb's unwinder API) is malfunctioning.
                    #
                    # Just guess that the name of the frame is the same as the
                    # name of the block we're in.
                    try:
                        block = gdb.block_for_pc(int(rip))
                        name = block.function.name
                        print(
                            frame.stringify(
                                frame.create_native(idx=i,
                                                    fp=fp,
                                                    rip=rip,
                                                    name='? ' + name)))
                    except:
                        print(
                            frame.stringify(
                                frame.create_native(idx=i,
                                                    fp=fp,
                                                    rip=rip,
                                                    native_frame=None)))
                    i += 1
Beispiel #9
0
    def invoke(self, args, from_tty):
        argv = parse_argv(args)

        if len(argv) > 2:
            print('Usage: walkstk [sp] [rip]')
            return

        # Set sp = $rbp.
        sp_type = T('uintptr_t').pointer()
        sp = gdb.parse_and_eval('$rbp').cast(sp_type)
        if len(argv) >= 1:
            sp = argv[0].cast(sp_type)

        # Set rip = $rip.
        rip_type = T('uintptr_t')
        rip = gdb.parse_and_eval('$rip').cast(rip_type)
        if len(argv) == 2:
            rip = argv[1].cast(rip_type)

        try:
            mcg = V('HPHP::jit::mcg')
            tc_base = mcg['code']['m_base']
            tc_end = tc_base + mcg['code']['m_codeSize']
        except:
            mcg = None

        i = 0
        native_frame = gdb.newest_frame()
        skip_tc = False  # Only used when we can't find HPHP::mcg.

        # Munge `sp' so that it looks like the stack pointer that would point
        # to it if we had another frame---this lets us promote the "increment"
        # to the beginning of the loop, so that we don't miss the final frame.
        sp = (sp, rip)

        while sp:
            rip = sp[1]
            sp = sp[0].cast(sp_type)

            if mcg is not None:
                in_tc = rip >= tc_base and rip < tc_end
            elif not skip_tc:
                # TC frames look like unnamed normal native frames.
                try:
                    next_frame = native_frame.older()
                    in_tc = (next_frame is not None
                             and next_frame.name() is None
                             and next_frame.type() == gdb.NORMAL_FRAME)
                except AttributeError:
                    # No older frame.
                    in_tc = False
            else:
                in_tc = False
                skip_tc = False

            # Try to get the PHP function name from the ActRec at %sp if we're
            # executing in the TC.
            if in_tc:
                ar_type = T('HPHP::ActRec').pointer()
                try:
                    print(
                        frame.stringify(
                            frame.create_php(idx=i + 1,
                                             ar=sp.cast(ar_type),
                                             rip=rip)))
                except gdb.MemoryError:
                    if mcg is None:
                        # We guessed wrong about whether we're in the TC.
                        skip_tc = True

                    print(
                        frame.stringify(
                            frame.create_native(idx=i + 1, sp=sp, rip=rip)))

            # Pop native frames until we find our current %sp.
            else:
                inlines = 0

                while (native_frame is not None and rip != native_frame.pc()):
                    if inlines > 0 and native_frame.name() is not None:
                        print(
                            frame.stringify(
                                frame.create_native(
                                    idx=i,
                                    sp='{inline frame}',
                                    rip=rip,
                                    native_frame=native_frame)))

                    i += 1
                    inlines += 1
                    native_frame = native_frame.older()

                print(
                    frame.stringify(
                        frame.create_native(idx=i,
                                            sp=sp,
                                            rip=rip,
                                            native_frame=native_frame)))
Beispiel #10
0
    def invoke(self, args, from_tty):
        argv = parse_argv(args)

        if len(argv) > 1:
            print('Usage: walkstk [fp]')
            return

        # Bail early if the custom unwinder has not been set up.
        if not unwind.try_unwinder_init():
            print('walkstk: Could not initialize the HHVM unwinder.')

        # Find the starting native frame.
        native_frame = gdb.newest_frame()
        if native_frame is None:
            print('walkstk: Cannot find any frames: corrupt stack?')
            return

        # Set fp = $rbp, rip = $rip.
        fp_type = T('uintptr_t').pointer()
        fp = native_frame.read_register('rbp').cast(fp_type)
        rip = native_frame.pc()

        if len(argv) == 1:
            # Start walking the stack from the user-provided `fp'.
            fp = argv[0].cast(fp_type)[0]
            rip = argv[0].cast(fp_type)[1]

            # Try to find a corresponding native frame.
            while (native_frame is not None
                   and rip != native_frame.pc()):
                native_frame = native_frame.older()

        i = 0

        # Make a fake frame for our `fp' and `rip'.  This lets us pop a frame
        # at the top of the loop, which makes it easier to include the final
        # frame.
        fp = (fp, rip)

        while fp:
            rip = fp[1]
            fp = fp[0].cast(fp_type)

            # Try to get the PHP function name from the ActRec at `fp' if we're
            # executing in the TC.
            if frame.is_jitted(fp, rip):
                ar_type = T('HPHP::ActRec').pointer()
                try:
                    print(frame.stringify(frame.create_php(
                        idx=i, ar=fp.cast(ar_type), rip=rip)))
                except gdb.MemoryError:
                    print(frame.stringify(frame.create_native(
                        idx=i, fp=fp, rip=rip, native_frame=native_frame)))

                if native_frame is not None:
                    native_frame = native_frame.older()
                i += 1

            else:
                if native_frame is None:
                    # If we couldn't find a native frame, then `walkstk' was
                    # invoked with a non-native `fp' argument.  Now that we
                    # don't seem to be in the TC, try to find the corresponding
                    # native frame.
                    native_frame = gdb.newest_frame()
                    while (native_frame is not None
                           and rip != native_frame.pc()):
                        native_frame = native_frame.older()

                if native_frame is not None:
                    # Pop native frames until we hit our caller's rip.
                    frames = []

                    while (native_frame is not None
                           and (fp == 0x0 or fp[1] != native_frame.pc())):
                        frames.append(frame.create_native(
                            idx=i,
                            fp='{inline frame}',
                            rip=native_frame.pc(),
                            native_frame=native_frame))

                        native_frame = native_frame.older()
                        i += 1

                    if frames:
                        # Associate the frame pointer with the un-inlined frame.
                        frames[-1]['fp'] = str(fp)

                    for f in frames:
                        print(frame.stringify(f))
                else:
                    # We only hit this case if gdb undercounted the TC's
                    # frames---which shouldn't happen unless the custom
                    # unwinder (or gdb's unwinder API) is malfunctioning.
                    #
                    # Just guess that the name of the frame is the same as the
                    # name of the block we're in.
                    try:
                        print(frame.stringify(frame.create_native(
                            idx=i, fp=fp, rip=rip, name=_function_for(rip))))
                    except:
                        print(frame.stringify(frame.create_native(
                            idx=i, fp=fp, rip=rip, native_frame=None)))
                    i += 1
Beispiel #11
0
    def invoke(self, args, from_tty):
        argv = parse_argv(args)

        if len(argv) > 2:
            print('Usage: walkstk [sp] [rip]')

        # Set sp = $rbp.
        sp_type = T('uintptr_t').pointer()
        sp = gdb.parse_and_eval('$rbp').cast(sp_type)
        if len(argv) >= 1:
            sp = argv[0].cast(sp_type)

        # Set rip = $rip.
        rip_type = T('uintptr_t')
        rip = gdb.parse_and_eval('$rip').cast(rip_type)
        if len(argv) == 2:
            rip = argv[1].cast(rip_type)

        try:
            mcg = V('HPHP::jit::mcg')
            tc_base = mcg['code']['m_base']
            tc_end = tc_base + mcg['code']['m_codeSize']
        except:
            mcg = None

        i = 0
        native_frame = gdb.newest_frame()
        skip_tc = False  # Only used when we can't find HPHP::mcg.

        # Munge `sp' so that it looks like the stack pointer that would point
        # to it if we had another frame---this lets us promote the "increment"
        # to the beginning of the loop, so that we don't miss the final frame.
        sp = (sp, rip)

        while sp:
            rip = sp[1]
            sp = sp[0].cast(sp_type)

            if mcg is not None:
                in_tc = rip >= tc_base and rip < tc_end
            elif not skip_tc:
                # TC frames look like unnamed normal native frames.
                try:
                    next_frame = native_frame.older()
                    in_tc = (next_frame is not None and
                             next_frame.name() is None and
                             next_frame.type() == gdb.NORMAL_FRAME)
                except AttributeError:
                    # No older frame.
                    in_tc = False
            else:
                in_tc = False
                skip_tc = False

            # Try to get the PHP function name from the ActRec at %sp if we're
            # executing in the TC.
            if in_tc:
                ar_type = T('HPHP::ActRec').pointer()
                try:
                    print(frame.stringify(frame.create_php(
                        idx=i + 1, ar=sp.cast(ar_type), rip=rip)))
                except gdb.MemoryError:
                    if mcg is None:
                        # We guessed wrong about whether we're in the TC.
                        skip_tc = True

                    print(frame.stringify(frame.create_native(
                        idx=i + 1, sp=sp, rip=rip)))

            # Pop native frames until we find our current %sp.
            else:
                inlines = 0

                while (native_frame is not None
                       and rip != native_frame.pc()):
                    if inlines > 0 and native_frame.name() is not None:
                        print(frame.stringify(frame.create_native(
                            idx=i,
                            sp='{inline frame}',
                            rip=rip,
                            native_frame=native_frame)))

                    i += 1
                    inlines += 1
                    native_frame = native_frame.older()

                print(frame.stringify(frame.create_native(
                    idx=i, sp=sp, rip=rip, native_frame=native_frame)))
Beispiel #12
0
    def invoke(self, args, from_tty):
        argv = parse_argv(args)

        if len(argv) > 1:
            print('Usage: walkstk [fp]')
            return

        # Set fp = $rbp.
        fp_type = T('uintptr_t').pointer()
        fp = gdb.parse_and_eval('$rbp').cast(fp_type)
        if len(argv) == 1:
            fp = argv[0].cast(fp_type)[0]

        # Set rip = $rip.
        rip_type = T('uintptr_t')
        rip = gdb.parse_and_eval('$rip').cast(rip_type)
        if len(argv) == 1:
            rip = argv[0].cast(fp_type)[1]

        # Find the starting native frame.
        native_frame = gdb.newest_frame()

        while (native_frame is not None
               and rip != native_frame.pc()):
            native_frame = native_frame.older()

        if native_frame is None:
            if len(argv) == 0:
                print('walkstk: Unknown error: corrupt stack?')
            else:
                print('walkstk: Invalid frame pointer')
            return

        # Get the address and value of `mcg', the global MCGenerator pointer.
        # For some reason, gdb doesn't have debug info about the symbol, so we
        # can't use V(); probably this is because we declare it extern "C" (and
        # maybe also because we do so in a namespace).
        mcg_type = T('HPHP::jit::MCGenerator').pointer()
        mcg_addr = gdb.parse_and_eval('&::mcg').cast(mcg_type.pointer())
        mcg = mcg_addr.dereference()

        # Set the bounds of the TC.
        try:
            tc_base = mcg['code']['m_base']
            tc_end = tc_base + mcg['code']['m_codeSize']
        except:
            # We can't access `mcg' for whatever reason.  Assume that the TC is
            # above the data section, but restricted to low memory.
            tc_base = mcg_addr.cast(T('uintptr_t'))
            tc_end = 0x100000000

        i = 0

        # Make a fake frame for our `fp' and `rip'.  This lets us pop a frame
        # at the top of the loop, which makes it easier to include the final
        # frame.
        fp = (fp, rip)

        while fp:
            rip = fp[1]
            fp = fp[0].cast(fp_type)

            in_tc = rip >= tc_base and rip < tc_end

            # Try to get the PHP function name from the ActRec at %fp if we're
            # executing in the TC.
            if in_tc:
                ar_type = T('HPHP::ActRec').pointer()
                try:
                    print(frame.stringify(frame.create_php(
                        idx=i + 1, ar=fp.cast(ar_type), rip=rip)))
                except gdb.MemoryError:
                    print(frame.stringify(frame.create_native(
                        idx=i + 1, fp=fp, rip=rip, native_frame=native_frame)))

            # Pop native frames until we hit our caller's rip.
            else:
                frames = []

                while (native_frame is not None
                       and fp[1] != native_frame.pc()):
                    frames.append(frame.create_native(
                        idx=i,
                        fp='{inline frame}',
                        rip=rip,
                        native_frame=native_frame))

                    i += 1
                    native_frame = native_frame.older()

                if frames:
                    # Associate the frame pointer with the un-inlined frame.
                    frames[-1]['fp'] = str(fp)

                for f in frames:
                    print(frame.stringify(f))