@@ -17,6 +17,7 @@ def lldbcommands():
17
17
FBFindInstancesCommand (),
18
18
FBMethodBreakpointEnableCommand (),
19
19
FBMethodBreakpointDisableCommand (),
20
+ FBHeapFromCommand (),
20
21
FBSequenceCommand (),
21
22
]
22
23
@@ -380,6 +381,52 @@ def chiselLibraryPath(self):
380
381
return os .path .join (source_dir , '..' , '..' , 'lib' , 'Chisel.framework' , 'Chisel' )
381
382
382
383
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
+
383
430
class FBSequenceCommand (fb .FBCommand ):
384
431
def name (self ):
385
432
return 'sequence'
0 commit comments