prod/native/libcommon/code/os/StackTraceCapture.cpp (57 lines of code) (raw):
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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 "StackTraceCapture.h"
#include "CommonUtils.h"
#include "os/OsUtils.h"
#include <cstring>
#ifndef __USE_GNU
#define __USE_GNU 1
#endif
#include <dlfcn.h>
#include <libunwind.h>
namespace elasticapm::osutils {
std::string getStackTrace(size_t numberOfFramesToSkip) {
unw_cursor_t unwindCursor;
unw_context_t unwindContext;
constexpr size_t funcNameBufferSize = 100;
char funcNameBuffer[funcNameBufferSize];
unw_word_t offsetInsideFunc;
if (unw_getcontext(&unwindContext) < 0) {
return {};
}
if (unw_init_local(&unwindCursor, &unwindContext) < 0) {
return {};
}
std::string output;
for (size_t frameIndex = 0;; ++frameIndex) {
// +1 is for this function frame
if (frameIndex >= numberOfFramesToSkip + 1) {
unw_proc_info_t pi;
if (unw_get_proc_info(&unwindCursor, &pi) == 0) {
*funcNameBuffer = 0;
offsetInsideFunc = 0;
int getProcNameRetVal = unw_get_proc_name(&unwindCursor, funcNameBuffer, funcNameBufferSize, &offsetInsideFunc);
if (getProcNameRetVal != UNW_ESUCCESS && getProcNameRetVal != -UNW_ENOMEM) {
strcpy(funcNameBuffer, "???");
unw_word_t pc;
unw_get_reg(&unwindCursor, UNW_REG_IP, &pc);
offsetInsideFunc = pc - pi.start_ip;
}
Dl_info dlInfo;
if (dladdr((const void *)pi.gp, &dlInfo)) {
output.append(elasticapm::utils::stringPrintf("%s(%s+0x%lx) ModuleBase: %p FuncStart: 0x%lx FuncEnd: 0x%lx FuncStartRelative: 0x%lx FuncOffsetRelative: 0x%lx\n\t'addr2line -afCp -e \"%s\" %lx'\n", dlInfo.dli_fname ? dlInfo.dli_fname : "???", dlInfo.dli_sname ? dlInfo.dli_sname : funcNameBuffer, offsetInsideFunc, dlInfo.dli_fbase, pi.start_ip, pi.end_ip, pi.start_ip - reinterpret_cast<unw_word_t>(dlInfo.dli_fbase), pi.start_ip - reinterpret_cast<unw_word_t>(dlInfo.dli_fbase) + offsetInsideFunc, dlInfo.dli_fname ? dlInfo.dli_fname : "???", pi.start_ip - reinterpret_cast<unw_word_t>(dlInfo.dli_fbase) + offsetInsideFunc));
} else {
output.append(elasticapm::utils::stringPrintf("dladdr failed on frame %zu\n", frameIndex));
}
} else {
output.append(elasticapm::utils::stringPrintf("unw_get_proc_info failed on frame %zu", frameIndex));
}
}
int unwindStepRetVal = 0;
unwindStepRetVal = unw_step(&unwindCursor);
if (unwindStepRetVal < 0) {
return output;
} else if (unwindStepRetVal == 0) {
break;
}
}
return output;
}
}