Debugging Guide on Linux

TRACE32
이동: 둘러보기, 검색

목차

  Overview

본 과정의 교육자료는 TRACE32 입문/중급 과정을 마치거나 동등 수준에 이른 분을 대상으로 작성되었으나 상황에 따라 사용에 미숙한 분들을 고려해 기본 개념 및 기초 사용에 대한 설명을 추가해 놓은 경우도 있습니다. 따라서 필요한 부분만 참조하여 보는 것도 좋은 방법이 되겠으며 내용은 Target OS가 Linux인 경우를 기준으로 작성되었습니다. 그러나 지극히 Linux에 특화된 내용을 제외하고는 다른 OS 환경에서 적용 및 사용이 가능할 것으로 보입니다.

본 교제의 사용 방법은 우선 앞의 목차에서 큰 제목을 확인하시고 관심항목을 Click 하시면 해당 내용으로 이동하니 사용에 참조하시기 바랍니다.

 

   실습환경

본 과정 실습 환경은 다음과 같습니다. TRACE32를 이용한 디버깅 측면에서는 최근 사용되고 있는 big.LITTLE processing 환경에서도 동일하게 적용하셔도 무방합니다.

 

CPU

CortexA57x4+CortexA53x4 big.LITTLE System

CortexA9MPcorex2 System

Target OS

Linux 3.10.44 based Android LollyPop

Linux 3.07.10 based Android JellyBean

TRACE32 PowerView version

2014. 12 이상 버전

iTSP version

iTSP version 3.8.8 이상 버전

TRACE32 ICD(In Circuit Debugger)

= PDMU(Power Debug Modue)+License Module

PowerDebug USB2/PowerDebug USB3/PowerDebug II

License Module

 

l  PowerView : PC에서 동작하는 TRACE32 Software GUI 개발환경의 이름입니다.

l  PDMU : PC와 통신 및 디버그 인터페이스 신호을 만들어 내는 본체를 통틀어 지칭하는 이름입니다.

l  License Module : JTAG License Cable이라고도 하며 License 정보를 가지고 있으며 Target과 연결하기 위해 Cable을 포함하고 있는 삼각형 형태의 모듈

   SoC에서 Debug 제약사항

JTAG을 이용한 Debug 환경 셋업이 완료되고 난 후 제약 사항은 따로 없으나, Target이 big.LITTLE과 같은 절전모드를 사용하여 특정 하드웨어 블록의 전원을 끈다거나 하는 경우에 SoC의 Power/Clock/Reset Domain의 설계에 따라서 칩내 Debug Logic 동작에 영향을 주어 정상적으로 동작 하지 않을 수 있습니다. 이는 해당 SoC의 특성이므로 초기 셋업 시 TRACE32 기술지원 담당자에게 문의하시면 관련 정보를 얻으실 수 있으며 Debug를 위한 Software Feature 추가가 필요할 수 있으니 확인하시기 바랍니다. 또한 OS Kerenl에서 Profiling과 같은 특정 기능을 실행하기 위해 Debug Logic Resource를 사용하는 경우가 있는데 이럴 경우에도 BreakPoint에 의한 Break Event가 발생하지 않는다든지 의도하지 않는 동작을 할 수 있습니다.

상기 기술된 내용 이외에 문제가 될만한 것은 Secure JTAG이 적용된 것일 수 있으며 Debug를 위한 보안 해제를 위해 SoC Secure Key 값을 미리 설정하여 Debug 가능 상태로 변경이 필요할 수 있습니다.

 

   iTSP(Integraged TRACE32 Support Package)에 대한 이해 및 기능

iTSP는 최근 복작한 SoC 구조에 따른 Debug를 위한 환경 셋업이 매우 복잡해짐으로 인해 매우 번거롭고 어려움을 느낄 수 있어 TRACE32 Debugger에 대한 기본 지식이 없는 초기 사용자라 할지라도 쉽게 설정하여 셋업할 수 있도록 도와주는 TRACE32 Script Package입니다. 기본적으로 설정 환경이 GUI로 되어 있어 쉽게 설정이 가능합니다. 설정 방법은 2. How to setup을 참조하시기 바랍니다.

또한 필요할 경우 요청하시면 해당 SoC를 추가하고 있으니 참조하시기 바랍니다. 현재는 주로 Linux/ Android/QnX/Nucleus/SLP/L4/WinCE6/WinCE7/WP8 등의 OS에 대한 iTSP를 제공하고 있습니다.

 

  How to setup

여기서는 TRACE32 설치 및 Target Debug를 위한 환경 셋업에 대해 알아 봅니다.

 

   Installation of PowerView

1)    우선 TRACE32 설치 CD를 넣은 후 setup.bat 파일을 실행하여 installer를 실행합니다. 다음 화면이 나올 때까지 Next를 선택하고 다음과 같이 설치 장비를 ICD(In Circuit Debugger)를 선택합니다.

2)    다음은 Host Interface 타입을 선택하는 윈도우가 나오는데 대부분은 USB Interface를 사용하므로 기본 설정대로 Next합니다.

3)    다음 윈도우가 나올 때까지 Next하시고 다음 윈도우가 나오면 설치할 CPU Debugger를 선택하는 항목으로 다음과 같이 ARM series debugger를 선택합니다.

-      ICD ARM(ARM7/9/11, Cortex, XScale) : 기존 ARMv7 Architecture debugger 설치 선택

-      ICD ARM64(ARMv8-A) : 64bit ARMv8 Architecture(CortexA57/CortexA53) debugger 설치 선택

필요에 따라 사용할 여러 processor들을 선택하여 설치할 수 있습니다.

4)    호스트 PC OS가 64bit Windows인 경우 64bit용 실행파일을 설치할 것인지 32bit용 실행파일을 설치할 것인지를 묻는 메시지 윈도우를 띄웁니다. 64bit인 경우 simulator사용 시 이점이 있으므로 “예(Y)”를 선택합니다. 32bit Windows에서 설치하는 경우는 본 순서는 없으며 자동으로 32bit용 SW를 설치합니다.

