[IAR시스템즈=라파엘 토빈거(Rafael Taubinger)] 디버깅은 항상 개발에 많은 리소스가 투입되는 부분으로, 소모적이며 최악의 경우에는 비효율적일 수 있다. 멀티태스킹 운영 체제와 이벤트 구동 인터럽트를 사용하도록 작성된 어플리케이션이 사례다. 이는 printf 계측 또는 중단점 설정과 같은 디버그 방법을 도입하고, 어플리케이션을 지루하고 비생산적으로 만든다. 코어가 지속적으로 중단되기 때문에, 개발자가 가장 복잡한 타이밍 문제를 놓칠 수 있다는 점은 더욱 심각한 문제다.

[이미지=게티이미지뱅크]

어떤 제품의 품질은 개발자가 이용가능한 디버깅 역량에 달려 있다. 개발자는 특정 버그의 정확한 원인을 분석 및 추적하거나, 모든 코드 라인에서 무슨 일이 발생하고 있는지 이해할 수 있어야 한다. 이러한기능이 없을 경우, 개발자는 실제 문제를 수정하는 대신 최선의 추측을 주된 해결 방법으로 적용할 수 있다.

개발 조직의 숙련 정도에 따라 개발자는 최대 80%의 시간을 디버깅에 할애할 수 있는 것으로 추정된다. 릴리스 빌드로 만들기 전에 결함을 격리할 수 있다면, 코드에 대한 결함 주입 비율이 낮아지게 된다.

조직의 품질 지표에 훨씬 더 빨리 도달할 수 있고 개발에 투입되는 전반적인 노력도 감소시킬 수 있다.

◆ RISC-V 의 핵심 기능 및 디버깅 성능

RISC-V 외부 디버그 지원 버전 0.13.2는 RISC-V 기반 디바이스 또는 SoC용 디버그 인터페이스를 지정한다.

RISC-V 외부 디버그 인터페이스는 I-jet 또는 유사한 프로브와 같은 가능한 디버그 프로브와 결합해 개발자가 다양한 각도에서 어플리케이션의 동작을 검사할 수 있도록 한다. 툴 체인과 함께, 디버그 아키텍처는 디버깅을 신속하고 용이하게 하며, 정확도를 높일 수 있다.

그 외에, 트레이스(trace) 함수를 통해, 어플리케이션을 더욱 세부적으로 분석하는 방법도 있다. RISC-V 국제 기구는 RISC-V에 대한 추적 사양을 표준화하기 위해 노력해 왔다. 이와 관련해 두 개의 주요 작업 그룹이 있으며 첫 번째 작업 그룹은 RISC-V용 E-Trace라고도 불린다.

추적 형식을 설명하는 표준을 첫 번째로 비준한 버전의 프로세서 추적 작업 그룹이다. 두 번째는 RISC-V 코어에 대한 Nexus IEEE-ISTO 5001 표준에 의해 정의된 추적 사용 방법에 대한 권장 사항에 따라 작업하는 RISC-V Nexus Trace 그룹이다. 장치에 추적 IP를 구현하면 실행 중인 어플리케이션을 간섭하지 않고 추적이 가능하다.

상세한 접근 방식은 어플리케이션에 선택된 부분에 대해 실행되는 각 명령어가 연속적으로 누적된 시퀀스로 추적 중 속도·코드 패널티가 없으므로 프로세스 중에 어플리케이션이 원활하게 실행된다. 트레이스와 프로브를 사용하기 때문에 최종 실리콘에 약간의 비용이 추가된다. 추적 지원이 가능한 고급 디버깅 프로브도 현재는 비교적 저렴한 비용으로 사용할 수 있다.

◆ RISC-V에 적용되는 고급 언어 디버거의 일반적 특징

임베디드 어플리케이션용 고급 언어 디버거는 동일한 어플리케이션 내에서 개발과 디버깅이 가능한 C/C++ 컴파일러, 어셈블러와 함께 사용하도록 설계됐다. 디버그 세션 중 디버깅 제어에 사용되는 동일한 소스 코드 창에서 직접 코드 수정이 가능하며, 디버거가 실행되고 있지 않을 때의 중단점 정의, 편집 도중의 소스 코드와 함께 중단점 정의의 흐름을 검사하고 수정하는 등 많은 기능이 가능하다.

그림 1. RISC-V 에 적용되는 고급 언어 디버거의 사례 [이미지=IAR시스템즈]
그림 1. RISC-V 에 적용되는 고급 언어 디버거의 사례 [이미지=IAR시스템즈]

