• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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