| [1cfdee9] | 1 | #
 | 
|---|
 | 2 | # Copyright (C) Lynn Tran, Jiachen Zhang 2018
 | 
|---|
 | 3 | #
 | 
|---|
 | 4 | # utils-gdb.py --
 | 
|---|
 | 5 | #
 | 
|---|
 | 6 | # Author           : Lynn Tran
 | 
|---|
 | 7 | # Created On       : Mon Oct 1 22:06:09 2018
 | 
|---|
 | 8 | # Last Modified By : Peter A. Buhr
 | 
|---|
 | 9 | # Last Modified On : Sat Jan 19 14:16:10 2019
 | 
|---|
 | 10 | # Update Count     : 11
 | 
|---|
 | 11 | #
 | 
|---|
 | 12 | 
 | 
|---|
 | 13 | """
 | 
|---|
 | 14 | To run this extension, the python name has to be as same as one of the loaded library
 | 
|---|
 | 15 | Additionally, the file must exist in a folder which is in gdb's safe path
 | 
|---|
 | 16 | """
 | 
|---|
 | 17 | import collections
 | 
|---|
 | 18 | import gdb
 | 
|---|
 | 19 | import re
 | 
|---|
 | 20 | 
 | 
|---|
 | 21 | # set these signal handlers with some settings (nostop, noprint, pass)
 | 
|---|
 | 22 | gdb.execute('handle SIGALRM nostop noprint pass')
 | 
|---|
 | 23 | gdb.execute('handle SIGUSR1 nostop noprint pass')
 | 
|---|
 | 24 | 
 | 
|---|
| [262d4d51] | 25 | CfaTypes = collections.namedtuple('CfaTypes', 'cluster_ptr processor_ptr thread_ptr int_ptr uintptr thread_state yield_state')
 | 
|---|
| [1cfdee9] | 26 | 
 | 
|---|
| [96df7c9c] | 27 | class ThreadInfo:
 | 
|---|
| [9987d79] | 28 |         tid = 0
 | 
|---|
 | 29 |         cluster = None
 | 
|---|
 | 30 |         value = None
 | 
|---|
| [1cfdee9] | 31 | 
 | 
|---|
| [9987d79] | 32 |         def __init__(self, cluster, value):
 | 
|---|
 | 33 |                 self.cluster = cluster
 | 
|---|
 | 34 |                 self.value = value
 | 
|---|
| [1cfdee9] | 35 | 
 | 
|---|
| [9987d79] | 36 |         def is_system(self):
 | 
|---|
 | 37 |                 return False
 | 
|---|
| [1cfdee9] | 38 | 
 | 
|---|
 | 39 | # A named tuple representing information about a stack
 | 
|---|
 | 40 | StackInfo = collections.namedtuple('StackInfo', 'sp fp pc')
 | 
|---|
 | 41 | 
 | 
|---|
 | 42 | # A global variable to keep track of stack information as one switches from one
 | 
|---|
 | 43 | # task to another task
 | 
|---|
 | 44 | STACK = []
 | 
|---|
 | 45 | 
 | 
|---|
 | 46 | not_supported_error_msg = "Not a supported command for this language"
 | 
|---|
 | 47 | 
 | 
|---|
 | 48 | def is_cforall():
 | 
|---|
| [9987d79] | 49 |         return True
 | 
|---|
| [1cfdee9] | 50 | 
 | 
|---|
 | 51 | def get_cfa_types():
 | 
|---|
| [9987d79] | 52 |         # GDB types for various structures/types in CFA
 | 
|---|
 | 53 |         return CfaTypes(cluster_ptr = gdb.lookup_type('struct cluster').pointer(),
 | 
|---|
| [6abcb4d] | 54 |                 processor_ptr = gdb.lookup_type('struct processor').pointer(),
 | 
|---|
| [b7d94ac5] | 55 |                 thread_ptr = gdb.lookup_type('struct thread$').pointer(),
 | 
|---|
| [6abcb4d] | 56 |                 int_ptr = gdb.lookup_type('int').pointer(),
 | 
|---|
| [262d4d51] | 57 |                 uintptr = gdb.lookup_type('uintptr_t'),
 | 
|---|
| [6abcb4d] | 58 |                 thread_state = gdb.lookup_type('enum __Coroutine_State'),
 | 
|---|
 | 59 |                 yield_state = gdb.lookup_type('enum __Preemption_Reason'))
 | 
|---|
| [1cfdee9] | 60 | 
 | 
|---|
 | 61 | def get_addr(addr):
 | 
|---|
| [9987d79] | 62 |         """
 | 
|---|
 | 63 |         NOTE: sketchy solution to retrieve address. There is a better solution...
 | 
|---|
 | 64 |         @addr: str of an address that can be in a format 0xfffff <type of the object
 | 
|---|
 | 65 |         at this address>
 | 
|---|
 | 66 |         Return: str of just the address
 | 
|---|
 | 67 |         """
 | 
|---|
 | 68 |         str_addr = str(addr)
 | 
|---|
 | 69 |         ending_addr_index = str_addr.find('<')
 | 
|---|
 | 70 |         if ending_addr_index == -1:
 | 
|---|
 | 71 |                 return str(addr)
 | 
|---|
 | 72 |         return str_addr[:ending_addr_index].strip()
 | 
|---|
| [1cfdee9] | 73 | 
 | 
|---|
| [bb75b4e] | 74 | def print_usage(obj):
 | 
|---|
| [9987d79] | 75 |         print(obj.__doc__)
 | 
|---|
| [1cfdee9] | 76 | 
 | 
|---|
 | 77 | def parse(args):
 | 
|---|
| [9987d79] | 78 |         """
 | 
|---|
 | 79 |         Split the argument list in string format, where each argument is separated
 | 
|---|
 | 80 |         by whitespace delimiter, to a list of arguments like argv
 | 
|---|
 | 81 |         @args: str of arguments
 | 
|---|
 | 82 |         Return:
 | 
|---|
 | 83 |                 [] if args is an empty string
 | 
|---|
 | 84 |                 list if args is not empty
 | 
|---|
 | 85 |         """
 | 
|---|
 | 86 |         # parse the string format of arguments and return a list of arguments
 | 
|---|
 | 87 |         argv = args.split(' ')
 | 
|---|
 | 88 |         if len(argv) == 1 and argv[0] == '':
 | 
|---|
 | 89 |                 return []
 | 
|---|
 | 90 |         return argv
 | 
|---|
| [1cfdee9] | 91 | 
 | 
|---|
| [262d4d51] | 92 | def single_field(obj):
 | 
