Embedded : : Linux/: : Device Tree

[Device Tree] 12. Device Tree 디버깅

Jay.P Morgan 2026. 3. 4. 16:49

 

 

 

  12.  Device Tree 디버깅

 

디바이스 트리(Device Tree) 디버깅은 "내가 쓴 코드(DTS)가 커널에 정말 잘 반영되었는가?"와 "커널이 그 정보를 제대로 해석했는가?"를 확인하는 과정입니다.

커널 소스 수준부터 실행 중인 타겟 시스템까지, 단계별 디버깅 기법을 정리해 드립니다.

 

1. 컴파일 타임 디버깅 (DTC 이용)

부팅 전, 문법 오류나 병합 결과를 확인하는 단계입니다.

  • 컴파일 오류 확인: make dtbs 실행 시 발생하는 에러 메시지를 확인합니다. 보통 세미콜론(;) 누락이나 phandle 참조 오류가 많습니다.
  • 최종 결과물 확인 (역컴파일): 여러 .dtsi 파일이 복잡하게 겹쳐 있을 때, 최종적으로 어떤 값이 들어갔는지 확인하려면 생성된 .dtb를 다시 .dts로 풀어봅니다.
    Bash
    # DTB를 읽기 쉬운 DTS로 역컴파일
    dtc -I dtb -O dts -o final_check.dts arch/arm64/boot/dts/my_board.dtb
    

 

 

2. 런타임 시스템 확인 (Live Tree)

부팅된 시스템에서 커널이 인식하고 있는 "현재의 데이터"를 직접 들여다보는 방법입니다.

 

/proc/device-tree 탐색

