본문으로 건너뛰기
5분 AI.
GITHUB TRENDING C MONTHLY #4 딥다이브 · 2026-10-23 분석

raddebugger 딥다이브
— 멈춘 프로그램에서 C 시스템 설계를 배우다

디버거

빠른 판단

무엇
로컬 x64 앱의 중단점·변수·레지스터·메모리·호출 스택을 탐색하는 C 기반 그래픽 디버거
이럴 때
Windows·Linux의 사용자 모드 프로그램에 붙어 실행 상태를 조사할 때
입력
로컬 실행 파일 또는 실행 중인 x64 프로세스와 디버그 정보
결과
멈춘 실행의 변수·레지스터·메모리·호출 스택
중단점 하나를 누르면 운영체제·스레드·기계어·심벌·화면이 함께 움직입니다. RAD Debugger는 이 과정을 자체 C 코드로 엮은 네이티브 그래픽 디버거입니다. 디버거를 사용하는 법에서 한발 더 나아가, 응답성을 지키는 메시지 처리와 메모리 수명, 디버그 정보 변환을 배웁니다. EpicGames/raddebugger · ⭐8,638 · 포크 428 · C · MIT · 2026-10-23 GitHub 기준. 소스 설명은 커밋 771f63d 기준입니다.
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

내 프로그램을 멈추고, 실행 중인 상태를 들여다보는 도구

raddebugger는 Windows와 초기 단계의 Linux x64를 대상으로 하는 사용자 모드·다중 프로세스 그래픽 디버거입니다. 사용자 모드는 일반 응용프로그램을 다룬다는 뜻입니다. 운영체제 커널을 디버깅하는 도구로 소개하면 범위를 벗어납니다. README가 명시하는 현재 지원 범위는 로컬 컴퓨터의 x64 디버깅입니다.

프로그램을 실행하거나 이미 실행 중인 프로세스에 붙고, 중단점에서 멈춘 뒤 변수·레지스터·메모리·호출 스택을 살펴봅니다. 소스 한 줄씩 이동하는 동작 뒤에는 기계어 명령 해석과 주소를 소스에 대응시키는 작업이 필요합니다. 이 저장소에서는 화면의 중단점 하나가 운영체제의 실행 제어로 바뀌는 전 과정을 따라갈 수 있습니다.

용어 먼저
디버거와 디버기(debuggee)
디버거는 조사하는 프로그램이고, 디버기는 조사받는 프로그램입니다. 둘은 별개의 프로세스입니다. 디버기가 멈춰도 디버거 화면은 조작할 수 있어야 합니다. 이 요구가 스레드와 메시지 설계를 결정합니다.
한 문장 비유

디버거는 움직이는 공장의 비상 정지 버튼과 계기판입니다

중단점은 특정 공정에서 설비를 멈추는 센서이고, 변수와 메모리는 그 순간의 재료와 창고 상태입니다. 호출 스택은 “누가 이 작업을 요청했는가”를 거슬러 올라가는 작업 지시서입니다.

공장을 멈췄을 때 계기판까지 얼어붙으면 조사할 수 없습니다. 그래서 설비를 제어하는 담당자와 화면을 갱신하는 담당자 사이에 명령과 보고를 주고받는 통로가 필요합니다. 이 비유를 기억하면 4절의 메시지 큐가 자연스럽게 읽힙니다.

1-1. 실행 파일은 하나의 역할만 갖지 않는다

src/raddbg/raddbg_main.c의 entry_point()는 명령행 인자에 따라 일반 GUI, IPC 명령 전송, 도움말, 이진 파일 유틸리티 모드로 분기합니다. 특히 --bin이면 rb_entry_point()로 들어갑니다. 같은 실행 파일이 화면과 디버그 정보 변환 도구의 입구를 함께 갖는 셈입니다.

# 아래는 사용 흐름을 보여주는 명령 예시
raddbg.exe                     # 일반 그래픽 디버거
raddbg.exe --help               # 도움말 모드
raddbg.exe --bin --help         # radbin 이진 파일 유틸리티 모드

코드 조각에서 생략한 부분과 학습용 예시는 주석으로 구분합니다. 빌드·실행 명령에 필요한 환경은 7절에서 설명합니다.

1-2. 디버거 바깥의 두 축

구성요소하는 일학습 관점
RAD Debugger실행 제어와 상태 시각화운영체제 API·동시성·GUI를 하나의 흐름으로 연결
RDIPDB·DWARF에서 변환해 사용하는 자체 디버그 정보 형식서로 다른 입력을 공통 데이터 모델로 정규화
RAD Linkerx64 PE/COFF 실행 파일과 PDB, 선택적으로 RDI 생성오브젝트 파일·심벌·재배치·대규모 병렬 처리
학습 범위
처음에는 디버거의 세 경계만 이해해도 충분합니다

화면과 엔진의 경계, 엔진과 운영체제의 경계, 외부 심벌과 RDI의 경계를 찾으세요. 링커까지 모두 이해해야 시작할 수 있는 프로젝트는 아닙니다.

2왜 주목받는가

트렌딩 순위와, 소스에서 설명할 수 있는 관심 요인을 구분하기

2026-10-23 분석 기준 GitHub Trending C Monthly 4위이며, 스타는 8,638개입니다. 다만 순위만으로 유입 경로나 인기를 만든 단일 원인을 증명할 수는 없습니다. 아래는 최근 변경과 구현을 토대로 해석한 주목할 만한 이유입니다.

2-1. Linux 지원이 새로운 독자를 부른다

CHANGELOG.md의 v0.9.29-alpha는 네이티브 Linux x64 디버깅의 예비 지원을 주요 변경으로 내세웁니다. src/linux/demon/linux_demon.c에도 dmn_ctrl_launch()·dmn_ctrl_attach()·dmn_ctrl_run()과 실제 ptrace() 호출이 있습니다. 선언만 존재하는 이식 계획에서 실제 구현으로 옮겨 온 점이 관심 요인이라고 해석할 수 있습니다.

동시에 변경 기록은 Linux가 매우 초기 단계라고 밝힙니다. 지원 플랫폼이 늘었다는 사실과 Windows 수준의 안정성이 확보됐다는 주장은 다릅니다. Linux 사용자는 기능 표와 제한 사항을 함께 읽어야 합니다.

2-2. UI부터 파일 형식까지 이어지는 C 사례

src/ui의 위젯, src/render의 그래픽 백엔드, src/eval의 표현식 처리, src/lib_rdi의 파일 형식이 한 저장소에 있습니다. 라이브러리를 조립한 결과만 보는 대신, 도구를 구성하는 추상화 자체가 어떻게 만들어지는지 배울 수 있습니다.

이는 자체 구현이 언제나 유리하다는 뜻은 아닙니다. 제어권이 넓은 만큼 창 관리·글꼴·입력·접근성·플랫폼 차이를 직접 유지해야 합니다. 학습할 때는 “무엇을 직접 만들었는가”와 “그 선택으로 어떤 부담을 얻었는가”를 함께 보세요.

2-3. 기존 도구와 비교하면 위치가 선명해진다

도구두드러지는 방향raddebugger에서 배울 차이
GDB다양한 언어·플랫폼, 네이티브·원격 대상 조사지원 범위를 좁힌 자체 GUI와 엔진의 연결을 추적하기 좋음
LLDBLLVM 기반 디버거, API·Python·IDE 연동자체 표현식 처리와 RDI 중심의 내부 데이터 모델을 관찰
WinDbgWindows 사용자 모드·커널·덤프 분석일반 응용프로그램의 실행 상태를 시각화하는 C 구현에 집중
RAD Debugger로컬 x64 중심의 자체 네이티브 GUI, 알파 단계동시성·메모리·심벌 변환·렌더링을 연속해서 공부

