From 00ec2fd2dba6306edacdf5b69f099912226a32d2 Mon Sep 17 00:00:00 2001 From: Dave Lee Date: Sat, 10 Mar 2018 23:04:25 -0800 Subject: [PATCH 1/4] Add heapfrom command --- commands/FBDebugCommands.py | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/commands/FBDebugCommands.py b/commands/FBDebugCommands.py index 9afe6d7..459e2f9 100644 --- a/commands/FBDebugCommands.py +++ b/commands/FBDebugCommands.py @@ -380,6 +380,48 @@ def chiselLibraryPath(self): return os.path.join(source_dir, '..', '..', 'lib', 'Chisel.framework', 'Chisel') +class FBHeapFromCommand(fb.FBCommand): + def name(self): + return 'heapfrom' + + def description(self): + return 'Show all nested heap pointers contained within a given variable.' + + def run(self, arguments, options): + # This command is like `expression --synthetic-type false`, except only showing nested heap references. + var = self.context.frame.var(arguments[0]) + # Use the actual underlying structure of the variable, not the human friendly (synthetic) one. + root = var.GetNonSyntheticValue() + + # Traversal of SBValue tree to get leaf nodes, which is where heap pointers will be. + leafs = [] + queue = [root] + while queue: + node = queue.pop(0) + if node.num_children == 0: + leafs.append(node) + else: + queue += [node.GetChildAtIndex(i) for i in range(node.num_children)] + + pointers = {} + for node in leafs: + # Assumption: an addr that has no value means a pointer. + if node.addr and not node.value: + pointers[node.load_addr] = node.path + + options = lldb.SBExpressionOptions() + options.SetLanguage(lldb.eLanguageTypeC) + def isHeap(addr): + lookup = '(int)malloc_size({})'.format(addr) + return self.context.frame.EvaluateExpression(lookup, options).unsigned != 0 + + allocations = (addr for addr in pointers if isHeap(addr)) + for addr in allocations: + print >>self.result, '0x{addr:x}: {path}'.format(addr=addr, path=pointers[addr]) + if not allocations: + print >>self.result, "No heap addresses found" + + class FBSequenceCommand(fb.FBCommand): def name(self): return 'sequence' From a99f6634f3b20af684ff72257b234cc69ce251f1 Mon Sep 17 00:00:00 2001 From: Dave Lee Date: Sat, 10 Mar 2018 23:12:37 -0800 Subject: [PATCH 2/4] Export heapfrom command --- commands/FBDebugCommands.py | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/FBDebugCommands.py b/commands/FBDebugCommands.py index 459e2f9..0c06923 100644 --- a/commands/FBDebugCommands.py +++ b/commands/FBDebugCommands.py @@ -17,6 +17,7 @@ def lldbcommands(): FBFindInstancesCommand(), FBMethodBreakpointEnableCommand(), FBMethodBreakpointDisableCommand(), + FBHeapFromCommand(), FBSequenceCommand(), ] From 30997628f7692bda907995e5a67dd9e883dee2f4 Mon Sep 17 00:00:00 2001 From: Dave Lee Date: Sat, 10 Mar 2018 23:21:30 -0800 Subject: [PATCH 3/4] Add heapfrom input validity check --- commands/FBDebugCommands.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/commands/FBDebugCommands.py b/commands/FBDebugCommands.py index 0c06923..9816ed5 100644 --- a/commands/FBDebugCommands.py +++ b/commands/FBDebugCommands.py @@ -391,6 +391,10 @@ def description(self): def run(self, arguments, options): # This command is like `expression --synthetic-type false`, except only showing nested heap references. var = self.context.frame.var(arguments[0]) + if not var or not var.IsValid(): + self.result.SetError('No variable named "{}"'.format(arguments[0])) + return + # Use the actual underlying structure of the variable, not the human friendly (synthetic) one. root = var.GetNonSyntheticValue() From ff3c25276163f75ac534779d543088e80e3e42d2 Mon Sep 17 00:00:00 2001 From: Dave Lee Date: Sun, 11 Mar 2018 14:40:01 -0700 Subject: [PATCH 4/4] Remove : after memory address --- commands/FBDebugCommands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/FBDebugCommands.py b/commands/FBDebugCommands.py index 9816ed5..751ddf2 100644 --- a/commands/FBDebugCommands.py +++ b/commands/FBDebugCommands.py @@ -422,7 +422,7 @@ def isHeap(addr): allocations = (addr for addr in pointers if isHeap(addr)) for addr in allocations: - print >>self.result, '0x{addr:x}: {path}'.format(addr=addr, path=pointers[addr]) + print >>self.result, '0x{addr:x} {path}'.format(addr=addr, path=pointers[addr]) if not allocations: print >>self.result, "No heap addresses found"