5)    다음은 모두 Next나 확인을 선택하여 설치하시고 USB driver설치 윈도우가 나오면 다음(Next)를 선택하여 USB Driver 설치 Resource를 복사하도록 합니다. 모든 설치가 완료된 후 장비를 연결하고 Power를 켜면 자동으로 USB Driver를 설치하게 됩니다. PC에 따라 설치하는 시간이 최대 1분여 정도 걸릴 수 있습니다. 추후 USB Driver를 Update하고자 하는 경우 Driver는 설치폴더나 CD:\files\bin 폴더에 있으니 해당 폴더를 선택하여 설치하시면 되겠습니다.

 

6)    다음 내용들은 모두 Next하여 설치하시고 다음과 같이 시작프로그램에 등록하는 윈도우가 나온 후 Next 하여 설치를 마무리 합니다.

 

   Installation of iTSP와 TRACE32 Update

iTSP와 TRACE32 Update는 두가지 방식으로 가능합니다.

 

1)    먼저는 “TRACE32 Update Manager”라고 하는 TRACE32 Update Utility를 이용하는 방법으로 사용이 간편하며 다양한 버전을 쉽게 update할 수 있습니다.

2)    다음은 수동으로 하는 방법입니다.

 

다만 iTSP 파일이나 TRACE32 Update 데이터를 다운로드하기 위해서는 다운 받는 곳의 Network 보안 설정이 다운로드 할 주소에 접근을 막아 놓고 있는 경우 불가합니다. 이러한 경우 Network 관리 담당자에게 보안 해제를 요청하시기 바랍니다. 자세한 사항은 각 항목을 참조하시기 바랍니다.

     ”TRACE32 Update Manager”를 이용한 iTSP 설치 및 TRACE32 Update

“TRACE32 Update manager”를 이용해 iTSP 설치 및 TRACE32 Update를 하는 경우 다운받는 곳의 사내 Network 보안설정이 http://www.TRACE32.com/ 80 port 를 열어 놓고 있어야 합니다.

1)    “TRACE32 Update Manager” 설치

“TRACE32 Update Manager” 사용을 위해서 우선 아래 순서에 딸 설치합니다.

www.TRACE32.com >> 자료실에 가셔서 “TRACE32 Update Manager”를 다운로드 받은 후 설치합니다. “TRACE32 Update Manager”의 설치 방법 및 자세한 사용법은 unzip하시면 있는 “TRACE32 Update Manager Install and User Guide.PDF” 문서를 참고하시기 바랍니다.

아이콘을 실행하면 다음과 같이 login 윈도우가 열리며 계정이 없는 경우 만드시고 login합니다. login이 성공하면 다음 그림과 같이 “TRACE32 Update Manager” 윈도우가 열리게 됩니다.

 

 

2)    “TRACE32 Update Manager”를 이용한 iTSP 설치

>> iTSP 탭을 선택한 후

>> 좌측의 iTSP 버전과 사용할 SoC를 선택

>> Download 버튼을 클릭

>> 다운로드 완료 후 Patch버튼이 활성화 되면 Patch 버튼 클릭

하면 iTSP가 설치 완료됩니다.

 

3)    “TRACE32 Update Manager”를 이용한 TRACE32 Update

>> 우선 PowerView Update 탭을 선택

>> Patch할 CPU core 종류와 TRACE32 버전 선택

>> 다운로드 버튼 클릭하여 Update 파일 다운로드

>> 다운로드 완료 후 Patch 버튼이 활성화 되면 Patch 버튼 클릭

하면 해당버전으로의 Update가 완료 됩니다.

 

     수동으로 iTSP 설치 및 Update하기

1)    iTSP 수동으로 설치하기

iTSP는 FTP를 통해 따로 제공하고 있지 않으며 “TRACE32 Update Manager”를 이용해 Update하여야 합니다. 만약 사내 보안설정으로 TRACE32 Update Manager를 이용한 Update가 불가한 경우

trace32@hancommds.com으로 연락처/성함/소속 정보와 함께 연락주시면 당일 내로 송부드립니다.

2)    TRACE32 수동으로 Update하기

수동으로 Update 파일 다운로드를 위해 사내 Network 보안설정이 ftp://ftp.trace32.com/ 21 port 를 열어 놓고 있어야 합니다.

>> ftp.trace32.com/TRACE32_Update 아래에서 Update 버전 년도에 따라 해당 폴더로 들어감

>> 사용하는 CPU 폴더로 들어감

>> 날짜별 Update 버전을 확인한 후 보유한 License Mainternace 기간 내의 SW 다운로드

>> Unzip 후 압축 해제된 파일들을 설치한 TRACE32 루트 폴더(Ex. C:\T32\)에 덮어 씌우기

>> Update 완료

 

   Starting PowerView

iTSP 설치가 완료되면 아래 그림과 같이 설치 폴더에 ARMv8 Core(CortexA5x series) Debugging 시는 “TRACE32 ICD Target ARM 64.lnk” 파일을, ARMv7(CortexA15x/Ax/Rx/Mx) Core의 경우 “TRACE32 ICD Target ARM.lnk” 파일을 실행하여 TRACE32 PowerView를 실행합니다.

 

실행하게 되면 아래 그림과 같이 연결할 SoC용 iTSP 선택 Dialog가 열리게 되는데 원하는 Target SoC와 OS를 선택한 후 Start 버튼을 클릭합니다.

 

그러면 해당 SoC와 OS에 맞는 Target 메뉴가 생성되며 추가로 두개의 아이콘도 생성됩니다. 다음은 디버깅할 Target의 Boot Loader나 OS에 대한 iTSP설정 후 디버징 작업을 진행하면 되겠습니다.

 

   iTSP Setup for u-boot debugging & Linux Kernel & Android

u-boot 나 Kernel debugging을 위한 iTSP 환경 Setup에 대하여 알아 봅니다. 아래 그림과 같이 Target Setting 아이콘을 클릭하면 iTSP Setup 윈도우가 열립니다.

프로젝트마다 사용될 iTSP 프로젝트 이름, 각종 심볼 경로 등 디버깅에 필요한 필수 정보들을 설정해 줍니다. 설정이 필요한 항목은 다음과 같습니다.

 

Project

5개까지 프로젝트 별로 iTSP 설정을 저장 가능

Bootloader Symbol

부트로더 심볼(ELF) 파일 선택

