예제 #1
0
    def unpack_memory(self):
        if self.mem is None:
            print_error("No memory found")
            raise Exception('sys.exit()')

        self.mutex = self.unpack_variable("<I", 0)
        self.flags = self.unpack_variable("<I", 4)
        offset = 8
        if self.version >= 2.23:
            if self.size_sz == 4:
                fmt = "<I"
            elif self.size_sz == 8:
                fmt = "<Q"
            # this is padded on 64-bit despite being int
            self.have_fastchunks = self.unpack_variable(fmt, offset)
            offset = offset + self.size_sz

        if self.size_sz == 4:
            fmt = "<10I"
        elif self.size_sz == 8:
            fmt = "<10Q"
        self.fastbinsY = struct.unpack_from(fmt, self.mem, offset)
        offset = offset + 10 * self.size_sz

        if self.size_sz == 4:
            fmt = "<I"
        elif self.size_sz == 8:
            fmt = "<Q"
        self.top = self.unpack_variable(fmt, offset)
        offset += self.size_sz

        self.last_remainder = self.unpack_variable(fmt, offset)
        offset = offset + self.size_sz

        if self.size_sz == 4:
            fmt = "<254I"
        elif self.size_sz == 8:
            fmt = "<254Q"
        self.bins = struct.unpack_from(fmt, self.mem, offset)

        offset = offset + (254 * self.size_sz)
        self.binmap = struct.unpack_from("<IIII", self.mem, offset)

        if self.size_sz == 4:
            fmt = "<I"
        elif self.size_sz == 8:
            fmt = "<Q"
        offset = offset + 16
        self.next = self.unpack_variable(fmt, offset)
        offset = offset + self.size_sz
        self.next_free = self.unpack_variable(fmt, offset)

        if self.version >= 2.23:
            offset = offset + self.size_sz
            self.attached_threads = self.unpack_variable(fmt, offset)

        offset = offset + self.size_sz
        self.system_mem = self.unpack_variable(fmt, offset)
        offset = offset + self.size_sz
        self.max_system_mem = self.unpack_variable(fmt, offset)
예제 #2
0
    def get_heap_address(self, mp=None):
        """Read heap address from glibc's mp_ structure if available,
        otherwise fall back to /proc/self/maps which is unreliable.
        """

        start, end = None, None

        if mp is not None:
            from libheap.ptmalloc.malloc_par import malloc_par
            if isinstance(mp, malloc_par):
                start = mp.sbrk_base
            else:
                print_error("Please specify a valid malloc_par variable")

            # XXX: add end from arena(s).system_mem ?
        else:
            pid, task_id, thread_id = gdb.selected_thread().ptid
            maps_file = "/proc/%d/task/%d/maps"
            maps_data = open(maps_file % (pid, task_id)).readlines()
            for line in maps_data:
                if any(x.strip() == '[heap]' for x in line.split(' ')):
                    heap_range = line.split(' ')[0]
                    start, end = [int(h, 16) for h in heap_range.split('-')]
                    break

        return start, end
예제 #3
0
    def get_heap_address(self, mp=None):
        """Read heap address from glibc's mp_ structure if available,
        otherwise fall back to /proc/self/maps which is unreliable.
        """

        start, end = None, None

        if mp is not None:
            from libheap.ptmalloc.malloc_par import malloc_par
            if isinstance(mp, malloc_par):
                start = mp.sbrk_base
            else:
                print_error("Please specify a valid malloc_par variable")

            # XXX: add end from arena(s).system_mem ?
        else:
            pid, task_id, thread_id = gdb.selected_thread().ptid
            maps_file = "/proc/%d/task/%d/maps"
            maps_data = open(maps_file % (pid, task_id)).readlines()
            for line in maps_data:
                if any(x.strip() == '[heap]' for x in line.split(' ')):
                    heap_range = line.split(' ')[0]
                    start, end = [int(h, 16) for h in heap_range.split('-')]
                    break

        return start, end
예제 #4
0
    def unpack_memory(self):
        if self.mem is None:
            print_error("No memory found")
            sys.exit()

        if self.sz == 4:
            fmt = "<I"
        elif self.sz == 8:
            fmt = "<Q"

        self.trim_threshold = self.unpack_variable(fmt, 0)
        self.top_pad = self.unpack_variable(fmt, self.sz)
        self.mmap_threshold = self.unpack_variable(fmt, self.sz * 2)
        self.arena_text = self.unpack_variable(fmt, self.sz * 3)
        self.arena_max = self.unpack_variable(fmt, self.sz * 4)

        # size shared on both 32bit and 64bit Intel
        fmt = "<I"

        offset = self.sz * 5
        self.n_mmaps = self.unpack_variable(fmt, offset)

        offset = offset + 4
        self.n_mmaps_max = self.unpack_variable(fmt, offset)

        offset = offset + 4
        self.max_n_mmaps = self.unpack_variable(fmt, offset)

        offset = offset + 4
        self.no_dyn_threshold = self.unpack_variable(fmt, offset)

        if self.sz == 4:
            fmt = "<I"
        elif self.sz == 8:
            fmt = "<Q"

        offset = offset + 4
        self.mmapped_mem = self.unpack_variable(fmt, offset)

        offset = offset + self.sz
        self.max_mmapped_mem = self.unpack_variable(fmt, offset)

        # max_total_mem removed in 2.24
        if self.version <= 2.23:
            offset = offset + self.sz
            self.max_total_mem = self.unpack_variable(fmt, offset)

        offset = offset + self.sz
        self.sbrk_base = self.unpack_variable(fmt, offset)

        # could not read sbrk_base from mp_, fall back to maps file
        if (self.sbrk_base == 0) or (self.sbrk_base is None):
            self.sbrk_base, end = self.dbg.get_heap_address()

        # we can't read heap address from mp_ or from maps file, exit libheap
        if (self.sbrk_base == 0) or (self.sbrk_base is None):
            print_error("Could not find sbrk_base, this setup is unsupported.")
            exit()
예제 #5
0
    def bin_at(self, m, i):
        "addressing -- note that bin_at(0) does not exist"

        if i == 0:
            print_error("bin_at(0) does not exist")
            sys.exit()

        index = (i-1) * 2
        return m.bins[index]
예제 #6
0
    def write_memory(self, address, buf, length=None):
        if self.inferior is None:
            self.inferior = self.get_inferior()

        try:
            if length is None:
                self.inferior.write_memory(address, buf)
            else:
                self.inferior.write_memory(address, buf, length)
        except MemoryError:
            print_error("GDB inferior write_memory error")
예제 #7
0
    def read_variable(self, variable=None):
        if variable is None:
            print_error("Please specify a variable to read")
            return None

        try:
            return gdb.selected_frame().read_var(variable)
        except RuntimeError:
            # No idea why this works but sometimes the frame is not selected
            print_error("No gdb frame is currently selected.\n")
            return gdb.selected_frame().read_var(variable)
예제 #8
0
    def __init__(self, debugger=None, version=None):
        super(smallbins, self).__init__("smallbins", gdb.COMMAND_OBSCURE,
                                        gdb.COMPLETE_NONE)

        if debugger is not None:
            self.dbg = debugger
        else:
            print_error("Please specify a debugger")
            sys.exit()

        self.version = version
예제 #9
0
    def write_memory(self, address, buf, length=None):
        if self.inferior is None:
            self.inferior = self.get_inferior()

        try:
            if length is None:
                self.inferior.write_memory(address, buf)
            else:
                self.inferior.write_memory(address, buf, length)
        except MemoryError:
            print_error("GDB inferior write_memory error")
