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
46
47from configuration import *
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 GetSizeOfCache():
86    """ Returns number of bytes held in cache.
87        returns:
88            int - size of cache including static and dynamic
89    """
90    global _static_data, _dynamic_data
91    return sys.getsizeof(_static_data) + sys.getsizeof(_dynamic_data)
92
93
94def GetStaticCacheData(key, default_value = None):
95    """ Get cached object based on key from the cache of static information.
96        params:
97            key: str - a unique string identifying your data.
98            default_value : obj - an object that should be returned if key is not found.
99        returns:
100            default_value - if the static cache does not have your data.
101            obj  - The data obj saved with SaveStaticCacheData()
102    """
103    global _static_data
104    key = str(key)
105    if key in _static_data:
106        return _static_data[key][0]
107    return default_value
108
109def SaveStaticCacheData(key, value):
110    """ Save data into the cache identified by key.
111        It will overwrite any data that was previously associated with key
112        params:
113            key  : str - a unique string identifying your data
114            value: obj - any object that is to be cached.
115        returns:
116            Nothing
117    """
118    global _static_data
119
120    if not config['CacheStaticData']:
121        return
122
123    key = str(key)
124    _static_data[key] = (value, _GetCurrentSessionID())
125    return
126
127
128def GetDynamicCacheData(key, default_value=None):
129    """ Get cached object based on key from the cache of dynamic information.
130        params:
131            key: str - a unique string identifying cached object
132            default_value : obj - an object that should be returned if key is not found.
133        returns:
134            default_value - if dynamic cache does not have data or if the saved version mismatches with current session id.
135            obj  - The data obj saved with SaveDynamicCacheData()
136    """
137    global _dynamic_data
138    key = str(key)
139    if key in _dynamic_data:
140        if _GetCurrentSessionID() == _dynamic_data[key][1]:
141            return _dynamic_data[key][0]
142        else:
143            del _dynamic_data[key]
144
145    return default_value
146
147
148def SaveDynamicCacheData(key, value):
149    """ Save data into the cache identified by key.
150        It will overwrite any data that was previously associated with key
151        params:
152            key  : str - a unique string identifying your data
153            value: obj - any object that is to be cached.
154        returns:
155            Nothing
156    """
157    global _dynamic_data
158
159    if not config['CacheDynamicData']:
160        return
161
162    key = str(key)
163    _dynamic_data[key] = (value, _GetCurrentSessionID())
164
165    return
166