Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/art/art/runtime/arch/arm64/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 8 kB image not shown  

Quelle  fault_handler_arm64.cc

  Sprache: C
 

/*
 * Copyright (C) 2014 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 <sys/ucontext.h>

#include "arch/instruction_set.h"
#include "art_method.h"
#include "base/hex_dump.h"
#include "base/logging.h"  // For VLOG.
#include "base/macros.h"
#include "base/pointer_size.h"
#include "fault_handler.h"
#include "interpreter/mterp/nterp.h"
#include "oat/oat_quick_method_header.h"
#include "registers_arm64.h"
#include "runtime_globals.h"
#include "thread-current-inl.h"

extern "C" void art_quick_throw_stack_overflow();
extern "C" void art_quick_throw_null_pointer_exception_from_signal();
extern "C" void art_quick_implicit_suspend();

//
// ARM64 specific fault handler functions.
//

namespace art HIDDEN {

uintptr_t FaultManager::GetFaultPc(siginfo_t* siginfo, void* context) {
  // SEGV_MTEAERR (Async MTE fault) is delivered at an arbitrary point after the actual fault.
  // Register contents, including PC and SP, are unrelated to the fault and can only confuse ART
  // signal handlers.
  if (siginfo->si_signo == SIGSEGV && siginfo->si_code == SEGV_MTEAERR) {
    VLOG(signals) << "Async MTE fault";
    return 0u;
  }

  ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
  mcontext_t* mc = reinterpret_cast<mcontext_t*>(&uc->uc_mcontext);
  if (mc->sp == 0) {
    VLOG(signals) << "Missing SP";
    return 0u;
  }
  return mc->pc;
}

uintptr_t FaultManager::GetFaultSp(void* context) {
  ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
  mcontext_t* mc = reinterpret_cast<mcontext_t*>(&uc->uc_mcontext);
  return mc->sp;
}

// Nterp details needed to check for `aget*`/`aput*` opcode handlers and export the dex PC.
extern "C" HIDDEN void nterp3_op_nop();
extern "C" HIDDEN void nterp3_op_aget();
static constexpr size_t kNterpAgetAputHandlersSize =
    (/* aget */ 7 + /* aput */ 7) * interpreter::kNterpHandlerSize;
static constexpr size_t kNterpDexPcReg = 22;
static constexpr size_t kNterpRefsReg = 25;
static constexpr size_t kNterpExportedDexPcOffset = 16;  // Below refs.

static uintptr_t nterp_op_aget_start() {
  // There are four nterp handler sets, 20KiB apart, and we're using the one that's 16KiB-aligned.
  uintptr_t op_nop = reinterpret_cast<uintptr_t>(nterp3_op_nop);
  uintptr_t op_aget = reinterpret_cast<uintptr_t>(nterp3_op_aget);
  uintptr_t num_sets_to_subtract = (op_nop >> 12) & 3u;
  DCHECK_ALIGNED(op_nop - num_sets_to_subtract * 20 * KB, 16 * KB);
  return op_aget - num_sets_to_subtract * 20 * KB;
}

bool NullPointerHandler::Action([[maybe_unused]] int sig, siginfo_t* info, void* context) {
  // If changing this function, also update CodeSimulatorArm64::HandleNullPointer as that should
  // stay in sync.

  uintptr_t fault_address = reinterpret_cast<uintptr_t>(info->si_addr);
  if (!IsValidFaultAddress(fault_address)) {
    return false;
  }

  // For null checks in compiled code we insert a stack map that is immediately
  // after the load/store instruction that might cause the fault and we need to
  // pass the return PC to the handler. For null checks in Nterp, we similarly
  // need the return PC to recognize that this was a null check in Nterp, so
  // that the handler can get the needed data from the Nterp frame.

  ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
  mcontext_t* mc = reinterpret_cast<mcontext_t*>(&uc->uc_mcontext);
  ArtMethod** sp = reinterpret_cast<ArtMethod**>(mc->sp);
  uintptr_t return_pc = mc->pc + 4u;
  if (!IsValidMethod(*sp) || !IsValidReturnPc(sp, return_pc)) {
    return false;
  }

  if (return_pc - nterp_op_aget_start() < kNterpAgetAputHandlersSize) {
    // Export the dex PC here, so that the nterp `aget*`/`aput*` opcode handlers do not need
    // to export it before doing implicit null checks. The `EXPORT_PC` in nterp expands to
    //     stur    x22, [x25, #-0x10]
    uintptr_t* dex_pc_slot =
        reinterpret_cast<uintptr_t*>(mc->regs[kNterpRefsReg] - kNterpExportedDexPcOffset);
    *dex_pc_slot = mc->regs[kNterpDexPcReg];
  }

  // Push the return PC to the stack and pass the fault address in LR.
  mc->sp -= sizeof(uintptr_t);
  *reinterpret_cast<uintptr_t*>(mc->sp) = return_pc;
  mc->regs[30] = fault_address;

  // Arrange for the signal handler to return to the NPE entrypoint.
  mc->pc = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception_from_signal);
  VLOG(signals) << "Generating null pointer exception";
  return true;
}