예제 #10
0
    def __init__(self, debugger=None, version=None):
        super(heaplsc, self).__init__("heaplsc", gdb.COMMAND_OBSCURE,
                                      gdb.COMPLETE_NONE)

        if debugger is not None:
            self.dbg = debugger
        else:
            print_error("Please specify a debugger")
            sys.exit()

        self.version = version
예제 #11
0
 def get_inferior(self):
     try:
         if self.inferior is None:
             if len(gdb.inferiors()) == 0:
                 print_error("No gdb inferior could be found.")
                 return -1
             else:
                 self.inferior = gdb.inferiors()[0]
                 return self.inferior
         else:
             return self.inferior
     except AttributeError:
         print_error("This gdb's python support is too old.")
         sys.exit()
예제 #12
0
 def get_inferior(self):
     try:
         if self.inferior is None:
             if len(gdb.inferiors()) == 0:
                 print_error("No gdb inferior could be found.")
                 return -1
             else:
                 self.inferior = gdb.inferiors()[0]
                 return self.inferior
         else:
             return self.inferior
     except AttributeError:
         print_error("This gdb's python support is too old.")
         sys.exit()
예제 #13
0
    def unpack_memory(self):
        if self.mem is None:
            print_error("No memory found")
            sys.exit()

        self.mutex = self.unpack_variable("<I", 0)
        self.flags = self.unpack_variable("<I", 4)

        if self.size_sz == 4:
            fmt = "<10I"
        elif self.size_sz == 8:
            fmt = "<10Q"
        self.fastbinsY = struct.unpack_from(fmt, self.mem, 8)

        if self.size_sz == 4:
            fmt = "<I"
        elif self.size_sz == 8:
            fmt = "<Q"
        offset = 8 + (10 * self.size_sz)
        self.top = self.unpack_variable(fmt, offset)
        offset = offset + self.size_sz
        self.last_remainder = self.unpack_variable(fmt, offset)

        if self.size_sz == 4:
            fmt = "<254I"
        elif self.size_sz == 8:
            fmt = "<254Q"
        offset = offset + self.size_sz
        self.bins = struct.unpack_from(fmt, self.mem, offset)

        offset = offset + (254 * self.size_sz)
        self.binmap = struct.unpack_from("<IIII", self.mem, offset)

        if self.size_sz == 4:
            fmt = "<I"
        elif self.size_sz == 8:
            fmt = "<Q"
        offset = offset + 16
        self.next = self.unpack_variable(fmt, offset)
        offset = offset + self.size_sz
        self.next_free = self.unpack_variable(fmt, offset)

        if self.version >= 2.23:
            offset = offset + self.size_sz
            self.attached_threads = self.unpack_variable(fmt, offset)

        offset = offset + self.size_sz
        self.system_mem = self.unpack_variable(fmt, offset)
        offset = offset + self.size_sz
        self.max_system_mem = self.unpack_variable(fmt, offset)
예제 #14
0
    def read_variable(self, variable=None):
        if variable is None:
            print_error("Please specify a variable to read")
            return None

        try:
            return gdb.selected_frame().read_var(variable)
        except RuntimeError:
            # No idea why this works but sometimes the frame is not selected
            # print_error("No gdb frame is currently selected.\n")
            try:
                return gdb.selected_frame().read_var(variable)
            except RuntimeError:
                # variable was not found
                # print_error("wrong here!")
                return None
        except ValueError:
            # variable was not found
            return None
예제 #15
0
    def set_globals(self, SIZE_SZ=None):
        if SIZE_SZ is None:
            if self.dbg is None:
                print_error("Please specify a debugger.")
                sys.exit()

            self.SIZE_SZ = self.dbg.get_size_sz()
        else:
            self.SIZE_SZ = SIZE_SZ

        self.MIN_CHUNK_SIZE = 4 * self.SIZE_SZ
        self.MALLOC_ALIGNMENT = 2 * self.SIZE_SZ
        self.MALLOC_ALIGN_MASK = self.MALLOC_ALIGNMENT - 1
        self.MINSIZE = ((self.MIN_CHUNK_SIZE +
                        self.MALLOC_ALIGN_MASK) & ~self.MALLOC_ALIGN_MASK)

        self.SMALLBIN_WIDTH = self.MALLOC_ALIGNMENT
        self.MIN_LARGE_SIZE = self.NSMALLBINS * self.SMALLBIN_WIDTH

        self.MAX_FAST_SIZE = (80 * self.SIZE_SZ / 4)
        size = self.request2size(self.MAX_FAST_SIZE)
        self.NFASTBINS = self.fastbin_index(size) + 1
예제 #16
0
    def get_size_sz(self):
        try:
            _machine = self.get_arch()[0]
        except IndexError:
            _machine = ""
            SIZE_SZ = 0
            print_error("Retrieving SIZE_SZ failed.")
        except TypeError:  # gdb is not running
            _machine = ""
            SIZE_SZ = 0
            print_error("Retrieving SIZE_SZ failed.")

        if "elf64" in _machine:
            SIZE_SZ = 8
        elif "elf32" in _machine:
            SIZE_SZ = 4
        else:
            SIZE_SZ = 0
            print_error("Retrieving SIZE_SZ failed.")

        return SIZE_SZ
예제 #17
0
    def get_size_sz(self):
        try:
            _machine = self.get_arch()[0]
        except IndexError:
            _machine = ""
            SIZE_SZ = 0
            print_error("Retrieving SIZE_SZ failed.")
        except TypeError:  # gdb is not running
            _machine = ""
            SIZE_SZ = 0
            print_error("Retrieving SIZE_SZ failed.")

        if "elf64" in _machine:
            SIZE_SZ = 8
        elif "elf32" in _machine:
            SIZE_SZ = 4
        else:
            SIZE_SZ = 0
            print_error("Retrieving SIZE_SZ failed.")

        return SIZE_SZ
예제 #18
0
 def write(self, inferior=None):
     # XXX: fixme
     print_error("malloc_par write() not yet implemented.")
예제 #19
0
    def __init__(self, addr=None, mem=None, debugger=None, version=None):
        self.trim_threshold = 0
        self.top_pad = 0
        self.mmap_threshold = 0
        self.arena_test = 0
        self.arena_max = 0
        self.n_mmaps = 0
        self.n_mmaps_max = 0
        self.max_n_mmaps = 0
        self.no_dyn_threshold = 0
        self.mmapped_mem = 0
        self.max_mmapped_mem = 0
        self.max_total_mem = 0
        self.sbrk_base = 0

        if addr is None:
            if mem is None:
                print_error("Please specify an address or raw memory.")
                return None

            self.address = None
        else:
            self.address = addr

        if debugger is not None:
            self.dbg = debugger
        else:
            print_error("Please specify a debugger")
            sys.exit()

        # get architecture SIZE_SZ
        self.sz = self.dbg.get_size_sz()

        if version is None:
            print_error("Please specify a malloc_par version.")
            sys.exit()
        else:
            self.version = version

        if mem is None:
            # a string of raw memory was not provided

            if self.version >= 2.15 and self.version <= 2.23:
                if self.sz == 4:
                    # sizeof(malloc_par) = 20 + 16 + 16
                    struct_malloc_par_size = 0x34
                elif self.sz == 8:
                    # sizeof(malloc_par) = 40 + 16 + 32
                    struct_malloc_par_size = 0x58
            elif self.version == 2.24 or self.version == 2.25:
                # max_total_mem removed in 2.24
                if self.sz == 4:
                    struct_malloc_par_size = 0x30
                elif self.sz == 8:
                    struct_malloc_par_size = 0x50

            try:
                self.mem = self.dbg.read_memory(addr, struct_malloc_par_size)
            except TypeError:
                print_error("Invalid address specified.")
                return None
            except RuntimeError:
                print_error("Could not read address {0:#x}".format(addr))
                return None
        else:
            self.mem = mem

        self.unpack_memory()