|---|
 | 93 |         """
 | 
|---|
 | 94 |         If the struct only has one field return it, otherwise error
 | 
|---|
 | 95 |         """
 | 
|---|
 | 96 | 
 | 
|---|
 | 97 |         _type = obj.type
 | 
|---|
 | 98 |         if len(_type.fields()) != 1:
 | 
|---|
 | 99 |                 return None
 | 
|---|
 | 100 | 
 | 
|---|
 | 101 |         return obj[_type.fields()[0].name]
 | 
|---|
 | 102 | 
 | 
|---|
 | 103 | 
 | 
|---|
 | 104 | def start_from_dlist(dlist):
 | 
|---|
 | 105 |         fs = dlist.type.fields()
 | 
|---|
 | 106 |         if len(fs) != 1:
 | 
|---|
 | 107 |                 print("Error, can't understand dlist type for", dlist, dlist.name, dlist.type)
 | 
|---|
 | 108 |                 return None
 | 
|---|
 | 109 | 
 | 
|---|
 | 110 |         return dlist[fs[0]]
 | 
|---|
 | 111 | 
 | 
|---|
 | 112 | def fix_dlink(ptr):
 | 
|---|
 | 113 |         """
 | 
|---|
 | 114 |         Remove the higher order bit from the pointer
 | 
|---|
 | 115 |         """
 | 
|---|
 | 116 |         ptype = ptr.type
 | 
|---|
 | 117 |         size = ptype.sizeof
 | 
|---|
 | 118 |         if size == 8:
 | 
|---|
 | 119 |                 bit = 1 << ((size*8)-1)
 | 
|---|
 | 120 |                 mask = bit - 1
 | 
|---|
 | 121 |         elif size == 4:
 | 
|---|
 | 122 |                 bit = 0
 | 
|---|
 | 123 |                 mask = 1
 | 
|---|
 | 124 |         else:
 | 
|---|
 | 125 |                 print("Unexpected pointer size while fixing dlink", size)
 | 
|---|
 | 126 | 
 | 
|---|
 | 127 |         cfa_t = get_cfa_types()
 | 
|---|
 | 128 |         uptr = ptr.cast(cfa_t.uintptr)
 | 
|---|
 | 129 |         return ptr if 0 == uptr & mask else gdb.Value(b'\x00'*size, ptype)
 | 
|---|
 | 130 | 
 | 
|---|
| [9dad5b3] | 131 | class ClusterIter:
 | 
|---|
 | 132 |         def __init__(self, root):
 | 
|---|
 | 133 |                 self.curr = None
 | 
|---|
 | 134 |                 self.root = root
 | 
|---|
 | 135 | 
 | 
|---|
 | 136 |         def __iter__(self):
 | 
|---|
 | 137 |                 return self
 | 
|---|
 | 138 | 
 | 
|---|
 | 139 |         def __next__(self):
 | 
|---|
 | 140 |                 # Clusters form a cycle
 | 
|---|
 | 141 |                 # If we haven't seen the root yet, then the root is the first
 | 
|---|
 | 142 |                 if not self.curr:
 | 
|---|
 | 143 |                         self.curr = self.root
 | 
|---|
 | 144 |                         return self.curr
 | 
|---|
 | 145 | 
 | 
|---|
 | 146 |                 # if we already saw the root, then go forward
 | 
|---|
 | 147 |                 self.curr = self.curr['_X4nodeS26__cluster____dbg_node_cltr_1']['_X4nextPS7cluster_1']
 | 
|---|
 | 148 | 
 | 
|---|
 | 149 |                 # if we reached the root again, then we are done
 | 
|---|
 | 150 |                 if self.curr == self.root:
 | 
|---|
 | 151 |                         raise StopIteration
 | 
|---|
 | 152 | 
 | 
|---|
 | 153 |                 # otherwise return the next
 | 
|---|
 | 154 |                 return self.curr
 | 
|---|
 | 155 | 
 | 
|---|
 | 156 | def all_clusters():
 | 
|---|
| [9987d79] | 157 |         """
 | 
|---|
| [9dad5b3] | 158 |         Return: a list of all the clusters as an iterator.
 | 
|---|
 | 159 |         obtained from gdb.Value of globalClusters.root (is an address)
 | 
|---|
| [9987d79] | 160 |         """
 | 
|---|
| [9dad5b3] | 161 |         if not is_cforall():
 | 
|---|
 | 162 |                 return []
 | 
|---|
 | 163 | 
 | 
|---|
| [9987d79] | 164 |         cluster_root = gdb.parse_and_eval('_X11mainClusterPS7cluster_1')
 | 
|---|
 | 165 |         if cluster_root.address == 0x0:
 | 
|---|
 | 166 |                 print('No clusters, program terminated')
 | 
|---|
| [9dad5b3] | 167 |                 return []
 | 
|---|
| [1cfdee9] | 168 | 
 | 
|---|
| [9dad5b3] | 169 |         return ClusterIter(cluster_root)
 | 
|---|
| [9987d79] | 170 | 
 | 
|---|
| [9dad5b3] | 171 | class ProcIter:
 | 
|---|
 | 172 |         def __init__(self, root):
 | 
|---|
 | 173 |                 self.curr = None
 | 
|---|
 | 174 |                 self.root = root
 | 
|---|
| [9987d79] | 175 | 
 | 
|---|
| [9dad5b3] | 176 |         def __iter__(self):
 | 
|---|
 | 177 |                 return self
 | 
|---|
| [9987d79] | 178 | 
 | 
|---|
| [9dad5b3] | 179 |         def check(self):
 | 
|---|
 | 180 |                 # check if this is the last value
 | 
|---|
| [262d4d51] | 181 |                 if not fix_dlink(self.curr):
 | 
|---|
| [9dad5b3] | 182 |                         raise StopIteration
 | 
|---|
| [9987d79] | 183 | 
 | 
|---|
| [9dad5b3] | 184 |         def __next__(self):
 | 
|---|
 | 185 |                 cfa_t = get_cfa_types()
 | 
|---|
| [9987d79] | 186 | 
 | 
|---|
| [9dad5b3] | 187 |                 # Processors form a cycle
 | 
|---|
 | 188 |                 # If we haven't seen the root yet, then the root is the first
 | 
|---|
 | 189 |                 if not self.curr:
 | 
|---|
 | 190 |                         my_next = self.root
 | 
|---|
 | 191 |                         self.curr = my_next.cast(cfa_t.processor_ptr)
 | 
|---|
| [9987d79] | 192 | 
 | 
