Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • tools/gdb/utils-gdb.py

    r9987d79 r96df7c9c  
    2626
    2727class ThreadInfo:
    28         tid = 0
    29         cluster = None
    30         value = None
    31 
    32         def __init__(self, cluster, value):
    33                 self.cluster = cluster
    34                 self.value = value
    35 
    36         def is_system(self):
    37                 return False
     28    tid = 0
     29    cluster = None
     30    value = None
     31
     32    def __init__(self, cluster, value):
     33        self.cluster = cluster
     34        self.value = value
     35
     36    def is_system(self):
     37        return False
    3838
    3939# A named tuple representing information about a stack
     
    5151
    5252def is_cforall():
    53         return True
     53    return True
    5454
    5555def get_cfa_types():
    56         # GDB types for various structures/types in CFA
    57         return CfaTypes(cluster_ptr = gdb.lookup_type('struct cluster').pointer(),
    58                                   processor_ptr = gdb.lookup_type('struct processor').pointer(),
    59                                         thread_ptr = gdb.lookup_type('struct $thread').pointer(),
    60                                                 int_ptr = gdb.lookup_type('int').pointer(),
    61                                    thread_state = gdb.lookup_type('enum coroutine_state'))
     56    # GDB types for various structures/types in CFA
     57    return CfaTypes(cluster_ptr = gdb.lookup_type('struct cluster').pointer(),
     58                  processor_ptr = gdb.lookup_type('struct processor').pointer(),
     59                    thread_ptr = gdb.lookup_type('struct $thread').pointer(),
     60                        int_ptr = gdb.lookup_type('int').pointer(),
     61                   thread_state = gdb.lookup_type('enum coroutine_state'))
    6262
    6363def get_addr(addr):
    64         """
    65         NOTE: sketchy solution to retrieve address. There is a better solution...
    66         @addr: str of an address that can be in a format 0xfffff <type of the object
    67         at this address>
    68         Return: str of just the address
    69         """
    70         str_addr = str(addr)
    71         ending_addr_index = str_addr.find('<')
    72         if ending_addr_index == -1:
    73                 return str(addr)
    74         return str_addr[:ending_addr_index].strip()
     64    """
     65    NOTE: sketchy solution to retrieve address. There is a better solution...
     66    @addr: str of an address that can be in a format 0xfffff <type of the object
     67    at this address>
     68    Return: str of just the address
     69    """
     70    str_addr = str(addr)
     71    ending_addr_index = str_addr.find('<')
     72    if ending_addr_index == -1:
     73        return str(addr)
     74    return str_addr[:ending_addr_index].strip()
    7575
    7676def print_usage(obj):
    77         print(obj.__doc__)
     77    print(obj.__doc__)
    7878
    7979def parse(args):
    80         """
    81         Split the argument list in string format, where each argument is separated
    82         by whitespace delimiter, to a list of arguments like argv
    83         @args: str of arguments
    84         Return:
    85                 [] if args is an empty string
    86                 list if args is not empty
    87         """
    88         # parse the string format of arguments and return a list of arguments
    89         argv = args.split(' ')
    90         if len(argv) == 1 and argv[0] == '':
    91                 return []
    92         return argv
     80    """
     81    Split the argument list in string format, where each argument is separated
     82    by whitespace delimiter, to a list of arguments like argv
     83    @args: str of arguments
     84    Return:
     85        [] if args is an empty string
     86        list if args is not empty
     87    """
     88    # parse the string format of arguments and return a list of arguments
     89    argv = args.split(' ')
     90    if len(argv) == 1 and argv[0] == '':
     91        return []
     92    return argv
    9393
    9494def get_cluster_root():
    95         """
    96         Return: gdb.Value of globalClusters.root (is an address)
    97         """
    98         cluster_root = gdb.parse_and_eval('_X11mainClusterPS7cluster_1')
    99         if cluster_root.address == 0x0:
    100                 print('No clusters, program terminated')
    101         return cluster_root
     95    """
     96    Return: gdb.Value of globalClusters.root (is an address)
     97    """
     98    cluster_root = gdb.parse_and_eval('_X11mainClusterPS7cluster_1')
     99    if cluster_root.address == 0x0:
     100        print('No clusters, program terminated')
     101    return cluster_root
    102102
    103103def find_curr_thread():
    104         # btstr = gdb.execute('bt', to_string = True).splitlines()
    105         # if len(btstr) == 0:
    106         #     print('error')
    107         #     return None
    108         # return btstr[0].split('this=',1)[1].split(',')[0].split(')')[0]
    109         return None
    110 
    111 def all_clusters():
    112         if not is_cforall():
    113                 return None
    114 
    115         cluster_root = get_cluster_root()
    116         if cluster_root.address == 0x0:
    117                 return
    118 
    119         curr = cluster_root
    120         ret = [curr]
    121 
    122         while True:
    123                 curr = curr['_X4nodeS26__cluster____dbg_node_cltr_1']['_X4nextPS7cluster_1']
    124                 if curr == cluster_root:
    125                         break
    126 
    127                 ret.append(curr)
    128 
    129         return ret
    130 
     104    # btstr = gdb.execute('bt', to_string = True).splitlines()
     105    # if len(btstr) == 0:
     106    #     print('error')
     107    #     return None
     108    # return btstr[0].split('this=',1)[1].split(',')[0].split(')')[0]
     109    return None
    131110
    132111def lookup_cluster(name = None):
    133         """
    134         Look up a cluster given its ID
    135         @name: str
    136         Return: gdb.Value
    137         """
    138         if not is_cforall():
    139                 return None
    140 
    141         root = get_cluster_root()
    142         if root.address == 0x0:
    143                 return None
    144 
    145         if not name:
    146                 return root
    147 
    148         # lookup for the task associated with the id
    149         cluster = None
    150         curr = root
    151         while True:
    152                 if curr['_X4namePKc_1'].string() == name:
    153                         cluster = curr.address
    154                         break
    155                 curr = curr['_X4nodeS26__cluster____dbg_node_cltr_1']['_X4nextPS7cluster_1']
    156                 if curr == root or curr == 0x0:
    157                         break
    158 
    159         if not cluster:
    160                 print("Cannot find a cluster with the name: {}.".format(name))
    161                 return None
    162 
    163         return cluster
     112    """
     113    Look up a cluster given its ID
     114    @name: str
     115    Return: gdb.Value
     116    """
     117    if not is_cforall():
     118        return None
     119
     120    root = get_cluster_root()
     121    if root.address == 0x0:
     122        return None
     123
     124    if not name:
     125        return root
     126
     127    # lookup for the task associated with the id
     128    cluster = None
     129    curr = root
     130    while True:
     131        if curr['_X4namePKc_1'].string() == name:
     132            cluster = curr.address
     133            break
     134        curr = curr['_X4nodeS26__cluster____dbg_node_cltr_1']['_X4nextPS7cluster_1']
     135        if curr == root or curr == 0x0:
     136            break
     137
     138    if not cluster:
     139        print("Cannot find a cluster with the name: {}.".format(name))
     140        return None
     141
     142    return cluster
    164143
    165144def lookup_threads_by_cluster(cluster):
    166                 # Iterate through a circular linked list of threads and accumulate them in an array
    167                 threads = []
    168 
    169                 cfa_t = get_cfa_types()
    170                 root = cluster['_X7threadsS8__dllist_S7$thread__1']['_X4headPY15__TYPE_generic__1'].cast(cfa_t.thread_ptr)
    171 
    172                 if root == 0x0 or root.address == 0x0:
    173                         print('There are no tasks for cluster: {}'.format(cluster))
    174                         return threads
    175 
    176                 curr = root
    177                 tid = 0
    178                 sid = -1
    179 
    180                 while True:
    181                         t = ThreadInfo(cluster, curr)
    182                         if t.is_system():
    183                                 t.tid = sid
    184                                 sid -= 1
    185                         else:
    186                                 t.tid = tid
    187                                 tid += 1
    188 
    189                         threads.append(t)
    190 
    191                         curr = curr['node']['next']
    192                         if curr == root or curr == 0x0:
    193                                 break
    194 
    195                 return threads
     145        # Iterate through a circular linked list of threads and accumulate them in an array
     146        threads = []
     147
     148        cfa_t = get_cfa_types()
     149        root = cluster['_X7threadsS8__dllist_S7$thread__1']['_X4headPY15__TYPE_generic__1'].cast(cfa_t.thread_ptr)
     150
     151        if root == 0x0 or root.address == 0x0:
     152            print('There are no tasks for cluster: {}'.format(cluster))
     153            return threads
     154
     155        curr = root
     156        tid = 0
     157        sid = -1
     158
     159        while True:
     160            t = ThreadInfo(cluster, curr)
     161            if t.is_system():
     162                t.tid = sid
     163                sid -= 1
     164            else:
     165                t.tid = tid
     166                tid += 1
     167
     168            threads.append(t)
     169
     170            curr = curr['node']['next']
     171            if curr == root or curr == 0x0:
     172                break
     173
     174        return threads
    196175
    197176def system_thread(thread):
    198         return False
     177    return False
    199178
    200179def adjust_stack(pc, fp, sp):
    201         # pop sp, fp, pc from global stack
    202         gdb.execute('set $pc = {}'.format(pc))
    203         gdb.execute('set $rbp = {}'.format(fp))
    204         gdb.execute('set $sp = {}'.format(sp))
     180    # pop sp, fp, pc from global stack
     181    gdb.execute('set $pc = {}'.format(pc))
     182    gdb.execute('set $rbp = {}'.format(fp))
     183    gdb.execute('set $sp = {}'.format(sp))
    205184
    206185############################ COMMAND IMPLEMENTATION #########################
    207186
    208187class Clusters(gdb.Command):
    209         """Cforall: Display currently known clusters
     188    """Cforall: Display currently known clusters
    210189Usage:
    211         info clusters                 : print out all the clusters
     190    info clusters                 : print out all the clusters
    212191"""
    213192
    214         def __init__(self):
    215                 super(Clusters, self).__init__('info clusters', gdb.COMMAND_USER)
    216 
    217         def print_cluster(self, cluster_name, cluster_address):
    218                 print('{:>20}  {:>20}'.format(cluster_name, cluster_address))
    219 
    220         #entry point from gdb
    221         def invoke(self, arg, from_tty):
    222                 if not is_cforall():
    223                         return
    224 
    225                 if arg:
    226                         print("info clusters does not take arguments")
    227                         print_usage(self)
    228                         return
    229 
    230                 self.print_cluster('Name', 'Address')
    231 
    232                 for c in all_clusters():
    233                         self.print_cluster(c['_X4namePKc_1'].string(), str(c))
    234 
    235                 print("")
     193    def __init__(self):
     194        super(Clusters, self).__init__('info clusters', gdb.COMMAND_USER)
     195
     196    def print_cluster(self, cluster_name, cluster_address):
     197        print('{:>20}  {:>20}'.format(cluster_name, cluster_address))
     198
     199    #entry point from gdb
     200    def invoke(self, arg, from_tty):
     201        if not is_cforall():
     202            return
     203
     204        if arg:
     205            print("info clusters does not take arguments")
     206            print_usage(self)
     207            return
     208
     209        cluster_root = get_cluster_root()
     210        if cluster_root.address == 0x0:
     211            return
     212
     213        curr = cluster_root
     214        self.print_cluster('Name', 'Address')
     215
     216        while True:
     217            self.print_cluster(curr['_X4namePKc_1'].string(), str(curr))
     218            curr = curr['_X4nodeS26__cluster____dbg_node_cltr_1']['_X4nextPS7cluster_1']
     219            if curr == cluster_root:
     220                break
     221
     222        print("")
    236223
    237224############
    238225class Processors(gdb.Command):
    239         """Cforall: Display currently known processors
     226    """Cforall: Display currently known processors
    240227Usage:
    241         info processors                 : print out all the processors in the Main Cluster
    242         info processors all             : print out all processors in all clusters
    243         info processors <cluster_name>  : print out all processors in a given cluster
     228    info processors                 : print out all the processors in the Main Cluster
     229    info processors <cluster_name>  : print out all processors in a given cluster
    244230"""
    245231
    246         def __init__(self):
    247                 super(Processors, self).__init__('info processors', gdb.COMMAND_USER)
    248 
    249         def print_processor(self, name, status, pending, address):
    250                 print('{:>20}  {:>11}  {:>13}  {:>20}'.format(name, status, pending, address))
    251 
    252         def iterate_procs(self, root, active):
    253                 if root == 0x0:
    254                         return
    255 
    256                 cfa_t = get_cfa_types()
    257                 curr = root
    258 
    259                 while True:
    260                         processor = curr
    261                         should_stop = processor['_X12do_terminateVb_1']
    262                         stop_count  = processor['_X10terminatedS9semaphore_1']['_X5counti_1']
    263                         if not should_stop:
    264                                 status = 'Active' if active else 'Idle'
    265                         else:
    266                                 status_str  = 'Last Thread' if stop_count >= 0 else 'Terminating'
    267                                 status      = '{}({},{})'.format(status_str, should_stop, stop_count)
    268 
    269                         self.print_processor(processor['_X4namePKc_1'].string(),
    270                                         status, str(processor['_X18pending_preemptionb_1']), str(processor)
    271                                 )
    272 
    273                         curr = curr['_X4nodeS28__processor____dbg_node_proc_1']['_X4nextPS9processor_1']
    274 
    275                         if curr == root or curr == 0x0:
    276                                 break
    277 
    278         #entry point from gdb
    279         def invoke(self, arg, from_tty):
    280                 if not is_cforall():
    281                         return
    282 
    283                 if not arg:
    284                         clusters = [lookup_cluster(None)]
    285                 elif arg == "all":
    286                         clusters = all_clusters()
    287                 else:
    288                         clusters = [lookup_cluster(arg)]
    289 
    290                 if not clusters:
    291                         print("No Cluster matching arguments found")
    292                         return
    293 
    294                 cfa_t = get_cfa_types()
    295                 for cluster in clusters:
    296                         print('Cluster: "{}"({})'.format(cluster['_X4namePKc_1'].string(), cluster.cast(cfa_t.cluster_ptr)))
    297 
    298                         active_root = cluster.cast(cfa_t.cluster_ptr) \
    299                                         ['_X5procsS8__dllist_S9processor__1'] \
    300                                         ['_X4headPY15__TYPE_generic__1'] \
    301                                         .cast(cfa_t.processor_ptr)
    302 
    303                         idle_root = cluster.cast(cfa_t.cluster_ptr) \
    304                                         ['_X5idlesS8__dllist_S9processor__1'] \
    305                                         ['_X4headPY15__TYPE_generic__1'] \
    306                                         .cast(cfa_t.processor_ptr)
    307 
    308                         if idle_root != 0x0 or active_root != 0x0:
    309                                 self.print_processor('Name', 'Status', 'Pending Yield', 'Address')
    310                                 self.iterate_procs(active_root, True)
    311                                 self.iterate_procs(idle_root, False)
    312                         else:
    313                                 print("No processors on cluster")
    314 
    315                 print()
     232    def __init__(self):
     233        super(Processors, self).__init__('info processors', gdb.COMMAND_USER)
     234
     235    def print_processor(self, name, status, pending, address):
     236        print('{:>20}  {:>11}  {:>13}  {:>20}'.format(name, status, pending, address))
     237
     238    def iterate_procs(self, root, active):
     239        if root == 0x0:
     240            return
     241
     242        cfa_t = get_cfa_types()
     243        curr = root
     244
     245        while True:
     246            processor = curr
     247            should_stop = processor['_X12do_terminateVb_1']
     248            stop_count  = processor['_X10terminatedS9semaphore_1']['_X5counti_1']
     249            if not should_stop:
     250                status = 'Active' if active else 'Idle'
     251            else:
     252                status_str  = 'Last Thread' if stop_count >= 0 else 'Terminating'
     253                status      = '{}({},{})'.format(status_str, should_stop, stop_count)
     254
     255            self.print_processor(processor['_X4namePKc_1'].string(),
     256                    status, str(processor['_X18pending_preemptionb_1']), str(processor)
     257                )
     258
     259            curr = curr['_X4nodeS28__processor____dbg_node_proc_1']['_X4nextPS9processor_1']
     260
     261            if curr == root or curr == 0x0:
     262                break
     263
     264    #entry point from gdb
     265    def invoke(self, arg, from_tty):
     266        if not is_cforall():
     267            return
     268
     269        cluster = lookup_cluster(arg if arg else None)
     270
     271        if not cluster:
     272            print("No Cluster matching arguments found")
     273            return
     274
     275        cfa_t = get_cfa_types()
     276        print('Cluster: "{}"({})'.format(cluster['_X4namePKc_1'].string(), cluster.cast(cfa_t.cluster_ptr)))
     277
     278        active_root = cluster.cast(cfa_t.cluster_ptr) \
     279                ['_X5procsS8__dllist_S9processor__1'] \
     280                ['_X4headPY15__TYPE_generic__1'] \
     281                .cast(cfa_t.processor_ptr)
     282
     283        idle_root = cluster.cast(cfa_t.cluster_ptr) \
     284                ['_X5idlesS8__dllist_S9processor__1'] \
     285                ['_X4headPY15__TYPE_generic__1'] \
     286                .cast(cfa_t.processor_ptr)
     287
     288        if idle_root != 0x0 or active_root != 0x0:
     289            self.print_processor('Name', 'Status', 'Pending Yield', 'Address')
     290            self.iterate_procs(active_root, True)
     291            self.iterate_procs(idle_root, False)
     292        else:
     293            print("No processors on cluster")
     294
     295        print()
    316296
    317297############
    318298class Threads(gdb.Command):
    319         """Cforall: Display currently known threads
     299    """Cforall: Display currently known threads
    320300Usage:
    321         cfathreads                           : print Main Cluster threads, application threads only
    322         cfathreads all                       : print all clusters, all threads
    323         cfathreads <clusterName>             : print cluster threads, application threads only
    324         """
    325         def __init__(self):
    326                 # The first parameter of the line below is the name of the command. You
    327                 # can call it 'uc++ task'
    328                 super(Threads, self).__init__('info cfathreads', gdb.COMMAND_USER)
    329 
    330         def print_formatted(self, marked, tid, name, state, address):
    331                 print('{:>1}  {:>4}  {:>20}  {:>10}  {:>20}'.format('*' if marked else ' ', tid, name, state, address))
    332 
    333         def print_thread(self, thread, tid, marked):
    334                 cfa_t = get_cfa_types()
    335                 self.print_formatted(marked, tid, thread['self_cor']['name'].string(), str(thread['state'].cast(cfa_t.thread_state)), str(thread))
    336 
    337         def print_threads_by_cluster(self, cluster, print_system = False):
    338                 # Iterate through a circular linked list of tasks and print out its
    339                 # name along with address associated to each cluster
    340                 threads = lookup_threads_by_cluster(cluster)
    341                 if not threads:
    342                         return
    343 
    344                 running_thread = find_curr_thread()
    345                 if running_thread is None:
    346                         print('Could not identify current thread')
    347 
    348                 self.print_formatted(False, '', 'Name', 'State', 'Address')
    349 
    350                 for t in threads:
    351                         if not t.is_system() or print_system:
    352                                 self.print_thread(t.value, t.tid, t.value == running_thread if running_thread else False)
    353 
    354                 print()
    355 
    356         def print_all_threads(self):
    357                 for c in all_clusters():
    358                         self.print_threads_by_cluster(c, False)
    359 
    360         def invoke(self, arg, from_tty):
    361                 """
    362                 @arg: str
    363                 @from_tty: bool
    364                 """
    365                 if not is_cforall():
    366                         return
    367 
    368                 if not arg:
    369                         cluster = lookup_cluster()
    370                         if not cluster:
    371                                 print("Could not find Main Cluster")
    372                                 return
    373 
    374                         # only tasks and main
    375                         self.print_threads_by_cluster(cluster, False)
    376 
    377                 elif arg == 'all':
    378                         # all threads, all clusters
    379                         self.print_all_threads()
    380 
    381                 else:
    382                         cluster = lookup_cluster(arg)
    383                         if not cluster:
    384                                 print("Could not find cluster '{}'".format(arg))
    385                                 return
    386 
    387                         # all tasks, specified cluster
    388                         self.print_threads_by_cluster(cluster, True)
     301    cfathreads                           : print Main Cluster threads, application threads only
     302    cfathreads all                       : print all clusters, all threads
     303    cfathreads <clusterName>             : print cluster threads, application threads only
     304    """
     305    def __init__(self):
     306        # The first parameter of the line below is the name of the command. You
     307        # can call it 'uc++ task'
     308        super(Threads, self).__init__('info cfathreads', gdb.COMMAND_USER)
     309
     310    def print_formatted(self, marked, tid, name, state, address):
     311        print('{:>1}  {:>4}  {:>20}  {:>10}  {:>20}'.format('*' if marked else ' ', tid, name, state, address))
     312
     313    def print_thread(self, thread, tid, marked):
     314        cfa_t = get_cfa_types()
     315        self.print_formatted(marked, tid, thread['self_cor']['name'].string(), str(thread['state'].cast(cfa_t.thread_state)), str(thread))
     316
     317    def print_formatted_cluster(self, str_format, cluster_name, cluster_addr):
     318        print(str_format.format(cluster_name, cluster_addr))
     319
     320    def print_threads_by_cluster(self, cluster, print_system = False):
     321        # Iterate through a circular linked list of tasks and print out its
     322        # name along with address associated to each cluster
     323        threads = lookup_threads_by_cluster(cluster)
     324        if not threads:
     325            return
     326
     327        running_thread = find_curr_thread()
     328        if running_thread is None:
     329            print('Could not identify current thread')
     330
     331        self.print_formatted(False, '', 'Name', 'State', 'Address')
     332
     333        for t in threads:
     334            if not t.is_system() or print_system:
     335                self.print_thread(t.value, t.tid, t.value == running_thread if running_thread else False)
     336
     337        print()
     338
     339    def print_all_threads(self):
     340        print("Not implemented")
     341
     342    def invoke(self, arg, from_tty):
     343        """
     344        @arg: str
     345        @from_tty: bool
     346        """
     347        if not is_cforall():
     348            return
     349
     350        if not arg:
     351            cluster = lookup_cluster()
     352            if not cluster:
     353                print("Could not find Main Cluster")
     354                return
     355
     356            # only tasks and main
     357            self.print_threads_by_cluster(cluster, False)
     358
     359        elif arg == 'all':
     360            # all threads, all clusters
     361            self.print_all_threads()
     362
     363        else:
     364            cluster = lookup_cluster(arg)
     365            if not cluster:
     366                print("Could not find cluster '{}'".format(arg))
     367                return
     368
     369            # all tasks, specified cluster
     370            self.print_threads_by_cluster(cluster, True)
    389371
    390372
    391373############
    392374class Thread(gdb.Command):
    393         """Cforall: Switch to specified user threads
    394 Usage:
    395         cfathread <id>                       : switch stack to thread id on main cluster
    396         cfathread 0x<address>                : switch stack to thread on any cluster
    397         cfathread <id> <clusterName>         : switch stack to thread on specified cluster
    398         """
    399         def __init__(self):
    400                 # The first parameter of the line below is the name of the command. You
    401                 # can call it 'uc++ task'
    402                 super(Thread, self).__init__('cfathread', gdb.COMMAND_USER)
    403 
    404         ############################ AUXILIARY FUNCTIONS #########################
    405 
    406         def switchto(self, thread):
    407                 """Change to a new task by switching to a different stack and manually
    408                 adjusting sp, fp and pc
    409                 @task_address: str
    410                         2 supported format:
    411                                 in hex format
    412                                         <hex_address>: literal hexadecimal address
    413                                         Ex: 0xffffff
    414                                 in name of the pointer to the task
    415                                         "task_name": pointer of the variable name of the cluster
    416                                                 Ex: T* s -> task_name = s
    417                         Return: gdb.value of the cluster's address
    418                 """
    419                 try:
    420                         if not gdb.lookup_symbol('__cfactx_switch'):
    421                                 print('__cfactx_switch symbol is unavailable')
    422                                 return
    423                 except:
    424                         print('here 3')
    425 
    426                 cfa_t = get_cfa_types()
    427 
    428                 state = thread['state'].cast(cfa_t.thread_state)
    429                 try:
    430                         if state == gdb.parse_and_eval('Halted'):
    431                                 print('Cannot switch to a terminated thread')
    432                                 return
    433 
    434                         if state == gdb.parse_and_eval('Start'):
    435                                 print('Cannjot switch to a thread not yet run')
    436                                 return
    437                 except:
    438                         print("here 2")
    439                         return
    440 
    441 
    442                 context = thread['context']
    443 
    444                 # lookup for sp,fp and uSwitch
    445                 xsp = context['SP'] + 48
    446                 xfp = context['FP']
    447 
    448                 # convert string so we can strip out the address
    449                 try:
    450                         xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address + 28)
    451                 except:
    452                         print("here")
    453                         return
    454 
    455                 # must be at frame 0 to set pc register
    456                 gdb.execute('select-frame 0')
    457 
    458                 # push sp, fp, pc into a global stack
    459                 global STACK
    460                 sp = gdb.parse_and_eval('$sp')
    461                 fp = gdb.parse_and_eval('$fp')
    462                 pc = gdb.parse_and_eval('$pc')
    463                 stack_info = StackInfo(sp = sp, fp = fp, pc = pc)
    464                 STACK.append(stack_info)
    465 
    466                 # update registers for new task
    467                 print('switching to ')
    468                 gdb.execute('set $rsp={}'.format(xsp))
    469                 gdb.execute('set $rbp={}'.format(xfp))
    470                 gdb.execute('set $pc={}'.format(xpc))
    471 
    472         def find_matching_gdb_thread_id():
    473                 """
    474                 Parse the str from info thread to get the number
    475                 """
    476                 info_thread_str = gdb.execute('info thread', to_string=True).splitlines()
    477                 for thread_str in info_thread_str:
    478                         if thread_str.find('this={}'.format(task)) != -1:
    479                                 thread_id_pattern = r'^\*?\s+(\d+)\s+Thread'
    480                                 # retrive gdb thread id
    481                                 return re.match(thread_id_pattern, thread_str).group(1)
    482 
    483                         # check if the task is running or not
    484                         if task_state == gdb.parse_and_eval('uBaseTask::Running'):
    485                                 # find the equivalent thread from info thread
    486                                 gdb_thread_id = find_matching_gdb_thread_id()
    487                                 if gdb_thread_id is None:
    488                                         print('cannot find the thread id to switch to')
    489                                         return
    490                                 # switch to that thread based using thread command
    491                                 gdb.execute('thread {}'.format(gdb_thread_id))
    492 
    493         def switchto_id(self, tid, cluster):
    494                 """
    495                 @cluster: cluster object
    496                 @tid: int
    497                 """
    498                 threads = lookup_threads_by_cluster( cluster )
    499 
    500                 for t in threads:
    501                         if t.tid == tid:
    502                                 self.switchto(t.value)
    503                                 return
    504 
    505                 print("Cound not find thread by id '{}'".format(tid))
    506 
    507         def invoke(self, arg, from_tty):
    508                 """
    509                 @arg: str
    510                 @from_tty: bool
    511                 """
    512                 if not is_cforall():
    513                         return
    514 
    515                 argv = parse(arg)
    516                 print(argv)
    517                 if argv[0].isdigit():
    518                         cname = " ".join(argv[1:]) if len(argv) > 1 else None
    519                         cluster = lookup_cluster(cname)
    520                         if not cluster:
    521                                 print("Could not find cluster '{}'".format(cname if cname else "Main Cluster"))
    522                                 return
    523 
    524                         try:
    525                                 tid = int(argv[0])
    526                         except:
    527                                 print("'{}' not a valid thread id".format(argv[0]))
    528                                 print_usage(self)
    529                                 return
    530 
    531                                 # by id, userCluster
    532                         self.switchto_id(tid, cluster)
    533 
    534                 elif argv[0].startswith('0x') or argv[0].startswith('0X'):
    535                         self.switchto(argv[0]) # by address, any cluster
     375    def __init__(self):
     376        # The first parameter of the line below is the name of the command. You
     377        # can call it 'uc++ task'
     378        super(Threads, self).__init__('cfathread', gdb.COMMAND_USER)
     379
     380    def print_usage(self):
     381        print_usage("""
     382    cfathread                            : print userCluster tasks, application tasks only
     383    cfathread <clusterName>              : print cluster tasks, application tasks only
     384    cfathread all                        : print all clusters, all tasks
     385    cfathread <id>                       : switch stack to thread id on userCluster
     386    cfathread 0x<address>                    : switch stack to thread on any cluster
     387    cfathread <id> <clusterName>         : switch stack to thread on specified cluster
     388    """)
     389
     390    ############################ AUXILIARY FUNCTIONS #########################
     391
     392    def print_formatted(self, marked, tid, name, state, address):
     393        print('{:>1}  {:>4}  {:>20}  {:>10}  {:>20}'.format('*' if marked else ' ', tid, name, state, address))
     394
     395    def print_thread(self, thread, tid, marked):
     396        cfa_t = get_cfa_types()
     397        self.print_formatted(marked, tid, thread['self_cor']['name'].string(), str(thread['state'].cast(cfa_t.thread_state)), str(thread))
     398
     399    def print_formatted_cluster(self, str_format, cluster_name, cluster_addr):
     400        print(str_format.format(cluster_name, cluster_addr))
     401
     402    def print_tasks_by_cluster_all(self, cluster_address):
     403        """
     404        Display a list of all info about all available tasks on a particular cluster
     405        @cluster_address: gdb.Value
     406        """
     407        cluster_address = cluster_address.cast(uCPPTypes.ucluster_ptr)
     408        task_root = cluster_address['tasksOnCluster']['root']
     409
     410        if task_root == 0x0 or task_root.address == 0x0:
     411            print('There are no tasks for cluster at address: {}'.format(cluster_address))
     412            return
     413
     414        self.print_formatted_task('', 'Task Name', 'Address', 'State')
     415        curr = task_root
     416        task_id = 0
     417        systask_id = -1
     418
     419        breakpoint_addr = self.find_curr_breakpoint_addr()
     420        if breakpoint_addr is None:
     421            return
     422
     423        while True:
     424            global SysTask_Name
     425            if (curr['task_']['name'].string() in SysTask_Name):
     426                self.print_formatted_tasks(systask_id, breakpoint_addr, curr)
     427                systask_id -= 1
     428            else:
     429                self.print_formatted_tasks(task_id, breakpoint_addr, curr)
     430                task_id += 1
     431
     432            curr = curr['next'].cast(uCPPTypes.uBaseTaskDL_ptr_type)
     433            if curr == task_root:
     434                break
     435
     436    def print_tasks_by_cluster_address_all(self, cluster_address):
     437        """
     438        Display a list of all info about all available tasks on a particular cluster
     439        @cluster_address: str
     440        """
     441        # Iterate through a circular linked list of tasks and print out its
     442        # name along with address associated to each cluster
     443
     444        # convert hex string to hex number
     445        try:
     446            hex_addr = int(cluster_address, 16)
     447        except:
     448            self.print_usage()
     449            return
     450
     451        cluster_address = gdb.Value(hex_addr)
     452        if not self.print_tasks_by_cluster_all(cluster_address):
     453            return
     454
     455    def print_threads_by_cluster(self, cluster, print_system = False):
     456        """
     457        Display a list of limited info about all available threads on a particular cluster
     458        @cluster: str
     459        @print_system: bool
     460        """
     461        # Iterate through a circular linked list of tasks and print out its
     462        # name along with address associated to each cluster
     463
     464        threads = self.threads_by_cluster(cluster)
     465        if not threads:
     466            return
     467
     468        running_thread = self.find_curr_thread()
     469        if running_thread is None:
     470            print('Could not identify current thread')
     471
     472        self.print_formatted(False, '', 'Name', 'State', 'Address')
     473
     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    ############################ COMMAND FUNCTIONS #########################
     481
     482    def print_all_threads(self):
     483        """Iterate through each cluster, iterate through all tasks and  print out info about all the tasks
     484        in those clusters"""
     485        uCPPTypes = None
     486        try:
     487            uCPPTypes = get_uCPP_types()
     488        except gdb.error:
     489            print(not_supported_error_msg)
     490            print(gdb.error)
     491            return
     492
     493        cluster_root = get_cluster_root()
     494        if cluster_root.address == 0x0:
     495            return
     496
     497        curr = cluster_root
     498        self.print_formatted_cluster(self.cluster_str_format, 'Cluster Name', 'Address')
     499
     500        while True:
     501            addr = str(curr['cluster_'].reference_value())[1:]
     502            self.print_formatted_cluster(self.cluster_str_format, curr['cluster_']['name'].string(), addr)
     503
     504            self.print_tasks_by_cluster_address_all(addr)
     505            curr = curr['next'].cast(uCPPTypes.uClusterDL_ptr_type)
     506            if curr == cluster_root:
     507                break
     508
     509    def switchto(self, thread):
     510        """Change to a new task by switching to a different stack and manually
     511        adjusting sp, fp and pc
     512        @task_address: str
     513            2 supported format:
     514                in hex format
     515                    <hex_address>: literal hexadecimal address
     516                    Ex: 0xffffff
     517                in name of the pointer to the task
     518                    "task_name": pointer of the variable name of the cluster
     519                        Ex: T* s -> task_name = s
     520            Return: gdb.value of the cluster's address
     521        """
     522        # uCPPTypes = None
     523        # try:
     524        #     uCPPTypes = get_uCPP_types()
     525        # except gdb.error:
     526        #     print(not_supported_error_msg)
     527        #     print(gdb.error)
     528        #     return
     529
     530        # # Task address has a format "task_address", which implies that it is the
     531        # # name of the variable, and it needs to be evaluated
     532        # if task_address.startswith('"') and task_address.endswith('"'):
     533        #     task = gdb.parse_and_eval(task_address.replace('"', ''))
     534        # else:
     535        # # Task address format does not include the quotation marks, which implies
     536        # # that it is a hex address
     537        #     # convert hex string to hex number
     538        #     try:
     539        #         hex_addr = int(task_address, 16)
     540        #     except:
     541        #         self.print_usage()
     542        #         return
     543        #     task_address = gdb.Value(hex_addr)
     544        #     task = task_address.cast(uCPPTypes.uBaseTask_ptr_type)
     545        try:
     546            if not gdb.lookup_symbol('__cfactx_switch'):
     547                print('__cfactx_switch symbol is unavailable')
     548                return
     549        except:
     550            print('here 3')
     551
     552        cfa_t = get_cfa_types()
     553
     554        state = thread['state'].cast(cfa_t.thread_state)
     555        try:
     556            if state == gdb.parse_and_eval('Halted'):
     557                print('Cannot switch to a terminated thread')
     558                return
     559
     560            if state == gdb.parse_and_eval('Start'):
     561                print('Cannjot switch to a thread not yet run')
     562                return
     563        except:
     564            print("here 2")
     565            return
     566
     567
     568        context = thread['context']
     569
     570        # lookup for sp,fp and uSwitch
     571        xsp = context['SP'] + 48
     572        xfp = context['FP']
     573
     574        # convert string so we can strip out the address
     575        try:
     576            xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address + 28)
     577        except:
     578            print("here")
     579            return
     580
     581        # must be at frame 0 to set pc register
     582        gdb.execute('select-frame 0')
     583
     584        # push sp, fp, pc into a global stack
     585        global STACK
     586        sp = gdb.parse_and_eval('$sp')
     587        fp = gdb.parse_and_eval('$fp')
     588        pc = gdb.parse_and_eval('$pc')
     589        stack_info = StackInfo(sp = sp, fp = fp, pc = pc)
     590        STACK.append(stack_info)
     591
     592        # update registers for new task
     593        print('switching to ')
     594        gdb.execute('set $rsp={}'.format(xsp))
     595        gdb.execute('set $rbp={}'.format(xfp))
     596        gdb.execute('set $pc={}'.format(xpc))
     597
     598    def find_matching_gdb_thread_id():
     599        """
     600        Parse the str from info thread to get the number
     601        """
     602        info_thread_str = gdb.execute('info thread', to_string=True).splitlines()
     603        for thread_str in info_thread_str:
     604            if thread_str.find('this={}'.format(task)) != -1:
     605                thread_id_pattern = r'^\*?\s+(\d+)\s+Thread'
     606                # retrive gdb thread id
     607                return re.match(thread_id_pattern, thread_str).group(1)
     608
     609            # check if the task is running or not
     610            if task_state == gdb.parse_and_eval('uBaseTask::Running'):
     611                # find the equivalent thread from info thread
     612                gdb_thread_id = find_matching_gdb_thread_id()
     613                if gdb_thread_id is None:
     614                    print('cannot find the thread id to switch to')
     615                    return
     616                # switch to that thread based using thread command
     617                gdb.execute('thread {}'.format(gdb_thread_id))
     618
     619    def switchto_id(self, tid, cluster):
     620        """
     621        @cluster: cluster object
     622        @tid: int
     623        """
     624        threads = self.threads_by_cluster( cluster )
     625
     626        for t in threads:
     627            if t.tid == tid:
     628                self.switchto(t.value)
     629                return
     630
     631        print("Cound not find thread by id '{}'".format(tid))
     632
     633    def invoke(self, arg, from_tty):
     634        """
     635        @arg: str
     636        @from_tty: bool
     637        """
     638        if not is_cforall():
     639            return
     640
     641        argv = parse(arg)
     642        print(argv)
     643        if len(argv) == 0:
     644            """
     645            Iterate only Main Thread, print only tasks and main
     646            """
     647            cluster = lookup_cluster()
     648            if not cluster:
     649                print("Could not find Main Cluster")
     650                return
     651
     652            # only tasks and main
     653            self.print_threads_by_cluster(cluster, False)
     654
     655        elif len(argv) == 1:
     656            if argv[0] == 'help':
     657                self.print_usage()
     658            # push task
     659            elif argv[0].isdigit():
     660                cluster = lookup_cluster()
     661                if not cluster:
     662                    print("Could not find Main Cluster")
     663                    return
     664
     665                try:
     666                    tid = int(argv[0])
     667                except:
     668                    print("'{}' not a valid thread id".format(argv[0]))
     669                    self.print_usage()
     670                    return
     671
     672                 # by id, userCluster
     673                self.switchto_id(tid, cluster)
     674
     675            elif argv[0].startswith('0x') or argv[0].startswith('0X'):
     676                self.switchto(argv[0]) # by address, any cluster
     677            # print tasks
     678            elif argv[0] == 'all':
     679                self.print_all_threads() # all tasks, all clusters
     680            else:
     681                """
     682                Print out all the tasks available in the specified cluster
     683                @cluster_name: str
     684                """
     685                print("cfathread by name")
     686                cluster = lookup_cluster(argv[0])
     687                if not cluster:
     688                    return
     689
     690                # all tasks, specified cluster
     691                self.print_threads_by_cluster(cluster, True)
     692
     693        elif len(argv) == 2:
     694            # push task
     695            self.pushtask_by_id(argv[0], argv[1]) # by id, specified cluster
     696        else:
     697            print('Invalid arguments')
     698            self.print_usage()
    536699
    537700############
    538701class PrevThread(gdb.Command):
    539         """Switch back to previous task on the stack"""
    540         usage_msg = 'prevtask'
    541 
    542         def __init__(self):
    543                 super(PrevThread, self).__init__('prevtask', gdb.COMMAND_USER)
    544 
    545         def invoke(self, arg, from_tty):
    546                 """
    547                 @arg: str
    548                 @from_tty: bool
    549                 """
    550                 global STACK
    551                 if len(STACK) != 0:
    552                         # must be at frame 0 to set pc register
    553                         gdb.execute('select-frame 0')
    554 
    555                         # pop stack
    556                         stack_info = STACK.pop()
    557                         pc = get_addr(stack_info.pc)
    558                         sp = stack_info.sp
    559                         fp = stack_info.fp
    560 
    561                         # pop sp, fp, pc from global stack
    562                         adjust_stack(pc, fp, sp)
    563 
    564                         # must be at C++ frame to access C++ vars
    565                         gdb.execute('frame 1')
    566                 else:
    567                         print('empty stack')
     702    """Switch back to previous task on the stack"""
     703    usage_msg = 'prevtask'
     704
     705    def __init__(self):
     706        super(PrevThread, self).__init__('prevtask', gdb.COMMAND_USER)
     707
     708    def invoke(self, arg, from_tty):
     709        """
     710        @arg: str
     711        @from_tty: bool
     712        """
     713        global STACK
     714        if len(STACK) != 0:
     715            # must be at frame 0 to set pc register
     716            gdb.execute('select-frame 0')
     717
     718            # pop stack
     719            stack_info = STACK.pop()
     720            pc = get_addr(stack_info.pc)
     721            sp = stack_info.sp
     722            fp = stack_info.fp
     723
     724            # pop sp, fp, pc from global stack
     725            adjust_stack(pc, fp, sp)
     726
     727            # must be at C++ frame to access C++ vars
     728            gdb.execute('frame 1')
     729        else:
     730            print('empty stack')
    568731
    569732class ResetOriginFrame(gdb.Command):
    570         """Reset to the origin frame prior to continue execution again"""
    571         usage_msg = 'resetOriginFrame'
    572         def __init__(self):
    573                 super(ResetOriginFrame, self).__init__('reset', gdb.COMMAND_USER)
    574 
    575         def invoke(self, arg, from_tty):
    576                 """
    577                 @arg: str
    578                 @from_tty: bool
    579                 """
    580                 global STACK
    581                 if len(STACK) != 0:
    582                         stack_info = STACK.pop(0)
    583                         STACK.clear()
    584                         pc = get_addr(stack_info.pc)
    585                         sp = stack_info.sp
    586                         fp = stack_info.fp
    587 
    588                         # pop sp, fp, pc from global stack
    589                         adjust_stack(pc, fp, sp)
    590 
    591                         # must be at C++ frame to access C++ vars
    592                         gdb.execute('frame 1')
    593                 #else:
    594                         #print('reset: empty stack') #probably does not have to print msg
     733    """Reset to the origin frame prior to continue execution again"""
     734    usage_msg = 'resetOriginFrame'
     735    def __init__(self):
     736        super(ResetOriginFrame, self).__init__('reset', gdb.COMMAND_USER)
     737
     738    def invoke(self, arg, from_tty):
     739        """
     740        @arg: str
     741        @from_tty: bool
     742        """
     743        global STACK
     744        if len(STACK) != 0:
     745            stack_info = STACK.pop(0)
     746            STACK.clear()
     747            pc = get_addr(stack_info.pc)
     748            sp = stack_info.sp
     749            fp = stack_info.fp
     750
     751            # pop sp, fp, pc from global stack
     752            adjust_stack(pc, fp, sp)
     753
     754            # must be at C++ frame to access C++ vars
     755            gdb.execute('frame 1')
     756        #else:
     757            #print('reset: empty stack') #probably does not have to print msg
    595758
    596759Clusters()
     
    599762PrevThread()
    600763Threads()
    601 Thread()
    602764
    603765# Local Variables: #
Note: See TracChangeset for help on using the changeset viewer.