1 # Copyright 2013 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 import copy 6 import logging 7 import sys 8 9 from lib.range_dict import ExclusiveRangeDict 10 from lib.policy import PolicySet 11 from lib.subcommand import SubCommand 12 13 14 LOGGER = logging.getLogger('dmprof') 15 16 17 class MapCommand(SubCommand): 18 def __init__(self): 19 super(MapCommand, self).__init__('Usage: %prog map <first-dump> <policy>') 20 21 def do(self, sys_argv, out=sys.stdout): 22 _, args = self._parse_args(sys_argv, 2) 23 dump_path = args[1] 24 target_policy = args[2] 25 (bucket_set, dumps) = SubCommand.load_basic_files(dump_path, True) 26 policy_set = PolicySet.load(SubCommand._parse_policy_list(target_policy)) 27 28 MapCommand._output(dumps, bucket_set, policy_set[target_policy], out) 29 return 0 30 31 @staticmethod 32 def _output(dumps, bucket_set, policy, out): 33 """Prints all stacktraces in a given component of given depth. 34 35 Args: 36 dumps: A list of Dump objects. 37 bucket_set: A BucketSet object. 38 policy: A Policy object. 39 out: An IO object to output. 40 """ 41 max_dump_count = 0 42 range_dict = ExclusiveRangeDict(ListAttribute) 43 for dump in dumps: 44 max_dump_count = max(max_dump_count, dump.count) 45 for key, value in dump.iter_map: 46 for begin, end, attr in range_dict.iter_range(key[0], key[1]): 47 attr[dump.count] = value 48 49 max_dump_count_digit = len(str(max_dump_count)) 50 for begin, end, attr in range_dict.iter_range(): 51 out.write('%x-%x\n' % (begin, end)) 52 if len(attr) < max_dump_count: 53 attr[max_dump_count] = None 54 for index, value in enumerate(attr[1:]): 55 out.write(' #%0*d: ' % (max_dump_count_digit, index + 1)) 56 if not value: 57 out.write('None\n') 58 elif value[0] == 'hooked': 59 component_match, _ = policy.find_mmap(value, bucket_set) 60 out.write('%s @ %d\n' % (component_match, value[1]['bucket_id'])) 61 else: 62 component_match = policy.find_unhooked(value) 63 region_info = value[1] 64 size = region_info['committed'] 65 out.write('%s [%d bytes] %s%s%s%s %s\n' % ( 66 component_match, size, value[1]['vma']['readable'], 67 value[1]['vma']['writable'], value[1]['vma']['executable'], 68 value[1]['vma']['private'], value[1]['vma']['name'])) 69 70 71 class ListAttribute(ExclusiveRangeDict.RangeAttribute): 72 """Represents a list for an attribute in range_dict.ExclusiveRangeDict.""" 73 def __init__(self): 74 super(ListAttribute, self).__init__() 75 self._list = [] 76 77 def __str__(self): 78 return str(self._list) 79 80 def __repr__(self): 81 return 'ListAttribute' + str(self._list) 82 83 def __len__(self): 84 return len(self._list) 85 86 def __iter__(self): 87 for x in self._list: 88 yield x 89 90 def __getitem__(self, index): 91 return self._list[index] 92 93 def __setitem__(self, index, value): 94 if index >= len(self._list): 95 self._list.extend([None] * (index + 1 - len(self._list))) 96 self._list[index] = value 97 98 def copy(self): 99 new_list = ListAttribute() 100 for index, item in enumerate(self._list): 101 new_list[index] = copy.deepcopy(item) 102 return new_list 103