|---|
| [9dad5b3] | 193 |                         #check if this is an empty list
 | 
|---|
 | 194 |                         self.check()
 | 
|---|
| [9987d79] | 195 | 
 | 
|---|
| [9dad5b3] | 196 |                         return self.curr
 | 
|---|
| [d8b17e2] | 197 | 
 | 
|---|
| [9dad5b3] | 198 |                 # if we already saw the root, then go forward
 | 
|---|
| [2e94d94f] | 199 |                 my_next = self.curr['_X4linkS5dlink_S9processor__1']['_X4nextPY13__tE_generic__1']
 | 
|---|
| [9dad5b3] | 200 |                 self.curr = my_next.cast(cfa_t.processor_ptr)
 | 
|---|
| [d8b17e2] | 201 | 
 | 
|---|
| [9dad5b3] | 202 |                 #check if we reached the end
 | 
|---|
 | 203 |                 self.check()
 | 
|---|
| [d8b17e2] | 204 | 
 | 
|---|
| [9dad5b3] | 205 |                 # otherwise return the next
 | 
|---|
 | 206 |                 return self.curr
 | 
|---|
| [d8b17e2] | 207 | 
 | 
|---|
| [9dad5b3] | 208 | def proc_list(cluster):
 | 
|---|
 | 209 |         """
 | 
|---|
 | 210 |         Return: for a given processor, return the active and idle processors, as 2 iterators
 | 
|---|
 | 211 |         """
 | 
|---|
 | 212 |         cfa_t = get_cfa_types()
 | 
|---|
 | 213 |         proclist = cluster['_X5procsS19__cluster_proc_list_1']
 | 
|---|
| [160f1aa] | 214 | 
 | 
|---|
| [262d4d51] | 215 |         idle = start_from_dlist(proclist['_X5idlesS5dlist_S9processorS5dlink_S9processor___1'])['_X4nextPY13__tE_generic__1']
 | 
|---|
 | 216 |         active = start_from_dlist(proclist['_X7activesS5dlist_S9processorS5dlink_S9processor___1'])['_X4nextPY13__tE_generic__1']
 | 
|---|
| [9dad5b3] | 217 |         return ProcIter(active.cast(cfa_t.processor_ptr)), ProcIter(idle.cast(cfa_t.processor_ptr))
 | 
|---|
| [d8b17e2] | 218 | 
 | 
|---|
| [9dad5b3] | 219 | def all_processors():
 | 
|---|
 | 220 |         procs = []
 | 
|---|
 | 221 |         for c in all_clusters():
 | 
|---|
 | 222 |                 active, idle = proc_list(c)
 | 
|---|
 | 223 |                 for p in active:
 | 
|---|
 | 224 |                         procs.append(p)
 | 
|---|
| [d8b17e2] | 225 | 
 | 
|---|
| [9dad5b3] | 226 |                 for p in idle:
 | 
|---|
 | 227 |                         procs.append(p)
 | 
|---|
 | 228 | 
 | 
|---|
 | 229 |         print(procs)
 | 
|---|
 | 230 |         return procs
 | 
|---|
| [d8b17e2] | 231 | 
 | 
|---|
 | 232 | def tls_for_pthread(pthrd):
 | 
|---|
 | 233 |         prev = gdb.selected_thread()
 | 
|---|
 | 234 |         inf = gdb.selected_inferior()
 | 
|---|
 | 235 | 
 | 
|---|
 | 236 |         thrd = inf.thread_from_thread_handle( pthrd )
 | 
|---|
 | 237 |         thrd.switch()
 | 
|---|
 | 238 |         tls = gdb.parse_and_eval('&_X9kernelTLSS16KernelThreadData_1')
 | 
|---|
 | 239 | 
 | 
|---|
 | 240 |         prev.switch()
 | 
|---|
 | 241 |         return tls
 | 
|---|
 | 242 | 
 | 
|---|
 | 243 | def tls_for_proc(proc):
 | 
|---|
| [9dad5b3] | 244 |         return proc['_X10local_dataPS16KernelThreadData_1']
 | 
|---|
| [d8b17e2] | 245 | 
 | 
|---|
 | 246 | def thread_for_pthread(pthrd):
 | 
|---|
| [b7d94ac5] | 247 |         return tls_for_pthread(pthrd)['_X11this_threadVPS7thread$_1']
 | 
|---|
| [d8b17e2] | 248 | 
 | 
|---|
 | 249 | def thread_for_proc(proc):
 | 
|---|
| [b7d94ac5] | 250 |         return tls_for_proc(proc)['_X11this_threadVPS7thread$_1']
 | 
|---|
| [d8b17e2] | 251 | 
 | 
|---|
 | 252 | 
 | 
|---|
 | 253 | 
 | 
|---|
 | 254 | def find_curr_thread():
 | 
|---|
 | 255 |         # btstr = gdb.execute('bt', to_string = True).splitlines()
 | 
|---|
 | 256 |         # if len(btstr) == 0:
 | 
|---|
 | 257 |         #     print('error')
 | 
|---|
 | 258 |         #     return None
 | 
|---|
 | 259 |         # return btstr[0].split('this=',1)[1].split(',')[0].split(')')[0]
 | 
|---|
 | 260 |         return None
 | 
|---|
| [96df7c9c] | 261 | 
 | 
|---|
| [1cfdee9] | 262 | def lookup_cluster(name = None):
 | 
|---|
| [9987d79] | 263 |         """
 | 
|---|
| [9dad5b3] | 264 |         Look up one or more cluster given a name
 | 
|---|
| [9987d79] | 265 |         @name: str
 | 
|---|
 | 266 |         Return: gdb.Value
 | 
|---|
 | 267 |         """
 | 
|---|
 | 268 |         if not is_cforall():
 | 
|---|
 | 269 |                 return None
 | 
|---|
 | 270 | 
 | 
|---|
| [9dad5b3] | 271 |         clusters = all_clusters()
 | 
|---|
 | 272 |         if not clusters:
 | 
|---|
| [9987d79] | 273 |                 return None
 | 
|---|
 | 274 | 
 | 
|---|
 | 275 |         if not name:
 | 
|---|
| [9dad5b3] | 276 |                 return clusters.root
 | 
|---|
| [9987d79] | 277 | 
 | 
|---|
 | 278 |         # lookup for the task associated with the id
 | 
|---|
| [9dad5b3] | 279 |         found = [c for c in clusters if c['_X4namePKc_1'].string() == name]
 | 
|---|
 | 280 | 
 | 
|---|
 | 281 |         if not found:
 | 
