1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
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
16 #include "signal_handler.h"
17 #include "utils/logger.h"
18 #include <algorithm>
19 #include <cstdlib>
20 #include "include/method.h"
21 #include <sys/ucontext.h>
22 #include "include/panda_vm.h"
23 #include "include/thread.h"
24 #include "include/stack_walker.h"
25 #if defined(PANDA_TARGET_UNIX)
26 #include "libpandabase/os/unix/sighooklib/sighook.h"
27 #endif // PANDA_TARGET_UNIX
28
29 namespace panda {
30
31 #ifdef PANDA_TARGET_ARM32
32 #define CONTEXT_PC uc_->uc_mcontext.arm_pc // NOLINT(cppcoreguidelines-macro-usage)
33 #define CONTEXT_FP uc_->uc_mcontext.arm_fp // NOLINT(cppcoreguidelines-macro-usage)
34 #elif defined(PANDA_TARGET_ARM64)
35 #define CONTEXT_PC uc_->uc_mcontext.pc // NOLINT(cppcoreguidelines-macro-usage)
36 #define CONTEXT_FP uc_->uc_mcontext.regs[29] // NOLINT(cppcoreguidelines-macro-usage)
37 #elif defined(PANDA_TARGET_AMD64)
38 #define CONTEXT_PC uc_->uc_mcontext.gregs[REG_RIP] // NOLINT(cppcoreguidelines-macro-usage)
39 #define CONTEXT_FP uc_->uc_mcontext.gregs[REG_RBP] // NOLINT(cppcoreguidelines-macro-usage)
40 #elif defined(PANDA_TARGET_X86)
41 #define CONTEXT_PC uc_->uc_mcontext.gregs[REG_EIP] // NOLINT(cppcoreguidelines-macro-usage)
42 #define CONTEXT_FP uc_->uc_mcontext.gregs[REG_EBP] // NOLINT(cppcoreguidelines-macro-usage)
43 #endif
44
45 class SignalContext {
46 public:
SignalContext(void * ucontext_raw)47 explicit SignalContext(void *ucontext_raw)
48 {
49 uc_ = reinterpret_cast<ucontext_t *>(ucontext_raw);
50 }
GetPC()51 uintptr_t GetPC()
52 {
53 return CONTEXT_PC;
54 }
SetPC(uintptr_t pc)55 void SetPC(uintptr_t pc)
56 {
57 CONTEXT_PC = pc;
58 }
GetFP()59 uintptr_t *GetFP()
60 {
61 return reinterpret_cast<uintptr_t *>(CONTEXT_FP);
62 }
63
64 private:
65 ucontext_t *uc_;
66 };
67
IsValidStack(ManagedThread * thread)68 static bool IsValidStack([[maybe_unused]] ManagedThread *thread)
69 {
70 // Issue #3649 CFrame::Initialize fires an ASSERT fail.
71 // The issue is that ManagedStack is not always in a consistent state.
72 return false;
73 }
74
75 // Something goes really wrong. Dump info and exit.
DumpStackTrace(int signo,siginfo_t * info,void * context)76 static void DumpStackTrace([[maybe_unused]] int signo, [[maybe_unused]] siginfo_t *info, [[maybe_unused]] void *context)
77 {
78 auto thread = ManagedThread::GetCurrent();
79 if (thread == nullptr) {
80 LOG(ERROR, RUNTIME) << "Native thread segmentation fault";
81 return;
82 }
83 if (!IsValidStack(thread)) {
84 return;
85 }
86
87 LOG(ERROR, RUNTIME) << "Managed thread segmentation fault";
88 for (StackWalker stack(thread); stack.HasFrame(); stack.NextFrame()) {
89 Method *method = stack.GetMethod();
90 auto *source = method->GetClassSourceFile().data;
91 auto line_num = method->GetLineNumFromBytecodeOffset(stack.GetBytecodePc());
92 if (source == nullptr) {
93 source = utf::CStringAsMutf8("<unknown>");
94 }
95 LOG(ERROR, RUNTIME) << method->GetClass()->GetName() << "." << method->GetName().data << " at " << source << ":"
96 << line_num;
97 }
98 }
99
UseDebuggerdSignalHandler(int sig)100 static void UseDebuggerdSignalHandler(int sig)
101 {
102 LOG(WARNING, RUNTIME) << "panda vm can not handle sig " << sig << ", call next handler";
103 }
104
CallSignalActionHandler(int sig,siginfo_t * info,void * context)105 static bool CallSignalActionHandler(int sig, siginfo_t *info, void *context)
106 { // NOLINT
107 return Runtime::GetCurrent()->GetSignalManager()->SignalActionHandler(sig, info, context);
108 }
109
SignalActionHandler(int sig,siginfo_t * info,void * context)110 bool SignalManager::SignalActionHandler(int sig, siginfo_t *info, void *context)
111 {
112 if (InOatCode(info, context, true)) {
113 for (const auto &handler : oat_code_handler_) {
114 if (handler->Action(sig, info, context)) {
115 return true;
116 }
117 }
118 }
119
120 // a signal can not handle in oat
121 if (InOtherCode(sig, info, context)) {
122 return true;
123 }
124
125 // Use the default exception handler function.
126 UseDebuggerdSignalHandler(sig);
127 return false;
128 }
129
InOatCode(const siginfo_t * siginfo,const void * context,bool check_bytecode_pc)130 bool SignalManager::InOatCode([[maybe_unused]] const siginfo_t *siginfo, [[maybe_unused]] const void *context,
131 [[maybe_unused]] bool check_bytecode_pc)
132 {
133 return true;
134 }
135
InOtherCode(int sig,siginfo_t * info,void * context)136 bool SignalManager::InOtherCode([[maybe_unused]] int sig, [[maybe_unused]] siginfo_t *info,
137 [[maybe_unused]] void *context)
138 {
139 return false;
140 }
141
AddHandler(SignalHandler * handler,bool oat_code)142 void SignalManager::AddHandler(SignalHandler *handler, bool oat_code)
143 {
144 if (oat_code) {
145 oat_code_handler_.push_back(handler);
146 } else {
147 other_handlers_.push_back(handler);
148 }
149 }
150
RemoveHandler(SignalHandler * handler)151 void SignalManager::RemoveHandler(SignalHandler *handler)
152 {
153 auto it_oat = std::find(oat_code_handler_.begin(), oat_code_handler_.end(), handler);
154 if (it_oat != oat_code_handler_.end()) {
155 oat_code_handler_.erase(it_oat);
156 return;
157 }
158 auto it_other = std::find(other_handlers_.begin(), other_handlers_.end(), handler);
159 if (it_other != other_handlers_.end()) {
160 other_handlers_.erase(it_other);
161 return;
162 }
163 LOG(FATAL, RUNTIME) << "handler doesn't exist: " << handler;
164 }
165
InitSignals()166 void SignalManager::InitSignals()
167 {
168 if (is_init_) {
169 return;
170 }
171 #if defined(PANDA_TARGET_UNIX)
172 sigset_t mask;
173 sigfillset(&mask);
174 sigdelset(&mask, SIGABRT);
175 sigdelset(&mask, SIGBUS);
176 sigdelset(&mask, SIGFPE);
177 sigdelset(&mask, SIGILL);
178 sigdelset(&mask, SIGSEGV);
179
180 ClearSignalHooksHandlersArray();
181
182 // If running on device, sigchain will work and AddSpecialSignalHandlerFn in sighook will not be used
183 SigchainAction sigchain_action = {
184 CallSignalActionHandler,
185 mask,
186 SA_SIGINFO,
187 };
188 AddSpecialSignalHandlerFn(SIGSEGV, &sigchain_action);
189
190 is_init_ = true;
191
192 for (auto tmp : oat_code_handler_) {
193 allocator_->Delete(tmp);
194 }
195 oat_code_handler_.clear();
196 for (auto tmp : other_handlers_) {
197 allocator_->Delete(tmp);
198 }
199 other_handlers_.clear();
200 #else
201 struct sigaction act1 = {};
202 sigfillset(&act1.sa_mask);
203 act1.sa_sigaction = RuntimeSEGVHandler;
204 act1.sa_flags = SA_RESTART | SA_SIGINFO | SA_NODEFER;
205 sigaction(SIGSEGV, &act1, nullptr);
206 #endif // PANDA_TARGET_UNIX
207 }
208
GetMethodAndReturnPcAndSp(const siginfo_t * siginfo,const void * context,const Method ** out_method,const uintptr_t * out_return_pc,const uintptr_t * out_sp)209 void SignalManager::GetMethodAndReturnPcAndSp([[maybe_unused]] const siginfo_t *siginfo,
210 [[maybe_unused]] const void *context,
211 [[maybe_unused]] const Method **out_method,
212 [[maybe_unused]] const uintptr_t *out_return_pc,
213 [[maybe_unused]] const uintptr_t *out_sp)
214 {
215 // just stub now
216 }
217
DeleteHandlersArray()218 void SignalManager::DeleteHandlersArray()
219 {
220 if (is_init_) {
221 for (auto tmp : oat_code_handler_) {
222 allocator_->Delete(tmp);
223 }
224 oat_code_handler_.clear();
225 for (auto tmp : other_handlers_) {
226 allocator_->Delete(tmp);
227 }
228 other_handlers_.clear();
229 RemoveSpecialSignalHandlerFn(SIGSEGV, CallSignalActionHandler);
230 is_init_ = false;
231 }
232 }
233
234 #if defined(PANDA_TARGET_UNIX)
DetectSEGVFromMemory(int sig,siginfo_t * siginfo,void * context)235 bool DetectSEGVFromMemory([[maybe_unused]] int sig, [[maybe_unused]] siginfo_t *siginfo,
236 #else
237 void DetectSEGVFromMemory([[maybe_unused]] int sig, [[maybe_unused]] siginfo_t *siginfo,
238 #endif // PANDA_TARGET_UNIX
239 void *context) // CODECHECK-NOLINT(C_RULE_ID_INDENT_CHECK)
240 {
241 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
242 auto mem_fault_location = ToUintPtr(siginfo->si_addr);
243 const uintptr_t MAX_OBJECT_SIZE = 1U << 30U;
244 // The expected fault address is nullptr and offset is within the object
245 if (mem_fault_location > MAX_OBJECT_SIZE) {
246 DumpStackTrace(sig, siginfo, context);
247 #if defined(PANDA_TARGET_UNIX)
248 return true;
249 #else
250 LOG(FATAL, RUNTIME) << "Memory location which caused fault:" << std::hex << mem_fault_location;
251 #endif
252 }
253 #if defined(PANDA_TARGET_UNIX)
254 return false;
255 #endif
256 }
257
258 #if defined(PANDA_TARGET_UNIX)
RuntimeSEGVHandler(int sig,siginfo_t * siginfo,void * context)259 bool RuntimeSEGVHandler([[maybe_unused]] int sig, [[maybe_unused]] siginfo_t *siginfo, void *context)
260 {
261 return !DetectSEGVFromMemory(sig, siginfo, context);
262 }
263 #else
RuntimeSEGVHandler(int sig,siginfo_t * siginfo,void * context)264 void RuntimeSEGVHandler([[maybe_unused]] int sig, [[maybe_unused]] siginfo_t *siginfo, void *context)
265 {
266 DetectSEGVFromMemory(sig, siginfo, context);
267 }
268 #endif // PANDA_TARGET_UNIX
269
Action(int sig,siginfo_t * siginfo,void * context)270 bool NullPointerHandler::Action(int sig, [[maybe_unused]] siginfo_t *siginfo, [[maybe_unused]] void *context)
271 {
272 if (sig != SIGSEGV) {
273 return false;
274 }
275 #if defined(PANDA_TARGET_UNIX)
276 if (!RuntimeSEGVHandler(sig, siginfo, context)) {
277 return false;
278 }
279 #endif // PANDA_TARGET_UNIX
280 LOG(DEBUG, RUNTIME) << "NullPointerHandler happen, Throw NullPointerHandler Exception, signal:" << sig;
281 // Issues 1437, NullPointer has been checked here or in aot,
282 // so let's return to interpreter, and exception is not built here.
283 // panda::ThrowNullPointerException()
284 return true;
285 }
286
287 NullPointerHandler::~NullPointerHandler() = default;
288
289 } // namespace panda
290