각 도구의 기능은 GDB 공식 문서, LLDB 공식 문서, WinDbg 공식 문서에서 확인할 수 있습니다. 이 표는 기능 방향의 비교이며 동일 조건의 속도 측정표가 아닙니다.

2-4. 성능 숫자는 어느 구성요소의 주장인가

README는 디버그 정보가 수 GiB인 테스트 사례에서 RAD Linker의 링크 성능을 “50% faster link times”라고 설명합니다. 이는 링커에 대한 저자 측 결과이며, 소요 시간이 50% 줄었다는 뜻으로 단정할 수 없습니다. 디버거의 모든 작업이 50% 빠르거나, 모든 프로젝트에서 같은 차이가 난다는 근거로 확대하면 안 됩니다.

비유

물류센터의 분류 설비가 빨라졌다고 매장 계산대까지 같은 비율로 빨라지는 것은 아닙니다. 링커는 실행 파일을 준비하는 단계이고, 디버거는 실행 중 상태를 조사하는 단계입니다. 성능을 읽을 때는 대상 작업과 입력 크기부터 찾으세요.

3기술 스택 전체 지도

웹 서버와 브라우저 대신, 한 네이티브 프로그램 안의 책임을 나눈다

이 프로젝트에서 백엔드·프론트엔드는 학습을 위한 역할 구분입니다. 백엔드에 해당하는 것은 디버깅 엔진과 운영체제 제어이고, 프론트엔드는 자체 C GUI입니다. 일반적인 웹 API 서버나 JavaScript 프레임워크를 필수 구성요소로 두지 않습니다.

3-1. 백엔드에 해당하는 층: 실행·데이터·표현식

역할실제 경로읽을 지점
디버깅 엔진src/dbg_engined_init(), d_tick(), 제어 스레드와 이벤트
플랫폼 제어src/demon, src/win32/demon, src/linux/demon공통 dmn_ API를 각 운영체제 API로 구현
디버그 정보src/dbg_info, src/lib_rdi, src/rdi_from_*변환 작업 예약·별도 프로세스 실행·RDI 파싱
표현식 평가src/eval, src/eval2토큰·구문 트리·형식 정보·평가 단계
내용과 캐시src/content, src/artifact_cache, src/file_stream데이터 해시, 비동기 계산 결과, 파일 내용 공급
기계어 해석src/disasm, src/x64/disasmdasm_inst_from_code()에서 x64 해석으로 위임

3-2. 프론트엔드: 자체 위젯에서 GPU까지

src/raddbg        사용자 명령·창·탭·디버거 화면
    ↓
src/ui            박스 트리·레이아웃·입력 신호
    ↓
src/draw          상위 그리기 명령과 묶음 처리
    ↓
src/render        D3D11 / OpenGL / 테스트용 stub

src/font_cache ← src/font_provider  글자 모양과 글꼴 래스터화
src/window_manager                 운영체제 창과 입력 이벤트

src/render/render_inc.h는 Windows 기본값을 R_BACKEND_D3D11, Linux 기본값을 R_BACKEND_OPENGL로 고릅니다. src/font_provider/font_provider_inc.h는 Windows에서 DirectWrite, Linux에서 FreeType을 선택합니다. 같은 상위 코드에 다른 하위 구현을 끼우는 구조입니다.

3-3. 의존성은 매니페스트 대신 동봉 소스와 빌드 설정에서 읽는다

이 커밋에는 package.json·Cargo.toml·pyproject.toml·go.mod·Dockerfile·CMakeLists.txt가 없습니다. 중심 빌드 파일은 build.bat와 build.sh입니다. 따라서 버전 근거는 동봉된 헤더와 CI 설정에서 찾아야 합니다.

항목확인한 버전·값근거와 의미
BLAKE31.8.7src/third_party/blake3/blake3.h의 BLAKE3_VERSION_STRING
xxHash0.8.2src/third_party/xxHash/xxhash.h의 major·minor·release 매크로
Zydis4.1.0.0src/third_party/zydis/zydis.h의 0x0004000100000000; 기계어 해석에 사용
stb_sprintf1.10 기반 수정본src/third_party/stb/stb_sprintf.h 머리말: 디버거용 서식 지정자 추가
RDI 인코딩23src/lib_rdi/rdi.h의 RDI_ENCODING_VERSION; 제품 버전과 별개
Linux CIubuntu-24.04, clang-17, clang-22, gcc.github/workflows/builds.yml; GCC의 정확한 패치 버전은 고정하지 않음
Windows CIwindows-2022, windows-2025MSVC·Clang 조합; Visual Studio 2022 및 경로상 18 계열 환경
GitHub Actionscheckout@v6, upload-artifact@v7후자는 비활성화된 실행 테스트 작업 안의 설정

FreeType·X11·OpenGL·EGL은 Linux 시스템 라이브러리로 연결하며, 빌드 설정에 정확한 패치 버전이 잠겨 있지 않습니다. README의 Clang 18.1.3·GCC 13.3.0 출력은 환경 예시입니다. CI의 컴파일러 목록이나 공식 최소 버전과 같은 뜻으로 읽으면 안 됩니다.

3-4. 인프라·빌드: C 파일을 모으고, 표를 생성한다

build.sh의 디버그 설정은 -O0 -DBUILD_DEBUG=1, 릴리스 설정은 -O2 -DBUILD_DEBUG=0이며, 공통으로 디버그 정보 생성 옵션 -g가 있습니다. Windows MSVC 설정은 /Od와 /O2로 갈립니다. 릴리스라는 이름만 보고 심벌까지 없앤다고 생각하지 마세요.

raddbg_main.c는 여러 레이어의 .c 구현을 직접 포함합니다. 흔히 unity build라고 부르는 방식으로, 그래픽 디버거의 주요 C 코드를 하나의 번역 단위에 모읍니다. BLAKE3 어셈블리처럼 따로 만들어 링크하는 입력도 있으므로, 모든 파일을 오직 한 번의 컴파일로 처리한다고 설명하면 부정확합니다.

// src/raddbg/raddbg_main.c의 구현 포함 방식 발췌
#include "base/base_inc.c"
#include "dbg_info/dbg_info.c"
#include "demon/demon_inc.c"
#include "dbg_engine/dbg_engine_inc.c"
#include "ui/ui_inc.c"
#include "raddbg/raddbg_inc.c"