|---|
| [9987d79] | 282 |                 print("Cannot find a cluster with the name: {}.".format(name))
 | 
|---|
 | 283 |                 return None
 | 
|---|
 | 284 | 
 | 
|---|
| [9dad5b3] | 285 |         return found
 | 
|---|
 | 286 | 
 | 
|---|
| [1cfdee9] | 287 | 
 | 
|---|
| [96df7c9c] | 288 | def lookup_threads_by_cluster(cluster):
 | 
|---|
| [9987d79] | 289 |                 # Iterate through a circular linked list of threads and accumulate them in an array
 | 
|---|
 | 290 |                 threads = []
 | 
|---|
| [96df7c9c] | 291 | 
 | 
|---|
| [9987d79] | 292 |                 cfa_t = get_cfa_types()
 | 
|---|
| [262d4d51] | 293 |                 head = single_field(cluster['_X7threadsS5dlist_S7thread$S18__thread_user_link__1'])
 | 
|---|
 | 294 |                 root = head['_X4nextPY13__tE_generic__1'].cast(cfa_t.thread_ptr)
 | 
|---|
| [96df7c9c] | 295 | 
 | 
|---|
| [9987d79] | 296 |                 if root == 0x0 or root.address == 0x0:
 | 
|---|
 | 297 |                         print('There are no tasks for cluster: {}'.format(cluster))
 | 
|---|
 | 298 |                         return threads
 | 
|---|
| [96df7c9c] | 299 | 
 | 
|---|
| [9987d79] | 300 |                 curr = root
 | 
|---|
 | 301 |                 tid = 0
 | 
|---|
 | 302 |                 sid = -1
 | 
|---|
| [96df7c9c] | 303 | 
 | 
|---|
| [9987d79] | 304 |                 while True:
 | 
|---|
 | 305 |                         t = ThreadInfo(cluster, curr)
 | 
|---|
 | 306 |                         if t.is_system():
 | 
|---|
 | 307 |                                 t.tid = sid
 | 
|---|
 | 308 |                                 sid -= 1
 | 
|---|
 | 309 |                         else:
 | 
|---|
 | 310 |                                 t.tid = tid
 | 
|---|
 | 311 |                                 tid += 1
 | 
|---|
| [96df7c9c] | 312 | 
 | 
|---|
| [9987d79] | 313 |                         threads.append(t)
 | 
|---|
| [96df7c9c] | 314 | 
 | 
|---|
| [262d4d51] | 315 |                         curr = fix_dlink(single_field(curr['cltr_link'])['_X4nextPY13__tE_generic__1']).cast(cfa_t.thread_ptr)
 | 
|---|
| [9987d79] | 316 |                         if curr == root or curr == 0x0:
 | 
|---|
 | 317 |                                 break
 | 
|---|
| [96df7c9c] | 318 | 
 | 
|---|
| [9987d79] | 319 |                 return threads
 | 
|---|
| [96df7c9c] | 320 | 
 | 
|---|
| [1cfdee9] | 321 | def system_thread(thread):
 | 
|---|
| [9987d79] | 322 |         return False
 | 
|---|
| [1cfdee9] | 323 | 
 | 
|---|
 | 324 | def adjust_stack(pc, fp, sp):
 | 
|---|
| [9987d79] | 325 |         # pop sp, fp, pc from global stack
 | 
|---|
 | 326 |         gdb.execute('set $pc = {}'.format(pc))
 | 
|---|
 | 327 |         gdb.execute('set $rbp = {}'.format(fp))
 | 
|---|
 | 328 |         gdb.execute('set $sp = {}'.format(sp))
 | 
|---|
| [1cfdee9] | 329 | 
 | 
|---|
 | 330 | ############################ COMMAND IMPLEMENTATION #########################
 | 
|---|
 | 331 | 
 | 
|---|
 | 332 | class Clusters(gdb.Command):
 | 
|---|
| [9987d79] | 333 |         """Cforall: Display currently known clusters
 | 
|---|
| [bb75b4e] | 334 | Usage:
 | 
|---|
| [9987d79] | 335 |         info clusters                 : print out all the clusters
 | 
|---|
| [bb75b4e] | 336 | """
 | 
|---|
| [1cfdee9] | 337 | 
 | 
|---|
| [9987d79] | 338 |         def __init__(self):
 | 
|---|
 | 339 |                 super(Clusters, self).__init__('info clusters', gdb.COMMAND_USER)
 | 
|---|
| [1cfdee9] | 340 | 
 | 
|---|
| [9987d79] | 341 |         def print_cluster(self, cluster_name, cluster_address):
 | 
|---|
 | 342 |                 print('{:>20}  {:>20}'.format(cluster_name, cluster_address))
 | 
|---|
| [1cfdee9] | 343 | 
 | 
|---|
| [9987d79] | 344 |         #entry point from gdb
 | 
|---|
 | 345 |         def invoke(self, arg, from_tty):
 | 
|---|
 | 346 |                 if not is_cforall():
 | 
|---|
 | 347 |                         return
 | 
|---|
| [1cfdee9] | 348 | 
 | 
|---|
| [9987d79] | 349 |                 if arg:
 | 
|---|
 | 350 |                         print("info clusters does not take arguments")
 | 
|---|
 | 351 |                         print_usage(self)
 | 
|---|
 | 352 |                         return
 | 
|---|
| [1cfdee9] | 353 | 
 | 
|---|
| [9987d79] | 354 |                 self.print_cluster('Name', 'Address')
 | 
|---|
| [1cfdee9] | 355 | 
 | 
|---|
| [9987d79] | 356 |                 for c in all_clusters():
 | 
|---|
 | 357 |                         self.print_cluster(c['_X4namePKc_1'].string(), str(c))
 | 
|---|
| [1cfdee9] | 358 | 
 | 
|---|
| [9987d79] | 359 |                 print("")
 | 
|---|
| [1cfdee9] | 360 | 
 | 
|---|
 | 361 | ############
 | 
|---|
 | 362 | class Processors(gdb.Command):
 | 
|---|
| [9987d79] | 363 |         """Cforall: Display currently known processors
 | 
|---|
| [bb75b4e] | 364 | Usage:
 | 
|---|
| [d8b17e2] | 365 |         info processors                 : print out all the processors
 | 
|---|
| [9987d79] | 366 |         info processors <cluster_name>  : print out all processors in a given cluster
 | 
|---|
| [bb75b4e] | 367 | """
 | 
|---|
| [1cfdee9] | 368 | 
 | 
|---|
| [9987d79] | 369 |         def __init__(self):
 | 
