core-image-sato, SDK, TOOLCHAIN_HOST_TASK, populate_sdk, gdb, gdbserver, dev 패키지, debug tools 설치, PACKAGE_DEBUG_SPLIT_STYLE

markyang92·2022년 9월 21일
0

yocto

목록 보기
46/53
post-thumbnail

do_populate_sdk()

  • SDK 생성

    • do_populate_sdk(), do_populate_sdk_ext()를 통해 SDK를 쉽게 구성할 수 있다.
      • /build/tmp/deploy/sdk/*.sh로 만들어 지고, 해당 파일만 있다면 개발자는 Cross-compile 환경을 쉽게가져갈 수 있다.
  • SDK(Software Development Kit): 개발과 디버깅을 하기 위한 파일과 toolchain 모음
    • toolchain: compiler, linker, debugger, 외부 라이브러리 헤더, utility, apps..
  1. Custom Source, lib(usb|gl)과 같은 외부 라이브러리런타임 빌드에 사용된다.
    1.1. Custom Source: 라이브러리 헤더 파일을 이용해 빌드
    1.2. 실행될 때 바이너리는 특정 위치로 이동 될 수 있다.
  2. 빌드 시점에서 사용되는 파일들은 포키 SDK의 일부로, sysroot에 있다.
  3. native toolchain: 포키가 bitbake를 이용해 task를 실행할 때, 타깃을 위한 바이너리를 컴파일하고 링크하기 위해 툴체인이 필요하다. 이러한 툴체인은 빌드 시스템 내부에서 사용되기 때문에, 내부 툴체인이라 부른다.
  4. 포키는 외부에서 사용할 수 있는 툴체인을 만들 수 있다. 설치된 환경과 무관하게 컴퓨터에 설치할 수 있는 SDK패키지를 만든다. 추가로 설치된 툴체인은 내부 툴체인과 호환가능하다. 툴체인 외에도 SDK는 목적에 맞게 헤더와 라이브러리 파일을 제공할 수 있다.

  • 이미지 기반 SDK만들기
$ bitbake core-image-full-cmdline -c populate_sdk
  • 이 명령으로 core-image-full-cmdline 이미지 레시피 기반을 둔 SDK가 만들어진다.
    SDK는 여기서 MACHINE의 아키텍처로 생성된다.
  • 빌드 된 후, 바이너리 스크립트가 생성된다.
    • native: x86_64
    • MACHINE: quemuarm64
    • 경로: ${TMPDIR}/deploy/sdk/poky-glibc-x86_64-core-image-full-cmdline-aarch64-qemuarm64-toolchain-3.1.13.sh
      이 생성된 스크립트는 사용하기 전에 설치해야한다.


sdk/*.sh

poky-glibc-x86_64-'image'-aarch64-qemuarm64-toolchain.3.1.13.sh

  • 위 이미지에서 만든, ${TMPDIR}/deploy/sdk/poky-glibc-x86_64-core-image-full-cmdline-aarch64-qemuarm64-toolchain-3.1.13.sh를 실행한다.
  • 이 예제에서 설치되는 디렉토리는 /opt/poky/3.1.13이다. 하지만 원하는 디렉토리를 설정 할 수도 있다.

  • 설치가 완료되면, 설치된 디렉토리(/opt/poky/3.1.13)에 아래의 파일 및 디렉토리가 생성된다.
install filedescription
1. environment-setup-aarch64-poky-linux툴체인을 사용하기 위해 필요한 모든 환경 변수의 설정을 위해 사용
2. site-config-aarch64-poky-linux툴체인 생성에 사용되는 변수들을 담고 있는 파일
3. sysrootsSDK 생성을 위해 사용된 이미지 rootfs 디렉토리의 복사본
다음과 같은 하위 디렉토리는 바이너리, 헤더, 라이브러리 파일들을 포함한다.
  • aarch64-poky-linux: ARM 머신을 위한 파일들 포함
  • x86_64-pokysdk-linux: x86_64 머신 호환 파일들 포함
4. version-armv5te-poky-linux-gnueabi버전과 타임스탬프 정보

  • environment-setup-aarch64-poky-linuxsource 명령어로 현재 쉘에 적용 시켜 보자.
$ source ./environment-setup-aarch64-poky-linux
$ echo ${CC}
aarch64-poky-linux-gcc  -march=armv8-a+crc -fstack-protector-strong  -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/opt/poky/3.1.13/sysroots/aarch64-poky-linux
$ echo ${LD}
aarch64-poky-linux-ld  --sysroot=/opt/poky/3.1.13/sysroots/aarch64-poky-linux
$ echo ${LDFLAGS}
-Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -fstack-protector-strong -Wl,-z,relro,-z,now
  • 엄청나게 쉽게, 툴체인이 환경변수로 적용되어있다.
  • 커스텀 애플리케이션을 빌드하기 위해 SDK를 사용해본다.
  • hello_world.c를 예로 들어, ARM 아키텍처를 타깃으로 빌드한다.
$ source /opt/poky/2.4/environment-setup-armv5e-poky-linux-gnueabi
$ ${CC} hello_world.c -o hello_world

생성된 바이너리가 원하는 타깃 이키텍처에 맞게 생성됐는지 확인 하려면 다음과 같이 입력한다.

$ file hello-world
hello-world: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV),
dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 3.2.0,
BuildID[sha1]=ce9b7..., not stripped

일반적으로 이용하는 또다른 프로젝트는 리눅스 커널이다. 리눅스 커널은 LD 유틸리티를 이용해 링킹을 하기 때문에 GCC를 사용해 정의한 기본 값으로 unset을 사용해 LDFLAGS 변수를 재설정해야한다. 리눅스 커널 소스코드를 빌드하려면 다음 명령을 이용하면된다.

$ source /opt/poky/2.4/environment-setup-armv5e-poky-linux-gnueabi
$ unset LDFLAGS
$ make defconfig
$ make zImage
  • Yocto 프로젝트 확장(Extensible) SDK(eSDK)를 사용하면 개발자가 프로젝트 개발 기간동안 기존 SDK 환경을 업데이트하고 확장할 수 있기 때문에 분산된 개발을 할 수 있다. eSDK를 잘 사용하려면, sstate-cache 미러와 eSDK서버와 같은 인프라 설정이 필요하다.

cmake

$ find /opt/poky/2.4/ -iname "*cmake*" 2> /dev/null
/opt/poky/2.4/sysroot/<arch>/usr/share/cmake/OEToolchainConfig.cmake
  • project
$ tree ./cmake-hello-world
CMakeLists.txt
main.cpp

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

project(cmake-hello-world-cpp)
add_executable(${PROJECT_NAME} "main.cpp")

main.cpp

#include <iostream>

using namespace std;

int main()
{
    cout << "Hello World!" << endl;
    return 0;
}

build

$ mkdir build
$ cd build
$ cmake -DCMAKE_TOOLCHAIN_FILE=/opt/poky/2.4/sysroot/<arch>/\
usr/share/cmake/OEToolchainConfig.cmake ..

build!
$ make

meta-toolchain

  • 범용적 SDK: meta-toolchain
  • SDK를 만드는 다른 방법은 크로스컴파일러, 디버그 도구, 기본 헤더와 라이브러리를 포함하는 범용적 SDK를 만드는 것이다. 이를 meta-toolchain이라고 부른다.
    보통 커널, 부트로더의 개발과 디버그를 위해 이용한다.
    이를 만들기 위해선, 아래의 명령을 사용한다.
$ bitbake meta-toolchain
  • qemuarm 머신을 위한 결과:
    • build/tmp/deploy/sdk/poky-eglibc-x86_64-meta-toolchain-aarch64-toolchain-3.1.13.sh에 의해 생성된다.
    • 설치 과정은 이미지 기반의 SDK와 동일하다.
  • 이 SDK가 유용하지만, 애플리케이션 용도에 맞는 커스텀 이미지를 만들고 이를 기반으로 SDK를 만드는 것을 권장한다.

RUNTIME 개발 on TARGET

IMAGE_FEATURES += "dev-pkgs" : .h, pkgconfig

  • Embedded System에서 어쩔 수 없이 개발을 해야하는 경우..
  1. Target시스템에서 외부 툴체인을 이용해 개발 이미지를 만드는 것이다.
    1.1. 개발 이미지.h 파일과, 라이브러리 링크 로 구성된다.
    1.2. 개발 이미지는 커스텀 애플리케이션을 위한 빌드 환경을 제공하고, 커스텀 툴체인이나 Yocto 프로젝트 외부 툴체인과 함께 사용될 수도 있다.
    1.3. 아래의 구문으로 이미지에 기능을 넣을 수 있다.
    참고로 dev-pkgs는 모든 ${PN}-dev 패키지를 이미지에 설치한다.
    IMAGE_FEATRUES += "dev-pkgs"
    1.4. local.conf 에서 기능을 넣고 싶은 경우 아래와 같이 한다.
    EXTRA_IMAGE_FEATRUES += "dev-pkgs"
  • 즉, 각 패키지의 dev 패키지까지, 추가하여 설치하는 것이다.
    • myhello를 보면, '개발'에 필요한 .h 헤더, /usr/lib/pkgconfig/*.pc 파일은 ${PN}-dev 패키지에 들어가 있다.이 것들을 패키지 하나하나 일일히 image에 설치하지않고
      커맨드 하나로 추가하는 것이 IMAGE_FEATURES += "dev-pkgs"

IMAGE_FEATURES += "tools-debug" : 디버그툴

  • 패키지 레시피 위치: meta/recipes-core/packagegroups/packagegroup-core-tools-debug.bb
  • gdb, gdbserver, MTRACE, STRACE 패키지를 설치하는 패키지그룹
    IMAGE_FEATURES += "tools-debug"

gdbserver

  • tools-debug 패키지에 gdbserver가 있는데, 이 패키지는 Embedded Target Device에서 메모리, 디스크 사용량 제약 때문에, On Device Runtime Debug가 불가능할 때 사용한다.
  • gdbserver타깃에서 실행하고, 디버깅 절차에 필요한 디버깅 정보들을 로드하지 않는다.
    • 대신 gdb instance는 호스트에서 디버깅 정보를 처리
    • 호스트 gdb는 디버그된 애플리케이션을 제어하기 위해 gdbserver로 제어 명령어를 보낸다.
  • 호스트 gdb가 디버깅 정보를 로드하고 디버깅에 필요한 처리를 수행하는 책임을 가짐으로써 타깃 디바이스에 디버깅 심볼을 설치할 필요가 없고, 호스트는 디버깅 정보를 가진 바이너리를 접근할 수 있으면 된다. 타깃 바이너리가 디버깅을 가능하게 하기 위해 최적화 없이 컴파일 될 때 가능하게 된다.
  • TODO: gdbserver를 사용하기 위한 처리와 적절한 방식으로 호스트와 타깃을 설정하는 방법은 yocto docs/dev-manual에서 자세히 살펴본다.
  • INHIBIT_PACKAGE_STRIP = "1" 설정하여 binary strips symbol을 방지하자!

core-image-sato.bb 를 이용해본다.

  1. poky kirkstone기반
  2. machine: meta-raspberrypi "raspberrypi4-64"

  • meta/recipes-sato/images/core-image-sato.bb
DESCRIPTION = "Image with Sato, a mobile environment and visual style for \
mobile devices. The image supports X11 with a Sato theme, Pimlico \
applications, and contains terminal, editor, and file manager."
HOMEPAGE = "https://www.yoctoproject.org/"

IMAGE_FEATURES += "splash package-management x11-base x11-sato ssh-server-dropbear hwcodecs"

LICENSE = "MIT"

inherit core-image

TOOLCHAIN_HOST_TASK:append = " nativesdk-intltool nativesdk-glib-2.0"
TOOLCHAIN_HOST_TASK:remove:task-populate-sdk-ext = " nativesdk-intltool nativesdk-glib-2.0"

QB_MEM = '${@bb.utils.contains("DISTRO_FEATURES", "opengl", "-m 512", "-m 256", d)}'
QB_MEM:qemuarmv5 = "-m 256"
QB_MEM:qemumips = "-m 256"
  • Sato 이미지, mobile device에 대한 visual style 및 mobile 환경.
    • X11 기반의 Sato theme 제공
    • Pimlico app
    • terminal, editor, file manager 포함
  • IMAGE_FEATURES
    • splash
    • package-management
    • x11-base, x11-sato, ssh-server-dropbear, hwcodes
  • TOOLCHAIN_HOST_TASK:append
    • nativesdk-intltool
    • nativesdk-glib-2.0
  • TOOLCHAIN_HOST_TASK:task-populate-sdk-ext에서 :remove
    • nativesdk-intltool
    • nativesdk-glib-2.0
Variable in core-image-satodescription
TOOLCHAIN_HOST_TASKnativesdk-packagegroup-sdk-host
packagegroup-cross-canadian-raspberrypi4-64
nativesdk-intltool
nativesdk-glib-2.0
TOOLCHAIN_HOST_TASK:remove:task-populate-sdk-extnativesdk-intltool
nativesdk-glib-2.0
TOOLCHAIN_HOST_TASK_ATTEMPTONLY-
TOOLCHAIN_HOST_TASK_ESDKmeta-environment-extsdk-raspberrypi4-64
TOOLCHAIN_TARGET_TASKpackagegroup-core-standalone-sdk-target
target-sdk-provides-dummy
packagegroup-core-boot
packagegroup-base-extended
run-postinsts
opkg
psplash-raspberrypi
packagegroup-core-ssh-dropbear
packagegroup-core-x11-base
packagegroup-core-x11-sato
TOOLCHAIN_TARGET_TASK_ATTEMPTONLY-
  • QB_MEM = '${@bb.utils.contains("DISTRO_FEATURES", "opengl", "-m 512", "-m 256", d)}'
    • QB_MEM:qemuarmv5 = "-m 256"
    • QB_MEM:qemumips = "-m 256"

QB?


TOOLCHAIN_HOST_TASK

  • OpenEmbedded build system이 SDK 빌드할 때 사용하는 패키지의 리스트를 담는 Variable
    • SDKMACHINE(default: $BUILD_ARCH)을 따른다.
  • SDK용 각 패키지는 일반적으로 prefixnativesdk-를 가진다.
  • SDK 빌드시 아래의 커맨드를 사용할 텐데,
    $ bitbake -c populate_sdk <image>
  • 이 경우, 아래의 변수를 control하여 sdk관련 package를 추가하거나 제거할 수 있다.
    • TOOLCHAIN_HOST_TASK : HOST(native)에서 실행되는 툴체인에 개별 패키지 control 변수
    • TOOLCHAIN_TARGET_TASK : TARGET에서 개별 패키지 control 변수
    • TOOLCHAIN_HOST_TASK_ESDK: eSDK의 호스트 부분에 설치된 항목을 확장
  • TOOLCHAIN_OUTPUTNAME
    TOOLCHAIN_OUTPUTNAME ?= "${SDK_NAME}-toolchain-${SDK_VERSION}"

$ bitbake core-image-sato -c populate_sdk

nativesdk- 패키지


디버깅을 위한 local.conf 설정


PACKAGE_DEBUG_SPLIT_STYLE

  • gdb에 사용할 dbg 패키지를 만들 때, 디버그 및 소스 정보를 분할하고 패키징하는 방법을 결정
    • 일반적으로, PACKAGE_DEBUG_SPLIT_STYLE 변수 값 기반으로 src, dbg단일 패키지로 만들거나,
      src를 독립적으로 설치할 수 있는 별도의 패키지를 만들거나
      src를 패키지화 하지 않도록 선택할 수 있다.
  • 세부 설정은 package.bbclass의 1100line 정도에 있다.
PACKAGE_DEBUG_SPLIT_STYLE                                                       Description
.debug
기본값
모든 src, dbg단일 -dbg 패키지로 만든다.
.debug디렉토리에 디버그 심볼을 위치 시켜, binary/bin에 설치되면, /bin/.debug에 해당 binary와 일치하는 디버그 심볼을 넣는다.
src파일 또한, -dbg 패키지에 있어, /usr/src/debug소스코드를 위치시킨다.
debug-file-directoryAs above, all debugging and source info is placed in a single *-dbg package; debug symbol files are placed entirely under the directory /usr/lib/debug and separated by the path from where the binary is installed, so that if a binary is installed in /bin, the corresponding debug symbols are installed in /usr/lib/debug/bin, and so on. As above, source is installed in the same package under /usr/src/debug.
debug-with-srcpkgDebugging info is placed in the standard -dbg package as with the .debug value, while source is placed in a separate -src package, which can be installed independently. This is the default setting for this variable, as defined in Poky’s bitbake.conf file.
debug-without-srcThe same behavior as with the .debug setting, but no source is packaged at all.

-dbg 패키지에서 저렇게 지정된대로 변환해야 -dbg 패키지로 file을 잘 가져올 수 있다.


core-image-sato 에서 PACKAGE_DEBUG_SPLIT_STYLE

PACKAGE_DEBUG_SPLIT_STYLE="debug-with-srcpkg"
PACKAGE_DEBUG_SPLIT_STYLE:toolchain-clang="debug-without-src"

core-image-sato를 기반으로 원격 디버깅

  • 우선, core-image-sato는 아래와 같음
  • 그래서, local.conf에 아래와 같이 추가한다.
# === local.conf ==== #
IMAGE_INSTALL:append = " gdbserver"
EXTRA_IMAGE_FEATURES = "tools-debug"
$ bitbake core-image-sato -c populate_sdk

core-image-sato -c populate_sdk

  • core-image-sato 대상
    • IMAGE_FEATURES
      • 'debug-tweaks'
      • 'splash'
      • 'package-management'
      • 'x11-base', 'x11-sato', 'ssh-server-dropbear', 'hwcodecs'
    • TOOLCHAIN_HOST_TASK:append=" nativesdk-intltool nativesdk-glib2.0"
    • TOOLCHAIN_HOST_TASK:remove:task-populate-sdk-ext=" nativesdk-intltool nativesdk-glib-2.0"
  • MACHINE = "raspberrypi4-64"
$ bitbake core-image-sato -c populate-sdk
  • 툴체인이 ${DEPLOY_DIR}/sdk에 설치되면 .sh 파일을 설치하면, (default: /opt/<distro>)sysroots 디렉토리가 생성되어 있는데, 엄밀히, Target sysroot는 저기 이다.

  • GDB 심볼 정보
    • sysroot내부 각 디렉토리에 .debug가 있음 여기서 심볼 정보를 찾음

  • 실행 파일소스코드sysroot/usr/src/debug 에 있음
  • 여기 있는 바이너리는 not stripped
  • 즉, populate_sdk() 자체가 IMAGE_FEATURES += "dbg-pkgs" 인셈

  • targetgdbserver가 설치 되어있다.
    • (수정) local.conf에 EXTRA_IMAGE_FEATURES = "tools-debug" 했기 때문에 Target 이미지에도 gdbserver 뿐만 아니라, gdb도 설치된 것 같다.

target gdb 수행

  1. IMAGE를 sd-card에 굽고 Target실행하여 ssh로 접속한다.
    Host(Native)Target은 현재 동일한 네트워크 환경에 있다. (하나의 공유기 환경)
    여기서, gdbserver를 열고 허용할 IP 옵션은 생략하면 어떤 IP 주소든 신경 쓰지 않는다.
    허용할 Port:10000으로 열어주고 디버깅 대상 binary를 써준다.
    여기서는 단순하게 "hello world!"를 stdout에 출력하는 hello(/usr/bin/hello)를 실행한다.
# Target ssh 접속 후
root@raspberrypi4-64:~ $ gdbserver :10000 hello
Process hello created; pid = <PID>
Listening on port 10000

  1. 이제 Host에서 gdb를 실행해야한다.
    아까 do_populate_sdk로 만든 toolchain이 설치된 디렉토리로 가자.
$ /opt/<distro>/<version>/

여기에 environment-setup-cortexa72-poky-linux라는 파일이 있는데 쉘에 먹이면 툴체인이 적용된다.

$ source ./environment-setup-cortexa72-poky-linux
혹은
$ . environment-setup-cortexa72-poky-linux

툴체인이 쉘에 먹히면, PATH에 관련 툴들이 자동완성으로 뜬다.
여기 gdb를 사용한다.
do_populate_sdkTargetsysroot가 설치되어 있으므로, 디버깅 바이너리가 있는 곳으로 가서 gdb를 실행한다.

$ aarch64-poky-linux-gdb ./hello

  • 이제 여기 gdb 디버깅 세션에서 Target(gdbserver)에 remote 명령으로 통신시켜준다.
(gdb) target remote 192.168.1.2:10000
# Target board의 ssh ip가 192.168.1.2 이다.
# 해당 IP에 10000 포트에 연결시킨다.
  • Target에서도 연결되었다고 뜬다.

  1. Host(Native)sysroot를 연결시킨다.
(gdb) set sysroot /opt/poky/4.1+snapshot/sysroots/cortexa72-poky/linux

  • gdb는 또한 디버깅을 위해 src도 필요로한다.
    • source code 디렉토리는 show directories를 입력하면 보여준다.
      • $cdir: 소스가 컴파일 된 디렉토리. DW_AT_comp_dir 태그를 사용해 객체 파일로 인코딩 되어 있으며, objdump --dwarf를 사용하면 태그를 볼 수 있다.
        $ aarch64-poky-linux-objdump --dwarf ./hello | grep DW_AT_comp_dir
        <160> DW_AT_comp_dir : (indirect string, offset: 0x244:
        /소스코드위치
      • $cwd: 호스트에서 실행 중인 gdb 인스턴스의 현재 작업 디렉토리
    • 만약 소스코드를 못찾는다고 하면, SDKsysroot에 위에 설명한대로 /usr/src/debug에 소스코드가 다 들어가있으므로, 여기를 등록해도 된다.
      (gdb) set sysroot /opt/poky/4.1+snapshot/sysroots/cortexa72-poky/linux
      (gdb) set substitute-path /usr/src/debug
      /opt/poky/4.1+snapshot/sysroots/cortexa72-poky/linux/usr/src/debug
    • 디버깅 binaryshared library를 사용한다면, 이 경우 shared library를 검색할 수 있도록 콜론으로 구분된 디렉토리 목록이 들어있는 set solib-search-path를 사용할 수 있다.
      gdb에서는, sysroot에서 binary를 찾을 수 없는 경우에만 solib-search-path를 검색한다.
    • 라이브러리와 프로그램 모두에서 gdbsource code를 찾을 곳을 알려주는 또다른 방법은
      directory명령을 사용하는 것이다.
      (gdb) directory 'path'
  • 이제 Host(Native)에서 gdb명령을 입력해보자.

    Host(Native)에서 target binary에 대해 gdb 명령이 잘 먹힌다.

TARGET에서 직접 GDB

  • 타겟에 GDB를 설치한다.
  • 디버깅할 실행 파일의 unstripped 버전과 target image에 설치된 소스코드도 필요하다.
  • local.conf
IMAGE_INSTALL:append = " gdb"
EXTRA_IMAGE_FEATURES += "dbg-pkgs"
  • 역시 소스코드는 /usr/src/debug/패키지이름
    • 으로 설치된다.
    • 이는 gdb가 set substitute-path를 실행할 필요없이 이소스를 설치할 것이다라는 뜻
    • 소스가 필요하지 않다면 PACKAGE_DEBUG_SPLIT_STYLE = "debug-without-src"를 local.conf에 추가한다.
  • dbg-pkgs를 포함해 설치한 core-image-sato-sdk

    용량이 엄청 커졌다!!

profile
pllpokko@alumni.kaist.ac.kr

0개의 댓글