본문 바로가기

시스템 소프트웨어 개발을 위한 Arm 아키텍처의 구조와 원리

[리눅스커널] 라즈비안: vmlinux 소스 코드 정보 추가 : CONFIG_DEBUG_INFO

리눅스 커널 코드를 빌드하면 vmlinux란 파일이 추출됩니다. 
바이너리 유틸리티를 활용하면 vmlinux에서 여러 디버깅 정보 확인을 할 수 있는데요.
아래 컨피그를 추가하면 vmlinux 심볼 테이블에 소스 코드 정보가 추가됩니다. 
 
diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig
index 96fbcc6..961829b 100644
--- a/arch/arm/configs/bcm2709_defconfig
+++ b/arch/arm/configs/bcm2709_defconfig
@@ -31,6 +31,7 @@ CONFIG_KPROBES=y
 CONFIG_JUMP_LABEL=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
+CONFIG_DEBUG_INFO=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_BLK_DEV_THROTTLING=y
 
위와 같이 컨피그 코드 수정 후 build_kernel.sh 파일을 실행시켜 생긴 .config 파일을 열어보면 CONFIG_DEBUG_INFO=y 컨피그가 실제 켜져 있네요. 
bald.candy~/src/raspberry_kernel/out$ vi .config
5459 # Compile-time checks and compiler options
5460 #
5461 CONFIG_DEBUG_INFO=y
5462 # CONFIG_DEBUG_INFO_REDUCED is not set
 
 
그런데 컴파일 도중 아래와 같은 에러 메세지와 함께 빌드가 중지됩니다.
lib/raid6/neon8.c: In function ‘raid6_neon8_gen_syndrome_real’:
lib/raid6/neon8.c:158:1: internal compiler error: in dwarf2out_frame_debug_adjust_cfa, at dwarf2cfi.c:1078
 }
 ^
Please submit a full bug report,
with preprocessed source if appropriate.
make[3]: *** [lib/raid6/neon8.o] Error 1
make[3]: *** Waiting for unfinished jobs....
lib/raid6/neon4.c: In function ‘raid6_neon4_gen_syndrome_real’:
lib/raid6/neon4.c:114:1: internal compiler error: in dwarf2out_frame_debug_adjust_cfa, at dwarf2cfi.c:1078
 }
 ^
 
소스 정보가 포함된 vmlinux 파일을 얻는 게 목적이므로 아래 패치를 적용하고 다시 빌드합니다.
diff --git a/lib/raid6/Makefile b/lib/raid6/Makefile
index 3057011..69f563e 100644
--- a/lib/raid6/Makefile
+++ b/lib/raid6/Makefile
@@ -5,7 +5,7 @@ raid6_pq-y      += algos.o recov.o tables.o int1.o int2.o int4.o \
 
 raid6_pq-$(CONFIG_X86) += recov_ssse3.o recov_avx2.o mmx.o sse1.o sse2.o avx2.o avx512.o recov_avx512.o
 raid6_pq-$(CONFIG_ALTIVEC) += altivec1.o altivec2.o altivec4.o altivec8.o
-raid6_pq-$(CONFIG_KERNEL_MODE_NEON) += neon.o neon1.o neon2.o neon4.o neon8.o
+raid6_pq-$(CONFIG_KERNEL_MODE_NEON) += neon.o neon1.o neon2.o
 raid6_pq-$(CONFIG_TILEGX) += tilegx8.o
 raid6_pq-$(CONFIG_S390) += s390vx8.o recov_s390xc.o
 
위 패치를 적용하고 난 후 out 폴더에 vmlinux가 제대로 생성됩니다. 
 
바이너리 유틸리티 사용
raspberry_tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-objdump 폴더에 위치한 arm-linux-gnueabihf-objdump 파일을 out 폴더에 복사합니다.
bald.candy~/src/raspberry_kernel/out$ cp ~/bin/raspberry_tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-objdump .
bald.candy:~/src/raspberry_kernel/out$
 
아래 명령어를 치면 arm-linux-gnueabihf-objdump 바이너리 유틸리티 옵션을 확인할 수 있습니다.
austindh.kim@~/src/raspberry_kernel/out$ ./arm-linux-gnueabihf-objdump
 
Usage: ./arm-linux-gnueabihf-objdump <option(s)> <file(s)>
 Display information from object <file(s)>.
 At least one of the following switches must be given:
  -a, --archive-headers    Display archive header information
  -f, --file-headers       Display the contents of the overall file header
  -p, --private-headers    Display object format specific file header contents
  -P, --private=OPT,OPT... Display object format specific contents
  -h, --[section-]headers  Display the contents of the section headers
  -x, --all-headers        Display the contents of all headers
  -d, --disassemble        Display assembler contents of executable sections
  -D, --disassemble-all    Display assembler contents of all sections
  -S, --source             Intermix source code with disassembly
  -s, --full-contents      Display the full contents of all sections requested
  -g, --debugging          Display debug information in object file
  -e, --debugging-tags     Display debug information using ctags style
  -G, --stabs              Display (in raw form) any STABS info in the file
  -W[lLiaprmfFsoRt] or
  --dwarf[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,
          =frames-interp,=str,=loc,=Ranges,=pubtypes,
          =gdb_index,=trace_info,=trace_abbrev,=trace_aranges,
          =addr,=cu_index]
                           Display DWARF info in the file
  -t, --syms               Display the contents of the symbol table(s)
  -T, --dynamic-syms       Display the contents of the dynamic symbol table
  -r, --reloc              Display the relocation entries in the file
  -R, --dynamic-reloc      Display the dynamic relocation entries in the file
  @<file>                  Read options from <file>
  -v, --version            Display this program's version number
  -i, --info               List object formats and architectures supported
  -H, --help               Display this information
 