예제 #20
0
    def invoke(self, arg, from_tty):
        """Inspired by jp's phrack print and arena.c"""

        ptm = ptmalloc(debugger=self.dbg)

        if ptm.SIZE_SZ == 0:
            ptm.set_globals()

        # XXX: from old heap command, replace
        main_arena = self.dbg.read_variable("main_arena")
        main_arena_address = self.dbg.format_address(main_arena.address)
        thread_arena = self.dbg.read_variable("thread_arena")
        if thread_arena is not None:
            thread_arena_address = self.dbg.format_address(thread_arena)
        else:
            thread_arena_address = main_arena_address

        argv = self.dbg.string_to_argv(arg)

        if len(argv) == 1:
            arena_address = int(argv[0], 16)
        elif len(argv):
            print_error('Too many arguments')
            return
        else:
            arena_address = thread_arena_address

        ar_ptr = malloc_state(arena_address,
                              debugger=self.dbg,
                              version=self.version)

        # XXX: add mp_ address guessing via offset without symbols
        mp_ = self.dbg.read_variable("mp_")
        mp_address = mp_.address
        mp = malloc_par(mp_address, debugger=self.dbg, version=self.version)

        if arena_address == main_arena_address:
            start, _ = self.dbg.get_heap_address(mp)
        else:
            # XXX: start offset
            start = arena_address + ar_ptr.size
        sbrk_base = start

        # print("{:>19}".format("arena @ "), end="")
        # print_value("{:#x}".format(arena_address), end="\n\n")
        # print_title("{:>15}".format("flat heap listing"), end="\n")
        print_title("{:>15}{:>17}{:>18}".format("ADDR", "SIZE", "STATUS"),
                    end="\n")
        print("{:11}".format("sbrk_base"), end="")
        print_value("{:#x}".format(int(sbrk_base)), end="\n")

        p = malloc_chunk(sbrk_base,
                         inuse=True,
                         read_data=False,
                         debugger=self.dbg)

        while (1):
            print("{:11}".format("chunk"), end="")
            print_value("{: <#17x}".format(int(p.address)), end="")
            print("{: <#16x}".format(int(ptm.chunksize(p))), end="")

            if p.address == ptm.top(ar_ptr):
                print("(top)")
                break
            elif p.size == (0 | ptm.PREV_INUSE):
                print("(fence)")
                break

            if ptm.inuse(p):
                print("(inuse)")
            else:
                p = malloc_chunk(p.address, inuse=False, debugger=self.dbg)
                print("(F) FD ", end="")
                print_value("{:#x} ".format(int(p.fd)))
                print("BK ", end="")
                print_value("{:#x} ".format(int(p.bk)))

                if ((p.fd == ar_ptr.last_remainder)
                        and (p.bk == ar_ptr.last_remainder)
                        and (ar_ptr.last_remainder != 0)):
                    print("(LR)")
                elif ((p.fd == p.bk) & ~ptm.inuse(p)):
                    print("(LC)")
                else:
                    print("")

            p = malloc_chunk(ptm.next_chunk(p),
                             inuse=True,
                             read_data=False,
                             debugger=self.dbg)

        sbrk_end = int(sbrk_base + ar_ptr.max_system_mem)
        print("{:11}".format("sbrk_end"), end="")
        print_value("{:#x}".format(sbrk_end), end="")
        print("")
예제 #21
0
    def invoke(self, arg, from_tty):
        """Inspired by jp's phrack print and arena.c"""

        ptm = ptmalloc(debugger=self.dbg)

        if ptm.SIZE_SZ == 0:
            ptm.set_globals()

        # XXX: from old heap command, replace
        main_arena = self.dbg.read_variable("main_arena")
        main_arena_address = self.dbg.format_address(main_arena.address)
        thread_arena = self.dbg.read_variable("thread_arena")
        if thread_arena is not None:
            thread_arena_address = self.dbg.format_address(thread_arena)
        else:
            thread_arena_address = main_arena_address

        argv = self.dbg.string_to_argv(arg)

        if len(argv) == 1:
            arena_address = int(argv[0], 16)
        elif len(argv):
            print_error('Too many arguments')
            return
        else:
            arena_address = thread_arena_address

        ar_ptr = malloc_state(arena_address, debugger=self.dbg,
                              version=self.version)

        # XXX: add mp_ address guessing via offset without symbols
        mp_ = self.dbg.read_variable("mp_")
        mp_address = mp_.address
        mp = malloc_par(mp_address, debugger=self.dbg, version=self.version)

        if arena_address == main_arena_address:
            start, _ = self.dbg.get_heap_address(mp)
        else:
            # XXX: start offset
            start = arena_address + ar_ptr.size
        sbrk_base = start

        # print("{:>19}".format("arena @ "), end="")
        # print_value("{:#x}".format(arena_address), end="\n\n")
        # print_title("{:>15}".format("flat heap listing"), end="\n")
        print_title("{:>15}{:>17}{:>18}".format("ADDR", "SIZE", "STATUS"),
                    end="\n")
        print("{:11}".format("sbrk_base"), end="")
        print_value("{:#x}".format(int(sbrk_base)), end="\n")

        p = malloc_chunk(sbrk_base, inuse=True, read_data=False,
                         debugger=self.dbg)

        while(1):
            print("{:11}".format("chunk"), end="")
            print_value("{: <#17x}".format(int(p.address)), end="")
            print("{: <#16x}".format(int(ptm.chunksize(p))), end="")

            if p.address == ptm.top(ar_ptr):
                print("(top)")
                break
            elif p.size == (0 | ptm.PREV_INUSE):
                print("(fence)")
                break

            if ptm.inuse(p):
                print("(inuse)")
            else:
                p = malloc_chunk(p.address, inuse=False, debugger=self.dbg)
                print("(F) FD ", end="")
                print_value("{:#x} ".format(int(p.fd)))
                print("BK ", end="")
                print_value("{:#x} ".format(int(p.bk)))

                if ((p.fd == ar_ptr.last_remainder) and
                   (p.bk == ar_ptr.last_remainder) and
                   (ar_ptr.last_remainder != 0)):
                    print("(LR)")
                elif ((p.fd == p.bk) & ~ptm.inuse(p)):
                    print("(LC)")
                else:
                    print("")

            p = malloc_chunk(ptm.next_chunk(p), inuse=True, read_data=False,
                             debugger=self.dbg)

        sbrk_end = int(sbrk_base + ar_ptr.max_system_mem)
        print("{:11}".format("sbrk_end"), end="")
        print_value("{:#x}".format(sbrk_end), end="")
        print("")
