;****************************************************************************
;**           WalkThruStackDump_QMC_32BitARM.cmm                                     
;**           This script is designed to restore a call stack per process in ARM32 QMC Platform.           
;**                        
;**
;**       
;** when        who      what, where, why
;** --------------   ------------     ------------------------------------------------------
;** 01/30/2016   austin.kim     First version: This script is based upon TraceStackDumpWithCallstack_64BitARM
;** 11/26/2016   austin.kim     Callstack hit/File Restore function
;****************************************************************************
 
;****************************************************************************
// The way to use this cmm
// cd [ramdump directory]
// do WalkThruStackDump_32BitARM.cmm  [task descriptor address]   
// do WalkThruStackDump_32BitARM.cmm  0xC0188000   
// do WalkThruStackDump_32BitARM.cmm  0xC0188000  D:\kernel_panic\11_Nov_2016\1103_oom_starvation_SOMETARGET-457 
 
Area.Create IO 80. 100.
Area.Select IO
Area IO
 
print
print
print "Start execution of dumptrace of a process in 32-bit process, austin.kim@lge.com, 01/30/2016"
 
ENTRY &TASK_ADDRESS &DUMP_DIRECTORY
 
// 콜 스택
v.f
 
// 파일 덤프 모드 
&FILE_DUMP_MODE=0
 
if "&DUMP_DIRECTORY"==""
(
   print "Manual Mode"
)
 
else
(
   print "File Dump Mode"
   &FILE_DUMP_MODE=0x1
)
 
// **********주요 변수 선언, [START] *************
// Dump File Path/Name
&DUMP_OUT_FILENAME=0x0
 
// Callstack을 잡은 횟수 기록
&CALLSTACK_HIT_TIMES=0
 
// &CURRENT_SP_ADDRESS 주소가 이 값이 되면 프로그램 종료. 추후 수정 요망
&STACK_SCAN_BOUNDARY_ADDRESS=0x0
 
&STACK_BOTTOM_ADDRESS=0
 
// 구동중인 CPU Number
&CPU_ON=0x0
// 스택이 자라나는 시작 주소임, 0x4000 만큼 오프셋
&STACK_STARTING_ADDRESS=0
 
// 현재 검색 중인 스택 주소
&CURRENT_SP_ADDRESS=0
 
// 임시로 선택된 스택 주소
&CANDIDATE_SP_ADDRESS=0
 
// FP 주소를 담고 있음
&CURRENT_FP_ADDRESS=0
 
// 현재 스택 덤프 주소
&CURRENT_SP_DUMP_ADDRESS=0
 
// 현재 스택 상단에 있는 Text 주소를 확인하기 위한 버퍼
&BUFFER_TEXT_ADDRESS_WITH_SP=0
 
// 현재 스택 상단에 있는 Text 주소를 가리키기 위한  버퍼
&ADDRESS_TEXT_ADDRESS_WITH_SP=0
 
// 현재 스택 덤프 주소
&BOUND_CONDITION=0
 
// 32 비트 프로세스 주소 처리 단위
&NEXT_STACK_ADDRESS_OFFSET=0x4
 
 
// due to MSM8909 memory section attribute
//     P:C00081C0--C0A03B13|\\vmlinux\.text                        |R-X|L-  |
//&KERNEL_TEXT_START_ADDR=0xC0100000
&KERNEL_TEXT_START_ADDR=0xC0008000
//&KERNEL_TEXT_END_ADDR=0xC0D00000
&KERNEL_TEXT_END_ADDR=0xC0F00000
y.create.var __curr_stack_address 0 unsigned int
y.create.done
 
y.create.var __curr_stack_contents 0 unsigned int
y.create.done
 
y.create.var __stack_program_counter_addr_buff 0 unsigned int
y.create.done
 
// **********주요 변수 선언, [END] *************
// 스택 초기 주소를 설정함
GOSUB configureStackAddress
 
if &FILE_DUMP_MODE==0x1
(
    // 아웃풋 파일 이름 설정
    gosub configureOutputFileName
 
     // RunQueue Dump
//    gosub dumpRunqueueDebugInformation   
    
    // 프린터 오픈
    printer.FILE &DUMP_OUT_FILENAME
    printer.OPEN &DUMP_OUT_FILENAME
)
 