커널은 현재 사용 중인 디바이스 트리를 파일 시스템 형태로 노출합니다.

  • 경로: /proc/device-tree/ (또는 /sys/firmware/devicetree/base/)
  • 확인 방법: ```bash
    hexdump -C /proc/device-tree/soc/serial@1c28000/status cat /proc/device-tree/model
  • 특정 노드의 프로퍼티 값 확인 (바이너리이므로 주로 hexdump 사용)

fdtdump  fdtget

타겟 시스템에 dtc 패키지가 설치되어 있다면 유용하게 쓸 수 있습니다.

  • fdtget: 특정 노드의 값을 바로 출력합니다.
    Bash
    fdtget /boot/dtb-$(uname -r) /soc/ethernet@5020000 status
    

 

 

3. 커널 메시지 (Dmesg) 분석

커널이 디바이스 트리를 파싱하며 내뱉는 로그를 확인합니다.

  • 매칭 실패 확인: 드라이버의 probe 함수가 호출되지 않는다면 dmesg에서 관련 단서를 찾습니다.
  • OF 전용 디버그 로그 활성화: 커널 부팅 파라미터(bootargs)에 tp_printk를 추가하거나, 커널 빌드 시 CONFIG_DYNAMIC_DEBUG를 켜고 관련 파일을 활성화합니다.
    Bash
     
    # 특정 파일의 디버그 메시지 활성화 (런타임)
    echo 'file drivers/of/*.c +p' > /sys/kernel/debug/dynamic_debug/control
    

 

 

4. 유용한 디버깅 도구 및 팁

dtv (Device Tree Visualizer) 또는 스크립트

/proc/device-tree는 구조가 복잡하므로 이를 시각화해 주는 도구를 사용하면 편리합니다. 도구가 없다면 간단한 find명령어로 구조를 한눈에 볼 수 있습니다.

Bash
find /proc/device-tree/ -maxdepth 2

 

드라이버 내 커스텀 로그

드라이버의 probe 함수 내에서 of_property_read_... 함수의 리턴 값을 체크하여 로그를 남기는 것이 가장 확실합니다.

C
if (of_property_read_u32(np, "my-prop", &val))
    dev_err(dev, "DTS에서 'my-prop'을 찾을 수 없습니다!\n");

 

 

5. 부팅 초기 단계 디버깅 (Early Boot)

커널이 아직 뜨기도 전에 문제가 생겨 화면에 아무것도 안 나온다면?

  1. U-Boot fdt 명령: 부트로더에서 fdt print, fdt list 명령어로 메모리에 로드된 DTB를 직접 수정하거나 검사할 수 있습니다.
  2. earlycon 사용: 시리얼 드라이버가 뜨기 전 로그를 보기 위해 bootargs에 earlycon을 추가합니다. 이는 DT의 chosen 노드 설정을 기반으로 동작합니다.

정리하자면...

디바이스 트리 디버깅의 핵심은 "단계적 좁히기"입니다.

  1. DTC로 컴파일이 잘 됐는지 확인하고,
  2. /proc/device-tree에서 값이 의도대로 들어갔는지 확인하며,
  3. dmesg를 통해 드라이버가 그 값을 제대로 읽었는지 검증하는 순서로 진행하세요.

 

 

 
  # ===== 실행 중인 시스템에서 DT 확인 =====
 
  # Live Device Tree (procfs)
  $ ls /proc/device-tree/
  #address-cells cpus memory@80000000 soc
  #size-cells chosen model compatible
 
  # 특정 노드의 프로퍼티 읽기
  $ cat /proc/device-tree/model
   MyVendor MyBoard Rev.A
  $ hexdump -C /proc/device-tree/soc/serial@1c28000/reg
   00000000 01 c2 80 00 00 00 04 00
 
  # sysfs를 통한 접근 (동일한 데이터)
  $ ls /sys/firmware/devicetree/base/
  $ cat /sys/firmware/devicetree/base/compatible
 
  # ===== 커널 로그에서 DT 관련 메시지 =====
  $ dmesg | grep -iE 'device.?tree|of_|dts|dtb|compatible'
   OF: fdt: Machine model: MyVendor MyBoard Rev.A
   OF: fdt: Ignoring memory range 0x0 - 0x80000000
 
  # ===== probe 실패 디버깅 =====
 
  # 매칭되지 않은(드라이버 없는) 디바이스 확인
  $ ls /sys/bus/platform/devices/
  # 1c28000.serial 1c2ac00.i2c ...
 
  # 특정 디바이스의 드라이버 바인딩 상태
  $ ls -la /sys/bus/platform/devices/1c28000.serial/driver
  # symlink → 해당 드라이버 (없으면 매칭 실패)
 
  # deferred probe 목록 (의존성 대기 중)
  $ cat /sys/kernel/debug/devices_deferred
  # 1c2ac00.i2c ← 클럭/레귤레이터 등 의존성 미충족
 
  # 드라이버 강제 바인드/언바인드
  $ echo "1c28000.serial" > /sys/bus/platform/drivers/my-device/bind
  $ echo "1c28000.serial" > /sys/bus/platform/drivers/my-device/unbind
 
  # ===== Overlay 상태 확인 =====
  $ ls /sys/kernel/config/device-tree/overlays/
   my-hat/
  $ cat /sys/kernel/config/device-tree/overlays/my-hat/status
   applied
 
  # ===== ftrace로 DT 매칭 추적 =====
  $ echo 1 > /sys/kernel/tracing/events/bus/bus_add_device/enable
  $ echo 1 > /sys/kernel/tracing/events/bus/driver_bound/enable
  $ cat /sys/kernel/tracing/trace_pipe
  # bus_add_device: device 1c28000.serial
  # driver_bound: device 1c28000.serial driver my-device
 
  # ===== DT Validation (빌드 시) =====
  $ make ARCH=arm64 dt_binding_check # YAML 스키마 검증
  $ make ARCH=arm64 dtbs_check # DTB vs 바인딩 검증
  $ make ARCH=arm64 W=1 dtbs # 경고 활성화 빌드
 

 

위 코드는 리눅스 시스템 엔지니어가 하드웨어 문제를 해결할 때 사용하는 "실전 디바이스 트리(DT) 디버깅 가이드"입니다. 단순히 이론에 그치지 않고, 시스템이 돌아가는 중에 내부를 들여다보고 강제로 조작하는 고급 기법들을 담고 있습니다.

핵심적인 포인트별로 나누어 설명해 드릴게요.

 

1. Live Device Tree: "커널이 보고 있는 현재 모습"

커널은 부팅 시 읽어들인 DTB 바이너리를 메모리에 올리고, 이를 사용자가 보기 쉽게 /proc과 /sys에 파일 형태로 노출합니다.

  • cat vs hexdump: 프로퍼티가 문자열(model, status)이면 cat으로 읽을 수 있지만, 숫자(reg, interrupts)라면 4바이트 단위의 빅 엔디안 바이너리이므로 hexdump를 써야 정확한 값을 알 수 있습니다.
  • 파일 시스템 접근: /proc/device-tree는 실시간 하드웨어 구조를 트리 형태로 탐색하기 가장 좋은 도구입니다.

 

2. Probe 및 드라이버 매칭 디버깅

드라이버가 로드되었는데 하드웨어가 동작하지 않을 때 가장 먼저 확인해야 할 부분입니다.

  • driver 심볼릭 링크: /sys/bus/platform/devices/[주소.이름]/driver 파일이 존재하지 않는다면, 드라이버와 장치의 compatible 문자열이 서로 맞지 않아 매칭(Matching)에 실패했다는 강력한 증거입니다.
  • Deferred Probe (devices_deferred): 매우 중요한 팁입니다! 드라이버 코드는 맞지만, 이 장치가 작동하기 위해 필요한 클럭(Clock)이나 전원(Regulator) 드라이버가 아직 로드되지 않았을 때 장치는 이 목록에 들어갑니다. "왜 안 뜨지?" 싶을 때 가장 먼저 확인해야 할 파일입니다.

 

3. 강제 바인딩 (Bind/Unbind)

드라이버 매칭 로직을 수동으로 테스트하고 싶을 때 사용합니다.

  • 커널의 자동 매칭을 기다리지 않고, 특정 주소의 하드웨어를 특정 드라이버에 강제로 할당하거나 떼어낼 수 있습니다. 드라이버 개발 중 probe와 remove 함수가 제대로 동작하는지 반복 테스트할 때 유용합니다.

 

4. Overlay 및 동적 변경 확인

라즈베리 파이처럼 런타임에 하드웨어가 추가되는 시스템(ConfigFS 이용)에서 사용합니다.

  • .dtbo 파일이 정상적으로 시스템에 "합체"되었는지 status 파일(applied)을 통해 확인할 수 있습니다.

 

5. ftrace를 통한 실시간 추적

커널 내부에서 장치가 등록되고 드라이버가 붙는 과정을 영화처럼 실시간으로 지켜보는 기능입니다.

  • bus_add_device: 커널이 DT를 읽어 "아, 이런 장치가 있구나"라고 인지하는 순간.
  • driver_bound: 인지한 장치에 딱 맞는 드라이버가 찾아와 "내가 제어할게!"라고 연결된 순간.
  • 로그가 찍히지 않는다면 커널이 장치 자체를 인식하지 못했거나, 맞는 드라이버를 찾지 못한 것입니다.

 

6. DT Validation (YAML 스키마)

최신 리눅스 커널(v5.x 이상)에서 도입된 **"문법 검사기"**입니다.

  • 과거에는 .txt 문서로 대충 적어두던 규칙을 이제는 YAML 파일로 엄격하게 관리합니다. dtbs_check를 실행하면 내가 만든 DT 파일이 표준 규격(필수 프로퍼티 누락 등)에 맞는지 빌드 타임에 미리 잡아낼 수 있습니다.

💡 실무 적용 팁

만약 "내가 만든 장치가 ls -la /dev/에도 안 나오고 묵묵부답이다"라면 다음 순서로 디버깅하세요:

  1. dmesg | grep OF로 DTB 로드 중 에러가 없었는지 확인.
  2. cat /sys/kernel/debug/devices_deferred에 내 장치가 있는지 확인 (전원/클럭 대기 중일 확률 높음).
  3. /sys/bus/platform/devices/.../driver 링크가 있는지 확인 (없다면 compatible 오타 확인).
  4. 안 되면 ftrace를 켜고 드라이버를 insmod 해서 매칭 시도 자체가 일어나는지 확인.

 

DT 작성 시 주의사항:
  • compatible 문자열은 가장 구체적인 것을 먼저, 일반적인 폴백을 나중에 기술합니다
  • status = "disabled"인 노드는 드라이버가 probe되지 않습니다. .dtsi에서 기본 disabled → .dts에서 필요한 것만 "okay"
  • reg 프로퍼티의 해석은 부모의 #address-cells/#size-cells에 따라 달라집니다. 실수하면 잘못된 주소로 매핑
  • phandle 참조(&label)는 레이블이 정의된 노드를 가리킵니다. 존재하지 않는 레이블은 컴파일 오류
  • 새로운 바인딩은 반드시 YAML 스키마를 작성하고 dt_binding_check로 검증해야 합니다
  • Overlay 사용 시 dtc -@로 기본 DTB를 컴파일해야 __symbols__ 노드가 포함되어 런타임 심볼 해석이 가능합니다

 

 

 

 

 

참고: https://www.minzkn.com/linuxkernel/pages/device-tree.html#dt-compile