import gdb

class PrintFrame (gdb.Command):

    def __init__ (self):
        super (PrintFrame, self).__init__ ("pframe", gdb.COMMAND_STACK)

    def syntax (self):
        print("Syntax: pframe[/nn][/-mm] where nn is the number of longs to be printed above sp (16 by default) and mm is the number of longs to be printed below sp (0 by default in 32bit, 16 by default in 64bit)")

    def invoke (self, arg, from_tty):
        try:
            wordstar = gdb.lookup_type("unsigned long").pointer()
            wordsize = gdb.lookup_type("unsigned long").sizeof

            nabove = 16
            if wordsize == 4:
                nbelow = 0
            else:
                nbelow = 16

            if arg:
                l = arg.split('/')
                if l[0] != '':
                    self.syntax()
                    return
                for i in l[1:]:
                    try:
                        n = int(i)
                        if n >= 0:
                            nabove = n
                        if n < 0:
                            nbelow = -n
                    except:
                        self.syntax()
                        return

            frame = gdb.selected_frame()
            sp = frame.read_register('sp')
            if wordsize == 4:
                bp = frame.read_register('ebp')
                ip = frame.read_register('eip')
            else:
                bp = frame.read_register('rbp')
                ip = frame.read_register('rip')
            last = -nbelow*wordsize-1
            prevbp = bp.cast(wordstar).dereference()

            if bp >= sp and bp < sp + 512:
                start = bp - sp + wordsize*8
            else:
                start = 0
            if start < wordsize*nabove:
                start = wordsize*nabove

            for offset in range(start, last, -wordsize):
                addr = sp + offset
                s = '0x{:x}'.format(int(addr))

                if ip >= addr and ip < addr + wordsize:
                    s += ' ip'
                else:
                    s += '   '

                if addr == bp:
                    s += '   bp'
                elif bp >= sp and addr == bp + wordsize:
                    s += ' ret@'
                elif bp >= sp and addr == bp + 2*wordsize and (prevbp == 0 or addr < prevbp):
                    s += ' arg1'
                elif bp >= sp and addr == bp + 3*wordsize and (prevbp == 0 or addr < prevbp):
                    s += ' arg2'
                elif bp >= sp and addr == bp + 4*wordsize and (prevbp == 0 or addr < prevbp):
                    s += ' arg3'
                elif bp >= sp and addr == bp + 5*wordsize and (prevbp == 0 or addr < prevbp):
                    s += ' ... '
                else:
                    s += '     '

                if addr == sp:
                    s += ' sp '
                else:
                    s += '    '

                val = int(addr.cast(wordstar).dereference())
                s += ('0x{:0'+str(wordsize*2)+'x}').format(val)
                print(s)

        except gdb.error:
            print("Is the program running?")

PrintFrame ()

