Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / tools / memory_inspector / memory_inspector / backends / memdump_parser.py
1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """This parser turns the am memdump output into a |memory_map.Map| instance."""
6
7 import base64
8 import logging
9 import re
10
11 from memory_inspector.core import memory_map
12
13
14 def Parse(lines):
15   """Parses the output of memdump.
16
17   memdump (see chrome/src/tools/memdump) is a Linux/Android binary meant to be
18   executed on the target device which extracts memory map information about one
19   or more processes. In principle is can be seen as an alternative to cat-ing
20   /proc/PID/smaps, but with extra features (multiprocess accounting and resident
21   pages reporting).
22
23   The expected memdump output looks like this:
24   ------------------------------------------------------------------------------
25   [ PID=1234]
26   1000-2000 r-xp 0 private_unevictable=4096 private=8192 shared_app=[] \
27       shared_other_unevictable=4096 shared_other=4096 "/lib/foo.so" [v///fv0D]
28   ... other entries like the one above.
29   ------------------------------------------------------------------------------
30   The output is extremely similar to /proc/PID/smaps, with the following notes:
31    - unevictable has pretty much the same meaning of "dirty", in VM terms.
32    - private and shared_other are cumulative. This means the the "clean" part
33      must be calculated as difference of (private - private_unevictable).
34    - The final field [v///fv0D] is a base64 encoded bitmap which contains the
35      information about which pages inside the mapping are resident (present).
36   See tests/android_backend_test.py for a more complete example.
37
38   Args:
39       lines: array of strings containing memdump output.
40
41   Returns:
42       An instance of |memory_map.Map|.
43   """
44   RE = (r'^([0-9a-f]+)-([0-9a-f]+)\s+'
45         r'([rwxps-]{4})\s+'
46         r'([0-9a-f]+)\s+'
47         r'private_unevictable=(\d+) private=(\d+) '
48         r'shared_app=(.*?) '
49         r'shared_other_unevictable=(\d+) shared_other=(\d+) '
50         r'\"(.*)\" '
51         r'\[([a-zA-Z0-9+/=-_:]*)\]$')
52   map_re = re.compile(RE)
53   skip_first_n_lines = 1
54   maps = memory_map.Map()
55
56   for line in lines:
57     line = line.rstrip('\r\n')
58
59     if skip_first_n_lines > 0:
60       skip_first_n_lines -= 1
61       continue
62
63     m = map_re.match(line)
64     if not m:
65       logging.warning('Skipping unrecognized memdump line "%s"' % line)
66       continue
67
68     start = int(m.group(1), 16)
69     end = int(m.group(2), 16) - 1 # end addr is inclusive in memdump output.
70     if (start > end):
71       # Sadly, this actually happened. Probably a kernel bug, see b/17402069.
72       logging.warning('Skipping unfeasible mmap "%s"' % line)
73       continue
74     entry = memory_map.MapEntry(
75         start=start,
76         end=end,
77         prot_flags=m.group(3),
78         mapped_file=m.group(10),
79         mapped_offset=int(m.group(4), 16))
80     entry.priv_dirty_bytes = int(m.group(5))
81     entry.priv_clean_bytes = int(m.group(6)) - entry.priv_dirty_bytes
82     entry.shared_dirty_bytes = int(m.group(8))
83     entry.shared_clean_bytes = int(m.group(9)) - entry.shared_dirty_bytes
84     entry.resident_pages = [ord(c) for c in base64.b64decode(m.group(11))]
85     maps.Add(entry)
86
87   return maps