1 // Copyright 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "util/crash_report.h"
16
17 #include <fcntl.h>
18 #include <stdio.h>
19 #include <unistd.h>
20 #if defined(_WIN32)
21 #include <windows.h>
22 #endif
23
24 #if defined(__linux__)
25
26 #ifndef NETSIM_ANDROID_EMULATOR
27 #include <client/linux/handler/exception_handler.h>
28 #include <fmt/format.h>
29 #include <unwindstack/AndroidUnwinder.h>
30
31 #include <iostream>
32 #else
33 #include <signal.h>
34 #endif
35
36 #include <execinfo.h>
37 #include <unistd.h>
38
39 #include <cstdio>
40 #include <cstdlib>
41 #endif
42
43 #include "util/filesystem.h"
44 #include "util/ini_file.h"
45 #include "util/log.h"
46
47 namespace netsim {
48 namespace {
49
50 #if defined(__linux__)
51 #ifndef NETSIM_ANDROID_EMULATOR
crash_callback(const void * crash_context,size_t crash_context_size,void *)52 bool crash_callback(const void *crash_context, size_t crash_context_size,
53 void * /* context */) {
54 std::optional<pid_t> tid;
55 std::cerr << "netsimd crash_callback invoked\n";
56 if (crash_context_size >=
57 sizeof(google_breakpad::ExceptionHandler::CrashContext)) {
58 auto *ctx =
59 static_cast<const google_breakpad::ExceptionHandler::CrashContext *>(
60 crash_context);
61 tid = ctx->tid;
62 int signal_number = ctx->siginfo.si_signo;
63 std::cerr << fmt::format("Process crashed, signal: {}[{}], tid: {}\n",
64 strsignal(signal_number), signal_number, ctx->tid)
65 .c_str();
66 } else {
67 std::cerr << "Process crashed, signal: unknown, tid: unknown\n";
68 }
69 unwindstack::AndroidLocalUnwinder unwinder;
70 unwindstack::AndroidUnwinderData data;
71 if (!unwinder.Unwind(tid, data)) {
72 std::cerr << "Unwind failed\n";
73 return false;
74 }
75 std::cerr << "Backtrace:\n";
76 for (const auto &frame : data.frames) {
77 std::cerr << fmt::format("{}\n", unwinder.FormatFrame(frame)).c_str();
78 }
79 return true;
80 }
81 #else
82 // Signal handler to print backtraces and then terminate the program.
83 void SignalHandler(int sig) {
84 size_t buffer_size = 20; // Number of entries in that array.
85 void *buffer[buffer_size];
86
87 auto size = backtrace(buffer, buffer_size);
88 fprintf(stderr,
89 "netsim error: interrupt by signal %d. Obtained %d stack frames:\n",
90 sig, size);
91 backtrace_symbols_fd(buffer, size, STDERR_FILENO);
92 exit(sig);
93 }
94 #endif
95 #endif
96
97 } // namespace
98
SetUpCrashReport()99 void SetUpCrashReport() {
100 #if defined(__linux__)
101 #ifndef NETSIM_ANDROID_EMULATOR
102 google_breakpad::MinidumpDescriptor descriptor("/tmp");
103 google_breakpad::ExceptionHandler eh(descriptor, nullptr, nullptr, nullptr,
104 true, -1);
105 eh.set_crash_handler(crash_callback);
106 #else
107 signal(SIGSEGV, SignalHandler);
108 #endif
109 #endif
110 }
111
112 } // namespace netsim
113