빌드 도구에 의해 생성된 디버거에 대한 광범위한 디버그 정보(디버그 기호가 있는 ELF/DWARF 아웃풋)가 RISC-V 외부 디버그 지원 버전 0.13.2와 결합하면, <그림 1>과 같은 우수한 디버깅 가능성으로 구현된다.

그림을 자세히 살펴보면, 고급 언어 디버거를 사용하면 C 또는 C++ 및 어셈블러 소스 코드에 대해 필요에 따라 소스 디버깅과 디스어셈블리 디버깅 간의 전환이 모두 가능함을 관찰할 수 있다.

소스 수준 스테핑에 대한 가장 세밀한 단위가 줄 단위인 기존 디버거와 비교하면 고급 언어 디버거는 모든 명령문과 함수 호출을 개별 단계의 수준으로 식별해 더욱 세밀한 수준으로 제어할 수 있도록 한다. 내부 표현식의 각 함수 호출과, 다른 함수에 대한 매개변수 목록의 일부인 함수 호출이 각각 한 조작마다 명령을 하나씩 내리며 수행될 수 있음을 의미한다.

예를 들어 이러한 기능은 객체 생성자에 대해 수많은 추가 함수를 호출하는 C++ 코드를 디버깅할 때 특히 유용하다.

또한 고급 언어 디버거의 중단점 시스템을 사용하면, 디버깅 중인 어플리케이션에서 다양한 유형의 중단점을 설정할 수 있어 특정한 위치에서 중지할 수 있다. 예를 들면 프로그램 논리의 합당함과 데이터 변경의 내용과 시점을 조사하기 위해 중단점을 설정할 수 있다.

마찬가지로 변수와 표현식의 경우 폭넓은 특징을 보유하고 있다. 지정된 변수 및 표현식 세트의 값을 지속적으로 또는 요청에 따라 모니터링 가능하다. 로컬변수, 정적 변수 등만 선별적으로 모니터링하도록 설정할 수도 있다.

어플리케이션이 고급 언어 디버거에서 실행될 때 STL 목록 및 벡터와 같은 라이브러리 데이터 유형의 요소를 볼 수 있다. 이러한 요소를 통해 C++ STL 컨테이너로 작업할 때의 개요와 디버깅이 높은 수준으로 진행될 수 있다.

컴파일러는 광범위한 호출 스택 정보를 생성한다는 것이다. 광범위한 호출 스택 정보를 통해 디버거는 런타임 패널티 없이 프로그램 카운터가 있는 곳이면 어디든지 함수 호출의 전체 스택을 표시하고 호출 스택에서 모든 함수를 선택, 각 함수에 대해 로컬 변수 및 사용 가능한 레지스터에 대한 유효한 정보를 얻을 수 있다.

마지막으로 RTOS awareness는 RTOS 위에 구축된 어플리케이션에 대한 높은 수준의 제어 및 가시성을 제공한다. RTOS awareness는 작업 목록, 대기열, 세마포어, 메일함, 다양한 RTOS 시스템 변수 등의 RTOS 관련 항목을 표시하고 있다. 작업별 중단점과 작업별 스테핑을 통해 디버깅을 더욱 용이하게 할 수 있다.

◆ 중단점과 디버깅의 본질적인 의미

개발자에게는 중단점이 반드시 필요하다. 고급 언어 디버거를 사용하면 디버깅할 어플리케이션에서 중단점을 다양한 유형으로 설정할 수 있어 중단하고자 하는 특정 위치에서의 중단도 가능하다. 프로그램 논리의 합당함을 조사하거나 추적의 아웃풋을 획득하기 위해, 코드 위치에 중단점도 설정할 수 있다. 코드 중단점 외에도 추가 중단점 유형을 사용할 수 있다.

예를 들어 데이터의 중단점을 설정해 데이터의 변경 시점 및 변경 관련 내용들을 조사할 수 있다. 지정가능한 특정 조건에서 실행을 중지할 수도 있다. 중단점에서는 실행 중인 디버깅을 확실하게 중지한 후에 재개하기 때문에 매크로 함수의 실행과 같은 사이드 이펙트가 발생할 수도 있다. 매크로 함수는 하드웨어 동작 시뮬레이션과 같은 다양한 작업을 수행하도록 정의할 수 있다.

◆ 고급 언어 디버거에 지원되는 다양한 유형의 중단점

다양한 중단점을 이용해 다양한 문제를 조사하거나 최상의 결과를 위해 결합할 수도 있다. 가장 일반적인 사용 사례를 설명하면 코드 중단점은 프로그램 논리의 합당함을 조사하거나 추적 아웃풋을 얻기 위한 코드 위치에 사용된다. 지정된 코드 위치에서 명령어를 불러올 때, 코드 중단점이 작동된다. 특정 기계 명령어에 중단점이 설정되면 중단점이 작동되며, 명령어 실행 전에 해당 코드의 실행이 중지된다.

