21.10.3. 하드 폴트(Hard Fault) 분석 및 크래시(Crash) 로그 덤프 복원
모든 성능 테스트를 통과하고 비행하던 당신의 픽스호크가 갑자기 하늘에서 전조 증상도 없이 툭 떨어졌다. LED는 뻘겋게 깜빡이고 터미널엔 아무런 에러 로그도 남아있지 않다.
이 상황을 임베디드 세계에서는 하드 폴트(Hard Fault) 혹은 임베디드 커널 패닉이라고 부른다.
리눅스 데스크톱 환경(Ubuntu)에서 C++ 프로그램이 죽으면 커널이 자비롭게 core_dump 파일을 남겨주며 “니 코드 132번 줄에서 죽었어“라고 친절하게 알려준다.
하지만 픽스호크의 뇌인 STM32 칩셋은 그런 친절한 리눅스 커널 따위는 없다. 칩이 치명적인 논리 오류(잘못된 메모리 포인터 접근, 0으로 나누기, 존재하지 않는 명령어 실행 등)를 겪는 순간, CPU는 숨을 멈추고 하드웨어 예외 처리기(Hardware Exception Handler)로 무조건 점프해 버린다.
이 참혹한 비행기 추락 현장에서 우리가 건져낼 수 있는 유일한 블랙박스는 바로 **크래시 덤프(Crash Dump)**다.
1. 하드 폴트의 3대 주범
추락 원인을 부검하기 전에 먼저 우리를 찌를 수 있는 범인들의 몽타주를 외워두자.
- 널 포인터 역참조 (Null Pointer Dereference): FSM 모듈 안에서 객체가 초기화되기도 전에 포인터를 타고 멤버 변수에 접근했을 때 발생한다. (가장 흔한 원인)
- 스택 오버플로우 (Stack Overflow): 앞선 21.10.2장에서 경고했던 것처럼, 좁은 메모리를 뚫고 다른 데몬의 영역을 침범하여 커널을 폭파시켰을 때 발생한다.
- 메모리 정렬 오류 (Unaligned Memory Access): ARM Cortex 아키텍처 특성상, 32비트 변수를 읽을 땐 메모리 주소가 4의 배수여야 하는데 이를 무시하고 접근했을 때 발생한다. (보통 캐스팅 실수)
2. 커널의 마지막 유언장: fault_*.log
NuttX 운영체제는 하드 폴트로 죽어가는 마지막 그 1밀리초의 순간에, CPU 레지스터에 남아있던 모든 값들을 쥐어짜 내어 텍스트 파일로 남기도록 설계되어 있다.
기체를 줍고 마이크로 SD 카드를 뽑아 컴퓨터에 꽂아보면, 최상단 폴더에 섬뜩한 이름의 파일이 생성된 것을 볼 수 있다.
fault_2023_10_26_15_30_00.log
이 파일을 열역학적 엔트로피 속에서 인간의 언어(C++ 소스코드 라인)로 번역해 내는 것이 이번 장의 핵심이다.
이 파일 안에는 범인의 지문 역할을 하는 세 가지 치명적인 단서, PC (Program Counter), LR (Link Register), SP (Stack Pointer) 가 적혀 있다. 21.10.3.1.1장에서 이 암호문 같은 텍스트 파일의 레지스터 구조를 먼저 뜯어보자.