본문 바로가기
WWDC

WWDC24: Run, Break, and Inspect Explore effective debugging in LLDB

by songmoro 2024. 7. 22.
728x90

본문은 영어 공부를 겸해 WWDC 영상을 보고 정리한 것으로 오역이 있을 수 있습니다.

정확한 내용은 원문 참고 바랍니다.

 

원문


소개

이 영상은 코드를 탐색하고, 버그를 빠르게 찾을 수 있는 디버깅 테크닉에 대한 소개 영상이다.

 

lldb는 XCode와 함께 제공되는 기본 디버거로 프로그램을 일시 중지하고, 변수 상태를 검사하고, 식(expression)을 평가하는 등의 기능을 수행할 수 있다.

 

Debugging model

프로그램에서 이슈를 디버깅 할 때 크래시, 잘못된 값 혹은 프로그램이 중단되는 것처럼 잘못된 포인트를 제공받는다.

 

프로그램이 실행되고 잘못된 명령이 관찰되는 지점 사이 어딘가에서 잘못된 코드가 실행되었을 것이고, 우리의 목표는 그 코드 조각을 찾는 것이다.

버그는 보통 다른 시점에서 프로그램의 상태를 검사함으로써 찾을 수 있으며, 검사할 때마다 문제가 있는 코드에 가까워진다.

 

아마도 대부분 프로그램의 상태를 검사하는 몇 가지 다른 테크닉에 익숙할 것이다.

 

 

예를 들어, 코드-베이스 프로그램에서는 로그를 사용하는데 로그 파일을 읽는 것은 프로그램의 한 시점을 검사하는 것과 같다. 로그가 충분히 상세하다면 코드의 버그를 정확히 파악할 수 있을 것이다.

 

이를 위해서는 프로그래머가 로그에서 무엇이 유용한 정보인지 미리 파악해야 하지만, 사용자와 개발자 간의 앱 분석을 위해선 강력한 기술이 된다.

 

 

 

print 디버깅 방법은 자주 사용되는 또 다른 테크닉인데, 아마 모두가 처음 배우는 디버깅 방법일 것이다.

print 디버깅은 프로그램에 print 문을 삽입하고, 코드를 다시 컴파일하여 프로그램을 실행하고 버그를 재현한다.

마지막으로 print 된 코드를 검사하고, 새로운 print가 필요하다면 모든 과정을 반복한다.

 

버그를 찾고, 해결한 뒤에는 print 문을 지우는 것으로 디버깅을 종료한다.

 

 

 

위 두 기술은 시간을 많이 소비하고, 에러가 많이 발생한다.

그래서 lldb에서 제공하는 Backtraces, variable inspection, breakpoints, expression evaluation과 같은 도구에 대해 다룰 것이다.

 

 

Starting the debug session

XCode에서 시작 버튼을 누르거나, lldb를 실행하는 것은 매우 자주 필요하다.

그러나 문제를 디버깅하는 첫 번째 단계는 버그를 재현하는 것으로, lldb는 응용 프로그램을 시작할 필요 없이 버그를 재현할 수 있다.

 

애플 플랫폼 안에서 프로그램이 크래시 된다면 crash log가 생성된다.

lldb는 이 crash log를 열 수 있다.

 

backtrace는 프로그램이 포인트에 도달할 수 있도록 하는 도구로 함수 호출의 순서 혹은 스택 프레임을 나타낸다.(디버그 네비게이터에 나타나는 거). 또한, 프로그램의 제어 흐름을 이해하는 데 최고의 도구이다.

 

 

Breaking

 

이 뷰에서 “Add to Watch Later” Button이 어떻게 동작하는지에 대해서 알아보고 싶고, 그를 위해서 브레이크 포인트를 설정했다.

 

lldb는 브레이크 포인트에 대해 3개의 개별 브레이크 포인트를 설정했다. 첫 번째로 버튼이 생성자를 호출할 때 프로그램이 정지한다.

지금은 첫 브레이크 포인트에서 정지했지만, lldb는 이 라인과 관련된 브레이크 포인트를 알고 있다. 이 정보는 "lldb break list"를 사용하면 알 수 있다.

 

