[Arm] Debugging patch for stack corruption
No matter how carefully you examine the code, it's common for people to believe that the code they wrote has no issues. This belief can make it hard to spot code that causes stack corruption. In such cases, adding appropriate debugging code to the function can help identify the problem by logging the behavior.
Stack Debugging Code for 32-bit Armv7-A Architecture
First, let's look at debugging code for the 32-bit Armv7-A architecture.
01 #define GET_SP_REGISTER_DEBUG() \
02 debug_sp_register()
03
04 unsigned long sp_value;
05 unsigned long lr_value;
06
07 static inline void debug_sp_register(void)
08 {
09 asm volatile ("mov %0, sp\n" \
10 "mov %1, r14"\
11 :"=r" (sp_value), "=r" (lr_value));
12
13 printf("sp: 0x%x, x30: 0x%x \n", sp_value, lr_value);
14
15 printf("[0x%lx]: 0x%lx \n", (unsigned long)sp_value, *((unsigned long*)(sp_value + 0x0)) );
16 printf("[0x%lx]: 0x%lx \n", (unsigned long)(sp_value + 0x4), *((unsigned long*)(sp_value + 0x4)) );
17 printf("[0x%lx]: 0x%lx \n", (unsigned long)(sp_value + 0x8), *((unsigned int*)(sp_value + 0x8)) )
18 }
The debugging code above prints the stack address and the value of the link register. The key routine is implemented in the debug_sp_register() function. Let's look at lines 09-11:
09 asm volatile ("mov %0, sp\n" \
10 "mov %1, r14"\
11 :"=r" (sp_value), "=r" (lr_value));
.Lines 09-11 store the stack pointer register (sp) and the link register (r14) in the global variables sp_value and lr_value. Line 13 then prints the values of the stack pointer and link register.
Next, let's look at lines 15-17:
15 printf("[0x%lx]: 0x%lx \n", (unsigned long)sp_value, *((unsigned long*)(sp_value + 0x0)) );
16 printf("[0x%lx]: 0x%lx \n", (unsigned long)(sp_value + 0x4), *((unsigned long*)(sp_value + 0x4)) );
17 printf("[0x%lx]: 0x%lx \n", (unsigned long)(sp_value + 0x8), *((unsigned int*)(sp_value + 0x8)) )
These lines print the data stored in the stack. Running this code will display the data stored in the stack.
Now, let's look at the GET_SP_REGISTER_DEBUG() macro on lines 01-02:
01 #define GET_SP_REGISTER_DEBUG() \
02 debug_sp_register()
This macro allows you to add the GET_SP_REGISTER_DEBUG() function to your code. The compiler will replace it with a call to debug_sp_register().
You can simply add the GET_SP_REGISTER_DEBUG() macro to any function where you want to check the stack address or link register.
领英推荐
Stack Debugging Code for 64-bit Armv8-A Architecture
Now, let's look at debugging code for the 64-bit Armv8-A architecture.
01 #define GET_SP_REGISTER_DEBUG() \
02 get_sp_register_with_function(__func__, __LINE__)
03
04 unsigned long sp_value;
05 unsigned long lr_value;
06
07 static inline void debug_sp_register(void)
08 {
09 asm volatile ("mov %0, sp\n" \
10 "mov %1, x30"\
11 :"=r" (sp_value), "=r" (lr_value));
12
13 printf("sp: 0x%x, x30: 0x%x \n", sp_value, lr_value);
14
15 printf("[0x%lx]: 0x%lx \n", (unsigned long)sp_value, *((unsigned long*)(sp_value + 0x0)) );
16 printf("[0x%lx]: 0x%lx \n", (unsigned long)(sp_value + 0x8), *((unsigned long*)(sp_value + 0x8)) );
17 printf("[0x%lx]: 0x%lx \n", (unsigned long)(sp_value + 0x10), *((unsigned int*)(sp_value + 0x10)) )
18 }
The function name and code are similar, but the assembly code in lines 09-11 is different:
09 asm volatile ("mov %0, sp\n" \
10 "mov %1, x30"\
11 :"=r" (sp_value), "=r" (lr_value));
In the Armv8 architecture, the link register is x30, so line 10 uses x30 instead of r14.
How to Use the Stack Debugging Code
To use the above code, simply add the GET_SP_REGISTER_DEBUG() function to any function where you want to print the current stack address and link register values.
Here's an example of how to add it to a function:
01 int add_func(int x, int y)
02 {
03 int result = x + y;
04 GET_SP_REGISTER_DEBUG();
05
06 printf("x:%d, y:%d \n", x, y);
07
08 return result;
09 }
.By adding the GET_SP_REGISTER_DEBUG() function, you can see the stack register and the data stored in the stack in the terminal. For example:
01 sp: 0x7fe564d940 lr: 0x556b5a0b48
02 [0x7fe564d940]: 0x7fe564d960
03 [0x7fe564d948]: 0x556b5a0b48
04 [0x7fe564d950]: 0x6b5a0720
In the output, line 01 shows the stack address 0x7fe564d940 and the link register 0x556b5a0b48. Lines 02-04 show the data stored at the stack addresses.
This debugging code can be used in various ways in real-world projects to efficiently detect stack corruption. I hope you find it useful in your own projects!
Software Engineer @Sigma Connectivity . Ex-Qualcomm | Bluetooth Development, Embedded Systems
1 个月Insightful
Linux Kernel | Memory Management
1 个月Austin Kim we already have dump_stack() and current_thread_info() and similar functions, are that not enough?
Principal Engineering Manager at Qualcomm
1 个月Very informative