diff --git a/level_zero/tools/source/debug/debug_session_imp.cpp b/level_zero/tools/source/debug/debug_session_imp.cpp index e7bc5081e0..35a97f6491 100644 --- a/level_zero/tools/source/debug/debug_session_imp.cpp +++ b/level_zero/tools/source/debug/debug_session_imp.cpp @@ -717,6 +717,18 @@ void DebugSessionImp::generateEventsForStoppedThreads(const std::vector &data) { + auto pStateSaveArea = reinterpret_cast(data.data()); + if (0 == strcmp(pStateSaveArea->versionHeader.magic, "tssarea")) { + size_t size = pStateSaveArea->versionHeader.size * 8u; + DEBUG_BREAK_IF(size != sizeof(SIP::StateSaveAreaHeader)); + stateSaveAreaHeader.assign(data.begin(), data.begin() + size); + PRINT_DEBUGGER_INFO_LOG("Context State Save Area : version == %d.%d.%d\n", (int)pStateSaveArea->versionHeader.version.major, (int)pStateSaveArea->versionHeader.version.minor, (int)pStateSaveArea->versionHeader.version.patch); + } else { + PRINT_DEBUGGER_ERROR_LOG("Setting Context State Save Area: failed to match magic numbers\n", ""); + } +} + const SIP::StateSaveAreaHeader *DebugSessionImp::getStateSaveAreaHeader() { if (stateSaveAreaHeader.empty()) { readStateSaveAreaHeader(); diff --git a/level_zero/tools/source/debug/debug_session_imp.h b/level_zero/tools/source/debug/debug_session_imp.h index c694b5a0b1..3827030089 100644 --- a/level_zero/tools/source/debug/debug_session_imp.h +++ b/level_zero/tools/source/debug/debug_session_imp.h @@ -69,6 +69,7 @@ struct DebugSessionImp : DebugSession { MOCKABLE_VIRTUAL void generateEventsForPendingInterrupts(); const SIP::StateSaveAreaHeader *getStateSaveAreaHeader(); + void validateAndSetStateSaveAreaHeader(const std::vector &data); virtual void readStateSaveAreaHeader(){}; virtual uint64_t getContextStateSaveAreaGpuVa(uint64_t memoryHandle) { diff --git a/level_zero/tools/source/debug/linux/prelim/debug_session.cpp b/level_zero/tools/source/debug/linux/prelim/debug_session.cpp index ab72f3566d..9ba91520e2 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.cpp +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.cpp @@ -647,14 +647,7 @@ void DebugSessionLinux::readStateSaveAreaHeader() { if (retVal != 0) { PRINT_DEBUGGER_ERROR_LOG("Reading Context State Save Area failed, error = %d\n", retVal); } else { - auto pStateSaveArea = reinterpret_cast(data.data()); - if (0 == strcmp(pStateSaveArea->versionHeader.magic, "tssarea")) { - size_t size = pStateSaveArea->versionHeader.size * 8u; - DEBUG_BREAK_IF(size != sizeof(SIP::StateSaveAreaHeader)); - stateSaveAreaHeader.assign(data.begin(), data.begin() + size); - - PRINT_DEBUGGER_INFO_LOG("Context State Save Area : version == %d.%d.%d\n", (int)pStateSaveArea->versionHeader.version.major, (int)pStateSaveArea->versionHeader.version.minor, (int)pStateSaveArea->versionHeader.version.patch); - } + validateAndSetStateSaveAreaHeader(data); } } } diff --git a/level_zero/tools/source/debug/windows/debug_session.cpp b/level_zero/tools/source/debug/windows/debug_session.cpp index 69ba04792e..9fc054176d 100644 --- a/level_zero/tools/source/debug/windows/debug_session.cpp +++ b/level_zero/tools/source/debug/windows/debug_session.cpp @@ -9,6 +9,8 @@ #include "shared/source/helpers/register_offsets.h" +#include "common/StateSaveAreaHeader.h" + namespace L0 { DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd); @@ -60,11 +62,13 @@ ze_result_t DebugSessionWindows::initialize() { PRINT_DEBUGGER_INFO_LOG("DBGUMD_ACTION_ATTACH_DEBUGGER: SUCCESS - ProcessId: %d DebugHandle: 0x%llx\n", processId, debugHandle); auto result = ZE_RESULT_SUCCESS; + do { result = readAndHandleEvent(100); } while (result == ZE_RESULT_SUCCESS && !moduleDebugAreaCaptured); if (moduleDebugAreaCaptured) { + readModuleDebugArea(); return ZE_RESULT_SUCCESS; } @@ -203,7 +207,13 @@ ze_result_t DebugSessionWindows::handleAllocationDataEvent(uint32_t seqNo, DBGUM } if (allocationDebugData->DataType == MODULE_HEAP_DEBUG_AREA) { + DEBUG_BREAK_IF(moduleDebugAreaCaptured && (registrationData.gpuVirtualAddress != this->debugAreaVA)); moduleDebugAreaCaptured = true; + this->debugAreaVA = registrationData.gpuVirtualAddress; + } else if (allocationDebugData->DataType == SIP_CONTEXT_SAVE_AREA) { + DEBUG_BREAK_IF(stateSaveAreaCaptured && (registrationData.gpuVirtualAddress != this->stateSaveAreaVA.load())); + stateSaveAreaVA.store(registrationData.gpuVirtualAddress); + stateSaveAreaCaptured = true; } PRINT_DEBUGGER_INFO_LOG("DBGUMD_ACTION_READ_ALLOCATION_DATA - Success - gpuVA=0x%llX Size=0x%X\n", registrationData.gpuVirtualAddress, registrationData.size); } @@ -454,10 +464,6 @@ bool DebugSessionWindows::readSystemRoutineIdent(EuThread *thread, uint64_t vmHa return false; } -bool DebugSessionWindows::readModuleDebugArea() { - return false; -} - ze_result_t DebugSessionWindows::readSbaBuffer(EuThread::ThreadId threadId, NEO::SbaTrackedAddresses &sbaBuffer) { uint64_t gpuVa = 0; getSbaBufferGpuVa(gpuVa); @@ -493,4 +499,58 @@ void DebugSessionWindows::getSbaBufferGpuVa(uint64_t &gpuVa) { return; } +bool DebugSessionWindows::readModuleDebugArea() { + + uint64_t memoryHandle = 0; + uint64_t gpuVa = this->debugAreaVA; + if (!moduleDebugAreaCaptured || allContexts.empty()) { + return false; + } + memoryHandle = *allContexts.begin(); + + memset(this->debugArea.magic, 0, sizeof(this->debugArea.magic)); + auto retVal = readGpuMemory(memoryHandle, reinterpret_cast(&this->debugArea), sizeof(this->debugArea), gpuVa); + + if (retVal != ZE_RESULT_SUCCESS) { + PRINT_DEBUGGER_ERROR_LOG("Reading Module Debug Area failed, error = %d\n", retVal); + return false; + } + + if (strncmp(this->debugArea.magic, "dbgarea", sizeof(NEO::DebugAreaHeader::magic)) != 0) { + PRINT_DEBUGGER_ERROR_LOG("Module Debug Area failed to match magic numbers\n"); + return false; + } + PRINT_DEBUGGER_INFO_LOG("Reading Module Debug Area Passed"); + return true; +} + +void DebugSessionWindows::readStateSaveAreaHeader() { + + uint64_t memoryHandle = 0; + uint64_t gpuVa = 0; + if (!stateSaveAreaCaptured) { + return; + } + gpuVa = this->stateSaveAreaVA.load(); + + { + std::unique_lock lock(asyncThreadMutex); + if (allContexts.empty()) { + return; + } + memoryHandle = *allContexts.begin(); + } + + auto headerSize = sizeof(SIP::StateSaveAreaHeader); + std::vector data(headerSize); + auto retVal = readGpuMemory(memoryHandle, data.data(), headerSize, gpuVa); + + if (retVal != ZE_RESULT_SUCCESS) { + PRINT_DEBUGGER_ERROR_LOG("Reading Context State Save Area failed, error = %d\n", retVal); + return; + } + + validateAndSetStateSaveAreaHeader(data); +} + } // namespace L0 diff --git a/level_zero/tools/source/debug/windows/debug_session.h b/level_zero/tools/source/debug/windows/debug_session.h index 3dad131852..0eed266b7f 100644 --- a/level_zero/tools/source/debug/windows/debug_session.h +++ b/level_zero/tools/source/debug/windows/debug_session.h @@ -16,6 +16,7 @@ #include "KmEscape.h" +#include #include namespace L0 { @@ -45,6 +46,7 @@ struct DebugSessionWindows : DebugSessionImp { ze_result_t readElfSpace(const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer); ze_result_t readSbaBuffer(EuThread::ThreadId, NEO::SbaTrackedAddresses &sbaBuffer) override; + void readStateSaveAreaHeader() override; MOCKABLE_VIRTUAL ze_result_t readAndHandleEvent(uint64_t timeoutMs); ze_result_t handleModuleCreateEvent(DBGUMD_READ_EVENT_MODULE_CREATE_EVENT_PARAMS &moduleCreateParams); @@ -65,7 +67,6 @@ struct DebugSessionWindows : DebugSessionImp { ThreadHelper asyncThread; std::mutex asyncThreadMutex; MOCKABLE_VIRTUAL void getSbaBufferGpuVa(uint64_t &gpuVa); - MOCKABLE_VIRTUAL NTSTATUS runEscape(KM_ESCAPE_INFO &escapeInfo); bool moduleDebugAreaCaptured = false; @@ -79,6 +80,11 @@ struct DebugSessionWindows : DebugSessionImp { uint64_t endVA; }; + uint64_t debugAreaVA; + NEO::DebugAreaHeader debugArea; + std::atomic stateSaveAreaVA{0}; + bool stateSaveAreaCaptured = false; + std::unordered_set allContexts; std::vector allElfs; }; diff --git a/level_zero/tools/test/unit_tests/sources/debug/windows/test_debug_api_windows.cpp b/level_zero/tools/test/unit_tests/sources/debug/windows/test_debug_api_windows.cpp index 9c4ba0e216..5495bd804c 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/windows/test_debug_api_windows.cpp +++ b/level_zero/tools/test/unit_tests/sources/debug/windows/test_debug_api_windows.cpp @@ -5,13 +5,17 @@ * */ +#include "shared/source/built_ins/sip.h" #include "shared/source/os_interface/windows/wddm_allocation.h" +#include "shared/test/common/mocks/mock_sip.h" #include "shared/test/common/mocks/windows/mock_wddm_eudebug.h" #include "shared/test/common/test_macros/hw_test.h" #include "level_zero/core/test/unit_tests/fixtures/device_fixture.h" #include "level_zero/tools/source/debug/windows/debug_session.h" +#include "common/StateSaveAreaHeader.h" + namespace L0 { namespace ult { @@ -20,6 +24,8 @@ struct MockDebugSessionWindows : DebugSessionWindows { using DebugSessionWindows::allElfs; using DebugSessionWindows::asyncThread; using DebugSessionWindows::closeAsyncThread; + using DebugSessionWindows::debugArea; + using DebugSessionWindows::debugAreaVA; using DebugSessionWindows::debugHandle; using DebugSessionWindows::ElfRange; using DebugSessionWindows::getSbaBufferGpuVa; @@ -30,11 +36,16 @@ struct MockDebugSessionWindows : DebugSessionWindows { using DebugSessionWindows::readAllocationDebugData; using DebugSessionWindows::readAndHandleEvent; using DebugSessionWindows::readGpuMemory; + using DebugSessionWindows::readModuleDebugArea; using DebugSessionWindows::readSbaBuffer; + using DebugSessionWindows::readStateSaveAreaHeader; using DebugSessionWindows::runEscape; using DebugSessionWindows::startAsyncThread; + using DebugSessionWindows::stateSaveAreaCaptured; + using DebugSessionWindows::stateSaveAreaVA; using DebugSessionWindows::wddm; using DebugSessionWindows::writeGpuMemory; + using L0::DebugSessionImp::getStateSaveAreaHeader; using L0::DebugSessionImp::isValidGpuAddress; MockDebugSessionWindows(const zet_debug_config_t &config, L0::Device *device) : DebugSessionWindows(config, device) {} @@ -336,6 +347,7 @@ TEST_F(DebugApiWindowsTest, givenDebugSessionInitializeCalledAndEventQueueIsNotA EXPECT_EQ(ZE_RESULT_SUCCESS, result); EXPECT_TRUE(session->moduleDebugAreaCaptured); + EXPECT_EQ(session->debugAreaVA, 0x12345678U); EXPECT_EQ(1u, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_ATTACH_DEBUGGER]); EXPECT_EQ(3u, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_READ_EVENT]); EXPECT_EQ(1u, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_READ_ALLOCATION_DATA]); @@ -470,6 +482,27 @@ TEST_F(DebugApiWindowsTest, givenDebugDataEventTypeWhenReadAndHandleEventCalledT EXPECT_EQ(elf.endVA, 0xa008u); } +TEST_F(DebugApiWindowsTest, givenAllocationEventTypeForStateSaveWhenReadAndHandleEventCalledThenStateSaveIsCaptured) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + auto session = std::make_unique(config, device); + session->wddm = mockWddm; + + mockWddm->numEvents = 1; + mockWddm->eventQueue[0].readEventType = DBGUMD_READ_EVENT_ALLOCATION_DATA_INFO; + mockWddm->eventQueue[0].eventParamsBuffer.eventParamsBuffer.ReadAdditionalAllocDataParams.NumOfDebugData = 1; + GFX_ALLOCATION_DEBUG_DATA_INFO *allocDebugDataInfo = reinterpret_cast(&mockWddm->eventQueue[0].eventParamsBuffer.eventParamsBuffer.ReadAdditionalAllocDataParams.DebugDataBufferPtr); + allocDebugDataInfo->DataType = SIP_CONTEXT_SAVE_AREA; + + WddmAllocation::RegistrationData registrationData = {0x12345678, 0x1000}; + mockWddm->readAllocationDataOutParams.outData = ®istrationData; + mockWddm->readAllocationDataOutParams.outDataSize = sizeof(registrationData); + + EXPECT_EQ(ZE_RESULT_SUCCESS, session->readAndHandleEvent(100)); + EXPECT_EQ(session->stateSaveAreaVA.load(), 0x12345678u); + EXPECT_TRUE(session->stateSaveAreaCaptured); +} + TEST_F(DebugApiWindowsTest, givenContextCreateEventTypeWhenReadAndHandleEventCalledThenAllContextsIsSetCorrectly) { zet_debug_config_t config = {}; config.pid = 0x1234; @@ -927,5 +960,117 @@ TEST_F(DebugApiWindowsTest, WhenCallingReadMemoryForExpectedFailureCasesThenErro EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, retVal); } +TEST_F(DebugApiWindowsTest, GivenModuleDebugAreaVaWhenReadingModuleDebugAreaThenGpuMemoryIsRead) { + auto session = std::make_unique(zet_debug_config_t{0x1234}, device); + ASSERT_NE(nullptr, session); + session->wddm = mockWddm; + session->debugHandle = MockDebugSessionWindows::mockDebugHandle; + session->allContexts.insert(0x12345); + session->moduleDebugAreaCaptured = true; + session->debugAreaVA = 0xABCDABCD; + + DebugAreaHeader debugArea; + debugArea.reserved1 = 1; + debugArea.pgsize = uint8_t(4); + debugArea.version = 1; + mockWddm->srcReadBuffer = &debugArea; + + auto retVal = session->readModuleDebugArea(); + EXPECT_TRUE(retVal); + ASSERT_EQ(1, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_READ_GFX_MEMORY]); + EXPECT_EQ(1u, session->debugArea.reserved1); + EXPECT_EQ(1u, session->debugArea.version); + EXPECT_EQ(4u, session->debugArea.pgsize); +} + +TEST_F(DebugApiWindowsTest, GivenModuleDebugAreaVaWhenReadingModuleDebugAreaReturnsIncorrectDataThenFailIsReturned) { + auto session = std::make_unique(zet_debug_config_t{0x1234}, device); + ASSERT_NE(nullptr, session); + session->wddm = mockWddm; + session->debugHandle = MockDebugSessionWindows::mockDebugHandle; + session->allContexts.insert(0x12345); + session->moduleDebugAreaCaptured = true; + session->debugAreaVA = 0xABCDABCD; + + DebugAreaHeader debugArea; + debugArea.magic[0] = 'x'; + mockWddm->srcReadBuffer = &debugArea; + + auto retVal = session->readModuleDebugArea(); + EXPECT_FALSE(retVal); +} + +TEST_F(DebugApiWindowsTest, GivenErrorInModuleDebugAreaDataWhenReadingModuleDebugAreaThenGpuMemoryIsNotReadAndFalseReturned) { + auto session = std::make_unique(zet_debug_config_t{0x1234}, device); + ASSERT_NE(nullptr, session); + session->wddm = mockWddm; + session->debugHandle = MockDebugSessionWindows::mockDebugHandle; + + auto retVal = session->readModuleDebugArea(); + EXPECT_FALSE(retVal); + ASSERT_EQ(0, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_READ_GFX_MEMORY]); + session->moduleDebugAreaCaptured = true; + retVal = session->readModuleDebugArea(); + EXPECT_FALSE(retVal); + ASSERT_EQ(0, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_READ_GFX_MEMORY]); + session->allContexts.insert(0x12345); + mockWddm->escapeReturnStatus = DBGUMD_RETURN_INVALID_ARGS; + retVal = session->readModuleDebugArea(); + EXPECT_FALSE(retVal); + ASSERT_EQ(1, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_READ_GFX_MEMORY]); +} + +TEST_F(DebugApiWindowsTest, GivenStateSaveAreaVaWhenReadingStateSaveAreaThenGpuMemoryIsRead) { + auto session = std::make_unique(zet_debug_config_t{0x1234}, device); + ASSERT_NE(nullptr, session); + session->wddm = mockWddm; + session->debugHandle = MockDebugSessionWindows::mockDebugHandle; + session->allContexts.insert(0x12345); + session->stateSaveAreaCaptured = true; + session->stateSaveAreaVA.store(0xABCDABCD); + auto stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + mockWddm->srcReadBuffer = stateSaveAreaHeader.data(); + + session->readStateSaveAreaHeader(); + ASSERT_EQ(1, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_READ_GFX_MEMORY]); + auto stateSaveAreaRead = session->getStateSaveAreaHeader(); + ASSERT_NE(nullptr, stateSaveAreaRead); + EXPECT_EQ(0, memcmp(stateSaveAreaRead, stateSaveAreaHeader.data(), sizeof(SIP::StateSaveAreaHeader))); +} + +TEST_F(DebugApiWindowsTest, GivenStateSaveAreaVaWhenReadingStateSaveAreaReturnsIncorrectDataThenStateSaveAreaIsNotUpdated) { + auto session = std::make_unique(zet_debug_config_t{0x1234}, device); + ASSERT_NE(nullptr, session); + session->wddm = mockWddm; + session->debugHandle = MockDebugSessionWindows::mockDebugHandle; + session->allContexts.insert(0x12345); + session->stateSaveAreaCaptured = true; + session->stateSaveAreaVA.store(0xABCDABCD); + auto stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + stateSaveAreaHeader[3] = 'x'; + mockWddm->srcReadBuffer = stateSaveAreaHeader.data(); + + session->readStateSaveAreaHeader(); + ASSERT_EQ(1, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_READ_GFX_MEMORY]); + auto stateSaveAreaRead = session->getStateSaveAreaHeader(); + ASSERT_EQ(nullptr, stateSaveAreaRead); +} + +TEST_F(DebugApiWindowsTest, GivenErrorCasesWhenReadingStateSaveAreThenMemoryIsNotRead) { + auto session = std::make_unique(zet_debug_config_t{0x1234}, device); + ASSERT_NE(nullptr, session); + session->wddm = mockWddm; + session->debugHandle = MockDebugSessionWindows::mockDebugHandle; + session->readStateSaveAreaHeader(); + ASSERT_EQ(0, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_READ_GFX_MEMORY]); + session->stateSaveAreaCaptured = true; + session->readStateSaveAreaHeader(); + ASSERT_EQ(0, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_READ_GFX_MEMORY]); + session->allContexts.insert(0x12345); + mockWddm->escapeReturnStatus = DBGUMD_RETURN_INVALID_ARGS; + session->readStateSaveAreaHeader(); + ASSERT_EQ(1, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_READ_GFX_MEMORY]); +} + } // namespace ult } // namespace L0 diff --git a/shared/test/common/mocks/windows/mock_wddm_eudebug.h b/shared/test/common/mocks/windows/mock_wddm_eudebug.h index 5145f1853c..c6e37b4eb7 100644 --- a/shared/test/common/mocks/windows/mock_wddm_eudebug.h +++ b/shared/test/common/mocks/windows/mock_wddm_eudebug.h @@ -68,7 +68,11 @@ struct WddmEuDebugInterfaceMock : public WddmMock { case DBGUMD_ACTION_READ_GFX_MEMORY: { void *dst = reinterpret_cast(pEscapeInfo->KmEuDbgL0EscapeInfo.ReadGfxMemoryParams.MemoryBufferPtr); size_t size = pEscapeInfo->KmEuDbgL0EscapeInfo.ReadGfxMemoryParams.MemoryBufferSize; - memset(dst, 0xaa, size); + if (srcReadBuffer) { + memcpy(dst, srcReadBuffer, size); + } else { + memset(dst, 0xaa, size); + } pEscapeInfo->KmEuDbgL0EscapeInfo.EscapeReturnStatus = escapeReturnStatus; break; } @@ -122,6 +126,7 @@ struct WddmEuDebugInterfaceMock : public WddmMock { static constexpr size_t bufferSize = 16; uint8_t testBuffer[bufferSize] = {0}; uint64_t mockGpuVa = 0x12345678; + void *srcReadBuffer = nullptr; }; } // namespace NEO