我想捕获 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/