Skip to content

Commit 573aec4

Browse files
authored
DPL: factorise out backtrace support (#13333)
1 parent bc871a0 commit 573aec4

File tree

8 files changed

+166
-120
lines changed

8 files changed

+166
-120
lines changed

Framework/Core/src/DataProcessingDevice.cxx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ void DataProcessingDevice::Init()
431431
auto& err = error_from_ref(e);
432432
O2_SIGNPOST_ID_FROM_POINTER(cid, device, &context);
433433
O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "Init", "Exception caught while in Init: %{public}s. Invoking errorCallback.", err.what);
434-
demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO);
434+
BacktraceHelpers::demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO);
435435
auto& stats = ref.get<DataProcessingStats>();
436436
stats.updateStats({(int)ProcessingStatsId::EXCEPTION_COUNT, DataProcessingStats::Op::Add, 1});
437437
InitErrorContext errorContext{ref, e};
@@ -446,7 +446,7 @@ void DataProcessingDevice::Init()
446446
auto& context = ref.get<DataProcessorContext>();
447447
O2_SIGNPOST_ID_FROM_POINTER(cid, device, &context);
448448
O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "Init", "Exception caught while in Init: %{public}s. Exiting with 1.", err.what);
449-
demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO);
449+
BacktraceHelpers::demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO);
450450
auto& stats = ref.get<DataProcessingStats>();
451451
stats.updateStats({(int)ProcessingStatsId::EXCEPTION_COUNT, DataProcessingStats::Op::Add, 1});
452452
exit(1);
@@ -1111,7 +1111,7 @@ void DataProcessingDevice::fillContext(DataProcessorContext& context, DeviceCont
11111111
auto& context = ref.get<DataProcessorContext>();
11121112
O2_SIGNPOST_ID_FROM_POINTER(cid, device, &context);
11131113
O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "Run", "Exception while running: %{public}s. Invoking callback.", err.what);
1114-
demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO);
1114+
BacktraceHelpers::demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO);
11151115
auto& stats = ref.get<DataProcessingStats>();
11161116
stats.updateStats({(int)ProcessingStatsId::EXCEPTION_COUNT, DataProcessingStats::Op::Add, 1});
11171117
ErrorContext errorContext{record, ref, e};
@@ -1126,7 +1126,7 @@ void DataProcessingDevice::fillContext(DataProcessorContext& context, DeviceCont
11261126
ServiceRegistryRef ref{serviceRegistry, ServiceRegistry::globalDeviceSalt()};
11271127
auto& context = ref.get<DataProcessorContext>();
11281128
O2_SIGNPOST_ID_FROM_POINTER(cid, device, &context);
1129-
demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO);
1129+
BacktraceHelpers::demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO);
11301130
auto& stats = ref.get<DataProcessingStats>();
11311131
stats.updateStats({(int)ProcessingStatsId::EXCEPTION_COUNT, DataProcessingStats::Op::Add, 1});
11321132
switch (errorPolicy) {

Framework/Core/src/runDataProcessing.cxx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
1212
#include <stdexcept>
1313
#include "Framework/BoostOptionsRetriever.h"
14+
#include "Framework/BacktraceHelpers.h"
1415
#include "Framework/CallbacksPolicy.h"
1516
#include "Framework/ChannelConfigurationPolicy.h"
1617
#include "Framework/ChannelMatching.h"
@@ -656,7 +657,7 @@ void handle_crash(int sig)
656657
auto retVal = write(STDERR_FILENO, buffer, strlen(buffer));
657658
(void)retVal;
658659
}
659-
demangled_backtrace_symbols(array, size, STDERR_FILENO);
660+
BacktraceHelpers::demangled_backtrace_symbols(array, size, STDERR_FILENO);
660661
{
661662
char const* msg = "Backtrace complete.\n";
662663
int len = strlen(msg); /* the byte length of the string */
@@ -982,7 +983,7 @@ void doDPLException(RuntimeErrorRef& e, char const* processName)
982983
" Reason: {}"
983984
"\n Backtrace follow: \n",
984985
processName, err.what);
985-
demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO);
986+
BacktraceHelpers::demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO);
986987
} else {
987988
LOGP(fatal,
988989
"Unhandled o2::framework::runtime_error reached the top of main of {}, device shutting down."
@@ -1928,7 +1929,7 @@ int runStateMachine(DataProcessorSpecs const& workflow,
19281929
} catch (o2::framework::RuntimeErrorRef ref) {
19291930
auto& err = o2::framework::error_from_ref(ref);
19301931
#ifdef DPL_ENABLE_BACKTRACE
1931-
demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO);
1932+
BacktraceHelpers::demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO);
19321933
#endif
19331934
LOGP(error, "invalid workflow in {}: {}", driverInfo.argv[0], err.what);
19341935
return 1;
@@ -2059,7 +2060,7 @@ int runStateMachine(DataProcessorSpecs const& workflow,
20592060
LOGP(error, "unable to merge configurations in {}: {}", driverInfo.argv[0], err.what);
20602061
#ifdef DPL_ENABLE_BACKTRACE
20612062
std::cerr << "\nStacktrace follows:\n\n";
2062-
demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO);
2063+
BacktraceHelpers::demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO);
20632064
#endif
20642065
return 1;
20652066
}