Linux Kernel Symbol

리눅스 커널 심볼 파일인 vmlinux ELF 파일 선택

Android Symbol Directory

Android 빌드 시 생성되는 out 폴더 내에 있는 Anroid ELF 파일들을 모아 놓은 symbols라는 폴더의 Network 경로를 지정

ex) <Android Root>\out\target\product\smdkc210\symbols

Kernel Address Range

Kernel이 위치해 있는 물리메모리 영역(Low Memory Range) 지정

AutoMMU

Booting 후 vmlinux ELF를 /nocode 옵션과 로드(Linux 심볼 로드) 후 AutoMMU 버튼을 누르면 Kernel Address Range를 자동으로 찾아 설정. vmlinux 파일은 반드시 현재 보드에 올라간 image 빌드시 파일이어야 함

Symbol Path

위의 Android Symbol Directory에 설정된 폴더에 위치하지 않은 image를 디버깅 하고자 한다면 해당 ELF image가 있는 폴더 위치를 추가로 지정하기 위한 설정

 

모든 설정이 완료된 후 설정을 Save하고 Target Power를 OFF >> ON 한 다음 아래 그림과 같이

Kernel-Debug 버튼을 클릭하게 되면

Target은 booting 후 Start_Kernel()까지 실행하고 멈추게 되는데 여기까지 동작이 확인 되면 모든 설정이 정상적으로 완료된 것이라고 생각해도 되겠습니다.

 

마지막으로 Kernel Address Range의 정확한 확인을 위해 Target를 일정시간(3~5초) 실행시켜 멈춘 후 TRACE32 Command line에서

 

do ./OS/linux/mmu_setinfo.cmm

 

명령을 입력하여 실행하거나

 

MMU.List.List.PageTable 0xC0000000

or

MMU.List.KernelPageTable

 

입력하여 실행하면 정확한 Kernel Physical Range를 확인할 수 있습니다. MMU Table에서 리니어하게 배치된 커널 물리 영역을 얻어 냅니다.

 

<32bit Kernel에서 Kernel MMU Table List>

 

위 예제의 경우 0x40000000—0x6F7FFFFF가 됩니다.

 

만약 ARMv8의 경우라면

MMU.List.PageTable 0xFFFFFFC000000000

 

를 실행하면

아래와 같이 64bit Address space를 갖는 형태로 현재 Mapping된 MMU Table List를 보여줍니다.

 

<64bit Kernel에서 Kernel MMU Table List>

 

참고로 Target의 Kernel Binary Image와 로드된 vmlinux 파일의 일치 여부를 확인하기 위해 TRACE32 Command Line에서

 

TASK.TEST

 

명령을 실행하면 정확한 Linux text banner와 현재 사용된 Linux 정보들을 확인할 수 있습니다. 만약

 

<32bit Kernel에서 TASK.TEST 결과>

 

Binary Image와 vmlinux 파일이 같은 빌드시 생성된 것이 아니(다른 경우)라면 banner의 String이 일부 보이지 않거나 모두 보이지 않는 현상을 볼 수 있습니다.

 

<64bit Kernel에서 TASK.TEST 결과>

 

위와 같이 64bit Linux Kernel이라면 “ptr size”와 “MMU format”이 64bit 인것을 확인할 수 있습니다.

 

 

   u-boot Debugging

앞의 iTSP 설정이 완료되고 난 후 u-boot debugging을 위해서는 Target 메뉴 >> boot-Debug 항목을 클릭하게 되면 u-boot의 맨처음 실행되는 C-함수 실행 중 멈추게 됩니다.

만약 JTAG debugging을 위해 JTAG Port에 “System Reset” 신호가 연결되어 있지 않은 경우나, JTAG Port의 “System Reset”에 연결된 신호에 의해 재부팅 제어가 불가한 경우는 Target을 재 부팅시킬 수 없기 때문에 Power를 Off 한 후 ON 하고 “boot-Debug” 항목을 클릭하도록 합니다.

 

 

 

 

 

   Kernel Debugging

Kernel debugging시 경우에 따라

 

1)    start_kernel() 코드 실행부터 디버깅 하기

2)    smp_cpus_done() 코드 실행부터 debugging 하기

 

를 원하는 경우가 있을 것입니다. SMP 환경에서 모든 core들이 깨어난 뒤 Kernel 코드실행을 보고자 한다면  smp_cpus_done() 코드 실행부터 debugging 하기를 따라하시면 되겠습니다.

     start_kernel() 함수부터 debugging 하기

앞의 iTSP 설정이 완료되고 난 후 Target 메뉴 >> Kernel-Debug 항목을 클릭하게 되면 Kernel의 start_kernel()함수 실행 시작에서 멈추게 됩니다.

만약 debugging을 위한 JTAG Port에 “System Reset”이 연결되어 있지 않은 경우나 JTAG Port의 “System Reset” 핀에 연결된 신호에 의해 재부팅 제어가 불가능한 경우는 Target을 재 부팅시킬 수 없기 때문에 Power를 Off 한 후 ON 한 다음 바로 Kernel-Debug 항목을 클릭하도록 합니다.

 

     smp_cpus_done() 함수부터 debugging 하기

앞의 iTSP 설정이 완료되고 난 후 Target 메뉴 >> Kernel SMP-Debug 항목을 클릭하게 되면 Kernel의 smp_cpus_done()함수 실행 시작에서 멈추게 됩니다.

만약 debugging을 위한 JTAG Port에 “System Reset”이 연결되어 있지 않은 경우나 JTAG Port의 “System Reset” 핀에 연결된 신호에 의해 재부팅 제어가 불가능한 경우는 TRACE32가 Target을 재 부팅시킬 수 없기 때문에 Power를 Off 한 다음 ON 하고 바로 Kernel SMP-Debug 항목을 클릭하도록 합니다.

 

     부팅후 Kernel 동작 중 중간에 연결하여 디버깅하기

앞의 iTSP 설정이 완료되고 난 후 Target 메뉴 >> Kernel-Attach 나 Kernel SMP(Attach)-Debug 항목을 클릭하게 되면 Target Reset을 실행하지 않고 Target 동작 중 중간에 연결하여 디버깅 모드로 진입하게 됩니다.

