Skip to content

Commit

Permalink
Stack backtrace in exceptions (#2100)
Browse files Browse the repository at this point in the history
- print the backtrace when unexpected exceptions are caught at the top
  level
  • Loading branch information
Chris Dodd authored Dec 1, 2019
1 parent 7029f1d commit 75df252
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 19 deletions.
6 changes: 3 additions & 3 deletions backends/bmv2/psa_switch/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ int main(int argc, char *const argv[]) {
P4::FrontEnd frontend;
frontend.addDebugHook(hook);
program = frontend.run(options, program);
} catch (const Util::P4CExceptionBase &bug) {
} catch (const std::exception &bug) {
std::cerr << bug.what() << std::endl;
return 1;
}
Expand Down Expand Up @@ -107,7 +107,7 @@ int main(int argc, char *const argv[]) {
return 1;
if (options.dumpJsonFile)
JSONGenerator(*openFile(options.dumpJsonFile, true), true) << program << std::endl;
} catch (const Util::P4CExceptionBase &bug) {
} catch (const std::exception &bug) {
std::cerr << bug.what() << std::endl;
return 1;
}
Expand All @@ -121,7 +121,7 @@ int main(int argc, char *const argv[]) {
AutoCompileContext autoContext(new BMV2::BMV2Context(BMV2::PsaSwitchContext::get()));
try {
backend->convert(toplevel);
} catch (const Util::P4CExceptionBase &bug) {
} catch (const std::exception &bug) {
std::cerr << bug.what() << std::endl;
return 1;
}
Expand Down
6 changes: 3 additions & 3 deletions backends/bmv2/simple_switch/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ int main(int argc, char *const argv[]) {
P4::FrontEnd frontend;
frontend.addDebugHook(hook);
program = frontend.run(options, program);
} catch (const Util::P4CExceptionBase &bug) {
} catch (const std::exception &bug) {
std::cerr << bug.what() << std::endl;
return 1;
}
Expand Down Expand Up @@ -107,7 +107,7 @@ int main(int argc, char *const argv[]) {
return 1;
if (options.dumpJsonFile && !options.loadIRFromJson)
JSONGenerator(*openFile(options.dumpJsonFile, true), true) << program << std::endl;
} catch (const Util::P4CExceptionBase &bug) {
} catch (const std::exception &bug) {
std::cerr << bug.what() << std::endl;
return 1;
}
Expand All @@ -121,7 +121,7 @@ int main(int argc, char *const argv[]) {
AutoCompileContext autoContext(new BMV2::BMV2Context(BMV2::SimpleSwitchContext::get()));
try {
backend->convert(toplevel);
} catch (const Util::P4CExceptionBase &bug) {
} catch (const std::exception &bug) {
std::cerr << bug.what() << std::endl;
return 1;
}
Expand Down
2 changes: 1 addition & 1 deletion backends/ebpf/p4c-ebpf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ int main(int argc, char *const argv[]) {

try {
compile(options);
} catch (const Util::P4CExceptionBase &bug) {
} catch (const std::exception &bug) {
std::cerr << bug.what() << std::endl;
return 1;
}
Expand Down
4 changes: 2 additions & 2 deletions backends/graphs/p4c-graphs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ int main(int argc, char *const argv[]) {
P4::FrontEnd fe;
fe.addDebugHook(hook);
program = fe.run(options, program);
} catch (const Util::P4CExceptionBase &bug) {
} catch (const std::exception &bug) {
std::cerr << bug.what() << std::endl;
return 1;
}
Expand All @@ -143,7 +143,7 @@ int main(int argc, char *const argv[]) {
top = midEnd.process(program);
if (options.dumpJsonFile)
JSONGenerator(*openFile(options.dumpJsonFile, true)) << program << std::endl;
} catch (const Util::P4CExceptionBase &bug) {
} catch (const std::exception &bug) {
std::cerr << bug.what() << std::endl;
return 1;
}
Expand Down
4 changes: 2 additions & 2 deletions backends/p4test/p4test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ int main(int argc, char *const argv[]) {
P4::FrontEnd fe;
fe.addDebugHook(hook);
program = fe.run(options, program);
} catch (const Util::P4CExceptionBase &bug) {
} catch (const std::exception &bug) {
std::cerr << bug.what() << std::endl;
return 1;
}
Expand Down Expand Up @@ -142,7 +142,7 @@ int main(int argc, char *const argv[]) {
const IR::ToplevelBlock *top = nullptr;
try {
top = midEnd.process(program);
} catch (const Util::P4CExceptionBase &bug) {
} catch (const std::exception &bug) {
std::cerr << bug.what() << std::endl;
return 1;
}
Expand Down
1 change: 1 addition & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

set (LIBP4CTOOLKIT_SRCS
backtrace.cpp
bitvec.cpp
compile_context.cpp
crash.cpp
Expand Down
88 changes: 88 additions & 0 deletions lib/backtrace.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
Copyright 2019-present Barefoot Networks, 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 "backtrace.h"
#include <stdarg.h>
#include <functional>
#include <regex>
#include <stdexcept>
#include <typeinfo>
#include "crash.h"

void backtrace_fill_stacktrace(std::string &msg, void *const*backtrace, int size) {
char **strings = backtrace_symbols(backtrace, size);
for (int i = 0; i < size; i++) {
if (strings) {
msg += "\n ";
msg += strings[i]; }
if (const char *line = addr2line(backtrace[i], strings ? strings[i] : 0)) {
msg += "\n ";
msg += line; } }
free(strings);
}

#ifdef __GLIBC__
/* DANGER -- overrides for glibc++ exception throwers to include a stack trace.
* correct functions depends on library internals, so may not work on some versions
* and will fail with non-GNU libc++ */

void std::__throw_bad_alloc() {
throw backtrace_exception<std::bad_alloc>();
}

void std::__throw_bad_cast() {
throw backtrace_exception<std::bad_cast>();
}

void std::__throw_bad_function_call() {
throw backtrace_exception<std::bad_function_call>();
}

void std::__throw_invalid_argument(char const *m) {
throw backtrace_exception<std::invalid_argument>(m);
}

void std::__throw_length_error(char const *m) {
throw backtrace_exception<std::length_error>(m);
}

void std::__throw_logic_error(char const *m) {
throw backtrace_exception<std::logic_error>(m);
}

void std::__throw_out_of_range(char const *m) {
throw backtrace_exception<std::out_of_range>(m);
}

void std::__throw_out_of_range_fmt(char const *fmt, ...) {
char buffer[1024]; // should be large enough for all cases?
va_list args;
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
throw backtrace_exception<std::out_of_range>(buffer);
}

void std::__throw_regex_error(std::regex_constants::error_type err) {
throw backtrace_exception<std::regex_error>(err);
}

void std::__throw_system_error(int err) {
throw backtrace_exception<std::system_error>(error_code(err, generic_category()));
}


#endif /* __GLIBC__ */
55 changes: 55 additions & 0 deletions lib/backtrace.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
Copyright 2019-present Barefoot Networks, 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.
*/

#ifndef _LIB_BACKTRACE_H_
#define _LIB_BACKTRACE_H_

#include <string>
#include <exception>
#include "config.h"

#if HAVE_EXECINFO_H
#include <execinfo.h>
#endif

void backtrace_fill_stacktrace(std::string &msg, void *const*backtrace, int size);

template<class E> class backtrace_exception : public E {
static constexpr int buffer_size = 64;
void *backtrace_buffer[buffer_size];
int backtrace_size;
mutable std::string message;
public:
template<class... Args> backtrace_exception(Args... args) : E(std::forward<Args>(args)...) {
#if HAVE_EXECINFO_H
backtrace_size = backtrace(backtrace_buffer, buffer_size);
#else
backtrace_size = 0;
#endif
}

const char *what() const noexcept {
try {
message = E::what();
if (backtrace_size > 0)
backtrace_fill_stacktrace(message, backtrace_buffer, backtrace_size);
return message.c_str();
} catch(...) {}
return E::what();
}
};

#endif /* _LIB_CRASH_H_ */
1 change: 1 addition & 0 deletions lib/crash.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ limitations under the License.
#define _LIB_CRASH_H_

void setup_signals();
const char *addr2line(void *addr, const char *text);

#endif /* _LIB_CRASH_H_ */
10 changes: 2 additions & 8 deletions lib/ordered_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,8 @@ class ordered_map {
it = data.emplace(data.end(), std::move(x), V());
data_map.emplace(&it->first, it); }
return it->second; }
V& at(const K &x) {
auto it = find(x);
if (it == data.end()) throw std::out_of_range("ordered_map");
return it->second; }
const V& at(const K &x) const {
auto it = find(x);
if (it == data.end()) throw std::out_of_range("ordered_map");
return it->second; }
V& at(const K &x) { return data_map.at(&x)->second; }
const V& at(const K &x) const { return data_map.at(&x)->second; }

template<typename KK, typename... VV>
std::pair<iterator, bool> emplace(KK &&k, VV &&... v) {
Expand Down

0 comments on commit 75df252

Please sign in to comment.