/*************************************************************************
 * Copyright (C) [2023-2024] by Cambricon, Inc.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *************************************************************************/
#ifdef __GNUC__

#include "stack_exception.h"
#include <cxxabi.h>
#include <dlfcn.h>
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX_DEPTH 32

namespace tmo {
namespace stack_exception {

call_stack::call_stack(const size_t num_discard /*= 0*/) {
  using namespace abi;

  // retrieve call-stack
  void *trace[MAX_DEPTH];
  int stack_depth = backtrace(trace, MAX_DEPTH);

  for (int i = num_discard + 1; i < stack_depth; i++) {
    Dl_info dlinfo;
    if (!dladdr(trace[i], &dlinfo)) break;

    const char *symname = dlinfo.dli_sname;

    int status;
    char *demangled = abi::__cxa_demangle(symname, NULL, 0, &status);
    if (status == 0 && demangled) symname = demangled;

    // printf("entry: %s, %s\n", dlinfo.dli_fname,symname);

    // store entry to stack
    if (dlinfo.dli_fname && symname) {
      entry e;
      e.file = dlinfo.dli_fname;
      e.line = 0;  // unsupported
      e.function = symname;
      stack.push_back(e);
    } else {
      break;  // skip last entries below main
    }

    if (demangled) free(demangled);
  }
}

call_stack::~call_stack() throw() {
  // automatic cleanup
}
}  // namespace stack_exception
}  // namespace tmo

#endif  // __GNUC__