Kernel-Attach 항목은 SMP core 중 main core 하나만 연결하게 되며 Kernel SMP(Attach)-Debug는 SMP로 구성된 모든 core를 연결하여 디버깅 상태로 전환합니다.

 

 

 

  BreakPoint

BreakPoint는 타깃 CPU가 특정 상태일 때 멈추도록 하여 그 때의 시스템 상태를 확인해 볼 수 있게 하는 유용한 기능입니다. BreakPoint는 크게 Hardware BreakPoint(이하 Onchip BreakPoint)와 Software BreakPoint로 나뉩니다.

*  Onchip BreakPoint

칩 내부의 Hardware인 debug logic을 이용하여 BreakPoint를 설정하는 것으로 Program의 Code나 Data에 상관없이 설정이 가능하며 주소가 할당된 어느 영역이든 설정이 가능합니다. 그러나 CPU에 내장된 debug logic을 사용하므로 개수가 제한적입니다. 보통 Cortex Series ARM의 경우 2개에서 12개까지 가능합니다. 가끔은 CPU의 Core Register에 BreakPoint 설정이 가능한지를 문의하는 경우가 있습니다만 대부분의 CPU에서는 Core Register에 BreakPoint 설정은 불가 합니다.

 

*  Software BreakPoint

원래 메모리에 있던 명령어를 Backup한 후 HLT/BKPT 명령어와 같은 Trap Code를 삽입하는 Software 적인 구현 방법을 사용하는 것으로 구현 특성상 초기화된 RAM의 코드영역에만 설정 가능합니다. Software 적인 구현 특성상 Code 삽입 방식을 사용하므로 무한대의 개수만큼 설정이 가능합니다.

 

  •   Program(or code) BreakPoint

프로그램 코드에 설정하는 BreakPoint로 Onchip/Software 방식 모두 설정이 가능합니다.

  •   Data BreakPoint:

프로그램의 코드가 실행되면서 읽고 쓰는 Data에 설정하는 BreakPoint로서 오직 Hardware (Onchip debug) logic을 통해서만 설정가능합니다. 왜냐하면 CPU core의 Read/Write bus cycle을 감지할 수 있는 방법은 오직 Hardware trigger 만이 가능하기 때문입니다.

 

 

   BreakPoint 설정정책 선택

아래 기본 설정과 같이 BreakPoint는 TRACE32가 자동으로 알아서 선택하여 설정하므로 특별한 경우를 제외하고는 염두할 필요가 없습니다. 다만 임의로 특정 BreakPoint Mechanism을 설정하여 사용하고자 할 경우

메뉴>>Break>>Implementation 클릭하여 정책을 바꿀 수 있습니다.

 

 

 

   Data BreakPoint 설정

     특정 주소에 access(read/Write/Read or write)

본 chapter에서는 특정 주소의 Data에 BreakPoint 설정 방법을 학습합니다. CPU는 현재 동작하고 있는 Memory Management mode를 기준으로 Break Event가 Trigger 됩니다. 즉 MMU가 켜져 있는 경우 Virtual을 기준으로 설정된 어드레스에 Trigger되며 MMU가 꺼져 있는 경우 Physical Address를 기준으로 설정된 Address에 Trigger됩니다.

*  kernel 영역(SFR 포함) Data BreakPoint 설정 

Kernel 영역은 Common 영역으로 각 Process의 MMU mapping table이 바뀌어 로드되더라도 항상 동일 어드레스와 내용을 갖는 영역입니다. 따라서 현재 CPU가 바라보는 virtual address를 기준으로 별다른 고려사항 없이 BreakPoint를 설정하면 됩니다.

 

  • 설정하고자 하는 virtual address  

만약 설정할 Virtual address 0xEC4D3800에 어떤 Data를 Write할 때 Break가 걸리도록 설정하고자 한다면 TRACE32 Command line에서

 

Break.Set 0xEC4D3800 /Write

 

명령을 입력하거나

TRACE32 메뉴>>Break>>Set 클릭 후 아래와 같이 설정할 수 있습니다.

 

만약 위 어드레스에 특정 값이 써질 때 멈추고자 한다면 Data Field에 다음과 같이 설정할 수 있습니다.

 

  • 설정하고자 하는 physical address 알고 있을 때 

MMU를 사용하는 시스템에서 CPU는 Virual Address만을 보게되므로 Physical에 해당하는 Virtual Address를 얻은 후 BreakPoint를 설정해야 합니다.

만약 Physical 0x11400000에 Data BreakPoint를 설정하고 싶다면 해당 번지에 대한 Virtual Address을 얻는 방법은 두가지가 있습니다.

1)    첫 째는 TRACE32 Script함수 중에 MMU.LOGICAL(A:물리주소)이라는 함수가 있어 쉽게 얻어 낼수 있습니다. 다만 해당 함수를 사용하기 전에는 반드시 MMU.SCAN.PageTable 이나 MMU.SCAN.KernelPageTable 명령을 실행하여 해당 Physical에 대한 Virtual Address를 준비하도록 하여야 합니다. 간단히 다음과 같이 실행하시면 원하는 곳에 BreakPoint를 설정할 수 있습니다.

 

MMU.SCAN.PageTable 또는

MMU.SCAN.KernelPageTable

Break.Set MMU.LOGICAL(A:0x11400000) /Onchip

 

위의 경우 Physical Address 0x11400000에 해당하는 Virtual Address에 BreakPoint를 설정합니다. ARMv8에 64bit Kernel을 사용하고 있다면 위와 동일하며 원하는 address를 적으면 되겠습니다.

 

2)    두 번째로는, TRACE32 Command Line에서

 

MMU.List.PageTable

을 입력하여 Table List를 보여주면 다음과 같이 그 Physical에 해당하는 Virtual Address 0xF0006000를 얻어 냅니다.

 

 

다음은 얻어낸 Virtual Address에 다음과 같이 TRACE32 Command Line을 이용하여 BreakPoint를 설정하거나

 

Break.Set 0xF0006000 /Write

 

TRACE32 메뉴>>Break>>Set 클릭 후 Break.Set 윈도우를 이용해 설정할 수 있습니다.

 

*  user 영역에 Data BreakPoint 설정 

