rockchip rk3566 디버깅 노트

Rockchip을 사용하여 컴파일하기 전에 다음 설정에 주의하십시오.
원키 컴파일 명령을 사용하기 전에 환경 변수를 설정하고 컴파일해야 하는 플랫폼을 선택해야 합니다.예:
source build/envsetup.sh
lunch rk3566_rgo -사용자 디버그
========= ========================================== ============= =
make installclean -j24;make -j24
rm rockdev/Image-tab10_rk66/*;./mkimage.sh;rm RKTools/linux/Linux_Pack_Firmware/rockdev/Image/*; cp rockdev/Image-tab10_rk66/* RKTools/linux/Linux_Pack_Firmware /rockdev/Image/


네트워크 테스트 도구
ifconfig eth0 192.168.9.132 넷마스크 255.255.255.0
iperf -s -i 10
iperf -c 192.168.1.133 -t 50

/************디스플레이 디버깅 관련 명령************/
//현재 디스플레이 프레임 속도를 출력하여 재생이 비정상인지 판단
setprop debug.sf .fps 1
logcat -c ;logcat | grep mFps
//SurfaceFlinger Services를 통해 합성 전략이 정상인지 확인
dumpsys SurfaceFlinger
//정상이 아니면 HWC 로그를 출력하여 비정상 원인 확인
adb shell "setprop sys.hwc.log 511 "
adb shell "logcat - c ;logcat" > hwc.log
/************************************* ******* /  

cat /sys/fs/pstore/console-ramoops-0은  
마지막 시스템 재설정 전에 장치 정보를 출력합니다. 비정상적인 복사 또는 비정상적인 정전 시 이 명령을 사용하여 마지막 시스템 실행 상태 로그를 출력할 수 있습니다.

/****************debugging disassembly command************/
Crash log 이
오류를 구성하고 HWC의 적절한 위치에 다음을 추가합니다. 코드 코드:
struct test_t{ int a = 0; int b = 0; int c = 0; void add(){return;}; }; struct test_t *test_a; //construct test_a test_a = NULL; //NULL로 설정 test_a ->c = 1; //NULL 포인터의 멤버에 접근











addr2line 명령을 사용하여 온사이트 오류 위치로 디컴파일: //000000000004195c 첫 번째 주소
addr2line -e $OUT/symbols/system/lib64/hw/hwcomposer.rk30board.so 000000000004195c를 충돌
시켜 오류 주소 가져오기

문제를 더 분석해 보겠습니다. 다음 명령을 사용하여 해당 어셈블리 소스 코드를 분해하고 출력할 수 있습니다
.
-S -D $OUTsymbols/system/lib64/hw/hwcomposer.rk30board.so > hwcomposer.dump
출력 파일 hwcomposer.dump에서 쿼리 4195c 스택 인쇄 주소 위치

/**************************** 스핀록******************** ** ***/
인터페이스 API의 종류 spinlock 정의 raw_spinlock 정의 spin lock 정의
및 초기화 DEFINE_SPINLOCK DEFINE_RAW_SPINLOCK
spin lock 동적 초기화 spin_lock_init raw_spin_lock_init
지정된 spin lock 가져오기 spin_lock raw_spin_lock
지정된 spin lock 가져오기와 동시에 CPU 인터럽트 비활성화 spin_lock_irq raw_spin_lock_irq
save CPU의 현재 irq 상태, CPU 인터럽트 비활성화 및 지정된 스핀 잠금 획득 spin_lock_irqsave raw_spin_lock_irqsave 지정된
스핀 잠금 획득 및 하단 절반 비활성화 spin_lock_bh raw_spin_lock_bh
지정된 스핀 잠금 해제 spin_unlock raw_spin_unlock
지정된 스핀 잠금 해제 및 CPU 인터럽트 spin_unlock_irq raw_spin_unock_irq는
지정된 스핀 잠금을 해제하고 동시에 CPU의 인터럽트 상태를 복원합니다. spin_unlock_irqstore raw_spin_unlock_irqstore
지정된 스핀 잠금 을 가져오고 동시에 이 CPU의 하반부 spin_unlock_bh를 활성화합니다
.
다른 스레드가 이미 잠금을 획득한 경우 0이 아닌 값을 반환하고, 그렇지 않으면 0을 반환 spin_is_locked raw_spin_is_locked
************************** *********** ***********************