예제 #22
0
파일: heap.py 프로젝트: cloudburst/libheap
    def invoke(self, arg, from_tty):
        # XXX: self.dbg.string_to_argv
        if arg.find("-h") != -1:
            # print_header("heap ", end="")
            # print("Options:", end="\n\n")
            # print_header("{:<15}".format("-a 0x1234"))
            # print("Specify an arena address")
            print_header("{:<15}".format("heapls"))
            print("Print a flat listing of all chunks in an arena")
            print_header("{:<15}".format("fastbins [#]"))
            print("Print all fast bins, or only a single fast bin")
            print_header("{:<15}".format("smallbins [#]"))
            print("Print all small bins, or only a single small bin")
            print_header("{:<15}".format("freebins"))
            print("Print compact bin listing (only free chunks)")
            print_header("{:<15}".format("heaplsc"))
            print("Print compact arena listing (all chunks)")
            print_header("{:<15}".format("mstats"), end="")
            print("Print memory alloc statistics similar to malloc_stats(3)")
            # print_header("{:<22}".format("print_bin_layout [#]"), end="")
            # print("Print the layout of a particular free bin")
            return

        ptm = ptmalloc(self.dbg)

        if ptm.SIZE_SZ == 0:
            ptm.set_globals()

        # XXX: from old heap command, replace
        main_arena = self.dbg.read_variable("main_arena")
        # XXX: add arena address guessing via offset without symbols
        arena_address = self.dbg.format_address(main_arena.address)
        ar_ptr = malloc_state(arena_address, debugger=self.dbg,
                              version=self.version)

        # XXX: add arena address passing via arg (-a)
        if (len(arg) == 0) and (ar_ptr.next == 0):
            # struct malloc_state may be invalid size (wrong glibc version)
            print_error("No arenas could be found at {:#x}".format(
                        ar_ptr.address))
            return

        print("Arena(s) found:", end="\n")
        print("  arena @ ", end="")
        print_header("{:#x}".format(int(ar_ptr.address)), end="\n")

        if ar_ptr.address != ar_ptr.next:
            # we have more than one arena

            curr_arena = malloc_state(ar_ptr.next, debugger=self.dbg,
                                      version=self.version)

            while (ar_ptr.address != curr_arena.address):
                print("  arena @ ", end="")
                print_header("{:#x}".format(int(curr_arena.address)), end="\n")
                curr_arena = malloc_state(curr_arena.next, debugger=self.dbg,
                                          version=self.version)

                if curr_arena.address == 0:
                    print_error("No arenas could be correctly found.")
                    break  # breaking infinite loop
예제 #23
0
    def invoke(self, arg, from_tty):
        ptm = ptmalloc(debugger=self.dbg)

        if ptm.SIZE_SZ == 0:
            ptm.set_globals()

        if ptm.SIZE_SZ == 4:
            pad_width = 27
        elif ptm.SIZE_SZ == 8:
            pad_width = 31

        # XXX: from old heap command, replace
        main_arena = self.dbg.read_variable("main_arena")
        arena_address = self.dbg.format_address(main_arena.address)
        ar_ptr = malloc_state(arena_address, debugger=self.dbg,
                              version=self.version)

        # mchunkptr bins in struct malloc_state
        if ptm.SIZE_SZ == 4:
            bins_offset = 4 + 4 + 40 + 4 + 4  # 56
            sb_base = int(ar_ptr.address) + bins_offset
        elif ptm.SIZE_SZ == 8:
            bins_offset = 4 + 4 + 80 + 8 + 8  # 104
            sb_base = int(ar_ptr.address) + bins_offset

        if len(arg) == 0:
            sb_num = None
        else:
            sb_num = int(arg.split(" ")[0])

            if (sb_num * 2) > ptm.NBINS:
                print_error("Invalid smallbin number")
                return

        print_title("smallbins", end="")

        for sb in range(2, ptm.NBINS + 2, 2):
            if sb_num is not None and sb_num != 0:
                sb = sb_num*2

            offset = sb_base + (sb - 2) * ptm.SIZE_SZ
            try:
                mem = self.dbg.read_memory(offset, 2 * ptm.SIZE_SZ)
                if ptm.SIZE_SZ == 4:
                    fd, bk = struct.unpack("<II", mem)
                elif ptm.SIZE_SZ == 8:
                    fd, bk = struct.unpack("<QQ", mem)
            except RuntimeError:
                print_error("Invalid smallbin addr {0:#x}".format(offset))
                return

            print("")
            print("[ sb {:02} ] ".format(int(sb / 2)), end="")
            print("{:#x}{:>{width}}".format(int(offset), "-> ", width=5),
                  end="")
            if fd == (offset - 2 * ptm.SIZE_SZ):
                print("[ {:#x} | {:#x} ] ".format(int(fd), int(bk)), end="")
            else:
                print_value("[ {:#x} | {:#x} ] ".format(int(fd), int(bk)))

            while (1):
                if fd == (offset - 2 * ptm.SIZE_SZ):
                    break

                chunk = malloc_chunk(fd, inuse=False, debugger=self.dbg)
                print("")
                print_value("{:>{width}}{:#x} | {:#x} ] ".format("[ ",
                            int(chunk.fd), int(chunk.bk), width=pad_width))
                print("({})".format(int(ptm.chunksize(chunk))), end="")
                fd = chunk.fd

            if sb_num is not None:  # only print one smallbin
                break

        print("")
예제 #24
0
 def _gdb_is_running(*args, **kwargs):
     if (gdb.selected_thread() is not None):
         return f(*args, **kwargs)
     else:
         print_error("GDB is not running.")
예제 #25
0
 def _gdb_is_running(*args, **kwargs):
     if (gdb.selected_thread() is not None):
         return f(*args, **kwargs)
     else:
         print_error("GDB is not running.")
예제 #26
0
    def invoke(self, arg, from_tty):
        ptm = ptmalloc(debugger=self.dbg)

        if ptm.SIZE_SZ == 0:
            ptm.set_globals()

        if ptm.SIZE_SZ == 4:
            pad_width = 25
        elif ptm.SIZE_SZ == 8:
            pad_width = 29

        # XXX: from old heap command, replace
        main_arena = self.dbg.read_variable("main_arena")
        arena_address = self.dbg.format_address(main_arena.address)
        thread_arena = self.dbg.read_variable("thread_arena")
        if thread_arena is not None:
            thread_arena_address = self.dbg.format_address(thread_arena)
        else:
            thread_arena_address = arena_address

        argv = self.dbg.string_to_argv(arg)
        if len(argv) == 1:
            arena_address = int(argv[0], 16)
        elif len(argv):
            print_error('Too many arguments')
            return
        else:
            arena_address = thread_arena_address

        ar_ptr = malloc_state(arena_address,
                              debugger=self.dbg,
                              version=self.version)

        # 8 bytes into struct malloc_state on both 32/64bit
        # XXX: fixme for glibc <= 2.19 with THREAD_STATS
        fastbinsY = int(ar_ptr.address) + 8
        fb_base = fastbinsY

        print_title("fastbins", end="")

        for fb in range(0, ptm.NFASTBINS):
            offset = int(fb_base + fb * ptm.SIZE_SZ)
            try:
                mem = self.dbg.read_memory(offset, ptm.SIZE_SZ)
                if ptm.SIZE_SZ == 4:
                    fd = struct.unpack("<I", mem)[0]
                elif ptm.SIZE_SZ == 8:
                    fd = struct.unpack("<Q", mem)[0]
            except RuntimeError:
                print_error("Invalid fastbin addr {0:#x}".format(offset))
                return

            print("")
            print("[ fb {} ] ".format(fb), end="")
            print("{:#x}{:>{width}}".format(offset, "-> ", width=5), end="")
            if fd == 0:
                print("[ {:#x} ] ".format(fd), end="")
            else:
                print_value("[ {:#x} ] ".format(fd))

            if fd != 0:  # fastbin is not empty
                fb_size = ((ptm.MIN_CHUNK_SIZE) + (ptm.MALLOC_ALIGNMENT) * fb)
                print("({})".format(int(fb_size)), end="")

                chunk = malloc_chunk(fd, inuse=False, debugger=self.dbg)
                while chunk.fd != 0:
                    if chunk.fd is None:
                        # could not read memory section
                        break

                    print_value("\n{:>{width}} {:#x} {} ".format(
                        "[", chunk.fd, "]", width=pad_width))
                    print("({})".format(fb_size), end="")

                    chunk = malloc_chunk(chunk.fd,
                                         inuse=False,
                                         debugger=self.dbg)

        print("")
