Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

W^X support #54954

Merged
merged 8 commits into from
Jul 11, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/coreclr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ add_subdirectory(pal/prebuilt/inc)

add_subdirectory(debug/debug-pal)

add_subdirectory(minipal)

if(CLR_CMAKE_TARGET_WIN32)
add_subdirectory(gc/sample)
endif()
Expand Down Expand Up @@ -171,6 +173,7 @@ include_directories("classlibnative/cryptography")
include_directories("classlibnative/inc")
include_directories("${GENERATED_INCLUDE_DIR}")
include_directories("hosts/inc")
include_directories("minipal")

if(CLR_CMAKE_TARGET_WIN32 AND FEATURE_EVENT_TRACE)
include_directories("${GENERATED_INCLUDE_DIR}/etw")
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/clrdefinitions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,6 @@ if(CLR_CMAKE_TARGET_WIN32)
endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386)
endif(CLR_CMAKE_TARGET_WIN32)

if(CLR_CMAKE_TARGET_OSX)
add_definitions(-DFEATURE_WRITEBARRIER_COPY)
endif(CLR_CMAKE_TARGET_OSX)

if (NOT CLR_CMAKE_TARGET_ARCH_I386 OR NOT CLR_CMAKE_TARGET_WIN32)
add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:IGNORE_DEFAULT_TARGET_ARCH>>>:FEATURE_EH_FUNCLETS>)
endif (NOT CLR_CMAKE_TARGET_ARCH_I386 OR NOT CLR_CMAKE_TARGET_WIN32)
Expand Down
9 changes: 8 additions & 1 deletion src/coreclr/debug/ee/arm64/arm64walker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,14 @@ BYTE* NativeWalker::SetupOrSimulateInstructionForPatchSkip(T_CONTEXT * context,
{
CORDbgSetInstruction((CORDB_ADDRESS_TYPE *)patchBypass, 0xd503201f); //Add Nop in buffer

m_pSharedPatchBypassBuffer->RipTargetFixup = ip; //Control Flow simulation alone is done DebuggerPatchSkip::TriggerExceptionHook
#if defined(HOST_OSX) && defined(HOST_ARM64)
ExecutableWriterHolder<UINT_PTR> ripTargetFixupWriterHolder(&m_pSharedPatchBypassBuffer->RipTargetFixup, sizeof(UINT_PTR));
UINT_PTR *pRipTargetFixupRW = ripTargetFixupWriterHolder.GetRW();
#else // HOST_OSX && HOST_ARM64
UINT_PTR *pRipTargetFixupRW = &m_pSharedPatchBypassBuffer->RipTargetFixup;
#endif // HOST_OSX && HOST_ARM64

*pRipTargetFixupRW = ip; //Control Flow simulation alone is done DebuggerPatchSkip::TriggerExceptionHook
LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x is a Control Flow instr \n", opcode));

if (walk == WALK_CALL) //initialize Lr
Expand Down
47 changes: 30 additions & 17 deletions src/coreclr/debug/ee/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,13 @@ SharedPatchBypassBuffer* DebuggerControllerPatch::GetOrCreateSharedPatchBypassBu
if (m_pSharedPatchBypassBuffer == NULL)
{
void *pSharedPatchBypassBufferRX = g_pDebugger->GetInteropSafeExecutableHeap()->Alloc(sizeof(SharedPatchBypassBuffer));
#if defined(HOST_OSX) && defined(HOST_ARM64)
ExecutableWriterHolder<SharedPatchBypassBuffer> sharedPatchBypassBufferWriterHolder((SharedPatchBypassBuffer*)pSharedPatchBypassBufferRX, sizeof(SharedPatchBypassBuffer));
new (sharedPatchBypassBufferWriterHolder.GetRW()) SharedPatchBypassBuffer();
void *pSharedPatchBypassBufferRW = sharedPatchBypassBufferWriterHolder.GetRW();
#else // HOST_OSX && HOST_ARM64
void *pSharedPatchBypassBufferRW = pSharedPatchBypassBufferRX;
#endif // HOST_OSX && HOST_ARM64
new (pSharedPatchBypassBufferRW) SharedPatchBypassBuffer();
m_pSharedPatchBypassBuffer = (SharedPatchBypassBuffer*)pSharedPatchBypassBufferRX;

_ASSERTE(m_pSharedPatchBypassBuffer);
Expand Down Expand Up @@ -4351,7 +4356,15 @@ DebuggerPatchSkip::DebuggerPatchSkip(Thread *thread,
//

m_pSharedPatchBypassBuffer = patch->GetOrCreateSharedPatchBypassBuffer();
BYTE* patchBypass = m_pSharedPatchBypassBuffer->PatchBypass;
#if defined(HOST_OSX) && defined(HOST_ARM64)
ExecutableWriterHolder<SharedPatchBypassBuffer> sharedPatchBypassBufferWriterHolder((SharedPatchBypassBuffer*)m_pSharedPatchBypassBuffer, sizeof(SharedPatchBypassBuffer));
SharedPatchBypassBuffer *pSharedPatchBypassBufferRW = sharedPatchBypassBufferWriterHolder.GetRW();
#else // HOST_OSX && HOST_ARM64
SharedPatchBypassBuffer *pSharedPatchBypassBufferRW = m_pSharedPatchBypassBuffer;
#endif // HOST_OSX && HOST_ARM64

BYTE* patchBypassRX = m_pSharedPatchBypassBuffer->PatchBypass;
BYTE* patchBypassRW = pSharedPatchBypassBufferRW->PatchBypass;
LOG((LF_CORDB, LL_INFO10000, "DPS::DPS: Patch skip for opcode 0x%.4x at address %p buffer allocated at 0x%.8x\n", patch->opcode, patch->address, m_pSharedPatchBypassBuffer));

// Copy the instruction block over to the patch skip
Expand All @@ -4367,19 +4380,19 @@ DebuggerPatchSkip::DebuggerPatchSkip(Thread *thread,
// the 2nd skip executes the new jump-stamp code and not the original method prologue code. Copying
// the code every time ensures that we have the most up-to-date version of the code in the buffer.
_ASSERTE( patch->IsBound() );
CopyInstructionBlock(patchBypass, (const BYTE *)patch->address);
CopyInstructionBlock(patchBypassRW, (const BYTE *)patch->address);

// Technically, we could create a patch skipper for an inactive patch, but we rely on the opcode being
// set here.
_ASSERTE( patch->IsActivated() );
CORDbgSetInstruction((CORDB_ADDRESS_TYPE *)patchBypass, patch->opcode);
CORDbgSetInstruction((CORDB_ADDRESS_TYPE *)patchBypassRW, patch->opcode);

LOG((LF_CORDB, LL_EVERYTHING, "SetInstruction was called\n"));
//
// Look at instruction to get some attributes
//

NativeWalker::DecodeInstructionForPatchSkip(patchBypass, &(m_instrAttrib));
NativeWalker::DecodeInstructionForPatchSkip(patchBypassRX, &(m_instrAttrib));

#if defined(TARGET_AMD64)

Expand All @@ -4395,33 +4408,33 @@ DebuggerPatchSkip::DebuggerPatchSkip(Thread *thread,
// Populate the RIP-relative buffer with the current value if needed
//

BYTE* bufferBypass = m_pSharedPatchBypassBuffer->BypassBuffer;
BYTE* bufferBypassRW = pSharedPatchBypassBufferRW->BypassBuffer;

// Overwrite the *signed* displacement.
int dwOldDisp = *(int*)(&patchBypass[m_instrAttrib.m_dwOffsetToDisp]);
int dwOldDisp = *(int*)(&patchBypassRX[m_instrAttrib.m_dwOffsetToDisp]);
int dwNewDisp = offsetof(SharedPatchBypassBuffer, BypassBuffer) -
(offsetof(SharedPatchBypassBuffer, PatchBypass) + m_instrAttrib.m_cbInstr);
*(int*)(&patchBypass[m_instrAttrib.m_dwOffsetToDisp]) = dwNewDisp;
*(int*)(&patchBypassRW[m_instrAttrib.m_dwOffsetToDisp]) = dwNewDisp;

// This could be an LEA, which we'll just have to change into a MOV
// and copy the original address
if (((patchBypass[0] == 0x4C) || (patchBypass[0] == 0x48)) && (patchBypass[1] == 0x8d))
if (((patchBypassRX[0] == 0x4C) || (patchBypassRX[0] == 0x48)) && (patchBypassRX[1] == 0x8d))
{
patchBypass[1] = 0x8b; // MOV reg, mem
patchBypassRW[1] = 0x8b; // MOV reg, mem
_ASSERTE((int)sizeof(void*) <= SharedPatchBypassBuffer::cbBufferBypass);
*(void**)bufferBypass = (void*)(patch->address + m_instrAttrib.m_cbInstr + dwOldDisp);
*(void**)bufferBypassRW = (void*)(patch->address + m_instrAttrib.m_cbInstr + dwOldDisp);
}
else
{
_ASSERTE(m_instrAttrib.m_cOperandSize <= SharedPatchBypassBuffer::cbBufferBypass);
// Copy the data into our buffer.
memcpy(bufferBypass, patch->address + m_instrAttrib.m_cbInstr + dwOldDisp, m_instrAttrib.m_cOperandSize);
memcpy(bufferBypassRW, patch->address + m_instrAttrib.m_cbInstr + dwOldDisp, m_instrAttrib.m_cOperandSize);

if (m_instrAttrib.m_fIsWrite)
{
// save the actual destination address and size so when we TriggerSingleStep() we can update the value
m_pSharedPatchBypassBuffer->RipTargetFixup = (UINT_PTR)(patch->address + m_instrAttrib.m_cbInstr + dwOldDisp);
m_pSharedPatchBypassBuffer->RipTargetFixupSize = m_instrAttrib.m_cOperandSize;
pSharedPatchBypassBufferRW->RipTargetFixup = (UINT_PTR)(patch->address + m_instrAttrib.m_cbInstr + dwOldDisp);
pSharedPatchBypassBufferRW->RipTargetFixupSize = m_instrAttrib.m_cOperandSize;
}
}
}
Expand Down Expand Up @@ -4490,17 +4503,17 @@ DebuggerPatchSkip::DebuggerPatchSkip(Thread *thread,
#else // FEATURE_EMULATE_SINGLESTEP

#ifdef TARGET_ARM64
patchBypass = NativeWalker::SetupOrSimulateInstructionForPatchSkip(context, m_pSharedPatchBypassBuffer, (const BYTE *)patch->address, patch->opcode);
patchBypassRX = NativeWalker::SetupOrSimulateInstructionForPatchSkip(context, m_pSharedPatchBypassBuffer, (const BYTE *)patch->address, patch->opcode);
#endif //TARGET_ARM64

//set eip to point to buffer...
SetIP(context, (PCODE)patchBypass);
SetIP(context, (PCODE)patchBypassRX);

if (context ==(T_CONTEXT*) &c)
thread->SetThreadContext(&c);


LOG((LF_CORDB, LL_INFO10000, "DPS::DPS Bypass at 0x%p for opcode %p \n", patchBypass, patch->opcode));
LOG((LF_CORDB, LL_INFO10000, "DPS::DPS Bypass at 0x%p for opcode %p \n", patchBypassRX, patch->opcode));

//
// Turn on single step (if the platform supports it) so we can
Expand Down
18 changes: 16 additions & 2 deletions src/coreclr/debug/ee/controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,14 +266,28 @@ class SharedPatchBypassBuffer

LONG AddRef()
{
LONG newRefCount = InterlockedIncrement(&m_refCount);
#if !defined(DACCESS_COMPILE) && defined(HOST_OSX) && defined(HOST_ARM64)
ExecutableWriterHolder<LONG> refCountWriterHolder(&m_refCount, sizeof(LONG));
LONG *pRefCountRW = refCountWriterHolder.GetRW();
#else // !DACCESS_COMPILE && HOST_OSX && HOST_ARM64
LONG *pRefCountRW = &m_refCount;
#endif // !DACCESS_COMPILE && HOST_OSX && HOST_ARM64

LONG newRefCount = InterlockedIncrement(pRefCountRW);
_ASSERTE(newRefCount > 0);
return newRefCount;
}

LONG Release()
{
LONG newRefCount = InterlockedDecrement(&m_refCount);
#if !DACCESS_COMPILE && HOST_OSX && HOST_ARM64
ExecutableWriterHolder<LONG> refCountWriterHolder(&m_refCount, sizeof(LONG));
LONG *pRefCountRW = refCountWriterHolder.GetRW();
#else // !DACCESS_COMPILE && HOST_OSX && HOST_ARM64
LONG *pRefCountRW = &m_refCount;
#endif // !DACCESS_COMPILE && HOST_OSX && HOST_ARM64

LONG newRefCount = InterlockedDecrement(pRefCountRW);
_ASSERTE(newRefCount >= 0);

if (newRefCount == 0)
Expand Down
30 changes: 24 additions & 6 deletions src/coreclr/debug/ee/debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1317,13 +1317,19 @@ DebuggerEval::DebuggerEval(CONTEXT * pContext, DebuggerIPCE_FuncEvalInfo * pEval

// Allocate the breakpoint instruction info in executable memory.
void *bpInfoSegmentRX = g_pDebugger->GetInteropSafeExecutableHeap()->Alloc(sizeof(DebuggerEvalBreakpointInfoSegment));

#if !defined(DBI_COMPILE) && !defined(DACCESS_COMPILE) && defined(HOST_OSX) && defined(HOST_ARM64)
ExecutableWriterHolder<DebuggerEvalBreakpointInfoSegment> bpInfoSegmentWriterHolder((DebuggerEvalBreakpointInfoSegment*)bpInfoSegmentRX, sizeof(DebuggerEvalBreakpointInfoSegment));
new (bpInfoSegmentWriterHolder.GetRW()) DebuggerEvalBreakpointInfoSegment(this);
DebuggerEvalBreakpointInfoSegment *bpInfoSegmentRW = bpInfoSegmentWriterHolder.GetRW();
#else // !DBI_COMPILE && !DACCESS_COMPILE && HOST_OSX && HOST_ARM64
DebuggerEvalBreakpointInfoSegment *bpInfoSegmentRW = (DebuggerEvalBreakpointInfoSegment*)bpInfoSegmentRX;
#endif // !DBI_COMPILE && !DACCESS_COMPILE && HOST_OSX && HOST_ARM64
new (bpInfoSegmentRW) DebuggerEvalBreakpointInfoSegment(this);
m_bpInfoSegment = (DebuggerEvalBreakpointInfoSegment*)bpInfoSegmentRX;

// This must be non-zero so that the saved opcode is non-zero, and on IA64 we want it to be 0x16
// so that we can have a breakpoint instruction in any slot in the bundle.
bpInfoSegmentWriterHolder.GetRW()->m_breakpointInstruction[0] = 0x16;
bpInfoSegmentRW->m_breakpointInstruction[0] = 0x16;
#if defined(TARGET_ARM)
USHORT *bp = (USHORT*)&m_bpInfoSegment->m_breakpointInstruction;
*bp = CORDbg_BREAK_INSTRUCTION;
Expand Down Expand Up @@ -16234,6 +16240,7 @@ void Debugger::ReleaseDebuggerDataLock(Debugger *pDebugger)
}
#endif // DACCESS_COMPILE

#ifndef DACCESS_COMPILE
/* ------------------------------------------------------------------------ *
* Functions for DebuggerHeap executable memory allocations
* ------------------------------------------------------------------------ */
Expand Down Expand Up @@ -16378,6 +16385,7 @@ void* DebuggerHeapExecutableMemoryAllocator::GetPointerToChunkWithUsageUpdate(De

return page->GetPointerToChunk(chunkNumber);
}
#endif // DACCESS_COMPILE

/* ------------------------------------------------------------------------ *
* DebuggerHeap impl
Expand Down Expand Up @@ -16412,7 +16420,7 @@ void DebuggerHeap::Destroy()
m_hHeap = NULL;
}
#endif
#ifndef HOST_WINDOWS
#if !defined(HOST_WINDOWS) && !defined(DACCESS_COMPILE)
if (m_execMemAllocator != NULL)
{
delete m_execMemAllocator;
Expand All @@ -16439,6 +16447,8 @@ HRESULT DebuggerHeap::Init(BOOL fExecutable)
}
CONTRACTL_END;

#ifndef DACCESS_COMPILE

// Have knob catch if we don't want to lazy init the debugger.
_ASSERTE(!g_DbgShouldntUseDebugger);
m_fExecutable = fExecutable;
Expand Down Expand Up @@ -16472,7 +16482,9 @@ HRESULT DebuggerHeap::Init(BOOL fExecutable)
return E_OUTOFMEMORY;
}
}
#endif
#endif

#endif // !DACCESS_COMPILE

return S_OK;
}
Expand Down Expand Up @@ -16549,7 +16561,10 @@ void *DebuggerHeap::Alloc(DWORD size)
size += sizeof(InteropHeapCanary);
#endif

void *ret;
void *ret = NULL;

#ifndef DACCESS_COMPILE

#ifdef USE_INTEROPSAFE_HEAP
_ASSERTE(m_hHeap != NULL);
ret = ::HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, size);
Expand Down Expand Up @@ -16585,7 +16600,7 @@ void *DebuggerHeap::Alloc(DWORD size)
InteropHeapCanary * pCanary = InteropHeapCanary::GetFromRawAddr(ret);
ret = pCanary->GetUserAddr();
#endif

#endif // !DACCESS_COMPILE
return ret;
}

Expand Down Expand Up @@ -16638,6 +16653,8 @@ void DebuggerHeap::Free(void *pMem)
}
CONTRACTL_END;

#ifndef DACCESS_COMPILE

#ifdef USE_INTEROPSAFE_CANARY
// Check for canary

Expand Down Expand Up @@ -16673,6 +16690,7 @@ void DebuggerHeap::Free(void *pMem)
#endif // HOST_WINDOWS
}
#endif
#endif // !DACCESS_COMPILE
}

#ifndef DACCESS_COMPILE
Expand Down
32 changes: 26 additions & 6 deletions src/coreclr/debug/ee/debugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,8 @@ constexpr uint64_t CHUNKS_PER_DEBUGGERHEAP=(DEBUGGERHEAP_PAGESIZE / EXPECTED_CHU
constexpr uint64_t MAX_CHUNK_MASK=((1ull << CHUNKS_PER_DEBUGGERHEAP) - 1);
constexpr uint64_t BOOKKEEPING_CHUNK_MASK (1ull << (CHUNKS_PER_DEBUGGERHEAP - 1));

#ifndef DACCESS_COMPILE

// Forward declaration
struct DebuggerHeapExecutableMemoryPage;

Expand Down Expand Up @@ -1110,8 +1112,13 @@ struct DECLSPEC_ALIGN(DEBUGGERHEAP_PAGESIZE) DebuggerHeapExecutableMemoryPage

inline void SetNextPage(DebuggerHeapExecutableMemoryPage* nextPage)
{
#if defined(HOST_OSX) && defined(HOST_ARM64)
ExecutableWriterHolder<DebuggerHeapExecutableMemoryPage> debuggerHeapPageWriterHolder(this, sizeof(DebuggerHeapExecutableMemoryPage));
debuggerHeapPageWriterHolder.GetRW()->chunks[0].bookkeeping.nextPage = nextPage;
DebuggerHeapExecutableMemoryPage *pHeapPageRW = debuggerHeapPageWriterHolder.GetRW();
#else
DebuggerHeapExecutableMemoryPage *pHeapPageRW = this;
#endif
pHeapPageRW->chunks[0].bookkeeping.nextPage = nextPage;
}

inline uint64_t GetPageOccupancy() const
Expand All @@ -1124,8 +1131,13 @@ struct DECLSPEC_ALIGN(DEBUGGERHEAP_PAGESIZE) DebuggerHeapExecutableMemoryPage
// Can't unset the bookmark chunk!
ASSERT((newOccupancy & BOOKKEEPING_CHUNK_MASK) != 0);
ASSERT(newOccupancy <= MAX_CHUNK_MASK);
#if defined(HOST_OSX) && defined(HOST_ARM64)
ExecutableWriterHolder<DebuggerHeapExecutableMemoryPage> debuggerHeapPageWriterHolder(this, sizeof(DebuggerHeapExecutableMemoryPage));
debuggerHeapPageWriterHolder.GetRW()->chunks[0].bookkeeping.pageOccupancy = newOccupancy;
DebuggerHeapExecutableMemoryPage *pHeapPageRW = debuggerHeapPageWriterHolder.GetRW();
#else
DebuggerHeapExecutableMemoryPage *pHeapPageRW = this;
#endif
pHeapPageRW->chunks[0].bookkeeping.pageOccupancy = newOccupancy;
}

inline void* GetPointerToChunk(int chunkNum) const
Expand All @@ -1136,14 +1148,18 @@ struct DECLSPEC_ALIGN(DEBUGGERHEAP_PAGESIZE) DebuggerHeapExecutableMemoryPage

DebuggerHeapExecutableMemoryPage()
{
ExecutableWriterHolder<DebuggerHeapExecutableMemoryPage> debuggerHeapPageWriterHolder(this, sizeof(DebuggerHeapExecutableMemoryPage));

SetPageOccupancy(BOOKKEEPING_CHUNK_MASK); // only the first bit is set.
#if defined(HOST_OSX) && defined(HOST_ARM64)
ExecutableWriterHolder<DebuggerHeapExecutableMemoryPage> debuggerHeapPageWriterHolder(this, sizeof(DebuggerHeapExecutableMemoryPage));
DebuggerHeapExecutableMemoryPage *pHeapPageRW = debuggerHeapPageWriterHolder.GetRW();
#else
DebuggerHeapExecutableMemoryPage *pHeapPageRW = this;
#endif
for (uint8_t i = 1; i < CHUNKS_PER_DEBUGGERHEAP; i++)
{
ASSERT(i != 0);
debuggerHeapPageWriterHolder.GetRW()->chunks[i].data.startOfPage = this;
debuggerHeapPageWriterHolder.GetRW()->chunks[i].data.chunkNumber = i;
pHeapPageRW->chunks[i].data.startOfPage = this;
pHeapPageRW->chunks[i].data.chunkNumber = i;
}
}

Expand Down Expand Up @@ -1190,6 +1206,8 @@ class DebuggerHeapExecutableMemoryAllocator
Crst m_execMemAllocMutex;
};

#endif // DACCESS_COMPILE

// ------------------------------------------------------------------------ *
// DebuggerHeap class
// For interop debugging, we need a heap that:
Expand All @@ -1201,6 +1219,8 @@ class DebuggerHeapExecutableMemoryAllocator
#define USE_INTEROPSAFE_HEAP
#endif

class DebuggerHeapExecutableMemoryAllocator;

class DebuggerHeap
{
public:
Expand Down
Loading