21.10.3.1.1. SD 카드에 기록된 fault_*.log의 레지스터 정보(PC, LR, SP) 추출
마이크로컨트롤러가 내뿜은 최후의 숨결인 fault_*.log 파일은 얼핏 보면 헥사(Hexadecimal) 코드의 무의미한 나열 같지만, 철저하게 ARM Cortex-M 아키텍처의 레지스터 맵(Register Map) 규칙을 따르고 있다.
이 장에서는 실제 추락한 드론의 SD 카드에서 덤프 파일을 뽑아와, 어떤 숫자들을 메모장으로 파싱(Parsing)해야 하는지 실전 사례를 통해 알아본다.
1. 실제 크래시 덤프(fault_*.log)의 해부
아래는 커스텀 payload_autodrop 모듈 내부에 개발자가 실수로 널 포인터(Null Pointer)를 삽입해 억지로 터뜨린 직후 생성된 덤프 파일의 실제 모습이다. (주소값은 보드 메모리 매핑에 따라 다를 수 있다)
[ 15.421000] ERROR [HardFault] HARD FAULT:
[ 15.421000] ERROR [HardFault] FAR: 00000000 (valid) -> 펌웨어가 이 메모리를 읽/쓰려다 터짐
[ 15.421005] ERROR [HardFault] R0: 00000000 R1: 200021c0 R2: 00000001
...
[ 15.421013] ERROR [HardFault] PC: 0802c11e LR: 0802c0f9 SP: 2001eaf0
[ 15.421015] ERROR [HardFault] xPSR: 61000000
복잡해 보이지만 우리가 추출해야 할 핵심 전리품은 오직 4개다.
1.1 FAR (Fault Address Register): 살해 흉기
위 로그에서 FAR: 00000000 이라는 충격적인 숫자가 보인다.
C++에서 0x00000000은 바로 NULL 포인터를 의미한다!
어떤 멍청한 코드(아마도 나 자신)가 초기화되지 않은 빈 공간(NULL)을 향해 변수를 쓰려다가(write) 하드웨어 메모리 방어막(MMU/MPU)에 막혀 시스템이 폭파된 것이다.
만약 이 값이 0x20000000 대역 밖의 터무니없는 값(예: 0xFFFFFFFF)이라면, 배열 인덱스 초과나 쓰레기값(Garbage Value) 참조일 확률이 높다.
1.2 PC (Program Counter): 살인 현장 주소 추출
가장 중요한 단서다. 로그 하단에 PC: 0802c11e 가 찍혀있다.
이는 펌웨어 바이너리 리스트립(listrip) 메모리의 0x0802c11e 번지에 꽂혀있던 기계어 명령어(Assembly Instruction)를 마이크로프로세서가 실행하려던 찰나에 죽었다는 뜻이다.
우리는 이 0802c11e 라는 암호를 반드시 복사해 두어야 한다.
1.3 LR (Link Register): 공범의 주소 추출
PC 레지스터 바로 옆에 LR: 0802c0f9 가 붙어있다.
코드 멈춤(Crash)의 방아쇠를 당긴 것은 PC 주소에 있는 녀석이지만, 그 녀석에게 흉기를 쥐어주고 널 포인터를 던져준 흑막(상위 호출 함수, Caller)은 저 0x0802c0f9 주소에 머물고 있다.
PC 분석만으로 원인을 도저히 모를 때, 이 LR 주소도 함께 분석하면 “아~ 이 FSM 초기화 함수에서 널 포인터를 넘겼구나!” 하고 연쇄적인 범행 논리(Call Stack)를 파악할 수 있다.
1.4 SP (Stack Pointer): 내 밥그릇(스택) 잔량 확인
마지막으로 SP: 2001eaf0 를 확인한다.
이 주소값이 앞서 21.10.2장에서 다룬 STACK_MAIN 할당 메모리 영역을 넘어선 곳에 있는지 살펴보아야 한다. 칩셋의 SRAM 경계값에 위험하게 다가가 있다면, 널 포인터 에러가 1차 원인이 아니라 ’스택 넘침으로 인한 메모리 오염(Corruption)이 널 포인터를 만듦’이라는 다중 충돌 논리로 접근해야 한다.
이제 텍스트 무덤에서 가장 가치 있는 다이아몬드, PC: 0x0802c11e 를 손에 쥐었다.
하지만 우리는 사람이기에 16진수 주소로는 도저히 이 코드가 PayloadAutoDrop.cpp의 245번째 줄인지 311번째 줄인지 알 도리가 없다.
이 16진수 암호를 인간의 언어(C++ 소스코드 위치)로 번역해 주는 리눅스의 강력한 흑마법 유틸리티, arm-none-eabi-addr2line 사용법을 21.10.3.1.2장에서 펼쳐보자.