예제 #27
0
    def invoke(self, arg, from_tty):
        "Specify an optional arena addr: print_bin_layout main_arena=0x12345"

        ptm = ptmalloc(debugger=self.dbg)

        if ptm.SIZE_SZ == 0:
            ptm.set_globals()

        if len(arg) == 0:
            print_error("Please specify the free bin to dump")
            return

        try:
            if arg.find("main_arena") == -1:
                main_arena = self.dbg.read_variable("main_arena")
                main_arena_address = self.dbg.format_address(
                                                    main_arena.address)
            else:
                # XXX: fixme
                arg = arg.split()
                for item in arg:
                    if item.find("main_arena") != -1:
                        if len(item) < 12:
                            print_error("Malformed main_arena parameter")
                            return
                        else:
                            main_arena_address = int(item[11:], 16)
        except RuntimeError:
            print_error("No frame is currently selected.")
            return
        except ValueError:
            print_error("Debug glibc was not found.")
            return

        if main_arena_address == 0:
            print_error("Invalid main_arena address (0)")
            return

        ar_ptr = malloc_state(main_arena_address, debugger=self.dbg,
                              version=self.version)
        ptm.mutex_lock(ar_ptr)

        # print_title("Bin Layout")

        if int(arg) == 0:
            print_error("bin_at(0) does not exist")
            return

        b = ptm.bin_at(ar_ptr, int(arg))
        first = ptm.first(malloc_chunk(b, inuse=False, debugger=self.dbg))
        p = malloc_chunk(first, inuse=False, debugger=self.dbg)
        print_once = True
        print_str = ""
        count = 0

        while p.address != int(b):
            if print_once:
                print_once = False
                print_str += "-->  "
                print_str += color_value("[bin {}]".format(int(arg)))
                count += 1

            print_str += "  <-->  "
            print_str += color_value("{:#x}".format(int(p.address)))
            count += 1
            p = malloc_chunk(ptm.first(p), inuse=False, debugger=self.dbg)

        if len(print_str) != 0:
            print_str += "  <--"
            print(print_str)
            print("|{}|".format(" " * (len(print_str) - 2 - count*12)))
            print("{}".format("-" * (len(print_str) - count*12)))
        else:
            print_value("Bin {} ".format(int(arg)), end="")
            print("empty")

        ptm.mutex_unlock(ar_ptr)
예제 #28
0
    def invoke(self, arg, from_tty):
        if arg.find("-h") != -1:
            # print_header("heap ", end="")
            # print("Options:", end="\n\n")
            # print_header("{:<15}".format("-a 0x1234"))
            # print("Specify an arena address")
            print_header("{:<15}".format("heapls"))
            print("Print a flat listing of all chunks in an arena")
            print_header("{:<15}".format("fastbins [#]"))
            print("Print all fast bins, or only a single fast bin")
            print_header("{:<15}".format("smallbins [#]"))
            print("Print all small bins, or only a single small bin")
            print_header("{:<15}".format("freebins"))
            print("Print compact bin listing (only free chunks)")
            print_header("{:<15}".format("heaplsc"))
            print("Print compact arena listing (all chunks)")
            print_header("{:<15}".format("mstats"), end="")
            print("Print memory alloc statistics similar to malloc_stats(3)")
            # print_header("{:<22}".format("print_bin_layout [#]"), end="")
            # print("Print the layout of a particular free bin")
            return

        ptm = ptmalloc(self.dbg)

        if ptm.SIZE_SZ == 0:
            ptm.set_globals()

        # XXX: from old heap command, replace
        main_arena = self.dbg.read_variable("main_arena")
        # XXX: add arena address guessing via offset without symbols
        arena_address = self.dbg.format_address(main_arena.address)
        ar_ptr = malloc_state(arena_address,
                              debugger=self.dbg,
                              version=self.version)

        # XXX: add arena address passing via arg (-a)
        if (len(arg) == 0) and (ar_ptr.next == 0):
            # struct malloc_state may be invalid size (wrong glibc version)
            print_error("No arenas could be found at {:#x}".format(
                ar_ptr.address))
            return

        print("Arena(s) found:", end="\n")
        print("  arena @ ", end="")
        print_header("{:#x}".format(int(ar_ptr.address)), end="\n")

        if ar_ptr.address != ar_ptr.next:
            # we have more than one arena

            curr_arena = malloc_state(ar_ptr.next,
                                      debugger=self.dbg,
                                      version=self.version)

            while (ar_ptr.address != curr_arena.address):
                print("  arena @ ", end="")
                print_header("{:#x}".format(int(curr_arena.address)), end="\n")
                curr_arena = malloc_state(curr_arena.next,
                                          debugger=self.dbg,
                                          version=self.version)

                if curr_arena.address == 0:
                    print_error("No arenas could be correctly found.")
                    break  # breaking infinite loop
예제 #29
0
    def __init__(self, addr=None, mem=None, size=None, inuse=False,
                 read_data=True, debugger=None):
        self.prev_size = 0
        self.size = 0
        self.data = None
        self.fd = None
        self.bk = None
        self.fd_nextsize = None
        self.bk_nextsize = None

        if addr is None or addr == 0:
            if mem is None:
                print_error("Please specify a valid struct malloc_chunk addr.")
                return None

            self.address = None
        else:
            self.address = addr

        if debugger is not None:
            self.dbg = debugger
        else:
            print_error("Please specify a debugger")
            sys.exit()

        self.SIZE_SZ = self.dbg.get_size_sz()

        if mem is None:
            # a string of raw memory was not provided
            try:
                if self.SIZE_SZ == 4:
                    mem = self.dbg.read_memory(addr, 0x8)
                elif self.SIZE_SZ == 8:
                    mem = self.dbg.read_memory(addr, 0x10)
            except TypeError:
                print_error("Invalid address specified.")
                return None
            except RuntimeError:
                print_error("Could not read address {0:#x}".format(addr))
                return None
        else:
            # a string of raw memory was provided
            if inuse:
                if (len(mem) != 0x8) and (len(mem) < 0x10):
                    print_error("Insufficient mem provided for malloc_chunk.")
                    return None
                if len(mem) == 0x8 or len(mem) == 0x10:
                    # header only provided
                    read_data = False
            else:
                if (len(mem) != 0x18) and (len(mem) < 0x30):
                    print_error("Insufficient mem provided for a free chunk.")
                    return None

        if self.SIZE_SZ == 4:
            (self.prev_size, self.size) = struct.unpack_from("<II", mem, 0x0)
        elif self.SIZE_SZ == 8:
            (self.prev_size, self.size) = struct.unpack_from("<QQ", mem, 0x0)

        ptm = ptmalloc.ptmalloc.ptmalloc(debugger=self.dbg)

        if size is None:
            real_size = (self.size & ~ptm.SIZE_BITS)
        else:
            # a size was provided (for a malformed chunk with an invalid size)
            real_size = size & ~ptm.SIZE_BITS

        if inuse:
            if read_data:
                if self.address is not None:
                    # a string of raw memory was not provided
                    try:
                        mem = self.dbg.read_memory(addr, real_size +
                                                   self.SIZE_SZ)
                    except TypeError:
                        print_error("Invalid address specified.")
                        return None
                    except RuntimeError:
                        print_error("Could not read address {0:#x}".format(
                                    addr))
                        return None

                real_size = (real_size - self.SIZE_SZ) / self.SIZE_SZ
                if self.SIZE_SZ == 4:
                    self.data = struct.unpack_from("<%dI" % real_size, mem,
                                                   0x8)
                elif self.SIZE_SZ == 8:
                    self.data = struct.unpack_from("<%dQ" % real_size, mem,
                                                   0x10)

        if not inuse:
            if self.address is not None:
                # a string of raw memory was not provided
                if self.SIZE_SZ == 4:
                    mem = self.dbg.read_memory(addr, 0x18)
                elif self.SIZE_SZ == 8:
                    mem = self.dbg.read_memory(addr, 0x30)

            if self.SIZE_SZ == 4:
                (self.fd, self.bk, self.fd_nextsize,
                 self.bk_nextsize) = struct.unpack_from("<IIII", mem, 0x8)
            elif self.SIZE_SZ == 8:
                (self.fd, self.bk, self.fd_nextsize,
                 self.bk_nextsize) = struct.unpack_from("<QQQQ", mem, 0x10)
