I. Test Code
The test code is as follows:
#include <stdio.h> #include <string.h> #include <stdlib.h> void getmemory(char *p) { p=(char *)malloc(100); strcpy(p,"helloworld"); return; } void test1_printf() { printf("aefawfaeeaa /n"); return; } void test1_printf2() { int bbb = 0x5555; printf("test = %d /n",bbb); return; } void test1_printf3() { printf("aefawfaeeaa /n"); return; } void test1_printf4() { int bbb = 0x5555; printf("test = %d /n",bbb); return; } void teswtaaaaa(void ) { char*str=NULL; getmemory(str); *str = 12; printf("%s /n",str); return; } int main(int argc,char *argv[]) { test1_printf(); test1_printf2(); teswtaaaaa(); test1_printf3(); test1_printf4(); #if 0 char strss[10] = {0}; strss[11] = 6; printf("%s /n",strss); #endif return 0; }
Compilation takes Hisi3559A as an example:
Generation.o: aarch64-himix100-linux-g C C-C test.c-Wall-Werror-g
Generate executable file: aarch64-himix100-linux-gcc-o test.o-Wall-Werror-g
Explain:
- Wall: The option opens all of the most commonly used compilation warnings, strongly recommended, to catch many of the most common errors in C programming.
- Werror: Treat warnings as errors
- g:. Create a symbol table that contains a list of variable names used in the program.
Close all optimization mechanisms so that the original C code is strictly followed during program execution
II. Test Running
Put it on board and execute:
There was a mistake.
The error message is as follows:
test[1775]: unhandled level 2 translation fault (11) at 0x00000000, esr 0x92000046 pgd = ffffffc020807000 [00000000] *pgd=00000000617ac003, *pud=00000000617ac003 , *pmd=0000000000000000 CPU: 1 PID: 1775 Comm: test Tainted: P O 4.9.37 #1 Hardware name: Hisilicon HI3559AV100 DEMO Board (DT) task: ffffffc021f53000 task.stack: ffffffc02100c000 PC is at 0x4006d8 LR is at 0x4006d0 pc : [<00000000004006d8>] lr : [<00000000004006d0>] pstate: 60000000 sp : 0000007ffbbcae20 x29: 0000007ffbbcae20 x28: 0000000000000000 x27: 0000000000000000 x26: 0000000000000000 x25: 0000000000000000 x24: 0000000000000000 x23: 0000000000000000 x22: 0000000000000000 x21: 0000000000400490 x20: 0000000000000000 x19: 0000000000400728 x18: 0000000000000000 x17: 0000000000411000 x16: 0000007fabc52780 x15: 0000000000000482 x14: 0000000000000005 x13: 0000000000000000 x12: 0000000000000000 x11: 0000000000000018 x10: 0101010101010101 x9 : ffffff80ffffffc8 x8 : 0000000000000003 x7 : 000000000000007b x6 : 000000006e2f2020 x5 : 0000000000000071 x4 : 0000000000413020 x3 : 0000000000000071 x2 : 726f776f6c6c6568 x1 : 000000000000000c x0 : 0000000000000000
3. Error Analysis
3.1 ARM PC Register
PC stands for program counter, pipeline uses three stages, so instructions are divided into three stages: 1. finger fetching (loading an instruction from memory); 2. decoding (identifying the instructions to be executed); 3. execution (processing instructions and writing the results back to the register). And R15 (PC) always points to "taking" instructions, not "executing" instructions or "decoding" instructions.
3.2 ARM LR registers:
The occurrence of exceptions will lead to the interruption of the normal operation of the program, and transfer the control flow to the corresponding exception handling (exception response). After some exceptions (fiq, irq) are processed, the system also hopes to return to the source program breakpoint where the original exceptions were interrupted and continue to complete the execution of the source program (exception return). This requires a solution for recording the source process. The breakpoint position of the order so that the correct exception returns.
Similarly, there are subroutine calls and returns. When calling a subroutine in the main program (by calling instructions through subroutines), it is also necessary to record the location of the call point in the main program for the return of future subroutines.
In ARM processors, R14 is used to record breakpoints and call points, even though R14 is used as a return connection register (LR). On hardware and instruction execution, the CPU automatically completes the recording of the corresponding return point. In ARM assembly language programming, R14 and LR are universal.
When the ARM processor is abnormal, it will automatically save the current PC to the LR register.
When an error occurs, the two registers have the following values:
PC is at 0x4006d8 LR is at 0x4006d0
3.4 nm command
3.4 nm command is used to display symbol table of binary object file
aarch64-himix100-linux-nm test
It is shown as follows:
U abort@@GLIBC_2.17 0000000000411040 B __bss_end__ 0000000000411040 B _bss_end__ 0000000000411038 B __bss_start 0000000000411038 B __bss_start__ 00000000004004d8 t call_weak_fn 0000000000411038 b completed.7391 0000000000411028 D __data_start 0000000000411028 W data_start 00000000004004f0 t deregister_tm_clones 0000000000400570 t __do_global_dtors_aux 0000000000410df8 t __do_global_dtors_aux_fini_array_entry 0000000000411030 D __dso_handle 0000000000410e08 d _DYNAMIC 0000000000411038 D _edata 0000000000411040 B _end 0000000000411040 B __end__ 00000000004007a4 T _fini 00000000004005a0 t frame_dummy 0000000000410df0 t __frame_dummy_init_array_entry 00000000004007f8 r __FRAME_END__ 00000000004005e0 T getmemory 0000000000410fd8 d _GLOBAL_OFFSET_TABLE_ w __gmon_start__ 0000000000400408 T _init 0000000000410df8 t __init_array_end 0000000000410df0 t __init_array_start 00000000004007b8 R _IO_stdin_used 0000000000410e00 d __JCR_END__ 0000000000410e00 d __JCR_LIST__ 00000000004007a0 T __libc_csu_fini 0000000000400728 T __libc_csu_init U __libc_start_main@@GLIBC_2.17 00000000004006f8 T main U malloc@@GLIBC_2.17 U printf@@GLIBC_2.17 0000000000400530 t register_tm_clones 0000000000400490 T _start 0000000000400624 T test1_printf 0000000000400644 T test1_printf2 0000000000400670 T test1_printf3 0000000000400690 T test1_printf4 00000000004006bc T teswtaaaaa 0000000000411038 D __TMC_END__
3.5 objdump command
The objdump command is a command for disassembling object files or executable files under Linux. It allows you to learn more about the additional information that binary files may carry in a readable format.
aarch64-himix100-linux-objdump -x -s -d test
Intercept part of the content:
00000000004006bc <teswtaaaaa>: 4006bc: a9be7bfd stp x29, x30, [sp, #-32]! 4006c0: 910003fd mov x29, sp 4006c4: f9000fbf str xzr, [x29, #24] 4006c8: f9400fa0 ldr x0, [x29, #24] 4006cc: 97ffffc5 bl 4005e0 <getmemory> 4006d0: f9400fa0 ldr x0, [x29, #24] 4006d4: 52800181 mov w1, #0xc // #12 4006d8: 39000001 strb w1, [x0] 4006dc: 90000000 adrp x0, 400000 <_init-0x408> 4006e0: 911fc000 add x0, x0, #0x7f0 4006e4: f9400fa1 ldr x1, [x29, #24] 4006e8: 97ffff66 bl 400480 <printf@plt> 4006ec: d503201f nop 4006f0: a8c27bfd ldp x29, x30, [sp], #32 4006f4: d65f03c0 ret
You can see a specified error in the function teswtaaaaa
3.6 addr2line tool
Using the addr2line tool, sometimes you can use this tool directly to locate the number of rows in the application:
addr2line 0x4006d8 -e test -f
Print as follows:
$ addr2line 0x4006d8 -e test -f teswtaaaaa /home/lie/code_test/test.c:49
End!