@@ -17,6 +17,7 @@ def lldbcommands():
1717 FBFindInstancesCommand (),
1818 FBMethodBreakpointEnableCommand (),
1919 FBMethodBreakpointDisableCommand (),
20+ FBHeapFromCommand (),
2021 FBSequenceCommand (),
2122 ]
2223
@@ -380,6 +381,52 @@ def chiselLibraryPath(self):
380381 return os .path .join (source_dir , '..' , '..' , 'lib' , 'Chisel.framework' , 'Chisel' )
381382
382383
384+ class FBHeapFromCommand (fb .FBCommand ):
385+ def name (self ):
386+ return 'heapfrom'
387+
388+ def description (self ):
389+ return 'Show all nested heap pointers contained within a given variable.'
390+
391+ def run (self , arguments , options ):
392+ # This command is like `expression --synthetic-type false`, except only showing nested heap references.
393+ var = self .context .frame .var (arguments [0 ])
394+ if not var or not var .IsValid ():
395+ self .result .SetError ('No variable named "{}"' .format (arguments [0 ]))
396+ return
397+
398+ # Use the actual underlying structure of the variable, not the human friendly (synthetic) one.
399+ root = var .GetNonSyntheticValue ()
400+
401+ # Traversal of SBValue tree to get leaf nodes, which is where heap pointers will be.
402+ leafs = []
403+ queue = [root ]
404+ while queue :
405+ node = queue .pop (0 )
406+ if node .num_children == 0 :
407+ leafs .append (node )
408+ else :
409+ queue += [node .GetChildAtIndex (i ) for i in range (node .num_children )]
410+
411+ pointers = {}
412+ for node in leafs :
413+ # Assumption: an addr that has no value means a pointer.
414+ if node .addr and not node .value :
415+ pointers [node .load_addr ] = node .path
416+
417+ options = lldb .SBExpressionOptions ()
418+ options .SetLanguage (lldb .eLanguageTypeC )
419+ def isHeap (addr ):
420+ lookup = '(int)malloc_size({})' .format (addr )
421+ return self .context .frame .EvaluateExpression (lookup , options ).unsigned != 0
422+
423+ allocations = (addr for addr in pointers if isHeap (addr ))
424+ for addr in allocations :
425+ print >> self .result , '0x{addr:x} {path}' .format (addr = addr , path = pointers [addr ])
426+ if not allocations :
427+ print >> self .result , "No heap addresses found"
428+
429+
383430class FBSequenceCommand (fb .FBCommand ):
384431 def name (self ):
385432 return 'sequence'
0 commit comments