;****************************************************************************
;** 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
// ***********************************************
'[Debugging] Tips' 카테고리의 다른 글
printk 컴파일 에러 시 해더 파일 (0) | 2023.05.05 |
---|---|
[Linux][Debug][T32] macro offsetof/container_of (0) | 2023.05.05 |
TraceStackDumpWithCallstack_64BitARM.cmm (0) | 2023.05.05 |
[Linux][Kernel] T32 - 구조체 확인 (v.type) (0) | 2023.05.05 |
[Linux][Kernel] 전처리 Preprocess File 추출 방법 (0) | 2023.05.04 |