Skip to content

Commit eac3d21

Browse files
fix: correclty report pagefaults while single-stepping or resuming bp
- while resuming threads - after checking threads stopped immediately check for FE bit, if set do not generate thread stop event - if PageFault occured, report stop event based on pagefault event Related-To: GSD-7316 Signed-off-by: Mateusz Hoppe <[email protected]>
1 parent 33a36e5 commit eac3d21

File tree

4 files changed

+103
-3
lines changed

4 files changed

+103
-3
lines changed

level_zero/tools/source/debug/linux/prelim/debug_session.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1558,6 +1558,22 @@ int DebugSessionLinuxi915::threadControl(const std::vector<EuThread::ThreadId> &
15581558
return euControlRetVal;
15591559
}
15601560

1561+
bool DebugSessionLinuxi915::checkForceExceptionBit(uint64_t memoryHandle, EuThread::ThreadId threadId, uint32_t *cr0, const SIP::regset_desc *regDesc) {
1562+
1563+
auto gpuVa = getContextStateSaveAreaGpuVa(memoryHandle);
1564+
auto threadSlotOffset = calculateThreadSlotOffset(threadId);
1565+
auto startRegOffset = threadSlotOffset + calculateRegisterOffsetInThreadSlot(regDesc, 0);
1566+
1567+
[[maybe_unused]] int ret = readGpuMemory(memoryHandle, reinterpret_cast<char *>(cr0), 1 * regDesc->bytes, gpuVa + startRegOffset);
1568+
DEBUG_BREAK_IF(ret != ZE_RESULT_SUCCESS);
1569+
1570+
const uint32_t cr0ForcedExcpetionBitmask = 0x04000000;
1571+
if (cr0[1] & cr0ForcedExcpetionBitmask) {
1572+
return true;
1573+
}
1574+
return false;
1575+
}
1576+
15611577
void DebugSessionLinuxi915::checkStoppedThreadsAndGenerateEvents(const std::vector<EuThread::ThreadId> &threads, uint64_t memoryHandle, uint32_t deviceIndex) {
15621578

15631579
std::vector<EuThread::ThreadId> threadsWithAttention;
@@ -1588,19 +1604,30 @@ void DebugSessionLinuxi915::checkStoppedThreadsAndGenerateEvents(const std::vect
15881604
const auto &threadsToCheck = threadsWithAttention.size() > 0 ? threadsWithAttention : threads;
15891605
stoppedThreadsToReport.reserve(threadsToCheck.size());
15901606

1607+
const auto regSize = std::max(getRegisterSize(ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU), 64u);
1608+
auto cr0 = std::make_unique<uint32_t[]>(regSize / sizeof(uint32_t));
1609+
auto regDesc = typeToRegsetDesc(ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU);
1610+
15911611
for (auto &threadId : threadsToCheck) {
15921612
SIP::sr_ident srMagic = {{0}};
15931613
srMagic.count = 0;
15941614

15951615
if (readSystemRoutineIdent(allThreads[threadId].get(), memoryHandle, srMagic)) {
15961616
bool wasStopped = allThreads[threadId]->isStopped();
1617+
bool checkIfStopped = true;
15971618

1598-
if (allThreads[threadId]->verifyStopped(srMagic.count)) {
1619+
if (srMagic.count % 2 == 1) {
1620+
memset(cr0.get(), 0, regSize);
1621+
checkIfStopped = !checkForceExceptionBit(memoryHandle, threadId, cr0.get(), regDesc);
1622+
}
1623+
1624+
if (checkIfStopped && allThreads[threadId]->verifyStopped(srMagic.count)) {
15991625
allThreads[threadId]->stopThread(memoryHandle);
16001626
if (!wasStopped) {
16011627
stoppedThreadsToReport.push_back(threadId);
16021628
}
16031629
}
1630+
16041631
} else {
16051632
break;
16061633
}

level_zero/tools/source/debug/linux/prelim/debug_session.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ struct DebugSessionLinuxi915 : DebugSessionLinux {
189189
ze_result_t resumeImp(const std::vector<EuThread::ThreadId> &threads, uint32_t deviceIndex) override;
190190
ze_result_t interruptImp(uint32_t deviceIndex) override;
191191
void checkStoppedThreadsAndGenerateEvents(const std::vector<EuThread::ThreadId> &threads, uint64_t memoryHandle, uint32_t deviceIndex) override;
192+
MOCKABLE_VIRTUAL bool checkForceExceptionBit(uint64_t memoryHandle, EuThread::ThreadId threadId, uint32_t *cr0, const SIP::regset_desc *regDesc);
192193

193194
void enqueueApiEvent(zet_debug_event_t &debugEvent) override {
194195
pushApiEvent(debugEvent);

level_zero/tools/test/unit_tests/sources/debug/linux/prelim/debug_session_fixtures_linux.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,13 @@ struct MockDebugSessionLinuxi915 : public L0::DebugSessionLinuxi915 {
439439
return L0::DebugSessionLinuxi915::checkThreadIsResumed(threadID);
440440
}
441441

442+
bool checkForceExceptionBit(uint64_t memoryHandle, EuThread::ThreadId threadId, uint32_t *cr0, const SIP::regset_desc *regDesc) override {
443+
if (skipCheckForceExceptionBit) {
444+
return false;
445+
}
446+
return L0::DebugSessionLinuxi915::checkForceExceptionBit(memoryHandle, threadId, cr0, regDesc);
447+
}
448+
442449
float getThreadStartLimitTime() override {
443450
if (threadStartLimit >= 0.0) {
444451
return threadStartLimit;
@@ -501,6 +508,7 @@ struct MockDebugSessionLinuxi915 : public L0::DebugSessionLinuxi915 {
501508
uint32_t writeResumeCommandCalled = 0;
502509
bool skipcheckThreadIsResumed = true;
503510
uint32_t checkThreadIsResumedCalled = 0;
511+
bool skipCheckForceExceptionBit = false;
504512
uint32_t interruptedDevice = std::numeric_limits<uint32_t>::max();
505513
uint32_t processPendingVmBindEventsCalled = 0;
506514
uint32_t checkStoppedThreadsAndGenerateEventsCallCount = 0;

level_zero/tools/test/unit_tests/sources/debug/linux/prelim/test_debug_api_linux.cpp

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5418,15 +5418,23 @@ TEST_F(DebugApiLinuxTest, WhenCallingThreadControlForResumeThenProperIoctlsIsCal
54185418
TEST_F(DebugApiLinuxTest, GivenStoppedAndRunningThreadWhenCheckStoppedThreadsAndGenerateEventsCalledThenThreadStoppedEventsGeneratedOnlyForNewlyStoppedThreads) {
54195419
zet_debug_config_t config = {};
54205420
config.pid = 0x1234;
5421+
const auto memoryHandle = 1u;
54215422

54225423
auto sessionMock = std::make_unique<MockDebugSessionLinuxi915>(config, device, 10);
54235424
ASSERT_NE(nullptr, sessionMock);
5425+
SIP::version version = {2, 0, 0};
5426+
initStateSaveArea(sessionMock->stateSaveAreaHeader, version, device);
54245427

54255428
auto handler = new MockIoctlHandler;
54265429
sessionMock->ioctlHandler.reset(handler);
5430+
handler->setPreadMemory(sessionMock->stateSaveAreaHeader.data(), sessionMock->stateSaveAreaHeader.size(), 0x1000);
5431+
5432+
DebugSessionLinuxi915::BindInfo cssaInfo = {0x1000, sessionMock->stateSaveAreaHeader.size()};
5433+
sessionMock->clientHandleToConnection[MockDebugSessionLinuxi915::mockClientHandle]->vmToContextStateSaveAreaBindInfo[memoryHandle] = cssaInfo;
5434+
54275435
EuThread::ThreadId thread = {0, 0, 0, 0, 0};
54285436
EuThread::ThreadId thread1 = {0, 0, 0, 0, 1};
5429-
const auto memoryHandle = 1u;
5437+
54305438
sessionMock->allThreads[thread.packed]->stopThread(memoryHandle);
54315439
sessionMock->allThreads[thread.packed]->reportAsStopped();
54325440

@@ -5449,7 +5457,7 @@ TEST_F(DebugApiLinuxTest, GivenStoppedAndRunningThreadWhenCheckStoppedThreadsAnd
54495457

54505458
sessionMock->checkStoppedThreadsAndGenerateEvents(threads, memoryHandle, 0);
54515459

5452-
EXPECT_EQ(1, handler->ioctlCalled);
5460+
EXPECT_EQ(3, handler->ioctlCalled);
54535461
EXPECT_EQ(1u, handler->euControlArgs.size());
54545462
EXPECT_EQ(2u, sessionMock->numThreadsPassedToThreadControl);
54555463
EXPECT_EQ(uint32_t(PRELIM_I915_DEBUG_EU_THREADS_CMD_STOPPED), handler->euControlArgs[0].euControl.cmd);
@@ -5471,6 +5479,61 @@ TEST_F(DebugApiLinuxTest, GivenStoppedAndRunningThreadWhenCheckStoppedThreadsAnd
54715479
EXPECT_EQ(thread1.thread, event.info.thread.thread.thread);
54725480
}
54735481

5482+
TEST_F(DebugApiLinuxTest, GivenStoppedThreadResumeCausingPageFaultAndFEBitSetWhenCheckStoppedThreadsAndGenerateEventsCalledThenThreadStoppedEventIsNotGenerated) {
5483+
zet_debug_config_t config = {};
5484+
config.pid = 0x1234;
5485+
const auto memoryHandle = 1u;
5486+
5487+
auto sessionMock = std::make_unique<MockDebugSessionLinuxi915>(config, device, 10);
5488+
ASSERT_NE(nullptr, sessionMock);
5489+
SIP::version version = {2, 0, 0};
5490+
initStateSaveArea(sessionMock->stateSaveAreaHeader, version, device);
5491+
5492+
auto handler = new MockIoctlHandler;
5493+
sessionMock->ioctlHandler.reset(handler);
5494+
handler->setPreadMemory(sessionMock->stateSaveAreaHeader.data(), sessionMock->stateSaveAreaHeader.size(), 0x1000);
5495+
5496+
DebugSessionLinuxi915::BindInfo cssaInfo = {0x1000, sessionMock->stateSaveAreaHeader.size()};
5497+
sessionMock->clientHandleToConnection[MockDebugSessionLinuxi915::mockClientHandle]->vmToContextStateSaveAreaBindInfo[memoryHandle] = cssaInfo;
5498+
5499+
EuThread::ThreadId thread = {0, 0, 0, 0, 0};
5500+
5501+
sessionMock->allThreads[thread.packed]->stopThread(memoryHandle);
5502+
sessionMock->allThreads[thread.packed]->reportAsStopped();
5503+
sessionMock->allThreads[thread.packed]->resumeThread();
5504+
std::vector<EuThread::ThreadId> threads;
5505+
threads.push_back(thread);
5506+
5507+
for (auto thread : threads) {
5508+
sessionMock->stoppedThreads[thread.packed] = 3;
5509+
}
5510+
5511+
auto regDesc = sessionMock->typeToRegsetDesc(ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU);
5512+
uint32_t cr0[2] = {};
5513+
cr0[1] = 1 << 26;
5514+
5515+
memcpy_s(sessionMock->stateSaveAreaHeader.data() +
5516+
threadSlotOffset(reinterpret_cast<SIP::StateSaveAreaHeader *>(sessionMock->stateSaveAreaHeader.data()), thread.slice, thread.subslice, thread.eu, thread.thread) +
5517+
regOffsetInThreadSlot(regDesc, 0),
5518+
regDesc->bytes, cr0, sizeof(cr0));
5519+
5520+
std::unique_ptr<uint8_t[]> bitmask;
5521+
size_t bitmaskSize = 0;
5522+
auto &hwInfo = neoDevice->getHardwareInfo();
5523+
auto &l0GfxCoreHelper = neoDevice->getRootDeviceEnvironment().getHelper<L0GfxCoreHelper>();
5524+
l0GfxCoreHelper.getAttentionBitmaskForSingleThreads(threads, hwInfo, bitmask, bitmaskSize);
5525+
5526+
handler->outputBitmaskSize = bitmaskSize;
5527+
handler->outputBitmask = std::move(bitmask);
5528+
5529+
sessionMock->checkStoppedThreadsAndGenerateEvents(threads, memoryHandle, 0);
5530+
5531+
EXPECT_EQ(1, handler->ioctlCalled);
5532+
5533+
EXPECT_FALSE(sessionMock->allThreads[thread.packed]->isStopped());
5534+
EXPECT_EQ(0u, sessionMock->apiEvents.size());
5535+
}
5536+
54745537
TEST_F(DebugApiLinuxTest, GivenNoAttentionBitsWhenMultipleThreadsPassedToCheckStoppedThreadsAndGenerateEventsThenThreadsStateNotCheckedAndEventsNotGenerated) {
54755538
zet_debug_config_t config = {};
54765539
config.pid = 0x1234;
@@ -5547,6 +5610,7 @@ TEST_F(DebugApiLinuxTest, GivenNoAttentionBitsWhenSingleThreadPassedToCheckStopp
55475610

55485611
handler->outputBitmaskSize = bitmaskSize;
55495612
handler->outputBitmask = std::move(bitmask);
5613+
sessionMock->skipCheckForceExceptionBit = true;
55505614

55515615
sessionMock->checkStoppedThreadsAndGenerateEvents({thread1}, memoryHandle, 0);
55525616

0 commit comments

Comments
 (0)