tcc - 在 Tiny C 下获取回溯

标签 tcc

nptrs = backtrace(buffer, SIZE);

标准 backtrace 函数在 Tiny C 下不起作用(它只返回一个地址)。如何在 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;
}

最佳答案

只需几个小时的思考,您就会得到 backtrace()它与 TinyC 兼容(令人惊讶的是,出于某种原因它也适用于 GCC,因此即使 #define __TINYC__ 也不是必需的)。

这里的技巧是使用内联汇编来获取基指针和extern __libc_stack_end为您提供堆栈的开头(尽管有名称,但请记住堆栈向下增长)。

请注意,要获取符号名称,您需要 -rdynamic来自 GCC(由于某些原因不需要 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;
}

关于tcc - 在 Tiny C 下获取回溯,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47609816/

相关文章:

c - TCC -c 选项错误

c - 微型 C 编译器 (TCC) 和 winsock?

c - Tiny C编译器: Undefined symbol "main" when main is defined?

c - 微型 C 编译器臂

c - 基本 C SDL2 程序不能与 TCC 一起工作,但它可以与 GCC (Linux) 一起工作

c - 通过实现定义的宏识别 clang、gcc 和 tcc

c - 将 token 从数组传递到 strcmp

c - TCC 和winsock.h

c - pow() 转换为整数,意外结果