Ubuntu 환경에서 .NET Core 어플리케이션의 crash core dump 분석 가이드

다음은 Ubuntu 기반의 .NET Core 애플리케이션에서 crash가 발생했을 때, core dump를 가지고 postmortem debugging 과정을 기술한 내용이다.
Ubuntu (16.04)에서 수행중인 .NET Core 2.0 애플리케이션에서 crash가 발생하면, 애플리케이션 수행 폴더의 위치에서 core dump를 확인할 수 있다.

.NET Core application crash에 기인한 Core dump 파일을 분석하기 위해서는 debugging 환경 구축이 필요한데, 일치하는 .NET Core 버전을 Ubuntu 머신에 설치하고, 이를 load해서 분석할 LLDB 디버거 역시 설치한다.
아래는 terminal을 통해 .NET Core 2.0 SDK의 설치과정이다.

 sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ xenial main" > /etc/apt/sources.list.d/dotnetdev.list'
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 417A0893
sudo apt-get update
sudo apt-get install dotnet-sdk-2.0.0

그리고, LLDB debugger를 설치한다.

 sudo apt-get install lldb-3.6

설치가 완료되었다면, LLDB debugger를 통해 core dump 파일을 다음과 같이 오픈한다.

 sudo lldb-3.6 -c core /usr/share/dotnet/dotnet

 

Crash dump에서 무엇보다 먼저 확인하고 싶은 것이 crashed callstack인데, 일반적으로 bt명령어를 이용하여 callstack을 확인한다.

 

bt 명령을 통해 확인한 back trace에서 frame #7을 보면, 정확한 function정보를 확인할 수 없는 데, 실제적인 .NET callstack을 확인하기 위해서는 .NET Core 에서 제공하는 libsosplugin.so debugger extension을 이용해야 한다. 다음은 해당 extension을 load 하는 과정이다.

 plugin load /usr/share/dotnet/shared/Microsoft.NETCore.App/2.0.0/libsosplugin.so
setclrpath /usr/share/dotnet/shared/Microsoft.NETCore.App/2.0.0

 

이후에는 아래와 같이 managed threads를 확인할 수 있다. 그다음에는 익숙하지만 다른 libsosplugin.so에서 제공하는 명령어를 통해 분석을 할 수 있다.

 

우선 흔히 생각하는 2번 thread에서 System.ArgumentNullException이 발생한 것으로 확인할 수 있다. 먼저 “setsostid <OSID> <ID>”명령을 통해 해당 thread를 설정한 후에 clrstack 명령어를 통해 managed callstack을 확인할 수 있다.

 

또 다른 callstack 정보인데, 이 경우에는 MethodDesc 정보를 알 수 있다.

 

보고자 하는 것은 문제가 발생한 시점의 method 정보이다. MedthodDesc 를 가리키는 주소를 이용하면, IL code를 확인할 수 있다.

 

System.Text.Encoding()메소드는 parameter로 전달된 Byte[]가 NULL 일 경우에 ArgumentNullException을 출력하는 것으로 보인다. 실제 문제가 된 고객의 코드의 위치는 다음과 같다.  clru 명령어는 문제가 발생한 위치를 (>>>) assembly 코드에서 표시한다.

 

IL Code와 문제가 발생한 assembly 위치를 비교해보자.

 

이쯤되면 실제 코드를 확인해 보는 것이 좋겠지만, Syetem.Text.Encoding::get_UTF8에 Syetem.Text.Encoding::GetString의 입력 parameter인 ldarg.0 가 Null Byte Array로 문제가 발생한 것으로 보인다. 그러므로 입력 parameter를 확인해야 하는 데, 이는 다음과 같이 확인할 수 있다.

ldarg.0 는 buffer가 가리키는 주소이고, (이것은 NULL 이고 crash의 원인이다.) ldarg.1 은 0x64값으로 보인다. 결국, extension만 load하면, managed debugging은 windbg에서 분석하는 것과 크게 다르지 않다.