source: tools/gdb/utils-gdb.py @ c02cef1

ADTast-experimental
Last change on this file since c02cef1 was 2e94d94f, checked in by Thierry Delisle <tdelisle@…>, 2 years ago

Fixed a few bugs in the processor listing.

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