@@ -1710,6 +1710,15 @@ def psprint(self) -> str:
17101710 msg .append (f"\n \n { self ._str_pointers ()} " )
17111711 return "\n " .join (msg ) + "\n "
17121712
1713+ def resolve_type (self ) -> str :
1714+ ptr_data = gef .memory .read_integer (self .data_address )
1715+ if ptr_data != 0 :
1716+ sym = gdb_get_location_from_symbol (ptr_data )
1717+ if sym is not None and "vtable for" in sym [0 ]:
1718+ return sym [0 ].replace ("vtable for " , "" )
1719+
1720+ return ""
1721+
17131722
17141723class GlibcFastChunk (GlibcChunk ):
17151724
@@ -1999,7 +2008,6 @@ def gdb_lookup_symbol(sym: str) -> Optional[Tuple[Optional[str], Optional[Tuple[
19992008 except gdb .error :
20002009 return None
20012010
2002-
20032011@lru_cache (maxsize = 512 )
20042012def gdb_get_location_from_symbol (address : int ) -> Optional [Tuple [str , int ]]:
20052013 """Retrieve the location of the `address` argument from the symbol table.
@@ -6302,7 +6310,8 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None:
63026310
63036311
63046312class GlibcHeapChunkSummary :
6305- def __init__ (self ):
6313+ def __init__ (self , desc = "" ):
6314+ self .desc = desc
63066315 self .count = 0
63076316 self .total_bytes = 0
63086317
@@ -6312,7 +6321,8 @@ def process_chunk(self, chunk: GlibcChunk) -> None:
63126321
63136322
63146323class GlibcHeapArenaSummary :
6315- def __init__ (self ) -> None :
6324+ def __init__ (self , resolve_type = False ) -> None :
6325+ self .resolve_symbol = resolve_type
63166326 self .size_distribution = {}
63176327 self .flag_distribution = {
63186328 "PREV_INUSE" : GlibcHeapChunkSummary (),
@@ -6321,10 +6331,12 @@ def __init__(self) -> None:
63216331 }
63226332
63236333 def process_chunk (self , chunk : GlibcChunk ) -> None :
6324- per_size_summary = self .size_distribution .get (chunk .size , None )
6334+ chunk_type = "" if not self .resolve_symbol else chunk .resolve_type ()
6335+
6336+ per_size_summary = self .size_distribution .get ((chunk .size , chunk_type ), None )
63256337 if per_size_summary is None :
6326- per_size_summary = GlibcHeapChunkSummary ()
6327- self .size_distribution [chunk .size ] = per_size_summary
6338+ per_size_summary = GlibcHeapChunkSummary (desc = chunk_type )
6339+ self .size_distribution [( chunk .size , chunk_type ) ] = per_size_summary
63286340 per_size_summary .process_chunk (chunk )
63296341
63306342 if chunk .has_p_bit ():
@@ -6336,9 +6348,9 @@ def process_chunk(self, chunk: GlibcChunk) -> None:
63366348
63376349 def print (self ) -> None :
63386350 gef_print ("== Chunk distribution by size ==" )
6339- gef_print ("{:<10s}\t {:<10s}\t {:s}" .format ("ChunkBytes" , "Count" , "TotalBytes" ))
6340- for chunk_size , chunk_summary in sorted (self .size_distribution .items (), key = lambda x : x [1 ].total_bytes , reverse = True ):
6341- gef_print ("{:<10d}\t {:<10d}\t {:<d} " .format (chunk_size , chunk_summary .count , chunk_summary .total_bytes ))
6351+ gef_print ("{:<10s}\t {:<10s}\t {:15s} \t {: s}" .format ("ChunkBytes" , "Count" , "TotalBytes" , "Description " ))
6352+ for chunk_info , chunk_summary in sorted (self .size_distribution .items (), key = lambda x : x [1 ].total_bytes , reverse = True ):
6353+ gef_print ("{:<10d}\t {:<10d}\t {:<15d} \t {:s} " .format (chunk_info [ 0 ] , chunk_summary .count , chunk_summary .total_bytes , chunk_summary . desc ))
63426354
63436355 gef_print ("\n == Chunk distribution by flag ==" )
63446356 gef_print ("{:<15s}\t {:<10s}\t {:s}" .format ("Flag" , "TotalCount" , "TotalBytes" ))
@@ -6352,7 +6364,7 @@ class GlibcHeapChunksCommand(GenericCommand):
63526364 the base address of a different arena can be passed"""
63536365
63546366 _cmdline_ = "heap chunks"
6355- _syntax_ = f"{ _cmdline_ } [-h] [--all] [--allow-unaligned] [--summary] [--min-size MIN_SIZE] [--max-size MAX_SIZE] [arena_address]"
6367+ _syntax_ = f"{ _cmdline_ } [-h] [--all] [--allow-unaligned] [--summary] [--min-size MIN_SIZE] [--max-size MAX_SIZE] [--resolve] [ arena_address]"
63566368 _example_ = (f"\n { _cmdline_ } "
63576369 f"\n { _cmdline_ } 0x555555775000" )
63586370
@@ -6361,24 +6373,24 @@ def __init__(self) -> None:
63616373 self ["peek_nb_byte" ] = (16 , "Hexdump N first byte(s) inside the chunk data (0 to disable)" )
63626374 return
63636375
6364- @parse_arguments ({"arena_address" : "" }, {("--all" , "-a" ): True , "--allow-unaligned" : True , "--min-size" : 0 , "--max-size" : 0 , ("--summary" , "-s" ): True })
6376+ @parse_arguments ({"arena_address" : "" }, {("--all" , "-a" ): True , "--allow-unaligned" : True , "--min-size" : 0 , "--max-size" : 0 , ("--summary" , "-s" ): True , "--resolve" : True })
63656377 @only_if_gdb_running
63666378 def do_invoke (self , _ : List [str ], ** kwargs : Any ) -> None :
63676379 args = kwargs ["arguments" ]
63686380 if args .all or not args .arena_address :
63696381 for arena in gef .heap .arenas :
6370- self .dump_chunks_arena (arena , print_arena = args .all , allow_unaligned = args .allow_unaligned , min_size = args .min_size , max_size = args .max_size , summary = args .summary )
6382+ self .dump_chunks_arena (arena , print_arena = args .all , allow_unaligned = args .allow_unaligned , min_size = args .min_size , max_size = args .max_size , summary = args .summary , resolve_type = args . resolve )
63716383 if not args .all :
63726384 return
63736385 try :
63746386 arena_addr = parse_address (args .arena_address )
63756387 arena = GlibcArena (f"*{ arena_addr :#x} " )
6376- self .dump_chunks_arena (arena , allow_unaligned = args .allow_unaligned , min_size = args .min_size , max_size = args .max_size , summary = args .summary )
6388+ self .dump_chunks_arena (arena , allow_unaligned = args .allow_unaligned , min_size = args .min_size , max_size = args .max_size , summary = args .summary , resolve_type = args . resolve )
63776389 except gdb .error :
63786390 err ("Invalid arena" )
63796391 return
63806392
6381- def dump_chunks_arena (self , arena : GlibcArena , print_arena : bool = False , allow_unaligned : bool = False , min_size : int = 0 , max_size : int = 0 , summary : bool = False ) -> None :
6393+ def dump_chunks_arena (self , arena : GlibcArena , print_arena : bool = False , allow_unaligned : bool = False , min_size : int = 0 , max_size : int = 0 , summary : bool = False , resolve_type : bool = False ) -> None :
63826394 heap_addr = arena .heap_addr (allow_unaligned = allow_unaligned )
63836395 if heap_addr is None :
63846396 err ("Could not find heap for arena" )
@@ -6387,18 +6399,18 @@ def dump_chunks_arena(self, arena: GlibcArena, print_arena: bool = False, allow_
63876399 gef_print (str (arena ))
63886400 if arena .is_main_arena ():
63896401 heap_end = arena .top + GlibcChunk (arena .top , from_base = True ).size
6390- self .dump_chunks_heap (heap_addr , heap_end , arena , allow_unaligned = allow_unaligned , min_size = min_size , max_size = max_size , summary = summary )
6402+ self .dump_chunks_heap (heap_addr , heap_end , arena , allow_unaligned = allow_unaligned , min_size = min_size , max_size = max_size , summary = summary , resolve_type = resolve_type )
63916403 else :
63926404 heap_info_structs = arena .get_heap_info_list () or []
63936405 for heap_info in heap_info_structs :
6394- if not self .dump_chunks_heap (heap_info .heap_start , heap_info .heap_end , arena , allow_unaligned = allow_unaligned , min_size = min_size , max_size = max_size , summary = summary ):
6406+ if not self .dump_chunks_heap (heap_info .heap_start , heap_info .heap_end , arena , allow_unaligned = allow_unaligned , min_size = min_size , max_size = max_size , summary = summary , resolve_type = resolve_type ):
63956407 break
63966408 return
63976409
6398- def dump_chunks_heap (self , start : int , end : int , arena : GlibcArena , allow_unaligned : bool = False , min_size : int = 0 , max_size : int = 0 , summary : bool = False ) -> bool :
6410+ def dump_chunks_heap (self , start : int , end : int , arena : GlibcArena , allow_unaligned : bool = False , min_size : int = 0 , max_size : int = 0 , summary : bool = False , resolve_type : bool = False ) -> bool :
63996411 nb = self ["peek_nb_byte" ]
64006412 chunk_iterator = GlibcChunk (start , from_base = True , allow_unaligned = allow_unaligned )
6401- heap_summary = GlibcHeapArenaSummary ()
6413+ heap_summary = GlibcHeapArenaSummary (resolve_type = resolve_type )
64026414 for chunk in chunk_iterator :
64036415 heap_corrupted = chunk .base_address > end
64046416 should_process = self .should_process_chunk (chunk , min_size , max_size )
0 commit comments