user 영역의 경우 특별히 고정된 Hardware Address에 해당하는 Virtual Address를 직접 Access한다거나 하는 일이 없기 때문에 다른 고려 사항은 없습니다. 따라서 원하는 Virtual Address에 BreakPoint를 설정하면 되겠습니다. 다만 주의할 것은 아래 그림과 같이 CPU에서 바라보는 user 영영의 Virtual Address는 현재 Process 뿐 아니라 다른 Process도 동일한 Address를 가질 수 있기 때문에 설정해 놓은 BreakPoint Address에 다른 Process가 실행하다 Access하는 경우도 Break Event가 발생하여 멈추게 됩니다. 멈추었을 때 원하는 SpaceID를 갖지 않는 경우 간단히 Run 시키시면 되겠습니다.

 

만약 다른 Process가 실행하다 해당 Address를 Access하는 경우 멈추지 않도록 설정하고 싶은 경우에는 아래와 같이 TASK 옵션의 해당 Thread 선택 박스를 클릭해 디버깅하던 현재 Process나 Thread를 선택해 주면 되겠습니다. 아래 예의 경우 Address 0xBF001600에 데이터를 쓰거나 읽는 경우 Break Trigger를 거는 설정입니다. 다만 kthreadd Process나 Thread일 경우만 트리거하여 멈추겠다는 설정입니다.

 

참고할 점은 상기와 같이 설정한 경우 해당 Address를 어떤 Process나 Thread가 Access했는지 확인하기 위해 CPU를 잠깐 세우게 되는데 이에 따라 약간 느려질 수 있습니다. 즉 Realtime 동작이 아닌 경우가 되며 아래와 같이 TRACE32 상태바에서 갈색으로 S라는 표기해 개발자로 하여금 확인할 수 있게 해줍니다.

 

 

     특정 symbol 에 access(read and/or write) 시 BreakPoint 설정

BreakPoint 설정 시 symbol에 BreakPoint 설정하는 것은 Symbol이 이미 해당 Address를 포함하고 있기 때문에 Kernel이나 User 영역 상관없이 기존에 알고 있는 symbol을 이용해 BreakPoint를 설정하면 됩니다. 다만 User 영역의 경우 다른 Process가 해당 Address를 Access하는 경우도 Trigger될 수 있으므로 TASK 설정이 필요합니다.

1)    kernel 영역에 있는 특정 symbol에 BreakPoint설정하기

우선 Trigger 하고자 하는 변수를 Symbol윈도우를 이용해 먼저 찾습니다. 찾은 후 아래 그림과 같이 변수에 우클릭하면 PopUp에 Breakpoints라는 항목을 찾을 수 있으며 여기를 클릭하면 Data Access Cycle에 대한 설정을 할 수 있게 되는데 Read/Write나 Read 또는 Write중 원하는 조건을 선택하는 것으로 설정을 완료할 수 있습니다.

 

 보통 자주 확인하는 변수의 경우 Watch윈도우에 등록해 놓은 경우가 있습니다. 그런 경우 아래 그림과 같이 Watch윈도우에서 해당 변수를 우클릭하여 동일한 방법으로 BreakPoint를 등록할 수 있습니다.

 

2)    user 영역에 있는 특정 sybmol에 BreakPoint설정하기

역시 Kernel 영역에 있는 변수에 BreakPoint 설정하는 방법과 동일하나 다른 점이 있다면 User 영역에 설정하는 것이므로 해당 Process나 Thread일 때만 Trigger되도록 TASK 항목을 설정하여야 합니다. 아래 예는 vold라는 Process에서 fs_mgr_flags 변수에 값을 쓰거나 읽는 경우 Break Evnet를 발생시키도록 설정한 예입니다. 만약 TASK 항목을 설정하지 않으면 symbol이 가진 address가 Aceess되면 다른 Process라 할지라도 멈추게 됩니다.

 

참고할 점은 상기와 같이 설정한 경우 해당 Address를 어떤 Process나 Thread가 Access했는지 확인하기 위해 CPU를 잠깐 세우게 되는데 이에 따라 약간 느려질 수 있습니다. 즉 Realtime 동작이 아닌 경우가 되며 아래와 같이 TRACE32 상태바에서 갈색으로 S라는 표기를 해주며 개발자로 하여금 현재 상태를 확인할 수 있게 해줍니다.

 

 

     특정 주소나 symbol 의 값이 특정 값일 때

3.2.2와 같이 Kernel이나 User 영역의 특정 symbol에 BreakPoint를 설정하고 아래 그림처럼 Data 필드와 Size 필드를 설정하면 특정 변수에 특정 값이 Access된 경우 Break Trigger Event를 발생시킬 수 있습니다.

CPU core에 따라 Access 데이터 값을 모니터링 hardware가 없는 경우가 많으며, 이런 경우 Write Cycle에서 항상 멈추도록 설정하여 멈추면 해당 변수 값을 TRACE32가 Software적으로 확인하는 방법으로 구현을 하게됩니다. 이의 경우 Realtime 동작이 아닌 경우가 되며 TRACE32 상태바에서 갈색으로 S라는 표시를 해주게 됩니다

 

 

   Program(code) BreakPoint 설정

본장에서는 Linux Kernel이 동작하는 Target 위에서 특정 code에 BreakPoint 설정하는 방법을 학습합니다.

     Kernel의 특정 함수에 BreakPoint 설정하기

Kernel의 특정함수에 BreakPoint설정하는 방법은 특별이 고려할 것 없이 기존에 사용하던 방식으로 설정하면 되겠습니다.

1)    아이콘 중 Symbol() 버튼을 클릭하여 열거나 View 메뉴 >> Symbols >> Browse 항목을 클릭하여 Symbol 윈도우를 엽니다.

2)    Symbol 윈도우에서 설정하고자 하는 함수이름을 찾습니다.

3)    우클릭하여 PopUp 메뉴로부터 아래와 같이 선택하여 BreakPoint를 설정하거나 해당 함수를 더블클릭하여 Data.List를 연 후 해당함수에 더블 클릭하여 BreakPoint를 설정합니다. 설정하고 나면 윈도우 좌측에 갈색 수직바로 BreakPoint가 설정 되어 있음을 표기해 줍니다.

 

 

     특정 process의 Main 함수에 BreakPoint를 설정하여 멈추기

