"""Source this file into gdb `source ../../tools/gdb-stack-size.py` then run
   `stack-size` to print a backtrace with each frame size next to it."""


class StackSize(gdb.Command):
    def __init__(self):
        super(StackSize, self).__init__("stack-size", gdb.COMMAND_USER)

    def invoke(self, arg, from_tty):
        frame = gdb.newest_frame()
        total_size = 0
        while frame:
            sp = frame.read_register("sp")
            frame_up = frame.older()
            if not frame_up:
                break
            f = frame.function()
            l = frame.level()
            if l < 10:
                l = "#" + str(l) + " "
            else:
                l = "#" + str(l)
            size = frame_up.read_register("sp") - sp
            total_size += size
            print(l, sp, frame.type(), f, " " * (40 - len(str(f))), size)
            # print(dir(f))
            # Tweak this if for more detail for a specific function.
            if False and f.name == "mp_execute_bytecode":
                b = frame.block()
                prev_b = None
                while not b.is_static:
                    print("  block", hex(b.start), hex(b.end), b.function)
                    for sym in b:
                        if not sym.needs_frame:
                            continue
                        v = sym.value(frame)
                        print("   ", sym.addr_class, v.address, sym.type.sizeof, sym, sym.type, v)
                    prev_b = b
                    b = b.superblock

                    if b.function == f:
                        break
                b = prev_b
                print("pc scan", hex(b.start), hex(b.end))
                seen = set()
                for pc in range(b.start, b.end, 2):
                    b = gdb.block_for_pc(pc)
                    r = (b.start, b.end)
                    if r in seen:
                        continue
                    seen.add(r)
                    print(" ", hex(pc), hex(b.start), hex(b.end), b.function)
                    for sym in b:
                        if not sym.needs_frame:
                            continue
                        # if sym.type.sizeof <= 4:
                        #     continue
                        v = sym.value(frame)
                        print("   ", sym.addr_class, v.address, sym.type.sizeof, sym, sym.type, v)
            frame = frame_up
        print("total size:", total_size)


StackSize()