"로그 봐줘요"로 고통받는 핑프맘들을 위해 바칩니다
-준비물-
1. 크래시 로그의 구조 - 무엇이 의미있는 정보일까?
Unhandled exception "EXCEPTION_ACCESS_VIOLATION" at 0x7FF6A3BC1EEE Fallout4.exe+1B41EEE
일단 처음 열면 딱 보이는 저 한줄.
굵게 표시해둔 부분만이 의미있는 정보임
Fallout4.exe 안에는 "집에 가라" "총을 쏴라" "밥을 먹어라" 같은 행동 지시문들이 빼곡하게 적혀있는데
그 프로그램의 메모리 베이스에서 1B41EEE 떨어진 곳에 있는 지시문을 실행하다 튕겼다는거
대부분 EXCEPTION_ACCESS_VIOLATION을 볼건데 이건 이 프로그램이 건드릴 수 없는 메모리 영역을 건드리려 했다는 의미임
그 다음 중요한 정보는 PROBABLE CALL STACK이 있음
이건 튕김이 발생했던 지시문까지 오는 과정에서 받은 모든 지시들을 나열해둔 것이라고 보면 됨.
현재 지시가 끝나면 1번부터해서 차근차근 저 지점으로 되돌아가서 나머지 지시를 완료하게 된다는 것.
예를 들어서 "밥을 먹고" -> "물을 마시고" -> "리모컨을 들어서" -> "TV를 켜라" 라고 했다면
콜스택은
[0] TV를 켜라
[1] 리모컨을 들어서
[2] 물을 마시고
[3] 밥을 먹고
이렇게 됨.
그런데 TV 리모컨이 개뜬끔없이 옆집에 있다면 내가 옆집에 함부로 들어갈 수 없으니 "리모컨을 들어서" 에서 튕기겠지?
그 다음에 적혀있는건 REGISTERS와 STACK인데 여긴 기억들을 저장해둔거라고 생각하면 됨.
REGISTERS는 현재 막 사용하고 있는 변수들. 그리고 STACK은 REGISTERS가 모자라서, 또는 나중에 쓰려고 저장해둔 변수들.
STACK은 보통 약 RSP+0x800까지가 그나마 의미있는 정보이지 않나 싶음.
2. 죽은 폴아웃 4의 마지막 행적을 되돌아보기
로그가 어떻게 생겨먹은 녀석인지 이제 알았으니 내 폴아웃 4가 왜 죽었는지 분석할 시간임.
일단 첫 줄에서 오류가 발생한 지시문 위치를 알려준다고 했잖음?
이게 Fallout4.exe 내부의 함수일 수도 있고, 시스템 dll 내부의 함수일 수도 있고, 아니면 모드 dll 내부의 함수일 수도 있음.
모드 dll 내부의 함수에서 오류를 일으킨 경우에는 굉장히 희망적임. 모더 또는 소스에 접근할 수 있는 사람이 고칠 수 있거든.
시스템 dll에서 에러가 난 경우는 보통 콜스택을 보면 Fallout4.exe에서 건너왔다는걸 알 수 있을건데
뭐 쓰레드 ID를 받아가려 했다던지... 렌더링 관련 호출이 있다던지 기타등등
시스템에서 미리 마련해준 함수를 이용하려다가 튕겼다는걸 뜻함.
이건 애초에 폴아웃에서 정보를 잘못 넘겨줬기 때문에 생기는 오류니까 결국 Fallout4.exe 내부 함수의 오류라고 보면 됨
자꾸 내부 함수, 내부 함수 하는데 거기 있는 함수가 대체 뭔일을 하는지 어떻게 아냐고?
여기서 필요한게 Fallout 4 Name Database 와 CommonLibF4 임.
여러 전문가들이 고민하고 고통받으면서 쌓아올린 폴아웃 4의 게놈지도라고 보면 됨.
데이터베이스 가이드를 착실히 따라왔다면 IDA에 여러 함수들의 이름들이 다 나와있을텐데
아까 발생했던 로그에서 Fallout4.exe+1B41EEE 가 있었지? 거기로 가보는거임.
Fallout4.exe의 베이스 주소가 140000000으로 고정되어있기 때문에 맨 앞에 14를 쓰고 +뒤의 숫자를 그대로 복사하면 됨.
141B41EE4로 왔더니 함수명이 BSFixedString::operator=임.
이건 베데스다 게임에서 사용하는 문자열 클래스인데 뭔가와 비교를 하려다가 튕겼다는걸 알 수 있음.
아까 REGISTERS 를 봤을 때 R8 0xFF00270200004028 (size_t) 였는데 딱봐도 이상하게 생겼음
그 위의 지시문을 보면 mov r8, [rdx]가 있음.
rdx는 x64 호출 규약에 따라 이 함수에서 두번째 파라미터인데 이 함수는 두 개의 문자열을 비교하는거니 비교 대상 문자열이겠지?
CommonLibF4에서 BSFixedString의 구조를 보면
0x0에 BSStringPool::Entry의 포인터가 있음
그래서 [rdx]를 해주면 BSStringPool::Entry로 가져야 정상이라는 것.
그리고 BSStringPool::Entry + 0x8은 flags임
플래그를 가져오려했는데 결국 못가져오고 이상한걸 집어오다 폴아웃이 탈이 났다.. 그러니 문자열 자체가 잘못됐다고 봐야겠지?
0번은 우리가 방금까지 있던 곳이고.. 3번과 4번이 같은걸로 봐선 재귀호출이 이루어진 것 같음.
일단 각각의 함수를 모두 찾아봐야댐.
스림 로그는 이걸 자동으로 해주는데 똥오줌4는 그딴것도 없어 씩빨.
딱 보아하니 Task 큐에 NPC의 3D 모델을 업데이트하라는 작업이 할당돼있었고 그걸 실행하는 과정에서
모델을 바꿔치기하기 위해 구성품들을 불러오고 Skin 된 본들의 크기를 바꾸다가 튕겼다고 하고있죠?
이제 스텍을 보면 이럼
내가 튕긴 상황은 버티버드에서 뜯어낸 미니건을 파워아머 1인칭 상태에서 장착하려했을 때였음.
스택과 함수 호출들이 모두 그 상황과 일치한다는 것을 확인할 수 있음.
이제 내가 해야하는 일은 Fallout4.exe+05B2453 TESNPC::ScaleSkinBones 에서 하려던 일이 정확히 무엇이었고
제대로 실행됐을때는 어떤 일이 일어나는지, 그게 제대로 실행되지 않는 상황은 어떤 때인지를 조사하는거임.
이건 게임을 켜고 여러 디버깅 툴을 이용해서 알아낼 수 있겠지.
3. 로그를 읽는게 의미가 있을까?
나는 노력에 비해 로그를 읽는건 의미가 없다고 생각함.
니가 만든 모드가 CTD의 원인이야? 그럴땐 물론 로그를 읽어야지.
하지만 그 외의 상황에서 로그는 이래서 튕겼을 가능성이 있으니 조사를 해달라는 권고에 가까움.
로그 내용을 아무리 스캔해도, 백날 읽어봐도 너가 그 CTD를 고칠 가능성은 희박함.
문제되는 모드를 빼는 방법이 가장 빠름.
(고급정보) 버프아웃 4 크래시 로그 읽는 법 - 정보글이전