로그 중단점은 어플리케이션 소스 코드에 기타 코드를 추가하지 않고도 추적 출력물을 추가할 수 있는 편리한 방법을 제공한다. 로그 중단점은 지정된 위치에서 명령어를 불러올 때 작동되고 특정 기계 명령어에 중단점이 설정, 작동되면 코드의 실행이 일시적으로 중지되고, 디버그 로그 창에 지정된 메시지가 출력된다.

그림 2. . RISC-V 고급 언어 디버거에 대한 중단점의 사용 방법에 관한 사례 [이미지=IAR시스템즈]
그림 2. . RISC-V 고급 언어 디버거에 대한 중단점의 사용 방법에 관한 사례 [이미지=IAR시스템즈]

<그림 2>는 RISC-V 고급 언어 디버거에서의 중단점 사용을 설명하고 있다. 모든 중단점을 비활성화 하고, 차후 사용 가능하게끔 본래의 위치에 보관할 수 있다.

데이터 중단점은 주로 메모리에 고정 주소를 갖추고 있는 변수에 유용하다. 접근가능한 로컬 변수에 중단점이 설정되면 해당 메모리 위치에 중단점이 설정된다. 코드의 작은 일부분에만 해당 위치의 유효성이 보장되며 데이터 중단점은 지정된 위치에서 데이터에 액세스할 때 작동된다. 코드의 실행은 대체로 데이터에 액세스한 명령이 실행된 직후에 중지된다.

데이터 로그의 중단점은 지정된 메모리 주소에 액세스할 때 작동된다. 각각의 액세스는 데이터 로그 창에 로그 입력값으로 기록된다. 단일 명령어를 사용해 마이크로컨트롤러는 4바이트 이하의 값에만 액세스할 수 있다.

고급 언어 디버거는 명령 실행을 일시적으로 중지하는 즉시, 중단점도 지원한다. 이를 통해 시뮬레이션 된 프로세서가 어떤 위치에서 데이터를 읽으려고 하거나 데이터를 기록한 직후 매크로 함수를 호출할 수 있다. 명령 실행은 작업 후에 다시 시작된다. 이 유형의 중단점은 메모리가 매핑된 다양한 유형의 장치(예: 직렬 포트 및 타이머)를 시뮬레이션하는 데 유용하다.

마지막으로, 추적 데이터 수집을 시작 및 중지하는 추적 시작 작동 및 추적 중지 작동의 중단점 역시 두 실행 지점 간의 명령을 분석하는 편리한 방법으로 언급할 만하다. 추적 중단점은 RISC-V 추적 구현을 지원하는 프로브와 디바이스에만 사용 가능하다.

◆ 스택 메모리 사용 방법에 대한 모니터링

스택 처리는 임베디드 소프트웨어 개발자의 주요 과제 중 하나이다. 스택을 적절하게 구성해야만 시스템 안정성과 신뢰성을 달성할 수 있다. 스택의 크기가 너무 작은 경우에는 오버플로우가 발생할 수 있고 스택 크기를 너무 크게 설정하면 일부 RISC-V 기반 임베디드 시스템에서 제한될 수 있는 RAM 리소스가 낭비된다.

전문 개발 툴은 컴파일러와 링커를 통한 추정과, 디버거를 통한 스택 사용량의 제어와 모니터링이 가능해야 한다.

그림 3. 스택 메모리의 사용에 대한 모니터링 사례 [이미지=IAR시스템즈]
그림 3. 스택 메모리의 사용에 대한 모니터링 사례 [이미지=IAR시스템즈]

<그림 3>은 모니터링 스택의 사례다. 어플리케이션이 처음 로드되고 재설정될 때마다, 스택 영역의 메모리는 어플리케이션 가동 전에 0xCD와 같은 전용 바이트 값으로 채워진다. 실행이 중지될 때마다 스택의 끝에서 값이 0xCD가 아닌 바이트를 찾을 때까지 스택 메모리를 검색하며 이는 스택이 사용된 크기로 추정된다. 스택 막대의 밝은 회색 영역은 미사용 스택 메모리의 영역을 나타내며 스택 막대의 어두운 회색 영역은 사용된 스택 메모리를 나타낸다. 해당 사례에서는 예약된 메모리 주소 범위의 44%만 사용됐음을 확인할 수 있다.

