jdk
576 строк · 18.7 Кб
1/*
2* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*
5* This code is free software; you can redistribute it and/or modify it
6* under the terms of the GNU General Public License version 2 only, as
7* published by the Free Software Foundation.
8*
9* This code is distributed in the hope that it will be useful, but WITHOUT
10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12* version 2 for more details (a copy is included in the LICENSE file that
13* accompanied this code).
14*
15* You should have received a copy of the GNU General Public License version
16* 2 along with this work; if not, write to the Free Software Foundation,
17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18*
19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20* or visit www.oracle.com if you need additional information or have any
21* questions.
22*
23*/
24
25// no precompiled headers
26#include "asm/macroAssembler.hpp"27#include "classfile/vmSymbols.hpp"28#include "code/vtableStubs.hpp"29#include "interpreter/interpreter.hpp"30#include "jvm.h"31#include "memory/allocation.inline.hpp"32#include "memory/resourceArea.hpp"33#include "nativeInst_x86.hpp"34#include "os_windows.hpp"35#include "prims/jniFastGetField.hpp"36#include "prims/jvm_misc.hpp"37#include "runtime/arguments.hpp"38#include "runtime/frame.inline.hpp"39#include "runtime/interfaceSupport.inline.hpp"40#include "runtime/java.hpp"41#include "runtime/javaCalls.hpp"42#include "runtime/javaThread.hpp"43#include "runtime/mutexLocker.hpp"44#include "runtime/os.inline.hpp"45#include "runtime/osThread.hpp"46#include "runtime/sharedRuntime.hpp"47#include "runtime/stubRoutines.hpp"48#include "runtime/timer.hpp"49#include "symbolengine.hpp"50#include "unwind_windows_x86.hpp"51#include "utilities/events.hpp"52#include "utilities/vmError.hpp"53#include "windbghelp.hpp"54
55
56#undef REG_SP57#undef REG_FP58#undef REG_PC59#ifdef AMD6460#define REG_SP Rsp61#define REG_FP Rbp62#define REG_PC Rip63#else64#define REG_SP Esp65#define REG_FP Ebp66#define REG_PC Eip67#endif // AMD6468
69JNIEXPORT
70extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* );71
72// Install a win32 structured exception handler around thread.
73void os::os_exception_wrapper(java_call_t f, JavaValue* value, const methodHandle& method, JavaCallArguments* args, JavaThread* thread) {74__try {75
76#ifndef AMD6477// We store the current thread in this wrapperthread location78// and determine how far away this address is from the structured79// exception pointer that FS:[0] points to. This get_thread80// code can then get the thread pointer via FS.81//82// Warning: This routine must NEVER be inlined since we'd end up with83// multiple offsets.84//85volatile Thread* wrapperthread = thread;86
87if (os::win32::get_thread_ptr_offset() == 0) {88int thread_ptr_offset;89__asm {90lea eax, dword ptr wrapperthread;91sub eax, dword ptr FS:[0H];92mov thread_ptr_offset, eax93};94os::win32::set_thread_ptr_offset(thread_ptr_offset);95}96#ifdef ASSERT97// Verify that the offset hasn't changed since we initially captured98// it. This might happen if we accidentally ended up with an99// inlined version of this routine.100else {101int test_thread_ptr_offset;102__asm {103lea eax, dword ptr wrapperthread;104sub eax, dword ptr FS:[0H];105mov test_thread_ptr_offset, eax106};107assert(test_thread_ptr_offset == os::win32::get_thread_ptr_offset(),108"thread pointer offset from SEH changed");109}110#endif // ASSERT111#endif // !AMD64112
113f(value, method, args, thread);114} __except(topLevelExceptionFilter((_EXCEPTION_POINTERS*)_exception_info())) {115// Nothing to do.116}117}
118
119#ifdef AMD64120
121// This is the language specific handler for exceptions
122// originating from dynamically generated code.
123// We call the standard structured exception handler
124// We only expect Continued Execution since we cannot unwind
125// from generated code.
126LONG HandleExceptionFromCodeCache(127IN PEXCEPTION_RECORD ExceptionRecord,128IN ULONG64 EstablisherFrame,129IN OUT PCONTEXT ContextRecord,130IN OUT PDISPATCHER_CONTEXT DispatcherContext) {131EXCEPTION_POINTERS ep;132LONG result;133
134ep.ExceptionRecord = ExceptionRecord;135ep.ContextRecord = ContextRecord;136
137result = topLevelExceptionFilter(&ep);138
139// We better only get a CONTINUE_EXECUTION from our handler140// since we don't have unwind information registered.141
142guarantee( result == EXCEPTION_CONTINUE_EXECUTION,143"Unexpected result from topLevelExceptionFilter");144
145return(ExceptionContinueExecution);146}
147
148
149// Structure containing the Windows Data Structures required
150// to register our Code Cache exception handler.
151// We put these in the CodeCache since the API requires
152// all addresses in these structures are relative to the Code
153// area registered with RtlAddFunctionTable.
154typedef struct {155char ExceptionHandlerInstr[16]; // jmp HandleExceptionFromCodeCache156RUNTIME_FUNCTION rt;157UNWIND_INFO_EH_ONLY unw;158} DynamicCodeData, *pDynamicCodeData;159
160#endif // AMD64161//
162// Register our CodeCache area with the OS so it will dispatch exceptions
163// to our topLevelExceptionFilter when we take an exception in our
164// dynamically generated code.
165//
166// Arguments: low and high are the address of the full reserved
167// codeCache area
168//
169bool os::win32::register_code_area(char *low, char *high) {170#ifdef AMD64171
172ResourceMark rm;173
174pDynamicCodeData pDCD;175PRUNTIME_FUNCTION prt;176PUNWIND_INFO_EH_ONLY punwind;177
178BufferBlob* blob = BufferBlob::create("CodeCache Exception Handler", sizeof(DynamicCodeData));179CodeBuffer cb(blob);180MacroAssembler* masm = new MacroAssembler(&cb);181pDCD = (pDynamicCodeData) masm->pc();182
183masm->jump(ExternalAddress((address)&HandleExceptionFromCodeCache), rscratch1);184masm->flush();185
186// Create an Unwind Structure specifying no unwind info187// other than an Exception Handler188punwind = &pDCD->unw;189punwind->Version = 1;190punwind->Flags = UNW_FLAG_EHANDLER;191punwind->SizeOfProlog = 0;192punwind->CountOfCodes = 0;193punwind->FrameRegister = 0;194punwind->FrameOffset = 0;195punwind->ExceptionHandler = (char *)(&(pDCD->ExceptionHandlerInstr[0])) -196(char*)low;197punwind->ExceptionData[0] = 0;198
199// This structure describes the covered dynamic code area.200// Addresses are relative to the beginning on the code cache area201prt = &pDCD->rt;202prt->BeginAddress = 0;203prt->EndAddress = (ULONG)(high - low);204prt->UnwindData = ((char *)punwind - low);205
206guarantee(RtlAddFunctionTable(prt, 1, (ULONGLONG)low),207"Failed to register Dynamic Code Exception Handler with RtlAddFunctionTable");208
209#endif // AMD64210return true;211}
212
213#ifdef HAVE_PLATFORM_PRINT_NATIVE_STACK214/*
215* Windows/x64 does not use stack frames the way expected by Java:
216* [1] in most cases, there is no frame pointer. All locals are addressed via RSP
217* [2] in rare cases, when alloca() is used, a frame pointer is used, but this may
218* not be RBP.
219* See http://msdn.microsoft.com/en-us/library/ew5tede7.aspx
220*
221* So it's not possible to print the native stack using the
222* while (...) {... fr = os::get_sender_for_C_frame(&fr); }
223* loop in vmError.cpp. We need to roll our own loop.
224*/
225bool os::win32::platform_print_native_stack(outputStream* st, const void* context,226char *buf, int buf_size, address& lastpc)227{
228CONTEXT ctx;229if (context != nullptr) {230memcpy(&ctx, context, sizeof(ctx));231} else {232RtlCaptureContext(&ctx);233}234
235st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");236
237STACKFRAME stk;238memset(&stk, 0, sizeof(stk));239stk.AddrStack.Offset = ctx.Rsp;240stk.AddrStack.Mode = AddrModeFlat;241stk.AddrFrame.Offset = ctx.Rbp;242stk.AddrFrame.Mode = AddrModeFlat;243stk.AddrPC.Offset = ctx.Rip;244stk.AddrPC.Mode = AddrModeFlat;245
246// Ensure we consider dynamically loaded dll's247SymbolEngine::refreshModuleList();248
249int count = 0;250address lastpc_internal = 0;251while (count++ < StackPrintLimit) {252intptr_t* sp = (intptr_t*)stk.AddrStack.Offset;253intptr_t* fp = (intptr_t*)stk.AddrFrame.Offset; // NOT necessarily the same as ctx.Rbp!254address pc = (address)stk.AddrPC.Offset;255
256if (pc != nullptr) {257if (count == 2 && lastpc_internal == pc) {258// Skip it -- StackWalk64() may return the same PC259// (but different SP) on the first try.260} else {261// Don't try to create a frame(sp, fp, pc) -- on WinX64, stk.AddrFrame262// may not contain what Java expects, and may cause the frame() constructor263// to crash. Let's just print out the symbolic address.264frame::print_C_frame(st, buf, buf_size, pc);265// print source file and line, if available266char buf[128];267int line_no;268if (SymbolEngine::get_source_info(pc, buf, sizeof(buf), &line_no)) {269st->print(" (%s:%d)", buf, line_no);270} else {271st->print(" (no source info available)");272}273st->cr();274}275lastpc_internal = pc;276}277
278PVOID p = WindowsDbgHelp::symFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset);279if (!p) {280// StackWalk64() can't handle this PC. Calling StackWalk64 again may cause crash.281lastpc = lastpc_internal;282break;283}284
285BOOL result = WindowsDbgHelp::stackWalk64(286IMAGE_FILE_MACHINE_AMD64, // __in DWORD MachineType,287GetCurrentProcess(), // __in HANDLE hProcess,288GetCurrentThread(), // __in HANDLE hThread,289&stk, // __inout LP STACKFRAME64 StackFrame,290&ctx); // __inout PVOID ContextRecord,291
292if (!result) {293break;294}295}296if (count > StackPrintLimit) {297st->print_cr("...<more frames>...");298}299st->cr();300
301return true;302}
303#endif // HAVE_PLATFORM_PRINT_NATIVE_STACK304
305address os::fetch_frame_from_context(const void* ucVoid,306intptr_t** ret_sp, intptr_t** ret_fp) {307
308address epc;309CONTEXT* uc = (CONTEXT*)ucVoid;310
311if (uc != nullptr) {312epc = (address)uc->REG_PC;313if (ret_sp) *ret_sp = (intptr_t*)uc->REG_SP;314if (ret_fp) *ret_fp = (intptr_t*)uc->REG_FP;315} else {316epc = nullptr;317if (ret_sp) *ret_sp = (intptr_t *)nullptr;318if (ret_fp) *ret_fp = (intptr_t *)nullptr;319}320
321return epc;322}
323
324frame os::fetch_frame_from_context(const void* ucVoid) {325intptr_t* sp;326intptr_t* fp;327address epc = fetch_frame_from_context(ucVoid, &sp, &fp);328if (!is_readable_pointer(epc)) {329// Try to recover from calling into bad memory330// Assume new frame has not been set up, the same as331// compiled frame stack bang332return frame(sp + 1, fp, (address)*sp);333}334return frame(sp, fp, epc);335}
336
337#ifndef AMD64338// Ignore "C4172: returning address of local variable or temporary" on 32bit
339PRAGMA_DIAG_PUSH
340PRAGMA_DISABLE_MSVC_WARNING(4172)341// Returns an estimate of the current stack pointer. Result must be guaranteed
342// to point into the calling threads stack, and be no lower than the current
343// stack pointer.
344address os::current_stack_pointer() {345int dummy;346address sp = (address)&dummy;347return sp;348}
349PRAGMA_DIAG_POP
350#else351// Returns the current stack pointer. Accurate value needed for
352// os::verify_stack_alignment().
353address os::current_stack_pointer() {354typedef address get_sp_func();355get_sp_func* func = CAST_TO_FN_PTR(get_sp_func*,356StubRoutines::x86::get_previous_sp_entry());357return (*func)();358}
359#endif360
361bool os::win32::get_frame_at_stack_banging_point(JavaThread* thread,362struct _EXCEPTION_POINTERS* exceptionInfo, address pc, frame* fr) {363PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord;364address addr = (address) exceptionRecord->ExceptionInformation[1];365if (Interpreter::contains(pc)) {366*fr = os::fetch_frame_from_context((void*)exceptionInfo->ContextRecord);367if (!fr->is_first_java_frame()) {368// get_frame_at_stack_banging_point() is only called when we369// have well defined stacks so java_sender() calls do not need370// to assert safe_for_sender() first.371*fr = fr->java_sender();372}373} else {374// more complex code with compiled code375assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");376CodeBlob* cb = CodeCache::find_blob(pc);377if (cb == nullptr || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {378// Not sure where the pc points to, fallback to default379// stack overflow handling380return false;381} else {382// in compiled code, the stack banging is performed just after the return pc383// has been pushed on the stack384intptr_t* fp = (intptr_t*)exceptionInfo->ContextRecord->REG_FP;385intptr_t* sp = (intptr_t*)exceptionInfo->ContextRecord->REG_SP;386*fr = frame(sp + 1, fp, (address)*sp);387if (!fr->is_java_frame()) {388// See java_sender() comment above.389*fr = fr->java_sender();390}391}392}393assert(fr->is_java_frame(), "Safety check");394return true;395}
396
397
398// VC++ does not save frame pointer on stack in optimized build. It
399// can be turned off by /Oy-. If we really want to walk C frames,
400// we can use the StackWalk() API.
401frame os::get_sender_for_C_frame(frame* fr) {402ShouldNotReachHere();403return frame();404}
405
406frame os::current_frame() {407return frame(); // cannot walk Windows frames this way. See os::get_native_stack408// and os::platform_print_native_stack409}
410
411void os::print_context(outputStream *st, const void *context) {412if (context == nullptr) return;413
414const CONTEXT* uc = (const CONTEXT*)context;415
416st->print_cr("Registers:");417#ifdef AMD64418st->print( "RAX=" INTPTR_FORMAT, uc->Rax);419st->print(", RBX=" INTPTR_FORMAT, uc->Rbx);420st->print(", RCX=" INTPTR_FORMAT, uc->Rcx);421st->print(", RDX=" INTPTR_FORMAT, uc->Rdx);422st->cr();423st->print( "RSP=" INTPTR_FORMAT, uc->Rsp);424st->print(", RBP=" INTPTR_FORMAT, uc->Rbp);425st->print(", RSI=" INTPTR_FORMAT, uc->Rsi);426st->print(", RDI=" INTPTR_FORMAT, uc->Rdi);427st->cr();428st->print( "R8 =" INTPTR_FORMAT, uc->R8);429st->print(", R9 =" INTPTR_FORMAT, uc->R9);430st->print(", R10=" INTPTR_FORMAT, uc->R10);431st->print(", R11=" INTPTR_FORMAT, uc->R11);432st->cr();433st->print( "R12=" INTPTR_FORMAT, uc->R12);434st->print(", R13=" INTPTR_FORMAT, uc->R13);435st->print(", R14=" INTPTR_FORMAT, uc->R14);436st->print(", R15=" INTPTR_FORMAT, uc->R15);437st->cr();438st->print( "RIP=" INTPTR_FORMAT, uc->Rip);439st->print(", EFLAGS=" INTPTR_FORMAT, uc->EFlags);440#else441st->print( "EAX=" INTPTR_FORMAT, uc->Eax);442st->print(", EBX=" INTPTR_FORMAT, uc->Ebx);443st->print(", ECX=" INTPTR_FORMAT, uc->Ecx);444st->print(", EDX=" INTPTR_FORMAT, uc->Edx);445st->cr();446st->print( "ESP=" INTPTR_FORMAT, uc->Esp);447st->print(", EBP=" INTPTR_FORMAT, uc->Ebp);448st->print(", ESI=" INTPTR_FORMAT, uc->Esi);449st->print(", EDI=" INTPTR_FORMAT, uc->Edi);450st->cr();451st->print( "EIP=" INTPTR_FORMAT, uc->Eip);452st->print(", EFLAGS=" INTPTR_FORMAT, uc->EFlags);453#endif // AMD64454st->cr();455st->cr();456}
457
458void os::print_tos_pc(outputStream *st, const void *context) {459if (context == nullptr) return;460
461const CONTEXT* uc = (const CONTEXT*)context;462
463address sp = (address)uc->REG_SP;464print_tos(st, sp);465st->cr();466
467// Note: it may be unsafe to inspect memory near pc. For example, pc may468// point to garbage if entry point in an nmethod is corrupted. Leave469// this at the end, and hope for the best.470address pc = os::fetch_frame_from_context(uc).pc();471print_instructions(st, pc);472st->cr();473}
474
475void os::print_register_info(outputStream *st, const void *context, int& continuation) {476const int register_count = AMD64_ONLY(16) NOT_AMD64(8);477int n = continuation;478assert(n >= 0 && n <= register_count, "Invalid continuation value");479if (context == nullptr || n == register_count) {480return;481}482
483const CONTEXT* uc = (const CONTEXT*)context;484while (n < register_count) {485// Update continuation with next index before printing location486continuation = n + 1;487# define CASE_PRINT_REG(n, str, id) case n: st->print(str); print_location(st, uc->id);488switch (n) {489#ifdef AMD64490CASE_PRINT_REG( 0, "RAX=", Rax); break;491CASE_PRINT_REG( 1, "RBX=", Rbx); break;492CASE_PRINT_REG( 2, "RCX=", Rcx); break;493CASE_PRINT_REG( 3, "RDX=", Rdx); break;494CASE_PRINT_REG( 4, "RSP=", Rsp); break;495CASE_PRINT_REG( 5, "RBP=", Rbp); break;496CASE_PRINT_REG( 6, "RSI=", Rsi); break;497CASE_PRINT_REG( 7, "RDI=", Rdi); break;498CASE_PRINT_REG( 8, "R8 =", R8); break;499CASE_PRINT_REG( 9, "R9 =", R9); break;500CASE_PRINT_REG(10, "R10=", R10); break;501CASE_PRINT_REG(11, "R11=", R11); break;502CASE_PRINT_REG(12, "R12=", R12); break;503CASE_PRINT_REG(13, "R13=", R13); break;504CASE_PRINT_REG(14, "R14=", R14); break;505CASE_PRINT_REG(15, "R15=", R15); break;506#else507CASE_PRINT_REG(0, "EAX=", Eax); break;508CASE_PRINT_REG(1, "EBX=", Ebx); break;509CASE_PRINT_REG(2, "ECX=", Ecx); break;510CASE_PRINT_REG(3, "EDX=", Edx); break;511CASE_PRINT_REG(4, "ESP=", Esp); break;512CASE_PRINT_REG(5, "EBP=", Ebp); break;513CASE_PRINT_REG(6, "ESI=", Esi); break;514CASE_PRINT_REG(7, "EDI=", Edi); break;515#endif // AMD64516}517# undef CASE_PRINT_REG518++n;519}520}
521
522extern "C" int SpinPause () {523#ifdef AMD64524return 0 ;525#else526// pause == rep:nop527// On systems that don't support pause a rep:nop528// is executed as a nop. The rep: prefix is ignored.529_asm {530pause ;531};532return 1 ;533#endif // AMD64534}
535
536juint os::cpu_microcode_revision() {537juint result = 0;538BYTE data[8] = {0};539HKEY key;540DWORD status = RegOpenKey(HKEY_LOCAL_MACHINE,541"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &key);542if (status == ERROR_SUCCESS) {543DWORD size = sizeof(data);544status = RegQueryValueEx(key, "Update Revision", nullptr, nullptr, data, &size);545if (status == ERROR_SUCCESS) {546if (size == 4) result = *((juint*)data);547if (size == 8) result = *((juint*)data + 1); // upper 32-bits548}549RegCloseKey(key);550}551return result;552}
553
554void os::setup_fpu() {555#ifndef AMD64556int fpu_cntrl_word = StubRoutines::x86::fpu_cntrl_wrd_std();557__asm fldcw fpu_cntrl_word;558#endif // !AMD64559}
560
561#ifndef PRODUCT562void os::verify_stack_alignment() {563#ifdef AMD64564// The current_stack_pointer() calls generated get_previous_sp stub routine.565// Only enable the assert after the routine becomes available.566if (StubRoutines::initial_stubs_code() != nullptr) {567assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment");568}569#endif570}
571#endif572
573int os::extra_bang_size_in_bytes() {574// JDK-8050147 requires the full cache line bang for x86.575return VM_Version::L1_line_size();576}
577