// Backtrace handling part of i77 perms.

#define _POSIX_C_SOURCE 200809L

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
#include <unistd.h>
#include <string.h>
#include <backtrace.h>

#include "pbacktrace.h"

void *__bt_state = NULL;
static int bt_started = 0;

int bt_callback(void *v, uintptr_t u, const char *filename, int lineno, const char *function) {
  const char *func_name = function;
  int status;

  if ((filename || lineno || func_name) && (strcmp(func_name, "print_back_trace"))) {
    if (!bt_started) {
      fprintf(stderr, "\nMONITOR ENTERED FROM IMP\n\n"); bt_started = 1;
    }
    fprintf(stderr, "Entered from %s at %s:%d\n\n", func_name, filename, lineno);
  }
  return 0;
}

void bt_error_callback(void *v, const char *msg, int errnum) {
  if (strcmp(msg, "no debug info in ELF executable")) {
    fprintf(stderr, "Error %d occurred when getting the stacktrace: %s", errnum, msg);
  }
}

void bt_error_callback_create(void *v, const char *msg, int errnum) {
  fprintf(stderr, "Error %d occurred when initializing the stacktrace: %s", errnum, msg);
}

void init_back_trace(const char *filename) {
  __bt_state = backtrace_create_state(filename, 0, bt_error_callback_create, NULL);
}

void print_back_trace(void) {
  if (!__bt_state) { /// make sure init_back_trace() is called
    fprintf(stderr, "Make sure init_back_trace() is called before calling print_stack_trace()\n");
    abort();
  }
  bt_started = 0;
  backtrace_full((struct backtrace_state *) __bt_state, 0, bt_callback, bt_error_callback, NULL);
  bt_started = 0;
}
