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