빌드 앞단에는 C로 작성한 metagen이 있습니다. .mdesk 파일의 표를 읽고 generated/*.meta.h·*.meta.c를 만듭니다. 이름·열거형·보조 표를 한 선언에서 생성해, 같은 사실을 여러 곳에 수동으로 맞추는 부담을 줄입니다.

CI에는 여러 대상의 디버그·릴리스 빌드가 정의되어 있습니다. 반면 run-ubuntu-24-04와 run-windows-2022 작업은 if: false입니다. 테스트 실행 파일과 스크립트가 있다는 사실만으로 CI에서 실행 테스트가 매번 통과한다고 말할 수 없습니다.

4아키텍처 심화 분석

중단점을 누른 뒤의 흐름과, 그 흐름을 지탱하는 네 가지 설계

먼저 전체 지도를 봅시다. 아래 도식에서 세로 방향은 사용자 조작이 실행 제어로 내려가는 흐름이고, 오른쪽은 그 상태를 사람이 읽을 수 있도록 해석하는 흐름입니다. 같은 화면에 보이는 값이라도 운영체제에서 읽는 바이트와 디버그 정보에서 찾는 형식·이름은 서로 다른 출처입니다.

사용자: 실행 / 중단점 / 한 단계 이동 / 변수 조사 | v +-----------------------------------------------+ | raddbg: entry_point() / rd_frame() | | 창·탭·명령·뷰 | +----------------------+------------------------+ | v +-----------------------------------------------+ | dbg_engine: d_tick() | | 사용자 측 상태 / 명령 → D_Msg / 결과 ← D_Event | +----------------------+------------------------+ | | u2c / c2u 링 버퍼 +----→ eval → 변수·형식 해석 각 64 KiB, 잠금·조건 변수 +----→ disasm → 기계어 해석 | +----→ dbg_info → RDI v ^ +-----------------------------------------------+ | | d_ctrl_thread__entry_point() | PDB / DWARF | Launch / Attach / Run / SingleStep | | +----------------------+------------------------+ 별도 변환 프로세스 | --bin --rdi v +-----------------------------------------------+ | demon: dmn_ctrl_launch/attach/run | +----------------------+------------------------+ | +------------+------------+ v v Windows 디버그 API Linux ptrace / 대기 WaitForDebugEvent PTRACE_CONT 등 | | +------------+------------+ v 조사 대상 프로세스·스레드·메모리 화면 출력: ui → draw → render → D3D11 / OpenGL 글자 출력: font_provider → font_cache → 그리기

4-1. 패턴 ① 실행 담당과 화면 담당을 메시지로 연결한다

src/dbg_engine/dbg_engine_core.c의 d_init()는 사용자→제어 통로 u2c와 제어→사용자 통로 c2u를 각각 KB(64)로 할당합니다. 각 통로에는 뮤텍스와 조건 변수가 붙습니다. 이름에 링 버퍼가 들어간다고 잠금 없는 구조인 것은 아닙니다.

동시성 용어
뮤텍스와 조건 변수
뮤텍스는 동시에 고치면 안 되는 데이터에 출입문을 하나 두는 장치입니다. 조건 변수는 “새 명령이 오거나 공간이 생길 때까지 기다리기”를 돕습니다. 계속 반복하며 확인하는 대기보다 불필요한 CPU 사용을 줄일 수 있습니다.

src/dbg_engine/dbg_engine_ctrl.c의 d_u2c_push_msgs()는 명령 목록을 직렬화하고, 빈 공간이 있으면 길이와 본문을 기록합니다. 공간이 부족하면 기한까지 기다리며, 실패 여부를 반환합니다. 반대쪽 d_u2c_pop_msgs()는 바이트를 읽어 다시 D_MsgList로 복원합니다.

// d_u2c_push_msgs()의 공간 판단 부분 발췌
U64 unconsumed_size =
    d_ctrl_state->u2c_ring_write_pos -
    d_ctrl_state->u2c_ring_read_pos;
U64 available_size = d_ctrl_state->u2c_ring_size - unconsumed_size;
U64 needed_size = sizeof(msgs_srlzed_baked.size)
                + msgs_srlzed_baked.size;

// available_size가 needed_size 이상이면 길이와 본문 기록
// 부족하면 기한 확인 후 조건 변수로 대기

제어 스레드의 입구는 d_ctrl_thread__entry_point()입니다. 여기서 메시지를 꺼내 D_MsgKind_Launch·Attach·Run·SingleStep별로 처리합니다. 보고는 d_c2u_push_events(), 사용자 측 수신은 d_c2u_pop_events()가 맡습니다.

src/dbg_engine/dbg_engine_user.c는 보낼 명령을 별도 아레나에 깊은 복사하고, 전송이 성공한 경우에 목록과 아레나를 비웁니다. 이 순서가 중요합니다. 임시 포인터를 넘긴 뒤 발신 측 메모리를 먼저 지우면 수신 측이 이미 사라진 데이터를 읽을 수 있기 때문입니다.

비동기 설계의 핵심은 스레드 개수보다, 명령의 소유권과 결과가 돌아오는 경로를 명확히 정하는 데 있습니다. 이 코드에서는 메시지 직렬화와 복사가 그 경계를 드러냅니다.

비유

식당 접수대가 주방에 손님 메모지를 잠깐 빌려주는 대신 주문서를 복사해 넘기는 상황입니다. 접수대 메모지를 지워도 주방의 주문서는 남아 있어야 합니다. 완료된 음식은 별도의 전달대에서 알려 줍니다.

여기서 스레드 사이의 링 버퍼와 프로그램 인스턴스 사이의 IPC를 구분하세요. raddbg_main.c의 IPC는 기본 포트 7423을 쓰는 소켓 경로입니다. 변경 기록의 “IPC가 소켓으로 바뀌었다”는 문장은 엔진 내부의 두 링 버퍼가 없어졌다는 뜻이 아닙니다.

4-2. 패턴 ② 외부 형식을 RDI로 모으는 변환 파이프라인

PDB와 DWARF는 변수·함수·소스 줄 등 디버깅용 정보를 표현하지만 구조가 다릅니다. 화면의 모든 기능이 두 형식을 직접 처리한다면 분기와 중복이 늘어납니다. 이 프로젝트는 입력 형식별 변환기 → RDI → 공통 조회로 문제를 나눕니다.

PDB   → src/rdi_from_pdb   ┐
                          ├→ RDI → src/lib_rdi → src/dbg_info → 화면·평가
DWARF → src/rdi_from_dwarf ┘

RDI_ENCODING_VERSION = 23
제품 릴리스          = v0.9.29-alpha

src/dbg_info/dbg_info.c는 기존 RDI 헤더의 인코딩 버전을 비교해 오래된 결과인지 판단합니다. 필요할 때는 현재 실행 파일을 --bin --quiet --rdi 인자와 함께 별도 프로세스로 실행하고, 출력 경로·스레드 수·완료 신호 인자를 전달합니다. UI에서 PDB 전체를 매번 즉시 해석하는 방식과 다른 경계입니다.

로딩 요청 입구인 di_open(), 결과 조회인 di_rdi_from_key(), 실제 RDI 파서인 rdi_parse()를 연결해서 읽어 보세요. 특히 결과를 기다리는 상태와 실제 데이터가 준비된 상태를 나눠 다루는 부분이 캐시와 비동기 API 학습에 좋습니다.

src/lib_rdi/rdi_parse.c의 파서 첫 단계는 파일 크기와 매직 값, 인코딩 버전, 섹션 표가 파일 범위 안에 있는지를 검사합니다. 아래는 헤더 버전 검사 발췌입니다.

if(hdr != 0 && hdr->encoding_version != RDI_ENCODING_VERSION)
{
  hdr = 0;
  result = RDI_ParseStatus_UnsupportedVersionNumber;
}
파일 형식 용어
매직 값과 인코딩 버전
매직 값은 파일 종류를 알아보는 표식이고, 버전은 내부 배치를 해석할 규칙입니다. 확장자가 같아도 배치가 달라지면 잘못 읽을 수 있습니다. 파서 초입의 검사는 중요한 방어선이지만, 그것만으로 모든 잘못된 입력이 안전하다고 증명되지는 않습니다.

추가로 주소에는 기준점이 있습니다. 모듈 기준 오프셋이 0x1234이고 실제 적재 기준 주소가 0x140000000이면 실행 중 주소는 0x140001234입니다. 이 계산 예시는 심벌의 위치와 프로세스의 실제 주소를 연결해야 하는 이유를 보여 줍니다. 디스크 파일 오프셋까지 같은 숫자로 취급하면 안 됩니다.

4-3. 패턴 ③ 아레나로 메모리의 수명을 묶는다

src/base/base_arena.h는 기본 예약 크기를 MB(64), 기본 커밋 크기를 KB(64)로 둡니다. arena_push()는 정렬된 공간을 내주고 필요하면 영역을 확장하며, temp_begin()은 현재 위치를 저장하고 temp_end()는 그 위치까지 되돌립니다.

// 수명 규칙을 보여주는 교육용 예시
Temp checkpoint = temp_begin(arena);
U8 *buffer = push_array(arena, U8, 256);
// 여기서 buffer를 사용한다.
temp_end(checkpoint);
// 이제 buffer를 계속 쓰면 안 된다.

개별 객체마다 해제 코드를 흩뿌리는 대신, “이 작업이 끝날 때 함께 버린다”는 수명을 코드로 드러냅니다. 문자열·파싱 결과·프레임 중간 계산처럼 묶음으로 사라지는 데이터에 잘 맞습니다. 오래 살아야 하는 결과는 그 수명에 맞는 다른 아레나로 옮겨야 합니다.

src/base/base_thread_context.c는 스레드별 임시 아레나 두 개를 준비합니다. tctx_get_scratch()는 전달된 충돌 목록과 겹치지 않는 것을 고릅니다. scratch_begin(&arena, 1) 같은 호출은 출력용 아레나를 임시 작업 때문에 되감지 않으려는 의도를 보여 줍니다.

비유

한 요리를 만들 때 재료를 큰 쟁반 하나에 놓고, 요리가 끝나면 쟁반을 한 번에 치우는 방식입니다. 완성된 음식까지 그 쟁반에 두고 치우면 안 됩니다. 아레나에서 가장 중요한 질문도 “누가 해제하나”와 함께 “언제까지 살아야 하나”입니다.

예약 주소 공간과 실제 메모리 사용도 구분해야 합니다. metagen_main.c는 GB(64) 예약·MB(64) 커밋을 요청합니다. 이 한 줄을 “최소 RAM 64GB가 필요하다”고 읽을 수는 없습니다.

4-4. 패턴 ④ 화면을 다시 구성하되, 식별자로 상태를 이어 간다

src/ui/ui_core.c의 ui_begin_build()와 ui_end_build() 사이에서 박스 트리를 구성합니다. 버튼·레이블 같은 위젯은 그리기와 클릭 등의 플래그를 가진 박스를 만들고, ui_signal_from_box()로 입력 결과를 얻습니다. src/ui/ui_basic_widgets.c의 ui_button()부터 읽으면 구조가 작아 접근하기 쉽습니다.

// ui_button()의 핵심만 남긴 축약
UI_Box *box = ui_build_box_from_string(
    UI_BoxFlag_Clickable | UI_BoxFlag_DrawText, string);
UI_Signal interact = ui_signal_from_box(box);
return interact;

이 방식은 호출 흐름에서 UI를 기술하는 즉시 모드 스타일입니다. 그렇다고 내부 상태가 전혀 없는 것은 아닙니다. UI_Key로 박스를 찾고, last_touched_build_index로 이번 구성에서 사용했는지 기록합니다. ui_end_build()는 사용하지 않은 박스를 정리하고 축별 레이아웃을 계산합니다.

웹의 가상 DOM과 같다고 외우기보다, 이번 화면의 선언과 이전 화면의 상호작용 상태를 무엇으로 연결하는가를 보세요. 이름·키·캐시가 그 연결을 맡습니다. 안정적인 식별자가 중요한 이유를 실제 C 코드로 확인할 수 있습니다.

4-5. 기준 커밋에서 보는 작은 경계 처리

771f63d의 변경 대상은 src/linux/window_manager/linux_window_manager.c입니다. wm_rect_from_window()와 wm_client_rect_from_window()는 결과를 0으로 초기화하고 창 포인터가 0이 아닐 때만 창 정보를 읽습니다. 거대한 아키텍처도 이런 작은 입력 경계 위에 서 있습니다.

// 두 함수에 공통으로 나타나는 형태를 축약
LNX_WM_Window *w = (LNX_WM_Window *)handle.u64[0];
Rng2F32 result = {0};
if(w != 0)
{
  // 유효한 창의 사각형을 계산한다.
}
return result;

이 수정은 0 핸들을 방어합니다. 임의의 잘못된 0이 아닌 포인터나 모든 X11 호출 실패까지 해결한다고 확대하지 마세요. 버그 수정의 보장 범위를 입력 조건과 함께 읽는 습관도 중요한 학습입니다.

5디렉토리 구조 해부

큰 폴더부터 정독하지 말고, 한 기능의 경로를 가로질러 읽기

저장소는 src 아래에 비교적 평평한 레이어를 둡니다. 아래 트리는 저장소 루트를 기준으로 학습에 필요한 경로를 추린 것입니다. build와 local은 빌드 과정에서 만들어지는 경로입니다.

raddebugger/ ├── README.md / CHANGELOG.md / LICENSE ├── build.bat / build.sh 빌드 대상과 컴파일·링크 설정 ├── run_tests.bat / run_tests.sh 빌드와 테스트 실행을 묶는 스크립트 ├── .github/workflows/builds.yml 플랫폼·컴파일러별 CI 설정 ├── data/ 글꼴·아이콘 등 입력 자산 ├── obsolete/ 예전 구현 자료 └── src/ ├── base/ 문자열·메모리·스레드·파일 등 공통 기반 ├── win32/ / linux/ 운영체제별 구현 ├── demon/ 저수준 프로세스 제어 공통 API ├── dbg_engine/ 실행·이동·중단점·상태 관리 ├── dbg_info/ 심벌 변환 예약과 로딩 ├── lib_rdi/ / lib_rdi_make/ 독립적으로 쓸 수 있는 RDI 핵심 ├── rdi/ / rdi_make/ 프로젝트 내부 RDI 보조 기능 ├── rdi_from_pdb/ PDB 변환 ├── rdi_from_dwarf/ DWARF 변환 ├── pdb/ / dwarf/ / codeview/디버그 형식 처리 ├── pe/ / elf/ / coff/ 실행·오브젝트 파일 형식 처리 ├── eval/ / eval2/ 표현식과 형식 해석 ├── disasm/ / x64/ 기계어 해석과 아키텍처 정보 ├── content/ 해시로 식별하는 데이터 보관 ├── artifact_cache/ 비동기 계산 결과 캐시 ├── file_stream/ 파일 내용 공급과 변경 추적 ├── ui/ / draw/ / render/ 위젯·그리기·그래픽 백엔드 ├── window_manager/ 창·입력 공통 인터페이스 ├── font_provider/ DirectWrite / FreeType ├── font_cache/ 글자 데이터·GPU 아틀라스 캐시 ├── raddbg/ 그래픽 디버거의 앱 로직 ├── radbin/ 이진 파일 변환·덤프 도구 ├── linker/ RAD Linker ├── mdesk/ / metagen/ 선언 파일 파서·코드 생성기 ├── mule/ / torture/ 조사 대상 예제와 테스트 실행기 └── third_party/ 동봉 외부 소스

5-1. 이름의 접두사가 작은 이름공간이다

접두사주요 레이어예시
RD_ / rd_디버거 애플리케이션RD_WindowState, rd_frame()
D_ / d_디버깅 엔진D_MsgList, d_tick()
DMN_ / dmn_저수준 제어DMN_CtrlCtx, dmn_ctrl_run()
DI_ / di_디버그 정보 관리DI_Key, di_rdi_from_key()
UI_ / ui_사용자 인터페이스UI_Box, ui_button()
E_ / e_표현식 평가E_Parse, e_interpret()

C에 C++식 이름공간 문법이 없어도 이런 규칙으로 소속을 표현할 수 있습니다. 타입과 함수 이름을 보고 다음에 열 폴더를 예상해 보세요. 헤더 선언에서 구현으로 이동하는 속도가 빨라집니다.

5-2. 커밋 기준 코드 규모

종류파일 수물리적 줄 수
C .c281278,824
C 헤더 .h261103,584
C++ .cpp67,207
어셈블리 .S·.asm919,876
Metadesk .mdesk259,290
셸·배치 .sh·.bat4591
YAML .yml1218

계수는 커밋 771f63d의 저장소 전체에서 .git을 제외하고 파일별 개행 문자 수를 합친 값입니다. 빈 줄·주석·테스트·외부 소스·생성 코드·obsolete를 포함하며, 헤더를 모두 C 항목으로 묶었습니다. GitHub의 언어 비율이나 순수 구현 줄 수와는 다릅니다.

C·헤더 합계 382,408줄 중 third_party가 96,929줄, 그 밖의 generated가 31,317줄입니다. 두 범주를 제외하면 254,162줄이며, 여전히 주석·테스트·과거 코드가 포함됩니다. src 내부 C·헤더는 370,522줄, obsolete의 C·헤더는 11,886줄입니다.

레이어별 C·헤더 합계는 raddbg 56,832줄, linker 43,447줄, eval 12,776줄, base 12,027줄, dbg_engine 11,813줄입니다. 이 레이어 수치는 내부 생성 코드를 포함합니다. 파일 크기를 보고 진입점을 고르되, 크기를 품질 점수로 바꾸지는 마세요.

5-3. README의 지도와 실제 경로가 다른 부분

README의 레이어 목록에는 ctrl과 os/core·os/gfx 같은 이름이 남아 있습니다. 이 커밋에서 제어 코드는 src/dbg_engine/dbg_engine_ctrl.c, 운영체제 구현은 src/win32·src/linux 등에서 찾을 수 있습니다. 설명의 개념은 참고하되 파일 이동은 현재 경로를 기준으로 해야 합니다.

저장소를 공부할 때는 폴더 전체보다, 작은 함수 하나에서 시작해 호출자와 피호출자를 한 단계씩 연결하는 편이 길을 잃지 않습니다. 첫 경로로 ui_button(), 두 번째 경로로 d_u2c_push_msgs()를 권합니다.

6학습 포인트 (기술별)

코드를 읽고 나서 설명할 수 있어야 하는 질문들

6-1. C: 포인터와 길이를 함께 다루기

이 코드에서는 String8과 String8List를 자주 만납니다. 문자열을 0 종료 포인터 하나로만 보지 않고 바이트 주소와 길이가 있는 값으로 다룹니다. src/base/base_strings.h에서 타입을 확인하고, src/base/base_strings.c의 복사·부분 문자열·결합 함수를 따라가 보세요.

6-2. 운영체제: 실행을 멈춘다는 말의 실제 의미

Windows의 src/win32/demon/win32_demon.c에는 WaitForDebugEvent()가, Linux의 대응 파일에는 PTRACE_SEIZE·PTRACE_CONT·레지스터 읽기 호출이 나타납니다. 상위 함수 이름은 같아도 이벤트와 스레드를 다루는 절차는 다릅니다.

6-3. 동시성: 큐가 가득 찬 상황을 먼저 생각하기

정상 흐름에서 메시지를 한 번 보내는 것은 쉽습니다. 더 좋은 질문은 공간이 부족하거나 받는 쪽이 늦을 때의 동작입니다. 엔진은 송신 기한과 성공 여부를 다루고, 성공 전까지 보낼 목록을 유지합니다. 처리량과 응답성은 이런 경계 조건에서 갈립니다.

6-4. 컴파일러 기초: 변수 조사창도 작은 언어 처리기다

조사창의 player.health + 1을 표시하려면 이름을 해석하고, 멤버의 형식과 위치를 찾고, 값을 읽어 연산해야 합니다. src/eval/eval_parse.h의 e_token_array_from_text()·e_push_parse_from_string(), src/eval/eval_ir.c, src/eval/eval_interpret.c를 연결해 보세요.

학습용 개념 흐름: 실제 함수 전체의 호출 순서를 복제한 것은 아님
표현식 문자열
  → 토큰
  → 구문 트리
  → 형식·이름 해석
  → 중간 표현과 평가용 코드
  → 대상 메모리·레지스터를 이용한 값

일반 프로그램 안에서 같은 수식을 계산하는 것과도 다릅니다. 변수의 값이 디버거 자신의 메모리에 있는 것이 아니기 때문입니다. 표현식의 문법을 이해하는 일과, 다른 프로세스에서 그 값이 어디 있는지 찾는 일은 별도의 문제입니다.

6-5. GUI·그래픽: 클릭 처리와 픽셀 출력을 분리하기

ui_button()의 반환값은 입력 신호이며 GPU 명령 그 자체가 아닙니다. UI 레이어는 박스의 의미와 배치를, draw·render 레이어는 실제 그리기를 맡습니다. 글꼴도 font_provider와 font_cache로 나눠져 있습니다.

6-6. 코드 생성: 반복되는 선언의 원본 찾기

src/ui/ui.mdesk의 UI_StackTable에는 PrefWidth·FontSize 같은 항목과 기본값이 있습니다. 아래 @gen·@expand 선언이 이를 C 구조와 보조 코드로 펼칩니다. 생성된 헤더만 읽으면 같은 모양의 함수가 왜 많은지 놓치기 쉽습니다.

6-7. 테스트: 디버거와 조사 대상 양쪽을 준비하기

src/mule는 디버거 기능을 시험할 대상 프로그램들을 담고, src/torture/torture_main.c는 테스트 실행기의 입구입니다. src/base/tests/base_tests.c·src/raddbg/tests/raddbg_tests.c·src/linker/tests/linker_tests.c도 있습니다. 테스트가 있다는 사실, 실행 대상이 있다는 사실, CI가 실제로 실행한다는 사실은 따로 확인해야 합니다.

공부 기록 방법
함수마다 입력·출력·소유권·대기를 네 줄로 적기

어떤 값을 받는지, 무엇을 돌려주는지, 메모리를 누가 유지하는지, 어디서 기다릴 수 있는지 적어 보세요. 코드를 한국어로 한 줄씩 옮기는 것보다 구조를 오래 기억하는 데 도움이 됩니다.

7하드웨어 / 시스템 요구사항

공식 지원 범위, 코드에서 읽히는 조건, 학습용 여유를 구분한다
항목확인한 조건근거·해석
CPU·대상로컬 x64 디버깅README의 지원 범위. 다른 아키텍처 자료가 있어도 제품 지원을 뜻하지 않음
운영체제Windows x64, 초기 Linux x64macOS·ARM64를 현재 지원 환경으로 제시하지 않음
Windows 빌드Build Tools v15(2017) 이상과 Windows SDK; 또는 SDK를 갖춘 ClangREADME 기준. CI는 별도의 더 최신 환경 조합을 정의
Linux 빌드GCC 또는 Clang, 빌드 도구, 시스템 개발 라이브러리build.sh와 CI 기준; 정확한 GCC 최소 버전은 명시하지 않음
Windows 화면D3D11 기본, 기능 수준 11_0 요청render_d3d11.c의 r_init(); 하드웨어 실패 시 WARP 재시도 경로
Linux 화면X11과 OpenGL 3.3 계열 경로GLX·EGL 구현의 3.3 컨텍스트 요청, 셰이더의 #version 330 core
RAM·디스크일반적인 최소 수치는 명시되지 않음대상 프로세스, PDB·DWARF, 변환 RDI와 빌드 산출물 크기에 좌우됨

Linux 빌드는 pkg-config로 freetype2, x11 xext xfixes xrandr, gl egl을 찾습니다. pkg-config 실행 파일이 없을 때 기본 경로와 라이브러리 옵션으로 대체하며, 패키지 조회 실패 시 대체하는 분기는 없습니다. X11 의존성이 있으므로 순수 Wayland 전용 네이티브 구현이라고 소개해서는 안 됩니다.

학습용으로는 작은 C 프로그램과 심벌부터 다루면 메모리 부담을 줄일 수 있습니다. 16GiB RAM이나 SSD가 있는 환경은 여유를 잡는 예시일 뿐 공식 최소 사양이 아닙니다. 거대한 게임 프로젝트의 심벌 변환·링크에 필요한 자원을 이 예시로 보장할 수는 없습니다.

7-1. 디버그 정보와 최적화 설정도 실습 조건이다

변수명과 소스 줄을 보려면 대상 프로그램의 디버그 정보가 필요합니다. 최적화된 프로그램에서는 변수가 사라지거나 줄 이동이 예상과 달라질 수 있습니다. 첫 실습은 디버그 정보가 있는 작은 프로그램으로 하고, 다음에 최적화 설정만 바꿔 비교하면 원인을 분리하기 쉽습니다.

환경 용어
예약(reserve)과 커밋(commit)
예약은 사용할 주소 범위를 잡는 단계이고, 커밋은 그 주소를 실제로 사용할 수 있게 메모리 자원을 뒷받침하는 단계입니다. 예약량을 RAM 사용량으로 그대로 합산하면 요구사항을 과장하게 됩니다. 운영체제별 세부 동작은 다르지만 둘을 구분해야 한다는 점은 같습니다.

7-2. 학습자가 참고할 빌드 명령

# Windows: x64 개발 도구 명령 프롬프트, 저장소 루트에서
build raddbg msvc debug
build raddbg msvc release
build radbin msvc release

# Linux: 필요한 개발 라이브러리를 준비한 뒤
./build.sh raddbg clang debug
./build.sh raddbg clang release
./build.sh radbin clang release

첫 빌드에는 metagen의 컴파일·실행과 생성 파일 갱신이 포함됩니다. build뿐 아니라 src 내부 생성 파일도 바뀔 수 있습니다. 읽기 전용 학습 단계와 직접 빌드하는 단계를 구분하고, 실습용 사본에서 변경 사항을 확인하는 습관을 들이세요.

Oodle은 oodle 옵션으로 활성화하는 선택 경로입니다. 빌드 스크립트는 OODLE_SDK_DIR 또는 local/oodle2*에서 별도 SDK를 찾습니다. 기본 빌드의 필수 동봉 의존성이나 버전이 고정된 패키지로 취급하지 마세요.

8직접 해볼 수 있는 실습 과제

읽기 과제에서 출발해, 작은 프로그램과 설계 실험으로 확장하기

과제의 완료 기준을 기능 추가량보다, 관찰한 동작을 코드의 근거와 연결해 설명할 수 있는지에 두세요. 처음 두 과제는 큰 기능을 구현하지 않아도 시작할 수 있고, 뒤의 과제는 동시성·생성기·파일 형식으로 넓어집니다.

과제 1 · 입문

0 핸들 방어를 입력·출력 표로 설명하기

목표: 커밋 771f63d의 작은 수정을 읽고, 무엇을 보장하는지 정확히 설명합니다.

  1. src/linux/window_manager/linux_window_manager.c에서 두 wm_*rect_from_window() 함수를 찾습니다.
  2. 핸들이 0인 경우, 일반 창인 경우, resize_draw가 켜진 경우의 분기를 나눕니다.
  3. 각 분기에서 X11을 호출하는지와 어떤 좌표계를 반환하는지 기록합니다.

완료 기준: “0 입력은 0 사각형을 반환하며 창 정보 조회를 건너뛴다”를 소스에 근거해 설명하고, 창 위치를 포함한 사각형과 원점이 (0, 0)인 클라이언트 사각형을 구분한 표를 만듭니다.

한 단계 더: X11 호출의 실패 반환값까지 처리하는지 별도 질문으로 남깁니다. 0 핸들 수정이 모든 오류 처리를 끝냈다고 결론 내리지 않습니다.

과제 2 · 입문

작은 합계 프로그램에서 한 줄 이동과 변수 관찰하기

목표: 디버거의 값 표시가 소스 줄·호출 스택·실행 위치와 어떻게 연결되는지 직접 관찰합니다. 별도의 실습용 파일에 아래 코드를 준비합니다.

int main(void)
{
    int values[] = {1, 2, 3, 4};
    int total = 0;
    for(int i = 0; i < 3; ++i)
    {
        total += values[i];
    }
    return total == 10 ? 0 : 1;
}
  1. 디버그 정보와 최적화 해제 설정으로 컴파일합니다. Windows 예시는 cl /Zi /Od sum.c /Fe:sum.exe, Linux 예시는 cc -g -O0 sum.c -o sum입니다.
  2. 디버거의 대상 설정에서 실행 파일을 등록하고 반복문 본문에 중단점을 둡니다.
  3. 한 줄씩 이동하면서 i와 total을 Locals 또는 Watch에서 확인합니다.
  4. 조건을 i < 4로 고친 뒤 다시 컴파일하고 결과를 비교합니다.

완료 기준: 수정 전 합계는 6, 수정 후 합계는 10입니다. 각 반복의 i·total과 정지 위치를 표로 정리합니다. 최적화 설정을 바꿨을 때 관찰이 달라질 수 있는 이유도 적어 보세요.

과제 3 · 중급

작은 링 버퍼로 가득 찬 큐와 감김을 계산하기

목표: d_u2c_push_msgs()의 길이·본문·공간 판단을 작은 숫자로 재현합니다. 실제 엔진의 64KiB 대신 32바이트 버퍼를 가정합니다.

  1. 메시지 길이 필드는 8바이트, 첫 본문은 20바이트로 둡니다.
  2. 읽기·쓰기 위치가 0일 때 첫 메시지를 기록하고 남은 공간을 계산합니다.
  3. 두 번째 본문은 16바이트로 두고, 소비 전과 소비 후에 기록할 수 있는지 판단합니다.
  4. 쓰기 위치가 버퍼 끝을 넘을 때 실제 저장 인덱스를 나머지 연산으로 표시합니다.
처음:      read = 0,  write = 0,  빈 공간 = 32
첫 기록:   read = 0,  write = 28, 빈 공간 = 4
둘째 요구: 8 + 16 = 24 → 지금은 기록 불가
첫 소비:   read = 28, write = 28, 빈 공간 = 32
둘째 기록: read = 28, write = 52, 빈 공간 = 8
실제 다음 쓰기 인덱스: 52 % 32 = 20

완료 기준: 논리적인 읽기·쓰기 위치와 물리적인 배열 인덱스의 차이를 설명하고, “버퍼 전체보다 큰 메시지는 어떤 정책으로 다뤄야 할까?”라는 질문에 분할·거부·확장 중 설계안을 제시합니다. 현재 구현의 모든 경로가 그 정책을 갖췄다고 추정하지 마세요.

과제 4 · 중급

하나의 선언이 여러 C 이름으로 펼쳐지는 과정 찾기

목표: 코드를 수정하기 전에 생성기의 원본을 식별합니다. 읽기만으로 완성할 수 있는 과제입니다.

  1. src/ui/ui.mdesk에서 UI_StackTable의 PrefWidth 행을 찾습니다.
  2. src/ui/generated/ui.meta.h에서 UI_PrefWidthNode·ui_top_pref_width()·ui_push_pref_width()를 찾습니다.
  3. @expand의 치환값과 생성된 타입·함수 이름을 연결합니다.
  4. src/metagen/metagen_main.c에서 입력 검색과 출력 파일 쓰기 부분을 찾습니다.

완료 기준: 원본 한 행 → 생성된 구조체·스택·함수 선언의 대응표를 만듭니다. 생성 결과만 수동 수정하면 다음 생성 때 수정이 사라질 수 있는 이유도 설명합니다.

과제 5 · 고급

디버그 정보 로더의 상태 전이를 설계도로 복원하기

목표: src/dbg_info/dbg_info.c에서 비동기 변환의 조건과 완료 처리를 읽습니다. 처음에는 별도 파서를 만들거나 원본 코드를 수정하지 않아도 됩니다.

  1. di_open()·di_rdi_from_key()와 rdi_is_stale 주변을 읽습니다.
  2. 원본 준비 여부, RDI 갱신 필요 여부, 가용 스레드 수, 작업 활성 상태를 분리합니다.
  3. 변환 프로세스 시작 인자와 완료 후 파일 파싱·캐시 등록 순서를 그립니다.
  4. 원본 없음·버전 불일치·파싱 실패 같은 경우에 표시할 상태를 설계합니다.

완료 기준: 준비 전 → 대기 → 변환 중 → 로딩 → 사용 가능 또는 실패로 이어지는 학습용 상태도를 만듭니다. 이 이름들이 실제 열거형과 모두 일치하는 것은 아니므로, 각 화살표에 근거 함수·조건을 따로 붙입니다.

확장: 독립적인 작은 파일 형식을 설계하고 매직 값·버전·길이를 검사하는 파서를 작성합니다. 파일 길이를 벗어나는 입력에 대해 예상 오류를 표로 정한 뒤 검증합니다.

9관련 기술 심화 학습 로드맵

6주 동안 결과물 하나씩 남기며, 기반에서 제품 흐름으로 올라가기

처음부터 링커와 그래픽 코드를 동시에 읽으면 등장하는 개념이 너무 많습니다. 매주 작은 결과물을 만들고, 그 결과물을 다음 주의 소스 읽기에 사용하는 순서로 공부하세요. 아래 일정은 C의 조건문·반복문·함수·포인터 기초를 알고 있다는 가정입니다.

주차핵심 개념소스와 실습남길 결과물
1주포인터·길이·메모리 수명base_strings, base_arena, 임시 데이터 되감기문자열 뷰와 복사본의 메모리 그림
2주프로세스·스레드·정지 이벤트demon의 공통 선언과 Windows 또는 Linux 구현연결·정지·재개의 단계표, 합계 프로그램 관찰 기록
3주뮤텍스·조건 변수·메시지dbg_engine_core·dbg_engine_ctrl, 링 버퍼 계산큐 포화·시간 제한·복사 수명 설명서
4주심벌·파일 배치·주소lib_rdi·dbg_info, RDI 헤더와 변환 흐름파일 오프셋·모듈 오프셋·실행 주소 비교표
5주토큰·구문 트리·형식eval_parse·eval_ir·eval_interpret산술식과 멤버 접근식의 처리 단계도
6주UI 키·레이아웃·코드 생성ui_button(), ui_end_build(), UI_StackTable중단점 조작에서 결과 표시까지의 한 장 지도

9-1. 배경 지식을 보강할 순서

  1. C 메모리: 배열과 포인터, 구조체, 정렬, 수명과 소유권부터 익힙니다. 매크로를 읽기 어렵다면 확장 전후 코드를 손으로 대응시킵니다.
  2. 컴퓨터 구조: x64 레지스터, 호출 규약, 스택 프레임, 분기 명령을 공부합니다. 소스 한 줄이 기계어 여러 개가 될 수 있음을 이해합니다.
  3. 운영체제: 프로세스 주소 공간과 스레드, 예외·시그널, 동기화 도구를 공부합니다. Windows와 Linux를 처음부터 동시에 깊게 팔 필요는 없습니다.
  4. 실행 파일·심벌: PE/COFF 또는 ELF 하나부터 선택하고 PDB·DWARF의 역할을 붙입니다. 이후 RDI를 공통 조회 형식으로 읽습니다.
  5. 제품 설계: 준비되지 않은 데이터의 표시, 작업 취소·실패·재시도, 캐시 갱신 같은 사용자 경험을 엔진 설계와 연결합니다.
스스로 점검하기
함수 이름 없이도 흐름을 설명할 수 있는가

명령이 복사되는 이유, 심벌 변환이 별도 작업인 이유, 임시 메모리를 되감는 시점, UI 키가 필요한 이유를 먼저 한국어로 설명해 보세요. 이후 실제 함수와 경로를 붙일 수 있다면 구조를 이해한 것입니다.

10핵심 키워드 사전

문서와 소스 사이를 오갈 때 필요한 최소 어휘
용어쉬운 설명
사용자 모드일반 응용프로그램이 실행되는 영역. 커널 내부를 조사하는 기능과 범위가 다릅니다.
프로세스 / 스레드프로세스는 실행 중 프로그램의 자원 단위, 스레드는 그 안에서 명령을 실행하는 흐름입니다.
디버기디버거가 조사하는 대상 프로그램입니다.
중단점지정한 위치나 조건에서 실행을 멈추도록 설정한 지점입니다.
단계 실행소스 또는 명령 단위로 실행을 조금씩 진행하며 상태를 살펴보는 기능입니다.
레지스터CPU가 명령 실행에 직접 쓰는 작은 저장 공간. 현재 위치와 계산 중간값 등을 담습니다.
호출 스택 / 언와인딩누가 누구를 호출했는지 이어진 기록과, 그 기록을 역으로 복원하는 작업입니다.
심벌 / 디버그 정보주소를 함수·변수·형식·소스 줄 등 사람이 아는 정보와 연결하는 자료입니다.
PDB / CodeViewWindows 도구 생태계의 디버그 정보와 관련된 형식들. 컨테이너와 내부 레코드를 같은 개념으로 뭉뚱그리지 마세요.
DWARF소스 수준 디버깅을 위한 정보 형식 표준. Linux 등에서 널리 사용됩니다.
RDI이 프로젝트가 공통 조회를 위해 사용하는 자체 디버그 정보 형식입니다.
PE/COFF / ELF실행 파일이나 오브젝트 파일의 구조를 정의하는 형식 계열입니다.
링커 / 재배치여러 오브젝트를 실행 파일로 엮는 도구와, 최종 위치에 맞춰 주소 참조 등을 조정하는 작업입니다.
모듈 기준 오프셋모듈 시작점을 기준으로 한 상대 위치. 실제 실행 주소나 디스크 파일 위치와 구분합니다.
ASLR보안 등을 위해 프로그램 적재 주소를 바꾸는 방식. 같은 심벌의 실행 주소가 매번 같다고 가정하면 안 됩니다.
IPC서로 다른 프로세스 사이의 통신. 이 프로젝트의 인스턴스 명령 전달에는 소켓 경로가 있습니다.
링 버퍼배열 끝 다음을 다시 처음으로 이어 사용하는 버퍼. 읽기·쓰기 위치와 남은 공간을 관리합니다.
역압력받는 쪽이 밀릴 때 보내는 쪽의 속도나 요청을 제한해 넘침을 다루는 방식입니다.
직렬화구조화된 값을 통로에 보낼 수 있는 바이트 순서로 바꾸는 작업입니다.
아레나 / 임시 아레나메모리 수명을 묶어서 관리하는 영역과, 작업 후 위치를 되감아 재사용하는 임시 영역입니다.
즉시 모드 UI화면을 구성하는 코드를 반복 호출해 현재 UI를 기술하는 스타일. 내부 캐시나 지속 상태와 함께 쓸 수 있습니다.
글리프 아틀라스래스터화한 글자 모양을 큰 텍스처에 모아 두어 화면에 효율적으로 그리는 저장 방식입니다.
Metadesk / metagen이 프로젝트의 선언 파일 형식과, 그 선언을 읽어 코드·데이터 등을 생성하는 프로그램입니다.
AST / IR문법 구조를 담은 트리와, 다음 처리 단계가 다루기 좋게 변환한 중간 표현입니다.
unity build여러 구현 파일을 한 번역 단위에 포함해 컴파일하는 구성 방식입니다.
알파기능과 안정성이 계속 바뀌는 초기 배포 단계. 버전 이름 자체가 완성도를 보장하지는 않습니다.

용어를 외운 다음에는 자신이 읽은 함수와 하나씩 연결해 보세요. 예를 들어 직렬화는 d_serialized_string_from_msg_list(), 임시 수명은 temp_end(), UI 입력은 ui_signal_from_box()에 대응시킬 수 있습니다.

11참고 링크

공식 설명과 고정된 소스 시점을 함께 찾아보기

프로젝트 공식 자료

루트 README는 기술 개요이며 디버거 사용 설명서를 대신하지 않는다고 스스로 밝힙니다. 사용 안내는 릴리스 패키지나 빌드 결과의 README도 함께 확인해야 합니다. 특정 메뉴 위치와 키 바인딩을 소스의 오래된 설명만으로 외우지 마세요.

소스 읽기 순서와 근거 파일

주제고정된 소스 링크먼저 볼 식별자
앱 입구src/raddbg/raddbg_main.centry_point(), ExecMode
화면과 엔진src/raddbg/raddbg_core.crd_frame(), d_tick() 호출
엔진 초기화src/dbg_engine/dbg_engine_core.cd_init(), 두 링 버퍼
스레드 통신src/dbg_engine/dbg_engine_ctrl.cd_u2c_push_msgs(), 제어 스레드 입구
사용자 측 명령src/dbg_engine/dbg_engine_user.cd_tick(), 명령 깊은 복사·송신
플랫폼별 제어Windows 구현 / Linux 구현dmn_ctrl_attach(), dmn_ctrl_run()
RDI 변환·로딩src/dbg_info/dbg_info.cdi_open(), di_rdi_from_key()
RDI 형식·파서rdi.h / rdi_parse.cRDI_ENCODING_VERSION, rdi_parse()
메모리 수명src/base/base_arena.c / base_thread_context.carena_push(), temp_end(), 임시 아레나 선택
UI 구성ui_core.c / ui_basic_widgets.cui_begin_build(), ui_button()
표현식eval_parse.c / eval_interpret.c토큰·구문 분석, e_interpret()
선언과 생성ui.mdesk / metagen_main.cUI_StackTable, 파일 검색·출력
빌드·CIbuild.sh / build.bat / builds.yml컴파일 옵션·대상 행렬·비활성 실행 작업
0 핸들 처리linux_window_manager.cwm_rect_from_window(), wm_client_rect_from_window()

관련 기술 공식 자료

현재 상태 (2026-10-23 확인)

항목상태
선정 기준GitHub Trending C Monthly #4 · 2026-10-23 분석
스타 / 포크⭐8,638 / 428 · 2026-10-23 GitHub 기준
생성일2024-01-10
최신 릴리스v0.9.29-alpha · 2026-09-30
최근 push2026-10-22 · GitHub 기준
소스 기준 커밋771f63d · 2026-10-20 · Linux 창 사각형 함수의 0 핸들 방어
주 언어 / 코드 규모C · C 278,824줄 + 헤더 103,584줄, 합계 382,408줄
계수 범위개행 기준, 외부·생성·테스트·과거 코드 포함
대표 의존성동봉 BLAKE3 1.8.7 · xxHash 0.8.2 · Zydis 4.1.0.0 · stb_sprintf 1.10 기반 수정본
지원 범위로컬 Windows·Linux x64 사용자 모드 디버깅; Linux는 초기 단계
라이선스루트 MIT · 저작권자 Epic Games Tools

최근 push는 저장소 갱신 시각이고 커밋 시각과 같은 개념이 아닙니다. 소스 기준은 커밋 771f63d(2026-10-20)이며, 릴리스·인기도 등 저장소 상태는 2026-10-23 GitHub 기준입니다.

사용 전에 알아둘 한계
알파 제품의 지원 범위와 정적 분석의 경계

① Linux는 초기 단계입니다. v0.9.29 변경 기록은 Linux 바이너리를 배포하지 않았다고 밝히며, fork·vfork 디버깅, TLS 계산에서의 libc 가정, .eh_frame_hdr 부재 시 언와인딩, 비트필드 형식 정보 등의 제한을 열거합니다. 이는 해당 릴리스의 안내이므로 이후 수정 여부는 이슈와 새 릴리스에서 다시 확인해야 합니다.

② 지원 계획과 코드 존재를 구분해야 합니다. README는 원격·다중 머신 디버깅을 확장 계획으로 설명하지만, 이 커밋에는 원격 서버 관련 메시지와 함수도 있습니다. 소켓 IPC나 함수 이름만으로 완성된 원격 디버깅을 지원한다고 판정할 수 없습니다. macOS·ARM64·커널 디버깅도 현재 지원 범위에 포함하지 않습니다.

③ 성능 수치는 조건과 출처를 함께 봐야 합니다. 링커 성능 수치는 README의 저자 측 테스트 사례에 한정됩니다. CI에는 빌드 작업이 정의되어 있지만 실행 테스트 두 작업은 비활성 상태입니다. 코드의 존재만으로 특정 장비에서의 성능·안정성을 보장할 수는 없습니다.

④ 문서와 소스가 함께 이동하는 것은 아닙니다. README의 일부 레이어 이름은 현재 디렉터리와 다릅니다. 생성 코드와 동봉 외부 코드도 상당한 비중을 차지하므로, 줄 수를 전부 직접 작성한 구현량으로 읽지 마세요. 재사용할 때는 루트 라이선스와 외부 코드의 고지 파일을 각각 확인할 수 있습니다.