• 2008-04-19

    IDA反汇辅助BDI2000调试EBOOT - [电路与驱动]

    Tag:

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://hunbalo.blogbus.com/logs/19330110.html

        虽然eboot的全部源代码已经发布,但是在对于一个bootloader程序员来说,适当看一点反汇编还是有必要的,毕竟这才是实际在处理器上跑的代码。
        BDI2000是调试LINUX bootloader的优秀工具,通过它可以直接用gdb调试uboot,乃至linux kernel. 但是gdb并不能识别*.pdb的符号表文件,因此,这么优秀的工具调试起eboot就不那么方便了。虽然eboot也有相应的工具调试,但是重复投资也不划算,其实借助与IDA 反汇编工具结合BDI2000,也可以达到近似与源码级调试的效果。
        Bootloader的第一条指令所在的ROM地址是cpu的程序入口,这一点,无论是x86的BIOS,还是UBOOT,EBOOT都是一个道理,和裸奔的单片机程序也别无二样。对于ARM系列处理器来说,这个地址就是0x00000000,也就是RESET VECTOR地址。
    以PXA270Mainstone ii平台为例,eboot编译链接后生成eboot.exe, romimage会后生成eboot.bin和eboot.nb0, eboot.bin是eboot自更新用的。对于裸片也可以利用烧写器将eboot.nb0写入XIP的BOOT FLASH中。Eboot.exe和eboot.nb0的区别在于前者是PE格式的,反汇编时可以看到程序入口是0x00011000,68K偏移的地方,这个文件的方便之处在于反汇编的时候,可以把PDB加载进来,C语言及汇编中的全局变量名及函数名还能完全还原出来,以便阅读和搜索,但是它的链接地址和执行地址还不一样,下面是eboot.exe入口startup反汇编后的代码。
    .text:00011000
    .text:00011000
    .text:00011000                EXPORT StartUp
    .text:00011000 StartUp
    .text:00011000
    .text:00011000 ; FUNCTION CHUNK AT .text:0002CE94 SIZE 00000038 BYTES
    .text:00011000 ; FUNCTION CHUNK AT .text:0002CEE0 SIZE 00000010 BYTES
    .text:00011000
    .text:00011000                BL      sub_110A0
    .text:00011000
    .text:00011004                TST    R10, #1
    .text:00011008                BNE    loc_11020
    .text:00011008
    .text:0001100C                TST    R10, #4
    .text:00011010                BNE    loc_11020
    .text:00011010
    .text:00011014                TST    R10, #8
    .text:00011018                BNE    loc_1106C
    .text:00011018
    .text:0001101C                BEQ    OALStartUp

            在$(WINCEROOT)\PLATFORM\COMMON\SRC\ARM\INTEL\PXA27X\STARTUP\start.s
    对应上述反汇编的源代码
      LEAF_ENTRY StartUp

        ; Perform pre-initialization (enter supervisor mode, disable MMU and caches,
        ; and determine the reason for the reset.
        ;
        bl      PreInit

        ; r10 now contains the contents of the power manager registers RCSR in the
        ; lower half and PSSR in the upper half.  If we're in this routine because
        ; of a hardware/power-on reset, then we need to continue in this routine and
        ; initialize all hardware.  Otherwise, we'll assume the hardware's already
        ; been initialized and we can skip.
        ;
        tst    r10, #RCSR_HARD_RESET
        bne  MemInit

        tst    r10, #RCSR_SLEEP_RESET
        bne  MemInit
     
        ; If we're here because of a GPIO reset, skip the memory controller
        ; initialization because all memory registers (except for configuration
        ; registers are maintained across the reboot).
        ;
        tst    r10, #RCSR_GPIO_RESET
        bne  Continue_StartUp
        beq  OALStartUp


            在$(_TGTPLAT)\src\eboot\下的source文件中有EXEENTRY=StartUp链接指示将入口链接为startup。
    但是这段代码并不是在0x00000000执行的,这段代码是在0x00001000,4Kb的地方执行的,我们反汇编一下eboot.nb0可以看到,第一条指令是
    ROM:00000000                B      loc_1000
    跳转到4KB的start.s执行。
        一般说来就ARM来讲,开始几条指令应当依次是
    0x00000000 b reset;
    0x00000004 b isr0;
    0x00000008 b isr1;
    ……
        这个结构对于用过UBOOT和blob等linux下bootloader的人应该并不陌生。
    但是eboot本身并不支持中断,cpu初始化后也是完全处于关中断状态下的,所以中断处理完全没有必要,就只需要一个b reset了,reset就是0x000001000。而PE格式的Eboot.exe中对应的地址是0x00011000,这样如果我们看着eboot.exe的反汇编用bdi2000设置断点的时候就要自己手动计算这个地址了。
        比如说,我要在OALStartUp设置断点,那么,我先看eboot.exe的反汇编.
    text:0001E668 OALStartUp
    可以计算出OALStartUp的地址是0xE668, 可以直接用BDI2000在0xE668设断点。
        但是EBOOT的很大一部分是拷贝到RAM中执行的。EBOOT做了一些简单的初始化,诸如初始化内存控制器,创建页表等的工作后,就把自己拷贝到内存执行了,那么到内存中执行时我们要怎么设置断点呢?
        且看$(WINCEROOT)\PLATFORM\MAINSTONEII\SRC\BOOTLOADER\EBOOT下start.s中的这一段代码
    CODEINRAM

        ;bl        LED_ON
        ; We're now running out of RAM.
        ;
        ;ldr    r0, =MAINSTONEII_BASE_REG_PA_FPGA
        ;mov    r1, pc              ; Get the RAM-based PC.
        ;setHexLED  r0, r1          ; Display it.

        ; Now that we're running out of RAM, construct the first-level Section descriptors
        ; to create 1MB mapped regions from the addresses defined in the OEMAddressTable.
        ; This will allow us to enable the MMU and use a virtual address space that matches
        ; the mapping used by the OS image.
        ;
        ; We'll create two different mappings from the addresses specified:
        ;    [8000 0000 --> 9FFF FFFF] = Cacheable, Bufferable
        ;    [A000 0000 --> BFFF FFFF] = NonCacheable, nonBufferable
        ;
    BUILDTTB
        add    r11, pc, #g_oalAddressTable - (. + 8)    ; Pointer to OEMAddressTable.
       
        ; Set the TTB.
        ;
        ldr    r9, =MAINSTONEII_BASE_PA_SDRAM    ; Physical address of the first-level table (base of SDRAM).
        ldr    r0, =0xFFFFC000                  ;
        and    r9, r9, r0                        ; Mask off TTB[31:0] (must be 0's).
        mcr    p15, 0, r9, c2, c0, 0            ; Set the TTB.

        add    r11, pc, #g_oalAddressTable - (. + 8)    ; Pointer to OEMAddressTable.
    在我的代码中,注解了几条指令。
    这段代码计算出add    r11, pc, #g_oalAddressTable - (. + 8) 这条指令在RAM中的物理地址偏移,再跳转过去,在image_cfg.h中可以看到IMAGE_BOOT_BLDRIMAGE_RAM_PA_START的值是0xA0020000,如果我们要对add    r11, pc, #g_oalAddressTable - (. + 8)设置断点怎么做呢?
    看看反汇编eboot.exe的相应代码
    .text:0001E84C                ADR    R11, g_oalAddressTable
    这个地址是E84C+0xA0020000 = 0xA002E84C,于是我们BDI设置BI 0xA002E84C。
    接着,设置完页表后,RAM物理地址被映射到0x8000 0000处,开启MMU后,RAM的地址又要重新计算。
    0xA0020000被映射到0x8002 0000处。如果我要对main函数设置断点,看相应的反汇编.text:00018C28 main                                    ; CODE XREF: .text:0001E90Cp
    .text:00018C28                                        ; DATA XREF: .pdata:000370E0o
    .text:00018C28
    .text:00018C28 var_4          = -4
    .text:00018C28 arg_4          =  4
    .text:00018C28
    .text:00018C28                STR    LR, [SP,#var_4]!
    .text:00018C2C                SUB    SP, SP, #4
    设置0x800028C28断点即可。
      综合上述,就是在EBOOT运行的各个阶段,断点的设置不一样,根据eboot.exe的地址和平台的配置,可以计算出索要设置断点的地址。
        写了这些,不指导表述清楚了没有,如果能对人有所帮助,我很高兴,如果没啥帮助,我也不郁闷,以后会继续写点有用的。
        反汇编工具及BDI2000的使用,很多地方都介绍过,我也不再赘述。看过 楚狂人写的《天天夜读》,对X86下反汇编代码阅读写的甚为明晰,我本也想对ARM下的反汇编代码阅读写个拙笨的帖子,就看休假回来还有没有这个心力了。
    明天我就要回家了,祝版上各位朋友新春愉快,加薪晋级。

    2007年春节前在驱动开发网发的帖子,在这里存一下档


    历史上的今天:


    随机文章:

    癞蛤蟆 2004-05-13
    自我介绍 2004-05-13

    收藏到:Del.icio.us