From bede9f3b3c9f93464c80751a55668b333363ffb1 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 28 Mar 2018 11:17:17 -0700 Subject: [PATCH] Handle num fields that aren't one. The new version of malloc debug supports using a num field that is more than one. Modify the parser to handle this case. Bug: 74361929 Test: Ran on a file that contained non-one numbers and verified the output. Change-Id: I158922e51ce99afff88f20a80df414d653f95e65 --- scripts/native_heapdump_viewer.py | 43 +++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/scripts/native_heapdump_viewer.py b/scripts/native_heapdump_viewer.py index 0689a1d1d..5d5db1093 100755 --- a/scripts/native_heapdump_viewer.py +++ b/scripts/native_heapdump_viewer.py @@ -86,9 +86,10 @@ native_heap = args[0] re_map = re.compile("(?P[0-9a-f]+)-(?P[0-9a-f]+) .... (?P[0-9a-f]+) [0-9a-f]+:[0-9a-f]+ [0-9]+ +(?P.*)") class Backtrace: - def __init__(self, is_zygote, size, frames): + def __init__(self, is_zygote, size, num_allocs, frames): self.is_zygote = is_zygote self.size = size + self.num_allocs = num_allocs self.frames = frames class Mapping: @@ -105,18 +106,43 @@ class FrameDescription: self.library = library +def GetVersion(native_heap): + """Get the version of the native heap dump.""" + + re_line = re.compile("Android\s+Native\s+Heap\s+Dump\s+(?Pv\d+\.\d+)\s*$") + matched = 0 + for line in open(native_heap, "r"): + m = re_line.match(line) + if m: + return m.group('version') + return None + +version = GetVersion(native_heap) +if not version or version == "v1.0": + # Version v1.0 was produced by a buggy version of malloc debug where the + # num field was set incorrectly. + num_field_valid = False +else: + num_field_valid = True + backtraces = [] mappings = [] for line in open(native_heap, "r"): + # Format of line: + # z 0 sz 50 num 1 bt 000000000000a100 000000000000b200 parts = line.split() if len(parts) > 7 and parts[0] == "z" and parts[2] == "sz": is_zygote = parts[1] != "1" size = int(parts[3]) + if num_field_valid: + num_allocs = int(parts[5]) + else: + num_allocs = 1 frames = map(lambda x: int(x, 16), parts[7:]) if reverse_frames: frames = list(reversed(frames)) - backtraces.append(Backtrace(is_zygote, size, frames)) + backtraces.append(Backtrace(is_zygote, size, num_allocs, frames)) continue m = re_map.match(line) @@ -209,16 +235,17 @@ class AddrInfo: self.addr = addr self.size = 0 self.number = 0 + self.num_allocs = 0 self.children = {} - def addStack(self, size, stack): - self.size += size - self.number += 1 + def addStack(self, size, num_allocs, stack): + self.size += size * num_allocs + self.number += num_allocs if len(stack) > 0: child = stack[0] if not (child.addr in self.children): self.children[child.addr] = child - self.children[child.addr].addStack(size, stack[1:]) + self.children[child.addr].addStack(size, num_allocs, stack[1:]) zygote = AddrInfo("ZYGOTE") app = AddrInfo("APP") @@ -272,9 +299,9 @@ for backtrace in backtraces: stack.append(AddrInfo("%x" % addr)) stack.reverse() if backtrace.is_zygote: - zygote.addStack(backtrace.size, stack) + zygote.addStack(backtrace.size, backtrace.num_allocs, stack) else: - app.addStack(backtrace.size, stack) + app.addStack(backtrace.size, backtrace.num_allocs, stack) html_header = """