1 /*
2  * Copyright (C) 2018-2021 Intel Corporation
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  */
7 
8 #include "shared/source/source_level_debugger/source_level_debugger.h"
9 
10 #include "shared/source/debug_settings/debug_settings_manager.h"
11 #include "shared/source/debugger/debugger.h"
12 #include "shared/source/helpers/debug_helpers.h"
13 #include "shared/source/helpers/file_io.h"
14 #include "shared/source/kernel/debug_data.h"
15 #include "shared/source/os_interface/os_interface.h"
16 
17 #include "igfx_debug_interchange_types.h"
18 #include "lib_names.h"
19 
20 #define IGFXDBG_CURRENT_VERSION 4
21 
22 namespace NEO {
23 
24 static_assert(std::is_pod<GfxDbgKernelDebugData>::value);
25 
26 const char *SourceLevelDebugger::notifyNewDeviceSymbol = "notifyNewDevice";
27 const char *SourceLevelDebugger::notifySourceCodeSymbol = "notifySourceCode";
28 const char *SourceLevelDebugger::getDebuggerOptionSymbol = "getDebuggerOption";
29 const char *SourceLevelDebugger::notifyKernelDebugDataSymbol = "notifyKernelDebugData";
30 const char *SourceLevelDebugger::initSymbol = "init";
31 const char *SourceLevelDebugger::isDebuggerActiveSymbol = "isDebuggerActive";
32 const char *SourceLevelDebugger::notifyDeviceDestructionSymbol = "notifyDeviceDestruction";
33 const char *SourceLevelDebugger::dllName = SLD_LIBRARY_NAME;
34 
35 class SourceLevelDebugger::SourceLevelDebuggerInterface {
36   public:
37     SourceLevelDebuggerInterface() = default;
38     ~SourceLevelDebuggerInterface() = default;
39 
40     typedef int (*NotifyNewDeviceFunction)(GfxDbgNewDeviceData *data);
41     typedef int (*NotifySourceCodeFunction)(GfxDbgSourceCode *data);
42     typedef int (*GetDebuggerOptionFunction)(GfxDbgOption *);
43     typedef int (*NotifyKernelDebugDataFunction)(GfxDbgKernelDebugData *data);
44     typedef int (*InitFunction)(GfxDbgTargetCaps *data);
45     typedef int (*IsDebuggerActiveFunction)(void);
46     typedef int (*NotifyDeviceDestructionFunction)(GfxDbgDeviceDestructionData *data);
47 
48     NotifyNewDeviceFunction notifyNewDeviceFunc = nullptr;
49     NotifySourceCodeFunction notifySourceCodeFunc = nullptr;
50     GetDebuggerOptionFunction getDebuggerOptionFunc = nullptr;
51     NotifyKernelDebugDataFunction notifyKernelDebugDataFunc = nullptr;
52     InitFunction initFunc = nullptr;
53     IsDebuggerActiveFunction isDebuggerActive = nullptr;
54     NotifyDeviceDestructionFunction notifyDeviceDestructionFunc = nullptr;
55 };
56 
create()57 SourceLevelDebugger *SourceLevelDebugger::create() {
58     auto library = SourceLevelDebugger::loadDebugger();
59     if (library) {
60         auto isActiveFunc = reinterpret_cast<SourceLevelDebuggerInterface::IsDebuggerActiveFunction>(library->getProcAddress(isDebuggerActiveSymbol));
61         int result = isActiveFunc();
62         if (result == 1) {
63             // pass library ownership to Source Level Debugger
64             return new SourceLevelDebugger(library);
65         }
66         delete library;
67     }
68     if (DebugManager.flags.EnableMockSourceLevelDebugger.get()) {
69         auto sld = new SourceLevelDebugger(nullptr);
70         sld->isActive = true;
71         return sld;
72     }
73     return nullptr;
74 }
SourceLevelDebugger(OsLibrary * library)75 SourceLevelDebugger::SourceLevelDebugger(OsLibrary *library) {
76     debuggerLibrary.reset(library);
77     isLegacyMode = true;
78 
79     if (debuggerLibrary.get() == nullptr) {
80         return;
81     }
82     sourceLevelDebuggerInterface = new SourceLevelDebuggerInterface;
83     getFunctions();
84 
85     if (sourceLevelDebuggerInterface->isDebuggerActive == nullptr) {
86         return;
87     }
88 
89     int result = sourceLevelDebuggerInterface->isDebuggerActive();
90     if (result == 1) {
91         UNRECOVERABLE_IF(sourceLevelDebuggerInterface->getDebuggerOptionFunc == nullptr);
92         UNRECOVERABLE_IF(sourceLevelDebuggerInterface->initFunc == nullptr);
93         UNRECOVERABLE_IF(sourceLevelDebuggerInterface->notifyKernelDebugDataFunc == nullptr);
94         UNRECOVERABLE_IF(sourceLevelDebuggerInterface->notifyNewDeviceFunc == nullptr);
95         UNRECOVERABLE_IF(sourceLevelDebuggerInterface->notifySourceCodeFunc == nullptr);
96         UNRECOVERABLE_IF(sourceLevelDebuggerInterface->notifyDeviceDestructionFunc == nullptr);
97         isActive = true;
98     }
99 }
100 
~SourceLevelDebugger()101 SourceLevelDebugger::~SourceLevelDebugger() {
102     if (sourceLevelDebuggerInterface) {
103         delete sourceLevelDebuggerInterface;
104     }
105 }
106 
isDebuggerActive()107 bool SourceLevelDebugger::isDebuggerActive() {
108     return isActive;
109 }
110 
getFunctions()111 void SourceLevelDebugger::getFunctions() {
112     UNRECOVERABLE_IF(debuggerLibrary.get() == nullptr);
113 
114     sourceLevelDebuggerInterface->notifyNewDeviceFunc = reinterpret_cast<SourceLevelDebuggerInterface::NotifyNewDeviceFunction>(debuggerLibrary->getProcAddress(notifyNewDeviceSymbol));
115     sourceLevelDebuggerInterface->notifySourceCodeFunc = reinterpret_cast<SourceLevelDebuggerInterface::NotifySourceCodeFunction>(debuggerLibrary->getProcAddress(notifySourceCodeSymbol));
116     sourceLevelDebuggerInterface->getDebuggerOptionFunc = reinterpret_cast<SourceLevelDebuggerInterface::GetDebuggerOptionFunction>(debuggerLibrary->getProcAddress(getDebuggerOptionSymbol));
117     sourceLevelDebuggerInterface->notifyKernelDebugDataFunc = reinterpret_cast<SourceLevelDebuggerInterface::NotifyKernelDebugDataFunction>(debuggerLibrary->getProcAddress(notifyKernelDebugDataSymbol));
118     sourceLevelDebuggerInterface->initFunc = reinterpret_cast<SourceLevelDebuggerInterface::InitFunction>(debuggerLibrary->getProcAddress(initSymbol));
119     sourceLevelDebuggerInterface->isDebuggerActive = reinterpret_cast<SourceLevelDebuggerInterface::IsDebuggerActiveFunction>(debuggerLibrary->getProcAddress(isDebuggerActiveSymbol));
120     sourceLevelDebuggerInterface->notifyDeviceDestructionFunc = reinterpret_cast<SourceLevelDebuggerInterface::NotifyDeviceDestructionFunction>(debuggerLibrary->getProcAddress(notifyDeviceDestructionSymbol));
121 }
122 
notifyNewDevice(uint32_t deviceHandle)123 bool SourceLevelDebugger::notifyNewDevice(uint32_t deviceHandle) {
124     if (isActive) {
125         GfxDbgNewDeviceData newDevice = {};
126         newDevice.version = IGFXDBG_CURRENT_VERSION;
127         newDevice.dh = reinterpret_cast<GfxDeviceHandle>(static_cast<uint64_t>(deviceHandle));
128         newDevice.udh = GfxDeviceHandle(0);
129         if (sourceLevelDebuggerInterface) {
130             int result = sourceLevelDebuggerInterface->notifyNewDeviceFunc(&newDevice);
131             DEBUG_BREAK_IF(static_cast<IgfxdbgRetVal>(result) != IgfxdbgRetVal::IGFXDBG_SUCCESS);
132             static_cast<void>(result);
133         }
134         this->deviceHandle = deviceHandle;
135     }
136     return false;
137 }
138 
notifyDeviceDestruction()139 bool SourceLevelDebugger::notifyDeviceDestruction() {
140     if (isActive) {
141         GfxDbgDeviceDestructionData deviceDestruction = {};
142         deviceDestruction.version = IGFXDBG_CURRENT_VERSION;
143         deviceDestruction.dh = reinterpret_cast<GfxDeviceHandle>(static_cast<uint64_t>(this->deviceHandle));
144         if (sourceLevelDebuggerInterface) {
145             int result = sourceLevelDebuggerInterface->notifyDeviceDestructionFunc(&deviceDestruction);
146             DEBUG_BREAK_IF(static_cast<IgfxdbgRetVal>(result) != IgfxdbgRetVal::IGFXDBG_SUCCESS);
147             static_cast<void>(result);
148         }
149         this->deviceHandle = 0;
150         return true;
151     }
152     return false;
153 }
154 
notifySourceCode(const char * source,size_t sourceSize,std::string & file) const155 bool SourceLevelDebugger::notifySourceCode(const char *source, size_t sourceSize, std::string &file) const {
156     if (isActive) {
157         GfxDbgSourceCode sourceCode = {};
158         char fileName[FILENAME_MAX] = "";
159 
160         sourceCode.version = IGFXDBG_CURRENT_VERSION;
161         sourceCode.hDevice = reinterpret_cast<GfxDeviceHandle>(static_cast<uint64_t>(this->deviceHandle));
162         sourceCode.sourceCode = source;
163         sourceCode.sourceCodeSize = static_cast<unsigned int>(sourceSize);
164         sourceCode.sourceName = &fileName[0];
165         sourceCode.sourceNameMaxLen = sizeof(fileName);
166 
167         if (sourceLevelDebuggerInterface) {
168             int result = sourceLevelDebuggerInterface->notifySourceCodeFunc(&sourceCode);
169             DEBUG_BREAK_IF(static_cast<IgfxdbgRetVal>(result) != IgfxdbgRetVal::IGFXDBG_SUCCESS);
170             static_cast<void>(result);
171         }
172         file = fileName;
173     }
174     return false;
175 }
176 
isOptimizationDisabled() const177 bool SourceLevelDebugger::isOptimizationDisabled() const {
178     if (isActive) {
179         const size_t optionValueSize = 4;
180         char value[optionValueSize] = {0};
181         GfxDbgOption option = {};
182         option.version = IGFXDBG_CURRENT_VERSION;
183         option.optionName = DBG_OPTION_IS_OPTIMIZATION_DISABLED;
184         option.valueLen = sizeof(value);
185         option.value = &value[0];
186 
187         if (sourceLevelDebuggerInterface) {
188             int result = sourceLevelDebuggerInterface->getDebuggerOptionFunc(&option);
189             if (result == 1) {
190                 if (option.value[0] == '1') {
191                     return true;
192                 }
193             }
194         } else {
195             return DebugManager.flags.EnableMockSourceLevelDebugger.get() == 1 ? true : false;
196         }
197     }
198     return false;
199 }
200 
notifyKernelDebugData(const DebugData * debugData,const std::string & name,const void * isa,size_t isaSize) const201 bool SourceLevelDebugger::notifyKernelDebugData(const DebugData *debugData, const std::string &name, const void *isa, size_t isaSize) const {
202     if (isActive) {
203         GfxDbgKernelDebugData kernelDebugData = {};
204         kernelDebugData.hDevice = reinterpret_cast<GfxDeviceHandle>(static_cast<uint64_t>(this->deviceHandle));
205         kernelDebugData.version = IGFXDBG_CURRENT_VERSION;
206         kernelDebugData.hProgram = reinterpret_cast<GenRtProgramHandle>(0);
207 
208         kernelDebugData.kernelName = name.c_str();
209         kernelDebugData.kernelBinBuffer = const_cast<void *>(isa);
210         kernelDebugData.KernelBinSize = static_cast<uint32_t>(isaSize);
211 
212         if (debugData) {
213             kernelDebugData.dbgVisaBuffer = debugData->vIsa;
214             kernelDebugData.dbgVisaSize = debugData->vIsaSize;
215             kernelDebugData.dbgGenIsaBuffer = debugData->genIsa;
216             kernelDebugData.dbgGenIsaSize = debugData->genIsaSize;
217 
218             if (NEO::DebugManager.flags.DebuggerLogBitmask.get() & NEO::DebugVariables::DEBUGGER_LOG_BITMASK::DUMP_ELF) {
219                 std::ofstream elfFile;
220                 std::string fileName = name + ".elf";
221 
222                 int suffix = 0;
223                 while (fileExists(fileName)) {
224                     fileName = name + "_" + std::to_string(suffix) + ".elf";
225                     suffix++;
226                 }
227                 writeDataToFile(fileName.c_str(), kernelDebugData.dbgVisaBuffer, kernelDebugData.dbgVisaSize);
228             }
229         }
230 
231         if (sourceLevelDebuggerInterface) {
232             int result = sourceLevelDebuggerInterface->notifyKernelDebugDataFunc(&kernelDebugData);
233             DEBUG_BREAK_IF(static_cast<IgfxdbgRetVal>(result) != IgfxdbgRetVal::IGFXDBG_SUCCESS);
234             static_cast<void>(result);
235         }
236     }
237     return false;
238 }
239 
initialize(bool useLocalMemory)240 bool SourceLevelDebugger::initialize(bool useLocalMemory) {
241     if (isActive) {
242         GfxDbgTargetCaps caps = {IGFXDBG_CURRENT_VERSION, useLocalMemory};
243         if (sourceLevelDebuggerInterface) {
244             int result = sourceLevelDebuggerInterface->initFunc(&caps);
245             if (static_cast<IgfxdbgRetVal>(result) != IgfxdbgRetVal::IGFXDBG_SUCCESS) {
246                 isActive = false;
247             }
248         }
249     }
250     return false;
251 }
252 } // namespace NEO
253