在 Tiny C 下获取回溯
Get backtrace under Tiny C
nptrs = backtrace(buffer, SIZE);
标准 backtrace
函数在 Tiny C 下不起作用,(它只 returns 一个地址)。如何在 Tiny C 编译程序中获取当前堆栈跟踪?
更新:
我试过像这样的手动堆栈遍历 found on git hub,同样它只适用于 GCC 但不适用于 Tiny:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#define CALL_OFFSET 5
#define RELATIVE_ADDR_OFFSET 4
#define CALL_CMD 0xe8
extern uint8_t _start;
extern uint8_t _etext;
extern void *__libc_stack_end;
typedef uint8_t * pointer;
void stack_show() {
uint8_t shift = 1;
uint8_t stack_top = 0;
pointer ptr = &stack_top;
while((ptr + 3) <= (pointer)__libc_stack_end) {
uint32_t * lbs = (uint32_t *)ptr;
uint32_t * mbs = (uint32_t *)(ptr+3);
uint64_t addr = ((*(mbs))<<16) | *lbs;
if(addr > CALL_OFFSET &&
(addr - CALL_OFFSET) >= (uint64_t)&_start &&
addr < (uint64_t)&_etext) {
if(*(pointer)(addr - CALL_OFFSET) == CALL_CMD) {
uint64_t fun_addr = *(int*)(addr - RELATIVE_ADDR_OFFSET) + *(int*)ptr;
if(fun_addr >= (uint64_t)&_start && fun_addr < (uint64_t)&_etext)
printf("%016llx\n", fun_addr);
}
}
ptr += shift;
}
return;
}
仅仅几个小时的思考,你就得到了与 TinyC 兼容的 backtrace()
(令人惊讶的是,出于某种原因它也适用于 GCC,所以即使 #define __TINYC__
也不是必需的)。
这里的技巧是使用内联汇编来获取基指针,extern __libc_stack_end
给你堆栈的开头(尽管有这个名字,记住堆栈向下增长)。
请注意,要从 GCC 中获取符号名称,您需要 -rdynamic
(由于某些原因 tcc
不需要),而且如果您使用 -run
选项,则符号不可用TinyC 或 运行 它从 RAM 中嵌入。
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <stdint.h>
#ifdef __TINYC__
int backtrace(void **buffer, int size) {
extern uint64_t *__libc_stack_end;
uint64_t **p, *bp, *frame;
asm ("mov %%rbp, %0;" : "=r" (bp));
p = (uint64_t**) bp;
int i = 0;
while (i < size) {
frame = p[0];
if (frame < bp || frame > __libc_stack_end) {
return i;
}
buffer[i++] = p[1];
p = (uint64_t**) frame;
}
return i;
}
#endif
// Below is a demonstration of use, note that backtrace_symbols() is compatible
// with our backtrace replacement.
void show() {
void *buffer[10];
int size = backtrace(buffer, 10);
char **strings = backtrace_symbols(buffer, size);
if (strings == NULL) {
perror("backtrace_symbols");
exit(EXIT_FAILURE);
}
for (int j = 0; j < size; j++) {
printf("%s\n", strings[j]);
}
free(strings);
}
void d() {
show(); // show current back trace here
}
int c(uint64_t a, uint64_t b) {
d();
return a + b;
}
void b(int x, int y, int z, int zz) {
c(100, 200);
}
void a() {
b(1,2,3,4);
}
int main(){
a();
return 0;
}
nptrs = backtrace(buffer, SIZE);
标准 backtrace
函数在 Tiny C 下不起作用,(它只 returns 一个地址)。如何在 Tiny C 编译程序中获取当前堆栈跟踪?
更新:
我试过像这样的手动堆栈遍历 found on git hub,同样它只适用于 GCC 但不适用于 Tiny:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#define CALL_OFFSET 5
#define RELATIVE_ADDR_OFFSET 4
#define CALL_CMD 0xe8
extern uint8_t _start;
extern uint8_t _etext;
extern void *__libc_stack_end;
typedef uint8_t * pointer;
void stack_show() {
uint8_t shift = 1;
uint8_t stack_top = 0;
pointer ptr = &stack_top;
while((ptr + 3) <= (pointer)__libc_stack_end) {
uint32_t * lbs = (uint32_t *)ptr;
uint32_t * mbs = (uint32_t *)(ptr+3);
uint64_t addr = ((*(mbs))<<16) | *lbs;
if(addr > CALL_OFFSET &&
(addr - CALL_OFFSET) >= (uint64_t)&_start &&
addr < (uint64_t)&_etext) {
if(*(pointer)(addr - CALL_OFFSET) == CALL_CMD) {
uint64_t fun_addr = *(int*)(addr - RELATIVE_ADDR_OFFSET) + *(int*)ptr;
if(fun_addr >= (uint64_t)&_start && fun_addr < (uint64_t)&_etext)
printf("%016llx\n", fun_addr);
}
}
ptr += shift;
}
return;
}
仅仅几个小时的思考,你就得到了与 TinyC 兼容的 backtrace()
(令人惊讶的是,出于某种原因它也适用于 GCC,所以即使 #define __TINYC__
也不是必需的)。
这里的技巧是使用内联汇编来获取基指针,extern __libc_stack_end
给你堆栈的开头(尽管有这个名字,记住堆栈向下增长)。
请注意,要从 GCC 中获取符号名称,您需要 -rdynamic
(由于某些原因 tcc
不需要),而且如果您使用 -run
选项,则符号不可用TinyC 或 运行 它从 RAM 中嵌入。
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <stdint.h>
#ifdef __TINYC__
int backtrace(void **buffer, int size) {
extern uint64_t *__libc_stack_end;
uint64_t **p, *bp, *frame;
asm ("mov %%rbp, %0;" : "=r" (bp));
p = (uint64_t**) bp;
int i = 0;
while (i < size) {
frame = p[0];
if (frame < bp || frame > __libc_stack_end) {
return i;
}
buffer[i++] = p[1];
p = (uint64_t**) frame;
}
return i;
}
#endif
// Below is a demonstration of use, note that backtrace_symbols() is compatible
// with our backtrace replacement.
void show() {
void *buffer[10];
int size = backtrace(buffer, 10);
char **strings = backtrace_symbols(buffer, size);
if (strings == NULL) {
perror("backtrace_symbols");
exit(EXIT_FAILURE);
}
for (int j = 0; j < size; j++) {
printf("%s\n", strings[j]);
}
free(strings);
}
void d() {
show(); // show current back trace here
}
int c(uint64_t a, uint64_t b) {
d();
return a + b;
}
void b(int x, int y, int z, int zz) {
c(100, 200);
}
void a() {
b(1,2,3,4);
}
int main(){
a();
return 0;
}