def jeparse_general(): global jeheap try: jeheap.narenas = gdbutil.to_int(gdb.parse_and_eval('narenas')) except RuntimeError: print '[unmask_jemalloc] error: symbol narenas not found' sys.exit() try: jeheap.nbins = gdbutil.to_int(gdb.parse_and_eval('nbins')) except RuntimeError: # XXX: these are firefox specific, we must add support for more # jemalloc variants in the future if sys.platform == 'darwin': jeheap.nbins = 35 else: if jeheap.DWORD_SIZE == 4: jeheap.nbins = 24 elif jeheap.DWORD_SIZE == 8: jeheap.nbins = 23 # XXX: figure out how to calculate the chunk size correctly, this is # firefox specific jeheap.chunk_size = 1 << 20
def jeparse_general(): global jeheap try: jeheap.narenas = gdbutil.to_int(gdb.parse_and_eval('narenas')) except RuntimeError: print('[unmask_jemalloc] error: symbol narenas not found') sys.exit() try: jeheap.nbins = gdbutil.to_int(gdb.parse_and_eval('nbins')) except RuntimeError: # XXX: these are firefox specific, we must add support for more # jemalloc variants in the future if sys.platform == 'darwin': jeheap.ntbins = gdbutil.to_int(gdb.parse_and_eval('ntbins')) jeheap.nsbins = gdbutil.to_int(gdb.parse_and_eval('nsbins')) jeheap.nqbins = gdbutil.to_int(gdb.parse_and_eval('nqbins')) jeheap.nbins = jeheap.ntbins + jeheap.nsbins + jeheap.nqbins else: if jeheap.DWORD_SIZE == 4: jeheap.nbins = 36 elif jeheap.DWORD_SIZE == 8: jeheap.nbins = 35 # XXX: figure out how to calculate the chunk size correctly, this is # firefox specific jeheap.chunk_size = 1 << 20
def jeparse_chunks(): global jeheap # delete the chunks' list jeheap.chunks[:] = [] try: root = gdbutil.to_int(gdb.parse_and_eval('chunk_rtree.root')) height = gdbutil.to_int(gdb.parse_and_eval('chunk_rtree.height')) level2bits = [] for i in range(0, height): expr = 'chunk_rtree.level2bits[%d]' % (i) level2bits.append(gdbutil.to_int(gdb.parse_and_eval(expr))) except: print('[unmask_jemalloc] error: cannot parse chunk radix tree') sys.exit() # check if we're running on x86_64 if jeheap.DWORD_SIZE == 8: dw_fmt = 'g' else: dw_fmt = 'w' # parse the radix tree using a stack stack = [(root, 0)] while len(stack): (node, node_height) = stack.pop() child_cnt = 1 << level2bits[node_height] dump = gdb.execute('x/%d%sx %#x' % (child_cnt, dw_fmt, node), to_string=true) for line in dump.split('\n'): line = line[line.find(':') + 1:] for address in line.split(): address = int(address, 16) if address != 0: # leaf nodes hold pointers to actual values if node_height == height - 1: expr = '((arena_chunk_t *)%#x)->arena' % address arena = gdbutil.to_int(gdb.parse_and_eval(expr)) exists = false if arena in [i.addr for i in jeheap.arenas]: exists = true if exists: jeheap.chunks.append( jemalloc.arena_chunk(address, arena)) else: jeheap.chunks.append(jemalloc.arena_chunk(address)) # non-leaf nodes are inserted in the stack else: stack.append((address, node_height + 1))
def jeparse_chunks(): global jeheap # delete the chunks' list jeheap.chunks = [] try: root = gdbutil.to_int(gdb.parse_and_eval('chunk_rtree.root')) height = gdbutil.to_int(gdb.parse_and_eval('chunk_rtree.height')) level2bits = [] for i in range(0, height): expr = 'chunk_rtree.level2bits[%d]' % (i) level2bits.append(gdbutil.to_int(gdb.parse_and_eval(expr))) except: print '[unmask_jemalloc] error: cannot parse chunk radix tree' sys.exit() # check if we're running on x86_64 if jeheap.DWORD_SIZE == 8: dw_fmt = 'g' else: dw_fmt = 'w' # parse the radix tree using a stack stack = [(root, 0)] while len(stack): (node, node_height) = stack.pop() child_cnt = 1 << level2bits[node_height] dump = gdb.execute('x/%d%sx %#x' % (child_cnt, dw_fmt, node), to_string = true) for line in dump.split('\n'): line = line[line.find(':') + 1:] for address in line.split(): address = int(address, 16) if address != 0: # leaf nodes hold pointers to actual values if node_height == height - 1: expr = '((arena_chunk_t *)%#x)->arena' % address arena = gdbutil.to_int(gdb.parse_and_eval(expr)) exists = false if arena in [i.addr for i in jeheap.arenas]: exists = true if exists: jeheap.chunks.append(jemalloc.arena_chunk(address, arena)) else: jeheap.chunks.append(jemalloc.arena_chunk(address)) # non-leaf nodes are inserted in the stack else: stack.append((address, node_height + 1))
def jeparse_options(): global jeheap opt_tcache = gdb.parse_and_eval('je_opt_tcache') if opt_tcache != 0: jeheap.MAGAZINES = true try: expr = 'sizeof(mag_rack_t) + (sizeof(bin_mags_t) * (jeheap.nbins - 1))' jeheap.magrack_size = gdbutil.to_int(gdb.parse_and_eval(expr)) except RuntimeError: # standalone variant jeheap.STANDALONE = true expr = 'sizeof(tcache_t) + (sizeof(tcache_bin_t) * %d)' % (jeheap.nbins - 1) jemalloc.magrack_size = gdbutil.to_int(gdb.parse_and_eval(expr))
def jeparse_general(): global jeheap try: jeheap.narenas = gdbutil.to_int(gdb.parse_and_eval('narenas')) except RuntimeError: print('[unmask_jemalloc] error: symbol narenas not found') sys.exit() if LG_SIZEOF_PTR == 2 and LG_TINY_MIN == 3 and LG_QUANTUM == 3 and LG_PAGE == 12: jeheap.ntbins = 0 jeheap.nlbins = 32 jeheap.nbins = 39 jeheap.NSIZES = 107 elif LG_SIZEOF_PTR == 2 and LG_TINY_MIN == 3 and LG_QUANTUM == 4 and LG_PAGE == 12: jeheap.ntbins = 1 jeheap.nlbins = 29 jeheap.nbins = 36 jeheap.NSIZES = 104 elif LG_SIZEOF_PTR == 2 and LG_TINY_MIN == 4 and LG_QUANTUM == 4 and LG_PAGE == 12: jeheap.ntbins = 0 jeheap.nlbins = 28 jeheap.nbins = 35 jeheap.NSIZES = 103 elif LG_SIZEOF_PTR == 3 and LG_TINY_MIN == 3 and LG_QUANTUM == 3 and LG_PAGE == 12: jeheap.ntbins = 0 jeheap.nlbins = 32 jeheap.nbins = 39 jeheap.NSIZES = 235 elif LG_SIZEOF_PTR == 3 and LG_TINY_MIN == 3 and LG_QUANTUM == 4 and LG_PAGE == 12: jeheap.ntbins = 1 jeheap.nlbins = 29 jeheap.nbins = 36 jeheap.NSIZES = 232 elif LG_SIZEOF_PTR == 3 and LG_TINY_MIN == 4 and LG_QUANTUM == 4 and LG_PAGE == 12: jeheap.ntbins = 0 jeheap.nlbins = 28 jeheap.nbins = 35 jeheap.NSIZES = 231 else: print("[unmask_jemalloc] error: configuation not specified!") sys.exit() # usually 1<<21 jeheap.chunk_size = gdbutil.to_int(gdb.parse_and_eval('je_chunksize'))
def jeparse_options(): global jeheap # thread magazine caches (disabled on firefox) try: opt_mag = gdb.parse_and_eval('opt_mag') except RuntimeError: opt_mag = 0 try: opt_tcache = gdb.parse_and_eval('opt_tcache') except RuntimeError: opt_tcache = 0 try: opt_lg_tcache_nslots = \ gdb.parse_and_eval('opt_lg_tcache_nslots') except RuntimeError: opt_lg_tcache_nslots = 0 if opt_mag != 0 or opt_tcache != 0 or opt_lg_tcache_nslots != 0: jeheap.MAGAZINES = true if jeheap.MAGAZINES == true: try: expr = 'sizeof(mag_rack_t) + (sizeof(bin_mags_t) * (jeheap.nbins - 1))' jeheap.magrack_size = \ gdbutil.to_int(gdb.parse_and_eval(expr)) except RuntimeError: # standalone variant jeheap.STANDALONE = true expr = 'sizeof(tcache_t) + (sizeof(tcache_bin_t) * (jeheap.nbins - 1))' jemalloc.magrack_size = \ gdbutil.to_int(gdb.parse_and_eval())
def jeparse_options(): global jeheap # thread magazine caches (disabled on firefox) try: opt_mag = gdb.parse_and_eval('opt_mag') except RuntimeError: opt_mag = 0 try: opt_tcache = gdb.parse_and_eval('opt_tcache') except RuntimeError: opt_tcache = 0 try: opt_lg_tcache_nslots = \ gdb.parse_and_eval('opt_lg_tcache_nslots') except RuntimeError: opt_lg_tcache_nslots = 0 if opt_mag != 0 or opt_tcache != 0 or opt_lg_tcache_nslots != 0: jeheap.MAGAZINES = true if jeheap.MAGAZINES == true: try: expr = 'sizeof(mag_rack_t) + (sizeof(bin_mags_t) * (jeheap.nbins - 1))' jeheap.magrack_size = \ gdbutil.to_int(gdb.parse_and_eval(expr)) except RuntimeError: # standalone variant jeheap.STANDALONE = true expr = 'sizeof(tcache_t) + (sizeof(tcache_bin_t) * (jeheap.nbins - 1))' jemalloc.magrack_size = \ gdbutil.to_int(gdb.parse_and_eval(expr))
def jeparse_arenas(): global jeheap jeheap.arenas[:] = [] for i in range(0, jeheap.narenas): current_arena = jemalloc.arena(0, i, []) try: current_arena.addr = \ gdbutil.to_int(gdb.parse_and_eval('arenas[%d]' % (i))) except: print '[unmask_jemalloc] error: cannot evaluate arenas[%d]' % (i) sys.exit() for j in range(0, jeheap.nbins): nrg = 0 run_sz = 0 reg_size = 0 reg_offset = 0 end_addr = 0 try: expr = 'arenas[%d].bins[%d].reg_size' % (i, j) reg_size = \ gdbutil.to_int(gdb.parse_and_eval(expr)) expr = 'arenas[%d].bins[%d].reg0_offset' % (i, j) reg_offset = \ gdbutil.to_int(gdb.parse_and_eval(expr)) except RuntimeError: # XXX: for now assume it's a standalone variant; we # need to do some error checking here too. jeheap.STANDALONE = true expr = 'arena_bin_info[%d].reg_size' % (j) reg_size = \ gdbutil.to_int(gdb.parse_and_eval(expr)) expr = 'arena_bin_info[%d].nregs' % (j) nrg = \ gdbutil.to_int(gdb.parse_and_eval(expr)) expr = 'arena_bin_info[%d].run_size' % (j) run_sz = \ gdbutil.to_int(gdb.parse_and_eval(expr)) try: expr = 'arenas[%d].bins[%d].runcur' % (i, j) runcur_addr = runcur = \ gdbutil.to_int(gdb.parse_and_eval(expr)) end_addr = runcur_addr + run_sz if runcur != 0: current_run = \ jemalloc.arena_run(runcur, end_addr, run_sz, 0, \ int(reg_size), reg_offset, nrg, 0, []) current_bin = jemalloc.arena_bin(0, j, current_run) current_bin.addr = \ gdbutil.to_int(gdb.parse_and_eval('&arenas[%d].bins[%d]' % (i, j))) current_arena.bins.append(current_bin) else: # no regions for this size class yet, therefore no runcur current_run = jemalloc.arena_run() current_bin = jemalloc.arena_bin(0, j, current_run) current_arena.bins.append(current_bin) except RuntimeError: current_run = jemalloc.arena_run() current_bin = jemalloc.arena_bin(0, j, current_run) current_arena.bins.append(current_bin) continue # add arena to the list of arenas jeheap.arenas.append(current_arena)
def jeparse_arenas(): global jeheap jeheap.arenas[:] = [] for i in range(0, jeheap.narenas): current_arena = jemalloc.arena(0, i, []) try: current_arena.addr = \ gdbutil.to_int(gdb.parse_and_eval('arenas[%d]' % (i))) except: print('[unmask_jemalloc] error: cannot evaluate arenas[%d]') % (i) sys.exit() for j in range(0, jeheap.nbins): nrg = 0 run_sz = 0 reg_size = 0 reg_offset = 0 end_addr = 0 try: expr = 'arenas[%d].bins[%d].reg_size' % (i, j) reg_size = \ gdbutil.to_int(gdb.parse_and_eval(expr)) expr = 'arenas[%d].bins[%d].reg0_offset' % (i, j) reg_offset = \ gdbutil.to_int(gdb.parse_and_eval(expr)) except RuntimeError: # XXX: for now assume it's a standalone variant; we # need to do some error checking here too. jeheap.STANDALONE = true expr = 'arena_bin_info[%d].reg_size' % (j) reg_size = \ gdbutil.to_int(gdb.parse_and_eval(expr)) expr = 'arena_bin_info[%d].nregs' % (j) nrg = \ gdbutil.to_int(gdb.parse_and_eval(expr)) expr = 'arena_bin_info[%d].run_size' % (j) run_sz = \ gdbutil.to_int(gdb.parse_and_eval(expr)) try: expr = 'arenas[%d].bins[%d].runcur' % (i, j) runcur_addr = runcur = \ gdbutil.to_int(gdb.parse_and_eval(expr)) end_addr = runcur_addr + run_sz if runcur != 0: current_run = \ jemalloc.arena_run(runcur, end_addr, run_sz, 0, \ int(reg_size), reg_offset, nrg, 0, []) current_bin = jemalloc.arena_bin(0, j, current_run) current_bin.addr = \ gdbutil.to_int(gdb.parse_and_eval('&arenas[%d].bins[%d]' % (i, j))) current_arena.bins.append(current_bin) else: # no regions for this size class yet, therefore no runcur current_run = jemalloc.arena_run() current_bin = jemalloc.arena_bin(0, j, current_run) current_arena.bins.append(current_bin) except RuntimeError: current_run = jemalloc.arena_run() current_bin = jemalloc.arena_bin(0, j, current_run) current_arena.bins.append(current_bin) continue # add arena to the list of arenas jeheap.arenas.append(current_arena)
def jeparse_all_runs(proc): global jeheap # number of pages a chunk occupies chunk_npages = gdbutil.to_int(gdb.parse_and_eval("je_chunk_npages")) # offset of bits in arena_chunk_map_t in double words bitmap_offset = \ gdbutil.offsetof('arena_chunk_map_bits_t', 'bits') / jeheap.DWORD_SIZE # number of double words occupied by an arena_chunk_map_t chunk_map_dwords = (bitmap_offset / jeheap.DWORD_SIZE) + 1 # prefix to use in gdb's examine command if jeheap.DWORD_SIZE == 8: dword_fmt = 'g' else: dword_fmt = 'w' # the 12 least significant bits of each bitmap entry hold # various flags for the corresponding run flags_mask = (1 << 13) - 1 # delete the heap's runs' array jeheap.runs[:] = [] for chunk in jeheap.chunks: if not chunk.arena: continue try: # parse the whole map at once to avoid gdb delays expr = 'x/%d%sx ((arena_chunk_t *)%#x)->map_bits' % \ (chunk_npages * chunk_map_dwords, dword_fmt, chunk.addr) except: print('[unmask_jemalloc] error: cannot read bitmap from chunk %#x' % (chunk.addr)) sys.exit() lines = (gdb.execute(expr, to_string = true)).split('\n') dwords = [] i = 0 for line in lines: dwords += [int(dw, 16) for dw in line[line.find(':') + 1:].split()] bitmap = [dwords[i] for i in range(int(bitmap_offset), \ int(len(dwords)), int(bitmap_offset + 1))] # traverse the bitmap for mapelm in bitmap: flags = mapelm & flags_mask # flags == 1 means the chunk is small and the rest of the bits # hold the actual run address if flags == 1: addr = mapelm & ~flags_mask size = gdbutil.get_page_size() # flags = 3 indicates a large chunk; calculate the run's address # directly from the map element index and extract the run's size elif flags == 3: addr = chunk.addr + i * gdbutil.get_page_size() size = mapelm & ~flags_mask # run is not allocated? skip it else: continue if addr not in [r.start for r in jeheap.runs]: # XXX: we need to parse run headers here with a # dedicated function new_run = jemalloc.arena_run(addr, 0, size, 0, 0, 0, 0, 0, []) jeheap.runs.append(new_run)
def jeparse_chunks(): global jeheap # delete the chunks' list jeheap.chunks[:] = [] try: height = gdbutil.to_int(gdb.parse_and_eval('je_chunks_rtree.height')) except: print('[unmask_jemalloc] error: cannot parse chunk radix tree') sys.exit() # check if we're running on x86_64 # TODO: make it global if jeheap.DWORD_SIZE == 8: dw_fmt = 'g' else: dw_fmt = 'w' # insert root node to stack first (on level[0]) stack = [] for level in range(0, 3): bits = gdbutil.to_int(gdb.parse_and_eval('je_chunks_rtree.levels[%d].bits' % (level))) for bit in range(0, bits): try: subtree = gdbutil.to_int(gdb.parse_and_eval('je_chunks_rtree.levels[%d].subtree[%d]' %(level, bit))) print(subtree) if subtree == 0: continue except: continue print("f****d!") while len(stack): (node, node_height) = stack.pop() child_cnt = gdbutil.to_int(node.bits) dump = gdb.execute('x/%d%sx %#x' % (child_cnt, dw_fmt, node), to_string = true) print(dump) print('--------') for line in dump.split('\n'): line = line[line.find(':') + 1:] for address in line.split(): address = int(address, 16) if address != 0: # leaf nodes hold pointers to actual values if node_height == height - 1: expr = '((arena_chunk_t *)%#x)->arena' % address arena = gdbutil.to_int(gdb.parse_and_eval(expr)) exists = false if arena in [i.addr for i in jeheap.arenas]: exists = true if exists: jeheap.chunks.append(jemalloc.arena_chunk(address, arena)) else: jeheap.chunks.append(jemalloc.arena_chunk(address)) # non-leaf nodes are inserted in the stack else: stack.append((address, node_height + 1))
def jeparse_arenas(): global jeheap jeheap.arenas[:] = [] for i in range(0, jeheap.narenas): current_arena = jemalloc.arena(0, i, []) try: current_arena.addr = \ gdbutil.to_int(gdb.parse_and_eval('je_arenas[%d]' % (i))) except: print('[unmask_jemalloc] error: cannot evaluate je_arenas[%d]') % (i) sys.exit() for j in range(0, jeheap.nbins): nrg = 0 run_sz = 0 reg_size = 0 reg_offset = 0 end_addr = 0 jeheap.STANDALONE = true reg_size = gdbutil.to_int(gdb.parse_and_eval('je_arena_bin_info[%d].reg_size' % (j))) nrg = gdbutil.to_int(gdb.parse_and_eval('je_arena_bin_info[%d].nregs' % (j))) run_sz = gdbutil.to_int(gdb.parse_and_eval('je_arena_bin_info[%d].run_size' % (j))) reg_offset = gdbutil.to_int(gdb.parse_and_eval('je_arena_bin_info[%d].reg0_offset' % (j))) try: expr = 'je_arenas[%d].bins[%d].runcur' % (i, j) runcur_addr = runcur = gdbutil.to_int(gdb.parse_and_eval(expr)) end_addr = runcur_addr + run_sz if runcur != 0: expr = 'je_arenas[%d].bins[%d].runcur.nfree' % (i, j) nfree = gdbutil.to_int(gdb.parse_and_eval(expr)) current_run = \ jemalloc.arena_run(runcur, end_addr, run_sz, 0, \ int(reg_size), reg_offset, nrg, nfree, []) current_bin = jemalloc.arena_bin(0, j, current_run) current_bin.addr = \ gdbutil.to_int(gdb.parse_and_eval('&je_arenas[%d].bins[%d]' % (i, j))) current_arena.bins.append(current_bin) else: # no regions for this size class yet, therefore no runcur current_run = jemalloc.arena_run() current_bin = jemalloc.arena_bin(0, j, current_run) current_arena.bins.append(current_bin) except RuntimeError: current_run = jemalloc.arena_run() current_bin = jemalloc.arena_bin(0, j, current_run) current_arena.bins.append(current_bin) continue # add arena to the list of arenas jeheap.arenas.append(current_arena)