// 프로세스 정보를 찍어줌
GOSUB dumpProcessInformation
 
&CALLSTACK_HIT_TIMES=0x0
while &CURRENT_SP_ADDRESS<&STACK_STARTING_ADDRESS
(
   // 스택에 있는 덤프 주소를 가져옴
   symbol.modify.address __curr_stack_address V.VALUE(&CURRENT_SP_ADDRESS)
   &CURR_CONTENTS_OF_SP_ADDR=data.long(__curr_stack_address)
   
   symbol.modify.address __curr_stack_contents V.VALUE(&CURR_CONTENTS_OF_SP_ADDR)
   
   gosub checkValidFPAddressWithSymbol &fpAddrDumpBuff
   entry &real_fp_status
   
   if &real_fp_status==0x1
   (
    GOSUB dumpProcessInformation
    GOSUB configureRegisterForCallstack
   )
   
   &CURRENT_SP_ADDRESS=&CURRENT_SP_ADDRESS-&NEXT_STACK_ADDRESS_OFFSET
 
   if &FILE_DUMP_MODE==0x1
   (
    if &CURRENT_SP_ADDRESS==&STACK_SCAN_BOUNDARY_ADDRESS
    (
    printer.CLOSE
    enddo
    )  
   )    
)  // ; end of while &CURRENT_SP_ADDRESS<&STACK_STARTING_ADDRESS  
 
enddo
 
// ***********************************************
// 아웃풋 파일 이름 설정
//Function: configureOutputFileName
//Parameter: NONE
// ***********************************************
configureOutputFileName:
   LOCAL &task_comm &task_temp &cpu_num &pid_temp &pid_dec &filename
   
    // 프로세스 이름
   &task_temp=VAR.STRING( ((struct task_struct *)&TASK_ADDRESS).comm)
   &task_comm=string.mid("&task_temp", 0., 3.) 
   
   &pid_temp=VAR.VALUE( ((struct task_struct*)&TASK_ADDRESS).pid)
   &pid_dec=FORMAT.DECIMAL(0., &pid_temp)
   
   &CPU_ON=V.VALUE( ((struct thread_info *)&STACK_BOTTOM_ADDRESS).cpu) 
 
   &filename="&TASK_ADDRESS"+"_"+"&task_comm"+"_"+"&pid_dec"+"_"+"&CPU_ON"+".c"
//   &filename="&TASK_ADDRESS"+"_"+"&pid_temp"+"_"+"&CPU_ON"+".txt"
   
   &DUMP_OUT_FILENAME="&DUMP_DIRECTORY"+"/&filename"
   
   RETURN
// End: configureOutputFileName
// ***********************************************
 
// ***********************************************
// Runqueue Dump
//Function: dumpRunqueueDebugInformation
//Parameter: NONE
// ***********************************************
dumpRunqueueDebugInformation:
   LOCAL &dump_runq_name
   
   &dump_runq_name="&DUMP_DIRECTORY"+"/demiGod_Runqueue.c"
   
   printer.FILE &dump_runq_name
   printer.OPEN &dump_runq_name
   
   wp.v.v %s %y %h (*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[0])))).curr (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[0])))).curr)).comm (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[0])))).curr)).pid v.v %s %y (*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[1])))).curr (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[1])))).curr)).comm (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[1])))).curr)).pid v.v %s %y (*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[2])))).curr (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[2])))).curr)).comm (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[2])))).curr)).pid v.v %s %y (*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[3])))).curr (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[3])))).curr)).comm (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[3])))).curr)).pid
   wp.v.v %s %y %h (*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[4])))).curr (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[4])))).curr)).comm (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[4])))).curr)).pid v.v %s %y (*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[5])))).curr (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[5])))).curr)).comm (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[5])))).curr)).pid v.v %s %y (*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[6])))).curr (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[6])))).curr)).comm (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[6])))).curr)).pid v.v %s %y (*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[7])))).curr (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[7])))).curr)).comm (*((*(((struct rq*)(((void*)&runqueues)+__per_cpu_offset[7])))).curr)).pid
 
   wp.v.v %all (struct rq*)(((void*)&runqueues)+__per_cpu_offset[0]) (struct rq*)(((void*)&runqueues)+__per_cpu_offset[1]) (struct rq*)(((void*)&runqueues)+__per_cpu_offset[2]) (struct rq*)(((void*)&runqueues)+__per_cpu_offset[3])  (struct rq*)(((void*)&runqueues)+__per_cpu_offset[4]) (struct rq*)(((void*)&runqueues)+__per_cpu_offset[5]) (struct rq*)(((void*)&runqueues)+__per_cpu_offset[6]) (struct rq*)(((void*)&runqueues)+__per_cpu_offset[7])
   
   printer.CLOSE
   
   RETURN
