/* * Copyright (C) 2023 The Android Open Source Project * * 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 "berberis/runtime_primitives/runtime_library.h" #include #include "berberis/base/checks.h" #include "berberis/base/logging.h" #include "berberis/base/tracing.h" #include "berberis/guest_os_primitives/guest_thread.h" #include "berberis/guest_state/guest_state_opaque.h" #include "berberis/runtime/execute_guest.h" namespace berberis { void ExecuteGuestCall(ThreadState* state) { CHECK(state); auto* thread = GetGuestThread(*state); GuestCallExecution guest_call_execution{.parent = thread->guest_call_execution(), .sp = GetStackRegister(GetCPUState(*state))}; // ATTENTION: don't save/restore signal mask, this is done by guest! sigsetjmp(guest_call_execution.buf, 0); // Set current execution for normal flow, or reset it after a longjmp. thread->set_guest_call_execution(&guest_call_execution); ExecuteGuest(state); thread->set_guest_call_execution(guest_call_execution.parent); if (guest_call_execution.sp == GetStackRegister(GetCPUState(*state))) { return; } // Stack pointer may not be restored if guest executed a statically linked longjmp. // Search parent executions for current sp. for (auto* curr = thread->guest_call_execution(); curr; curr = curr->parent) { // TODO(b/232598137): It'd be more reliable to also check (stop_pc == // insn_addr) for the matching execution, but currently stop_pc is always the // same for all executions. if (curr->sp == GetStackRegister(GetCPUState(*state))) { TRACE("Detected statically linked longjmp"); siglongjmp(curr->buf, 1); } } LOG_ALWAYS_FATAL("Guest call didn't restore sp: expected %p, actual %p", ToHostAddr(guest_call_execution.sp), ToHostAddr(GetStackRegister(GetCPUState(*state)))); } } // namespace berberis