|---|
 | 370 |                 super(Processors, self).__init__('info processors', gdb.COMMAND_USER)
 | 
|---|
 | 371 | 
 | 
|---|
| [9dad5b3] | 372 |         def print_processor(self, processor, in_stats):
 | 
|---|
| [d8b17e2] | 373 |                 should_stop = processor['_X12do_terminateVb_1']
 | 
|---|
 | 374 |                 if not should_stop:
 | 
|---|
| [9dad5b3] | 375 |                         status = in_stats
 | 
|---|
| [d8b17e2] | 376 |                 else:
 | 
|---|
| [9987d79] | 377 |                         stop_count  = processor['_X10terminatedS9semaphore_1']['_X5counti_1']
 | 
|---|
| [d8b17e2] | 378 |                         status_str  = 'Last Thread' if stop_count >= 0 else 'Terminating'
 | 
|---|
 | 379 |                         status      = '{}({},{})'.format(status_str, should_stop, stop_count)
 | 
|---|
 | 380 | 
 | 
|---|
 | 381 |                 print('{:>20}  {:>11}  {:<7}  {:<}'.format(
 | 
|---|
 | 382 |                         processor['_X4namePKc_1'].string(),
 | 
|---|
 | 383 |                         status,
 | 
|---|
 | 384 |                         str(processor['_X18pending_preemptionb_1']),
 | 
|---|
 | 385 |                         str(processor)
 | 
|---|
 | 386 |                 ))
 | 
|---|
 | 387 |                 tls = tls_for_proc( processor )
 | 
|---|
| [2e94d94f] | 388 |                 thrd = thread_for_proc( processor )
 | 
|---|
| [d8b17e2] | 389 |                 if thrd != 0x0:
 | 
|---|
 | 390 |                         tname = '{} {}'.format(thrd['self_cor']['name'].string(), str(thrd))
 | 
|---|
 | 391 |                 else:
 | 
|---|
 | 392 |                         tname = None
 | 
|---|
| [9987d79] | 393 | 
 | 
|---|
| [d8b17e2] | 394 |                 print('{:>20}  {}'.format('Thread', tname))
 | 
|---|
 | 395 |                 print('{:>20}  {}'.format('TLS', tls))
 | 
|---|
| [9987d79] | 396 | 
 | 
|---|
 | 397 |         #entry point from gdb
 | 
|---|
 | 398 |         def invoke(self, arg, from_tty):
 | 
|---|
 | 399 |                 if not is_cforall():
 | 
|---|
 | 400 |                         return
 | 
|---|
 | 401 | 
 | 
|---|
 | 402 |                 if not arg:
 | 
|---|
 | 403 |                         clusters = all_clusters()
 | 
|---|
 | 404 |                 else:
 | 
|---|
 | 405 |                         clusters = [lookup_cluster(arg)]
 | 
|---|
 | 406 | 
 | 
|---|
 | 407 |                 if not clusters:
 | 
|---|
 | 408 |                         print("No Cluster matching arguments found")
 | 
|---|
 | 409 |                         return
 | 
|---|
 | 410 | 
 | 
|---|
| [d8b17e2] | 411 |                 print('{:>20}  {:>11}  {:<7}  {}'.format('Processor', '', 'Pending', 'Object'))
 | 
|---|
 | 412 |                 print('{:>20}  {:>11}  {:<7}  {}'.format('Name', 'Status', 'Yield', 'Address'))
 | 
|---|
| [9dad5b3] | 413 |                 for c in clusters:
 | 
|---|
 | 414 |                         print('Cluster {}'.format(c['_X4namePKc_1'].string()))
 | 
|---|
| [d8b17e2] | 415 | 
 | 
|---|
| [9dad5b3] | 416 |                         active, idle = proc_list(c)
 | 
|---|
| [d8b17e2] | 417 |                         # print the processor information
 | 
|---|
| [9dad5b3] | 418 |                         for p in active:
 | 
|---|
 | 419 |                                 self.print_processor(p, 'Active')
 | 
|---|
 | 420 | 
 | 
|---|
 | 421 |                         for p in idle:
 | 
|---|
 | 422 |                                 self.print_processor(p, 'Idle')
 | 
|---|
 | 423 | 
 | 
|---|
 | 424 |                         print()
 | 
|---|
| [9987d79] | 425 | 
 | 
|---|
 | 426 |                 print()
 | 
|---|
| [1cfdee9] | 427 | 
 | 
|---|
 | 428 | ############
 | 
|---|
 | 429 | class Threads(gdb.Command):
 | 
|---|
| [9987d79] | 430 |         """Cforall: Display currently known threads
 | 
|---|
| [96df7c9c] | 431 | Usage:
 | 
|---|
| [9987d79] | 432 |         cfathreads                           : print Main Cluster threads, application threads only
 | 
|---|
 | 433 |         cfathreads all                       : print all clusters, all threads
 | 
|---|
 | 434 |         cfathreads <clusterName>             : print cluster threads, application threads only
 | 
|---|
 | 435 |         """
 | 
|---|
 | 436 |         def __init__(self):
 | 
|---|
 | 437 |                 # The first parameter of the line below is the name of the command. You
 | 
|---|
 | 438 |                 # can call it 'uc++ task'
 | 
|---|
 | 439 |                 super(Threads, self).__init__('info cfathreads', gdb.COMMAND_USER)
 | 
|---|
 | 440 | 
 | 
|---|
 | 441 |         def print_formatted(self, marked, tid, name, state, address):
 | 
|---|
| [262d4d51] | 442 |                 # print(marked, tid, name, state, address)
 | 
|---|
| [9987d79] | 443 |                 print('{:>1}  {:>4}  {:>20}  {:>10}  {:>20}'.format('*' if marked else ' ', tid, name, state, address))
 | 
|---|
 | 444 | 
 | 
|---|
 | 445 |         def print_thread(self, thread, tid, marked):
 | 
|---|
| [262d4d51] | 446 |                 # print("print", thread, tid, marked)
 | 
|---|
| [9987d79] | 447 |                 cfa_t = get_cfa_types()
 | 
|---|
| [6abcb4d] | 448 |                 ys = str(thread['preempted'].cast(cfa_t.yield_state))
 | 
|---|
 | 449 |                 if ys == '_X15__NO_PREEMPTIONKM19__Preemption_Reason_1':
 | 
|---|
 | 450 |                         state = str(thread['state'].cast(cfa_t.thread_state))
 | 
|---|
 | 451 |                 elif ys == '_X18__ALARM_PREEMPTIONKM19__Preemption_Reason_1':
 | 
