180814287SRaphael Isemann //===-- RenderScriptRuntime.cpp -------------------------------------------===//
25ec532a9SColin Riley //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ec532a9SColin Riley //
75ec532a9SColin Riley //===----------------------------------------------------------------------===//
85ec532a9SColin Riley 
95ec532a9SColin Riley #include "RenderScriptRuntime.h"
1021fed052SAidan Dodds #include "RenderScriptScriptGroup.h"
115ec532a9SColin Riley 
12b3f7f69dSAidan Dodds #include "lldb/Breakpoint/StoppointCallbackContext.h"
135ec532a9SColin Riley #include "lldb/Core/Debugger.h"
1429cb868aSZachary Turner #include "lldb/Core/DumpDataExtractor.h"
155ec532a9SColin Riley #include "lldb/Core/PluginManager.h"
16b3f7f69dSAidan Dodds #include "lldb/Core/ValueObjectVariable.h"
178b244e21SEwan Crawford #include "lldb/DataFormatters/DumpValueObjectOptions.h"
18b3f7f69dSAidan Dodds #include "lldb/Expression/UserExpression.h"
193eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h"
20b3f7f69dSAidan Dodds #include "lldb/Interpreter/CommandInterpreter.h"
21b3f7f69dSAidan Dodds #include "lldb/Interpreter/CommandObjectMultiword.h"
22b3f7f69dSAidan Dodds #include "lldb/Interpreter/CommandReturnObject.h"
23b3f7f69dSAidan Dodds #include "lldb/Interpreter/Options.h"
2421fed052SAidan Dodds #include "lldb/Symbol/Function.h"
255ec532a9SColin Riley #include "lldb/Symbol/Symbol.h"
264640cde1SColin Riley #include "lldb/Symbol/Type.h"
27b3f7f69dSAidan Dodds #include "lldb/Symbol/VariableList.h"
285ec532a9SColin Riley #include "lldb/Target/Process.h"
29b3f7f69dSAidan Dodds #include "lldb/Target/RegisterContext.h"
3021fed052SAidan Dodds #include "lldb/Target/SectionLoadList.h"
315ec532a9SColin Riley #include "lldb/Target/Target.h"
32018f5a7eSEwan Crawford #include "lldb/Target/Thread.h"
33145d95c9SPavel Labath #include "lldb/Utility/Args.h"
34bf9a7730SZachary Turner #include "lldb/Utility/ConstString.h"
356f9e6901SZachary Turner #include "lldb/Utility/Log.h"
36d821c997SPavel Labath #include "lldb/Utility/RegisterValue.h"
37bf9a7730SZachary Turner #include "lldb/Utility/RegularExpression.h"
3897206d57SZachary Turner #include "lldb/Utility/Status.h"
395ec532a9SColin Riley 
40796ac80bSJonas Devlieghere #include "llvm/ADT/StringSwitch.h"
41796ac80bSJonas Devlieghere 
42796ac80bSJonas Devlieghere #include <memory>
43796ac80bSJonas Devlieghere 
445ec532a9SColin Riley using namespace lldb;
455ec532a9SColin Riley using namespace lldb_private;
4698156583SEwan Crawford using namespace lldb_renderscript;
475ec532a9SColin Riley 
48bba9ba8dSJonas Devlieghere LLDB_PLUGIN_DEFINE(RenderScriptRuntime)
49fbb4d1e4SJonas Devlieghere 
5000f56eebSLuke Drummond #define FMT_COORD "(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")"
5100f56eebSLuke Drummond 
52056f6f18SAlex Langford char RenderScriptRuntime::ID = 0;
53056f6f18SAlex Langford 
54b9c1b51eSKate Stone namespace {
5578f339d1SEwan Crawford 
5678f339d1SEwan Crawford // The empirical_type adds a basic level of validation to arbitrary data
5780af0b9eSLuke Drummond // allowing us to track if data has been discovered and stored or not. An
5880af0b9eSLuke Drummond // empirical_type will be marked as valid only if it has been explicitly
59b9c1b51eSKate Stone // assigned to.
60b9c1b51eSKate Stone template <typename type_t> class empirical_type {
6178f339d1SEwan Crawford public:
6278f339d1SEwan Crawford   // Ctor. Contents is invalid when constructed.
63fd2433e1SJonas Devlieghere   empirical_type() = default;
6478f339d1SEwan Crawford 
6578f339d1SEwan Crawford   // Return true and copy contents to out if valid, else return false.
66b9c1b51eSKate Stone   bool get(type_t &out) const {
6778f339d1SEwan Crawford     if (valid)
6878f339d1SEwan Crawford       out = data;
6978f339d1SEwan Crawford     return valid;
7078f339d1SEwan Crawford   }
7178f339d1SEwan Crawford 
7278f339d1SEwan Crawford   // Return a pointer to the contents or nullptr if it was not valid.
73b9c1b51eSKate Stone   const type_t *get() const { return valid ? &data : nullptr; }
7478f339d1SEwan Crawford 
7578f339d1SEwan Crawford   // Assign data explicitly.
76b9c1b51eSKate Stone   void set(const type_t in) {
7778f339d1SEwan Crawford     data = in;
7878f339d1SEwan Crawford     valid = true;
7978f339d1SEwan Crawford   }
8078f339d1SEwan Crawford 
8178f339d1SEwan Crawford   // Mark contents as invalid.
82b9c1b51eSKate Stone   void invalidate() { valid = false; }
8378f339d1SEwan Crawford 
8478f339d1SEwan Crawford   // Returns true if this type contains valid data.
85b9c1b51eSKate Stone   bool isValid() const { return valid; }
8678f339d1SEwan Crawford 
8778f339d1SEwan Crawford   // Assignment operator.
88b9c1b51eSKate Stone   empirical_type<type_t> &operator=(const type_t in) {
8978f339d1SEwan Crawford     set(in);
9078f339d1SEwan Crawford     return *this;
9178f339d1SEwan Crawford   }
9278f339d1SEwan Crawford 
9378f339d1SEwan Crawford   // Dereference operator returns contents.
9478f339d1SEwan Crawford   // Warning: Will assert if not valid so use only when you know data is valid.
95b9c1b51eSKate Stone   const type_t &operator*() const {
9678f339d1SEwan Crawford     assert(valid);
9778f339d1SEwan Crawford     return data;
9878f339d1SEwan Crawford   }
9978f339d1SEwan Crawford 
10078f339d1SEwan Crawford protected:
1019494c510SJonas Devlieghere   bool valid = false;
10278f339d1SEwan Crawford   type_t data;
10378f339d1SEwan Crawford };
10478f339d1SEwan Crawford 
105b9c1b51eSKate Stone // ArgItem is used by the GetArgs() function when reading function arguments
106b9c1b51eSKate Stone // from the target.
107b9c1b51eSKate Stone struct ArgItem {
108b9c1b51eSKate Stone   enum { ePointer, eInt32, eInt64, eLong, eBool } type;
109f4786785SAidan Dodds 
110f4786785SAidan Dodds   uint64_t value;
111f4786785SAidan Dodds 
112f4786785SAidan Dodds   explicit operator uint64_t() const { return value; }
113f4786785SAidan Dodds };
114f4786785SAidan Dodds 
115b9c1b51eSKate Stone // Context structure to be passed into GetArgsXXX(), argument reading functions
116b9c1b51eSKate Stone // below.
117b9c1b51eSKate Stone struct GetArgsCtx {
118f4786785SAidan Dodds   RegisterContext *reg_ctx;
119f4786785SAidan Dodds   Process *process;
120f4786785SAidan Dodds };
121f4786785SAidan Dodds 
122b9c1b51eSKate Stone bool GetArgsX86(const GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
123*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
124f4786785SAidan Dodds 
12597206d57SZachary Turner   Status err;
12667dc3e15SAidan Dodds 
127f4786785SAidan Dodds   // get the current stack pointer
128f4786785SAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP();
129f4786785SAidan Dodds 
130b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
131f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
132f4786785SAidan Dodds     // advance up the stack by one argument
133f4786785SAidan Dodds     sp += sizeof(uint32_t);
134f4786785SAidan Dodds     // get the argument type size
135f4786785SAidan Dodds     size_t arg_size = sizeof(uint32_t);
136f4786785SAidan Dodds     // read the argument from memory
137f4786785SAidan Dodds     arg.value = 0;
13897206d57SZachary Turner     Status err;
139b9c1b51eSKate Stone     size_t read =
14080af0b9eSLuke Drummond         ctx.process->ReadMemory(sp, &arg.value, sizeof(uint32_t), err);
14180af0b9eSLuke Drummond     if (read != arg_size || !err.Success()) {
14263e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 " '%s'",
14380af0b9eSLuke Drummond                 __FUNCTION__, uint64_t(i), err.AsCString());
144f4786785SAidan Dodds       return false;
145f4786785SAidan Dodds     }
146f4786785SAidan Dodds   }
147f4786785SAidan Dodds   return true;
148f4786785SAidan Dodds }
149f4786785SAidan Dodds 
150b9c1b51eSKate Stone bool GetArgsX86_64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
151*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
152f4786785SAidan Dodds 
153f4786785SAidan Dodds   // number of arguments passed in registers
15480af0b9eSLuke Drummond   static const uint32_t args_in_reg = 6;
155f4786785SAidan Dodds   // register passing order
15680af0b9eSLuke Drummond   static const std::array<const char *, args_in_reg> reg_names{
157b9c1b51eSKate Stone       {"rdi", "rsi", "rdx", "rcx", "r8", "r9"}};
158f4786785SAidan Dodds   // argument type to size mapping
1591ee07253SSaleem Abdulrasool   static const std::array<size_t, 5> arg_size{{
160f4786785SAidan Dodds       8, // ePointer,
161f4786785SAidan Dodds       4, // eInt32,
162f4786785SAidan Dodds       8, // eInt64,
163f4786785SAidan Dodds       8, // eLong,
164f4786785SAidan Dodds       4, // eBool,
1651ee07253SSaleem Abdulrasool   }};
166f4786785SAidan Dodds 
16797206d57SZachary Turner   Status err;
16817e07c0aSAidan Dodds 
169f4786785SAidan Dodds   // get the current stack pointer
170f4786785SAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP();
171f4786785SAidan Dodds   // step over the return address
172f4786785SAidan Dodds   sp += sizeof(uint64_t);
173f4786785SAidan Dodds 
174f4786785SAidan Dodds   // check the stack alignment was correct (16 byte aligned)
175b9c1b51eSKate Stone   if ((sp & 0xf) != 0x0) {
17663e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - stack misaligned", __FUNCTION__);
177f4786785SAidan Dodds     return false;
178f4786785SAidan Dodds   }
179f4786785SAidan Dodds 
180f4786785SAidan Dodds   // find the start of arguments on the stack
181f4786785SAidan Dodds   uint64_t sp_offset = 0;
18280af0b9eSLuke Drummond   for (uint32_t i = args_in_reg; i < num_args; ++i) {
183f4786785SAidan Dodds     sp_offset += arg_size[arg_list[i].type];
184f4786785SAidan Dodds   }
185f4786785SAidan Dodds   // round up to multiple of 16
186f4786785SAidan Dodds   sp_offset = (sp_offset + 0xf) & 0xf;
187f4786785SAidan Dodds   sp += sp_offset;
188f4786785SAidan Dodds 
189b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
190f4786785SAidan Dodds     bool success = false;
191f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
192f4786785SAidan Dodds     // arguments passed in registers
19380af0b9eSLuke Drummond     if (i < args_in_reg) {
19480af0b9eSLuke Drummond       const RegisterInfo *reg =
19580af0b9eSLuke Drummond           ctx.reg_ctx->GetRegisterInfoByName(reg_names[i]);
19680af0b9eSLuke Drummond       RegisterValue reg_val;
19780af0b9eSLuke Drummond       if (ctx.reg_ctx->ReadRegister(reg, reg_val))
19880af0b9eSLuke Drummond         arg.value = reg_val.GetAsUInt64(0, &success);
199f4786785SAidan Dodds     }
200f4786785SAidan Dodds     // arguments passed on the stack
201b9c1b51eSKate Stone     else {
202f4786785SAidan Dodds       // get the argument type size
203f4786785SAidan Dodds       const size_t size = arg_size[arg_list[i].type];
204f4786785SAidan Dodds       // read the argument from memory
205f4786785SAidan Dodds       arg.value = 0;
206b9c1b51eSKate Stone       // note: due to little endian layout reading 4 or 8 bytes will give the
207b9c1b51eSKate Stone       // correct value.
20880af0b9eSLuke Drummond       size_t read = ctx.process->ReadMemory(sp, &arg.value, size, err);
20980af0b9eSLuke Drummond       success = (err.Success() && read == size);
210f4786785SAidan Dodds       // advance past this argument
211f4786785SAidan Dodds       sp -= size;
212f4786785SAidan Dodds     }
213f4786785SAidan Dodds     // fail if we couldn't read this argument
214b9c1b51eSKate Stone     if (!success) {
21563e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s",
21680af0b9eSLuke Drummond                 __FUNCTION__, uint64_t(i), err.AsCString("n/a"));
217f4786785SAidan Dodds       return false;
218f4786785SAidan Dodds     }
219f4786785SAidan Dodds   }
220f4786785SAidan Dodds   return true;
221f4786785SAidan Dodds }
222f4786785SAidan Dodds 
223b9c1b51eSKate Stone bool GetArgsArm(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
224f4786785SAidan Dodds   // number of arguments passed in registers
22580af0b9eSLuke Drummond   static const uint32_t args_in_reg = 4;
226f4786785SAidan Dodds 
227*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
228f4786785SAidan Dodds 
22997206d57SZachary Turner   Status err;
23017e07c0aSAidan Dodds 
231f4786785SAidan Dodds   // get the current stack pointer
232f4786785SAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP();
233f4786785SAidan Dodds 
234b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
235f4786785SAidan Dodds     bool success = false;
236f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
237f4786785SAidan Dodds     // arguments passed in registers
23880af0b9eSLuke Drummond     if (i < args_in_reg) {
23980af0b9eSLuke Drummond       const RegisterInfo *reg = ctx.reg_ctx->GetRegisterInfoAtIndex(i);
24080af0b9eSLuke Drummond       RegisterValue reg_val;
24180af0b9eSLuke Drummond       if (ctx.reg_ctx->ReadRegister(reg, reg_val))
24280af0b9eSLuke Drummond         arg.value = reg_val.GetAsUInt32(0, &success);
243f4786785SAidan Dodds     }
244f4786785SAidan Dodds     // arguments passed on the stack
245b9c1b51eSKate Stone     else {
246f4786785SAidan Dodds       // get the argument type size
247f4786785SAidan Dodds       const size_t arg_size = sizeof(uint32_t);
248f4786785SAidan Dodds       // clear all 64bits
249f4786785SAidan Dodds       arg.value = 0;
250f4786785SAidan Dodds       // read this argument from memory
251b9c1b51eSKate Stone       size_t bytes_read =
25280af0b9eSLuke Drummond           ctx.process->ReadMemory(sp, &arg.value, arg_size, err);
25380af0b9eSLuke Drummond       success = (err.Success() && bytes_read == arg_size);
254f4786785SAidan Dodds       // advance the stack pointer
255f4786785SAidan Dodds       sp += sizeof(uint32_t);
256f4786785SAidan Dodds     }
257f4786785SAidan Dodds     // fail if we couldn't read this argument
258b9c1b51eSKate Stone     if (!success) {
25963e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s",
26080af0b9eSLuke Drummond                 __FUNCTION__, uint64_t(i), err.AsCString("n/a"));
261f4786785SAidan Dodds       return false;
262f4786785SAidan Dodds     }
263f4786785SAidan Dodds   }
264f4786785SAidan Dodds   return true;
265f4786785SAidan Dodds }
266f4786785SAidan Dodds 
267b9c1b51eSKate Stone bool GetArgsAarch64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
268f4786785SAidan Dodds   // number of arguments passed in registers
26980af0b9eSLuke Drummond   static const uint32_t args_in_reg = 8;
270f4786785SAidan Dodds 
271*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
272f4786785SAidan Dodds 
273b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
274f4786785SAidan Dodds     bool success = false;
275f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
276f4786785SAidan Dodds     // arguments passed in registers
27780af0b9eSLuke Drummond     if (i < args_in_reg) {
27880af0b9eSLuke Drummond       const RegisterInfo *reg = ctx.reg_ctx->GetRegisterInfoAtIndex(i);
27980af0b9eSLuke Drummond       RegisterValue reg_val;
28080af0b9eSLuke Drummond       if (ctx.reg_ctx->ReadRegister(reg, reg_val))
28180af0b9eSLuke Drummond         arg.value = reg_val.GetAsUInt64(0, &success);
282f4786785SAidan Dodds     }
283f4786785SAidan Dodds     // arguments passed on the stack
284b9c1b51eSKate Stone     else {
28563e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - reading arguments spilled to stack not implemented",
286b9c1b51eSKate Stone                 __FUNCTION__);
287f4786785SAidan Dodds     }
288f4786785SAidan Dodds     // fail if we couldn't read this argument
289b9c1b51eSKate Stone     if (!success) {
29063e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - error reading argument: %" PRIu64, __FUNCTION__,
291f4786785SAidan Dodds                 uint64_t(i));
292f4786785SAidan Dodds       return false;
293f4786785SAidan Dodds     }
294f4786785SAidan Dodds   }
295f4786785SAidan Dodds   return true;
296f4786785SAidan Dodds }
297f4786785SAidan Dodds 
298b9c1b51eSKate Stone bool GetArgsMipsel(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
299f4786785SAidan Dodds   // number of arguments passed in registers
30080af0b9eSLuke Drummond   static const uint32_t args_in_reg = 4;
301f4786785SAidan Dodds   // register file offset to first argument
30280af0b9eSLuke Drummond   static const uint32_t reg_offset = 4;
303f4786785SAidan Dodds 
304*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
305f4786785SAidan Dodds 
30697206d57SZachary Turner   Status err;
30717e07c0aSAidan Dodds 
30805097246SAdrian Prantl   // find offset to arguments on the stack (+16 to skip over a0-a3 shadow
30905097246SAdrian Prantl   // space)
31017e07c0aSAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP() + 16;
31117e07c0aSAidan Dodds 
312b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
313f4786785SAidan Dodds     bool success = false;
314f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
315f4786785SAidan Dodds     // arguments passed in registers
31680af0b9eSLuke Drummond     if (i < args_in_reg) {
31780af0b9eSLuke Drummond       const RegisterInfo *reg =
31880af0b9eSLuke Drummond           ctx.reg_ctx->GetRegisterInfoAtIndex(i + reg_offset);
31980af0b9eSLuke Drummond       RegisterValue reg_val;
32080af0b9eSLuke Drummond       if (ctx.reg_ctx->ReadRegister(reg, reg_val))
32180af0b9eSLuke Drummond         arg.value = reg_val.GetAsUInt64(0, &success);
322f4786785SAidan Dodds     }
323f4786785SAidan Dodds     // arguments passed on the stack
324b9c1b51eSKate Stone     else {
3256dd4b579SAidan Dodds       const size_t arg_size = sizeof(uint32_t);
3266dd4b579SAidan Dodds       arg.value = 0;
327b9c1b51eSKate Stone       size_t bytes_read =
32880af0b9eSLuke Drummond           ctx.process->ReadMemory(sp, &arg.value, arg_size, err);
32980af0b9eSLuke Drummond       success = (err.Success() && bytes_read == arg_size);
33067dc3e15SAidan Dodds       // advance the stack pointer
33167dc3e15SAidan Dodds       sp += arg_size;
332f4786785SAidan Dodds     }
333f4786785SAidan Dodds     // fail if we couldn't read this argument
334b9c1b51eSKate Stone     if (!success) {
33563e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s",
33680af0b9eSLuke Drummond                 __FUNCTION__, uint64_t(i), err.AsCString("n/a"));
337f4786785SAidan Dodds       return false;
338f4786785SAidan Dodds     }
339f4786785SAidan Dodds   }
340f4786785SAidan Dodds   return true;
341f4786785SAidan Dodds }
342f4786785SAidan Dodds 
343b9c1b51eSKate Stone bool GetArgsMips64el(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
344f4786785SAidan Dodds   // number of arguments passed in registers
34580af0b9eSLuke Drummond   static const uint32_t args_in_reg = 8;
346f4786785SAidan Dodds   // register file offset to first argument
34780af0b9eSLuke Drummond   static const uint32_t reg_offset = 4;
348f4786785SAidan Dodds 
349*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
350f4786785SAidan Dodds 
35197206d57SZachary Turner   Status err;
35217e07c0aSAidan Dodds 
353f4786785SAidan Dodds   // get the current stack pointer
354f4786785SAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP();
355f4786785SAidan Dodds 
356b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
357f4786785SAidan Dodds     bool success = false;
358f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
359f4786785SAidan Dodds     // arguments passed in registers
36080af0b9eSLuke Drummond     if (i < args_in_reg) {
36180af0b9eSLuke Drummond       const RegisterInfo *reg =
36280af0b9eSLuke Drummond           ctx.reg_ctx->GetRegisterInfoAtIndex(i + reg_offset);
36380af0b9eSLuke Drummond       RegisterValue reg_val;
36480af0b9eSLuke Drummond       if (ctx.reg_ctx->ReadRegister(reg, reg_val))
36580af0b9eSLuke Drummond         arg.value = reg_val.GetAsUInt64(0, &success);
366f4786785SAidan Dodds     }
367f4786785SAidan Dodds     // arguments passed on the stack
368b9c1b51eSKate Stone     else {
369f4786785SAidan Dodds       // get the argument type size
370f4786785SAidan Dodds       const size_t arg_size = sizeof(uint64_t);
371f4786785SAidan Dodds       // clear all 64bits
372f4786785SAidan Dodds       arg.value = 0;
373f4786785SAidan Dodds       // read this argument from memory
374b9c1b51eSKate Stone       size_t bytes_read =
37580af0b9eSLuke Drummond           ctx.process->ReadMemory(sp, &arg.value, arg_size, err);
37680af0b9eSLuke Drummond       success = (err.Success() && bytes_read == arg_size);
377f4786785SAidan Dodds       // advance the stack pointer
378f4786785SAidan Dodds       sp += arg_size;
379f4786785SAidan Dodds     }
380f4786785SAidan Dodds     // fail if we couldn't read this argument
381b9c1b51eSKate Stone     if (!success) {
38263e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s",
38380af0b9eSLuke Drummond                 __FUNCTION__, uint64_t(i), err.AsCString("n/a"));
384f4786785SAidan Dodds       return false;
385f4786785SAidan Dodds     }
386f4786785SAidan Dodds   }
387f4786785SAidan Dodds   return true;
388f4786785SAidan Dodds }
389f4786785SAidan Dodds 
39080af0b9eSLuke Drummond bool GetArgs(ExecutionContext &exe_ctx, ArgItem *arg_list, size_t num_args) {
391*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
392f4786785SAidan Dodds 
393f4786785SAidan Dodds   // verify that we have a target
39480af0b9eSLuke Drummond   if (!exe_ctx.GetTargetPtr()) {
39563e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - invalid target", __FUNCTION__);
396f4786785SAidan Dodds     return false;
397f4786785SAidan Dodds   }
398f4786785SAidan Dodds 
39980af0b9eSLuke Drummond   GetArgsCtx ctx = {exe_ctx.GetRegisterContext(), exe_ctx.GetProcessPtr()};
400f4786785SAidan Dodds   assert(ctx.reg_ctx && ctx.process);
401f4786785SAidan Dodds 
402f4786785SAidan Dodds   // dispatch based on architecture
40380af0b9eSLuke Drummond   switch (exe_ctx.GetTargetPtr()->GetArchitecture().GetMachine()) {
404f4786785SAidan Dodds   case llvm::Triple::ArchType::x86:
405f4786785SAidan Dodds     return GetArgsX86(ctx, arg_list, num_args);
406f4786785SAidan Dodds 
407f4786785SAidan Dodds   case llvm::Triple::ArchType::x86_64:
408f4786785SAidan Dodds     return GetArgsX86_64(ctx, arg_list, num_args);
409f4786785SAidan Dodds 
410f4786785SAidan Dodds   case llvm::Triple::ArchType::arm:
411f4786785SAidan Dodds     return GetArgsArm(ctx, arg_list, num_args);
412f4786785SAidan Dodds 
413f4786785SAidan Dodds   case llvm::Triple::ArchType::aarch64:
414f4786785SAidan Dodds     return GetArgsAarch64(ctx, arg_list, num_args);
415f4786785SAidan Dodds 
416f4786785SAidan Dodds   case llvm::Triple::ArchType::mipsel:
417f4786785SAidan Dodds     return GetArgsMipsel(ctx, arg_list, num_args);
418f4786785SAidan Dodds 
419f4786785SAidan Dodds   case llvm::Triple::ArchType::mips64el:
420f4786785SAidan Dodds     return GetArgsMips64el(ctx, arg_list, num_args);
421f4786785SAidan Dodds 
422f4786785SAidan Dodds   default:
423f4786785SAidan Dodds     // unsupported architecture
424b9c1b51eSKate Stone     if (log) {
42563e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - architecture not supported: '%s'", __FUNCTION__,
42680af0b9eSLuke Drummond                 exe_ctx.GetTargetRef().GetArchitecture().GetArchitectureName());
427f4786785SAidan Dodds     }
428f4786785SAidan Dodds     return false;
429f4786785SAidan Dodds   }
430f4786785SAidan Dodds }
43100f56eebSLuke Drummond 
432b3bbcb12SLuke Drummond bool IsRenderScriptScriptModule(ModuleSP module) {
433b3bbcb12SLuke Drummond   if (!module)
434b3bbcb12SLuke Drummond     return false;
435b3bbcb12SLuke Drummond   return module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"),
436b3bbcb12SLuke Drummond                                                 eSymbolTypeData) != nullptr;
437b3bbcb12SLuke Drummond }
438b3bbcb12SLuke Drummond 
43900f56eebSLuke Drummond bool ParseCoordinate(llvm::StringRef coord_s, RSCoordinate &coord) {
44005097246SAdrian Prantl   // takes an argument of the form 'num[,num][,num]'. Where 'coord_s' is a
44105097246SAdrian Prantl   // comma separated 1,2 or 3-dimensional coordinate with the whitespace
44205097246SAdrian Prantl   // trimmed. Missing coordinates are defaulted to zero. If parsing of any
44305097246SAdrian Prantl   // elements fails the contents of &coord are undefined and `false` is
44405097246SAdrian Prantl   // returned, `true` otherwise
44500f56eebSLuke Drummond 
4463af3f1e8SJonas Devlieghere   llvm::SmallVector<llvm::StringRef, 4> matches;
44700f56eebSLuke Drummond 
448f9d90bc5SJan Kratochvil   if (!RegularExpression("^([0-9]+),([0-9]+),([0-9]+)$")
449f9d90bc5SJan Kratochvil            .Execute(coord_s, &matches) &&
450f9d90bc5SJan Kratochvil       !RegularExpression("^([0-9]+),([0-9]+)$").Execute(coord_s, &matches) &&
451f9d90bc5SJan Kratochvil       !RegularExpression("^([0-9]+)$").Execute(coord_s, &matches))
45200f56eebSLuke Drummond     return false;
45300f56eebSLuke Drummond 
4543af3f1e8SJonas Devlieghere   auto get_index = [&](size_t idx, uint32_t &i) -> bool {
45500f56eebSLuke Drummond     std::string group;
45600f56eebSLuke Drummond     errno = 0;
4573af3f1e8SJonas Devlieghere     if (idx + 1 < matches.size()) {
4583af3f1e8SJonas Devlieghere       return !llvm::StringRef(matches[idx + 1]).getAsInteger<uint32_t>(10, i);
4593af3f1e8SJonas Devlieghere     }
46000f56eebSLuke Drummond     return true;
46100f56eebSLuke Drummond   };
46200f56eebSLuke Drummond 
46300f56eebSLuke Drummond   return get_index(0, coord.x) && get_index(1, coord.y) &&
46400f56eebSLuke Drummond          get_index(2, coord.z);
46500f56eebSLuke Drummond }
46621fed052SAidan Dodds 
46721fed052SAidan Dodds bool SkipPrologue(lldb::ModuleSP &module, Address &addr) {
468*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
46921fed052SAidan Dodds   SymbolContext sc;
47021fed052SAidan Dodds   uint32_t resolved_flags =
47121fed052SAidan Dodds       module->ResolveSymbolContextForAddress(addr, eSymbolContextFunction, sc);
47221fed052SAidan Dodds   if (resolved_flags & eSymbolContextFunction) {
47321fed052SAidan Dodds     if (sc.function) {
47421fed052SAidan Dodds       const uint32_t offset = sc.function->GetPrologueByteSize();
47521fed052SAidan Dodds       ConstString name = sc.GetFunctionName();
47621fed052SAidan Dodds       if (offset)
47721fed052SAidan Dodds         addr.Slide(offset);
47863e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s: Prologue offset for %s is %" PRIu32, __FUNCTION__,
47921fed052SAidan Dodds                 name.AsCString(), offset);
48021fed052SAidan Dodds     }
48121fed052SAidan Dodds     return true;
48221fed052SAidan Dodds   } else
48321fed052SAidan Dodds     return false;
48421fed052SAidan Dodds }
485222b937cSEugene Zelenko } // anonymous namespace
48678f339d1SEwan Crawford 
487b9c1b51eSKate Stone // The ScriptDetails class collects data associated with a single script
488b9c1b51eSKate Stone // instance.
489b9c1b51eSKate Stone struct RenderScriptRuntime::ScriptDetails {
490222b937cSEugene Zelenko   ~ScriptDetails() = default;
49178f339d1SEwan Crawford 
492b9c1b51eSKate Stone   enum ScriptType { eScript, eScriptC };
49378f339d1SEwan Crawford 
49478f339d1SEwan Crawford   // The derived type of the script.
49578f339d1SEwan Crawford   empirical_type<ScriptType> type;
49678f339d1SEwan Crawford   // The name of the original source file.
49780af0b9eSLuke Drummond   empirical_type<std::string> res_name;
49878f339d1SEwan Crawford   // Path to script .so file on the device.
49980af0b9eSLuke Drummond   empirical_type<std::string> shared_lib;
50078f339d1SEwan Crawford   // Directory where kernel objects are cached on device.
50180af0b9eSLuke Drummond   empirical_type<std::string> cache_dir;
50278f339d1SEwan Crawford   // Pointer to the context which owns this script.
50378f339d1SEwan Crawford   empirical_type<lldb::addr_t> context;
50478f339d1SEwan Crawford   // Pointer to the script object itself.
50578f339d1SEwan Crawford   empirical_type<lldb::addr_t> script;
50678f339d1SEwan Crawford };
50778f339d1SEwan Crawford 
50880af0b9eSLuke Drummond // This Element class represents the Element object in RS, defining the type
50980af0b9eSLuke Drummond // associated with an Allocation.
510b9c1b51eSKate Stone struct RenderScriptRuntime::Element {
51115f2bd95SEwan Crawford   // Taken from rsDefines.h
512b9c1b51eSKate Stone   enum DataKind {
51315f2bd95SEwan Crawford     RS_KIND_USER,
51415f2bd95SEwan Crawford     RS_KIND_PIXEL_L = 7,
51515f2bd95SEwan Crawford     RS_KIND_PIXEL_A,
51615f2bd95SEwan Crawford     RS_KIND_PIXEL_LA,
51715f2bd95SEwan Crawford     RS_KIND_PIXEL_RGB,
51815f2bd95SEwan Crawford     RS_KIND_PIXEL_RGBA,
51915f2bd95SEwan Crawford     RS_KIND_PIXEL_DEPTH,
52015f2bd95SEwan Crawford     RS_KIND_PIXEL_YUV,
52115f2bd95SEwan Crawford     RS_KIND_INVALID = 100
52215f2bd95SEwan Crawford   };
52378f339d1SEwan Crawford 
52415f2bd95SEwan Crawford   // Taken from rsDefines.h
525b9c1b51eSKate Stone   enum DataType {
52615f2bd95SEwan Crawford     RS_TYPE_NONE = 0,
52715f2bd95SEwan Crawford     RS_TYPE_FLOAT_16,
52815f2bd95SEwan Crawford     RS_TYPE_FLOAT_32,
52915f2bd95SEwan Crawford     RS_TYPE_FLOAT_64,
53015f2bd95SEwan Crawford     RS_TYPE_SIGNED_8,
53115f2bd95SEwan Crawford     RS_TYPE_SIGNED_16,
53215f2bd95SEwan Crawford     RS_TYPE_SIGNED_32,
53315f2bd95SEwan Crawford     RS_TYPE_SIGNED_64,
53415f2bd95SEwan Crawford     RS_TYPE_UNSIGNED_8,
53515f2bd95SEwan Crawford     RS_TYPE_UNSIGNED_16,
53615f2bd95SEwan Crawford     RS_TYPE_UNSIGNED_32,
53715f2bd95SEwan Crawford     RS_TYPE_UNSIGNED_64,
5382e920715SEwan Crawford     RS_TYPE_BOOLEAN,
5392e920715SEwan Crawford 
5402e920715SEwan Crawford     RS_TYPE_UNSIGNED_5_6_5,
5412e920715SEwan Crawford     RS_TYPE_UNSIGNED_5_5_5_1,
5422e920715SEwan Crawford     RS_TYPE_UNSIGNED_4_4_4_4,
5432e920715SEwan Crawford 
5442e920715SEwan Crawford     RS_TYPE_MATRIX_4X4,
5452e920715SEwan Crawford     RS_TYPE_MATRIX_3X3,
5462e920715SEwan Crawford     RS_TYPE_MATRIX_2X2,
5472e920715SEwan Crawford 
5482e920715SEwan Crawford     RS_TYPE_ELEMENT = 1000,
5492e920715SEwan Crawford     RS_TYPE_TYPE,
5502e920715SEwan Crawford     RS_TYPE_ALLOCATION,
5512e920715SEwan Crawford     RS_TYPE_SAMPLER,
5522e920715SEwan Crawford     RS_TYPE_SCRIPT,
5532e920715SEwan Crawford     RS_TYPE_MESH,
5542e920715SEwan Crawford     RS_TYPE_PROGRAM_FRAGMENT,
5552e920715SEwan Crawford     RS_TYPE_PROGRAM_VERTEX,
5562e920715SEwan Crawford     RS_TYPE_PROGRAM_RASTER,
5572e920715SEwan Crawford     RS_TYPE_PROGRAM_STORE,
5582e920715SEwan Crawford     RS_TYPE_FONT,
5592e920715SEwan Crawford 
5602e920715SEwan Crawford     RS_TYPE_INVALID = 10000
56178f339d1SEwan Crawford   };
56278f339d1SEwan Crawford 
5638b244e21SEwan Crawford   std::vector<Element> children; // Child Element fields for structs
564b9c1b51eSKate Stone   empirical_type<lldb::addr_t>
565b9c1b51eSKate Stone       element_ptr; // Pointer to the RS Element of the Type
566b9c1b51eSKate Stone   empirical_type<DataType>
567b9c1b51eSKate Stone       type; // Type of each data pointer stored by the allocation
568b9c1b51eSKate Stone   empirical_type<DataKind>
569b9c1b51eSKate Stone       type_kind; // Defines pixel type if Allocation is created from an image
570b9c1b51eSKate Stone   empirical_type<uint32_t>
571b9c1b51eSKate Stone       type_vec_size; // Vector size of each data point, e.g '4' for uchar4
5728b244e21SEwan Crawford   empirical_type<uint32_t> field_count; // Number of Subelements
5738b244e21SEwan Crawford   empirical_type<uint32_t> datum_size;  // Size of a single Element with padding
5748b244e21SEwan Crawford   empirical_type<uint32_t> padding;     // Number of padding bytes
575b9c1b51eSKate Stone   empirical_type<uint32_t>
5764ebdee0aSBruce Mitchener       array_size;        // Number of items in array, only needed for structs
5778b244e21SEwan Crawford   ConstString type_name; // Name of type, only needed for structs
5788b244e21SEwan Crawford 
5790e4c4821SAdrian Prantl   static ConstString
580b3f7f69dSAidan Dodds   GetFallbackStructName(); // Print this as the type name of a struct Element
5818b244e21SEwan Crawford                            // If we can't resolve the actual struct name
5828b59062aSEwan Crawford 
58380af0b9eSLuke Drummond   bool ShouldRefresh() const {
5848b59062aSEwan Crawford     const bool valid_ptr = element_ptr.isValid() && *element_ptr.get() != 0x0;
585b9c1b51eSKate Stone     const bool valid_type =
586b9c1b51eSKate Stone         type.isValid() && type_vec_size.isValid() && type_kind.isValid();
5878b59062aSEwan Crawford     return !valid_ptr || !valid_type || !datum_size.isValid();
5888b59062aSEwan Crawford   }
5898b244e21SEwan Crawford };
5908b244e21SEwan Crawford 
5918b244e21SEwan Crawford // This AllocationDetails class collects data associated with a single
5928b244e21SEwan Crawford // allocation instance.
593b9c1b51eSKate Stone struct RenderScriptRuntime::AllocationDetails {
594b9c1b51eSKate Stone   struct Dimension {
59515f2bd95SEwan Crawford     uint32_t dim_1;
59615f2bd95SEwan Crawford     uint32_t dim_2;
59715f2bd95SEwan Crawford     uint32_t dim_3;
59880af0b9eSLuke Drummond     uint32_t cube_map;
59915f2bd95SEwan Crawford 
600b9c1b51eSKate Stone     Dimension() {
60115f2bd95SEwan Crawford       dim_1 = 0;
60215f2bd95SEwan Crawford       dim_2 = 0;
60315f2bd95SEwan Crawford       dim_3 = 0;
60480af0b9eSLuke Drummond       cube_map = 0;
60515f2bd95SEwan Crawford     }
60678f339d1SEwan Crawford   };
60778f339d1SEwan Crawford 
608b9c1b51eSKate Stone   // The FileHeader struct specifies the header we use for writing allocations
60980af0b9eSLuke Drummond   // to a binary file. Our format begins with the ASCII characters "RSAD",
61080af0b9eSLuke Drummond   // identifying the file as an allocation dump. Member variables dims and
61180af0b9eSLuke Drummond   // hdr_size are then written consecutively, immediately followed by an
61280af0b9eSLuke Drummond   // instance of the ElementHeader struct. Because Elements can contain
61380af0b9eSLuke Drummond   // subelements, there may be more than one instance of the ElementHeader
61480af0b9eSLuke Drummond   // struct. With this first instance being the root element, and the other
61580af0b9eSLuke Drummond   // instances being the root's descendants. To identify which instances are an
61605097246SAdrian Prantl   // ElementHeader's children, each struct is immediately followed by a
61705097246SAdrian Prantl   // sequence of consecutive offsets to the start of its child structs. These
61805097246SAdrian Prantl   // offsets are
61980af0b9eSLuke Drummond   // 4 bytes in size, and the 0 offset signifies no more children.
620b9c1b51eSKate Stone   struct FileHeader {
62155232f09SEwan Crawford     uint8_t ident[4];  // ASCII 'RSAD' identifying the file
62226e52a70SEwan Crawford     uint32_t dims[3];  // Dimensions
62326e52a70SEwan Crawford     uint16_t hdr_size; // Header size in bytes, including all element headers
62426e52a70SEwan Crawford   };
62526e52a70SEwan Crawford 
626b9c1b51eSKate Stone   struct ElementHeader {
62755232f09SEwan Crawford     uint16_t type;         // DataType enum
62855232f09SEwan Crawford     uint32_t kind;         // DataKind enum
62955232f09SEwan Crawford     uint32_t element_size; // Size of a single element, including padding
63026e52a70SEwan Crawford     uint16_t vector_size;  // Vector width
63126e52a70SEwan Crawford     uint32_t array_size;   // Number of elements in array
63255232f09SEwan Crawford   };
63355232f09SEwan Crawford 
63415f2bd95SEwan Crawford   // Monotonically increasing from 1
635b3f7f69dSAidan Dodds   static uint32_t ID;
63615f2bd95SEwan Crawford 
63705097246SAdrian Prantl   // Maps Allocation DataType enum and vector size to printable strings using
63805097246SAdrian Prantl   // mapping from RenderScript numerical types summary documentation
63915f2bd95SEwan Crawford   static const char *RsDataTypeToString[][4];
64015f2bd95SEwan Crawford 
64115f2bd95SEwan Crawford   // Maps Allocation DataKind enum to printable strings
64215f2bd95SEwan Crawford   static const char *RsDataKindToString[];
64315f2bd95SEwan Crawford 
644a0f08674SEwan Crawford   // Maps allocation types to format sizes for printing.
645b3f7f69dSAidan Dodds   static const uint32_t RSTypeToFormat[][3];
646a0f08674SEwan Crawford 
64715f2bd95SEwan Crawford   // Give each allocation an ID as a way
64815f2bd95SEwan Crawford   // for commands to reference it.
649b3f7f69dSAidan Dodds   const uint32_t id;
65015f2bd95SEwan Crawford 
65180af0b9eSLuke Drummond   // Allocation Element type
65280af0b9eSLuke Drummond   RenderScriptRuntime::Element element;
65380af0b9eSLuke Drummond   // Dimensions of the Allocation
65480af0b9eSLuke Drummond   empirical_type<Dimension> dimension;
65580af0b9eSLuke Drummond   // Pointer to address of the RS Allocation
65680af0b9eSLuke Drummond   empirical_type<lldb::addr_t> address;
65780af0b9eSLuke Drummond   // Pointer to the data held by the Allocation
65880af0b9eSLuke Drummond   empirical_type<lldb::addr_t> data_ptr;
65980af0b9eSLuke Drummond   // Pointer to the RS Type of the Allocation
66080af0b9eSLuke Drummond   empirical_type<lldb::addr_t> type_ptr;
66180af0b9eSLuke Drummond   // Pointer to the RS Context of the Allocation
66280af0b9eSLuke Drummond   empirical_type<lldb::addr_t> context;
66380af0b9eSLuke Drummond   // Size of the allocation
66480af0b9eSLuke Drummond   empirical_type<uint32_t> size;
66580af0b9eSLuke Drummond   // Stride between rows of the allocation
66680af0b9eSLuke Drummond   empirical_type<uint32_t> stride;
66715f2bd95SEwan Crawford 
66815f2bd95SEwan Crawford   // Give each allocation an id, so we can reference it in user commands.
669b3f7f69dSAidan Dodds   AllocationDetails() : id(ID++) {}
6708b59062aSEwan Crawford 
67180af0b9eSLuke Drummond   bool ShouldRefresh() const {
6728b59062aSEwan Crawford     bool valid_ptrs = data_ptr.isValid() && *data_ptr.get() != 0x0;
6738b59062aSEwan Crawford     valid_ptrs = valid_ptrs && type_ptr.isValid() && *type_ptr.get() != 0x0;
674b9c1b51eSKate Stone     return !valid_ptrs || !dimension.isValid() || !size.isValid() ||
67580af0b9eSLuke Drummond            element.ShouldRefresh();
6768b59062aSEwan Crawford   }
67715f2bd95SEwan Crawford };
67815f2bd95SEwan Crawford 
6790e4c4821SAdrian Prantl ConstString RenderScriptRuntime::Element::GetFallbackStructName() {
680fe06b5adSAdrian McCarthy   static const ConstString FallbackStructName("struct");
681fe06b5adSAdrian McCarthy   return FallbackStructName;
682fe06b5adSAdrian McCarthy }
6838b244e21SEwan Crawford 
684b3f7f69dSAidan Dodds uint32_t RenderScriptRuntime::AllocationDetails::ID = 1;
68515f2bd95SEwan Crawford 
686b3f7f69dSAidan Dodds const char *RenderScriptRuntime::AllocationDetails::RsDataKindToString[] = {
687b9c1b51eSKate Stone     "User",       "Undefined",   "Undefined", "Undefined",
688b9c1b51eSKate Stone     "Undefined",  "Undefined",   "Undefined", // Enum jumps from 0 to 7
689b3f7f69dSAidan Dodds     "L Pixel",    "A Pixel",     "LA Pixel",  "RGB Pixel",
690b3f7f69dSAidan Dodds     "RGBA Pixel", "Pixel Depth", "YUV Pixel"};
69115f2bd95SEwan Crawford 
692b3f7f69dSAidan Dodds const char *RenderScriptRuntime::AllocationDetails::RsDataTypeToString[][4] = {
69315f2bd95SEwan Crawford     {"None", "None", "None", "None"},
69415f2bd95SEwan Crawford     {"half", "half2", "half3", "half4"},
69515f2bd95SEwan Crawford     {"float", "float2", "float3", "float4"},
69615f2bd95SEwan Crawford     {"double", "double2", "double3", "double4"},
69715f2bd95SEwan Crawford     {"char", "char2", "char3", "char4"},
69815f2bd95SEwan Crawford     {"short", "short2", "short3", "short4"},
69915f2bd95SEwan Crawford     {"int", "int2", "int3", "int4"},
70015f2bd95SEwan Crawford     {"long", "long2", "long3", "long4"},
70115f2bd95SEwan Crawford     {"uchar", "uchar2", "uchar3", "uchar4"},
70215f2bd95SEwan Crawford     {"ushort", "ushort2", "ushort3", "ushort4"},
70315f2bd95SEwan Crawford     {"uint", "uint2", "uint3", "uint4"},
70415f2bd95SEwan Crawford     {"ulong", "ulong2", "ulong3", "ulong4"},
7052e920715SEwan Crawford     {"bool", "bool2", "bool3", "bool4"},
7062e920715SEwan Crawford     {"packed_565", "packed_565", "packed_565", "packed_565"},
7072e920715SEwan Crawford     {"packed_5551", "packed_5551", "packed_5551", "packed_5551"},
7082e920715SEwan Crawford     {"packed_4444", "packed_4444", "packed_4444", "packed_4444"},
7092e920715SEwan Crawford     {"rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4"},
7102e920715SEwan Crawford     {"rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3"},
7112e920715SEwan Crawford     {"rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2"},
7122e920715SEwan Crawford 
7132e920715SEwan Crawford     // Handlers
7142e920715SEwan Crawford     {"RS Element", "RS Element", "RS Element", "RS Element"},
7152e920715SEwan Crawford     {"RS Type", "RS Type", "RS Type", "RS Type"},
7162e920715SEwan Crawford     {"RS Allocation", "RS Allocation", "RS Allocation", "RS Allocation"},
7172e920715SEwan Crawford     {"RS Sampler", "RS Sampler", "RS Sampler", "RS Sampler"},
7182e920715SEwan Crawford     {"RS Script", "RS Script", "RS Script", "RS Script"},
7192e920715SEwan Crawford 
7202e920715SEwan Crawford     // Deprecated
7212e920715SEwan Crawford     {"RS Mesh", "RS Mesh", "RS Mesh", "RS Mesh"},
722b9c1b51eSKate Stone     {"RS Program Fragment", "RS Program Fragment", "RS Program Fragment",
723b9c1b51eSKate Stone      "RS Program Fragment"},
724b9c1b51eSKate Stone     {"RS Program Vertex", "RS Program Vertex", "RS Program Vertex",
725b9c1b51eSKate Stone      "RS Program Vertex"},
726b9c1b51eSKate Stone     {"RS Program Raster", "RS Program Raster", "RS Program Raster",
727b9c1b51eSKate Stone      "RS Program Raster"},
728b9c1b51eSKate Stone     {"RS Program Store", "RS Program Store", "RS Program Store",
729b9c1b51eSKate Stone      "RS Program Store"},
730b3f7f69dSAidan Dodds     {"RS Font", "RS Font", "RS Font", "RS Font"}};
73178f339d1SEwan Crawford 
732a0f08674SEwan Crawford // Used as an index into the RSTypeToFormat array elements
733b9c1b51eSKate Stone enum TypeToFormatIndex { eFormatSingle = 0, eFormatVector, eElementSize };
734a0f08674SEwan Crawford 
735b9c1b51eSKate Stone // { format enum of single element, format enum of element vector, size of
736b9c1b51eSKate Stone // element}
737b3f7f69dSAidan Dodds const uint32_t RenderScriptRuntime::AllocationDetails::RSTypeToFormat[][3] = {
73880af0b9eSLuke Drummond     // RS_TYPE_NONE
73980af0b9eSLuke Drummond     {eFormatHex, eFormatHex, 1},
74080af0b9eSLuke Drummond     // RS_TYPE_FLOAT_16
74180af0b9eSLuke Drummond     {eFormatFloat, eFormatVectorOfFloat16, 2},
74280af0b9eSLuke Drummond     // RS_TYPE_FLOAT_32
74380af0b9eSLuke Drummond     {eFormatFloat, eFormatVectorOfFloat32, sizeof(float)},
74480af0b9eSLuke Drummond     // RS_TYPE_FLOAT_64
74580af0b9eSLuke Drummond     {eFormatFloat, eFormatVectorOfFloat64, sizeof(double)},
74680af0b9eSLuke Drummond     // RS_TYPE_SIGNED_8
74780af0b9eSLuke Drummond     {eFormatDecimal, eFormatVectorOfSInt8, sizeof(int8_t)},
74880af0b9eSLuke Drummond     // RS_TYPE_SIGNED_16
74980af0b9eSLuke Drummond     {eFormatDecimal, eFormatVectorOfSInt16, sizeof(int16_t)},
75080af0b9eSLuke Drummond     // RS_TYPE_SIGNED_32
75180af0b9eSLuke Drummond     {eFormatDecimal, eFormatVectorOfSInt32, sizeof(int32_t)},
75280af0b9eSLuke Drummond     // RS_TYPE_SIGNED_64
75380af0b9eSLuke Drummond     {eFormatDecimal, eFormatVectorOfSInt64, sizeof(int64_t)},
75480af0b9eSLuke Drummond     // RS_TYPE_UNSIGNED_8
75580af0b9eSLuke Drummond     {eFormatDecimal, eFormatVectorOfUInt8, sizeof(uint8_t)},
75680af0b9eSLuke Drummond     // RS_TYPE_UNSIGNED_16
75780af0b9eSLuke Drummond     {eFormatDecimal, eFormatVectorOfUInt16, sizeof(uint16_t)},
75880af0b9eSLuke Drummond     // RS_TYPE_UNSIGNED_32
75980af0b9eSLuke Drummond     {eFormatDecimal, eFormatVectorOfUInt32, sizeof(uint32_t)},
76080af0b9eSLuke Drummond     // RS_TYPE_UNSIGNED_64
76180af0b9eSLuke Drummond     {eFormatDecimal, eFormatVectorOfUInt64, sizeof(uint64_t)},
76280af0b9eSLuke Drummond     // RS_TYPE_BOOL
76380af0b9eSLuke Drummond     {eFormatBoolean, eFormatBoolean, 1},
76480af0b9eSLuke Drummond     // RS_TYPE_UNSIGNED_5_6_5
76580af0b9eSLuke Drummond     {eFormatHex, eFormatHex, sizeof(uint16_t)},
76680af0b9eSLuke Drummond     // RS_TYPE_UNSIGNED_5_5_5_1
76780af0b9eSLuke Drummond     {eFormatHex, eFormatHex, sizeof(uint16_t)},
76880af0b9eSLuke Drummond     // RS_TYPE_UNSIGNED_4_4_4_4
76980af0b9eSLuke Drummond     {eFormatHex, eFormatHex, sizeof(uint16_t)},
77080af0b9eSLuke Drummond     // RS_TYPE_MATRIX_4X4
77180af0b9eSLuke Drummond     {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 16},
77280af0b9eSLuke Drummond     // RS_TYPE_MATRIX_3X3
77380af0b9eSLuke Drummond     {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 9},
77480af0b9eSLuke Drummond     // RS_TYPE_MATRIX_2X2
77580af0b9eSLuke Drummond     {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 4}};
776a0f08674SEwan Crawford 
7775ec532a9SColin Riley // Static Functions
7785ec532a9SColin Riley LanguageRuntime *
779b9c1b51eSKate Stone RenderScriptRuntime::CreateInstance(Process *process,
780b9c1b51eSKate Stone                                     lldb::LanguageType language) {
7815ec532a9SColin Riley 
7825ec532a9SColin Riley   if (language == eLanguageTypeExtRenderScript)
7835ec532a9SColin Riley     return new RenderScriptRuntime(process);
7845ec532a9SColin Riley   else
785b3f7f69dSAidan Dodds     return nullptr;
7865ec532a9SColin Riley }
7875ec532a9SColin Riley 
78880af0b9eSLuke Drummond // Callback with a module to search for matching symbols. We first check that
78980af0b9eSLuke Drummond // the module contains RS kernels. Then look for a symbol which matches our
79080af0b9eSLuke Drummond // kernel name. The breakpoint address is finally set using the address of this
79180af0b9eSLuke Drummond // symbol.
79298156583SEwan Crawford Searcher::CallbackReturn
793b9c1b51eSKate Stone RSBreakpointResolver::SearchCallback(SearchFilter &filter,
79495e264fcSRaphael Isemann                                      SymbolContext &context, Address *) {
7956c17cc53STatyana Krasnukha   BreakpointSP breakpoint_sp = GetBreakpoint();
7966c17cc53STatyana Krasnukha   assert(breakpoint_sp);
7976c17cc53STatyana Krasnukha 
79898156583SEwan Crawford   ModuleSP module = context.module_sp;
79998156583SEwan Crawford 
800b3bbcb12SLuke Drummond   if (!module || !IsRenderScriptScriptModule(module))
80198156583SEwan Crawford     return Searcher::eCallbackReturnContinue;
80298156583SEwan Crawford 
803b9c1b51eSKate Stone   // Attempt to set a breakpoint on the kernel name symbol within the module
80480af0b9eSLuke Drummond   // library. If it's not found, it's likely debug info is unavailable - try to
80580af0b9eSLuke Drummond   // set a breakpoint on <name>.expand.
806b9c1b51eSKate Stone   const Symbol *kernel_sym =
807b9c1b51eSKate Stone       module->FindFirstSymbolWithNameAndType(m_kernel_name, eSymbolTypeCode);
808b9c1b51eSKate Stone   if (!kernel_sym) {
80998156583SEwan Crawford     std::string kernel_name_expanded(m_kernel_name.AsCString());
81098156583SEwan Crawford     kernel_name_expanded.append(".expand");
811b9c1b51eSKate Stone     kernel_sym = module->FindFirstSymbolWithNameAndType(
812b9c1b51eSKate Stone         ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode);
81398156583SEwan Crawford   }
81498156583SEwan Crawford 
815b9c1b51eSKate Stone   if (kernel_sym) {
81698156583SEwan Crawford     Address bp_addr = kernel_sym->GetAddress();
81798156583SEwan Crawford     if (filter.AddressPasses(bp_addr))
8186c17cc53STatyana Krasnukha       breakpoint_sp->AddLocation(bp_addr);
81998156583SEwan Crawford   }
82098156583SEwan Crawford 
82198156583SEwan Crawford   return Searcher::eCallbackReturnContinue;
82298156583SEwan Crawford }
82398156583SEwan Crawford 
824b3bbcb12SLuke Drummond Searcher::CallbackReturn
825b3bbcb12SLuke Drummond RSReduceBreakpointResolver::SearchCallback(lldb_private::SearchFilter &filter,
826b3bbcb12SLuke Drummond                                            lldb_private::SymbolContext &context,
82795e264fcSRaphael Isemann                                            Address *) {
8286c17cc53STatyana Krasnukha   BreakpointSP breakpoint_sp = GetBreakpoint();
8296c17cc53STatyana Krasnukha   assert(breakpoint_sp);
8306c17cc53STatyana Krasnukha 
831b3bbcb12SLuke Drummond   // We need to have access to the list of reductions currently parsed, as
83205097246SAdrian Prantl   // reduce names don't actually exist as symbols in a module. They are only
83305097246SAdrian Prantl   // identifiable by parsing the .rs.info packet, or finding the expand symbol.
83405097246SAdrian Prantl   // We therefore need access to the list of parsed rs modules to properly
83505097246SAdrian Prantl   // resolve reduction names.
836*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Breakpoints);
837b3bbcb12SLuke Drummond   ModuleSP module = context.module_sp;
838b3bbcb12SLuke Drummond 
839b3bbcb12SLuke Drummond   if (!module || !IsRenderScriptScriptModule(module))
840b3bbcb12SLuke Drummond     return Searcher::eCallbackReturnContinue;
841b3bbcb12SLuke Drummond 
842b3bbcb12SLuke Drummond   if (!m_rsmodules)
843b3bbcb12SLuke Drummond     return Searcher::eCallbackReturnContinue;
844b3bbcb12SLuke Drummond 
845b3bbcb12SLuke Drummond   for (const auto &module_desc : *m_rsmodules) {
846b3bbcb12SLuke Drummond     if (module_desc->m_module != module)
847b3bbcb12SLuke Drummond       continue;
848b3bbcb12SLuke Drummond 
849b3bbcb12SLuke Drummond     for (const auto &reduction : module_desc->m_reductions) {
850b3bbcb12SLuke Drummond       if (reduction.m_reduce_name != m_reduce_name)
851b3bbcb12SLuke Drummond         continue;
852b3bbcb12SLuke Drummond 
853b3bbcb12SLuke Drummond       std::array<std::pair<ConstString, int>, 5> funcs{
854b3bbcb12SLuke Drummond           {{reduction.m_init_name, eKernelTypeInit},
855b3bbcb12SLuke Drummond            {reduction.m_accum_name, eKernelTypeAccum},
856b3bbcb12SLuke Drummond            {reduction.m_comb_name, eKernelTypeComb},
857b3bbcb12SLuke Drummond            {reduction.m_outc_name, eKernelTypeOutC},
858b3bbcb12SLuke Drummond            {reduction.m_halter_name, eKernelTypeHalter}}};
859b3bbcb12SLuke Drummond 
860b3bbcb12SLuke Drummond       for (const auto &kernel : funcs) {
861b3bbcb12SLuke Drummond         // Skip constituent functions that don't match our spec
862b3bbcb12SLuke Drummond         if (!(m_kernel_types & kernel.second))
863b3bbcb12SLuke Drummond           continue;
864b3bbcb12SLuke Drummond 
865b3bbcb12SLuke Drummond         const auto kernel_name = kernel.first;
866b3bbcb12SLuke Drummond         const auto symbol = module->FindFirstSymbolWithNameAndType(
867b3bbcb12SLuke Drummond             kernel_name, eSymbolTypeCode);
868b3bbcb12SLuke Drummond         if (!symbol)
869b3bbcb12SLuke Drummond           continue;
870b3bbcb12SLuke Drummond 
871b3bbcb12SLuke Drummond         auto address = symbol->GetAddress();
872b3bbcb12SLuke Drummond         if (filter.AddressPasses(address)) {
873b3bbcb12SLuke Drummond           bool new_bp;
87481fc84faSLuke Drummond           if (!SkipPrologue(module, address)) {
87563e5fb76SJonas Devlieghere             LLDB_LOGF(log, "%s: Error trying to skip prologue", __FUNCTION__);
87681fc84faSLuke Drummond           }
8776c17cc53STatyana Krasnukha           breakpoint_sp->AddLocation(address, &new_bp);
87863e5fb76SJonas Devlieghere           LLDB_LOGF(log, "%s: %s reduction breakpoint on %s in %s",
87963e5fb76SJonas Devlieghere                     __FUNCTION__, new_bp ? "new" : "existing",
88063e5fb76SJonas Devlieghere                     kernel_name.GetCString(),
881b3bbcb12SLuke Drummond                     address.GetModule()->GetFileSpec().GetCString());
882b3bbcb12SLuke Drummond         }
883b3bbcb12SLuke Drummond       }
884b3bbcb12SLuke Drummond     }
885b3bbcb12SLuke Drummond   }
886b3bbcb12SLuke Drummond   return eCallbackReturnContinue;
887b3bbcb12SLuke Drummond }
888b3bbcb12SLuke Drummond 
88921fed052SAidan Dodds Searcher::CallbackReturn RSScriptGroupBreakpointResolver::SearchCallback(
89095e264fcSRaphael Isemann     SearchFilter &filter, SymbolContext &context, Address *addr) {
89121fed052SAidan Dodds 
8926c17cc53STatyana Krasnukha   BreakpointSP breakpoint_sp = GetBreakpoint();
8936c17cc53STatyana Krasnukha   if (!breakpoint_sp)
89421fed052SAidan Dodds     return eCallbackReturnContinue;
89521fed052SAidan Dodds 
896*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Breakpoints);
89721fed052SAidan Dodds   ModuleSP &module = context.module_sp;
89821fed052SAidan Dodds 
89921fed052SAidan Dodds   if (!module || !IsRenderScriptScriptModule(module))
90021fed052SAidan Dodds     return Searcher::eCallbackReturnContinue;
90121fed052SAidan Dodds 
90221fed052SAidan Dodds   std::vector<std::string> names;
9036c17cc53STatyana Krasnukha   Breakpoint& breakpoint = *breakpoint_sp;
9046c17cc53STatyana Krasnukha   breakpoint.GetNames(names);
90521fed052SAidan Dodds   if (names.empty())
90621fed052SAidan Dodds     return eCallbackReturnContinue;
90721fed052SAidan Dodds 
90821fed052SAidan Dodds   for (auto &name : names) {
90921fed052SAidan Dodds     const RSScriptGroupDescriptorSP sg = FindScriptGroup(ConstString(name));
91021fed052SAidan Dodds     if (!sg) {
91163e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s: could not find script group for %s", __FUNCTION__,
91221fed052SAidan Dodds                 name.c_str());
91321fed052SAidan Dodds       continue;
91421fed052SAidan Dodds     }
91521fed052SAidan Dodds 
91663e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s: Found ScriptGroup for %s", __FUNCTION__, name.c_str());
91721fed052SAidan Dodds 
91821fed052SAidan Dodds     for (const RSScriptGroupDescriptor::Kernel &k : sg->m_kernels) {
91921fed052SAidan Dodds       if (log) {
92063e5fb76SJonas Devlieghere         LLDB_LOGF(log, "%s: Adding breakpoint for %s", __FUNCTION__,
92121fed052SAidan Dodds                   k.m_name.AsCString());
92263e5fb76SJonas Devlieghere         LLDB_LOGF(log, "%s: Kernel address 0x%" PRIx64, __FUNCTION__, k.m_addr);
92321fed052SAidan Dodds       }
92421fed052SAidan Dodds 
92521fed052SAidan Dodds       const lldb_private::Symbol *sym =
92621fed052SAidan Dodds           module->FindFirstSymbolWithNameAndType(k.m_name, eSymbolTypeCode);
92721fed052SAidan Dodds       if (!sym) {
92863e5fb76SJonas Devlieghere         LLDB_LOGF(log, "%s: Unable to find symbol for %s", __FUNCTION__,
92921fed052SAidan Dodds                   k.m_name.AsCString());
93021fed052SAidan Dodds         continue;
93121fed052SAidan Dodds       }
93221fed052SAidan Dodds 
93321fed052SAidan Dodds       if (log) {
93463e5fb76SJonas Devlieghere         LLDB_LOGF(log, "%s: Found symbol name is %s", __FUNCTION__,
93521fed052SAidan Dodds                   sym->GetName().AsCString());
93621fed052SAidan Dodds       }
93721fed052SAidan Dodds 
93821fed052SAidan Dodds       auto address = sym->GetAddress();
93921fed052SAidan Dodds       if (!SkipPrologue(module, address)) {
94063e5fb76SJonas Devlieghere         LLDB_LOGF(log, "%s: Error trying to skip prologue", __FUNCTION__);
94121fed052SAidan Dodds       }
94221fed052SAidan Dodds 
94321fed052SAidan Dodds       bool new_bp;
9446c17cc53STatyana Krasnukha       breakpoint.AddLocation(address, &new_bp);
94521fed052SAidan Dodds 
94663e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s: Placed %sbreakpoint on %s", __FUNCTION__,
94721fed052SAidan Dodds                 new_bp ? "new " : "", k.m_name.AsCString());
94821fed052SAidan Dodds 
94905097246SAdrian Prantl       // exit after placing the first breakpoint if we do not intend to stop on
95005097246SAdrian Prantl       // all kernels making up this script group
95121fed052SAidan Dodds       if (!m_stop_on_all)
95221fed052SAidan Dodds         break;
95321fed052SAidan Dodds     }
95421fed052SAidan Dodds   }
95521fed052SAidan Dodds 
95621fed052SAidan Dodds   return eCallbackReturnContinue;
95721fed052SAidan Dodds }
95821fed052SAidan Dodds 
959b9c1b51eSKate Stone void RenderScriptRuntime::Initialize() {
960b9c1b51eSKate Stone   PluginManager::RegisterPlugin(GetPluginNameStatic(),
961b9c1b51eSKate Stone                                 "RenderScript language support", CreateInstance,
962b3f7f69dSAidan Dodds                                 GetCommandObject);
9635ec532a9SColin Riley }
9645ec532a9SColin Riley 
965b9c1b51eSKate Stone void RenderScriptRuntime::Terminate() {
9665ec532a9SColin Riley   PluginManager::UnregisterPlugin(CreateInstance);
9675ec532a9SColin Riley }
9685ec532a9SColin Riley 
969ef20b08fSColin Riley RenderScriptRuntime::ModuleKind
970b9c1b51eSKate Stone RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp) {
971b9c1b51eSKate Stone   if (module_sp) {
972b3bbcb12SLuke Drummond     if (IsRenderScriptScriptModule(module_sp))
973ef20b08fSColin Riley       return eModuleKindKernelObj;
9744640cde1SColin Riley 
9754640cde1SColin Riley     // Is this the main RS runtime library
9764640cde1SColin Riley     const ConstString rs_lib("libRS.so");
977b9c1b51eSKate Stone     if (module_sp->GetFileSpec().GetFilename() == rs_lib) {
9784640cde1SColin Riley       return eModuleKindLibRS;
9794640cde1SColin Riley     }
9804640cde1SColin Riley 
9814640cde1SColin Riley     const ConstString rs_driverlib("libRSDriver.so");
982b9c1b51eSKate Stone     if (module_sp->GetFileSpec().GetFilename() == rs_driverlib) {
9834640cde1SColin Riley       return eModuleKindDriver;
9844640cde1SColin Riley     }
9854640cde1SColin Riley 
98615f2bd95SEwan Crawford     const ConstString rs_cpureflib("libRSCpuRef.so");
987b9c1b51eSKate Stone     if (module_sp->GetFileSpec().GetFilename() == rs_cpureflib) {
9884640cde1SColin Riley       return eModuleKindImpl;
9894640cde1SColin Riley     }
990ef20b08fSColin Riley   }
991ef20b08fSColin Riley   return eModuleKindIgnored;
992ef20b08fSColin Riley }
993ef20b08fSColin Riley 
994b9c1b51eSKate Stone bool RenderScriptRuntime::IsRenderScriptModule(
995b9c1b51eSKate Stone     const lldb::ModuleSP &module_sp) {
996ef20b08fSColin Riley   return GetModuleKind(module_sp) != eModuleKindIgnored;
997ef20b08fSColin Riley }
998ef20b08fSColin Riley 
999b9c1b51eSKate Stone void RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list) {
1000bb19a13cSSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
1001ef20b08fSColin Riley 
1002ef20b08fSColin Riley   size_t num_modules = module_list.GetSize();
1003b9c1b51eSKate Stone   for (size_t i = 0; i < num_modules; i++) {
1004ef20b08fSColin Riley     auto mod = module_list.GetModuleAtIndex(i);
1005b9c1b51eSKate Stone     if (IsRenderScriptModule(mod)) {
1006ef20b08fSColin Riley       LoadModule(mod);
1007ef20b08fSColin Riley     }
1008ef20b08fSColin Riley   }
1009ef20b08fSColin Riley }
1010ef20b08fSColin Riley 
1011b9c1b51eSKate Stone bool RenderScriptRuntime::GetDynamicTypeAndAddress(
1012b9c1b51eSKate Stone     ValueObject &in_value, lldb::DynamicValueType use_dynamic,
10135f57b6eeSEnrico Granata     TypeAndOrName &class_type_or_name, Address &address,
1014b9c1b51eSKate Stone     Value::ValueType &value_type) {
10155ec532a9SColin Riley   return false;
10165ec532a9SColin Riley }
10175ec532a9SColin Riley 
1018c74275bcSEnrico Granata TypeAndOrName
1019b9c1b51eSKate Stone RenderScriptRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
1020b9c1b51eSKate Stone                                       ValueObject &static_value) {
1021c74275bcSEnrico Granata   return type_and_or_name;
1022c74275bcSEnrico Granata }
1023c74275bcSEnrico Granata 
1024b9c1b51eSKate Stone bool RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
10255ec532a9SColin Riley   return false;
10265ec532a9SColin Riley }
10275ec532a9SColin Riley 
10285ec532a9SColin Riley lldb::BreakpointResolverSP
10296c17cc53STatyana Krasnukha RenderScriptRuntime::CreateExceptionResolver(const lldb::BreakpointSP &bp,
10306c17cc53STatyana Krasnukha                                              bool catch_bp, bool throw_bp) {
10315ec532a9SColin Riley   BreakpointResolverSP resolver_sp;
10325ec532a9SColin Riley   return resolver_sp;
10335ec532a9SColin Riley }
10345ec532a9SColin Riley 
1035b9c1b51eSKate Stone const RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] =
1036b9c1b51eSKate Stone     {
10374640cde1SColin Riley         // rsdScript
1038b9c1b51eSKate Stone         {"rsdScriptInit", "_Z13rsdScriptInitPKN7android12renderscript7ContextEP"
1039b9c1b51eSKate Stone                           "NS0_7ScriptCEPKcS7_PKhjj",
1040b9c1b51eSKate Stone          "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_"
1041b9c1b51eSKate Stone          "7ScriptCEPKcS7_PKhmj",
1042b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
1043b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureScriptInit},
1044b9c1b51eSKate Stone         {"rsdScriptInvokeForEachMulti",
1045b9c1b51eSKate Stone          "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0"
1046b9c1b51eSKate Stone          "_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall",
1047b9c1b51eSKate Stone          "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0"
1048b9c1b51eSKate Stone          "_6ScriptEjPPKNS0_10AllocationEmPS6_PKvmPK12RsScriptCall",
1049b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
1050b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureScriptInvokeForEachMulti},
1051b9c1b51eSKate Stone         {"rsdScriptSetGlobalVar", "_Z21rsdScriptSetGlobalVarPKN7android12render"
1052b9c1b51eSKate Stone                                   "script7ContextEPKNS0_6ScriptEjPvj",
1053b9c1b51eSKate Stone          "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_"
1054b9c1b51eSKate Stone          "6ScriptEjPvm",
1055b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
1056b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar},
10574640cde1SColin Riley 
10584640cde1SColin Riley         // rsdAllocation
1059b9c1b51eSKate Stone         {"rsdAllocationInit", "_Z17rsdAllocationInitPKN7android12renderscript7C"
1060b9c1b51eSKate Stone                               "ontextEPNS0_10AllocationEb",
1061b9c1b51eSKate Stone          "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_"
1062b9c1b51eSKate Stone          "10AllocationEb",
1063b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
1064b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureAllocationInit},
1065b9c1b51eSKate Stone         {"rsdAllocationRead2D",
1066b9c1b51eSKate Stone          "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_"
1067b9c1b51eSKate Stone          "10AllocationEjjj23RsAllocationCubemapFacejjPvjj",
1068b9c1b51eSKate Stone          "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_"
1069b9c1b51eSKate Stone          "10AllocationEjjj23RsAllocationCubemapFacejjPvmm",
1070b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver, nullptr},
1071b9c1b51eSKate Stone         {"rsdAllocationDestroy", "_Z20rsdAllocationDestroyPKN7android12rendersc"
1072b9c1b51eSKate Stone                                  "ript7ContextEPNS0_10AllocationE",
1073b9c1b51eSKate Stone          "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_"
1074b9c1b51eSKate Stone          "10AllocationE",
1075b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
1076b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy},
107721fed052SAidan Dodds 
107821fed052SAidan Dodds         // renderscript script groups
107921fed052SAidan Dodds         {"rsdDebugHintScriptGroup2", "_ZN7android12renderscript21debugHintScrip"
108021fed052SAidan Dodds                                      "tGroup2EPKcjPKPFvPK24RsExpandKernelDriver"
108121fed052SAidan Dodds                                      "InfojjjEj",
108221fed052SAidan Dodds          "_ZN7android12renderscript21debugHintScriptGroup2EPKcjPKPFvPK24RsExpan"
108321fed052SAidan Dodds          "dKernelDriverInfojjjEj",
108421fed052SAidan Dodds          0, RenderScriptRuntime::eModuleKindImpl,
108521fed052SAidan Dodds          &lldb_private::RenderScriptRuntime::CaptureDebugHintScriptGroup2}};
10864640cde1SColin Riley 
1087b9c1b51eSKate Stone const size_t RenderScriptRuntime::s_runtimeHookCount =
1088b9c1b51eSKate Stone     sizeof(s_runtimeHookDefns) / sizeof(s_runtimeHookDefns[0]);
10894640cde1SColin Riley 
1090b9c1b51eSKate Stone bool RenderScriptRuntime::HookCallback(void *baton,
1091b9c1b51eSKate Stone                                        StoppointCallbackContext *ctx,
1092b9c1b51eSKate Stone                                        lldb::user_id_t break_id,
1093b9c1b51eSKate Stone                                        lldb::user_id_t break_loc_id) {
109480af0b9eSLuke Drummond   RuntimeHook *hook = (RuntimeHook *)baton;
109580af0b9eSLuke Drummond   ExecutionContext exe_ctx(ctx->exe_ctx_ref);
10964640cde1SColin Riley 
1097056f6f18SAlex Langford   RenderScriptRuntime *lang_rt = llvm::cast<RenderScriptRuntime>(
1098056f6f18SAlex Langford       exe_ctx.GetProcessPtr()->GetLanguageRuntime(
1099056f6f18SAlex Langford           eLanguageTypeExtRenderScript));
11004640cde1SColin Riley 
110180af0b9eSLuke Drummond   lang_rt->HookCallback(hook, exe_ctx);
11024640cde1SColin Riley 
11034640cde1SColin Riley   return false;
11044640cde1SColin Riley }
11054640cde1SColin Riley 
110680af0b9eSLuke Drummond void RenderScriptRuntime::HookCallback(RuntimeHook *hook,
110780af0b9eSLuke Drummond                                        ExecutionContext &exe_ctx) {
1108*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
11094640cde1SColin Riley 
111063e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - '%s'", __FUNCTION__, hook->defn->name);
11114640cde1SColin Riley 
111280af0b9eSLuke Drummond   if (hook->defn->grabber) {
111380af0b9eSLuke Drummond     (this->*(hook->defn->grabber))(hook, exe_ctx);
11144640cde1SColin Riley   }
11154640cde1SColin Riley }
11164640cde1SColin Riley 
111721fed052SAidan Dodds void RenderScriptRuntime::CaptureDebugHintScriptGroup2(
111821fed052SAidan Dodds     RuntimeHook *hook_info, ExecutionContext &context) {
1119*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
112021fed052SAidan Dodds 
112121fed052SAidan Dodds   enum {
112221fed052SAidan Dodds     eGroupName = 0,
112321fed052SAidan Dodds     eGroupNameSize,
112421fed052SAidan Dodds     eKernel,
112521fed052SAidan Dodds     eKernelCount,
112621fed052SAidan Dodds   };
112721fed052SAidan Dodds 
112821fed052SAidan Dodds   std::array<ArgItem, 4> args{{
112921fed052SAidan Dodds       {ArgItem::ePointer, 0}, // const char         *groupName
113021fed052SAidan Dodds       {ArgItem::eInt32, 0},   // const uint32_t      groupNameSize
113121fed052SAidan Dodds       {ArgItem::ePointer, 0}, // const ExpandFuncTy *kernel
113221fed052SAidan Dodds       {ArgItem::eInt32, 0},   // const uint32_t      kernelCount
113321fed052SAidan Dodds   }};
113421fed052SAidan Dodds 
113521fed052SAidan Dodds   if (!GetArgs(context, args.data(), args.size())) {
113663e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - Error while reading the function parameters",
113721fed052SAidan Dodds               __FUNCTION__);
113821fed052SAidan Dodds     return;
113921fed052SAidan Dodds   } else if (log) {
114063e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - groupName    : 0x%" PRIx64, __FUNCTION__,
114121fed052SAidan Dodds               addr_t(args[eGroupName]));
114263e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - groupNameSize: %" PRIu64, __FUNCTION__,
114321fed052SAidan Dodds               uint64_t(args[eGroupNameSize]));
114463e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - kernel       : 0x%" PRIx64, __FUNCTION__,
114521fed052SAidan Dodds               addr_t(args[eKernel]));
114663e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - kernelCount  : %" PRIu64, __FUNCTION__,
114721fed052SAidan Dodds               uint64_t(args[eKernelCount]));
114821fed052SAidan Dodds   }
114921fed052SAidan Dodds 
115021fed052SAidan Dodds   // parse script group name
115121fed052SAidan Dodds   ConstString group_name;
115221fed052SAidan Dodds   {
115397206d57SZachary Turner     Status err;
115421fed052SAidan Dodds     const uint64_t len = uint64_t(args[eGroupNameSize]);
115521fed052SAidan Dodds     std::unique_ptr<char[]> buffer(new char[uint32_t(len + 1)]);
115621fed052SAidan Dodds     m_process->ReadMemory(addr_t(args[eGroupName]), buffer.get(), len, err);
115721fed052SAidan Dodds     buffer.get()[len] = '\0';
115821fed052SAidan Dodds     if (!err.Success()) {
115963e5fb76SJonas Devlieghere       LLDB_LOGF(log, "Error reading scriptgroup name from target");
116021fed052SAidan Dodds       return;
116121fed052SAidan Dodds     } else {
116263e5fb76SJonas Devlieghere       LLDB_LOGF(log, "Extracted scriptgroup name %s", buffer.get());
116321fed052SAidan Dodds     }
116421fed052SAidan Dodds     // write back the script group name
116521fed052SAidan Dodds     group_name.SetCString(buffer.get());
116621fed052SAidan Dodds   }
116721fed052SAidan Dodds 
116821fed052SAidan Dodds   // create or access existing script group
116921fed052SAidan Dodds   RSScriptGroupDescriptorSP group;
117021fed052SAidan Dodds   {
117121fed052SAidan Dodds     // search for existing script group
117221fed052SAidan Dodds     for (auto sg : m_scriptGroups) {
117321fed052SAidan Dodds       if (sg->m_name == group_name) {
117421fed052SAidan Dodds         group = sg;
117521fed052SAidan Dodds         break;
117621fed052SAidan Dodds       }
117721fed052SAidan Dodds     }
117821fed052SAidan Dodds     if (!group) {
1179796ac80bSJonas Devlieghere       group = std::make_shared<RSScriptGroupDescriptor>();
118021fed052SAidan Dodds       group->m_name = group_name;
118121fed052SAidan Dodds       m_scriptGroups.push_back(group);
118221fed052SAidan Dodds     } else {
118321fed052SAidan Dodds       // already have this script group
118463e5fb76SJonas Devlieghere       LLDB_LOGF(log, "Attempt to add duplicate script group %s",
118521fed052SAidan Dodds                 group_name.AsCString());
118621fed052SAidan Dodds       return;
118721fed052SAidan Dodds     }
118821fed052SAidan Dodds   }
118921fed052SAidan Dodds   assert(group);
119021fed052SAidan Dodds 
119121fed052SAidan Dodds   const uint32_t target_ptr_size = m_process->GetAddressByteSize();
119221fed052SAidan Dodds   std::vector<addr_t> kernels;
119321fed052SAidan Dodds   // parse kernel addresses in script group
119421fed052SAidan Dodds   for (uint64_t i = 0; i < uint64_t(args[eKernelCount]); ++i) {
119521fed052SAidan Dodds     RSScriptGroupDescriptor::Kernel kernel;
119621fed052SAidan Dodds     // extract script group kernel addresses from the target
119721fed052SAidan Dodds     const addr_t ptr_addr = addr_t(args[eKernel]) + i * target_ptr_size;
119821fed052SAidan Dodds     uint64_t kernel_addr = 0;
119997206d57SZachary Turner     Status err;
120021fed052SAidan Dodds     size_t read =
120121fed052SAidan Dodds         m_process->ReadMemory(ptr_addr, &kernel_addr, target_ptr_size, err);
120221fed052SAidan Dodds     if (!err.Success() || read != target_ptr_size) {
120363e5fb76SJonas Devlieghere       LLDB_LOGF(log, "Error parsing kernel address %" PRIu64 " in script group",
120421fed052SAidan Dodds                 i);
120521fed052SAidan Dodds       return;
120621fed052SAidan Dodds     }
120763e5fb76SJonas Devlieghere     LLDB_LOGF(log, "Extracted scriptgroup kernel address - 0x%" PRIx64,
120821fed052SAidan Dodds               kernel_addr);
120921fed052SAidan Dodds     kernel.m_addr = kernel_addr;
121021fed052SAidan Dodds 
121121fed052SAidan Dodds     // try to resolve the associated kernel name
121221fed052SAidan Dodds     if (!ResolveKernelName(kernel.m_addr, kernel.m_name)) {
121363e5fb76SJonas Devlieghere       LLDB_LOGF(log, "Parsed scriptgroup kernel %" PRIu64 " - 0x%" PRIx64, i,
121421fed052SAidan Dodds                 kernel_addr);
121521fed052SAidan Dodds       return;
121621fed052SAidan Dodds     }
121721fed052SAidan Dodds 
121821fed052SAidan Dodds     // try to find the non '.expand' function
121921fed052SAidan Dodds     {
122021fed052SAidan Dodds       const llvm::StringRef expand(".expand");
122121fed052SAidan Dodds       const llvm::StringRef name_ref = kernel.m_name.GetStringRef();
122221fed052SAidan Dodds       if (name_ref.endswith(expand)) {
122321fed052SAidan Dodds         const ConstString base_kernel(name_ref.drop_back(expand.size()));
122421fed052SAidan Dodds         // verify this function is a valid kernel
122521fed052SAidan Dodds         if (IsKnownKernel(base_kernel)) {
122621fed052SAidan Dodds           kernel.m_name = base_kernel;
122763e5fb76SJonas Devlieghere           LLDB_LOGF(log, "%s - found non expand version '%s'", __FUNCTION__,
122821fed052SAidan Dodds                     base_kernel.GetCString());
122921fed052SAidan Dodds         }
123021fed052SAidan Dodds       }
123121fed052SAidan Dodds     }
123221fed052SAidan Dodds     // add to a list of script group kernels we know about
123321fed052SAidan Dodds     group->m_kernels.push_back(kernel);
123421fed052SAidan Dodds   }
123521fed052SAidan Dodds 
123621fed052SAidan Dodds   // Resolve any pending scriptgroup breakpoints
123721fed052SAidan Dodds   {
123821fed052SAidan Dodds     Target &target = m_process->GetTarget();
123921fed052SAidan Dodds     const BreakpointList &list = target.GetBreakpointList();
124021fed052SAidan Dodds     const size_t num_breakpoints = list.GetSize();
124163e5fb76SJonas Devlieghere     LLDB_LOGF(log, "Resolving %zu breakpoints", num_breakpoints);
124221fed052SAidan Dodds     for (size_t i = 0; i < num_breakpoints; ++i) {
124321fed052SAidan Dodds       const BreakpointSP bp = list.GetBreakpointAtIndex(i);
124421fed052SAidan Dodds       if (bp) {
124521fed052SAidan Dodds         if (bp->MatchesName(group_name.AsCString())) {
124663e5fb76SJonas Devlieghere           LLDB_LOGF(log, "Found breakpoint with name %s",
124721fed052SAidan Dodds                     group_name.AsCString());
124821fed052SAidan Dodds           bp->ResolveBreakpoint();
124921fed052SAidan Dodds         }
125021fed052SAidan Dodds       }
125121fed052SAidan Dodds     }
125221fed052SAidan Dodds   }
125321fed052SAidan Dodds }
125421fed052SAidan Dodds 
1255b9c1b51eSKate Stone void RenderScriptRuntime::CaptureScriptInvokeForEachMulti(
125680af0b9eSLuke Drummond     RuntimeHook *hook, ExecutionContext &exe_ctx) {
1257*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
1258e09c44b6SAidan Dodds 
1259b9c1b51eSKate Stone   enum {
1260f4786785SAidan Dodds     eRsContext = 0,
1261f4786785SAidan Dodds     eRsScript,
1262f4786785SAidan Dodds     eRsSlot,
1263f4786785SAidan Dodds     eRsAIns,
1264f4786785SAidan Dodds     eRsInLen,
1265f4786785SAidan Dodds     eRsAOut,
1266f4786785SAidan Dodds     eRsUsr,
1267f4786785SAidan Dodds     eRsUsrLen,
1268f4786785SAidan Dodds     eRsSc,
1269f4786785SAidan Dodds   };
1270e09c44b6SAidan Dodds 
12711ee07253SSaleem Abdulrasool   std::array<ArgItem, 9> args{{
1272f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // const Context       *rsc
1273f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // Script              *s
1274f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // uint32_t             slot
1275f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // const Allocation   **aIns
1276f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // size_t               inLen
1277f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // Allocation          *aout
1278f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // const void          *usr
1279f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // size_t               usrLen
1280f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // const RsScriptCall  *sc
12811ee07253SSaleem Abdulrasool   }};
1282e09c44b6SAidan Dodds 
128380af0b9eSLuke Drummond   bool success = GetArgs(exe_ctx, &args[0], args.size());
1284b9c1b51eSKate Stone   if (!success) {
128563e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - Error while reading the function parameters",
1286b9c1b51eSKate Stone               __FUNCTION__);
1287e09c44b6SAidan Dodds     return;
1288e09c44b6SAidan Dodds   }
1289e09c44b6SAidan Dodds 
1290e09c44b6SAidan Dodds   const uint32_t target_ptr_size = m_process->GetAddressByteSize();
129197206d57SZachary Turner   Status err;
1292e09c44b6SAidan Dodds   std::vector<uint64_t> allocs;
1293e09c44b6SAidan Dodds 
1294e09c44b6SAidan Dodds   // traverse allocation list
1295b9c1b51eSKate Stone   for (uint64_t i = 0; i < uint64_t(args[eRsInLen]); ++i) {
1296e09c44b6SAidan Dodds     // calculate offest to allocation pointer
1297f4786785SAidan Dodds     const addr_t addr = addr_t(args[eRsAIns]) + i * target_ptr_size;
1298e09c44b6SAidan Dodds 
129980af0b9eSLuke Drummond     // Note: due to little endian layout, reading 32bits or 64bits into res
130080af0b9eSLuke Drummond     // will give the correct results.
130180af0b9eSLuke Drummond     uint64_t result = 0;
130280af0b9eSLuke Drummond     size_t read = m_process->ReadMemory(addr, &result, target_ptr_size, err);
130380af0b9eSLuke Drummond     if (read != target_ptr_size || !err.Success()) {
130463e5fb76SJonas Devlieghere       LLDB_LOGF(log,
1305b9c1b51eSKate Stone                 "%s - Error while reading allocation list argument %" PRIu64,
1306b9c1b51eSKate Stone                 __FUNCTION__, i);
1307b9c1b51eSKate Stone     } else {
130880af0b9eSLuke Drummond       allocs.push_back(result);
1309e09c44b6SAidan Dodds     }
1310e09c44b6SAidan Dodds   }
1311e09c44b6SAidan Dodds 
1312e09c44b6SAidan Dodds   // if there is an output allocation track it
131380af0b9eSLuke Drummond   if (uint64_t alloc_out = uint64_t(args[eRsAOut])) {
131480af0b9eSLuke Drummond     allocs.push_back(alloc_out);
1315e09c44b6SAidan Dodds   }
1316e09c44b6SAidan Dodds 
1317e09c44b6SAidan Dodds   // for all allocations we have found
1318b9c1b51eSKate Stone   for (const uint64_t alloc_addr : allocs) {
13195d057637SLuke Drummond     AllocationDetails *alloc = LookUpAllocation(alloc_addr);
13205d057637SLuke Drummond     if (!alloc)
13215d057637SLuke Drummond       alloc = CreateAllocation(alloc_addr);
13225d057637SLuke Drummond 
1323b9c1b51eSKate Stone     if (alloc) {
1324e09c44b6SAidan Dodds       // save the allocation address
1325b9c1b51eSKate Stone       if (alloc->address.isValid()) {
1326e09c44b6SAidan Dodds         // check the allocation address we already have matches
1327e09c44b6SAidan Dodds         assert(*alloc->address.get() == alloc_addr);
1328b9c1b51eSKate Stone       } else {
1329e09c44b6SAidan Dodds         alloc->address = alloc_addr;
1330e09c44b6SAidan Dodds       }
1331e09c44b6SAidan Dodds 
1332e09c44b6SAidan Dodds       // save the context
1333b9c1b51eSKate Stone       if (log) {
1334b9c1b51eSKate Stone         if (alloc->context.isValid() &&
1335b9c1b51eSKate Stone             *alloc->context.get() != addr_t(args[eRsContext]))
133663e5fb76SJonas Devlieghere           LLDB_LOGF(log, "%s - Allocation used by multiple contexts",
1337b9c1b51eSKate Stone                     __FUNCTION__);
1338e09c44b6SAidan Dodds       }
1339f4786785SAidan Dodds       alloc->context = addr_t(args[eRsContext]);
1340e09c44b6SAidan Dodds     }
1341e09c44b6SAidan Dodds   }
1342e09c44b6SAidan Dodds 
1343e09c44b6SAidan Dodds   // make sure we track this script object
1344b9c1b51eSKate Stone   if (lldb_private::RenderScriptRuntime::ScriptDetails *script =
1345b9c1b51eSKate Stone           LookUpScript(addr_t(args[eRsScript]), true)) {
1346b9c1b51eSKate Stone     if (log) {
1347b9c1b51eSKate Stone       if (script->context.isValid() &&
1348b9c1b51eSKate Stone           *script->context.get() != addr_t(args[eRsContext]))
134963e5fb76SJonas Devlieghere         LLDB_LOGF(log, "%s - Script used by multiple contexts", __FUNCTION__);
1350e09c44b6SAidan Dodds     }
1351f4786785SAidan Dodds     script->context = addr_t(args[eRsContext]);
1352e09c44b6SAidan Dodds   }
1353e09c44b6SAidan Dodds }
1354e09c44b6SAidan Dodds 
135580af0b9eSLuke Drummond void RenderScriptRuntime::CaptureSetGlobalVar(RuntimeHook *hook,
1356b9c1b51eSKate Stone                                               ExecutionContext &context) {
1357*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
13584640cde1SColin Riley 
1359b9c1b51eSKate Stone   enum {
1360f4786785SAidan Dodds     eRsContext,
1361f4786785SAidan Dodds     eRsScript,
1362f4786785SAidan Dodds     eRsId,
1363f4786785SAidan Dodds     eRsData,
1364f4786785SAidan Dodds     eRsLength,
1365f4786785SAidan Dodds   };
13664640cde1SColin Riley 
13671ee07253SSaleem Abdulrasool   std::array<ArgItem, 5> args{{
1368f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsContext
1369f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsScript
1370f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // eRsId
1371f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsData
1372f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // eRsLength
13731ee07253SSaleem Abdulrasool   }};
13744640cde1SColin Riley 
1375f4786785SAidan Dodds   bool success = GetArgs(context, &args[0], args.size());
1376b9c1b51eSKate Stone   if (!success) {
137763e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error reading the function parameters.", __FUNCTION__);
137882780287SAidan Dodds     return;
137982780287SAidan Dodds   }
13804640cde1SColin Riley 
1381b9c1b51eSKate Stone   if (log) {
138263e5fb76SJonas Devlieghere     LLDB_LOGF(log,
138363e5fb76SJonas Devlieghere               "%s - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64
1384b9c1b51eSKate Stone               ":%" PRIu64 "bytes.",
1385b9c1b51eSKate Stone               __FUNCTION__, uint64_t(args[eRsContext]),
1386b9c1b51eSKate Stone               uint64_t(args[eRsScript]), uint64_t(args[eRsId]),
1387f4786785SAidan Dodds               uint64_t(args[eRsData]), uint64_t(args[eRsLength]));
13884640cde1SColin Riley 
1389f4786785SAidan Dodds     addr_t script_addr = addr_t(args[eRsScript]);
1390b9c1b51eSKate Stone     if (m_scriptMappings.find(script_addr) != m_scriptMappings.end()) {
13914640cde1SColin Riley       auto rsm = m_scriptMappings[script_addr];
1392b9c1b51eSKate Stone       if (uint64_t(args[eRsId]) < rsm->m_globals.size()) {
1393f4786785SAidan Dodds         auto rsg = rsm->m_globals[uint64_t(args[eRsId])];
139463e5fb76SJonas Devlieghere         LLDB_LOGF(log, "%s - Setting of '%s' within '%s' inferred",
139563e5fb76SJonas Devlieghere                   __FUNCTION__, rsg.m_name.AsCString(),
1396f4786785SAidan Dodds                   rsm->m_module->GetFileSpec().GetFilename().AsCString());
13974640cde1SColin Riley       }
13984640cde1SColin Riley     }
13994640cde1SColin Riley   }
14004640cde1SColin Riley }
14014640cde1SColin Riley 
140280af0b9eSLuke Drummond void RenderScriptRuntime::CaptureAllocationInit(RuntimeHook *hook,
140380af0b9eSLuke Drummond                                                 ExecutionContext &exe_ctx) {
1404*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
14054640cde1SColin Riley 
1406b9c1b51eSKate Stone   enum { eRsContext, eRsAlloc, eRsForceZero };
14074640cde1SColin Riley 
14081ee07253SSaleem Abdulrasool   std::array<ArgItem, 3> args{{
1409f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsContext
1410f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsAlloc
1411f4786785SAidan Dodds       ArgItem{ArgItem::eBool, 0},    // eRsForceZero
14121ee07253SSaleem Abdulrasool   }};
14134640cde1SColin Riley 
141480af0b9eSLuke Drummond   bool success = GetArgs(exe_ctx, &args[0], args.size());
141580af0b9eSLuke Drummond   if (!success) {
141663e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error while reading the function parameters",
1417b9c1b51eSKate Stone               __FUNCTION__);
141880af0b9eSLuke Drummond     return;
141982780287SAidan Dodds   }
14204640cde1SColin Riley 
142163e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .",
142263e5fb76SJonas Devlieghere             __FUNCTION__, uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc]),
142363e5fb76SJonas Devlieghere             uint64_t(args[eRsForceZero]));
142478f339d1SEwan Crawford 
14255d057637SLuke Drummond   AllocationDetails *alloc = CreateAllocation(uint64_t(args[eRsAlloc]));
142678f339d1SEwan Crawford   if (alloc)
1427f4786785SAidan Dodds     alloc->context = uint64_t(args[eRsContext]);
14284640cde1SColin Riley }
14294640cde1SColin Riley 
143080af0b9eSLuke Drummond void RenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook *hook,
143180af0b9eSLuke Drummond                                                    ExecutionContext &exe_ctx) {
1432*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
1433e69df382SEwan Crawford 
1434b9c1b51eSKate Stone   enum {
1435f4786785SAidan Dodds     eRsContext,
1436f4786785SAidan Dodds     eRsAlloc,
1437f4786785SAidan Dodds   };
1438e69df382SEwan Crawford 
14391ee07253SSaleem Abdulrasool   std::array<ArgItem, 2> args{{
1440f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsContext
1441f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsAlloc
14421ee07253SSaleem Abdulrasool   }};
1443f4786785SAidan Dodds 
144480af0b9eSLuke Drummond   bool success = GetArgs(exe_ctx, &args[0], args.size());
1445b9c1b51eSKate Stone   if (!success) {
144663e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error while reading the function parameters.",
1447b9c1b51eSKate Stone               __FUNCTION__);
1448b3f7f69dSAidan Dodds     return;
1449e69df382SEwan Crawford   }
1450e69df382SEwan Crawford 
145163e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - 0x%" PRIx64 ", 0x%" PRIx64 ".", __FUNCTION__,
1452b9c1b51eSKate Stone             uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc]));
1453e69df382SEwan Crawford 
1454b9c1b51eSKate Stone   for (auto iter = m_allocations.begin(); iter != m_allocations.end(); ++iter) {
1455d5b44036SJonas Devlieghere     auto &allocation_up = *iter; // get the unique pointer
1456d5b44036SJonas Devlieghere     if (allocation_up->address.isValid() &&
1457d5b44036SJonas Devlieghere         *allocation_up->address.get() == addr_t(args[eRsAlloc])) {
1458e69df382SEwan Crawford       m_allocations.erase(iter);
145963e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - deleted allocation entry.", __FUNCTION__);
1460e69df382SEwan Crawford       return;
1461e69df382SEwan Crawford     }
1462e69df382SEwan Crawford   }
1463e69df382SEwan Crawford 
146463e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - couldn't find destroyed allocation.", __FUNCTION__);
1465e69df382SEwan Crawford }
1466e69df382SEwan Crawford 
146780af0b9eSLuke Drummond void RenderScriptRuntime::CaptureScriptInit(RuntimeHook *hook,
146880af0b9eSLuke Drummond                                             ExecutionContext &exe_ctx) {
1469*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
14704640cde1SColin Riley 
147197206d57SZachary Turner   Status err;
147280af0b9eSLuke Drummond   Process *process = exe_ctx.GetProcessPtr();
14734640cde1SColin Riley 
1474b9c1b51eSKate Stone   enum { eRsContext, eRsScript, eRsResNamePtr, eRsCachedDirPtr };
14754640cde1SColin Riley 
1476b9c1b51eSKate Stone   std::array<ArgItem, 4> args{
1477b9c1b51eSKate Stone       {ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0},
14781ee07253SSaleem Abdulrasool        ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}}};
147980af0b9eSLuke Drummond   bool success = GetArgs(exe_ctx, &args[0], args.size());
1480b9c1b51eSKate Stone   if (!success) {
148163e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error while reading the function parameters.",
1482b9c1b51eSKate Stone               __FUNCTION__);
148382780287SAidan Dodds     return;
148482780287SAidan Dodds   }
148582780287SAidan Dodds 
148680af0b9eSLuke Drummond   std::string res_name;
148780af0b9eSLuke Drummond   process->ReadCStringFromMemory(addr_t(args[eRsResNamePtr]), res_name, err);
148880af0b9eSLuke Drummond   if (err.Fail()) {
148963e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error reading res_name: %s.", __FUNCTION__,
149080af0b9eSLuke Drummond               err.AsCString());
14914640cde1SColin Riley   }
14924640cde1SColin Riley 
149380af0b9eSLuke Drummond   std::string cache_dir;
149480af0b9eSLuke Drummond   process->ReadCStringFromMemory(addr_t(args[eRsCachedDirPtr]), cache_dir, err);
149580af0b9eSLuke Drummond   if (err.Fail()) {
149663e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error reading cache_dir: %s.", __FUNCTION__,
149780af0b9eSLuke Drummond               err.AsCString());
14984640cde1SColin Riley   }
14994640cde1SColin Riley 
150063e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .",
150163e5fb76SJonas Devlieghere             __FUNCTION__, uint64_t(args[eRsContext]), uint64_t(args[eRsScript]),
150263e5fb76SJonas Devlieghere             res_name.c_str(), cache_dir.c_str());
15034640cde1SColin Riley 
150480af0b9eSLuke Drummond   if (res_name.size() > 0) {
15054640cde1SColin Riley     StreamString strm;
150680af0b9eSLuke Drummond     strm.Printf("librs.%s.so", res_name.c_str());
15074640cde1SColin Riley 
1508f4786785SAidan Dodds     ScriptDetails *script = LookUpScript(addr_t(args[eRsScript]), true);
1509b9c1b51eSKate Stone     if (script) {
151078f339d1SEwan Crawford       script->type = ScriptDetails::eScriptC;
151180af0b9eSLuke Drummond       script->cache_dir = cache_dir;
151280af0b9eSLuke Drummond       script->res_name = res_name;
1513adcd0268SBenjamin Kramer       script->shared_lib = std::string(strm.GetString());
1514f4786785SAidan Dodds       script->context = addr_t(args[eRsContext]);
151578f339d1SEwan Crawford     }
15164640cde1SColin Riley 
151763e5fb76SJonas Devlieghere     LLDB_LOGF(log,
151863e5fb76SJonas Devlieghere               "%s - '%s' tagged with context 0x%" PRIx64
1519b9c1b51eSKate Stone               " and script 0x%" PRIx64 ".",
1520b9c1b51eSKate Stone               __FUNCTION__, strm.GetData(), uint64_t(args[eRsContext]),
1521b9c1b51eSKate Stone               uint64_t(args[eRsScript]));
1522b9c1b51eSKate Stone   } else if (log) {
152363e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - resource name invalid, Script not tagged.",
152463e5fb76SJonas Devlieghere               __FUNCTION__);
15254640cde1SColin Riley   }
15264640cde1SColin Riley }
15274640cde1SColin Riley 
1528b9c1b51eSKate Stone void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module,
1529b9c1b51eSKate Stone                                            ModuleKind kind) {
1530*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
15314640cde1SColin Riley 
1532b9c1b51eSKate Stone   if (!module) {
15334640cde1SColin Riley     return;
15344640cde1SColin Riley   }
15354640cde1SColin Riley 
153682780287SAidan Dodds   Target &target = GetProcess()->GetTarget();
153721fed052SAidan Dodds   const llvm::Triple::ArchType machine = target.GetArchitecture().GetMachine();
153882780287SAidan Dodds 
153980af0b9eSLuke Drummond   if (machine != llvm::Triple::ArchType::x86 &&
154080af0b9eSLuke Drummond       machine != llvm::Triple::ArchType::arm &&
154180af0b9eSLuke Drummond       machine != llvm::Triple::ArchType::aarch64 &&
154280af0b9eSLuke Drummond       machine != llvm::Triple::ArchType::mipsel &&
154380af0b9eSLuke Drummond       machine != llvm::Triple::ArchType::mips64el &&
154480af0b9eSLuke Drummond       machine != llvm::Triple::ArchType::x86_64) {
154563e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - unable to hook runtime functions.", __FUNCTION__);
15464640cde1SColin Riley     return;
15474640cde1SColin Riley   }
15484640cde1SColin Riley 
154921fed052SAidan Dodds   const uint32_t target_ptr_size =
155021fed052SAidan Dodds       target.GetArchitecture().GetAddressByteSize();
155121fed052SAidan Dodds 
155221fed052SAidan Dodds   std::array<bool, s_runtimeHookCount> hook_placed;
155321fed052SAidan Dodds   hook_placed.fill(false);
15544640cde1SColin Riley 
1555b9c1b51eSKate Stone   for (size_t idx = 0; idx < s_runtimeHookCount; idx++) {
15564640cde1SColin Riley     const HookDefn *hook_defn = &s_runtimeHookDefns[idx];
1557b9c1b51eSKate Stone     if (hook_defn->kind != kind) {
15584640cde1SColin Riley       continue;
15594640cde1SColin Riley     }
15604640cde1SColin Riley 
156180af0b9eSLuke Drummond     const char *symbol_name = (target_ptr_size == 4)
156280af0b9eSLuke Drummond                                   ? hook_defn->symbol_name_m32
1563b9c1b51eSKate Stone                                   : hook_defn->symbol_name_m64;
156482780287SAidan Dodds 
1565b9c1b51eSKate Stone     const Symbol *sym = module->FindFirstSymbolWithNameAndType(
1566b9c1b51eSKate Stone         ConstString(symbol_name), eSymbolTypeCode);
1567b9c1b51eSKate Stone     if (!sym) {
1568b9c1b51eSKate Stone       if (log) {
156963e5fb76SJonas Devlieghere         LLDB_LOGF(log, "%s - symbol '%s' related to the function %s not found",
1570b3f7f69dSAidan Dodds                   __FUNCTION__, symbol_name, hook_defn->name);
157182780287SAidan Dodds       }
157282780287SAidan Dodds       continue;
157382780287SAidan Dodds     }
15744640cde1SColin Riley 
1575358cf1eaSGreg Clayton     addr_t addr = sym->GetLoadAddress(&target);
1576b9c1b51eSKate Stone     if (addr == LLDB_INVALID_ADDRESS) {
157763e5fb76SJonas Devlieghere       LLDB_LOGF(log,
157863e5fb76SJonas Devlieghere                 "%s - unable to resolve the address of hook function '%s' "
1579b9c1b51eSKate Stone                 "with symbol '%s'.",
1580b3f7f69dSAidan Dodds                 __FUNCTION__, hook_defn->name, symbol_name);
15814640cde1SColin Riley       continue;
1582b9c1b51eSKate Stone     } else {
158363e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - function %s, address resolved at 0x%" PRIx64,
1584b3f7f69dSAidan Dodds                 __FUNCTION__, hook_defn->name, addr);
158582780287SAidan Dodds     }
15864640cde1SColin Riley 
15874640cde1SColin Riley     RuntimeHookSP hook(new RuntimeHook());
15884640cde1SColin Riley     hook->address = addr;
15894640cde1SColin Riley     hook->defn = hook_defn;
15904640cde1SColin Riley     hook->bp_sp = target.CreateBreakpoint(addr, true, false);
15914640cde1SColin Riley     hook->bp_sp->SetCallback(HookCallback, hook.get(), true);
15924640cde1SColin Riley     m_runtimeHooks[addr] = hook;
1593b9c1b51eSKate Stone     if (log) {
159463e5fb76SJonas Devlieghere       LLDB_LOGF(log,
159563e5fb76SJonas Devlieghere                 "%s - successfully hooked '%s' in '%s' version %" PRIu64
1596b9c1b51eSKate Stone                 " at 0x%" PRIx64 ".",
1597b9c1b51eSKate Stone                 __FUNCTION__, hook_defn->name,
1598b9c1b51eSKate Stone                 module->GetFileSpec().GetFilename().AsCString(),
1599b3f7f69dSAidan Dodds                 (uint64_t)hook_defn->version, (uint64_t)addr);
16004640cde1SColin Riley     }
160121fed052SAidan Dodds     hook_placed[idx] = true;
160221fed052SAidan Dodds   }
160321fed052SAidan Dodds 
160421fed052SAidan Dodds   // log any unhooked function
160521fed052SAidan Dodds   if (log) {
160621fed052SAidan Dodds     for (size_t i = 0; i < hook_placed.size(); ++i) {
160721fed052SAidan Dodds       if (hook_placed[i])
160821fed052SAidan Dodds         continue;
160921fed052SAidan Dodds       const HookDefn &hook_defn = s_runtimeHookDefns[i];
161021fed052SAidan Dodds       if (hook_defn.kind != kind)
161121fed052SAidan Dodds         continue;
161263e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - function %s was not hooked", __FUNCTION__,
161321fed052SAidan Dodds                 hook_defn.name);
161421fed052SAidan Dodds     }
16154640cde1SColin Riley   }
16164640cde1SColin Riley }
16174640cde1SColin Riley 
1618b9c1b51eSKate Stone void RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp) {
16194640cde1SColin Riley   if (!rsmodule_sp)
16204640cde1SColin Riley     return;
16214640cde1SColin Riley 
1622*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
16234640cde1SColin Riley 
16244640cde1SColin Riley   const ModuleSP module = rsmodule_sp->m_module;
16254640cde1SColin Riley   const FileSpec &file = module->GetPlatformFileSpec();
16264640cde1SColin Riley 
162705097246SAdrian Prantl   // Iterate over all of the scripts that we currently know of. Note: We cant
162805097246SAdrian Prantl   // push or pop to m_scripts here or it may invalidate rs_script.
1629b9c1b51eSKate Stone   for (const auto &rs_script : m_scripts) {
163078f339d1SEwan Crawford     // Extract the expected .so file path for this script.
163180af0b9eSLuke Drummond     std::string shared_lib;
163280af0b9eSLuke Drummond     if (!rs_script->shared_lib.get(shared_lib))
163378f339d1SEwan Crawford       continue;
163478f339d1SEwan Crawford 
163578f339d1SEwan Crawford     // Only proceed if the module that has loaded corresponds to this script.
163680af0b9eSLuke Drummond     if (file.GetFilename() != ConstString(shared_lib.c_str()))
163778f339d1SEwan Crawford       continue;
163878f339d1SEwan Crawford 
163978f339d1SEwan Crawford     // Obtain the script address which we use as a key.
164078f339d1SEwan Crawford     lldb::addr_t script;
164178f339d1SEwan Crawford     if (!rs_script->script.get(script))
164278f339d1SEwan Crawford       continue;
164378f339d1SEwan Crawford 
164478f339d1SEwan Crawford     // If we have a script mapping for the current script.
1645b9c1b51eSKate Stone     if (m_scriptMappings.find(script) != m_scriptMappings.end()) {
164678f339d1SEwan Crawford       // if the module we have stored is different to the one we just received.
1647b9c1b51eSKate Stone       if (m_scriptMappings[script] != rsmodule_sp) {
164863e5fb76SJonas Devlieghere         LLDB_LOGF(
164963e5fb76SJonas Devlieghere             log,
1650b9c1b51eSKate Stone             "%s - script %" PRIx64 " wants reassigned to new rsmodule '%s'.",
1651b9c1b51eSKate Stone             __FUNCTION__, (uint64_t)script,
1652b9c1b51eSKate Stone             rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
16534640cde1SColin Riley       }
16544640cde1SColin Riley     }
165578f339d1SEwan Crawford     // We don't have a script mapping for the current script.
1656b9c1b51eSKate Stone     else {
165778f339d1SEwan Crawford       // Obtain the script resource name.
165880af0b9eSLuke Drummond       std::string res_name;
165980af0b9eSLuke Drummond       if (rs_script->res_name.get(res_name))
166078f339d1SEwan Crawford         // Set the modules resource name.
166180af0b9eSLuke Drummond         rsmodule_sp->m_resname = res_name;
166278f339d1SEwan Crawford       // Add Script/Module pair to map.
166378f339d1SEwan Crawford       m_scriptMappings[script] = rsmodule_sp;
166463e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - script %" PRIx64 " associated with rsmodule '%s'.",
1665b9c1b51eSKate Stone                 __FUNCTION__, (uint64_t)script,
1666b9c1b51eSKate Stone                 rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
16674640cde1SColin Riley     }
16684640cde1SColin Riley   }
16694640cde1SColin Riley }
16704640cde1SColin Riley 
1671b9c1b51eSKate Stone // Uses the Target API to evaluate the expression passed as a parameter to the
167280af0b9eSLuke Drummond // function The result of that expression is returned an unsigned 64 bit int,
167380af0b9eSLuke Drummond // via the result* parameter. Function returns true on success, and false on
167480af0b9eSLuke Drummond // failure
167580af0b9eSLuke Drummond bool RenderScriptRuntime::EvalRSExpression(const char *expr,
1676b9c1b51eSKate Stone                                            StackFrame *frame_ptr,
1677b9c1b51eSKate Stone                                            uint64_t *result) {
1678*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
167963e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s(%s)", __FUNCTION__, expr);
168015f2bd95SEwan Crawford 
168115f2bd95SEwan Crawford   ValueObjectSP expr_result;
16828433fdbeSAidan Dodds   EvaluateExpressionOptions options;
16838433fdbeSAidan Dodds   options.SetLanguage(lldb::eLanguageTypeC_plus_plus);
168415f2bd95SEwan Crawford   // Perform the actual expression evaluation
168580af0b9eSLuke Drummond   auto &target = GetProcess()->GetTarget();
168680af0b9eSLuke Drummond   target.EvaluateExpression(expr, frame_ptr, expr_result, options);
168715f2bd95SEwan Crawford 
1688b9c1b51eSKate Stone   if (!expr_result) {
168963e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s: couldn't evaluate expression.", __FUNCTION__);
169015f2bd95SEwan Crawford     return false;
169115f2bd95SEwan Crawford   }
169215f2bd95SEwan Crawford 
169315f2bd95SEwan Crawford   // The result of the expression is invalid
1694b9c1b51eSKate Stone   if (!expr_result->GetError().Success()) {
169597206d57SZachary Turner     Status err = expr_result->GetError();
169680af0b9eSLuke Drummond     // Expression returned is void, so this is actually a success
1697a35912daSKrasimir Georgiev     if (err.GetError() == UserExpression::kNoResult) {
169863e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - expression returned void.", __FUNCTION__);
169915f2bd95SEwan Crawford 
170015f2bd95SEwan Crawford       result = nullptr;
170115f2bd95SEwan Crawford       return true;
170215f2bd95SEwan Crawford     }
170315f2bd95SEwan Crawford 
170463e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error evaluating expression result: %s", __FUNCTION__,
1705b3f7f69dSAidan Dodds               err.AsCString());
170615f2bd95SEwan Crawford     return false;
170715f2bd95SEwan Crawford   }
170815f2bd95SEwan Crawford 
170915f2bd95SEwan Crawford   bool success = false;
171080af0b9eSLuke Drummond   // We only read the result as an uint32_t.
171180af0b9eSLuke Drummond   *result = expr_result->GetValueAsUnsigned(0, &success);
171215f2bd95SEwan Crawford 
1713b9c1b51eSKate Stone   if (!success) {
171463e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - couldn't convert expression result to uint32_t",
1715b9c1b51eSKate Stone               __FUNCTION__);
171615f2bd95SEwan Crawford     return false;
171715f2bd95SEwan Crawford   }
171815f2bd95SEwan Crawford 
171915f2bd95SEwan Crawford   return true;
172015f2bd95SEwan Crawford }
172115f2bd95SEwan Crawford 
1722b9c1b51eSKate Stone namespace {
1723836d9651SEwan Crawford // Used to index expression format strings
1724b9c1b51eSKate Stone enum ExpressionStrings {
1725836d9651SEwan Crawford   eExprGetOffsetPtr = 0,
1726836d9651SEwan Crawford   eExprAllocGetType,
1727836d9651SEwan Crawford   eExprTypeDimX,
1728836d9651SEwan Crawford   eExprTypeDimY,
1729836d9651SEwan Crawford   eExprTypeDimZ,
1730836d9651SEwan Crawford   eExprTypeElemPtr,
1731836d9651SEwan Crawford   eExprElementType,
1732836d9651SEwan Crawford   eExprElementKind,
1733836d9651SEwan Crawford   eExprElementVec,
1734836d9651SEwan Crawford   eExprElementFieldCount,
1735836d9651SEwan Crawford   eExprSubelementsId,
1736836d9651SEwan Crawford   eExprSubelementsName,
1737ea0636b5SEwan Crawford   eExprSubelementsArrSize,
1738ea0636b5SEwan Crawford 
173980af0b9eSLuke Drummond   _eExprLast // keep at the end, implicit size of the array runtime_expressions
1740836d9651SEwan Crawford };
174115f2bd95SEwan Crawford 
1742ea0636b5SEwan Crawford // max length of an expanded expression
1743ea0636b5SEwan Crawford const int jit_max_expr_size = 512;
1744ea0636b5SEwan Crawford 
1745ea0636b5SEwan Crawford // Retrieve the string to JIT for the given expression
174636d783ebSDavid Gross #define JIT_TEMPLATE_CONTEXT "void* ctxt = (void*)rsDebugGetContextWrapper(0x%" PRIx64 "); "
1747b9c1b51eSKate Stone const char *JITTemplate(ExpressionStrings e) {
1748ea0636b5SEwan Crawford   // Format strings containing the expressions we may need to evaluate.
174980af0b9eSLuke Drummond   static std::array<const char *, _eExprLast> runtime_expressions = {
1750b9c1b51eSKate Stone       {// Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap)
1751b9c1b51eSKate Stone        "(int*)_"
1752b9c1b51eSKate Stone        "Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocation"
1753b9c1b51eSKate Stone        "CubemapFace"
175436d783ebSDavid Gross        "(0x%" PRIx64 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", 0, 0)", // eExprGetOffsetPtr
175515f2bd95SEwan Crawford 
175615f2bd95SEwan Crawford        // Type* rsaAllocationGetType(Context*, Allocation*)
175736d783ebSDavid Gross        JIT_TEMPLATE_CONTEXT "(void*)rsaAllocationGetType(ctxt, 0x%" PRIx64 ")", // eExprAllocGetType
175815f2bd95SEwan Crawford 
175980af0b9eSLuke Drummond        // rsaTypeGetNativeData(Context*, Type*, void* typeData, size) Pack the
176080af0b9eSLuke Drummond        // data in the following way mHal.state.dimX; mHal.state.dimY;
176105097246SAdrian Prantl        // mHal.state.dimZ; mHal.state.lodCount; mHal.state.faces; mElement;
176205097246SAdrian Prantl        // into typeData Need to specify 32 or 64 bit for uint_t since this
176305097246SAdrian Prantl        // differs between devices
176436d783ebSDavid Gross        JIT_TEMPLATE_CONTEXT
176536d783ebSDavid Gross        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
176636d783ebSDavid Gross        ", 0x%" PRIx64 ", data, 6); data[0]", // eExprTypeDimX
176736d783ebSDavid Gross        JIT_TEMPLATE_CONTEXT
176836d783ebSDavid Gross        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
176936d783ebSDavid Gross        ", 0x%" PRIx64 ", data, 6); data[1]", // eExprTypeDimY
177036d783ebSDavid Gross        JIT_TEMPLATE_CONTEXT
177136d783ebSDavid Gross        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
177236d783ebSDavid Gross        ", 0x%" PRIx64 ", data, 6); data[2]", // eExprTypeDimZ
177336d783ebSDavid Gross        JIT_TEMPLATE_CONTEXT
177436d783ebSDavid Gross        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
177536d783ebSDavid Gross        ", 0x%" PRIx64 ", data, 6); data[5]", // eExprTypeElemPtr
177615f2bd95SEwan Crawford 
177715f2bd95SEwan Crawford        // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size)
1778b9c1b51eSKate Stone        // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into
1779b9c1b51eSKate Stone        // elemData
178036d783ebSDavid Gross        JIT_TEMPLATE_CONTEXT
178136d783ebSDavid Gross        "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
178236d783ebSDavid Gross        ", 0x%" PRIx64 ", data, 5); data[0]", // eExprElementType
178336d783ebSDavid Gross        JIT_TEMPLATE_CONTEXT
178436d783ebSDavid Gross        "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
178536d783ebSDavid Gross        ", 0x%" PRIx64 ", data, 5); data[1]", // eExprElementKind
178636d783ebSDavid Gross        JIT_TEMPLATE_CONTEXT
178736d783ebSDavid Gross        "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
178836d783ebSDavid Gross        ", 0x%" PRIx64 ", data, 5); data[3]", // eExprElementVec
178936d783ebSDavid Gross        JIT_TEMPLATE_CONTEXT
179036d783ebSDavid Gross        "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
179136d783ebSDavid Gross        ", 0x%" PRIx64 ", data, 5); data[4]", // eExprElementFieldCount
17928b244e21SEwan Crawford 
1793b9c1b51eSKate Stone        // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t
179480af0b9eSLuke Drummond        // *ids, const char **names, size_t *arraySizes, uint32_t dataSize)
1795b9c1b51eSKate Stone        // Needed for Allocations of structs to gather details about
179680af0b9eSLuke Drummond        // fields/Subelements Element* of field
179736d783ebSDavid Gross        JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
1798b9c1b51eSKate Stone        "]; size_t arr_size[%" PRIu32 "];"
179936d783ebSDavid Gross        "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64
180036d783ebSDavid Gross        ", ids, names, arr_size, %" PRIu32 "); ids[%" PRIu32 "]", // eExprSubelementsId
18018b244e21SEwan Crawford 
1802577570b4SAidan Dodds        // Name of field
180336d783ebSDavid Gross        JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
1804b9c1b51eSKate Stone        "]; size_t arr_size[%" PRIu32 "];"
180536d783ebSDavid Gross        "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64
180636d783ebSDavid Gross        ", ids, names, arr_size, %" PRIu32 "); names[%" PRIu32 "]", // eExprSubelementsName
18078b244e21SEwan Crawford 
1808577570b4SAidan Dodds        // Array size of field
180936d783ebSDavid Gross        JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
1810b9c1b51eSKate Stone        "]; size_t arr_size[%" PRIu32 "];"
181136d783ebSDavid Gross        "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64
181236d783ebSDavid Gross        ", ids, names, arr_size, %" PRIu32 "); arr_size[%" PRIu32 "]"}}; // eExprSubelementsArrSize
1813ea0636b5SEwan Crawford 
181480af0b9eSLuke Drummond   return runtime_expressions[e];
1815ea0636b5SEwan Crawford }
1816ea0636b5SEwan Crawford } // end of the anonymous namespace
1817ea0636b5SEwan Crawford 
181805097246SAdrian Prantl // JITs the RS runtime for the internal data pointer of an allocation. Is
181905097246SAdrian Prantl // passed x,y,z coordinates for the pointer to a specific element. Then sets
182005097246SAdrian Prantl // the data_ptr member in Allocation with the result. Returns true on success,
182105097246SAdrian Prantl // false otherwise
182280af0b9eSLuke Drummond bool RenderScriptRuntime::JITDataPointer(AllocationDetails *alloc,
1823b9c1b51eSKate Stone                                          StackFrame *frame_ptr, uint32_t x,
1824b9c1b51eSKate Stone                                          uint32_t y, uint32_t z) {
1825*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
182615f2bd95SEwan Crawford 
182780af0b9eSLuke Drummond   if (!alloc->address.isValid()) {
182863e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
182915f2bd95SEwan Crawford     return false;
183015f2bd95SEwan Crawford   }
183115f2bd95SEwan Crawford 
183280af0b9eSLuke Drummond   const char *fmt_str = JITTemplate(eExprGetOffsetPtr);
183380af0b9eSLuke Drummond   char expr_buf[jit_max_expr_size];
183415f2bd95SEwan Crawford 
183580af0b9eSLuke Drummond   int written = snprintf(expr_buf, jit_max_expr_size, fmt_str,
183680af0b9eSLuke Drummond                          *alloc->address.get(), x, y, z);
183780af0b9eSLuke Drummond   if (written < 0) {
183863e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
183915f2bd95SEwan Crawford     return false;
184080af0b9eSLuke Drummond   } else if (written >= jit_max_expr_size) {
184163e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
184215f2bd95SEwan Crawford     return false;
184315f2bd95SEwan Crawford   }
184415f2bd95SEwan Crawford 
184515f2bd95SEwan Crawford   uint64_t result = 0;
184680af0b9eSLuke Drummond   if (!EvalRSExpression(expr_buf, frame_ptr, &result))
184715f2bd95SEwan Crawford     return false;
184815f2bd95SEwan Crawford 
184980af0b9eSLuke Drummond   addr_t data_ptr = static_cast<lldb::addr_t>(result);
185080af0b9eSLuke Drummond   alloc->data_ptr = data_ptr;
185115f2bd95SEwan Crawford 
185215f2bd95SEwan Crawford   return true;
185315f2bd95SEwan Crawford }
185415f2bd95SEwan Crawford 
185515f2bd95SEwan Crawford // JITs the RS runtime for the internal pointer to the RS Type of an allocation
185680af0b9eSLuke Drummond // Then sets the type_ptr member in Allocation with the result. Returns true on
185780af0b9eSLuke Drummond // success, false otherwise
185880af0b9eSLuke Drummond bool RenderScriptRuntime::JITTypePointer(AllocationDetails *alloc,
1859b9c1b51eSKate Stone                                          StackFrame *frame_ptr) {
1860*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
186115f2bd95SEwan Crawford 
186280af0b9eSLuke Drummond   if (!alloc->address.isValid() || !alloc->context.isValid()) {
186363e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
186415f2bd95SEwan Crawford     return false;
186515f2bd95SEwan Crawford   }
186615f2bd95SEwan Crawford 
186780af0b9eSLuke Drummond   const char *fmt_str = JITTemplate(eExprAllocGetType);
186880af0b9eSLuke Drummond   char expr_buf[jit_max_expr_size];
186915f2bd95SEwan Crawford 
187080af0b9eSLuke Drummond   int written = snprintf(expr_buf, jit_max_expr_size, fmt_str,
187180af0b9eSLuke Drummond                          *alloc->context.get(), *alloc->address.get());
187280af0b9eSLuke Drummond   if (written < 0) {
187363e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
187415f2bd95SEwan Crawford     return false;
187580af0b9eSLuke Drummond   } else if (written >= jit_max_expr_size) {
187663e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
187715f2bd95SEwan Crawford     return false;
187815f2bd95SEwan Crawford   }
187915f2bd95SEwan Crawford 
188015f2bd95SEwan Crawford   uint64_t result = 0;
188180af0b9eSLuke Drummond   if (!EvalRSExpression(expr_buf, frame_ptr, &result))
188215f2bd95SEwan Crawford     return false;
188315f2bd95SEwan Crawford 
188415f2bd95SEwan Crawford   addr_t type_ptr = static_cast<lldb::addr_t>(result);
188580af0b9eSLuke Drummond   alloc->type_ptr = type_ptr;
188615f2bd95SEwan Crawford 
188715f2bd95SEwan Crawford   return true;
188815f2bd95SEwan Crawford }
188915f2bd95SEwan Crawford 
1890b9c1b51eSKate Stone // JITs the RS runtime for information about the dimensions and type of an
189105097246SAdrian Prantl // allocation Then sets dimension and element_ptr members in Allocation with
189205097246SAdrian Prantl // the result. Returns true on success, false otherwise
189380af0b9eSLuke Drummond bool RenderScriptRuntime::JITTypePacked(AllocationDetails *alloc,
1894b9c1b51eSKate Stone                                         StackFrame *frame_ptr) {
1895*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
189615f2bd95SEwan Crawford 
189780af0b9eSLuke Drummond   if (!alloc->type_ptr.isValid() || !alloc->context.isValid()) {
189863e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - Failed to find allocation details.", __FUNCTION__);
189915f2bd95SEwan Crawford     return false;
190015f2bd95SEwan Crawford   }
190115f2bd95SEwan Crawford 
190215f2bd95SEwan Crawford   // Expression is different depending on if device is 32 or 64 bit
190380af0b9eSLuke Drummond   uint32_t target_ptr_size =
1904b9c1b51eSKate Stone       GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
190580af0b9eSLuke Drummond   const uint32_t bits = target_ptr_size == 4 ? 32 : 64;
190615f2bd95SEwan Crawford 
190715f2bd95SEwan Crawford   // We want 4 elements from packed data
1908b3f7f69dSAidan Dodds   const uint32_t num_exprs = 4;
19094c1d6ee8SJonas Devlieghere   static_assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1),
1910b9c1b51eSKate Stone                 "Invalid number of expressions");
191115f2bd95SEwan Crawford 
191280af0b9eSLuke Drummond   char expr_bufs[num_exprs][jit_max_expr_size];
191315f2bd95SEwan Crawford   uint64_t results[num_exprs];
191415f2bd95SEwan Crawford 
1915b9c1b51eSKate Stone   for (uint32_t i = 0; i < num_exprs; ++i) {
191680af0b9eSLuke Drummond     const char *fmt_str = JITTemplate(ExpressionStrings(eExprTypeDimX + i));
191736d783ebSDavid Gross     int written = snprintf(expr_bufs[i], jit_max_expr_size, fmt_str,
191836d783ebSDavid Gross                            *alloc->context.get(), bits, *alloc->type_ptr.get());
191980af0b9eSLuke Drummond     if (written < 0) {
192063e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
192115f2bd95SEwan Crawford       return false;
192280af0b9eSLuke Drummond     } else if (written >= jit_max_expr_size) {
192363e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
192415f2bd95SEwan Crawford       return false;
192515f2bd95SEwan Crawford     }
192615f2bd95SEwan Crawford 
192715f2bd95SEwan Crawford     // Perform expression evaluation
192880af0b9eSLuke Drummond     if (!EvalRSExpression(expr_bufs[i], frame_ptr, &results[i]))
192915f2bd95SEwan Crawford       return false;
193015f2bd95SEwan Crawford   }
193115f2bd95SEwan Crawford 
193215f2bd95SEwan Crawford   // Assign results to allocation members
193315f2bd95SEwan Crawford   AllocationDetails::Dimension dims;
193415f2bd95SEwan Crawford   dims.dim_1 = static_cast<uint32_t>(results[0]);
193515f2bd95SEwan Crawford   dims.dim_2 = static_cast<uint32_t>(results[1]);
193615f2bd95SEwan Crawford   dims.dim_3 = static_cast<uint32_t>(results[2]);
193780af0b9eSLuke Drummond   alloc->dimension = dims;
193815f2bd95SEwan Crawford 
193980af0b9eSLuke Drummond   addr_t element_ptr = static_cast<lldb::addr_t>(results[3]);
194080af0b9eSLuke Drummond   alloc->element.element_ptr = element_ptr;
194115f2bd95SEwan Crawford 
194263e5fb76SJonas Devlieghere   LLDB_LOGF(log,
194363e5fb76SJonas Devlieghere             "%s - dims (%" PRIu32 ", %" PRIu32 ", %" PRIu32
1944b9c1b51eSKate Stone             ") Element*: 0x%" PRIx64 ".",
194580af0b9eSLuke Drummond             __FUNCTION__, dims.dim_1, dims.dim_2, dims.dim_3, element_ptr);
194615f2bd95SEwan Crawford 
194715f2bd95SEwan Crawford   return true;
194815f2bd95SEwan Crawford }
194915f2bd95SEwan Crawford 
195080af0b9eSLuke Drummond // JITs the RS runtime for information about the Element of an allocation Then
195180af0b9eSLuke Drummond // sets type, type_vec_size, field_count and type_kind members in Element with
195280af0b9eSLuke Drummond // the result. Returns true on success, false otherwise
1953b9c1b51eSKate Stone bool RenderScriptRuntime::JITElementPacked(Element &elem,
1954b9c1b51eSKate Stone                                            const lldb::addr_t context,
1955b9c1b51eSKate Stone                                            StackFrame *frame_ptr) {
1956*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
195715f2bd95SEwan Crawford 
1958b9c1b51eSKate Stone   if (!elem.element_ptr.isValid()) {
195963e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
196015f2bd95SEwan Crawford     return false;
196115f2bd95SEwan Crawford   }
196215f2bd95SEwan Crawford 
19638b244e21SEwan Crawford   // We want 4 elements from packed data
1964b3f7f69dSAidan Dodds   const uint32_t num_exprs = 4;
19654c1d6ee8SJonas Devlieghere   static_assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1),
1966b9c1b51eSKate Stone                 "Invalid number of expressions");
196715f2bd95SEwan Crawford 
196880af0b9eSLuke Drummond   char expr_bufs[num_exprs][jit_max_expr_size];
196915f2bd95SEwan Crawford   uint64_t results[num_exprs];
197015f2bd95SEwan Crawford 
1971b9c1b51eSKate Stone   for (uint32_t i = 0; i < num_exprs; i++) {
197280af0b9eSLuke Drummond     const char *fmt_str = JITTemplate(ExpressionStrings(eExprElementType + i));
197380af0b9eSLuke Drummond     int written = snprintf(expr_bufs[i], jit_max_expr_size, fmt_str, context,
197480af0b9eSLuke Drummond                            *elem.element_ptr.get());
197580af0b9eSLuke Drummond     if (written < 0) {
197663e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
197715f2bd95SEwan Crawford       return false;
197880af0b9eSLuke Drummond     } else if (written >= jit_max_expr_size) {
197963e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
198015f2bd95SEwan Crawford       return false;
198115f2bd95SEwan Crawford     }
198215f2bd95SEwan Crawford 
198315f2bd95SEwan Crawford     // Perform expression evaluation
198480af0b9eSLuke Drummond     if (!EvalRSExpression(expr_bufs[i], frame_ptr, &results[i]))
198515f2bd95SEwan Crawford       return false;
198615f2bd95SEwan Crawford   }
198715f2bd95SEwan Crawford 
198815f2bd95SEwan Crawford   // Assign results to allocation members
19898b244e21SEwan Crawford   elem.type = static_cast<RenderScriptRuntime::Element::DataType>(results[0]);
1990b9c1b51eSKate Stone   elem.type_kind =
1991b9c1b51eSKate Stone       static_cast<RenderScriptRuntime::Element::DataKind>(results[1]);
19928b244e21SEwan Crawford   elem.type_vec_size = static_cast<uint32_t>(results[2]);
19938b244e21SEwan Crawford   elem.field_count = static_cast<uint32_t>(results[3]);
199415f2bd95SEwan Crawford 
199563e5fb76SJonas Devlieghere   LLDB_LOGF(log,
199663e5fb76SJonas Devlieghere             "%s - data type %" PRIu32 ", pixel type %" PRIu32
1997b9c1b51eSKate Stone             ", vector size %" PRIu32 ", field count %" PRIu32,
1998b9c1b51eSKate Stone             __FUNCTION__, *elem.type.get(), *elem.type_kind.get(),
1999b9c1b51eSKate Stone             *elem.type_vec_size.get(), *elem.field_count.get());
20008b244e21SEwan Crawford 
2001b9c1b51eSKate Stone   // If this Element has subelements then JIT rsaElementGetSubElements() for
2002b9c1b51eSKate Stone   // details about its fields
2003a6682a41SJonas Devlieghere   return !(*elem.field_count.get() > 0 &&
2004a6682a41SJonas Devlieghere            !JITSubelements(elem, context, frame_ptr));
20058b244e21SEwan Crawford }
20068b244e21SEwan Crawford 
2007b9c1b51eSKate Stone // JITs the RS runtime for information about the subelements/fields of a struct
200880af0b9eSLuke Drummond // allocation This is necessary for infering the struct type so we can pretty
200980af0b9eSLuke Drummond // print the allocation's contents. Returns true on success, false otherwise
2010b9c1b51eSKate Stone bool RenderScriptRuntime::JITSubelements(Element &elem,
2011b9c1b51eSKate Stone                                          const lldb::addr_t context,
2012b9c1b51eSKate Stone                                          StackFrame *frame_ptr) {
2013*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
20148b244e21SEwan Crawford 
2015b9c1b51eSKate Stone   if (!elem.element_ptr.isValid() || !elem.field_count.isValid()) {
201663e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
20178b244e21SEwan Crawford     return false;
20188b244e21SEwan Crawford   }
20198b244e21SEwan Crawford 
20208b244e21SEwan Crawford   const short num_exprs = 3;
20214c1d6ee8SJonas Devlieghere   static_assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1),
2022b9c1b51eSKate Stone                 "Invalid number of expressions");
20238b244e21SEwan Crawford 
2024ea0636b5SEwan Crawford   char expr_buffer[jit_max_expr_size];
20258b244e21SEwan Crawford   uint64_t results;
20268b244e21SEwan Crawford 
20278b244e21SEwan Crawford   // Iterate over struct fields.
20288b244e21SEwan Crawford   const uint32_t field_count = *elem.field_count.get();
2029b9c1b51eSKate Stone   for (uint32_t field_index = 0; field_index < field_count; ++field_index) {
20308b244e21SEwan Crawford     Element child;
2031b9c1b51eSKate Stone     for (uint32_t expr_index = 0; expr_index < num_exprs; ++expr_index) {
203280af0b9eSLuke Drummond       const char *fmt_str =
2033b9c1b51eSKate Stone           JITTemplate(ExpressionStrings(eExprSubelementsId + expr_index));
203480af0b9eSLuke Drummond       int written = snprintf(expr_buffer, jit_max_expr_size, fmt_str,
203536d783ebSDavid Gross                              context, field_count, field_count, field_count,
203680af0b9eSLuke Drummond                              *elem.element_ptr.get(), field_count, field_index);
203780af0b9eSLuke Drummond       if (written < 0) {
203863e5fb76SJonas Devlieghere         LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
20398b244e21SEwan Crawford         return false;
204080af0b9eSLuke Drummond       } else if (written >= jit_max_expr_size) {
204163e5fb76SJonas Devlieghere         LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
20428b244e21SEwan Crawford         return false;
20438b244e21SEwan Crawford       }
20448b244e21SEwan Crawford 
20458b244e21SEwan Crawford       // Perform expression evaluation
20468b244e21SEwan Crawford       if (!EvalRSExpression(expr_buffer, frame_ptr, &results))
20478b244e21SEwan Crawford         return false;
20488b244e21SEwan Crawford 
204963e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - expr result 0x%" PRIx64 ".", __FUNCTION__, results);
20508b244e21SEwan Crawford 
2051b9c1b51eSKate Stone       switch (expr_index) {
20528b244e21SEwan Crawford       case 0: // Element* of child
20538b244e21SEwan Crawford         child.element_ptr = static_cast<addr_t>(results);
20548b244e21SEwan Crawford         break;
20558b244e21SEwan Crawford       case 1: // Name of child
20568b244e21SEwan Crawford       {
20578b244e21SEwan Crawford         lldb::addr_t address = static_cast<addr_t>(results);
205897206d57SZachary Turner         Status err;
20598b244e21SEwan Crawford         std::string name;
20608b244e21SEwan Crawford         GetProcess()->ReadCStringFromMemory(address, name, err);
20618b244e21SEwan Crawford         if (!err.Fail())
20628b244e21SEwan Crawford           child.type_name = ConstString(name);
2063b9c1b51eSKate Stone         else {
206463e5fb76SJonas Devlieghere           LLDB_LOGF(log, "%s - warning: Couldn't read field name.",
2065b9c1b51eSKate Stone                     __FUNCTION__);
20668b244e21SEwan Crawford         }
20678b244e21SEwan Crawford         break;
20688b244e21SEwan Crawford       }
20698b244e21SEwan Crawford       case 2: // Array size of child
20708b244e21SEwan Crawford         child.array_size = static_cast<uint32_t>(results);
20718b244e21SEwan Crawford         break;
20728b244e21SEwan Crawford       }
20738b244e21SEwan Crawford     }
20748b244e21SEwan Crawford 
20758b244e21SEwan Crawford     // We need to recursively JIT each Element field of the struct since
20768b244e21SEwan Crawford     // structs can be nested inside structs.
20778b244e21SEwan Crawford     if (!JITElementPacked(child, context, frame_ptr))
20788b244e21SEwan Crawford       return false;
20798b244e21SEwan Crawford     elem.children.push_back(child);
20808b244e21SEwan Crawford   }
20818b244e21SEwan Crawford 
2082b9c1b51eSKate Stone   // Try to infer the name of the struct type so we can pretty print the
2083b9c1b51eSKate Stone   // allocation contents.
20848b244e21SEwan Crawford   FindStructTypeName(elem, frame_ptr);
208515f2bd95SEwan Crawford 
208615f2bd95SEwan Crawford   return true;
208715f2bd95SEwan Crawford }
208815f2bd95SEwan Crawford 
2089a0f08674SEwan Crawford // JITs the RS runtime for the address of the last element in the allocation.
2090b9c1b51eSKate Stone // The `elem_size` parameter represents the size of a single element, including
209180af0b9eSLuke Drummond // padding. Which is needed as an offset from the last element pointer. Using
209280af0b9eSLuke Drummond // this offset minus the starting address we can calculate the size of the
209380af0b9eSLuke Drummond // allocation. Returns true on success, false otherwise
209480af0b9eSLuke Drummond bool RenderScriptRuntime::JITAllocationSize(AllocationDetails *alloc,
2095b9c1b51eSKate Stone                                             StackFrame *frame_ptr) {
2096*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
2097a0f08674SEwan Crawford 
209880af0b9eSLuke Drummond   if (!alloc->address.isValid() || !alloc->dimension.isValid() ||
209980af0b9eSLuke Drummond       !alloc->data_ptr.isValid() || !alloc->element.datum_size.isValid()) {
210063e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
2101a0f08674SEwan Crawford     return false;
2102a0f08674SEwan Crawford   }
2103a0f08674SEwan Crawford 
2104a0f08674SEwan Crawford   // Find dimensions
210580af0b9eSLuke Drummond   uint32_t dim_x = alloc->dimension.get()->dim_1;
210680af0b9eSLuke Drummond   uint32_t dim_y = alloc->dimension.get()->dim_2;
210780af0b9eSLuke Drummond   uint32_t dim_z = alloc->dimension.get()->dim_3;
2108a0f08674SEwan Crawford 
2109b9c1b51eSKate Stone   // Our plan of jitting the last element address doesn't seem to work for
211080af0b9eSLuke Drummond   // struct Allocations` Instead try to infer the size ourselves without any
211180af0b9eSLuke Drummond   // inter element padding.
211280af0b9eSLuke Drummond   if (alloc->element.children.size() > 0) {
2113b9c1b51eSKate Stone     if (dim_x == 0)
2114b9c1b51eSKate Stone       dim_x = 1;
2115b9c1b51eSKate Stone     if (dim_y == 0)
2116b9c1b51eSKate Stone       dim_y = 1;
2117b9c1b51eSKate Stone     if (dim_z == 0)
2118b9c1b51eSKate Stone       dim_z = 1;
21198b244e21SEwan Crawford 
212080af0b9eSLuke Drummond     alloc->size = dim_x * dim_y * dim_z * *alloc->element.datum_size.get();
21218b244e21SEwan Crawford 
212263e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - inferred size of struct allocation %" PRIu32 ".",
212380af0b9eSLuke Drummond               __FUNCTION__, *alloc->size.get());
21248b244e21SEwan Crawford     return true;
21258b244e21SEwan Crawford   }
21268b244e21SEwan Crawford 
212780af0b9eSLuke Drummond   const char *fmt_str = JITTemplate(eExprGetOffsetPtr);
212880af0b9eSLuke Drummond   char expr_buf[jit_max_expr_size];
21298b244e21SEwan Crawford 
2130a0f08674SEwan Crawford   // Calculate last element
2131a0f08674SEwan Crawford   dim_x = dim_x == 0 ? 0 : dim_x - 1;
2132a0f08674SEwan Crawford   dim_y = dim_y == 0 ? 0 : dim_y - 1;
2133a0f08674SEwan Crawford   dim_z = dim_z == 0 ? 0 : dim_z - 1;
2134a0f08674SEwan Crawford 
213580af0b9eSLuke Drummond   int written = snprintf(expr_buf, jit_max_expr_size, fmt_str,
213680af0b9eSLuke Drummond                          *alloc->address.get(), dim_x, dim_y, dim_z);
213780af0b9eSLuke Drummond   if (written < 0) {
213863e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
2139a0f08674SEwan Crawford     return false;
214080af0b9eSLuke Drummond   } else if (written >= jit_max_expr_size) {
214163e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
2142a0f08674SEwan Crawford     return false;
2143a0f08674SEwan Crawford   }
2144a0f08674SEwan Crawford 
2145a0f08674SEwan Crawford   uint64_t result = 0;
214680af0b9eSLuke Drummond   if (!EvalRSExpression(expr_buf, frame_ptr, &result))
2147a0f08674SEwan Crawford     return false;
2148a0f08674SEwan Crawford 
2149a0f08674SEwan Crawford   addr_t mem_ptr = static_cast<lldb::addr_t>(result);
2150a0f08674SEwan Crawford   // Find pointer to last element and add on size of an element
215180af0b9eSLuke Drummond   alloc->size = static_cast<uint32_t>(mem_ptr - *alloc->data_ptr.get()) +
215280af0b9eSLuke Drummond                 *alloc->element.datum_size.get();
2153a0f08674SEwan Crawford 
2154a0f08674SEwan Crawford   return true;
2155a0f08674SEwan Crawford }
2156a0f08674SEwan Crawford 
2157b9c1b51eSKate Stone // JITs the RS runtime for information about the stride between rows in the
215805097246SAdrian Prantl // allocation. This is done to detect padding, since allocated memory is
215905097246SAdrian Prantl // 16-byte aligned. Returns true on success, false otherwise
216080af0b9eSLuke Drummond bool RenderScriptRuntime::JITAllocationStride(AllocationDetails *alloc,
2161b9c1b51eSKate Stone                                               StackFrame *frame_ptr) {
2162*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
2163a0f08674SEwan Crawford 
216480af0b9eSLuke Drummond   if (!alloc->address.isValid() || !alloc->data_ptr.isValid()) {
216563e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
2166a0f08674SEwan Crawford     return false;
2167a0f08674SEwan Crawford   }
2168a0f08674SEwan Crawford 
216980af0b9eSLuke Drummond   const char *fmt_str = JITTemplate(eExprGetOffsetPtr);
217080af0b9eSLuke Drummond   char expr_buf[jit_max_expr_size];
2171a0f08674SEwan Crawford 
217280af0b9eSLuke Drummond   int written = snprintf(expr_buf, jit_max_expr_size, fmt_str,
217380af0b9eSLuke Drummond                          *alloc->address.get(), 0, 1, 0);
217480af0b9eSLuke Drummond   if (written < 0) {
217563e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
2176a0f08674SEwan Crawford     return false;
217780af0b9eSLuke Drummond   } else if (written >= jit_max_expr_size) {
217863e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
2179a0f08674SEwan Crawford     return false;
2180a0f08674SEwan Crawford   }
2181a0f08674SEwan Crawford 
2182a0f08674SEwan Crawford   uint64_t result = 0;
218380af0b9eSLuke Drummond   if (!EvalRSExpression(expr_buf, frame_ptr, &result))
2184a0f08674SEwan Crawford     return false;
2185a0f08674SEwan Crawford 
2186a0f08674SEwan Crawford   addr_t mem_ptr = static_cast<lldb::addr_t>(result);
218780af0b9eSLuke Drummond   alloc->stride = static_cast<uint32_t>(mem_ptr - *alloc->data_ptr.get());
2188a0f08674SEwan Crawford 
2189a0f08674SEwan Crawford   return true;
2190a0f08674SEwan Crawford }
2191a0f08674SEwan Crawford 
219215f2bd95SEwan Crawford // JIT all the current runtime info regarding an allocation
219380af0b9eSLuke Drummond bool RenderScriptRuntime::RefreshAllocation(AllocationDetails *alloc,
2194b9c1b51eSKate Stone                                             StackFrame *frame_ptr) {
219515f2bd95SEwan Crawford   // GetOffsetPointer()
219680af0b9eSLuke Drummond   if (!JITDataPointer(alloc, frame_ptr))
219715f2bd95SEwan Crawford     return false;
219815f2bd95SEwan Crawford 
219915f2bd95SEwan Crawford   // rsaAllocationGetType()
220080af0b9eSLuke Drummond   if (!JITTypePointer(alloc, frame_ptr))
220115f2bd95SEwan Crawford     return false;
220215f2bd95SEwan Crawford 
220315f2bd95SEwan Crawford   // rsaTypeGetNativeData()
220480af0b9eSLuke Drummond   if (!JITTypePacked(alloc, frame_ptr))
220515f2bd95SEwan Crawford     return false;
220615f2bd95SEwan Crawford 
220715f2bd95SEwan Crawford   // rsaElementGetNativeData()
220880af0b9eSLuke Drummond   if (!JITElementPacked(alloc->element, *alloc->context.get(), frame_ptr))
220915f2bd95SEwan Crawford     return false;
221015f2bd95SEwan Crawford 
22118b244e21SEwan Crawford   // Sets the datum_size member in Element
221280af0b9eSLuke Drummond   SetElementSize(alloc->element);
22138b244e21SEwan Crawford 
221455232f09SEwan Crawford   // Use GetOffsetPointer() to infer size of the allocation
2215a6682a41SJonas Devlieghere   return JITAllocationSize(alloc, frame_ptr);
221655232f09SEwan Crawford }
221755232f09SEwan Crawford 
221836597e47SBruce Mitchener // Function attempts to set the type_name member of the parameterised Element
221905097246SAdrian Prantl // object. This string should be the name of the struct type the Element
222005097246SAdrian Prantl // represents. We need this string for pretty printing the Element to users.
2221b9c1b51eSKate Stone void RenderScriptRuntime::FindStructTypeName(Element &elem,
2222b9c1b51eSKate Stone                                              StackFrame *frame_ptr) {
2223*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
22248b244e21SEwan Crawford 
22258b244e21SEwan Crawford   if (!elem.type_name.IsEmpty()) // Name already set
22268b244e21SEwan Crawford     return;
22278b244e21SEwan Crawford   else
2228b9c1b51eSKate Stone     elem.type_name = Element::GetFallbackStructName(); // Default type name if
2229b9c1b51eSKate Stone                                                        // we don't succeed
22308b244e21SEwan Crawford 
22318b244e21SEwan Crawford   // Find all the global variables from the script rs modules
223280af0b9eSLuke Drummond   VariableList var_list;
22338b244e21SEwan Crawford   for (auto module_sp : m_rsmodules)
223495eae423SZachary Turner     module_sp->m_module->FindGlobalVariables(
223534cda14bSPavel Labath         RegularExpression(llvm::StringRef(".")), UINT32_MAX, var_list);
22368b244e21SEwan Crawford 
2237b9c1b51eSKate Stone   // Iterate over all the global variables looking for one with a matching type
223805097246SAdrian Prantl   // to the Element. We make the assumption a match exists since there needs to
223905097246SAdrian Prantl   // be a global variable to reflect the struct type back into java host code.
2240d1782133SRaphael Isemann   for (const VariableSP &var_sp : var_list) {
22418b244e21SEwan Crawford     if (!var_sp)
22428b244e21SEwan Crawford       continue;
22438b244e21SEwan Crawford 
22448b244e21SEwan Crawford     ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp);
22458b244e21SEwan Crawford     if (!valobj_sp)
22468b244e21SEwan Crawford       continue;
22478b244e21SEwan Crawford 
22488b244e21SEwan Crawford     // Find the number of variable fields.
2249b9c1b51eSKate Stone     // If it has no fields, or more fields than our Element, then it can't be
225005097246SAdrian Prantl     // the struct we're looking for. Don't check for equality since RS can add
225105097246SAdrian Prantl     // extra struct members for padding.
22528b244e21SEwan Crawford     size_t num_children = valobj_sp->GetNumChildren();
22538b244e21SEwan Crawford     if (num_children > elem.children.size() || num_children == 0)
22548b244e21SEwan Crawford       continue;
22558b244e21SEwan Crawford 
225605097246SAdrian Prantl     // Iterate over children looking for members with matching field names. If
225705097246SAdrian Prantl     // all the field names match, this is likely the struct we want.
2258b9c1b51eSKate Stone     //   TODO: This could be made more robust by also checking children data
2259b9c1b51eSKate Stone     //   sizes, or array size
22608b244e21SEwan Crawford     bool found = true;
226180af0b9eSLuke Drummond     for (size_t i = 0; i < num_children; ++i) {
226280af0b9eSLuke Drummond       ValueObjectSP child = valobj_sp->GetChildAtIndex(i, true);
226380af0b9eSLuke Drummond       if (!child || (child->GetName() != elem.children[i].type_name)) {
22648b244e21SEwan Crawford         found = false;
22658b244e21SEwan Crawford         break;
22668b244e21SEwan Crawford       }
22678b244e21SEwan Crawford     }
22688b244e21SEwan Crawford 
2269b9c1b51eSKate Stone     // RS can add extra struct members for padding in the format
2270b9c1b51eSKate Stone     // '#rs_padding_[0-9]+'
2271b9c1b51eSKate Stone     if (found && num_children < elem.children.size()) {
2272b3f7f69dSAidan Dodds       const uint32_t size_diff = elem.children.size() - num_children;
227363e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - %" PRIu32 " padding struct entries", __FUNCTION__,
2274b9c1b51eSKate Stone                 size_diff);
22758b244e21SEwan Crawford 
227680af0b9eSLuke Drummond       for (uint32_t i = 0; i < size_diff; ++i) {
22770e4c4821SAdrian Prantl         ConstString name = elem.children[num_children + i].type_name;
22788b244e21SEwan Crawford         if (strcmp(name.AsCString(), "#rs_padding") < 0)
22798b244e21SEwan Crawford           found = false;
22808b244e21SEwan Crawford       }
22818b244e21SEwan Crawford     }
22828b244e21SEwan Crawford 
228380af0b9eSLuke Drummond     // We've found a global variable with matching type
2284b9c1b51eSKate Stone     if (found) {
22858b244e21SEwan Crawford       // Dereference since our Element type isn't a pointer.
2286b9c1b51eSKate Stone       if (valobj_sp->IsPointerType()) {
228797206d57SZachary Turner         Status err;
22888b244e21SEwan Crawford         ValueObjectSP deref_valobj = valobj_sp->Dereference(err);
22898b244e21SEwan Crawford         if (!err.Fail())
22908b244e21SEwan Crawford           valobj_sp = deref_valobj;
22918b244e21SEwan Crawford       }
22928b244e21SEwan Crawford 
22938b244e21SEwan Crawford       // Save name of variable in Element.
22948b244e21SEwan Crawford       elem.type_name = valobj_sp->GetTypeName();
229563e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - element name set to %s", __FUNCTION__,
2296b9c1b51eSKate Stone                 elem.type_name.AsCString());
22978b244e21SEwan Crawford 
22988b244e21SEwan Crawford       return;
22998b244e21SEwan Crawford     }
23008b244e21SEwan Crawford   }
23018b244e21SEwan Crawford }
23028b244e21SEwan Crawford 
2303b9c1b51eSKate Stone // Function sets the datum_size member of Element. Representing the size of a
230405097246SAdrian Prantl // single instance including padding. Assumes the relevant allocation
230505097246SAdrian Prantl // information has already been jitted.
2306b9c1b51eSKate Stone void RenderScriptRuntime::SetElementSize(Element &elem) {
2307*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
23088b244e21SEwan Crawford   const Element::DataType type = *elem.type.get();
2309b9c1b51eSKate Stone   assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT &&
2310b9c1b51eSKate Stone          "Invalid allocation type");
231155232f09SEwan Crawford 
2312b3f7f69dSAidan Dodds   const uint32_t vec_size = *elem.type_vec_size.get();
2313b3f7f69dSAidan Dodds   uint32_t data_size = 0;
2314b3f7f69dSAidan Dodds   uint32_t padding = 0;
231555232f09SEwan Crawford 
23168b244e21SEwan Crawford   // Element is of a struct type, calculate size recursively.
2317b9c1b51eSKate Stone   if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) {
2318b9c1b51eSKate Stone     for (Element &child : elem.children) {
23198b244e21SEwan Crawford       SetElementSize(child);
2320b9c1b51eSKate Stone       const uint32_t array_size =
2321b9c1b51eSKate Stone           child.array_size.isValid() ? *child.array_size.get() : 1;
23228b244e21SEwan Crawford       data_size += *child.datum_size.get() * array_size;
23238b244e21SEwan Crawford     }
23248b244e21SEwan Crawford   }
2325b3f7f69dSAidan Dodds   // These have been packed already
2326b3f7f69dSAidan Dodds   else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 ||
2327b3f7f69dSAidan Dodds            type == Element::RS_TYPE_UNSIGNED_5_5_5_1 ||
2328b9c1b51eSKate Stone            type == Element::RS_TYPE_UNSIGNED_4_4_4_4) {
23292e920715SEwan Crawford     data_size = AllocationDetails::RSTypeToFormat[type][eElementSize];
2330b9c1b51eSKate Stone   } else if (type < Element::RS_TYPE_ELEMENT) {
2331b9c1b51eSKate Stone     data_size =
2332b9c1b51eSKate Stone         vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize];
23332e920715SEwan Crawford     if (vec_size == 3)
23342e920715SEwan Crawford       padding = AllocationDetails::RSTypeToFormat[type][eElementSize];
2335b9c1b51eSKate Stone   } else
2336b9c1b51eSKate Stone     data_size =
2337b9c1b51eSKate Stone         GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
23388b244e21SEwan Crawford 
23398b244e21SEwan Crawford   elem.padding = padding;
23408b244e21SEwan Crawford   elem.datum_size = data_size + padding;
234163e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - element size set to %" PRIu32, __FUNCTION__,
2342b9c1b51eSKate Stone             data_size + padding);
234355232f09SEwan Crawford }
234455232f09SEwan Crawford 
234505097246SAdrian Prantl // Given an allocation, this function copies the allocation contents from
234605097246SAdrian Prantl // device into a buffer on the heap. Returning a shared pointer to the buffer
234705097246SAdrian Prantl // containing the data.
234855232f09SEwan Crawford std::shared_ptr<uint8_t>
234980af0b9eSLuke Drummond RenderScriptRuntime::GetAllocationData(AllocationDetails *alloc,
2350b9c1b51eSKate Stone                                        StackFrame *frame_ptr) {
2351*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
235255232f09SEwan Crawford 
235355232f09SEwan Crawford   // JIT all the allocation details
235480af0b9eSLuke Drummond   if (alloc->ShouldRefresh()) {
235563e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info",
2356b9c1b51eSKate Stone               __FUNCTION__);
235755232f09SEwan Crawford 
235880af0b9eSLuke Drummond     if (!RefreshAllocation(alloc, frame_ptr)) {
235963e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - couldn't JIT allocation details", __FUNCTION__);
236055232f09SEwan Crawford       return nullptr;
236155232f09SEwan Crawford     }
236255232f09SEwan Crawford   }
236355232f09SEwan Crawford 
236480af0b9eSLuke Drummond   assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
236580af0b9eSLuke Drummond          alloc->element.type_vec_size.isValid() && alloc->size.isValid() &&
236680af0b9eSLuke Drummond          "Allocation information not available");
236755232f09SEwan Crawford 
236855232f09SEwan Crawford   // Allocate a buffer to copy data into
236980af0b9eSLuke Drummond   const uint32_t size = *alloc->size.get();
237055232f09SEwan Crawford   std::shared_ptr<uint8_t> buffer(new uint8_t[size]);
2371b9c1b51eSKate Stone   if (!buffer) {
237263e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - couldn't allocate a %" PRIu32 " byte buffer",
2373b9c1b51eSKate Stone               __FUNCTION__, size);
237455232f09SEwan Crawford     return nullptr;
237555232f09SEwan Crawford   }
237655232f09SEwan Crawford 
237755232f09SEwan Crawford   // Read the inferior memory
237897206d57SZachary Turner   Status err;
237980af0b9eSLuke Drummond   lldb::addr_t data_ptr = *alloc->data_ptr.get();
238080af0b9eSLuke Drummond   GetProcess()->ReadMemory(data_ptr, buffer.get(), size, err);
238180af0b9eSLuke Drummond   if (err.Fail()) {
238263e5fb76SJonas Devlieghere     LLDB_LOGF(log,
238363e5fb76SJonas Devlieghere               "%s - '%s' Couldn't read %" PRIu32
2384b9c1b51eSKate Stone               " bytes of allocation data from 0x%" PRIx64,
238580af0b9eSLuke Drummond               __FUNCTION__, err.AsCString(), size, data_ptr);
238655232f09SEwan Crawford     return nullptr;
238755232f09SEwan Crawford   }
238855232f09SEwan Crawford 
238955232f09SEwan Crawford   return buffer;
239055232f09SEwan Crawford }
239155232f09SEwan Crawford 
239205097246SAdrian Prantl // Function copies data from a binary file into an allocation. There is a
239305097246SAdrian Prantl // header at the start of the file, FileHeader, before the data content itself.
2394b9c1b51eSKate Stone // Information from this header is used to display warnings to the user about
2395b9c1b51eSKate Stone // incompatibilities
2396b9c1b51eSKate Stone bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id,
239780af0b9eSLuke Drummond                                          const char *path,
2398b9c1b51eSKate Stone                                          StackFrame *frame_ptr) {
2399*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
240055232f09SEwan Crawford 
240155232f09SEwan Crawford   // Find allocation with the given id
240255232f09SEwan Crawford   AllocationDetails *alloc = FindAllocByID(strm, alloc_id);
240355232f09SEwan Crawford   if (!alloc)
240455232f09SEwan Crawford     return false;
240555232f09SEwan Crawford 
240663e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64, __FUNCTION__,
2407b9c1b51eSKate Stone             *alloc->address.get());
240855232f09SEwan Crawford 
240955232f09SEwan Crawford   // JIT all the allocation details
241080af0b9eSLuke Drummond   if (alloc->ShouldRefresh()) {
241163e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.",
2412b9c1b51eSKate Stone               __FUNCTION__);
241355232f09SEwan Crawford 
2414b9c1b51eSKate Stone     if (!RefreshAllocation(alloc, frame_ptr)) {
241563e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - couldn't JIT allocation details", __FUNCTION__);
24164cfc9198SSylvestre Ledru       return false;
241755232f09SEwan Crawford     }
241855232f09SEwan Crawford   }
241955232f09SEwan Crawford 
2420b9c1b51eSKate Stone   assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
2421b9c1b51eSKate Stone          alloc->element.type_vec_size.isValid() && alloc->size.isValid() &&
2422b9c1b51eSKate Stone          alloc->element.datum_size.isValid() &&
2423b9c1b51eSKate Stone          "Allocation information not available");
242455232f09SEwan Crawford 
242555232f09SEwan Crawford   // Check we can read from file
24268f3be7a3SJonas Devlieghere   FileSpec file(path);
24278f3be7a3SJonas Devlieghere   FileSystem::Instance().Resolve(file);
2428dbd7fabaSJonas Devlieghere   if (!FileSystem::Instance().Exists(file)) {
242980af0b9eSLuke Drummond     strm.Printf("Error: File %s does not exist", path);
243055232f09SEwan Crawford     strm.EOL();
243155232f09SEwan Crawford     return false;
243255232f09SEwan Crawford   }
243355232f09SEwan Crawford 
24347c5310bbSJonas Devlieghere   if (!FileSystem::Instance().Readable(file)) {
243580af0b9eSLuke Drummond     strm.Printf("Error: File %s does not have readable permissions", path);
243655232f09SEwan Crawford     strm.EOL();
243755232f09SEwan Crawford     return false;
243855232f09SEwan Crawford   }
243955232f09SEwan Crawford 
244055232f09SEwan Crawford   // Read file into data buffer
244187e403aaSJonas Devlieghere   auto data_sp = FileSystem::Instance().CreateDataBuffer(file.GetPath());
244255232f09SEwan Crawford 
244355232f09SEwan Crawford   // Cast start of buffer to FileHeader and use pointer to read metadata
244480af0b9eSLuke Drummond   void *file_buf = data_sp->GetBytes();
244580af0b9eSLuke Drummond   if (file_buf == nullptr ||
2446b9c1b51eSKate Stone       data_sp->GetByteSize() < (sizeof(AllocationDetails::FileHeader) +
2447b9c1b51eSKate Stone                                 sizeof(AllocationDetails::ElementHeader))) {
244880af0b9eSLuke Drummond     strm.Printf("Error: File %s does not contain enough data for header", path);
244926e52a70SEwan Crawford     strm.EOL();
245026e52a70SEwan Crawford     return false;
245126e52a70SEwan Crawford   }
2452b9c1b51eSKate Stone   const AllocationDetails::FileHeader *file_header =
245380af0b9eSLuke Drummond       static_cast<AllocationDetails::FileHeader *>(file_buf);
245455232f09SEwan Crawford 
245526e52a70SEwan Crawford   // Check file starts with ascii characters "RSAD"
2456b9c1b51eSKate Stone   if (memcmp(file_header->ident, "RSAD", 4)) {
2457b9c1b51eSKate Stone     strm.Printf("Error: File doesn't contain identifier for an RS allocation "
2458b9c1b51eSKate Stone                 "dump. Are you sure this is the correct file?");
245926e52a70SEwan Crawford     strm.EOL();
246026e52a70SEwan Crawford     return false;
246126e52a70SEwan Crawford   }
246226e52a70SEwan Crawford 
246326e52a70SEwan Crawford   // Look at the type of the root element in the header
246480af0b9eSLuke Drummond   AllocationDetails::ElementHeader root_el_hdr;
246580af0b9eSLuke Drummond   memcpy(&root_el_hdr, static_cast<uint8_t *>(file_buf) +
2466b9c1b51eSKate Stone                            sizeof(AllocationDetails::FileHeader),
246726e52a70SEwan Crawford          sizeof(AllocationDetails::ElementHeader));
246855232f09SEwan Crawford 
246963e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - header type %" PRIu32 ", element size %" PRIu32,
247080af0b9eSLuke Drummond             __FUNCTION__, root_el_hdr.type, root_el_hdr.element_size);
247155232f09SEwan Crawford 
2472b9c1b51eSKate Stone   // Check if the target allocation and file both have the same number of bytes
2473b9c1b51eSKate Stone   // for an Element
247480af0b9eSLuke Drummond   if (*alloc->element.datum_size.get() != root_el_hdr.element_size) {
2475b9c1b51eSKate Stone     strm.Printf("Warning: Mismatched Element sizes - file %" PRIu32
2476b9c1b51eSKate Stone                 " bytes, allocation %" PRIu32 " bytes",
247780af0b9eSLuke Drummond                 root_el_hdr.element_size, *alloc->element.datum_size.get());
247855232f09SEwan Crawford     strm.EOL();
247955232f09SEwan Crawford   }
248055232f09SEwan Crawford 
248126e52a70SEwan Crawford   // Check if the target allocation and file both have the same type
2482b3f7f69dSAidan Dodds   const uint32_t alloc_type = static_cast<uint32_t>(*alloc->element.type.get());
248380af0b9eSLuke Drummond   const uint32_t file_type = root_el_hdr.type;
248426e52a70SEwan Crawford 
2485b9c1b51eSKate Stone   if (file_type > Element::RS_TYPE_FONT) {
248626e52a70SEwan Crawford     strm.Printf("Warning: File has unknown allocation type");
248726e52a70SEwan Crawford     strm.EOL();
2488b9c1b51eSKate Stone   } else if (alloc_type != file_type) {
2489b9c1b51eSKate Stone     // Enum value isn't monotonous, so doesn't always index RsDataTypeToString
2490b9c1b51eSKate Stone     // array
249180af0b9eSLuke Drummond     uint32_t target_type_name_idx = alloc_type;
249280af0b9eSLuke Drummond     uint32_t head_type_name_idx = file_type;
2493b9c1b51eSKate Stone     if (alloc_type >= Element::RS_TYPE_ELEMENT &&
2494b9c1b51eSKate Stone         alloc_type <= Element::RS_TYPE_FONT)
249580af0b9eSLuke Drummond       target_type_name_idx = static_cast<Element::DataType>(
2496b9c1b51eSKate Stone           (alloc_type - Element::RS_TYPE_ELEMENT) +
2497b3f7f69dSAidan Dodds           Element::RS_TYPE_MATRIX_2X2 + 1);
24982e920715SEwan Crawford 
2499b9c1b51eSKate Stone     if (file_type >= Element::RS_TYPE_ELEMENT &&
2500b9c1b51eSKate Stone         file_type <= Element::RS_TYPE_FONT)
250180af0b9eSLuke Drummond       head_type_name_idx = static_cast<Element::DataType>(
2502b9c1b51eSKate Stone           (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 +
2503b9c1b51eSKate Stone           1);
25042e920715SEwan Crawford 
250580af0b9eSLuke Drummond     const char *head_type_name =
250680af0b9eSLuke Drummond         AllocationDetails::RsDataTypeToString[head_type_name_idx][0];
250780af0b9eSLuke Drummond     const char *target_type_name =
250880af0b9eSLuke Drummond         AllocationDetails::RsDataTypeToString[target_type_name_idx][0];
250955232f09SEwan Crawford 
2510b9c1b51eSKate Stone     strm.Printf(
2511b9c1b51eSKate Stone         "Warning: Mismatched Types - file '%s' type, allocation '%s' type",
251280af0b9eSLuke Drummond         head_type_name, target_type_name);
251355232f09SEwan Crawford     strm.EOL();
251455232f09SEwan Crawford   }
251555232f09SEwan Crawford 
251626e52a70SEwan Crawford   // Advance buffer past header
251780af0b9eSLuke Drummond   file_buf = static_cast<uint8_t *>(file_buf) + file_header->hdr_size;
251826e52a70SEwan Crawford 
251955232f09SEwan Crawford   // Calculate size of allocation data in file
252080af0b9eSLuke Drummond   size_t size = data_sp->GetByteSize() - file_header->hdr_size;
252155232f09SEwan Crawford 
252205097246SAdrian Prantl   // Check if the target allocation and file both have the same total data
252305097246SAdrian Prantl   // size.
2524b3f7f69dSAidan Dodds   const uint32_t alloc_size = *alloc->size.get();
252580af0b9eSLuke Drummond   if (alloc_size != size) {
2526b9c1b51eSKate Stone     strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64
2527b9c1b51eSKate Stone                 " bytes, allocation 0x%" PRIx32 " bytes",
252880af0b9eSLuke Drummond                 (uint64_t)size, alloc_size);
252955232f09SEwan Crawford     strm.EOL();
253080af0b9eSLuke Drummond     // Set length to copy to minimum
253180af0b9eSLuke Drummond     size = alloc_size < size ? alloc_size : size;
253255232f09SEwan Crawford   }
253355232f09SEwan Crawford 
253455232f09SEwan Crawford   // Copy file data from our buffer into the target allocation.
253555232f09SEwan Crawford   lldb::addr_t alloc_data = *alloc->data_ptr.get();
253697206d57SZachary Turner   Status err;
253780af0b9eSLuke Drummond   size_t written = GetProcess()->WriteMemory(alloc_data, file_buf, size, err);
253880af0b9eSLuke Drummond   if (!err.Success() || written != size) {
253980af0b9eSLuke Drummond     strm.Printf("Error: Couldn't write data to allocation %s", err.AsCString());
254055232f09SEwan Crawford     strm.EOL();
254155232f09SEwan Crawford     return false;
254255232f09SEwan Crawford   }
254355232f09SEwan Crawford 
254480af0b9eSLuke Drummond   strm.Printf("Contents of file '%s' read into allocation %" PRIu32, path,
2545b9c1b51eSKate Stone               alloc->id);
254655232f09SEwan Crawford   strm.EOL();
254755232f09SEwan Crawford 
254855232f09SEwan Crawford   return true;
254955232f09SEwan Crawford }
255055232f09SEwan Crawford 
2551b9c1b51eSKate Stone // Function takes as parameters a byte buffer, which will eventually be written
255280af0b9eSLuke Drummond // to file as the element header, an offset into that buffer, and an Element
255305097246SAdrian Prantl // that will be saved into the buffer at the parametrised offset. Return value
255405097246SAdrian Prantl // is the new offset after writing the element into the buffer. Elements are
255505097246SAdrian Prantl // saved to the file as the ElementHeader struct followed by offsets to the
255605097246SAdrian Prantl // structs of all the element's children.
2557b9c1b51eSKate Stone size_t RenderScriptRuntime::PopulateElementHeaders(
2558b9c1b51eSKate Stone     const std::shared_ptr<uint8_t> header_buffer, size_t offset,
2559b9c1b51eSKate Stone     const Element &elem) {
256005097246SAdrian Prantl   // File struct for an element header with all the relevant details copied
256105097246SAdrian Prantl   // from elem. We assume members are valid already.
256226e52a70SEwan Crawford   AllocationDetails::ElementHeader elem_header;
256326e52a70SEwan Crawford   elem_header.type = *elem.type.get();
256426e52a70SEwan Crawford   elem_header.kind = *elem.type_kind.get();
256526e52a70SEwan Crawford   elem_header.element_size = *elem.datum_size.get();
256626e52a70SEwan Crawford   elem_header.vector_size = *elem.type_vec_size.get();
2567b9c1b51eSKate Stone   elem_header.array_size =
2568b9c1b51eSKate Stone       elem.array_size.isValid() ? *elem.array_size.get() : 0;
256926e52a70SEwan Crawford   const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader);
257026e52a70SEwan Crawford 
257105097246SAdrian Prantl   // Copy struct into buffer and advance offset We assume that header_buffer
257205097246SAdrian Prantl   // has been checked for nullptr before this method is called
257326e52a70SEwan Crawford   memcpy(header_buffer.get() + offset, &elem_header, elem_header_size);
257426e52a70SEwan Crawford   offset += elem_header_size;
257526e52a70SEwan Crawford 
257626e52a70SEwan Crawford   // Starting offset of child ElementHeader struct
2577b9c1b51eSKate Stone   size_t child_offset =
2578b9c1b51eSKate Stone       offset + ((elem.children.size() + 1) * sizeof(uint32_t));
2579b9c1b51eSKate Stone   for (const RenderScriptRuntime::Element &child : elem.children) {
2580b9c1b51eSKate Stone     // Recursively populate the buffer with the element header structs of
258180af0b9eSLuke Drummond     // children. Then save the offsets where they were set after the parent
258280af0b9eSLuke Drummond     // element header.
258326e52a70SEwan Crawford     memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t));
258426e52a70SEwan Crawford     offset += sizeof(uint32_t);
258526e52a70SEwan Crawford 
258626e52a70SEwan Crawford     child_offset = PopulateElementHeaders(header_buffer, child_offset, child);
258726e52a70SEwan Crawford   }
258826e52a70SEwan Crawford 
258926e52a70SEwan Crawford   // Zero indicates no more children
259026e52a70SEwan Crawford   memset(header_buffer.get() + offset, 0, sizeof(uint32_t));
259126e52a70SEwan Crawford 
259226e52a70SEwan Crawford   return child_offset;
259326e52a70SEwan Crawford }
259426e52a70SEwan Crawford 
2595b9c1b51eSKate Stone // Given an Element object this function returns the total size needed in the
259680af0b9eSLuke Drummond // file header to store the element's details. Taking into account the size of
259780af0b9eSLuke Drummond // the element header struct, plus the offsets to all the element's children.
2598b9c1b51eSKate Stone // Function is recursive so that the size of all ancestors is taken into
2599b9c1b51eSKate Stone // account.
2600b9c1b51eSKate Stone size_t RenderScriptRuntime::CalculateElementHeaderSize(const Element &elem) {
260180af0b9eSLuke Drummond   // Offsets to children plus zero terminator
260280af0b9eSLuke Drummond   size_t size = (elem.children.size() + 1) * sizeof(uint32_t);
260380af0b9eSLuke Drummond   // Size of header struct with type details
260480af0b9eSLuke Drummond   size += sizeof(AllocationDetails::ElementHeader);
260526e52a70SEwan Crawford 
260626e52a70SEwan Crawford   // Calculate recursively for all descendants
260726e52a70SEwan Crawford   for (const Element &child : elem.children)
260826e52a70SEwan Crawford     size += CalculateElementHeaderSize(child);
260926e52a70SEwan Crawford 
261026e52a70SEwan Crawford   return size;
261126e52a70SEwan Crawford }
261226e52a70SEwan Crawford 
261305097246SAdrian Prantl // Function copies allocation contents into a binary file. This file can then
261405097246SAdrian Prantl // be loaded later into a different allocation. There is a header, FileHeader,
261580af0b9eSLuke Drummond // before the allocation data containing meta-data.
2616b9c1b51eSKate Stone bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id,
261780af0b9eSLuke Drummond                                          const char *path,
2618b9c1b51eSKate Stone                                          StackFrame *frame_ptr) {
2619*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
262055232f09SEwan Crawford 
262155232f09SEwan Crawford   // Find allocation with the given id
262255232f09SEwan Crawford   AllocationDetails *alloc = FindAllocByID(strm, alloc_id);
262355232f09SEwan Crawford   if (!alloc)
262455232f09SEwan Crawford     return false;
262555232f09SEwan Crawford 
262663e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64 ".", __FUNCTION__,
2627b9c1b51eSKate Stone             *alloc->address.get());
262855232f09SEwan Crawford 
262955232f09SEwan Crawford   // JIT all the allocation details
263080af0b9eSLuke Drummond   if (alloc->ShouldRefresh()) {
263163e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.",
2632b9c1b51eSKate Stone               __FUNCTION__);
263355232f09SEwan Crawford 
2634b9c1b51eSKate Stone     if (!RefreshAllocation(alloc, frame_ptr)) {
263563e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - couldn't JIT allocation details.", __FUNCTION__);
26364cfc9198SSylvestre Ledru       return false;
263755232f09SEwan Crawford     }
263855232f09SEwan Crawford   }
263955232f09SEwan Crawford 
2640b9c1b51eSKate Stone   assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
2641b9c1b51eSKate Stone          alloc->element.type_vec_size.isValid() &&
2642b9c1b51eSKate Stone          alloc->element.datum_size.get() &&
2643b9c1b51eSKate Stone          alloc->element.type_kind.isValid() && alloc->dimension.isValid() &&
2644b3f7f69dSAidan Dodds          "Allocation information not available");
264555232f09SEwan Crawford 
264655232f09SEwan Crawford   // Check we can create writable file
26478f3be7a3SJonas Devlieghere   FileSpec file_spec(path);
26488f3be7a3SJonas Devlieghere   FileSystem::Instance().Resolve(file_spec);
26492fce1137SLawrence D'Anna   auto file = FileSystem::Instance().Open(
265014735cabSMichał Górny       file_spec, File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate |
2651b9c1b51eSKate Stone                      File::eOpenOptionTruncate);
265250bc1ed2SJonas Devlieghere 
2653b9c1b51eSKate Stone   if (!file) {
26542fce1137SLawrence D'Anna     std::string error = llvm::toString(file.takeError());
26552fce1137SLawrence D'Anna     strm.Printf("Error: Failed to open '%s' for writing: %s", path,
26562fce1137SLawrence D'Anna                 error.c_str());
265755232f09SEwan Crawford     strm.EOL();
265855232f09SEwan Crawford     return false;
265955232f09SEwan Crawford   }
266055232f09SEwan Crawford 
266155232f09SEwan Crawford   // Read allocation into buffer of heap memory
266255232f09SEwan Crawford   const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
2663b9c1b51eSKate Stone   if (!buffer) {
266455232f09SEwan Crawford     strm.Printf("Error: Couldn't read allocation data into buffer");
266555232f09SEwan Crawford     strm.EOL();
266655232f09SEwan Crawford     return false;
266755232f09SEwan Crawford   }
266855232f09SEwan Crawford 
266955232f09SEwan Crawford   // Create the file header
267055232f09SEwan Crawford   AllocationDetails::FileHeader head;
2671b3f7f69dSAidan Dodds   memcpy(head.ident, "RSAD", 4);
26722d62328aSEwan Crawford   head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1);
26732d62328aSEwan Crawford   head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2);
26742d62328aSEwan Crawford   head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3);
267526e52a70SEwan Crawford 
267626e52a70SEwan Crawford   const size_t element_header_size = CalculateElementHeaderSize(alloc->element);
2677b9c1b51eSKate Stone   assert((sizeof(AllocationDetails::FileHeader) + element_header_size) <
2678b9c1b51eSKate Stone              UINT16_MAX &&
2679b9c1b51eSKate Stone          "Element header too large");
2680b9c1b51eSKate Stone   head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) +
2681b9c1b51eSKate Stone                                         element_header_size);
268255232f09SEwan Crawford 
268355232f09SEwan Crawford   // Write the file header
268455232f09SEwan Crawford   size_t num_bytes = sizeof(AllocationDetails::FileHeader);
268563e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - writing File Header, 0x%" PRIx64 " bytes", __FUNCTION__,
2686b9c1b51eSKate Stone             (uint64_t)num_bytes);
268726e52a70SEwan Crawford 
26882fce1137SLawrence D'Anna   Status err = file.get()->Write(&head, num_bytes);
2689b9c1b51eSKate Stone   if (!err.Success()) {
269080af0b9eSLuke Drummond     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path);
269126e52a70SEwan Crawford     strm.EOL();
269226e52a70SEwan Crawford     return false;
269326e52a70SEwan Crawford   }
269426e52a70SEwan Crawford 
269526e52a70SEwan Crawford   // Create the headers describing the element type of the allocation.
2696b9c1b51eSKate Stone   std::shared_ptr<uint8_t> element_header_buffer(
2697b9c1b51eSKate Stone       new uint8_t[element_header_size]);
2698b9c1b51eSKate Stone   if (element_header_buffer == nullptr) {
2699b9c1b51eSKate Stone     strm.Printf("Internal Error: Couldn't allocate %" PRIu64
2700b9c1b51eSKate Stone                 " bytes on the heap",
2701b9c1b51eSKate Stone                 (uint64_t)element_header_size);
270226e52a70SEwan Crawford     strm.EOL();
270326e52a70SEwan Crawford     return false;
270426e52a70SEwan Crawford   }
270526e52a70SEwan Crawford 
270626e52a70SEwan Crawford   PopulateElementHeaders(element_header_buffer, 0, alloc->element);
270726e52a70SEwan Crawford 
270826e52a70SEwan Crawford   // Write headers for allocation element type to file
270926e52a70SEwan Crawford   num_bytes = element_header_size;
271063e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - writing element headers, 0x%" PRIx64 " bytes.",
2711b9c1b51eSKate Stone             __FUNCTION__, (uint64_t)num_bytes);
271226e52a70SEwan Crawford 
27132fce1137SLawrence D'Anna   err = file.get()->Write(element_header_buffer.get(), num_bytes);
2714b9c1b51eSKate Stone   if (!err.Success()) {
271580af0b9eSLuke Drummond     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path);
271655232f09SEwan Crawford     strm.EOL();
271755232f09SEwan Crawford     return false;
271855232f09SEwan Crawford   }
271955232f09SEwan Crawford 
272055232f09SEwan Crawford   // Write allocation data to file
272155232f09SEwan Crawford   num_bytes = static_cast<size_t>(*alloc->size.get());
272263e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - writing 0x%" PRIx64 " bytes", __FUNCTION__,
2723b9c1b51eSKate Stone             (uint64_t)num_bytes);
272455232f09SEwan Crawford 
27252fce1137SLawrence D'Anna   err = file.get()->Write(buffer.get(), num_bytes);
2726b9c1b51eSKate Stone   if (!err.Success()) {
272780af0b9eSLuke Drummond     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path);
272855232f09SEwan Crawford     strm.EOL();
272955232f09SEwan Crawford     return false;
273055232f09SEwan Crawford   }
273155232f09SEwan Crawford 
273280af0b9eSLuke Drummond   strm.Printf("Allocation written to file '%s'", path);
273355232f09SEwan Crawford   strm.EOL();
273415f2bd95SEwan Crawford   return true;
273515f2bd95SEwan Crawford }
273615f2bd95SEwan Crawford 
2737b9c1b51eSKate Stone bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) {
2738*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
27394640cde1SColin Riley 
2740b9c1b51eSKate Stone   if (module_sp) {
2741b9c1b51eSKate Stone     for (const auto &rs_module : m_rsmodules) {
2742b9c1b51eSKate Stone       if (rs_module->m_module == module_sp) {
274305097246SAdrian Prantl         // Check if the user has enabled automatically breaking on all RS
274405097246SAdrian Prantl         // kernels.
27457dc7771cSEwan Crawford         if (m_breakAllKernels)
27467dc7771cSEwan Crawford           BreakOnModuleKernels(rs_module);
27477dc7771cSEwan Crawford 
27485ec532a9SColin Riley         return false;
27495ec532a9SColin Riley       }
27507dc7771cSEwan Crawford     }
2751ef20b08fSColin Riley     bool module_loaded = false;
2752b9c1b51eSKate Stone     switch (GetModuleKind(module_sp)) {
2753b9c1b51eSKate Stone     case eModuleKindKernelObj: {
27544640cde1SColin Riley       RSModuleDescriptorSP module_desc;
2755796ac80bSJonas Devlieghere       module_desc = std::make_shared<RSModuleDescriptor>(module_sp);
2756b9c1b51eSKate Stone       if (module_desc->ParseRSInfo()) {
27575ec532a9SColin Riley         m_rsmodules.push_back(module_desc);
275847d64161SLuke Drummond         module_desc->WarnIfVersionMismatch(GetProcess()
275947d64161SLuke Drummond                                                ->GetTarget()
276047d64161SLuke Drummond                                                .GetDebugger()
276147d64161SLuke Drummond                                                .GetAsyncOutputStream()
276247d64161SLuke Drummond                                                .get());
2763ef20b08fSColin Riley         module_loaded = true;
27645ec532a9SColin Riley       }
2765b9c1b51eSKate Stone       if (module_loaded) {
27664640cde1SColin Riley         FixupScriptDetails(module_desc);
27674640cde1SColin Riley       }
2768ef20b08fSColin Riley       break;
2769ef20b08fSColin Riley     }
2770b9c1b51eSKate Stone     case eModuleKindDriver: {
2771b9c1b51eSKate Stone       if (!m_libRSDriver) {
27724640cde1SColin Riley         m_libRSDriver = module_sp;
27734640cde1SColin Riley         LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver);
27744640cde1SColin Riley       }
27754640cde1SColin Riley       break;
27764640cde1SColin Riley     }
2777b9c1b51eSKate Stone     case eModuleKindImpl: {
277821fed052SAidan Dodds       if (!m_libRSCpuRef) {
27794640cde1SColin Riley         m_libRSCpuRef = module_sp;
278021fed052SAidan Dodds         LoadRuntimeHooks(m_libRSCpuRef, RenderScriptRuntime::eModuleKindImpl);
278121fed052SAidan Dodds       }
27824640cde1SColin Riley       break;
27834640cde1SColin Riley     }
2784b9c1b51eSKate Stone     case eModuleKindLibRS: {
2785b9c1b51eSKate Stone       if (!m_libRS) {
27864640cde1SColin Riley         m_libRS = module_sp;
27874640cde1SColin Riley         static ConstString gDbgPresentStr("gDebuggerPresent");
2788b9c1b51eSKate Stone         const Symbol *debug_present = m_libRS->FindFirstSymbolWithNameAndType(
2789b9c1b51eSKate Stone             gDbgPresentStr, eSymbolTypeData);
2790b9c1b51eSKate Stone         if (debug_present) {
279197206d57SZachary Turner           Status err;
27924640cde1SColin Riley           uint32_t flag = 0x00000001U;
27934640cde1SColin Riley           Target &target = GetProcess()->GetTarget();
2794358cf1eaSGreg Clayton           addr_t addr = debug_present->GetLoadAddress(&target);
279580af0b9eSLuke Drummond           GetProcess()->WriteMemory(addr, &flag, sizeof(flag), err);
279680af0b9eSLuke Drummond           if (err.Success()) {
279763e5fb76SJonas Devlieghere             LLDB_LOGF(log, "%s - debugger present flag set on debugee.",
2798b9c1b51eSKate Stone                       __FUNCTION__);
27994640cde1SColin Riley 
28004640cde1SColin Riley             m_debuggerPresentFlagged = true;
2801b9c1b51eSKate Stone           } else if (log) {
280263e5fb76SJonas Devlieghere             LLDB_LOGF(log, "%s - error writing debugger present flags '%s' ",
280380af0b9eSLuke Drummond                       __FUNCTION__, err.AsCString());
28044640cde1SColin Riley           }
2805b9c1b51eSKate Stone         } else if (log) {
280663e5fb76SJonas Devlieghere           LLDB_LOGF(
280763e5fb76SJonas Devlieghere               log,
2808b9c1b51eSKate Stone               "%s - error writing debugger present flags - symbol not found",
2809b9c1b51eSKate Stone               __FUNCTION__);
28104640cde1SColin Riley         }
28114640cde1SColin Riley       }
28124640cde1SColin Riley       break;
28134640cde1SColin Riley     }
2814ef20b08fSColin Riley     default:
2815ef20b08fSColin Riley       break;
2816ef20b08fSColin Riley     }
2817ef20b08fSColin Riley     if (module_loaded)
2818ef20b08fSColin Riley       Update();
2819ef20b08fSColin Riley     return module_loaded;
28205ec532a9SColin Riley   }
28215ec532a9SColin Riley   return false;
28225ec532a9SColin Riley }
28235ec532a9SColin Riley 
2824b9c1b51eSKate Stone void RenderScriptRuntime::Update() {
2825b9c1b51eSKate Stone   if (m_rsmodules.size() > 0) {
2826b9c1b51eSKate Stone     if (!m_initiated) {
2827ef20b08fSColin Riley       Initiate();
2828ef20b08fSColin Riley     }
2829ef20b08fSColin Riley   }
2830ef20b08fSColin Riley }
2831ef20b08fSColin Riley 
283247d64161SLuke Drummond void RSModuleDescriptor::WarnIfVersionMismatch(lldb_private::Stream *s) const {
283347d64161SLuke Drummond   if (!s)
283447d64161SLuke Drummond     return;
283547d64161SLuke Drummond 
283647d64161SLuke Drummond   if (m_slang_version.empty() || m_bcc_version.empty()) {
283747d64161SLuke Drummond     s->PutCString("WARNING: Unknown bcc or slang (llvm-rs-cc) version; debug "
283847d64161SLuke Drummond                   "experience may be unreliable");
283947d64161SLuke Drummond     s->EOL();
284047d64161SLuke Drummond   } else if (m_slang_version != m_bcc_version) {
284147d64161SLuke Drummond     s->Printf("WARNING: The debug info emitted by the slang frontend "
284247d64161SLuke Drummond               "(llvm-rs-cc) used to build this module (%s) does not match the "
284347d64161SLuke Drummond               "version of bcc used to generate the debug information (%s). "
284447d64161SLuke Drummond               "This is an unsupported configuration and may result in a poor "
284547d64161SLuke Drummond               "debugging experience; proceed with caution",
284647d64161SLuke Drummond               m_slang_version.c_str(), m_bcc_version.c_str());
284747d64161SLuke Drummond     s->EOL();
284847d64161SLuke Drummond   }
284947d64161SLuke Drummond }
285047d64161SLuke Drummond 
28517f193d69SLuke Drummond bool RSModuleDescriptor::ParsePragmaCount(llvm::StringRef *lines,
28527f193d69SLuke Drummond                                           size_t n_lines) {
28537f193d69SLuke Drummond   // Skip the pragma prototype line
28547f193d69SLuke Drummond   ++lines;
28557f193d69SLuke Drummond   for (; n_lines--; ++lines) {
28567f193d69SLuke Drummond     const auto kv_pair = lines->split(" - ");
28577f193d69SLuke Drummond     m_pragmas[kv_pair.first.trim().str()] = kv_pair.second.trim().str();
28587f193d69SLuke Drummond   }
28597f193d69SLuke Drummond   return true;
28607f193d69SLuke Drummond }
28617f193d69SLuke Drummond 
28627f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportReduceCount(llvm::StringRef *lines,
28637f193d69SLuke Drummond                                                 size_t n_lines) {
28647f193d69SLuke Drummond   // The list of reduction kernels in the `.rs.info` symbol is of the form
28657f193d69SLuke Drummond   // "signature - accumulatordatasize - reduction_name - initializer_name -
286605097246SAdrian Prantl   // accumulator_name - combiner_name - outconverter_name - halter_name" Where
286705097246SAdrian Prantl   // a function is not explicitly named by the user, or is not generated by the
286805097246SAdrian Prantl   // compiler, it is named "." so the dash separated list should always be 8
286905097246SAdrian Prantl   // items long
2870*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
28717f193d69SLuke Drummond   // Skip the exportReduceCount line
28727f193d69SLuke Drummond   ++lines;
28737f193d69SLuke Drummond   for (; n_lines--; ++lines) {
28747f193d69SLuke Drummond     llvm::SmallVector<llvm::StringRef, 8> spec;
28757f193d69SLuke Drummond     lines->split(spec, " - ");
28767f193d69SLuke Drummond     if (spec.size() != 8) {
28777f193d69SLuke Drummond       if (spec.size() < 8) {
28787f193d69SLuke Drummond         if (log)
28797f193d69SLuke Drummond           log->Error("Error parsing RenderScript reduction spec. wrong number "
28807f193d69SLuke Drummond                      "of fields");
28817f193d69SLuke Drummond         return false;
28827f193d69SLuke Drummond       } else if (log)
28837f193d69SLuke Drummond         log->Warning("Extraneous members in reduction spec: '%s'",
28847f193d69SLuke Drummond                      lines->str().c_str());
28857f193d69SLuke Drummond     }
28867f193d69SLuke Drummond 
28877f193d69SLuke Drummond     const auto sig_s = spec[0];
28887f193d69SLuke Drummond     uint32_t sig;
28897f193d69SLuke Drummond     if (sig_s.getAsInteger(10, sig)) {
28907f193d69SLuke Drummond       if (log)
28917f193d69SLuke Drummond         log->Error("Error parsing Renderscript reduction spec: invalid kernel "
28927f193d69SLuke Drummond                    "signature: '%s'",
28937f193d69SLuke Drummond                    sig_s.str().c_str());
28947f193d69SLuke Drummond       return false;
28957f193d69SLuke Drummond     }
28967f193d69SLuke Drummond 
28977f193d69SLuke Drummond     const auto accum_data_size_s = spec[1];
28987f193d69SLuke Drummond     uint32_t accum_data_size;
28997f193d69SLuke Drummond     if (accum_data_size_s.getAsInteger(10, accum_data_size)) {
29007f193d69SLuke Drummond       if (log)
29017f193d69SLuke Drummond         log->Error("Error parsing Renderscript reduction spec: invalid "
29027f193d69SLuke Drummond                    "accumulator data size %s",
29037f193d69SLuke Drummond                    accum_data_size_s.str().c_str());
29047f193d69SLuke Drummond       return false;
29057f193d69SLuke Drummond     }
29067f193d69SLuke Drummond 
290763e5fb76SJonas Devlieghere     LLDB_LOGF(log, "Found RenderScript reduction '%s'", spec[2].str().c_str());
29087f193d69SLuke Drummond 
29097f193d69SLuke Drummond     m_reductions.push_back(RSReductionDescriptor(this, sig, accum_data_size,
29107f193d69SLuke Drummond                                                  spec[2], spec[3], spec[4],
29117f193d69SLuke Drummond                                                  spec[5], spec[6], spec[7]));
29127f193d69SLuke Drummond   }
29137f193d69SLuke Drummond   return true;
29147f193d69SLuke Drummond }
29157f193d69SLuke Drummond 
291647d64161SLuke Drummond bool RSModuleDescriptor::ParseVersionInfo(llvm::StringRef *lines,
291747d64161SLuke Drummond                                           size_t n_lines) {
291847d64161SLuke Drummond   // Skip the versionInfo line
291947d64161SLuke Drummond   ++lines;
292047d64161SLuke Drummond   for (; n_lines--; ++lines) {
292147d64161SLuke Drummond     // We're only interested in bcc and slang versions, and ignore all other
292247d64161SLuke Drummond     // versionInfo lines
292347d64161SLuke Drummond     const auto kv_pair = lines->split(" - ");
292447d64161SLuke Drummond     if (kv_pair.first == "slang")
292547d64161SLuke Drummond       m_slang_version = kv_pair.second.str();
292647d64161SLuke Drummond     else if (kv_pair.first == "bcc")
292747d64161SLuke Drummond       m_bcc_version = kv_pair.second.str();
292847d64161SLuke Drummond   }
292947d64161SLuke Drummond   return true;
293047d64161SLuke Drummond }
293147d64161SLuke Drummond 
29327f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportForeachCount(llvm::StringRef *lines,
29337f193d69SLuke Drummond                                                  size_t n_lines) {
29347f193d69SLuke Drummond   // Skip the exportForeachCount line
29357f193d69SLuke Drummond   ++lines;
29367f193d69SLuke Drummond   for (; n_lines--; ++lines) {
29377f193d69SLuke Drummond     uint32_t slot;
29387f193d69SLuke Drummond     // `forEach` kernels are listed in the `.rs.info` packet as a "slot - name"
29397f193d69SLuke Drummond     // pair per line
29407f193d69SLuke Drummond     const auto kv_pair = lines->split(" - ");
29417f193d69SLuke Drummond     if (kv_pair.first.getAsInteger(10, slot))
29427f193d69SLuke Drummond       return false;
29437f193d69SLuke Drummond     m_kernels.push_back(RSKernelDescriptor(this, kv_pair.second, slot));
29447f193d69SLuke Drummond   }
29457f193d69SLuke Drummond   return true;
29467f193d69SLuke Drummond }
29477f193d69SLuke Drummond 
29487f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportVarCount(llvm::StringRef *lines,
29497f193d69SLuke Drummond                                              size_t n_lines) {
29507f193d69SLuke Drummond   // Skip the ExportVarCount line
29517f193d69SLuke Drummond   ++lines;
29527f193d69SLuke Drummond   for (; n_lines--; ++lines)
29537f193d69SLuke Drummond     m_globals.push_back(RSGlobalDescriptor(this, *lines));
29547f193d69SLuke Drummond   return true;
29557f193d69SLuke Drummond }
29565ec532a9SColin Riley 
2957b9c1b51eSKate Stone // The .rs.info symbol in renderscript modules contains a string which needs to
295805097246SAdrian Prantl // be parsed. The string is basic and is parsed on a line by line basis.
2959b9c1b51eSKate Stone bool RSModuleDescriptor::ParseRSInfo() {
2960b0be30f7SAidan Dodds   assert(m_module);
2961*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
2962b9c1b51eSKate Stone   const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType(
2963b9c1b51eSKate Stone       ConstString(".rs.info"), eSymbolTypeData);
2964b0be30f7SAidan Dodds   if (!info_sym)
2965b0be30f7SAidan Dodds     return false;
2966b0be30f7SAidan Dodds 
2967358cf1eaSGreg Clayton   const addr_t addr = info_sym->GetAddressRef().GetFileAddress();
2968b0be30f7SAidan Dodds   if (addr == LLDB_INVALID_ADDRESS)
2969b0be30f7SAidan Dodds     return false;
2970b0be30f7SAidan Dodds 
29715ec532a9SColin Riley   const addr_t size = info_sym->GetByteSize();
29725ec532a9SColin Riley   const FileSpec fs = m_module->GetFileSpec();
29735ec532a9SColin Riley 
297487e403aaSJonas Devlieghere   auto buffer =
297587e403aaSJonas Devlieghere       FileSystem::Instance().CreateDataBuffer(fs.GetPath(), size, addr);
29765ec532a9SColin Riley   if (!buffer)
29775ec532a9SColin Riley     return false;
29785ec532a9SColin Riley 
2979b0be30f7SAidan Dodds   // split rs.info. contents into lines
29807f193d69SLuke Drummond   llvm::SmallVector<llvm::StringRef, 128> info_lines;
29815ec532a9SColin Riley   {
29827f193d69SLuke Drummond     const llvm::StringRef raw_rs_info((const char *)buffer->GetBytes());
29837f193d69SLuke Drummond     raw_rs_info.split(info_lines, '\n');
298463e5fb76SJonas Devlieghere     LLDB_LOGF(log, "'.rs.info symbol for '%s':\n%s",
298563e5fb76SJonas Devlieghere               m_module->GetFileSpec().GetCString(), raw_rs_info.str().c_str());
2986b0be30f7SAidan Dodds   }
2987b0be30f7SAidan Dodds 
29887f193d69SLuke Drummond   enum {
29897f193d69SLuke Drummond     eExportVar,
29907f193d69SLuke Drummond     eExportForEach,
29917f193d69SLuke Drummond     eExportReduce,
29927f193d69SLuke Drummond     ePragma,
29937f193d69SLuke Drummond     eBuildChecksum,
299447d64161SLuke Drummond     eObjectSlot,
299547d64161SLuke Drummond     eVersionInfo,
29967f193d69SLuke Drummond   };
29977f193d69SLuke Drummond 
2998b3bbcb12SLuke Drummond   const auto rs_info_handler = [](llvm::StringRef name) -> int {
2999b3bbcb12SLuke Drummond     return llvm::StringSwitch<int>(name)
3000b3bbcb12SLuke Drummond         // The number of visible global variables in the script
3001b3bbcb12SLuke Drummond         .Case("exportVarCount", eExportVar)
30027f193d69SLuke Drummond         // The number of RenderScrip `forEach` kernels __attribute__((kernel))
3003b3bbcb12SLuke Drummond         .Case("exportForEachCount", eExportForEach)
3004b3bbcb12SLuke Drummond         // The number of generalreductions: This marked in the script by
3005b3bbcb12SLuke Drummond         // `#pragma reduce()`
3006b3bbcb12SLuke Drummond         .Case("exportReduceCount", eExportReduce)
3007b3bbcb12SLuke Drummond         // Total count of all RenderScript specific `#pragmas` used in the
3008b3bbcb12SLuke Drummond         // script
3009b3bbcb12SLuke Drummond         .Case("pragmaCount", ePragma)
3010b3bbcb12SLuke Drummond         .Case("objectSlotCount", eObjectSlot)
301147d64161SLuke Drummond         .Case("versionInfo", eVersionInfo)
3012b3bbcb12SLuke Drummond         .Default(-1);
3013b3bbcb12SLuke Drummond   };
3014b0be30f7SAidan Dodds 
3015b0be30f7SAidan Dodds   // parse all text lines of .rs.info
3016b9c1b51eSKate Stone   for (auto line = info_lines.begin(); line != info_lines.end(); ++line) {
30177f193d69SLuke Drummond     const auto kv_pair = line->split(": ");
30187f193d69SLuke Drummond     const auto key = kv_pair.first;
30197f193d69SLuke Drummond     const auto val = kv_pair.second.trim();
30205ec532a9SColin Riley 
3021b3bbcb12SLuke Drummond     const auto handler = rs_info_handler(key);
3022b3bbcb12SLuke Drummond     if (handler == -1)
30237f193d69SLuke Drummond       continue;
302405097246SAdrian Prantl     // getAsInteger returns `true` on an error condition - we're only
302505097246SAdrian Prantl     // interested in numeric fields at the moment
30267f193d69SLuke Drummond     uint64_t n_lines;
30277f193d69SLuke Drummond     if (val.getAsInteger(10, n_lines)) {
30286302bf6aSPavel Labath       LLDB_LOGV(log, "Failed to parse non-numeric '.rs.info' section {0}",
30296302bf6aSPavel Labath                 line->str());
30307f193d69SLuke Drummond       continue;
30317f193d69SLuke Drummond     }
30327f193d69SLuke Drummond     if (info_lines.end() - (line + 1) < (ptrdiff_t)n_lines)
30337f193d69SLuke Drummond       return false;
30347f193d69SLuke Drummond 
30357f193d69SLuke Drummond     bool success = false;
3036b3bbcb12SLuke Drummond     switch (handler) {
30377f193d69SLuke Drummond     case eExportVar:
30387f193d69SLuke Drummond       success = ParseExportVarCount(line, n_lines);
30397f193d69SLuke Drummond       break;
30407f193d69SLuke Drummond     case eExportForEach:
30417f193d69SLuke Drummond       success = ParseExportForeachCount(line, n_lines);
30427f193d69SLuke Drummond       break;
30437f193d69SLuke Drummond     case eExportReduce:
30447f193d69SLuke Drummond       success = ParseExportReduceCount(line, n_lines);
30457f193d69SLuke Drummond       break;
30467f193d69SLuke Drummond     case ePragma:
30477f193d69SLuke Drummond       success = ParsePragmaCount(line, n_lines);
30487f193d69SLuke Drummond       break;
304947d64161SLuke Drummond     case eVersionInfo:
305047d64161SLuke Drummond       success = ParseVersionInfo(line, n_lines);
305147d64161SLuke Drummond       break;
30527f193d69SLuke Drummond     default: {
305363e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - skipping .rs.info field '%s'", __FUNCTION__,
30547f193d69SLuke Drummond                 line->str().c_str());
30557f193d69SLuke Drummond       continue;
30567f193d69SLuke Drummond     }
30577f193d69SLuke Drummond     }
30587f193d69SLuke Drummond     if (!success)
30597f193d69SLuke Drummond       return false;
30607f193d69SLuke Drummond     line += n_lines;
30617f193d69SLuke Drummond   }
30627f193d69SLuke Drummond   return info_lines.size() > 0;
30635ec532a9SColin Riley }
30645ec532a9SColin Riley 
306597206d57SZachary Turner void RenderScriptRuntime::DumpStatus(Stream &strm) const {
3066b9c1b51eSKate Stone   if (m_libRS) {
30674640cde1SColin Riley     strm.Printf("Runtime Library discovered.");
30684640cde1SColin Riley     strm.EOL();
30694640cde1SColin Riley   }
3070b9c1b51eSKate Stone   if (m_libRSDriver) {
30714640cde1SColin Riley     strm.Printf("Runtime Driver discovered.");
30724640cde1SColin Riley     strm.EOL();
30734640cde1SColin Riley   }
3074b9c1b51eSKate Stone   if (m_libRSCpuRef) {
30754640cde1SColin Riley     strm.Printf("CPU Reference Implementation discovered.");
30764640cde1SColin Riley     strm.EOL();
30774640cde1SColin Riley   }
30784640cde1SColin Riley 
3079b9c1b51eSKate Stone   if (m_runtimeHooks.size()) {
30804640cde1SColin Riley     strm.Printf("Runtime functions hooked:");
30814640cde1SColin Riley     strm.EOL();
3082b9c1b51eSKate Stone     for (auto b : m_runtimeHooks) {
30834640cde1SColin Riley       strm.Indent(b.second->defn->name);
30844640cde1SColin Riley       strm.EOL();
30854640cde1SColin Riley     }
3086b9c1b51eSKate Stone   } else {
30874640cde1SColin Riley     strm.Printf("Runtime is not hooked.");
30884640cde1SColin Riley     strm.EOL();
30894640cde1SColin Riley   }
30904640cde1SColin Riley }
30914640cde1SColin Riley 
3092b9c1b51eSKate Stone void RenderScriptRuntime::DumpContexts(Stream &strm) const {
30934640cde1SColin Riley   strm.Printf("Inferred RenderScript Contexts:");
30944640cde1SColin Riley   strm.EOL();
30954640cde1SColin Riley   strm.IndentMore();
30964640cde1SColin Riley 
30974640cde1SColin Riley   std::map<addr_t, uint64_t> contextReferences;
30984640cde1SColin Riley 
309905097246SAdrian Prantl   // Iterate over all of the currently discovered scripts. Note: We cant push
310005097246SAdrian Prantl   // or pop from m_scripts inside this loop or it may invalidate script.
3101b9c1b51eSKate Stone   for (const auto &script : m_scripts) {
310278f339d1SEwan Crawford     if (!script->context.isValid())
310378f339d1SEwan Crawford       continue;
310478f339d1SEwan Crawford     lldb::addr_t context = *script->context;
310578f339d1SEwan Crawford 
3106b9c1b51eSKate Stone     if (contextReferences.find(context) != contextReferences.end()) {
310778f339d1SEwan Crawford       contextReferences[context]++;
3108b9c1b51eSKate Stone     } else {
310978f339d1SEwan Crawford       contextReferences[context] = 1;
31104640cde1SColin Riley     }
31114640cde1SColin Riley   }
31124640cde1SColin Riley 
3113b9c1b51eSKate Stone   for (const auto &cRef : contextReferences) {
3114b9c1b51eSKate Stone     strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances",
3115b9c1b51eSKate Stone                 cRef.first, cRef.second);
31164640cde1SColin Riley     strm.EOL();
31174640cde1SColin Riley   }
31184640cde1SColin Riley   strm.IndentLess();
31194640cde1SColin Riley }
31204640cde1SColin Riley 
3121b9c1b51eSKate Stone void RenderScriptRuntime::DumpKernels(Stream &strm) const {
31224640cde1SColin Riley   strm.Printf("RenderScript Kernels:");
31234640cde1SColin Riley   strm.EOL();
31244640cde1SColin Riley   strm.IndentMore();
3125b9c1b51eSKate Stone   for (const auto &module : m_rsmodules) {
31264640cde1SColin Riley     strm.Printf("Resource '%s':", module->m_resname.c_str());
31274640cde1SColin Riley     strm.EOL();
3128b9c1b51eSKate Stone     for (const auto &kernel : module->m_kernels) {
31299dfd4e26SRaphael Isemann       strm.Indent(kernel.m_name.GetStringRef());
31304640cde1SColin Riley       strm.EOL();
31314640cde1SColin Riley     }
31324640cde1SColin Riley   }
31334640cde1SColin Riley   strm.IndentLess();
31344640cde1SColin Riley }
31354640cde1SColin Riley 
3136a0f08674SEwan Crawford RenderScriptRuntime::AllocationDetails *
3137b9c1b51eSKate Stone RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) {
3138a0f08674SEwan Crawford   AllocationDetails *alloc = nullptr;
3139a0f08674SEwan Crawford 
3140a0f08674SEwan Crawford   // See if we can find allocation using id as an index;
3141b9c1b51eSKate Stone   if (alloc_id <= m_allocations.size() && alloc_id != 0 &&
3142b9c1b51eSKate Stone       m_allocations[alloc_id - 1]->id == alloc_id) {
3143a0f08674SEwan Crawford     alloc = m_allocations[alloc_id - 1].get();
3144a0f08674SEwan Crawford     return alloc;
3145a0f08674SEwan Crawford   }
3146a0f08674SEwan Crawford 
3147a0f08674SEwan Crawford   // Fallback to searching
3148b9c1b51eSKate Stone   for (const auto &a : m_allocations) {
3149b9c1b51eSKate Stone     if (a->id == alloc_id) {
3150a0f08674SEwan Crawford       alloc = a.get();
3151a0f08674SEwan Crawford       break;
3152a0f08674SEwan Crawford     }
3153a0f08674SEwan Crawford   }
3154a0f08674SEwan Crawford 
3155b9c1b51eSKate Stone   if (alloc == nullptr) {
3156b9c1b51eSKate Stone     strm.Printf("Error: Couldn't find allocation with id matching %" PRIu32,
3157b9c1b51eSKate Stone                 alloc_id);
3158a0f08674SEwan Crawford     strm.EOL();
3159a0f08674SEwan Crawford   }
3160a0f08674SEwan Crawford 
3161a0f08674SEwan Crawford   return alloc;
3162a0f08674SEwan Crawford }
3163a0f08674SEwan Crawford 
3164b9c1b51eSKate Stone // Prints the contents of an allocation to the output stream, which may be a
3165b9c1b51eSKate Stone // file
3166b9c1b51eSKate Stone bool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr,
3167b9c1b51eSKate Stone                                          const uint32_t id) {
3168*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
3169a0f08674SEwan Crawford 
3170a0f08674SEwan Crawford   // Check we can find the desired allocation
3171a0f08674SEwan Crawford   AllocationDetails *alloc = FindAllocByID(strm, id);
3172a0f08674SEwan Crawford   if (!alloc)
3173a0f08674SEwan Crawford     return false; // FindAllocByID() will print error message for us here
3174a0f08674SEwan Crawford 
317563e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64, __FUNCTION__,
3176b9c1b51eSKate Stone             *alloc->address.get());
3177a0f08674SEwan Crawford 
3178a0f08674SEwan Crawford   // Check we have information about the allocation, if not calculate it
317980af0b9eSLuke Drummond   if (alloc->ShouldRefresh()) {
318063e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.",
3181b9c1b51eSKate Stone               __FUNCTION__);
3182a0f08674SEwan Crawford 
3183a0f08674SEwan Crawford     // JIT all the allocation information
3184b9c1b51eSKate Stone     if (!RefreshAllocation(alloc, frame_ptr)) {
3185a0f08674SEwan Crawford       strm.Printf("Error: Couldn't JIT allocation details");
3186a0f08674SEwan Crawford       strm.EOL();
3187a0f08674SEwan Crawford       return false;
3188a0f08674SEwan Crawford     }
3189a0f08674SEwan Crawford   }
3190a0f08674SEwan Crawford 
3191a0f08674SEwan Crawford   // Establish format and size of each data element
3192b3f7f69dSAidan Dodds   const uint32_t vec_size = *alloc->element.type_vec_size.get();
31938b244e21SEwan Crawford   const Element::DataType type = *alloc->element.type.get();
3194a0f08674SEwan Crawford 
3195b9c1b51eSKate Stone   assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT &&
3196b9c1b51eSKate Stone          "Invalid allocation type");
3197a0f08674SEwan Crawford 
31982e920715SEwan Crawford   lldb::Format format;
31992e920715SEwan Crawford   if (type >= Element::RS_TYPE_ELEMENT)
32002e920715SEwan Crawford     format = eFormatHex;
32012e920715SEwan Crawford   else
3202b9c1b51eSKate Stone     format = vec_size == 1
3203b9c1b51eSKate Stone                  ? static_cast<lldb::Format>(
3204b9c1b51eSKate Stone                        AllocationDetails::RSTypeToFormat[type][eFormatSingle])
3205b9c1b51eSKate Stone                  : static_cast<lldb::Format>(
3206b9c1b51eSKate Stone                        AllocationDetails::RSTypeToFormat[type][eFormatVector]);
3207a0f08674SEwan Crawford 
3208b3f7f69dSAidan Dodds   const uint32_t data_size = *alloc->element.datum_size.get();
3209a0f08674SEwan Crawford 
321063e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - element size %" PRIu32 " bytes, including padding",
3211b9c1b51eSKate Stone             __FUNCTION__, data_size);
3212a0f08674SEwan Crawford 
321355232f09SEwan Crawford   // Allocate a buffer to copy data into
321455232f09SEwan Crawford   std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
3215b9c1b51eSKate Stone   if (!buffer) {
32162e920715SEwan Crawford     strm.Printf("Error: Couldn't read allocation data");
321755232f09SEwan Crawford     strm.EOL();
321855232f09SEwan Crawford     return false;
321955232f09SEwan Crawford   }
322055232f09SEwan Crawford 
3221a0f08674SEwan Crawford   // Calculate stride between rows as there may be padding at end of rows since
3222a0f08674SEwan Crawford   // allocated memory is 16-byte aligned
3223b9c1b51eSKate Stone   if (!alloc->stride.isValid()) {
3224a0f08674SEwan Crawford     if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension
3225a0f08674SEwan Crawford       alloc->stride = 0;
3226b9c1b51eSKate Stone     else if (!JITAllocationStride(alloc, frame_ptr)) {
3227a0f08674SEwan Crawford       strm.Printf("Error: Couldn't calculate allocation row stride");
3228a0f08674SEwan Crawford       strm.EOL();
3229a0f08674SEwan Crawford       return false;
3230a0f08674SEwan Crawford     }
3231a0f08674SEwan Crawford   }
3232b3f7f69dSAidan Dodds   const uint32_t stride = *alloc->stride.get();
3233b3f7f69dSAidan Dodds   const uint32_t size = *alloc->size.get(); // Size of whole allocation
3234b9c1b51eSKate Stone   const uint32_t padding =
3235b9c1b51eSKate Stone       alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0;
323663e5fb76SJonas Devlieghere   LLDB_LOGF(log,
323763e5fb76SJonas Devlieghere             "%s - stride %" PRIu32 " bytes, size %" PRIu32
3238b9c1b51eSKate Stone             " bytes, padding %" PRIu32,
3239b3f7f69dSAidan Dodds             __FUNCTION__, stride, size, padding);
3240a0f08674SEwan Crawford 
3241a0f08674SEwan Crawford   // Find dimensions used to index loops, so need to be non-zero
3242b3f7f69dSAidan Dodds   uint32_t dim_x = alloc->dimension.get()->dim_1;
3243a0f08674SEwan Crawford   dim_x = dim_x == 0 ? 1 : dim_x;
3244a0f08674SEwan Crawford 
3245b3f7f69dSAidan Dodds   uint32_t dim_y = alloc->dimension.get()->dim_2;
3246a0f08674SEwan Crawford   dim_y = dim_y == 0 ? 1 : dim_y;
3247a0f08674SEwan Crawford 
3248b3f7f69dSAidan Dodds   uint32_t dim_z = alloc->dimension.get()->dim_3;
3249a0f08674SEwan Crawford   dim_z = dim_z == 0 ? 1 : dim_z;
3250a0f08674SEwan Crawford 
325155232f09SEwan Crawford   // Use data extractor to format output
325280af0b9eSLuke Drummond   const uint32_t target_ptr_size =
3253b9c1b51eSKate Stone       GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
3254b9c1b51eSKate Stone   DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(),
325580af0b9eSLuke Drummond                            target_ptr_size);
325655232f09SEwan Crawford 
3257b3f7f69dSAidan Dodds   uint32_t offset = 0;   // Offset in buffer to next element to be printed
3258b3f7f69dSAidan Dodds   uint32_t prev_row = 0; // Offset to the start of the previous row
3259a0f08674SEwan Crawford 
3260a0f08674SEwan Crawford   // Iterate over allocation dimensions, printing results to user
3261a0f08674SEwan Crawford   strm.Printf("Data (X, Y, Z):");
3262b9c1b51eSKate Stone   for (uint32_t z = 0; z < dim_z; ++z) {
3263b9c1b51eSKate Stone     for (uint32_t y = 0; y < dim_y; ++y) {
3264a0f08674SEwan Crawford       // Use stride to index start of next row.
3265a0f08674SEwan Crawford       if (!(y == 0 && z == 0))
3266a0f08674SEwan Crawford         offset = prev_row + stride;
3267a0f08674SEwan Crawford       prev_row = offset;
3268a0f08674SEwan Crawford 
3269a0f08674SEwan Crawford       // Print each element in the row individually
3270b9c1b51eSKate Stone       for (uint32_t x = 0; x < dim_x; ++x) {
3271b3f7f69dSAidan Dodds         strm.Printf("\n(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") = ", x, y, z);
3272b9c1b51eSKate Stone         if ((type == Element::RS_TYPE_NONE) &&
3273b9c1b51eSKate Stone             (alloc->element.children.size() > 0) &&
3274b9c1b51eSKate Stone             (alloc->element.type_name != Element::GetFallbackStructName())) {
327505097246SAdrian Prantl           // Here we are dumping an Element of struct type. This is done using
327605097246SAdrian Prantl           // expression evaluation with the name of the struct type and pointer
327705097246SAdrian Prantl           // to element. Don't print the name of the resulting expression,
327805097246SAdrian Prantl           // since this will be '$[0-9]+'
32798b244e21SEwan Crawford           DumpValueObjectOptions expr_options;
32808b244e21SEwan Crawford           expr_options.SetHideName(true);
32818b244e21SEwan Crawford 
32824ebdee0aSBruce Mitchener           // Setup expression as dereferencing a pointer cast to element
328305097246SAdrian Prantl           // address.
3284ea0636b5SEwan Crawford           char expr_char_buffer[jit_max_expr_size];
328580af0b9eSLuke Drummond           int written =
3286b9c1b51eSKate Stone               snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64,
3287b9c1b51eSKate Stone                        alloc->element.type_name.AsCString(),
3288b9c1b51eSKate Stone                        *alloc->data_ptr.get() + offset);
32898b244e21SEwan Crawford 
329080af0b9eSLuke Drummond           if (written < 0 || written >= jit_max_expr_size) {
329163e5fb76SJonas Devlieghere             LLDB_LOGF(log, "%s - error in snprintf().", __FUNCTION__);
32928b244e21SEwan Crawford             continue;
32938b244e21SEwan Crawford           }
32948b244e21SEwan Crawford 
32958b244e21SEwan Crawford           // Evaluate expression
32968b244e21SEwan Crawford           ValueObjectSP expr_result;
3297b9c1b51eSKate Stone           GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer,
3298b9c1b51eSKate Stone                                                        frame_ptr, expr_result);
32998b244e21SEwan Crawford 
33008b244e21SEwan Crawford           // Print the results to our stream.
33018b244e21SEwan Crawford           expr_result->Dump(strm, expr_options);
3302b9c1b51eSKate Stone         } else {
330329cb868aSZachary Turner           DumpDataExtractor(alloc_data, &strm, offset, format,
330429cb868aSZachary Turner                             data_size - padding, 1, 1, LLDB_INVALID_ADDRESS, 0,
330529cb868aSZachary Turner                             0);
33068b244e21SEwan Crawford         }
33078b244e21SEwan Crawford         offset += data_size;
3308a0f08674SEwan Crawford       }
3309a0f08674SEwan Crawford     }
3310a0f08674SEwan Crawford   }
3311a0f08674SEwan Crawford   strm.EOL();
3312a0f08674SEwan Crawford 
3313a0f08674SEwan Crawford   return true;
3314a0f08674SEwan Crawford }
3315a0f08674SEwan Crawford 
331605097246SAdrian Prantl // Function recalculates all our cached information about allocations by
331705097246SAdrian Prantl // jitting the RS runtime regarding each allocation we know about. Returns true
331805097246SAdrian Prantl // if all allocations could be recomputed, false otherwise.
3319b9c1b51eSKate Stone bool RenderScriptRuntime::RecomputeAllAllocations(Stream &strm,
3320b9c1b51eSKate Stone                                                   StackFrame *frame_ptr) {
33210d2bfcfbSEwan Crawford   bool success = true;
3322b9c1b51eSKate Stone   for (auto &alloc : m_allocations) {
33230d2bfcfbSEwan Crawford     // JIT current allocation information
3324b9c1b51eSKate Stone     if (!RefreshAllocation(alloc.get(), frame_ptr)) {
3325b9c1b51eSKate Stone       strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32
3326b9c1b51eSKate Stone                   "\n",
3327b9c1b51eSKate Stone                   alloc->id);
33280d2bfcfbSEwan Crawford       success = false;
33290d2bfcfbSEwan Crawford     }
33300d2bfcfbSEwan Crawford   }
33310d2bfcfbSEwan Crawford 
33320d2bfcfbSEwan Crawford   if (success)
33330d2bfcfbSEwan Crawford     strm.Printf("All allocations successfully recomputed");
33340d2bfcfbSEwan Crawford   strm.EOL();
33350d2bfcfbSEwan Crawford 
33360d2bfcfbSEwan Crawford   return success;
33370d2bfcfbSEwan Crawford }
33380d2bfcfbSEwan Crawford 
333980af0b9eSLuke Drummond // Prints information regarding currently loaded allocations. These details are
334080af0b9eSLuke Drummond // gathered by jitting the runtime, which has as latency. Index parameter
334180af0b9eSLuke Drummond // specifies a single allocation ID to print, or a zero value to print them all
3342b9c1b51eSKate Stone void RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame *frame_ptr,
3343b9c1b51eSKate Stone                                           const uint32_t index) {
334415f2bd95SEwan Crawford   strm.Printf("RenderScript Allocations:");
334515f2bd95SEwan Crawford   strm.EOL();
334615f2bd95SEwan Crawford   strm.IndentMore();
334715f2bd95SEwan Crawford 
3348b9c1b51eSKate Stone   for (auto &alloc : m_allocations) {
3349b649b005SEwan Crawford     // index will only be zero if we want to print all allocations
3350b649b005SEwan Crawford     if (index != 0 && index != alloc->id)
3351b649b005SEwan Crawford       continue;
335215f2bd95SEwan Crawford 
335315f2bd95SEwan Crawford     // JIT current allocation information
335480af0b9eSLuke Drummond     if (alloc->ShouldRefresh() && !RefreshAllocation(alloc.get(), frame_ptr)) {
3355b9c1b51eSKate Stone       strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32,
3356b9c1b51eSKate Stone                   alloc->id);
3357b3f7f69dSAidan Dodds       strm.EOL();
335815f2bd95SEwan Crawford       continue;
335915f2bd95SEwan Crawford     }
336015f2bd95SEwan Crawford 
3361b3f7f69dSAidan Dodds     strm.Printf("%" PRIu32 ":", alloc->id);
3362b3f7f69dSAidan Dodds     strm.EOL();
336315f2bd95SEwan Crawford     strm.IndentMore();
336415f2bd95SEwan Crawford 
336515f2bd95SEwan Crawford     strm.Indent("Context: ");
336615f2bd95SEwan Crawford     if (!alloc->context.isValid())
336715f2bd95SEwan Crawford       strm.Printf("unknown\n");
336815f2bd95SEwan Crawford     else
336915f2bd95SEwan Crawford       strm.Printf("0x%" PRIx64 "\n", *alloc->context.get());
337015f2bd95SEwan Crawford 
337115f2bd95SEwan Crawford     strm.Indent("Address: ");
337215f2bd95SEwan Crawford     if (!alloc->address.isValid())
337315f2bd95SEwan Crawford       strm.Printf("unknown\n");
337415f2bd95SEwan Crawford     else
337515f2bd95SEwan Crawford       strm.Printf("0x%" PRIx64 "\n", *alloc->address.get());
337615f2bd95SEwan Crawford 
337715f2bd95SEwan Crawford     strm.Indent("Data pointer: ");
337815f2bd95SEwan Crawford     if (!alloc->data_ptr.isValid())
337915f2bd95SEwan Crawford       strm.Printf("unknown\n");
338015f2bd95SEwan Crawford     else
338115f2bd95SEwan Crawford       strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get());
338215f2bd95SEwan Crawford 
338315f2bd95SEwan Crawford     strm.Indent("Dimensions: ");
338415f2bd95SEwan Crawford     if (!alloc->dimension.isValid())
338515f2bd95SEwan Crawford       strm.Printf("unknown\n");
338615f2bd95SEwan Crawford     else
3387b3f7f69dSAidan Dodds       strm.Printf("(%" PRId32 ", %" PRId32 ", %" PRId32 ")\n",
3388b9c1b51eSKate Stone                   alloc->dimension.get()->dim_1, alloc->dimension.get()->dim_2,
3389b9c1b51eSKate Stone                   alloc->dimension.get()->dim_3);
339015f2bd95SEwan Crawford 
339115f2bd95SEwan Crawford     strm.Indent("Data Type: ");
3392b9c1b51eSKate Stone     if (!alloc->element.type.isValid() ||
3393b9c1b51eSKate Stone         !alloc->element.type_vec_size.isValid())
339415f2bd95SEwan Crawford       strm.Printf("unknown\n");
3395b9c1b51eSKate Stone     else {
33968b244e21SEwan Crawford       const int vector_size = *alloc->element.type_vec_size.get();
33972e920715SEwan Crawford       Element::DataType type = *alloc->element.type.get();
339815f2bd95SEwan Crawford 
33998b244e21SEwan Crawford       if (!alloc->element.type_name.IsEmpty())
34008b244e21SEwan Crawford         strm.Printf("%s\n", alloc->element.type_name.AsCString());
3401b9c1b51eSKate Stone       else {
3402b9c1b51eSKate Stone         // Enum value isn't monotonous, so doesn't always index
3403b9c1b51eSKate Stone         // RsDataTypeToString array
34042e920715SEwan Crawford         if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT)
3405b9c1b51eSKate Stone           type =
3406b9c1b51eSKate Stone               static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) +
3407b3f7f69dSAidan Dodds                                              Element::RS_TYPE_MATRIX_2X2 + 1);
34082e920715SEwan Crawford 
3409b3f7f69dSAidan Dodds         if (type >= (sizeof(AllocationDetails::RsDataTypeToString) /
3410b3f7f69dSAidan Dodds                      sizeof(AllocationDetails::RsDataTypeToString[0])) ||
3411b3f7f69dSAidan Dodds             vector_size > 4 || vector_size < 1)
341215f2bd95SEwan Crawford           strm.Printf("invalid type\n");
341315f2bd95SEwan Crawford         else
3414b9c1b51eSKate Stone           strm.Printf(
3415b9c1b51eSKate Stone               "%s\n",
3416b9c1b51eSKate Stone               AllocationDetails::RsDataTypeToString[static_cast<uint32_t>(type)]
3417b3f7f69dSAidan Dodds                                                    [vector_size - 1]);
341815f2bd95SEwan Crawford       }
34192e920715SEwan Crawford     }
342015f2bd95SEwan Crawford 
342115f2bd95SEwan Crawford     strm.Indent("Data Kind: ");
34228b244e21SEwan Crawford     if (!alloc->element.type_kind.isValid())
342315f2bd95SEwan Crawford       strm.Printf("unknown\n");
3424b9c1b51eSKate Stone     else {
34258b244e21SEwan Crawford       const Element::DataKind kind = *alloc->element.type_kind.get();
34268b244e21SEwan Crawford       if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV)
342715f2bd95SEwan Crawford         strm.Printf("invalid kind\n");
342815f2bd95SEwan Crawford       else
3429b9c1b51eSKate Stone         strm.Printf(
3430b9c1b51eSKate Stone             "%s\n",
3431b9c1b51eSKate Stone             AllocationDetails::RsDataKindToString[static_cast<uint32_t>(kind)]);
343215f2bd95SEwan Crawford     }
343315f2bd95SEwan Crawford 
343415f2bd95SEwan Crawford     strm.EOL();
343515f2bd95SEwan Crawford     strm.IndentLess();
343615f2bd95SEwan Crawford   }
343715f2bd95SEwan Crawford   strm.IndentLess();
343815f2bd95SEwan Crawford }
343915f2bd95SEwan Crawford 
34407dc7771cSEwan Crawford // Set breakpoints on every kernel found in RS module
3441b9c1b51eSKate Stone void RenderScriptRuntime::BreakOnModuleKernels(
3442b9c1b51eSKate Stone     const RSModuleDescriptorSP rsmodule_sp) {
3443b9c1b51eSKate Stone   for (const auto &kernel : rsmodule_sp->m_kernels) {
34447dc7771cSEwan Crawford     // Don't set breakpoint on 'root' kernel
34457dc7771cSEwan Crawford     if (strcmp(kernel.m_name.AsCString(), "root") == 0)
34467dc7771cSEwan Crawford       continue;
34477dc7771cSEwan Crawford 
34487dc7771cSEwan Crawford     CreateKernelBreakpoint(kernel.m_name);
34497dc7771cSEwan Crawford   }
34507dc7771cSEwan Crawford }
34517dc7771cSEwan Crawford 
345280af0b9eSLuke Drummond // Method is internally called by the 'kernel breakpoint all' command to enable
345380af0b9eSLuke Drummond // or disable breaking on all kernels. When do_break is true we want to enable
345480af0b9eSLuke Drummond // this functionality. When do_break is false we want to disable it.
3455b9c1b51eSKate Stone void RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) {
3456*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language | LLDBLog::Breakpoints);
34577dc7771cSEwan Crawford 
34587dc7771cSEwan Crawford   InitSearchFilter(target);
34597dc7771cSEwan Crawford 
34607dc7771cSEwan Crawford   // Set breakpoints on all the kernels
3461b9c1b51eSKate Stone   if (do_break && !m_breakAllKernels) {
34627dc7771cSEwan Crawford     m_breakAllKernels = true;
34637dc7771cSEwan Crawford 
34647dc7771cSEwan Crawford     for (const auto &module : m_rsmodules)
34657dc7771cSEwan Crawford       BreakOnModuleKernels(module);
34667dc7771cSEwan Crawford 
346763e5fb76SJonas Devlieghere     LLDB_LOGF(log,
346863e5fb76SJonas Devlieghere               "%s(True) - breakpoints set on all currently loaded kernels.",
3469b9c1b51eSKate Stone               __FUNCTION__);
3470b9c1b51eSKate Stone   } else if (!do_break &&
3471b9c1b51eSKate Stone              m_breakAllKernels) // Breakpoints won't be set on any new kernels.
34727dc7771cSEwan Crawford   {
34737dc7771cSEwan Crawford     m_breakAllKernels = false;
34747dc7771cSEwan Crawford 
347563e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s(False) - breakpoints no longer automatically set.",
3476b9c1b51eSKate Stone               __FUNCTION__);
34777dc7771cSEwan Crawford   }
34787dc7771cSEwan Crawford }
34797dc7771cSEwan Crawford 
348005097246SAdrian Prantl // Given the name of a kernel this function creates a breakpoint using our own
348105097246SAdrian Prantl // breakpoint resolver, and returns the Breakpoint shared pointer.
34827dc7771cSEwan Crawford BreakpointSP
34830e4c4821SAdrian Prantl RenderScriptRuntime::CreateKernelBreakpoint(ConstString name) {
3484*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language | LLDBLog::Breakpoints);
34857dc7771cSEwan Crawford 
3486b9c1b51eSKate Stone   if (!m_filtersp) {
348763e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error, no breakpoint search filter set.",
348863e5fb76SJonas Devlieghere               __FUNCTION__);
34897dc7771cSEwan Crawford     return nullptr;
34907dc7771cSEwan Crawford   }
34917dc7771cSEwan Crawford 
34927dc7771cSEwan Crawford   BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name));
3493b842f2ecSJim Ingham   Target &target = GetProcess()->GetTarget();
3494b842f2ecSJim Ingham   BreakpointSP bp = target.CreateBreakpoint(
3495b9c1b51eSKate Stone       m_filtersp, resolver_sp, false, false, false);
34967dc7771cSEwan Crawford 
3497b9c1b51eSKate Stone   // Give RS breakpoints a specific name, so the user can manipulate them as a
3498b9c1b51eSKate Stone   // group.
349997206d57SZachary Turner   Status err;
3500b842f2ecSJim Ingham   target.AddNameToBreakpoint(bp, "RenderScriptKernel", err);
3501b842f2ecSJim Ingham   if (err.Fail() && log)
350263e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error setting break name, '%s'.", __FUNCTION__,
3503b3bbcb12SLuke Drummond               err.AsCString());
3504b3bbcb12SLuke Drummond 
3505b3bbcb12SLuke Drummond   return bp;
3506b3bbcb12SLuke Drummond }
3507b3bbcb12SLuke Drummond 
3508b3bbcb12SLuke Drummond BreakpointSP
35090e4c4821SAdrian Prantl RenderScriptRuntime::CreateReductionBreakpoint(ConstString name,
3510b3bbcb12SLuke Drummond                                                int kernel_types) {
3511*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language | LLDBLog::Breakpoints);
3512b3bbcb12SLuke Drummond 
3513b3bbcb12SLuke Drummond   if (!m_filtersp) {
351463e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error, no breakpoint search filter set.",
351563e5fb76SJonas Devlieghere               __FUNCTION__);
3516b3bbcb12SLuke Drummond     return nullptr;
3517b3bbcb12SLuke Drummond   }
3518b3bbcb12SLuke Drummond 
3519b3bbcb12SLuke Drummond   BreakpointResolverSP resolver_sp(new RSReduceBreakpointResolver(
3520b3bbcb12SLuke Drummond       nullptr, name, &m_rsmodules, kernel_types));
3521b842f2ecSJim Ingham   Target &target = GetProcess()->GetTarget();
3522b842f2ecSJim Ingham   BreakpointSP bp = target.CreateBreakpoint(
3523b3bbcb12SLuke Drummond       m_filtersp, resolver_sp, false, false, false);
3524b3bbcb12SLuke Drummond 
3525b3bbcb12SLuke Drummond   // Give RS breakpoints a specific name, so the user can manipulate them as a
3526b3bbcb12SLuke Drummond   // group.
352797206d57SZachary Turner   Status err;
3528b842f2ecSJim Ingham   target.AddNameToBreakpoint(bp, "RenderScriptReduction", err);
3529b842f2ecSJim Ingham   if (err.Fail() && log)
353063e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error setting break name, '%s'.", __FUNCTION__,
3531b9c1b51eSKate Stone               err.AsCString());
353254782db7SEwan Crawford 
35337dc7771cSEwan Crawford   return bp;
35347dc7771cSEwan Crawford }
35357dc7771cSEwan Crawford 
3536b9c1b51eSKate Stone // Given an expression for a variable this function tries to calculate the
353780af0b9eSLuke Drummond // variable's value. If this is possible it returns true and sets the uint64_t
353880af0b9eSLuke Drummond // parameter to the variables unsigned value. Otherwise function returns false.
3539b9c1b51eSKate Stone bool RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp,
3540b9c1b51eSKate Stone                                                 const char *var_name,
3541b9c1b51eSKate Stone                                                 uint64_t &val) {
3542*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
354397206d57SZachary Turner   Status err;
3544018f5a7eSEwan Crawford   VariableSP var_sp;
3545018f5a7eSEwan Crawford 
3546018f5a7eSEwan Crawford   // Find variable in stack frame
3547b3f7f69dSAidan Dodds   ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath(
3548b3f7f69dSAidan Dodds       var_name, eNoDynamicValues,
3549b9c1b51eSKate Stone       StackFrame::eExpressionPathOptionCheckPtrVsMember |
3550b9c1b51eSKate Stone           StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
355180af0b9eSLuke Drummond       var_sp, err));
355280af0b9eSLuke Drummond   if (!err.Success()) {
355363e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error, couldn't find '%s' in frame", __FUNCTION__,
3554b9c1b51eSKate Stone               var_name);
3555018f5a7eSEwan Crawford     return false;
3556018f5a7eSEwan Crawford   }
3557018f5a7eSEwan Crawford 
3558b3f7f69dSAidan Dodds   // Find the uint32_t value for the variable
3559018f5a7eSEwan Crawford   bool success = false;
3560018f5a7eSEwan Crawford   val = value_sp->GetValueAsUnsigned(0, &success);
3561b9c1b51eSKate Stone   if (!success) {
356263e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error, couldn't parse '%s' as an uint32_t.",
3563b9c1b51eSKate Stone               __FUNCTION__, var_name);
3564018f5a7eSEwan Crawford     return false;
3565018f5a7eSEwan Crawford   }
3566018f5a7eSEwan Crawford 
3567018f5a7eSEwan Crawford   return true;
3568018f5a7eSEwan Crawford }
3569018f5a7eSEwan Crawford 
3570b9c1b51eSKate Stone // Function attempts to find the current coordinate of a kernel invocation by
357180af0b9eSLuke Drummond // investigating the values of frame variables in the .expand function. These
357280af0b9eSLuke Drummond // coordinates are returned via the coord array reference parameter. Returns
357380af0b9eSLuke Drummond // true if the coordinates could be found, and false otherwise.
3574b9c1b51eSKate Stone bool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord,
3575b9c1b51eSKate Stone                                               Thread *thread_ptr) {
357600f56eebSLuke Drummond   static const char *const x_expr = "rsIndex";
357700f56eebSLuke Drummond   static const char *const y_expr = "p->current.y";
357800f56eebSLuke Drummond   static const char *const z_expr = "p->current.z";
35791e05c3bcSGreg Clayton 
3580*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
35814f8817c2SEwan Crawford 
3582b9c1b51eSKate Stone   if (!thread_ptr) {
358363e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - Error, No thread pointer", __FUNCTION__);
35844f8817c2SEwan Crawford 
35854f8817c2SEwan Crawford     return false;
35864f8817c2SEwan Crawford   }
35874f8817c2SEwan Crawford 
3588b9c1b51eSKate Stone   // Walk the call stack looking for a function whose name has the suffix
358980af0b9eSLuke Drummond   // '.expand' and contains the variables we're looking for.
3590b9c1b51eSKate Stone   for (uint32_t i = 0; i < thread_ptr->GetStackFrameCount(); ++i) {
35914f8817c2SEwan Crawford     if (!thread_ptr->SetSelectedFrameByIndex(i))
35924f8817c2SEwan Crawford       continue;
35934f8817c2SEwan Crawford 
35944f8817c2SEwan Crawford     StackFrameSP frame_sp = thread_ptr->GetSelectedFrame();
35954f8817c2SEwan Crawford     if (!frame_sp)
35964f8817c2SEwan Crawford       continue;
35974f8817c2SEwan Crawford 
35984f8817c2SEwan Crawford     // Find the function name
3599991e4453SZachary Turner     const SymbolContext sym_ctx =
3600991e4453SZachary Turner         frame_sp->GetSymbolContext(eSymbolContextFunction);
360100f56eebSLuke Drummond     const ConstString func_name = sym_ctx.GetFunctionName();
360200f56eebSLuke Drummond     if (!func_name)
36034f8817c2SEwan Crawford       continue;
36044f8817c2SEwan Crawford 
360563e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - Inspecting function '%s'", __FUNCTION__,
360600f56eebSLuke Drummond               func_name.GetCString());
36074f8817c2SEwan Crawford 
36084f8817c2SEwan Crawford     // Check if function name has .expand suffix
360900f56eebSLuke Drummond     if (!func_name.GetStringRef().endswith(".expand"))
36104f8817c2SEwan Crawford       continue;
36114f8817c2SEwan Crawford 
361263e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - Found .expand function '%s'", __FUNCTION__,
361300f56eebSLuke Drummond               func_name.GetCString());
36144f8817c2SEwan Crawford 
361505097246SAdrian Prantl     // Get values for variables in .expand frame that tell us the current
361605097246SAdrian Prantl     // kernel invocation
361700f56eebSLuke Drummond     uint64_t x, y, z;
361800f56eebSLuke Drummond     bool found = GetFrameVarAsUnsigned(frame_sp, x_expr, x) &&
361900f56eebSLuke Drummond                  GetFrameVarAsUnsigned(frame_sp, y_expr, y) &&
362000f56eebSLuke Drummond                  GetFrameVarAsUnsigned(frame_sp, z_expr, z);
36214f8817c2SEwan Crawford 
362200f56eebSLuke Drummond     if (found) {
362300f56eebSLuke Drummond       // The RenderScript runtime uses uint32_t for these vars. If they're not
362400f56eebSLuke Drummond       // within bounds, our frame parsing is garbage
362500f56eebSLuke Drummond       assert(x <= UINT32_MAX && y <= UINT32_MAX && z <= UINT32_MAX);
362600f56eebSLuke Drummond       coord.x = (uint32_t)x;
362700f56eebSLuke Drummond       coord.y = (uint32_t)y;
362800f56eebSLuke Drummond       coord.z = (uint32_t)z;
36294f8817c2SEwan Crawford       return true;
36304f8817c2SEwan Crawford     }
363100f56eebSLuke Drummond   }
36324f8817c2SEwan Crawford   return false;
36334f8817c2SEwan Crawford }
36344f8817c2SEwan Crawford 
3635b9c1b51eSKate Stone // Callback when a kernel breakpoint hits and we're looking for a specific
363680af0b9eSLuke Drummond // coordinate. Baton parameter contains a pointer to the target coordinate we
363705097246SAdrian Prantl // want to break on. Function then checks the .expand frame for the current
363805097246SAdrian Prantl // coordinate and breaks to user if it matches. Parameter 'break_id' is the id
363905097246SAdrian Prantl // of the Breakpoint which made the callback. Parameter 'break_loc_id' is the
364005097246SAdrian Prantl // id for the BreakpointLocation which was hit, a single logical breakpoint can
364105097246SAdrian Prantl // have multiple addresses.
3642b9c1b51eSKate Stone bool RenderScriptRuntime::KernelBreakpointHit(void *baton,
3643b9c1b51eSKate Stone                                               StoppointCallbackContext *ctx,
3644b9c1b51eSKate Stone                                               user_id_t break_id,
3645b9c1b51eSKate Stone                                               user_id_t break_loc_id) {
3646*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language | LLDBLog::Breakpoints);
3647018f5a7eSEwan Crawford 
3648b9c1b51eSKate Stone   assert(baton &&
3649b9c1b51eSKate Stone          "Error: null baton in conditional kernel breakpoint callback");
3650018f5a7eSEwan Crawford 
3651018f5a7eSEwan Crawford   // Coordinate we want to stop on
365200f56eebSLuke Drummond   RSCoordinate target_coord = *static_cast<RSCoordinate *>(baton);
3653018f5a7eSEwan Crawford 
365463e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - Break ID %" PRIu64 ", " FMT_COORD, __FUNCTION__,
365563e5fb76SJonas Devlieghere             break_id, target_coord.x, target_coord.y, target_coord.z);
3656018f5a7eSEwan Crawford 
36574f8817c2SEwan Crawford   // Select current thread
3658018f5a7eSEwan Crawford   ExecutionContext context(ctx->exe_ctx_ref);
36594f8817c2SEwan Crawford   Thread *thread_ptr = context.GetThreadPtr();
36604f8817c2SEwan Crawford   assert(thread_ptr && "Null thread pointer");
36614f8817c2SEwan Crawford 
36624f8817c2SEwan Crawford   // Find current kernel invocation from .expand frame variables
366300f56eebSLuke Drummond   RSCoordinate current_coord{};
3664b9c1b51eSKate Stone   if (!GetKernelCoordinate(current_coord, thread_ptr)) {
366563e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - Error, couldn't select .expand stack frame",
3666b9c1b51eSKate Stone               __FUNCTION__);
3667018f5a7eSEwan Crawford     return false;
3668018f5a7eSEwan Crawford   }
3669018f5a7eSEwan Crawford 
367063e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s - " FMT_COORD, __FUNCTION__, current_coord.x,
367100f56eebSLuke Drummond             current_coord.y, current_coord.z);
3672018f5a7eSEwan Crawford 
3673b9c1b51eSKate Stone   // Check if the current kernel invocation coordinate matches our target
3674b9c1b51eSKate Stone   // coordinate
367500f56eebSLuke Drummond   if (target_coord == current_coord) {
367663e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s, BREAKING " FMT_COORD, __FUNCTION__, current_coord.x,
367700f56eebSLuke Drummond               current_coord.y, current_coord.z);
3678018f5a7eSEwan Crawford 
3679b9c1b51eSKate Stone     BreakpointSP breakpoint_sp =
3680b9c1b51eSKate Stone         context.GetTargetPtr()->GetBreakpointByID(break_id);
3681b9c1b51eSKate Stone     assert(breakpoint_sp != nullptr &&
3682b9c1b51eSKate Stone            "Error: Couldn't find breakpoint matching break id for callback");
3683b9c1b51eSKate Stone     breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint
3684b9c1b51eSKate Stone                                       // should only be hit once.
3685018f5a7eSEwan Crawford     return true;
3686018f5a7eSEwan Crawford   }
3687018f5a7eSEwan Crawford 
3688018f5a7eSEwan Crawford   // No match on coordinate
3689018f5a7eSEwan Crawford   return false;
3690018f5a7eSEwan Crawford }
3691018f5a7eSEwan Crawford 
369200f56eebSLuke Drummond void RenderScriptRuntime::SetConditional(BreakpointSP bp, Stream &messages,
369300f56eebSLuke Drummond                                          const RSCoordinate &coord) {
369400f56eebSLuke Drummond   messages.Printf("Conditional kernel breakpoint on coordinate " FMT_COORD,
369500f56eebSLuke Drummond                   coord.x, coord.y, coord.z);
369600f56eebSLuke Drummond   messages.EOL();
369700f56eebSLuke Drummond 
369800f56eebSLuke Drummond   // Allocate memory for the baton, and copy over coordinate
369900f56eebSLuke Drummond   RSCoordinate *baton = new RSCoordinate(coord);
370000f56eebSLuke Drummond 
370100f56eebSLuke Drummond   // Create a callback that will be invoked every time the breakpoint is hit.
370200f56eebSLuke Drummond   // The baton object passed to the handler is the target coordinate we want to
370300f56eebSLuke Drummond   // break on.
370400f56eebSLuke Drummond   bp->SetCallback(KernelBreakpointHit, baton, true);
370500f56eebSLuke Drummond 
370600f56eebSLuke Drummond   // Store a shared pointer to the baton, so the memory will eventually be
370700f56eebSLuke Drummond   // cleaned up after destruction
370800f56eebSLuke Drummond   m_conditional_breaks[bp->GetID()] = std::unique_ptr<RSCoordinate>(baton);
370900f56eebSLuke Drummond }
371000f56eebSLuke Drummond 
371105097246SAdrian Prantl // Tries to set a breakpoint on the start of a kernel, resolved using the
371205097246SAdrian Prantl // kernel name. Argument 'coords', represents a three dimensional coordinate
371305097246SAdrian Prantl // which can be used to specify a single kernel instance to break on. If this
371405097246SAdrian Prantl // is set then we add a callback to the breakpoint.
371500f56eebSLuke Drummond bool RenderScriptRuntime::PlaceBreakpointOnKernel(TargetSP target,
371600f56eebSLuke Drummond                                                   Stream &messages,
371700f56eebSLuke Drummond                                                   const char *name,
371800f56eebSLuke Drummond                                                   const RSCoordinate *coord) {
371900f56eebSLuke Drummond   if (!name)
372000f56eebSLuke Drummond     return false;
37214640cde1SColin Riley 
37227dc7771cSEwan Crawford   InitSearchFilter(target);
372398156583SEwan Crawford 
37244640cde1SColin Riley   ConstString kernel_name(name);
37257dc7771cSEwan Crawford   BreakpointSP bp = CreateKernelBreakpoint(kernel_name);
372600f56eebSLuke Drummond   if (!bp)
372700f56eebSLuke Drummond     return false;
3728018f5a7eSEwan Crawford 
3729018f5a7eSEwan Crawford   // We have a conditional breakpoint on a specific coordinate
373000f56eebSLuke Drummond   if (coord)
373100f56eebSLuke Drummond     SetConditional(bp, messages, *coord);
3732018f5a7eSEwan Crawford 
373300f56eebSLuke Drummond   bp->GetDescription(&messages, lldb::eDescriptionLevelInitial, false);
3734018f5a7eSEwan Crawford 
373500f56eebSLuke Drummond   return true;
37364640cde1SColin Riley }
37374640cde1SColin Riley 
373821fed052SAidan Dodds BreakpointSP
37390e4c4821SAdrian Prantl RenderScriptRuntime::CreateScriptGroupBreakpoint(ConstString name,
374021fed052SAidan Dodds                                                  bool stop_on_all) {
3741*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language | LLDBLog::Breakpoints);
374221fed052SAidan Dodds 
374321fed052SAidan Dodds   if (!m_filtersp) {
374463e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error, no breakpoint search filter set.",
374563e5fb76SJonas Devlieghere               __FUNCTION__);
374621fed052SAidan Dodds     return nullptr;
374721fed052SAidan Dodds   }
374821fed052SAidan Dodds 
374921fed052SAidan Dodds   BreakpointResolverSP resolver_sp(new RSScriptGroupBreakpointResolver(
375021fed052SAidan Dodds       nullptr, name, m_scriptGroups, stop_on_all));
3751b842f2ecSJim Ingham   Target &target = GetProcess()->GetTarget();
3752b842f2ecSJim Ingham   BreakpointSP bp = target.CreateBreakpoint(
375321fed052SAidan Dodds       m_filtersp, resolver_sp, false, false, false);
375421fed052SAidan Dodds   // Give RS breakpoints a specific name, so the user can manipulate them as a
375521fed052SAidan Dodds   // group.
375697206d57SZachary Turner   Status err;
3757b842f2ecSJim Ingham   target.AddNameToBreakpoint(bp, name.GetCString(), err);
3758b842f2ecSJim Ingham   if (err.Fail() && log)
375963e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s - error setting break name, '%s'.", __FUNCTION__,
376021fed052SAidan Dodds               err.AsCString());
376121fed052SAidan Dodds   // ask the breakpoint to resolve itself
376221fed052SAidan Dodds   bp->ResolveBreakpoint();
376321fed052SAidan Dodds   return bp;
376421fed052SAidan Dodds }
376521fed052SAidan Dodds 
376621fed052SAidan Dodds bool RenderScriptRuntime::PlaceBreakpointOnScriptGroup(TargetSP target,
376721fed052SAidan Dodds                                                        Stream &strm,
37680e4c4821SAdrian Prantl                                                        ConstString name,
376921fed052SAidan Dodds                                                        bool multi) {
377021fed052SAidan Dodds   InitSearchFilter(target);
377121fed052SAidan Dodds   BreakpointSP bp = CreateScriptGroupBreakpoint(name, multi);
377221fed052SAidan Dodds   if (bp)
377321fed052SAidan Dodds     bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false);
377421fed052SAidan Dodds   return bool(bp);
377521fed052SAidan Dodds }
377621fed052SAidan Dodds 
3777b3bbcb12SLuke Drummond bool RenderScriptRuntime::PlaceBreakpointOnReduction(TargetSP target,
3778b3bbcb12SLuke Drummond                                                      Stream &messages,
3779b3bbcb12SLuke Drummond                                                      const char *reduce_name,
3780b3bbcb12SLuke Drummond                                                      const RSCoordinate *coord,
3781b3bbcb12SLuke Drummond                                                      int kernel_types) {
3782b3bbcb12SLuke Drummond   if (!reduce_name)
3783b3bbcb12SLuke Drummond     return false;
3784b3bbcb12SLuke Drummond 
3785b3bbcb12SLuke Drummond   InitSearchFilter(target);
3786b3bbcb12SLuke Drummond   BreakpointSP bp =
3787b3bbcb12SLuke Drummond       CreateReductionBreakpoint(ConstString(reduce_name), kernel_types);
3788b3bbcb12SLuke Drummond   if (!bp)
3789b3bbcb12SLuke Drummond     return false;
3790b3bbcb12SLuke Drummond 
3791b3bbcb12SLuke Drummond   if (coord)
3792b3bbcb12SLuke Drummond     SetConditional(bp, messages, *coord);
3793b3bbcb12SLuke Drummond 
3794b3bbcb12SLuke Drummond   bp->GetDescription(&messages, lldb::eDescriptionLevelInitial, false);
3795b3bbcb12SLuke Drummond 
3796b3bbcb12SLuke Drummond   return true;
3797b3bbcb12SLuke Drummond }
3798b3bbcb12SLuke Drummond 
3799b9c1b51eSKate Stone void RenderScriptRuntime::DumpModules(Stream &strm) const {
38005ec532a9SColin Riley   strm.Printf("RenderScript Modules:");
38015ec532a9SColin Riley   strm.EOL();
38025ec532a9SColin Riley   strm.IndentMore();
3803b9c1b51eSKate Stone   for (const auto &module : m_rsmodules) {
38044640cde1SColin Riley     module->Dump(strm);
38055ec532a9SColin Riley   }
38065ec532a9SColin Riley   strm.IndentLess();
38075ec532a9SColin Riley }
38085ec532a9SColin Riley 
380978f339d1SEwan Crawford RenderScriptRuntime::ScriptDetails *
3810b9c1b51eSKate Stone RenderScriptRuntime::LookUpScript(addr_t address, bool create) {
3811b9c1b51eSKate Stone   for (const auto &s : m_scripts) {
381278f339d1SEwan Crawford     if (s->script.isValid())
381378f339d1SEwan Crawford       if (*s->script == address)
381478f339d1SEwan Crawford         return s.get();
381578f339d1SEwan Crawford   }
3816b9c1b51eSKate Stone   if (create) {
381778f339d1SEwan Crawford     std::unique_ptr<ScriptDetails> s(new ScriptDetails);
381878f339d1SEwan Crawford     s->script = address;
381978f339d1SEwan Crawford     m_scripts.push_back(std::move(s));
3820d10ca9deSEwan Crawford     return m_scripts.back().get();
382178f339d1SEwan Crawford   }
382278f339d1SEwan Crawford   return nullptr;
382378f339d1SEwan Crawford }
382478f339d1SEwan Crawford 
382578f339d1SEwan Crawford RenderScriptRuntime::AllocationDetails *
3826b9c1b51eSKate Stone RenderScriptRuntime::LookUpAllocation(addr_t address) {
3827b9c1b51eSKate Stone   for (const auto &a : m_allocations) {
382878f339d1SEwan Crawford     if (a->address.isValid())
382978f339d1SEwan Crawford       if (*a->address == address)
383078f339d1SEwan Crawford         return a.get();
383178f339d1SEwan Crawford   }
38325d057637SLuke Drummond   return nullptr;
38335d057637SLuke Drummond }
38345d057637SLuke Drummond 
38355d057637SLuke Drummond RenderScriptRuntime::AllocationDetails *
3836b9c1b51eSKate Stone RenderScriptRuntime::CreateAllocation(addr_t address) {
3837*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Language);
38385d057637SLuke Drummond 
38395d057637SLuke Drummond   // Remove any previous allocation which contains the same address
38405d057637SLuke Drummond   auto it = m_allocations.begin();
3841b9c1b51eSKate Stone   while (it != m_allocations.end()) {
3842b9c1b51eSKate Stone     if (*((*it)->address) == address) {
384363e5fb76SJonas Devlieghere       LLDB_LOGF(log, "%s - Removing allocation id: %d, address: 0x%" PRIx64,
3844b9c1b51eSKate Stone                 __FUNCTION__, (*it)->id, address);
38455d057637SLuke Drummond 
38465d057637SLuke Drummond       it = m_allocations.erase(it);
3847b9c1b51eSKate Stone     } else {
38485d057637SLuke Drummond       it++;
38495d057637SLuke Drummond     }
38505d057637SLuke Drummond   }
38515d057637SLuke Drummond 
385278f339d1SEwan Crawford   std::unique_ptr<AllocationDetails> a(new AllocationDetails);
385378f339d1SEwan Crawford   a->address = address;
385478f339d1SEwan Crawford   m_allocations.push_back(std::move(a));
3855d10ca9deSEwan Crawford   return m_allocations.back().get();
385678f339d1SEwan Crawford }
385778f339d1SEwan Crawford 
385821fed052SAidan Dodds bool RenderScriptRuntime::ResolveKernelName(lldb::addr_t kernel_addr,
385921fed052SAidan Dodds                                             ConstString &name) {
3860*a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Symbols);
386121fed052SAidan Dodds 
386221fed052SAidan Dodds   Target &target = GetProcess()->GetTarget();
386321fed052SAidan Dodds   Address resolved;
386421fed052SAidan Dodds   // RenderScript module
386521fed052SAidan Dodds   if (!target.GetSectionLoadList().ResolveLoadAddress(kernel_addr, resolved)) {
386663e5fb76SJonas Devlieghere     LLDB_LOGF(log, "%s: unable to resolve 0x%" PRIx64 " to a loaded symbol",
386721fed052SAidan Dodds               __FUNCTION__, kernel_addr);
386821fed052SAidan Dodds     return false;
386921fed052SAidan Dodds   }
387021fed052SAidan Dodds 
387121fed052SAidan Dodds   Symbol *sym = resolved.CalculateSymbolContextSymbol();
387221fed052SAidan Dodds   if (!sym)
387321fed052SAidan Dodds     return false;
387421fed052SAidan Dodds 
387521fed052SAidan Dodds   name = sym->GetName();
387621fed052SAidan Dodds   assert(IsRenderScriptModule(resolved.CalculateSymbolContextModule()));
387763e5fb76SJonas Devlieghere   LLDB_LOGF(log, "%s: 0x%" PRIx64 " resolved to the symbol '%s'", __FUNCTION__,
387821fed052SAidan Dodds             kernel_addr, name.GetCString());
387921fed052SAidan Dodds   return true;
388021fed052SAidan Dodds }
388121fed052SAidan Dodds 
3882b9c1b51eSKate Stone void RSModuleDescriptor::Dump(Stream &strm) const {
38837f193d69SLuke Drummond   int indent = strm.GetIndentLevel();
38847f193d69SLuke Drummond 
38855ec532a9SColin Riley   strm.Indent();
38864dac97ebSRaphael Isemann   m_module->GetFileSpec().Dump(strm.AsRawOstream());
38877f193d69SLuke Drummond   strm.Indent(m_module->GetNumCompileUnits() ? "Debug info loaded."
38887f193d69SLuke Drummond                                              : "Debug info does not exist.");
38895ec532a9SColin Riley   strm.EOL();
38905ec532a9SColin Riley   strm.IndentMore();
38917f193d69SLuke Drummond 
38925ec532a9SColin Riley   strm.Indent();
3893189598edSColin Riley   strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size()));
38945ec532a9SColin Riley   strm.EOL();
38955ec532a9SColin Riley   strm.IndentMore();
3896b9c1b51eSKate Stone   for (const auto &global : m_globals) {
38975ec532a9SColin Riley     global.Dump(strm);
38985ec532a9SColin Riley   }
38995ec532a9SColin Riley   strm.IndentLess();
39007f193d69SLuke Drummond 
39015ec532a9SColin Riley   strm.Indent();
3902189598edSColin Riley   strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size()));
39035ec532a9SColin Riley   strm.EOL();
39045ec532a9SColin Riley   strm.IndentMore();
3905b9c1b51eSKate Stone   for (const auto &kernel : m_kernels) {
39065ec532a9SColin Riley     kernel.Dump(strm);
39075ec532a9SColin Riley   }
39087f193d69SLuke Drummond   strm.IndentLess();
39097f193d69SLuke Drummond 
39107f193d69SLuke Drummond   strm.Indent();
39114640cde1SColin Riley   strm.Printf("Pragmas: %" PRIu64, static_cast<uint64_t>(m_pragmas.size()));
39124640cde1SColin Riley   strm.EOL();
39134640cde1SColin Riley   strm.IndentMore();
3914b9c1b51eSKate Stone   for (const auto &key_val : m_pragmas) {
39157f193d69SLuke Drummond     strm.Indent();
39164640cde1SColin Riley     strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str());
39174640cde1SColin Riley     strm.EOL();
39184640cde1SColin Riley   }
39197f193d69SLuke Drummond   strm.IndentLess();
39207f193d69SLuke Drummond 
39217f193d69SLuke Drummond   strm.Indent();
39227f193d69SLuke Drummond   strm.Printf("Reductions: %" PRIu64,
39237f193d69SLuke Drummond               static_cast<uint64_t>(m_reductions.size()));
39247f193d69SLuke Drummond   strm.EOL();
39257f193d69SLuke Drummond   strm.IndentMore();
39267f193d69SLuke Drummond   for (const auto &reduction : m_reductions) {
39277f193d69SLuke Drummond     reduction.Dump(strm);
39287f193d69SLuke Drummond   }
39297f193d69SLuke Drummond 
39307f193d69SLuke Drummond   strm.SetIndentLevel(indent);
39315ec532a9SColin Riley }
39325ec532a9SColin Riley 
3933b9c1b51eSKate Stone void RSGlobalDescriptor::Dump(Stream &strm) const {
39349dfd4e26SRaphael Isemann   strm.Indent(m_name.GetStringRef());
39354640cde1SColin Riley   VariableList var_list;
3936f9568a95SRaphael Isemann   m_module->m_module->FindGlobalVariables(m_name, CompilerDeclContext(), 1U,
3937f9568a95SRaphael Isemann                                           var_list);
3938b9c1b51eSKate Stone   if (var_list.GetSize() == 1) {
39394640cde1SColin Riley     auto var = var_list.GetVariableAtIndex(0);
39404640cde1SColin Riley     auto type = var->GetType();
3941b9c1b51eSKate Stone     if (type) {
39424640cde1SColin Riley       strm.Printf(" - ");
39434640cde1SColin Riley       type->DumpTypeName(&strm);
3944b9c1b51eSKate Stone     } else {
39454640cde1SColin Riley       strm.Printf(" - Unknown Type");
39464640cde1SColin Riley     }
3947b9c1b51eSKate Stone   } else {
39484640cde1SColin Riley     strm.Printf(" - variable identified, but not found in binary");
3949b9c1b51eSKate Stone     const Symbol *s = m_module->m_module->FindFirstSymbolWithNameAndType(
3950b9c1b51eSKate Stone         m_name, eSymbolTypeData);
3951b9c1b51eSKate Stone     if (s) {
39524640cde1SColin Riley       strm.Printf(" (symbol exists) ");
39534640cde1SColin Riley     }
39544640cde1SColin Riley   }
39554640cde1SColin Riley 
39565ec532a9SColin Riley   strm.EOL();
39575ec532a9SColin Riley }
39585ec532a9SColin Riley 
3959b9c1b51eSKate Stone void RSKernelDescriptor::Dump(Stream &strm) const {
39609dfd4e26SRaphael Isemann   strm.Indent(m_name.GetStringRef());
39615ec532a9SColin Riley   strm.EOL();
39625ec532a9SColin Riley }
39635ec532a9SColin Riley 
39647f193d69SLuke Drummond void RSReductionDescriptor::Dump(lldb_private::Stream &stream) const {
39659dfd4e26SRaphael Isemann   stream.Indent(m_reduce_name.GetStringRef());
39667f193d69SLuke Drummond   stream.IndentMore();
39677f193d69SLuke Drummond   stream.EOL();
39687f193d69SLuke Drummond   stream.Indent();
39697f193d69SLuke Drummond   stream.Printf("accumulator: %s", m_accum_name.AsCString());
39707f193d69SLuke Drummond   stream.EOL();
39717f193d69SLuke Drummond   stream.Indent();
39727f193d69SLuke Drummond   stream.Printf("initializer: %s", m_init_name.AsCString());
39737f193d69SLuke Drummond   stream.EOL();
39747f193d69SLuke Drummond   stream.Indent();
39757f193d69SLuke Drummond   stream.Printf("combiner: %s", m_comb_name.AsCString());
39767f193d69SLuke Drummond   stream.EOL();
39777f193d69SLuke Drummond   stream.Indent();
39787f193d69SLuke Drummond   stream.Printf("outconverter: %s", m_outc_name.AsCString());
39797f193d69SLuke Drummond   stream.EOL();
39807f193d69SLuke Drummond   // XXX This is currently unspecified by RenderScript, and unused
39817f193d69SLuke Drummond   // stream.Indent();
39827f193d69SLuke Drummond   // stream.Printf("halter: '%s'", m_init_name.AsCString());
39837f193d69SLuke Drummond   // stream.EOL();
39847f193d69SLuke Drummond   stream.IndentLess();
39857f193d69SLuke Drummond }
39867f193d69SLuke Drummond 
3987b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed {
39885ec532a9SColin Riley public:
39895ec532a9SColin Riley   CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter)
3990b9c1b51eSKate Stone       : CommandObjectParsed(
3991b9c1b51eSKate Stone             interpreter, "renderscript module dump",
3992b9c1b51eSKate Stone             "Dumps renderscript specific information for all modules.",
3993b9c1b51eSKate Stone             "renderscript module dump",
3994b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
39955ec532a9SColin Riley 
3996222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeModuleDump() override = default;
39975ec532a9SColin Riley 
3998b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
3999056f6f18SAlex Langford     RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>(
4000056f6f18SAlex Langford         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4001056f6f18SAlex Langford             eLanguageTypeExtRenderScript));
40025ec532a9SColin Riley     runtime->DumpModules(result.GetOutputStream());
40035ec532a9SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
40045ec532a9SColin Riley     return true;
40055ec532a9SColin Riley   }
40065ec532a9SColin Riley };
40075ec532a9SColin Riley 
4008b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword {
40095ec532a9SColin Riley public:
40105ec532a9SColin Riley   CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter)
4011b9c1b51eSKate Stone       : CommandObjectMultiword(interpreter, "renderscript module",
4012b9c1b51eSKate Stone                                "Commands that deal with RenderScript modules.",
4013b9c1b51eSKate Stone                                nullptr) {
4014b9c1b51eSKate Stone     LoadSubCommand(
4015b9c1b51eSKate Stone         "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump(
4016b9c1b51eSKate Stone                     interpreter)));
40175ec532a9SColin Riley   }
40185ec532a9SColin Riley 
4019222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeModule() override = default;
40205ec532a9SColin Riley };
40215ec532a9SColin Riley 
4022b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed {
40234640cde1SColin Riley public:
40244640cde1SColin Riley   CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter)
4025b9c1b51eSKate Stone       : CommandObjectParsed(
4026b9c1b51eSKate Stone             interpreter, "renderscript kernel list",
4027b3f7f69dSAidan Dodds             "Lists renderscript kernel names and associated script resources.",
4028b9c1b51eSKate Stone             "renderscript kernel list",
4029b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
40304640cde1SColin Riley 
4031222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelList() override = default;
40324640cde1SColin Riley 
4033b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
4034056f6f18SAlex Langford     RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>(
4035056f6f18SAlex Langford         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4036056f6f18SAlex Langford             eLanguageTypeExtRenderScript));
40374640cde1SColin Riley     runtime->DumpKernels(result.GetOutputStream());
40384640cde1SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
40394640cde1SColin Riley     return true;
40404640cde1SColin Riley   }
40414640cde1SColin Riley };
40424640cde1SColin Riley 
40438fe53c49STatyana Krasnukha static constexpr OptionDefinition g_renderscript_reduction_bp_set_options[] = {
4044b3bbcb12SLuke Drummond     {LLDB_OPT_SET_1, false, "function-role", 't',
40458fe53c49STatyana Krasnukha      OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOneLiner,
4046b3bbcb12SLuke Drummond      "Break on a comma separated set of reduction kernel types "
4047b3bbcb12SLuke Drummond      "(accumulator,outcoverter,combiner,initializer"},
4048b3bbcb12SLuke Drummond     {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument,
40498fe53c49STatyana Krasnukha      nullptr, {}, 0, eArgTypeValue,
4050b3bbcb12SLuke Drummond      "Set a breakpoint on a single invocation of the kernel with specified "
4051b3bbcb12SLuke Drummond      "coordinate.\n"
4052b3bbcb12SLuke Drummond      "Coordinate takes the form 'x[,y][,z] where x,y,z are positive "
4053b3bbcb12SLuke Drummond      "integers representing kernel dimensions. "
4054b3bbcb12SLuke Drummond      "Any unset dimensions will be defaulted to zero."}};
4055b3bbcb12SLuke Drummond 
4056b3bbcb12SLuke Drummond class CommandObjectRenderScriptRuntimeReductionBreakpointSet
4057b3bbcb12SLuke Drummond     : public CommandObjectParsed {
4058b3bbcb12SLuke Drummond public:
4059b3bbcb12SLuke Drummond   CommandObjectRenderScriptRuntimeReductionBreakpointSet(
4060b3bbcb12SLuke Drummond       CommandInterpreter &interpreter)
4061b3bbcb12SLuke Drummond       : CommandObjectParsed(
4062b3bbcb12SLuke Drummond             interpreter, "renderscript reduction breakpoint set",
4063b3bbcb12SLuke Drummond             "Set a breakpoint on named RenderScript general reductions",
4064b3bbcb12SLuke Drummond             "renderscript reduction breakpoint set  <kernel_name> [-t "
4065b3bbcb12SLuke Drummond             "<reduction_kernel_type,...>]",
4066b3bbcb12SLuke Drummond             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
4067b3bbcb12SLuke Drummond                 eCommandProcessMustBePaused),
4068b3bbcb12SLuke Drummond         m_options(){};
4069b3bbcb12SLuke Drummond 
4070b3bbcb12SLuke Drummond   class CommandOptions : public Options {
4071b3bbcb12SLuke Drummond   public:
40729494c510SJonas Devlieghere     CommandOptions() : Options() {}
4073b3bbcb12SLuke Drummond 
4074b3bbcb12SLuke Drummond     ~CommandOptions() override = default;
4075b3bbcb12SLuke Drummond 
407697206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
4077b3bbcb12SLuke Drummond                           ExecutionContext *exe_ctx) override {
407897206d57SZachary Turner       Status err;
4079b3bbcb12SLuke Drummond       StreamString err_str;
4080b3bbcb12SLuke Drummond       const int short_option = m_getopt_table[option_idx].val;
4081b3bbcb12SLuke Drummond       switch (short_option) {
4082b3bbcb12SLuke Drummond       case 't':
4083fe11483bSZachary Turner         if (!ParseReductionTypes(option_arg, err_str))
4084b3bbcb12SLuke Drummond           err.SetErrorStringWithFormat(
4085fe11483bSZachary Turner               "Unable to deduce reduction types for %s: %s",
4086fe11483bSZachary Turner               option_arg.str().c_str(), err_str.GetData());
4087b3bbcb12SLuke Drummond         break;
4088b3bbcb12SLuke Drummond       case 'c': {
4089b3bbcb12SLuke Drummond         auto coord = RSCoordinate{};
4090fe11483bSZachary Turner         if (!ParseCoordinate(option_arg, coord))
4091b3bbcb12SLuke Drummond           err.SetErrorStringWithFormat("unable to parse coordinate for %s",
4092fe11483bSZachary Turner                                        option_arg.str().c_str());
4093b3bbcb12SLuke Drummond         else {
4094b3bbcb12SLuke Drummond           m_have_coord = true;
4095b3bbcb12SLuke Drummond           m_coord = coord;
4096b3bbcb12SLuke Drummond         }
4097b3bbcb12SLuke Drummond         break;
4098b3bbcb12SLuke Drummond       }
4099b3bbcb12SLuke Drummond       default:
4100b3bbcb12SLuke Drummond         err.SetErrorStringWithFormat("Invalid option '-%c'", short_option);
4101b3bbcb12SLuke Drummond       }
4102b3bbcb12SLuke Drummond       return err;
4103b3bbcb12SLuke Drummond     }
4104b3bbcb12SLuke Drummond 
4105b3bbcb12SLuke Drummond     void OptionParsingStarting(ExecutionContext *exe_ctx) override {
4106b3bbcb12SLuke Drummond       m_have_coord = false;
4107b3bbcb12SLuke Drummond     }
4108b3bbcb12SLuke Drummond 
4109b3bbcb12SLuke Drummond     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
4110b3bbcb12SLuke Drummond       return llvm::makeArrayRef(g_renderscript_reduction_bp_set_options);
4111b3bbcb12SLuke Drummond     }
4112b3bbcb12SLuke Drummond 
4113fe11483bSZachary Turner     bool ParseReductionTypes(llvm::StringRef option_val,
4114fe11483bSZachary Turner                              StreamString &err_str) {
4115b3bbcb12SLuke Drummond       m_kernel_types = RSReduceBreakpointResolver::eKernelTypeNone;
4116b3bbcb12SLuke Drummond       const auto reduce_name_to_type = [](llvm::StringRef name) -> int {
4117b3bbcb12SLuke Drummond         return llvm::StringSwitch<int>(name)
4118b3bbcb12SLuke Drummond             .Case("accumulator", RSReduceBreakpointResolver::eKernelTypeAccum)
4119b3bbcb12SLuke Drummond             .Case("initializer", RSReduceBreakpointResolver::eKernelTypeInit)
4120b3bbcb12SLuke Drummond             .Case("outconverter", RSReduceBreakpointResolver::eKernelTypeOutC)
4121b3bbcb12SLuke Drummond             .Case("combiner", RSReduceBreakpointResolver::eKernelTypeComb)
4122b3bbcb12SLuke Drummond             .Case("all", RSReduceBreakpointResolver::eKernelTypeAll)
4123b3bbcb12SLuke Drummond             // Currently not exposed by the runtime
4124b3bbcb12SLuke Drummond             // .Case("halter", RSReduceBreakpointResolver::eKernelTypeHalter)
4125b3bbcb12SLuke Drummond             .Default(0);
4126b3bbcb12SLuke Drummond       };
4127b3bbcb12SLuke Drummond 
4128b3bbcb12SLuke Drummond       // Matching a comma separated list of known words is fairly
412905097246SAdrian Prantl       // straightforward with PCRE, but we're using ERE, so we end up with a
413005097246SAdrian Prantl       // little ugliness...
4131b3bbcb12SLuke Drummond       RegularExpression match_type_list(
4132b3bbcb12SLuke Drummond           llvm::StringRef("^([[:alpha:]]+)(,[[:alpha:]]+){0,4}$"));
4133b3bbcb12SLuke Drummond 
4134b3bbcb12SLuke Drummond       assert(match_type_list.IsValid());
4135b3bbcb12SLuke Drummond 
41363af3f1e8SJonas Devlieghere       if (!match_type_list.Execute(option_val)) {
4137b3bbcb12SLuke Drummond         err_str.PutCString(
4138b3bbcb12SLuke Drummond             "a comma-separated list of kernel types is required");
4139b3bbcb12SLuke Drummond         return false;
4140b3bbcb12SLuke Drummond       }
4141b3bbcb12SLuke Drummond 
4142b3bbcb12SLuke Drummond       // splitting on commas is much easier with llvm::StringRef than regex
4143b3bbcb12SLuke Drummond       llvm::SmallVector<llvm::StringRef, 5> type_names;
4144b3bbcb12SLuke Drummond       llvm::StringRef(option_val).split(type_names, ',');
4145b3bbcb12SLuke Drummond 
4146b3bbcb12SLuke Drummond       for (const auto &name : type_names) {
4147b3bbcb12SLuke Drummond         const int type = reduce_name_to_type(name);
4148b3bbcb12SLuke Drummond         if (!type) {
4149b3bbcb12SLuke Drummond           err_str.Printf("unknown kernel type name %s", name.str().c_str());
4150b3bbcb12SLuke Drummond           return false;
4151b3bbcb12SLuke Drummond         }
4152b3bbcb12SLuke Drummond         m_kernel_types |= type;
4153b3bbcb12SLuke Drummond       }
4154b3bbcb12SLuke Drummond 
4155b3bbcb12SLuke Drummond       return true;
4156b3bbcb12SLuke Drummond     }
4157b3bbcb12SLuke Drummond 
41589494c510SJonas Devlieghere     int m_kernel_types = RSReduceBreakpointResolver::eKernelTypeAll;
4159b3bbcb12SLuke Drummond     llvm::StringRef m_reduce_name;
4160b3bbcb12SLuke Drummond     RSCoordinate m_coord;
4161b3bbcb12SLuke Drummond     bool m_have_coord;
4162b3bbcb12SLuke Drummond   };
4163b3bbcb12SLuke Drummond 
4164b3bbcb12SLuke Drummond   Options *GetOptions() override { return &m_options; }
4165b3bbcb12SLuke Drummond 
4166b3bbcb12SLuke Drummond   bool DoExecute(Args &command, CommandReturnObject &result) override {
4167b3bbcb12SLuke Drummond     const size_t argc = command.GetArgumentCount();
4168b3bbcb12SLuke Drummond     if (argc < 1) {
4169b3bbcb12SLuke Drummond       result.AppendErrorWithFormat("'%s' takes 1 argument of reduction name, "
4170b3bbcb12SLuke Drummond                                    "and an optional kernel type list",
4171b3bbcb12SLuke Drummond                                    m_cmd_name.c_str());
4172b3bbcb12SLuke Drummond       return false;
4173b3bbcb12SLuke Drummond     }
4174b3bbcb12SLuke Drummond 
4175b3bbcb12SLuke Drummond     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4176b3bbcb12SLuke Drummond         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4177b3bbcb12SLuke Drummond             eLanguageTypeExtRenderScript));
4178b3bbcb12SLuke Drummond 
4179b3bbcb12SLuke Drummond     auto &outstream = result.GetOutputStream();
4180b3bbcb12SLuke Drummond     auto name = command.GetArgumentAtIndex(0);
4181b3bbcb12SLuke Drummond     auto &target = m_exe_ctx.GetTargetSP();
4182b3bbcb12SLuke Drummond     auto coord = m_options.m_have_coord ? &m_options.m_coord : nullptr;
4183b3bbcb12SLuke Drummond     if (!runtime->PlaceBreakpointOnReduction(target, outstream, name, coord,
4184b3bbcb12SLuke Drummond                                              m_options.m_kernel_types)) {
4185b3bbcb12SLuke Drummond       result.AppendError("Error: unable to place breakpoint on reduction");
4186b3bbcb12SLuke Drummond       return false;
4187b3bbcb12SLuke Drummond     }
4188b3bbcb12SLuke Drummond     result.AppendMessage("Breakpoint(s) created");
4189b3bbcb12SLuke Drummond     result.SetStatus(eReturnStatusSuccessFinishResult);
4190b3bbcb12SLuke Drummond     return true;
4191b3bbcb12SLuke Drummond   }
4192b3bbcb12SLuke Drummond 
4193b3bbcb12SLuke Drummond private:
4194b3bbcb12SLuke Drummond   CommandOptions m_options;
4195b3bbcb12SLuke Drummond };
4196b3bbcb12SLuke Drummond 
41978fe53c49STatyana Krasnukha static constexpr OptionDefinition g_renderscript_kernel_bp_set_options[] = {
41981f0f5b5bSZachary Turner     {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument,
41998fe53c49STatyana Krasnukha      nullptr, {}, 0, eArgTypeValue,
42001f0f5b5bSZachary Turner      "Set a breakpoint on a single invocation of the kernel with specified "
42011f0f5b5bSZachary Turner      "coordinate.\n"
42021f0f5b5bSZachary Turner      "Coordinate takes the form 'x[,y][,z] where x,y,z are positive "
42031f0f5b5bSZachary Turner      "integers representing kernel dimensions. "
42041f0f5b5bSZachary Turner      "Any unset dimensions will be defaulted to zero."}};
42051f0f5b5bSZachary Turner 
4206b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpointSet
4207b9c1b51eSKate Stone     : public CommandObjectParsed {
42084640cde1SColin Riley public:
4209b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelBreakpointSet(
4210b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4211b9c1b51eSKate Stone       : CommandObjectParsed(
4212b9c1b51eSKate Stone             interpreter, "renderscript kernel breakpoint set",
4213b3f7f69dSAidan Dodds             "Sets a breakpoint on a renderscript kernel.",
4214b3f7f69dSAidan Dodds             "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]",
4215b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
4216b9c1b51eSKate Stone                 eCommandProcessMustBePaused),
4217b9c1b51eSKate Stone         m_options() {}
42184640cde1SColin Riley 
4219222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default;
4220222b937cSEugene Zelenko 
4221b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
4222018f5a7eSEwan Crawford 
4223b9c1b51eSKate Stone   class CommandOptions : public Options {
4224018f5a7eSEwan Crawford   public:
4225e1cfbc79STodd Fiala     CommandOptions() : Options() {}
4226018f5a7eSEwan Crawford 
4227222b937cSEugene Zelenko     ~CommandOptions() override = default;
4228018f5a7eSEwan Crawford 
422997206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
4230b3bbcb12SLuke Drummond                           ExecutionContext *exe_ctx) override {
423197206d57SZachary Turner       Status err;
4232018f5a7eSEwan Crawford       const int short_option = m_getopt_table[option_idx].val;
4233018f5a7eSEwan Crawford 
4234b9c1b51eSKate Stone       switch (short_option) {
423500f56eebSLuke Drummond       case 'c': {
423600f56eebSLuke Drummond         auto coord = RSCoordinate{};
423700f56eebSLuke Drummond         if (!ParseCoordinate(option_arg, coord))
423880af0b9eSLuke Drummond           err.SetErrorStringWithFormat(
4239b9c1b51eSKate Stone               "Couldn't parse coordinate '%s', should be in format 'x,y,z'.",
4240fe11483bSZachary Turner               option_arg.str().c_str());
424100f56eebSLuke Drummond         else {
424200f56eebSLuke Drummond           m_have_coord = true;
424300f56eebSLuke Drummond           m_coord = coord;
424400f56eebSLuke Drummond         }
4245018f5a7eSEwan Crawford         break;
424600f56eebSLuke Drummond       }
4247018f5a7eSEwan Crawford       default:
424880af0b9eSLuke Drummond         err.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
4249018f5a7eSEwan Crawford         break;
4250018f5a7eSEwan Crawford       }
425180af0b9eSLuke Drummond       return err;
4252018f5a7eSEwan Crawford     }
4253018f5a7eSEwan Crawford 
4254b3bbcb12SLuke Drummond     void OptionParsingStarting(ExecutionContext *exe_ctx) override {
425500f56eebSLuke Drummond       m_have_coord = false;
4256018f5a7eSEwan Crawford     }
4257018f5a7eSEwan Crawford 
42581f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
425970602439SZachary Turner       return llvm::makeArrayRef(g_renderscript_kernel_bp_set_options);
42601f0f5b5bSZachary Turner     }
4261018f5a7eSEwan Crawford 
426200f56eebSLuke Drummond     RSCoordinate m_coord;
426300f56eebSLuke Drummond     bool m_have_coord;
4264018f5a7eSEwan Crawford   };
4265018f5a7eSEwan Crawford 
4266b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
42674640cde1SColin Riley     const size_t argc = command.GetArgumentCount();
4268b9c1b51eSKate Stone     if (argc < 1) {
4269b9c1b51eSKate Stone       result.AppendErrorWithFormat(
4270b9c1b51eSKate Stone           "'%s' takes 1 argument of kernel name, and an optional coordinate.",
4271b3f7f69dSAidan Dodds           m_cmd_name.c_str());
4272018f5a7eSEwan Crawford       return false;
4273018f5a7eSEwan Crawford     }
4274018f5a7eSEwan Crawford 
4275056f6f18SAlex Langford     RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>(
4276056f6f18SAlex Langford         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4277056f6f18SAlex Langford             eLanguageTypeExtRenderScript));
42784640cde1SColin Riley 
427900f56eebSLuke Drummond     auto &outstream = result.GetOutputStream();
428000f56eebSLuke Drummond     auto &target = m_exe_ctx.GetTargetSP();
428100f56eebSLuke Drummond     auto name = command.GetArgumentAtIndex(0);
428200f56eebSLuke Drummond     auto coord = m_options.m_have_coord ? &m_options.m_coord : nullptr;
428300f56eebSLuke Drummond     if (!runtime->PlaceBreakpointOnKernel(target, outstream, name, coord)) {
428400f56eebSLuke Drummond       result.AppendErrorWithFormat(
428500f56eebSLuke Drummond           "Error: unable to set breakpoint on kernel '%s'", name);
428600f56eebSLuke Drummond       return false;
428700f56eebSLuke Drummond     }
42884640cde1SColin Riley 
42894640cde1SColin Riley     result.AppendMessage("Breakpoint(s) created");
42904640cde1SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
42914640cde1SColin Riley     return true;
42924640cde1SColin Riley   }
42934640cde1SColin Riley 
4294018f5a7eSEwan Crawford private:
4295018f5a7eSEwan Crawford   CommandOptions m_options;
42964640cde1SColin Riley };
42974640cde1SColin Riley 
4298b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpointAll
4299b9c1b51eSKate Stone     : public CommandObjectParsed {
43007dc7771cSEwan Crawford public:
4301b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelBreakpointAll(
4302b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4303b3f7f69dSAidan Dodds       : CommandObjectParsed(
4304b3f7f69dSAidan Dodds             interpreter, "renderscript kernel breakpoint all",
4305b9c1b51eSKate Stone             "Automatically sets a breakpoint on all renderscript kernels that "
4306b9c1b51eSKate Stone             "are or will be loaded.\n"
4307b9c1b51eSKate Stone             "Disabling option means breakpoints will no longer be set on any "
4308b9c1b51eSKate Stone             "kernels loaded in the future, "
43097dc7771cSEwan Crawford             "but does not remove currently set breakpoints.",
43107dc7771cSEwan Crawford             "renderscript kernel breakpoint all <enable/disable>",
4311b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
4312b9c1b51eSKate Stone                 eCommandProcessMustBePaused) {}
43137dc7771cSEwan Crawford 
4314222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default;
43157dc7771cSEwan Crawford 
4316b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
43177dc7771cSEwan Crawford     const size_t argc = command.GetArgumentCount();
4318b9c1b51eSKate Stone     if (argc != 1) {
4319b9c1b51eSKate Stone       result.AppendErrorWithFormat(
4320b9c1b51eSKate Stone           "'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str());
43217dc7771cSEwan Crawford       return false;
43227dc7771cSEwan Crawford     }
43237dc7771cSEwan Crawford 
4324b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4325b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4326b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
43277dc7771cSEwan Crawford 
43287dc7771cSEwan Crawford     bool do_break = false;
43297dc7771cSEwan Crawford     const char *argument = command.GetArgumentAtIndex(0);
4330b9c1b51eSKate Stone     if (strcmp(argument, "enable") == 0) {
43317dc7771cSEwan Crawford       do_break = true;
43327dc7771cSEwan Crawford       result.AppendMessage("Breakpoints will be set on all kernels.");
4333b9c1b51eSKate Stone     } else if (strcmp(argument, "disable") == 0) {
43347dc7771cSEwan Crawford       do_break = false;
43357dc7771cSEwan Crawford       result.AppendMessage("Breakpoints will not be set on any new kernels.");
4336b9c1b51eSKate Stone     } else {
4337b9c1b51eSKate Stone       result.AppendErrorWithFormat(
4338b9c1b51eSKate Stone           "Argument must be either 'enable' or 'disable'");
43397dc7771cSEwan Crawford       return false;
43407dc7771cSEwan Crawford     }
43417dc7771cSEwan Crawford 
43427dc7771cSEwan Crawford     runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP());
43437dc7771cSEwan Crawford 
43447dc7771cSEwan Crawford     result.SetStatus(eReturnStatusSuccessFinishResult);
43457dc7771cSEwan Crawford     return true;
43467dc7771cSEwan Crawford   }
43477dc7771cSEwan Crawford };
43487dc7771cSEwan Crawford 
4349b3bbcb12SLuke Drummond class CommandObjectRenderScriptRuntimeReductionBreakpoint
4350b3bbcb12SLuke Drummond     : public CommandObjectMultiword {
4351b3bbcb12SLuke Drummond public:
4352b3bbcb12SLuke Drummond   CommandObjectRenderScriptRuntimeReductionBreakpoint(
4353b3bbcb12SLuke Drummond       CommandInterpreter &interpreter)
4354b3bbcb12SLuke Drummond       : CommandObjectMultiword(interpreter, "renderscript reduction breakpoint",
4355b3bbcb12SLuke Drummond                                "Commands that manipulate breakpoints on "
4356b3bbcb12SLuke Drummond                                "renderscript general reductions.",
4357b3bbcb12SLuke Drummond                                nullptr) {
4358b3bbcb12SLuke Drummond     LoadSubCommand(
4359b3bbcb12SLuke Drummond         "set", CommandObjectSP(
4360b3bbcb12SLuke Drummond                    new CommandObjectRenderScriptRuntimeReductionBreakpointSet(
4361b3bbcb12SLuke Drummond                        interpreter)));
4362b3bbcb12SLuke Drummond   }
4363b3bbcb12SLuke Drummond 
4364b3bbcb12SLuke Drummond   ~CommandObjectRenderScriptRuntimeReductionBreakpoint() override = default;
4365b3bbcb12SLuke Drummond };
4366b3bbcb12SLuke Drummond 
4367b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelCoordinate
4368b9c1b51eSKate Stone     : public CommandObjectParsed {
43694f8817c2SEwan Crawford public:
4370b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelCoordinate(
4371b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4372b9c1b51eSKate Stone       : CommandObjectParsed(
4373b9c1b51eSKate Stone             interpreter, "renderscript kernel coordinate",
43744f8817c2SEwan Crawford             "Shows the (x,y,z) coordinate of the current kernel invocation.",
43754f8817c2SEwan Crawford             "renderscript kernel coordinate",
4376b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
4377b9c1b51eSKate Stone                 eCommandProcessMustBePaused) {}
43784f8817c2SEwan Crawford 
43794f8817c2SEwan Crawford   ~CommandObjectRenderScriptRuntimeKernelCoordinate() override = default;
43804f8817c2SEwan Crawford 
4381b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
438200f56eebSLuke Drummond     RSCoordinate coord{};
4383b9c1b51eSKate Stone     bool success = RenderScriptRuntime::GetKernelCoordinate(
4384b9c1b51eSKate Stone         coord, m_exe_ctx.GetThreadPtr());
43854f8817c2SEwan Crawford     Stream &stream = result.GetOutputStream();
43864f8817c2SEwan Crawford 
4387b9c1b51eSKate Stone     if (success) {
438800f56eebSLuke Drummond       stream.Printf("Coordinate: " FMT_COORD, coord.x, coord.y, coord.z);
43894f8817c2SEwan Crawford       stream.EOL();
43904f8817c2SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
4391b9c1b51eSKate Stone     } else {
43924f8817c2SEwan Crawford       stream.Printf("Error: Coordinate could not be found.");
43934f8817c2SEwan Crawford       stream.EOL();
43944f8817c2SEwan Crawford       result.SetStatus(eReturnStatusFailed);
43954f8817c2SEwan Crawford     }
43964f8817c2SEwan Crawford     return true;
43974f8817c2SEwan Crawford   }
43984f8817c2SEwan Crawford };
43994f8817c2SEwan Crawford 
4400b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpoint
4401b9c1b51eSKate Stone     : public CommandObjectMultiword {
44027dc7771cSEwan Crawford public:
4403b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelBreakpoint(
4404b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4405b9c1b51eSKate Stone       : CommandObjectMultiword(
4406b9c1b51eSKate Stone             interpreter, "renderscript kernel",
4407b9c1b51eSKate Stone             "Commands that generate breakpoints on renderscript kernels.",
4408b9c1b51eSKate Stone             nullptr) {
4409b9c1b51eSKate Stone     LoadSubCommand(
4410b9c1b51eSKate Stone         "set",
4411b9c1b51eSKate Stone         CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet(
4412b9c1b51eSKate Stone             interpreter)));
4413b9c1b51eSKate Stone     LoadSubCommand(
4414b9c1b51eSKate Stone         "all",
4415b9c1b51eSKate Stone         CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll(
4416b9c1b51eSKate Stone             interpreter)));
44177dc7771cSEwan Crawford   }
44187dc7771cSEwan Crawford 
4419222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default;
44207dc7771cSEwan Crawford };
44217dc7771cSEwan Crawford 
4422b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword {
44234640cde1SColin Riley public:
44244640cde1SColin Riley   CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter)
4425b9c1b51eSKate Stone       : CommandObjectMultiword(interpreter, "renderscript kernel",
4426b9c1b51eSKate Stone                                "Commands that deal with RenderScript kernels.",
4427b9c1b51eSKate Stone                                nullptr) {
4428b9c1b51eSKate Stone     LoadSubCommand(
4429b9c1b51eSKate Stone         "list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList(
4430b9c1b51eSKate Stone                     interpreter)));
4431b9c1b51eSKate Stone     LoadSubCommand(
4432b9c1b51eSKate Stone         "coordinate",
4433b9c1b51eSKate Stone         CommandObjectSP(
4434b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeKernelCoordinate(interpreter)));
4435b9c1b51eSKate Stone     LoadSubCommand(
4436b9c1b51eSKate Stone         "breakpoint",
4437b9c1b51eSKate Stone         CommandObjectSP(
4438b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter)));
44394640cde1SColin Riley   }
44404640cde1SColin Riley 
4441222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernel() override = default;
44424640cde1SColin Riley };
44434640cde1SColin Riley 
4444b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed {
44454640cde1SColin Riley public:
44464640cde1SColin Riley   CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter)
4447b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "renderscript context dump",
4448b9c1b51eSKate Stone                             "Dumps renderscript context information.",
4449b9c1b51eSKate Stone                             "renderscript context dump",
4450b9c1b51eSKate Stone                             eCommandRequiresProcess |
4451b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
44524640cde1SColin Riley 
4453222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeContextDump() override = default;
44544640cde1SColin Riley 
4455b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
4456056f6f18SAlex Langford     RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>(
4457056f6f18SAlex Langford         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4458056f6f18SAlex Langford             eLanguageTypeExtRenderScript));
44594640cde1SColin Riley     runtime->DumpContexts(result.GetOutputStream());
44604640cde1SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
44614640cde1SColin Riley     return true;
44624640cde1SColin Riley   }
44634640cde1SColin Riley };
44644640cde1SColin Riley 
44658fe53c49STatyana Krasnukha static constexpr OptionDefinition g_renderscript_runtime_alloc_dump_options[] = {
44661f0f5b5bSZachary Turner     {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument,
44678fe53c49STatyana Krasnukha      nullptr, {}, 0, eArgTypeFilename,
44681f0f5b5bSZachary Turner      "Print results to specified file instead of command line."}};
44691f0f5b5bSZachary Turner 
4470b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword {
44714640cde1SColin Riley public:
44724640cde1SColin Riley   CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter)
4473b9c1b51eSKate Stone       : CommandObjectMultiword(interpreter, "renderscript context",
4474b9c1b51eSKate Stone                                "Commands that deal with RenderScript contexts.",
4475b9c1b51eSKate Stone                                nullptr) {
4476b9c1b51eSKate Stone     LoadSubCommand(
4477b9c1b51eSKate Stone         "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump(
4478b9c1b51eSKate Stone                     interpreter)));
44794640cde1SColin Riley   }
44804640cde1SColin Riley 
4481222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeContext() override = default;
44824640cde1SColin Riley };
44834640cde1SColin Riley 
4484b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationDump
4485b9c1b51eSKate Stone     : public CommandObjectParsed {
4486a0f08674SEwan Crawford public:
4487b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationDump(
4488b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4489a0f08674SEwan Crawford       : CommandObjectParsed(interpreter, "renderscript allocation dump",
4490b9c1b51eSKate Stone                             "Displays the contents of a particular allocation",
4491b9c1b51eSKate Stone                             "renderscript allocation dump <ID>",
4492b9c1b51eSKate Stone                             eCommandRequiresProcess |
4493b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched),
4494b9c1b51eSKate Stone         m_options() {}
4495a0f08674SEwan Crawford 
4496222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationDump() override = default;
4497222b937cSEugene Zelenko 
4498b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
4499a0f08674SEwan Crawford 
4500b9c1b51eSKate Stone   class CommandOptions : public Options {
4501a0f08674SEwan Crawford   public:
4502e1cfbc79STodd Fiala     CommandOptions() : Options() {}
4503a0f08674SEwan Crawford 
4504222b937cSEugene Zelenko     ~CommandOptions() override = default;
4505a0f08674SEwan Crawford 
450697206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
4507b3bbcb12SLuke Drummond                           ExecutionContext *exe_ctx) override {
450897206d57SZachary Turner       Status err;
4509a0f08674SEwan Crawford       const int short_option = m_getopt_table[option_idx].val;
4510a0f08674SEwan Crawford 
4511b9c1b51eSKate Stone       switch (short_option) {
4512a0f08674SEwan Crawford       case 'f':
45138f3be7a3SJonas Devlieghere         m_outfile.SetFile(option_arg, FileSpec::Style::native);
45148f3be7a3SJonas Devlieghere         FileSystem::Instance().Resolve(m_outfile);
4515dbd7fabaSJonas Devlieghere         if (FileSystem::Instance().Exists(m_outfile)) {
4516a0f08674SEwan Crawford           m_outfile.Clear();
4517fe11483bSZachary Turner           err.SetErrorStringWithFormat("file already exists: '%s'",
4518fe11483bSZachary Turner                                        option_arg.str().c_str());
4519a0f08674SEwan Crawford         }
4520a0f08674SEwan Crawford         break;
4521a0f08674SEwan Crawford       default:
452280af0b9eSLuke Drummond         err.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
4523a0f08674SEwan Crawford         break;
4524a0f08674SEwan Crawford       }
452580af0b9eSLuke Drummond       return err;
4526a0f08674SEwan Crawford     }
4527a0f08674SEwan Crawford 
4528b3bbcb12SLuke Drummond     void OptionParsingStarting(ExecutionContext *exe_ctx) override {
4529a0f08674SEwan Crawford       m_outfile.Clear();
4530a0f08674SEwan Crawford     }
4531a0f08674SEwan Crawford 
45321f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
453370602439SZachary Turner       return llvm::makeArrayRef(g_renderscript_runtime_alloc_dump_options);
45341f0f5b5bSZachary Turner     }
4535a0f08674SEwan Crawford 
4536a0f08674SEwan Crawford     FileSpec m_outfile;
4537a0f08674SEwan Crawford   };
4538a0f08674SEwan Crawford 
4539b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
4540a0f08674SEwan Crawford     const size_t argc = command.GetArgumentCount();
4541b9c1b51eSKate Stone     if (argc < 1) {
4542b9c1b51eSKate Stone       result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. "
4543b9c1b51eSKate Stone                                    "As well as an optional -f argument",
4544a0f08674SEwan Crawford                                    m_cmd_name.c_str());
4545a0f08674SEwan Crawford       return false;
4546a0f08674SEwan Crawford     }
4547a0f08674SEwan Crawford 
4548b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4549b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4550b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
4551a0f08674SEwan Crawford 
4552a0f08674SEwan Crawford     const char *id_cstr = command.GetArgumentAtIndex(0);
45533a6ba367SMichał Górny     uint32_t id;
45543a6ba367SMichał Górny     if (!llvm::to_integer(id_cstr, id)) {
4555b9c1b51eSKate Stone       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
4556b9c1b51eSKate Stone                                    id_cstr);
4557a0f08674SEwan Crawford       return false;
4558a0f08674SEwan Crawford     }
4559a0f08674SEwan Crawford 
45602fce1137SLawrence D'Anna     Stream *output_stream_p = nullptr;
45612fce1137SLawrence D'Anna     std::unique_ptr<Stream> output_stream_storage;
45622fce1137SLawrence D'Anna 
4563b9c1b51eSKate Stone     const FileSpec &outfile_spec =
4564b9c1b51eSKate Stone         m_options.m_outfile; // Dump allocation to file instead
4565b9c1b51eSKate Stone     if (outfile_spec) {
4566a0f08674SEwan Crawford       // Open output file
456750bc1ed2SJonas Devlieghere       std::string path = outfile_spec.GetPath();
456814735cabSMichał Górny       auto file = FileSystem::Instance().Open(outfile_spec,
456914735cabSMichał Górny                                               File::eOpenOptionWriteOnly |
457014735cabSMichał Górny                                                   File::eOpenOptionCanCreate);
45712fce1137SLawrence D'Anna       if (file) {
45722fce1137SLawrence D'Anna         output_stream_storage =
45732fce1137SLawrence D'Anna             std::make_unique<StreamFile>(std::move(file.get()));
45742fce1137SLawrence D'Anna         output_stream_p = output_stream_storage.get();
457550bc1ed2SJonas Devlieghere         result.GetOutputStream().Printf("Results written to '%s'",
457650bc1ed2SJonas Devlieghere                                         path.c_str());
4577a0f08674SEwan Crawford         result.GetOutputStream().EOL();
4578b9c1b51eSKate Stone       } else {
45792fce1137SLawrence D'Anna         std::string error = llvm::toString(file.takeError());
45802fce1137SLawrence D'Anna         result.AppendErrorWithFormat("Couldn't open file '%s': %s",
45812fce1137SLawrence D'Anna                                      path.c_str(), error.c_str());
4582a0f08674SEwan Crawford         return false;
4583a0f08674SEwan Crawford       }
4584b9c1b51eSKate Stone     } else
45852fce1137SLawrence D'Anna       output_stream_p = &result.GetOutputStream();
4586a0f08674SEwan Crawford 
45872fce1137SLawrence D'Anna     assert(output_stream_p != nullptr);
458880af0b9eSLuke Drummond     bool dumped =
45892fce1137SLawrence D'Anna         runtime->DumpAllocation(*output_stream_p, m_exe_ctx.GetFramePtr(), id);
4590a0f08674SEwan Crawford 
459180af0b9eSLuke Drummond     if (dumped)
4592a0f08674SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
4593a0f08674SEwan Crawford     else
4594a0f08674SEwan Crawford       result.SetStatus(eReturnStatusFailed);
4595a0f08674SEwan Crawford 
4596a0f08674SEwan Crawford     return true;
4597a0f08674SEwan Crawford   }
4598a0f08674SEwan Crawford 
4599a0f08674SEwan Crawford private:
4600a0f08674SEwan Crawford   CommandOptions m_options;
4601a0f08674SEwan Crawford };
4602a0f08674SEwan Crawford 
46038fe53c49STatyana Krasnukha static constexpr OptionDefinition g_renderscript_runtime_alloc_list_options[] = {
46041f0f5b5bSZachary Turner     {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument, nullptr,
46058fe53c49STatyana Krasnukha      {}, 0, eArgTypeIndex,
46061f0f5b5bSZachary Turner      "Only show details of a single allocation with specified id."}};
4607a0f08674SEwan Crawford 
4608b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationList
4609b9c1b51eSKate Stone     : public CommandObjectParsed {
461015f2bd95SEwan Crawford public:
4611b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationList(
4612b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4613b9c1b51eSKate Stone       : CommandObjectParsed(
4614b9c1b51eSKate Stone             interpreter, "renderscript allocation list",
4615b9c1b51eSKate Stone             "List renderscript allocations and their information.",
4616b9c1b51eSKate Stone             "renderscript allocation list",
4617b3f7f69dSAidan Dodds             eCommandRequiresProcess | eCommandProcessMustBeLaunched),
4618b9c1b51eSKate Stone         m_options() {}
461915f2bd95SEwan Crawford 
4620222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationList() override = default;
4621222b937cSEugene Zelenko 
4622b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
462315f2bd95SEwan Crawford 
4624b9c1b51eSKate Stone   class CommandOptions : public Options {
462515f2bd95SEwan Crawford   public:
46269494c510SJonas Devlieghere     CommandOptions() : Options() {}
462715f2bd95SEwan Crawford 
4628222b937cSEugene Zelenko     ~CommandOptions() override = default;
462915f2bd95SEwan Crawford 
463097206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
4631b3bbcb12SLuke Drummond                           ExecutionContext *exe_ctx) override {
463297206d57SZachary Turner       Status err;
463315f2bd95SEwan Crawford       const int short_option = m_getopt_table[option_idx].val;
463415f2bd95SEwan Crawford 
4635b9c1b51eSKate Stone       switch (short_option) {
4636b649b005SEwan Crawford       case 'i':
4637fe11483bSZachary Turner         if (option_arg.getAsInteger(0, m_id))
463880af0b9eSLuke Drummond           err.SetErrorStringWithFormat("invalid integer value for option '%c'",
4639b9c1b51eSKate Stone                                        short_option);
464015f2bd95SEwan Crawford         break;
464180af0b9eSLuke Drummond       default:
464280af0b9eSLuke Drummond         err.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
464380af0b9eSLuke Drummond         break;
464415f2bd95SEwan Crawford       }
464580af0b9eSLuke Drummond       return err;
464615f2bd95SEwan Crawford     }
464715f2bd95SEwan Crawford 
4648b3bbcb12SLuke Drummond     void OptionParsingStarting(ExecutionContext *exe_ctx) override { m_id = 0; }
464915f2bd95SEwan Crawford 
46501f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
465170602439SZachary Turner       return llvm::makeArrayRef(g_renderscript_runtime_alloc_list_options);
46521f0f5b5bSZachary Turner     }
465315f2bd95SEwan Crawford 
46549494c510SJonas Devlieghere     uint32_t m_id = 0;
465515f2bd95SEwan Crawford   };
465615f2bd95SEwan Crawford 
4657b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
4658b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4659b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4660b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
4661b9c1b51eSKate Stone     runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(),
4662b9c1b51eSKate Stone                              m_options.m_id);
466315f2bd95SEwan Crawford     result.SetStatus(eReturnStatusSuccessFinishResult);
466415f2bd95SEwan Crawford     return true;
466515f2bd95SEwan Crawford   }
466615f2bd95SEwan Crawford 
466715f2bd95SEwan Crawford private:
466815f2bd95SEwan Crawford   CommandOptions m_options;
466915f2bd95SEwan Crawford };
467015f2bd95SEwan Crawford 
4671b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationLoad
4672b9c1b51eSKate Stone     : public CommandObjectParsed {
467355232f09SEwan Crawford public:
4674b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationLoad(
4675b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4676b3f7f69dSAidan Dodds       : CommandObjectParsed(
4677b9c1b51eSKate Stone             interpreter, "renderscript allocation load",
4678b9c1b51eSKate Stone             "Loads renderscript allocation contents from a file.",
4679b9c1b51eSKate Stone             "renderscript allocation load <ID> <filename>",
4680b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
468155232f09SEwan Crawford 
4682222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default;
468355232f09SEwan Crawford 
4684b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
468555232f09SEwan Crawford     const size_t argc = command.GetArgumentCount();
4686b9c1b51eSKate Stone     if (argc != 2) {
4687b9c1b51eSKate Stone       result.AppendErrorWithFormat(
4688b9c1b51eSKate Stone           "'%s' takes 2 arguments, an allocation ID and filename to read from.",
4689b3f7f69dSAidan Dodds           m_cmd_name.c_str());
469055232f09SEwan Crawford       return false;
469155232f09SEwan Crawford     }
469255232f09SEwan Crawford 
4693b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4694b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4695b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
469655232f09SEwan Crawford 
469755232f09SEwan Crawford     const char *id_cstr = command.GetArgumentAtIndex(0);
46983a6ba367SMichał Górny     uint32_t id;
46993a6ba367SMichał Górny     if (!llvm::to_integer(id_cstr, id)) {
4700b9c1b51eSKate Stone       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
4701b9c1b51eSKate Stone                                    id_cstr);
470255232f09SEwan Crawford       return false;
470355232f09SEwan Crawford     }
470455232f09SEwan Crawford 
470580af0b9eSLuke Drummond     const char *path = command.GetArgumentAtIndex(1);
470680af0b9eSLuke Drummond     bool loaded = runtime->LoadAllocation(result.GetOutputStream(), id, path,
470780af0b9eSLuke Drummond                                           m_exe_ctx.GetFramePtr());
470855232f09SEwan Crawford 
470980af0b9eSLuke Drummond     if (loaded)
471055232f09SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
471155232f09SEwan Crawford     else
471255232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
471355232f09SEwan Crawford 
471455232f09SEwan Crawford     return true;
471555232f09SEwan Crawford   }
471655232f09SEwan Crawford };
471755232f09SEwan Crawford 
4718b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationSave
4719b9c1b51eSKate Stone     : public CommandObjectParsed {
472055232f09SEwan Crawford public:
4721b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationSave(
4722b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4723b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "renderscript allocation save",
4724b9c1b51eSKate Stone                             "Write renderscript allocation contents to a file.",
4725b9c1b51eSKate Stone                             "renderscript allocation save <ID> <filename>",
4726b9c1b51eSKate Stone                             eCommandRequiresProcess |
4727b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
472855232f09SEwan Crawford 
4729222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationSave() override = default;
473055232f09SEwan Crawford 
4731b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
473255232f09SEwan Crawford     const size_t argc = command.GetArgumentCount();
4733b9c1b51eSKate Stone     if (argc != 2) {
4734b9c1b51eSKate Stone       result.AppendErrorWithFormat(
4735b9c1b51eSKate Stone           "'%s' takes 2 arguments, an allocation ID and filename to read from.",
4736b3f7f69dSAidan Dodds           m_cmd_name.c_str());
473755232f09SEwan Crawford       return false;
473855232f09SEwan Crawford     }
473955232f09SEwan Crawford 
4740b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4741b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4742b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
474355232f09SEwan Crawford 
474455232f09SEwan Crawford     const char *id_cstr = command.GetArgumentAtIndex(0);
47453a6ba367SMichał Górny     uint32_t id;
47463a6ba367SMichał Górny     if (!llvm::to_integer(id_cstr, id)) {
4747b9c1b51eSKate Stone       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
4748b9c1b51eSKate Stone                                    id_cstr);
474955232f09SEwan Crawford       return false;
475055232f09SEwan Crawford     }
475155232f09SEwan Crawford 
475280af0b9eSLuke Drummond     const char *path = command.GetArgumentAtIndex(1);
475380af0b9eSLuke Drummond     bool saved = runtime->SaveAllocation(result.GetOutputStream(), id, path,
475480af0b9eSLuke Drummond                                          m_exe_ctx.GetFramePtr());
475555232f09SEwan Crawford 
475680af0b9eSLuke Drummond     if (saved)
475755232f09SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
475855232f09SEwan Crawford     else
475955232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
476055232f09SEwan Crawford 
476155232f09SEwan Crawford     return true;
476255232f09SEwan Crawford   }
476355232f09SEwan Crawford };
476455232f09SEwan Crawford 
4765b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationRefresh
4766b9c1b51eSKate Stone     : public CommandObjectParsed {
47670d2bfcfbSEwan Crawford public:
4768b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationRefresh(
4769b9c1b51eSKate Stone       CommandInterpreter &interpreter)
47700d2bfcfbSEwan Crawford       : CommandObjectParsed(interpreter, "renderscript allocation refresh",
4771b9c1b51eSKate Stone                             "Recomputes the details of all allocations.",
4772b9c1b51eSKate Stone                             "renderscript allocation refresh",
4773b9c1b51eSKate Stone                             eCommandRequiresProcess |
4774b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
47750d2bfcfbSEwan Crawford 
47760d2bfcfbSEwan Crawford   ~CommandObjectRenderScriptRuntimeAllocationRefresh() override = default;
47770d2bfcfbSEwan Crawford 
4778b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
47790d2bfcfbSEwan Crawford     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4780b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4781b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
47820d2bfcfbSEwan Crawford 
4783b9c1b51eSKate Stone     bool success = runtime->RecomputeAllAllocations(result.GetOutputStream(),
4784b9c1b51eSKate Stone                                                     m_exe_ctx.GetFramePtr());
47850d2bfcfbSEwan Crawford 
4786b9c1b51eSKate Stone     if (success) {
47870d2bfcfbSEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
47880d2bfcfbSEwan Crawford       return true;
4789b9c1b51eSKate Stone     } else {
47900d2bfcfbSEwan Crawford       result.SetStatus(eReturnStatusFailed);
47910d2bfcfbSEwan Crawford       return false;
47920d2bfcfbSEwan Crawford     }
47930d2bfcfbSEwan Crawford   }
47940d2bfcfbSEwan Crawford };
47950d2bfcfbSEwan Crawford 
4796b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocation
4797b9c1b51eSKate Stone     : public CommandObjectMultiword {
479815f2bd95SEwan Crawford public:
479915f2bd95SEwan Crawford   CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter)
4800b9c1b51eSKate Stone       : CommandObjectMultiword(
4801b9c1b51eSKate Stone             interpreter, "renderscript allocation",
4802b9c1b51eSKate Stone             "Commands that deal with RenderScript allocations.", nullptr) {
4803b9c1b51eSKate Stone     LoadSubCommand(
4804b9c1b51eSKate Stone         "list",
4805b9c1b51eSKate Stone         CommandObjectSP(
4806b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationList(interpreter)));
4807b9c1b51eSKate Stone     LoadSubCommand(
4808b9c1b51eSKate Stone         "dump",
4809b9c1b51eSKate Stone         CommandObjectSP(
4810b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationDump(interpreter)));
4811b9c1b51eSKate Stone     LoadSubCommand(
4812b9c1b51eSKate Stone         "save",
4813b9c1b51eSKate Stone         CommandObjectSP(
4814b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationSave(interpreter)));
4815b9c1b51eSKate Stone     LoadSubCommand(
4816b9c1b51eSKate Stone         "load",
4817b9c1b51eSKate Stone         CommandObjectSP(
4818b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter)));
4819b9c1b51eSKate Stone     LoadSubCommand(
4820b9c1b51eSKate Stone         "refresh",
4821b9c1b51eSKate Stone         CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationRefresh(
4822b9c1b51eSKate Stone             interpreter)));
482315f2bd95SEwan Crawford   }
482415f2bd95SEwan Crawford 
4825222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocation() override = default;
482615f2bd95SEwan Crawford };
482715f2bd95SEwan Crawford 
4828b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed {
48294640cde1SColin Riley public:
48304640cde1SColin Riley   CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter)
4831b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "renderscript status",
4832b9c1b51eSKate Stone                             "Displays current RenderScript runtime status.",
4833b9c1b51eSKate Stone                             "renderscript status",
4834b9c1b51eSKate Stone                             eCommandRequiresProcess |
4835b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
48364640cde1SColin Riley 
4837222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeStatus() override = default;
48384640cde1SColin Riley 
4839b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
4840056f6f18SAlex Langford     RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>(
4841056f6f18SAlex Langford         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4842056f6f18SAlex Langford             eLanguageTypeExtRenderScript));
484397206d57SZachary Turner     runtime->DumpStatus(result.GetOutputStream());
48444640cde1SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
48454640cde1SColin Riley     return true;
48464640cde1SColin Riley   }
48474640cde1SColin Riley };
48484640cde1SColin Riley 
4849b3bbcb12SLuke Drummond class CommandObjectRenderScriptRuntimeReduction
4850b3bbcb12SLuke Drummond     : public CommandObjectMultiword {
4851b3bbcb12SLuke Drummond public:
4852b3bbcb12SLuke Drummond   CommandObjectRenderScriptRuntimeReduction(CommandInterpreter &interpreter)
4853b3bbcb12SLuke Drummond       : CommandObjectMultiword(interpreter, "renderscript reduction",
4854b3bbcb12SLuke Drummond                                "Commands that handle general reduction kernels",
4855b3bbcb12SLuke Drummond                                nullptr) {
4856b3bbcb12SLuke Drummond     LoadSubCommand(
4857b3bbcb12SLuke Drummond         "breakpoint",
4858b3bbcb12SLuke Drummond         CommandObjectSP(new CommandObjectRenderScriptRuntimeReductionBreakpoint(
4859b3bbcb12SLuke Drummond             interpreter)));
4860b3bbcb12SLuke Drummond   }
4861b3bbcb12SLuke Drummond   ~CommandObjectRenderScriptRuntimeReduction() override = default;
4862b3bbcb12SLuke Drummond };
4863b3bbcb12SLuke Drummond 
4864b9c1b51eSKate Stone class CommandObjectRenderScriptRuntime : public CommandObjectMultiword {
48655ec532a9SColin Riley public:
48665ec532a9SColin Riley   CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter)
4867b9c1b51eSKate Stone       : CommandObjectMultiword(
4868b9c1b51eSKate Stone             interpreter, "renderscript",
4869b9c1b51eSKate Stone             "Commands for operating on the RenderScript runtime.",
4870b9c1b51eSKate Stone             "renderscript <subcommand> [<subcommand-options>]") {
4871b9c1b51eSKate Stone     LoadSubCommand(
4872b9c1b51eSKate Stone         "module", CommandObjectSP(
4873b9c1b51eSKate Stone                       new CommandObjectRenderScriptRuntimeModule(interpreter)));
4874b9c1b51eSKate Stone     LoadSubCommand(
4875b9c1b51eSKate Stone         "status", CommandObjectSP(
4876b9c1b51eSKate Stone                       new CommandObjectRenderScriptRuntimeStatus(interpreter)));
4877b9c1b51eSKate Stone     LoadSubCommand(
4878b9c1b51eSKate Stone         "kernel", CommandObjectSP(
4879b9c1b51eSKate Stone                       new CommandObjectRenderScriptRuntimeKernel(interpreter)));
4880b9c1b51eSKate Stone     LoadSubCommand("context",
4881b9c1b51eSKate Stone                    CommandObjectSP(new CommandObjectRenderScriptRuntimeContext(
4882b9c1b51eSKate Stone                        interpreter)));
4883b9c1b51eSKate Stone     LoadSubCommand(
4884b9c1b51eSKate Stone         "allocation",
4885b9c1b51eSKate Stone         CommandObjectSP(
4886b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocation(interpreter)));
488721fed052SAidan Dodds     LoadSubCommand("scriptgroup",
488821fed052SAidan Dodds                    NewCommandObjectRenderScriptScriptGroup(interpreter));
4889b3bbcb12SLuke Drummond     LoadSubCommand(
4890b3bbcb12SLuke Drummond         "reduction",
4891b3bbcb12SLuke Drummond         CommandObjectSP(
4892b3bbcb12SLuke Drummond             new CommandObjectRenderScriptRuntimeReduction(interpreter)));
48935ec532a9SColin Riley   }
48945ec532a9SColin Riley 
4895222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntime() override = default;
48965ec532a9SColin Riley };
4897ef20b08fSColin Riley 
4898b9c1b51eSKate Stone void RenderScriptRuntime::Initiate() { assert(!m_initiated); }
4899ef20b08fSColin Riley 
4900ef20b08fSColin Riley RenderScriptRuntime::RenderScriptRuntime(Process *process)
4901b9c1b51eSKate Stone     : lldb_private::CPPLanguageRuntime(process), m_initiated(false),
4902b9c1b51eSKate Stone       m_debuggerPresentFlagged(false), m_breakAllKernels(false),
4903b9c1b51eSKate Stone       m_ir_passes(nullptr) {
49044640cde1SColin Riley   ModulesDidLoad(process->GetTarget().GetImages());
4905ef20b08fSColin Riley }
49064640cde1SColin Riley 
4907b9c1b51eSKate Stone lldb::CommandObjectSP RenderScriptRuntime::GetCommandObject(
4908b9c1b51eSKate Stone     lldb_private::CommandInterpreter &interpreter) {
49090a66e2f1SEnrico Granata   return CommandObjectSP(new CommandObjectRenderScriptRuntime(interpreter));
49104640cde1SColin Riley }
49114640cde1SColin Riley 
491278f339d1SEwan Crawford RenderScriptRuntime::~RenderScriptRuntime() = default;
4913