예제 #30
0
    def __init__(self,
                 addr=None,
                 mem=None,
                 size=None,
                 inuse=False,
                 read_data=True,
                 debugger=None):
        self.prev_size = 0
        self.size = 0
        self.data = None
        self.fd = None
        self.bk = None
        self.fd_nextsize = None
        self.bk_nextsize = None

        if addr is None or addr == 0:
            if mem is None:
                print_error("Please specify a valid struct malloc_chunk addr.")
                return None

            self.address = None
        else:
            self.address = addr

        if debugger is not None:
            self.dbg = debugger
        else:
            print_error("Please specify a debugger")
            sys.exit()

        self.SIZE_SZ = self.dbg.get_size_sz()

        if mem is None:
            # a string of raw memory was not provided
            try:
                if self.SIZE_SZ == 4:
                    mem = self.dbg.read_memory(addr, 0x8)
                elif self.SIZE_SZ == 8:
                    mem = self.dbg.read_memory(addr, 0x10)
            except TypeError:
                print_error("Invalid address specified.")
                return None
            except RuntimeError:
                print_error("Could not read address {0:#x}".format(addr))
                return None
        else:
            # a string of raw memory was provided
            if inuse:
                if (len(mem) != 0x8) and (len(mem) < 0x10):
                    print_error("Insufficient mem provided for malloc_chunk.")
                    return None
                if len(mem) == 0x8 or len(mem) == 0x10:
                    # header only provided
                    read_data = False
            else:
                if (len(mem) != 0x18) and (len(mem) < 0x30):
                    print_error("Insufficient mem provided for a free chunk.")
                    return None

        if self.SIZE_SZ == 4:
            (self.prev_size, self.size) = struct.unpack_from("<II", mem, 0x0)
        elif self.SIZE_SZ == 8:
            (self.prev_size, self.size) = struct.unpack_from("<QQ", mem, 0x0)

        ptm = ptmalloc.ptmalloc.ptmalloc(debugger=self.dbg)

        if size is None:
            real_size = (self.size & ~ptm.SIZE_BITS)
        else:
            # a size was provided (for a malformed chunk with an invalid size)
            real_size = size & ~ptm.SIZE_BITS

        if inuse:
            if read_data:
                if self.address is not None:
                    # a string of raw memory was not provided
                    try:
                        mem = self.dbg.read_memory(addr,
                                                   real_size + self.SIZE_SZ)
                    except TypeError:
                        print_error("Invalid address specified.")
                        return None
                    except RuntimeError:
                        print_error(
                            "Could not read address {0:#x}".format(addr))
                        return None

                real_size = (real_size - self.SIZE_SZ) / self.SIZE_SZ
                if self.SIZE_SZ == 4:
                    self.data = struct.unpack_from("<%dI" % real_size, mem,
                                                   0x8)
                elif self.SIZE_SZ == 8:
                    self.data = struct.unpack_from("<%dQ" % real_size, mem,
                                                   0x10)

        if not inuse:
            if self.address is not None:
                # a string of raw memory was not provided
                if self.SIZE_SZ == 4:
                    mem = self.dbg.read_memory(addr, 0x18)
                elif self.SIZE_SZ == 8:
                    mem = self.dbg.read_memory(addr, 0x30)

            if self.SIZE_SZ == 4:
                (self.fd, self.bk, self.fd_nextsize,
                 self.bk_nextsize) = struct.unpack_from("<IIII", mem, 0x8)
            elif self.SIZE_SZ == 8:
                (self.fd, self.bk, self.fd_nextsize,
                 self.bk_nextsize) = struct.unpack_from("<QQQQ", mem, 0x10)
예제 #31
0
    def invoke(self, arg, from_tty):
        "Specify an optional arena addr: print_bin_layout main_arena=0x12345"

        ptm = ptmalloc(debugger=self.dbg)

        if ptm.SIZE_SZ == 0:
            ptm.set_globals()

        if len(arg) == 0:
            print_error("Please specify the free bin to dump")
            return

        try:
            if arg.find("main_arena") == -1:
                main_arena = self.dbg.read_variable("main_arena")
                main_arena_address = self.dbg.format_address(
                    main_arena.address)
            else:
                # XXX: fixme
                arg = arg.split()
                for item in arg:
                    if item.find("main_arena") != -1:
                        if len(item) < 12:
                            print_error("Malformed main_arena parameter")
                            return
                        else:
                            main_arena_address = int(item[11:], 16)
        except RuntimeError:
            print_error("No frame is currently selected.")
            return
        except ValueError:
            print_error("Debug glibc was not found.")
            return

        if main_arena_address == 0:
            print_error("Invalid main_arena address (0)")
            return

        ar_ptr = malloc_state(main_arena_address,
                              debugger=self.dbg,
                              version=self.version)
        ptm.mutex_lock(ar_ptr)

        # print_title("Bin Layout")

        if int(arg) == 0:
            print_error("bin_at(0) does not exist")
            return

        b = ptm.bin_at(ar_ptr, int(arg))
        first = ptm.first(malloc_chunk(b, inuse=False, debugger=self.dbg))
        p = malloc_chunk(first, inuse=False, debugger=self.dbg)
        print_once = True
        print_str = ""
        count = 0

        while p.address != int(b):
            if print_once:
                print_once = False
                print_str += "-->  "
                print_str += color_value("[bin {}]".format(int(arg)))
                count += 1

            print_str += "  <-->  "
            print_str += color_value("{:#x}".format(int(p.address)))
            count += 1
            p = malloc_chunk(ptm.first(p), inuse=False, debugger=self.dbg)

        if len(print_str) != 0:
            print_str += "  <--"
            print(print_str)
            print("|{}|".format(" " * (len(print_str) - 2 - count * 12)))
            print("{}".format("-" * (len(print_str) - count * 12)))
        else:
            print_value("Bin {} ".format(int(arg)), end="")
            print("empty")

        ptm.mutex_unlock(ar_ptr)