|---|
 | 452 |                         state = 'preempted'
 | 
|---|
 | 453 |                 elif ys == '_X19__MANUAL_PREEMPTIONKM19__Preemption_Reason_1':
 | 
|---|
 | 454 |                         state = 'yield'
 | 
|---|
 | 455 |                 elif ys == '_X17__POLL_PREEMPTIONKM19__Preemption_Reason_1':
 | 
|---|
 | 456 |                         state = 'poll'
 | 
|---|
 | 457 |                 else:
 | 
|---|
 | 458 |                         print("error: thread {} in undefined preemption state {}".format(thread, ys))
 | 
|---|
 | 459 |                         state = 'error'
 | 
|---|
 | 460 |                 self.print_formatted(marked, tid, thread['self_cor']['name'].string(), state, str(thread))
 | 
|---|
| [9987d79] | 461 | 
 | 
|---|
 | 462 |         def print_threads_by_cluster(self, cluster, print_system = False):
 | 
|---|
 | 463 |                 # Iterate through a circular linked list of tasks and print out its
 | 
|---|
 | 464 |                 # name along with address associated to each cluster
 | 
|---|
 | 465 |                 threads = lookup_threads_by_cluster(cluster)
 | 
|---|
 | 466 |                 if not threads:
 | 
|---|
 | 467 |                         return
 | 
|---|
 | 468 | 
 | 
|---|
 | 469 |                 running_thread = find_curr_thread()
 | 
|---|
 | 470 |                 if running_thread is None:
 | 
|---|
 | 471 |                         print('Could not identify current thread')
 | 
|---|
 | 472 | 
 | 
|---|
 | 473 |                 self.print_formatted(False, '', 'Name', 'State', 'Address')
 | 
|---|
 | 474 |                 for t in threads:
 | 
|---|
 | 475 |                         if not t.is_system() or print_system:
 | 
|---|
 | 476 |                                 self.print_thread(t.value, t.tid, t.value == running_thread if running_thread else False)
 | 
|---|
 | 477 | 
 | 
|---|
 | 478 |                 print()
 | 
|---|
 | 479 | 
 | 
|---|
 | 480 |         def print_all_threads(self):
 | 
|---|
 | 481 |                 for c in all_clusters():
 | 
|---|
 | 482 |                         self.print_threads_by_cluster(c, False)
 | 
|---|
 | 483 | 
 | 
|---|
 | 484 |         def invoke(self, arg, from_tty):
 | 
|---|
 | 485 |                 """
 | 
|---|
 | 486 |                 @arg: str
 | 
|---|
 | 487 |                 @from_tty: bool
 | 
|---|
 | 488 |                 """
 | 
|---|
 | 489 |                 if not is_cforall():
 | 
|---|
 | 490 |                         return
 | 
|---|
 | 491 | 
 | 
|---|
 | 492 |                 if not arg:
 | 
|---|
 | 493 |                         cluster = lookup_cluster()
 | 
|---|
 | 494 |                         if not cluster:
 | 
|---|
 | 495 |                                 print("Could not find Main Cluster")
 | 
|---|
 | 496 |                                 return
 | 
|---|
 | 497 | 
 | 
|---|
 | 498 |                         # only tasks and main
 | 
|---|
 | 499 |                         self.print_threads_by_cluster(cluster, False)
 | 
|---|
 | 500 | 
 | 
|---|
 | 501 |                 elif arg == 'all':
 | 
|---|
 | 502 |                         # all threads, all clusters
 | 
|---|
 | 503 |                         self.print_all_threads()
 | 
|---|
 | 504 | 
 | 
|---|
 | 505 |                 else:
 | 
|---|
 | 506 |                         cluster = lookup_cluster(arg)
 | 
|---|
 | 507 |                         if not cluster:
 | 
|---|
| [9dad5b3] | 508 |                                 print("No matching cluster")
 | 
|---|
| [9987d79] | 509 |                                 return
 | 
|---|
 | 510 | 
 | 
|---|
 | 511 |                         # all tasks, specified cluster
 | 
|---|
 | 512 |                         self.print_threads_by_cluster(cluster, True)
 | 
|---|
| [96df7c9c] | 513 | 
 | 
|---|
| [bb75b4e] | 514 | 
 | 
|---|
 | 515 | ############
 | 
|---|
 | 516 | class Thread(gdb.Command):
 | 
|---|
| [9987d79] | 517 |         """Cforall: Switch to specified user threads
 | 
|---|
 | 518 | Usage:
 | 
|---|
 | 519 |         cfathread <id>                       : switch stack to thread id on main cluster
 | 
|---|
 | 520 |         cfathread 0x<address>                : switch stack to thread on any cluster
 | 
|---|
 | 521 |         cfathread <id> <clusterName>         : switch stack to thread on specified cluster
 | 
|---|
 | 522 |         """
 | 
|---|
 | 523 |         def __init__(self):
 | 
|---|
 | 524 |                 # The first parameter of the line below is the name of the command. You
 | 
|---|
 | 525 |                 # can call it 'uc++ task'
 | 
|---|
 | 526 |                 super(Thread, self).__init__('cfathread', gdb.COMMAND_USER)
 | 
|---|
 | 527 | 
 | 
|---|
 | 528 |         ############################ AUXILIARY FUNCTIONS #########################
 | 
|---|
 | 529 | 
 | 
|---|
 | 530 |         def switchto(self, thread):
 | 
|---|
 | 531 |                 """Change to a new task by switching to a different stack and manually
 | 
|---|
 | 532 |                 adjusting sp, fp and pc
 | 
|---|
 | 533 |                 @task_address: str
 | 
|---|
 | 534 |                         2 supported format:
 | 
|---|
 | 535 |                                 in hex format
 | 
|---|
 | 536 |                                         <hex_address>: literal hexadecimal address
 | 
|---|
 | 537 |                                         Ex: 0xffffff
 | 
|---|
 | 538 |                                 in name of the pointer to the task
 | 
|---|
 | 539 |                                         "task_name": pointer of the variable name of the cluster
 | 
|---|
 | 540 |                                                 Ex: T* s -> task_name = s
 | 
|---|
 | 541 |                         Return: gdb.value of the cluster's address
 | 
|---|
 | 542 |                 """
 | 
|---|
 | 543 |                 try:
 | 
|---|
 | 544 |                         if not gdb.lookup_symbol('__cfactx_switch'):
 | 
|---|
 | 545 |                                 print('__cfactx_switch symbol is unavailable')
 | 
