1""" 2A basic caching module for xnu debug macros to use. 3It is recommended to use [Get|Save][Static|Dynamic]CacheData() apis for 4your caching needs. These APIs will handle the case of clearing caches when 5a debugger continues and stops or hit a breakpoint. 6 7Use Static caches for data that will not change if the program is run and stopped again. e.g. typedata, version numbers etc. 8An example invocation could be like 9def getDSYMPathForUUID(uuid): 10 # Get the data from cache 11 cached_data = caching.GetStaticCacheData('dsym.for.uuid', {}) 12 13 if uuid in cached_data: 14 return cached_data[uuid] 15 else: 16 path = #get info for uuid 17 cached_data[uuid] = path 18 19 # save the cached_data object to cache. 20 caching.SaveStaticCacheData('dsym.for.uuid', cached_data) 21 22 return cached_data[uuid] 23 24And use Dynamic caches for things like thread data, zones information etc. 25These will automatically be dropped when debugger continues the target 26An example use of Dynamic cache could be as follows 27 28def GetExecutablePathForPid(pid): 29 # Get the data from cache 30 cached_data = caching.GetDynamicCacheData('exec_for_path', {}) 31 32 if pid in cached_data: 33 return cached_data[pid] 34 else: 35 exec_path = "/path/to/exec" #get exec path for pid 36 cached_data[pid] = path 37 38 # save the cached_data object to cache. 39 caching.SaveDynamicCacheData('exec_for_path', cached_data) 40 41 return cached_data[pid] 42 43""" 44 45# Private Routines and objects 46from __future__ import absolute_import 47from .configuration import config 48 49import sys 50 51""" 52The format for the saved data dictionaries is 53{ 54 'key' : (valueobj, versno), 55 ... 56} 57 58The versno is an int defining the version of obj. In case of version mismatch it will set valueobj to default upon access. 59 60""" 61_static_data = {} 62_dynamic_data = {} 63 64 65 66def _GetDebuggerSessionID(): 67 """ A default callable function that _GetCurrentSessionID uses to 68 identify a stopped session. 69 """ 70 return 0 71 72def _GetCurrentSessionID(): 73 """ Get the current session id. This will update whenever 74 system is continued or if there is new information that would 75 cause the dynamic cache to be deleted. 76 77 returns: int - session id number. 78 """ 79 session_id = _GetDebuggerSessionID() 80 return session_id 81 82 83#Public APIs 84 85def ClearAllCache(): 86 """ remove all cached data. 87 """ 88 global _static_data, _dynamic_data 89 _static_data = {} 90 _dynamic_data = {} 91 92def GetSizeOfCache(): 93 """ Returns number of bytes held in cache. 94 returns: 95 int - size of cache including static and dynamic 96 """ 97 global _static_data, _dynamic_data 98 return sys.getsizeof(_static_data) + sys.getsizeof(_dynamic_data) 99 100 101def GetStaticCacheData(key, default_value = None): 102 """ Get cached object based on key from the cache of static information. 103 params: 104 key: str - a unique string identifying your data. 105 default_value : obj - an object that should be returned if key is not found. 106 returns: 107 default_value - if the static cache does not have your data. 108 obj - The data obj saved with SaveStaticCacheData() 109 """ 110 global _static_data 111 key = str(key) 112 if key in _static_data: 113 return _static_data[key][0] 114 return default_value 115 116def SaveStaticCacheData(key, value): 117 """ Save data into the cache identified by key. 118 It will overwrite any data that was previously associated with key 119 params: 120 key : str - a unique string identifying your data 121 value: obj - any object that is to be cached. 122 returns: 123 Nothing 124 """ 125 global _static_data 126 127 if not config['CacheStaticData']: 128 return 129 130 key = str(key) 131 _static_data[key] = (value, _GetCurrentSessionID()) 132 return 133 134 135def GetDynamicCacheData(key, default_value=None): 136 """ Get cached object based on key from the cache of dynamic information. 137 params: 138 key: str - a unique string identifying cached object 139 default_value : obj - an object that should be returned if key is not found. 140 returns: 141 default_value - if dynamic cache does not have data or if the saved version mismatches with current session id. 142 obj - The data obj saved with SaveDynamicCacheData() 143 """ 144 global _dynamic_data 145 key = str(key) 146 if key in _dynamic_data: 147 if _GetCurrentSessionID() == _dynamic_data[key][1]: 148 return _dynamic_data[key][0] 149 else: 150 del _dynamic_data[key] 151 152 return default_value 153 154 155def SaveDynamicCacheData(key, value): 156 """ Save data into the cache identified by key. 157 It will overwrite any data that was previously associated with key 158 params: 159 key : str - a unique string identifying your data 160 value: obj - any object that is to be cached. 161 returns: 162 Nothing 163 """ 164 global _dynamic_data 165 166 if not config['CacheDynamicData']: 167 return 168 169 key = str(key) 170 _dynamic_data[key] = (value, _GetCurrentSessionID()) 171 172 return 173