본문 바로가기
공부/[iOS&Swift]

[iOS] LLDB(Low-Level-Debugger)에 대하여

by 인생은아름다워 2022. 1. 18.

✏️ Debugging이란?

디버깅(또는 디버그)이란 프로그램 개발 단계 중에 발생하는 시스템의 논리적인 오류나 비정상적 연산(버그)을 찾아내고 그 원인을 밝히고 수정하는 작업을 말한다. - 위키백과

 

iOS개발을 위해서는 Xcode라는 IDE(통합 개발환경)을 이용하는데, 이 Xcode에는 디버깅을 위해 LLDB라는 디버거가 내장되어있다고 한다. 우선 LLDB가 무엇인지 알아보고 이를 사용하는 방법에 대해 간단하게 알아보면 좋을 것 같다.

 

개발의 효율을 높이는 다양한 방법 중 단연 최고는 디버깅스킬 이라고 한다!👍

-> 버그 발생 원인을 명확하게 알 수 있고, 불필요한 빌드 횟수를 줄여주기도 한다. 규모가 큰 프로젝트의 경우 빌드 횟수를 줄이는 것 자체가 개발 시간을 매우 단축시켜 준다는 것은 당연하다.

 

LLDB는 Xcode IDE에 기본으로 내장되어있는 Commad-Line Debug 환경입니다. Xcode IDE의 LLDB Terminal에 곧바로 접근해서 실행중인 프로세스의 값을 변경하거나, 흐름을 제어하는 등 다양한 디버깅 작업을 할 수 있습니다. 이번 코스에서는 이번 코스에서는 LLDB의 유용한 명령어들을 공부해보겠습니다.

✏️ LLDB(Low Level Debugger)란?

LLDB 디버거의 공식문서에는 LLDB 디버거를 다음과같이 소개한다.

LLDB is a next generation, high-performance debugger. It is built as a set of reusable components which highly leverage existing libraries in the larger LLVM Project, such as the Clang expression parser and LLVM disassembler.

Clang expression parse와 LLVM disassembler같은 대규모 LLVM프로젝트의 기존 라이브러리를 최대한 활용하는 reusable한 구성요소 집합.... (뭐라는거니)🤔

 

여기서 LLVM이란 Apple에서 진행한 Compiler에 필요한 Toolchain 개발 프로젝트라고 한다.

이 LLVM의 서브프로젝트 중 하나가 LLDB이다. 그리고 툴체인이란 다른 컴퓨터나 시스템의 소프트웨어 제품을 만드는데 사용되는 프로그램 개발 도구들의 집합.

 

자, 다시 LLDB를 내 나름대로 정의해보면 이 정도인 것 같다.

 

LLDB란? 애플에서 어떤 시스템을 개발할때 필요한 프로그램 도구들(tool chain)을 만들었는데 그 이름이 LLVM이고, 이 툴체인 중 하나인 디버깅 툴! 물론 Swift만 디버깅 가능한 것은 아니고 기계어에 가까운 영역까지 디버깅 가능하다고 하며, C, C++, Objecive-C, Swift를 지원한다고 한다. LLDB를 잘 이용하면 프로그램이 어떤 식으로 동작하는지 더 깊이있게 이해할 수 있다!(디버깅 과정을 통해 프로그램을 한층 깊게 이해한다는 이야기인듯)

✏️ LLDB시작하는 법

Xcode에서 실행중인 프로젝트의 프로세스가 Breakpoint에서 멈추거나, pause버튼을 통해 실행이 일시정지되면 Xcode에서 LLDB Debug콘솔이 나타난다.(물론 Xcode에서 실행해야만 LLDB를 실행할 수 있는 것은 아니다!)

Breakpoint를 잡는 방법은 뒤에서 소개하고, 참고로 앱 실행 중 pause의 단축키는 comman + control + y이다.

 

✏️ Breakpoint

프로그램에서 디버깅을 할 때 Breakpoint설정하고 여러가지 다른 시도를 해 보는것은 매우 필수적이다. 이것은 iOS나 앱 개발 뿐만아니라, 어떤 프로그래밍에서도 마찬가지(임베디드 등)

  1. Breakpoint 설정하기
(lldb) breakpoint set [option] "arguments"
(lldb) br s [option] "arguments"

브레이크포인트는 위 코드와 같이 설정할 수 있다. (줄임 표현 확인)

다음은 여러 브레이크포인트 설정의 내용들이다.

// viewDidLoad 함수의 이름을 이용하여  break
(lldb) breakpoint set --name viewDidLoad
(lldb) b -n viewDidLoad

// ViewController.swift의 20번째 line에서 break!
(lldb) br s --file ViewController.swift --line 20
(lldb) br s -f ViewController.swift -l 20

// viewWillAppear 호출 시, animated가 true인 경우만 breakpoint!
(lldb) breakpoint set --name "viewWillAppear" --condition animated
(lldb) br s -n "niewWillAppear" -c animated