|---|
 | 546 |                                 return
 | 
|---|
 | 547 |                 except:
 | 
|---|
 | 548 |                         print('here 3')
 | 
|---|
 | 549 | 
 | 
|---|
 | 550 |                 cfa_t = get_cfa_types()
 | 
|---|
 | 551 | 
 | 
|---|
 | 552 |                 state = thread['state'].cast(cfa_t.thread_state)
 | 
|---|
 | 553 |                 try:
 | 
|---|
 | 554 |                         if state == gdb.parse_and_eval('Halted'):
 | 
|---|
 | 555 |                                 print('Cannot switch to a terminated thread')
 | 
|---|
 | 556 |                                 return
 | 
|---|
 | 557 | 
 | 
|---|
 | 558 |                         if state == gdb.parse_and_eval('Start'):
 | 
|---|
 | 559 |                                 print('Cannjot switch to a thread not yet run')
 | 
|---|
 | 560 |                                 return
 | 
|---|
 | 561 |                 except:
 | 
|---|
 | 562 |                         print("here 2")
 | 
|---|
 | 563 |                         return
 | 
|---|
 | 564 | 
 | 
|---|
 | 565 | 
 | 
|---|
 | 566 |                 context = thread['context']
 | 
|---|
 | 567 | 
 | 
|---|
| [c0c0bd5] | 568 | 
 | 
|---|
 | 569 | 
 | 
|---|
 | 570 |                 # must be at frame 0 to set pc register
 | 
|---|
 | 571 |                 gdb.execute('select-frame 0')
 | 
|---|
 | 572 |                 if gdb.selected_frame().architecture().name() != 'i386:x86-64':
 | 
|---|
 | 573 |                         print('gdb debugging only supported for i386:x86-64 for now')
 | 
|---|
 | 574 |                         return
 | 
|---|
 | 575 | 
 | 
|---|
 | 576 |                 # gdb seems to handle things much better if we pretend we just entered the context switch
 | 
|---|
 | 577 |                 # pretend the pc is __cfactx_switch and adjust the sp, base pointer doesn't need to change
 | 
|---|
| [9987d79] | 578 |                 # lookup for sp,fp and uSwitch
 | 
|---|
| [c0c0bd5] | 579 |                 xsp = context['SP'] + 40 # 40 = 5 64bit registers : %r15, %r14, %r13, %r12, %rbx WARNING: x64 specific
 | 
|---|
| [9987d79] | 580 |                 xfp = context['FP']
 | 
|---|
 | 581 | 
 | 
|---|
 | 582 |                 # convert string so we can strip out the address
 | 
|---|
 | 583 |                 try:
 | 
|---|
| [c0c0bd5] | 584 |                         xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address)
 | 
|---|
| [9987d79] | 585 |                 except:
 | 
|---|
 | 586 |                         print("here")
 | 
|---|
 | 587 |                         return
 | 
|---|
 | 588 | 
 | 
|---|
 | 589 |                 # push sp, fp, pc into a global stack
 | 
|---|
 | 590 |                 global STACK
 | 
|---|
 | 591 |                 sp = gdb.parse_and_eval('$sp')
 | 
|---|
 | 592 |                 fp = gdb.parse_and_eval('$fp')
 | 
|---|
 | 593 |                 pc = gdb.parse_and_eval('$pc')
 | 
|---|
 | 594 |                 stack_info = StackInfo(sp = sp, fp = fp, pc = pc)
 | 
|---|
 | 595 |                 STACK.append(stack_info)
 | 
|---|
 | 596 | 
 | 
|---|
 | 597 |                 # update registers for new task
 | 
|---|
| [c0c0bd5] | 598 |                 # print('switching to {} ({}) : [{}, {}, {}]'.format(thread['self_cor']['name'].string(), str(thread), str(xsp), str(xfp), str(xpc)))
 | 
|---|
 | 599 |                 print('switching to thread {} ({})'.format(str(thread), thread['self_cor']['name'].string()))
 | 
|---|
| [9987d79] | 600 |                 gdb.execute('set $rsp={}'.format(xsp))
 | 
|---|
 | 601 |                 gdb.execute('set $rbp={}'.format(xfp))
 | 
|---|
 | 602 |                 gdb.execute('set $pc={}'.format(xpc))
 | 
|---|
 | 603 | 
 | 
|---|
 | 604 |         def find_matching_gdb_thread_id():
 | 
|---|
 | 605 |                 """
 | 
|---|
 | 606 |                 Parse the str from info thread to get the number
 | 
|---|
 | 607 |                 """
 | 
|---|
 | 608 |                 info_thread_str = gdb.execute('info thread', to_string=True).splitlines()
 | 
|---|
 | 609 |                 for thread_str in info_thread_str:
 | 
|---|
 | 610 |                         if thread_str.find('this={}'.format(task)) != -1:
 | 
|---|
 | 611 |                                 thread_id_pattern = r'^\*?\s+(\d+)\s+Thread'
 | 
|---|
 | 612 |                                 # retrive gdb thread id
 | 
|---|
 | 613 |                                 return re.match(thread_id_pattern, thread_str).group(1)
 | 
|---|
 | 614 | 
 | 
|---|
 | 615 |                         # check if the task is running or not
 | 
|---|
 | 616 |                         if task_state == gdb.parse_and_eval('uBaseTask::Running'):
 | 
|---|
 | 617 |                                 # find the equivalent thread from info thread
 | 
|---|
 | 618 |                                 gdb_thread_id = find_matching_gdb_thread_id()
 | 
|---|
 | 619 |                                 if gdb_thread_id is None:
 | 
|---|
 | 620 |                                         print('cannot find the thread id to switch to')
 | 
|---|
 | 621 |                                         return
 | 
|---|
 | 622 |                                 # switch to that thread based using thread command
 | 
|---|
 | 623 |                                 gdb.execute('thread {}'.format(gdb_thread_id))
 | 
|---|
 | 624 | 
 | 
|---|
 | 625 |         def switchto_id(self, tid, cluster):
 | 
|---|
 | 626 |                 """
 | 
|---|
 | 627 |                 @cluster: cluster object
 | 
|---|
 | 628 |                 @tid: int
 | 
|---|
 | 629 |                 """
 | 
|---|
 | 630 |                 threads = lookup_threads_by_cluster( cluster )
 | 
|---|
 | 631 | 
 | 
|---|
 | 632 |                 for t in threads:
 | 
|---|
 | 633 |                         if t.tid == tid:
 | 
|---|
 | 634 |                                 self.switchto(t.value)
 | 
|---|
 | 635 |                                 return
 | 