특정 process의 Main함수는 Process가 만들어지고 한번만 실행될 것입니다. 따라서 Main 함수에서 멈추도록 하기 위해서는 해당 Process가 만들어 지는 시점 후 Process Symbol을 로드하고 Main함수에 BreakPoint를 설정하여 실행하면 멈추게 될 것입니다. 이 과정은 상당히 복잡한 과정을 거쳐야 하지만 TRACE32의 Linux Awareness를 사용하게 되면 쉽게 가능합니다.

 

1)    해당 Process가 실행되기 전 Target을 Stop시킨 후 Linux 메뉴 >> Process Debugging >> Debug Process on Main... 을 클릭합니다.

 

2)    1)의 과정을 실행하게 되면 아래 디버깅 Process이름 입력 윈도우가 열립니다. 디버깅을 원하는 Process 이름 입력 후 OK 버튼을 클릭합니다.

 

3)    이후 해당 Process가 실행되면 자동으로 해당 Process의 Main함수에 BreakPoint를 설정해 멈추도록 합니다. 다음 그림은 Main함수에서 멈춘 상태를 보여주고 있으며 TASK.Process윈도우에 보면 현재 Process가 입력했던 Process인 것을 확인할 수 있습니다.

 

 

 

     특정 process의 함수에 BreakPoint 설정하기

Linux Platform에서는 대단히 많은 process들이 로드되어 실행되고 있습니다. 따라서 이 Process들에 대한 모든 symbol을 로드 해놓은 상태에서 디버깅하는 것은 장점보다는 단점들이 더 많은 상태가 될 것입니다.

TRACE32는 기본적으로 필요에 따라 symbol을 로드해 사용하는 정책을 가지며 다음과 같은 순서로 원하는 함수에 BreakPoint를 설정하시기 바랍니다.

1)    다음 그림과 같이 TASK.Process윈도우를 통해 해당 Process symbol을 로드합니다.

 

2)    1)을 실행하고 Symbol 윈도우()를 열고 Up 버튼()을 클릭해 상위로 올라가면 현재 어떤 ELF symbol 들이 로드되었는지 확인할 수 있습니다. 다음은 아래 symbol 윈도우에서 해당 ELF(netd>> )를 클릭해 들어가거나(해당 ELF에 대한 symbol들만 보임),  버튼을 클릭해 들어간 후 다시 한번 클릭하면 로드된 모든 ELF의 symbol들을 보여줍니다.

 

3)    설정하고자 하는 함수를 찾아 더블클릭하여 Data.List윈도우를 열고 원하는 소스라인에 더블클릭하여 BreakPoint를 설정합니다.

 

4)    해당 Process에서만 멈추고자 한다면 아래 그림과 같이 Break.List 창에서 우클릭후 Change를 클릭하

여 TASK 필드를 해당 Process로 설정해 줍니다.

 

 

 

     특정 process 내의 Library 함수에 BreakPoint 설정하기

우리는 필요에 따라 특정 Process에서 로드하여 사용하는 특정 Library의 함수를 디버깅하고자 하는 경우가 있습니다. 다음과 같은 순서로 우리는 쉽게 해당 함수에서 BreakPoint를 설정하여 디버깅 할 수 있습니다.

1)    특정 Process의 Library Symbol을 로드하기 위해 Linux메뉴 >> Display Process... 항목을 클릭(또는 Command line에서 TASK.Process 입력)하여 디버깅하고자 하는 Process를 찾고 더블클릭하여 해당 Process 정보를 엽니다.

 

2)    여러 정보 중 Code File 항목은 해당 Process가 사용하는 Resource들에 대한 정보를 담고 있는 부분으로 디버깅하고자 하는 Library의 파일 이름을 찾습니다. 해당 파일을 찾은 후 우클릭하고 PopUp 메뉴의 Load Library Symbols 항목을 클릭하면 자동으로 해당 Library Symbol을 로드하게 됩니다. 만약 해당 .so 파일을 찾지 못한 경우 File Browse 윈도우가 띄우게 되는데 해당 .so 파일을 찾아 지정하면 되겠습니다.

 

3)    2)를 실행하고 Symbol 윈도우()를 열고 Up 버튼()을 클릭해 상위로 올라가면 현재 어떤 ELF symbol 들이 로드되었는지 확인할 수 있습니다. 다음은 아래 symbol 윈도우에서 해당 ELF(netd >> )를 클릭해 들어가거나(해당 ELF에 대한 symbol들만 보임),  버튼을 클릭해 들어간 후 다시 한번 클릭하면 로드된 모든 ELF의 symbol들을 보여줍니다.

 

4)    Symbol 중 원하는 함수를 찾아 BreakPoint를 설정합니다. 해당 함수를 찾았다면 더블클릭하여그 함수의 Data.List 윈도우를 열고 원하는 소스라인에 더블 클릭하여 BreakPoint를 설정합니다. 설정이 완료 되었으며 Target을 Run하면 해당 함수가 실행될 경우 멈추게 될 것입니다.

 

5)    만약 해당 Process에서만 멈추고자 한다면 아래 그림과 같이 Break.List 창에서 우클릭한 후 Change를

클릭하고 TASK 필드에 해당 Process를 설정해 줍니다.

 

 

 

 

 

 

 

 

 

     특정 kernel module 이 loading 될 때 Init 함수에 BreakPoint 설정하여 멈추기

Module이 로딩될 때 symbol을 올린 후 Init 함수에 BreakPoint를 설정하여 멈추도록 하는 개념을 갖습니다. 이 과정을 수동으로 하는 것은 생각보다 상당히 복잡한 과정을 거쳐야 합니다. 하지만 TRACE32의 Linux Awareness를 사용하게 되면 쉽게 가능합니다.

 

1)    우선 모듈이 로딩되기전 Linux 메뉴 >> Module Debugging >> Debug Module on Init... 항목을 클릭합니다. 클릭하면 우측과 같은 디버깅할 모듈이름 입력 윈도우가 열립니다. 모듈이름을 입력하고 Ok 버튼을 클릭하면 Module이 로딩 될때까지 waiting 합니다.

 