static constexpr uint32_t kSuspendCheckRegister = 21;

// A suspend check is done using the following instruction:
//      0x...: f94002b5  ldr x21, [x21, #0]
// To check for a suspend check, we examine the instruction that caused the fault (at PC).
bool SuspensionHandler::Action([[maybe_unused]] int sig,
                               [[maybe_unused]] siginfo_t* info,
                               void* context) {
  constexpr uint32_t checkinst =
      0xf9400000 | (kSuspendCheckRegister << 5) | (kSuspendCheckRegister << 0);

  ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
  mcontext_t* mc = reinterpret_cast<mcontext_t*>(&uc->uc_mcontext);

  if (OatQuickMethodHeader::IsNterpPc(mc->pc)) {
    // Interpreter does not do suspend check through the exception handler
    return false;
  }

  uint32_t inst = *reinterpret_cast<uint32_t*>(mc->pc);
  VLOG(signals) << "checking suspend; inst: " << std::hex << inst << " checkinst: " << checkinst;
  if (inst != checkinst) {
    // The instruction is not good, not ours.
    return false;
  }

  // This is a suspend check.
  VLOG(signals) << "suspend check match";

  // Set LR so that after the suspend check it will resume after the
  // `ldr x21, [x21,#0]` instruction that triggered the suspend check.
  mc->regs[30] = mc->pc + 4;
  // Arrange for the signal handler to return to `art_quick_implicit_suspend()`.
  mc->pc = reinterpret_cast<uintptr_t>(art_quick_implicit_suspend);

  // Now remove the suspend trigger that caused this fault.
  Thread::Current()->RemoveSuspendTrigger();
  VLOG(signals) << "removed suspend trigger invoking test suspend";

  return true;
}

void FaultManager::SuspendFaster(siginfo_t* info, void* context) {
  // We need to trigger a suspend check. Since we are in an asynchronous signal handler, we
  // cannot do so directly. But we can make sure the next suspend check does so, rather than
  // waiting for the one after that, by clearing kSuspendCheckRegister. This is likely to be
  // beneficial immediately after a flip, when we are likely to see several signals in a row.

  if (!IsInGeneratedCode(info, context)) {
    // Suspend trigger register is reserved for the purpose only in ART-generated code.
    return;
  }
  ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
  mcontext_t* mc = reinterpret_cast<mcontext_t*>(&uc->uc_mcontext);
  mc->regs[kSuspendCheckRegister] = reinterpret_cast<uintptr_t>(static_cast<void*>(nullptr));
  VLOG(signals) << "Accelerating suspension";
}

bool StackOverflowHandler::Action([[maybe_unused]] int sig,
                                  [[maybe_unused]] siginfo_t* info,
                                  void* context) {
  ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
  mcontext_t* mc = reinterpret_cast<mcontext_t*>(&uc->uc_mcontext);
  VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc;
  VLOG(signals) << "sigcontext: " << std::hex << mc;

  uintptr_t sp = mc->sp;
  VLOG(signals) << "sp: " << std::hex << sp;

  uintptr_t fault_addr = mc->fault_address;
  VLOG(signals) << "fault_addr: " << std::hex << fault_addr;
  VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp <<
      ", fault_addr: " << fault_addr;

  uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(InstructionSet::kArm64);

  // Check that the fault address is the value expected for a stack overflow.
  if (fault_addr != overflow_addr) {
    VLOG(signals) << "Not a stack overflow";
    return false;
  }

  VLOG(signals) << "Stack overflow found";

  // Now arrange for the signal handler to return to art_quick_throw_stack_overflow.
  // The value of LR must be the same as it was when we entered the code that
  // caused this fault.  This will be inserted into a callee save frame by
  // the function to which this handler returns (art_quick_throw_stack_overflow).
  mc->pc = reinterpret_cast<uintptr_t>(art_quick_throw_stack_overflow);

  // The kernel will now return to the address in sc->pc.
  return true;
}
}       // namespace art

Messung V0.5 in Prozent
C=91 H=95 G=92

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.