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