Framework/Foundation/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/Framework
1616
o2_add_library(FrameworkFoundation
1717
SOURCES src/RuntimeError.cxx
1818
src/Signpost.cxx
19+
src/BacktraceHelpers.cxx
1920
TARGETVARNAME targetName
2021
PUBLIC_LINK_LIBRARIES O2::FrameworkFoundation3rdparty
2122
)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
#ifndef O2_FRAMEWORK_BACKTRACE_HELPERS_H_
12+
#define O2_FRAMEWORK_BACKTRACE_HELPERS_H_
13+
14+
namespace o2::framework
15+
{
16+
struct BacktraceHelpers {
17+
static constexpr unsigned int MAX_BACKTRACE_SIZE = 100;
18+
static void demangled_backtrace_symbols(void** backtrace, unsigned int total, int fd);
19+
};
20+
} // namespace o2::framework
21+
22+
#endif // O2_FRAMEWORK_BACKTRACE_HELPERS_H_

Framework/Foundation/include/Framework/RuntimeError.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,23 @@
1111
#ifndef O2_FRAMEWORK_RUNTIMEERROR_H_
1212
#define O2_FRAMEWORK_RUNTIMEERROR_H_
1313

14+
#include "BacktraceHelpers.h"
15+
1416
namespace o2::framework
1517
{
1618

1719
struct RuntimeError {
1820
static constexpr unsigned int MAX_RUNTIME_ERRORS = 64;
1921
static constexpr unsigned int MAX_RUNTIME_ERROR_SIZE = 1024;
20-
static constexpr unsigned int MAX_BACKTRACE_SIZE = 100;
2122
char what[MAX_RUNTIME_ERROR_SIZE];
22-
void* backtrace[MAX_BACKTRACE_SIZE];
23+
void* backtrace[BacktraceHelpers::MAX_BACKTRACE_SIZE];
2324
int maxBacktrace = 0;
2425
};
2526

2627
struct RuntimeErrorRef {
2728
int index = 0;
2829
};
2930

30-
void demangled_backtrace_symbols(void** backtrace, unsigned int total, int fd);
31-
3231
RuntimeErrorRef runtime_error(const char*);
3332
RuntimeErrorRef runtime_error_f(const char*, ...);
3433
RuntimeError& error_from_ref(RuntimeErrorRef);
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
#include "Framework/BacktraceHelpers.h"
12+
#include <climits>
13+
#include <cstddef>
14+
#include <cstdio>
15+
#include <cstdlib>
16+
#include <unistd.h>
17+
#include <cxxabi.h>
18+
#include <execinfo.h>
19+
20+
namespace o2::framework
21+
{
22+
23+
void BacktraceHelpers::demangled_backtrace_symbols(void** stackTrace, unsigned int stackDepth, int fd)
24+
{
25+
char** stackStrings;
26+
stackStrings = backtrace_symbols(stackTrace, stackDepth);
27+
char exe[PATH_MAX];
28+
bool hasExe = false;
29+
int exeSize = 0;
30+
31+
#if __linux__
32+
exeSize = readlink("/proc/self/exe", exe, PATH_MAX);
33+
if (exeSize == -1) {
34+
dprintf(fd, "Unable to detect exectuable name\n");
35+
hasExe = false;
36+
} else {
37+
dprintf(fd, "Executable is %.*s\n", exeSize, exe);
38+
hasExe = true;
39+
}
40+
#endif
41+
42+
for (size_t i = 1; i < stackDepth; i++) {
43+
44+
size_t sz = 64000; // 64K ought to be enough for our templates...
45+
char* function = static_cast<char*>(malloc(sz));
46+
char *begin = nullptr, *end = nullptr;
47+
// find the last space and address offset surrounding the mangled name
48+
#if __APPLE__
49+
for (char* j = stackStrings[i]; *j; ++j) {
50+
if (*j == ' ' && *(j + 1) != '+') {
51+
begin = j;
52+
} else if (*j == ' ' && *(j + 1) == '+') {
53+
end = j;
54+
break;
55+
}
56+
}
57+
bool tryAddr2Line = false;
58+
#else
59+
for (char* j = stackStrings[i]; j && *j; ++j) {
60+
if (*j == '(') {
61+
begin = j;
62+
} else if (*j == '+') {
63+
end = j;
64+
break;
65+
}
66+
}
67+
bool tryAddr2Line = true;
68+
#endif
69+
if (begin && end) {
70+
*begin++ = '\0';
71+
*end = '\0';
72+
// found our mangled name, now in [begin, end)
73+
74+
int status;
75+
char* ret = abi::__cxa_demangle(begin, function, &sz, &status);
76+
if (ret) {
77+
// return value may be a realloc() of the input
78+
function = ret;
79+
dprintf(fd, " %s: %s\n", stackStrings[i], function);
80+
tryAddr2Line = false;
81+
}
82+
}
83+
if (tryAddr2Line) {
84+
// didn't find the mangled name, just print the whole line
85+
dprintf(fd, " %s: ", stackStrings[i]);
86+
if (stackTrace[i] && hasExe) {
87+
char syscom[4096 + PATH_MAX];
88+
89+
// Find c++filt from the environment
90+
// This is needed for platforms where we still need c++filt -r
91+
char const* cxxfilt = getenv("CXXFILT");
92+
if (cxxfilt == nullptr) {
93+
cxxfilt = "c++filt";
94+
}
95+
// Do the same for addr2line, just in case we wanted to pass some options
96+
char const* addr2line = getenv("ADDR2LINE");
97+
if (addr2line == nullptr) {
98+
addr2line = "addr2line";
99+
}
100+
snprintf(syscom, 4096, "%s %p -p -s -f -e %.*s 2>/dev/null | %s ", addr2line, stackTrace[i], exeSize, exe, cxxfilt); // last parameter is the name of this app
101+
102+
FILE* fp;
103+
char path[1024];
104+
105+
fp = popen(syscom, "r");
106+
if (fp == nullptr) {
107+
dprintf(fd, "-- no source could be retrieved --\n");
108+
continue;
109+
}
110+
111+
while (fgets(path, sizeof(path) - 1, fp) != nullptr) {
112+
dprintf(fd, " %s", path);
113+
}
114+
115+
pclose(fp);
116+
} else {
117+
dprintf(fd, "-- no source avaliable --\n");
118+
}
119+
}
120+
free(function);
121+
}
122+
free(stackStrings); // malloc()ed by backtrace_symbols
123+
fsync(fd);
124+
}
125+
} // namespace o2::framework

0 commit comments

Comments
 (0)