// End: dumpRunqueueDebugInformation
// ***********************************************
 
 
 
// ***********************************************
// 스택 초기 주소를 설정함
//Function: configureStackAddress
//Parameter: NONE
// ***********************************************
configureStackAddress:
 
   &STACK_BOTTOM_ADDRESS=v.value( ((struct task_struct *)&TASK_ADDRESS).stack )
   &STACK_STARTING_ADDRESS=&STACK_BOTTOM_ADDRESS+0x2000
   
   // 이 값은 램덤프 관찰 후 설정한 값이다. 업데이트가 필요함
   &STACK_SCAN_BOUNDARY_ADDRESS=&STACK_BOTTOM_ADDRESS+0x500
   &CURRENT_SP_ADDRESS=&STACK_BOTTOM_ADDRESS+0x1ffc
   
   RETURN
// End: configureStackAddress
// ***********************************************
 
// ***********************************************
// 프로세스 정보를 찍어줌
//Function: dumpProcessInformation
//Parameter: NONE
// ***********************************************
dumpProcessInformation:
 
   wp.v.v %s ((struct task_struct *)&TASK_ADDRESS).comm
   wp.v.v %all ((struct task_struct *)&TASK_ADDRESS).pid
       
   RETURN
// End: dumpProcessInformation
// ***********************************************
 
 
// ***********************************************
// 레지스터를 설정하고 콜스택을 뿌려줌
//Function: configureRegisterForCallstack
//Parameter: NONE
// ***********************************************
configureRegisterForCallstack:
 
   r.s sp &CANDIDATE_SP_ADDRESS
   r.s pc &ADDRESS_TEXT_ADDRESS_WITH_SP
   
   &CALLSTACK_HIT_TIMES=&CALLSTACK_HIT_TIMES+1
   print "Callstack hit time: " format.udecimal(4,&CALLSTACK_HIT_TIMES)
   
   // dump callstacks in file
   if &FILE_DUMP_MODE==0x1
   (
    wp.v.f
    wp.r
    if &CALLSTACK_HIT_TIMES==0x60
    (
printer.CLOSE
enddo   
    )
   )
  
   RETURN
// End: configureRegisterForCallstack
// ***********************************************
 
// ***********************************************
// 현재 스택 덤프 주소가 Text 주소 공간 내에 있는 지
//
//확인하고 있으면 1을 리턴 아니면 0 
//Function: checkValidFPAddressWithSymbol
//Parameter: NONE
// ***********************************************
checkValidFPAddressWithSymbol:
 
   ENTRY &stackAddress
   LOCAL &stackWith4Offset &stackDump &cur_stack_content &retVal
   
   &retVal=0
   &stackWith4Offset=&CURRENT_SP_ADDRESS+0x4
   
   if &CURR_CONTENTS_OF_SP_ADDR==0x0
   (
    RETURN &retVal
   )
      // 현재 스택덤프 값이 Text 영역 내에 있는 지 확인
   if (&KERNEL_TEXT_START_ADDR<&CURR_CONTENTS_OF_SP_ADDR)&&(&CURR_CONTENTS_OF_SP_ADDR<&KERNEL_TEXT_END_ADDR)
   (
     &ADDRESS_TEXT_ADDRESS_WITH_SP=&CURR_CONTENTS_OF_SP_ADDR
      &CANDIDATE_SP_ADDRESS=&stackWith4Offset
 
&retVal=1
   )
      
   RETURN &retVal
// End: checkValidFPAddressWithSymbol
// ***********************************************
 

+ Recent posts