15ec532a9SColin Riley //===-- RenderScriptRuntime.cpp ---------------------------------*- C++ -*-===//
25ec532a9SColin Riley //
35ec532a9SColin Riley //                     The LLVM Compiler Infrastructure
45ec532a9SColin Riley //
55ec532a9SColin Riley // This file is distributed under the University of Illinois Open Source
65ec532a9SColin Riley // License. See LICENSE.TXT for details.
75ec532a9SColin Riley //
85ec532a9SColin Riley //===----------------------------------------------------------------------===//
95ec532a9SColin Riley 
10222b937cSEugene Zelenko // C Includes
11222b937cSEugene Zelenko // C++ Includes
12222b937cSEugene Zelenko // Other libraries and framework includes
13222b937cSEugene Zelenko // Project includes
145ec532a9SColin Riley #include "RenderScriptRuntime.h"
155ec532a9SColin Riley 
16b3f7f69dSAidan Dodds #include "lldb/Breakpoint/StoppointCallbackContext.h"
175ec532a9SColin Riley #include "lldb/Core/ConstString.h"
185ec532a9SColin Riley #include "lldb/Core/Debugger.h"
195ec532a9SColin Riley #include "lldb/Core/Error.h"
205ec532a9SColin Riley #include "lldb/Core/Log.h"
215ec532a9SColin Riley #include "lldb/Core/PluginManager.h"
22018f5a7eSEwan Crawford #include "lldb/Core/RegularExpression.h"
23b3f7f69dSAidan Dodds #include "lldb/Core/ValueObjectVariable.h"
248b244e21SEwan Crawford #include "lldb/DataFormatters/DumpValueObjectOptions.h"
25b3f7f69dSAidan Dodds #include "lldb/Expression/UserExpression.h"
26a0f08674SEwan Crawford #include "lldb/Host/StringConvert.h"
27b3f7f69dSAidan Dodds #include "lldb/Interpreter/Args.h"
28b3f7f69dSAidan Dodds #include "lldb/Interpreter/CommandInterpreter.h"
29b3f7f69dSAidan Dodds #include "lldb/Interpreter/CommandObjectMultiword.h"
30b3f7f69dSAidan Dodds #include "lldb/Interpreter/CommandReturnObject.h"
31b3f7f69dSAidan Dodds #include "lldb/Interpreter/Options.h"
325ec532a9SColin Riley #include "lldb/Symbol/Symbol.h"
334640cde1SColin Riley #include "lldb/Symbol/Type.h"
34b3f7f69dSAidan Dodds #include "lldb/Symbol/VariableList.h"
355ec532a9SColin Riley #include "lldb/Target/Process.h"
36b3f7f69dSAidan Dodds #include "lldb/Target/RegisterContext.h"
375ec532a9SColin Riley #include "lldb/Target/Target.h"
38018f5a7eSEwan Crawford #include "lldb/Target/Thread.h"
395ec532a9SColin Riley 
405ec532a9SColin Riley using namespace lldb;
415ec532a9SColin Riley using namespace lldb_private;
4298156583SEwan Crawford using namespace lldb_renderscript;
435ec532a9SColin Riley 
44*b9c1b51eSKate Stone namespace {
4578f339d1SEwan Crawford 
4678f339d1SEwan Crawford // The empirical_type adds a basic level of validation to arbitrary data
4778f339d1SEwan Crawford // allowing us to track if data has been discovered and stored or not.
48*b9c1b51eSKate Stone // An empirical_type will be marked as valid only if it has been explicitly
49*b9c1b51eSKate Stone // assigned to.
50*b9c1b51eSKate Stone template <typename type_t> class empirical_type {
5178f339d1SEwan Crawford public:
5278f339d1SEwan Crawford   // Ctor. Contents is invalid when constructed.
53b3f7f69dSAidan Dodds   empirical_type() : valid(false) {}
5478f339d1SEwan Crawford 
5578f339d1SEwan Crawford   // Return true and copy contents to out if valid, else return false.
56*b9c1b51eSKate Stone   bool get(type_t &out) const {
5778f339d1SEwan Crawford     if (valid)
5878f339d1SEwan Crawford       out = data;
5978f339d1SEwan Crawford     return valid;
6078f339d1SEwan Crawford   }
6178f339d1SEwan Crawford 
6278f339d1SEwan Crawford   // Return a pointer to the contents or nullptr if it was not valid.
63*b9c1b51eSKate Stone   const type_t *get() const { return valid ? &data : nullptr; }
6478f339d1SEwan Crawford 
6578f339d1SEwan Crawford   // Assign data explicitly.
66*b9c1b51eSKate Stone   void set(const type_t in) {
6778f339d1SEwan Crawford     data = in;
6878f339d1SEwan Crawford     valid = true;
6978f339d1SEwan Crawford   }
7078f339d1SEwan Crawford 
7178f339d1SEwan Crawford   // Mark contents as invalid.
72*b9c1b51eSKate Stone   void invalidate() { valid = false; }
7378f339d1SEwan Crawford 
7478f339d1SEwan Crawford   // Returns true if this type contains valid data.
75*b9c1b51eSKate Stone   bool isValid() const { return valid; }
7678f339d1SEwan Crawford 
7778f339d1SEwan Crawford   // Assignment operator.
78*b9c1b51eSKate Stone   empirical_type<type_t> &operator=(const type_t in) {
7978f339d1SEwan Crawford     set(in);
8078f339d1SEwan Crawford     return *this;
8178f339d1SEwan Crawford   }
8278f339d1SEwan Crawford 
8378f339d1SEwan Crawford   // Dereference operator returns contents.
8478f339d1SEwan Crawford   // Warning: Will assert if not valid so use only when you know data is valid.
85*b9c1b51eSKate Stone   const type_t &operator*() const {
8678f339d1SEwan Crawford     assert(valid);
8778f339d1SEwan Crawford     return data;
8878f339d1SEwan Crawford   }
8978f339d1SEwan Crawford 
9078f339d1SEwan Crawford protected:
9178f339d1SEwan Crawford   bool valid;
9278f339d1SEwan Crawford   type_t data;
9378f339d1SEwan Crawford };
9478f339d1SEwan Crawford 
95*b9c1b51eSKate Stone // ArgItem is used by the GetArgs() function when reading function arguments
96*b9c1b51eSKate Stone // from the target.
97*b9c1b51eSKate Stone struct ArgItem {
98*b9c1b51eSKate Stone   enum { ePointer, eInt32, eInt64, eLong, eBool } type;
99f4786785SAidan Dodds 
100f4786785SAidan Dodds   uint64_t value;
101f4786785SAidan Dodds 
102f4786785SAidan Dodds   explicit operator uint64_t() const { return value; }
103f4786785SAidan Dodds };
104f4786785SAidan Dodds 
105*b9c1b51eSKate Stone // Context structure to be passed into GetArgsXXX(), argument reading functions
106*b9c1b51eSKate Stone // below.
107*b9c1b51eSKate Stone struct GetArgsCtx {
108f4786785SAidan Dodds   RegisterContext *reg_ctx;
109f4786785SAidan Dodds   Process *process;
110f4786785SAidan Dodds };
111f4786785SAidan Dodds 
112*b9c1b51eSKate Stone bool GetArgsX86(const GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
113f4786785SAidan Dodds   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
114f4786785SAidan Dodds 
11567dc3e15SAidan Dodds   Error error;
11667dc3e15SAidan Dodds 
117f4786785SAidan Dodds   // get the current stack pointer
118f4786785SAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP();
119f4786785SAidan Dodds 
120*b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
121f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
122f4786785SAidan Dodds     // advance up the stack by one argument
123f4786785SAidan Dodds     sp += sizeof(uint32_t);
124f4786785SAidan Dodds     // get the argument type size
125f4786785SAidan Dodds     size_t arg_size = sizeof(uint32_t);
126f4786785SAidan Dodds     // read the argument from memory
127f4786785SAidan Dodds     arg.value = 0;
128f4786785SAidan Dodds     Error error;
129*b9c1b51eSKate Stone     size_t read =
130*b9c1b51eSKate Stone         ctx.process->ReadMemory(sp, &arg.value, sizeof(uint32_t), error);
131*b9c1b51eSKate Stone     if (read != arg_size || !error.Success()) {
132f4786785SAidan Dodds       if (log)
133*b9c1b51eSKate Stone         log->Printf("%s - error reading argument: %" PRIu64 " '%s'",
134*b9c1b51eSKate Stone                     __FUNCTION__, uint64_t(i), error.AsCString());
135f4786785SAidan Dodds       return false;
136f4786785SAidan Dodds     }
137f4786785SAidan Dodds   }
138f4786785SAidan Dodds   return true;
139f4786785SAidan Dodds }
140f4786785SAidan Dodds 
141*b9c1b51eSKate Stone bool GetArgsX86_64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
142f4786785SAidan Dodds   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
143f4786785SAidan Dodds 
144f4786785SAidan Dodds   // number of arguments passed in registers
145f4786785SAidan Dodds   static const uint32_t c_args_in_reg = 6;
146f4786785SAidan Dodds   // register passing order
147*b9c1b51eSKate Stone   static const std::array<const char *, c_args_in_reg> c_reg_names{
148*b9c1b51eSKate Stone       {"rdi", "rsi", "rdx", "rcx", "r8", "r9"}};
149f4786785SAidan Dodds   // argument type to size mapping
1501ee07253SSaleem Abdulrasool   static const std::array<size_t, 5> arg_size{{
151f4786785SAidan Dodds       8, // ePointer,
152f4786785SAidan Dodds       4, // eInt32,
153f4786785SAidan Dodds       8, // eInt64,
154f4786785SAidan Dodds       8, // eLong,
155f4786785SAidan Dodds       4, // eBool,
1561ee07253SSaleem Abdulrasool   }};
157f4786785SAidan Dodds 
15817e07c0aSAidan Dodds   Error error;
15917e07c0aSAidan Dodds 
160f4786785SAidan Dodds   // get the current stack pointer
161f4786785SAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP();
162f4786785SAidan Dodds   // step over the return address
163f4786785SAidan Dodds   sp += sizeof(uint64_t);
164f4786785SAidan Dodds 
165f4786785SAidan Dodds   // check the stack alignment was correct (16 byte aligned)
166*b9c1b51eSKate Stone   if ((sp & 0xf) != 0x0) {
167f4786785SAidan Dodds     if (log)
168f4786785SAidan Dodds       log->Printf("%s - stack misaligned", __FUNCTION__);
169f4786785SAidan Dodds     return false;
170f4786785SAidan Dodds   }
171f4786785SAidan Dodds 
172f4786785SAidan Dodds   // find the start of arguments on the stack
173f4786785SAidan Dodds   uint64_t sp_offset = 0;
174*b9c1b51eSKate Stone   for (uint32_t i = c_args_in_reg; i < num_args; ++i) {
175f4786785SAidan Dodds     sp_offset += arg_size[arg_list[i].type];
176f4786785SAidan Dodds   }
177f4786785SAidan Dodds   // round up to multiple of 16
178f4786785SAidan Dodds   sp_offset = (sp_offset + 0xf) & 0xf;
179f4786785SAidan Dodds   sp += sp_offset;
180f4786785SAidan Dodds 
181*b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
182f4786785SAidan Dodds     bool success = false;
183f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
184f4786785SAidan Dodds     // arguments passed in registers
185*b9c1b51eSKate Stone     if (i < c_args_in_reg) {
186*b9c1b51eSKate Stone       const RegisterInfo *rArg =
187*b9c1b51eSKate Stone           ctx.reg_ctx->GetRegisterInfoByName(c_reg_names[i]);
188f4786785SAidan Dodds       RegisterValue rVal;
189f4786785SAidan Dodds       if (ctx.reg_ctx->ReadRegister(rArg, rVal))
190f4786785SAidan Dodds         arg.value = rVal.GetAsUInt64(0, &success);
191f4786785SAidan Dodds     }
192f4786785SAidan Dodds     // arguments passed on the stack
193*b9c1b51eSKate Stone     else {
194f4786785SAidan Dodds       // get the argument type size
195f4786785SAidan Dodds       const size_t size = arg_size[arg_list[i].type];
196f4786785SAidan Dodds       // read the argument from memory
197f4786785SAidan Dodds       arg.value = 0;
198*b9c1b51eSKate Stone       // note: due to little endian layout reading 4 or 8 bytes will give the
199*b9c1b51eSKate Stone       // correct value.
200f4786785SAidan Dodds       size_t read = ctx.process->ReadMemory(sp, &arg.value, size, error);
201f4786785SAidan Dodds       success = (error.Success() && read == size);
202f4786785SAidan Dodds       // advance past this argument
203f4786785SAidan Dodds       sp -= size;
204f4786785SAidan Dodds     }
205f4786785SAidan Dodds     // fail if we couldn't read this argument
206*b9c1b51eSKate Stone     if (!success) {
207f4786785SAidan Dodds       if (log)
20817e07c0aSAidan Dodds         log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s",
20917e07c0aSAidan Dodds                     __FUNCTION__, uint64_t(i), error.AsCString("n/a"));
210f4786785SAidan Dodds       return false;
211f4786785SAidan Dodds     }
212f4786785SAidan Dodds   }
213f4786785SAidan Dodds   return true;
214f4786785SAidan Dodds }
215f4786785SAidan Dodds 
216*b9c1b51eSKate Stone bool GetArgsArm(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
217f4786785SAidan Dodds   // number of arguments passed in registers
218f4786785SAidan Dodds   static const uint32_t c_args_in_reg = 4;
219f4786785SAidan Dodds 
220f4786785SAidan Dodds   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
221f4786785SAidan Dodds 
22217e07c0aSAidan Dodds   Error error;
22317e07c0aSAidan Dodds 
224f4786785SAidan Dodds   // get the current stack pointer
225f4786785SAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP();
226f4786785SAidan Dodds 
227*b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
228f4786785SAidan Dodds     bool success = false;
229f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
230f4786785SAidan Dodds     // arguments passed in registers
231*b9c1b51eSKate Stone     if (i < c_args_in_reg) {
232f4786785SAidan Dodds       const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoAtIndex(i);
233f4786785SAidan Dodds       RegisterValue rVal;
234f4786785SAidan Dodds       if (ctx.reg_ctx->ReadRegister(rArg, rVal))
235f4786785SAidan Dodds         arg.value = rVal.GetAsUInt32(0, &success);
236f4786785SAidan Dodds     }
237f4786785SAidan Dodds     // arguments passed on the stack
238*b9c1b51eSKate Stone     else {
239f4786785SAidan Dodds       // get the argument type size
240f4786785SAidan Dodds       const size_t arg_size = sizeof(uint32_t);
241f4786785SAidan Dodds       // clear all 64bits
242f4786785SAidan Dodds       arg.value = 0;
243f4786785SAidan Dodds       // read this argument from memory
244*b9c1b51eSKate Stone       size_t bytes_read =
245*b9c1b51eSKate Stone           ctx.process->ReadMemory(sp, &arg.value, arg_size, error);
246f4786785SAidan Dodds       success = (error.Success() && bytes_read == arg_size);
247f4786785SAidan Dodds       // advance the stack pointer
248f4786785SAidan Dodds       sp += sizeof(uint32_t);
249f4786785SAidan Dodds     }
250f4786785SAidan Dodds     // fail if we couldn't read this argument
251*b9c1b51eSKate Stone     if (!success) {
252f4786785SAidan Dodds       if (log)
25317e07c0aSAidan Dodds         log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s",
25417e07c0aSAidan Dodds                     __FUNCTION__, uint64_t(i), error.AsCString("n/a"));
255f4786785SAidan Dodds       return false;
256f4786785SAidan Dodds     }
257f4786785SAidan Dodds   }
258f4786785SAidan Dodds   return true;
259f4786785SAidan Dodds }
260f4786785SAidan Dodds 
261*b9c1b51eSKate Stone bool GetArgsAarch64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
262f4786785SAidan Dodds   // number of arguments passed in registers
263f4786785SAidan Dodds   static const uint32_t c_args_in_reg = 8;
264f4786785SAidan Dodds 
265f4786785SAidan Dodds   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
266f4786785SAidan Dodds 
267*b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
268f4786785SAidan Dodds     bool success = false;
269f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
270f4786785SAidan Dodds     // arguments passed in registers
271*b9c1b51eSKate Stone     if (i < c_args_in_reg) {
272f4786785SAidan Dodds       const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoAtIndex(i);
273f4786785SAidan Dodds       RegisterValue rVal;
274f4786785SAidan Dodds       if (ctx.reg_ctx->ReadRegister(rArg, rVal))
275f4786785SAidan Dodds         arg.value = rVal.GetAsUInt64(0, &success);
276f4786785SAidan Dodds     }
277f4786785SAidan Dodds     // arguments passed on the stack
278*b9c1b51eSKate Stone     else {
279f4786785SAidan Dodds       if (log)
280*b9c1b51eSKate Stone         log->Printf("%s - reading arguments spilled to stack not implemented",
281*b9c1b51eSKate Stone                     __FUNCTION__);
282f4786785SAidan Dodds     }
283f4786785SAidan Dodds     // fail if we couldn't read this argument
284*b9c1b51eSKate Stone     if (!success) {
285f4786785SAidan Dodds       if (log)
286f4786785SAidan Dodds         log->Printf("%s - error reading argument: %" PRIu64, __FUNCTION__,
287f4786785SAidan Dodds                     uint64_t(i));
288f4786785SAidan Dodds       return false;
289f4786785SAidan Dodds     }
290f4786785SAidan Dodds   }
291f4786785SAidan Dodds   return true;
292f4786785SAidan Dodds }
293f4786785SAidan Dodds 
294*b9c1b51eSKate Stone bool GetArgsMipsel(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
295f4786785SAidan Dodds   // number of arguments passed in registers
296f4786785SAidan Dodds   static const uint32_t c_args_in_reg = 4;
297f4786785SAidan Dodds   // register file offset to first argument
298f4786785SAidan Dodds   static const uint32_t c_reg_offset = 4;
299f4786785SAidan Dodds 
300f4786785SAidan Dodds   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
301f4786785SAidan Dodds 
30217e07c0aSAidan Dodds   Error error;
30317e07c0aSAidan Dodds 
30417e07c0aSAidan Dodds   // find offset to arguments on the stack (+16 to skip over a0-a3 shadow space)
30517e07c0aSAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP() + 16;
30617e07c0aSAidan Dodds 
307*b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
308f4786785SAidan Dodds     bool success = false;
309f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
310f4786785SAidan Dodds     // arguments passed in registers
311*b9c1b51eSKate Stone     if (i < c_args_in_reg) {
312*b9c1b51eSKate Stone       const RegisterInfo *rArg =
313*b9c1b51eSKate Stone           ctx.reg_ctx->GetRegisterInfoAtIndex(i + c_reg_offset);
314f4786785SAidan Dodds       RegisterValue rVal;
315f4786785SAidan Dodds       if (ctx.reg_ctx->ReadRegister(rArg, rVal))
316f4786785SAidan Dodds         arg.value = rVal.GetAsUInt64(0, &success);
317f4786785SAidan Dodds     }
318f4786785SAidan Dodds     // arguments passed on the stack
319*b9c1b51eSKate Stone     else {
3206dd4b579SAidan Dodds       const size_t arg_size = sizeof(uint32_t);
3216dd4b579SAidan Dodds       arg.value = 0;
322*b9c1b51eSKate Stone       size_t bytes_read =
323*b9c1b51eSKate Stone           ctx.process->ReadMemory(sp, &arg.value, arg_size, error);
3246dd4b579SAidan Dodds       success = (error.Success() && bytes_read == arg_size);
32567dc3e15SAidan Dodds       // advance the stack pointer
32667dc3e15SAidan Dodds       sp += arg_size;
327f4786785SAidan Dodds     }
328f4786785SAidan Dodds     // fail if we couldn't read this argument
329*b9c1b51eSKate Stone     if (!success) {
330f4786785SAidan Dodds       if (log)
33167dc3e15SAidan Dodds         log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s",
33267dc3e15SAidan Dodds                     __FUNCTION__, uint64_t(i), error.AsCString("n/a"));
333f4786785SAidan Dodds       return false;
334f4786785SAidan Dodds     }
335f4786785SAidan Dodds   }
336f4786785SAidan Dodds   return true;
337f4786785SAidan Dodds }
338f4786785SAidan Dodds 
339*b9c1b51eSKate Stone bool GetArgsMips64el(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
340f4786785SAidan Dodds   // number of arguments passed in registers
341f4786785SAidan Dodds   static const uint32_t c_args_in_reg = 8;
342f4786785SAidan Dodds   // register file offset to first argument
343f4786785SAidan Dodds   static const uint32_t c_reg_offset = 4;
344f4786785SAidan Dodds 
345f4786785SAidan Dodds   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
346f4786785SAidan Dodds 
34717e07c0aSAidan Dodds   Error error;
34817e07c0aSAidan Dodds 
349f4786785SAidan Dodds   // get the current stack pointer
350f4786785SAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP();
351f4786785SAidan Dodds 
352*b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
353f4786785SAidan Dodds     bool success = false;
354f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
355f4786785SAidan Dodds     // arguments passed in registers
356*b9c1b51eSKate Stone     if (i < c_args_in_reg) {
357*b9c1b51eSKate Stone       const RegisterInfo *rArg =
358*b9c1b51eSKate Stone           ctx.reg_ctx->GetRegisterInfoAtIndex(i + c_reg_offset);
359f4786785SAidan Dodds       RegisterValue rVal;
360f4786785SAidan Dodds       if (ctx.reg_ctx->ReadRegister(rArg, rVal))
36172f77525SAidan Dodds         arg.value = rVal.GetAsUInt64(0, &success);
362f4786785SAidan Dodds     }
363f4786785SAidan Dodds     // arguments passed on the stack
364*b9c1b51eSKate Stone     else {
365f4786785SAidan Dodds       // get the argument type size
366f4786785SAidan Dodds       const size_t arg_size = sizeof(uint64_t);
367f4786785SAidan Dodds       // clear all 64bits
368f4786785SAidan Dodds       arg.value = 0;
369f4786785SAidan Dodds       // read this argument from memory
370*b9c1b51eSKate Stone       size_t bytes_read =
371*b9c1b51eSKate Stone           ctx.process->ReadMemory(sp, &arg.value, arg_size, error);
372f4786785SAidan Dodds       success = (error.Success() && bytes_read == arg_size);
373f4786785SAidan Dodds       // advance the stack pointer
374f4786785SAidan Dodds       sp += arg_size;
375f4786785SAidan Dodds     }
376f4786785SAidan Dodds     // fail if we couldn't read this argument
377*b9c1b51eSKate Stone     if (!success) {
378f4786785SAidan Dodds       if (log)
37917e07c0aSAidan Dodds         log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s",
38017e07c0aSAidan Dodds                     __FUNCTION__, uint64_t(i), error.AsCString("n/a"));
381f4786785SAidan Dodds       return false;
382f4786785SAidan Dodds     }
383f4786785SAidan Dodds   }
384f4786785SAidan Dodds   return true;
385f4786785SAidan Dodds }
386f4786785SAidan Dodds 
387*b9c1b51eSKate Stone bool GetArgs(ExecutionContext &context, ArgItem *arg_list, size_t num_args) {
388f4786785SAidan Dodds   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
389f4786785SAidan Dodds 
390f4786785SAidan Dodds   // verify that we have a target
391*b9c1b51eSKate Stone   if (!context.GetTargetPtr()) {
392f4786785SAidan Dodds     if (log)
393f4786785SAidan Dodds       log->Printf("%s - invalid target", __FUNCTION__);
394f4786785SAidan Dodds     return false;
395f4786785SAidan Dodds   }
396f4786785SAidan Dodds 
397f4786785SAidan Dodds   GetArgsCtx ctx = {context.GetRegisterContext(), context.GetProcessPtr()};
398f4786785SAidan Dodds   assert(ctx.reg_ctx && ctx.process);
399f4786785SAidan Dodds 
400f4786785SAidan Dodds   // dispatch based on architecture
401*b9c1b51eSKate Stone   switch (context.GetTargetPtr()->GetArchitecture().GetMachine()) {
402f4786785SAidan Dodds   case llvm::Triple::ArchType::x86:
403f4786785SAidan Dodds     return GetArgsX86(ctx, arg_list, num_args);
404f4786785SAidan Dodds 
405f4786785SAidan Dodds   case llvm::Triple::ArchType::x86_64:
406f4786785SAidan Dodds     return GetArgsX86_64(ctx, arg_list, num_args);
407f4786785SAidan Dodds 
408f4786785SAidan Dodds   case llvm::Triple::ArchType::arm:
409f4786785SAidan Dodds     return GetArgsArm(ctx, arg_list, num_args);
410f4786785SAidan Dodds 
411f4786785SAidan Dodds   case llvm::Triple::ArchType::aarch64:
412f4786785SAidan Dodds     return GetArgsAarch64(ctx, arg_list, num_args);
413f4786785SAidan Dodds 
414f4786785SAidan Dodds   case llvm::Triple::ArchType::mipsel:
415f4786785SAidan Dodds     return GetArgsMipsel(ctx, arg_list, num_args);
416f4786785SAidan Dodds 
417f4786785SAidan Dodds   case llvm::Triple::ArchType::mips64el:
418f4786785SAidan Dodds     return GetArgsMips64el(ctx, arg_list, num_args);
419f4786785SAidan Dodds 
420f4786785SAidan Dodds   default:
421f4786785SAidan Dodds     // unsupported architecture
422*b9c1b51eSKate Stone     if (log) {
423*b9c1b51eSKate Stone       log->Printf(
424*b9c1b51eSKate Stone           "%s - architecture not supported: '%s'", __FUNCTION__,
425f4786785SAidan Dodds           context.GetTargetRef().GetArchitecture().GetArchitectureName());
426f4786785SAidan Dodds     }
427f4786785SAidan Dodds     return false;
428f4786785SAidan Dodds   }
429f4786785SAidan Dodds }
430222b937cSEugene Zelenko } // anonymous namespace
43178f339d1SEwan Crawford 
432*b9c1b51eSKate Stone // The ScriptDetails class collects data associated with a single script
433*b9c1b51eSKate Stone // instance.
434*b9c1b51eSKate Stone struct RenderScriptRuntime::ScriptDetails {
435222b937cSEugene Zelenko   ~ScriptDetails() = default;
43678f339d1SEwan Crawford 
437*b9c1b51eSKate Stone   enum ScriptType { eScript, eScriptC };
43878f339d1SEwan Crawford 
43978f339d1SEwan Crawford   // The derived type of the script.
44078f339d1SEwan Crawford   empirical_type<ScriptType> type;
44178f339d1SEwan Crawford   // The name of the original source file.
44278f339d1SEwan Crawford   empirical_type<std::string> resName;
44378f339d1SEwan Crawford   // Path to script .so file on the device.
44478f339d1SEwan Crawford   empirical_type<std::string> scriptDyLib;
44578f339d1SEwan Crawford   // Directory where kernel objects are cached on device.
44678f339d1SEwan Crawford   empirical_type<std::string> cacheDir;
44778f339d1SEwan Crawford   // Pointer to the context which owns this script.
44878f339d1SEwan Crawford   empirical_type<lldb::addr_t> context;
44978f339d1SEwan Crawford   // Pointer to the script object itself.
45078f339d1SEwan Crawford   empirical_type<lldb::addr_t> script;
45178f339d1SEwan Crawford };
45278f339d1SEwan Crawford 
4538b244e21SEwan Crawford // This Element class represents the Element object in RS,
4548b244e21SEwan Crawford // defining the type associated with an Allocation.
455*b9c1b51eSKate Stone struct RenderScriptRuntime::Element {
45615f2bd95SEwan Crawford   // Taken from rsDefines.h
457*b9c1b51eSKate Stone   enum DataKind {
45815f2bd95SEwan Crawford     RS_KIND_USER,
45915f2bd95SEwan Crawford     RS_KIND_PIXEL_L = 7,
46015f2bd95SEwan Crawford     RS_KIND_PIXEL_A,
46115f2bd95SEwan Crawford     RS_KIND_PIXEL_LA,
46215f2bd95SEwan Crawford     RS_KIND_PIXEL_RGB,
46315f2bd95SEwan Crawford     RS_KIND_PIXEL_RGBA,
46415f2bd95SEwan Crawford     RS_KIND_PIXEL_DEPTH,
46515f2bd95SEwan Crawford     RS_KIND_PIXEL_YUV,
46615f2bd95SEwan Crawford     RS_KIND_INVALID = 100
46715f2bd95SEwan Crawford   };
46878f339d1SEwan Crawford 
46915f2bd95SEwan Crawford   // Taken from rsDefines.h
470*b9c1b51eSKate Stone   enum DataType {
47115f2bd95SEwan Crawford     RS_TYPE_NONE = 0,
47215f2bd95SEwan Crawford     RS_TYPE_FLOAT_16,
47315f2bd95SEwan Crawford     RS_TYPE_FLOAT_32,
47415f2bd95SEwan Crawford     RS_TYPE_FLOAT_64,
47515f2bd95SEwan Crawford     RS_TYPE_SIGNED_8,
47615f2bd95SEwan Crawford     RS_TYPE_SIGNED_16,
47715f2bd95SEwan Crawford     RS_TYPE_SIGNED_32,
47815f2bd95SEwan Crawford     RS_TYPE_SIGNED_64,
47915f2bd95SEwan Crawford     RS_TYPE_UNSIGNED_8,
48015f2bd95SEwan Crawford     RS_TYPE_UNSIGNED_16,
48115f2bd95SEwan Crawford     RS_TYPE_UNSIGNED_32,
48215f2bd95SEwan Crawford     RS_TYPE_UNSIGNED_64,
4832e920715SEwan Crawford     RS_TYPE_BOOLEAN,
4842e920715SEwan Crawford 
4852e920715SEwan Crawford     RS_TYPE_UNSIGNED_5_6_5,
4862e920715SEwan Crawford     RS_TYPE_UNSIGNED_5_5_5_1,
4872e920715SEwan Crawford     RS_TYPE_UNSIGNED_4_4_4_4,
4882e920715SEwan Crawford 
4892e920715SEwan Crawford     RS_TYPE_MATRIX_4X4,
4902e920715SEwan Crawford     RS_TYPE_MATRIX_3X3,
4912e920715SEwan Crawford     RS_TYPE_MATRIX_2X2,
4922e920715SEwan Crawford 
4932e920715SEwan Crawford     RS_TYPE_ELEMENT = 1000,
4942e920715SEwan Crawford     RS_TYPE_TYPE,
4952e920715SEwan Crawford     RS_TYPE_ALLOCATION,
4962e920715SEwan Crawford     RS_TYPE_SAMPLER,
4972e920715SEwan Crawford     RS_TYPE_SCRIPT,
4982e920715SEwan Crawford     RS_TYPE_MESH,
4992e920715SEwan Crawford     RS_TYPE_PROGRAM_FRAGMENT,
5002e920715SEwan Crawford     RS_TYPE_PROGRAM_VERTEX,
5012e920715SEwan Crawford     RS_TYPE_PROGRAM_RASTER,
5022e920715SEwan Crawford     RS_TYPE_PROGRAM_STORE,
5032e920715SEwan Crawford     RS_TYPE_FONT,
5042e920715SEwan Crawford 
5052e920715SEwan Crawford     RS_TYPE_INVALID = 10000
50678f339d1SEwan Crawford   };
50778f339d1SEwan Crawford 
5088b244e21SEwan Crawford   std::vector<Element> children; // Child Element fields for structs
509*b9c1b51eSKate Stone   empirical_type<lldb::addr_t>
510*b9c1b51eSKate Stone       element_ptr; // Pointer to the RS Element of the Type
511*b9c1b51eSKate Stone   empirical_type<DataType>
512*b9c1b51eSKate Stone       type; // Type of each data pointer stored by the allocation
513*b9c1b51eSKate Stone   empirical_type<DataKind>
514*b9c1b51eSKate Stone       type_kind; // Defines pixel type if Allocation is created from an image
515*b9c1b51eSKate Stone   empirical_type<uint32_t>
516*b9c1b51eSKate Stone       type_vec_size; // Vector size of each data point, e.g '4' for uchar4
5178b244e21SEwan Crawford   empirical_type<uint32_t> field_count; // Number of Subelements
5188b244e21SEwan Crawford   empirical_type<uint32_t> datum_size;  // Size of a single Element with padding
5198b244e21SEwan Crawford   empirical_type<uint32_t> padding;     // Number of padding bytes
520*b9c1b51eSKate Stone   empirical_type<uint32_t>
521*b9c1b51eSKate Stone       array_size;        // Number of items in array, only needed for strucrs
5228b244e21SEwan Crawford   ConstString type_name; // Name of type, only needed for structs
5238b244e21SEwan Crawford 
524b3f7f69dSAidan Dodds   static const ConstString &
525b3f7f69dSAidan Dodds   GetFallbackStructName(); // Print this as the type name of a struct Element
5268b244e21SEwan Crawford                            // If we can't resolve the actual struct name
5278b59062aSEwan Crawford 
528*b9c1b51eSKate Stone   bool shouldRefresh() const {
5298b59062aSEwan Crawford     const bool valid_ptr = element_ptr.isValid() && *element_ptr.get() != 0x0;
530*b9c1b51eSKate Stone     const bool valid_type =
531*b9c1b51eSKate Stone         type.isValid() && type_vec_size.isValid() && type_kind.isValid();
5328b59062aSEwan Crawford     return !valid_ptr || !valid_type || !datum_size.isValid();
5338b59062aSEwan Crawford   }
5348b244e21SEwan Crawford };
5358b244e21SEwan Crawford 
5368b244e21SEwan Crawford // This AllocationDetails class collects data associated with a single
5378b244e21SEwan Crawford // allocation instance.
538*b9c1b51eSKate Stone struct RenderScriptRuntime::AllocationDetails {
539*b9c1b51eSKate Stone   struct Dimension {
54015f2bd95SEwan Crawford     uint32_t dim_1;
54115f2bd95SEwan Crawford     uint32_t dim_2;
54215f2bd95SEwan Crawford     uint32_t dim_3;
54315f2bd95SEwan Crawford     uint32_t cubeMap;
54415f2bd95SEwan Crawford 
545*b9c1b51eSKate Stone     Dimension() {
54615f2bd95SEwan Crawford       dim_1 = 0;
54715f2bd95SEwan Crawford       dim_2 = 0;
54815f2bd95SEwan Crawford       dim_3 = 0;
54915f2bd95SEwan Crawford       cubeMap = 0;
55015f2bd95SEwan Crawford     }
55178f339d1SEwan Crawford   };
55278f339d1SEwan Crawford 
553*b9c1b51eSKate Stone   // The FileHeader struct specifies the header we use for writing allocations
554*b9c1b51eSKate Stone   // to a binary file.
555*b9c1b51eSKate Stone   // Our format begins with the ASCII characters "RSAD", identifying the file as
556*b9c1b51eSKate Stone   // an allocation dump.
557*b9c1b51eSKate Stone   // Member variables dims and hdr_size are then written consecutively,
558*b9c1b51eSKate Stone   // immediately followed by an instance of
559*b9c1b51eSKate Stone   // the ElementHeader struct. Because Elements can contain subelements, there
560*b9c1b51eSKate Stone   // may be more than one instance
561*b9c1b51eSKate Stone   // of the ElementHeader struct. With this first instance being the root
562*b9c1b51eSKate Stone   // element, and the other instances being
563*b9c1b51eSKate Stone   // the root's descendants. To identify which instances are an ElementHeader's
564*b9c1b51eSKate Stone   // children, each struct
565*b9c1b51eSKate Stone   // is immediately followed by a sequence of consecutive offsets to the start
566*b9c1b51eSKate Stone   // of its child structs.
567*b9c1b51eSKate Stone   // These offsets are 4 bytes in size, and the 0 offset signifies no more
568*b9c1b51eSKate Stone   // children.
569*b9c1b51eSKate Stone   struct FileHeader {
57055232f09SEwan Crawford     uint8_t ident[4];  // ASCII 'RSAD' identifying the file
57126e52a70SEwan Crawford     uint32_t dims[3];  // Dimensions
57226e52a70SEwan Crawford     uint16_t hdr_size; // Header size in bytes, including all element headers
57326e52a70SEwan Crawford   };
57426e52a70SEwan Crawford 
575*b9c1b51eSKate Stone   struct ElementHeader {
57655232f09SEwan Crawford     uint16_t type;         // DataType enum
57755232f09SEwan Crawford     uint32_t kind;         // DataKind enum
57855232f09SEwan Crawford     uint32_t element_size; // Size of a single element, including padding
57926e52a70SEwan Crawford     uint16_t vector_size;  // Vector width
58026e52a70SEwan Crawford     uint32_t array_size;   // Number of elements in array
58155232f09SEwan Crawford   };
58255232f09SEwan Crawford 
58315f2bd95SEwan Crawford   // Monotonically increasing from 1
584b3f7f69dSAidan Dodds   static uint32_t ID;
58515f2bd95SEwan Crawford 
58615f2bd95SEwan Crawford   // Maps Allocation DataType enum and vector size to printable strings
58715f2bd95SEwan Crawford   // using mapping from RenderScript numerical types summary documentation
58815f2bd95SEwan Crawford   static const char *RsDataTypeToString[][4];
58915f2bd95SEwan Crawford 
59015f2bd95SEwan Crawford   // Maps Allocation DataKind enum to printable strings
59115f2bd95SEwan Crawford   static const char *RsDataKindToString[];
59215f2bd95SEwan Crawford 
593a0f08674SEwan Crawford   // Maps allocation types to format sizes for printing.
594b3f7f69dSAidan Dodds   static const uint32_t RSTypeToFormat[][3];
595a0f08674SEwan Crawford 
59615f2bd95SEwan Crawford   // Give each allocation an ID as a way
59715f2bd95SEwan Crawford   // for commands to reference it.
598b3f7f69dSAidan Dodds   const uint32_t id;
59915f2bd95SEwan Crawford 
6008b244e21SEwan Crawford   RenderScriptRuntime::Element element; // Allocation Element type
60115f2bd95SEwan Crawford   empirical_type<Dimension> dimension;  // Dimensions of the Allocation
602*b9c1b51eSKate Stone   empirical_type<lldb::addr_t>
603*b9c1b51eSKate Stone       address; // Pointer to address of the RS Allocation
604*b9c1b51eSKate Stone   empirical_type<lldb::addr_t>
605*b9c1b51eSKate Stone       data_ptr; // Pointer to the data held by the Allocation
606*b9c1b51eSKate Stone   empirical_type<lldb::addr_t>
607*b9c1b51eSKate Stone       type_ptr; // Pointer to the RS Type of the Allocation
608*b9c1b51eSKate Stone   empirical_type<lldb::addr_t>
609*b9c1b51eSKate Stone       context;                   // Pointer to the RS Context of the Allocation
610a0f08674SEwan Crawford   empirical_type<uint32_t> size; // Size of the allocation
611a0f08674SEwan Crawford   empirical_type<uint32_t> stride; // Stride between rows of the allocation
61215f2bd95SEwan Crawford 
61315f2bd95SEwan Crawford   // Give each allocation an id, so we can reference it in user commands.
614b3f7f69dSAidan Dodds   AllocationDetails() : id(ID++) {}
6158b59062aSEwan Crawford 
616*b9c1b51eSKate Stone   bool shouldRefresh() const {
6178b59062aSEwan Crawford     bool valid_ptrs = data_ptr.isValid() && *data_ptr.get() != 0x0;
6188b59062aSEwan Crawford     valid_ptrs = valid_ptrs && type_ptr.isValid() && *type_ptr.get() != 0x0;
619*b9c1b51eSKate Stone     return !valid_ptrs || !dimension.isValid() || !size.isValid() ||
620*b9c1b51eSKate Stone            element.shouldRefresh();
6218b59062aSEwan Crawford   }
62215f2bd95SEwan Crawford };
62315f2bd95SEwan Crawford 
624*b9c1b51eSKate Stone const ConstString &RenderScriptRuntime::Element::GetFallbackStructName() {
625fe06b5adSAdrian McCarthy   static const ConstString FallbackStructName("struct");
626fe06b5adSAdrian McCarthy   return FallbackStructName;
627fe06b5adSAdrian McCarthy }
6288b244e21SEwan Crawford 
629b3f7f69dSAidan Dodds uint32_t RenderScriptRuntime::AllocationDetails::ID = 1;
63015f2bd95SEwan Crawford 
631b3f7f69dSAidan Dodds const char *RenderScriptRuntime::AllocationDetails::RsDataKindToString[] = {
632*b9c1b51eSKate Stone     "User",       "Undefined",   "Undefined", "Undefined",
633*b9c1b51eSKate Stone     "Undefined",  "Undefined",   "Undefined", // Enum jumps from 0 to 7
634b3f7f69dSAidan Dodds     "L Pixel",    "A Pixel",     "LA Pixel",  "RGB Pixel",
635b3f7f69dSAidan Dodds     "RGBA Pixel", "Pixel Depth", "YUV Pixel"};
63615f2bd95SEwan Crawford 
637b3f7f69dSAidan Dodds const char *RenderScriptRuntime::AllocationDetails::RsDataTypeToString[][4] = {
63815f2bd95SEwan Crawford     {"None", "None", "None", "None"},
63915f2bd95SEwan Crawford     {"half", "half2", "half3", "half4"},
64015f2bd95SEwan Crawford     {"float", "float2", "float3", "float4"},
64115f2bd95SEwan Crawford     {"double", "double2", "double3", "double4"},
64215f2bd95SEwan Crawford     {"char", "char2", "char3", "char4"},
64315f2bd95SEwan Crawford     {"short", "short2", "short3", "short4"},
64415f2bd95SEwan Crawford     {"int", "int2", "int3", "int4"},
64515f2bd95SEwan Crawford     {"long", "long2", "long3", "long4"},
64615f2bd95SEwan Crawford     {"uchar", "uchar2", "uchar3", "uchar4"},
64715f2bd95SEwan Crawford     {"ushort", "ushort2", "ushort3", "ushort4"},
64815f2bd95SEwan Crawford     {"uint", "uint2", "uint3", "uint4"},
64915f2bd95SEwan Crawford     {"ulong", "ulong2", "ulong3", "ulong4"},
6502e920715SEwan Crawford     {"bool", "bool2", "bool3", "bool4"},
6512e920715SEwan Crawford     {"packed_565", "packed_565", "packed_565", "packed_565"},
6522e920715SEwan Crawford     {"packed_5551", "packed_5551", "packed_5551", "packed_5551"},
6532e920715SEwan Crawford     {"packed_4444", "packed_4444", "packed_4444", "packed_4444"},
6542e920715SEwan Crawford     {"rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4"},
6552e920715SEwan Crawford     {"rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3"},
6562e920715SEwan Crawford     {"rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2"},
6572e920715SEwan Crawford 
6582e920715SEwan Crawford     // Handlers
6592e920715SEwan Crawford     {"RS Element", "RS Element", "RS Element", "RS Element"},
6602e920715SEwan Crawford     {"RS Type", "RS Type", "RS Type", "RS Type"},
6612e920715SEwan Crawford     {"RS Allocation", "RS Allocation", "RS Allocation", "RS Allocation"},
6622e920715SEwan Crawford     {"RS Sampler", "RS Sampler", "RS Sampler", "RS Sampler"},
6632e920715SEwan Crawford     {"RS Script", "RS Script", "RS Script", "RS Script"},
6642e920715SEwan Crawford 
6652e920715SEwan Crawford     // Deprecated
6662e920715SEwan Crawford     {"RS Mesh", "RS Mesh", "RS Mesh", "RS Mesh"},
667*b9c1b51eSKate Stone     {"RS Program Fragment", "RS Program Fragment", "RS Program Fragment",
668*b9c1b51eSKate Stone      "RS Program Fragment"},
669*b9c1b51eSKate Stone     {"RS Program Vertex", "RS Program Vertex", "RS Program Vertex",
670*b9c1b51eSKate Stone      "RS Program Vertex"},
671*b9c1b51eSKate Stone     {"RS Program Raster", "RS Program Raster", "RS Program Raster",
672*b9c1b51eSKate Stone      "RS Program Raster"},
673*b9c1b51eSKate Stone     {"RS Program Store", "RS Program Store", "RS Program Store",
674*b9c1b51eSKate Stone      "RS Program Store"},
675b3f7f69dSAidan Dodds     {"RS Font", "RS Font", "RS Font", "RS Font"}};
67678f339d1SEwan Crawford 
677a0f08674SEwan Crawford // Used as an index into the RSTypeToFormat array elements
678*b9c1b51eSKate Stone enum TypeToFormatIndex { eFormatSingle = 0, eFormatVector, eElementSize };
679a0f08674SEwan Crawford 
680*b9c1b51eSKate Stone // { format enum of single element, format enum of element vector, size of
681*b9c1b51eSKate Stone // element}
682b3f7f69dSAidan Dodds const uint32_t RenderScriptRuntime::AllocationDetails::RSTypeToFormat[][3] = {
683a0f08674SEwan Crawford     {eFormatHex, eFormatHex, 1},                            // RS_TYPE_NONE
684a0f08674SEwan Crawford     {eFormatFloat, eFormatVectorOfFloat16, 2},              // RS_TYPE_FLOAT_16
685a0f08674SEwan Crawford     {eFormatFloat, eFormatVectorOfFloat32, sizeof(float)},  // RS_TYPE_FLOAT_32
686a0f08674SEwan Crawford     {eFormatFloat, eFormatVectorOfFloat64, sizeof(double)}, // RS_TYPE_FLOAT_64
687a0f08674SEwan Crawford     {eFormatDecimal, eFormatVectorOfSInt8, sizeof(int8_t)}, // RS_TYPE_SIGNED_8
688*b9c1b51eSKate Stone     {eFormatDecimal, eFormatVectorOfSInt16,
689*b9c1b51eSKate Stone      sizeof(int16_t)}, // RS_TYPE_SIGNED_16
690*b9c1b51eSKate Stone     {eFormatDecimal, eFormatVectorOfSInt32,
691*b9c1b51eSKate Stone      sizeof(int32_t)}, // RS_TYPE_SIGNED_32
692*b9c1b51eSKate Stone     {eFormatDecimal, eFormatVectorOfSInt64,
693*b9c1b51eSKate Stone      sizeof(int64_t)}, // RS_TYPE_SIGNED_64
694*b9c1b51eSKate Stone     {eFormatDecimal, eFormatVectorOfUInt8,
695*b9c1b51eSKate Stone      sizeof(uint8_t)}, // RS_TYPE_UNSIGNED_8
696*b9c1b51eSKate Stone     {eFormatDecimal, eFormatVectorOfUInt16,
697*b9c1b51eSKate Stone      sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_16
698*b9c1b51eSKate Stone     {eFormatDecimal, eFormatVectorOfUInt32,
699*b9c1b51eSKate Stone      sizeof(uint32_t)}, // RS_TYPE_UNSIGNED_32
700*b9c1b51eSKate Stone     {eFormatDecimal, eFormatVectorOfUInt64,
701*b9c1b51eSKate Stone      sizeof(uint64_t)},                         // RS_TYPE_UNSIGNED_64
7022e920715SEwan Crawford     {eFormatBoolean, eFormatBoolean, 1},        // RS_TYPE_BOOL
7032e920715SEwan Crawford     {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_6_5
7042e920715SEwan Crawford     {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_5_5_1
7052e920715SEwan Crawford     {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_4_4_4_4
706*b9c1b51eSKate Stone     {eFormatVectorOfFloat32, eFormatVectorOfFloat32,
707*b9c1b51eSKate Stone      sizeof(float) * 16}, // RS_TYPE_MATRIX_4X4
708*b9c1b51eSKate Stone     {eFormatVectorOfFloat32, eFormatVectorOfFloat32,
709*b9c1b51eSKate Stone      sizeof(float) * 9}, // RS_TYPE_MATRIX_3X3
710*b9c1b51eSKate Stone     {eFormatVectorOfFloat32, eFormatVectorOfFloat32,
711*b9c1b51eSKate Stone      sizeof(float) * 4} // RS_TYPE_MATRIX_2X2
712a0f08674SEwan Crawford };
713a0f08674SEwan Crawford 
7145ec532a9SColin Riley //------------------------------------------------------------------
7155ec532a9SColin Riley // Static Functions
7165ec532a9SColin Riley //------------------------------------------------------------------
7175ec532a9SColin Riley LanguageRuntime *
718*b9c1b51eSKate Stone RenderScriptRuntime::CreateInstance(Process *process,
719*b9c1b51eSKate Stone                                     lldb::LanguageType language) {
7205ec532a9SColin Riley 
7215ec532a9SColin Riley   if (language == eLanguageTypeExtRenderScript)
7225ec532a9SColin Riley     return new RenderScriptRuntime(process);
7235ec532a9SColin Riley   else
724b3f7f69dSAidan Dodds     return nullptr;
7255ec532a9SColin Riley }
7265ec532a9SColin Riley 
72798156583SEwan Crawford // Callback with a module to search for matching symbols.
72898156583SEwan Crawford // We first check that the module contains RS kernels.
72998156583SEwan Crawford // Then look for a symbol which matches our kernel name.
73098156583SEwan Crawford // The breakpoint address is finally set using the address of this symbol.
73198156583SEwan Crawford Searcher::CallbackReturn
732*b9c1b51eSKate Stone RSBreakpointResolver::SearchCallback(SearchFilter &filter,
733*b9c1b51eSKate Stone                                      SymbolContext &context, Address *, bool) {
73498156583SEwan Crawford   ModuleSP module = context.module_sp;
73598156583SEwan Crawford 
73698156583SEwan Crawford   if (!module)
73798156583SEwan Crawford     return Searcher::eCallbackReturnContinue;
73898156583SEwan Crawford 
73998156583SEwan Crawford   // Is this a module containing renderscript kernels?
740*b9c1b51eSKate Stone   if (nullptr ==
741*b9c1b51eSKate Stone       module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"),
742*b9c1b51eSKate Stone                                              eSymbolTypeData))
74398156583SEwan Crawford     return Searcher::eCallbackReturnContinue;
74498156583SEwan Crawford 
745*b9c1b51eSKate Stone   // Attempt to set a breakpoint on the kernel name symbol within the module
746*b9c1b51eSKate Stone   // library.
74798156583SEwan Crawford   // If it's not found, it's likely debug info is unavailable - try to set a
74898156583SEwan Crawford   // breakpoint on <name>.expand.
74998156583SEwan Crawford 
750*b9c1b51eSKate Stone   const Symbol *kernel_sym =
751*b9c1b51eSKate Stone       module->FindFirstSymbolWithNameAndType(m_kernel_name, eSymbolTypeCode);
752*b9c1b51eSKate Stone   if (!kernel_sym) {
75398156583SEwan Crawford     std::string kernel_name_expanded(m_kernel_name.AsCString());
75498156583SEwan Crawford     kernel_name_expanded.append(".expand");
755*b9c1b51eSKate Stone     kernel_sym = module->FindFirstSymbolWithNameAndType(
756*b9c1b51eSKate Stone         ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode);
75798156583SEwan Crawford   }
75898156583SEwan Crawford 
759*b9c1b51eSKate Stone   if (kernel_sym) {
76098156583SEwan Crawford     Address bp_addr = kernel_sym->GetAddress();
76198156583SEwan Crawford     if (filter.AddressPasses(bp_addr))
76298156583SEwan Crawford       m_breakpoint->AddLocation(bp_addr);
76398156583SEwan Crawford   }
76498156583SEwan Crawford 
76598156583SEwan Crawford   return Searcher::eCallbackReturnContinue;
76698156583SEwan Crawford }
76798156583SEwan Crawford 
768*b9c1b51eSKate Stone void RenderScriptRuntime::Initialize() {
769*b9c1b51eSKate Stone   PluginManager::RegisterPlugin(GetPluginNameStatic(),
770*b9c1b51eSKate Stone                                 "RenderScript language support", CreateInstance,
771b3f7f69dSAidan Dodds                                 GetCommandObject);
7725ec532a9SColin Riley }
7735ec532a9SColin Riley 
774*b9c1b51eSKate Stone void RenderScriptRuntime::Terminate() {
7755ec532a9SColin Riley   PluginManager::UnregisterPlugin(CreateInstance);
7765ec532a9SColin Riley }
7775ec532a9SColin Riley 
778*b9c1b51eSKate Stone lldb_private::ConstString RenderScriptRuntime::GetPluginNameStatic() {
7795ec532a9SColin Riley   static ConstString g_name("renderscript");
7805ec532a9SColin Riley   return g_name;
7815ec532a9SColin Riley }
7825ec532a9SColin Riley 
783ef20b08fSColin Riley RenderScriptRuntime::ModuleKind
784*b9c1b51eSKate Stone RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp) {
785*b9c1b51eSKate Stone   if (module_sp) {
786ef20b08fSColin Riley     // Is this a module containing renderscript kernels?
787*b9c1b51eSKate Stone     const Symbol *info_sym = module_sp->FindFirstSymbolWithNameAndType(
788*b9c1b51eSKate Stone         ConstString(".rs.info"), eSymbolTypeData);
789*b9c1b51eSKate Stone     if (info_sym) {
790ef20b08fSColin Riley       return eModuleKindKernelObj;
791ef20b08fSColin Riley     }
7924640cde1SColin Riley 
7934640cde1SColin Riley     // Is this the main RS runtime library
7944640cde1SColin Riley     const ConstString rs_lib("libRS.so");
795*b9c1b51eSKate Stone     if (module_sp->GetFileSpec().GetFilename() == rs_lib) {
7964640cde1SColin Riley       return eModuleKindLibRS;
7974640cde1SColin Riley     }
7984640cde1SColin Riley 
7994640cde1SColin Riley     const ConstString rs_driverlib("libRSDriver.so");
800*b9c1b51eSKate Stone     if (module_sp->GetFileSpec().GetFilename() == rs_driverlib) {
8014640cde1SColin Riley       return eModuleKindDriver;
8024640cde1SColin Riley     }
8034640cde1SColin Riley 
80415f2bd95SEwan Crawford     const ConstString rs_cpureflib("libRSCpuRef.so");
805*b9c1b51eSKate Stone     if (module_sp->GetFileSpec().GetFilename() == rs_cpureflib) {
8064640cde1SColin Riley       return eModuleKindImpl;
8074640cde1SColin Riley     }
808ef20b08fSColin Riley   }
809ef20b08fSColin Riley   return eModuleKindIgnored;
810ef20b08fSColin Riley }
811ef20b08fSColin Riley 
812*b9c1b51eSKate Stone bool RenderScriptRuntime::IsRenderScriptModule(
813*b9c1b51eSKate Stone     const lldb::ModuleSP &module_sp) {
814ef20b08fSColin Riley   return GetModuleKind(module_sp) != eModuleKindIgnored;
815ef20b08fSColin Riley }
816ef20b08fSColin Riley 
817*b9c1b51eSKate Stone void RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list) {
818bb19a13cSSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
819ef20b08fSColin Riley 
820ef20b08fSColin Riley   size_t num_modules = module_list.GetSize();
821*b9c1b51eSKate Stone   for (size_t i = 0; i < num_modules; i++) {
822ef20b08fSColin Riley     auto mod = module_list.GetModuleAtIndex(i);
823*b9c1b51eSKate Stone     if (IsRenderScriptModule(mod)) {
824ef20b08fSColin Riley       LoadModule(mod);
825ef20b08fSColin Riley     }
826ef20b08fSColin Riley   }
827ef20b08fSColin Riley }
828ef20b08fSColin Riley 
8295ec532a9SColin Riley //------------------------------------------------------------------
8305ec532a9SColin Riley // PluginInterface protocol
8315ec532a9SColin Riley //------------------------------------------------------------------
832*b9c1b51eSKate Stone lldb_private::ConstString RenderScriptRuntime::GetPluginName() {
8335ec532a9SColin Riley   return GetPluginNameStatic();
8345ec532a9SColin Riley }
8355ec532a9SColin Riley 
836*b9c1b51eSKate Stone uint32_t RenderScriptRuntime::GetPluginVersion() { return 1; }
8375ec532a9SColin Riley 
838*b9c1b51eSKate Stone bool RenderScriptRuntime::IsVTableName(const char *name) { return false; }
8395ec532a9SColin Riley 
840*b9c1b51eSKate Stone bool RenderScriptRuntime::GetDynamicTypeAndAddress(
841*b9c1b51eSKate Stone     ValueObject &in_value, lldb::DynamicValueType use_dynamic,
8425f57b6eeSEnrico Granata     TypeAndOrName &class_type_or_name, Address &address,
843*b9c1b51eSKate Stone     Value::ValueType &value_type) {
8445ec532a9SColin Riley   return false;
8455ec532a9SColin Riley }
8465ec532a9SColin Riley 
847c74275bcSEnrico Granata TypeAndOrName
848*b9c1b51eSKate Stone RenderScriptRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
849*b9c1b51eSKate Stone                                       ValueObject &static_value) {
850c74275bcSEnrico Granata   return type_and_or_name;
851c74275bcSEnrico Granata }
852c74275bcSEnrico Granata 
853*b9c1b51eSKate Stone bool RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
8545ec532a9SColin Riley   return false;
8555ec532a9SColin Riley }
8565ec532a9SColin Riley 
8575ec532a9SColin Riley lldb::BreakpointResolverSP
858*b9c1b51eSKate Stone RenderScriptRuntime::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp,
859*b9c1b51eSKate Stone                                              bool throw_bp) {
8605ec532a9SColin Riley   BreakpointResolverSP resolver_sp;
8615ec532a9SColin Riley   return resolver_sp;
8625ec532a9SColin Riley }
8635ec532a9SColin Riley 
864*b9c1b51eSKate Stone const RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] =
865*b9c1b51eSKate Stone     {
8664640cde1SColin Riley         // rsdScript
867*b9c1b51eSKate Stone         {"rsdScriptInit", "_Z13rsdScriptInitPKN7android12renderscript7ContextEP"
868*b9c1b51eSKate Stone                           "NS0_7ScriptCEPKcS7_PKhjj",
869*b9c1b51eSKate Stone          "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_"
870*b9c1b51eSKate Stone          "7ScriptCEPKcS7_PKhmj",
871*b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
872*b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureScriptInit},
873*b9c1b51eSKate Stone         {"rsdScriptInvokeForEachMulti",
874*b9c1b51eSKate Stone          "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0"
875*b9c1b51eSKate Stone          "_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall",
876*b9c1b51eSKate Stone          "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0"
877*b9c1b51eSKate Stone          "_6ScriptEjPPKNS0_10AllocationEmPS6_PKvmPK12RsScriptCall",
878*b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
879*b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureScriptInvokeForEachMulti},
880*b9c1b51eSKate Stone         {"rsdScriptSetGlobalVar", "_Z21rsdScriptSetGlobalVarPKN7android12render"
881*b9c1b51eSKate Stone                                   "script7ContextEPKNS0_6ScriptEjPvj",
882*b9c1b51eSKate Stone          "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_"
883*b9c1b51eSKate Stone          "6ScriptEjPvm",
884*b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
885*b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar},
8864640cde1SColin Riley 
8874640cde1SColin Riley         // rsdAllocation
888*b9c1b51eSKate Stone         {"rsdAllocationInit", "_Z17rsdAllocationInitPKN7android12renderscript7C"
889*b9c1b51eSKate Stone                               "ontextEPNS0_10AllocationEb",
890*b9c1b51eSKate Stone          "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_"
891*b9c1b51eSKate Stone          "10AllocationEb",
892*b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
893*b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureAllocationInit},
894*b9c1b51eSKate Stone         {"rsdAllocationRead2D",
895*b9c1b51eSKate Stone          "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_"
896*b9c1b51eSKate Stone          "10AllocationEjjj23RsAllocationCubemapFacejjPvjj",
897*b9c1b51eSKate Stone          "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_"
898*b9c1b51eSKate Stone          "10AllocationEjjj23RsAllocationCubemapFacejjPvmm",
899*b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver, nullptr},
900*b9c1b51eSKate Stone         {"rsdAllocationDestroy", "_Z20rsdAllocationDestroyPKN7android12rendersc"
901*b9c1b51eSKate Stone                                  "ript7ContextEPNS0_10AllocationE",
902*b9c1b51eSKate Stone          "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_"
903*b9c1b51eSKate Stone          "10AllocationE",
904*b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
905*b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy},
9064640cde1SColin Riley };
9074640cde1SColin Riley 
908*b9c1b51eSKate Stone const size_t RenderScriptRuntime::s_runtimeHookCount =
909*b9c1b51eSKate Stone     sizeof(s_runtimeHookDefns) / sizeof(s_runtimeHookDefns[0]);
9104640cde1SColin Riley 
911*b9c1b51eSKate Stone bool RenderScriptRuntime::HookCallback(void *baton,
912*b9c1b51eSKate Stone                                        StoppointCallbackContext *ctx,
913*b9c1b51eSKate Stone                                        lldb::user_id_t break_id,
914*b9c1b51eSKate Stone                                        lldb::user_id_t break_loc_id) {
9154640cde1SColin Riley   RuntimeHook *hook_info = (RuntimeHook *)baton;
9164640cde1SColin Riley   ExecutionContext context(ctx->exe_ctx_ref);
9174640cde1SColin Riley 
918b3f7f69dSAidan Dodds   RenderScriptRuntime *lang_rt =
919*b9c1b51eSKate Stone       (RenderScriptRuntime *)context.GetProcessPtr()->GetLanguageRuntime(
920*b9c1b51eSKate Stone           eLanguageTypeExtRenderScript);
9214640cde1SColin Riley 
9224640cde1SColin Riley   lang_rt->HookCallback(hook_info, context);
9234640cde1SColin Riley 
9244640cde1SColin Riley   return false;
9254640cde1SColin Riley }
9264640cde1SColin Riley 
927*b9c1b51eSKate Stone void RenderScriptRuntime::HookCallback(RuntimeHook *hook_info,
928*b9c1b51eSKate Stone                                        ExecutionContext &context) {
9294640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
9304640cde1SColin Riley 
9314640cde1SColin Riley   if (log)
932b3f7f69dSAidan Dodds     log->Printf("%s - '%s'", __FUNCTION__, hook_info->defn->name);
9334640cde1SColin Riley 
934*b9c1b51eSKate Stone   if (hook_info->defn->grabber) {
9354640cde1SColin Riley     (this->*(hook_info->defn->grabber))(hook_info, context);
9364640cde1SColin Riley   }
9374640cde1SColin Riley }
9384640cde1SColin Riley 
939*b9c1b51eSKate Stone void RenderScriptRuntime::CaptureScriptInvokeForEachMulti(
940*b9c1b51eSKate Stone     RuntimeHook *hook_info, ExecutionContext &context) {
941e09c44b6SAidan Dodds   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
942e09c44b6SAidan Dodds 
943*b9c1b51eSKate Stone   enum {
944f4786785SAidan Dodds     eRsContext = 0,
945f4786785SAidan Dodds     eRsScript,
946f4786785SAidan Dodds     eRsSlot,
947f4786785SAidan Dodds     eRsAIns,
948f4786785SAidan Dodds     eRsInLen,
949f4786785SAidan Dodds     eRsAOut,
950f4786785SAidan Dodds     eRsUsr,
951f4786785SAidan Dodds     eRsUsrLen,
952f4786785SAidan Dodds     eRsSc,
953f4786785SAidan Dodds   };
954e09c44b6SAidan Dodds 
9551ee07253SSaleem Abdulrasool   std::array<ArgItem, 9> args{{
956f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // const Context       *rsc
957f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // Script              *s
958f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // uint32_t             slot
959f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // const Allocation   **aIns
960f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // size_t               inLen
961f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // Allocation          *aout
962f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // const void          *usr
963f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // size_t               usrLen
964f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // const RsScriptCall  *sc
9651ee07253SSaleem Abdulrasool   }};
966e09c44b6SAidan Dodds 
967f4786785SAidan Dodds   bool success = GetArgs(context, &args[0], args.size());
968*b9c1b51eSKate Stone   if (!success) {
969e09c44b6SAidan Dodds     if (log)
970*b9c1b51eSKate Stone       log->Printf("%s - Error while reading the function parameters",
971*b9c1b51eSKate Stone                   __FUNCTION__);
972e09c44b6SAidan Dodds     return;
973e09c44b6SAidan Dodds   }
974e09c44b6SAidan Dodds 
975e09c44b6SAidan Dodds   const uint32_t target_ptr_size = m_process->GetAddressByteSize();
976e09c44b6SAidan Dodds   Error error;
977e09c44b6SAidan Dodds   std::vector<uint64_t> allocs;
978e09c44b6SAidan Dodds 
979e09c44b6SAidan Dodds   // traverse allocation list
980*b9c1b51eSKate Stone   for (uint64_t i = 0; i < uint64_t(args[eRsInLen]); ++i) {
981e09c44b6SAidan Dodds     // calculate offest to allocation pointer
982f4786785SAidan Dodds     const addr_t addr = addr_t(args[eRsAIns]) + i * target_ptr_size;
983e09c44b6SAidan Dodds 
984*b9c1b51eSKate Stone     // Note: due to little endian layout, reading 32bits or 64bits into res64
985*b9c1b51eSKate Stone     // will
986e09c44b6SAidan Dodds     //       give the correct results.
987e09c44b6SAidan Dodds 
988e09c44b6SAidan Dodds     uint64_t res64 = 0;
989e09c44b6SAidan Dodds     size_t read = m_process->ReadMemory(addr, &res64, target_ptr_size, error);
990*b9c1b51eSKate Stone     if (read != target_ptr_size || !error.Success()) {
991e09c44b6SAidan Dodds       if (log)
992*b9c1b51eSKate Stone         log->Printf(
993*b9c1b51eSKate Stone             "%s - Error while reading allocation list argument %" PRIu64,
994*b9c1b51eSKate Stone             __FUNCTION__, i);
995*b9c1b51eSKate Stone     } else {
996e09c44b6SAidan Dodds       allocs.push_back(res64);
997e09c44b6SAidan Dodds     }
998e09c44b6SAidan Dodds   }
999e09c44b6SAidan Dodds 
1000e09c44b6SAidan Dodds   // if there is an output allocation track it
1001*b9c1b51eSKate Stone   if (uint64_t aOut = uint64_t(args[eRsAOut])) {
1002f4786785SAidan Dodds     allocs.push_back(aOut);
1003e09c44b6SAidan Dodds   }
1004e09c44b6SAidan Dodds 
1005e09c44b6SAidan Dodds   // for all allocations we have found
1006*b9c1b51eSKate Stone   for (const uint64_t alloc_addr : allocs) {
10075d057637SLuke Drummond     AllocationDetails *alloc = LookUpAllocation(alloc_addr);
10085d057637SLuke Drummond     if (!alloc)
10095d057637SLuke Drummond       alloc = CreateAllocation(alloc_addr);
10105d057637SLuke Drummond 
1011*b9c1b51eSKate Stone     if (alloc) {
1012e09c44b6SAidan Dodds       // save the allocation address
1013*b9c1b51eSKate Stone       if (alloc->address.isValid()) {
1014e09c44b6SAidan Dodds         // check the allocation address we already have matches
1015e09c44b6SAidan Dodds         assert(*alloc->address.get() == alloc_addr);
1016*b9c1b51eSKate Stone       } else {
1017e09c44b6SAidan Dodds         alloc->address = alloc_addr;
1018e09c44b6SAidan Dodds       }
1019e09c44b6SAidan Dodds 
1020e09c44b6SAidan Dodds       // save the context
1021*b9c1b51eSKate Stone       if (log) {
1022*b9c1b51eSKate Stone         if (alloc->context.isValid() &&
1023*b9c1b51eSKate Stone             *alloc->context.get() != addr_t(args[eRsContext]))
1024*b9c1b51eSKate Stone           log->Printf("%s - Allocation used by multiple contexts",
1025*b9c1b51eSKate Stone                       __FUNCTION__);
1026e09c44b6SAidan Dodds       }
1027f4786785SAidan Dodds       alloc->context = addr_t(args[eRsContext]);
1028e09c44b6SAidan Dodds     }
1029e09c44b6SAidan Dodds   }
1030e09c44b6SAidan Dodds 
1031e09c44b6SAidan Dodds   // make sure we track this script object
1032*b9c1b51eSKate Stone   if (lldb_private::RenderScriptRuntime::ScriptDetails *script =
1033*b9c1b51eSKate Stone           LookUpScript(addr_t(args[eRsScript]), true)) {
1034*b9c1b51eSKate Stone     if (log) {
1035*b9c1b51eSKate Stone       if (script->context.isValid() &&
1036*b9c1b51eSKate Stone           *script->context.get() != addr_t(args[eRsContext]))
1037b3f7f69dSAidan Dodds         log->Printf("%s - Script used by multiple contexts", __FUNCTION__);
1038e09c44b6SAidan Dodds     }
1039f4786785SAidan Dodds     script->context = addr_t(args[eRsContext]);
1040e09c44b6SAidan Dodds   }
1041e09c44b6SAidan Dodds }
1042e09c44b6SAidan Dodds 
1043*b9c1b51eSKate Stone void RenderScriptRuntime::CaptureSetGlobalVar(RuntimeHook *hook_info,
1044*b9c1b51eSKate Stone                                               ExecutionContext &context) {
10454640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
10464640cde1SColin Riley 
1047*b9c1b51eSKate Stone   enum {
1048f4786785SAidan Dodds     eRsContext,
1049f4786785SAidan Dodds     eRsScript,
1050f4786785SAidan Dodds     eRsId,
1051f4786785SAidan Dodds     eRsData,
1052f4786785SAidan Dodds     eRsLength,
1053f4786785SAidan Dodds   };
10544640cde1SColin Riley 
10551ee07253SSaleem Abdulrasool   std::array<ArgItem, 5> args{{
1056f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsContext
1057f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsScript
1058f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // eRsId
1059f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsData
1060f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // eRsLength
10611ee07253SSaleem Abdulrasool   }};
10624640cde1SColin Riley 
1063f4786785SAidan Dodds   bool success = GetArgs(context, &args[0], args.size());
1064*b9c1b51eSKate Stone   if (!success) {
106582780287SAidan Dodds     if (log)
1066b3f7f69dSAidan Dodds       log->Printf("%s - error reading the function parameters.", __FUNCTION__);
106782780287SAidan Dodds     return;
106882780287SAidan Dodds   }
10694640cde1SColin Riley 
1070*b9c1b51eSKate Stone   if (log) {
1071*b9c1b51eSKate Stone     log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64
1072*b9c1b51eSKate Stone                 ":%" PRIu64 "bytes.",
1073*b9c1b51eSKate Stone                 __FUNCTION__, uint64_t(args[eRsContext]),
1074*b9c1b51eSKate Stone                 uint64_t(args[eRsScript]), uint64_t(args[eRsId]),
1075f4786785SAidan Dodds                 uint64_t(args[eRsData]), uint64_t(args[eRsLength]));
10764640cde1SColin Riley 
1077f4786785SAidan Dodds     addr_t script_addr = addr_t(args[eRsScript]);
1078*b9c1b51eSKate Stone     if (m_scriptMappings.find(script_addr) != m_scriptMappings.end()) {
10794640cde1SColin Riley       auto rsm = m_scriptMappings[script_addr];
1080*b9c1b51eSKate Stone       if (uint64_t(args[eRsId]) < rsm->m_globals.size()) {
1081f4786785SAidan Dodds         auto rsg = rsm->m_globals[uint64_t(args[eRsId])];
1082*b9c1b51eSKate Stone         log->Printf("%s - Setting of '%s' within '%s' inferred", __FUNCTION__,
1083*b9c1b51eSKate Stone                     rsg.m_name.AsCString(),
1084f4786785SAidan Dodds                     rsm->m_module->GetFileSpec().GetFilename().AsCString());
10854640cde1SColin Riley       }
10864640cde1SColin Riley     }
10874640cde1SColin Riley   }
10884640cde1SColin Riley }
10894640cde1SColin Riley 
1090*b9c1b51eSKate Stone void RenderScriptRuntime::CaptureAllocationInit(RuntimeHook *hook_info,
1091*b9c1b51eSKate Stone                                                 ExecutionContext &context) {
10924640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
10934640cde1SColin Riley 
1094*b9c1b51eSKate Stone   enum { eRsContext, eRsAlloc, eRsForceZero };
10954640cde1SColin Riley 
10961ee07253SSaleem Abdulrasool   std::array<ArgItem, 3> args{{
1097f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsContext
1098f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsAlloc
1099f4786785SAidan Dodds       ArgItem{ArgItem::eBool, 0},    // eRsForceZero
11001ee07253SSaleem Abdulrasool   }};
11014640cde1SColin Riley 
1102f4786785SAidan Dodds   bool success = GetArgs(context, &args[0], args.size());
110382780287SAidan Dodds   if (!success) // error case
110482780287SAidan Dodds   {
110582780287SAidan Dodds     if (log)
1106*b9c1b51eSKate Stone       log->Printf("%s - error while reading the function parameters",
1107*b9c1b51eSKate Stone                   __FUNCTION__);
110882780287SAidan Dodds     return; // abort
110982780287SAidan Dodds   }
11104640cde1SColin Riley 
11114640cde1SColin Riley   if (log)
1112*b9c1b51eSKate Stone     log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .",
1113*b9c1b51eSKate Stone                 __FUNCTION__, uint64_t(args[eRsContext]),
1114f4786785SAidan Dodds                 uint64_t(args[eRsAlloc]), uint64_t(args[eRsForceZero]));
111578f339d1SEwan Crawford 
11165d057637SLuke Drummond   AllocationDetails *alloc = CreateAllocation(uint64_t(args[eRsAlloc]));
111778f339d1SEwan Crawford   if (alloc)
1118f4786785SAidan Dodds     alloc->context = uint64_t(args[eRsContext]);
11194640cde1SColin Riley }
11204640cde1SColin Riley 
1121*b9c1b51eSKate Stone void RenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook *hook_info,
1122*b9c1b51eSKate Stone                                                    ExecutionContext &context) {
1123e69df382SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1124e69df382SEwan Crawford 
1125*b9c1b51eSKate Stone   enum {
1126f4786785SAidan Dodds     eRsContext,
1127f4786785SAidan Dodds     eRsAlloc,
1128f4786785SAidan Dodds   };
1129e69df382SEwan Crawford 
11301ee07253SSaleem Abdulrasool   std::array<ArgItem, 2> args{{
1131f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsContext
1132f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsAlloc
11331ee07253SSaleem Abdulrasool   }};
1134f4786785SAidan Dodds 
1135f4786785SAidan Dodds   bool success = GetArgs(context, &args[0], args.size());
1136*b9c1b51eSKate Stone   if (!success) {
1137e69df382SEwan Crawford     if (log)
1138*b9c1b51eSKate Stone       log->Printf("%s - error while reading the function parameters.",
1139*b9c1b51eSKate Stone                   __FUNCTION__);
1140b3f7f69dSAidan Dodds     return;
1141e69df382SEwan Crawford   }
1142e69df382SEwan Crawford 
1143e69df382SEwan Crawford   if (log)
1144*b9c1b51eSKate Stone     log->Printf("%s - 0x%" PRIx64 ", 0x%" PRIx64 ".", __FUNCTION__,
1145*b9c1b51eSKate Stone                 uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc]));
1146e69df382SEwan Crawford 
1147*b9c1b51eSKate Stone   for (auto iter = m_allocations.begin(); iter != m_allocations.end(); ++iter) {
1148e69df382SEwan Crawford     auto &allocation_ap = *iter; // get the unique pointer
1149*b9c1b51eSKate Stone     if (allocation_ap->address.isValid() &&
1150*b9c1b51eSKate Stone         *allocation_ap->address.get() == addr_t(args[eRsAlloc])) {
1151e69df382SEwan Crawford       m_allocations.erase(iter);
1152e69df382SEwan Crawford       if (log)
1153b3f7f69dSAidan Dodds         log->Printf("%s - deleted allocation entry.", __FUNCTION__);
1154e69df382SEwan Crawford       return;
1155e69df382SEwan Crawford     }
1156e69df382SEwan Crawford   }
1157e69df382SEwan Crawford 
1158e69df382SEwan Crawford   if (log)
1159b3f7f69dSAidan Dodds     log->Printf("%s - couldn't find destroyed allocation.", __FUNCTION__);
1160e69df382SEwan Crawford }
1161e69df382SEwan Crawford 
1162*b9c1b51eSKate Stone void RenderScriptRuntime::CaptureScriptInit(RuntimeHook *hook_info,
1163*b9c1b51eSKate Stone                                             ExecutionContext &context) {
11644640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
11654640cde1SColin Riley 
11664640cde1SColin Riley   Error error;
11674640cde1SColin Riley   Process *process = context.GetProcessPtr();
11684640cde1SColin Riley 
1169*b9c1b51eSKate Stone   enum { eRsContext, eRsScript, eRsResNamePtr, eRsCachedDirPtr };
11704640cde1SColin Riley 
1171*b9c1b51eSKate Stone   std::array<ArgItem, 4> args{
1172*b9c1b51eSKate Stone       {ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0},
11731ee07253SSaleem Abdulrasool        ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}}};
1174f4786785SAidan Dodds   bool success = GetArgs(context, &args[0], args.size());
1175*b9c1b51eSKate Stone   if (!success) {
117682780287SAidan Dodds     if (log)
1177*b9c1b51eSKate Stone       log->Printf("%s - error while reading the function parameters.",
1178*b9c1b51eSKate Stone                   __FUNCTION__);
117982780287SAidan Dodds     return;
118082780287SAidan Dodds   }
118182780287SAidan Dodds 
1182f4786785SAidan Dodds   std::string resname;
1183f4786785SAidan Dodds   process->ReadCStringFromMemory(addr_t(args[eRsResNamePtr]), resname, error);
1184*b9c1b51eSKate Stone   if (error.Fail()) {
11854640cde1SColin Riley     if (log)
1186*b9c1b51eSKate Stone       log->Printf("%s - error reading resname: %s.", __FUNCTION__,
1187*b9c1b51eSKate Stone                   error.AsCString());
11884640cde1SColin Riley   }
11894640cde1SColin Riley 
1190f4786785SAidan Dodds   std::string cachedir;
1191*b9c1b51eSKate Stone   process->ReadCStringFromMemory(addr_t(args[eRsCachedDirPtr]), cachedir,
1192*b9c1b51eSKate Stone                                  error);
1193*b9c1b51eSKate Stone   if (error.Fail()) {
11944640cde1SColin Riley     if (log)
1195*b9c1b51eSKate Stone       log->Printf("%s - error reading cachedir: %s.", __FUNCTION__,
1196*b9c1b51eSKate Stone                   error.AsCString());
11974640cde1SColin Riley   }
11984640cde1SColin Riley 
11994640cde1SColin Riley   if (log)
1200*b9c1b51eSKate Stone     log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .",
1201*b9c1b51eSKate Stone                 __FUNCTION__, uint64_t(args[eRsContext]),
1202f4786785SAidan Dodds                 uint64_t(args[eRsScript]), resname.c_str(), cachedir.c_str());
12034640cde1SColin Riley 
1204*b9c1b51eSKate Stone   if (resname.size() > 0) {
12054640cde1SColin Riley     StreamString strm;
12064640cde1SColin Riley     strm.Printf("librs.%s.so", resname.c_str());
12074640cde1SColin Riley 
1208f4786785SAidan Dodds     ScriptDetails *script = LookUpScript(addr_t(args[eRsScript]), true);
1209*b9c1b51eSKate Stone     if (script) {
121078f339d1SEwan Crawford       script->type = ScriptDetails::eScriptC;
121178f339d1SEwan Crawford       script->cacheDir = cachedir;
121278f339d1SEwan Crawford       script->resName = resname;
121378f339d1SEwan Crawford       script->scriptDyLib = strm.GetData();
1214f4786785SAidan Dodds       script->context = addr_t(args[eRsContext]);
121578f339d1SEwan Crawford     }
12164640cde1SColin Riley 
12174640cde1SColin Riley     if (log)
1218*b9c1b51eSKate Stone       log->Printf("%s - '%s' tagged with context 0x%" PRIx64
1219*b9c1b51eSKate Stone                   " and script 0x%" PRIx64 ".",
1220*b9c1b51eSKate Stone                   __FUNCTION__, strm.GetData(), uint64_t(args[eRsContext]),
1221*b9c1b51eSKate Stone                   uint64_t(args[eRsScript]));
1222*b9c1b51eSKate Stone   } else if (log) {
1223b3f7f69dSAidan Dodds     log->Printf("%s - resource name invalid, Script not tagged.", __FUNCTION__);
12244640cde1SColin Riley   }
12254640cde1SColin Riley }
12264640cde1SColin Riley 
1227*b9c1b51eSKate Stone void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module,
1228*b9c1b51eSKate Stone                                            ModuleKind kind) {
12294640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
12304640cde1SColin Riley 
1231*b9c1b51eSKate Stone   if (!module) {
12324640cde1SColin Riley     return;
12334640cde1SColin Riley   }
12344640cde1SColin Riley 
123582780287SAidan Dodds   Target &target = GetProcess()->GetTarget();
123682780287SAidan Dodds   llvm::Triple::ArchType targetArchType = target.GetArchitecture().GetMachine();
123782780287SAidan Dodds 
1238b3f7f69dSAidan Dodds   if (targetArchType != llvm::Triple::ArchType::x86 &&
1239b3f7f69dSAidan Dodds       targetArchType != llvm::Triple::ArchType::arm &&
1240b3f7f69dSAidan Dodds       targetArchType != llvm::Triple::ArchType::aarch64 &&
1241b3f7f69dSAidan Dodds       targetArchType != llvm::Triple::ArchType::mipsel &&
1242b3f7f69dSAidan Dodds       targetArchType != llvm::Triple::ArchType::mips64el &&
1243*b9c1b51eSKate Stone       targetArchType != llvm::Triple::ArchType::x86_64) {
12444640cde1SColin Riley     if (log)
1245b3f7f69dSAidan Dodds       log->Printf("%s - unable to hook runtime functions.", __FUNCTION__);
12464640cde1SColin Riley     return;
12474640cde1SColin Riley   }
12484640cde1SColin Riley 
124982780287SAidan Dodds   uint32_t archByteSize = target.GetArchitecture().GetAddressByteSize();
12504640cde1SColin Riley 
1251*b9c1b51eSKate Stone   for (size_t idx = 0; idx < s_runtimeHookCount; idx++) {
12524640cde1SColin Riley     const HookDefn *hook_defn = &s_runtimeHookDefns[idx];
1253*b9c1b51eSKate Stone     if (hook_defn->kind != kind) {
12544640cde1SColin Riley       continue;
12554640cde1SColin Riley     }
12564640cde1SColin Riley 
1257*b9c1b51eSKate Stone     const char *symbol_name = (archByteSize == 4) ? hook_defn->symbol_name_m32
1258*b9c1b51eSKate Stone                                                   : hook_defn->symbol_name_m64;
125982780287SAidan Dodds 
1260*b9c1b51eSKate Stone     const Symbol *sym = module->FindFirstSymbolWithNameAndType(
1261*b9c1b51eSKate Stone         ConstString(symbol_name), eSymbolTypeCode);
1262*b9c1b51eSKate Stone     if (!sym) {
1263*b9c1b51eSKate Stone       if (log) {
1264b3f7f69dSAidan Dodds         log->Printf("%s - symbol '%s' related to the function %s not found",
1265b3f7f69dSAidan Dodds                     __FUNCTION__, symbol_name, hook_defn->name);
126682780287SAidan Dodds       }
126782780287SAidan Dodds       continue;
126882780287SAidan Dodds     }
12694640cde1SColin Riley 
1270358cf1eaSGreg Clayton     addr_t addr = sym->GetLoadAddress(&target);
1271*b9c1b51eSKate Stone     if (addr == LLDB_INVALID_ADDRESS) {
12724640cde1SColin Riley       if (log)
1273*b9c1b51eSKate Stone         log->Printf("%s - unable to resolve the address of hook function '%s' "
1274*b9c1b51eSKate Stone                     "with symbol '%s'.",
1275b3f7f69dSAidan Dodds                     __FUNCTION__, hook_defn->name, symbol_name);
12764640cde1SColin Riley       continue;
1277*b9c1b51eSKate Stone     } else {
127882780287SAidan Dodds       if (log)
1279b3f7f69dSAidan Dodds         log->Printf("%s - function %s, address resolved at 0x%" PRIx64,
1280b3f7f69dSAidan Dodds                     __FUNCTION__, hook_defn->name, addr);
128182780287SAidan Dodds     }
12824640cde1SColin Riley 
12834640cde1SColin Riley     RuntimeHookSP hook(new RuntimeHook());
12844640cde1SColin Riley     hook->address = addr;
12854640cde1SColin Riley     hook->defn = hook_defn;
12864640cde1SColin Riley     hook->bp_sp = target.CreateBreakpoint(addr, true, false);
12874640cde1SColin Riley     hook->bp_sp->SetCallback(HookCallback, hook.get(), true);
12884640cde1SColin Riley     m_runtimeHooks[addr] = hook;
1289*b9c1b51eSKate Stone     if (log) {
1290*b9c1b51eSKate Stone       log->Printf("%s - successfully hooked '%s' in '%s' version %" PRIu64
1291*b9c1b51eSKate Stone                   " at 0x%" PRIx64 ".",
1292*b9c1b51eSKate Stone                   __FUNCTION__, hook_defn->name,
1293*b9c1b51eSKate Stone                   module->GetFileSpec().GetFilename().AsCString(),
1294b3f7f69dSAidan Dodds                   (uint64_t)hook_defn->version, (uint64_t)addr);
12954640cde1SColin Riley     }
12964640cde1SColin Riley   }
12974640cde1SColin Riley }
12984640cde1SColin Riley 
1299*b9c1b51eSKate Stone void RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp) {
13004640cde1SColin Riley   if (!rsmodule_sp)
13014640cde1SColin Riley     return;
13024640cde1SColin Riley 
13034640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
13044640cde1SColin Riley 
13054640cde1SColin Riley   const ModuleSP module = rsmodule_sp->m_module;
13064640cde1SColin Riley   const FileSpec &file = module->GetPlatformFileSpec();
13074640cde1SColin Riley 
130878f339d1SEwan Crawford   // Iterate over all of the scripts that we currently know of.
130978f339d1SEwan Crawford   // Note: We cant push or pop to m_scripts here or it may invalidate rs_script.
1310*b9c1b51eSKate Stone   for (const auto &rs_script : m_scripts) {
131178f339d1SEwan Crawford     // Extract the expected .so file path for this script.
131278f339d1SEwan Crawford     std::string dylib;
131378f339d1SEwan Crawford     if (!rs_script->scriptDyLib.get(dylib))
131478f339d1SEwan Crawford       continue;
131578f339d1SEwan Crawford 
131678f339d1SEwan Crawford     // Only proceed if the module that has loaded corresponds to this script.
131778f339d1SEwan Crawford     if (file.GetFilename() != ConstString(dylib.c_str()))
131878f339d1SEwan Crawford       continue;
131978f339d1SEwan Crawford 
132078f339d1SEwan Crawford     // Obtain the script address which we use as a key.
132178f339d1SEwan Crawford     lldb::addr_t script;
132278f339d1SEwan Crawford     if (!rs_script->script.get(script))
132378f339d1SEwan Crawford       continue;
132478f339d1SEwan Crawford 
132578f339d1SEwan Crawford     // If we have a script mapping for the current script.
1326*b9c1b51eSKate Stone     if (m_scriptMappings.find(script) != m_scriptMappings.end()) {
132778f339d1SEwan Crawford       // if the module we have stored is different to the one we just received.
1328*b9c1b51eSKate Stone       if (m_scriptMappings[script] != rsmodule_sp) {
13294640cde1SColin Riley         if (log)
1330*b9c1b51eSKate Stone           log->Printf(
1331*b9c1b51eSKate Stone               "%s - script %" PRIx64 " wants reassigned to new rsmodule '%s'.",
1332*b9c1b51eSKate Stone               __FUNCTION__, (uint64_t)script,
1333*b9c1b51eSKate Stone               rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
13344640cde1SColin Riley       }
13354640cde1SColin Riley     }
133678f339d1SEwan Crawford     // We don't have a script mapping for the current script.
1337*b9c1b51eSKate Stone     else {
133878f339d1SEwan Crawford       // Obtain the script resource name.
133978f339d1SEwan Crawford       std::string resName;
134078f339d1SEwan Crawford       if (rs_script->resName.get(resName))
134178f339d1SEwan Crawford         // Set the modules resource name.
134278f339d1SEwan Crawford         rsmodule_sp->m_resname = resName;
134378f339d1SEwan Crawford       // Add Script/Module pair to map.
134478f339d1SEwan Crawford       m_scriptMappings[script] = rsmodule_sp;
13454640cde1SColin Riley       if (log)
1346*b9c1b51eSKate Stone         log->Printf(
1347*b9c1b51eSKate Stone             "%s - script %" PRIx64 " associated with rsmodule '%s'.",
1348*b9c1b51eSKate Stone             __FUNCTION__, (uint64_t)script,
1349*b9c1b51eSKate Stone             rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
13504640cde1SColin Riley     }
13514640cde1SColin Riley   }
13524640cde1SColin Riley }
13534640cde1SColin Riley 
1354*b9c1b51eSKate Stone // Uses the Target API to evaluate the expression passed as a parameter to the
1355*b9c1b51eSKate Stone // function
1356*b9c1b51eSKate Stone // The result of that expression is returned an unsigned 64 bit int, via the
1357*b9c1b51eSKate Stone // result* parameter.
135815f2bd95SEwan Crawford // Function returns true on success, and false on failure
1359*b9c1b51eSKate Stone bool RenderScriptRuntime::EvalRSExpression(const char *expression,
1360*b9c1b51eSKate Stone                                            StackFrame *frame_ptr,
1361*b9c1b51eSKate Stone                                            uint64_t *result) {
136215f2bd95SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
136315f2bd95SEwan Crawford   if (log)
1364b3f7f69dSAidan Dodds     log->Printf("%s(%s)", __FUNCTION__, expression);
136515f2bd95SEwan Crawford 
136615f2bd95SEwan Crawford   ValueObjectSP expr_result;
13678433fdbeSAidan Dodds   EvaluateExpressionOptions options;
13688433fdbeSAidan Dodds   options.SetLanguage(lldb::eLanguageTypeC_plus_plus);
136915f2bd95SEwan Crawford   // Perform the actual expression evaluation
1370*b9c1b51eSKate Stone   GetProcess()->GetTarget().EvaluateExpression(expression, frame_ptr,
1371*b9c1b51eSKate Stone                                                expr_result, options);
137215f2bd95SEwan Crawford 
1373*b9c1b51eSKate Stone   if (!expr_result) {
137415f2bd95SEwan Crawford     if (log)
1375b3f7f69dSAidan Dodds       log->Printf("%s: couldn't evaluate expression.", __FUNCTION__);
137615f2bd95SEwan Crawford     return false;
137715f2bd95SEwan Crawford   }
137815f2bd95SEwan Crawford 
137915f2bd95SEwan Crawford   // The result of the expression is invalid
1380*b9c1b51eSKate Stone   if (!expr_result->GetError().Success()) {
138115f2bd95SEwan Crawford     Error err = expr_result->GetError();
1382*b9c1b51eSKate Stone     if (err.GetError() == UserExpression::kNoResult) // Expression returned
1383*b9c1b51eSKate Stone                                                      // void, so this is
1384*b9c1b51eSKate Stone                                                      // actually a success
138515f2bd95SEwan Crawford     {
138615f2bd95SEwan Crawford       if (log)
1387b3f7f69dSAidan Dodds         log->Printf("%s - expression returned void.", __FUNCTION__);
138815f2bd95SEwan Crawford 
138915f2bd95SEwan Crawford       result = nullptr;
139015f2bd95SEwan Crawford       return true;
139115f2bd95SEwan Crawford     }
139215f2bd95SEwan Crawford 
139315f2bd95SEwan Crawford     if (log)
1394b3f7f69dSAidan Dodds       log->Printf("%s - error evaluating expression result: %s", __FUNCTION__,
1395b3f7f69dSAidan Dodds                   err.AsCString());
139615f2bd95SEwan Crawford     return false;
139715f2bd95SEwan Crawford   }
139815f2bd95SEwan Crawford 
139915f2bd95SEwan Crawford   bool success = false;
1400*b9c1b51eSKate Stone   *result = expr_result->GetValueAsUnsigned(
1401*b9c1b51eSKate Stone       0, &success); // We only read the result as an uint32_t.
140215f2bd95SEwan Crawford 
1403*b9c1b51eSKate Stone   if (!success) {
140415f2bd95SEwan Crawford     if (log)
1405*b9c1b51eSKate Stone       log->Printf("%s - couldn't convert expression result to uint32_t",
1406*b9c1b51eSKate Stone                   __FUNCTION__);
140715f2bd95SEwan Crawford     return false;
140815f2bd95SEwan Crawford   }
140915f2bd95SEwan Crawford 
141015f2bd95SEwan Crawford   return true;
141115f2bd95SEwan Crawford }
141215f2bd95SEwan Crawford 
1413*b9c1b51eSKate Stone namespace {
1414836d9651SEwan Crawford // Used to index expression format strings
1415*b9c1b51eSKate Stone enum ExpressionStrings {
1416836d9651SEwan Crawford   eExprGetOffsetPtr = 0,
1417836d9651SEwan Crawford   eExprAllocGetType,
1418836d9651SEwan Crawford   eExprTypeDimX,
1419836d9651SEwan Crawford   eExprTypeDimY,
1420836d9651SEwan Crawford   eExprTypeDimZ,
1421836d9651SEwan Crawford   eExprTypeElemPtr,
1422836d9651SEwan Crawford   eExprElementType,
1423836d9651SEwan Crawford   eExprElementKind,
1424836d9651SEwan Crawford   eExprElementVec,
1425836d9651SEwan Crawford   eExprElementFieldCount,
1426836d9651SEwan Crawford   eExprSubelementsId,
1427836d9651SEwan Crawford   eExprSubelementsName,
1428ea0636b5SEwan Crawford   eExprSubelementsArrSize,
1429ea0636b5SEwan Crawford 
1430ea0636b5SEwan Crawford   _eExprLast // keep at the end, implicit size of the array runtimeExpressions
1431836d9651SEwan Crawford };
143215f2bd95SEwan Crawford 
1433ea0636b5SEwan Crawford // max length of an expanded expression
1434ea0636b5SEwan Crawford const int jit_max_expr_size = 512;
1435ea0636b5SEwan Crawford 
1436ea0636b5SEwan Crawford // Retrieve the string to JIT for the given expression
1437*b9c1b51eSKate Stone const char *JITTemplate(ExpressionStrings e) {
1438ea0636b5SEwan Crawford   // Format strings containing the expressions we may need to evaluate.
1439*b9c1b51eSKate Stone   static std::array<const char *, _eExprLast> runtimeExpressions = {
1440*b9c1b51eSKate Stone       {// Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap)
1441*b9c1b51eSKate Stone        "(int*)_"
1442*b9c1b51eSKate Stone        "Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocation"
1443*b9c1b51eSKate Stone        "CubemapFace"
1444577570b4SAidan Dodds        "(0x%" PRIx64 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", 0, 0)",
144515f2bd95SEwan Crawford 
144615f2bd95SEwan Crawford        // Type* rsaAllocationGetType(Context*, Allocation*)
1447577570b4SAidan Dodds        "(void*)rsaAllocationGetType(0x%" PRIx64 ", 0x%" PRIx64 ")",
144815f2bd95SEwan Crawford 
144915f2bd95SEwan Crawford        // rsaTypeGetNativeData(Context*, Type*, void* typeData, size)
1450*b9c1b51eSKate Stone        // Pack the data in the following way mHal.state.dimX; mHal.state.dimY;
1451*b9c1b51eSKate Stone        // mHal.state.dimZ;
145215f2bd95SEwan Crawford        // mHal.state.lodCount; mHal.state.faces; mElement; into typeData
1453*b9c1b51eSKate Stone        // Need to specify 32 or 64 bit for uint_t since this differs between
1454*b9c1b51eSKate Stone        // devices
1455*b9c1b51eSKate Stone        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64
1456*b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 6); data[0]", // X dim
1457*b9c1b51eSKate Stone        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64
1458*b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 6); data[1]", // Y dim
1459*b9c1b51eSKate Stone        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64
1460*b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 6); data[2]", // Z dim
1461*b9c1b51eSKate Stone        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64
1462*b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 6); data[5]", // Element ptr
146315f2bd95SEwan Crawford 
146415f2bd95SEwan Crawford        // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size)
1465*b9c1b51eSKate Stone        // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into
1466*b9c1b51eSKate Stone        // elemData
1467*b9c1b51eSKate Stone        "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64
1468*b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 5); data[0]", // Type
1469*b9c1b51eSKate Stone        "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64
1470*b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 5); data[1]", // Kind
1471*b9c1b51eSKate Stone        "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64
1472*b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 5); data[3]", // Vector Size
1473*b9c1b51eSKate Stone        "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64
1474*b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 5); data[4]", // Field Count
14758b244e21SEwan Crawford 
1476*b9c1b51eSKate Stone        // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t
1477*b9c1b51eSKate Stone        // *ids, const char **names,
14788b244e21SEwan Crawford        // size_t *arraySizes, uint32_t dataSize)
1479*b9c1b51eSKate Stone        // Needed for Allocations of structs to gather details about
1480*b9c1b51eSKate Stone        // fields/Subelements
1481577570b4SAidan Dodds        // Element* of field
1482*b9c1b51eSKate Stone        "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
1483*b9c1b51eSKate Stone        "]; size_t arr_size[%" PRIu32 "];"
1484*b9c1b51eSKate Stone        "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64
1485*b9c1b51eSKate Stone        ", ids, names, arr_size, %" PRIu32 "); ids[%" PRIu32 "]",
14868b244e21SEwan Crawford 
1487577570b4SAidan Dodds        // Name of field
1488*b9c1b51eSKate Stone        "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
1489*b9c1b51eSKate Stone        "]; size_t arr_size[%" PRIu32 "];"
1490*b9c1b51eSKate Stone        "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64
1491*b9c1b51eSKate Stone        ", ids, names, arr_size, %" PRIu32 "); names[%" PRIu32 "]",
14928b244e21SEwan Crawford 
1493577570b4SAidan Dodds        // Array size of field
1494*b9c1b51eSKate Stone        "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
1495*b9c1b51eSKate Stone        "]; size_t arr_size[%" PRIu32 "];"
1496*b9c1b51eSKate Stone        "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64
1497*b9c1b51eSKate Stone        ", ids, names, arr_size, %" PRIu32 "); arr_size[%" PRIu32 "]"}};
1498ea0636b5SEwan Crawford 
1499ea0636b5SEwan Crawford   return runtimeExpressions[e];
1500ea0636b5SEwan Crawford }
1501ea0636b5SEwan Crawford } // end of the anonymous namespace
1502ea0636b5SEwan Crawford 
150315f2bd95SEwan Crawford // JITs the RS runtime for the internal data pointer of an allocation.
150415f2bd95SEwan Crawford // Is passed x,y,z coordinates for the pointer to a specific element.
150515f2bd95SEwan Crawford // Then sets the data_ptr member in Allocation with the result.
150615f2bd95SEwan Crawford // Returns true on success, false otherwise
1507*b9c1b51eSKate Stone bool RenderScriptRuntime::JITDataPointer(AllocationDetails *allocation,
1508*b9c1b51eSKate Stone                                          StackFrame *frame_ptr, uint32_t x,
1509*b9c1b51eSKate Stone                                          uint32_t y, uint32_t z) {
151015f2bd95SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
151115f2bd95SEwan Crawford 
1512*b9c1b51eSKate Stone   if (!allocation->address.isValid()) {
151315f2bd95SEwan Crawford     if (log)
1514b3f7f69dSAidan Dodds       log->Printf("%s - failed to find allocation details.", __FUNCTION__);
151515f2bd95SEwan Crawford     return false;
151615f2bd95SEwan Crawford   }
151715f2bd95SEwan Crawford 
1518ea0636b5SEwan Crawford   const char *expr_cstr = JITTemplate(eExprGetOffsetPtr);
1519ea0636b5SEwan Crawford   char buffer[jit_max_expr_size];
152015f2bd95SEwan Crawford 
1521*b9c1b51eSKate Stone   int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr,
1522*b9c1b51eSKate Stone                                *allocation->address.get(), x, y, z);
1523*b9c1b51eSKate Stone   if (chars_written < 0) {
152415f2bd95SEwan Crawford     if (log)
1525b3f7f69dSAidan Dodds       log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
152615f2bd95SEwan Crawford     return false;
1527*b9c1b51eSKate Stone   } else if (chars_written >= jit_max_expr_size) {
152815f2bd95SEwan Crawford     if (log)
1529b3f7f69dSAidan Dodds       log->Printf("%s - expression too long.", __FUNCTION__);
153015f2bd95SEwan Crawford     return false;
153115f2bd95SEwan Crawford   }
153215f2bd95SEwan Crawford 
153315f2bd95SEwan Crawford   uint64_t result = 0;
153415f2bd95SEwan Crawford   if (!EvalRSExpression(buffer, frame_ptr, &result))
153515f2bd95SEwan Crawford     return false;
153615f2bd95SEwan Crawford 
153715f2bd95SEwan Crawford   addr_t mem_ptr = static_cast<lldb::addr_t>(result);
153815f2bd95SEwan Crawford   allocation->data_ptr = mem_ptr;
153915f2bd95SEwan Crawford 
154015f2bd95SEwan Crawford   return true;
154115f2bd95SEwan Crawford }
154215f2bd95SEwan Crawford 
154315f2bd95SEwan Crawford // JITs the RS runtime for the internal pointer to the RS Type of an allocation
154415f2bd95SEwan Crawford // Then sets the type_ptr member in Allocation with the result.
154515f2bd95SEwan Crawford // Returns true on success, false otherwise
1546*b9c1b51eSKate Stone bool RenderScriptRuntime::JITTypePointer(AllocationDetails *allocation,
1547*b9c1b51eSKate Stone                                          StackFrame *frame_ptr) {
154815f2bd95SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
154915f2bd95SEwan Crawford 
1550*b9c1b51eSKate Stone   if (!allocation->address.isValid() || !allocation->context.isValid()) {
155115f2bd95SEwan Crawford     if (log)
1552b3f7f69dSAidan Dodds       log->Printf("%s - failed to find allocation details.", __FUNCTION__);
155315f2bd95SEwan Crawford     return false;
155415f2bd95SEwan Crawford   }
155515f2bd95SEwan Crawford 
1556ea0636b5SEwan Crawford   const char *expr_cstr = JITTemplate(eExprAllocGetType);
1557ea0636b5SEwan Crawford   char buffer[jit_max_expr_size];
155815f2bd95SEwan Crawford 
1559ea0636b5SEwan Crawford   int chars_written =
1560*b9c1b51eSKate Stone       snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->context.get(),
1561*b9c1b51eSKate Stone                *allocation->address.get());
1562*b9c1b51eSKate Stone   if (chars_written < 0) {
156315f2bd95SEwan Crawford     if (log)
1564b3f7f69dSAidan Dodds       log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
156515f2bd95SEwan Crawford     return false;
1566*b9c1b51eSKate Stone   } else if (chars_written >= jit_max_expr_size) {
156715f2bd95SEwan Crawford     if (log)
1568b3f7f69dSAidan Dodds       log->Printf("%s - expression too long.", __FUNCTION__);
156915f2bd95SEwan Crawford     return false;
157015f2bd95SEwan Crawford   }
157115f2bd95SEwan Crawford 
157215f2bd95SEwan Crawford   uint64_t result = 0;
157315f2bd95SEwan Crawford   if (!EvalRSExpression(buffer, frame_ptr, &result))
157415f2bd95SEwan Crawford     return false;
157515f2bd95SEwan Crawford 
157615f2bd95SEwan Crawford   addr_t type_ptr = static_cast<lldb::addr_t>(result);
157715f2bd95SEwan Crawford   allocation->type_ptr = type_ptr;
157815f2bd95SEwan Crawford 
157915f2bd95SEwan Crawford   return true;
158015f2bd95SEwan Crawford }
158115f2bd95SEwan Crawford 
1582*b9c1b51eSKate Stone // JITs the RS runtime for information about the dimensions and type of an
1583*b9c1b51eSKate Stone // allocation
158415f2bd95SEwan Crawford // Then sets dimension and element_ptr members in Allocation with the result.
158515f2bd95SEwan Crawford // Returns true on success, false otherwise
1586*b9c1b51eSKate Stone bool RenderScriptRuntime::JITTypePacked(AllocationDetails *allocation,
1587*b9c1b51eSKate Stone                                         StackFrame *frame_ptr) {
158815f2bd95SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
158915f2bd95SEwan Crawford 
1590*b9c1b51eSKate Stone   if (!allocation->type_ptr.isValid() || !allocation->context.isValid()) {
159115f2bd95SEwan Crawford     if (log)
1592b3f7f69dSAidan Dodds       log->Printf("%s - Failed to find allocation details.", __FUNCTION__);
159315f2bd95SEwan Crawford     return false;
159415f2bd95SEwan Crawford   }
159515f2bd95SEwan Crawford 
159615f2bd95SEwan Crawford   // Expression is different depending on if device is 32 or 64 bit
1597*b9c1b51eSKate Stone   uint32_t archByteSize =
1598*b9c1b51eSKate Stone       GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
1599b3f7f69dSAidan Dodds   const uint32_t bits = archByteSize == 4 ? 32 : 64;
160015f2bd95SEwan Crawford 
160115f2bd95SEwan Crawford   // We want 4 elements from packed data
1602b3f7f69dSAidan Dodds   const uint32_t num_exprs = 4;
1603*b9c1b51eSKate Stone   assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1) &&
1604*b9c1b51eSKate Stone          "Invalid number of expressions");
160515f2bd95SEwan Crawford 
1606ea0636b5SEwan Crawford   char buffer[num_exprs][jit_max_expr_size];
160715f2bd95SEwan Crawford   uint64_t results[num_exprs];
160815f2bd95SEwan Crawford 
1609*b9c1b51eSKate Stone   for (uint32_t i = 0; i < num_exprs; ++i) {
1610ea0636b5SEwan Crawford     const char *expr_cstr = JITTemplate(ExpressionStrings(eExprTypeDimX + i));
1611*b9c1b51eSKate Stone     int chars_written =
1612*b9c1b51eSKate Stone         snprintf(buffer[i], jit_max_expr_size, expr_cstr, bits,
1613*b9c1b51eSKate Stone                  *allocation->context.get(), *allocation->type_ptr.get());
1614*b9c1b51eSKate Stone     if (chars_written < 0) {
161515f2bd95SEwan Crawford       if (log)
1616b3f7f69dSAidan Dodds         log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
161715f2bd95SEwan Crawford       return false;
1618*b9c1b51eSKate Stone     } else if (chars_written >= jit_max_expr_size) {
161915f2bd95SEwan Crawford       if (log)
1620b3f7f69dSAidan Dodds         log->Printf("%s - expression too long.", __FUNCTION__);
162115f2bd95SEwan Crawford       return false;
162215f2bd95SEwan Crawford     }
162315f2bd95SEwan Crawford 
162415f2bd95SEwan Crawford     // Perform expression evaluation
162515f2bd95SEwan Crawford     if (!EvalRSExpression(buffer[i], frame_ptr, &results[i]))
162615f2bd95SEwan Crawford       return false;
162715f2bd95SEwan Crawford   }
162815f2bd95SEwan Crawford 
162915f2bd95SEwan Crawford   // Assign results to allocation members
163015f2bd95SEwan Crawford   AllocationDetails::Dimension dims;
163115f2bd95SEwan Crawford   dims.dim_1 = static_cast<uint32_t>(results[0]);
163215f2bd95SEwan Crawford   dims.dim_2 = static_cast<uint32_t>(results[1]);
163315f2bd95SEwan Crawford   dims.dim_3 = static_cast<uint32_t>(results[2]);
163415f2bd95SEwan Crawford   allocation->dimension = dims;
163515f2bd95SEwan Crawford 
163615f2bd95SEwan Crawford   addr_t elem_ptr = static_cast<lldb::addr_t>(results[3]);
16378b244e21SEwan Crawford   allocation->element.element_ptr = elem_ptr;
163815f2bd95SEwan Crawford 
163915f2bd95SEwan Crawford   if (log)
1640*b9c1b51eSKate Stone     log->Printf("%s - dims (%" PRIu32 ", %" PRIu32 ", %" PRIu32
1641*b9c1b51eSKate Stone                 ") Element*: 0x%" PRIx64 ".",
1642*b9c1b51eSKate Stone                 __FUNCTION__, dims.dim_1, dims.dim_2, dims.dim_3, elem_ptr);
164315f2bd95SEwan Crawford 
164415f2bd95SEwan Crawford   return true;
164515f2bd95SEwan Crawford }
164615f2bd95SEwan Crawford 
164715f2bd95SEwan Crawford // JITs the RS runtime for information about the Element of an allocation
1648*b9c1b51eSKate Stone // Then sets type, type_vec_size, field_count and type_kind members in Element
1649*b9c1b51eSKate Stone // with the result.
165015f2bd95SEwan Crawford // Returns true on success, false otherwise
1651*b9c1b51eSKate Stone bool RenderScriptRuntime::JITElementPacked(Element &elem,
1652*b9c1b51eSKate Stone                                            const lldb::addr_t context,
1653*b9c1b51eSKate Stone                                            StackFrame *frame_ptr) {
165415f2bd95SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
165515f2bd95SEwan Crawford 
1656*b9c1b51eSKate Stone   if (!elem.element_ptr.isValid()) {
165715f2bd95SEwan Crawford     if (log)
1658b3f7f69dSAidan Dodds       log->Printf("%s - failed to find allocation details.", __FUNCTION__);
165915f2bd95SEwan Crawford     return false;
166015f2bd95SEwan Crawford   }
166115f2bd95SEwan Crawford 
16628b244e21SEwan Crawford   // We want 4 elements from packed data
1663b3f7f69dSAidan Dodds   const uint32_t num_exprs = 4;
1664*b9c1b51eSKate Stone   assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1) &&
1665*b9c1b51eSKate Stone          "Invalid number of expressions");
166615f2bd95SEwan Crawford 
1667ea0636b5SEwan Crawford   char buffer[num_exprs][jit_max_expr_size];
166815f2bd95SEwan Crawford   uint64_t results[num_exprs];
166915f2bd95SEwan Crawford 
1670*b9c1b51eSKate Stone   for (uint32_t i = 0; i < num_exprs; i++) {
1671*b9c1b51eSKate Stone     const char *expr_cstr =
1672*b9c1b51eSKate Stone         JITTemplate(ExpressionStrings(eExprElementType + i));
1673*b9c1b51eSKate Stone     int chars_written = snprintf(buffer[i], jit_max_expr_size, expr_cstr,
1674*b9c1b51eSKate Stone                                  context, *elem.element_ptr.get());
1675*b9c1b51eSKate Stone     if (chars_written < 0) {
167615f2bd95SEwan Crawford       if (log)
1677b3f7f69dSAidan Dodds         log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
167815f2bd95SEwan Crawford       return false;
1679*b9c1b51eSKate Stone     } else if (chars_written >= jit_max_expr_size) {
168015f2bd95SEwan Crawford       if (log)
1681b3f7f69dSAidan Dodds         log->Printf("%s - expression too long.", __FUNCTION__);
168215f2bd95SEwan Crawford       return false;
168315f2bd95SEwan Crawford     }
168415f2bd95SEwan Crawford 
168515f2bd95SEwan Crawford     // Perform expression evaluation
168615f2bd95SEwan Crawford     if (!EvalRSExpression(buffer[i], frame_ptr, &results[i]))
168715f2bd95SEwan Crawford       return false;
168815f2bd95SEwan Crawford   }
168915f2bd95SEwan Crawford 
169015f2bd95SEwan Crawford   // Assign results to allocation members
16918b244e21SEwan Crawford   elem.type = static_cast<RenderScriptRuntime::Element::DataType>(results[0]);
1692*b9c1b51eSKate Stone   elem.type_kind =
1693*b9c1b51eSKate Stone       static_cast<RenderScriptRuntime::Element::DataKind>(results[1]);
16948b244e21SEwan Crawford   elem.type_vec_size = static_cast<uint32_t>(results[2]);
16958b244e21SEwan Crawford   elem.field_count = static_cast<uint32_t>(results[3]);
169615f2bd95SEwan Crawford 
169715f2bd95SEwan Crawford   if (log)
1698*b9c1b51eSKate Stone     log->Printf("%s - data type %" PRIu32 ", pixel type %" PRIu32
1699*b9c1b51eSKate Stone                 ", vector size %" PRIu32 ", field count %" PRIu32,
1700*b9c1b51eSKate Stone                 __FUNCTION__, *elem.type.get(), *elem.type_kind.get(),
1701*b9c1b51eSKate Stone                 *elem.type_vec_size.get(), *elem.field_count.get());
17028b244e21SEwan Crawford 
1703*b9c1b51eSKate Stone   // If this Element has subelements then JIT rsaElementGetSubElements() for
1704*b9c1b51eSKate Stone   // details about its fields
17058b244e21SEwan Crawford   if (*elem.field_count.get() > 0 && !JITSubelements(elem, context, frame_ptr))
17068b244e21SEwan Crawford     return false;
17078b244e21SEwan Crawford 
17088b244e21SEwan Crawford   return true;
17098b244e21SEwan Crawford }
17108b244e21SEwan Crawford 
1711*b9c1b51eSKate Stone // JITs the RS runtime for information about the subelements/fields of a struct
1712*b9c1b51eSKate Stone // allocation
1713*b9c1b51eSKate Stone // This is necessary for infering the struct type so we can pretty print the
1714*b9c1b51eSKate Stone // allocation's contents.
17158b244e21SEwan Crawford // Returns true on success, false otherwise
1716*b9c1b51eSKate Stone bool RenderScriptRuntime::JITSubelements(Element &elem,
1717*b9c1b51eSKate Stone                                          const lldb::addr_t context,
1718*b9c1b51eSKate Stone                                          StackFrame *frame_ptr) {
17198b244e21SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
17208b244e21SEwan Crawford 
1721*b9c1b51eSKate Stone   if (!elem.element_ptr.isValid() || !elem.field_count.isValid()) {
17228b244e21SEwan Crawford     if (log)
1723b3f7f69dSAidan Dodds       log->Printf("%s - failed to find allocation details.", __FUNCTION__);
17248b244e21SEwan Crawford     return false;
17258b244e21SEwan Crawford   }
17268b244e21SEwan Crawford 
17278b244e21SEwan Crawford   const short num_exprs = 3;
1728*b9c1b51eSKate Stone   assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1) &&
1729*b9c1b51eSKate Stone          "Invalid number of expressions");
17308b244e21SEwan Crawford 
1731ea0636b5SEwan Crawford   char expr_buffer[jit_max_expr_size];
17328b244e21SEwan Crawford   uint64_t results;
17338b244e21SEwan Crawford 
17348b244e21SEwan Crawford   // Iterate over struct fields.
17358b244e21SEwan Crawford   const uint32_t field_count = *elem.field_count.get();
1736*b9c1b51eSKate Stone   for (uint32_t field_index = 0; field_index < field_count; ++field_index) {
17378b244e21SEwan Crawford     Element child;
1738*b9c1b51eSKate Stone     for (uint32_t expr_index = 0; expr_index < num_exprs; ++expr_index) {
1739*b9c1b51eSKate Stone       const char *expr_cstr =
1740*b9c1b51eSKate Stone           JITTemplate(ExpressionStrings(eExprSubelementsId + expr_index));
1741*b9c1b51eSKate Stone       int chars_written =
1742*b9c1b51eSKate Stone           snprintf(expr_buffer, jit_max_expr_size, expr_cstr, field_count,
1743*b9c1b51eSKate Stone                    field_count, field_count, context, *elem.element_ptr.get(),
1744*b9c1b51eSKate Stone                    field_count, field_index);
1745*b9c1b51eSKate Stone       if (chars_written < 0) {
17468b244e21SEwan Crawford         if (log)
1747b3f7f69dSAidan Dodds           log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
17488b244e21SEwan Crawford         return false;
1749*b9c1b51eSKate Stone       } else if (chars_written >= jit_max_expr_size) {
17508b244e21SEwan Crawford         if (log)
1751b3f7f69dSAidan Dodds           log->Printf("%s - expression too long.", __FUNCTION__);
17528b244e21SEwan Crawford         return false;
17538b244e21SEwan Crawford       }
17548b244e21SEwan Crawford 
17558b244e21SEwan Crawford       // Perform expression evaluation
17568b244e21SEwan Crawford       if (!EvalRSExpression(expr_buffer, frame_ptr, &results))
17578b244e21SEwan Crawford         return false;
17588b244e21SEwan Crawford 
17598b244e21SEwan Crawford       if (log)
1760b3f7f69dSAidan Dodds         log->Printf("%s - expr result 0x%" PRIx64 ".", __FUNCTION__, results);
17618b244e21SEwan Crawford 
1762*b9c1b51eSKate Stone       switch (expr_index) {
17638b244e21SEwan Crawford       case 0: // Element* of child
17648b244e21SEwan Crawford         child.element_ptr = static_cast<addr_t>(results);
17658b244e21SEwan Crawford         break;
17668b244e21SEwan Crawford       case 1: // Name of child
17678b244e21SEwan Crawford       {
17688b244e21SEwan Crawford         lldb::addr_t address = static_cast<addr_t>(results);
17698b244e21SEwan Crawford         Error err;
17708b244e21SEwan Crawford         std::string name;
17718b244e21SEwan Crawford         GetProcess()->ReadCStringFromMemory(address, name, err);
17728b244e21SEwan Crawford         if (!err.Fail())
17738b244e21SEwan Crawford           child.type_name = ConstString(name);
1774*b9c1b51eSKate Stone         else {
17758b244e21SEwan Crawford           if (log)
1776*b9c1b51eSKate Stone             log->Printf("%s - warning: Couldn't read field name.",
1777*b9c1b51eSKate Stone                         __FUNCTION__);
17788b244e21SEwan Crawford         }
17798b244e21SEwan Crawford         break;
17808b244e21SEwan Crawford       }
17818b244e21SEwan Crawford       case 2: // Array size of child
17828b244e21SEwan Crawford         child.array_size = static_cast<uint32_t>(results);
17838b244e21SEwan Crawford         break;
17848b244e21SEwan Crawford       }
17858b244e21SEwan Crawford     }
17868b244e21SEwan Crawford 
17878b244e21SEwan Crawford     // We need to recursively JIT each Element field of the struct since
17888b244e21SEwan Crawford     // structs can be nested inside structs.
17898b244e21SEwan Crawford     if (!JITElementPacked(child, context, frame_ptr))
17908b244e21SEwan Crawford       return false;
17918b244e21SEwan Crawford     elem.children.push_back(child);
17928b244e21SEwan Crawford   }
17938b244e21SEwan Crawford 
1794*b9c1b51eSKate Stone   // Try to infer the name of the struct type so we can pretty print the
1795*b9c1b51eSKate Stone   // allocation contents.
17968b244e21SEwan Crawford   FindStructTypeName(elem, frame_ptr);
179715f2bd95SEwan Crawford 
179815f2bd95SEwan Crawford   return true;
179915f2bd95SEwan Crawford }
180015f2bd95SEwan Crawford 
1801a0f08674SEwan Crawford // JITs the RS runtime for the address of the last element in the allocation.
1802*b9c1b51eSKate Stone // The `elem_size` parameter represents the size of a single element, including
1803*b9c1b51eSKate Stone // padding.
1804a0f08674SEwan Crawford // Which is needed as an offset from the last element pointer.
1805*b9c1b51eSKate Stone // Using this offset minus the starting address we can calculate the size of the
1806*b9c1b51eSKate Stone // allocation.
1807a0f08674SEwan Crawford // Returns true on success, false otherwise
1808*b9c1b51eSKate Stone bool RenderScriptRuntime::JITAllocationSize(AllocationDetails *allocation,
1809*b9c1b51eSKate Stone                                             StackFrame *frame_ptr) {
1810a0f08674SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1811a0f08674SEwan Crawford 
1812*b9c1b51eSKate Stone   if (!allocation->address.isValid() || !allocation->dimension.isValid() ||
1813*b9c1b51eSKate Stone       !allocation->data_ptr.isValid() ||
1814*b9c1b51eSKate Stone       !allocation->element.datum_size.isValid()) {
1815a0f08674SEwan Crawford     if (log)
1816b3f7f69dSAidan Dodds       log->Printf("%s - failed to find allocation details.", __FUNCTION__);
1817a0f08674SEwan Crawford     return false;
1818a0f08674SEwan Crawford   }
1819a0f08674SEwan Crawford 
1820a0f08674SEwan Crawford   // Find dimensions
1821b3f7f69dSAidan Dodds   uint32_t dim_x = allocation->dimension.get()->dim_1;
1822b3f7f69dSAidan Dodds   uint32_t dim_y = allocation->dimension.get()->dim_2;
1823b3f7f69dSAidan Dodds   uint32_t dim_z = allocation->dimension.get()->dim_3;
1824a0f08674SEwan Crawford 
1825*b9c1b51eSKate Stone   // Our plan of jitting the last element address doesn't seem to work for
1826*b9c1b51eSKate Stone   // struct Allocations
18278b244e21SEwan Crawford   // Instead try to infer the size ourselves without any inter element padding.
1828*b9c1b51eSKate Stone   if (allocation->element.children.size() > 0) {
1829*b9c1b51eSKate Stone     if (dim_x == 0)
1830*b9c1b51eSKate Stone       dim_x = 1;
1831*b9c1b51eSKate Stone     if (dim_y == 0)
1832*b9c1b51eSKate Stone       dim_y = 1;
1833*b9c1b51eSKate Stone     if (dim_z == 0)
1834*b9c1b51eSKate Stone       dim_z = 1;
18358b244e21SEwan Crawford 
1836*b9c1b51eSKate Stone     allocation->size =
1837*b9c1b51eSKate Stone         dim_x * dim_y * dim_z * *allocation->element.datum_size.get();
18388b244e21SEwan Crawford 
18398b244e21SEwan Crawford     if (log)
1840*b9c1b51eSKate Stone       log->Printf("%s - inferred size of struct allocation %" PRIu32 ".",
1841*b9c1b51eSKate Stone                   __FUNCTION__, *allocation->size.get());
18428b244e21SEwan Crawford     return true;
18438b244e21SEwan Crawford   }
18448b244e21SEwan Crawford 
1845ea0636b5SEwan Crawford   const char *expr_cstr = JITTemplate(eExprGetOffsetPtr);
1846ea0636b5SEwan Crawford   char buffer[jit_max_expr_size];
18478b244e21SEwan Crawford 
1848a0f08674SEwan Crawford   // Calculate last element
1849a0f08674SEwan Crawford   dim_x = dim_x == 0 ? 0 : dim_x - 1;
1850a0f08674SEwan Crawford   dim_y = dim_y == 0 ? 0 : dim_y - 1;
1851a0f08674SEwan Crawford   dim_z = dim_z == 0 ? 0 : dim_z - 1;
1852a0f08674SEwan Crawford 
1853*b9c1b51eSKate Stone   int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr,
1854*b9c1b51eSKate Stone                                *allocation->address.get(), dim_x, dim_y, dim_z);
1855*b9c1b51eSKate Stone   if (chars_written < 0) {
1856a0f08674SEwan Crawford     if (log)
1857b3f7f69dSAidan Dodds       log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
1858a0f08674SEwan Crawford     return false;
1859*b9c1b51eSKate Stone   } else if (chars_written >= jit_max_expr_size) {
1860a0f08674SEwan Crawford     if (log)
1861b3f7f69dSAidan Dodds       log->Printf("%s - expression too long.", __FUNCTION__);
1862a0f08674SEwan Crawford     return false;
1863a0f08674SEwan Crawford   }
1864a0f08674SEwan Crawford 
1865a0f08674SEwan Crawford   uint64_t result = 0;
1866a0f08674SEwan Crawford   if (!EvalRSExpression(buffer, frame_ptr, &result))
1867a0f08674SEwan Crawford     return false;
1868a0f08674SEwan Crawford 
1869a0f08674SEwan Crawford   addr_t mem_ptr = static_cast<lldb::addr_t>(result);
1870a0f08674SEwan Crawford   // Find pointer to last element and add on size of an element
1871b3f7f69dSAidan Dodds   allocation->size =
1872*b9c1b51eSKate Stone       static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()) +
1873*b9c1b51eSKate Stone       *allocation->element.datum_size.get();
1874a0f08674SEwan Crawford 
1875a0f08674SEwan Crawford   return true;
1876a0f08674SEwan Crawford }
1877a0f08674SEwan Crawford 
1878*b9c1b51eSKate Stone // JITs the RS runtime for information about the stride between rows in the
1879*b9c1b51eSKate Stone // allocation.
1880a0f08674SEwan Crawford // This is done to detect padding, since allocated memory is 16-byte aligned.
1881a0f08674SEwan Crawford // Returns true on success, false otherwise
1882*b9c1b51eSKate Stone bool RenderScriptRuntime::JITAllocationStride(AllocationDetails *allocation,
1883*b9c1b51eSKate Stone                                               StackFrame *frame_ptr) {
1884a0f08674SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1885a0f08674SEwan Crawford 
1886*b9c1b51eSKate Stone   if (!allocation->address.isValid() || !allocation->data_ptr.isValid()) {
1887a0f08674SEwan Crawford     if (log)
1888b3f7f69dSAidan Dodds       log->Printf("%s - failed to find allocation details.", __FUNCTION__);
1889a0f08674SEwan Crawford     return false;
1890a0f08674SEwan Crawford   }
1891a0f08674SEwan Crawford 
1892ea0636b5SEwan Crawford   const char *expr_cstr = JITTemplate(eExprGetOffsetPtr);
1893ea0636b5SEwan Crawford   char buffer[jit_max_expr_size];
1894a0f08674SEwan Crawford 
1895*b9c1b51eSKate Stone   int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr,
1896*b9c1b51eSKate Stone                                *allocation->address.get(), 0, 1, 0);
1897*b9c1b51eSKate Stone   if (chars_written < 0) {
1898a0f08674SEwan Crawford     if (log)
1899b3f7f69dSAidan Dodds       log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
1900a0f08674SEwan Crawford     return false;
1901*b9c1b51eSKate Stone   } else if (chars_written >= jit_max_expr_size) {
1902a0f08674SEwan Crawford     if (log)
1903b3f7f69dSAidan Dodds       log->Printf("%s - expression too long.", __FUNCTION__);
1904a0f08674SEwan Crawford     return false;
1905a0f08674SEwan Crawford   }
1906a0f08674SEwan Crawford 
1907a0f08674SEwan Crawford   uint64_t result = 0;
1908a0f08674SEwan Crawford   if (!EvalRSExpression(buffer, frame_ptr, &result))
1909a0f08674SEwan Crawford     return false;
1910a0f08674SEwan Crawford 
1911a0f08674SEwan Crawford   addr_t mem_ptr = static_cast<lldb::addr_t>(result);
1912*b9c1b51eSKate Stone   allocation->stride =
1913*b9c1b51eSKate Stone       static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get());
1914a0f08674SEwan Crawford 
1915a0f08674SEwan Crawford   return true;
1916a0f08674SEwan Crawford }
1917a0f08674SEwan Crawford 
191815f2bd95SEwan Crawford // JIT all the current runtime info regarding an allocation
1919*b9c1b51eSKate Stone bool RenderScriptRuntime::RefreshAllocation(AllocationDetails *allocation,
1920*b9c1b51eSKate Stone                                             StackFrame *frame_ptr) {
192115f2bd95SEwan Crawford   // GetOffsetPointer()
192215f2bd95SEwan Crawford   if (!JITDataPointer(allocation, frame_ptr))
192315f2bd95SEwan Crawford     return false;
192415f2bd95SEwan Crawford 
192515f2bd95SEwan Crawford   // rsaAllocationGetType()
192615f2bd95SEwan Crawford   if (!JITTypePointer(allocation, frame_ptr))
192715f2bd95SEwan Crawford     return false;
192815f2bd95SEwan Crawford 
192915f2bd95SEwan Crawford   // rsaTypeGetNativeData()
193015f2bd95SEwan Crawford   if (!JITTypePacked(allocation, frame_ptr))
193115f2bd95SEwan Crawford     return false;
193215f2bd95SEwan Crawford 
193315f2bd95SEwan Crawford   // rsaElementGetNativeData()
1934*b9c1b51eSKate Stone   if (!JITElementPacked(allocation->element, *allocation->context.get(),
1935*b9c1b51eSKate Stone                         frame_ptr))
193615f2bd95SEwan Crawford     return false;
193715f2bd95SEwan Crawford 
19388b244e21SEwan Crawford   // Sets the datum_size member in Element
19398b244e21SEwan Crawford   SetElementSize(allocation->element);
19408b244e21SEwan Crawford 
194155232f09SEwan Crawford   // Use GetOffsetPointer() to infer size of the allocation
19428b244e21SEwan Crawford   if (!JITAllocationSize(allocation, frame_ptr))
194355232f09SEwan Crawford     return false;
194455232f09SEwan Crawford 
194555232f09SEwan Crawford   return true;
194655232f09SEwan Crawford }
194755232f09SEwan Crawford 
1948*b9c1b51eSKate Stone // Function attempts to set the type_name member of the paramaterised Element
1949*b9c1b51eSKate Stone // object.
19508b244e21SEwan Crawford // This string should be the name of the struct type the Element represents.
19518b244e21SEwan Crawford // We need this string for pretty printing the Element to users.
1952*b9c1b51eSKate Stone void RenderScriptRuntime::FindStructTypeName(Element &elem,
1953*b9c1b51eSKate Stone                                              StackFrame *frame_ptr) {
19548b244e21SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
19558b244e21SEwan Crawford 
19568b244e21SEwan Crawford   if (!elem.type_name.IsEmpty()) // Name already set
19578b244e21SEwan Crawford     return;
19588b244e21SEwan Crawford   else
1959*b9c1b51eSKate Stone     elem.type_name = Element::GetFallbackStructName(); // Default type name if
1960*b9c1b51eSKate Stone                                                        // we don't succeed
19618b244e21SEwan Crawford 
19628b244e21SEwan Crawford   // Find all the global variables from the script rs modules
19638b244e21SEwan Crawford   VariableList variable_list;
19648b244e21SEwan Crawford   for (auto module_sp : m_rsmodules)
1965*b9c1b51eSKate Stone     module_sp->m_module->FindGlobalVariables(RegularExpression("."), true,
1966*b9c1b51eSKate Stone                                              UINT32_MAX, variable_list);
19678b244e21SEwan Crawford 
1968*b9c1b51eSKate Stone   // Iterate over all the global variables looking for one with a matching type
1969*b9c1b51eSKate Stone   // to the Element.
1970*b9c1b51eSKate Stone   // We make the assumption a match exists since there needs to be a global
1971*b9c1b51eSKate Stone   // variable to reflect the
19728b244e21SEwan Crawford   // struct type back into java host code.
1973*b9c1b51eSKate Stone   for (uint32_t var_index = 0; var_index < variable_list.GetSize();
1974*b9c1b51eSKate Stone        ++var_index) {
19758b244e21SEwan Crawford     const VariableSP var_sp(variable_list.GetVariableAtIndex(var_index));
19768b244e21SEwan Crawford     if (!var_sp)
19778b244e21SEwan Crawford       continue;
19788b244e21SEwan Crawford 
19798b244e21SEwan Crawford     ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp);
19808b244e21SEwan Crawford     if (!valobj_sp)
19818b244e21SEwan Crawford       continue;
19828b244e21SEwan Crawford 
19838b244e21SEwan Crawford     // Find the number of variable fields.
1984*b9c1b51eSKate Stone     // If it has no fields, or more fields than our Element, then it can't be
1985*b9c1b51eSKate Stone     // the struct we're looking for.
1986*b9c1b51eSKate Stone     // Don't check for equality since RS can add extra struct members for
1987*b9c1b51eSKate Stone     // padding.
19888b244e21SEwan Crawford     size_t num_children = valobj_sp->GetNumChildren();
19898b244e21SEwan Crawford     if (num_children > elem.children.size() || num_children == 0)
19908b244e21SEwan Crawford       continue;
19918b244e21SEwan Crawford 
19928b244e21SEwan Crawford     // Iterate over children looking for members with matching field names.
19938b244e21SEwan Crawford     // If all the field names match, this is likely the struct we want.
19948b244e21SEwan Crawford     //
1995*b9c1b51eSKate Stone     //   TODO: This could be made more robust by also checking children data
1996*b9c1b51eSKate Stone     //   sizes, or array size
19978b244e21SEwan Crawford     bool found = true;
1998*b9c1b51eSKate Stone     for (size_t child_index = 0; child_index < num_children; ++child_index) {
19998b244e21SEwan Crawford       ValueObjectSP child = valobj_sp->GetChildAtIndex(child_index, true);
2000*b9c1b51eSKate Stone       if (!child ||
2001*b9c1b51eSKate Stone           (child->GetName() != elem.children[child_index].type_name)) {
20028b244e21SEwan Crawford         found = false;
20038b244e21SEwan Crawford         break;
20048b244e21SEwan Crawford       }
20058b244e21SEwan Crawford     }
20068b244e21SEwan Crawford 
2007*b9c1b51eSKate Stone     // RS can add extra struct members for padding in the format
2008*b9c1b51eSKate Stone     // '#rs_padding_[0-9]+'
2009*b9c1b51eSKate Stone     if (found && num_children < elem.children.size()) {
2010b3f7f69dSAidan Dodds       const uint32_t size_diff = elem.children.size() - num_children;
20118b244e21SEwan Crawford       if (log)
2012*b9c1b51eSKate Stone         log->Printf("%s - %" PRIu32 " padding struct entries", __FUNCTION__,
2013*b9c1b51eSKate Stone                     size_diff);
20148b244e21SEwan Crawford 
2015*b9c1b51eSKate Stone       for (uint32_t padding_index = 0; padding_index < size_diff;
2016*b9c1b51eSKate Stone            ++padding_index) {
2017*b9c1b51eSKate Stone         const ConstString &name =
2018*b9c1b51eSKate Stone             elem.children[num_children + padding_index].type_name;
20198b244e21SEwan Crawford         if (strcmp(name.AsCString(), "#rs_padding") < 0)
20208b244e21SEwan Crawford           found = false;
20218b244e21SEwan Crawford       }
20228b244e21SEwan Crawford     }
20238b244e21SEwan Crawford 
20248b244e21SEwan Crawford     // We've found a global var with matching type
2025*b9c1b51eSKate Stone     if (found) {
20268b244e21SEwan Crawford       // Dereference since our Element type isn't a pointer.
2027*b9c1b51eSKate Stone       if (valobj_sp->IsPointerType()) {
20288b244e21SEwan Crawford         Error err;
20298b244e21SEwan Crawford         ValueObjectSP deref_valobj = valobj_sp->Dereference(err);
20308b244e21SEwan Crawford         if (!err.Fail())
20318b244e21SEwan Crawford           valobj_sp = deref_valobj;
20328b244e21SEwan Crawford       }
20338b244e21SEwan Crawford 
20348b244e21SEwan Crawford       // Save name of variable in Element.
20358b244e21SEwan Crawford       elem.type_name = valobj_sp->GetTypeName();
20368b244e21SEwan Crawford       if (log)
2037*b9c1b51eSKate Stone         log->Printf("%s - element name set to %s", __FUNCTION__,
2038*b9c1b51eSKate Stone                     elem.type_name.AsCString());
20398b244e21SEwan Crawford 
20408b244e21SEwan Crawford       return;
20418b244e21SEwan Crawford     }
20428b244e21SEwan Crawford   }
20438b244e21SEwan Crawford }
20448b244e21SEwan Crawford 
2045*b9c1b51eSKate Stone // Function sets the datum_size member of Element. Representing the size of a
2046*b9c1b51eSKate Stone // single instance including padding.
20478b244e21SEwan Crawford // Assumes the relevant allocation information has already been jitted.
2048*b9c1b51eSKate Stone void RenderScriptRuntime::SetElementSize(Element &elem) {
20498b244e21SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
20508b244e21SEwan Crawford   const Element::DataType type = *elem.type.get();
2051*b9c1b51eSKate Stone   assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT &&
2052*b9c1b51eSKate Stone          "Invalid allocation type");
205355232f09SEwan Crawford 
2054b3f7f69dSAidan Dodds   const uint32_t vec_size = *elem.type_vec_size.get();
2055b3f7f69dSAidan Dodds   uint32_t data_size = 0;
2056b3f7f69dSAidan Dodds   uint32_t padding = 0;
205755232f09SEwan Crawford 
20588b244e21SEwan Crawford   // Element is of a struct type, calculate size recursively.
2059*b9c1b51eSKate Stone   if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) {
2060*b9c1b51eSKate Stone     for (Element &child : elem.children) {
20618b244e21SEwan Crawford       SetElementSize(child);
2062*b9c1b51eSKate Stone       const uint32_t array_size =
2063*b9c1b51eSKate Stone           child.array_size.isValid() ? *child.array_size.get() : 1;
20648b244e21SEwan Crawford       data_size += *child.datum_size.get() * array_size;
20658b244e21SEwan Crawford     }
20668b244e21SEwan Crawford   }
2067b3f7f69dSAidan Dodds   // These have been packed already
2068b3f7f69dSAidan Dodds   else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 ||
2069b3f7f69dSAidan Dodds            type == Element::RS_TYPE_UNSIGNED_5_5_5_1 ||
2070*b9c1b51eSKate Stone            type == Element::RS_TYPE_UNSIGNED_4_4_4_4) {
20712e920715SEwan Crawford     data_size = AllocationDetails::RSTypeToFormat[type][eElementSize];
2072*b9c1b51eSKate Stone   } else if (type < Element::RS_TYPE_ELEMENT) {
2073*b9c1b51eSKate Stone     data_size =
2074*b9c1b51eSKate Stone         vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize];
20752e920715SEwan Crawford     if (vec_size == 3)
20762e920715SEwan Crawford       padding = AllocationDetails::RSTypeToFormat[type][eElementSize];
2077*b9c1b51eSKate Stone   } else
2078*b9c1b51eSKate Stone     data_size =
2079*b9c1b51eSKate Stone         GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
20808b244e21SEwan Crawford 
20818b244e21SEwan Crawford   elem.padding = padding;
20828b244e21SEwan Crawford   elem.datum_size = data_size + padding;
20838b244e21SEwan Crawford   if (log)
2084*b9c1b51eSKate Stone     log->Printf("%s - element size set to %" PRIu32, __FUNCTION__,
2085*b9c1b51eSKate Stone                 data_size + padding);
208655232f09SEwan Crawford }
208755232f09SEwan Crawford 
2088*b9c1b51eSKate Stone // Given an allocation, this function copies the allocation contents from device
2089*b9c1b51eSKate Stone // into a buffer on the heap.
209055232f09SEwan Crawford // Returning a shared pointer to the buffer containing the data.
209155232f09SEwan Crawford std::shared_ptr<uint8_t>
2092*b9c1b51eSKate Stone RenderScriptRuntime::GetAllocationData(AllocationDetails *allocation,
2093*b9c1b51eSKate Stone                                        StackFrame *frame_ptr) {
209455232f09SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
209555232f09SEwan Crawford 
209655232f09SEwan Crawford   // JIT all the allocation details
2097*b9c1b51eSKate Stone   if (allocation->shouldRefresh()) {
209855232f09SEwan Crawford     if (log)
2099*b9c1b51eSKate Stone       log->Printf("%s - allocation details not calculated yet, jitting info",
2100*b9c1b51eSKate Stone                   __FUNCTION__);
210155232f09SEwan Crawford 
2102*b9c1b51eSKate Stone     if (!RefreshAllocation(allocation, frame_ptr)) {
210355232f09SEwan Crawford       if (log)
2104b3f7f69dSAidan Dodds         log->Printf("%s - couldn't JIT allocation details", __FUNCTION__);
210555232f09SEwan Crawford       return nullptr;
210655232f09SEwan Crawford     }
210755232f09SEwan Crawford   }
210855232f09SEwan Crawford 
2109b3f7f69dSAidan Dodds   assert(allocation->data_ptr.isValid() && allocation->element.type.isValid() &&
2110*b9c1b51eSKate Stone          allocation->element.type_vec_size.isValid() &&
2111*b9c1b51eSKate Stone          allocation->size.isValid() && "Allocation information not available");
211255232f09SEwan Crawford 
211355232f09SEwan Crawford   // Allocate a buffer to copy data into
2114b3f7f69dSAidan Dodds   const uint32_t size = *allocation->size.get();
211555232f09SEwan Crawford   std::shared_ptr<uint8_t> buffer(new uint8_t[size]);
2116*b9c1b51eSKate Stone   if (!buffer) {
211755232f09SEwan Crawford     if (log)
2118*b9c1b51eSKate Stone       log->Printf("%s - couldn't allocate a %" PRIu32 " byte buffer",
2119*b9c1b51eSKate Stone                   __FUNCTION__, size);
212055232f09SEwan Crawford     return nullptr;
212155232f09SEwan Crawford   }
212255232f09SEwan Crawford 
212355232f09SEwan Crawford   // Read the inferior memory
212455232f09SEwan Crawford   Error error;
212555232f09SEwan Crawford   lldb::addr_t data_ptr = *allocation->data_ptr.get();
212655232f09SEwan Crawford   GetProcess()->ReadMemory(data_ptr, buffer.get(), size, error);
2127*b9c1b51eSKate Stone   if (error.Fail()) {
212855232f09SEwan Crawford     if (log)
2129*b9c1b51eSKate Stone       log->Printf("%s - '%s' Couldn't read %" PRIu32
2130*b9c1b51eSKate Stone                   " bytes of allocation data from 0x%" PRIx64,
2131b3f7f69dSAidan Dodds                   __FUNCTION__, error.AsCString(), size, data_ptr);
213255232f09SEwan Crawford     return nullptr;
213355232f09SEwan Crawford   }
213455232f09SEwan Crawford 
213555232f09SEwan Crawford   return buffer;
213655232f09SEwan Crawford }
213755232f09SEwan Crawford 
213855232f09SEwan Crawford // Function copies data from a binary file into an allocation.
2139*b9c1b51eSKate Stone // There is a header at the start of the file, FileHeader, before the data
2140*b9c1b51eSKate Stone // content itself.
2141*b9c1b51eSKate Stone // Information from this header is used to display warnings to the user about
2142*b9c1b51eSKate Stone // incompatibilities
2143*b9c1b51eSKate Stone bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id,
2144*b9c1b51eSKate Stone                                          const char *filename,
2145*b9c1b51eSKate Stone                                          StackFrame *frame_ptr) {
214655232f09SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
214755232f09SEwan Crawford 
214855232f09SEwan Crawford   // Find allocation with the given id
214955232f09SEwan Crawford   AllocationDetails *alloc = FindAllocByID(strm, alloc_id);
215055232f09SEwan Crawford   if (!alloc)
215155232f09SEwan Crawford     return false;
215255232f09SEwan Crawford 
215355232f09SEwan Crawford   if (log)
2154*b9c1b51eSKate Stone     log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__,
2155*b9c1b51eSKate Stone                 *alloc->address.get());
215655232f09SEwan Crawford 
215755232f09SEwan Crawford   // JIT all the allocation details
2158*b9c1b51eSKate Stone   if (alloc->shouldRefresh()) {
215955232f09SEwan Crawford     if (log)
2160*b9c1b51eSKate Stone       log->Printf("%s - allocation details not calculated yet, jitting info.",
2161*b9c1b51eSKate Stone                   __FUNCTION__);
216255232f09SEwan Crawford 
2163*b9c1b51eSKate Stone     if (!RefreshAllocation(alloc, frame_ptr)) {
216455232f09SEwan Crawford       if (log)
2165b3f7f69dSAidan Dodds         log->Printf("%s - couldn't JIT allocation details", __FUNCTION__);
21664cfc9198SSylvestre Ledru       return false;
216755232f09SEwan Crawford     }
216855232f09SEwan Crawford   }
216955232f09SEwan Crawford 
2170*b9c1b51eSKate Stone   assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
2171*b9c1b51eSKate Stone          alloc->element.type_vec_size.isValid() && alloc->size.isValid() &&
2172*b9c1b51eSKate Stone          alloc->element.datum_size.isValid() &&
2173*b9c1b51eSKate Stone          "Allocation information not available");
217455232f09SEwan Crawford 
217555232f09SEwan Crawford   // Check we can read from file
217655232f09SEwan Crawford   FileSpec file(filename, true);
2177*b9c1b51eSKate Stone   if (!file.Exists()) {
217855232f09SEwan Crawford     strm.Printf("Error: File %s does not exist", filename);
217955232f09SEwan Crawford     strm.EOL();
218055232f09SEwan Crawford     return false;
218155232f09SEwan Crawford   }
218255232f09SEwan Crawford 
2183*b9c1b51eSKate Stone   if (!file.Readable()) {
218455232f09SEwan Crawford     strm.Printf("Error: File %s does not have readable permissions", filename);
218555232f09SEwan Crawford     strm.EOL();
218655232f09SEwan Crawford     return false;
218755232f09SEwan Crawford   }
218855232f09SEwan Crawford 
218955232f09SEwan Crawford   // Read file into data buffer
219055232f09SEwan Crawford   DataBufferSP data_sp(file.ReadFileContents());
219155232f09SEwan Crawford 
219255232f09SEwan Crawford   // Cast start of buffer to FileHeader and use pointer to read metadata
219355232f09SEwan Crawford   void *file_buffer = data_sp->GetBytes();
2194b3f7f69dSAidan Dodds   if (file_buffer == nullptr ||
2195*b9c1b51eSKate Stone       data_sp->GetByteSize() < (sizeof(AllocationDetails::FileHeader) +
2196*b9c1b51eSKate Stone                                 sizeof(AllocationDetails::ElementHeader))) {
2197*b9c1b51eSKate Stone     strm.Printf("Error: File %s does not contain enough data for header",
2198*b9c1b51eSKate Stone                 filename);
219926e52a70SEwan Crawford     strm.EOL();
220026e52a70SEwan Crawford     return false;
220126e52a70SEwan Crawford   }
2202*b9c1b51eSKate Stone   const AllocationDetails::FileHeader *file_header =
2203*b9c1b51eSKate Stone       static_cast<AllocationDetails::FileHeader *>(file_buffer);
220455232f09SEwan Crawford 
220526e52a70SEwan Crawford   // Check file starts with ascii characters "RSAD"
2206*b9c1b51eSKate Stone   if (memcmp(file_header->ident, "RSAD", 4)) {
2207*b9c1b51eSKate Stone     strm.Printf("Error: File doesn't contain identifier for an RS allocation "
2208*b9c1b51eSKate Stone                 "dump. Are you sure this is the correct file?");
220926e52a70SEwan Crawford     strm.EOL();
221026e52a70SEwan Crawford     return false;
221126e52a70SEwan Crawford   }
221226e52a70SEwan Crawford 
221326e52a70SEwan Crawford   // Look at the type of the root element in the header
221426e52a70SEwan Crawford   AllocationDetails::ElementHeader root_element_header;
2215*b9c1b51eSKate Stone   memcpy(&root_element_header, static_cast<uint8_t *>(file_buffer) +
2216*b9c1b51eSKate Stone                                    sizeof(AllocationDetails::FileHeader),
221726e52a70SEwan Crawford          sizeof(AllocationDetails::ElementHeader));
221855232f09SEwan Crawford 
221955232f09SEwan Crawford   if (log)
2220*b9c1b51eSKate Stone     log->Printf("%s - header type %" PRIu32 ", element size %" PRIu32,
2221*b9c1b51eSKate Stone                 __FUNCTION__, root_element_header.type,
2222*b9c1b51eSKate Stone                 root_element_header.element_size);
222355232f09SEwan Crawford 
2224*b9c1b51eSKate Stone   // Check if the target allocation and file both have the same number of bytes
2225*b9c1b51eSKate Stone   // for an Element
2226*b9c1b51eSKate Stone   if (*alloc->element.datum_size.get() != root_element_header.element_size) {
2227*b9c1b51eSKate Stone     strm.Printf("Warning: Mismatched Element sizes - file %" PRIu32
2228*b9c1b51eSKate Stone                 " bytes, allocation %" PRIu32 " bytes",
2229*b9c1b51eSKate Stone                 root_element_header.element_size,
2230*b9c1b51eSKate Stone                 *alloc->element.datum_size.get());
223155232f09SEwan Crawford     strm.EOL();
223255232f09SEwan Crawford   }
223355232f09SEwan Crawford 
223426e52a70SEwan Crawford   // Check if the target allocation and file both have the same type
2235b3f7f69dSAidan Dodds   const uint32_t alloc_type = static_cast<uint32_t>(*alloc->element.type.get());
2236b3f7f69dSAidan Dodds   const uint32_t file_type = root_element_header.type;
223726e52a70SEwan Crawford 
2238*b9c1b51eSKate Stone   if (file_type > Element::RS_TYPE_FONT) {
223926e52a70SEwan Crawford     strm.Printf("Warning: File has unknown allocation type");
224026e52a70SEwan Crawford     strm.EOL();
2241*b9c1b51eSKate Stone   } else if (alloc_type != file_type) {
2242*b9c1b51eSKate Stone     // Enum value isn't monotonous, so doesn't always index RsDataTypeToString
2243*b9c1b51eSKate Stone     // array
2244b3f7f69dSAidan Dodds     uint32_t printable_target_type_index = alloc_type;
2245b3f7f69dSAidan Dodds     uint32_t printable_head_type_index = file_type;
2246*b9c1b51eSKate Stone     if (alloc_type >= Element::RS_TYPE_ELEMENT &&
2247*b9c1b51eSKate Stone         alloc_type <= Element::RS_TYPE_FONT)
2248*b9c1b51eSKate Stone       printable_target_type_index = static_cast<Element::DataType>(
2249*b9c1b51eSKate Stone           (alloc_type - Element::RS_TYPE_ELEMENT) +
2250b3f7f69dSAidan Dodds           Element::RS_TYPE_MATRIX_2X2 + 1);
22512e920715SEwan Crawford 
2252*b9c1b51eSKate Stone     if (file_type >= Element::RS_TYPE_ELEMENT &&
2253*b9c1b51eSKate Stone         file_type <= Element::RS_TYPE_FONT)
2254*b9c1b51eSKate Stone       printable_head_type_index = static_cast<Element::DataType>(
2255*b9c1b51eSKate Stone           (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 +
2256*b9c1b51eSKate Stone           1);
22572e920715SEwan Crawford 
2258*b9c1b51eSKate Stone     const char *file_type_cstr =
2259*b9c1b51eSKate Stone         AllocationDetails::RsDataTypeToString[printable_head_type_index][0];
2260*b9c1b51eSKate Stone     const char *target_type_cstr =
2261*b9c1b51eSKate Stone         AllocationDetails::RsDataTypeToString[printable_target_type_index][0];
226255232f09SEwan Crawford 
2263*b9c1b51eSKate Stone     strm.Printf(
2264*b9c1b51eSKate Stone         "Warning: Mismatched Types - file '%s' type, allocation '%s' type",
2265*b9c1b51eSKate Stone         file_type_cstr, target_type_cstr);
226655232f09SEwan Crawford     strm.EOL();
226755232f09SEwan Crawford   }
226855232f09SEwan Crawford 
226926e52a70SEwan Crawford   // Advance buffer past header
227026e52a70SEwan Crawford   file_buffer = static_cast<uint8_t *>(file_buffer) + file_header->hdr_size;
227126e52a70SEwan Crawford 
227255232f09SEwan Crawford   // Calculate size of allocation data in file
227326e52a70SEwan Crawford   size_t length = data_sp->GetByteSize() - file_header->hdr_size;
227455232f09SEwan Crawford 
227555232f09SEwan Crawford   // Check if the target allocation and file both have the same total data size.
2276b3f7f69dSAidan Dodds   const uint32_t alloc_size = *alloc->size.get();
2277*b9c1b51eSKate Stone   if (alloc_size != length) {
2278*b9c1b51eSKate Stone     strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64
2279*b9c1b51eSKate Stone                 " bytes, allocation 0x%" PRIx32 " bytes",
2280eba832beSJason Molenda                 (uint64_t)length, alloc_size);
228155232f09SEwan Crawford     strm.EOL();
2282*b9c1b51eSKate Stone     length = alloc_size < length ? alloc_size
2283*b9c1b51eSKate Stone                                  : length; // Set length to copy to minimum
228455232f09SEwan Crawford   }
228555232f09SEwan Crawford 
228655232f09SEwan Crawford   // Copy file data from our buffer into the target allocation.
228755232f09SEwan Crawford   lldb::addr_t alloc_data = *alloc->data_ptr.get();
228855232f09SEwan Crawford   Error error;
2289*b9c1b51eSKate Stone   size_t bytes_written =
2290*b9c1b51eSKate Stone       GetProcess()->WriteMemory(alloc_data, file_buffer, length, error);
2291*b9c1b51eSKate Stone   if (!error.Success() || bytes_written != length) {
2292*b9c1b51eSKate Stone     strm.Printf("Error: Couldn't write data to allocation %s",
2293*b9c1b51eSKate Stone                 error.AsCString());
229455232f09SEwan Crawford     strm.EOL();
229555232f09SEwan Crawford     return false;
229655232f09SEwan Crawford   }
229755232f09SEwan Crawford 
2298*b9c1b51eSKate Stone   strm.Printf("Contents of file '%s' read into allocation %" PRIu32, filename,
2299*b9c1b51eSKate Stone               alloc->id);
230055232f09SEwan Crawford   strm.EOL();
230155232f09SEwan Crawford 
230255232f09SEwan Crawford   return true;
230355232f09SEwan Crawford }
230455232f09SEwan Crawford 
2305*b9c1b51eSKate Stone // Function takes as parameters a byte buffer, which will eventually be written
2306*b9c1b51eSKate Stone // to file as the element header,
2307*b9c1b51eSKate Stone // an offset into that buffer, and an Element that will be saved into the buffer
2308*b9c1b51eSKate Stone // at the parametrised offset.
230926e52a70SEwan Crawford // Return value is the new offset after writing the element into the buffer.
2310*b9c1b51eSKate Stone // Elements are saved to the file as the ElementHeader struct followed by
2311*b9c1b51eSKate Stone // offsets to the structs of all the element's
2312b3f7f69dSAidan Dodds // children.
2313*b9c1b51eSKate Stone size_t RenderScriptRuntime::PopulateElementHeaders(
2314*b9c1b51eSKate Stone     const std::shared_ptr<uint8_t> header_buffer, size_t offset,
2315*b9c1b51eSKate Stone     const Element &elem) {
2316*b9c1b51eSKate Stone   // File struct for an element header with all the relevant details copied from
2317*b9c1b51eSKate Stone   // elem.
231826e52a70SEwan Crawford   // We assume members are valid already.
231926e52a70SEwan Crawford   AllocationDetails::ElementHeader elem_header;
232026e52a70SEwan Crawford   elem_header.type = *elem.type.get();
232126e52a70SEwan Crawford   elem_header.kind = *elem.type_kind.get();
232226e52a70SEwan Crawford   elem_header.element_size = *elem.datum_size.get();
232326e52a70SEwan Crawford   elem_header.vector_size = *elem.type_vec_size.get();
2324*b9c1b51eSKate Stone   elem_header.array_size =
2325*b9c1b51eSKate Stone       elem.array_size.isValid() ? *elem.array_size.get() : 0;
232626e52a70SEwan Crawford   const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader);
232726e52a70SEwan Crawford 
232826e52a70SEwan Crawford   // Copy struct into buffer and advance offset
2329*b9c1b51eSKate Stone   // We assume that header_buffer has been checked for nullptr before this
2330*b9c1b51eSKate Stone   // method is called
233126e52a70SEwan Crawford   memcpy(header_buffer.get() + offset, &elem_header, elem_header_size);
233226e52a70SEwan Crawford   offset += elem_header_size;
233326e52a70SEwan Crawford 
233426e52a70SEwan Crawford   // Starting offset of child ElementHeader struct
2335*b9c1b51eSKate Stone   size_t child_offset =
2336*b9c1b51eSKate Stone       offset + ((elem.children.size() + 1) * sizeof(uint32_t));
2337*b9c1b51eSKate Stone   for (const RenderScriptRuntime::Element &child : elem.children) {
2338*b9c1b51eSKate Stone     // Recursively populate the buffer with the element header structs of
2339*b9c1b51eSKate Stone     // children.
2340*b9c1b51eSKate Stone     // Then save the offsets where they were set after the parent element
2341*b9c1b51eSKate Stone     // header.
234226e52a70SEwan Crawford     memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t));
234326e52a70SEwan Crawford     offset += sizeof(uint32_t);
234426e52a70SEwan Crawford 
234526e52a70SEwan Crawford     child_offset = PopulateElementHeaders(header_buffer, child_offset, child);
234626e52a70SEwan Crawford   }
234726e52a70SEwan Crawford 
234826e52a70SEwan Crawford   // Zero indicates no more children
234926e52a70SEwan Crawford   memset(header_buffer.get() + offset, 0, sizeof(uint32_t));
235026e52a70SEwan Crawford 
235126e52a70SEwan Crawford   return child_offset;
235226e52a70SEwan Crawford }
235326e52a70SEwan Crawford 
2354*b9c1b51eSKate Stone // Given an Element object this function returns the total size needed in the
2355*b9c1b51eSKate Stone // file header to store the element's
2356b3f7f69dSAidan Dodds // details.
2357*b9c1b51eSKate Stone // Taking into account the size of the element header struct, plus the offsets
2358*b9c1b51eSKate Stone // to all the element's children.
2359*b9c1b51eSKate Stone // Function is recursive so that the size of all ancestors is taken into
2360*b9c1b51eSKate Stone // account.
2361*b9c1b51eSKate Stone size_t RenderScriptRuntime::CalculateElementHeaderSize(const Element &elem) {
2362*b9c1b51eSKate Stone   size_t size = (elem.children.size() + 1) *
2363*b9c1b51eSKate Stone                 sizeof(uint32_t); // Offsets to children plus zero terminator
2364*b9c1b51eSKate Stone   size += sizeof(AllocationDetails::ElementHeader); // Size of header struct
2365*b9c1b51eSKate Stone                                                     // with type details
236626e52a70SEwan Crawford 
236726e52a70SEwan Crawford   // Calculate recursively for all descendants
236826e52a70SEwan Crawford   for (const Element &child : elem.children)
236926e52a70SEwan Crawford     size += CalculateElementHeaderSize(child);
237026e52a70SEwan Crawford 
237126e52a70SEwan Crawford   return size;
237226e52a70SEwan Crawford }
237326e52a70SEwan Crawford 
237455232f09SEwan Crawford // Function copies allocation contents into a binary file.
237555232f09SEwan Crawford // This file can then be loaded later into a different allocation.
2376*b9c1b51eSKate Stone // There is a header, FileHeader, before the allocation data containing
2377*b9c1b51eSKate Stone // meta-data.
2378*b9c1b51eSKate Stone bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id,
2379*b9c1b51eSKate Stone                                          const char *filename,
2380*b9c1b51eSKate Stone                                          StackFrame *frame_ptr) {
238155232f09SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
238255232f09SEwan Crawford 
238355232f09SEwan Crawford   // Find allocation with the given id
238455232f09SEwan Crawford   AllocationDetails *alloc = FindAllocByID(strm, alloc_id);
238555232f09SEwan Crawford   if (!alloc)
238655232f09SEwan Crawford     return false;
238755232f09SEwan Crawford 
238855232f09SEwan Crawford   if (log)
2389*b9c1b51eSKate Stone     log->Printf("%s - found allocation 0x%" PRIx64 ".", __FUNCTION__,
2390*b9c1b51eSKate Stone                 *alloc->address.get());
239155232f09SEwan Crawford 
239255232f09SEwan Crawford   // JIT all the allocation details
2393*b9c1b51eSKate Stone   if (alloc->shouldRefresh()) {
239455232f09SEwan Crawford     if (log)
2395*b9c1b51eSKate Stone       log->Printf("%s - allocation details not calculated yet, jitting info.",
2396*b9c1b51eSKate Stone                   __FUNCTION__);
239755232f09SEwan Crawford 
2398*b9c1b51eSKate Stone     if (!RefreshAllocation(alloc, frame_ptr)) {
239955232f09SEwan Crawford       if (log)
2400b3f7f69dSAidan Dodds         log->Printf("%s - couldn't JIT allocation details.", __FUNCTION__);
24014cfc9198SSylvestre Ledru       return false;
240255232f09SEwan Crawford     }
240355232f09SEwan Crawford   }
240455232f09SEwan Crawford 
2405*b9c1b51eSKate Stone   assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
2406*b9c1b51eSKate Stone          alloc->element.type_vec_size.isValid() &&
2407*b9c1b51eSKate Stone          alloc->element.datum_size.get() &&
2408*b9c1b51eSKate Stone          alloc->element.type_kind.isValid() && alloc->dimension.isValid() &&
2409b3f7f69dSAidan Dodds          "Allocation information not available");
241055232f09SEwan Crawford 
241155232f09SEwan Crawford   // Check we can create writable file
241255232f09SEwan Crawford   FileSpec file_spec(filename, true);
2413*b9c1b51eSKate Stone   File file(file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate |
2414*b9c1b51eSKate Stone                            File::eOpenOptionTruncate);
2415*b9c1b51eSKate Stone   if (!file) {
241655232f09SEwan Crawford     strm.Printf("Error: Failed to open '%s' for writing", filename);
241755232f09SEwan Crawford     strm.EOL();
241855232f09SEwan Crawford     return false;
241955232f09SEwan Crawford   }
242055232f09SEwan Crawford 
242155232f09SEwan Crawford   // Read allocation into buffer of heap memory
242255232f09SEwan Crawford   const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
2423*b9c1b51eSKate Stone   if (!buffer) {
242455232f09SEwan Crawford     strm.Printf("Error: Couldn't read allocation data into buffer");
242555232f09SEwan Crawford     strm.EOL();
242655232f09SEwan Crawford     return false;
242755232f09SEwan Crawford   }
242855232f09SEwan Crawford 
242955232f09SEwan Crawford   // Create the file header
243055232f09SEwan Crawford   AllocationDetails::FileHeader head;
2431b3f7f69dSAidan Dodds   memcpy(head.ident, "RSAD", 4);
24322d62328aSEwan Crawford   head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1);
24332d62328aSEwan Crawford   head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2);
24342d62328aSEwan Crawford   head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3);
243526e52a70SEwan Crawford 
243626e52a70SEwan Crawford   const size_t element_header_size = CalculateElementHeaderSize(alloc->element);
2437*b9c1b51eSKate Stone   assert((sizeof(AllocationDetails::FileHeader) + element_header_size) <
2438*b9c1b51eSKate Stone              UINT16_MAX &&
2439*b9c1b51eSKate Stone          "Element header too large");
2440*b9c1b51eSKate Stone   head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) +
2441*b9c1b51eSKate Stone                                         element_header_size);
244255232f09SEwan Crawford 
244355232f09SEwan Crawford   // Write the file header
244455232f09SEwan Crawford   size_t num_bytes = sizeof(AllocationDetails::FileHeader);
244526e52a70SEwan Crawford   if (log)
2446*b9c1b51eSKate Stone     log->Printf("%s - writing File Header, 0x%" PRIx64 " bytes", __FUNCTION__,
2447*b9c1b51eSKate Stone                 (uint64_t)num_bytes);
244826e52a70SEwan Crawford 
244926e52a70SEwan Crawford   Error err = file.Write(&head, num_bytes);
2450*b9c1b51eSKate Stone   if (!err.Success()) {
2451*b9c1b51eSKate Stone     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(),
2452*b9c1b51eSKate Stone                 filename);
245326e52a70SEwan Crawford     strm.EOL();
245426e52a70SEwan Crawford     return false;
245526e52a70SEwan Crawford   }
245626e52a70SEwan Crawford 
245726e52a70SEwan Crawford   // Create the headers describing the element type of the allocation.
2458*b9c1b51eSKate Stone   std::shared_ptr<uint8_t> element_header_buffer(
2459*b9c1b51eSKate Stone       new uint8_t[element_header_size]);
2460*b9c1b51eSKate Stone   if (element_header_buffer == nullptr) {
2461*b9c1b51eSKate Stone     strm.Printf("Internal Error: Couldn't allocate %" PRIu64
2462*b9c1b51eSKate Stone                 " bytes on the heap",
2463*b9c1b51eSKate Stone                 (uint64_t)element_header_size);
246426e52a70SEwan Crawford     strm.EOL();
246526e52a70SEwan Crawford     return false;
246626e52a70SEwan Crawford   }
246726e52a70SEwan Crawford 
246826e52a70SEwan Crawford   PopulateElementHeaders(element_header_buffer, 0, alloc->element);
246926e52a70SEwan Crawford 
247026e52a70SEwan Crawford   // Write headers for allocation element type to file
247126e52a70SEwan Crawford   num_bytes = element_header_size;
247226e52a70SEwan Crawford   if (log)
2473*b9c1b51eSKate Stone     log->Printf("%s - writing element headers, 0x%" PRIx64 " bytes.",
2474*b9c1b51eSKate Stone                 __FUNCTION__, (uint64_t)num_bytes);
247526e52a70SEwan Crawford 
247626e52a70SEwan Crawford   err = file.Write(element_header_buffer.get(), num_bytes);
2477*b9c1b51eSKate Stone   if (!err.Success()) {
2478*b9c1b51eSKate Stone     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(),
2479*b9c1b51eSKate Stone                 filename);
248055232f09SEwan Crawford     strm.EOL();
248155232f09SEwan Crawford     return false;
248255232f09SEwan Crawford   }
248355232f09SEwan Crawford 
248455232f09SEwan Crawford   // Write allocation data to file
248555232f09SEwan Crawford   num_bytes = static_cast<size_t>(*alloc->size.get());
248655232f09SEwan Crawford   if (log)
2487*b9c1b51eSKate Stone     log->Printf("%s - writing 0x%" PRIx64 " bytes", __FUNCTION__,
2488*b9c1b51eSKate Stone                 (uint64_t)num_bytes);
248955232f09SEwan Crawford 
249055232f09SEwan Crawford   err = file.Write(buffer.get(), num_bytes);
2491*b9c1b51eSKate Stone   if (!err.Success()) {
2492*b9c1b51eSKate Stone     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(),
2493*b9c1b51eSKate Stone                 filename);
249455232f09SEwan Crawford     strm.EOL();
249555232f09SEwan Crawford     return false;
249655232f09SEwan Crawford   }
249755232f09SEwan Crawford 
249855232f09SEwan Crawford   strm.Printf("Allocation written to file '%s'", filename);
249955232f09SEwan Crawford   strm.EOL();
250015f2bd95SEwan Crawford   return true;
250115f2bd95SEwan Crawford }
250215f2bd95SEwan Crawford 
2503*b9c1b51eSKate Stone bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) {
25044640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
25054640cde1SColin Riley 
2506*b9c1b51eSKate Stone   if (module_sp) {
2507*b9c1b51eSKate Stone     for (const auto &rs_module : m_rsmodules) {
2508*b9c1b51eSKate Stone       if (rs_module->m_module == module_sp) {
25097dc7771cSEwan Crawford         // Check if the user has enabled automatically breaking on
25107dc7771cSEwan Crawford         // all RS kernels.
25117dc7771cSEwan Crawford         if (m_breakAllKernels)
25127dc7771cSEwan Crawford           BreakOnModuleKernels(rs_module);
25137dc7771cSEwan Crawford 
25145ec532a9SColin Riley         return false;
25155ec532a9SColin Riley       }
25167dc7771cSEwan Crawford     }
2517ef20b08fSColin Riley     bool module_loaded = false;
2518*b9c1b51eSKate Stone     switch (GetModuleKind(module_sp)) {
2519*b9c1b51eSKate Stone     case eModuleKindKernelObj: {
25204640cde1SColin Riley       RSModuleDescriptorSP module_desc;
25214640cde1SColin Riley       module_desc.reset(new RSModuleDescriptor(module_sp));
2522*b9c1b51eSKate Stone       if (module_desc->ParseRSInfo()) {
25235ec532a9SColin Riley         m_rsmodules.push_back(module_desc);
2524ef20b08fSColin Riley         module_loaded = true;
25255ec532a9SColin Riley       }
2526*b9c1b51eSKate Stone       if (module_loaded) {
25274640cde1SColin Riley         FixupScriptDetails(module_desc);
25284640cde1SColin Riley       }
2529ef20b08fSColin Riley       break;
2530ef20b08fSColin Riley     }
2531*b9c1b51eSKate Stone     case eModuleKindDriver: {
2532*b9c1b51eSKate Stone       if (!m_libRSDriver) {
25334640cde1SColin Riley         m_libRSDriver = module_sp;
25344640cde1SColin Riley         LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver);
25354640cde1SColin Riley       }
25364640cde1SColin Riley       break;
25374640cde1SColin Riley     }
2538*b9c1b51eSKate Stone     case eModuleKindImpl: {
25394640cde1SColin Riley       m_libRSCpuRef = module_sp;
25404640cde1SColin Riley       break;
25414640cde1SColin Riley     }
2542*b9c1b51eSKate Stone     case eModuleKindLibRS: {
2543*b9c1b51eSKate Stone       if (!m_libRS) {
25444640cde1SColin Riley         m_libRS = module_sp;
25454640cde1SColin Riley         static ConstString gDbgPresentStr("gDebuggerPresent");
2546*b9c1b51eSKate Stone         const Symbol *debug_present = m_libRS->FindFirstSymbolWithNameAndType(
2547*b9c1b51eSKate Stone             gDbgPresentStr, eSymbolTypeData);
2548*b9c1b51eSKate Stone         if (debug_present) {
25494640cde1SColin Riley           Error error;
25504640cde1SColin Riley           uint32_t flag = 0x00000001U;
25514640cde1SColin Riley           Target &target = GetProcess()->GetTarget();
2552358cf1eaSGreg Clayton           addr_t addr = debug_present->GetLoadAddress(&target);
25534640cde1SColin Riley           GetProcess()->WriteMemory(addr, &flag, sizeof(flag), error);
2554*b9c1b51eSKate Stone           if (error.Success()) {
25554640cde1SColin Riley             if (log)
2556*b9c1b51eSKate Stone               log->Printf("%s - debugger present flag set on debugee.",
2557*b9c1b51eSKate Stone                           __FUNCTION__);
25584640cde1SColin Riley 
25594640cde1SColin Riley             m_debuggerPresentFlagged = true;
2560*b9c1b51eSKate Stone           } else if (log) {
2561*b9c1b51eSKate Stone             log->Printf("%s - error writing debugger present flags '%s' ",
2562*b9c1b51eSKate Stone                         __FUNCTION__, error.AsCString());
25634640cde1SColin Riley           }
2564*b9c1b51eSKate Stone         } else if (log) {
2565*b9c1b51eSKate Stone           log->Printf(
2566*b9c1b51eSKate Stone               "%s - error writing debugger present flags - symbol not found",
2567*b9c1b51eSKate Stone               __FUNCTION__);
25684640cde1SColin Riley         }
25694640cde1SColin Riley       }
25704640cde1SColin Riley       break;
25714640cde1SColin Riley     }
2572ef20b08fSColin Riley     default:
2573ef20b08fSColin Riley       break;
2574ef20b08fSColin Riley     }
2575ef20b08fSColin Riley     if (module_loaded)
2576ef20b08fSColin Riley       Update();
2577ef20b08fSColin Riley     return module_loaded;
25785ec532a9SColin Riley   }
25795ec532a9SColin Riley   return false;
25805ec532a9SColin Riley }
25815ec532a9SColin Riley 
2582*b9c1b51eSKate Stone void RenderScriptRuntime::Update() {
2583*b9c1b51eSKate Stone   if (m_rsmodules.size() > 0) {
2584*b9c1b51eSKate Stone     if (!m_initiated) {
2585ef20b08fSColin Riley       Initiate();
2586ef20b08fSColin Riley     }
2587ef20b08fSColin Riley   }
2588ef20b08fSColin Riley }
2589ef20b08fSColin Riley 
25905ec532a9SColin Riley // The maximum line length of an .rs.info packet
25915ec532a9SColin Riley #define MAXLINE 500
2592b0be30f7SAidan Dodds #define STRINGIFY(x) #x
2593b0be30f7SAidan Dodds #define MAXLINESTR_(x) "%" STRINGIFY(x) "s"
2594b0be30f7SAidan Dodds #define MAXLINESTR MAXLINESTR_(MAXLINE)
25955ec532a9SColin Riley 
2596*b9c1b51eSKate Stone // The .rs.info symbol in renderscript modules contains a string which needs to
2597*b9c1b51eSKate Stone // be parsed.
25985ec532a9SColin Riley // The string is basic and is parsed on a line by line basis.
2599*b9c1b51eSKate Stone bool RSModuleDescriptor::ParseRSInfo() {
2600b0be30f7SAidan Dodds   assert(m_module);
2601*b9c1b51eSKate Stone   const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType(
2602*b9c1b51eSKate Stone       ConstString(".rs.info"), eSymbolTypeData);
2603b0be30f7SAidan Dodds   if (!info_sym)
2604b0be30f7SAidan Dodds     return false;
2605b0be30f7SAidan Dodds 
2606358cf1eaSGreg Clayton   const addr_t addr = info_sym->GetAddressRef().GetFileAddress();
2607b0be30f7SAidan Dodds   if (addr == LLDB_INVALID_ADDRESS)
2608b0be30f7SAidan Dodds     return false;
2609b0be30f7SAidan Dodds 
26105ec532a9SColin Riley   const addr_t size = info_sym->GetByteSize();
26115ec532a9SColin Riley   const FileSpec fs = m_module->GetFileSpec();
26125ec532a9SColin Riley 
2613b0be30f7SAidan Dodds   const DataBufferSP buffer = fs.ReadFileContents(addr, size);
26145ec532a9SColin Riley   if (!buffer)
26155ec532a9SColin Riley     return false;
26165ec532a9SColin Riley 
2617b0be30f7SAidan Dodds   // split rs.info. contents into lines
26185ec532a9SColin Riley   std::vector<std::string> info_lines;
26195ec532a9SColin Riley   {
2620b0be30f7SAidan Dodds     const std::string info((const char *)buffer->GetBytes());
2621*b9c1b51eSKate Stone     for (size_t tail = 0; tail < info.size();) {
2622b0be30f7SAidan Dodds       // find next new line or end of string
2623b0be30f7SAidan Dodds       size_t head = info.find('\n', tail);
2624b0be30f7SAidan Dodds       head = (head == std::string::npos) ? info.size() : head;
2625b0be30f7SAidan Dodds       std::string line = info.substr(tail, head - tail);
2626b0be30f7SAidan Dodds       // add to line list
2627b0be30f7SAidan Dodds       info_lines.push_back(line);
2628b0be30f7SAidan Dodds       tail = head + 1;
26295ec532a9SColin Riley     }
2630b0be30f7SAidan Dodds   }
2631b0be30f7SAidan Dodds 
26327ccf1373SSaleem Abdulrasool   std::array<char, MAXLINE> name{{'\0'}};
26337ccf1373SSaleem Abdulrasool   std::array<char, MAXLINE> value{{'\0'}};
2634b0be30f7SAidan Dodds 
2635b0be30f7SAidan Dodds   // parse all text lines of .rs.info
2636*b9c1b51eSKate Stone   for (auto line = info_lines.begin(); line != info_lines.end(); ++line) {
26375ec532a9SColin Riley     uint32_t numDefns = 0;
2638*b9c1b51eSKate Stone     if (sscanf(line->c_str(), "exportVarCount: %" PRIu32 "", &numDefns) == 1) {
26395ec532a9SColin Riley       while (numDefns--)
2640b0be30f7SAidan Dodds         m_globals.push_back(RSGlobalDescriptor(this, (++line)->c_str()));
2641*b9c1b51eSKate Stone     } else if (sscanf(line->c_str(), "exportForEachCount: %" PRIu32 "",
2642*b9c1b51eSKate Stone                       &numDefns) == 1) {
2643*b9c1b51eSKate Stone       while (numDefns--) {
26445ec532a9SColin Riley         uint32_t slot = 0;
26455ec532a9SColin Riley         name[0] = '\0';
2646b0be30f7SAidan Dodds         static const char *fmt_s = "%" PRIu32 " - " MAXLINESTR;
2647*b9c1b51eSKate Stone         if (sscanf((++line)->c_str(), fmt_s, &slot, name.data()) == 2) {
2648b0be30f7SAidan Dodds           if (name[0] != '\0')
2649b0be30f7SAidan Dodds             m_kernels.push_back(RSKernelDescriptor(this, name.data(), slot));
26504640cde1SColin Riley         }
26514640cde1SColin Riley       }
2652*b9c1b51eSKate Stone     } else if (sscanf(line->c_str(), "pragmaCount: %" PRIu32 "", &numDefns) ==
2653*b9c1b51eSKate Stone                1) {
2654*b9c1b51eSKate Stone       while (numDefns--) {
2655b0be30f7SAidan Dodds         name[0] = value[0] = '\0';
2656b0be30f7SAidan Dodds         static const char *fmt_s = MAXLINESTR " - " MAXLINESTR;
2657*b9c1b51eSKate Stone         if (sscanf((++line)->c_str(), fmt_s, name.data(), value.data()) != 0) {
2658b0be30f7SAidan Dodds           if (name[0] != '\0')
2659b0be30f7SAidan Dodds             m_pragmas[std::string(name.data())] = value.data();
26605ec532a9SColin Riley         }
26615ec532a9SColin Riley       }
2662*b9c1b51eSKate Stone     } else {
2663b0be30f7SAidan Dodds       Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2664*b9c1b51eSKate Stone       if (log) {
2665*b9c1b51eSKate Stone         log->Printf("%s - skipping .rs.info field '%s'", __FUNCTION__,
2666*b9c1b51eSKate Stone                     line->c_str());
2667b0be30f7SAidan Dodds       }
2668b0be30f7SAidan Dodds     }
26695ec532a9SColin Riley   }
26705ec532a9SColin Riley 
2671b0be30f7SAidan Dodds   // 'root' kernel should always be present
26725ec532a9SColin Riley   return m_kernels.size() > 0;
26735ec532a9SColin Riley }
26745ec532a9SColin Riley 
2675*b9c1b51eSKate Stone void RenderScriptRuntime::Status(Stream &strm) const {
2676*b9c1b51eSKate Stone   if (m_libRS) {
26774640cde1SColin Riley     strm.Printf("Runtime Library discovered.");
26784640cde1SColin Riley     strm.EOL();
26794640cde1SColin Riley   }
2680*b9c1b51eSKate Stone   if (m_libRSDriver) {
26814640cde1SColin Riley     strm.Printf("Runtime Driver discovered.");
26824640cde1SColin Riley     strm.EOL();
26834640cde1SColin Riley   }
2684*b9c1b51eSKate Stone   if (m_libRSCpuRef) {
26854640cde1SColin Riley     strm.Printf("CPU Reference Implementation discovered.");
26864640cde1SColin Riley     strm.EOL();
26874640cde1SColin Riley   }
26884640cde1SColin Riley 
2689*b9c1b51eSKate Stone   if (m_runtimeHooks.size()) {
26904640cde1SColin Riley     strm.Printf("Runtime functions hooked:");
26914640cde1SColin Riley     strm.EOL();
2692*b9c1b51eSKate Stone     for (auto b : m_runtimeHooks) {
26934640cde1SColin Riley       strm.Indent(b.second->defn->name);
26944640cde1SColin Riley       strm.EOL();
26954640cde1SColin Riley     }
2696*b9c1b51eSKate Stone   } else {
26974640cde1SColin Riley     strm.Printf("Runtime is not hooked.");
26984640cde1SColin Riley     strm.EOL();
26994640cde1SColin Riley   }
27004640cde1SColin Riley }
27014640cde1SColin Riley 
2702*b9c1b51eSKate Stone void RenderScriptRuntime::DumpContexts(Stream &strm) const {
27034640cde1SColin Riley   strm.Printf("Inferred RenderScript Contexts:");
27044640cde1SColin Riley   strm.EOL();
27054640cde1SColin Riley   strm.IndentMore();
27064640cde1SColin Riley 
27074640cde1SColin Riley   std::map<addr_t, uint64_t> contextReferences;
27084640cde1SColin Riley 
270978f339d1SEwan Crawford   // Iterate over all of the currently discovered scripts.
2710*b9c1b51eSKate Stone   // Note: We cant push or pop from m_scripts inside this loop or it may
2711*b9c1b51eSKate Stone   // invalidate script.
2712*b9c1b51eSKate Stone   for (const auto &script : m_scripts) {
271378f339d1SEwan Crawford     if (!script->context.isValid())
271478f339d1SEwan Crawford       continue;
271578f339d1SEwan Crawford     lldb::addr_t context = *script->context;
271678f339d1SEwan Crawford 
2717*b9c1b51eSKate Stone     if (contextReferences.find(context) != contextReferences.end()) {
271878f339d1SEwan Crawford       contextReferences[context]++;
2719*b9c1b51eSKate Stone     } else {
272078f339d1SEwan Crawford       contextReferences[context] = 1;
27214640cde1SColin Riley     }
27224640cde1SColin Riley   }
27234640cde1SColin Riley 
2724*b9c1b51eSKate Stone   for (const auto &cRef : contextReferences) {
2725*b9c1b51eSKate Stone     strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances",
2726*b9c1b51eSKate Stone                 cRef.first, cRef.second);
27274640cde1SColin Riley     strm.EOL();
27284640cde1SColin Riley   }
27294640cde1SColin Riley   strm.IndentLess();
27304640cde1SColin Riley }
27314640cde1SColin Riley 
2732*b9c1b51eSKate Stone void RenderScriptRuntime::DumpKernels(Stream &strm) const {
27334640cde1SColin Riley   strm.Printf("RenderScript Kernels:");
27344640cde1SColin Riley   strm.EOL();
27354640cde1SColin Riley   strm.IndentMore();
2736*b9c1b51eSKate Stone   for (const auto &module : m_rsmodules) {
27374640cde1SColin Riley     strm.Printf("Resource '%s':", module->m_resname.c_str());
27384640cde1SColin Riley     strm.EOL();
2739*b9c1b51eSKate Stone     for (const auto &kernel : module->m_kernels) {
27404640cde1SColin Riley       strm.Indent(kernel.m_name.AsCString());
27414640cde1SColin Riley       strm.EOL();
27424640cde1SColin Riley     }
27434640cde1SColin Riley   }
27444640cde1SColin Riley   strm.IndentLess();
27454640cde1SColin Riley }
27464640cde1SColin Riley 
2747a0f08674SEwan Crawford RenderScriptRuntime::AllocationDetails *
2748*b9c1b51eSKate Stone RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) {
2749a0f08674SEwan Crawford   AllocationDetails *alloc = nullptr;
2750a0f08674SEwan Crawford 
2751a0f08674SEwan Crawford   // See if we can find allocation using id as an index;
2752*b9c1b51eSKate Stone   if (alloc_id <= m_allocations.size() && alloc_id != 0 &&
2753*b9c1b51eSKate Stone       m_allocations[alloc_id - 1]->id == alloc_id) {
2754a0f08674SEwan Crawford     alloc = m_allocations[alloc_id - 1].get();
2755a0f08674SEwan Crawford     return alloc;
2756a0f08674SEwan Crawford   }
2757a0f08674SEwan Crawford 
2758a0f08674SEwan Crawford   // Fallback to searching
2759*b9c1b51eSKate Stone   for (const auto &a : m_allocations) {
2760*b9c1b51eSKate Stone     if (a->id == alloc_id) {
2761a0f08674SEwan Crawford       alloc = a.get();
2762a0f08674SEwan Crawford       break;
2763a0f08674SEwan Crawford     }
2764a0f08674SEwan Crawford   }
2765a0f08674SEwan Crawford 
2766*b9c1b51eSKate Stone   if (alloc == nullptr) {
2767*b9c1b51eSKate Stone     strm.Printf("Error: Couldn't find allocation with id matching %" PRIu32,
2768*b9c1b51eSKate Stone                 alloc_id);
2769a0f08674SEwan Crawford     strm.EOL();
2770a0f08674SEwan Crawford   }
2771a0f08674SEwan Crawford 
2772a0f08674SEwan Crawford   return alloc;
2773a0f08674SEwan Crawford }
2774a0f08674SEwan Crawford 
2775*b9c1b51eSKate Stone // Prints the contents of an allocation to the output stream, which may be a
2776*b9c1b51eSKate Stone // file
2777*b9c1b51eSKate Stone bool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr,
2778*b9c1b51eSKate Stone                                          const uint32_t id) {
2779a0f08674SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2780a0f08674SEwan Crawford 
2781a0f08674SEwan Crawford   // Check we can find the desired allocation
2782a0f08674SEwan Crawford   AllocationDetails *alloc = FindAllocByID(strm, id);
2783a0f08674SEwan Crawford   if (!alloc)
2784a0f08674SEwan Crawford     return false; // FindAllocByID() will print error message for us here
2785a0f08674SEwan Crawford 
2786a0f08674SEwan Crawford   if (log)
2787*b9c1b51eSKate Stone     log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__,
2788*b9c1b51eSKate Stone                 *alloc->address.get());
2789a0f08674SEwan Crawford 
2790a0f08674SEwan Crawford   // Check we have information about the allocation, if not calculate it
2791*b9c1b51eSKate Stone   if (alloc->shouldRefresh()) {
2792a0f08674SEwan Crawford     if (log)
2793*b9c1b51eSKate Stone       log->Printf("%s - allocation details not calculated yet, jitting info.",
2794*b9c1b51eSKate Stone                   __FUNCTION__);
2795a0f08674SEwan Crawford 
2796a0f08674SEwan Crawford     // JIT all the allocation information
2797*b9c1b51eSKate Stone     if (!RefreshAllocation(alloc, frame_ptr)) {
2798a0f08674SEwan Crawford       strm.Printf("Error: Couldn't JIT allocation details");
2799a0f08674SEwan Crawford       strm.EOL();
2800a0f08674SEwan Crawford       return false;
2801a0f08674SEwan Crawford     }
2802a0f08674SEwan Crawford   }
2803a0f08674SEwan Crawford 
2804a0f08674SEwan Crawford   // Establish format and size of each data element
2805b3f7f69dSAidan Dodds   const uint32_t vec_size = *alloc->element.type_vec_size.get();
28068b244e21SEwan Crawford   const Element::DataType type = *alloc->element.type.get();
2807a0f08674SEwan Crawford 
2808*b9c1b51eSKate Stone   assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT &&
2809*b9c1b51eSKate Stone          "Invalid allocation type");
2810a0f08674SEwan Crawford 
28112e920715SEwan Crawford   lldb::Format format;
28122e920715SEwan Crawford   if (type >= Element::RS_TYPE_ELEMENT)
28132e920715SEwan Crawford     format = eFormatHex;
28142e920715SEwan Crawford   else
2815*b9c1b51eSKate Stone     format = vec_size == 1
2816*b9c1b51eSKate Stone                  ? static_cast<lldb::Format>(
2817*b9c1b51eSKate Stone                        AllocationDetails::RSTypeToFormat[type][eFormatSingle])
2818*b9c1b51eSKate Stone                  : static_cast<lldb::Format>(
2819*b9c1b51eSKate Stone                        AllocationDetails::RSTypeToFormat[type][eFormatVector]);
2820a0f08674SEwan Crawford 
2821b3f7f69dSAidan Dodds   const uint32_t data_size = *alloc->element.datum_size.get();
2822a0f08674SEwan Crawford 
2823a0f08674SEwan Crawford   if (log)
2824*b9c1b51eSKate Stone     log->Printf("%s - element size %" PRIu32 " bytes, including padding",
2825*b9c1b51eSKate Stone                 __FUNCTION__, data_size);
2826a0f08674SEwan Crawford 
282755232f09SEwan Crawford   // Allocate a buffer to copy data into
282855232f09SEwan Crawford   std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
2829*b9c1b51eSKate Stone   if (!buffer) {
28302e920715SEwan Crawford     strm.Printf("Error: Couldn't read allocation data");
283155232f09SEwan Crawford     strm.EOL();
283255232f09SEwan Crawford     return false;
283355232f09SEwan Crawford   }
283455232f09SEwan Crawford 
2835a0f08674SEwan Crawford   // Calculate stride between rows as there may be padding at end of rows since
2836a0f08674SEwan Crawford   // allocated memory is 16-byte aligned
2837*b9c1b51eSKate Stone   if (!alloc->stride.isValid()) {
2838a0f08674SEwan Crawford     if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension
2839a0f08674SEwan Crawford       alloc->stride = 0;
2840*b9c1b51eSKate Stone     else if (!JITAllocationStride(alloc, frame_ptr)) {
2841a0f08674SEwan Crawford       strm.Printf("Error: Couldn't calculate allocation row stride");
2842a0f08674SEwan Crawford       strm.EOL();
2843a0f08674SEwan Crawford       return false;
2844a0f08674SEwan Crawford     }
2845a0f08674SEwan Crawford   }
2846b3f7f69dSAidan Dodds   const uint32_t stride = *alloc->stride.get();
2847b3f7f69dSAidan Dodds   const uint32_t size = *alloc->size.get(); // Size of whole allocation
2848*b9c1b51eSKate Stone   const uint32_t padding =
2849*b9c1b51eSKate Stone       alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0;
2850a0f08674SEwan Crawford   if (log)
2851*b9c1b51eSKate Stone     log->Printf("%s - stride %" PRIu32 " bytes, size %" PRIu32
2852*b9c1b51eSKate Stone                 " bytes, padding %" PRIu32,
2853b3f7f69dSAidan Dodds                 __FUNCTION__, stride, size, padding);
2854a0f08674SEwan Crawford 
2855a0f08674SEwan Crawford   // Find dimensions used to index loops, so need to be non-zero
2856b3f7f69dSAidan Dodds   uint32_t dim_x = alloc->dimension.get()->dim_1;
2857a0f08674SEwan Crawford   dim_x = dim_x == 0 ? 1 : dim_x;
2858a0f08674SEwan Crawford 
2859b3f7f69dSAidan Dodds   uint32_t dim_y = alloc->dimension.get()->dim_2;
2860a0f08674SEwan Crawford   dim_y = dim_y == 0 ? 1 : dim_y;
2861a0f08674SEwan Crawford 
2862b3f7f69dSAidan Dodds   uint32_t dim_z = alloc->dimension.get()->dim_3;
2863a0f08674SEwan Crawford   dim_z = dim_z == 0 ? 1 : dim_z;
2864a0f08674SEwan Crawford 
286555232f09SEwan Crawford   // Use data extractor to format output
2866*b9c1b51eSKate Stone   const uint32_t archByteSize =
2867*b9c1b51eSKate Stone       GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
2868*b9c1b51eSKate Stone   DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(),
2869*b9c1b51eSKate Stone                            archByteSize);
287055232f09SEwan Crawford 
2871b3f7f69dSAidan Dodds   uint32_t offset = 0;   // Offset in buffer to next element to be printed
2872b3f7f69dSAidan Dodds   uint32_t prev_row = 0; // Offset to the start of the previous row
2873a0f08674SEwan Crawford 
2874a0f08674SEwan Crawford   // Iterate over allocation dimensions, printing results to user
2875a0f08674SEwan Crawford   strm.Printf("Data (X, Y, Z):");
2876*b9c1b51eSKate Stone   for (uint32_t z = 0; z < dim_z; ++z) {
2877*b9c1b51eSKate Stone     for (uint32_t y = 0; y < dim_y; ++y) {
2878a0f08674SEwan Crawford       // Use stride to index start of next row.
2879a0f08674SEwan Crawford       if (!(y == 0 && z == 0))
2880a0f08674SEwan Crawford         offset = prev_row + stride;
2881a0f08674SEwan Crawford       prev_row = offset;
2882a0f08674SEwan Crawford 
2883a0f08674SEwan Crawford       // Print each element in the row individually
2884*b9c1b51eSKate Stone       for (uint32_t x = 0; x < dim_x; ++x) {
2885b3f7f69dSAidan Dodds         strm.Printf("\n(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") = ", x, y, z);
2886*b9c1b51eSKate Stone         if ((type == Element::RS_TYPE_NONE) &&
2887*b9c1b51eSKate Stone             (alloc->element.children.size() > 0) &&
2888*b9c1b51eSKate Stone             (alloc->element.type_name != Element::GetFallbackStructName())) {
28898b244e21SEwan Crawford           // Here we are dumping an Element of struct type.
2890*b9c1b51eSKate Stone           // This is done using expression evaluation with the name of the
2891*b9c1b51eSKate Stone           // struct type and pointer to element.
28928b244e21SEwan Crawford 
2893*b9c1b51eSKate Stone           // Don't print the name of the resulting expression, since this will
2894*b9c1b51eSKate Stone           // be '$[0-9]+'
28958b244e21SEwan Crawford           DumpValueObjectOptions expr_options;
28968b244e21SEwan Crawford           expr_options.SetHideName(true);
28978b244e21SEwan Crawford 
28988b244e21SEwan Crawford           // Setup expression as derefrencing a pointer cast to element address.
2899ea0636b5SEwan Crawford           char expr_char_buffer[jit_max_expr_size];
2900*b9c1b51eSKate Stone           int chars_written =
2901*b9c1b51eSKate Stone               snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64,
2902*b9c1b51eSKate Stone                        alloc->element.type_name.AsCString(),
2903*b9c1b51eSKate Stone                        *alloc->data_ptr.get() + offset);
29048b244e21SEwan Crawford 
2905*b9c1b51eSKate Stone           if (chars_written < 0 || chars_written >= jit_max_expr_size) {
29068b244e21SEwan Crawford             if (log)
2907b3f7f69dSAidan Dodds               log->Printf("%s - error in snprintf().", __FUNCTION__);
29088b244e21SEwan Crawford             continue;
29098b244e21SEwan Crawford           }
29108b244e21SEwan Crawford 
29118b244e21SEwan Crawford           // Evaluate expression
29128b244e21SEwan Crawford           ValueObjectSP expr_result;
2913*b9c1b51eSKate Stone           GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer,
2914*b9c1b51eSKate Stone                                                        frame_ptr, expr_result);
29158b244e21SEwan Crawford 
29168b244e21SEwan Crawford           // Print the results to our stream.
29178b244e21SEwan Crawford           expr_result->Dump(strm, expr_options);
2918*b9c1b51eSKate Stone         } else {
2919*b9c1b51eSKate Stone           alloc_data.Dump(&strm, offset, format, data_size - padding, 1, 1,
2920*b9c1b51eSKate Stone                           LLDB_INVALID_ADDRESS, 0, 0);
29218b244e21SEwan Crawford         }
29228b244e21SEwan Crawford         offset += data_size;
2923a0f08674SEwan Crawford       }
2924a0f08674SEwan Crawford     }
2925a0f08674SEwan Crawford   }
2926a0f08674SEwan Crawford   strm.EOL();
2927a0f08674SEwan Crawford 
2928a0f08674SEwan Crawford   return true;
2929a0f08674SEwan Crawford }
2930a0f08674SEwan Crawford 
2931*b9c1b51eSKate Stone // Function recalculates all our cached information about allocations by jitting
2932*b9c1b51eSKate Stone // the
29330d2bfcfbSEwan Crawford // RS runtime regarding each allocation we know about.
29340d2bfcfbSEwan Crawford // Returns true if all allocations could be recomputed, false otherwise.
2935*b9c1b51eSKate Stone bool RenderScriptRuntime::RecomputeAllAllocations(Stream &strm,
2936*b9c1b51eSKate Stone                                                   StackFrame *frame_ptr) {
29370d2bfcfbSEwan Crawford   bool success = true;
2938*b9c1b51eSKate Stone   for (auto &alloc : m_allocations) {
29390d2bfcfbSEwan Crawford     // JIT current allocation information
2940*b9c1b51eSKate Stone     if (!RefreshAllocation(alloc.get(), frame_ptr)) {
2941*b9c1b51eSKate Stone       strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32
2942*b9c1b51eSKate Stone                   "\n",
2943*b9c1b51eSKate Stone                   alloc->id);
29440d2bfcfbSEwan Crawford       success = false;
29450d2bfcfbSEwan Crawford     }
29460d2bfcfbSEwan Crawford   }
29470d2bfcfbSEwan Crawford 
29480d2bfcfbSEwan Crawford   if (success)
29490d2bfcfbSEwan Crawford     strm.Printf("All allocations successfully recomputed");
29500d2bfcfbSEwan Crawford   strm.EOL();
29510d2bfcfbSEwan Crawford 
29520d2bfcfbSEwan Crawford   return success;
29530d2bfcfbSEwan Crawford }
29540d2bfcfbSEwan Crawford 
2955b649b005SEwan Crawford // Prints information regarding currently loaded allocations.
295615f2bd95SEwan Crawford // These details are gathered by jitting the runtime, which has as latency.
2957*b9c1b51eSKate Stone // Index parameter specifies a single allocation ID to print, or a zero value to
2958*b9c1b51eSKate Stone // print them all
2959*b9c1b51eSKate Stone void RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame *frame_ptr,
2960*b9c1b51eSKate Stone                                           const uint32_t index) {
296115f2bd95SEwan Crawford   strm.Printf("RenderScript Allocations:");
296215f2bd95SEwan Crawford   strm.EOL();
296315f2bd95SEwan Crawford   strm.IndentMore();
296415f2bd95SEwan Crawford 
2965*b9c1b51eSKate Stone   for (auto &alloc : m_allocations) {
2966b649b005SEwan Crawford     // index will only be zero if we want to print all allocations
2967b649b005SEwan Crawford     if (index != 0 && index != alloc->id)
2968b649b005SEwan Crawford       continue;
296915f2bd95SEwan Crawford 
297015f2bd95SEwan Crawford     // JIT current allocation information
2971*b9c1b51eSKate Stone     if (alloc->shouldRefresh() && !RefreshAllocation(alloc.get(), frame_ptr)) {
2972*b9c1b51eSKate Stone       strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32,
2973*b9c1b51eSKate Stone                   alloc->id);
2974b3f7f69dSAidan Dodds       strm.EOL();
297515f2bd95SEwan Crawford       continue;
297615f2bd95SEwan Crawford     }
297715f2bd95SEwan Crawford 
2978b3f7f69dSAidan Dodds     strm.Printf("%" PRIu32 ":", alloc->id);
2979b3f7f69dSAidan Dodds     strm.EOL();
298015f2bd95SEwan Crawford     strm.IndentMore();
298115f2bd95SEwan Crawford 
298215f2bd95SEwan Crawford     strm.Indent("Context: ");
298315f2bd95SEwan Crawford     if (!alloc->context.isValid())
298415f2bd95SEwan Crawford       strm.Printf("unknown\n");
298515f2bd95SEwan Crawford     else
298615f2bd95SEwan Crawford       strm.Printf("0x%" PRIx64 "\n", *alloc->context.get());
298715f2bd95SEwan Crawford 
298815f2bd95SEwan Crawford     strm.Indent("Address: ");
298915f2bd95SEwan Crawford     if (!alloc->address.isValid())
299015f2bd95SEwan Crawford       strm.Printf("unknown\n");
299115f2bd95SEwan Crawford     else
299215f2bd95SEwan Crawford       strm.Printf("0x%" PRIx64 "\n", *alloc->address.get());
299315f2bd95SEwan Crawford 
299415f2bd95SEwan Crawford     strm.Indent("Data pointer: ");
299515f2bd95SEwan Crawford     if (!alloc->data_ptr.isValid())
299615f2bd95SEwan Crawford       strm.Printf("unknown\n");
299715f2bd95SEwan Crawford     else
299815f2bd95SEwan Crawford       strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get());
299915f2bd95SEwan Crawford 
300015f2bd95SEwan Crawford     strm.Indent("Dimensions: ");
300115f2bd95SEwan Crawford     if (!alloc->dimension.isValid())
300215f2bd95SEwan Crawford       strm.Printf("unknown\n");
300315f2bd95SEwan Crawford     else
3004b3f7f69dSAidan Dodds       strm.Printf("(%" PRId32 ", %" PRId32 ", %" PRId32 ")\n",
3005*b9c1b51eSKate Stone                   alloc->dimension.get()->dim_1, alloc->dimension.get()->dim_2,
3006*b9c1b51eSKate Stone                   alloc->dimension.get()->dim_3);
300715f2bd95SEwan Crawford 
300815f2bd95SEwan Crawford     strm.Indent("Data Type: ");
3009*b9c1b51eSKate Stone     if (!alloc->element.type.isValid() ||
3010*b9c1b51eSKate Stone         !alloc->element.type_vec_size.isValid())
301115f2bd95SEwan Crawford       strm.Printf("unknown\n");
3012*b9c1b51eSKate Stone     else {
30138b244e21SEwan Crawford       const int vector_size = *alloc->element.type_vec_size.get();
30142e920715SEwan Crawford       Element::DataType type = *alloc->element.type.get();
301515f2bd95SEwan Crawford 
30168b244e21SEwan Crawford       if (!alloc->element.type_name.IsEmpty())
30178b244e21SEwan Crawford         strm.Printf("%s\n", alloc->element.type_name.AsCString());
3018*b9c1b51eSKate Stone       else {
3019*b9c1b51eSKate Stone         // Enum value isn't monotonous, so doesn't always index
3020*b9c1b51eSKate Stone         // RsDataTypeToString array
30212e920715SEwan Crawford         if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT)
3022*b9c1b51eSKate Stone           type =
3023*b9c1b51eSKate Stone               static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) +
3024b3f7f69dSAidan Dodds                                              Element::RS_TYPE_MATRIX_2X2 + 1);
30252e920715SEwan Crawford 
3026b3f7f69dSAidan Dodds         if (type >= (sizeof(AllocationDetails::RsDataTypeToString) /
3027b3f7f69dSAidan Dodds                      sizeof(AllocationDetails::RsDataTypeToString[0])) ||
3028b3f7f69dSAidan Dodds             vector_size > 4 || vector_size < 1)
302915f2bd95SEwan Crawford           strm.Printf("invalid type\n");
303015f2bd95SEwan Crawford         else
3031*b9c1b51eSKate Stone           strm.Printf(
3032*b9c1b51eSKate Stone               "%s\n",
3033*b9c1b51eSKate Stone               AllocationDetails::RsDataTypeToString[static_cast<uint32_t>(type)]
3034b3f7f69dSAidan Dodds                                                    [vector_size - 1]);
303515f2bd95SEwan Crawford       }
30362e920715SEwan Crawford     }
303715f2bd95SEwan Crawford 
303815f2bd95SEwan Crawford     strm.Indent("Data Kind: ");
30398b244e21SEwan Crawford     if (!alloc->element.type_kind.isValid())
304015f2bd95SEwan Crawford       strm.Printf("unknown\n");
3041*b9c1b51eSKate Stone     else {
30428b244e21SEwan Crawford       const Element::DataKind kind = *alloc->element.type_kind.get();
30438b244e21SEwan Crawford       if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV)
304415f2bd95SEwan Crawford         strm.Printf("invalid kind\n");
304515f2bd95SEwan Crawford       else
3046*b9c1b51eSKate Stone         strm.Printf(
3047*b9c1b51eSKate Stone             "%s\n",
3048*b9c1b51eSKate Stone             AllocationDetails::RsDataKindToString[static_cast<uint32_t>(kind)]);
304915f2bd95SEwan Crawford     }
305015f2bd95SEwan Crawford 
305115f2bd95SEwan Crawford     strm.EOL();
305215f2bd95SEwan Crawford     strm.IndentLess();
305315f2bd95SEwan Crawford   }
305415f2bd95SEwan Crawford   strm.IndentLess();
305515f2bd95SEwan Crawford }
305615f2bd95SEwan Crawford 
30577dc7771cSEwan Crawford // Set breakpoints on every kernel found in RS module
3058*b9c1b51eSKate Stone void RenderScriptRuntime::BreakOnModuleKernels(
3059*b9c1b51eSKate Stone     const RSModuleDescriptorSP rsmodule_sp) {
3060*b9c1b51eSKate Stone   for (const auto &kernel : rsmodule_sp->m_kernels) {
30617dc7771cSEwan Crawford     // Don't set breakpoint on 'root' kernel
30627dc7771cSEwan Crawford     if (strcmp(kernel.m_name.AsCString(), "root") == 0)
30637dc7771cSEwan Crawford       continue;
30647dc7771cSEwan Crawford 
30657dc7771cSEwan Crawford     CreateKernelBreakpoint(kernel.m_name);
30667dc7771cSEwan Crawford   }
30677dc7771cSEwan Crawford }
30687dc7771cSEwan Crawford 
30697dc7771cSEwan Crawford // Method is internally called by the 'kernel breakpoint all' command to
30707dc7771cSEwan Crawford // enable or disable breaking on all kernels.
30717dc7771cSEwan Crawford //
30727dc7771cSEwan Crawford // When do_break is true we want to enable this functionality.
30737dc7771cSEwan Crawford // When do_break is false we want to disable it.
3074*b9c1b51eSKate Stone void RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) {
3075*b9c1b51eSKate Stone   Log *log(
3076*b9c1b51eSKate Stone       GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
30777dc7771cSEwan Crawford 
30787dc7771cSEwan Crawford   InitSearchFilter(target);
30797dc7771cSEwan Crawford 
30807dc7771cSEwan Crawford   // Set breakpoints on all the kernels
3081*b9c1b51eSKate Stone   if (do_break && !m_breakAllKernels) {
30827dc7771cSEwan Crawford     m_breakAllKernels = true;
30837dc7771cSEwan Crawford 
30847dc7771cSEwan Crawford     for (const auto &module : m_rsmodules)
30857dc7771cSEwan Crawford       BreakOnModuleKernels(module);
30867dc7771cSEwan Crawford 
30877dc7771cSEwan Crawford     if (log)
3088*b9c1b51eSKate Stone       log->Printf("%s(True) - breakpoints set on all currently loaded kernels.",
3089*b9c1b51eSKate Stone                   __FUNCTION__);
3090*b9c1b51eSKate Stone   } else if (!do_break &&
3091*b9c1b51eSKate Stone              m_breakAllKernels) // Breakpoints won't be set on any new kernels.
30927dc7771cSEwan Crawford   {
30937dc7771cSEwan Crawford     m_breakAllKernels = false;
30947dc7771cSEwan Crawford 
30957dc7771cSEwan Crawford     if (log)
3096*b9c1b51eSKate Stone       log->Printf("%s(False) - breakpoints no longer automatically set.",
3097*b9c1b51eSKate Stone                   __FUNCTION__);
30987dc7771cSEwan Crawford   }
30997dc7771cSEwan Crawford }
31007dc7771cSEwan Crawford 
31017dc7771cSEwan Crawford // Given the name of a kernel this function creates a breakpoint using our
31027dc7771cSEwan Crawford // own breakpoint resolver, and returns the Breakpoint shared pointer.
31037dc7771cSEwan Crawford BreakpointSP
3104*b9c1b51eSKate Stone RenderScriptRuntime::CreateKernelBreakpoint(const ConstString &name) {
3105*b9c1b51eSKate Stone   Log *log(
3106*b9c1b51eSKate Stone       GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
31077dc7771cSEwan Crawford 
3108*b9c1b51eSKate Stone   if (!m_filtersp) {
31097dc7771cSEwan Crawford     if (log)
3110b3f7f69dSAidan Dodds       log->Printf("%s - error, no breakpoint search filter set.", __FUNCTION__);
31117dc7771cSEwan Crawford     return nullptr;
31127dc7771cSEwan Crawford   }
31137dc7771cSEwan Crawford 
31147dc7771cSEwan Crawford   BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name));
3115*b9c1b51eSKate Stone   BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint(
3116*b9c1b51eSKate Stone       m_filtersp, resolver_sp, false, false, false);
31177dc7771cSEwan Crawford 
3118*b9c1b51eSKate Stone   // Give RS breakpoints a specific name, so the user can manipulate them as a
3119*b9c1b51eSKate Stone   // group.
312054782db7SEwan Crawford   Error err;
312154782db7SEwan Crawford   if (!bp->AddName("RenderScriptKernel", err) && log)
3122*b9c1b51eSKate Stone     log->Printf("%s - error setting break name, '%s'.", __FUNCTION__,
3123*b9c1b51eSKate Stone                 err.AsCString());
312454782db7SEwan Crawford 
31257dc7771cSEwan Crawford   return bp;
31267dc7771cSEwan Crawford }
31277dc7771cSEwan Crawford 
3128*b9c1b51eSKate Stone // Given an expression for a variable this function tries to calculate the
3129*b9c1b51eSKate Stone // variable's value.
3130*b9c1b51eSKate Stone // If this is possible it returns true and sets the uint64_t parameter to the
3131*b9c1b51eSKate Stone // variables unsigned value.
3132018f5a7eSEwan Crawford // Otherwise function returns false.
3133*b9c1b51eSKate Stone bool RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp,
3134*b9c1b51eSKate Stone                                                 const char *var_name,
3135*b9c1b51eSKate Stone                                                 uint64_t &val) {
3136018f5a7eSEwan Crawford   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE));
3137018f5a7eSEwan Crawford   Error error;
3138018f5a7eSEwan Crawford   VariableSP var_sp;
3139018f5a7eSEwan Crawford 
3140018f5a7eSEwan Crawford   // Find variable in stack frame
3141b3f7f69dSAidan Dodds   ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath(
3142b3f7f69dSAidan Dodds       var_name, eNoDynamicValues,
3143*b9c1b51eSKate Stone       StackFrame::eExpressionPathOptionCheckPtrVsMember |
3144*b9c1b51eSKate Stone           StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
3145b3f7f69dSAidan Dodds       var_sp, error));
3146*b9c1b51eSKate Stone   if (!error.Success()) {
3147018f5a7eSEwan Crawford     if (log)
3148*b9c1b51eSKate Stone       log->Printf("%s - error, couldn't find '%s' in frame", __FUNCTION__,
3149*b9c1b51eSKate Stone                   var_name);
3150018f5a7eSEwan Crawford     return false;
3151018f5a7eSEwan Crawford   }
3152018f5a7eSEwan Crawford 
3153b3f7f69dSAidan Dodds   // Find the uint32_t value for the variable
3154018f5a7eSEwan Crawford   bool success = false;
3155018f5a7eSEwan Crawford   val = value_sp->GetValueAsUnsigned(0, &success);
3156*b9c1b51eSKate Stone   if (!success) {
3157018f5a7eSEwan Crawford     if (log)
3158*b9c1b51eSKate Stone       log->Printf("%s - error, couldn't parse '%s' as an uint32_t.",
3159*b9c1b51eSKate Stone                   __FUNCTION__, var_name);
3160018f5a7eSEwan Crawford     return false;
3161018f5a7eSEwan Crawford   }
3162018f5a7eSEwan Crawford 
3163018f5a7eSEwan Crawford   return true;
3164018f5a7eSEwan Crawford }
3165018f5a7eSEwan Crawford 
3166*b9c1b51eSKate Stone // Function attempts to find the current coordinate of a kernel invocation by
3167*b9c1b51eSKate Stone // investigating the
3168*b9c1b51eSKate Stone // values of frame variables in the .expand function. These coordinates are
3169*b9c1b51eSKate Stone // returned via the coord
3170*b9c1b51eSKate Stone // array reference parameter. Returns true if the coordinates could be found,
3171*b9c1b51eSKate Stone // and false otherwise.
3172*b9c1b51eSKate Stone bool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord,
3173*b9c1b51eSKate Stone                                               Thread *thread_ptr) {
31741e05c3bcSGreg Clayton   static const std::string s_runtimeExpandSuffix(".expand");
3175*b9c1b51eSKate Stone   static const std::array<const char *, 3> s_runtimeCoordVars{
3176*b9c1b51eSKate Stone       {"rsIndex", "p->current.y", "p->current.z"}};
31771e05c3bcSGreg Clayton 
31784f8817c2SEwan Crawford   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE));
31794f8817c2SEwan Crawford 
3180*b9c1b51eSKate Stone   if (!thread_ptr) {
31814f8817c2SEwan Crawford     if (log)
31824f8817c2SEwan Crawford       log->Printf("%s - Error, No thread pointer", __FUNCTION__);
31834f8817c2SEwan Crawford 
31844f8817c2SEwan Crawford     return false;
31854f8817c2SEwan Crawford   }
31864f8817c2SEwan Crawford 
3187*b9c1b51eSKate Stone   // Walk the call stack looking for a function whose name has the suffix
3188*b9c1b51eSKate Stone   // '.expand'
31894f8817c2SEwan Crawford   // and contains the variables we're looking for.
3190*b9c1b51eSKate Stone   for (uint32_t i = 0; i < thread_ptr->GetStackFrameCount(); ++i) {
31914f8817c2SEwan Crawford     if (!thread_ptr->SetSelectedFrameByIndex(i))
31924f8817c2SEwan Crawford       continue;
31934f8817c2SEwan Crawford 
31944f8817c2SEwan Crawford     StackFrameSP frame_sp = thread_ptr->GetSelectedFrame();
31954f8817c2SEwan Crawford     if (!frame_sp)
31964f8817c2SEwan Crawford       continue;
31974f8817c2SEwan Crawford 
31984f8817c2SEwan Crawford     // Find the function name
31994f8817c2SEwan Crawford     const SymbolContext sym_ctx = frame_sp->GetSymbolContext(false);
32004f8817c2SEwan Crawford     const char *func_name_cstr = sym_ctx.GetFunctionName().AsCString();
32014f8817c2SEwan Crawford     if (!func_name_cstr)
32024f8817c2SEwan Crawford       continue;
32034f8817c2SEwan Crawford 
32044f8817c2SEwan Crawford     if (log)
3205*b9c1b51eSKate Stone       log->Printf("%s - Inspecting function '%s'", __FUNCTION__,
3206*b9c1b51eSKate Stone                   func_name_cstr);
32074f8817c2SEwan Crawford 
32084f8817c2SEwan Crawford     // Check if function name has .expand suffix
32094f8817c2SEwan Crawford     std::string func_name(func_name_cstr);
3210*b9c1b51eSKate Stone     const int length_difference =
3211*b9c1b51eSKate Stone         func_name.length() - s_runtimeExpandSuffix.length();
32124f8817c2SEwan Crawford     if (length_difference <= 0)
32134f8817c2SEwan Crawford       continue;
32144f8817c2SEwan Crawford 
3215*b9c1b51eSKate Stone     const int32_t has_expand_suffix =
3216*b9c1b51eSKate Stone         func_name.compare(length_difference, s_runtimeExpandSuffix.length(),
32171e05c3bcSGreg Clayton                           s_runtimeExpandSuffix);
32184f8817c2SEwan Crawford 
32194f8817c2SEwan Crawford     if (has_expand_suffix != 0)
32204f8817c2SEwan Crawford       continue;
32214f8817c2SEwan Crawford 
32224f8817c2SEwan Crawford     if (log)
3223*b9c1b51eSKate Stone       log->Printf("%s - Found .expand function '%s'", __FUNCTION__,
3224*b9c1b51eSKate Stone                   func_name_cstr);
32254f8817c2SEwan Crawford 
3226*b9c1b51eSKate Stone     // Get values for variables in .expand frame that tell us the current kernel
3227*b9c1b51eSKate Stone     // invocation
32284f8817c2SEwan Crawford     bool found_coord_variables = true;
32291e05c3bcSGreg Clayton     assert(s_runtimeCoordVars.size() == coord.size());
32304f8817c2SEwan Crawford 
3231*b9c1b51eSKate Stone     for (uint32_t i = 0; i < coord.size(); ++i) {
32324f8817c2SEwan Crawford       uint64_t value = 0;
3233*b9c1b51eSKate Stone       if (!GetFrameVarAsUnsigned(frame_sp, s_runtimeCoordVars[i], value)) {
32344f8817c2SEwan Crawford         found_coord_variables = false;
32354f8817c2SEwan Crawford         break;
32364f8817c2SEwan Crawford       }
32374f8817c2SEwan Crawford       coord[i] = value;
32384f8817c2SEwan Crawford     }
32394f8817c2SEwan Crawford 
32404f8817c2SEwan Crawford     if (found_coord_variables)
32414f8817c2SEwan Crawford       return true;
32424f8817c2SEwan Crawford   }
32434f8817c2SEwan Crawford   return false;
32444f8817c2SEwan Crawford }
32454f8817c2SEwan Crawford 
3246*b9c1b51eSKate Stone // Callback when a kernel breakpoint hits and we're looking for a specific
3247*b9c1b51eSKate Stone // coordinate.
3248*b9c1b51eSKate Stone // Baton parameter contains a pointer to the target coordinate we want to break
3249*b9c1b51eSKate Stone // on.
3250*b9c1b51eSKate Stone // Function then checks the .expand frame for the current coordinate and breaks
3251*b9c1b51eSKate Stone // to user if it matches.
3252018f5a7eSEwan Crawford // Parameter 'break_id' is the id of the Breakpoint which made the callback.
3253018f5a7eSEwan Crawford // Parameter 'break_loc_id' is the id for the BreakpointLocation which was hit,
3254018f5a7eSEwan Crawford // a single logical breakpoint can have multiple addresses.
3255*b9c1b51eSKate Stone bool RenderScriptRuntime::KernelBreakpointHit(void *baton,
3256*b9c1b51eSKate Stone                                               StoppointCallbackContext *ctx,
3257*b9c1b51eSKate Stone                                               user_id_t break_id,
3258*b9c1b51eSKate Stone                                               user_id_t break_loc_id) {
3259*b9c1b51eSKate Stone   Log *log(
3260*b9c1b51eSKate Stone       GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
3261018f5a7eSEwan Crawford 
3262*b9c1b51eSKate Stone   assert(baton &&
3263*b9c1b51eSKate Stone          "Error: null baton in conditional kernel breakpoint callback");
3264018f5a7eSEwan Crawford 
3265018f5a7eSEwan Crawford   // Coordinate we want to stop on
32664f8817c2SEwan Crawford   const uint32_t *target_coord = static_cast<const uint32_t *>(baton);
3267018f5a7eSEwan Crawford 
3268018f5a7eSEwan Crawford   if (log)
3269*b9c1b51eSKate Stone     log->Printf("%s - Break ID %" PRIu64 ", (%" PRIu32 ", %" PRIu32 ", %" PRIu32
3270*b9c1b51eSKate Stone                 ")",
3271*b9c1b51eSKate Stone                 __FUNCTION__, break_id, target_coord[0], target_coord[1],
3272*b9c1b51eSKate Stone                 target_coord[2]);
3273018f5a7eSEwan Crawford 
32744f8817c2SEwan Crawford   // Select current thread
3275018f5a7eSEwan Crawford   ExecutionContext context(ctx->exe_ctx_ref);
32764f8817c2SEwan Crawford   Thread *thread_ptr = context.GetThreadPtr();
32774f8817c2SEwan Crawford   assert(thread_ptr && "Null thread pointer");
32784f8817c2SEwan Crawford 
32794f8817c2SEwan Crawford   // Find current kernel invocation from .expand frame variables
32804f8817c2SEwan Crawford   RSCoordinate current_coord{}; // Zero initialise array
3281*b9c1b51eSKate Stone   if (!GetKernelCoordinate(current_coord, thread_ptr)) {
3282018f5a7eSEwan Crawford     if (log)
3283*b9c1b51eSKate Stone       log->Printf("%s - Error, couldn't select .expand stack frame",
3284*b9c1b51eSKate Stone                   __FUNCTION__);
3285018f5a7eSEwan Crawford     return false;
3286018f5a7eSEwan Crawford   }
3287018f5a7eSEwan Crawford 
3288018f5a7eSEwan Crawford   if (log)
3289*b9c1b51eSKate Stone     log->Printf("%s - (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", __FUNCTION__,
3290*b9c1b51eSKate Stone                 current_coord[0], current_coord[1], current_coord[2]);
3291018f5a7eSEwan Crawford 
3292*b9c1b51eSKate Stone   // Check if the current kernel invocation coordinate matches our target
3293*b9c1b51eSKate Stone   // coordinate
3294b3f7f69dSAidan Dodds   if (current_coord[0] == target_coord[0] &&
3295b3f7f69dSAidan Dodds       current_coord[1] == target_coord[1] &&
3296*b9c1b51eSKate Stone       current_coord[2] == target_coord[2]) {
3297018f5a7eSEwan Crawford     if (log)
3298*b9c1b51eSKate Stone       log->Printf("%s, BREAKING (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")",
3299*b9c1b51eSKate Stone                   __FUNCTION__, current_coord[0], current_coord[1],
3300*b9c1b51eSKate Stone                   current_coord[2]);
3301018f5a7eSEwan Crawford 
3302*b9c1b51eSKate Stone     BreakpointSP breakpoint_sp =
3303*b9c1b51eSKate Stone         context.GetTargetPtr()->GetBreakpointByID(break_id);
3304*b9c1b51eSKate Stone     assert(breakpoint_sp != nullptr &&
3305*b9c1b51eSKate Stone            "Error: Couldn't find breakpoint matching break id for callback");
3306*b9c1b51eSKate Stone     breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint
3307*b9c1b51eSKate Stone                                       // should only be hit once.
3308018f5a7eSEwan Crawford     return true;
3309018f5a7eSEwan Crawford   }
3310018f5a7eSEwan Crawford 
3311018f5a7eSEwan Crawford   // No match on coordinate
3312018f5a7eSEwan Crawford   return false;
3313018f5a7eSEwan Crawford }
3314018f5a7eSEwan Crawford 
3315*b9c1b51eSKate Stone // Tries to set a breakpoint on the start of a kernel, resolved using the kernel
3316*b9c1b51eSKate Stone // name.
3317*b9c1b51eSKate Stone // Argument 'coords', represents a three dimensional coordinate which can be
3318*b9c1b51eSKate Stone // used to specify
3319*b9c1b51eSKate Stone // a single kernel instance to break on. If this is set then we add a callback
3320*b9c1b51eSKate Stone // to the breakpoint.
3321*b9c1b51eSKate Stone void RenderScriptRuntime::PlaceBreakpointOnKernel(
3322*b9c1b51eSKate Stone     Stream &strm, const char *name, const std::array<int, 3> coords,
3323*b9c1b51eSKate Stone     Error &error, TargetSP target) {
3324*b9c1b51eSKate Stone   if (!name) {
33254640cde1SColin Riley     error.SetErrorString("invalid kernel name");
33264640cde1SColin Riley     return;
33274640cde1SColin Riley   }
33284640cde1SColin Riley 
33297dc7771cSEwan Crawford   InitSearchFilter(target);
333098156583SEwan Crawford 
33314640cde1SColin Riley   ConstString kernel_name(name);
33327dc7771cSEwan Crawford   BreakpointSP bp = CreateKernelBreakpoint(kernel_name);
3333018f5a7eSEwan Crawford 
3334018f5a7eSEwan Crawford   // We have a conditional breakpoint on a specific coordinate
3335*b9c1b51eSKate Stone   if (coords[0] != -1) {
3336*b9c1b51eSKate Stone     strm.Printf("Conditional kernel breakpoint on coordinate %" PRId32
3337*b9c1b51eSKate Stone                 ", %" PRId32 ", %" PRId32,
3338b3f7f69dSAidan Dodds                 coords[0], coords[1], coords[2]);
3339018f5a7eSEwan Crawford     strm.EOL();
3340018f5a7eSEwan Crawford 
3341018f5a7eSEwan Crawford     // Allocate memory for the baton, and copy over coordinate
33424f8817c2SEwan Crawford     uint32_t *baton = new uint32_t[coords.size()];
3343*b9c1b51eSKate Stone     baton[0] = coords[0];
3344*b9c1b51eSKate Stone     baton[1] = coords[1];
3345*b9c1b51eSKate Stone     baton[2] = coords[2];
3346018f5a7eSEwan Crawford 
3347018f5a7eSEwan Crawford     // Create a callback that will be invoked every time the breakpoint is hit.
3348*b9c1b51eSKate Stone     // The baton object passed to the handler is the target coordinate we want
3349*b9c1b51eSKate Stone     // to break on.
3350018f5a7eSEwan Crawford     bp->SetCallback(KernelBreakpointHit, baton, true);
3351018f5a7eSEwan Crawford 
3352*b9c1b51eSKate Stone     // Store a shared pointer to the baton, so the memory will eventually be
3353*b9c1b51eSKate Stone     // cleaned up after destruction
33544f8817c2SEwan Crawford     m_conditional_breaks[bp->GetID()] = std::shared_ptr<uint32_t>(baton);
3355018f5a7eSEwan Crawford   }
3356018f5a7eSEwan Crawford 
335798156583SEwan Crawford   if (bp)
335898156583SEwan Crawford     bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false);
33594640cde1SColin Riley }
33604640cde1SColin Riley 
3361*b9c1b51eSKate Stone void RenderScriptRuntime::DumpModules(Stream &strm) const {
33625ec532a9SColin Riley   strm.Printf("RenderScript Modules:");
33635ec532a9SColin Riley   strm.EOL();
33645ec532a9SColin Riley   strm.IndentMore();
3365*b9c1b51eSKate Stone   for (const auto &module : m_rsmodules) {
33664640cde1SColin Riley     module->Dump(strm);
33675ec532a9SColin Riley   }
33685ec532a9SColin Riley   strm.IndentLess();
33695ec532a9SColin Riley }
33705ec532a9SColin Riley 
337178f339d1SEwan Crawford RenderScriptRuntime::ScriptDetails *
3372*b9c1b51eSKate Stone RenderScriptRuntime::LookUpScript(addr_t address, bool create) {
3373*b9c1b51eSKate Stone   for (const auto &s : m_scripts) {
337478f339d1SEwan Crawford     if (s->script.isValid())
337578f339d1SEwan Crawford       if (*s->script == address)
337678f339d1SEwan Crawford         return s.get();
337778f339d1SEwan Crawford   }
3378*b9c1b51eSKate Stone   if (create) {
337978f339d1SEwan Crawford     std::unique_ptr<ScriptDetails> s(new ScriptDetails);
338078f339d1SEwan Crawford     s->script = address;
338178f339d1SEwan Crawford     m_scripts.push_back(std::move(s));
3382d10ca9deSEwan Crawford     return m_scripts.back().get();
338378f339d1SEwan Crawford   }
338478f339d1SEwan Crawford   return nullptr;
338578f339d1SEwan Crawford }
338678f339d1SEwan Crawford 
338778f339d1SEwan Crawford RenderScriptRuntime::AllocationDetails *
3388*b9c1b51eSKate Stone RenderScriptRuntime::LookUpAllocation(addr_t address) {
3389*b9c1b51eSKate Stone   for (const auto &a : m_allocations) {
339078f339d1SEwan Crawford     if (a->address.isValid())
339178f339d1SEwan Crawford       if (*a->address == address)
339278f339d1SEwan Crawford         return a.get();
339378f339d1SEwan Crawford   }
33945d057637SLuke Drummond   return nullptr;
33955d057637SLuke Drummond }
33965d057637SLuke Drummond 
33975d057637SLuke Drummond RenderScriptRuntime::AllocationDetails *
3398*b9c1b51eSKate Stone RenderScriptRuntime::CreateAllocation(addr_t address) {
33995d057637SLuke Drummond   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
34005d057637SLuke Drummond 
34015d057637SLuke Drummond   // Remove any previous allocation which contains the same address
34025d057637SLuke Drummond   auto it = m_allocations.begin();
3403*b9c1b51eSKate Stone   while (it != m_allocations.end()) {
3404*b9c1b51eSKate Stone     if (*((*it)->address) == address) {
34055d057637SLuke Drummond       if (log)
3406*b9c1b51eSKate Stone         log->Printf("%s - Removing allocation id: %d, address: 0x%" PRIx64,
3407*b9c1b51eSKate Stone                     __FUNCTION__, (*it)->id, address);
34085d057637SLuke Drummond 
34095d057637SLuke Drummond       it = m_allocations.erase(it);
3410*b9c1b51eSKate Stone     } else {
34115d057637SLuke Drummond       it++;
34125d057637SLuke Drummond     }
34135d057637SLuke Drummond   }
34145d057637SLuke Drummond 
341578f339d1SEwan Crawford   std::unique_ptr<AllocationDetails> a(new AllocationDetails);
341678f339d1SEwan Crawford   a->address = address;
341778f339d1SEwan Crawford   m_allocations.push_back(std::move(a));
3418d10ca9deSEwan Crawford   return m_allocations.back().get();
341978f339d1SEwan Crawford }
342078f339d1SEwan Crawford 
3421*b9c1b51eSKate Stone void RSModuleDescriptor::Dump(Stream &strm) const {
34225ec532a9SColin Riley   strm.Indent();
34235ec532a9SColin Riley   m_module->GetFileSpec().Dump(&strm);
3424*b9c1b51eSKate Stone   if (m_module->GetNumCompileUnits()) {
34254640cde1SColin Riley     strm.Indent("Debug info loaded.");
3426*b9c1b51eSKate Stone   } else {
34274640cde1SColin Riley     strm.Indent("Debug info does not exist.");
34284640cde1SColin Riley   }
34295ec532a9SColin Riley   strm.EOL();
34305ec532a9SColin Riley   strm.IndentMore();
34315ec532a9SColin Riley   strm.Indent();
3432189598edSColin Riley   strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size()));
34335ec532a9SColin Riley   strm.EOL();
34345ec532a9SColin Riley   strm.IndentMore();
3435*b9c1b51eSKate Stone   for (const auto &global : m_globals) {
34365ec532a9SColin Riley     global.Dump(strm);
34375ec532a9SColin Riley   }
34385ec532a9SColin Riley   strm.IndentLess();
34395ec532a9SColin Riley   strm.Indent();
3440189598edSColin Riley   strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size()));
34415ec532a9SColin Riley   strm.EOL();
34425ec532a9SColin Riley   strm.IndentMore();
3443*b9c1b51eSKate Stone   for (const auto &kernel : m_kernels) {
34445ec532a9SColin Riley     kernel.Dump(strm);
34455ec532a9SColin Riley   }
34464640cde1SColin Riley   strm.Printf("Pragmas: %" PRIu64, static_cast<uint64_t>(m_pragmas.size()));
34474640cde1SColin Riley   strm.EOL();
34484640cde1SColin Riley   strm.IndentMore();
3449*b9c1b51eSKate Stone   for (const auto &key_val : m_pragmas) {
34504640cde1SColin Riley     strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str());
34514640cde1SColin Riley     strm.EOL();
34524640cde1SColin Riley   }
34535ec532a9SColin Riley   strm.IndentLess(4);
34545ec532a9SColin Riley }
34555ec532a9SColin Riley 
3456*b9c1b51eSKate Stone void RSGlobalDescriptor::Dump(Stream &strm) const {
34575ec532a9SColin Riley   strm.Indent(m_name.AsCString());
34584640cde1SColin Riley   VariableList var_list;
34594640cde1SColin Riley   m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list);
3460*b9c1b51eSKate Stone   if (var_list.GetSize() == 1) {
34614640cde1SColin Riley     auto var = var_list.GetVariableAtIndex(0);
34624640cde1SColin Riley     auto type = var->GetType();
3463*b9c1b51eSKate Stone     if (type) {
34644640cde1SColin Riley       strm.Printf(" - ");
34654640cde1SColin Riley       type->DumpTypeName(&strm);
3466*b9c1b51eSKate Stone     } else {
34674640cde1SColin Riley       strm.Printf(" - Unknown Type");
34684640cde1SColin Riley     }
3469*b9c1b51eSKate Stone   } else {
34704640cde1SColin Riley     strm.Printf(" - variable identified, but not found in binary");
3471*b9c1b51eSKate Stone     const Symbol *s = m_module->m_module->FindFirstSymbolWithNameAndType(
3472*b9c1b51eSKate Stone         m_name, eSymbolTypeData);
3473*b9c1b51eSKate Stone     if (s) {
34744640cde1SColin Riley       strm.Printf(" (symbol exists) ");
34754640cde1SColin Riley     }
34764640cde1SColin Riley   }
34774640cde1SColin Riley 
34785ec532a9SColin Riley   strm.EOL();
34795ec532a9SColin Riley }
34805ec532a9SColin Riley 
3481*b9c1b51eSKate Stone void RSKernelDescriptor::Dump(Stream &strm) const {
34825ec532a9SColin Riley   strm.Indent(m_name.AsCString());
34835ec532a9SColin Riley   strm.EOL();
34845ec532a9SColin Riley }
34855ec532a9SColin Riley 
3486*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed {
34875ec532a9SColin Riley public:
34885ec532a9SColin Riley   CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter)
3489*b9c1b51eSKate Stone       : CommandObjectParsed(
3490*b9c1b51eSKate Stone             interpreter, "renderscript module dump",
3491*b9c1b51eSKate Stone             "Dumps renderscript specific information for all modules.",
3492*b9c1b51eSKate Stone             "renderscript module dump",
3493*b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
34945ec532a9SColin Riley 
3495222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeModuleDump() override = default;
34965ec532a9SColin Riley 
3497*b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
34985ec532a9SColin Riley     RenderScriptRuntime *runtime =
3499*b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3500*b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
35015ec532a9SColin Riley     runtime->DumpModules(result.GetOutputStream());
35025ec532a9SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
35035ec532a9SColin Riley     return true;
35045ec532a9SColin Riley   }
35055ec532a9SColin Riley };
35065ec532a9SColin Riley 
3507*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword {
35085ec532a9SColin Riley public:
35095ec532a9SColin Riley   CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter)
3510*b9c1b51eSKate Stone       : CommandObjectMultiword(interpreter, "renderscript module",
3511*b9c1b51eSKate Stone                                "Commands that deal with RenderScript modules.",
3512*b9c1b51eSKate Stone                                nullptr) {
3513*b9c1b51eSKate Stone     LoadSubCommand(
3514*b9c1b51eSKate Stone         "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump(
3515*b9c1b51eSKate Stone                     interpreter)));
35165ec532a9SColin Riley   }
35175ec532a9SColin Riley 
3518222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeModule() override = default;
35195ec532a9SColin Riley };
35205ec532a9SColin Riley 
3521*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed {
35224640cde1SColin Riley public:
35234640cde1SColin Riley   CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter)
3524*b9c1b51eSKate Stone       : CommandObjectParsed(
3525*b9c1b51eSKate Stone             interpreter, "renderscript kernel list",
3526b3f7f69dSAidan Dodds             "Lists renderscript kernel names and associated script resources.",
3527*b9c1b51eSKate Stone             "renderscript kernel list",
3528*b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
35294640cde1SColin Riley 
3530222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelList() override = default;
35314640cde1SColin Riley 
3532*b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
35334640cde1SColin Riley     RenderScriptRuntime *runtime =
3534*b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3535*b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
35364640cde1SColin Riley     runtime->DumpKernels(result.GetOutputStream());
35374640cde1SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
35384640cde1SColin Riley     return true;
35394640cde1SColin Riley   }
35404640cde1SColin Riley };
35414640cde1SColin Riley 
3542*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpointSet
3543*b9c1b51eSKate Stone     : public CommandObjectParsed {
35444640cde1SColin Riley public:
3545*b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelBreakpointSet(
3546*b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3547*b9c1b51eSKate Stone       : CommandObjectParsed(
3548*b9c1b51eSKate Stone             interpreter, "renderscript kernel breakpoint set",
3549b3f7f69dSAidan Dodds             "Sets a breakpoint on a renderscript kernel.",
3550b3f7f69dSAidan Dodds             "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]",
3551*b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
3552*b9c1b51eSKate Stone                 eCommandProcessMustBePaused),
3553*b9c1b51eSKate Stone         m_options() {}
35544640cde1SColin Riley 
3555222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default;
3556222b937cSEugene Zelenko 
3557*b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
3558018f5a7eSEwan Crawford 
3559*b9c1b51eSKate Stone   class CommandOptions : public Options {
3560018f5a7eSEwan Crawford   public:
3561e1cfbc79STodd Fiala     CommandOptions() : Options() {}
3562018f5a7eSEwan Crawford 
3563222b937cSEugene Zelenko     ~CommandOptions() override = default;
3564018f5a7eSEwan Crawford 
3565*b9c1b51eSKate Stone     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
3566*b9c1b51eSKate Stone                          ExecutionContext *execution_context) override {
3567018f5a7eSEwan Crawford       Error error;
3568018f5a7eSEwan Crawford       const int short_option = m_getopt_table[option_idx].val;
3569018f5a7eSEwan Crawford 
3570*b9c1b51eSKate Stone       switch (short_option) {
3571018f5a7eSEwan Crawford       case 'c':
3572018f5a7eSEwan Crawford         if (!ParseCoordinate(option_arg))
3573*b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
3574*b9c1b51eSKate Stone               "Couldn't parse coordinate '%s', should be in format 'x,y,z'.",
3575b3f7f69dSAidan Dodds               option_arg);
3576018f5a7eSEwan Crawford         break;
3577018f5a7eSEwan Crawford       default:
3578*b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
3579*b9c1b51eSKate Stone                                        short_option);
3580018f5a7eSEwan Crawford         break;
3581018f5a7eSEwan Crawford       }
3582018f5a7eSEwan Crawford       return error;
3583018f5a7eSEwan Crawford     }
3584018f5a7eSEwan Crawford 
3585018f5a7eSEwan Crawford     // -c takes an argument of the form 'num[,num][,num]'.
3586018f5a7eSEwan Crawford     // Where 'id_cstr' is this argument with the whitespace trimmed.
3587018f5a7eSEwan Crawford     // Missing coordinates are defaulted to zero.
3588*b9c1b51eSKate Stone     bool ParseCoordinate(const char *id_cstr) {
3589018f5a7eSEwan Crawford       RegularExpression regex;
3590018f5a7eSEwan Crawford       RegularExpression::Match regex_match(3);
3591018f5a7eSEwan Crawford 
3592018f5a7eSEwan Crawford       bool matched = false;
3593*b9c1b51eSKate Stone       if (regex.Compile("^([0-9]+),([0-9]+),([0-9]+)$") &&
3594*b9c1b51eSKate Stone           regex.Execute(id_cstr, &regex_match))
3595018f5a7eSEwan Crawford         matched = true;
3596*b9c1b51eSKate Stone       else if (regex.Compile("^([0-9]+),([0-9]+)$") &&
3597*b9c1b51eSKate Stone                regex.Execute(id_cstr, &regex_match))
3598018f5a7eSEwan Crawford         matched = true;
3599*b9c1b51eSKate Stone       else if (regex.Compile("^([0-9]+)$") &&
3600*b9c1b51eSKate Stone                regex.Execute(id_cstr, &regex_match))
3601018f5a7eSEwan Crawford         matched = true;
3602*b9c1b51eSKate Stone       for (uint32_t i = 0; i < 3; i++) {
3603018f5a7eSEwan Crawford         std::string group;
3604018f5a7eSEwan Crawford         if (regex_match.GetMatchAtIndex(id_cstr, i + 1, group))
3605b3f7f69dSAidan Dodds           m_coord[i] = (uint32_t)strtoul(group.c_str(), nullptr, 0);
3606018f5a7eSEwan Crawford         else
3607018f5a7eSEwan Crawford           m_coord[i] = 0;
3608018f5a7eSEwan Crawford       }
3609018f5a7eSEwan Crawford       return matched;
3610018f5a7eSEwan Crawford     }
3611018f5a7eSEwan Crawford 
3612*b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
3613018f5a7eSEwan Crawford       // -1 means the -c option hasn't been set
3614018f5a7eSEwan Crawford       m_coord[0] = -1;
3615018f5a7eSEwan Crawford       m_coord[1] = -1;
3616018f5a7eSEwan Crawford       m_coord[2] = -1;
3617018f5a7eSEwan Crawford     }
3618018f5a7eSEwan Crawford 
3619*b9c1b51eSKate Stone     const OptionDefinition *GetDefinitions() override { return g_option_table; }
3620018f5a7eSEwan Crawford 
3621018f5a7eSEwan Crawford     static OptionDefinition g_option_table[];
3622018f5a7eSEwan Crawford     std::array<int, 3> m_coord;
3623018f5a7eSEwan Crawford   };
3624018f5a7eSEwan Crawford 
3625*b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
36264640cde1SColin Riley     const size_t argc = command.GetArgumentCount();
3627*b9c1b51eSKate Stone     if (argc < 1) {
3628*b9c1b51eSKate Stone       result.AppendErrorWithFormat(
3629*b9c1b51eSKate Stone           "'%s' takes 1 argument of kernel name, and an optional coordinate.",
3630b3f7f69dSAidan Dodds           m_cmd_name.c_str());
3631018f5a7eSEwan Crawford       result.SetStatus(eReturnStatusFailed);
3632018f5a7eSEwan Crawford       return false;
3633018f5a7eSEwan Crawford     }
3634018f5a7eSEwan Crawford 
36354640cde1SColin Riley     RenderScriptRuntime *runtime =
3636*b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3637*b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
36384640cde1SColin Riley 
36394640cde1SColin Riley     Error error;
3640*b9c1b51eSKate Stone     runtime->PlaceBreakpointOnKernel(
3641*b9c1b51eSKate Stone         result.GetOutputStream(), command.GetArgumentAtIndex(0),
3642*b9c1b51eSKate Stone         m_options.m_coord, error, m_exe_ctx.GetTargetSP());
36434640cde1SColin Riley 
3644*b9c1b51eSKate Stone     if (error.Success()) {
36454640cde1SColin Riley       result.AppendMessage("Breakpoint(s) created");
36464640cde1SColin Riley       result.SetStatus(eReturnStatusSuccessFinishResult);
36474640cde1SColin Riley       return true;
36484640cde1SColin Riley     }
36494640cde1SColin Riley     result.SetStatus(eReturnStatusFailed);
36504640cde1SColin Riley     result.AppendErrorWithFormat("Error: %s", error.AsCString());
36514640cde1SColin Riley     return false;
36524640cde1SColin Riley   }
36534640cde1SColin Riley 
3654018f5a7eSEwan Crawford private:
3655018f5a7eSEwan Crawford   CommandOptions m_options;
36564640cde1SColin Riley };
36574640cde1SColin Riley 
3658*b9c1b51eSKate Stone OptionDefinition CommandObjectRenderScriptRuntimeKernelBreakpointSet::
3659*b9c1b51eSKate Stone     CommandOptions::g_option_table[] = {
3660*b9c1b51eSKate Stone         {LLDB_OPT_SET_1, false, "coordinate", 'c',
3661*b9c1b51eSKate Stone          OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeValue,
3662*b9c1b51eSKate Stone          "Set a breakpoint on a single invocation of the kernel with specified "
3663*b9c1b51eSKate Stone          "coordinate.\n"
3664*b9c1b51eSKate Stone          "Coordinate takes the form 'x[,y][,z] where x,y,z are positive "
3665*b9c1b51eSKate Stone          "integers representing kernel dimensions. "
3666018f5a7eSEwan Crawford          "Any unset dimensions will be defaulted to zero."},
3667b3f7f69dSAidan Dodds         {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}};
3668018f5a7eSEwan Crawford 
3669*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpointAll
3670*b9c1b51eSKate Stone     : public CommandObjectParsed {
36717dc7771cSEwan Crawford public:
3672*b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelBreakpointAll(
3673*b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3674b3f7f69dSAidan Dodds       : CommandObjectParsed(
3675b3f7f69dSAidan Dodds             interpreter, "renderscript kernel breakpoint all",
3676*b9c1b51eSKate Stone             "Automatically sets a breakpoint on all renderscript kernels that "
3677*b9c1b51eSKate Stone             "are or will be loaded.\n"
3678*b9c1b51eSKate Stone             "Disabling option means breakpoints will no longer be set on any "
3679*b9c1b51eSKate Stone             "kernels loaded in the future, "
36807dc7771cSEwan Crawford             "but does not remove currently set breakpoints.",
36817dc7771cSEwan Crawford             "renderscript kernel breakpoint all <enable/disable>",
3682*b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
3683*b9c1b51eSKate Stone                 eCommandProcessMustBePaused) {}
36847dc7771cSEwan Crawford 
3685222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default;
36867dc7771cSEwan Crawford 
3687*b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
36887dc7771cSEwan Crawford     const size_t argc = command.GetArgumentCount();
3689*b9c1b51eSKate Stone     if (argc != 1) {
3690*b9c1b51eSKate Stone       result.AppendErrorWithFormat(
3691*b9c1b51eSKate Stone           "'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str());
36927dc7771cSEwan Crawford       result.SetStatus(eReturnStatusFailed);
36937dc7771cSEwan Crawford       return false;
36947dc7771cSEwan Crawford     }
36957dc7771cSEwan Crawford 
3696b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
3697*b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3698*b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
36997dc7771cSEwan Crawford 
37007dc7771cSEwan Crawford     bool do_break = false;
37017dc7771cSEwan Crawford     const char *argument = command.GetArgumentAtIndex(0);
3702*b9c1b51eSKate Stone     if (strcmp(argument, "enable") == 0) {
37037dc7771cSEwan Crawford       do_break = true;
37047dc7771cSEwan Crawford       result.AppendMessage("Breakpoints will be set on all kernels.");
3705*b9c1b51eSKate Stone     } else if (strcmp(argument, "disable") == 0) {
37067dc7771cSEwan Crawford       do_break = false;
37077dc7771cSEwan Crawford       result.AppendMessage("Breakpoints will not be set on any new kernels.");
3708*b9c1b51eSKate Stone     } else {
3709*b9c1b51eSKate Stone       result.AppendErrorWithFormat(
3710*b9c1b51eSKate Stone           "Argument must be either 'enable' or 'disable'");
37117dc7771cSEwan Crawford       result.SetStatus(eReturnStatusFailed);
37127dc7771cSEwan Crawford       return false;
37137dc7771cSEwan Crawford     }
37147dc7771cSEwan Crawford 
37157dc7771cSEwan Crawford     runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP());
37167dc7771cSEwan Crawford 
37177dc7771cSEwan Crawford     result.SetStatus(eReturnStatusSuccessFinishResult);
37187dc7771cSEwan Crawford     return true;
37197dc7771cSEwan Crawford   }
37207dc7771cSEwan Crawford };
37217dc7771cSEwan Crawford 
3722*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelCoordinate
3723*b9c1b51eSKate Stone     : public CommandObjectParsed {
37244f8817c2SEwan Crawford public:
3725*b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelCoordinate(
3726*b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3727*b9c1b51eSKate Stone       : CommandObjectParsed(
3728*b9c1b51eSKate Stone             interpreter, "renderscript kernel coordinate",
37294f8817c2SEwan Crawford             "Shows the (x,y,z) coordinate of the current kernel invocation.",
37304f8817c2SEwan Crawford             "renderscript kernel coordinate",
3731*b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
3732*b9c1b51eSKate Stone                 eCommandProcessMustBePaused) {}
37334f8817c2SEwan Crawford 
37344f8817c2SEwan Crawford   ~CommandObjectRenderScriptRuntimeKernelCoordinate() override = default;
37354f8817c2SEwan Crawford 
3736*b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
37374f8817c2SEwan Crawford     RSCoordinate coord{}; // Zero initialize array
3738*b9c1b51eSKate Stone     bool success = RenderScriptRuntime::GetKernelCoordinate(
3739*b9c1b51eSKate Stone         coord, m_exe_ctx.GetThreadPtr());
37404f8817c2SEwan Crawford     Stream &stream = result.GetOutputStream();
37414f8817c2SEwan Crawford 
3742*b9c1b51eSKate Stone     if (success) {
3743*b9c1b51eSKate Stone       stream.Printf("Coordinate: (%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")",
3744*b9c1b51eSKate Stone                     coord[0], coord[1], coord[2]);
37454f8817c2SEwan Crawford       stream.EOL();
37464f8817c2SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
3747*b9c1b51eSKate Stone     } else {
37484f8817c2SEwan Crawford       stream.Printf("Error: Coordinate could not be found.");
37494f8817c2SEwan Crawford       stream.EOL();
37504f8817c2SEwan Crawford       result.SetStatus(eReturnStatusFailed);
37514f8817c2SEwan Crawford     }
37524f8817c2SEwan Crawford     return true;
37534f8817c2SEwan Crawford   }
37544f8817c2SEwan Crawford };
37554f8817c2SEwan Crawford 
3756*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpoint
3757*b9c1b51eSKate Stone     : public CommandObjectMultiword {
37587dc7771cSEwan Crawford public:
3759*b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelBreakpoint(
3760*b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3761*b9c1b51eSKate Stone       : CommandObjectMultiword(
3762*b9c1b51eSKate Stone             interpreter, "renderscript kernel",
3763*b9c1b51eSKate Stone             "Commands that generate breakpoints on renderscript kernels.",
3764*b9c1b51eSKate Stone             nullptr) {
3765*b9c1b51eSKate Stone     LoadSubCommand(
3766*b9c1b51eSKate Stone         "set",
3767*b9c1b51eSKate Stone         CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet(
3768*b9c1b51eSKate Stone             interpreter)));
3769*b9c1b51eSKate Stone     LoadSubCommand(
3770*b9c1b51eSKate Stone         "all",
3771*b9c1b51eSKate Stone         CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll(
3772*b9c1b51eSKate Stone             interpreter)));
37737dc7771cSEwan Crawford   }
37747dc7771cSEwan Crawford 
3775222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default;
37767dc7771cSEwan Crawford };
37777dc7771cSEwan Crawford 
3778*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword {
37794640cde1SColin Riley public:
37804640cde1SColin Riley   CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter)
3781*b9c1b51eSKate Stone       : CommandObjectMultiword(interpreter, "renderscript kernel",
3782*b9c1b51eSKate Stone                                "Commands that deal with RenderScript kernels.",
3783*b9c1b51eSKate Stone                                nullptr) {
3784*b9c1b51eSKate Stone     LoadSubCommand(
3785*b9c1b51eSKate Stone         "list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList(
3786*b9c1b51eSKate Stone                     interpreter)));
3787*b9c1b51eSKate Stone     LoadSubCommand(
3788*b9c1b51eSKate Stone         "coordinate",
3789*b9c1b51eSKate Stone         CommandObjectSP(
3790*b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeKernelCoordinate(interpreter)));
3791*b9c1b51eSKate Stone     LoadSubCommand(
3792*b9c1b51eSKate Stone         "breakpoint",
3793*b9c1b51eSKate Stone         CommandObjectSP(
3794*b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter)));
37954640cde1SColin Riley   }
37964640cde1SColin Riley 
3797222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernel() override = default;
37984640cde1SColin Riley };
37994640cde1SColin Riley 
3800*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed {
38014640cde1SColin Riley public:
38024640cde1SColin Riley   CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter)
3803*b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "renderscript context dump",
3804*b9c1b51eSKate Stone                             "Dumps renderscript context information.",
3805*b9c1b51eSKate Stone                             "renderscript context dump",
3806*b9c1b51eSKate Stone                             eCommandRequiresProcess |
3807*b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
38084640cde1SColin Riley 
3809222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeContextDump() override = default;
38104640cde1SColin Riley 
3811*b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
38124640cde1SColin Riley     RenderScriptRuntime *runtime =
3813*b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3814*b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
38154640cde1SColin Riley     runtime->DumpContexts(result.GetOutputStream());
38164640cde1SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
38174640cde1SColin Riley     return true;
38184640cde1SColin Riley   }
38194640cde1SColin Riley };
38204640cde1SColin Riley 
3821*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword {
38224640cde1SColin Riley public:
38234640cde1SColin Riley   CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter)
3824*b9c1b51eSKate Stone       : CommandObjectMultiword(interpreter, "renderscript context",
3825*b9c1b51eSKate Stone                                "Commands that deal with RenderScript contexts.",
3826*b9c1b51eSKate Stone                                nullptr) {
3827*b9c1b51eSKate Stone     LoadSubCommand(
3828*b9c1b51eSKate Stone         "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump(
3829*b9c1b51eSKate Stone                     interpreter)));
38304640cde1SColin Riley   }
38314640cde1SColin Riley 
3832222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeContext() override = default;
38334640cde1SColin Riley };
38344640cde1SColin Riley 
3835*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationDump
3836*b9c1b51eSKate Stone     : public CommandObjectParsed {
3837a0f08674SEwan Crawford public:
3838*b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationDump(
3839*b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3840a0f08674SEwan Crawford       : CommandObjectParsed(interpreter, "renderscript allocation dump",
3841*b9c1b51eSKate Stone                             "Displays the contents of a particular allocation",
3842*b9c1b51eSKate Stone                             "renderscript allocation dump <ID>",
3843*b9c1b51eSKate Stone                             eCommandRequiresProcess |
3844*b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched),
3845*b9c1b51eSKate Stone         m_options() {}
3846a0f08674SEwan Crawford 
3847222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationDump() override = default;
3848222b937cSEugene Zelenko 
3849*b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
3850a0f08674SEwan Crawford 
3851*b9c1b51eSKate Stone   class CommandOptions : public Options {
3852a0f08674SEwan Crawford   public:
3853e1cfbc79STodd Fiala     CommandOptions() : Options() {}
3854a0f08674SEwan Crawford 
3855222b937cSEugene Zelenko     ~CommandOptions() override = default;
3856a0f08674SEwan Crawford 
3857*b9c1b51eSKate Stone     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
3858*b9c1b51eSKate Stone                          ExecutionContext *execution_context) override {
3859a0f08674SEwan Crawford       Error error;
3860a0f08674SEwan Crawford       const int short_option = m_getopt_table[option_idx].val;
3861a0f08674SEwan Crawford 
3862*b9c1b51eSKate Stone       switch (short_option) {
3863a0f08674SEwan Crawford       case 'f':
3864a0f08674SEwan Crawford         m_outfile.SetFile(option_arg, true);
3865*b9c1b51eSKate Stone         if (m_outfile.Exists()) {
3866a0f08674SEwan Crawford           m_outfile.Clear();
3867*b9c1b51eSKate Stone           error.SetErrorStringWithFormat("file already exists: '%s'",
3868*b9c1b51eSKate Stone                                          option_arg);
3869a0f08674SEwan Crawford         }
3870a0f08674SEwan Crawford         break;
3871a0f08674SEwan Crawford       default:
3872*b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
3873*b9c1b51eSKate Stone                                        short_option);
3874a0f08674SEwan Crawford         break;
3875a0f08674SEwan Crawford       }
3876a0f08674SEwan Crawford       return error;
3877a0f08674SEwan Crawford     }
3878a0f08674SEwan Crawford 
3879*b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
3880a0f08674SEwan Crawford       m_outfile.Clear();
3881a0f08674SEwan Crawford     }
3882a0f08674SEwan Crawford 
3883*b9c1b51eSKate Stone     const OptionDefinition *GetDefinitions() override { return g_option_table; }
3884a0f08674SEwan Crawford 
3885a0f08674SEwan Crawford     static OptionDefinition g_option_table[];
3886a0f08674SEwan Crawford     FileSpec m_outfile;
3887a0f08674SEwan Crawford   };
3888a0f08674SEwan Crawford 
3889*b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
3890a0f08674SEwan Crawford     const size_t argc = command.GetArgumentCount();
3891*b9c1b51eSKate Stone     if (argc < 1) {
3892*b9c1b51eSKate Stone       result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. "
3893*b9c1b51eSKate Stone                                    "As well as an optional -f argument",
3894a0f08674SEwan Crawford                                    m_cmd_name.c_str());
3895a0f08674SEwan Crawford       result.SetStatus(eReturnStatusFailed);
3896a0f08674SEwan Crawford       return false;
3897a0f08674SEwan Crawford     }
3898a0f08674SEwan Crawford 
3899b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
3900*b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3901*b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
3902a0f08674SEwan Crawford 
3903a0f08674SEwan Crawford     const char *id_cstr = command.GetArgumentAtIndex(0);
3904a0f08674SEwan Crawford     bool convert_complete = false;
3905*b9c1b51eSKate Stone     const uint32_t id =
3906*b9c1b51eSKate Stone         StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
3907*b9c1b51eSKate Stone     if (!convert_complete) {
3908*b9c1b51eSKate Stone       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
3909*b9c1b51eSKate Stone                                    id_cstr);
3910a0f08674SEwan Crawford       result.SetStatus(eReturnStatusFailed);
3911a0f08674SEwan Crawford       return false;
3912a0f08674SEwan Crawford     }
3913a0f08674SEwan Crawford 
3914a0f08674SEwan Crawford     Stream *output_strm = nullptr;
3915a0f08674SEwan Crawford     StreamFile outfile_stream;
3916*b9c1b51eSKate Stone     const FileSpec &outfile_spec =
3917*b9c1b51eSKate Stone         m_options.m_outfile; // Dump allocation to file instead
3918*b9c1b51eSKate Stone     if (outfile_spec) {
3919a0f08674SEwan Crawford       // Open output file
3920a0f08674SEwan Crawford       char path[256];
3921a0f08674SEwan Crawford       outfile_spec.GetPath(path, sizeof(path));
3922*b9c1b51eSKate Stone       if (outfile_stream.GetFile()
3923*b9c1b51eSKate Stone               .Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate)
3924*b9c1b51eSKate Stone               .Success()) {
3925a0f08674SEwan Crawford         output_strm = &outfile_stream;
3926a0f08674SEwan Crawford         result.GetOutputStream().Printf("Results written to '%s'", path);
3927a0f08674SEwan Crawford         result.GetOutputStream().EOL();
3928*b9c1b51eSKate Stone       } else {
3929a0f08674SEwan Crawford         result.AppendErrorWithFormat("Couldn't open file '%s'", path);
3930a0f08674SEwan Crawford         result.SetStatus(eReturnStatusFailed);
3931a0f08674SEwan Crawford         return false;
3932a0f08674SEwan Crawford       }
3933*b9c1b51eSKate Stone     } else
3934a0f08674SEwan Crawford       output_strm = &result.GetOutputStream();
3935a0f08674SEwan Crawford 
3936a0f08674SEwan Crawford     assert(output_strm != nullptr);
3937*b9c1b51eSKate Stone     bool success =
3938*b9c1b51eSKate Stone         runtime->DumpAllocation(*output_strm, m_exe_ctx.GetFramePtr(), id);
3939a0f08674SEwan Crawford 
3940a0f08674SEwan Crawford     if (success)
3941a0f08674SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
3942a0f08674SEwan Crawford     else
3943a0f08674SEwan Crawford       result.SetStatus(eReturnStatusFailed);
3944a0f08674SEwan Crawford 
3945a0f08674SEwan Crawford     return true;
3946a0f08674SEwan Crawford   }
3947a0f08674SEwan Crawford 
3948a0f08674SEwan Crawford private:
3949a0f08674SEwan Crawford   CommandOptions m_options;
3950a0f08674SEwan Crawford };
3951a0f08674SEwan Crawford 
3952*b9c1b51eSKate Stone OptionDefinition CommandObjectRenderScriptRuntimeAllocationDump::
3953*b9c1b51eSKate Stone     CommandOptions::g_option_table[] = {
3954*b9c1b51eSKate Stone         {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument,
3955*b9c1b51eSKate Stone          nullptr, nullptr, 0, eArgTypeFilename,
3956a0f08674SEwan Crawford          "Print results to specified file instead of command line."},
3957b3f7f69dSAidan Dodds         {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}};
3958a0f08674SEwan Crawford 
3959*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationList
3960*b9c1b51eSKate Stone     : public CommandObjectParsed {
396115f2bd95SEwan Crawford public:
3962*b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationList(
3963*b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3964*b9c1b51eSKate Stone       : CommandObjectParsed(
3965*b9c1b51eSKate Stone             interpreter, "renderscript allocation list",
3966*b9c1b51eSKate Stone             "List renderscript allocations and their information.",
3967*b9c1b51eSKate Stone             "renderscript allocation list",
3968b3f7f69dSAidan Dodds             eCommandRequiresProcess | eCommandProcessMustBeLaunched),
3969*b9c1b51eSKate Stone         m_options() {}
397015f2bd95SEwan Crawford 
3971222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationList() override = default;
3972222b937cSEugene Zelenko 
3973*b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
397415f2bd95SEwan Crawford 
3975*b9c1b51eSKate Stone   class CommandOptions : public Options {
397615f2bd95SEwan Crawford   public:
3977e1cfbc79STodd Fiala     CommandOptions() : Options(), m_id(0) {}
397815f2bd95SEwan Crawford 
3979222b937cSEugene Zelenko     ~CommandOptions() override = default;
398015f2bd95SEwan Crawford 
3981*b9c1b51eSKate Stone     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
3982*b9c1b51eSKate Stone                          ExecutionContext *execution_context) override {
398315f2bd95SEwan Crawford       Error error;
398415f2bd95SEwan Crawford       const int short_option = m_getopt_table[option_idx].val;
398515f2bd95SEwan Crawford 
3986*b9c1b51eSKate Stone       switch (short_option) {
3987b649b005SEwan Crawford       case 'i':
3988b649b005SEwan Crawford         bool success;
3989b649b005SEwan Crawford         m_id = StringConvert::ToUInt32(option_arg, 0, 0, &success);
3990b649b005SEwan Crawford         if (!success)
3991*b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
3992*b9c1b51eSKate Stone               "invalid integer value for option '%c'", short_option);
399315f2bd95SEwan Crawford         break;
399415f2bd95SEwan Crawford       default:
3995*b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
3996*b9c1b51eSKate Stone                                        short_option);
399715f2bd95SEwan Crawford         break;
399815f2bd95SEwan Crawford       }
399915f2bd95SEwan Crawford       return error;
400015f2bd95SEwan Crawford     }
400115f2bd95SEwan Crawford 
4002*b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
4003b649b005SEwan Crawford       m_id = 0;
400415f2bd95SEwan Crawford     }
400515f2bd95SEwan Crawford 
4006*b9c1b51eSKate Stone     const OptionDefinition *GetDefinitions() override { return g_option_table; }
400715f2bd95SEwan Crawford 
400815f2bd95SEwan Crawford     static OptionDefinition g_option_table[];
4009b649b005SEwan Crawford     uint32_t m_id;
401015f2bd95SEwan Crawford   };
401115f2bd95SEwan Crawford 
4012*b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
4013b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4014*b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4015*b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
4016*b9c1b51eSKate Stone     runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(),
4017*b9c1b51eSKate Stone                              m_options.m_id);
401815f2bd95SEwan Crawford     result.SetStatus(eReturnStatusSuccessFinishResult);
401915f2bd95SEwan Crawford     return true;
402015f2bd95SEwan Crawford   }
402115f2bd95SEwan Crawford 
402215f2bd95SEwan Crawford private:
402315f2bd95SEwan Crawford   CommandOptions m_options;
402415f2bd95SEwan Crawford };
402515f2bd95SEwan Crawford 
4026*b9c1b51eSKate Stone OptionDefinition CommandObjectRenderScriptRuntimeAllocationList::
4027*b9c1b51eSKate Stone     CommandOptions::g_option_table[] = {
4028*b9c1b51eSKate Stone         {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument,
4029*b9c1b51eSKate Stone          nullptr, nullptr, 0, eArgTypeIndex,
4030b649b005SEwan Crawford          "Only show details of a single allocation with specified id."},
4031b3f7f69dSAidan Dodds         {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}};
403215f2bd95SEwan Crawford 
4033*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationLoad
4034*b9c1b51eSKate Stone     : public CommandObjectParsed {
403555232f09SEwan Crawford public:
4036*b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationLoad(
4037*b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4038b3f7f69dSAidan Dodds       : CommandObjectParsed(
4039*b9c1b51eSKate Stone             interpreter, "renderscript allocation load",
4040*b9c1b51eSKate Stone             "Loads renderscript allocation contents from a file.",
4041*b9c1b51eSKate Stone             "renderscript allocation load <ID> <filename>",
4042*b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
404355232f09SEwan Crawford 
4044222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default;
404555232f09SEwan Crawford 
4046*b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
404755232f09SEwan Crawford     const size_t argc = command.GetArgumentCount();
4048*b9c1b51eSKate Stone     if (argc != 2) {
4049*b9c1b51eSKate Stone       result.AppendErrorWithFormat(
4050*b9c1b51eSKate Stone           "'%s' takes 2 arguments, an allocation ID and filename to read from.",
4051b3f7f69dSAidan Dodds           m_cmd_name.c_str());
405255232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
405355232f09SEwan Crawford       return false;
405455232f09SEwan Crawford     }
405555232f09SEwan Crawford 
4056b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4057*b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4058*b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
405955232f09SEwan Crawford 
406055232f09SEwan Crawford     const char *id_cstr = command.GetArgumentAtIndex(0);
406155232f09SEwan Crawford     bool convert_complete = false;
4062*b9c1b51eSKate Stone     const uint32_t id =
4063*b9c1b51eSKate Stone         StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
4064*b9c1b51eSKate Stone     if (!convert_complete) {
4065*b9c1b51eSKate Stone       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
4066*b9c1b51eSKate Stone                                    id_cstr);
406755232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
406855232f09SEwan Crawford       return false;
406955232f09SEwan Crawford     }
407055232f09SEwan Crawford 
407155232f09SEwan Crawford     const char *filename = command.GetArgumentAtIndex(1);
4072*b9c1b51eSKate Stone     bool success = runtime->LoadAllocation(result.GetOutputStream(), id,
4073*b9c1b51eSKate Stone                                            filename, m_exe_ctx.GetFramePtr());
407455232f09SEwan Crawford 
407555232f09SEwan Crawford     if (success)
407655232f09SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
407755232f09SEwan Crawford     else
407855232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
407955232f09SEwan Crawford 
408055232f09SEwan Crawford     return true;
408155232f09SEwan Crawford   }
408255232f09SEwan Crawford };
408355232f09SEwan Crawford 
4084*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationSave
4085*b9c1b51eSKate Stone     : public CommandObjectParsed {
408655232f09SEwan Crawford public:
4087*b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationSave(
4088*b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4089*b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "renderscript allocation save",
4090*b9c1b51eSKate Stone                             "Write renderscript allocation contents to a file.",
4091*b9c1b51eSKate Stone                             "renderscript allocation save <ID> <filename>",
4092*b9c1b51eSKate Stone                             eCommandRequiresProcess |
4093*b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
409455232f09SEwan Crawford 
4095222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationSave() override = default;
409655232f09SEwan Crawford 
4097*b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
409855232f09SEwan Crawford     const size_t argc = command.GetArgumentCount();
4099*b9c1b51eSKate Stone     if (argc != 2) {
4100*b9c1b51eSKate Stone       result.AppendErrorWithFormat(
4101*b9c1b51eSKate Stone           "'%s' takes 2 arguments, an allocation ID and filename to read from.",
4102b3f7f69dSAidan Dodds           m_cmd_name.c_str());
410355232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
410455232f09SEwan Crawford       return false;
410555232f09SEwan Crawford     }
410655232f09SEwan Crawford 
4107b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4108*b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4109*b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
411055232f09SEwan Crawford 
411155232f09SEwan Crawford     const char *id_cstr = command.GetArgumentAtIndex(0);
411255232f09SEwan Crawford     bool convert_complete = false;
4113*b9c1b51eSKate Stone     const uint32_t id =
4114*b9c1b51eSKate Stone         StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
4115*b9c1b51eSKate Stone     if (!convert_complete) {
4116*b9c1b51eSKate Stone       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
4117*b9c1b51eSKate Stone                                    id_cstr);
411855232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
411955232f09SEwan Crawford       return false;
412055232f09SEwan Crawford     }
412155232f09SEwan Crawford 
412255232f09SEwan Crawford     const char *filename = command.GetArgumentAtIndex(1);
4123*b9c1b51eSKate Stone     bool success = runtime->SaveAllocation(result.GetOutputStream(), id,
4124*b9c1b51eSKate Stone                                            filename, m_exe_ctx.GetFramePtr());
412555232f09SEwan Crawford 
412655232f09SEwan Crawford     if (success)
412755232f09SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
412855232f09SEwan Crawford     else
412955232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
413055232f09SEwan Crawford 
413155232f09SEwan Crawford     return true;
413255232f09SEwan Crawford   }
413355232f09SEwan Crawford };
413455232f09SEwan Crawford 
4135*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationRefresh
4136*b9c1b51eSKate Stone     : public CommandObjectParsed {
41370d2bfcfbSEwan Crawford public:
4138*b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationRefresh(
4139*b9c1b51eSKate Stone       CommandInterpreter &interpreter)
41400d2bfcfbSEwan Crawford       : CommandObjectParsed(interpreter, "renderscript allocation refresh",
4141*b9c1b51eSKate Stone                             "Recomputes the details of all allocations.",
4142*b9c1b51eSKate Stone                             "renderscript allocation refresh",
4143*b9c1b51eSKate Stone                             eCommandRequiresProcess |
4144*b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
41450d2bfcfbSEwan Crawford 
41460d2bfcfbSEwan Crawford   ~CommandObjectRenderScriptRuntimeAllocationRefresh() override = default;
41470d2bfcfbSEwan Crawford 
4148*b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
41490d2bfcfbSEwan Crawford     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4150*b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4151*b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
41520d2bfcfbSEwan Crawford 
4153*b9c1b51eSKate Stone     bool success = runtime->RecomputeAllAllocations(result.GetOutputStream(),
4154*b9c1b51eSKate Stone                                                     m_exe_ctx.GetFramePtr());
41550d2bfcfbSEwan Crawford 
4156*b9c1b51eSKate Stone     if (success) {
41570d2bfcfbSEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
41580d2bfcfbSEwan Crawford       return true;
4159*b9c1b51eSKate Stone     } else {
41600d2bfcfbSEwan Crawford       result.SetStatus(eReturnStatusFailed);
41610d2bfcfbSEwan Crawford       return false;
41620d2bfcfbSEwan Crawford     }
41630d2bfcfbSEwan Crawford   }
41640d2bfcfbSEwan Crawford };
41650d2bfcfbSEwan Crawford 
4166*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocation
4167*b9c1b51eSKate Stone     : public CommandObjectMultiword {
416815f2bd95SEwan Crawford public:
416915f2bd95SEwan Crawford   CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter)
4170*b9c1b51eSKate Stone       : CommandObjectMultiword(
4171*b9c1b51eSKate Stone             interpreter, "renderscript allocation",
4172*b9c1b51eSKate Stone             "Commands that deal with RenderScript allocations.", nullptr) {
4173*b9c1b51eSKate Stone     LoadSubCommand(
4174*b9c1b51eSKate Stone         "list",
4175*b9c1b51eSKate Stone         CommandObjectSP(
4176*b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationList(interpreter)));
4177*b9c1b51eSKate Stone     LoadSubCommand(
4178*b9c1b51eSKate Stone         "dump",
4179*b9c1b51eSKate Stone         CommandObjectSP(
4180*b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationDump(interpreter)));
4181*b9c1b51eSKate Stone     LoadSubCommand(
4182*b9c1b51eSKate Stone         "save",
4183*b9c1b51eSKate Stone         CommandObjectSP(
4184*b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationSave(interpreter)));
4185*b9c1b51eSKate Stone     LoadSubCommand(
4186*b9c1b51eSKate Stone         "load",
4187*b9c1b51eSKate Stone         CommandObjectSP(
4188*b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter)));
4189*b9c1b51eSKate Stone     LoadSubCommand(
4190*b9c1b51eSKate Stone         "refresh",
4191*b9c1b51eSKate Stone         CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationRefresh(
4192*b9c1b51eSKate Stone             interpreter)));
419315f2bd95SEwan Crawford   }
419415f2bd95SEwan Crawford 
4195222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocation() override = default;
419615f2bd95SEwan Crawford };
419715f2bd95SEwan Crawford 
4198*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed {
41994640cde1SColin Riley public:
42004640cde1SColin Riley   CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter)
4201*b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "renderscript status",
4202*b9c1b51eSKate Stone                             "Displays current RenderScript runtime status.",
4203*b9c1b51eSKate Stone                             "renderscript status",
4204*b9c1b51eSKate Stone                             eCommandRequiresProcess |
4205*b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
42064640cde1SColin Riley 
4207222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeStatus() override = default;
42084640cde1SColin Riley 
4209*b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
42104640cde1SColin Riley     RenderScriptRuntime *runtime =
4211*b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4212*b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
42134640cde1SColin Riley     runtime->Status(result.GetOutputStream());
42144640cde1SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
42154640cde1SColin Riley     return true;
42164640cde1SColin Riley   }
42174640cde1SColin Riley };
42184640cde1SColin Riley 
4219*b9c1b51eSKate Stone class CommandObjectRenderScriptRuntime : public CommandObjectMultiword {
42205ec532a9SColin Riley public:
42215ec532a9SColin Riley   CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter)
4222*b9c1b51eSKate Stone       : CommandObjectMultiword(
4223*b9c1b51eSKate Stone             interpreter, "renderscript",
4224*b9c1b51eSKate Stone             "Commands for operating on the RenderScript runtime.",
4225*b9c1b51eSKate Stone             "renderscript <subcommand> [<subcommand-options>]") {
4226*b9c1b51eSKate Stone     LoadSubCommand(
4227*b9c1b51eSKate Stone         "module", CommandObjectSP(
4228*b9c1b51eSKate Stone                       new CommandObjectRenderScriptRuntimeModule(interpreter)));
4229*b9c1b51eSKate Stone     LoadSubCommand(
4230*b9c1b51eSKate Stone         "status", CommandObjectSP(
4231*b9c1b51eSKate Stone                       new CommandObjectRenderScriptRuntimeStatus(interpreter)));
4232*b9c1b51eSKate Stone     LoadSubCommand(
4233*b9c1b51eSKate Stone         "kernel", CommandObjectSP(
4234*b9c1b51eSKate Stone                       new CommandObjectRenderScriptRuntimeKernel(interpreter)));
4235*b9c1b51eSKate Stone     LoadSubCommand("context",
4236*b9c1b51eSKate Stone                    CommandObjectSP(new CommandObjectRenderScriptRuntimeContext(
4237*b9c1b51eSKate Stone                        interpreter)));
4238*b9c1b51eSKate Stone     LoadSubCommand(
4239*b9c1b51eSKate Stone         "allocation",
4240*b9c1b51eSKate Stone         CommandObjectSP(
4241*b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocation(interpreter)));
42425ec532a9SColin Riley   }
42435ec532a9SColin Riley 
4244222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntime() override = default;
42455ec532a9SColin Riley };
4246ef20b08fSColin Riley 
4247*b9c1b51eSKate Stone void RenderScriptRuntime::Initiate() { assert(!m_initiated); }
4248ef20b08fSColin Riley 
4249ef20b08fSColin Riley RenderScriptRuntime::RenderScriptRuntime(Process *process)
4250*b9c1b51eSKate Stone     : lldb_private::CPPLanguageRuntime(process), m_initiated(false),
4251*b9c1b51eSKate Stone       m_debuggerPresentFlagged(false), m_breakAllKernels(false),
4252*b9c1b51eSKate Stone       m_ir_passes(nullptr) {
42534640cde1SColin Riley   ModulesDidLoad(process->GetTarget().GetImages());
4254ef20b08fSColin Riley }
42554640cde1SColin Riley 
4256*b9c1b51eSKate Stone lldb::CommandObjectSP RenderScriptRuntime::GetCommandObject(
4257*b9c1b51eSKate Stone     lldb_private::CommandInterpreter &interpreter) {
42580a66e2f1SEnrico Granata   return CommandObjectSP(new CommandObjectRenderScriptRuntime(interpreter));
42594640cde1SColin Riley }
42604640cde1SColin Riley 
426178f339d1SEwan Crawford RenderScriptRuntime::~RenderScriptRuntime() = default;
4262