;****************************************************************************
;** TraceStackDumpWithCallstack_64BitARM.cmm
;** This script is designed to restore a call stack per process in ARM64 bit process.
;**
;**
;**
;** when who what, where, why
;** -------------- ------------ ------------------------------------------------------
;** 01/30/2016 austin.kim First version
;** 11/26/2016 austin.kim Callstack hit/File Restore function
;****************************************************************************
;****************************************************************************
// The way to use this cmm
// cd [ramdump directory]
// do TraceStackDumpWithCallstack_64BitARM [task descriptor address]
// do TraceStackDumpWithCallstack_64BitARM 0xFFFFFFC011388000
// do MTCallStackDump_cortexA9ARM.cmm 0xFFFFFFC011388000 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 64-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_FP_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
// 64 비트 프로세스 주소 처리 단위
&NEXT_STACK_ADDRESS_OFFSET=0x8
// This code will be throughly examined for many times.
&KERNEL_TEXT_START_ADDR=ADDRESS.OFFSET(sYmbol.SECADDRESS(\\vmlinux\.text))
&KERNEL_TEXT_END_ADDR=&KERNEL_TEXT_START_ADDR+0x1000000
//&KERNEL_TEXT_START_ADDR=0xFFFFFFC000080000
//&KERNEL_TEXT_END_ADDR=0xFFFFFFC000D2983F
// Implemented using "02322247_SKT_Crash" ramdump for RenderThread process
//&TASK_ADDRESS=0xffffffc098b56200
v.f
y.create.var __curr_stack_address 0 unsigned long
y.create.done
y.create.var __curr_stack_contents 0 unsigned long
y.create.done
y.create.var __stack_program_counter_addr_buff 0 unsigned long
y.create.done
// **********주요 변수 선언, [END] *************
;ENTRY &STACK_ADDRESS &PROCESS_NAME
;ENTRY &TASK_ADDRESS //&PROCESS_NAME
// 스택 초기 주소를 설정함
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.quad(__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 configureRegisterForCallstack
)
&CURRENT_SP_ADDRESS=&CURRENT_SP_ADDRESS-0x8
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+0x4000
// 이 값은 램덤프 관찰 후 설정한 값이다. 업데이트가 필요함
&STACK_SCAN_BOUNDARY_ADDRESS=&STACK_BOTTOM_ADDRESS+0x500
&CURRENT_SP_ADDRESS=&STACK_BOTTOM_ADDRESS+0x3ff0
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_FP_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
// ***********************************************
// ***********************************************
// 현재 스택 덤프 주소가 Stack 주소 공간 내에 있는 지
// 현재 스택 0x8 offset 공간에 Text Symbol이 있는 지
//
//확인하고 있으면 1을 리턴 아니면 0
//Function: checkValidFPAddressWithSymbol
//Parameter: NONE
// ***********************************************
checkValidFPAddressWithSymbol:
ENTRY &stackAddress
LOCAL &stackWith8Offset &stackDump &cur_stack_content &retVal
&retVal=0
&stackWith8Offset=&CURRENT_SP_ADDRESS+0x8
if &CURR_CONTENTS_OF_SP_ADDR==0x0
(
RETURN &retVal
)
// 현재 스택덤프 값이 스택 내부 주소를 지정하는 지 확인
if (&STACK_BOTTOM_ADDRESS<&CURR_CONTENTS_OF_SP_ADDR)&&(&CURR_CONTENTS_OF_SP_ADDR<&STACK_STARTING_ADDRESS)
(
symbol.modify.address __stack_program_counter_addr_buff V.VALUE(&stackWith8Offset)
&cur_stack_content=data.quad(__stack_program_counter_addr_buff)
if (&KERNEL_TEXT_START_ADDR<&cur_stack_content)&&(&cur_stack_content<&KERNEL_TEXT_END_ADDR)
(
&CANDIDATE_FP_ADDRESS=&CURR_CONTENTS_OF_SP_ADDR
&ADDRESS_TEXT_ADDRESS_WITH_SP=&cur_stack_content
&retVal=1
)
)
RETURN &retVal
// End: checkValidFPAddressWithSymbol
// ***********************************************
'[Debugging] Tips' 카테고리의 다른 글
[Linux][Debug][T32] macro offsetof/container_of (0) | 2023.05.05 |
---|---|
WalkThruStackDump_QMC_32BitARM.cmm (0) | 2023.05.05 |
[Linux][Kernel] T32 - 구조체 확인 (v.type) (0) | 2023.05.05 |
[Linux][Kernel] 전처리 Preprocess File 추출 방법 (0) | 2023.05.04 |
[Linux][Kernel] T32 - Linked List 디버깅 cmm Script (0) | 2023.05.04 |