|---|
 | 636 | 
 | 
|---|
 | 637 |                 print("Cound not find thread by id '{}'".format(tid))
 | 
|---|
 | 638 | 
 | 
|---|
 | 639 |         def invoke(self, arg, from_tty):
 | 
|---|
 | 640 |                 """
 | 
|---|
 | 641 |                 @arg: str
 | 
|---|
 | 642 |                 @from_tty: bool
 | 
|---|
 | 643 |                 """
 | 
|---|
 | 644 |                 if not is_cforall():
 | 
|---|
 | 645 |                         return
 | 
|---|
 | 646 | 
 | 
|---|
 | 647 |                 argv = parse(arg)
 | 
|---|
 | 648 |                 if argv[0].isdigit():
 | 
|---|
 | 649 |                         cname = " ".join(argv[1:]) if len(argv) > 1 else None
 | 
|---|
 | 650 |                         cluster = lookup_cluster(cname)
 | 
|---|
 | 651 |                         if not cluster:
 | 
|---|
 | 652 |                                 print("Could not find cluster '{}'".format(cname if cname else "Main Cluster"))
 | 
|---|
 | 653 |                                 return
 | 
|---|
 | 654 | 
 | 
|---|
 | 655 |                         try:
 | 
|---|
 | 656 |                                 tid = int(argv[0])
 | 
|---|
 | 657 |                         except:
 | 
|---|
 | 658 |                                 print("'{}' not a valid thread id".format(argv[0]))
 | 
|---|
 | 659 |                                 print_usage(self)
 | 
|---|
 | 660 |                                 return
 | 
|---|
 | 661 | 
 | 
|---|
 | 662 |                                 # by id, userCluster
 | 
|---|
 | 663 |                         self.switchto_id(tid, cluster)
 | 
|---|
 | 664 | 
 | 
|---|
 | 665 |                 elif argv[0].startswith('0x') or argv[0].startswith('0X'):
 | 
|---|
 | 666 |                         self.switchto(argv[0]) # by address, any cluster
 | 
|---|
| [1cfdee9] | 667 | 
 | 
|---|
 | 668 | ############
 | 
|---|
 | 669 | class PrevThread(gdb.Command):
 | 
|---|
| [9987d79] | 670 |         """Switch back to previous task on the stack"""
 | 
|---|
 | 671 |         usage_msg = 'prevtask'
 | 
|---|
 | 672 | 
 | 
|---|
 | 673 |         def __init__(self):
 | 
|---|
 | 674 |                 super(PrevThread, self).__init__('prevtask', gdb.COMMAND_USER)
 | 
|---|
 | 675 | 
 | 
|---|
 | 676 |         def invoke(self, arg, from_tty):
 | 
|---|
 | 677 |                 """
 | 
|---|
 | 678 |                 @arg: str
 | 
|---|
 | 679 |                 @from_tty: bool
 | 
|---|
 | 680 |                 """
 | 
|---|
 | 681 |                 global STACK
 | 
|---|
 | 682 |                 if len(STACK) != 0:
 | 
|---|
 | 683 |                         # must be at frame 0 to set pc register
 | 
|---|
 | 684 |                         gdb.execute('select-frame 0')
 | 
|---|
 | 685 | 
 | 
|---|
 | 686 |                         # pop stack
 | 
|---|
 | 687 |                         stack_info = STACK.pop()
 | 
|---|
 | 688 |                         pc = get_addr(stack_info.pc)
 | 
|---|
 | 689 |                         sp = stack_info.sp
 | 
|---|
 | 690 |                         fp = stack_info.fp
 | 
|---|
 | 691 | 
 | 
|---|
 | 692 |                         # pop sp, fp, pc from global stack
 | 
|---|
 | 693 |                         adjust_stack(pc, fp, sp)
 | 
|---|
 | 694 | 
 | 
|---|
 | 695 |                         # must be at C++ frame to access C++ vars
 | 
|---|
 | 696 |                         gdb.execute('frame 1')
 | 
|---|
 | 697 |                 else:
 | 
|---|
 | 698 |                         print('empty stack')
 | 
|---|
| [1cfdee9] | 699 | 
 | 
|---|
 | 700 | class ResetOriginFrame(gdb.Command):
 | 
|---|
| [9987d79] | 701 |         """Reset to the origin frame prior to continue execution again"""
 | 
|---|
 | 702 |         usage_msg = 'resetOriginFrame'
 | 
|---|
 | 703 |         def __init__(self):
 | 
|---|
 | 704 |                 super(ResetOriginFrame, self).__init__('reset', gdb.COMMAND_USER)
 | 
|---|
 | 705 | 
 | 
|---|
 | 706 |         def invoke(self, arg, from_tty):
 | 
|---|
 | 707 |                 """
 | 
|---|
 | 708 |                 @arg: str
 | 
|---|
 | 709 |                 @from_tty: bool
 | 
|---|
 | 710 |                 """
 | 
|---|
 | 711 |                 global STACK
 | 
|---|
 | 712 |                 if len(STACK) != 0:
 | 
|---|
 | 713 |                         stack_info = STACK.pop(0)
 | 
|---|
 | 714 |                         STACK.clear()
 | 
|---|
 | 715 |                         pc = get_addr(stack_info.pc)
 | 
|---|
 | 716 |                         sp = stack_info.sp
 | 
|---|
 | 717 |                         fp = stack_info.fp
 | 
|---|
 | 718 | 
 | 
|---|
 | 719 |                         # pop sp, fp, pc from global stack
 | 
|---|
 | 720 |                         adjust_stack(pc, fp, sp)
 | 
|---|
 | 721 | 
 | 
|---|
 | 722 |                         # must be at C++ frame to access C++ vars
 | 
|---|
 | 723 |                         gdb.execute('frame 1')
 | 
|---|
 | 724 |                 #else:
 | 
|---|
 | 725 |                         #print('reset: empty stack') #probably does not have to print msg
 | 
|---|
| [1cfdee9] | 726 | 
 | 
|---|
 | 727 | Clusters()
 | 
|---|
 | 728 | Processors()
 | 
|---|
 | 729 | ResetOriginFrame()
 | 
|---|
 | 730 | PrevThread()
 | 
|---|
 | 731 | Threads()
 | 
|---|
| [9987d79] | 732 | Thread()
 | 
|---|
| [1cfdee9] | 733 | 
 | 
|---|
 | 734 | # Local Variables: #
 | 
|---|
 | 735 | # mode: Python #
 | 
|---|
 | 736 | # End: #
 | 
|---|