// ViewControler.swiftdml 17번째 라인에서 helloWorld가 "abc"인 경우 break
(lldb) ViewController.swift -l 17 -c 'helloWorld == "abc"'

위의 예시들 이외에도 많은 Breakpoint설정방법이 있으니 아래 참고링크에서 필요시 확인 해보면 좋을 듯 하다!

  1. Breakpoint 리스트 확인하기
// breakpoint 리스트 확인
(lldb) breakpoint list
(lldb) br list

위 명령어를 통해 브레이크포인트 리스트를 확인할 수 있으며, 이것을 통해 각 브레이크포인트의 목록 및 여러 정보들을 함께 확인할 수 있으니 실습을 통해 확인해보도록 하자.

  1. Breakpoint 삭제와 비활성화
// 전체 breakpoint 삭제
(lldb) breakpoint delete
(lldb) br de

// 특정 breakpoint  삭제
(lldb) br de 1

// 전체 breakpoint 비활성화
(lldb) breakpoint desable
(lldb) br di

// 특정 breakpoint 비활성화
(lldb) br di 1.1

✏️ Stepping

Stepping은 Break되어있는 상태에서 프로세스를 단계별로 진행하면서 상태변화를 관찰할 수 있는 기능이다.

결국 LLDB를 사용하면서 가장 유용한 기능 중 하나일 것이다.

Stepping은 크게 세 가지로 나눠진다. Stepping Over / Steping In / Stepping Out

  1. Stepping Over

statement단위로 이동한다. 다음 명령어를 통해 다음 statement로 진행한다.

(lldb) next
(lldb) n
  1. Stepping In

다음 statement가 function call일 경우 LLDB디버거를 function내부의 시작점으로 이동시킨다.

stepping over는 function call이더라도 jump하여 다음 statement로 이동할 것이다.

(lldb) step
(lldb) s
  1. Stepping Out

현재 진행중인 function이 return(종료)될 때 까지 프로그램을 실행한 후 break를 걸어주는 기능!

(lldb) finish

 

✏️ Expression

Breakpoint를 set하고 이동하는 방법까지 알아봤으면, 이제 멈춰있는 동안 새로운 동작을 시키는 명령어들을 알아봐야할 차례이다.

1. po

LLDB 명령어 중에 가장 많이 사용되는 것이 (lldb) po라고 한다. 객체의 정보를 콘솔에 출력하는 명령어.

po는 NSObject의 debugDescription을 콘솔에 출력해준다고 한다. 그러므로 이 debugDescription을 오버라이딩 해서 보기 편하게 사용할 수 있다. (커스터마이징)

 

2. expression

예를 들어서 아래와 같이 viewDidLoad함수에서 break되어있는 상황이라고 하자.

이 상태에서 (lldb) e self.view 명령어를 입력하면 다음과 같은 출력이 콘솔에 나타난다.

여기서 e는 expression명령어의 줄임 표현이며, expression 명령어는 self.view의 정보를 콘솔에 출력하며 동시에 $R1이라는 변수에 저장함을 알 수 있다.(원래 $R0부터 저장하기 시작하는데, 이전에 한번 명령어를 사용하여 $R1에 저장된 것 같다.)

이 상황에 추가적으로 (lldb) expression $R1!.backgroundColor 을 실행하면 결과가 아래와 같다.

아마도 $R1(즉 self.view)의 backgroundColor만 딱 빼서 $R2에 저장한 것 같다.(물론 콘솔에 출력도)

옵셔널로 저장되어서 강제언래핑을 한 부분을 확인하자.

이 상태에서 또 (lldb) $R1.backgroundColor = UIColor.green 을 입력하고 continue를 통해 진행해보면 아래와 같이 viewDidLoad에서 넘어가며 프로세스가 실행되고, 뷰의 배경색이 초록색이 된것을 확인할 수 있다.

참고로, (lldb) $R2! = UIColor.green는 사용되지 않는다, immutable변수를 바꾼다고 나온느 것을 보니 View내부에서 바꿀 수 없도록 처리되어있는 것 같다.

뿐만 아니라 expression 명령어를 통해 변수나 상수를 만들어서 사용할 수도 있다.

다만, 변수명(또는 상수) 이름 앞에 $기호를 표기해줘야 한다는 것!

이렇게 (lldb) expression 명령어는 유용하게 사용할 수 있으니 잘 알아두도록 하자!

🍎  결론

LLDB디버거가 어떤식으로 디버깅을 하는지 감을 잡을 수 있었다.

추가적으로,(lldb) image 명령어를 이용하면, crash log를 추적할 수 있다는 사실 정도는 알아두면 좋을 것 같다.

🍎  참고링크

야곰닷넷_LLDB 정복

LLDB debugger 공식홈페이지

댓글