diff --git a/backends/bmv2/psa_switch/main.cpp b/backends/bmv2/psa_switch/main.cpp index c42e9c3d9a3..57cc16d500d 100644 --- a/backends/bmv2/psa_switch/main.cpp +++ b/backends/bmv2/psa_switch/main.cpp @@ -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; } @@ -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; } @@ -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; } diff --git a/backends/bmv2/simple_switch/main.cpp b/backends/bmv2/simple_switch/main.cpp index f308e52a39c..76abec29e80 100644 --- a/backends/bmv2/simple_switch/main.cpp +++ b/backends/bmv2/simple_switch/main.cpp @@ -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; } @@ -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; } @@ -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; } diff --git a/backends/ebpf/p4c-ebpf.cpp b/backends/ebpf/p4c-ebpf.cpp index db78c57e6e0..ed0db20cdab 100644 --- a/backends/ebpf/p4c-ebpf.cpp +++ b/backends/ebpf/p4c-ebpf.cpp @@ -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; } diff --git a/backends/graphs/p4c-graphs.cpp b/backends/graphs/p4c-graphs.cpp index 928c2eab5b2..e2e26996010 100644 --- a/backends/graphs/p4c-graphs.cpp +++ b/backends/graphs/p4c-graphs.cpp @@ -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; } @@ -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; } diff --git a/backends/p4test/p4test.cpp b/backends/p4test/p4test.cpp index 0813e658fc1..63842c90686 100644 --- a/backends/p4test/p4test.cpp +++ b/backends/p4test/p4test.cpp @@ -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; } @@ -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; } diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 4cfdf677449..f7bd0d76212 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -13,6 +13,7 @@ # limitations under the License. set (LIBP4CTOOLKIT_SRCS + backtrace.cpp bitvec.cpp compile_context.cpp crash.cpp diff --git a/lib/backtrace.cpp b/lib/backtrace.cpp new file mode 100644 index 00000000000..a4746d94a92 --- /dev/null +++ b/lib/backtrace.cpp @@ -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 +#include +#include +#include +#include +#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(); +} + +void std::__throw_bad_cast() { + throw backtrace_exception(); +} + +void std::__throw_bad_function_call() { + throw backtrace_exception(); +} + +void std::__throw_invalid_argument(char const *m) { + throw backtrace_exception(m); +} + +void std::__throw_length_error(char const *m) { + throw backtrace_exception(m); +} + +void std::__throw_logic_error(char const *m) { + throw backtrace_exception(m); +} + +void std::__throw_out_of_range(char const *m) { + throw backtrace_exception(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(buffer); +} + +void std::__throw_regex_error(std::regex_constants::error_type err) { + throw backtrace_exception(err); +} + +void std::__throw_system_error(int err) { + throw backtrace_exception(error_code(err, generic_category())); +} + + +#endif /* __GLIBC__ */ diff --git a/lib/backtrace.h b/lib/backtrace.h new file mode 100644 index 00000000000..824a102caf1 --- /dev/null +++ b/lib/backtrace.h @@ -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 +#include +#include "config.h" + +#if HAVE_EXECINFO_H +#include +#endif + +void backtrace_fill_stacktrace(std::string &msg, void *const*backtrace, int size); + +template 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 backtrace_exception(Args... args) : E(std::forward(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_ */ diff --git a/lib/crash.h b/lib/crash.h index 3b1f3b41a89..4ddacbf6a1f 100644 --- a/lib/crash.h +++ b/lib/crash.h @@ -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_ */ diff --git a/lib/ordered_map.h b/lib/ordered_map.h index 7dc8dda37f9..5f221629fee 100644 --- a/lib/ordered_map.h +++ b/lib/ordered_map.h @@ -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 std::pair emplace(KK &&k, VV &&... v) {