이 파일은 왜 필요한가요?
함수 앞에 추적 함수를 끼워 넣더라도 원래 함수의 인자와 복귀 주소는 유지되어야 합니다. 추적 자체가 프로그램의 계산을 바꾸면 관찰 도구가 될 수 없기 때문입니다. 이 코드는 추적용 정보를 따로 모아 콜백에 넘긴 뒤 원래 함수가 시작하려던 자리로 돌아갑니다.
명령·지시문·라벨을 원본 줄 번호에 맞춰 설명합니다. 주석과 빈 줄을 포함한 전체 원문은 아래에 따로 두었습니다. 매크로 정의와 조건부 코드는 모두 차례대로 실행되는 명령 목록이 아닙니다.
기존 코드 분석과 함께 읽기 · 원본 파일 · 설명 원고
먼저 알아둘 개념: 호출 주소와 복귀 주소, 호출 규약, SP와 스택 공간, 스택 프레임과 복귀 기록, 실행 코드의 패치
처음 읽을 때
원래 함수가 부모에게 돌아갈 주소와 추적을 마친 직후 원래 함수 본문으로 갈 주소는 서로 다릅니다. x9와 x30을 구분해 따라가세요.
더 깊이 살펴볼 때
함수 진입 패치, ftrace_regs, 프레임 연결, direct trampoline은 서로 다른 규약입니다. 반환값을 관찰하는 경로에서는 x0–x7을 왜 다시 저장하는지도 ABI와 연결해 보세요.
한 줄씩 레지스터와 메모리 상태 보기
각 코드 아래의 ‘행 그림’을 펼치면, 그 줄에서 읽는 값과 실행 전·후의 상태를 나란히 볼 수 있습니다. 여기서 ‘명령 직전’은 지금 보고 있는 명령이 실행되기 바로 전을 뜻합니다. 함수 진입 때나 소스의 바로 윗줄을 가리키는 말은 아닙니다. 앞서 실행한 명령이 값을 바꿨다면 그 결과가 들어 있습니다.
소스로 정해지는 상수, 호출자가 넘기는 값, 실제 실행에서 정해지는 주소를 구분해서 읽어야 합니다. 주소 숫자를 몰라도 무엇을 가리키는지와 어디서 받아 오는지는 설명할 수 있습니다. ‘명령 직전 x0의 값’처럼 일반 표기로 남은 곳은 한 명령의 동작을 나타내며, 특정 호출 경로의 값까지 확인했다는 뜻은 아닙니다.
일반 명령은 그 한 줄의 효과를, 매크로는 여러 명령을 묶은 주요 결과를 표시합니다. 함수 호출은 호출 직후의 PC와 LR까지만 나타냅니다. 메모리 접근은 정상적으로 끝나는 경우를 가정합니다. 생략된 항목까지 모두 보존된다는 뜻은 아닙니다.
화살표 →는 같은 항목의 전후 비교입니다. 메모리 칸에는 주소와 크기를 따로 적었습니다. SP가 줄어들면 낮은 주소 쪽을 사용하며, 화면의 위아래와 메모리 주소 방향은 별개입니다. 전처리·어셈블·링크 지시문은 CPU 실행과 구분합니다.
‘이전·다음 행’은 소스에 적힌 순서입니다. 분기·반복·호출이 있으므로 파일 위에서 아래로 실제 실행된다고 가정하지 않습니다. 값이 여러 줄에 걸쳐 이어지는 모습은 cpu-reset.S의 단계별 예제에서 보실 수 있습니다.
총 161개 줄에 그림을 붙였습니다. 기존 코드와 설명은 그 아래에서 이어집니다.
먼저 그림으로 살펴보기
추적 지점과 direct call
#include <linux/linkage.h>SYM_FUNC_START·SYM_CODE_START·SYM_INNER_LABEL 등의 심볼 선언 규칙을 가져옵니다. 함수인지 코드 내부 라벨인지, 다른 오브젝트에 보일 이름인지와 정렬·크기 정보를 빌드 도구에 전달하는 데 필요합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
9행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#include <linux/cfi_types.h>간접 호출 대상의 함수 형식을 검사하는 CFI용 어셈블리 심볼 표기를 가져옵니다. 추적 callback과 stub가 빌드의 제어 흐름 보호 규약에 맞는 정보를 갖도록 합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
10행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#include <asm/asm-offsets.h>C 구조체에서 계산한 필드 오프셋을 가져옵니다. 어셈블리가 task_struct·pt_regs 등에서 값을 읽고 쓸 때 C 빌드의 실제 배치와 일치하도록 생성하는 헤더입니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
11행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#include <asm/assembler.h>ARM64의 큰 주소 구성, CPU별 값 조회, 시스템 레지스터 처리, 동기화 등에 쓰는 어셈블리 매크로를 가져옵니다. 각 사용 위치에서 일반 명령 여러 개로 펼쳐지는 작업입니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
12행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#include <asm/ftrace.h>ARM64 ftrace의 저장 레지스터 형식과 호출 규약에 관한 정의를 가져옵니다. 추적 callback과 어셈블리 trampoline이 같은 프레임 크기·의미를 사용하게 합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
13행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#include <asm/insn.h>AArch64 명령의 크기·인코딩 관련 정의를 가져옵니다. 계측 BL 다음 주소에서 실제 callsite를 구할 때 명령 한 개의 크기만큼 보정하는 근거입니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
14행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS함수 인수도 추적기에 제공하는 동적 ftrace 구현을 선택합니다. 켜지면 x0~x8과 SP·FP·LR 등의 ftrace_regs를 만들어 callback에 넘기고, 꺼지면 아래 #else의 전통적인 _mcount/frame 기반 경로를 사용합니다. 추적을 실제로 켜는 런타임 설정과 빌드 기능을 구분해야 합니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
16행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_CODE_START(ftrace_caller)이 위치부터 (ftrace_caller)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. 실제 작업은 아래의 명령들이 수행합니다.
36행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
bti c간접 호출이 들어와도 되는 위치임을 표시합니다. 실제 보호 적용은 CPU 기능과 페이지 설정에 따릅니다.
37행 그림 · 동기화·캐시·대기 상태
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
bti 매크로 본문 · 766행
arch/arm64/include/asm/assembler.h · Linux v6.18.37
정의 선택 조건: #ifndef __ASM_ASSEMBLER_H
.macro bti, targets
.equ .L__bti_targets_c, 34
.equ .L__bti_targets_j, 36
.equ .L__bti_targets_jc,38
hint #.L__bti_targets_\targets
.endm#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS호출 지점마다 연결된 ftrace_ops를 읽을 수 있는 구성을 선택합니다. 켜지면 callsite 앞의 데이터에서 op를 얻어 그 op의 callback을 직접 고르고, 꺼지면 공통 function_trace_op와 패치 가능한 ftrace_call 지점을 사용합니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
39행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
bic x11, x30, 0x7ftrace 호출 뒤의 LR을 8바이트 경계로 내려 callsite 앞에 둔 op 포인터 슬롯을 찾을 기준을 만듭니다. 임의로 함수 주소의 하위 비트를 지우는 보안 검사는 아닙니다. BIC는 마스크에서 1인 위치만 0으로 만들고 나머지 비트는 유지합니다.
LR은 ops 리터럴+16 또는 +20입니다. 하위 세 비트를 지우면 두 경우 모두 리터럴+16이 됩니다.
51행 그림 · 레지스터 상태
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
ldr x11, [x11, #-(4 * AARCH64_INSN_SIZE)] // op정렬 기준에서 네 개 AArch64 명령 크기만큼 앞에 둔 ftrace_ops 포인터를 읽습니다. CALL_OPS가 정의한 callsite 배치와 맞아야 callback을 올바르게 찾을 수 있습니다. 실제로 x11 + (-(4 * AARCH64_INSN_SIZE)) 주소의 메모리 8바이트를 x11에 읽습니다.
52행 그림 · 메모리 읽기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLSdirect-call 구성이면 일반 ftrace callback을 거치지 않고 지정된 trampoline으로 보낼 수 있습니다. 켜진 빌드에서 op->direct_call을 확인하고 0이 아닐 때 직접 경로를 선택하며, 꺼지면 이 빠른 선택 코드는 없습니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
54행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
ldr x17, [x11, #FTRACE_OPS_DIRECT_CALL] // op->direct_call이 callsite의 op가 지정한 direct trampoline 주소를 x17에 읽습니다. 값 0은 이 op에 직접 보낼 목적지가 없음을 뜻합니다. 실제로 x11 + (FTRACE_OPS_DIRECT_CALL) 주소의 메모리 8바이트를 x17에 읽습니다. 이 주소 형식은 기준 레지스터 x11 자체를 갱신하지 않습니다.
59행 그림 · 메모리 읽기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
cbnz x17, ftrace_caller_directdirect trampoline 주소가 있으면 아직 공통 저장 프레임을 만들기 전에 직접 경로로 갑니다. 0이면 일반 ftrace_regs를 만드는 처리로 이어집니다. 이 분기는 지정 레지스터의 값이나 비트를 직접 검사하며 CMP가 남긴 NZCV를 읽거나 바꾸지 않습니다. 조건이 맞지 않으면 바로 다음 명령으로 진행합니다.
60행 그림 · 조건별 실행 위치
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 조건이 맞는 한 경로만 실행합니다. 이 분기 명령은 NZCV를 새로 계산하지 않습니다.
#endif빌드 조건으로 나누었던 구간을 닫습니다. 대상:
61행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#endif빌드 조건으로 나누었던 구간을 닫습니다. 대상:
62행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
ftrace_regs와 두 프레임
mov x10, sp현재 SP의 숫자를 x10에 기억해 둡니다. 스택 자체는 이동하거나 복사되지 않습니다. 나중에 이 값으로 원래 위치를 찾을 수 있습니다.
65행 그림 · 값 복사
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 화살표는 값의 변화를 뜻합니다. 주소값을 옮겨도 그 주소의 메모리 내용은 복사하지 않습니다.
sub sp, sp, #(FREGS_SIZE + 32)함수 인수와 추적 상태를 담을 FREGS_SIZE에 unwind용 프레임 두 개 32바이트를 더해 확보합니다. 추적 callback이 원래 함수 인수를 덮어써도 되돌릴 수 있게 할 공간입니다. 이 명령은 SP의 주소값을 조정하며, 확보하거나 반환하는 스택 공간의 데이터를 직접 저장하거나 지우지는 않습니다. 이 SUB 형식은 NZCV 조건 플래그를 바꾸지 않습니다.
FREGS_SIZE 외 32바이트는 16바이트 프레임 레코드 두 개입니다.
68행 그림 · 레지스터 상태
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
- SP는 주소만 바뀝니다. 스택 데이터 저장·복원은 STR/STP·LDR/LDP 같은 별도 메모리 명령이 수행합니다.
stp x0, x1, [sp, #FREGS_X0]x0, x1의 값을 sp를 기준으로 FREGS_X0만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 첫 위치에는 x0, 그보다 8바이트 높은 위치에는 x1의 값이 들어갑니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
71행 그림 · 메모리 쓰기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
stp x2, x3, [sp, #FREGS_X2]x2, x3의 값을 sp를 기준으로 FREGS_X2만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 첫 위치에는 x2, 그보다 8바이트 높은 위치에는 x3의 값이 들어갑니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
72행 그림 · 메모리 쓰기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
stp x4, x5, [sp, #FREGS_X4]x4, x5의 값을 sp를 기준으로 FREGS_X4만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 첫 위치에는 x4, 그보다 8바이트 높은 위치에는 x5의 값이 들어갑니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
73행 그림 · 메모리 쓰기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
stp x6, x7, [sp, #FREGS_X6]x6, x7의 값을 sp를 기준으로 FREGS_X6만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 첫 위치에는 x6, 그보다 8바이트 높은 위치에는 x7의 값이 들어갑니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
74행 그림 · 메모리 쓰기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
str x8, [sp, #FREGS_X8]x8의 값을 sp를 기준으로 FREGS_X8만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
75행 그림 · 메모리 쓰기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLSdirect-call을 지원하는 빌드에는 ftrace_regs 안의 direct_tramp 슬롯을 준비합니다. 일반 callback이 뒤에서 직접 trampoline을 선택할 가능성을 표현하는 필드이며 미지원 빌드에는 이 경로가 없습니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
77행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
str xzr, [sp, #FREGS_DIRECT_TRAMP]아직 선택된 direct trampoline이 없다는 뜻으로 direct_tramp를 0으로 초기화합니다. callback 후 이 값이 채워졌는지 검사하는 늦은 direct 경로와 연결됩니다. 실제로 sp + (FREGS_DIRECT_TRAMP) 주소의 메모리 8바이트를 xzr의 값으로 씁니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
78행 그림 · 메모리 쓰기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
#endif빌드 조건으로 나누었던 구간을 닫습니다. 대상:
79행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
str x29, [sp, #FREGS_FP]x29의 값을 sp를 기준으로 FREGS_FP만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
82행 그림 · 메모리 쓰기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
str x9, [sp, #FREGS_LR]x9의 값을 sp를 기준으로 FREGS_LR만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
x9에는 BL 전에 MOV x9,LR로 보존한 추적 대상 함수의 원래 LR이 있습니다.
83행 그림 · 메모리 쓰기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
str x10, [sp, #FREGS_SP]x10의 값을 sp를 기준으로 FREGS_SP만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
84행 그림 · 메모리 쓰기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
str x30, [sp, #FREGS_PC]ftrace로 들어오기 직전의 LR, 즉 추적 대상 함수의 callsite 다음 위치를 PC 필드에 저장합니다. 실제 부모에게 돌아갈 주소 x9를 보관한 FREGS_LR과 구분합니다. 실제로 sp + (FREGS_PC) 주소의 메모리 8바이트를 x30의 값으로 씁니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
현재 x30은 추적 대상 함수로 재개할 PC입니다.
87행 그림 · 메모리 쓰기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
stp x29, x9, [sp, #FREGS_SIZE + 16]x29, x9의 값을 sp를 기준으로 FREGS_SIZE + 16만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 첫 위치에는 x29, 그보다 8바이트 높은 위치에는 x9의 값이 들어갑니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
90행 그림 · 메모리 쓰기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
add x29, sp, #FREGS_SIZE + 16sp를 기준으로 FREGS_SIZE + 16을 더해 x29에 결과를 둡니다. 주소 계산에 쓰이는 경우에는 구조체의 필드나 다음 저장 위치를 찾는 동작입니다. 이 형태는 조건 플래그를 바꾸지 않습니다.
91행 그림 · 레지스터 상태
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
stp x29, x30, [sp, #FREGS_SIZE]x29, x30의 값을 sp를 기준으로 FREGS_SIZE만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 첫 위치에는 x29, 그보다 8바이트 높은 위치에는 x30의 값이 들어갑니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
94행 그림 · 메모리 쓰기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
add x29, sp, #FREGS_SIZEsp를 기준으로 FREGS_SIZE을 더해 x29에 결과를 둡니다. 주소 계산에 쓰이는 경우에는 구조체의 필드나 다음 저장 위치를 찾는 동작입니다. 이 형태는 조건 플래그를 바꾸지 않습니다.
95행 그림 · 레지스터 상태
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
sub x0, x30, #AARCH64_INSN_SIZE // ip (callsite's BL insn)BL 다음 주소인 x30에서 명령 크기 4바이트를 빼 실제 ftrace callsite의 주소 ip를 첫 인수 x0로 만듭니다. 이 SUB 형식은 NZCV 조건 플래그를 바꾸지 않습니다.
BL 이후 PC에서 4를 빼 추적 호출 지점 ip를 전달합니다.
98행 그림 · 레지스터 상태
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
mov x1, x9 // parent_ip (callsite's LR)추적 대상 함수가 부모로 돌아갈 주소 x9를 parent_ip 인수 x1로 넘깁니다. ftrace 내부에서 돌아갈 LR과 다른 주소입니다. MOV는 x1의 기존 값을 대체합니다. 원본이 주소값이어도 그 주소의 메모리를 읽거나 복사하지 않습니다.
99행 그림 · 값 복사
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 화살표는 값의 변화를 뜻합니다. 주소값을 옮겨도 그 주소의 메모리 내용은 복사하지 않습니다.
mov x3, sp // regs현재 SP가 가리키는 ftrace_regs 저장 영역을 네 번째 인수 x3로 넘겨 callback이 함수 인수·문맥을 확인할 수 있게 합니다. x3에 담기는 것은 SP의 주소값이며, SP와 스택 메모리의 내용은 그대로입니다.
100행 그림 · 값 복사
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 화살표는 값의 변화를 뜻합니다. 주소값을 옮겨도 그 주소의 메모리 내용은 복사하지 않습니다.
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPSCALL_OPS가 켜져 있으면 이미 callsite에서 얻은 op와 op->func를 사용합니다. 꺼진 빌드는 다음 #else에서 공통 op 및 패치 가능한 호출을 사용합니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
102행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
mov x2, x11 // opx2에 x11에 들어 있는 값을 넣습니다. 원래 x2의 내용은 덮어쓰며, 다른 레지스터나 그 주소의 메모리까지 복사하지는 않습니다.
103행 그림 · 값 복사
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 화살표는 값의 변화를 뜻합니다. 주소값을 옮겨도 그 주소의 메모리 내용은 복사하지 않습니다.
ldr x4, [x2, #FTRACE_OPS_FUNC] // op->funcftrace_ops의 func 필드에서 실제 callback 주소를 꺼냅니다. 단순한 코드 상수가 아니라 op마다 다른 함수 포인터입니다. 실제로 x2 + (FTRACE_OPS_FUNC) 주소의 메모리 8바이트를 x4에 읽습니다. 이 주소 형식은 기준 레지스터 x2 자체를 갱신하지 않습니다.
104행 그림 · 메모리 읽기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
blr x4 // op->func(ip, parent_ip, op, regs)op->func(ip, parent_ip, op, regs)를 호출합니다. x0~x3는 앞서 준비한 추적 위치·부모 주소·op·저장 레지스터이며, 원래 대상 함수의 인수는 스택에 보존되어 callback 뒤에 복원합니다. BLR은 다음 명령의 주소를 LR(x30)에 기록하고 레지스터에 든 목적지로 분기합니다.
105행 그림 · 호출과 실행 위치
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 그림은 분기 명령 자체의 효과입니다. 호출된 함수가 실행된 뒤의 레지스터 값은 그 함수의 반환·보존 규칙을 따라야 합니다.
#elsecallsite별 op를 쓰지 않는 구성에서는 공통 function_trace_op를 로드하고 ftrace_call의 명령을 패치하는 경로를 사용합니다. ftrace 전체가 꺼진다는 뜻은 아닙니다.
107행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
ldr_l x2, function_trace_op // op현재 추적 작업 객체 function_trace_op의 값을 세 번째 인수 x2로 읽습니다. callback이 어느 ftrace_ops 설정으로 호출되었는지 알 수 있게 하며, 변수의 주소 자체를 넘기는 것이 아닙니다. ldr_l은 ADRP로 심벌이 속한 페이지를 구한 뒤 LDR로 그 위치의 값을 읽는 매크로입니다. 주소를 구하는 adr_l과 달리 실제 메모리 접근이 있습니다.
108행 그림 · 주소·값 구분
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 이 매크로의 임시 레지스터는 내부에서 사용됩니다.
ldr_l 매크로 본문 · 187행
arch/arm64/include/asm/assembler.h · Linux v6.18.37
정의 선택 조건: #ifndef __ASM_ASSEMBLER_H
.macro ldr_l, dst, sym, tmp=
.ifb \tmp
adrp \dst, \sym
ldr \dst, [\dst, :lo12:\sym]
.else
adrp \tmp, \sym
ldr \dst, [\tmp, :lo12:\sym]
.endif
.endmSYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)기존 함수 안의 중간 위치에 이름을 붙입니다. 다른 분기에서 찾아올 수 있지만 새 함수를 호출하거나 스택 프레임을 만드는 동작은 아닙니다.
110행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
bl ftrace_stub // func(ip, parent_ip, op, regs)초기에는 아무 일도 하지 않는 ftrace_stub로 호출하지만 ftrace_call 지점은 실행 중 추적 callback으로 패치될 수 있습니다. 인수는 ip, parent_ip, op, ftrace_regs이며 추적이 끝나면 저장한 대상 함수 인수를 복구합니다. BL은 다음 명령의 주소를 LR(x30)에 기록하고 목적지로 분기합니다. 호출된 코드가 x0 같은 작업 레지스터를 바꿀 수 있으므로, 호출 뒤의 값은 그 코드의 반환·보존 규칙에 따릅니다.
111행 그림 · 호출과 실행 위치
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 그림은 분기 명령 자체의 효과입니다. 호출된 함수가 실행된 뒤의 레지스터 값은 그 함수의 반환·보존 규칙을 따라야 합니다.
#endif빌드 조건으로 나누었던 구간을 닫습니다. 대상:
112행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
복원과 direct trampoline
ldp x0, x1, [sp, #FREGS_X0]sp를 기준으로 FREGS_X0만큼 계산한 메모리 위치에 보관된 값을 x0, x1로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 첫 위치에서 x0, 그보다 8바이트 높은 위치에서 x1의 값을 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다.
120행 그림 · 메모리 읽기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
ldp x2, x3, [sp, #FREGS_X2]sp를 기준으로 FREGS_X2만큼 계산한 메모리 위치에 보관된 값을 x2, x3로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 첫 위치에서 x2, 그보다 8바이트 높은 위치에서 x3의 값을 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다.
121행 그림 · 메모리 읽기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
ldp x4, x5, [sp, #FREGS_X4]sp를 기준으로 FREGS_X4만큼 계산한 메모리 위치에 보관된 값을 x4, x5로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 첫 위치에서 x4, 그보다 8바이트 높은 위치에서 x5의 값을 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다.
122행 그림 · 메모리 읽기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
ldp x6, x7, [sp, #FREGS_X6]sp를 기준으로 FREGS_X6만큼 계산한 메모리 위치에 보관된 값을 x6, x7로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 첫 위치에서 x6, 그보다 8바이트 높은 위치에서 x7의 값을 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다.
123행 그림 · 메모리 읽기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
ldr x8, [sp, #FREGS_X8]sp를 기준으로 FREGS_X8만큼 계산한 메모리 위치에 보관된 값을 x8로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다.
124행 그림 · 메모리 읽기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
ldr x29, [sp, #FREGS_FP]sp를 기준으로 FREGS_FP만큼 계산한 메모리 위치에 보관된 값을 x29로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다.
127행 그림 · 메모리 읽기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLSdirect-call 지원 빌드에서 일반 callback이 ftrace_regs.direct_tramp를 설정했는지 검사하는 코드를 포함합니다. 초기에 direct 목적지가 없었더라도 callback 후 늦게 경로가 선택될 수 있습니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
129행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
ldr x17, [sp, #FREGS_DIRECT_TRAMP]callback이 지정했을 수 있는 direct trampoline 주소를 x17에 읽습니다. 이 슬롯을 앞에서 0으로 초기화했기 때문에 0은 일반 복귀를 뜻합니다. 실제로 sp + (FREGS_DIRECT_TRAMP) 주소의 메모리 8바이트를 x17에 읽습니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
130행 그림 · 메모리 읽기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
cbnz x17, ftrace_caller_direct_latecallback 뒤에 direct 목적지가 생겼으면 이미 만든 저장 프레임을 정리하는 late 경로로 갑니다. 바로 초기 direct 경로로 가면 SP·LR 배치가 맞지 않습니다. 이 분기는 지정 레지스터의 값이나 비트를 직접 검사하며 CMP가 남긴 NZCV를 읽거나 바꾸지 않습니다. 조건이 맞지 않으면 바로 다음 명령으로 진행합니다.
131행 그림 · 조건별 실행 위치
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 조건이 맞는 한 경로만 실행합니다. 이 분기 명령은 NZCV를 새로 계산하지 않습니다.
#endif빌드 조건으로 나누었던 구간을 닫습니다. 대상:
132행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
ldr x30, [sp, #FREGS_LR]sp를 기준으로 FREGS_LR만큼 계산한 메모리 위치에 보관된 값을 x30로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다.
원래 함수가 나중에 부모에게 돌아갈 LR을 복원합니다.
135행 그림 · 메모리 읽기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
ldr x9, [sp, #FREGS_PC]sp를 기준으로 FREGS_PC만큼 계산한 메모리 위치에 보관된 값을 x9로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다.
추적을 끝내고 즉시 계속할 위치는 별도 x9에 읽습니다.
136행 그림 · 메모리 읽기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
add sp, sp, #FREGS_SIZE + 32현재 사용한 스택 공간 FREGS_SIZE + 32바이트를 해제합니다. SP를 높은 주소로 되돌리며 메모리 내용을 0으로 지우는 것은 아닙니다.
139행 그림 · 레지스터 상태
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
- SP는 주소만 바뀝니다. 스택 데이터 저장·복원은 STR/STP·LDR/LDP 같은 별도 메모리 명령이 수행합니다.
ret x9x9에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
X30의 부모 주소가 아니라 X9의 함수 본문 재개 주소로 이동합니다.
141행 그림 · 호출과 실행 위치
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS늦은 direct-call 전환이 필요한 빌드에만 아래 프레임 해제·LR 재배치 경로를 생성합니다. 일반 callback을 호출한 뒤의 상태를 direct trampoline의 호출 규칙에 맞춥니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
143행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_INNER_LABEL(ftrace_caller_direct_late, SYM_L_LOCAL)기존 함수 안의 중간 위치에 이름을 붙입니다. 다른 분기에서 찾아올 수 있지만 새 함수를 호출하거나 스택 프레임을 만드는 동작은 아닙니다.
144행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
ldr x9, [sp, #FREGS_LR]sp를 기준으로 FREGS_LR만큼 계산한 메모리 위치에 보관된 값을 x9로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다.
155행 그림 · 메모리 읽기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
ldr x30, [sp, #FREGS_PC]sp를 기준으로 FREGS_PC만큼 계산한 메모리 위치에 보관된 값을 x30로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다.
156행 그림 · 메모리 읽기
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
add sp, sp, #FREGS_SIZE + 32현재 사용한 스택 공간 FREGS_SIZE + 32바이트를 해제합니다. SP를 높은 주소로 되돌리며 메모리 내용을 0으로 지우는 것은 아닙니다.
159행 그림 · 레지스터 상태
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
- SP는 주소만 바뀝니다. 스택 데이터 저장·복원은 STR/STP·LDR/LDP 같은 별도 메모리 명령이 수행합니다.
SYM_INNER_LABEL(ftrace_caller_direct, SYM_L_LOCAL)기존 함수 안의 중간 위치에 이름을 붙입니다. 다른 분기에서 찾아올 수 있지만 새 함수를 호출하거나 스택 프레임을 만드는 동작은 아닙니다.
161행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
br x17x17의 direct trampoline으로 새 LR을 만들지 않고 이동합니다. 앞서 x9와 x30을 이 경로의 규칙대로 준비하여 trampoline이 대상 함수와 부모의 복귀 주소를 구분할 수 있게 합니다. 레지스터가 담은 주소로 실행 위치를 바꾸며, 그 주소에서 값을 읽어 다른 레지스터에 복사하는 load 명령은 아닙니다.
직접 trampoline 호출 규약의 x9·x30을 유지합니다.
168행 그림 · 호출과 실행 위치
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */빌드 조건으로 나누었던 구간을 닫습니다. 대상:
169행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_CODE_END(ftrace_caller)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
170행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLSdirect-call 지원 빌드에는 특별한 작업 없이 정상 복귀만 이어 주는 stub trampoline도 포함합니다. 아래에서 x30과 x9의 역할을 교환해 direct 호출 규칙을 유지합니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
172행 그림 · 전처리 단계
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_CODE_START(ftrace_stub_direct_tramp)이 위치부터 (ftrace_stub_direct_tramp)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. 실제 작업은 아래의 명령들이 수행합니다.
173행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_stub_direct_tramp
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
bti c간접 호출이 들어와도 되는 위치임을 표시합니다. 실제 보호 적용은 CPU 기능과 페이지 설정에 따릅니다.
174행 그림 · 동기화·캐시·대기 상태
함수·코드 범위: ftrace_stub_direct_tramp
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
bti 매크로 본문 · 766행
arch/arm64/include/asm/assembler.h · Linux v6.18.37
정의 선택 조건: #ifndef __ASM_ASSEMBLER_H
.macro bti, targets
.equ .L__bti_targets_c, 34
.equ .L__bti_targets_j, 36
.equ .L__bti_targets_jc,38
hint #.L__bti_targets_\targets
.endm mov x10, x30x10에 LR(x30)에 들어 있는 값을 넣습니다. 원래 x10의 내용은 덮어쓰며, 다른 레지스터나 그 주소의 메모리까지 복사하지는 않습니다.
175행 그림 · 값 복사
함수·코드 범위: ftrace_stub_direct_tramp
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 화살표는 값의 변화를 뜻합니다. 주소값을 옮겨도 그 주소의 메모리 내용은 복사하지 않습니다.
mov x30, x9x30에 x9에 들어 있는 값을 넣습니다. 원래 x30의 내용은 덮어쓰며, 다른 레지스터나 그 주소의 메모리까지 복사하지는 않습니다.
176행 그림 · 값 복사
함수·코드 범위: ftrace_stub_direct_tramp
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 화살표는 값의 변화를 뜻합니다. 주소값을 옮겨도 그 주소의 메모리 내용은 복사하지 않습니다.
ret x10x10에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
177행 그림 · 호출과 실행 위치
함수·코드 범위: ftrace_stub_direct_tramp
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_CODE_END(ftrace_stub_direct_tramp)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
178행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_stub_direct_tramp
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
전통적인 _mcount 프레임 매크로
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */빌드 조건으로 나누었던 구간을 닫습니다. 대상:
179행 그림 · 전처리 단계
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS / #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */인수 전달형 동적 ftrace를 사용하지 않는 빌드는 기존 _mcount/frame 기반 구현을 만듭니다. 아래 코드는 저장 프레임을 따라 함수·부모 주소를 구하며 위의 ftrace_regs 구성과 섞어 읽으면 안 됩니다.
181행 그림 · 전처리 단계
이 줄을 포함하는 조건: #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.macro mcount_enter추적 코드가 C 함수를 호출해도 원래 FP와 LR을 잃지 않도록 16바이트 프레임을 만드는 매크로입니다. x29를 새 프레임의 기준으로 삼아 뒤의 부모 프레임 조회가 가능해집니다. 이 줄은 어셈블러 매크로 정의의 시작입니다. 본문은 매크로를 사용하는 위치에 펼쳐지며, 정의 자체가 런타임 함수 호출은 아닙니다.
215행 그림 · 어셈블·링크 단계
매크로 본문: mcount_enter
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 뒤의 본문은 이 이름을 사용하는 위치에 펼쳐집니다. 정의 위치를 CPU가 함수처럼 호출하지 않습니다.
stp x29, x30, [sp, #-16]!x29, x30의 값을 sp를 기준으로 -16만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 첫 위치에는 x29, 그보다 8바이트 높은 위치에는 x30의 값이 들어갑니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다. 쓰기 전에 기준 주소를 갱신합니다. SP의 음수 오프셋이면 낮은 주소 쪽에 저장 공간을 확보하는 뜻입니다.
216행 그림 · 메모리 쓰기
매크로 본문: mcount_enter
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- !는 전위 갱신입니다. 오프셋을 더한 주소로 접근하고 그 주소를 기준 레지스터에도 남깁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
- 매크로 mcount_enter의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
mov x29, sp현재 SP의 숫자를 x29에 기억해 둡니다. 스택 자체는 이동하거나 복사되지 않습니다. 나중에 이 값으로 원래 위치를 찾을 수 있습니다.
217행 그림 · 값 복사
매크로 본문: mcount_enter
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 화살표는 값의 변화를 뜻합니다. 주소값을 옮겨도 그 주소의 메모리 내용은 복사하지 않습니다.
- 매크로 mcount_enter의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
.endm공통 작업의 정의를 여기서 마칩니다. RET가 아니라 빌드 도구가 읽는 경계입니다.
218행 그림 · 어셈블·링크 단계
매크로 본문: mcount_enter
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
.macro mcount_exitmcount_enter가 만든 프레임에서 FP·LR을 되돌리고 SP를 16바이트 복구한 뒤 반환하는 매크로입니다. 진입과 대칭이어야 대상 함수의 스택이 유지됩니다. 이 줄은 어셈블러 매크로 정의의 시작입니다. 본문은 매크로를 사용하는 위치에 펼쳐지며, 정의 자체가 런타임 함수 호출은 아닙니다.
220행 그림 · 어셈블·링크 단계
매크로 본문: mcount_exit
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 뒤의 본문은 이 이름을 사용하는 위치에 펼쳐집니다. 정의 위치를 CPU가 함수처럼 호출하지 않습니다.
ldp x29, x30, [sp], #16sp가 가리키는 메모리 위치에 보관된 값을 x29, x30로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 첫 위치에서 x29, 그보다 8바이트 높은 위치에서 x30의 값을 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다. 읽은 뒤 기준 포인터를 옮깁니다. SP가 증가하는 경우는 사용한 스택 공간을 해제하는 단계입니다.
221행 그림 · 메모리 읽기
매크로 본문: mcount_exit
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 대괄호 밖의 오프셋은 후위 갱신입니다. 이전 주소로 접근한 뒤 기준 레지스터를 갱신합니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
- 매크로 mcount_exit의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
222행 그림 · 호출과 실행 위치
매크로 본문: mcount_exit
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
- 매크로 mcount_exit의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
.endm공통 작업의 정의를 여기서 마칩니다. RET가 아니라 빌드 도구가 읽는 경계입니다.
223행 그림 · 어셈블·링크 단계
매크로 본문: mcount_exit
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
.macro mcount_adjust_addr rd, rnBL이 LR에 남긴 다음 명령 주소 rn에서 AArch64 명령 크기 4를 빼 호출 명령 자체의 주소를 rd에 만듭니다. 추적 로그에 callsite를 정확히 기록하기 위한 주소 보정입니다. 이 줄은 어셈블러 매크로 정의의 시작입니다. 본문은 매크로를 사용하는 위치에 펼쳐지며, 정의 자체가 런타임 함수 호출은 아닙니다.
225행 그림 · 어셈블·링크 단계
매크로 본문: mcount_adjust_addr
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 뒤의 본문은 이 이름을 사용하는 위치에 펼쳐집니다. 정의 위치를 CPU가 함수처럼 호출하지 않습니다.
sub \rd, \rn, #AARCH64_INSN_SIZE\rn를 기준으로 AARCH64_INSN_SIZE을 빼서 \rd에 결과를 둡니다. 주소 계산에 쓰이는 경우에는 구조체의 필드나 다음 저장 위치를 찾는 동작입니다. 이 형태는 조건 플래그를 바꾸지 않습니다.
226행 그림 · 레지스터 상태
매크로 본문: mcount_adjust_addr
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
- 매크로 mcount_adjust_addr의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
.endm공통 작업의 정의를 여기서 마칩니다. RET가 아니라 빌드 도구가 읽는 경계입니다.
227행 그림 · 어셈블·링크 단계
매크로 본문: mcount_adjust_addr
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
.macro mcount_get_parent_fp reg현재 mcount 프레임과 그 호출 프레임의 FP 연결을 두 번 따라 부모 함수의 FP를 구합니다. 두 load는 같은 값을 중복 읽는 것이 아니라 한 단계씩 스택 프레임을 거슬러 갑니다. 이 줄은 어셈블러 매크로 정의의 시작입니다. 본문은 매크로를 사용하는 위치에 펼쳐지며, 정의 자체가 런타임 함수 호출은 아닙니다.
230행 그림 · 어셈블·링크 단계
매크로 본문: mcount_get_parent_fp
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 뒤의 본문은 이 이름을 사용하는 위치에 펼쳐집니다. 정의 위치를 CPU가 함수처럼 호출하지 않습니다.
ldr \reg, [x29]x29가 가리키는 메모리 위치에 보관된 값을 \reg로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다.
231행 그림 · 메모리 읽기
매크로 본문: mcount_get_parent_fp
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 mcount_get_parent_fp의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldr \reg, [\reg]\reg가 가리키는 메모리 위치에 보관된 값을 \reg로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다.
232행 그림 · 메모리 읽기
매크로 본문: mcount_get_parent_fp
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 mcount_get_parent_fp의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
.endm공통 작업의 정의를 여기서 마칩니다. RET가 아니라 빌드 도구가 읽는 경계입니다.
233행 그림 · 어셈블·링크 단계
매크로 본문: mcount_get_parent_fp
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
.macro mcount_get_pc0 reg새 추적 프레임을 만들기 전의 x30에서 4를 빼 대상 함수의 ftrace callsite 주소를 구합니다. 입력 위치가 이미 스택에 저장된 PC를 읽는 아래 매크로와 다릅니다. 이 줄은 어셈블러 매크로 정의의 시작입니다. 본문은 매크로를 사용하는 위치에 펼쳐지며, 정의 자체가 런타임 함수 호출은 아닙니다.
236행 그림 · 어셈블·링크 단계
매크로 본문: mcount_get_pc0
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 뒤의 본문은 이 이름을 사용하는 위치에 펼쳐집니다. 정의 위치를 CPU가 함수처럼 호출하지 않습니다.
mcount_adjust_addr \reg, x30현재 LR에서 4를 빼 ftrace 호출 명령의 주소를 만듭니다. 추적기에 전달할 PC는 BL 다음 복귀 위치가 아니라 계측된 callsite여야 합니다.
237행 그림 · 매크로 전체의 상태 변화
매크로 본문: mcount_get_pc0
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 매크로 mcount_get_pc0의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
mcount_adjust_addr 매크로 본문 · 225행
arch/arm64/kernel/entry-ftrace.S · Linux v6.18.37
정의 선택 조건: 앞 조건의 반대
.macro mcount_adjust_addr rd, rn
sub \rd, \rn, #AARCH64_INSN_SIZE
.endm .endm공통 작업의 정의를 여기서 마칩니다. RET가 아니라 빌드 도구가 읽는 경계입니다.
238행 그림 · 어셈블·링크 단계
매크로 본문: mcount_get_pc0
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
.macro mcount_get_pc regmcount 프레임에 저장된 LR을 읽고 4를 빼 callsite PC로 만듭니다. 추가 호출로 현재 x30이 바뀐 경우에도 저장된 주소를 사용합니다. 이 줄은 어셈블러 매크로 정의의 시작입니다. 본문은 매크로를 사용하는 위치에 펼쳐지며, 정의 자체가 런타임 함수 호출은 아닙니다.
240행 그림 · 어셈블·링크 단계
매크로 본문: mcount_get_pc
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 뒤의 본문은 이 이름을 사용하는 위치에 펼쳐집니다. 정의 위치를 CPU가 함수처럼 호출하지 않습니다.
ldr \reg, [x29, #8]x29를 기준으로 8만큼 계산한 메모리 위치에 보관된 값을 \reg로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다.
241행 그림 · 메모리 읽기
매크로 본문: mcount_get_pc
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 mcount_get_pc의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
mcount_adjust_addr \reg, \reg프레임에서 읽은 LR에서 4를 빼 원래 계측 callsite를 구합니다. 현재 LR은 다른 호출로 바뀔 수 있으므로 저장 사본을 기준으로 합니다.
242행 그림 · 매크로 전체의 상태 변화
매크로 본문: mcount_get_pc
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 매크로 mcount_get_pc의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
mcount_adjust_addr 매크로 본문 · 225행
arch/arm64/kernel/entry-ftrace.S · Linux v6.18.37
정의 선택 조건: 앞 조건의 반대
.macro mcount_adjust_addr rd, rn
sub \rd, \rn, #AARCH64_INSN_SIZE
.endm .endm공통 작업의 정의를 여기서 마칩니다. RET가 아니라 빌드 도구가 읽는 경계입니다.
243행 그림 · 어셈블·링크 단계
매크로 본문: mcount_get_pc
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
.macro mcount_get_lr reg이전 프레임의 LR 슬롯을 읽어 추적 대상 함수가 부모로 돌아갈 주소를 구합니다. 함수 시작 주소나 현재 PC를 구하는 매크로가 아닙니다. 이 줄은 어셈블러 매크로 정의의 시작입니다. 본문은 매크로를 사용하는 위치에 펼쳐지며, 정의 자체가 런타임 함수 호출은 아닙니다.
245행 그림 · 어셈블·링크 단계
매크로 본문: mcount_get_lr
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 뒤의 본문은 이 이름을 사용하는 위치에 펼쳐집니다. 정의 위치를 CPU가 함수처럼 호출하지 않습니다.
ldr \reg, [x29]x29가 가리키는 메모리 위치에 보관된 값을 \reg로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다.
246행 그림 · 메모리 읽기
매크로 본문: mcount_get_lr
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 mcount_get_lr의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldr \reg, [\reg, #8]\reg를 기준으로 8만큼 계산한 메모리 위치에 보관된 값을 \reg로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다.
247행 그림 · 메모리 읽기
매크로 본문: mcount_get_lr
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 mcount_get_lr의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
.endm공통 작업의 정의를 여기서 마칩니다. RET가 아니라 빌드 도구가 읽는 경계입니다.
248행 그림 · 어셈블·링크 단계
매크로 본문: mcount_get_lr
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
.macro mcount_get_lr_addr reg이전 프레임에서 LR 값 자체가 아니라 LR이 저장된 메모리 주소를 구합니다. function graph tracer가 이 슬롯을 return_to_handler로 바꿀 수 있게 하기 위한 인수입니다. 이 줄은 어셈블러 매크로 정의의 시작입니다. 본문은 매크로를 사용하는 위치에 펼쳐지며, 정의 자체가 런타임 함수 호출은 아닙니다.
250행 그림 · 어셈블·링크 단계
매크로 본문: mcount_get_lr_addr
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 뒤의 본문은 이 이름을 사용하는 위치에 펼쳐집니다. 정의 위치를 CPU가 함수처럼 호출하지 않습니다.
ldr \reg, [x29]x29가 가리키는 메모리 위치에 보관된 값을 \reg로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다.
251행 그림 · 메모리 읽기
매크로 본문: mcount_get_lr_addr
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 mcount_get_lr_addr의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
add \reg, \reg, #8\reg를 기준으로 8을 더해 \reg에 결과를 둡니다. 주소 계산에 쓰이는 경우에는 구조체의 필드나 다음 저장 위치를 찾는 동작입니다. 이 형태는 조건 플래그를 바꾸지 않습니다.
252행 그림 · 레지스터 상태
매크로 본문: mcount_get_lr_addr
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
- 매크로 mcount_get_lr_addr의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
.endm공통 작업의 정의를 여기서 마칩니다. RET가 아니라 빌드 도구가 읽는 경계입니다.
253행 그림 · 어셈블·링크 단계
매크로 본문: mcount_get_lr_addr
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
패치 위치와 함수 그래프 진입
SYM_FUNC_START(_mcount)이 위치부터 (_mcount)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
261행 그림 · 어셈블·링크 단계
함수·코드 범위: _mcount
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
262행 그림 · 호출과 실행 위치
함수·코드 범위: _mcount
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(_mcount)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
263행 그림 · 어셈블·링크 단계
함수·코드 범위: _mcount
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
EXPORT_SYMBOL(_mcount)계측된 커널 모듈도 _mcount 진입점을 연결할 수 있도록 커널 export 정보를 만듭니다. 모듈의 함수 추적 호출이 이 공통 구현을 참조하기 위한 조치입니다. 빌드할 때 심벌을 가리키는 메타데이터를 만드는 표기이며, 이 위치에서 함수를 호출하는 명령은 아닙니다.
264행 그림 · 어셈블·링크 단계
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
NOKPROBE(_mcount)_mcount을 kprobe 설치 금지 목록에 넣습니다. 추적기 자체에 probe를 걸면 재귀 계측으로 이어질 수 있어 이 저수준 추적 진입을 보호합니다. CONFIG_KPROBES가 꺼지면 이 목록 항목도 필요 없습니다. 빌드할 때 심벌을 가리키는 메타데이터를 만드는 표기이며, 이 위치에서 함수를 호출하는 명령은 아닙니다.
265행 그림 · 어셈블·링크 단계
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_START(ftrace_caller)이 위치부터 (ftrace_caller)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
276행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
mcount_enter추적 코드가 다른 함수를 부르기 전에 원래 프레임과 복귀 주소를 스택에 보관합니다. 추적을 마친 뒤 돌아갈 자리를 남기는 일입니다. 여기의 인자는 없음입니다.
277행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
mcount_enter 매크로 본문 · 215행
arch/arm64/kernel/entry-ftrace.S · Linux v6.18.37
정의 선택 조건: 앞 조건의 반대
.macro mcount_enter
stp x29, x30, [sp, #-16]!
mov x29, sp
.endm mcount_get_pc0 x0 // function's pc추적 대상 함수의 callsite PC를 첫 인수 x0에 만듭니다. mcount_enter를 하기 전이므로 현재 x30에서 4를 빼면 원래 BL 위치를 얻습니다.
279행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
mcount_get_pc0 매크로 본문 · 236행
arch/arm64/kernel/entry-ftrace.S · Linux v6.18.37
정의 선택 조건: 앞 조건의 반대
.macro mcount_get_pc0 reg
mcount_adjust_addr \reg, x30
.endm mcount_get_lr x1 // function's lr스택 프레임에 보존된 부모 복귀 주소를 두 번째 인수 x1에 읽습니다. 첫 인수의 계측 위치와 함께 어느 함수 호출 관계인지 추적 callback에 전달합니다. 먼저 현재 프레임에 저장된 FP를 읽고, 그 FP의 +8 위치에서 부모에게 돌아갈 LR을 읽습니다.
280행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
mcount_get_lr 매크로 본문 · 245행
arch/arm64/kernel/entry-ftrace.S · Linux v6.18.37
정의 선택 조건: 앞 조건의 반대
.macro mcount_get_lr reg
ldr \reg, [x29]
ldr \reg, [\reg, #8]
.endmSYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) // tracer(pc, lr);기존 함수 안의 중간 위치에 이름을 붙입니다. 다른 분기에서 찾아올 수 있지만 새 함수를 호출하거나 스택 프레임을 만드는 동작은 아닙니다.
282행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
nop // This will be replaced with "bl xxx"현재 바이트는 아무 일도 하지 않는 자리입니다. 추적이나 CPU 기능 대체 패치의 대상이면 나중에 다른 명령이 들어갈 수 있습니다.
런타임 패치 시 추적 함수 BL로 바뀌는 위치입니다.
283행 그림 · 동기화·캐시·대기 상태
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#ifdef CONFIG_FUNCTION_GRAPH_TRACERfunction graph tracer는 함수 진입뿐 아니라 복귀도 기록하여 호출 관계와 수행 시간을 관찰합니다. 켜지면 graph caller를 부를 패치 지점을 포함하고, 꺼지면 일반 함수 진입 추적만 이어집니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
286행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) // ftrace_graph_caller();기존 함수 안의 중간 위치에 이름을 붙입니다. 다른 분기에서 찾아올 수 있지만 새 함수를 호출하거나 스택 프레임을 만드는 동작은 아닙니다.
287행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: 앞 조건의 반대 / #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
nop // If enabled, this will be replaced현재 바이트는 아무 일도 하지 않는 자리입니다. 추적이나 CPU 기능 대체 패치의 대상이면 나중에 다른 명령이 들어갈 수 있습니다.
함수 그래프 추적이 켜지면 ftrace_graph_caller로 향하는 B로 바뀝니다.
288행 그림 · 동기화·캐시·대기 상태
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: 앞 조건의 반대 / #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#endif빌드 조건으로 나누었던 구간을 닫습니다. 대상:
290행 그림 · 전처리 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: 앞 조건의 반대 / #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
mcount_exit추적에 쓰려고 만든 프레임을 해제하고 보관한 복귀 주소로 돌아갑니다. 여기의 인자는 없음입니다.
292행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
mcount_exit 매크로 본문 · 220행
arch/arm64/kernel/entry-ftrace.S · Linux v6.18.37
정의 선택 조건: 앞 조건의 반대
.macro mcount_exit
ldp x29, x30, [sp], #16
ret
.endmSYM_FUNC_END(ftrace_caller)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
293행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_caller
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
#ifdef CONFIG_FUNCTION_GRAPH_TRACER함수 복귀를 가로채는 graph caller 구현을 빌드합니다. 원래 복귀 주소는 추적 자료에 보존하고 스택의 LR 슬롯을 추적용 handler로 바꾸는 준비가 아래에서 이루어집니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
295행 그림 · 전처리 단계
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_START(ftrace_graph_caller)이 위치부터 (ftrace_graph_caller)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
305행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_graph_caller
이 줄을 포함하는 조건: 앞 조건의 반대 / #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
mcount_get_pc x0 // function's pc추가 추적 프레임에 저장된 LR에서 대상 함수의 callsite PC를 복원하여 x0에 전달합니다. 현재 x30을 바로 쓰면 직전 추적 호출의 주소와 섞일 수 있습니다. 저장된 LR은 BL 다음 주소이므로 여기서 4바이트를 빼 호출 명령의 위치를 구합니다.
306행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: ftrace_graph_caller
이 줄을 포함하는 조건: 앞 조건의 반대 / #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
mcount_get_pc 매크로 본문 · 240행
arch/arm64/kernel/entry-ftrace.S · Linux v6.18.37
정의 선택 조건: 앞 조건의 반대
.macro mcount_get_pc reg
ldr \reg, [x29, #8]
mcount_adjust_addr \reg, \reg
.endm mcount_get_lr_addr x1 // pointer to function's saved lr대상 함수의 부모 LR이 저장된 슬롯 주소를 x1에 전달합니다. prepare_ftrace_return이 그 슬롯을 복귀 추적 handler로 바꿀 수 있어야 하므로 LR 값 자체가 아니라 주소가 필요합니다. 매크로는 현재 프레임에 저장된 FP를 읽고 8을 더해 LR 슬롯의 주소를 구합니다.
307행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: ftrace_graph_caller
이 줄을 포함하는 조건: 앞 조건의 반대 / #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
mcount_get_lr_addr 매크로 본문 · 250행
arch/arm64/kernel/entry-ftrace.S · Linux v6.18.37
정의 선택 조건: 앞 조건의 반대
.macro mcount_get_lr_addr reg
ldr \reg, [x29]
add \reg, \reg, #8
.endm mcount_get_parent_fp x2 // parent's fpFP 연결을 따라 부모 프레임 포인터를 x2에 전달합니다. prepare_ftrace_return이 함수 진입 정보와 복귀 추적 상태를 올바른 프레임에 연결하는 입력입니다. 매크로 내부에서는 저장된 FP 연결을 두 번 읽어 부모 프레임에 도달합니다.
308행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: ftrace_graph_caller
이 줄을 포함하는 조건: 앞 조건의 반대 / #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
mcount_get_parent_fp 매크로 본문 · 230행
arch/arm64/kernel/entry-ftrace.S · Linux v6.18.37
정의 선택 조건: 앞 조건의 반대
.macro mcount_get_parent_fp reg
ldr \reg, [x29]
ldr \reg, [\reg]
.endm bl prepare_ftrace_return // prepare_ftrace_return(pc, &lr, fp)prepare_ftrace_return에 대상 PC, 저장된 부모 LR 슬롯의 주소, 부모 FP를 전달합니다. graph 추적이 허용되면 원래 복귀 주소를 보관하고 그 슬롯을 return_to_handler로 바꾸어 함수가 끝날 때도 추적기를 거치게 합니다. BL은 다음 명령의 주소를 LR(x30)에 기록하고 목적지로 분기합니다. 호출된 코드가 x0 같은 작업 레지스터를 바꿀 수 있으므로, 호출 뒤의 값은 그 코드의 반환·보존 규칙에 따릅니다.
309행 그림 · 호출과 실행 위치
함수·코드 범위: ftrace_graph_caller
이 줄을 포함하는 조건: 앞 조건의 반대 / #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 그림은 분기 명령 자체의 효과입니다. 호출된 함수가 실행된 뒤의 레지스터 값은 그 함수의 반환·보존 규칙을 따라야 합니다.
mcount_exit추적에 쓰려고 만든 프레임을 해제하고 보관한 복귀 주소로 돌아갑니다. 여기의 인자는 없음입니다.
311행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: ftrace_graph_caller
이 줄을 포함하는 조건: 앞 조건의 반대 / #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
mcount_exit 매크로 본문 · 220행
arch/arm64/kernel/entry-ftrace.S · Linux v6.18.37
정의 선택 조건: 앞 조건의 반대
.macro mcount_exit
ldp x29, x30, [sp], #16
ret
.endmSYM_FUNC_END(ftrace_graph_caller)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
312행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_graph_caller
이 줄을 포함하는 조건: 앞 조건의 반대 / #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */빌드 조건으로 나누었던 구간을 닫습니다. 대상:
313행 그림 · 전처리 단계
이 줄을 포함하는 조건: 앞 조건의 반대 / #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */빌드 조건으로 나누었던 구간을 닫습니다. 대상:
314행 그림 · 전처리 단계
이 줄을 포함하는 조건: 앞 조건의 반대
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
반환값 보존과 원래 부모로 복귀
SYM_TYPED_FUNC_START(ftrace_stub)이 위치부터 (ftrace_stub)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
316행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_stub
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
317행 그림 · 호출과 실행 위치
함수·코드 범위: ftrace_stub
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(ftrace_stub)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
318행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_stub
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
#ifdef CONFIG_FUNCTION_GRAPH_TRACERfunction graph tracer가 켜진 빌드에서만 복귀 추적용 stub와 return_to_handler를 포함합니다. 꺼진 경우 함수의 원래 반환 경로를 가로챌 이 코드는 필요 없습니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
320행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_TYPED_FUNC_START(ftrace_stub_graph)이 위치부터 (ftrace_stub_graph)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
321행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_stub_graph
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
322행 그림 · 호출과 실행 위치
함수·코드 범위: ftrace_stub_graph
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(ftrace_stub_graph)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
323행 그림 · 어셈블·링크 단계
함수·코드 범위: ftrace_stub_graph
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_CODE_START(return_to_handler)이 위치부터 (return_to_handler)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. 실제 작업은 아래의 명령들이 수행합니다.
331행 그림 · 어셈블·링크 단계
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
sub sp, sp, #FREGS_SIZE스택에서 FREGS_SIZE바이트만큼 사용할 공간을 잡습니다. SP가 낮은 주소로 이동하지만, 아직 이 명령이 데이터를 저장한 것은 아닙니다.
333행 그림 · 레지스터 상태
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
- SP는 주소만 바뀝니다. 스택 데이터 저장·복원은 STR/STP·LDR/LDP 같은 별도 메모리 명령이 수행합니다.
stp x0, x1, [sp, #FREGS_X0]x0, x1의 값을 sp를 기준으로 FREGS_X0만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 첫 위치에는 x0, 그보다 8바이트 높은 위치에는 x1의 값이 들어갑니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
336행 그림 · 메모리 쓰기
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
stp x2, x3, [sp, #FREGS_X2]x2, x3의 값을 sp를 기준으로 FREGS_X2만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 첫 위치에는 x2, 그보다 8바이트 높은 위치에는 x3의 값이 들어갑니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
337행 그림 · 메모리 쓰기
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
stp x4, x5, [sp, #FREGS_X4]x4, x5의 값을 sp를 기준으로 FREGS_X4만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 첫 위치에는 x4, 그보다 8바이트 높은 위치에는 x5의 값이 들어갑니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
338행 그림 · 메모리 쓰기
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
stp x6, x7, [sp, #FREGS_X6]x6, x7의 값을 sp를 기준으로 FREGS_X6만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 첫 위치에는 x6, 그보다 8바이트 높은 위치에는 x7의 값이 들어갑니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
339행 그림 · 메모리 쓰기
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
str x29, [sp, #FREGS_FP]x29의 값을 sp를 기준으로 FREGS_FP만큼 계산한 메모리 위치에 기록합니다. 레지스터 값을 나중에 다시 쓰거나 다른 코드가 읽을 수 있도록 메모리에 남기는 줄입니다. 이 스택 위치는 현재 함수 또는 예외 처리의 보관 공간입니다.
342행 그림 · 메모리 쓰기
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
mov x0, sp현재 SP의 숫자를 x0에 기억해 둡니다. 스택 자체는 이동하거나 복사되지 않습니다. 나중에 이 값으로 원래 위치를 찾을 수 있습니다.
344행 그림 · 값 복사
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 화살표는 값의 변화를 뜻합니다. 주소값을 옮겨도 그 주소의 메모리 내용은 복사하지 않습니다.
bl ftrace_return_to_handler // addr = ftrace_return_to_hander(fregs);저장한 ftrace_regs 주소를 x0로 전달해 함수 복귀 사건을 기록하고, 따로 보관했던 원래 부모 복귀 주소를 x0로 돌려받습니다. 추적 대상 함수의 실제 반환값은 스택의 x0~x7 사본에 있으므로 이 반환 주소와 섞이지 않습니다. BL은 다음 명령의 주소를 LR(x30)에 기록하고 목적지로 분기합니다.
반환 x0는 원래 부모 복귀 주소입니다. 추적 대상 함수의 반환값은 스택에 보존되어 있습니다.
345행 그림 · 호출과 실행 위치
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 그림은 분기 명령 자체의 효과입니다. 호출된 함수가 실행된 뒤의 레지스터 값은 그 함수의 반환·보존 규칙을 따라야 합니다.
mov x30, x0 // restore the original return address추적기가 반환한 원래 부모 주소를 LR에 옮깁니다. 뒤에서 실제 함수 반환값을 x0~x7로 되살린 후 RET가 이 LR로 돌아갑니다. MOV는 x30의 기존 값을 대체합니다. 원본이 주소값이어도 그 주소의 메모리를 읽거나 복사하지 않습니다.
그 주소를 LR에 옮긴 다음 x0–x7의 원래 결과 값을 복원합니다.
346행 그림 · 값 복사
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 화살표는 값의 변화를 뜻합니다. 주소값을 옮겨도 그 주소의 메모리 내용은 복사하지 않습니다.
ldp x0, x1, [sp, #FREGS_X0]sp를 기준으로 FREGS_X0만큼 계산한 메모리 위치에 보관된 값을 x0, x1로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 첫 위치에서 x0, 그보다 8바이트 높은 위치에서 x1의 값을 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다.
349행 그림 · 메모리 읽기
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
ldp x2, x3, [sp, #FREGS_X2]sp를 기준으로 FREGS_X2만큼 계산한 메모리 위치에 보관된 값을 x2, x3로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 첫 위치에서 x2, 그보다 8바이트 높은 위치에서 x3의 값을 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다.
350행 그림 · 메모리 읽기
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
ldp x4, x5, [sp, #FREGS_X4]sp를 기준으로 FREGS_X4만큼 계산한 메모리 위치에 보관된 값을 x4, x5로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 첫 위치에서 x4, 그보다 8바이트 높은 위치에서 x5의 값을 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다.
351행 그림 · 메모리 읽기
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
ldp x6, x7, [sp, #FREGS_X6]sp를 기준으로 FREGS_X6만큼 계산한 메모리 위치에 보관된 값을 x6, x7로 가져옵니다. 주소 숫자를 옮기는 MOV와 달리 실제 메모리를 읽습니다. 첫 위치에서 x6, 그보다 8바이트 높은 위치에서 x7의 값을 읽습니다. 앞서 보관한 상태를 되살리거나 스택으로 전달된 인자를 얻는 과정입니다.
352행 그림 · 메모리 읽기
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
add sp, sp, #FREGS_SIZE현재 사용한 스택 공간 FREGS_SIZE바이트를 해제합니다. SP를 높은 주소로 되돌리며 메모리 내용을 0으로 지우는 것은 아닙니다.
353행 그림 · 레지스터 상태
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
- SP는 주소만 바뀝니다. 스택 데이터 저장·복원은 STR/STP·LDR/LDP 같은 별도 메모리 명령이 수행합니다.
retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
355행 그림 · 호출과 실행 위치
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_CODE_END(return_to_handler)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
356행 그림 · 어셈블·링크 단계
함수·코드 범위: return_to_handler
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */빌드 조건으로 나누었던 구간을 닫습니다. 대상:
357행 그림 · 전처리 단계
이 줄을 포함하는 조건: #ifdef CONFIG_FUNCTION_GRAPH_TRACER
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
설명한 뒤 함께 생각해 볼 질문
추적 코드에서 x0를 마음대로 바꾸면 왜 안 되나요?
추적 대상 함수가 아직 사용할 인자가 x0에 남아 있을 수 있습니다. 콜백 전에 저장하고 이후 복원해야 합니다.
RET x9는 이상한 반환인가요?
RET의 목적 레지스터를 명시한 것입니다. 이 경로에서 x9는 추적 뒤 원래 함수의 실행을 계속할 주소입니다.
함수 그래프 추적은 반환 시점을 어떻게 잡나요?
함수의 저장된 복귀 주소를 추적 핸들러를 거치도록 바꾸고, 나중에 원래 부모 주소를 찾아 되돌려 줍니다.
주석을 포함한 전체 원문
1/* SPDX-License-Identifier: GPL-2.0-only */2/*3* arch/arm64/kernel/entry-ftrace.S4*5* Copyright (C) 2013 Linaro Limited6* Author: AKASHI Takahiro <[email protected]>7*/89#include <linux/linkage.h>10#include <linux/cfi_types.h>11#include <asm/asm-offsets.h>12#include <asm/assembler.h>13#include <asm/ftrace.h>14#include <asm/insn.h>1516#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS17/*18* Due to -fpatchable-function-entry=2, the compiler has placed two NOPs before19* the regular function prologue. For an enabled callsite, ftrace_init_nop() and20* ftrace_make_call() have patched those NOPs to:21*22* MOV X9, LR23* BL ftrace_caller24*25* Each instrumented function follows the AAPCS, so here x0-x8 and x18-x30 are26* live (x18 holds the Shadow Call Stack pointer), and x9-x17 are safe to27* clobber.28*29* We save the callsite's context into a struct ftrace_regs before invoking any30* ftrace callbacks. So that we can get a sensible backtrace, we create frame31* records for the callsite and the ftrace entry assembly. This is not32* sufficient for reliable stacktrace: until we create the callsite stack33* record, its caller is missing from the LR and existing chain of frame34* records.35*/36SYM_CODE_START(ftrace_caller)37bti c3839#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS40/*41* The literal pointer to the ops is at an 8-byte aligned boundary42* which is either 12 or 16 bytes before the BL instruction in the call43* site. See ftrace_call_adjust() for details.44*45* Therefore here the LR points at `literal + 16` or `literal + 20`,46* and we can find the address of the literal in either case by47* aligning to an 8-byte boundary and subtracting 16. We do the48* alignment first as this allows us to fold the subtraction into the49* LDR.50*/51bic x11, x30, 0x752ldr x11, [x11, #-(4 * AARCH64_INSN_SIZE)] // op5354#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS55/*56* If the op has a direct call, handle it immediately without57* saving/restoring registers.58*/59ldr x17, [x11, #FTRACE_OPS_DIRECT_CALL] // op->direct_call60cbnz x17, ftrace_caller_direct61#endif62#endif6364/* Save original SP */65mov x10, sp6667/* Make room for ftrace regs, plus two frame records */68sub sp, sp, #(FREGS_SIZE + 32)6970/* Save function arguments */71stp x0, x1, [sp, #FREGS_X0]72stp x2, x3, [sp, #FREGS_X2]73stp x4, x5, [sp, #FREGS_X4]74stp x6, x7, [sp, #FREGS_X6]75str x8, [sp, #FREGS_X8]7677#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS78str xzr, [sp, #FREGS_DIRECT_TRAMP]79#endif8081/* Save the callsite's FP, LR, SP */82str x29, [sp, #FREGS_FP]83str x9, [sp, #FREGS_LR]84str x10, [sp, #FREGS_SP]8586/* Save the PC after the ftrace callsite */87str x30, [sp, #FREGS_PC]8889/* Create a frame record for the callsite above the ftrace regs */90stp x29, x9, [sp, #FREGS_SIZE + 16]91add x29, sp, #FREGS_SIZE + 169293/* Create our frame record above the ftrace regs */94stp x29, x30, [sp, #FREGS_SIZE]95add x29, sp, #FREGS_SIZE9697/* Prepare arguments for the the tracer func */98sub x0, x30, #AARCH64_INSN_SIZE // ip (callsite's BL insn)99mov x1, x9 // parent_ip (callsite's LR)100mov x3, sp // regs101102#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS103mov x2, x11 // op104ldr x4, [x2, #FTRACE_OPS_FUNC] // op->func105blr x4 // op->func(ip, parent_ip, op, regs)106107#else108ldr_l x2, function_trace_op // op109110SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)111bl ftrace_stub // func(ip, parent_ip, op, regs)112#endif113114/*115* At the callsite x0-x8 and x19-x30 were live. Any C code will have preserved116* x19-x29 per the AAPCS, and we created frame records upon entry, so we need117* to restore x0-x8, x29, and x30.118*/119/* Restore function arguments */120ldp x0, x1, [sp, #FREGS_X0]121ldp x2, x3, [sp, #FREGS_X2]122ldp x4, x5, [sp, #FREGS_X4]123ldp x6, x7, [sp, #FREGS_X6]124ldr x8, [sp, #FREGS_X8]125126/* Restore the callsite's FP */127ldr x29, [sp, #FREGS_FP]128129#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS130ldr x17, [sp, #FREGS_DIRECT_TRAMP]131cbnz x17, ftrace_caller_direct_late132#endif133134/* Restore the callsite's LR and PC */135ldr x30, [sp, #FREGS_LR]136ldr x9, [sp, #FREGS_PC]137138/* Restore the callsite's SP */139add sp, sp, #FREGS_SIZE + 32140141ret x9142143#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS144SYM_INNER_LABEL(ftrace_caller_direct_late, SYM_L_LOCAL)145/*146* Head to a direct trampoline in x17 after having run other tracers.147* The ftrace_regs are live, and x0-x8 and FP have been restored. The148* LR, PC, and SP have not been restored.149*/150151/*152* Restore the callsite's LR and PC matching the trampoline calling153* convention.154*/155ldr x9, [sp, #FREGS_LR]156ldr x30, [sp, #FREGS_PC]157158/* Restore the callsite's SP */159add sp, sp, #FREGS_SIZE + 32160161SYM_INNER_LABEL(ftrace_caller_direct, SYM_L_LOCAL)162/*163* Head to a direct trampoline in x17.164*165* We use `BR X17` as this can safely land on a `BTI C` or `PACIASP` in166* the trampoline, and will not unbalance any return stack.167*/168br x17169#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */170SYM_CODE_END(ftrace_caller)171172#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS173SYM_CODE_START(ftrace_stub_direct_tramp)174bti c175mov x10, x30176mov x30, x9177ret x10178SYM_CODE_END(ftrace_stub_direct_tramp)179#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */180181#else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */182183/*184* Gcc with -pg will put the following code in the beginning of each function:185* mov x0, x30186* bl _mcount187* [function's body ...]188* "bl _mcount" may be replaced to "bl ftrace_caller" or NOP if dynamic189* ftrace is enabled.190*191* Please note that x0 as an argument will not be used here because we can192* get lr(x30) of instrumented function at any time by winding up call stack193* as long as the kernel is compiled without -fomit-frame-pointer.194* (or CONFIG_FRAME_POINTER, this is forced on arm64)195*196* stack layout after mcount_enter in _mcount():197*198* current sp/fp => 0:+-----+199* in _mcount() | x29 | -> instrumented function's fp200* +-----+201* | x30 | -> _mcount()'s lr (= instrumented function's pc)202* old sp => +16:+-----+203* when instrumented | |204* function calls | ... |205* _mcount() | |206* | |207* instrumented => +xx:+-----+208* function's fp | x29 | -> parent's fp209* +-----+210* | x30 | -> instrumented function's lr (= parent's pc)211* +-----+212* | ... |213*/214215.macro mcount_enter216stp x29, x30, [sp, #-16]!217mov x29, sp218.endm219220.macro mcount_exit221ldp x29, x30, [sp], #16222ret223.endm224225.macro mcount_adjust_addr rd, rn226sub \rd, \rn, #AARCH64_INSN_SIZE227.endm228229/* for instrumented function's parent */230.macro mcount_get_parent_fp reg231ldr \reg, [x29]232ldr \reg, [\reg]233.endm234235/* for instrumented function */236.macro mcount_get_pc0 reg237mcount_adjust_addr \reg, x30238.endm239240.macro mcount_get_pc reg241ldr \reg, [x29, #8]242mcount_adjust_addr \reg, \reg243.endm244245.macro mcount_get_lr reg246ldr \reg, [x29]247ldr \reg, [\reg, #8]248.endm249250.macro mcount_get_lr_addr reg251ldr \reg, [x29]252add \reg, \reg, #8253.endm254255/*256* _mcount() is used to build the kernel with -pg option, but all the branch257* instructions to _mcount() are replaced to NOP initially at kernel start up,258* and later on, NOP to branch to ftrace_caller() when enabled or branch to259* NOP when disabled per-function base.260*/261SYM_FUNC_START(_mcount)262ret263SYM_FUNC_END(_mcount)264EXPORT_SYMBOL(_mcount)265NOKPROBE(_mcount)266267/*268* void ftrace_caller(unsigned long return_address)269* @return_address: return address to instrumented function270*271* This function is a counterpart of _mcount() in 'static' ftrace, and272* makes calls to:273* - tracer function to probe instrumented function's entry,274* - ftrace_graph_caller to set up an exit hook275*/276SYM_FUNC_START(ftrace_caller)277mcount_enter278279mcount_get_pc0 x0 // function's pc280mcount_get_lr x1 // function's lr281282SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) // tracer(pc, lr);283nop // This will be replaced with "bl xxx"284// where xxx can be any kind of tracer.285286#ifdef CONFIG_FUNCTION_GRAPH_TRACER287SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) // ftrace_graph_caller();288nop // If enabled, this will be replaced289// "b ftrace_graph_caller"290#endif291292mcount_exit293SYM_FUNC_END(ftrace_caller)294295#ifdef CONFIG_FUNCTION_GRAPH_TRACER296/*297* void ftrace_graph_caller(void)298*299* Called from _mcount() or ftrace_caller() when function_graph tracer is300* selected.301* This function w/ prepare_ftrace_return() fakes link register's value on302* the call stack in order to intercept instrumented function's return path303* and run return_to_handler() later on its exit.304*/305SYM_FUNC_START(ftrace_graph_caller)306mcount_get_pc x0 // function's pc307mcount_get_lr_addr x1 // pointer to function's saved lr308mcount_get_parent_fp x2 // parent's fp309bl prepare_ftrace_return // prepare_ftrace_return(pc, &lr, fp)310311mcount_exit312SYM_FUNC_END(ftrace_graph_caller)313#endif /* CONFIG_FUNCTION_GRAPH_TRACER */314#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */315316SYM_TYPED_FUNC_START(ftrace_stub)317ret318SYM_FUNC_END(ftrace_stub)319320#ifdef CONFIG_FUNCTION_GRAPH_TRACER321SYM_TYPED_FUNC_START(ftrace_stub_graph)322ret323SYM_FUNC_END(ftrace_stub_graph)324325/*326* void return_to_handler(void)327*328* Run ftrace_return_to_handler() before going back to parent.329* @fp is checked against the value passed by ftrace_graph_caller().330*/331SYM_CODE_START(return_to_handler)332/* Make room for ftrace_regs */333sub sp, sp, #FREGS_SIZE334335/* Save return value regs */336stp x0, x1, [sp, #FREGS_X0]337stp x2, x3, [sp, #FREGS_X2]338stp x4, x5, [sp, #FREGS_X4]339stp x6, x7, [sp, #FREGS_X6]340341/* Save the callsite's FP */342str x29, [sp, #FREGS_FP]343344mov x0, sp345bl ftrace_return_to_handler // addr = ftrace_return_to_hander(fregs);346mov x30, x0 // restore the original return address347348/* Restore return value regs */349ldp x0, x1, [sp, #FREGS_X0]350ldp x2, x3, [sp, #FREGS_X2]351ldp x4, x5, [sp, #FREGS_X4]352ldp x6, x7, [sp, #FREGS_X6]353add sp, sp, #FREGS_SIZE354355ret356SYM_CODE_END(return_to_handler)357#endif /* CONFIG_FUNCTION_GRAPH_TRACER */