/************************수면 전 로그 정보 넣기******************** ** *******/
echo N >sys/module/printk/parameters/console_suspend

/************************************************** **********************/

grep -nr rockchip_suspend | grep ipc 검색


/**************************죄송합니다 분석********************* * */

커널 개발 과정에서 널 포인터 예외 및 범위를 벗어난 메모리 액세스와 같은 커널 충돌이 자주 발생합니다. 일반적으로 우리는 충돌 위치와 원인을 찾기 위해 충돌 후에 출력된 비정상적인 호출 스택 정보에만 의존할 수 있습니다. 분석 방법 및 단계를 요약합니다.

일반적으로 oops가 발생한 후 직렬 포트 콘솔 또는 dmesg 로그 출력에서 ​​다음 로그를 볼 수 있습니다.예를 들어 특정 팔에서 Linux 커널의 충돌을 가져옵니다.

<2>[515753.310000] net/core/skbuff.c:1846의 커널 버그!
<1>[515753.310000] 가상 주소 00000000에서 커널 NULL 포인터 역참조를 처리할 수 없습니다.
<1>[515753.320000] pgd = c0004000
<1>[515753.320000] [00000000] *pgd=00000000
<0>[515753 .330000] 내부 오류: 죄송합니다. 817 [#1] PREEMPT SMP
<0>[515753.330000] 마지막 sysfs 파일: /sys/class/net/eth0.2/speed
<4>[515753.330000] 모듈: http_timeout bf098000 4142
...
<4>[515753.330000] CPU : 0 오염: P (2.6.36 #2)
<4>[515753.330000] PC는 __bug+0x20/0x28
<4>[515753.330000] LR은 __bug+0x1c/0x28
<4>[515753.330000] pc : [< c01472d0>] lr : [<c01472cc>] psr:
<4>[515753.330000] sp : c0593e20 ip : c0593d70 fp : cf1b5ba0
<4>[515753.330000] r10: 00000014 r9 : 4adec78d ​​r8 : 00000006 <4>
[515753.330000] r7 : 00000000 r6 : 0000003a r5 : 0000003a r4 : 00000060
<4 >[515753.330000] r3 : 00000000 r2 : 00000204 r1 : 00000001 r0 : 0000003c
<4>[515753.330000] 플래그: 모드 SVC_32 ISA ARM 세그먼트 커널 <4>[515753. 330000
] 컨트롤: 10c53c7d 테이블: 4fb5004a DAC: 00000017
<0>[515753.330000] 프로세스 스와퍼(pid: 0, 스택 제한 = 0xc0592270)
<0>[515753.330000] 스택: (0xc0593e20 ~ 0xc0594000) <0>[515753.330000]
3e20: ce2ce900 c0543 cf4 00000000 ceb4c400 000010cc c8f9b5d8 00000000 00000000
<0>[515753.330000] 3e40: 00000001 cd469200 c8f9b5d8 00000000 ce2ce8bc 00000006 00000026 00000010
...
<4>[515753.330000] [<c01472d0>] (PC는 __bug+0x20/0x28에 있음) <4>
[515753.330000] [<c01472d0> ] (__bug+0x20/0x28) from [<c0543cf4>] (skb_checksum+0x3f8/0x400)
<4>[515753.330000] [<c0543cf4>] (skb_checksum+0x3f8/0x400) from [<bf11a8f8>] (et_isr+0x2b4/ 0x3dc [et])
<4>[515753.330000] [<bf11a8f8>] (et_isr+0x2b4/0x3dc [et]) from [<bf11aa44>] (et_txq_work+0x24/0x54 [et]) <4>[515753.330000] [
< bf11aa44>] (et_txq_work+0x24/0x54 [et]) [<bf11aa88>]에서 (et_tx_tasklet+0x14/0x298 [et]) <4>[515753.330000] [<bf11aa88>] (et_tx_tasklet+0x14/0x298 [et]
) [<c0171510>에서] (tasklet_action+0x12c/0x174)
<4>[515753.330000] [<c0171510>] (tasklet_action+0x12c/0x174) from [<c05502b4>] (__do_softirq+0xfc/0x1a4) <4>[515753.330000] [<c05502b4>] (__do_softirq+0xfc/ 0x1a4)
에서 [<c0171c98>] (irq_exit+0x60/0x64)
<4>[515753.330000] [<c0171c98>] (irq_exit+0x60/0x64) from [<c01431fc>] (do_local_timer+0x60/0x74) <4>[515753.33000 0]
[ <c01431fc>] (do_local_timer+0x60/0x74) from [<c054f900>] (__irq_svc+0x60/0x10c)
<4>[515753.330000] 예외 스택(0xc0593f68 ~ 0xc0593fb0)

여기서는 다음 사항에 중점을 둡니다.

죄송합니다 net/core/skbuff.c:1846의 커널 버그입니다! 가상 주소 00000000에서 커널 NULL 포인터 역참조를 처리할 수 없습니다. 여기서 코드가 BUG()/BUG_ON() 유형을 직접 호출하는 경우 오류를 유발한 문제를 간단히 알 수 있습니다. , 뿐만 아니라 소스 코드에서 트리거 라인 번호를 제공합니다.

레지스터 PC/LR PC의 값은 __bug+0x20/0x28에 있습니다. LR은 __bug+0x1c/0x28에 있습니다. 여기서 PC는 oops를 보내는 명령이며 함수 호출자는 LR을 통해 찾을 수 있습니다.

CPU 번호 및 CPU 레지스터 값 sp ip fp r0~r10,

오류가 발생하면 응용 프로그램 계층의 프로세스 프로세스 스와퍼(pid: 0, 스택 제한 = 0xc0592270)가 커널 호출 컨텍스트에서 충돌이 발생하면 해당 사용자 모드 프로세스를 찾는 데 사용할 수 있습니다.

가장 중요한 것은 콜스택, 콜스택을 통해 오류 위치를 분석할 수 있습니다.

여기에서 설명해야 합니다. skb_checksum+0x3f8/0x400 분해 후 skb_checksum 함수 항목 주소 오프셋 0x3f8을 찾아 실행 지점을 정확하게 찾을 수 있습니다.

오류 위치를 정확하게 찾아야 하는 경우 디스어셈블리 도구 objdump를 사용해야 합니다. 다음은 예입니다.

    objdump -D -S xxx.o > xxx.txt

예를 들어 [<bf11aa44>](et_txq_work+0x24/0x54[et])에서 스택(et_isr+0x2b4/0x3dc[et])을 찾아야 하는 경우 여기에서 이 함수가 [et]에 있음을 알 수 있습니다. obj 파일 , et.o로 직접 이동한 다음 objdump -D -S et.o > et.txt를 분해하면 et.txt에 분해된 지침이 포함됩니다. 물론 조립 설명서만 봐서는 많이 번거로우실 텐데 분해 설명서와 소스코드를 일대일로 대응시켜 문제를 분석해야 합니다. 이렇게 하려면 컴파일할 때 -g 매개 변수를 추가하고 컴파일 프로세스 중에 기호 및 디버깅 정보를 최종 obj 파일에 추가해야 objdump 분해된 파일에 포함된 소스 코드 파일이 포함됩니다.

커널 컴파일을 위해서는 Makefile의 KBUILD_CFLAGS를 수정하고 커널 컴파일 루트 디렉토리에 -g 컴파일 옵션을 추가해야 합니다.

    KBUILD_CFLAGS := -g -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \                       
               -fno-strict-aliasing -fno-common \
               -Werror-implicit-function-declaration \
               -Wno-format-security \
               -fno-delete- null-pointer-checks -Wno-implicit-function-declaration \
               -Wno-unused-but-set-variable \
               -Wno-unused-local-typedefs

다음은 디컴파일된 파일의 부분 가로채기입니다. 여기서 0x1f0은 <et_isr> 함수의 엔트리 엔트리이고 c의 소스 코드가 앞에 있고 그 뒤에 오는 어셈블리 코드가 해당 분해 명령임을 알 수 있습니다.

f0 <et_isr>:
et_isr(int irq, void *dev_id)
#else
static irqreturn_t BCMFASTPATH
​​et_isr(int irq, void *dev_id, struct pt_regs *ptregs)
#endif
{ f0: e92d40f8 push {r3, r4, r5, r6, r7 , lr} f4: e1a04001 mov r4, r1     구조체 절단 * 절단;     무효 *ch;     단위 이벤트 = 0;




    et = (et_info_t *)dev_id;
    찹스 = et->etc->chops;
f8: e5913000 ldr r3, [r1]
    ch = et->etc->ch;

    /* 공유 인터럽트에 대한 보호 */
    if (!et->etc->up)
fc: e5d32028 ldrb r2, [r3, #40] ; 0x28
    구조체 절단 * 절단;
    무효 *ch;
    단위 이벤트 = 0;

    et = (et_info_t *)dev_id;
    찹스 = et->etc->chops;
: e5936078 ldr r6, [r3, #120] ; 0x78
    채널 = et->etc->ch;
: e593507c ldr r5, [r3, #124] ; 0x7c

    /* 공유 인터럽트에 대한 보호 */
    if (!et->etc->up)
: e3520000 cmp r2, #0
c: 1a000001 bne 218 <et_isr+0x28>
: e1a00002 mov r0, r2
: e8bd80f8 pop {r3, r4, r5, r6, r7, pc}
        완료되었습니다.

    /* 인터럽트 조건 비트 가져오기 */
    events = (*chops->getintrevents)(ch, TRUE);
: e5963028 ldr r3, [r6, #40] ; 0x28
c: e1a00005 이동 r0, r5
: e3a01001 이동 r1, #1
: e12fff33 blx r3
: e1a07000 이동 r7, r0

    /* 우리를 위한 것이 아님 */
    if (!(events & INTR_NEW))
c: e2100010 ands r0, r0, #16
: 08bd80f8 popeq {r3, r4, r5, r6, r7, pc}

    ET_TRACE(("et%d: et_isr: 이벤트 0x%x\n", et->etc->유닛, 이벤트));
    ET_LOG("et%d: et_isr: 이벤트 0x%x", et->etc->unit, events);

    /* 인터럽트 비활성화 */
    (*chops->intrsoff)(ch);
: e5963038 ldr r3, [r6, #56] ; 0x38
: e1a00005 mov r0, r5
c: e12fff33 blx r3
        (*chops->intrson)(ch);
    }

objdump가 명령을 분해한 후 호출 스택의 항목 오프셋에 따라 해당하는 정확한 호출 지점을 찾을 수 있습니다. 예를 들어, (et_isr+0x2b4/0x3dc [et]) from [<bf11aa44>] (et_txq_work+0x24/0x54 [et]) 호출 지점이 et_isr 진입 위치 +0x2b4 오프셋에 있음을 알 수 있습니다. 우리는 et_isr의 항목 위치가 0x1f0인 것을 보았습니다. 즉, 0x1f0+0x2b4=0x4a4의 오프셋 위치에 있습니다. 다음 명령어 4a4를 살펴보겠습니다: e585007c str r0, [r5, #124] ; 0x7c, 해당 소스 코드는 위의 c 코드, skb->csum = skb_checksum(skb, thoff, skb->len - thoff , 0); . 그리고 우리는 다음 호출 함수가 실제로 skb_checksum임을 알고 있으며 정확한 호출 명령이 정확함을 나타냅니다.

        ASSERT((prot == IP_PROT_TCP) || (prot == IP_PROT_UDP));
        check = (uint16 *)(th + ((prot == IP_PROT_UDP) ?
c: e3580011 cmp r8, #17
: 13a0a010 movne sl, #16
: 03a0a006 moveq sl, #6
            offsetof(struct udphdr, check) : offsetof(struct tcphdr, 확인)));
        *체크 = 0;
: e18720ba strh r2, [r7, sl]
    thoff = (th - skb->데이터);
    if (eth_type == HTON16(ETHER_TYPE_IP)) {         struct iphdr *ih = ip_hdr(skb);         prot = ih->프로토콜;         ASSERT((prot == IP_PROT_TCP) || (prot == IP_PROT_UDP));         확인 = (uint16 *)(th + ((prot == IP_PROT_UDP) ? c: e087200a r2, r7, sl 추가





: e58d2014 str r2, [sp, #20]
            offsetof(struct udphdr, check) : offsetof(struct tcphdr, check)));
        *체크 = 0;
        ET_TRACE(("et%d: skb_checksum: \n", et->etc->unit));
        skb->csum = skb_checksum(skb, thoff, skb->len - thoff, 0);
: e5952070 ldr r2, [r5, #112] ; 0x70
: e58dc008 스트립, [sp, #8]
c: e0612002 rsb r2, r1, r2
a0: ebfffffe bl 0 <skb_checksum>
a4: e585007c str r0, [r5, #124] ; 0x7c
        *체크 = csum_tcpudp_magic(ih->saddr, ih->daddr,
a8: e5953070 ldr r3, [r5, #112] ; 0x70

정적 인라인 __wsum
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
           unsigned short proto, __wsum sum)
{     
    __asm__(
ac: e59dc008 ldr ip, [sp, #8]

괴짜를 비교할 때 알아야 할 몇 가지 사항이 있습니다.

함수 호출 스택의 호출이 반드시 정확하지는 않지만(이유는 잘 모르겠습니다. LR을 통해 호출 프로세스가 반전되기 때문일 수 있으며, LR은 실행 중에 수정될 수 있습니까?) 한 가지 확인할 수 있는 것은 호출입니다. 즉, 호출하는 함수가 반드시 정확하지는 않지만 호출하는 함수 + 오프셋은
인라인 명령어로 호출되는 정확한 함수를 찾을 수 있으며 최적화된 함수는 호출 스택에 나타나지 않을 수 있습니다. 컴파일 중 최적화가 필요합니다. 코드를 제자리에서 확장하여 호출 스택 프레임(스택 프레임)이 여기에 존재하지 않도록 합니다.
/********************* *******oops end *******************************/
1. Linux 커널과 관련된 지연
은 바쁜 지연과 수면 지연 시간으로 나뉩니다. 바쁜 지연은 대기 시간이 매우 짧은 경우에 사용되며 프로세스와 인터럽트 모두 바쁜 지연을 사용할 수 있습니다. 수면 지연은 대기 시간이 긴 경우에 적용되며 중단할 수 없는 프로세스에서만 사용할 수 있습니다.
그리고 프로세스가 언제 어디서든 잠들고 깨울 수 있어야 한다면 이것은 리눅스 커널의 대기 큐 메커니즘을 사용해야 합니다. 전력소모를 줄이며 일반적으로 센서에 사용됩니다. . 그리고 세마포어 자체는 대기 큐를 기반으로 프로세스 자체를 절전 모드로 만들 수 있습니다.

2. Rockchip에서 발생한 제어할 수 없는 핀 문제
장치 트리의 구성이 정상이며 드라이버에 오류 보고, 핀 멀티플렉싱이 없으며 시스템에 해당 장치 노드가 있지만 echo 및 cat 명령을 통해 확인 소프트웨어의 상태는 항상 0으로 낮은 상태이지만 하드웨어 핀의 성능에서 핀의 전압은 항상 낮습니다. 즉, 전압은 0입니다. echo를 통해 전압을 높게 설정하십시오. 장치 노드 일반적으로 로그에 보고된 오류는 없지만 소프트웨어 cat은 노드 값이 0, 즉 전압이 0으로 유지되는지 확인합니다. 나중에 dts가 핀을 구성할 때 핀을 기본 상태, 즉 pinctrl-names = "default"로 설정해야 한다는 사실이 발견되었습니다. 기본적으로 gpio의 핀 기능이므로 이 구성 없이 제어할 수 있습니다. 이것은 제어할 수 없습니다. 사실 GPIO는 다른 기능에 있지만 현재 어떤 기능에 있는지 알 수 없습니다.)

3. TPL(Tiny Program Loader) 및 SPL(Secondary Program Loader)은 U-Boot보다 초기 단계의 로더입니다.
TPL: sram에서 실행되며 ddr 초기화 완료를 담당합니다.
SPL: ddr에서 실행되며 낮은 수준의 시스템 초기화, 사후 수준의 펌웨어 로딩(trust.img 및 uboot.img)
U-Boot 고유: 커널 부팅을 담당하는 일반적으로 "U-Boot"라고 부르는 ddr에서 실행합니다.
설명: U-Boot 고유 및 이 설명은 주로 SPL과 구별하기 위한 것입니다. U-Boot는 줄여서 U-Boot라고 부릅니다.

4. 가상 메모리의 어느 페이지가 페이지 테이블(페이지 테이블)에 의해 설명되는 물리적 메모리의 페이지 프레임에 매핑되는지 페이지 테이블은 물리적 메모리에 저장되며 MMU는 페이지 테이블을 조회하여 VA가 (가상 주소)는 어떤 PA(물리적 주소)에 매핑되어야 합니다. MMU가 활성화되면 프로그램에서 사용되는 주소는 모두 가상 메모리 주소이며 이로 인해 MMU가 테이블 조회 및 주소 변환 작업을 수행하게 됩니다. 변환된 가상 주소(MVA, 수정된 가상 주소)
분할 오류는 때때로 프로그램에서 프로세스 충돌을 일으키며 다음과 같이 생성됩니다.
(1) 사용자 프로그램이 VA에 액세스하려고 할 때 확인 후 액세스가 없습니다. MMU에 의해 .
(2) MMU는 예외를 생성하고 CPU는 사용자 모드에서 특권 모드로 전환하고 커널 코드로 점프하여 예외 서비스 프로그램을 실행합니다.
(3) 커널은 이 예외를 세그먼트 오류로 해석하고 예외를 발생시킨 프로세스를 종료합니다.
5. 커널에서 Delayed_work의 본질은 작업 대기열과 타이머를 통해서도 실현됩니다. Linux 인터럽트 처리는 두 부분으로 나뉘며, 위쪽 절반은 긴급한 하드웨어 작업을 처리하고, 아래쪽 절반은 긴급하지 않은 시간 소모적인 작업을 처리하며, tasklet 및 작업 대기열은 아래쪽 절반에서 인터럽트를 예약하는 좋은 메커니즘이며 tasklet은 기반입니다. 소프트 인터럽트 구현, 커널 타이머는 또한 소프트 인터럽트에 의존하여 달성합니다.

/******************** .so 라이브러리 명령 생성 *********************/
 gcc -fPIC - 공유 dl.c -o libdl.so

dl.c 파일명 libdl.so 생성할 라이브러리명 안드로이드에서 .so 파일은 일반적으로 android.mk에서 생성되어 컴파일된다.

 opendl.c를 실행 파일
 gcc -rdynamic -o opendl opendl.c -ldl
 
 c 언어로 컴파일한 후 프로그램을 쉽게 확장하고 다재다능하게 만들기 위해 플러그인 형태로 만들 수 있습니다. 비동기식 이벤트 구동 모델을 채택하여 기본 프로그램의 논리가 변경되지 않고 각 비즈니스가 소위 플러그인이라고 하는 동적 링크 라이브러리의 형태로 로드됩니다. Linux는 매우 편리한 동적 링크 라이브러리를 로드하고 처리하기 위한 시스템 호출을 제공합니다.
c 언어는 동적 링크 라이브러리 파일 android, 즉 .so 파일을 로드할 수 있도록 api를 제공합니다.

dlopen 함수는 지정된 모드에서 지정된 동적 링크 라이브러리 파일을 열고 dlsym()의 호출 프로세스에 대한 핸들을 반환합니다. dlclose는
열린 라이브러리를 언로드
합니다. dlerror는 발생한 오류를 반환합니다.
dlsym dlsym은 핸들을 통해 함수 이름 또는 변수 이름을 가져옵니다. 그리고 커넥터 이름

/************************************************** *****/

Supongo que te gusta

Origin blog.csdn.net/qq_48709036/article/details/123042648
Recomendado
Clasificación