예제 #32
0
    def invoke(self, arg, from_tty):
        ptm = ptmalloc(debugger=self.dbg)

        if ptm.SIZE_SZ == 0:
            ptm.set_globals()

        if ptm.SIZE_SZ == 4:
            pad_width = 27
        elif ptm.SIZE_SZ == 8:
            pad_width = 31

        # XXX: from old heap command, replace
        main_arena = self.dbg.read_variable("main_arena")
        arena_address = self.dbg.format_address(main_arena.address)
        ar_ptr = malloc_state(arena_address, debugger=self.dbg,
                              version=self.version)

        # mchunkptr bins in struct malloc_state
        sb_base = int(ar_ptr.address) + ar_ptr.bins_offset

        if len(arg) == 0:
            sb_num = None
        else:
            sb_num = int(arg.split(" ")[0])

            if (sb_num * 2) > ptm.NBINS:
                print_error("Invalid smallbin number")
                return

        print_title("smallbins", end="")

        for sb in range(2, ptm.NBINS + 2, 2):
            if sb_num is not None and sb_num != 0:
                sb = sb_num*2

            offset = sb_base + (sb - 2) * ptm.SIZE_SZ
            try:
                mem = self.dbg.read_memory(offset, 2 * ptm.SIZE_SZ)
                if ptm.SIZE_SZ == 4:
                    fd, bk = struct.unpack("<II", mem)
                elif ptm.SIZE_SZ == 8:
                    fd, bk = struct.unpack("<QQ", mem)
            except RuntimeError:
                print_error("Invalid smallbin addr {0:#x}".format(offset))
                return

            print("")
            print("[ sb {:02} ] ".format(int(sb / 2)), end="")
            print("{:#x}{:>{width}}".format(int(offset), "-> ", width=5),
                  end="")
            if fd == (offset - 2 * ptm.SIZE_SZ):
                print("[ {:#x} | {:#x} ] ".format(int(fd), int(bk)), end="")
            else:
                print_value("[ {:#x} | {:#x} ] ".format(int(fd), int(bk)))

            while (1):
                if fd == (offset - 2 * ptm.SIZE_SZ):
                    break

                chunk = malloc_chunk(fd, inuse=False, debugger=self.dbg)
                print("")
                print_value("{:>{width}}{:#x} | {:#x} ] ".format("[ ",
                            int(chunk.fd), int(chunk.bk), width=pad_width))
                print("({})".format(int(ptm.chunksize(chunk))), end="")
                fd = chunk.fd

            if sb_num is not None:  # only print one smallbin
                break

        print("")
예제 #33
0
    def __init__(self, addr=None, mem=None, debugger=None, version=None):
        self.size = 0
        self.mutex = 0
        self.flags = 0
        self.fastbinsY = 0
        self.top = 0
        self.last_remainder = 0
        self.bins = 0
        self.binmap = 0
        self.next = 0
        self.next_free = 0
        # self.attached_threads = 0
        self.system_mem = 0
        self.max_system_mem = 0

        if addr is None:
            if mem is None:
                print_error("Please specify a struct malloc_state address.")
                return None

            self.address = None
        else:
            self.address = addr

        if debugger is not None:
            self.dbg = debugger
        else:
            print_error("Please specify a debugger")
            sys.exit()

        self.size_sz = self.dbg.get_size_sz()

        if version is None:
            print_error("Please specify a malloc_state version.")
            sys.exit()
        else:
            self.version = version

        if mem is None:
            # a string of raw memory was not provided
            if self.version >= 2.15 and self.version < 2.23:
                if self.size_sz == 4:
                    # sizeof(malloc_state) = 4+4+40+4+4+(254*4)+16+4+4+4+4
                    self.size = 0x450
                elif self.size_sz == 8:
                    # sizeof(malloc_state) = 4+4+80+8+8+(254*8)+16+8+8+8+8
                    self.size = 0x888
            elif self.version >= 2.23 and self.version <= 2.25:
                # attached_threads added in 2.23
                if self.size_sz == 4:
                    self.size = 0x454
                elif self.size_sz == 8:
                    self.size = 0x890

            try:
                self.mem = self.dbg.read_memory(addr, self.size)
            except TypeError:
                print_error("Invalid address specified.")
                return None
            except RuntimeError:
                print_error("Could not read address {0:#x}".format(addr))
                return None
        else:
            # XXX: fix class size
            # self.size = len(mem)
            self.mem = mem

        self.unpack_memory()
예제 #34
0
    def invoke(self, arg, from_tty):
        "Specify an optional arena addr: print_mstats main_arena=0x12345"

        ptm = ptmalloc(debugger=self.dbg)

        if ptm.SIZE_SZ == 0:
            ptm.set_globals()

        try:
            # XXX: add mp_ address guessing via offset without symbols
            mp = self.dbg.read_variable("mp_")

            if arg.find("main_arena") == -1:
                main_arena = self.dbg.read_variable("main_arena")
                main_arena_address = self.dbg.format_address(
                                                main_arena.address)
            else:
                arg = arg.split()
                for item in arg:
                    if item.find("main_arena") != -1:
                        if len(item) < 12:
                            print_error("Malformed main_arena parameter")
                            return
                        else:
                            main_arena_address = int(item[11:], 16)
        except RuntimeError:
            print_error("No frame is currently selected.")
            return
        except ValueError:
            print_error("Debug glibc was not found.")
            return

        if main_arena_address == 0:
            print_error("Invalid main_arena address (0)")
            return

        in_use_b = mp['mmapped_mem']
        system_b = in_use_b

        print("Malloc Stats", end="\n\n")

        arena = 0
        ar_ptr = malloc_state(main_arena_address, debugger=self.dbg,
                              version=self.version)
        while(1):
            ptm.mutex_lock(ar_ptr)

            # account for top
            avail = ptm.chunksize(malloc_chunk(ptm.top(ar_ptr), inuse=True,
                                  read_data=False, debugger=self.dbg))
            nblocks = 1

            nfastblocks = 0
            fastavail = 0

            # traverse fastbins
            for i in range(ptm.NFASTBINS):
                p = ptm.fastbin(ar_ptr, i)
                while p != 0:
                    p = malloc_chunk(p, inuse=False, debugger=self.dbg)
                    nfastblocks += 1
                    fastavail += ptm.chunksize(p)
                    p = p.fd

            avail += fastavail

            # traverse regular bins
            for i in range(1, ptm.NBINS):
                b = ptm.bin_at(ar_ptr, i)
                first = malloc_chunk(b, inuse=False, debugger=self.dbg)
                first = ptm.first(first)
                p = malloc_chunk(first, inuse=False, debugger=self.dbg)

                while p.address != int(b):
                    nblocks += 1
                    avail += ptm.chunksize(p)
                    p = malloc_chunk(ptm.first(p), inuse=False,
                                     debugger=self.dbg)

            print_header("Arena {}:".format(arena), end="\n")
            print("{:16} = ".format("system bytes"), end='')
            print_value("{}".format(ar_ptr.max_system_mem), end='\n')
            print("{:16} = ".format("in use bytes"), end='')
            print_value("{}".format(ar_ptr.max_system_mem - avail), end='\n')

            system_b += ar_ptr.max_system_mem
            in_use_b += (ar_ptr.max_system_mem - avail)

            ptm.mutex_unlock(ar_ptr)
            if ar_ptr.next == main_arena_address:
                break
            else:
                next_addr = self.dbg.format_address(ar_ptr.next)
                ar_ptr = malloc_state(next_addr, debugger=self.dbg,
                                      version=self.version)
                arena += 1

        print_header("\nTotal (including mmap):", end="\n")
        print("{:16} = ".format("system bytes"), end='')
        print_value("{}".format(system_b), end='\n')
        print("{:16} = ".format("in use bytes"), end='')
        print_value("{}".format(in_use_b), end='\n')

        # XXX: max_total_mem removed in 2.24
        try:
            # catch the error before we print anything
            val = mp['max_total_mem']

            print("{:16} = ".format("max system bytes"), end='')
            print_value("{}".format(val), end='\n')
        except gdb.error:
            pass

        print("{:16} = ".format("max mmap regions"), end='')
        print_value("{}".format(mp['max_n_mmaps']), end='\n')
        print("{:16} = ".format("max mmap bytes"), end='')
        print_value("{}".format(mp['max_mmapped_mem']), end='\n')
