Function stack tracing and broadcom6838 functions are implemented in the broadcom6838 development environment.
In the development of embedded devices, the kernel provides good support for function stack tracing of kernel modules, but function stack tracing at the user layer does not provide good support. Collecting and learning function stack traces on the Internet mostly describe the implementation mechanism of the INTER architecture supporting stack frames, or directly provide glibc ready-made library functions. However, if the development environment is a broadcom-related solution, we usually use the MIPS32 architecture, and the C library uses a smaller uclibc, although the MIPS32 architecture also defines the stack frame register s8 (similar to the ebp register common in the Inter architecture), after the optimization Option Control of the GCC compiler, the optimization above O1 usually removes the use of the s8 stack frame, so it brings a little trouble to the implementation of function stack tracing.
Generally, the return value of a function is implemented by using the pressure stack. Therefore, you only need to know the offset between the return value (ra register) and the top (sp register) of the current stack for each function call, function stack tracing can be implemented. For function disassembly, we can see that this offset can be obtained through sw ra and xxxx (sp, another difficulty is how to obtain the top of the current stack (sp register) for each function call. Through function disassembly, we can learn about addiu sp, sp, the xxxx command allocates the current stack frame size to the function each time. Therefore, you only need to obtain the stack frame size and calculate the difference value using sp to roll back the value of the previous sp, the last question remains. How can I get the top of the stack of the previous function step by step? The answer is that as long as the top sp register of the stack is 0, it will be traced to the header. Through these analyses, we can understand that the current implementation mechanism is not used in the stack segment of the program, taking the program instruction segment as a clue completely, it looks cool to obtain the code for calling the function stack step by step when running the program, but the reality is also cruel, for example, the above analysis shows that if the register of the top sp on the stack is 0, it indicates tracing to the header. My current debugging environment is in _ start (refer to some related technical materials for Link loading, other main is not the starting function of c, __start is the starting function of c language.) In the function, make the Assembly command of sp 0 addu ra, zero, zero, I still don't know whether other compilers will use other instruction methods for setting, so the implementation code of the function stack tracing function we currently implement is not very standard, if you are lucky to refer to this code, you must understand the principles described above and debug it in your own compiling and development environment, make sure that the tracing function code will not trigger Crash and use it again. Otherwise, the joke will be too big.
I will not talk about the rest. I will directly pay for my current development environment and implementation source code, as well as the testing program that will eventually run on the broadcom6838 board.
Development Environment:
Architecture: mips32GCC version: gcc-4.6 kernel version: linux-3.4C library version: uclibc-0.9.32 tool Version: binutils-2.21
Source code:
#include <stdio.h>#include <string.h>#include <stdlib.h>#include <signal.h>#include <ucontext.h>#define abs(s) ((s) < 0 ? -(s) : (s))#define CALL_TRACE_MAX_SIZE (10)#define MIPS_ADDIU_SP_SP_XXXX (0x27bd0000) /* instruction code for addiu sp, sp, xxxx */#define MIPS_SW_RA_XXXX_SP (0xafbf0000) /* instruction code for sw ra, xxxx(sp) */#define MIPS_ADDU_RA_ZERO_ZERO (0x0000f821) /* instruction code for addu ra, zero, zero */int backtrace_mips32(void **buffer, int size, ucontext_t *uc){ unsigned long *addr = NULL; unsigned long *ra = NULL; unsigned long *sp = NULL; unsigned long *pc = NULL; size_t ra_offset = 0; size_t stack_size = 0; int depth = 0; if (size == 0) { return 0; } if (buffer == NULL || size < 0 || uc == NULL) { return -1; } pc = (unsigned long *)(unsigned long)uc->uc_mcontext.pc; ra = (unsigned long *)(unsigned long)uc->uc_mcontext.gregs[31]; sp = (unsigned long *)(unsigned long)uc->uc_mcontext.gregs[29]; buffer[0] = pc; if ( size == 1 ) { return 1; } for ( addr = pc; !ra_offset || !stack_size; --addr ) { if ( ((*addr) & 0xffff0000) == MIPS_SW_RA_XXXX_SP) { ra_offset = (short)((*addr) & 0xffff); } else if ( ((*addr) & 0xffff0000) == MIPS_ADDIU_SP_SP_XXXX) { stack_size = abs((short)((*addr) & 0xffff)); } else if ( (*addr) == MIPS_ADDU_RA_ZERO_ZERO ) { return 1; } } if ( ra_offset > 0 ) { ra = *(unsigned long *)((unsigned long)sp + ra_offset); } if ( stack_size > 0 ) { sp = (unsigned long *)((unsigned long)sp + stack_size); } for (depth = 1; depth < size && ra; ++depth) { buffer[depth] = ra; ra_offset = 0; stack_size = 0; for (addr = ra; !ra_offset || !stack_size; --addr) { if ( ((*addr) & 0xffff0000) == MIPS_SW_RA_XXXX_SP) { ra_offset = (short)((*addr) & 0xffff); } else if ( ((*addr) & 0xffff0000) == MIPS_ADDIU_SP_SP_XXXX) { stack_size = abs((short)((*addr) & 0xffff)); } else if ( (*addr) == MIPS_ADDU_RA_ZERO_ZERO ) { return depth + 1; } } ra = *(unsigned long *)((unsigned long)sp + ra_offset); sp = (unsigned long *)((unsigned long)sp + stack_size); } return depth;}void signal_process(int sig_no, siginfo_t *sig_info, void *ucontext){ int i = 0; unsigned long *callStack[CALL_TRACE_MAX_SIZE] = {0}; printf("\r\n*******************************************\r\n"); printf("recv signo %d\r\n", sig_no); backtrace_mips32((void **)callStack, CALL_TRACE_MAX_SIZE, (ucontext_t *)ucontext); printf("\r\ncall tracing:\r\n"); for ( i = 0; i < CALL_TRACE_MAX_SIZE; i++ ) { if ( callStack[i] == 0 ) { break; } printf("\t[%d] addr 0x%x\r\n", i, callStack[i]); } printf("*******************************************\r\n"); if (sig_no == SIGSEGV) { signal(sig_no, SIG_DFL); } sleep(3);}void c(void){ int *p = 0; printf("I am function [c]\r\n"); *p = 888;}void b(void){ printf("I am function [b]\r\n"); c();}void a(void){ printf("I am function [a]\r\n"); b();}int main(int argc, char *argv[]){ struct sigaction act = {0}; act.sa_handler = signal_process; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &act, NULL); printf("I am function [main]\r\n"); a(); return 0;}
Run:
How can I quickly jump to a subfunction when viewing code in the vs2005 development environment and jump back to the called position from the subfunction?
Check that the sub-function is F12. If it is skipped, Shift + Ctrl + 8.
Can I customize functions in the VB development environment? Can there be a return value?
Yes
Private (publish) function name () as return value type
End function
This is a UDF.
Return Value = function name