Return trace for ARC platform from signal handler context

I want to catch SIGSEGV and print back trace in logs before my program exits. This is for analyzing an accident at a later point in time. I am working on software that runs on multiple platforms. On the x86 platform, I can do this easily using the glibc backtrace () function. But the same is not available for MIPS and ARC platforms. I can print backtrace for MIPS architecture as described here

I want to do something similar for the ARC platform . It would be very helpful if someone could point out some data points where I can get similar data.

"Change"

After some research, I realized that in the ARC platform, to call a function, the stack is not allocated immediately, but allocated in parts. (Correct me if I am wrong. I went through the dump of the object and figured it out.) Thus, I feel that in this case it will be difficult to parse the binary code, not MIPS.

Another approach would be to write assembly code in C and get a pointer to the stack, a pointer to a frame, and a branch link (blink), and then try to expand the stack using the stack and frame size, and the print value in each frame. But I can not find the size of the frame.

Here is a sample code to get 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; } 

Yes, this is bad coding! I made a lot of assumptions. But for me this is normal, since it works on my board. :)

Any help would be greatly appreciated. Here is another link to ARC gcc.

+4
source share
1 answer

Finally, I found some open source code ( Apache license ) that does what is required. Here is the code that works.

Sorry for the big code post.

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

I hope this will be useful for someone else too!

0
source

Source: https://habr.com/ru/post/1439121/


All Articles