아래 리다이렉트 명령어로 결과 파일을 dump_kernel_code.c에 저장합니다. 
austindh.kim@~/src/raspberry_kernel/out$ ./arm-linux-gnueabihf-objdump -d -S vmlinux > dump_kernel_code.c
 
이제 dump_kernel_code.c 파일을 열어서 start_kernel 코드를 검색하면 어셈블리와 소스코드를 함께 볼 수 있습니다.
 80b00970 <start_kernel>:
         ioremap_huge_init();
         kaiser_init();
 }
 
 asmlinkage __visible void __init start_kernel(void)
 {
 80b00970:       e1a0c00d        mov     ip, sp
 80b00974:       e92ddff0        .word   0xe92ddff0
 80b00978:       e24cb004        sub     fp, ip, #4
 80b0097c:       e24dd01c        sub     sp, sp, #28
         char *command_line;
         char *after_dashes;
 
         set_task_stack_end_magic(&init_task);
 80b00980:       e59f0344        .word   0xe59f0344
 80b00984:       ebd8655d        bl      80119f00 <set_task_stack_end_magic>
         smp_setup_processor_id();
 80b00988:       eb000c3b        .word   0xeb000c3b
         /*
          * Set up the the initial canary ASAP:
          */
         boot_init_stack_canary();
 
         cgroup_init_early();
 
 
>>>
 
 
ffffff80080d58c0 <_do_fork>:
          unsigned long stack_start,
          unsigned long stack_size,
          int __user *parent_tidptr,
          int __user *child_tidptr,
          unsigned long tls)
{
ffffff80080d58c0:   a9b87bfd    stp x29, x30, [sp,#-128]!
ffffff80080d58c4:   910003fd    mov x29, sp
ffffff80080d58c8:   a90153f3    stp x19, x20, [sp,#16]
ffffff80080d58cc:   a9025bf5    stp x21, x22, [sp,#32]
ffffff80080d58d0:   a90363f7    stp x23, x24, [sp,#48]
ffffff80080d58d4:   a9046bf9    stp x25, x26, [sp,#64]
ffffff80080d58d8:   aa0003f3    mov x19, x0
ffffff80080d58dc:   aa1e03e0    mov x0, x30
ffffff80080d58e0:   aa0103f4    mov x20, x1
ffffff80080d58e4:   f0005e96    adrp    x22, ffffff8008ca8000 <page_wait_table+0x1500>
ffffff80080d58e8:   aa0203f8    mov x24, x2
ffffff80080d58ec:   aa0303f9    mov x25, x3
ffffff80080d58f0:   aa0403f5    mov x21, x4
ffffff80080d58f4:   97ff129a    bl  ffffff800809a35c <_mcount>
ffffff80080d58f8:   911a22c0    add x0, x22, #0x688
    struct completion vfork;
    struct pid *pid;
    struct task_struct *p;
    int trace = 0;
ffffff80080d58fc:   52800017    mov w23, #0x0                       // #0
...
    if (!(clone_flags & CLONE_UNTRACED)) {
ffffff80080d590c:   37b80113    tbnz    w19, #23, ffffff80080d592c <_do_fork+0x6c>
        if (clone_flags & CLONE_VFORK)
ffffff80080d5910:   36700a53    tbz w19, #14, ffffff80080d5a58 <_do_fork+0x198>
ffffff80080d5914:   52800400    mov w0, #0x20                   // #32
            trace = PTRACE_EVENT_VFORK;
ffffff80080d5918:   52800057    mov w23, #0x2                       // #2
ffffff80080d591c:   d5384101    mrs x1, sp_el0
 *
 * Returns %true if @event is enabled, %false otherwise.
 */
static inline bool ptrace_event_enabled(struct task_struct *task, int event)
{
    return task->ptrace & PT_EVENT_FLAG(event);
ffffff80080d5920:   b9403021    ldr w1, [x1,#48]
            trace = PTRACE_EVENT_CLONE;
        else
            trace = PTRACE_EVENT_FORK;
 
        if (likely(!ptrace_event_enabled(current, trace)))
            trace = 0;
ffffff80080d5924:   6a01001f    tst w0, w1
ffffff80080d5928:   1a9f12f7    csel    w23, w23, wzr, ne