<그림 3>과 같은 방법은 스택 사용 추적을 위한 상당히 안정적인 방법이지만 스택 오버플로우를 감지할 수 있다는 보장은 없다. 예를 들어 스택은 스택 범위의 끝 근처에 있는 바이트를 실제로 수정하지 않고 메모리 주소의 범위 밖으로 커질 수 있으며, 스택 영역 외부에서 메모리를 수정할 수도 있다. 어플리케이션에서 발생한 오작동으로 스택 영역 내의 메모리가 수정될 수도 있다.

◆ 추적은 어떠한 방법으로 중요하게 기능할 수 있는가

추적(Trace)은 찾기 어려운 일반적인 문제를 신속 진단하는데 도움이 되는 것으로 알려져 있다. 추적을 통해 어플리케이션의 충돌과 같은 특정 상태에 대한 부분까지 프로그램 흐름을 검사하고 추적한 데이터를 사용해 문제의 원인을 찾을 수 있다. 추적 데이터는 불규칙하게 나타나고 산발적으로 발생하는 프로그래밍 오류의 탐색에 유용할 수 있다.

추적을 사용하려면 대상 시스템이 추적 데이터를 생성할 수 있어야 합니다. 생성된 고급 언어 디버거는 추적 프로브를 통해 추적 대상 데이터를 수집할 수 있으며, 개발자는 다양한 윈도우와 대화 상자를 통해 데이터를 시각화 및 분석할 수 있다.

그림 4. C/C++ code와 동시에 진행되는 디바이스에서 제공된 추적 정보로부터의 IDE 및 추적 시각화 [이미지=IAR시스템즈]
그림 4. C/C++ code와 동시에 진행되는 디바이스에서 제공된 추적 정보로부터의 IDE 및 추적 시각화 [이미지=IAR시스템즈]

<그림 4>는 모든 함수 호출 및 타이밍 정보와 함께 추적 명령, 함수 추적 및 그래픽 타임라인을 포함하는 추적 관련 윈도우의 사용을 표현하고 있다.

추적 데이터가 수집된 데이터를 검색하여 관심 대상 코드나 데이터 부분(예: 특정 인터럽트 또는 특정 변수 액세스)을 탐색할 수 있다. 추적과 함께 사용 가능한 코드 검사 기능은 테스트 절차가 코드의 모든 부분의 실행 여부를 확인하도록 설계된 경우에 유용하다. 도달할 수 없는 코드 부분의 식별도 보조할 수 있다. 안전 측면에도 중요한 어플리케이션으로서, 작업 시의 안전 표준을 달성하기 위해 매우 중요하고 필수적이다.

추적 가능한 기능은 그 가치가 매우 높으며, RISC-V를 위한 추적 기술 - 추적 기술을 효율적으로 사용하는 방법에서 자세히 살펴본 바와 같이 추적은 어플리케이션에서 ‘백만 달러’짜리 버그를 탐색하기 위해 유용하게 활용될 수 있다.

◆ 적절한 디버깅 툴의 도움 받기

RISC-V 기반 설계에서 심각한 오류를 경험한 사람만이 궁극적인 문제의 추적의 난이도와 그 과정에서의 실망에 대해 잘 인식할 것이다. 문제를 분리해 낸후, 수정 사항을 제시하거나 그 우회 방법조차도 잘못된 해결 방법으로 찾아내는 것에만 며칠을 소요하는 것은 드문 일이 아니다. 일부 버그는 잡아내기 어려울 수 있으며 복잡한 상황에서 무작위적으로 발생한다.

복잡한 어플리케이션에서 복합적이며 조건에 맞게 발생시킬 수 있는 중단점, 데이터 및 로그의 중단점, 매크로, 스택 모니터링, 그 외의 추적과 같은 유용한 기능을 갖춘 고급 언어 디버거는 모든 코드 라인과 실행된 모든 단일 명령어를 완벽하게 제어하면서 효율성을 높일 수 있는 가장 빠른 길이다. 올바른 디버깅 도구를 올바른 방법으로 사용한다면, 버그를 실제로 수정해 개발 주기를 합리적으로 단축할 수 있다.

회원가입 후 이용바랍니다.
개의 댓글
0 / 400
댓글 정렬
BEST댓글
BEST 댓글 답글과 추천수를 합산하여 자동으로 노출됩니다.
댓글삭제
삭제한 댓글은 다시 복구할 수 없습니다.
그래도 삭제하시겠습니까?
댓글수정
댓글 수정은 작성 후 1분내에만 가능합니다.
/ 400
내 댓글 모음
저작권자 © 테크월드뉴스 무단전재 및 재배포 금지