4

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

我也想为ARC 平台做类似的事情。如果有人可以提供一些关于我在哪里可以获得类似详细信息的数据点,那将是非常有帮助的。

编辑:

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

另一种方法是在 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;
}

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

任何帮助将不胜感激。是关于 ARC gcc 的另一个参考资料。

4

1 回答 1

0

最后找到了一些可以满足要求的开源代码(Apache 许可证)。这是有效的代码。

对大代码帖子感到抱歉。

/*
 * 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

希望这对其他人也有用!

于 2012-11-29T15:47:03.070 回答