Skip to content

Commit fa0d4e7

Browse files
authored
Merge pull request #235 from facebook/heapfrom
Add heapfrom command
2 parents cd4582c + ff3c252 commit fa0d4e7

File tree

1 file changed

+47
-0
lines changed

1 file changed

+47
-0
lines changed

commands/FBDebugCommands.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
383430
class FBSequenceCommand(fb.FBCommand):
384431
def name(self):
385432
return 'sequence'

0 commit comments

Comments
 (0)