4

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

I want to do something similar for ARC platform as well. It would be great help if someone can give some data points on where I can get similar details.

Edit:

After some research I figured out that in ARC platform for a function call, stack is not allocated at once but allocated in parts. (Correct me if I am wrong. I went through the object dump and figured this out.) So I feel it will be hard to do binary code parsing in this case as opposed to MIPS.

Another approach would be to write some inline assembly in C and get stack pointer, frame pointer and branch link register content (blink) and then try to unwind the stack using stack & frame size and print value of blink in each frame. But I am not able to find the frame size.

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 not good coding! I have made many assumptions. But for me it is fine as far as it is working on my board. :)

Any help would be greatly appreciated. Here is another reference on ARC gcc.

Community
  • 1
  • 1
CCoder
  • 2,305
  • 19
  • 41

1 Answers1

0

Finally found some open source code (Apache license) which does what was required. Here is the code which works.

Sorry about 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

Hope this will be useful for someone else also !

CCoder
  • 2,305
  • 19
  • 41