c - 从信号处理程序上下文获取 ARC 平台的回溯跟踪

标签 c linux-kernel stack-trace signal-handling

我想捕获 SIGSEGV 并在我的程序退出之前在日志中打印回溯。这是为了在稍后的时间点分析崩溃。我正在开发一个在多个平台上运行的软件。在 x86 平台上,我可以使用 glibc backtrace() 函数轻松完成此操作。但同样不适用于 MIPS 和 ARC 平台。我能够按照说明打印 MIPS 架构的回溯跟踪 here

我想为 ARC platform 做类似的事情以及。如果有人可以提供一些数据点,说明我可以在哪里获得类似的详细信息,那将会很有帮助。

编辑:

经过一些研究,我发现在 ARC 平台中,对于函数调用,堆栈不是一次性分配的,而是分部分分配的。 (如果我错了请纠正我。我检查了对象转储并弄清楚了这一点。)所以我觉得在这种情况下与 MIPS 相比很难进行二进制代码解析。

另一种方法是写一些 inline assembly in C并获取堆栈指针、帧指针和分支链接寄存器内容(闪烁),然后尝试使用堆栈和帧大小以及每帧中闪烁的打印值来展开堆栈。但我无法找到帧大小。

这是获取 FP、SP、BLINK 的示例代码。

int func2(int func2_arg)
{
   unsigned long *stack2_addr;
   unsigned long *frame2_addr;
   unsigned long *blink2_addr;

   printf("\nFunc : %s\n",__FUNCTION__);

   __asm__ __volatile__ ("st sp,[sp,4]");
   printf("Stack pointer:  %d\n",stack2_addr);

   __asm__ __volatile__ ("st blink,[sp,12]");
   printf("Blink:       %d \n",blink2_addr);

   __asm__ __volatile__ ("st fp,[sp,8]");
   printf("Frame pointer2: %d, %d\n",frame2_addr,*frame2_addr);


   return 0;
}

是的,这不是好的编码!我做了很多假设。但对我来说,只要它在我的董事会上工作就很好。 :)

如有任何帮助,我们将不胜感激。 Here是关于 ARC gcc 的另一个引用。

最佳答案

终于找到了一些开源代码 ( Apache license ) 来完成所需的工作。这是有效的代码。

对于大代码帖子感到抱歉。

/*
 * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <config.h>

#include "backtrace.h"

#include <errno.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>

#include "compiler.h"
#include "vlog.h"

VLOG_DEFINE_THIS_MODULE(backtrace);

#ifdef HAVE_BACKTRACE
#include <execinfo.h>
void
backtrace_capture(struct backtrace *b)
{
    void *frames[BACKTRACE_MAX_FRAMES];
    int i;

    b->n_frames = backtrace(frames, BACKTRACE_MAX_FRAMES);
    for (i = 0; i < b->n_frames; i++) {
        b->frames[i] = (uintptr_t) frames[i];
    }
}
#elif __GNUC__
static uintptr_t
get_max_stack(void)
{
    static const char file_name[] = "/proc/self/maps";
    char line[1024];
    int line_number;
    FILE *f;

    f = fopen(file_name, "r");
    if (f == NULL) {
        VLOG_WARN("opening %s failed: %s", file_name, strerror(errno));
        return -1;
    }

    for (line_number = 1; fgets(line, sizeof line, f); line_number++) {
        if (strstr(line, "[stack]")) {
            uintptr_t end;
            if (sscanf(line, "%*x-%"SCNxPTR, &end) != 1) {
                VLOG_WARN("%s:%d: parse error", file_name, line_number);
                continue;
            }
            fclose(f);
            return end;
        }
    }
    fclose(f);

    VLOG_WARN("%s: no stack found", file_name);
    return -1;
}

static uintptr_t
stack_high(void)
{
    static uintptr_t high;
    if (!high) {
        high = get_max_stack();
    }
    return high;
}

static uintptr_t
stack_low(void)
{
    uintptr_t low = (uintptr_t) &low;
    return low;
}

static bool
in_stack(void *p)
{
    uintptr_t address = (uintptr_t) p;
    return address >= stack_low() && address < stack_high();
}

void
backtrace_capture(struct backtrace *backtrace)
{
    void **frame;
    size_t n;

    n = 0;
    for (frame = __builtin_frame_address(1);
         frame != NULL && in_stack(frame) && frame[0] != NULL
             && n < BACKTRACE_MAX_FRAMES;
         frame = frame[0])
    {
        backtrace->frames[n++] = (uintptr_t) frame[1];
    }
    backtrace->n_frames = n;
}
#else  /* !HAVE_BACKTRACE && !__GNUC__ */
void
backtrace_capture(struct backtrace *backtrace)
{
    backtrace->n_frames = 0;
}
#endif

希望这对其他人也有用!

关于c - 从信号处理程序上下文获取 ARC 平台的回溯跟踪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12837218/

相关文章:

c++ - 在 OS/X (10.5.7) 中生成 C++ BackTraces

c - 如何计算C中的内存消耗

c++ - C++/C 中以太网 ip 中的 eth_dr 是什么?

java - 如何在jni中创建CBTHook,然后在回调函数中调用java函数?

c - 如何在 Linux 源代码中包含用户级 C 程序以与 Linux 内核一起编译?

c++ - 如何在 Netbeans C++ IDE 中获取堆栈跟踪

android - 解决 'application has stopped' 崩溃错误

c++ - 库定义位于何处?

linux - 理解从进程内核栈中获取task_struct指针

linux - 如何在 linux 进程中找到属于堆的页面?