• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# coding:utf-8
3# Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import sys,string,re,os
17from ctypes import *
18from parse_basic import *
19from auto_class import *
20from config import *
21
22OS_TASK_STATUS_UNUSED = 0x0001
23OS_TASK_STATUS_SUSPEND = 0x0002
24OS_TASK_STATUS_READY = 0x0004
25OS_TASK_STATUS_PEND = 0x0008
26OS_TASK_STATUS_RUNNING = 0x0010
27OS_TASK_STATUS_DELAY = 0x0020
28OS_TASK_STATUS_TIMEOUT = 0x0040
29OS_TASK_STATUS_PEND_TIME = 0x0080
30OS_TASK_FLAG_DETACHED = 0x0001
31OS_TASK_FLAG_SYSTEM = 0x0002
32OS_SWTMR_STATUS_UNUSED = 0
33OS_SWTMR_STATUS_DELETING =1
34OS_SWTMR_STATUS_CREATED=2
35OS_SWTMR_STATUS_TICKING=3
36queueQUEUE_TYPE_BASE=0
37queueQUEUE_TYPE_SET=0
38queueQUEUE_TYPE_MUTEX=1
39queueQUEUE_TYPE_COUNTING_SEMAPHORE=2
40queueQUEUE_TYPE_BINARY_SEMAPHORE=3
41queueQUEUE_TYPE_RECURSIVE_MUTEX=4
42CONTEXT_OFFSET=4 * 4 + 33 * 4
43#ctypes.addressof(parameter) - ctypes.addressof(parent_structure)
44
45
46def _los_List_get_all_node(list_addr):
47    node_list=[]
48    node=parse_memory_2_class(list_addr,LOS_DL_LIST,sizeof(LOS_DL_LIST))
49    while node.pstNext!=list_addr:
50        node_list.append(node.pstNext)
51        node = parse_memory_2_class(node.pstNext,LOS_DL_LIST,sizeof(LOS_DL_LIST))
52    return (DEFINE_SUCCESS,node_list)
53
54def _addr_in_2_function_name(addr):
55    name=parse_addr_in_2_function_name(addr)
56    if name==None:
57        return hex(addr)
58    else:
59        return name
60
61class _PhaseFreertosCtrl:
62    def __init__(self):
63        self.core=None
64        self.info_fd = sys.__stdout__
65        self.task_cnt=None
66        self.tcb_array = []
67        self.ext_task_list=[]
68        self.ext_taskstatus_list=[]  ##freertos
69
70        self.heap_start = None
71        self.heap_end = None
72        self.heap_head = None
73        self.queue_cnt = configQUEUE_REGISTRY_SIZE
74        self.queue_array=[]
75        self.queue_ext_info=[]
76        self.timer_cnt = 0
77        self.timer_array=[]
78        self.timer_ext_info=[]
79        #self.sem_cnt=LOSCFG_BASE_IPC_SEM_LIMIT
80        #self.sem_array=[]
81        self.sem_ext_info=[]
82
83        self.excInfo=None
84
85        self.isr_ext_info=None
86
87    class _ExtPercpu:
88        def __init__(self):
89            self.handle_addr = None
90            self.per_cpu=None
91            self.g_tickCount=None
92            self.g_sysClock=None
93            self.g_tickPerSecond=None
94            self.g_cycle2NsScale=None
95            self.task_wait_addr=[]
96            self.timer_wait_addr=[]
97            self.g_intCount=None
98
99    class _ExtTaskInfo:
100        def __init__(self):
101            self.handle_addr=None
102            self.pend_addr=None
103            self.name='unknown'
104            self.buttom=0
105            self.peek_used=0
106            self.over=0
107            self.status_str=None
108            self.enter_name = 'unknown'
109            self.task_context = None
110            self.take_sem = None
111
112    class _ExtTaskStatus:
113        def __init__(self):
114            self.xHandle=None
115            self.pcTaskName='unknown'
116            self.xTaskNumber=0
117            self.eCurrentState=0
118            self.uxCurrentPriority=0
119            self.uxBasePriority=0
120            self.ulRunTimeCounter=0
121            self.pxStackBase = None
122            self.usStackHighWaterMark = 0
123
124    class _ExtTimerInfo:
125        def __init__(self):
126            self.handle_addr=None
127            self.func_name=None
128
129    class _ExtSemInfo:
130        def __init__(self):
131            self.handle_addr=None
132            self.pend_task_list=[]
133
134    class _ExtQueueInfo:
135        def __init__(self):
136            self.handle_addr=None
137            self.pend_read_task_list = []
138            self.pend_write_task_list =[]
139
140    class ExtIsrInfo:
141        def __init__(self):
142            self.isr_cnt = configHWI_MAX_VECTOR_CNT
143            self.pxAddr=None
144            self.pxHwiHandles_list = []
145
146    def make_isr_info(self):
147        self.isr_ext_info = self.ExtIsrInfo()
148        addr = parse_get_symbol_addr('pxHwiHandles')
149        self.isr_ext_info.pxAddr = parse_memory_2_class(addr,(uint32_t)*self.isr_ext_info.isr_cnt,sizeof((uint32_t)*self.isr_ext_info.isr_cnt))
150        for temp_addr in self.isr_ext_info.pxAddr:
151            if temp_addr!=0:
152                pxHwiHandles = parse_memory_2_class(temp_addr, HwiHandle_t, sizeof(HwiHandle_t))
153                self.isr_ext_info.pxHwiHandles_list.append(pxHwiHandles)
154
155
156    def print_isr_info(self):
157        print("\r\n---------------------content of 中断信息:---------------------",file=self.info_fd)
158        for hwi in self.isr_ext_info.pxHwiHandles_list:
159            if hwi.pxCb!=0 or hwi.xCounts!=0:
160                print("%s[0x%x][call_cnt=%d]"%(_addr_in_2_function_name(hwi.pxCb),hwi.pxCb,hwi.xCounts),file=self.info_fd)
161        print("",file=self.info_fd)
162
163    def _make_task_info(self,pxList):
164        pxCurrentTCB = parse_get_symbol_addr('pxCurrentTCB')
165        if pxList.uxNumberOfItems > 0:
166            num = 0
167            while num < pxList.uxNumberOfItems:
168                next_item = parse_memory_2_class(pxList.pxIndex, ListItem_t, sizeof(ListItem_t))
169                if not next_item:
170                    break
171                pxList.pxIndex = next_item.pxNext
172                pxTCB = parse_memory_2_class(next_item.pvOwner, TCB_t, sizeof(TCB_t))
173                if pxTCB:
174                    taskstatus = self._ExtTaskStatus()
175                    taskstatus.xHandle = next_item.pvOwner
176                    taskstatus.pcTaskName = pxTCB.pcTaskName
177                    taskstatus.xTaskNumber = pxTCB.uxTCBNumber
178                    if (next_item.pvOwner == pxCurrentTCB):
179                        taskstatus.eCurrentState = 0
180                    else:
181                        taskstatus.eCurrentState = 1
182                    taskstatus.uxCurrentPriority = pxTCB.uxPriority
183                    taskstatus.uxBasePriority = pxTCB.uxBasePriority
184                    #taskstatus.ulRunTimeCounter = pxTCB.ulRunTimeCounter
185                    taskstatus.pxStackBase = pxTCB.pxStack
186                    self.ext_taskstatus_list.append(taskstatus)
187                    self.tcb_array.append(pxTCB)
188                num = num + 1
189
190    def make_all_task_info(self):
191        addr = parse_get_symbol_addr('uxCurrentNumberOfTasks')
192        obj=parse_memory_2_class(addr,c_uint,4)
193        self.task_cnt = obj.value
194        addr = parse_get_symbol_addr('pxReadyTasksLists')
195        pxReadyLists=parse_memory_2_class(addr, List_t*configMAX_PRIORITIES, sizeof(List_t)*configMAX_PRIORITIES)
196        for pxList in pxReadyLists:
197            self._make_task_info(pxList)
198        TaskListName = ['xDelayedTaskList1', 'xDelayedTaskList2', 'xPendingReadyList', 'xTasksWaitingTermination', 'xSuspendedTaskList']
199        for tasklist_name in TaskListName:
200            addr = parse_get_symbol_addr(tasklist_name)
201            pxList = parse_memory_2_class(addr, List_t, sizeof(List_t))
202            self._make_task_info(pxList)
203
204
205
206    def _task_status_2_string(self,status):
207        str=''
208        if (status&OS_TASK_STATUS_UNUSED):
209            str=str+"unused,"
210        if (status&OS_TASK_STATUS_RUNNING):
211            str=str+'runing,'
212        if (status&OS_TASK_STATUS_READY):
213            str=str+'ready,'
214        if (status&OS_TASK_STATUS_SUSPEND):
215            str=str+'suspend,'
216        if (status&OS_TASK_STATUS_PEND):
217            str=str+'pend,'
218        if (status&OS_TASK_STATUS_DELAY):
219            str=str+'delay,'
220        if (status&OS_TASK_STATUS_TIMEOUT):
221            str=str+'timeout,'
222        if (status&OS_TASK_STATUS_PEND_TIME):
223            str=str+'pendtime,'
224        return str
225
226    def _make_task_extra_info(self):
227        i=0
228        while i < self.task_cnt:
229            tcb = self.tcb_array[i]
230            ext_info=self.ext_task_list[i]
231            if tcb.taskStatus & OS_TASK_STATUS_UNUSED: #未使用任务返回
232                i=i+1
233                continue;
234
235            ext_info.buttom = tcb.topOfStack+tcb.stackSize #计算栈buttom
236            ext_info.status_str = self._task_status_2_string(tcb.taskStatus)
237            if tcb.taskSem!=0:
238                ext_info.take_sem = parse_memory_2_class(tcb.taskSem,LosSemCB,sizeof(LosSemCB))
239
240            #生成taskname
241            addr=tcb.taskName
242            str = parse_memory_2_string(addr,32)
243            if str!=None:
244                ext_info.name=str
245
246            #判断栈是否溢出
247            obj = parse_memory_2_class(tcb.topOfStack,c_uint,sizeof(c_uint))
248            if obj.value==0xCCCCCCCC:
249                ext_info.over=0
250            else:
251                ext_info.over=1
252
253            #计算栈峰值
254            addr = tcb.topOfStack+4
255            while addr < ext_info.buttom:
256                obj = parse_memory_2_class(addr,c_uint,sizeof(c_uint))
257                if obj.value != 0xCACACACA:
258                    break
259                addr+=4
260            ext_info.peek_used = ext_info.buttom-addr
261
262            enter_name=parse_addr_2_function_name(tcb.taskEntry)
263            if enter_name!=None:
264                ext_info.enter_name = enter_name
265
266            ext_info.task_context=parse_memory_2_class(tcb.stackPointer,TaskContext,sizeof(TaskContext))
267            i=i+1
268
269    def print_task_short_info(self):
270        print("\r\n--------------------content of 任务信息摘要:--------------------",file=self.info_fd)
271        print('%4s|%20s|%4s|%10s|%10s|%s|%10s'%('xHandle','TaskName','xTaskNumber','eCurrentState','CurrentPriority','BasePriority','StackBase'),file=self.info_fd)
272        for taskstatus in self.ext_taskstatus_list:
273            print('0x%08x|%20s|%4d|%4d|0x%08x|0x%08x|0x%08x'
274                    %(taskstatus.xHandle,taskstatus.pcTaskName,taskstatus.xTaskNumber,taskstatus.eCurrentState,taskstatus.uxCurrentPriority,taskstatus.uxBasePriority,taskstatus.pxStackBase),file=self.info_fd)
275
276    def print_task_detail_info(self):
277        print("\r\n--------------------content of 任务详细信息:--------------------",file=self.info_fd)
278        print("说明:tcb任务控制块信息,context:任务上下文的寄存器信息,backtrace 栈回溯",file=self.info_fd)
279        for tcb in self.tcb_array:
280            print('',file=self.info_fd)
281            uapi_print_ctypes_obj('tcb',tcb,self.info_fd)
282            ext_info = parse_memory_2_class(tcb.pxTopOfStack+CONTEXT_OFFSET,exc_context_freertos_t,sizeof(exc_context_freertos_t))
283            #打印寄存器信息
284            print("[TASK]%s 寄存器:"%(tcb.pcTaskName),file=self.info_fd)
285            uapi_print_ctypes_obj('context',ext_info,self.info_fd)
286
287            #打印back_trace
288            print("[TASK]%s back trace..."%(tcb.pcTaskName))
289            print("[TASK]%s 栈回溯:"%(tcb.pcTaskName),file=self.info_fd)
290            sp = tcb.pxTopOfStack+CONTEXT_OFFSET
291            self.stack_back_trace(tcb.pxStack, sp)
292            #print("[TASK]%s 其它状态:"%(ext_info.name),file=self.info_fd)
293
294
295    def make_queue_info(self):
296        addr = parse_get_symbol_addr('xQueueRegistry')
297        i=0
298        while i< self.queue_cnt:
299            obj=parse_memory_2_class(addr,QueueRegistryItem_t,sizeof(QueueRegistryItem_t))
300            if obj:
301                queue_item=parse_memory_2_class(obj.xHandle,Queue_t,sizeof(Queue_t))
302                self.queue_array.append(queue_item)
303            addr=addr+sizeof(QueueRegistryItem_t)
304            i=i+1
305
306
307    def print_queue_info(self):
308        print("\r\n--------------------content of 消息队列信息:--------------------",file=self.info_fd)
309        print("说明:queueName队列名字,queueHandle队列的内存空间, queueType队列类型, queueLen队列长度, queueItemSize每个节点大小,queueUsed已用节点个数, queueAvailable剩余节点个数",file=self.info_fd)
310        i=0
311        for queue in self.queue_array:
312            if queue!=None:
313                if queue.ucQueueType == queueQUEUE_TYPE_BASE:
314                    uapi_print_ctypes_obj('queue',queue,self.info_fd)
315                    print("",file=self.info_fd)
316            i=i+1
317        print("",file=self.info_fd)
318
319    def make_timer_info(self):
320        pxaddr = parse_get_u32_symbol_val('pxCurrentTimerList')
321        addrList = parse_memory_2_class(pxaddr, uint32_t, sizeof(uint32_t))
322        if addrList:
323            pxList=parse_memory_2_class(addrList.value, List_t, sizeof(List_t))
324            if pxList != None:
325                if pxList.uxNumberOfItems > 0:
326                    while self.timer_cnt < pxList.uxNumberOfItems:
327                        next_item = parse_memory_2_class(pxList.pxIndex, ListItem_t, sizeof(ListItem_t))
328                        pxList.pxIndex = next_item.pxNext
329                        obj = parse_memory_2_class(next_item.pvOwner, Timer_t, sizeof(Timer_t))
330                        self.timer_array.append(obj)
331                        self.timer_cnt = self.timer_cnt + 1
332
333
334    def print_timer_info(self):
335        print("---------------------content of 定时器信息:---------------------",file=self.info_fd)
336        print("说明:SwTmr_Used定时器个数;SwTmr_Total定时器个数上限;timer_id定时器id;pxCallbackFunction回调函数的地址;xTimerPeriodInTicks调用周期;ucStatus(1:ACTIVE 2:STATICALLY_ALLOCATED 3:AUTORELOAD)",file=self.info_fd)
337        print("SwTmr_Used=%d, SwTmr_Total=unlimited"%(self.timer_cnt),file=self.info_fd)
338        i=0
339        while i< self.timer_cnt:
340            timer=self.timer_array[i]
341            print("timer_id=%d %s[0x%x]"%(timer.pvTimerID,_addr_in_2_function_name(timer.pxCallbackFunction),timer.pxCallbackFunction),file=self.info_fd)
342            uapi_print_ctypes_obj('timer',timer,self.info_fd)
343            print('',file=self.info_fd)
344            i=i+1
345        print("",file=self.info_fd)
346
347    def _make_sem_extra_info(self):
348        i=0
349        while i< self.sem_cnt:
350            sem=self.sem_array[i]
351            ext_info=self.sem_ext_info[i]
352            if sem.semStat==1: #used
353                (ret,addr_list)=_los_List_get_all_node(ext_info.handle_addr + ctype_member_offset('semList',LosSemCB))
354                for node_addr in addr_list:
355                    ext_info.pend_task_list.append(node_addr)
356            i=i+1
357
358    def make_sem_info(self):
359        addr = parse_get_u32_symbol_val('g_osAllSem')
360        i=0
361        while i< self.sem_cnt:
362            ext_info=self._ExtSemInfo()
363            obj=parse_memory_2_class(addr,LosSemCB,sizeof(LosSemCB))
364            ext_info.handle_addr=addr
365            self.sem_array.append(obj)
366            self.sem_ext_info.append(ext_info)
367            addr=addr+sizeof(LosSemCB)
368            i=i+1
369        self._make_sem_extra_info()
370
371    def get_pending_task(self,addr_list):
372        list=[]
373        for addr in addr_list:
374            i=0
375            while i < self.task_cnt:
376                ext_task = self.ext_task_list[i]
377                tcb = self.tcb_array[i]
378                if addr== ext_task.pend_addr:
379                    list.append(tcb.taskId)
380                i=i+1
381        return list
382
383    def print_sem_info(self):
384        print("--------------------content of 信号量:--------------------",file=self.info_fd)
385        print("说明:SemName信号量名字,SemHandle信号量的地址, MaxCount信号量最大个数, Count已用个数",file=self.info_fd)
386        i=0
387        for queue in self.queue_array:
388            if queue!=None:
389                if queue.ucQueueType==queueQUEUE_TYPE_COUNTING_SEMAPHORE or queue.ucQueueType==queueQUEUE_TYPE_BINARY_SEMAPHORE or queue.ucQueueType==queueQUEUE_TYPE_RECURSIVE_MUTEX:
390                    uapi_print_ctypes_obj('Sem',queue,self.info_fd)
391                    print("",file=self.info_fd)
392            i=i+1
393        print("",file=self.info_fd)
394
395    def make_crash_info(self):
396        addr = parse_get_symbol_addr('g_exc_buff_addr')
397        self.excInfo = parse_memory_2_class(addr,exc_context_t,sizeof(exc_context_t))
398
399    def print_crash_info(self):
400        print("--------------------content of 死机信息:--------------------",file=self.info_fd)
401        uapi_print_ctypes_obj('g_exc_buff_addr',self.excInfo,self.info_fd)
402        self.stack_back_trace(self.excInfo.task_context.sp+sizeof(task_context_t),self.excInfo.task_context.sp+0x1000)
403
404    def stack_back_trace(self,start_addr,end_addr):
405        sp=start_addr
406        while sp < end_addr:
407            obj=parse_memory_2_class(sp,c_uint,sizeof(c_uint))
408            name = parse_addr_in_2_function_name(obj.value-4)
409            if name:
410                print("[BACK Trace][addr=0x%08x][val=0x%08x]%s"%(sp,obj.value,name),file=self.info_fd)
411            else:
412                pass
413                #print("[BACK Trace][addr=0x%08x][val=0x%08x]"%(sp,obj.value),file=self.info_fd)
414
415            sp=sp+4
416
417_g_parse_freertos_ctrl=_PhaseFreertosCtrl()
418def make_freertos_info():
419    try:
420        _g_parse_freertos_ctrl.make_all_task_info()
421    except:
422        print("[EXCEPTION]make_all_task_info fail.")
423    try:
424        _g_parse_freertos_ctrl.make_queue_info()
425    except:
426        print("[EXCEPTION]make_queue_info fail.")
427    try:
428        _g_parse_freertos_ctrl.make_timer_info()
429    except:
430        print("[EXCEPTION]make_timer_info fail.")
431    try:
432        _g_parse_freertos_ctrl.make_crash_info()
433    except:
434        print("[EXCEPTION]make_crash_info fail.")
435    try:
436        _g_parse_freertos_ctrl.make_isr_info()
437    except:
438        print("[EXCEPTION]make_isr_info fail.")
439
440def print_freertos_info():
441    try:
442        _g_parse_freertos_ctrl.print_isr_info()
443    except:
444        print("[EXCEPTION]print_isr_info fail.")
445    try:
446        _g_parse_freertos_ctrl.print_queue_info()
447    except:
448        print("[EXCEPTION]print_queue_info fail.")
449    try:
450        _g_parse_freertos_ctrl.print_timer_info()
451    except:
452        print("[EXCEPTION]print_timer_info fail.")
453    try:
454        _g_parse_freertos_ctrl.print_sem_info()
455    except:
456        print("[EXCEPTION]print_sem_info fail.")
457    try:
458        _g_parse_freertos_ctrl.print_task_short_info()
459    except:
460        print("[EXCEPTION]print_task_short_info fail.")
461    try:
462        _g_parse_freertos_ctrl.print_task_detail_info()
463    except:
464        print("[EXCEPTION]print_task_detail_info fail.")
465    try:
466        _g_parse_freertos_ctrl.print_crash_info()
467    except:
468        print("[EXCEPTION]print_crash_info fail.")
469
470def parse_freertos_info(log_fp):
471    _g_parse_freertos_ctrl.info_fd = log_fp
472    make_freertos_info()
473    print_freertos_info()
474    print("parse_freertos_info end!")
475