1 //===-- RenderScriptRuntime.cpp ---------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "RenderScriptRuntime.h"
11 
12 #include "lldb/Core/ConstString.h"
13 #include "lldb/Core/Debugger.h"
14 #include "lldb/Core/Error.h"
15 #include "lldb/Core/Log.h"
16 #include "lldb/Core/PluginManager.h"
17 #include "lldb/Symbol/Symbol.h"
18 #include "lldb/Target/Process.h"
19 #include "lldb/Target/Target.h"
20 #include "lldb/Interpreter/Args.h"
21 #include "lldb/Interpreter/Options.h"
22 #include "lldb/Interpreter/CommandInterpreter.h"
23 #include "lldb/Interpreter/CommandReturnObject.h"
24 #include "lldb/Interpreter/CommandObjectMultiword.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 //------------------------------------------------------------------
30 // Static Functions
31 //------------------------------------------------------------------
32 LanguageRuntime *
33 RenderScriptRuntime::CreateInstance(Process *process, lldb::LanguageType language)
34 {
35 
36     if (language == eLanguageTypeExtRenderScript)
37         return new RenderScriptRuntime(process);
38     else
39         return NULL;
40 }
41 
42 void
43 RenderScriptRuntime::Initialize()
44 {
45     PluginManager::RegisterPlugin(GetPluginNameStatic(), "RenderScript language support", CreateInstance);
46 }
47 
48 void
49 RenderScriptRuntime::Terminate()
50 {
51     PluginManager::UnregisterPlugin(CreateInstance);
52 }
53 
54 lldb_private::ConstString
55 RenderScriptRuntime::GetPluginNameStatic()
56 {
57     static ConstString g_name("renderscript");
58     return g_name;
59 }
60 
61 RenderScriptRuntime::ModuleKind
62 RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp)
63 {
64     if (module_sp)
65     {
66         // Is this a module containing renderscript kernels?
67         const Symbol *info_sym = module_sp->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData);
68         if (info_sym)
69         {
70             return eModuleKindKernelObj;
71         }
72     }
73     return eModuleKindIgnored;
74 }
75 
76 bool
77 RenderScriptRuntime::IsRenderScriptModule(const lldb::ModuleSP &module_sp)
78 {
79     return GetModuleKind(module_sp) != eModuleKindIgnored;
80 }
81 
82 
83 void
84 RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list )
85 {
86     Mutex::Locker locker (module_list.GetMutex ());
87 
88     size_t num_modules = module_list.GetSize();
89     for (size_t i = 0; i < num_modules; i++)
90     {
91         auto mod = module_list.GetModuleAtIndex (i);
92         if (IsRenderScriptModule (mod))
93         {
94             LoadModule(mod);
95         }
96     }
97 }
98 
99 
100 //------------------------------------------------------------------
101 // PluginInterface protocol
102 //------------------------------------------------------------------
103 lldb_private::ConstString
104 RenderScriptRuntime::GetPluginName()
105 {
106     return GetPluginNameStatic();
107 }
108 
109 uint32_t
110 RenderScriptRuntime::GetPluginVersion()
111 {
112     return 1;
113 }
114 
115 bool
116 RenderScriptRuntime::IsVTableName(const char *name)
117 {
118     return false;
119 }
120 
121 bool
122 RenderScriptRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic,
123                                               TypeAndOrName &class_type_or_name, Address &address)
124 {
125     return false;
126 }
127 
128 bool
129 RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value)
130 {
131     return false;
132 }
133 
134 lldb::BreakpointResolverSP
135 RenderScriptRuntime::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp)
136 {
137     BreakpointResolverSP resolver_sp;
138     return resolver_sp;
139 }
140 
141 bool
142 RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp)
143 {
144     if (module_sp)
145     {
146         for (const auto &rs_module : m_rsmodules)
147         {
148             if (rs_module.m_module == module_sp)
149                 return false;
150         }
151         bool module_loaded = false;
152         switch (GetModuleKind(module_sp))
153         {
154             case eModuleKindKernelObj:
155             {
156                 RSModuleDescriptor module_desc(module_sp);
157                 if (module_desc.ParseRSInfo())
158                 {
159                     m_rsmodules.push_back(module_desc);
160                     module_loaded = true;
161                 }
162                 break;
163             }
164             case eModuleKindDriver:
165             case eModuleKindImpl:
166             case eModuleKindLibRS:
167             default:
168                 break;
169         }
170         if (module_loaded)
171             Update();
172         return module_loaded;
173     }
174     return false;
175 }
176 
177 void
178 RenderScriptRuntime::Update()
179 {
180     if (m_rsmodules.size() > 0)
181     {
182         if (!m_initiated)
183         {
184             Initiate();
185         }
186     }
187 }
188 
189 
190 // The maximum line length of an .rs.info packet
191 #define MAXLINE 500
192 
193 // The .rs.info symbol in renderscript modules contains a string which needs to be parsed.
194 // The string is basic and is parsed on a line by line basis.
195 bool
196 RSModuleDescriptor::ParseRSInfo()
197 {
198     const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData);
199     if (info_sym)
200     {
201         const addr_t addr = info_sym->GetAddress().GetFileAddress();
202         const addr_t size = info_sym->GetByteSize();
203         const FileSpec fs = m_module->GetFileSpec();
204 
205         DataBufferSP buffer = fs.ReadFileContents(addr, size);
206 
207         if (!buffer)
208             return false;
209 
210         std::string info((const char *)buffer->GetBytes());
211 
212         std::vector<std::string> info_lines;
213         size_t lpos = info.find_first_of("\n");
214         while (lpos != std::string::npos)
215         {
216             info_lines.push_back(info.substr(0, lpos));
217             info = info.substr(lpos + 1);
218             lpos = info.find_first_of("\n");
219         }
220         size_t offset = 0;
221         while (offset < info_lines.size())
222         {
223             std::string line = info_lines[offset];
224             // Parse directives
225             uint32_t numDefns = 0;
226             if (sscanf(line.c_str(), "exportVarCount: %u", &numDefns) == 1)
227             {
228                 while (numDefns--)
229                     m_globals.push_back(RSGlobalDescriptor(*this, info_lines[++offset].c_str()));
230             }
231             else if (sscanf(line.c_str(), "exportFuncCount: %u", &numDefns) == 1)
232             {
233             }
234             else if (sscanf(line.c_str(), "exportForEachCount: %u", &numDefns) == 1)
235             {
236                 char name[MAXLINE];
237                 while (numDefns--)
238                 {
239                     uint32_t slot = 0;
240                     name[0] = '\0';
241                     if (sscanf(info_lines[++offset].c_str(), "%u - %s", &slot, &name[0]) == 2)
242                     {
243                         m_kernels.push_back(RSKernelDescriptor(*this, name, slot));
244                     }
245                 }
246             }
247             else if (sscanf(line.c_str(), "objectSlotCount: %u", &numDefns) == 1)
248             {
249             }
250 
251             offset++;
252         }
253         return m_kernels.size() > 0;
254     }
255     return false;
256 }
257 
258 bool
259 RenderScriptRuntime::ProbeModules(const ModuleList module_list)
260 {
261     bool rs_found = false;
262     size_t num_modules = module_list.GetSize();
263     for (size_t i = 0; i < num_modules; i++)
264     {
265         auto module = module_list.GetModuleAtIndex(i);
266         rs_found |= LoadModule(module);
267     }
268     return rs_found;
269 }
270 
271 void
272 RenderScriptRuntime::DumpModules(Stream &strm) const
273 {
274     strm.Printf("RenderScript Modules:");
275     strm.EOL();
276     strm.IndentMore();
277     for (const auto &module : m_rsmodules)
278     {
279         module.Dump(strm);
280     }
281     strm.IndentLess();
282 }
283 
284 void
285 RSModuleDescriptor::Dump(Stream &strm) const
286 {
287     strm.Indent();
288     m_module->GetFileSpec().Dump(&strm);
289     strm.EOL();
290     strm.IndentMore();
291     strm.Indent();
292     strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size()));
293     strm.EOL();
294     strm.IndentMore();
295     for (const auto &global : m_globals)
296     {
297         global.Dump(strm);
298     }
299     strm.IndentLess();
300     strm.Indent();
301     strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size()));
302     strm.EOL();
303     strm.IndentMore();
304     for (const auto &kernel : m_kernels)
305     {
306         kernel.Dump(strm);
307     }
308     strm.IndentLess(4);
309 }
310 
311 void
312 RSGlobalDescriptor::Dump(Stream &strm) const
313 {
314     strm.Indent(m_name.AsCString());
315     strm.EOL();
316 }
317 
318 void
319 RSKernelDescriptor::Dump(Stream &strm) const
320 {
321     strm.Indent(m_name.AsCString());
322     strm.EOL();
323 }
324 
325 class CommandObjectRenderScriptRuntimeModuleProbe : public CommandObjectParsed
326 {
327   private:
328   public:
329     CommandObjectRenderScriptRuntimeModuleProbe(CommandInterpreter &interpreter)
330         : CommandObjectParsed(interpreter, "renderscript module probe",
331                               "Initiates a Probe of all loaded modules for kernels and other renderscript objects.",
332                               "renderscript module probe",
333                               eFlagRequiresTarget | eFlagRequiresProcess | eFlagProcessMustBeLaunched)
334     {
335     }
336 
337     ~CommandObjectRenderScriptRuntimeModuleProbe() {}
338 
339     bool
340     DoExecute(Args &command, CommandReturnObject &result)
341     {
342         const size_t argc = command.GetArgumentCount();
343         if (argc == 0)
344         {
345             Target *target = m_exe_ctx.GetTargetPtr();
346             RenderScriptRuntime *runtime =
347                 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
348             auto module_list = target->GetImages();
349             bool new_rs_details = runtime->ProbeModules(module_list);
350             if (new_rs_details)
351             {
352                 result.AppendMessage("New renderscript modules added to runtime model.");
353             }
354             result.SetStatus(eReturnStatusSuccessFinishResult);
355             return true;
356         }
357 
358         result.AppendErrorWithFormat("'%s' takes no arguments", m_cmd_name.c_str());
359         result.SetStatus(eReturnStatusFailed);
360         return false;
361     }
362 };
363 
364 class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed
365 {
366   private:
367   public:
368     CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter)
369         : CommandObjectParsed(interpreter, "renderscript module dump",
370                               "Dumps renderscript specific information for all modules.", "renderscript module dump",
371                               eFlagRequiresProcess | eFlagProcessMustBeLaunched)
372     {
373     }
374 
375     ~CommandObjectRenderScriptRuntimeModuleDump() {}
376 
377     bool
378     DoExecute(Args &command, CommandReturnObject &result)
379     {
380         RenderScriptRuntime *runtime =
381             (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
382         runtime->DumpModules(result.GetOutputStream());
383         result.SetStatus(eReturnStatusSuccessFinishResult);
384         return true;
385     }
386 };
387 
388 class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword
389 {
390   private:
391   public:
392     CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter)
393         : CommandObjectMultiword(interpreter, "renderscript module", "Commands that deal with renderscript modules.",
394                                  NULL)
395     {
396         LoadSubCommand("probe", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleProbe(interpreter)));
397         LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump(interpreter)));
398     }
399 
400     ~CommandObjectRenderScriptRuntimeModule() {}
401 };
402 
403 class CommandObjectRenderScriptRuntime : public CommandObjectMultiword
404 {
405   public:
406     CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter)
407         : CommandObjectMultiword(interpreter, "renderscript", "A set of commands for operating on renderscript.",
408                                  "renderscript <subcommand> [<subcommand-options>]")
409     {
410         LoadSubCommand("module", CommandObjectSP(new CommandObjectRenderScriptRuntimeModule(interpreter)));
411     }
412 
413     ~CommandObjectRenderScriptRuntime() {}
414 };
415 
416 void
417 RenderScriptRuntime::Initiate()
418 {
419     assert(!m_initiated);
420     Process* process = GetProcess();
421     if (process)
422     {
423         CommandInterpreter &interpreter = process->GetTarget().GetDebugger().GetCommandInterpreter();
424         m_initiated = interpreter.AddCommand("renderscript", CommandObjectSP(
425                                            new CommandObjectRenderScriptRuntime(interpreter)), true);
426     }
427 }
428 
429 RenderScriptRuntime::RenderScriptRuntime(Process *process)
430     : lldb_private::CPPLanguageRuntime(process), m_initiated(false)
431 {
432 
433 }
434