사이트맵 보기

활용사례

[이벤트 - 디버깅 경험 수상작] TRACE32을 이용한 “DOG error” Trace

작성자 관리자

조회수 6749

첨부파일


  • 문제점 및 증상


    Q사의 Processor를 사용하여 개발하다 보면, RTOS의 각 Task들이 현재 어느 위치에 있는지 궁금할 때가 있습니다. 예를 들어 Watchdog Report Error가 발생했을 때, Error를 유발시킨 Task가 어느 부분을 수행 중인지를 알면 위의 문제를 해결하기 위한 매우 중요한 정보가 될 수 있습니다.




    “RXTX task watchdog timeout! dog_task_index: 4” 이와 같은 에러 메시지가 출력될 때는 Watchdog Error를 유발한 RXTX Task가 어느 부분에 멈추어 있는지 알아야 합니다. 개발자가 잘 아는 Task에서 에러가 발생했다면, 오류발생 예상 지점에 Breakpoint를 설정하여 디버깅해 나가면 되겠지만, 잘 모르는 Task일 경우 이를 추적하기에는 상당한 시간이 소요됩니다. 위의 RXTX Task는 CDMA2000의 MUX 기능을 담당하는 것으로 Q사에서 제공하는 소스를 거의 수정하지 않고 사용하기에 개발자들이 그 내용을 잘 알지 못합니다.


    TRACE32를 이용하면 이와 같은 경우를 손쉽게 추적할 수 있다는 것을 알고 있었기에 디버깅을 시도하게 되었습니다.





  • TRACE32 접근방법(디버깅) I


    Task는 Switching을 할 때 Task의 자원인 Context를 자기 Stack에 넣게 됩니다. 따라서 rxtx_tcb가 가리키는 주소의 첫 번째 값이 Stack을 가리키게 되고 거기서 0x3C 만큼 떨어진 곳이 현재 Task의 PC(Program Counter)에 해당합니다.



    위 내용을 알고 있다면, TRACE32를 이용하여 아래와 같이 현재 Task의 PC를 알아볼 수 있습니다.


  • 먼저 원하는 Task를 열어서 해당 Task가 가리키는 주소 값을 확인합니다.


    (symbol을 가지고 있는 ELF포맷을 다운로딩 했다면, Task Name을 이용하면 되겠지요?)



  • Register 창을 열어서 R13(Stack Pointer)에 위의 Task 첫 번째 값을 입력합니다.

  • Stack Pointer에서 0x3C 만큼 떨어진 곳의 Data.List 창을 엽니다.


    이 디버깅 과정을 다음과 같이 그림으로 첨부하였습니다. 이를 보시면 rxtx는 특정 Signal을 기다리고 있고, 그 Signal을 받지 못해서 Watchdog Report를 하지 못한 것입니다. 그래서 그 Signal 이 무엇인지를 파악해서 문제상황을 해결 할 수 있었습니다.




  • TRACE32 접근방법(디버깅) II


    위와 같은 접근방법은 TRACE32의 기능을 십분 발휘하지 못한 수동적인 방법입니다. TRACE32의 CMM Script를 사용하면 위처럼 일일이 값을 쳐 넣어야 하는 번거로움 없이 좀 더 편리하고 빠르게 디버깅할 수 있습니다.



    아래와 같은 CMM 파일을 작성하여 사용하면, 내가 원하는 Task가 현재 어느 곳에 머물러 있는지를 쉽게 알 수 있습니다.

    //----------------------------------------


    // Get Task current program count

    //----------------------------------------

    GetTaskPos: //Label

    ENTRY &tcbName //tcbName을 인자로 받아들임

    PRINT ""-----------------------""

    PRINT ""TCB Name = "" ""&tcbName"" //tcbName 출력

    PRINT ""tcb address = 0x"" address.offset(&tcbName) //tcbName의 첫 번째 값 출력

    register.set r13 data.long(d:address.offset(&tcbName))

    //tcbName의 첫번째 값을 Stack Pointer에 입력

    print ""tcb pc = 0x"" data.long(d:register(r13)+0x3c)

    //Stack Pointer에서 0x3C만큼 떨어져 있는 곳(Program Counter)의 값을 출력

    d.l sd:data.long(d:register(r13)+0x3c)

    //Program Counter가 있는 Data.List 창을 열어줌.



    ENDDO



    위의 CMM 파일은 &tcbName을 입력으로 받아 앞에서 수동으로 했던 일(tcb의 첫번째 값 확인 Register창의 Stack Pointer에 해당 값 입력 Stack Pointer로부터 0x3C만큼 떨어진 곳의 값에 해당하는 Data.List 창 확인)들을 자동으로 수행하게 해줍니다.



    “B::do taskpos.cmm sleep_tcb” 로 CMM을 수행하였을 때 결과 화면을 첨부 하였습니다. AREA창에 sleep_tcb의 tcb Address가 출력되고, Data.List창에는 현재 Task의 위치를 보여줍니다. 아래 그림과 같이 sleep_tcb Task는 현재 0x25801C 번지(rex_int_free_32)를 수행하고 있음을 알 수 있습니다.








  • TRACE32 접근방법(디버깅) II

    여러 가지의 Task를 모두 출력하여 하나의 파일로 만들어서(로깅하여) 보고 싶을 때도 있습니다. 대부분의 task는 rex_wait을 하고 있을 테니, 현재 일을 하고 있는 Task가 어느 것인지를 알 수 있는 방법으로 사용할 수 있습니다.

    위에 만들어둔 CMM에 아래와 같은 부분을 추가한다면 여러 Task를 간단히 Logging 하여 볼 수 있습니다.

    //======================================================//

    // “buffer” 라는 AREA창을 생성하고 //

    // 그 내용을 register.txt 파일로 저장합니다. //

    //======================================================//

    area.create buffer

    area.select buffer

    area.open buffer register.txt

    area buffer



    // 아래와 같은 이름의 Task가 들어오면 GetTaskPos로 분기합니다 //

    gosub GetTaskPos dog_tcb

    gosub GetTaskPos mdsp_tcb

    gosub GetTaskPos qdsp_tcb

    gosub GetTaskPos voc_tcb


    gosub GetTaskPos sleep_tcb


    area.close

    enddo


    //---------------------------------------------------------

    // Get Task current program count

    //---------------------------------------------------------

    GetTaskPos:

    ENTRY &tcbName

    PRINT ""-----------------------""

    PRINT ""TCB Name = "" ""&tcbName""

    PRINT ""tcb address = 0x"" address.offset(&tcbName)

    register.set r13 data.long(d:address.offset(&tcbName))



    print ""tcb pc = 0x"" data.long(d:register(r13)+0x3c)

    d.l sd:data.long(d:register(r13)+0x3c)

    Return




    위의 CMM을 수행하여 얻은 register.txt 파일은 아래와 같습니다. 아래 내용을 바탕으로 해당 Task가 어느 위치에 있는지 알 수 있습니다.

    -----------------------

    TCB Name = dog_tcb

    tcb address = 0x2657F6C

    tcb pc = 0x21E29

    -----------------------

    TCB Name = mdsp_tcb

    tcb address = 0x26583F0

    tcb pc = 0x21E29

    -----------------------

    TCB Name = qdsp_tcb

    tcb address = 0x2658C74

    tcb pc = 0x21E29

    -----------------------

    TCB Name = voc_tcb

    tcb address = 0x26594F8

    tcb pc = 0x21E29


    -----------------------


    TCB Name = sleep_tcb

    tcb address = 0x26A0228

    tcb pc = 0x0B9027




    대부분의 Task가 0x21E29 값입니다. 0x21E29는 rex_wait입니다. 즉 대부분의 task가 signal을 기다리고 있는 것이죠. Sleep task는 0x0B9027이며 특정 공간에서 일을 하고 있습니다.
고객문의 기술지원/
데모/
SW요청
031-627-
3116