美文网首页
MAP 文件和 List 文件的解读(一个例子)

MAP 文件和 List 文件的解读(一个例子)

作者: 电工王大爷 | 来源:发表于2020-10-01 12:38 被阅读0次

    Keil 在生成程序的时候,可以生成两个辅助文件非常有帮助,他们分别是 map 文件和 list 文件。
    访问Options for Target -> Listing 勾选对应选项即可打开。
    这两个文件我仅能大概读懂,下面介绍一下如何根据PC和LR寄存器中的地址数据,通过map文件找到该指令所在的函数,并根据list文件找到出错的代码行号。抛砖引玉,欢迎大牛拍砖:
    map文件是连接器生成的二进制文件的信息,其中描述了各符号的交叉引用、函数和数据排布的顺序和大小等各种有用信息。要根据指令地址查找函数主要关注map文件中的Image Symbol Table这一部分内容。

    Symbol Name Value Ov Type Size Object(Section)
    main 0x00006245 Thumb Code 106 main.o(.text)
    OnPowerOff 0x000062af Thumb Code 8 main.o(.text)
    FAULT_PrintFaultRegs 0x000062dd Thumb Code 464 fault.o(.text)
    FAULT_PrintGeneralRegs 0x000064ad Thumb Code 194 fault.o(.text)

    随意取出其中的一部分,对于每行共有5列数据,每行代表一个符号(函数和全局变量)的数据。分别是:“符号名,符号地址,类型,长度,所在的.o文件”。我们主要关注“符号名,符号地址和长度”这部分内容。
    根据地址查找函数名,就是检索MAP文件的“Image Symbol Table”部分,查找到函数地址和所查询地址最接近,且函数地址比所查询地址小的函数。并根据函数的长度确认是否在函数的范围内。

    举一个真实的例子:
    比如说在发生Hardfault错误时,使用上述Hardfault Handler示例代码打印出的错误信息如下:

    Exceptions:
    r0 : 0x4006a000
    r1 : 0x0000000a
    r2 : 0x00000002
    r3 : 0x00000003
    r4 : 0x0001f420
    r5 : 0x0001f420
    r6 : 0x00000000
    r7 : 0x00000000
    r8 : 0x00000000
    r9 : 0x00000000
    r10 : 0x00000000
    r11 : 0x00000000
    r12 : 0x40048000
    lr : 0x00010681
    pc : 0x00010642
    xpsr: 0x01000000
    current xpsr: 0x00000003
    current lr : 0xffffffe9
    primask : 0x00000000
    basepri : 0x00000000
    faultmask: 0x00000000
    control : 0x00000000
    MMFSR : 0x00000000[]
    BFSR : 0x00000400[IMPRECISERR|]
    UFSR : 0x00000000[]
    HFSR : 0x40000000[FORCED|]
    DFSR : 0x00000008
    MMFAR : 0xe000ed34
    BFAR : 0xe000ed38

    错误类型为“非精确的数据访问违例”。处理器自动压入堆栈的PC寄存器的数据为0x00010642,在map文件中查找字符串“0x000106”(故意抹去末尾数据),找到的两个匹配数据,但是这里两个地址都比出现错误的地址0x00010642大,错误并非发生在这两个函数中。

    FS_Lock 0x000104ef Thumb Code 24 fs.o(.text)
    FS_Unlock 0x00010507 Thumb Code 10 fs.o(.text)
    UART7816_Init 0x00010673 Thumb Code 16 uart7816.o(.text)
    UART7816_SetBaudRate 0x00010683 Thumb Code 228 uart7816.o(.text)
    UART7816_StartClock 0x00010767 Thumb Code 18 uart7816.o(.text)
    UART7816_StopClock 0x00010779 Thumb Code 28 uart7816.o(.text)

    接着扩大范围继续循环,搜索“0x000105”,结果如下(仅关注Image Symbol Table部分):

    .text 0x00010530 Section 0 uart7816.o(.text)
    _timerInit 0x00010531 Thumb Code 58 uart7816.o(.text)
    _gpioInit 0x0001056b Thumb Code 118 uart7816.o(.text)
    _uartInit 0x000105e1 Thumb Code 146 uart7816.o(.text)

    FS_Unlock 0x00010507 Thumb Code 10 fs.o(.text)

    其中和0x00010642最为接近且小于0x00010642的为函数_uartInit,且函数地址0x000105e1+146大于0x00010642,,所以确认发生错误的指令在函数_uartInit中。
    下面轮到List文件出场了,List文件实际上是编译器生成的C代码和汇编的对照表,其中_uartInit的部分内容如下:

    _uartInit PROC
    ;;;110 static void _uartInit(void)
    0000b0 48d2 LDR r0,|L1.1020|
    ;;;111 {
        ;;;112
        ;;;113 SIM_SCGC4 |= SIM_SCGC4_UART0_MASK;
        0000b2 6b40 LDR r0,[r0,#0x34]
        0000b4 f4406080 ORR r0,r0,#0x400
        0000b8 49d0 LDR r1,|L1.1020|
        0000ba 6348 STR r0,[r1,#0x34]
        ;;;114
        ;;;115 UART0_C2 &= (uint8_t)~(uint8_t)((UART_C2_TE_MASK | UART_C2_RE_MASK));
        0000bc 48d1 LDR r0,|L1.1028|
        0000be 78c0 LDRB r0,[r0,#3]
        0000c0 f00000f3 AND r0,r0,#0xf3
        0000c4 49cf LDR r1,|L1.1028|
        0000c6 70c8 STRB r0,[r1,#3]
        ;;;116
        ;;;117 UART0_BDH = UART_BDH_SBR(0x02);
        0000c8 2002 MOVS r0,#2
        0000ca 7008 STRB r0,[r1,#0]
        ;;;118
        ;;;119 UART0_BDL = UART_BDL_SBR(0xE8);
        0000cc 20e8 MOVS r0,#0xe8
        0000ce 7048 STRB r0,[r1,#1]
        ;;;120
        ;;;121 UART0_MA1 = UART_MA1_MA(0x00);
        0000d0 2000 MOVS r0,#0
        0000d2 7208 STRB r0,[r1,#8]
        ;;;122
        ;;;123 UART0_MA2 = UART_MA2_MA(0x00);
        0000d4 7248 STRB r0,[r1,#9]
        ;;;124
        ;;;125 UART0_C4 = UART_C4_BRFA(0x00);
        0000d6 7288 STRB r0,[r1,#0xa]
        ;;;126
        ;;;127 UART0_C1 = (UART_C1_M_MASK | UART_C1_PE_MASK);
        0000d8 2012 MOVS r0,#0x12
        0000da 7088 STRB r0,[r1,#2]
        ;;;128
        ;;;129 UART0_S2 = (UART_S2_LBKDIF_MASK | UART_S2_RXEDGIF_MASK);
        0000dc 20c0 MOVS r0,#0xc0
        0000de 7148 STRB r0,[r1,#5]
        ;;;130
        ;;;131 UART0_MODEM = 0x00U;
        0000e0 2000 MOVS r0,#0
        0000e2 7348 STRB r0,[r1,#0xd]
        ;;;132
        ;;;133 UART0_IR = UART_IR_TNP(0x00);
        0000e4 7388 STRB r0,[r1,#0xe]
        ;;;134
        ;;;135 UART0_TWFIFO = UART_TWFIFO_TXWATER(0x00);
        0000e6 74c8 STRB r0,[r1,#0x13]
        ;;;136
        ;;;137 UART0_RWFIFO = UART_RWFIFO_RXWATER(0x01);
        0000e8 2001 MOVS r0,#1
        0000ea 7548 STRB r0,[r1,#0x15]
        ;;;138
        ;;;139 UART0_SFIFO = UART_SFIFO_TXEMPT_MASK |
        0000ec 20c7 MOVS r0,#0xc7
        0000ee 7488 STRB r0,[r1,#0x12]
        ;;;140 UART_SFIFO_RXEMPT_MASK |
        ;;;141 UART_SFIFO_RXOF_MASK |
        ;;;142 UART_SFIFO_TXOF_MASK |
        ;;;143 UART_SFIFO_RXUF_MASK;
        ;;;144
        ;;;145 UART0_CFIFO = (UART_CFIFO_TXFLUSH_MASK | UART_CFIFO_RXFLUSH_MASK);
        0000f0 20c0 MOVS r0,#0xc0
        0000f2 7448 STRB r0,[r1,#0x11]
        ;;;146
        ;;;147 UART0_PFIFO &= (uint8_t)~(uint8_t)(
            0000f4 4608 MOV r0,r1
            0000f6 7c00 LDRB r0,[r0,#0x10]
            0000f8 f0000077 AND r0,r0,#0x77
            0000fc 7408 STRB r0,[r1,#0x10]
            ;;;148 UART_PFIFO_TXFE_MASK |
            ;;;149 UART_PFIFO_RXFE_MASK
            ;;;150 );
        ;;;151
        ;;;152 UART0_WN7816 = UART_WN7816_GTN(0x00);
        0000fe 2000 MOVS r0,#0
        000100 7708 STRB r0,[r1,#0x1c]
        ;;;153
        ;;;154 UART0_WF7816 = UART_WF7816_GTFD(0x01);
        000102 2001 MOVS r0,#1
        000104 7748 STRB r0,[r1,#0x1d]
        ;;;155
        ;;;156 UART0_WP7816A_T0 = UART_WP7816A_T0_WI_H(0x00);
        000106 2000 MOVS r0,#0
        000108 49be LDR r1,|L1.1028|
        00010a 313c ADDS r1,r1,#0x3c
        00010c 7008 STRB r0,[r1,#0]
        ;;;157 UART0_WP7816B_T0 = UART_WP7816B_T0_WI_L(0x0A);
        00010e 210a MOVS r1,#0xa
        000110 48bc LDR r0,|L1.1028|
        000112 f880103d STRB r1,[r0,#0x3d]
    ;;;158 //UART0_WP7816 = UART_WP7816_WTX(0x0A);
    ;;;159
    ;;;160 UART0_ET7816 = (UART_ET7816_TXTHRESHOLD(0x00) | UART_ET7816_RXTHRESHOLD(0x00));
    000116 2000 MOVS r0,#0
    000118 49ba LDR r1,|L1.1028|
    00011a 7788 STRB r0,[r1,#0x1e]
    ;;;161
    ;;;162 UART0_IS7816 = UART_IS7816_WT_MASK |
    00011c 20f7 MOVS r0,#0xf7
    00011e 7688 STRB r0,[r1,#0x1a]
    ;;;163 UART_IS7816_CWT_MASK |
    ;;;164 UART_IS7816_BWT_MASK |
    ;;;165 UART_IS7816_INITD_MASK |
    ;;;166 UART_IS7816_GTV_MASK |
    ;;;167 UART_IS7816_TXT_MASK |
    ;;;168 UART_IS7816_RXT_MASK;
    ;;;169
    ;;;170 UART0_IE7816 = 0x00U;
    000120 2000 MOVS r0,#0
    000122 7648 STRB r0,[r1,#0x19]
    ;;;171
    ;;;172 UART0_C7816 = (UART_C7816_INIT_MASK | UART_C7816_ISO_7816E_MASK);
    000124 2005 MOVS r0,#5
    000126 7608 STRB r0,[r1,#0x18]
    ;;;173 (void) UART0_S1;
    000128 4608 MOV r0,r1
    00012a 7900 LDRB r0,[r0,#4]
    ;;;174 (void) UART0_D;
    00012c 4608 MOV r0,r1
    00012e 79c0 LDRB r0,[r0,#7]
    ;;;175
    ;;;176 UART0_C5 &= (uint8_t)~(uint8_t)(
        000130 4608 MOV r0,r1
        000132 7ac0 LDRB r0,[r0,#0xb]
        000134 f0000010 AND r0,r0,#0x10
        000138 72c8 STRB r0,[r1,#0xb]
        ;;;177 UART_C5_TDMAS_MASK |
        ;;;178 UART_C5_RDMAS_MASK |
        ;;;179 0x4FU
        ;;;180 );
    ;;;181
    ;;;182 UART0_C3 = 0x00U;
    00013a 2000 MOVS r0,#0
    00013c 7188 STRB r0,[r1,#6]
    ;;;183
    ;;;184 UART0_C2 = 0x00U;
    00013e 70c8 STRB r0,[r1,#3]
    ;;;185
    ;;;186 return;
    ;;;187 }
    000140 4770 BX lr
    ;;;188
    ENDP
    

    出错的地址是0x00010642,相对于函数起始地址0x000105e1的偏移为0x61,根据List文件中的内容,_UartInit中第一条指令在文件中的偏移是0xb0,因此出错代码的偏移应该是0x61+0xb0 = 0x111。因此可以定位出发生错误的语句在uart7816.c中的157行。
    找到产生错误的语句后,在有针对性的查找CPU手册中串口寄存器WP7816B的部分,发现用错了头文件,的确是访问了非法的内存区域。至此,问题解决。

    相关文章

      网友评论

          本文标题:MAP 文件和 List 文件的解读(一个例子)

          本文链接:https://www.haomeiwen.com/subject/srxeuktx.html