위 명령어는 라인과 열 번호를 사용하여 브레이크 포인트에 대해 설명하며, 브레이크 포인트 ID를 통해 브레이크 포인트 정보를 확인할 수 있다.(1.1, 1.2, …)

 

 

lldb의 p 명령어를 사용해서 자세한 정보를 분석할 수 있다.

 

 

Break, Inspect 디버깅 사이클에서 p처럼 같은 명령어를 반복해서 입력하는 건 지루할 수 있다.

이 과정 대신, break point action이라는 브레이크 포인트에 도달할 때 디버거가 명령어를 수행하도록 할 수 있다.

 

 

커맨드 라인에서 사용하는 방법

lldb b: 브레이크 포인트 설정(b DetailView.swift:70)

lldb break command add: 브레이크 포인트 액션 추가

이 외 자세한 도움말은 lldb help, lldb apropros <키워드>(키워드에 대한 검색 결과 제공)

 

 

High-firing breakpoints

(자주 중단되는 브레이크 포인트)

 

디버깅할 때, 종종 여러 번 트리거 되는 브레이크 포인트를 생성하지만 우리는 그중 일부분에만 관심이 있다.

일반적인 예는 브레이크 포인트가 반복문 내부에 있고, 모든 반복문을 중단하는 대신 특정 이벤트가 발생할 때만 중지시키는 것이다.

 

high-firing breakpoint를 처리하는 세 가지 주요 기법

  • lldb break modify <breakpoint ID> --condition “condition”: 브레이크 포인트에 도달했을 때 조건을 만족한다면 중단

 

  • tbreak: 일시적인 브레이크 포인트 생성

 

  • lldb break modify <breakpoint ID> --ignore-count N: 처음 N회의 브레이크 포인트 무시

 

 

만약, 한 줄의 코드가 수백만 번 실행되는 극단적인 경우, 디버거는 계속해서 프로그램을 중지할지 말지에 대해 결정해야 하기 때문에 위 테크닉들은 프로그램 실행 속도를 늦출 수도 있다.

 

이 경우, 사용할 수 있는 방법은 if 문 내부에 브레이크 포인트를 설정하는 방법이다.

if condition { raise(SIGSTOP) }

 

위 코드가 실행되면 브레이크 포인트에 도달한 것처럼 디버거가 실행된다.

 

Inspecting program state

 

프로그램이 시작되고, expection이 발생한 시점 사이에 문제가 발생했다.

 

 

 

이 시점에서 좋은 선택은 기능을 호출하기 직전에 브레이크 포인트를 설정하여 버그에 가까워지는지 확인하는 것이다.

 

 

 

url, filename은 문제가 없는 걸 확인했으므로, 아래와 같이 에러가 발생하는 시점을 좁힐 수 있다.

 

 

 

Video constructor에서 12번째 비디오에서 에러가 발생하는 걸 알고 있을 때,

high-firing 브레이크 포인트를 다루는 테크닉에서 말한 것처럼 ignore를 사용할 수 있지만 대신, Swift Error breakpoint를 사용할 수 있다.

 

에러 브레이크 포인트는 에러가 발생할 때 lldb가 프로그램을 중지시킨다.

 

 

 

 

에러 브레이크 포인트를 통해 imageName에서 에러가 발생하는 것을 확인했고, JSON 파일을 살펴본 결과 타이핑 에러가 발생했던 것을 찾을 수 있었다.

 

 

Custom type summaries

샘플 코드를 통해 p 명령어가 변수를 검사하고, 복잡한 표현식을 평가할 수 있는지 알아봤다.

코드를 다시 컴파일할 필요 없이 모든 단계에서 중간 결과를 인쇄하는 복잡한 표현식을 점진적으로 구축할 수 있었다.

 

p 명령어는 복잡한 변수나 짧은 설명에 대해 이점을 얻을 수 있지만, 많은 속성을 갖거나 컬렉션 내부에 저장되는 변수는 수동으로 확장하지 않는 한 정보를 알 수 없다.

 

Swift 6에서는 @DebugDescription 어노테이션을 사용해서 p의 출력 값을 커스텀할 수 있다.

 

728x90