2)    사용자에 의해 Module이 로딩된 후 TRACE32는 로딩된 것을 인식하고 해당 Module의 symbol을 자동으로 로드하게 될 것이며 모듈의 Init함수에 BreakPoint를 설정하고 다시 Run을 시키게 됩니다.

다음 그림은 위의 과정을 통해 해당 모듈의 Init 함수에서 멈춘 상태를 보여주고 있습니다.

 

     user_fault/kernel_fault/panic 등 의도하지 않은 exception 발생 대비 BreakPoint 설정

Linux Kernel은 Data Abort/Prepatch Abort/Undefined Exception을 임의의 용도로 사용하고 있습니다. 따라서 잘못된 코드 동작에 의한 excetption 발생에서 excetpion을 구분하여야 하며 이는 Kernel에서 제공하고 있습니다. 만약 의도하지 않은 Excetption 발생할 경우 특정 코드를 타도록 되어 있습니다.

따라서 의도하지 않은 Exception 발생 시 타는 특정 코드가 Debugging Point가 될 것이며 우리는 이곳에 BreakPoint를 설정하여 Trigger시 이 코드를 보는 작업을 하게 됩니다.

Linux의 경우 TRACE32에서는 좀더 간편한 Exception Debugging을 지원하기 위해 SegV.cmm이라는 파일을 제공하고 있는데 바로 의도하지 않은 Exception발생시 실행되는 코드에 자동으로 BreakPoint를 설정해 주고 BreakPoint Trigger시 자동으로 Exception위치를 추적해 주는 기능을 담당해 줍니다.

ARMv8을 Debugging 시 본기능을 사용하기 위해서는 반드시 iTSP version 3.8.5이상을 추천합니다.

 

1)    Exception 발생이 확인되었다면 system을 다시 시작하고 해당 Exception발생 전 아래 그림과 같이 SegV.cmm을 실행해 주는 ”Segment Violation” 버튼을 클릭하여 의도하지 않은 Exception발생시 실행되는 코드에 BreakPoint를 설정합니다.

SegV.cmm을 실행하면 die()/__do_user_fault()/__do_kernel_fault()/panic() 함수에 BreakPoint를 자동으로 설정하게 됩니다.

 

2)    다음은 Target을 실행시켜 Exception을 재현합니다. Exception이 재현되면 아래와 같이 의도하지 않은 Exeption발생 시 실행되는 Kernel 함수에서 멈추게 됩니다.

 

3)    다음으로는 Exception이 발생한 위치를 확인하기 위해 다시 ”Segment Violation” 버튼()을 클릭합니다. 그러면 아래 그림과 같이 Exeption이 발생했던 위치를 추적해 직전 상태를 보여 줍니다. 아래 원인을 살펴보면  Exception의 원인은 ldr r0,[r12]이며 R12가 가리키는 번지인 0번지(MMU에 Mapping되지 않은)로부터 데이터를 읽어 R0에 옮기는 작업을 진행하다 발생한 것임을 알 수 있습니다.

 

다음은 ARMv8용linux Kernel64에서의 해당 기능을 사용한 예입니다. 어떤 원인에 의해 “Kernel Fault”에서 멈춘 것을 확인할 수 있습니다. 이 상태에서 다시 ”Segment Violation” 버튼()을 클릭하시면

 

다음 그림과 같이 Fault를 발생시킨 코드 위치를 추적하여 찾아 오게 됩니다.

 

 

 

  SYStem Data Access

   CPU register Access

     CPU Register 값 확인하기

CPU Register 창은 TRACE32 Command line에서 Register 명령을 입력하거나 다음 그림과 같이 TRACE32 GUI에서 아이콘을 클릭하여 Register 읽기 창을 열 수 있습니다.

본 CPU Register 값들은 SMP(Symmetric MultiProcessing)의 경우 현재 선택된 Core의 값들을 보여 주게 됩니다. 현재 선택된 Core를 알고자 한다면

 

CORE.SHOWACTIVE

 

명령을 입력하시면 현재 선택된 Core를 쉽게 알수 있도록 보여줍니다. 아래 열린 윈도우에 검은색 상자로 표기된 3번 Core가 현재 선택된 Core 입니다. 또는 TRACE32 PowerView 하단 상태바에 선택된 Core번호를

표시하고 있는 것을 볼 수 있습니다.

 Register창의 맨 좌측 수직으로 나열된 빨간 박스 안의 정보들은 CPSR의 디코딩 정보이며 현재 Mode가 NonSecure mode이며 SVC mode에서 동작하고 있음을 나타내고 있습니다. 또한 각 Mode별 Banked된 Register 값들을 독립적으로 표시하고 있으며 맨 우측 열의 상단 SP-> 아래로 표시된 데이터는 현재 Stack Pointer(R13)가 가리키는 Stack 값들을 보여주고 있습니다.

 

아래 그림은 ARMv8에서 보여주는 예입니다. CORE.SHOWACTIVE 윈도우에서 회색으로 표시된 Coer들은 현재 Power Off mode에 들어가 있는 상태를 의미합니다.

 

     CPU Register 값 변경하기

CPSR의 각 bit field(Flag) 값들은 위 그림과 같이 값 선택 후 마우스 우클릭하면 설정 가능한 인자 값들을 볼 수 있으며 선택하면 해당 값으로 변경됩니다.

나머지 모든 Reigster들은 아래 그림과 같이 변경하고자 하는 Register의 값에 더블클릭하면 변경하는 명령이 TRACE32 Command line에 오게 되며 변경할 값을 써주고 Enter하면 값이 변경됩니다.

또는 TRACE32 Command line에서

 

Register.Set [RegName] [Value]

 

명령을 사용해서도 쉽게 변경 가능합니다. 예를 들면

Register.Set PC 0x1234          ; PC 값을 0x1234로 변경

Register.Set x0 0x1000           ; x0 값을 0x1000으로 변경

 

     SMP 환경에서 디버깅할 Core 선택 변경하기

