1 //===-- RenderScriptRuntime.h -----------------------------------*- 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 #ifndef liblldb_RenderScriptRuntime_h_
11 #define liblldb_RenderScriptRuntime_h_
12 
13 // C Includes
14 // C++ Includes
15 #include <array>
16 #include <map>
17 #include <memory>
18 #include <string>
19 #include <vector>
20 
21 // Other libraries and framework includes
22 #include "llvm/ADT/SmallVector.h"
23 #include "llvm/ADT/StringRef.h"
24 // Project includes
25 #include "lldb/Core/Module.h"
26 #include "lldb/Expression/LLVMUserExpression.h"
27 #include "lldb/Target/CPPLanguageRuntime.h"
28 #include "lldb/Target/LanguageRuntime.h"
29 #include "lldb/lldb-private.h"
30 
31 namespace lldb_private {
32 namespace lldb_renderscript {
33 
34 typedef uint32_t RSSlot;
35 class RSModuleDescriptor;
36 struct RSGlobalDescriptor;
37 struct RSKernelDescriptor;
38 struct RSReductionDescriptor;
39 
40 typedef std::shared_ptr<RSModuleDescriptor> RSModuleDescriptorSP;
41 typedef std::shared_ptr<RSGlobalDescriptor> RSGlobalDescriptorSP;
42 typedef std::shared_ptr<RSKernelDescriptor> RSKernelDescriptorSP;
43 struct RSCoordinate {
44   uint32_t x, y, z;
45 
46   RSCoordinate() : x(), y(), z(){};
47 
48   bool operator==(const lldb_renderscript::RSCoordinate &rhs) {
49     return x == rhs.x && y == rhs.y && z == rhs.z;
50   }
51 };
52 
53 // Breakpoint Resolvers decide where a breakpoint is placed, so having our own
54 // allows us to limit the search scope to RS kernel modules. As well as check
55 // for .expand kernels as a fallback.
56 class RSBreakpointResolver : public BreakpointResolver {
57 public:
58   RSBreakpointResolver(Breakpoint *bp, ConstString name)
59       : BreakpointResolver(bp, BreakpointResolver::NameResolver),
60         m_kernel_name(name) {}
61 
62   void GetDescription(Stream *strm) override {
63     if (strm)
64       strm->Printf("RenderScript kernel breakpoint for '%s'",
65                    m_kernel_name.AsCString());
66   }
67 
68   void Dump(Stream *s) const override {}
69 
70   Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
71                                           SymbolContext &context, Address *addr,
72                                           bool containing) override;
73 
74   Searcher::Depth GetDepth() override { return Searcher::eDepthModule; }
75 
76   lldb::BreakpointResolverSP
77   CopyForBreakpoint(Breakpoint &breakpoint) override {
78     lldb::BreakpointResolverSP ret_sp(
79         new RSBreakpointResolver(&breakpoint, m_kernel_name));
80     return ret_sp;
81   }
82 
83 protected:
84   ConstString m_kernel_name;
85 };
86 
87 class RSReduceBreakpointResolver : public BreakpointResolver {
88 public:
89   enum ReduceKernelTypeFlags {
90     eKernelTypeAll = ~(0),
91     eKernelTypeNone = 0,
92     eKernelTypeAccum = (1 << 0),
93     eKernelTypeInit = (1 << 1),
94     eKernelTypeComb = (1 << 2),
95     eKernelTypeOutC = (1 << 3),
96     eKernelTypeHalter = (1 << 4)
97   };
98 
99   RSReduceBreakpointResolver(
100       Breakpoint *breakpoint, ConstString reduce_name,
101       std::vector<lldb_renderscript::RSModuleDescriptorSP> *rs_modules,
102       int kernel_types = eKernelTypeAll)
103       : BreakpointResolver(breakpoint, BreakpointResolver::NameResolver),
104         m_reduce_name(reduce_name), m_rsmodules(rs_modules),
105         m_kernel_types(kernel_types) {
106     // The reduce breakpoint resolver handles adding breakpoints for named
107     // reductions.
108     // Breakpoints will be resolved for all constituent kernels in the named
109     // reduction
110   }
111 
112   void GetDescription(Stream *strm) override {
113     if (strm)
114       strm->Printf("RenderScript reduce breakpoint for '%s'",
115                    m_reduce_name.AsCString());
116   }
117 
118   void Dump(Stream *s) const override {}
119 
120   Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
121                                           SymbolContext &context, Address *addr,
122                                           bool containing) override;
123 
124   Searcher::Depth GetDepth() override { return Searcher::eDepthModule; }
125 
126   lldb::BreakpointResolverSP
127   CopyForBreakpoint(Breakpoint &breakpoint) override {
128     lldb::BreakpointResolverSP ret_sp(new RSReduceBreakpointResolver(
129         &breakpoint, m_reduce_name, m_rsmodules, m_kernel_types));
130     return ret_sp;
131   }
132 
133 private:
134   ConstString m_reduce_name; // The name of the reduction
135   std::vector<lldb_renderscript::RSModuleDescriptorSP> *m_rsmodules;
136   int m_kernel_types;
137 };
138 
139 struct RSKernelDescriptor {
140 public:
141   RSKernelDescriptor(const RSModuleDescriptor *module, llvm::StringRef name,
142                      uint32_t slot)
143       : m_module(module), m_name(name), m_slot(slot) {}
144 
145   void Dump(Stream &strm) const;
146 
147   const RSModuleDescriptor *m_module;
148   ConstString m_name;
149   RSSlot m_slot;
150 };
151 
152 struct RSGlobalDescriptor {
153 public:
154   RSGlobalDescriptor(const RSModuleDescriptor *module, llvm::StringRef name)
155       : m_module(module), m_name(name) {}
156 
157   void Dump(Stream &strm) const;
158 
159   const RSModuleDescriptor *m_module;
160   ConstString m_name;
161 };
162 
163 struct RSReductionDescriptor {
164   RSReductionDescriptor(const RSModuleDescriptor *module, uint32_t sig,
165                         uint32_t accum_data_size, llvm::StringRef name,
166                         llvm::StringRef init_name, llvm::StringRef accum_name,
167                         llvm::StringRef comb_name, llvm::StringRef outc_name,
168                         llvm::StringRef halter_name = ".")
169       : m_module(module), m_reduce_name(name), m_init_name(init_name),
170         m_accum_name(accum_name), m_comb_name(comb_name),
171         m_outc_name(outc_name), m_halter_name(halter_name) {
172     // TODO Check whether the combiner is an autogenerated name, and track
173     // this
174   }
175 
176   void Dump(Stream &strm) const;
177 
178   const RSModuleDescriptor *m_module;
179   ConstString m_reduce_name; // This is the name given to the general reduction
180                              // as a group as passed to pragma
181   // reduce(m_reduce_name). There is no kernel function with this name
182   ConstString m_init_name;  // The name of the initializer name. "." if no
183                             // initializer given
184   ConstString m_accum_name; // The accumulator function name. "." if not given
185   ConstString m_comb_name; // The name of the combiner function. If this was not
186                            // given, a name is generated by the
187                            // compiler. TODO
188   ConstString m_outc_name; // The name of the outconverter
189 
190   ConstString m_halter_name; // The name of the halter function. XXX This is not
191                              // yet specified by the RenderScript
192   // compiler or runtime, and its semantics and existence is still under
193   // discussion by the
194   // RenderScript Contributors
195   RSSlot m_accum_sig; // metatdata signature for this reduction (bitwise mask of
196                       // type information (see
197                       // libbcc/include/bcinfo/MetadataExtractor.h
198   uint32_t m_accum_data_size; // Data size of the accumulator function input
199   bool m_comb_name_generated; // Was the combiner name generated by the compiler
200 };
201 
202 class RSModuleDescriptor {
203   bool ParseExportForeachCount(llvm::StringRef *, size_t n_lines);
204 
205   bool ParseExportVarCount(llvm::StringRef *, size_t n_lines);
206 
207   bool ParseExportReduceCount(llvm::StringRef *, size_t n_lines);
208 
209   bool ParseBuildChecksum(llvm::StringRef *, size_t n_lines);
210 
211   bool ParsePragmaCount(llvm::StringRef *, size_t n_lines);
212 
213 public:
214   RSModuleDescriptor(const lldb::ModuleSP &module) : m_module(module) {}
215 
216   ~RSModuleDescriptor() = default;
217 
218   bool ParseRSInfo();
219 
220   void Dump(Stream &strm) const;
221 
222   const lldb::ModuleSP m_module;
223   std::vector<RSKernelDescriptor> m_kernels;
224   std::vector<RSGlobalDescriptor> m_globals;
225   std::vector<RSReductionDescriptor> m_reductions;
226   std::map<std::string, std::string> m_pragmas;
227   std::string m_resname;
228 };
229 
230 } // namespace lldb_renderscript
231 
232 class RenderScriptRuntime : public lldb_private::CPPLanguageRuntime {
233 public:
234   enum ModuleKind {
235     eModuleKindIgnored,
236     eModuleKindLibRS,
237     eModuleKindDriver,
238     eModuleKindImpl,
239     eModuleKindKernelObj
240   };
241 
242   ~RenderScriptRuntime() override;
243 
244   //------------------------------------------------------------------
245   // Static Functions
246   //------------------------------------------------------------------
247   static void Initialize();
248 
249   static void Terminate();
250 
251   static lldb_private::LanguageRuntime *
252   CreateInstance(Process *process, lldb::LanguageType language);
253 
254   static lldb::CommandObjectSP
255   GetCommandObject(CommandInterpreter &interpreter);
256 
257   static lldb_private::ConstString GetPluginNameStatic();
258 
259   static bool IsRenderScriptModule(const lldb::ModuleSP &module_sp);
260 
261   static ModuleKind GetModuleKind(const lldb::ModuleSP &module_sp);
262 
263   static void ModulesDidLoad(const lldb::ProcessSP &process_sp,
264                              const ModuleList &module_list);
265 
266   bool IsVTableName(const char *name) override;
267 
268   bool GetDynamicTypeAndAddress(ValueObject &in_value,
269                                 lldb::DynamicValueType use_dynamic,
270                                 TypeAndOrName &class_type_or_name,
271                                 Address &address,
272                                 Value::ValueType &value_type) override;
273 
274   TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
275                                  ValueObject &static_value) override;
276 
277   bool CouldHaveDynamicValue(ValueObject &in_value) override;
278 
279   lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bp,
280                                                      bool catch_bp,
281                                                      bool throw_bp) override;
282 
283   bool LoadModule(const lldb::ModuleSP &module_sp);
284 
285   void DumpModules(Stream &strm) const;
286 
287   void DumpContexts(Stream &strm) const;
288 
289   void DumpKernels(Stream &strm) const;
290 
291   bool DumpAllocation(Stream &strm, StackFrame *frame_ptr, const uint32_t id);
292 
293   void ListAllocations(Stream &strm, StackFrame *frame_ptr,
294                        const uint32_t index);
295 
296   bool RecomputeAllAllocations(Stream &strm, StackFrame *frame_ptr);
297 
298   bool PlaceBreakpointOnKernel(
299       lldb::TargetSP target, Stream &messages, const char *name,
300       const lldb_renderscript::RSCoordinate *coords = nullptr);
301 
302   bool PlaceBreakpointOnReduction(
303       lldb::TargetSP target, Stream &messages, const char *reduce_name,
304       const lldb_renderscript::RSCoordinate *coords = nullptr,
305       int kernel_types = ~(0));
306 
307   void SetBreakAllKernels(bool do_break, lldb::TargetSP target);
308 
309   void Status(Stream &strm) const;
310 
311   void ModulesDidLoad(const ModuleList &module_list) override;
312 
313   bool LoadAllocation(Stream &strm, const uint32_t alloc_id,
314                       const char *filename, StackFrame *frame_ptr);
315 
316   bool SaveAllocation(Stream &strm, const uint32_t alloc_id,
317                       const char *filename, StackFrame *frame_ptr);
318 
319   void Update();
320 
321   void Initiate();
322 
323   //------------------------------------------------------------------
324   // PluginInterface protocol
325   //------------------------------------------------------------------
326   lldb_private::ConstString GetPluginName() override;
327 
328   uint32_t GetPluginVersion() override;
329 
330   static bool GetKernelCoordinate(lldb_renderscript::RSCoordinate &coord,
331                                   Thread *thread_ptr);
332 
333 protected:
334   struct ScriptDetails;
335   struct AllocationDetails;
336   struct Element;
337 
338   void InitSearchFilter(lldb::TargetSP target) {
339     if (!m_filtersp)
340       m_filtersp.reset(new SearchFilterForUnconstrainedSearches(target));
341   }
342 
343   void FixupScriptDetails(lldb_renderscript::RSModuleDescriptorSP rsmodule_sp);
344 
345   void LoadRuntimeHooks(lldb::ModuleSP module, ModuleKind kind);
346 
347   bool RefreshAllocation(AllocationDetails *alloc, StackFrame *frame_ptr);
348 
349   bool EvalRSExpression(const char *expression, StackFrame *frame_ptr,
350                         uint64_t *result);
351 
352   lldb::BreakpointSP CreateKernelBreakpoint(const ConstString &name);
353 
354   lldb::BreakpointSP CreateReductionBreakpoint(const ConstString &name,
355                                                int kernel_types);
356 
357   void BreakOnModuleKernels(
358       const lldb_renderscript::RSModuleDescriptorSP rsmodule_sp);
359 
360   struct RuntimeHook;
361   typedef void (RenderScriptRuntime::*CaptureStateFn)(
362       RuntimeHook *hook_info,
363       ExecutionContext &context); // Please do this!
364 
365   struct HookDefn {
366     const char *name;
367     const char *symbol_name_m32; // mangled name for the 32 bit architectures
368     const char *symbol_name_m64; // mangled name for the 64 bit archs
369     uint32_t version;
370     ModuleKind kind;
371     CaptureStateFn grabber;
372   };
373 
374   struct RuntimeHook {
375     lldb::addr_t address;
376     const HookDefn *defn;
377     lldb::BreakpointSP bp_sp;
378   };
379 
380   typedef std::shared_ptr<RuntimeHook> RuntimeHookSP;
381 
382   lldb::ModuleSP m_libRS;
383   lldb::ModuleSP m_libRSDriver;
384   lldb::ModuleSP m_libRSCpuRef;
385   std::vector<lldb_renderscript::RSModuleDescriptorSP> m_rsmodules;
386 
387   std::vector<std::unique_ptr<ScriptDetails>> m_scripts;
388   std::vector<std::unique_ptr<AllocationDetails>> m_allocations;
389 
390   std::map<lldb::addr_t, lldb_renderscript::RSModuleDescriptorSP>
391       m_scriptMappings;
392   std::map<lldb::addr_t, RuntimeHookSP> m_runtimeHooks;
393   std::map<lldb::user_id_t, std::unique_ptr<lldb_renderscript::RSCoordinate>>
394       m_conditional_breaks;
395 
396   lldb::SearchFilterSP
397       m_filtersp; // Needed to create breakpoints through Target API
398 
399   bool m_initiated;
400   bool m_debuggerPresentFlagged;
401   bool m_breakAllKernels;
402   static const HookDefn s_runtimeHookDefns[];
403   static const size_t s_runtimeHookCount;
404   LLVMUserExpression::IRPasses *m_ir_passes;
405 
406 private:
407   RenderScriptRuntime(Process *process); // Call CreateInstance instead.
408 
409   static bool HookCallback(void *baton, StoppointCallbackContext *ctx,
410                            lldb::user_id_t break_id,
411                            lldb::user_id_t break_loc_id);
412 
413   static bool KernelBreakpointHit(void *baton, StoppointCallbackContext *ctx,
414                                   lldb::user_id_t break_id,
415                                   lldb::user_id_t break_loc_id);
416 
417   void HookCallback(RuntimeHook *hook_info, ExecutionContext &context);
418 
419   void CaptureScriptInit(RuntimeHook *hook_info, ExecutionContext &context);
420 
421   void CaptureAllocationInit(RuntimeHook *hook_info, ExecutionContext &context);
422 
423   void CaptureAllocationDestroy(RuntimeHook *hook_info,
424                                 ExecutionContext &context);
425 
426   void CaptureSetGlobalVar(RuntimeHook *hook_info, ExecutionContext &context);
427 
428   void CaptureScriptInvokeForEachMulti(RuntimeHook *hook_info,
429                                        ExecutionContext &context);
430 
431   AllocationDetails *FindAllocByID(Stream &strm, const uint32_t alloc_id);
432 
433   std::shared_ptr<uint8_t> GetAllocationData(AllocationDetails *alloc,
434                                              StackFrame *frame_ptr);
435 
436   void SetElementSize(Element &elem);
437 
438   static bool GetFrameVarAsUnsigned(const lldb::StackFrameSP,
439                                     const char *var_name, uint64_t &val);
440 
441   void FindStructTypeName(Element &elem, StackFrame *frame_ptr);
442 
443   size_t PopulateElementHeaders(const std::shared_ptr<uint8_t> header_buffer,
444                                 size_t offset, const Element &elem);
445 
446   size_t CalculateElementHeaderSize(const Element &elem);
447 
448   void SetConditional(lldb::BreakpointSP bp, lldb_private::Stream &messages,
449                       const lldb_renderscript::RSCoordinate &coord);
450   //
451   // Helper functions for jitting the runtime
452   //
453 
454   bool JITDataPointer(AllocationDetails *alloc, StackFrame *frame_ptr,
455                       uint32_t x = 0, uint32_t y = 0, uint32_t z = 0);
456 
457   bool JITTypePointer(AllocationDetails *alloc, StackFrame *frame_ptr);
458 
459   bool JITTypePacked(AllocationDetails *alloc, StackFrame *frame_ptr);
460 
461   bool JITElementPacked(Element &elem, const lldb::addr_t context,
462                         StackFrame *frame_ptr);
463 
464   bool JITAllocationSize(AllocationDetails *alloc, StackFrame *frame_ptr);
465 
466   bool JITSubelements(Element &elem, const lldb::addr_t context,
467                       StackFrame *frame_ptr);
468 
469   bool JITAllocationStride(AllocationDetails *alloc, StackFrame *frame_ptr);
470 
471   // Search for a script detail object using a target address.
472   // If a script does not currently exist this function will return nullptr.
473   // If 'create' is true and there is no previous script with this address,
474   // then a new Script detail object will be created for this address and
475   // returned.
476   ScriptDetails *LookUpScript(lldb::addr_t address, bool create);
477 
478   // Search for a previously saved allocation detail object using a target
479   // address.
480   // If an allocation does not exist for this address then nullptr will be
481   // returned.
482   AllocationDetails *LookUpAllocation(lldb::addr_t address);
483 
484   // Creates a new allocation with the specified address assigning a new ID and
485   // removes
486   // any previous stored allocation which has the same address.
487   AllocationDetails *CreateAllocation(lldb::addr_t address);
488 
489   bool GetOverrideExprOptions(clang::TargetOptions &prototype) override;
490 
491   bool GetIRPasses(LLVMUserExpression::IRPasses &passes) override;
492 };
493 
494 } // namespace lldb_private
495 
496 #endif // liblldb_RenderScriptRuntime_h_
497