iOS dSYM 이란 무엇인가

Jinhyuk
7 min readMay 7, 2020

앱스토어에서 크래쉬로 인해 리젝을 당하면 크래쉬 리포트를 함께 준다. 처음 따악 열어보는 순간 이상한 숫자들만 가득한 것을 확인할수 있다. 이럴때 필요한게 바로 dSYM이란 파일이다. 근데 dSYM 은 뭘까!? 한마디로 이상한 숫자들을 해석할수 있게 해주는 파일이다.
애플 공홈 링크 : https://developer.apple.com/library/archive/technotes/tn2151/_index.html

dSYM : debug symbol file
컴파일러가 소스코드를 기계어로 변환할때 생성되고 역할은 기계어를 다시 소스코드 라인으로 매핑하는 정보를 가진 파일
Build Settings -> ‘DEBUG_INFORMATION_FORMAT’ 에서 옵션 확인 간으

dSYM 파일 생성 시점
열심히 만든 앱을 Archive 할때 생성된다. 따라서 앱 크래쉬 리포트를 해석하기 위해선 반드시 dSYM이 포함된 아카이브를 잘 관리해야한다!!
(예외적인 경우도 있음 ㅎ)

해당 dSYM 확인할수 있는 경로~/Library/Developer/Xcode/ArchivesorXcode -> Window -> Organizer

예외적인 경우는 !?
바로 ‘Bitcode’ 라는 옵션이다. 너무 어려운 LLVM과 관련된 이야기인데 일단 Bitcode는 IR(Intermediate Reprosentation : 중간언어 )입이고 App Thining에 관련된 기술입니다. LLVM과 App Thining에 관해선 추후에 작성해보겠습니다.
마찬가지로 Build Settings에서 확인할수 있는 옵션이다. 이 상태를 enable로 하고 앱을 만들시 bitcode로 바이너리 파일이 생성된다. 아래의 그림으로 다시 한번 확인해 보자.

BC == bitcode

열심히 만든 앱을 Bitcode를 enable로 만들시 그림처럼 bitcode로 바이너리가 생성된다. 이 파일을 앱스토어를 통해 올리는 경우 애플에서 변환을 통해 일반적인 바이너리와 dsym 파일을 생성한다는 그림 그대로 의미입니다.

근데 이것을 왜사용할까!?
일단 dsym파일을 관리하기 힘드니 애플에서 직접 만들어서 관리해준다는 의미이다.
아래 이미지처럼 Archives 혹은 Appstore에서도 직접 다운받을수 있다.

다운로드가 가능함 Bitcode : enable

대신 주의할점이 존재한다!!
1. Bitcode로 생성된 dSYM 파일과 최종적으로 앱스토어에 dSYM은 전혀 다른 파일이다
2. 크래쉬와 관련된 프레임워크와 사용시 문제가 발생될수 있음!!
Example) Fabric같은 경우 dSYM파일이 필요한데 Bitcode 사용시 앱 빌드시 산출되는 dSYM이 아니기에 위의 그림처럼 다운로드해서 업로드해야 정상적으로 출력된다.
3. 개발자가 빌드한 바이너리와 앱스토어의 바이너리가 다르다?!
4. 앱스토에서 재빌드하는 중앙화된 형태의 경우 악의적으로 bitcode 취약점 발견시 이용할수 있다?!

3,4번은 직접 확인해보진 못했지만 찾아보니 이럴수도 있겠다 라고 생각이 들어 가져와봤습니다.…..ㅎㅎㅎ

Framework 에서 dSYM
프레임워크의 Mach-O에 따라 dSYM 생성 여부가 결정된다.
Static Framework의 경우, 최종 결과물인 앱의 바이너리 안에 포함되기에 dSYM 파일이 생성되지 않는다.
하지만 Dynamic Framework의 경우, dSYM 파일이 생성된다!!

dSYM 파일이 같을수 있을까?!

The Debug Symbol file and application binary are tied together on a per-build-basis by the build UUID.
디버그 심볼과 애플리케이션 바이너리는 'Build UUID'을 기준으로 묶여있다.
A new UUID is generated for each build of your application and uniquely identifies
UUID 는 각 애플리케이션의 빌드에 대해 생성되고 유니크하다.
Even if a functionally-identical executable is rebuilt from the same source code, with the same compiler settings,
같은 컴파일 세팅 및 소스 코드로 다시 빌드하더라도
it will have a different build UUID. Debug Symbol files from subsequent builds, even from the same source files, will not interoperate with binaries from other builds.
다시 빌드한 경우, UUID가 다르게 빌드되고 디버그 심볼 파일은 다른 빌드와 호환되지 않는다.

즉, 한번 생성된 dSYM 파일은 아무리 같은 환경, 소스로 빌드하더라도 호환되 지않는다. 여담으로 문서를 끝까지 안읽고 ‘Build’ 라는 의미가 빌드 번호를 나타내는건지 컴파일과 실행파일을 만드는 Build를 의미한건지 확실하지 않아서 같은 소스로 빌드 번호를 다르게 하여 테스트를 진행했다….. 어이없는 삽질…을 했지만 재밌는 발견을 했다.

재밌는 발견!?
일단 테스트 환경은 이렇다.
빌드버전만 다른 앱을 같은 위치에서 아래 코드로 강제로 Crash 발생시킨후 크래쉬 리포트 확인

- (void)viewDidAppear:(BOOL)animated {
//Force Crash
[self performSelector:@selector(die_die)];
}

당연히 심볼릭 링크가 가르키는 주소 (빨간박스 확인하면됨) 는 다르다!!
위에 그림(버전 11)에선 콜스택중 7번 UIKitCore 메모리 주소 0x1b63d9574
아래 그림(버전 12)에선 콜스택중 8번 UIKitCore 메모리 주소 0x1b63d9574

애플에서 말하는 ‘Build UUID’ 는 다르지만 애플에서 제공하는 프레임워크들의 메모리 주소는 같다는 것을 확인할수 있다.

7번 항목 주소를 확인해보세요 0x1b63d9574
8번 항목 주소를 확인해보세요 0x1b63d9574

크래쉬 리포트에서 직관적으로 의미가 와닿지 않던 용어들
1) Incident Identifier : 크래쉬 리포트의 고유 번호.

2) CrashReporter : 디바이스 식별 번호, 같은 디바이스에선 같음

3) Parent Process : ‘launchd [1]’ 이라 적혀있지만 말그대로 앱이 실행하자마자 크래쉬났다는 의미는 아님 ( 위의 크래쉬 리포트 보면, 특정 메소드에서 크래쉬가 발생했는데 실제로 저 메소드는 앱 실행시점이 아님 )
아쉽게도 애플 공홈에도 이 부분에 대한 설명은 없음 .. ㅜ

결론

DSYM 파일은 빌드 ( 컴파일 + 실행파일을 만드는 과정 ) 시 고유한 DSYM 파일이 생성된다.

앱스토어에서 크러쉬 로그를 보내줄시 DSYM 파일이 존재하지않는다면 난독화되어있는 파일을 해석할수 없다.

또한 난독화를 해제(애플에선 de-obfuscate 표현)할수 있다면, 소스 코드상에서 크러쉬가 난 소스 라인까지 파악이 가능한다.

(iOS 시스템에 존재하는 CoreFoundation, UIKitCore와 같은 프레임워크는 메모리 주소값이 같을수도 있다.)

마지막으로 dSYM 생성하도록 설정하는 방법

Xcode -> Project -> Build Settings -> ‘DEBUG_INFORMATION_FORMAT’ 검색 -> ‘DWARF with dSYM File’ 선택

--

--