Accessing System Data
목차
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 윈도우에서 회색으로 표시된 Core들은 현재 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”는 아래 순서을 참고하시기 바랍니다.
Memory 또는 Memory mappled I/O 값 Access하기
1) Virtual Address 를 알 때
Virual Memory Address를 알고 있을 때 다음과 같이”Data.dump” 명령을 사용해 쉽게 값을 읽거나 쓸 수 있습니다.
Data.dump [Address] : 정의된 address의 값들을 읽어 보여 줍니다.
Ex) Data.dump 0xB6FE2000
명령을 실행하면 기본적으로 현재 CPU core 상태에 대한 메모리 속성을 그대로 가져와 보여 주게 됩니다. 아래 그림에서 살펴보면 현재 Process “Space ID”는 0x0A2A이며 현재 CPU core 상태는 ZU입니다. 따라서 위명령을 사용하게되면 “Data.dump ZUD:0x0A2A:0xB6FE2000”으로 치환하여 현재 상태에서 Access 가능한 메모리 값을 읽어 보여주게 됩니다.
반대로 해당 메모리값을 변경하고자 한다면, 메모리 윈도우에서 해당 번지의 값에 더블클릭하면 메모리 값 변경 명령이 Command line에 내려오게 되는데 변경하고자 하는 값을 적은 후 Enter하면 값을 변경할 수 있습니다. 또는 아래와 같이 Command line에서 직접
Data.Set [Address] %[Long|Word|Byte] [Value]
Ex) Data.Set 0xB6FE2000 %Long 0x12345678 ; 0xB6FE2000에 32bit width로0x1234567값 쓰기
명령을 입력하면 해당번지의 값을 원하는 값으로 변경할 수 있습니다.
Address지정 시 Memory Class를 지정하지 않으면 기본적으로 현재 CPU core 상태에 대한 메모리 속성을 그대로 가져와 보여 주게 됩니다.
2) physical Address를 알 때
Physical Address를 알고 있을 때는 “Memory Class” A:를 사용합니다. 여기서 고려할 것은 현재 Cache 내용이 적용된 Physical Address의 값을 확인하고자 하는 경우가 있을 것이며 Cache내용이 적용되지 않은 Physical Address의 값을 확인하고자 하는 경우가 있을 것입니다.
Data.dump ASD:[PhysicalAddress] : Cache내용을 적용한 후 Physical Address 값을 보여줌
Data.dump ANC:[PhysicalAddress] : Cache내용을 적용하지 않고 Physical Address 값을 보여줌
여기선 “NC” Non Cached를 의미합니다.
아래 그림은 실제 예를 보여주고 있습니다. AZNC: 의 값은 순수하게 Cache 내용이 적용되기 전 Physical Address내용을 보여 주고 있으며 AZSD: 의 값은 Cache내용이 적용된 후의 Physical Address의 값을 보여 주고 있습니다.
따라서 AZSD: Class로 특정 메모리 값을 연후 AZNC: Class로 해당 메모리 값을 열면 Cache내용이 적용된 후 이므로 같은 값을 보여 주게되니 항상 AZNC: Class로 먼저 확인 후 AZSD:로 열어 확인하기 바랍니다.
만약 AZNC: class의 특정 Address에 특정 값을 32bit BUS width로 쓰고자 한다면
Data.Set AZNC:[Address] %[Long|Word|Byte] [Value]
Ex) Data.Set AZNC: 0x406D1ED0 %Long 0x7654321 ;NC Physical Address 0x406D1ED0에 0x7654321 쓰기
3) DAP의 AXI/AHB Master를 통한 physical Address Access
ARM SoC설계시 Debug Component중 DAP(Debug Access Port)을 설계할 경우 설계자가 DAP내에 AXI 또는 AHB master와 같은 MEM-AP(Memory Access Port)를 설계한 경우 TRACE32 Debugger는 CPU를 통하지 않고 내장된 BUS master를 통해 바로(직접) System BUS에 Access할 수 있습니다.
아래 Block Diagram은 DAP의 Memory Access Port 연결도를 보여 주고 있습니다. DAP은 최대 256 개의 MEM-AP를 가질 수 있으며 보통은 3~5개 정도를 설계하고 있습니다. 경우에 따라 AXI/AHB Access Port를 둘다 설계하는 경우도 있으며 CPU Core를 통하지 않고 DAP 내 MEM-AP인 AXI-AP또는 AHB-AP를 통해 System BUS를 Access하고자 하는 경우 사용하게 됩니다. 따라서 여러 개의 MEM-AP 중 어떤 MEM-AP를 통해 System BUS에 Access할것인지에 대한 설정이 필요하며 이의 구분을 위해 “Memory Class”라는 것을 두어 속성을 정의하게 되었습니다.
ZAXI:[address] : Secure 권한(Z)으로 AXI-AP를 통해 해당 BUS를 Access함
NAXI:[addresss] : Non-Secure 권한(N)으로 AXI-AP를 통해 해당 BUS를 Access함
ZAHB:[address] : Secure 권한(Z)으로 AHB-AP를 통해 해당 BUS를 Access함
NAHB:[address] : Non-Secure 권한(N)으로 AHB-AP를 통해 해당 BUS를 Access함
예를 들면 만약 CPU core를 통하지 않고 DAP에 내장된 AHB-AP를 통해 0x2020000 번지의 값을 읽어 확인하고 싶다면 아래와 같이 Access 할 수 있습니다.
Data.dump ZAHB:0x2020000 ; Scure권한으로 AHB-AP를 통해 0x2020000번지 읽기
아래 그림은 CPU core를 통하지 않고 DAP내의 AHB-AP를 통해 바로 0x2020000번지의 메모리 값을 Secure권한으로 읽어 낸 예입니다.
만약 AHB-AP나 AXI-AP를 통해 특정 번지에 특정 값을 쓰고자 한다면
Data.Set AXI:[Address] %[Long|Word|Byte] [Value]
Data.Set AHB:[Address] %[Long|Word|Byte] [Value]
Ex) Data.Set ZAHB: 0x406D1ED0 %Long 0x7654321
: Secure 권한으로 Access하되 AHB를 통해 0x406D1ED0번지에 32bit Bus size로 0x7654321 쓰기
그러나 DAP이 가질 수 있는 MEM-AP의 개수가 최대 256개다 보니DAP의 어느AP를 통해 Access할 것인지 그리고 그 AP의 Port 번호는 몇인지 TRACE32에게 알려줄 필요가 있겠습니다. 다음 그림은 이에 대한 설정 윈도우를 보여주고 있습니다. CPU 메뉴 >> SYStem Setting…. 클릭 후 SYStem 윈도우가 열리면 “CONFIG” 버튼을 클릭하고 우측과 같이 “SYStem.CONFIG” 윈도우가 열리면 DAP 탭을 선택하여 MEM-AP 에 대한 설정을 하시면 되겠습니다. 아래 설정의 경우 AHB-AP는 0번 포트를, AXI-AP는 5번 포트를, Debugging을 위한 Debug Component들이 위치한 APB-AP는 1번 포트를 사용하도록 설정하고 있습니다. 이는 해당 SoC의 AP설계 정보를 TRACE32에게 알려주는 역할을 하게 됩니다.
만약 Memory Class를 ZAXI:0x2020000으로 정의하여 Access하게 되며5번 포트인 AXI-AP를 통해 BUS에 Access하는 동작을 하게 됩니다.
Target 을 멈추지 않고 Runtime 중 physical address 데이터 Access 하기
4.3.2에서 언급한 것처럼 DAP 설계 시 System BUS Access를 위한 AHB-AP 또는 AXI-AP를 설계한 경우 CPU를 통하지 않고 System Bus에 Access할 수 있으므로 CPU core가 Runing 중에도 데이터를 Access할 수 있습니다.
이러한 동작을 위해서는 4.3.2에서도 언급한 것처럼 System BUS에 엑세스 할 수 있는 MEM-AP가 여러 개 있을 수 있으므로 어느 MEM-AP를 통해 읽어 보여줄 것인지에 대한 설정이 필요하게 되며 ”Memory Class”에서 학습했던 E: class를 사용하게 되면 Runtime중 원하는 메모리 값을 Access할 수 있게 됩니다.
다음 그림은 그 것에 대한 설정으로 CPU 메뉴 >> System Setting... 항목을 클릭하면 Sysem 윈도우가 열리며
1) MemAccess 항목을 DAP으로 설정
: ”Memory Class” E: 사용 시 System Running 중 Memory Access DAP으로 허용
2) CONFIG 윈도우의 MEMORYACCESSPORT를 사용할 MEM-AP로 설정
순서로 설정합니다. 아래와 같이설정하게 되면 MEM-AP 0, 즉 AHB-AP를 통해 System Memory Access를 통해 데이터를 읽어 보여주게 됩니다. MEM-AP를 통하므로 Virtual이 아닌 Physical Address로만 가능합니다.
위와 같이 설정하면 아래 그림과 같이 E: class를 통해 Target이 Run상태라 할 지라도 Access하고자 하는 Address 값을 Runtime 중 확인할 수 있게 됩니다. MEM-AP를 사용하므로 Addressing Mode는 Physical Address만 가능합니다. 따라서
Data.dump EA:[Address] : Runtime중 Physical Address 값 dump 명령
Ex) Data.dump EA:0x43EB74D0
Data.dump EA:[Address] %[Long|Word|Byte] : Runtime중 Physical Address 값 변경 명령
Ex) Data.dump EA:0x43EB74D0 %Word 0x1234 : Runtime중 해당 번지에 0x1234를 쓰는 명령
와 같이 사용하면 되겠습니다.
참고로 System BUS Access를 위한 MEM-AP를 설계하였다 하더라도 Clock gating과 같은 Control을 통해 해당 AP가 정상 동작할 수 없는 상태인 경우에는 당연히 Runtime중 Access가 불가하므로 Clock설정 등과 같은 Hardware설정에 유의하여야 합니다.
Assembly Code 변경
어떤 경우는 실행 중 Code영역에 있는 Assembly code를 임의로 변경하여 실행하고자 하는 경우가 있습니다. 이럴 경우 Data.List 윈도우 안에서 변경하고자 하는 Address에 우클릭하면 PopUp 메뉴에 ”Assemble Here”라는 항목이 있는데 이를 클릭하여 해당 Address에 Assembly code를 변경할 수 있습니다. 클릭하면 해당 Address의 Assembly Code를 변경하는 명령이 내려 오게되며 여기에 원하는 명령을 기술한 후 Enter하면 동작이 완료되겠습니다.
해당 기능은 당연히 Read/Write 가능한 RAM 공간에서만 가능합니다.
아래 그림은 변경하고자 하는 명령어 기술과 해당 명령어를 실행 한 후 Data.List창에 변경된 결과를 보여 주고 있습니다.
Coprocessor register Access
Coprocessor의 경우 일반적으로 MMU/CACHE/PMU 관련 CP15와 Debug Resource를 담고 있는 CP14가 있습니다. 이들 데이터 역시 많은 수의 데이터를 가지고 있으므로 Debugger입장에서는 Memory와 같이 Address를 부여해 관리하는 것이 편하며 역시 사용자 측면에서도 구분하기 편하도록 할 수 있습니다.
ARMv7 Coprocessor Register Addressing rule
1) Coprocessor 14
Cortex-A/R Series의 경우 CP14에는 Debug Control Register들이 위치해 있습니다. TRACE32에서 이들 CP14의 Coprocessor Reigster들의 Access를 위한 Memory Class는 C14이며 Access를 위한 Address는 DAP APB를 통한 Debug Register Base Address로부터 Offset/4 입니다.
예를 들면,
Debug Register Base Address가 0x80010000번지 이고
LAR(Lock Access Register)이라는 Register는 Offset이 0xFB0 입니다.
TRACE32에서 Access하기 위한 LAR의 Memory Class와 Address는
C14:0x03EC
입니다.
2) Coprocessor 15
Cortex-A/R에서 CP15 접근을 위한 Memory Class는 C15입니다. CP15 Register Access를 위한 ARM 명령은
32bit access의 경우
<MCR|MRC> p15, <op1>, Rd, CRn, CRm, <op2>
입니다. TRACE32에서 Addressing Rule은
BIT0-3:CRn, BIT4-7:CRm, BIT8-10:<op2>, BIT12-14:<op1>, Bit16=0
입니다. 만약 Coprocessor Access 명령이
MCR|MRC p15, 0, R7, C9, C4, 1
라면 이 CP15 Register Access를 위한 TRACE32 Memory Class와 Address는
C15:0x0149
가 됩니다.
64bit access의 경우 ARM 명령은
<MCRR|MRRC> p15, <op1>, <Rd1>, <Rd2>, <CRm>
이며 Addressing Rule은
BIT0-3: -, BIT4-7:CRm, BIT8-10: -, BIT12-14:<op1>, Bit16=1
입니다. 만약 Coprocessor Access 명령이
MCRR|MRRC p15, 1, R7, R6, C15
라면 이 CP15 Register Access를 위한 TRACE32 Memory Class와 Address는
C15:0x110F0
입니다.
ARMv8 System Register Addressing rule
ARMv8의 경우에는 Coprocessor라는 개념이 없어지고 모두 System Register라는 개념으로 통합되었으며 해당 System Register의 Access는 MRS/MSR/SYS 명령으로 통하여 하도록 되었습니다. ARMv8 TRM에서 System Register들을 보면 Access 방법과 MRS/MSR 명령에 대하여 아래와 같이 기술하고 있습니다.
엄밀히 말하면 SCTRL_EL1 read 명령은 ”MRS <Xt> #3, #0, c1, c0, #0”입니다. 우리가 보다 잘 이해할 수 있도록 ”#3, #0, c1, c0, #0”를 SCTLR_EL1으로 바꾼 것입니다.
System Register Addressing Rule
아래는 VBAR_EL3라는 System Register Address를 Decoding하는 방법을 기술하고 있습니다.
ARMv7 Coprocessor register 값 확인하기
1) 메뉴의 Peripheral Browser를 이용해 확인하기
Coprocessor Register 값은 우선 SYStem.CPU 항목을 설정하고 나면 아래 그림과 같이 설정한 CPU에 해당하는 메뉴가 추가로 생성됩니다. 메뉴 클릭 후 확인하고자 하는 Coprocessor Register 항목을 선택하면 데이터를 확인할 수 있습니다.
버전에 따라 설치한 폴더에 해당 CPU 정보파일이 없는 경우 메뉴가 추가되지 않을 수 있니 없는 경우는 trace32@hancommds.com에 연락처/부서명/사용CPU명 기입 후 요청하여 받으시기 바랍니다.
2) 메모리 Dump명령을 이용해 확인하기
메모리 열기 아이콘을 클릭하여 확인하고자 하는 Coprocessor의 Address와 Memory Class를 넣어 메모리 Dump윈도우를 열거나 TRACE32 Command line에서 Data.Dump 명령을 이용하여 메모리창을 열어 확인합니다. 만약 Coprocessor Addressing rule에 따라 확인하고자 하는 Coprocessor의 Address와 Memory Class가 C15:0x0001인 SCTLR이라면
Data.DUMP C15:0x0001
명령으로 해당 Register를 메모리 Dump창으로 열어 확인할 수 있습니다. 결과는 다음과 같습니다.
3) CMM Script에서 특정 Coprocessor의 현재 값 얻어 내기
CMM Script에서 특정 Address로부터 Data를 Read하는 함수는 Data.Long()입니다. 따라서
만약 SCTLR의 Address C15:0x0001으로부터 데이터를 읽고자 한다면
Local &Result
&Result= Data.Long(C15:0x0001)
Print &Result ; 읽은 값을 AREA창에 뿌려줍니다.
형식으로 읽어 낼 수 있습니다.
Coprocessor register에 값 쓰기
1) Perpheral Browser와 메모리 Dump창을 이용한 값 쓰기
아래 그림과 같이 변경하고자 하는 Coprocessor Register값에 더블클릭하거나 메모리 창에서 더블클릭하면 값을 변경할 명령이 TRACE32 Command line에 자동으로 표기되고 변경할 값을 입력하고 Enter하면 값이 변경됩니다. Peripheral Browser를 이용할 경우 아래 그림과 같이 특정 bit field를 선택 후 우클릭하면 변경할 수 있는 Popup이 뜨는데 원하는 값을 선택해도 값이 변경됩니다.
2) TRACE32 Command line을 이용해 바로 값 쓰기
Coprocessor Register 값 쓰기 명령은
Data.Set [C15|C14]:[Address] %Long [Value]
나
PER.Set [C15|C14]:[Address] %Long [Value]
Ex) Data.Set C15:0x0001 %Long 0x00C51078
: C15:0x0001 어드레스를 갖는 SCTLR의 값을 0x00C51078로 변경
하면 임의로 값을 변경할 수 있습니다.
ARMv8 System Register에 값 확인하기
1) Peripheral Browser를 이용하여 값 확인하기
확인하는 방법은 역시 Perpheral Browser와 메모리 Dump창을 이용해 가능합니다. SYStem 윈도우에 디버깅할 CPU 이름을 선택하고 나면 해당 CPU에 해당하는 Menu가 구성되며 클릭하면 System Register의 Peripheral Browse가 열리게 됩니다.
만약 Virtualization관련 System Register들을 보고자 한다면 해당 항목을 클릭하면 해당 System Register 들의 값을 보여줄 것입니다. Scroll 해보면 위 그림에서 보이는 모든 항목들이 보이는 것을 확인 할 수 있습니다.
버전에 따라 설치한 폴더에 해당 CPU 정보파일이 없는 경우 메뉴가 추가되지 않을 수 있니 없는 경우는 trace32@hancommds.com에 연락처/부서명/사용CPU명 기입 후 요청하여 받으시기 바랍니다.
2) 메모리 Dump명령을 이용해 확인하기
Data.dump SPR:0xAddress
Ex) Data.dump SPR:0x36C00 ; Addressing Rule에 따라 VBAR_EL3 의 Dump창 열기
ARMv8 System Register의 값 변경하기
아래 그림과 같이 Peripheral Browser나 메모리 Dump창으로부터 변경하고자 하는 System Register값에 더블클릭하면 해당 값을 변경할 수 있는 명령이 Command Line에 자동으로 내려오며 변경 값을 써넣은 후 Enter하면 값이 변경됩니다.
call stack 확인하기
코드 실행 후 우리는 자주 Stack Data를 확인하게 됩니다. Call Stack 윈도우는 아이콘 중 Stack()을 버튼을 클릭하거나 View 메뉴 >> Stack Frame with Locals 항목을 선택하면 해당 윈도우를 열수 있습니다.
Call path 및 지역변수 보기
Stack 윈도우는 아래 그림과 같이 Caller 확인 부분(Up/Down), 확인 정보 선택부분(Args, Locals, Caller) TASK 선택 부분, 정보확인 부분으로 나뉩니다.
Up |
한 단계 위의 Call 상태를 보여 줌. |
Down |
한 단계 아래의 Call 상태를 보여 줌 |
Args |
함수 Call 시 Argument 값 보여 줌 |
Locals |
다음 함수 Call 전 가지고 있던 지역변수 값 보여줌 |
Caller |
다음 함수 Call한 소스코드 위치 정보 |
TASK |
Kernel이 위치해 있는 물리메모리 영역(Low Memory Range) 지정 |
아래 그림은 Up/Down 버튼을 클릭해 특정 Call 단계에서의 Stack을 보여주고 있습니다. 맨 좌측 번호는 Call 단계를 의미하며 현재 3이므로 최종 Stack이 아님을 확인할 수 있습니다. 만약 최종 Stack 정보를 확인하고자 한다면 Down버튼을 눌러 0인 지점까지 옮겨가면 되겠습니다. 단계를 옮길때마다 그 Call 상태의 Regitser값들을 Register윈도우에서 확인할 수 있습니다.
Call 단계가 최종이 아닌 경우 Data.List윈도우의 PC Bar가 붉은 빛을 띈 회색 Bar임을 확인할 수 있으니 정보 파악에 고려하기 바랍니다. 최종 단계의(현재) PC Bar는 항상 회색입니다.
Args 체크 박스를 체크하면 함수 Call 시 전달된 인자 값들을 보여줍니다.
또한 Locals을 체크하면 해당 함수에서 다음 함수 Call되기 전 지역변수 값들을 보여주며 Caller를 체크하게 되면 다음함수 Call하는 소스라인 위치도 함께 표시해 줍니다.
다른 Process나 Thread Stack 정보 확인하기
만약 현재 Process나 Thread의 Call Stack이 아닌 다른 Process의 최종 Stack 정보를 확인하고 싶다면 Stack 윈도우의 TASK 항목을 선택하여 보고자하는 Process나 Thread를 선택하면 선택된 TASK의 Stack 정보를 확인할 수 있으며 역시 Up/Down 버튼을 이용해 Call 단계를 변경하여 정보를 확인할 수 있습니다.
watch window 활용
watch 윈도우는 Var 메뉴 >> Watch… 항목을 클릭해서 열거나 아이콘 중 Watch 아이콘()을 클릭해 서 열 수 있습니다. 이 윈도우는 디버깅 중 항상 모니터링하고자 하는 변수들을 등록해 놓은 후 항상 확인하고자 할 때 사용합니다.
: 변수 이름을 입력하여, Var.Watch창에 추가합니다
: 변수 이름을 찾아, Var.Watch창에 추가합니다
: 변수 이름을 찾아, 별도의 Var.View 창을 엽니다
: 등록된 변수를 모두 지웁니다
Watch 윈도우에 변수등록 및 제거 방법
1) Watch 윈도우에 변수 등록하는 법
- 등록하고자 하는 변수 이름을 에 입력하고 “엔터"키를 누릅니다
- 변수 이름이 길 경우, 에디터에서 “복사 후 붙여 넣기”를 하면 편리합니다
- 버튼을 누르고, 원하는 변수 이름을 입력합니다
- Data.List 창이나 sYmbol.Browse 창에서 원하는 변수를 우클릭한 후, “Add to Watch Window”를 선택합니다
2) Watch 윈도우에서 변수 제거하는 법
- 지우고자 하는 변수를 선택하고 “Delete”키를 누릅니다
- 변수를 선택하고 “우측 마우스 클릭 >> Remove” 합니다
- 모든 변수를 지우고자 할 때는 를 누릅니다
변수 우클릭 후 확장기능 사용
- 배열/구조체의 “+/-” 마크를 눌러 트리 구조로 볼 수 있습니다
- Go Till >> ReadWrite… : 변수에 접근하는 코드가 수행될 때 까지 타깃을 러닝 합니다
- Breakpoint… : 해당 변수에 Breakpoint를 설정할 수 있습니다
- Other >> View Graphical : 배열을 그래프로 표현합니다
- Other >> LOG to AREA : 변수 값을 모니터링 하여 AREA창에 출력합니다
변수 값 다양한 형태로 보기 및 값 변경하기
1) 변수 값 다양한 형태로 보기
변수선택 후 “우측마우스 클릭 à Format…” 을 선택하여 다른 형태로 포맷을 변경할 수 있습니다
- Decimal/Hex/BINary : 진수를 지정합니다
- String : 포인터를 문자열로 보여줍니다
- Recursive : 포인터 단계를 설정합니다
- Index : 배열 원소의 번호를 표시합니다
- Type : 변수타입(int 등)을 보여줍니다
- Location : 어드레스를 보여줍니다
- E : 실시간으로 값을 모니터링 합니다
- SpotLight : 값이 바뀌면 표시해 줍니다
2) 변수 값을 변경하기
Watch 윈도우에서 변경하고자 하는 값에 더
블 클릭하면 값 변경 명령이 Command line에
내려옵니다. 변경할 값을 입력 하고 엔터하면
값이 변경됩니다.
Peripheral IP 의 SFR data 보기 (SOC peri 정보 활용)
Peripheral IP의 SFR값을 보는 방법은 간단히 메모리 윈도우를 통해 보는 방법과 Peripheral 정보를 미리 기술해 decoding된 값으로 보는 두가지 정도로 설명드릴 수 있습니다.
Memory Windows를 열어 보는 방법
View 메뉴 >> Dump... 항목을 클릭하거나 아이콘 중 Memory Dump 아이콘()을 클릭하여 해당어드레스 값을 열어 확인합니다. I/O의 경우 Non Cacheable 속성을 가지므로 “Memory Class”는 ASD: ANC: 동일한 값을 가지므로 A: class를 사용하면 되겠습니다. “Memory Class”에 대한 좀더 자세한 사항을 알고자 할 경우 4.3.1 Memor Class를 참조하기 바랍니다.
다른 한가지 방법은 SoC 설계시 DAP에 AHB-AP나 AXI-AP를 설계한 경우 CPU core를 통하지 않고 해당 BUS master를 이용해 직접 Access할 수 있습니다. Data.Dump 윈도우의 Address 필드에
AHB:[Address] 또는 AXI:[Address]
형태로 기술할 경우 해당 DAP의 MEM-AP를 통해 데이터를 읽어 보여 줍니다. 자세한 사항은 4.3.2를 참조하기 바랍니다.
Command line에서 직접 입력해 확인하고자 한다면
Data.Dump A:[Address]
Data.Dump AHB:[Address] or Data.Dump AXI:[Address]
Ex) Data.Dump A:0x11400000, Data.Dump AHB:0x11400000, Data.Dump AXI:0x11400000
명령을 사용하여 윈도우를 확인할 수 있습니다.
Perpheral Browser를 열어 보는 방법
Peripheral SFR 정보를 TRACE32에서 기준으로 하는 Format대로 기술하면 Peripheral Browser라고 하는 UI 형태로 decoding된 SFR 값을 아래와 같이 볼 수 있으며 값들도 임의로 변경할 수 있습니다. 그러나 편리한 대신 SoC내의 Peripheral IP의 SFR에 대한 기술이 선행 되어야 합니다.
아래 그림은 SoC IP의 SFR을 UI 형태로 보기 위해 기술한 TRACE32 Peripheral Browser 파일 예입니다. 복잡하지 않으며 관련 자료는 C:\T32\pdf\per_prog.pdf를 참조하시고
ftp://ftp.trace32.com/Education/1.T32_Intermediate_Level/AdvancedEduData.zip에서 파일을 받은 후 Unpzip하면 .\AdvancedEduData\AdvancedEdu\Per 폴더에 예제가 있으니 필요한 경우 기술하여 사용하기 바랍니다. 아래 그림과 같이
Per.Program <fileName.per> ; .per 파일 편집기를 여는 명령
명령을 통해 editor를 열면 파일 수정과 Compile버튼을 눌러 문법체크를 할 수 있습니다. 또한 만들어진 .per 파일을 UI 형태로 보는 명령
Per <FileName.per> ; .per파일을 UI로 변경하여 보는 명령
을 통해 위와 같이 decoding된 값으로 볼 수 있습니다.
MMU page table 정보 확인
MMU Table 확인 명령은 MMU.List 입니다. 일반적으로 Linux Awareness가 적용되지 않은 경우는
MMU.List.PageTable <Address> ; Address는 보고자하는 Virtual Address
명령을 사용합니다. MMU.List.PageTable 명령은 Current MMU translation Table의 table decoding 정보를 보여 줍니다. 따라서 해당 명령을 이용하면 Linux Awareness와 상관 없이 Kernel 및 Current Process table을 볼 수 있습니다.
만약 Linux Awareness가 적용된 경우라면
MMU.List.KernelPageTable ; 32bit Kernel(ARMv7, ARMv8 AArch32)인 경우만 사용가능
이나
MMU.List.TaskPageTable “Process name” ; 32bit/64bit Kernel에서 모두 사용가능
을 사용합니다. 자세한 사항은 다음 아래 항목들을 참고하시기 바랍니다.
kernel 영역 MMU Table 확인
Kernel 영역의 MMU Table 확인 명령은
MMU.List.PageTable 0xC0000000 ; 현재 상태에서의 Virtual 0xC0000000에 해당하는 MMU table
MMU.List.PageTable 0xFFFFFFC000000000 ; 64bit Kernel이라면
만약 Linux Awareness가 적용되어 있고 32bit Kernel이라면(64bit Kernel은 MMU.List.PageTable 명령 사용)
MMU.List.KernelPageTable
명령을 사용해도 Kernel Page Table을 확인할 수 있습니다. 다음은 Kernel의 MMU Table을 보이고 있습니다.
현재의 Kernel/User Space 전영역의 MMU Table확인 명령은
MMU.List.PageTable
입니다. MMU.List.PageTable은 Default로 Virtual Address가 0x0이므로 Kernel/User Space의 전 영역을 보여줍니다. 아래 그림은 MMU.List.PT에 의한 현재 TTBRx가 가리키는 Current MMU Table을 보이고 있습니다. 즉 User Space는 현재 TTBR0가 가리키는 Table을 보입니다.
1) 32bit Kernel(ARMv7/ARMv8 AArch32)
2) 64bit Kernel(ARMv8 AArch64)
특정 process MMU Table 확인
특정 Process의 MMU Table 확인 명령은
MMU.List.TaskPageTable [Magic No.|”ProcessName”]
입니다. 이 명령은 Linux Awareness가 적용된 경우만 사용 가능하며 32bit/64bit Kernel에서 모두 사용 가능합니다. 해당 Process의 MMU Table을 열기 위해서는 그 Process의 Magic Number나 이름을 알고 있어야 합니다.
1) 우선 Task.Process를 열고 확인하고자 하는 Process의 이름이나 Magic Number를 확인합니다.
2) 확인된 정보와 MMU.List.TaskPageTable 명령을 사용해 Table을 엽니다.
아래 그림은 ”adbd” Process의 Page Table을 열어 보여주는 예제이며 역시 Magic Number이용해 열어도 동일한 정보가 열리는 것을 확인할 수 있습니다.
32bit Kernel Example)
64bit Kernel Example)
참고로 MMU.List.PageTable 명령을 통해 현재 실행 중인 Process가 아닌 다른 특정 Process의 MMU Table을 보는 것은 해당 Process의 MMU Table의 Base Address를 알고 있지 않는 한 불가 합니다. 왜냐하면 MMU.List.PT 명령은 현재 TTBRx의 내용을 기준으로 Decoding하기 때문입니다.
ARMv7, ARMv8-AArch32 Secure/NonSecure/HyperVisor/Virtualization PageTable
TRACE32 Command Line에서 MMU.List. 를 입력하면 각 Mode에 대한 PageTable을 볼 수 있는 하위 명령들을 Soft Key 버튼으로 보여 줍니다.
1) ARMv7, ARMv8-AArch32 Mode별 Page Table확인 명령
- MMU.List.NonSecurePageTable : TTBR0/1(Non-sec)을 사용한 변환테이블
- MMU.List.SecurePageTable : TTBR0/1(Sec)을 사용한 주소 변환을 보여줍니다
- MMU.List.IntermediatePageTable : VTTBR을 사용한 주소 변환을 보여줍니다
- MMU.List.HypervisorPageTable : HTTBR을 사용한 주소 변환을 보여줍니다
아래 그림은 원활한 이해를 돕기 위해 Address Translation과 TRACE32명령을 도식화한 것입니다.
만약 Virtulization을 위해 Stage 2 Translation을 사용하는 경우 Stage 2 MMU Table을 보고 싶은 경우
MMU.List.IntermediatePageTable
명령을 사용하면 됩니다.
ARMv8-AArch64 EL1/EL2/EL3/Virtualization PageTable 확인하기
TRACE32 Command Line에서 MMU.List. 를 입력하면 각 Mode에 대한 PageTable을 볼 수 있는 하위 명령들을 Soft Key 버튼으로 보여 줍니다.
1) ARMv8 AArch64 Exception Level별 Page Table확인하기
- MMU.List.EL1PageTable : TTBR0/1_EL1을 사용한 stage1 변환 값을 보여줍니다
- MMU.List.EL2PageTable : TTBR0_EL2를 사용한 주소 변환리스트를 보여줍니다
- MMU.List.IntermediatePageTable : VTTBR_EL2를 사용한 변환을 보여줍니다
- MMU.List.EL3PageTable : TTBR0_EL3를 사용한 주소 변환을 보여줍니다
아래 그림은 원활한 이해를 돕기 위해 Address Translation과 TRACE32명령을 도식화한 것입니다.
만약 EL2 Page Table을 보고 싶은 경우라면
MMU.List.EL2PageTable
명령을 사용하면 됩니다.
MMU TLB dump
MMU TLB dump기능은 Processor Core에 따라 다를 수 있습니다. 즉 Processor Core에서 TLB Dump 기능(Path)을 제공해야만 TRACE32가 그 내용들을 읽어 Decoding해 보여 줄 수 있다는 말과 같습니다.
각 TLB Dump 명령은 다음과 같습니다
MMU.DUMP.ITLB ; Instruction Translation Lookaside Buffer 내용을 보여줌
MMU.DUMP.DTLB ; DTLB 내용을 보여줌
MU.DUMP.TLB0 ; TLB0 내용을 보여줌
MMU.DUMP.TLB1 ; TLB1 내용을 보여줌
다음은 Core별 TLB Dump 기능 내장 여부를 보이고 있는 도표입니다. 해당 Core가 ”O”로 표기된 경우 물리적으로 Dump Path를 지원한다는 의미입니다.
|
CortexA5 |
CortexA7 |
CortexA8 |
CortexA9 |
CortexA15 |
KRAIT |
CortexA53 |
CortexA57 |
ITLB |
X |
X |
O |
X |
X |
X |
O |
O |
DTLB |
X |
X |
O |
X |
X |
X |
O |
O |
TLB0 |
X |
O |
X |
X |
X |
O |
X |
O |
TLB1 |
O |
X |
X |
O |
O |
X |
X |
X |
물리적으로 지원할 경우 TRACE32에서 해당 Core에 대한 TLB Dump기능이 구현 되었다면 다음과 같이 TLB 내용을 Dump해서 볼 수 있게 됩니다.
만약 TRACE32 TLB dump명령을 통해 특정 TLB를 열었을 때 아래 그림과 같이 ”funtion not supported by this device” 라는 message가 나오는 경우는 해당 Core가 물리적으로 Dump기능을 지원하지 않는 것입니다.
Cache Dump
Cache dump기능 역시 Processor Core에 따라 다를 수 있습니다. 즉 Processor Core에서 Cache Dump 기능(Path)을 제공해야만 TRACE32가 내용들을 Dump한 후 Decoding해 보여 줄 수 있습니다.
다음은 물리적으로 각 Core별로 Cache Dump 기능 지원여부를 보여주는 도표입니다.
|
CortexA5 |
CortexA7 |
CortexA8 |
CortexA9 |
CortexA15 |
KRAIT |
CortexA53 |
CortexA57 |
ICACHE |
O |
O |
O |
X |
X |
O |
O |
O |
DCACHE |
O |
O |
O |
X |
X |
O |
O |
O |
L2 |
X |
X |
O |
X |
X |
O |
x |
O |
Instruction Cache dump
CACHE.DUMP.IC ; Instruction Cache dump
Instruction Cache를 Dump하여 보여주는 명령입니다.
아래 그림과 같이 “function not supported by this device” message가 보이면 위 표에서 볼 수 있듯이 Cache Dump path가 물리적으로 지원되지 않는 Core인 경우 입니다.
Data Cache dump
CACHE.DUMP.DC ; Data Cache dump
L2 Cache dump
CACHE.DUMP.L2 ; L2 Cache dump
RAM dump 및 복원
RAM dump 및 복원은 Target Hang-Up(Lock-Up)상태 시 TRACE32와 같은 JTAG debugger 등으로 더 이상 정보 파악이 불가능한 경우 System Memory Contents를 dump하여 최종 상태의 동작 상황을 복원하는 작업입니다.
아래 그림은 CoreSight Trace데이터와 RAM dump된 데이터를 연동하여 분석하는 Sequence를 보이고 있습니다. RAM dump된 데이터만을 사용할 경우 Dump된 상태만을 복원할 수 있으나 Trace 데이터를 연동하여 복원한 경우 과거 Code의 실행 경로와 최종 실행코드 위치 정보를 쉽게 찾아 낼 수 있기 때문에 분석하는데 많은 정보를 제공합니다.
대부분의 hang-up(Lock-Up) 상태에서는 JTAG을 통한 Target CPU core들을 세울 수 없는 상태가 되며 어떠한 Peripheral(USB/Ethernet)도 동작하지 않은 상태가 되므로 이 때는 DAP의 AHB-AP나 AXI-AP를 통해 직접 BUS에 Access하여 System Memory Dump 하게 됩니다.
최악의 경우 System Reset 후 dump mode로 진입 시킨 후 RAM contents를 얻는 방법도 사용하게 됩니다.
memory data 를 file 로 저장하는 방법
Hang-Up 재현 전에 2. 4. iTSP setup에서 학습했던 Kernel Address Range 정보를 습득을 참고하여 Kernel 해당 정보를 얻어내기 바랍니다. 왜냐하면 메모리 Contents 전체를 dump해내는 것과 Kernel분석 만 필요할 경우 Kernel 영역만을 dump 해내는 경우가 있기 때문입니다.
1) Target Hang-Up을 재현합니다.
2) Target 연결 설정 후 CPU 메뉴 >> SYStem Setting… 클릭하여 SYStem window를 열고 Target 연결 시 System Reset를 방지하기 위하여 EnRest 옵션을 Off 합니다.
3) 다음은 SYStem.Mode.Prepare로 연결합니다.
4) RAM 내용을 파일로 저장합니다. 저장시 전영역을 저장하거나 Kernel Address range만 필요할 경우 해당 부분만 파일로 저장합니다. 사용할 MEM-AP에 따라
Data.Save.Binary TargetDRAM.bin ZAHB:StartAddr--EndAddr
or
Data.Save.Binary TargetDRAM.bin ZAXI:StartAddr--EndAddr
5) 만약 Trace Data를 받은 경우라면
Trace.Save.File TraceRecordFile.AD
명령으로 특정 파일로 저장합니다.
dump 된 image 를 TRACE32 Simulator 에서 복원하는 법
이전에 저장된 RAM dump데이터의 동작 상태를 복원하는 작업을 진행합니다. 우선 TRACE32를 Simulation Mode로 실행하여 띄웁니다.
설치 폴더에 confg.t32파일을 열고
PBI=
USB
항목을 PBI=sim으로 변경 후 다시 실행 합니다. 이는 TRACE32 Software를 Simulation Mode로 실행시키는 설정입니다.
CortexA15x4 System 32bit Kernel 복원 예
다음은 복원 Script를 이용해 복원 예입니다.
위 그림은 RAM dump데이터와 Trace데이터를 가지고 복원한 예입니다.
복원이 완료되면 이전에 실제 Target에서 분석하던 Linux Awarness기능 모두 가능하며 각 Process별 Call Stack 정보 등을 확인할 수 있습니다.
CortexA53x4+CortexA57x4개로 구성된 System에서 64bit Kernel 복원 예제
다음은 복원된 결과를 보여주고 있습니다.