예제 #35
0
    def invoke(self, arg, from_tty):
        ptm = ptmalloc(debugger=self.dbg)

        if ptm.SIZE_SZ == 0:
            ptm.set_globals()

        if ptm.SIZE_SZ == 4:
            pad_width = 25
        elif ptm.SIZE_SZ == 8:
            pad_width = 29

        # XXX: from old heap command, replace
        main_arena = self.dbg.read_variable("main_arena")
        arena_address = self.dbg.format_address(main_arena.address)
        thread_arena = self.dbg.read_variable("thread_arena")
        if thread_arena is not None:
            thread_arena_address = self.dbg.format_address(thread_arena)
        else:
            thread_arena_address = arena_address

        argv = self.dbg.string_to_argv(arg)
        if len(argv) == 1:
            arena_address = int(argv[0], 16)
        elif len(argv):
            print_error('Too many arguments')
            return
        else:
            arena_address = thread_arena_address

        ar_ptr = malloc_state(arena_address, debugger=self.dbg,
                              version=self.version)

        # 8 bytes into struct malloc_state on both 32/64bit
        # XXX: fixme for glibc <= 2.19 with THREAD_STATS
        fastbinsY = int(ar_ptr.address) + 8
        fb_base = fastbinsY

        print_title("fastbins", end="")

        for fb in range(0, ptm.NFASTBINS):
            offset = int(fb_base + fb * ptm.SIZE_SZ)
            try:
                mem = self.dbg.read_memory(offset, ptm.SIZE_SZ)
                if ptm.SIZE_SZ == 4:
                    fd = struct.unpack("<I", mem)[0]
                elif ptm.SIZE_SZ == 8:
                    fd = struct.unpack("<Q", mem)[0]
            except RuntimeError:
                print_error("Invalid fastbin addr {0:#x}".format(offset))
                return

            print("")
            print("[ fb {} ] ".format(fb), end="")
            print("{:#x}{:>{width}}".format(offset, "-> ", width=5), end="")
            if fd == 0:
                print("[ {:#x} ] ".format(fd), end="")
            else:
                print_value("[ {:#x} ] ".format(fd))

            if fd != 0:  # fastbin is not empty
                fb_size = ((ptm.MIN_CHUNK_SIZE) + (ptm.MALLOC_ALIGNMENT) * fb)
                print("({})".format(int(fb_size)), end="")

                chunk = malloc_chunk(fd, inuse=False, debugger=self.dbg)
                while chunk.fd != 0:
                    if chunk.fd is None:
                        # could not read memory section
                        break

                    print_value("\n{:>{width}} {:#x} {} ".format("[",
                                chunk.fd, "]", width=pad_width))
                    print("({})".format(fb_size), end="")

                    chunk = malloc_chunk(chunk.fd, inuse=False,
                                         debugger=self.dbg)

        print("")
예제 #36
0
    def invoke(self, arg, from_tty):
        "Specify an optional arena addr: print_mstats main_arena=0x12345"

        ptm = ptmalloc(debugger=self.dbg)

        if ptm.SIZE_SZ == 0:
            ptm.set_globals()

        try:
            # XXX: add mp_ address guessing via offset without symbols
            mp = self.dbg.read_variable("mp_")

            if arg.find("main_arena") == -1:
                main_arena = self.dbg.read_variable("main_arena")
                main_arena_address = self.dbg.format_address(
                    main_arena.address)
            else:
                arg = arg.split()
                for item in arg:
                    if item.find("main_arena") != -1:
                        if len(item) < 12:
                            print_error("Malformed main_arena parameter")
                            return
                        else:
                            main_arena_address = int(item[11:], 16)
        except RuntimeError:
            print_error("No frame is currently selected.")
            return
        except ValueError:
            print_error("Debug glibc was not found.")
            return

        if main_arena_address == 0:
            print_error("Invalid main_arena address (0)")
            return

        in_use_b = mp['mmapped_mem']
        system_b = in_use_b

        print("Malloc Stats", end="\n\n")

        arena = 0
        ar_ptr = malloc_state(main_arena_address,
                              debugger=self.dbg,
                              version=self.version)
        while (1):
            ptm.mutex_lock(ar_ptr)

            # account for top
            avail = ptm.chunksize(
                malloc_chunk(ptm.top(ar_ptr),
                             inuse=True,
                             read_data=False,
                             debugger=self.dbg))
            nblocks = 1

            nfastblocks = 0
            fastavail = 0

            # traverse fastbins
            for i in range(ptm.NFASTBINS):
                p = ptm.fastbin(ar_ptr, i)
                while p != 0:
                    p = malloc_chunk(p, inuse=False, debugger=self.dbg)
                    nfastblocks += 1
                    fastavail += ptm.chunksize(p)
                    p = p.fd

            avail += fastavail

            # traverse regular bins
            for i in range(1, ptm.NBINS):
                b = ptm.bin_at(ar_ptr, i)
                first = malloc_chunk(b, inuse=False, debugger=self.dbg)
                first = ptm.first(first)
                p = malloc_chunk(first, inuse=False, debugger=self.dbg)

                while p.address != int(b):
                    nblocks += 1
                    avail += ptm.chunksize(p)
                    p = malloc_chunk(ptm.first(p),
                                     inuse=False,
                                     debugger=self.dbg)

            print_header("Arena {}:".format(arena), end="\n")
            print("{:16} = ".format("system bytes"), end='')
            print_value("{}".format(ar_ptr.max_system_mem), end='\n')
            print("{:16} = ".format("in use bytes"), end='')
            print_value("{}".format(ar_ptr.max_system_mem - avail), end='\n')

            system_b += ar_ptr.max_system_mem
            in_use_b += (ar_ptr.max_system_mem - avail)

            ptm.mutex_unlock(ar_ptr)
            if ar_ptr.next == main_arena_address:
                break
            else:
                next_addr = self.dbg.format_address(ar_ptr.next)
                ar_ptr = malloc_state(next_addr,
                                      debugger=self.dbg,
                                      version=self.version)
                arena += 1

        print_header("\nTotal (including mmap):", end="\n")
        print("{:16} = ".format("system bytes"), end='')
        print_value("{}".format(system_b), end='\n')
        print("{:16} = ".format("in use bytes"), end='')
        print_value("{}".format(in_use_b), end='\n')

        # XXX: max_total_mem removed in 2.24
        try:
            # catch the error before we print anything
            print_value("{}".format(mp['max_total_mem']), end='\n')
            print("{:16} = ".format("max system bytes"), end='')
        except gdb.error:
            pass

        print("{:16} = ".format("max mmap regions"), end='')
        print_value("{}".format(mp['max_n_mmaps']), end='\n')
        print("{:16} = ".format("max mmap bytes"), end='')
        print_value("{}".format(mp['max_mmapped_mem']), end='\n')