현재 선택 상태를 보여주는 CORE.SHOWACTIVE 윈도우에서 선택하고자 하는 Core 번호를 클릭하거나 아래 그림과 같이 하단 상태바에서 선택된 Core 표시바에 커서를 옮긴 후 우클릭하면 Core선택 Popup이 나타나며 원하는 Core를 클릭하면 디서깅할 Core가 선택됩니다.

 

 다음 그림은 다른 Core1이 선택된 상태를 보여주고 있습니다.

 

또는 Command line에서

 

CORE.select [Core Number]

 

명령을 통해서도 가능합니다. 일예로

CORE.select 4.             ; 4번 core 선택

 

 

 

   TASK(Process/Thread) list 확인

우리는 대부분 OS포함하는 개발환경을 갖습니다. TRACE32에서 제공하는 OS awareness를 적용하게 되면 해당 OS에 대한 정보를 쉽게 확인할 수 있도록 해 줍니다.

본 장에서는 Linux의 Task List 윈도우에 대해 간단히 확인하도록 하겠습니다. Linux Awareness를 적용하고 나면 메뉴에 Linux 항목이 추가되며 여기를 클릭하면 Linux DB 정보들을 확인할 수 있는 여러 항목들을 볼 수 있습니다. “Display Process”(TASK.Process)와 “Display Tasks”(TASK.DTask) 항목을 클릭하면 현재 사태의 각 Process 및 Thread들에 대한 정보를 확인할 수 있습니다.

 

TASK.Process         

: Process별로 Sorting해서 보여 주며 Process의 상태 정보 및 그 Process에 할당된 MMU Space ID 값 그리고 Process에서 생성된 Thared 수와 그 Thread들의 PID 값을 요약해 보여 줍니다. 현재 실행되고 있는 Process/Thread(state에 Current로 표시됨) 정보와 해당 Process/Thread를 실행하고 있는 CPU core 번호를 확인할 수 있습니다. 이는 다음과 같이 표시해 줍니다.

State에 Current(N)                      ; N은 현재 Process/Thread를 실행하고 있는 Core번호

TASK.DTask           

: Tread별 Sorting 정보를 보여 SMP환경에서는 해당 Thread를 실행하는 CPU core 번호를 cpu 열에 보여 줍니다.

 

 

아래 그림은 각 Process의 ”Space ID”에 대한 정보를 표시하고 있습니다. 새로운 Process가 생성될 때 32bit Kernel의 경우 새로운 4GB의 Virtual Space가 할당되게 되는데 보통 32bit CPU는 최대 4GB Addressing 공간을 관리할 수 있으므로 여러 4GB 영역들에 대한 관리를 할 수 없게 됩니다. 따라서 Process마다 할당된 4GB 영역들에 대한 관리를 위해 각 Process의 4GB 영역에 ”Space ID”라고하는 것을 부여해 Logical하게 관리하게 되는데 이것을 TRACE32에서는 ”Space ID”라고 칭하고 있습니다.

아래 그림 중 ”Data.List” 창에 8자리 Address 앞에 4자리의 어드레스가 더 있는 것을 확인 할 수 있습니다. 바로 이 4자리 Address가 ”Space ID”이며 ”TASK.Process” 윈도우에서 보여주는 Process의 ”Space ID”와 일치하는 것을 볼 수 있습니다.

그림 중 Current(0)라는 상태을 보여주고 있는데 이는 해당 Process의 state 정보를 보여주는 것으로 해당Process가 현재 실행 중인 Process이며 SMP CPU core들 중 Core 0가 해당 Process를 실행하고 있음을 알려 줍니다.

”TASK.Process” 윈도우나 ”TASK.Dtask” 윈도우에서 Process나 Thread 이름을 더블클릭하면 해당 Process나 Thread의 속성 정보를 보여줍니다. 실행되고 있는 Address와 점유하고 있는 메모리 크기, Open한 파일 들 그리고 사용 중인 Library정보와 같은 다양한 현재 상태 정보를 확인할 수 있습니다.

 

 

   Memory Access

TRACE32 debugger는 기본적으로 CPU core를 통해 BUS의 Resource를 Access하기 때문에 CPU core가 현재 접근 가능한 Address 공간만을 Access하여 정보를 보여줍니다. 따라서 개발자로 하여금 CPU core가 현재 접근 가능한 Address 공간이 어디인지 알 수 있게 해줍니다.

그러나 경우에 따라서 개발자는 CPU의 현재 상태에서 접근 불가능한 영역의 데이터를 확인하고자 하는 경우가 있습니다. 예를 들어 현재 MMU에 Mapping되지 않은 Physical Address의 데이터를 확인하고자 하는 경우나 현재 Cache 내용이 적용되기 전인 Physical Address의 데이터를 확인하고자 하는 경우가 바로 그런 경우입니다. 따라서 현재 상태에서 CPU가 접근 불가능한 영역의 값을 임의로 확인하고자 하는 경우 TRACE32가 특별한 동작을 통해 해당 영역의 데이터를 접근할 수 있도록 하는 지정자가 필요하게 되는데 그것이 바로 “Memory Class”라고 하는 것이며 Address 공간에 속성을 두어 구분자 역할을 하도록 하는 것입니다. “Memory Class”를 지정하지 않고 Address만을 지정하면 현재 CPU 상태를 기준으로 해당 Address를 접근하여 보여주게 됨을 염두하시기 바랍니다.

아래 그림과 같이 TRACE32는 기본적으로 “Memory Class”를 주지않고 Address만을 지정할 경우 현재 CPU 상태를 기반으로 적근하여 읽은 후 “Memory Class”를 보여 줍니다. 아래의 경우 현제 CPU상태는 Secure/Supervisor 상태임을 의미합니다.

 

 

     TRACE32에서 Memory Class

Memory Class는 CPU core Architecture에 따라 다르며 설치폴더\PDF\debugger_corename.pdf 를 참조하면 확인할 수 있습니다. 여기서는 ARMv7과 ARMv8(X, SPR은 ARMv8에만 유효)에 대한 ”Memory Class”를 살펴 봅니다.

위에 언급되지 않은 NC/AHB/AXI/APB 등 몇가지 추가 “Memory Class”는 아래 순서을 참고하시기 바랍니다.

 

 

 

기술지원 요청은

TRACE32@hancommds.com 이나

031) 627-3119로 연락하시기 바랍니다.

 

 

 

 

감사합니다