전자 설계의 여명기부터 버그는 필연적이었고, 디버깅은 어떤 결함이 승리할지, 그리고 얼마나 철저히 해결할지 결정하는 필수 분야였습니다.
디버깅 기술은 이를 지원하는 설계만큼이나 매혹적으로 진화했습니다. 단순한 자극-응답-관찰 접근에서 오늘날의 정교한 도구, 장비, 방법론에 이르기까지, 이 분야는 점점 더 복잡해지는 시스템과 함께 성장했습니다. 2017년에는 기능 I/O를 통한 디버깅이 도입되어 더 큰 효율성과 역량을 약속하는 새로운 시대가 열렸습니다.
수십 년간 글로벌 혁신 끝에 저는 1984년부터 디버깅에 관여해 왔습니다. 현재 겪고 있는 패러다임 전환을 이해하려면 업계를 형성한 이정표를 되짚어볼 필요가 있습니다.
1970~1980년대
당시 시스템 설계는 오늘날과 크게 달랐습니다. 일반적인 보드는 CPU, (EP)ROM, RAM, 그리고 PIC, UART, DMA 컨트롤러, 타이머, I/O 디바이스 같은 주변 IC들로 구성되었으며, 각기 별도 칩으로 구현되었습니다.
1980년대 단일 보드 컴퓨터(SBC) (출처: https://oldcomputers.net/ampro-little-board.html)
개발자는 어셈블리어나 C로 코드를 작성하고, 컴파일, 링크하여 ROM 이미지용 HEX 파일을 만들었습니다. 과정은 UV 이레이저로 EPROM을 수동 지우고, 시리얼 또는 병렬 인터페이스로 프로그래밍한 뒤 보드에 다시 장착하는 것이었습니다. 프로그램이 예상대로 동작하지 않으면 여러 디버깅 기법을 쓸 수 있었습니다.
코드 검토
가장 기본적인 접근으로, 지금도 많은 이가 사용합니다. 코드를 머릿속으로 또는 텍스트 에디터로 단계별 실행하며 분석하는 기술로, 도구가 없거나 너무 비쌀 때 여전히 가치가 있습니다.
LED
고전적인 방법은 온보드 LED나 다른 표시기를 사용해 프로그램 상태를 알리는 것입니다. 핵심 지점에 LED 토글을 삽입하면 실행 흐름을 시각적으로 추적할 수 있습니다. 추가 I/O 핀과 로직 분석기가 있으면 실시간 상태 추적도 가능합니다.
온타깃 모니터
시리얼 포트와 충분한 메모리를 가진 보드에는 작은 모니터 프로그램을 올릴 수 있습니다. 이 모니터로 점프하면 어셈블리 단위 실행을 단계별로 진행하고, RS-232 명령어(s 스텝, m 83C4,16 메모리 표시 등)로 레지스터와 메모리를 검사할 수 있습니다.
인서킷 에뮬레이터(ICE)
여유가 있는 이들에게 ICE는 궁극의 디버거였습니다. CPU를 에뮬레이션 회로로 대체해 내부 신호를 관찰하고 제어할 수 있었습니다. 크고 비쌌으며(종종 수천 달러), 고급 브레이크포인트, 트레이스, EPROM을 에뮬레이션 RAM으로 교체해 개발 중 지우고 다시 플래싱할 필요를 없앴습니다.
모토로라 엑소사이저 ICE (출처: https://www.exorciser.net/personal/exorciser/Original%20Files/exorciser.jpg) 인텔 MDS ICE (출처: https://www.computinghistory.org.uk/userdata/images/large/PRODPIC-731.jpg)
1982~1990년
임베디드 개발자에게 세 가지 주요 변화가 나타났습니다:
통합 IC: CPU에 주변장치가 통합되기 시작했습니다. 인텔 80186/80188(8086/8088 진화), 질로그 Z180(Z80 기반), 모토로라 CPU32 패밀리(예: 68000 기반 68302) 등.
저가형 ICE: 제조사들이 본드아웃 칩 없는 저가 ICE를 생산해 80186 ICE 가격을 1만 달러 미만으로 낮췄습니다.
클럭 속도 도전: CPU 속도 상승으로 ICE 케이블과 제어 로직이 한계에 부딪혔습니다. 해결책은 온칩 디버그 회로(OCD)였으며, 풀 CPU 속도에서 단일 스텝, 레지스터 접근, 브레이크포인트를 제공했지만 초기 구현에는 완전한 트레이스 기능이 부족했습니다.
OCD 접근은 보통 BDM(Background Debug Mode) 같은 독자 인터페이스나 전통적으로 생산 테스트에 쓰이던 JTAG를 사용했습니다. 일부 도구는 CPU 실행 중 메모리 접근이 가능했지만 다른 도구는 불가능해 구현마다 차이가 있었습니다.
1990~2000년
높은 클럭 속도와 내부 캐시로 외부 트레이스가 비현실적이 되었습니다. 대신 제조사들은 압축된 코어 트레이스 데이터를 도입했습니다. 순차적이지 않은 프로그램 카운터 변경만 캡처하고 압축해 칩 외부로 전송했습니다. 이는 실행 중인 프로그램 지식을 이용해 디버거가 실행 경로를 재구성하게 했습니다. 주요 아키텍처로는 IBM 파워PC, 모토로라 콜드파이어, ARM 7TDMI 코어가 있었습니다.
2000~2010년
압축 트레이스 데이터셋 덕분에 ARM의 임베디드 트레이스 버퍼(ETB) 같은 온칩 트레이스 버퍼가 가능해졌고, JTAG로 접근할 수 있었습니다. 버퍼 크기는 구성 가능해 실리콘 면적과 트레이스 성능 간 균형을 맞췄습니다. 멀티코어 SoC는 새로운 과제를 가져왔습니다: 코어가 파워다운되면 JTAG 스캔 체인이 사라집니다. ARM 코어사이트(CoreSight) 아키텍처는 단일 JTAG 기반 디버그 접근 포트로 모든 메모리 맵 코어사이트 구성요소(독립적으로 파워사이클되는 멀티코어 포함)에 도달할 수 있게 했습니다.
2010년~현재
64비트 코어 부상과 리눅스/안드로이드 광범위한 사용으로 온디바이스 디버깅이 주목받았습니다. 커널 드라이버가 이제 코어사이트 구성요소를 노출해 perf 서브시스템을 통한 온타깃 트레이스 캡처를 가능하게 합니다. ARM 임베디드 로직 분석기(ELA)는 초기 ICE의 풍부함을 되살려 복잡한 브레이크포인트, 트리거, 내부 SoC 신호 접근을 실리콘 내에서 모두 제공합니다.
40년간 끊임없는 혁신 끝에 이 분야는 기존 기능 I/O를 통한 디버깅과 트레이싱이라는 새로운 장을 앞두고 있습니다. 이 변화는 개발 시간과 비용을 줄이면서 역량을 강화하는 더 간결한 솔루션을 약속하며, 버그와의 긴 전쟁을 이어갑니다.