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
137f193d69SLuke Drummond #include "llvm/ADT/StringMap.h"
147f193d69SLuke Drummond 
15222b937cSEugene Zelenko // Project includes
165ec532a9SColin Riley #include "RenderScriptRuntime.h"
175ec532a9SColin Riley 
18b3f7f69dSAidan Dodds #include "lldb/Breakpoint/StoppointCallbackContext.h"
195ec532a9SColin Riley #include "lldb/Core/ConstString.h"
205ec532a9SColin Riley #include "lldb/Core/Debugger.h"
215ec532a9SColin Riley #include "lldb/Core/Error.h"
225ec532a9SColin Riley #include "lldb/Core/Log.h"
235ec532a9SColin Riley #include "lldb/Core/PluginManager.h"
24018f5a7eSEwan Crawford #include "lldb/Core/RegularExpression.h"
25b3f7f69dSAidan Dodds #include "lldb/Core/ValueObjectVariable.h"
268b244e21SEwan Crawford #include "lldb/DataFormatters/DumpValueObjectOptions.h"
27b3f7f69dSAidan Dodds #include "lldb/Expression/UserExpression.h"
28a0f08674SEwan Crawford #include "lldb/Host/StringConvert.h"
29b3f7f69dSAidan Dodds #include "lldb/Interpreter/Args.h"
30b3f7f69dSAidan Dodds #include "lldb/Interpreter/CommandInterpreter.h"
31b3f7f69dSAidan Dodds #include "lldb/Interpreter/CommandObjectMultiword.h"
32b3f7f69dSAidan Dodds #include "lldb/Interpreter/CommandReturnObject.h"
33b3f7f69dSAidan Dodds #include "lldb/Interpreter/Options.h"
345ec532a9SColin Riley #include "lldb/Symbol/Symbol.h"
354640cde1SColin Riley #include "lldb/Symbol/Type.h"
36b3f7f69dSAidan Dodds #include "lldb/Symbol/VariableList.h"
375ec532a9SColin Riley #include "lldb/Target/Process.h"
38b3f7f69dSAidan Dodds #include "lldb/Target/RegisterContext.h"
395ec532a9SColin Riley #include "lldb/Target/Target.h"
40018f5a7eSEwan Crawford #include "lldb/Target/Thread.h"
415ec532a9SColin Riley 
425ec532a9SColin Riley using namespace lldb;
435ec532a9SColin Riley using namespace lldb_private;
4498156583SEwan Crawford using namespace lldb_renderscript;
455ec532a9SColin Riley 
46b9c1b51eSKate Stone namespace {
4778f339d1SEwan Crawford 
4878f339d1SEwan Crawford // The empirical_type adds a basic level of validation to arbitrary data
4978f339d1SEwan Crawford // allowing us to track if data has been discovered and stored or not.
50b9c1b51eSKate Stone // An empirical_type will be marked as valid only if it has been explicitly
51b9c1b51eSKate Stone // assigned to.
52b9c1b51eSKate Stone template <typename type_t> class empirical_type {
5378f339d1SEwan Crawford public:
5478f339d1SEwan Crawford   // Ctor. Contents is invalid when constructed.
55b3f7f69dSAidan Dodds   empirical_type() : valid(false) {}
5678f339d1SEwan Crawford 
5778f339d1SEwan Crawford   // Return true and copy contents to out if valid, else return false.
58b9c1b51eSKate Stone   bool get(type_t &out) const {
5978f339d1SEwan Crawford     if (valid)
6078f339d1SEwan Crawford       out = data;
6178f339d1SEwan Crawford     return valid;
6278f339d1SEwan Crawford   }
6378f339d1SEwan Crawford 
6478f339d1SEwan Crawford   // Return a pointer to the contents or nullptr if it was not valid.
65b9c1b51eSKate Stone   const type_t *get() const { return valid ? &data : nullptr; }
6678f339d1SEwan Crawford 
6778f339d1SEwan Crawford   // Assign data explicitly.
68b9c1b51eSKate Stone   void set(const type_t in) {
6978f339d1SEwan Crawford     data = in;
7078f339d1SEwan Crawford     valid = true;
7178f339d1SEwan Crawford   }
7278f339d1SEwan Crawford 
7378f339d1SEwan Crawford   // Mark contents as invalid.
74b9c1b51eSKate Stone   void invalidate() { valid = false; }
7578f339d1SEwan Crawford 
7678f339d1SEwan Crawford   // Returns true if this type contains valid data.
77b9c1b51eSKate Stone   bool isValid() const { return valid; }
7878f339d1SEwan Crawford 
7978f339d1SEwan Crawford   // Assignment operator.
80b9c1b51eSKate Stone   empirical_type<type_t> &operator=(const type_t in) {
8178f339d1SEwan Crawford     set(in);
8278f339d1SEwan Crawford     return *this;
8378f339d1SEwan Crawford   }
8478f339d1SEwan Crawford 
8578f339d1SEwan Crawford   // Dereference operator returns contents.
8678f339d1SEwan Crawford   // Warning: Will assert if not valid so use only when you know data is valid.
87b9c1b51eSKate Stone   const type_t &operator*() const {
8878f339d1SEwan Crawford     assert(valid);
8978f339d1SEwan Crawford     return data;
9078f339d1SEwan Crawford   }
9178f339d1SEwan Crawford 
9278f339d1SEwan Crawford protected:
9378f339d1SEwan Crawford   bool valid;
9478f339d1SEwan Crawford   type_t data;
9578f339d1SEwan Crawford };
9678f339d1SEwan Crawford 
97b9c1b51eSKate Stone // ArgItem is used by the GetArgs() function when reading function arguments
98b9c1b51eSKate Stone // from the target.
99b9c1b51eSKate Stone struct ArgItem {
100b9c1b51eSKate Stone   enum { ePointer, eInt32, eInt64, eLong, eBool } type;
101f4786785SAidan Dodds 
102f4786785SAidan Dodds   uint64_t value;
103f4786785SAidan Dodds 
104f4786785SAidan Dodds   explicit operator uint64_t() const { return value; }
105f4786785SAidan Dodds };
106f4786785SAidan Dodds 
107b9c1b51eSKate Stone // Context structure to be passed into GetArgsXXX(), argument reading functions
108b9c1b51eSKate Stone // below.
109b9c1b51eSKate Stone struct GetArgsCtx {
110f4786785SAidan Dodds   RegisterContext *reg_ctx;
111f4786785SAidan Dodds   Process *process;
112f4786785SAidan Dodds };
113f4786785SAidan Dodds 
114b9c1b51eSKate Stone bool GetArgsX86(const GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
115f4786785SAidan Dodds   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
116f4786785SAidan Dodds 
11767dc3e15SAidan Dodds   Error error;
11867dc3e15SAidan Dodds 
119f4786785SAidan Dodds   // get the current stack pointer
120f4786785SAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP();
121f4786785SAidan Dodds 
122b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
123f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
124f4786785SAidan Dodds     // advance up the stack by one argument
125f4786785SAidan Dodds     sp += sizeof(uint32_t);
126f4786785SAidan Dodds     // get the argument type size
127f4786785SAidan Dodds     size_t arg_size = sizeof(uint32_t);
128f4786785SAidan Dodds     // read the argument from memory
129f4786785SAidan Dodds     arg.value = 0;
130f4786785SAidan Dodds     Error error;
131b9c1b51eSKate Stone     size_t read =
132b9c1b51eSKate Stone         ctx.process->ReadMemory(sp, &arg.value, sizeof(uint32_t), error);
133b9c1b51eSKate Stone     if (read != arg_size || !error.Success()) {
134f4786785SAidan Dodds       if (log)
135b9c1b51eSKate Stone         log->Printf("%s - error reading argument: %" PRIu64 " '%s'",
136b9c1b51eSKate Stone                     __FUNCTION__, uint64_t(i), error.AsCString());
137f4786785SAidan Dodds       return false;
138f4786785SAidan Dodds     }
139f4786785SAidan Dodds   }
140f4786785SAidan Dodds   return true;
141f4786785SAidan Dodds }
142f4786785SAidan Dodds 
143b9c1b51eSKate Stone bool GetArgsX86_64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
144f4786785SAidan Dodds   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
145f4786785SAidan Dodds 
146f4786785SAidan Dodds   // number of arguments passed in registers
147f4786785SAidan Dodds   static const uint32_t c_args_in_reg = 6;
148f4786785SAidan Dodds   // register passing order
149b9c1b51eSKate Stone   static const std::array<const char *, c_args_in_reg> c_reg_names{
150b9c1b51eSKate Stone       {"rdi", "rsi", "rdx", "rcx", "r8", "r9"}};
151f4786785SAidan Dodds   // argument type to size mapping
1521ee07253SSaleem Abdulrasool   static const std::array<size_t, 5> arg_size{{
153f4786785SAidan Dodds       8, // ePointer,
154f4786785SAidan Dodds       4, // eInt32,
155f4786785SAidan Dodds       8, // eInt64,
156f4786785SAidan Dodds       8, // eLong,
157f4786785SAidan Dodds       4, // eBool,
1581ee07253SSaleem Abdulrasool   }};
159f4786785SAidan Dodds 
16017e07c0aSAidan Dodds   Error error;
16117e07c0aSAidan Dodds 
162f4786785SAidan Dodds   // get the current stack pointer
163f4786785SAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP();
164f4786785SAidan Dodds   // step over the return address
165f4786785SAidan Dodds   sp += sizeof(uint64_t);
166f4786785SAidan Dodds 
167f4786785SAidan Dodds   // check the stack alignment was correct (16 byte aligned)
168b9c1b51eSKate Stone   if ((sp & 0xf) != 0x0) {
169f4786785SAidan Dodds     if (log)
170f4786785SAidan Dodds       log->Printf("%s - stack misaligned", __FUNCTION__);
171f4786785SAidan Dodds     return false;
172f4786785SAidan Dodds   }
173f4786785SAidan Dodds 
174f4786785SAidan Dodds   // find the start of arguments on the stack
175f4786785SAidan Dodds   uint64_t sp_offset = 0;
176b9c1b51eSKate Stone   for (uint32_t i = c_args_in_reg; i < num_args; ++i) {
177f4786785SAidan Dodds     sp_offset += arg_size[arg_list[i].type];
178f4786785SAidan Dodds   }
179f4786785SAidan Dodds   // round up to multiple of 16
180f4786785SAidan Dodds   sp_offset = (sp_offset + 0xf) & 0xf;
181f4786785SAidan Dodds   sp += sp_offset;
182f4786785SAidan Dodds 
183b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
184f4786785SAidan Dodds     bool success = false;
185f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
186f4786785SAidan Dodds     // arguments passed in registers
187b9c1b51eSKate Stone     if (i < c_args_in_reg) {
188b9c1b51eSKate Stone       const RegisterInfo *rArg =
189b9c1b51eSKate Stone           ctx.reg_ctx->GetRegisterInfoByName(c_reg_names[i]);
190f4786785SAidan Dodds       RegisterValue rVal;
191f4786785SAidan Dodds       if (ctx.reg_ctx->ReadRegister(rArg, rVal))
192f4786785SAidan Dodds         arg.value = rVal.GetAsUInt64(0, &success);
193f4786785SAidan Dodds     }
194f4786785SAidan Dodds     // arguments passed on the stack
195b9c1b51eSKate Stone     else {
196f4786785SAidan Dodds       // get the argument type size
197f4786785SAidan Dodds       const size_t size = arg_size[arg_list[i].type];
198f4786785SAidan Dodds       // read the argument from memory
199f4786785SAidan Dodds       arg.value = 0;
200b9c1b51eSKate Stone       // note: due to little endian layout reading 4 or 8 bytes will give the
201b9c1b51eSKate Stone       // correct value.
202f4786785SAidan Dodds       size_t read = ctx.process->ReadMemory(sp, &arg.value, size, error);
203f4786785SAidan Dodds       success = (error.Success() && read == size);
204f4786785SAidan Dodds       // advance past this argument
205f4786785SAidan Dodds       sp -= size;
206f4786785SAidan Dodds     }
207f4786785SAidan Dodds     // fail if we couldn't read this argument
208b9c1b51eSKate Stone     if (!success) {
209f4786785SAidan Dodds       if (log)
21017e07c0aSAidan Dodds         log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s",
21117e07c0aSAidan Dodds                     __FUNCTION__, uint64_t(i), error.AsCString("n/a"));
212f4786785SAidan Dodds       return false;
213f4786785SAidan Dodds     }
214f4786785SAidan Dodds   }
215f4786785SAidan Dodds   return true;
216f4786785SAidan Dodds }
217f4786785SAidan Dodds 
218b9c1b51eSKate Stone bool GetArgsArm(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
219f4786785SAidan Dodds   // number of arguments passed in registers
220f4786785SAidan Dodds   static const uint32_t c_args_in_reg = 4;
221f4786785SAidan Dodds 
222f4786785SAidan Dodds   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
223f4786785SAidan Dodds 
22417e07c0aSAidan Dodds   Error error;
22517e07c0aSAidan Dodds 
226f4786785SAidan Dodds   // get the current stack pointer
227f4786785SAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP();
228f4786785SAidan Dodds 
229b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
230f4786785SAidan Dodds     bool success = false;
231f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
232f4786785SAidan Dodds     // arguments passed in registers
233b9c1b51eSKate Stone     if (i < c_args_in_reg) {
234f4786785SAidan Dodds       const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoAtIndex(i);
235f4786785SAidan Dodds       RegisterValue rVal;
236f4786785SAidan Dodds       if (ctx.reg_ctx->ReadRegister(rArg, rVal))
237f4786785SAidan Dodds         arg.value = rVal.GetAsUInt32(0, &success);
238f4786785SAidan Dodds     }
239f4786785SAidan Dodds     // arguments passed on the stack
240b9c1b51eSKate Stone     else {
241f4786785SAidan Dodds       // get the argument type size
242f4786785SAidan Dodds       const size_t arg_size = sizeof(uint32_t);
243f4786785SAidan Dodds       // clear all 64bits
244f4786785SAidan Dodds       arg.value = 0;
245f4786785SAidan Dodds       // read this argument from memory
246b9c1b51eSKate Stone       size_t bytes_read =
247b9c1b51eSKate Stone           ctx.process->ReadMemory(sp, &arg.value, arg_size, error);
248f4786785SAidan Dodds       success = (error.Success() && bytes_read == arg_size);
249f4786785SAidan Dodds       // advance the stack pointer
250f4786785SAidan Dodds       sp += sizeof(uint32_t);
251f4786785SAidan Dodds     }
252f4786785SAidan Dodds     // fail if we couldn't read this argument
253b9c1b51eSKate Stone     if (!success) {
254f4786785SAidan Dodds       if (log)
25517e07c0aSAidan Dodds         log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s",
25617e07c0aSAidan Dodds                     __FUNCTION__, uint64_t(i), error.AsCString("n/a"));
257f4786785SAidan Dodds       return false;
258f4786785SAidan Dodds     }
259f4786785SAidan Dodds   }
260f4786785SAidan Dodds   return true;
261f4786785SAidan Dodds }
262f4786785SAidan Dodds 
263b9c1b51eSKate Stone bool GetArgsAarch64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
264f4786785SAidan Dodds   // number of arguments passed in registers
265f4786785SAidan Dodds   static const uint32_t c_args_in_reg = 8;
266f4786785SAidan Dodds 
267f4786785SAidan Dodds   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
268f4786785SAidan Dodds 
269b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
270f4786785SAidan Dodds     bool success = false;
271f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
272f4786785SAidan Dodds     // arguments passed in registers
273b9c1b51eSKate Stone     if (i < c_args_in_reg) {
274f4786785SAidan Dodds       const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoAtIndex(i);
275f4786785SAidan Dodds       RegisterValue rVal;
276f4786785SAidan Dodds       if (ctx.reg_ctx->ReadRegister(rArg, rVal))
277f4786785SAidan Dodds         arg.value = rVal.GetAsUInt64(0, &success);
278f4786785SAidan Dodds     }
279f4786785SAidan Dodds     // arguments passed on the stack
280b9c1b51eSKate Stone     else {
281f4786785SAidan Dodds       if (log)
282b9c1b51eSKate Stone         log->Printf("%s - reading arguments spilled to stack not implemented",
283b9c1b51eSKate Stone                     __FUNCTION__);
284f4786785SAidan Dodds     }
285f4786785SAidan Dodds     // fail if we couldn't read this argument
286b9c1b51eSKate Stone     if (!success) {
287f4786785SAidan Dodds       if (log)
288f4786785SAidan Dodds         log->Printf("%s - error reading argument: %" PRIu64, __FUNCTION__,
289f4786785SAidan Dodds                     uint64_t(i));
290f4786785SAidan Dodds       return false;
291f4786785SAidan Dodds     }
292f4786785SAidan Dodds   }
293f4786785SAidan Dodds   return true;
294f4786785SAidan Dodds }
295f4786785SAidan Dodds 
296b9c1b51eSKate Stone bool GetArgsMipsel(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
297f4786785SAidan Dodds   // number of arguments passed in registers
298f4786785SAidan Dodds   static const uint32_t c_args_in_reg = 4;
299f4786785SAidan Dodds   // register file offset to first argument
300f4786785SAidan Dodds   static const uint32_t c_reg_offset = 4;
301f4786785SAidan Dodds 
302f4786785SAidan Dodds   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
303f4786785SAidan Dodds 
30417e07c0aSAidan Dodds   Error error;
30517e07c0aSAidan Dodds 
30617e07c0aSAidan Dodds   // find offset to arguments on the stack (+16 to skip over a0-a3 shadow space)
30717e07c0aSAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP() + 16;
30817e07c0aSAidan Dodds 
309b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
310f4786785SAidan Dodds     bool success = false;
311f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
312f4786785SAidan Dodds     // arguments passed in registers
313b9c1b51eSKate Stone     if (i < c_args_in_reg) {
314b9c1b51eSKate Stone       const RegisterInfo *rArg =
315b9c1b51eSKate Stone           ctx.reg_ctx->GetRegisterInfoAtIndex(i + c_reg_offset);
316f4786785SAidan Dodds       RegisterValue rVal;
317f4786785SAidan Dodds       if (ctx.reg_ctx->ReadRegister(rArg, rVal))
318f4786785SAidan Dodds         arg.value = rVal.GetAsUInt64(0, &success);
319f4786785SAidan Dodds     }
320f4786785SAidan Dodds     // arguments passed on the stack
321b9c1b51eSKate Stone     else {
3226dd4b579SAidan Dodds       const size_t arg_size = sizeof(uint32_t);
3236dd4b579SAidan Dodds       arg.value = 0;
324b9c1b51eSKate Stone       size_t bytes_read =
325b9c1b51eSKate Stone           ctx.process->ReadMemory(sp, &arg.value, arg_size, error);
3266dd4b579SAidan Dodds       success = (error.Success() && bytes_read == arg_size);
32767dc3e15SAidan Dodds       // advance the stack pointer
32867dc3e15SAidan Dodds       sp += arg_size;
329f4786785SAidan Dodds     }
330f4786785SAidan Dodds     // fail if we couldn't read this argument
331b9c1b51eSKate Stone     if (!success) {
332f4786785SAidan Dodds       if (log)
33367dc3e15SAidan Dodds         log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s",
33467dc3e15SAidan Dodds                     __FUNCTION__, uint64_t(i), error.AsCString("n/a"));
335f4786785SAidan Dodds       return false;
336f4786785SAidan Dodds     }
337f4786785SAidan Dodds   }
338f4786785SAidan Dodds   return true;
339f4786785SAidan Dodds }
340f4786785SAidan Dodds 
341b9c1b51eSKate Stone bool GetArgsMips64el(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
342f4786785SAidan Dodds   // number of arguments passed in registers
343f4786785SAidan Dodds   static const uint32_t c_args_in_reg = 8;
344f4786785SAidan Dodds   // register file offset to first argument
345f4786785SAidan Dodds   static const uint32_t c_reg_offset = 4;
346f4786785SAidan Dodds 
347f4786785SAidan Dodds   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
348f4786785SAidan Dodds 
34917e07c0aSAidan Dodds   Error error;
35017e07c0aSAidan Dodds 
351f4786785SAidan Dodds   // get the current stack pointer
352f4786785SAidan Dodds   uint64_t sp = ctx.reg_ctx->GetSP();
353f4786785SAidan Dodds 
354b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; ++i) {
355f4786785SAidan Dodds     bool success = false;
356f4786785SAidan Dodds     ArgItem &arg = arg_list[i];
357f4786785SAidan Dodds     // arguments passed in registers
358b9c1b51eSKate Stone     if (i < c_args_in_reg) {
359b9c1b51eSKate Stone       const RegisterInfo *rArg =
360b9c1b51eSKate Stone           ctx.reg_ctx->GetRegisterInfoAtIndex(i + c_reg_offset);
361f4786785SAidan Dodds       RegisterValue rVal;
362f4786785SAidan Dodds       if (ctx.reg_ctx->ReadRegister(rArg, rVal))
36372f77525SAidan Dodds         arg.value = rVal.GetAsUInt64(0, &success);
364f4786785SAidan Dodds     }
365f4786785SAidan Dodds     // arguments passed on the stack
366b9c1b51eSKate Stone     else {
367f4786785SAidan Dodds       // get the argument type size
368f4786785SAidan Dodds       const size_t arg_size = sizeof(uint64_t);
369f4786785SAidan Dodds       // clear all 64bits
370f4786785SAidan Dodds       arg.value = 0;
371f4786785SAidan Dodds       // read this argument from memory
372b9c1b51eSKate Stone       size_t bytes_read =
373b9c1b51eSKate Stone           ctx.process->ReadMemory(sp, &arg.value, arg_size, error);
374f4786785SAidan Dodds       success = (error.Success() && bytes_read == arg_size);
375f4786785SAidan Dodds       // advance the stack pointer
376f4786785SAidan Dodds       sp += arg_size;
377f4786785SAidan Dodds     }
378f4786785SAidan Dodds     // fail if we couldn't read this argument
379b9c1b51eSKate Stone     if (!success) {
380f4786785SAidan Dodds       if (log)
38117e07c0aSAidan Dodds         log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s",
38217e07c0aSAidan Dodds                     __FUNCTION__, uint64_t(i), error.AsCString("n/a"));
383f4786785SAidan Dodds       return false;
384f4786785SAidan Dodds     }
385f4786785SAidan Dodds   }
386f4786785SAidan Dodds   return true;
387f4786785SAidan Dodds }
388f4786785SAidan Dodds 
389b9c1b51eSKate Stone bool GetArgs(ExecutionContext &context, ArgItem *arg_list, size_t num_args) {
390f4786785SAidan Dodds   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
391f4786785SAidan Dodds 
392f4786785SAidan Dodds   // verify that we have a target
393b9c1b51eSKate Stone   if (!context.GetTargetPtr()) {
394f4786785SAidan Dodds     if (log)
395f4786785SAidan Dodds       log->Printf("%s - invalid target", __FUNCTION__);
396f4786785SAidan Dodds     return false;
397f4786785SAidan Dodds   }
398f4786785SAidan Dodds 
399f4786785SAidan Dodds   GetArgsCtx ctx = {context.GetRegisterContext(), context.GetProcessPtr()};
400f4786785SAidan Dodds   assert(ctx.reg_ctx && ctx.process);
401f4786785SAidan Dodds 
402f4786785SAidan Dodds   // dispatch based on architecture
403b9c1b51eSKate Stone   switch (context.GetTargetPtr()->GetArchitecture().GetMachine()) {
404f4786785SAidan Dodds   case llvm::Triple::ArchType::x86:
405f4786785SAidan Dodds     return GetArgsX86(ctx, arg_list, num_args);
406f4786785SAidan Dodds 
407f4786785SAidan Dodds   case llvm::Triple::ArchType::x86_64:
408f4786785SAidan Dodds     return GetArgsX86_64(ctx, arg_list, num_args);
409f4786785SAidan Dodds 
410f4786785SAidan Dodds   case llvm::Triple::ArchType::arm:
411f4786785SAidan Dodds     return GetArgsArm(ctx, arg_list, num_args);
412f4786785SAidan Dodds 
413f4786785SAidan Dodds   case llvm::Triple::ArchType::aarch64:
414f4786785SAidan Dodds     return GetArgsAarch64(ctx, arg_list, num_args);
415f4786785SAidan Dodds 
416f4786785SAidan Dodds   case llvm::Triple::ArchType::mipsel:
417f4786785SAidan Dodds     return GetArgsMipsel(ctx, arg_list, num_args);
418f4786785SAidan Dodds 
419f4786785SAidan Dodds   case llvm::Triple::ArchType::mips64el:
420f4786785SAidan Dodds     return GetArgsMips64el(ctx, arg_list, num_args);
421f4786785SAidan Dodds 
422f4786785SAidan Dodds   default:
423f4786785SAidan Dodds     // unsupported architecture
424b9c1b51eSKate Stone     if (log) {
425b9c1b51eSKate Stone       log->Printf(
426b9c1b51eSKate Stone           "%s - architecture not supported: '%s'", __FUNCTION__,
427f4786785SAidan Dodds           context.GetTargetRef().GetArchitecture().GetArchitectureName());
428f4786785SAidan Dodds     }
429f4786785SAidan Dodds     return false;
430f4786785SAidan Dodds   }
431f4786785SAidan Dodds }
432222b937cSEugene Zelenko } // anonymous namespace
43378f339d1SEwan Crawford 
434b9c1b51eSKate Stone // The ScriptDetails class collects data associated with a single script
435b9c1b51eSKate Stone // instance.
436b9c1b51eSKate Stone struct RenderScriptRuntime::ScriptDetails {
437222b937cSEugene Zelenko   ~ScriptDetails() = default;
43878f339d1SEwan Crawford 
439b9c1b51eSKate Stone   enum ScriptType { eScript, eScriptC };
44078f339d1SEwan Crawford 
44178f339d1SEwan Crawford   // The derived type of the script.
44278f339d1SEwan Crawford   empirical_type<ScriptType> type;
44378f339d1SEwan Crawford   // The name of the original source file.
44478f339d1SEwan Crawford   empirical_type<std::string> resName;
44578f339d1SEwan Crawford   // Path to script .so file on the device.
44678f339d1SEwan Crawford   empirical_type<std::string> scriptDyLib;
44778f339d1SEwan Crawford   // Directory where kernel objects are cached on device.
44878f339d1SEwan Crawford   empirical_type<std::string> cacheDir;
44978f339d1SEwan Crawford   // Pointer to the context which owns this script.
45078f339d1SEwan Crawford   empirical_type<lldb::addr_t> context;
45178f339d1SEwan Crawford   // Pointer to the script object itself.
45278f339d1SEwan Crawford   empirical_type<lldb::addr_t> script;
45378f339d1SEwan Crawford };
45478f339d1SEwan Crawford 
4558b244e21SEwan Crawford // This Element class represents the Element object in RS,
4568b244e21SEwan Crawford // defining the type associated with an Allocation.
457b9c1b51eSKate Stone struct RenderScriptRuntime::Element {
45815f2bd95SEwan Crawford   // Taken from rsDefines.h
459b9c1b51eSKate Stone   enum DataKind {
46015f2bd95SEwan Crawford     RS_KIND_USER,
46115f2bd95SEwan Crawford     RS_KIND_PIXEL_L = 7,
46215f2bd95SEwan Crawford     RS_KIND_PIXEL_A,
46315f2bd95SEwan Crawford     RS_KIND_PIXEL_LA,
46415f2bd95SEwan Crawford     RS_KIND_PIXEL_RGB,
46515f2bd95SEwan Crawford     RS_KIND_PIXEL_RGBA,
46615f2bd95SEwan Crawford     RS_KIND_PIXEL_DEPTH,
46715f2bd95SEwan Crawford     RS_KIND_PIXEL_YUV,
46815f2bd95SEwan Crawford     RS_KIND_INVALID = 100
46915f2bd95SEwan Crawford   };
47078f339d1SEwan Crawford 
47115f2bd95SEwan Crawford   // Taken from rsDefines.h
472b9c1b51eSKate Stone   enum DataType {
47315f2bd95SEwan Crawford     RS_TYPE_NONE = 0,
47415f2bd95SEwan Crawford     RS_TYPE_FLOAT_16,
47515f2bd95SEwan Crawford     RS_TYPE_FLOAT_32,
47615f2bd95SEwan Crawford     RS_TYPE_FLOAT_64,
47715f2bd95SEwan Crawford     RS_TYPE_SIGNED_8,
47815f2bd95SEwan Crawford     RS_TYPE_SIGNED_16,
47915f2bd95SEwan Crawford     RS_TYPE_SIGNED_32,
48015f2bd95SEwan Crawford     RS_TYPE_SIGNED_64,
48115f2bd95SEwan Crawford     RS_TYPE_UNSIGNED_8,
48215f2bd95SEwan Crawford     RS_TYPE_UNSIGNED_16,
48315f2bd95SEwan Crawford     RS_TYPE_UNSIGNED_32,
48415f2bd95SEwan Crawford     RS_TYPE_UNSIGNED_64,
4852e920715SEwan Crawford     RS_TYPE_BOOLEAN,
4862e920715SEwan Crawford 
4872e920715SEwan Crawford     RS_TYPE_UNSIGNED_5_6_5,
4882e920715SEwan Crawford     RS_TYPE_UNSIGNED_5_5_5_1,
4892e920715SEwan Crawford     RS_TYPE_UNSIGNED_4_4_4_4,
4902e920715SEwan Crawford 
4912e920715SEwan Crawford     RS_TYPE_MATRIX_4X4,
4922e920715SEwan Crawford     RS_TYPE_MATRIX_3X3,
4932e920715SEwan Crawford     RS_TYPE_MATRIX_2X2,
4942e920715SEwan Crawford 
4952e920715SEwan Crawford     RS_TYPE_ELEMENT = 1000,
4962e920715SEwan Crawford     RS_TYPE_TYPE,
4972e920715SEwan Crawford     RS_TYPE_ALLOCATION,
4982e920715SEwan Crawford     RS_TYPE_SAMPLER,
4992e920715SEwan Crawford     RS_TYPE_SCRIPT,
5002e920715SEwan Crawford     RS_TYPE_MESH,
5012e920715SEwan Crawford     RS_TYPE_PROGRAM_FRAGMENT,
5022e920715SEwan Crawford     RS_TYPE_PROGRAM_VERTEX,
5032e920715SEwan Crawford     RS_TYPE_PROGRAM_RASTER,
5042e920715SEwan Crawford     RS_TYPE_PROGRAM_STORE,
5052e920715SEwan Crawford     RS_TYPE_FONT,
5062e920715SEwan Crawford 
5072e920715SEwan Crawford     RS_TYPE_INVALID = 10000
50878f339d1SEwan Crawford   };
50978f339d1SEwan Crawford 
5108b244e21SEwan Crawford   std::vector<Element> children; // Child Element fields for structs
511b9c1b51eSKate Stone   empirical_type<lldb::addr_t>
512b9c1b51eSKate Stone       element_ptr; // Pointer to the RS Element of the Type
513b9c1b51eSKate Stone   empirical_type<DataType>
514b9c1b51eSKate Stone       type; // Type of each data pointer stored by the allocation
515b9c1b51eSKate Stone   empirical_type<DataKind>
516b9c1b51eSKate Stone       type_kind; // Defines pixel type if Allocation is created from an image
517b9c1b51eSKate Stone   empirical_type<uint32_t>
518b9c1b51eSKate Stone       type_vec_size; // Vector size of each data point, e.g '4' for uchar4
5198b244e21SEwan Crawford   empirical_type<uint32_t> field_count; // Number of Subelements
5208b244e21SEwan Crawford   empirical_type<uint32_t> datum_size;  // Size of a single Element with padding
5218b244e21SEwan Crawford   empirical_type<uint32_t> padding;     // Number of padding bytes
522b9c1b51eSKate Stone   empirical_type<uint32_t>
523b9c1b51eSKate Stone       array_size;        // Number of items in array, only needed for strucrs
5248b244e21SEwan Crawford   ConstString type_name; // Name of type, only needed for structs
5258b244e21SEwan Crawford 
526b3f7f69dSAidan Dodds   static const ConstString &
527b3f7f69dSAidan Dodds   GetFallbackStructName(); // Print this as the type name of a struct Element
5288b244e21SEwan Crawford                            // If we can't resolve the actual struct name
5298b59062aSEwan Crawford 
530b9c1b51eSKate Stone   bool shouldRefresh() const {
5318b59062aSEwan Crawford     const bool valid_ptr = element_ptr.isValid() && *element_ptr.get() != 0x0;
532b9c1b51eSKate Stone     const bool valid_type =
533b9c1b51eSKate Stone         type.isValid() && type_vec_size.isValid() && type_kind.isValid();
5348b59062aSEwan Crawford     return !valid_ptr || !valid_type || !datum_size.isValid();
5358b59062aSEwan Crawford   }
5368b244e21SEwan Crawford };
5378b244e21SEwan Crawford 
5388b244e21SEwan Crawford // This AllocationDetails class collects data associated with a single
5398b244e21SEwan Crawford // allocation instance.
540b9c1b51eSKate Stone struct RenderScriptRuntime::AllocationDetails {
541b9c1b51eSKate Stone   struct Dimension {
54215f2bd95SEwan Crawford     uint32_t dim_1;
54315f2bd95SEwan Crawford     uint32_t dim_2;
54415f2bd95SEwan Crawford     uint32_t dim_3;
54515f2bd95SEwan Crawford     uint32_t cubeMap;
54615f2bd95SEwan Crawford 
547b9c1b51eSKate Stone     Dimension() {
54815f2bd95SEwan Crawford       dim_1 = 0;
54915f2bd95SEwan Crawford       dim_2 = 0;
55015f2bd95SEwan Crawford       dim_3 = 0;
55115f2bd95SEwan Crawford       cubeMap = 0;
55215f2bd95SEwan Crawford     }
55378f339d1SEwan Crawford   };
55478f339d1SEwan Crawford 
555b9c1b51eSKate Stone   // The FileHeader struct specifies the header we use for writing allocations
556b9c1b51eSKate Stone   // to a binary file.
557b9c1b51eSKate Stone   // Our format begins with the ASCII characters "RSAD", identifying the file as
558b9c1b51eSKate Stone   // an allocation dump.
559b9c1b51eSKate Stone   // Member variables dims and hdr_size are then written consecutively,
560b9c1b51eSKate Stone   // immediately followed by an instance of
561b9c1b51eSKate Stone   // the ElementHeader struct. Because Elements can contain subelements, there
562b9c1b51eSKate Stone   // may be more than one instance
563b9c1b51eSKate Stone   // of the ElementHeader struct. With this first instance being the root
564b9c1b51eSKate Stone   // element, and the other instances being
565b9c1b51eSKate Stone   // the root's descendants. To identify which instances are an ElementHeader's
566b9c1b51eSKate Stone   // children, each struct
567b9c1b51eSKate Stone   // is immediately followed by a sequence of consecutive offsets to the start
568b9c1b51eSKate Stone   // of its child structs.
569b9c1b51eSKate Stone   // These offsets are 4 bytes in size, and the 0 offset signifies no more
570b9c1b51eSKate Stone   // children.
571b9c1b51eSKate Stone   struct FileHeader {
57255232f09SEwan Crawford     uint8_t ident[4];  // ASCII 'RSAD' identifying the file
57326e52a70SEwan Crawford     uint32_t dims[3];  // Dimensions
57426e52a70SEwan Crawford     uint16_t hdr_size; // Header size in bytes, including all element headers
57526e52a70SEwan Crawford   };
57626e52a70SEwan Crawford 
577b9c1b51eSKate Stone   struct ElementHeader {
57855232f09SEwan Crawford     uint16_t type;         // DataType enum
57955232f09SEwan Crawford     uint32_t kind;         // DataKind enum
58055232f09SEwan Crawford     uint32_t element_size; // Size of a single element, including padding
58126e52a70SEwan Crawford     uint16_t vector_size;  // Vector width
58226e52a70SEwan Crawford     uint32_t array_size;   // Number of elements in array
58355232f09SEwan Crawford   };
58455232f09SEwan Crawford 
58515f2bd95SEwan Crawford   // Monotonically increasing from 1
586b3f7f69dSAidan Dodds   static uint32_t ID;
58715f2bd95SEwan Crawford 
58815f2bd95SEwan Crawford   // Maps Allocation DataType enum and vector size to printable strings
58915f2bd95SEwan Crawford   // using mapping from RenderScript numerical types summary documentation
59015f2bd95SEwan Crawford   static const char *RsDataTypeToString[][4];
59115f2bd95SEwan Crawford 
59215f2bd95SEwan Crawford   // Maps Allocation DataKind enum to printable strings
59315f2bd95SEwan Crawford   static const char *RsDataKindToString[];
59415f2bd95SEwan Crawford 
595a0f08674SEwan Crawford   // Maps allocation types to format sizes for printing.
596b3f7f69dSAidan Dodds   static const uint32_t RSTypeToFormat[][3];
597a0f08674SEwan Crawford 
59815f2bd95SEwan Crawford   // Give each allocation an ID as a way
59915f2bd95SEwan Crawford   // for commands to reference it.
600b3f7f69dSAidan Dodds   const uint32_t id;
60115f2bd95SEwan Crawford 
6028b244e21SEwan Crawford   RenderScriptRuntime::Element element; // Allocation Element type
60315f2bd95SEwan Crawford   empirical_type<Dimension> dimension;  // Dimensions of the Allocation
604b9c1b51eSKate Stone   empirical_type<lldb::addr_t>
605b9c1b51eSKate Stone       address; // Pointer to address of the RS Allocation
606b9c1b51eSKate Stone   empirical_type<lldb::addr_t>
607b9c1b51eSKate Stone       data_ptr; // Pointer to the data held by the Allocation
608b9c1b51eSKate Stone   empirical_type<lldb::addr_t>
609b9c1b51eSKate Stone       type_ptr; // Pointer to the RS Type of the Allocation
610b9c1b51eSKate Stone   empirical_type<lldb::addr_t>
611b9c1b51eSKate Stone       context;                   // Pointer to the RS Context of the Allocation
612a0f08674SEwan Crawford   empirical_type<uint32_t> size; // Size of the allocation
613a0f08674SEwan Crawford   empirical_type<uint32_t> stride; // Stride between rows of the allocation
61415f2bd95SEwan Crawford 
61515f2bd95SEwan Crawford   // Give each allocation an id, so we can reference it in user commands.
616b3f7f69dSAidan Dodds   AllocationDetails() : id(ID++) {}
6178b59062aSEwan Crawford 
618b9c1b51eSKate Stone   bool shouldRefresh() const {
6198b59062aSEwan Crawford     bool valid_ptrs = data_ptr.isValid() && *data_ptr.get() != 0x0;
6208b59062aSEwan Crawford     valid_ptrs = valid_ptrs && type_ptr.isValid() && *type_ptr.get() != 0x0;
621b9c1b51eSKate Stone     return !valid_ptrs || !dimension.isValid() || !size.isValid() ||
622b9c1b51eSKate Stone            element.shouldRefresh();
6238b59062aSEwan Crawford   }
62415f2bd95SEwan Crawford };
62515f2bd95SEwan Crawford 
626b9c1b51eSKate Stone const ConstString &RenderScriptRuntime::Element::GetFallbackStructName() {
627fe06b5adSAdrian McCarthy   static const ConstString FallbackStructName("struct");
628fe06b5adSAdrian McCarthy   return FallbackStructName;
629fe06b5adSAdrian McCarthy }
6308b244e21SEwan Crawford 
631b3f7f69dSAidan Dodds uint32_t RenderScriptRuntime::AllocationDetails::ID = 1;
63215f2bd95SEwan Crawford 
633b3f7f69dSAidan Dodds const char *RenderScriptRuntime::AllocationDetails::RsDataKindToString[] = {
634b9c1b51eSKate Stone     "User",       "Undefined",   "Undefined", "Undefined",
635b9c1b51eSKate Stone     "Undefined",  "Undefined",   "Undefined", // Enum jumps from 0 to 7
636b3f7f69dSAidan Dodds     "L Pixel",    "A Pixel",     "LA Pixel",  "RGB Pixel",
637b3f7f69dSAidan Dodds     "RGBA Pixel", "Pixel Depth", "YUV Pixel"};
63815f2bd95SEwan Crawford 
639b3f7f69dSAidan Dodds const char *RenderScriptRuntime::AllocationDetails::RsDataTypeToString[][4] = {
64015f2bd95SEwan Crawford     {"None", "None", "None", "None"},
64115f2bd95SEwan Crawford     {"half", "half2", "half3", "half4"},
64215f2bd95SEwan Crawford     {"float", "float2", "float3", "float4"},
64315f2bd95SEwan Crawford     {"double", "double2", "double3", "double4"},
64415f2bd95SEwan Crawford     {"char", "char2", "char3", "char4"},
64515f2bd95SEwan Crawford     {"short", "short2", "short3", "short4"},
64615f2bd95SEwan Crawford     {"int", "int2", "int3", "int4"},
64715f2bd95SEwan Crawford     {"long", "long2", "long3", "long4"},
64815f2bd95SEwan Crawford     {"uchar", "uchar2", "uchar3", "uchar4"},
64915f2bd95SEwan Crawford     {"ushort", "ushort2", "ushort3", "ushort4"},
65015f2bd95SEwan Crawford     {"uint", "uint2", "uint3", "uint4"},
65115f2bd95SEwan Crawford     {"ulong", "ulong2", "ulong3", "ulong4"},
6522e920715SEwan Crawford     {"bool", "bool2", "bool3", "bool4"},
6532e920715SEwan Crawford     {"packed_565", "packed_565", "packed_565", "packed_565"},
6542e920715SEwan Crawford     {"packed_5551", "packed_5551", "packed_5551", "packed_5551"},
6552e920715SEwan Crawford     {"packed_4444", "packed_4444", "packed_4444", "packed_4444"},
6562e920715SEwan Crawford     {"rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4"},
6572e920715SEwan Crawford     {"rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3"},
6582e920715SEwan Crawford     {"rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2"},
6592e920715SEwan Crawford 
6602e920715SEwan Crawford     // Handlers
6612e920715SEwan Crawford     {"RS Element", "RS Element", "RS Element", "RS Element"},
6622e920715SEwan Crawford     {"RS Type", "RS Type", "RS Type", "RS Type"},
6632e920715SEwan Crawford     {"RS Allocation", "RS Allocation", "RS Allocation", "RS Allocation"},
6642e920715SEwan Crawford     {"RS Sampler", "RS Sampler", "RS Sampler", "RS Sampler"},
6652e920715SEwan Crawford     {"RS Script", "RS Script", "RS Script", "RS Script"},
6662e920715SEwan Crawford 
6672e920715SEwan Crawford     // Deprecated
6682e920715SEwan Crawford     {"RS Mesh", "RS Mesh", "RS Mesh", "RS Mesh"},
669b9c1b51eSKate Stone     {"RS Program Fragment", "RS Program Fragment", "RS Program Fragment",
670b9c1b51eSKate Stone      "RS Program Fragment"},
671b9c1b51eSKate Stone     {"RS Program Vertex", "RS Program Vertex", "RS Program Vertex",
672b9c1b51eSKate Stone      "RS Program Vertex"},
673b9c1b51eSKate Stone     {"RS Program Raster", "RS Program Raster", "RS Program Raster",
674b9c1b51eSKate Stone      "RS Program Raster"},
675b9c1b51eSKate Stone     {"RS Program Store", "RS Program Store", "RS Program Store",
676b9c1b51eSKate Stone      "RS Program Store"},
677b3f7f69dSAidan Dodds     {"RS Font", "RS Font", "RS Font", "RS Font"}};
67878f339d1SEwan Crawford 
679a0f08674SEwan Crawford // Used as an index into the RSTypeToFormat array elements
680b9c1b51eSKate Stone enum TypeToFormatIndex { eFormatSingle = 0, eFormatVector, eElementSize };
681a0f08674SEwan Crawford 
682b9c1b51eSKate Stone // { format enum of single element, format enum of element vector, size of
683b9c1b51eSKate Stone // element}
684b3f7f69dSAidan Dodds const uint32_t RenderScriptRuntime::AllocationDetails::RSTypeToFormat[][3] = {
685a0f08674SEwan Crawford     {eFormatHex, eFormatHex, 1},                            // RS_TYPE_NONE
686a0f08674SEwan Crawford     {eFormatFloat, eFormatVectorOfFloat16, 2},              // RS_TYPE_FLOAT_16
687a0f08674SEwan Crawford     {eFormatFloat, eFormatVectorOfFloat32, sizeof(float)},  // RS_TYPE_FLOAT_32
688a0f08674SEwan Crawford     {eFormatFloat, eFormatVectorOfFloat64, sizeof(double)}, // RS_TYPE_FLOAT_64
689a0f08674SEwan Crawford     {eFormatDecimal, eFormatVectorOfSInt8, sizeof(int8_t)}, // RS_TYPE_SIGNED_8
690b9c1b51eSKate Stone     {eFormatDecimal, eFormatVectorOfSInt16,
691b9c1b51eSKate Stone      sizeof(int16_t)}, // RS_TYPE_SIGNED_16
692b9c1b51eSKate Stone     {eFormatDecimal, eFormatVectorOfSInt32,
693b9c1b51eSKate Stone      sizeof(int32_t)}, // RS_TYPE_SIGNED_32
694b9c1b51eSKate Stone     {eFormatDecimal, eFormatVectorOfSInt64,
695b9c1b51eSKate Stone      sizeof(int64_t)}, // RS_TYPE_SIGNED_64
696b9c1b51eSKate Stone     {eFormatDecimal, eFormatVectorOfUInt8,
697b9c1b51eSKate Stone      sizeof(uint8_t)}, // RS_TYPE_UNSIGNED_8
698b9c1b51eSKate Stone     {eFormatDecimal, eFormatVectorOfUInt16,
699b9c1b51eSKate Stone      sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_16
700b9c1b51eSKate Stone     {eFormatDecimal, eFormatVectorOfUInt32,
701b9c1b51eSKate Stone      sizeof(uint32_t)}, // RS_TYPE_UNSIGNED_32
702b9c1b51eSKate Stone     {eFormatDecimal, eFormatVectorOfUInt64,
703b9c1b51eSKate Stone      sizeof(uint64_t)},                         // RS_TYPE_UNSIGNED_64
7042e920715SEwan Crawford     {eFormatBoolean, eFormatBoolean, 1},        // RS_TYPE_BOOL
7052e920715SEwan Crawford     {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_6_5
7062e920715SEwan Crawford     {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_5_5_1
7072e920715SEwan Crawford     {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_4_4_4_4
708b9c1b51eSKate Stone     {eFormatVectorOfFloat32, eFormatVectorOfFloat32,
709b9c1b51eSKate Stone      sizeof(float) * 16}, // RS_TYPE_MATRIX_4X4
710b9c1b51eSKate Stone     {eFormatVectorOfFloat32, eFormatVectorOfFloat32,
711b9c1b51eSKate Stone      sizeof(float) * 9}, // RS_TYPE_MATRIX_3X3
712b9c1b51eSKate Stone     {eFormatVectorOfFloat32, eFormatVectorOfFloat32,
713b9c1b51eSKate Stone      sizeof(float) * 4} // RS_TYPE_MATRIX_2X2
714a0f08674SEwan Crawford };
715a0f08674SEwan Crawford 
7165ec532a9SColin Riley //------------------------------------------------------------------
7175ec532a9SColin Riley // Static Functions
7185ec532a9SColin Riley //------------------------------------------------------------------
7195ec532a9SColin Riley LanguageRuntime *
720b9c1b51eSKate Stone RenderScriptRuntime::CreateInstance(Process *process,
721b9c1b51eSKate Stone                                     lldb::LanguageType language) {
7225ec532a9SColin Riley 
7235ec532a9SColin Riley   if (language == eLanguageTypeExtRenderScript)
7245ec532a9SColin Riley     return new RenderScriptRuntime(process);
7255ec532a9SColin Riley   else
726b3f7f69dSAidan Dodds     return nullptr;
7275ec532a9SColin Riley }
7285ec532a9SColin Riley 
72998156583SEwan Crawford // Callback with a module to search for matching symbols.
73098156583SEwan Crawford // We first check that the module contains RS kernels.
73198156583SEwan Crawford // Then look for a symbol which matches our kernel name.
73298156583SEwan Crawford // The breakpoint address is finally set using the address of this symbol.
73398156583SEwan Crawford Searcher::CallbackReturn
734b9c1b51eSKate Stone RSBreakpointResolver::SearchCallback(SearchFilter &filter,
735b9c1b51eSKate Stone                                      SymbolContext &context, Address *, bool) {
73698156583SEwan Crawford   ModuleSP module = context.module_sp;
73798156583SEwan Crawford 
73898156583SEwan Crawford   if (!module)
73998156583SEwan Crawford     return Searcher::eCallbackReturnContinue;
74098156583SEwan Crawford 
74198156583SEwan Crawford   // Is this a module containing renderscript kernels?
742b9c1b51eSKate Stone   if (nullptr ==
743b9c1b51eSKate Stone       module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"),
744b9c1b51eSKate Stone                                              eSymbolTypeData))
74598156583SEwan Crawford     return Searcher::eCallbackReturnContinue;
74698156583SEwan Crawford 
747b9c1b51eSKate Stone   // Attempt to set a breakpoint on the kernel name symbol within the module
748b9c1b51eSKate Stone   // library.
74998156583SEwan Crawford   // If it's not found, it's likely debug info is unavailable - try to set a
75098156583SEwan Crawford   // breakpoint on <name>.expand.
75198156583SEwan Crawford 
752b9c1b51eSKate Stone   const Symbol *kernel_sym =
753b9c1b51eSKate Stone       module->FindFirstSymbolWithNameAndType(m_kernel_name, eSymbolTypeCode);
754b9c1b51eSKate Stone   if (!kernel_sym) {
75598156583SEwan Crawford     std::string kernel_name_expanded(m_kernel_name.AsCString());
75698156583SEwan Crawford     kernel_name_expanded.append(".expand");
757b9c1b51eSKate Stone     kernel_sym = module->FindFirstSymbolWithNameAndType(
758b9c1b51eSKate Stone         ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode);
75998156583SEwan Crawford   }
76098156583SEwan Crawford 
761b9c1b51eSKate Stone   if (kernel_sym) {
76298156583SEwan Crawford     Address bp_addr = kernel_sym->GetAddress();
76398156583SEwan Crawford     if (filter.AddressPasses(bp_addr))
76498156583SEwan Crawford       m_breakpoint->AddLocation(bp_addr);
76598156583SEwan Crawford   }
76698156583SEwan Crawford 
76798156583SEwan Crawford   return Searcher::eCallbackReturnContinue;
76898156583SEwan Crawford }
76998156583SEwan Crawford 
770b9c1b51eSKate Stone void RenderScriptRuntime::Initialize() {
771b9c1b51eSKate Stone   PluginManager::RegisterPlugin(GetPluginNameStatic(),
772b9c1b51eSKate Stone                                 "RenderScript language support", CreateInstance,
773b3f7f69dSAidan Dodds                                 GetCommandObject);
7745ec532a9SColin Riley }
7755ec532a9SColin Riley 
776b9c1b51eSKate Stone void RenderScriptRuntime::Terminate() {
7775ec532a9SColin Riley   PluginManager::UnregisterPlugin(CreateInstance);
7785ec532a9SColin Riley }
7795ec532a9SColin Riley 
780b9c1b51eSKate Stone lldb_private::ConstString RenderScriptRuntime::GetPluginNameStatic() {
7815ec532a9SColin Riley   static ConstString g_name("renderscript");
7825ec532a9SColin Riley   return g_name;
7835ec532a9SColin Riley }
7845ec532a9SColin Riley 
785ef20b08fSColin Riley RenderScriptRuntime::ModuleKind
786b9c1b51eSKate Stone RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp) {
787b9c1b51eSKate Stone   if (module_sp) {
788ef20b08fSColin Riley     // Is this a module containing renderscript kernels?
789b9c1b51eSKate Stone     const Symbol *info_sym = module_sp->FindFirstSymbolWithNameAndType(
790b9c1b51eSKate Stone         ConstString(".rs.info"), eSymbolTypeData);
791b9c1b51eSKate Stone     if (info_sym) {
792ef20b08fSColin Riley       return eModuleKindKernelObj;
793ef20b08fSColin Riley     }
7944640cde1SColin Riley 
7954640cde1SColin Riley     // Is this the main RS runtime library
7964640cde1SColin Riley     const ConstString rs_lib("libRS.so");
797b9c1b51eSKate Stone     if (module_sp->GetFileSpec().GetFilename() == rs_lib) {
7984640cde1SColin Riley       return eModuleKindLibRS;
7994640cde1SColin Riley     }
8004640cde1SColin Riley 
8014640cde1SColin Riley     const ConstString rs_driverlib("libRSDriver.so");
802b9c1b51eSKate Stone     if (module_sp->GetFileSpec().GetFilename() == rs_driverlib) {
8034640cde1SColin Riley       return eModuleKindDriver;
8044640cde1SColin Riley     }
8054640cde1SColin Riley 
80615f2bd95SEwan Crawford     const ConstString rs_cpureflib("libRSCpuRef.so");
807b9c1b51eSKate Stone     if (module_sp->GetFileSpec().GetFilename() == rs_cpureflib) {
8084640cde1SColin Riley       return eModuleKindImpl;
8094640cde1SColin Riley     }
810ef20b08fSColin Riley   }
811ef20b08fSColin Riley   return eModuleKindIgnored;
812ef20b08fSColin Riley }
813ef20b08fSColin Riley 
814b9c1b51eSKate Stone bool RenderScriptRuntime::IsRenderScriptModule(
815b9c1b51eSKate Stone     const lldb::ModuleSP &module_sp) {
816ef20b08fSColin Riley   return GetModuleKind(module_sp) != eModuleKindIgnored;
817ef20b08fSColin Riley }
818ef20b08fSColin Riley 
819b9c1b51eSKate Stone void RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list) {
820bb19a13cSSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
821ef20b08fSColin Riley 
822ef20b08fSColin Riley   size_t num_modules = module_list.GetSize();
823b9c1b51eSKate Stone   for (size_t i = 0; i < num_modules; i++) {
824ef20b08fSColin Riley     auto mod = module_list.GetModuleAtIndex(i);
825b9c1b51eSKate Stone     if (IsRenderScriptModule(mod)) {
826ef20b08fSColin Riley       LoadModule(mod);
827ef20b08fSColin Riley     }
828ef20b08fSColin Riley   }
829ef20b08fSColin Riley }
830ef20b08fSColin Riley 
8315ec532a9SColin Riley //------------------------------------------------------------------
8325ec532a9SColin Riley // PluginInterface protocol
8335ec532a9SColin Riley //------------------------------------------------------------------
834b9c1b51eSKate Stone lldb_private::ConstString RenderScriptRuntime::GetPluginName() {
8355ec532a9SColin Riley   return GetPluginNameStatic();
8365ec532a9SColin Riley }
8375ec532a9SColin Riley 
838b9c1b51eSKate Stone uint32_t RenderScriptRuntime::GetPluginVersion() { return 1; }
8395ec532a9SColin Riley 
840b9c1b51eSKate Stone bool RenderScriptRuntime::IsVTableName(const char *name) { return false; }
8415ec532a9SColin Riley 
842b9c1b51eSKate Stone bool RenderScriptRuntime::GetDynamicTypeAndAddress(
843b9c1b51eSKate Stone     ValueObject &in_value, lldb::DynamicValueType use_dynamic,
8445f57b6eeSEnrico Granata     TypeAndOrName &class_type_or_name, Address &address,
845b9c1b51eSKate Stone     Value::ValueType &value_type) {
8465ec532a9SColin Riley   return false;
8475ec532a9SColin Riley }
8485ec532a9SColin Riley 
849c74275bcSEnrico Granata TypeAndOrName
850b9c1b51eSKate Stone RenderScriptRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
851b9c1b51eSKate Stone                                       ValueObject &static_value) {
852c74275bcSEnrico Granata   return type_and_or_name;
853c74275bcSEnrico Granata }
854c74275bcSEnrico Granata 
855b9c1b51eSKate Stone bool RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
8565ec532a9SColin Riley   return false;
8575ec532a9SColin Riley }
8585ec532a9SColin Riley 
8595ec532a9SColin Riley lldb::BreakpointResolverSP
860b9c1b51eSKate Stone RenderScriptRuntime::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp,
861b9c1b51eSKate Stone                                              bool throw_bp) {
8625ec532a9SColin Riley   BreakpointResolverSP resolver_sp;
8635ec532a9SColin Riley   return resolver_sp;
8645ec532a9SColin Riley }
8655ec532a9SColin Riley 
866b9c1b51eSKate Stone const RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] =
867b9c1b51eSKate Stone     {
8684640cde1SColin Riley         // rsdScript
869b9c1b51eSKate Stone         {"rsdScriptInit", "_Z13rsdScriptInitPKN7android12renderscript7ContextEP"
870b9c1b51eSKate Stone                           "NS0_7ScriptCEPKcS7_PKhjj",
871b9c1b51eSKate Stone          "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_"
872b9c1b51eSKate Stone          "7ScriptCEPKcS7_PKhmj",
873b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
874b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureScriptInit},
875b9c1b51eSKate Stone         {"rsdScriptInvokeForEachMulti",
876b9c1b51eSKate Stone          "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0"
877b9c1b51eSKate Stone          "_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall",
878b9c1b51eSKate Stone          "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0"
879b9c1b51eSKate Stone          "_6ScriptEjPPKNS0_10AllocationEmPS6_PKvmPK12RsScriptCall",
880b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
881b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureScriptInvokeForEachMulti},
882b9c1b51eSKate Stone         {"rsdScriptSetGlobalVar", "_Z21rsdScriptSetGlobalVarPKN7android12render"
883b9c1b51eSKate Stone                                   "script7ContextEPKNS0_6ScriptEjPvj",
884b9c1b51eSKate Stone          "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_"
885b9c1b51eSKate Stone          "6ScriptEjPvm",
886b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
887b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar},
8884640cde1SColin Riley 
8894640cde1SColin Riley         // rsdAllocation
890b9c1b51eSKate Stone         {"rsdAllocationInit", "_Z17rsdAllocationInitPKN7android12renderscript7C"
891b9c1b51eSKate Stone                               "ontextEPNS0_10AllocationEb",
892b9c1b51eSKate Stone          "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_"
893b9c1b51eSKate Stone          "10AllocationEb",
894b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
895b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureAllocationInit},
896b9c1b51eSKate Stone         {"rsdAllocationRead2D",
897b9c1b51eSKate Stone          "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_"
898b9c1b51eSKate Stone          "10AllocationEjjj23RsAllocationCubemapFacejjPvjj",
899b9c1b51eSKate Stone          "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_"
900b9c1b51eSKate Stone          "10AllocationEjjj23RsAllocationCubemapFacejjPvmm",
901b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver, nullptr},
902b9c1b51eSKate Stone         {"rsdAllocationDestroy", "_Z20rsdAllocationDestroyPKN7android12rendersc"
903b9c1b51eSKate Stone                                  "ript7ContextEPNS0_10AllocationE",
904b9c1b51eSKate Stone          "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_"
905b9c1b51eSKate Stone          "10AllocationE",
906b9c1b51eSKate Stone          0, RenderScriptRuntime::eModuleKindDriver,
907b9c1b51eSKate Stone          &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy},
9084640cde1SColin Riley };
9094640cde1SColin Riley 
910b9c1b51eSKate Stone const size_t RenderScriptRuntime::s_runtimeHookCount =
911b9c1b51eSKate Stone     sizeof(s_runtimeHookDefns) / sizeof(s_runtimeHookDefns[0]);
9124640cde1SColin Riley 
913b9c1b51eSKate Stone bool RenderScriptRuntime::HookCallback(void *baton,
914b9c1b51eSKate Stone                                        StoppointCallbackContext *ctx,
915b9c1b51eSKate Stone                                        lldb::user_id_t break_id,
916b9c1b51eSKate Stone                                        lldb::user_id_t break_loc_id) {
9174640cde1SColin Riley   RuntimeHook *hook_info = (RuntimeHook *)baton;
9184640cde1SColin Riley   ExecutionContext context(ctx->exe_ctx_ref);
9194640cde1SColin Riley 
920b3f7f69dSAidan Dodds   RenderScriptRuntime *lang_rt =
921b9c1b51eSKate Stone       (RenderScriptRuntime *)context.GetProcessPtr()->GetLanguageRuntime(
922b9c1b51eSKate Stone           eLanguageTypeExtRenderScript);
9234640cde1SColin Riley 
9244640cde1SColin Riley   lang_rt->HookCallback(hook_info, context);
9254640cde1SColin Riley 
9264640cde1SColin Riley   return false;
9274640cde1SColin Riley }
9284640cde1SColin Riley 
929b9c1b51eSKate Stone void RenderScriptRuntime::HookCallback(RuntimeHook *hook_info,
930b9c1b51eSKate Stone                                        ExecutionContext &context) {
9314640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
9324640cde1SColin Riley 
9334640cde1SColin Riley   if (log)
934b3f7f69dSAidan Dodds     log->Printf("%s - '%s'", __FUNCTION__, hook_info->defn->name);
9354640cde1SColin Riley 
936b9c1b51eSKate Stone   if (hook_info->defn->grabber) {
9374640cde1SColin Riley     (this->*(hook_info->defn->grabber))(hook_info, context);
9384640cde1SColin Riley   }
9394640cde1SColin Riley }
9404640cde1SColin Riley 
941b9c1b51eSKate Stone void RenderScriptRuntime::CaptureScriptInvokeForEachMulti(
942b9c1b51eSKate Stone     RuntimeHook *hook_info, ExecutionContext &context) {
943e09c44b6SAidan Dodds   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
944e09c44b6SAidan Dodds 
945b9c1b51eSKate Stone   enum {
946f4786785SAidan Dodds     eRsContext = 0,
947f4786785SAidan Dodds     eRsScript,
948f4786785SAidan Dodds     eRsSlot,
949f4786785SAidan Dodds     eRsAIns,
950f4786785SAidan Dodds     eRsInLen,
951f4786785SAidan Dodds     eRsAOut,
952f4786785SAidan Dodds     eRsUsr,
953f4786785SAidan Dodds     eRsUsrLen,
954f4786785SAidan Dodds     eRsSc,
955f4786785SAidan Dodds   };
956e09c44b6SAidan Dodds 
9571ee07253SSaleem Abdulrasool   std::array<ArgItem, 9> args{{
958f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // const Context       *rsc
959f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // Script              *s
960f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // uint32_t             slot
961f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // const Allocation   **aIns
962f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // size_t               inLen
963f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // Allocation          *aout
964f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // const void          *usr
965f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // size_t               usrLen
966f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // const RsScriptCall  *sc
9671ee07253SSaleem Abdulrasool   }};
968e09c44b6SAidan Dodds 
969f4786785SAidan Dodds   bool success = GetArgs(context, &args[0], args.size());
970b9c1b51eSKate Stone   if (!success) {
971e09c44b6SAidan Dodds     if (log)
972b9c1b51eSKate Stone       log->Printf("%s - Error while reading the function parameters",
973b9c1b51eSKate Stone                   __FUNCTION__);
974e09c44b6SAidan Dodds     return;
975e09c44b6SAidan Dodds   }
976e09c44b6SAidan Dodds 
977e09c44b6SAidan Dodds   const uint32_t target_ptr_size = m_process->GetAddressByteSize();
978e09c44b6SAidan Dodds   Error error;
979e09c44b6SAidan Dodds   std::vector<uint64_t> allocs;
980e09c44b6SAidan Dodds 
981e09c44b6SAidan Dodds   // traverse allocation list
982b9c1b51eSKate Stone   for (uint64_t i = 0; i < uint64_t(args[eRsInLen]); ++i) {
983e09c44b6SAidan Dodds     // calculate offest to allocation pointer
984f4786785SAidan Dodds     const addr_t addr = addr_t(args[eRsAIns]) + i * target_ptr_size;
985e09c44b6SAidan Dodds 
986b9c1b51eSKate Stone     // Note: due to little endian layout, reading 32bits or 64bits into res64
987b9c1b51eSKate Stone     // will
988e09c44b6SAidan Dodds     //       give the correct results.
989e09c44b6SAidan Dodds 
990e09c44b6SAidan Dodds     uint64_t res64 = 0;
991e09c44b6SAidan Dodds     size_t read = m_process->ReadMemory(addr, &res64, target_ptr_size, error);
992b9c1b51eSKate Stone     if (read != target_ptr_size || !error.Success()) {
993e09c44b6SAidan Dodds       if (log)
994b9c1b51eSKate Stone         log->Printf(
995b9c1b51eSKate Stone             "%s - Error while reading allocation list argument %" PRIu64,
996b9c1b51eSKate Stone             __FUNCTION__, i);
997b9c1b51eSKate Stone     } else {
998e09c44b6SAidan Dodds       allocs.push_back(res64);
999e09c44b6SAidan Dodds     }
1000e09c44b6SAidan Dodds   }
1001e09c44b6SAidan Dodds 
1002e09c44b6SAidan Dodds   // if there is an output allocation track it
1003b9c1b51eSKate Stone   if (uint64_t aOut = uint64_t(args[eRsAOut])) {
1004f4786785SAidan Dodds     allocs.push_back(aOut);
1005e09c44b6SAidan Dodds   }
1006e09c44b6SAidan Dodds 
1007e09c44b6SAidan Dodds   // for all allocations we have found
1008b9c1b51eSKate Stone   for (const uint64_t alloc_addr : allocs) {
10095d057637SLuke Drummond     AllocationDetails *alloc = LookUpAllocation(alloc_addr);
10105d057637SLuke Drummond     if (!alloc)
10115d057637SLuke Drummond       alloc = CreateAllocation(alloc_addr);
10125d057637SLuke Drummond 
1013b9c1b51eSKate Stone     if (alloc) {
1014e09c44b6SAidan Dodds       // save the allocation address
1015b9c1b51eSKate Stone       if (alloc->address.isValid()) {
1016e09c44b6SAidan Dodds         // check the allocation address we already have matches
1017e09c44b6SAidan Dodds         assert(*alloc->address.get() == alloc_addr);
1018b9c1b51eSKate Stone       } else {
1019e09c44b6SAidan Dodds         alloc->address = alloc_addr;
1020e09c44b6SAidan Dodds       }
1021e09c44b6SAidan Dodds 
1022e09c44b6SAidan Dodds       // save the context
1023b9c1b51eSKate Stone       if (log) {
1024b9c1b51eSKate Stone         if (alloc->context.isValid() &&
1025b9c1b51eSKate Stone             *alloc->context.get() != addr_t(args[eRsContext]))
1026b9c1b51eSKate Stone           log->Printf("%s - Allocation used by multiple contexts",
1027b9c1b51eSKate Stone                       __FUNCTION__);
1028e09c44b6SAidan Dodds       }
1029f4786785SAidan Dodds       alloc->context = addr_t(args[eRsContext]);
1030e09c44b6SAidan Dodds     }
1031e09c44b6SAidan Dodds   }
1032e09c44b6SAidan Dodds 
1033e09c44b6SAidan Dodds   // make sure we track this script object
1034b9c1b51eSKate Stone   if (lldb_private::RenderScriptRuntime::ScriptDetails *script =
1035b9c1b51eSKate Stone           LookUpScript(addr_t(args[eRsScript]), true)) {
1036b9c1b51eSKate Stone     if (log) {
1037b9c1b51eSKate Stone       if (script->context.isValid() &&
1038b9c1b51eSKate Stone           *script->context.get() != addr_t(args[eRsContext]))
1039b3f7f69dSAidan Dodds         log->Printf("%s - Script used by multiple contexts", __FUNCTION__);
1040e09c44b6SAidan Dodds     }
1041f4786785SAidan Dodds     script->context = addr_t(args[eRsContext]);
1042e09c44b6SAidan Dodds   }
1043e09c44b6SAidan Dodds }
1044e09c44b6SAidan Dodds 
1045b9c1b51eSKate Stone void RenderScriptRuntime::CaptureSetGlobalVar(RuntimeHook *hook_info,
1046b9c1b51eSKate Stone                                               ExecutionContext &context) {
10474640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
10484640cde1SColin Riley 
1049b9c1b51eSKate Stone   enum {
1050f4786785SAidan Dodds     eRsContext,
1051f4786785SAidan Dodds     eRsScript,
1052f4786785SAidan Dodds     eRsId,
1053f4786785SAidan Dodds     eRsData,
1054f4786785SAidan Dodds     eRsLength,
1055f4786785SAidan Dodds   };
10564640cde1SColin Riley 
10571ee07253SSaleem Abdulrasool   std::array<ArgItem, 5> args{{
1058f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsContext
1059f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsScript
1060f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // eRsId
1061f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsData
1062f4786785SAidan Dodds       ArgItem{ArgItem::eInt32, 0},   // eRsLength
10631ee07253SSaleem Abdulrasool   }};
10644640cde1SColin Riley 
1065f4786785SAidan Dodds   bool success = GetArgs(context, &args[0], args.size());
1066b9c1b51eSKate Stone   if (!success) {
106782780287SAidan Dodds     if (log)
1068b3f7f69dSAidan Dodds       log->Printf("%s - error reading the function parameters.", __FUNCTION__);
106982780287SAidan Dodds     return;
107082780287SAidan Dodds   }
10714640cde1SColin Riley 
1072b9c1b51eSKate Stone   if (log) {
1073b9c1b51eSKate Stone     log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64
1074b9c1b51eSKate Stone                 ":%" PRIu64 "bytes.",
1075b9c1b51eSKate Stone                 __FUNCTION__, uint64_t(args[eRsContext]),
1076b9c1b51eSKate Stone                 uint64_t(args[eRsScript]), uint64_t(args[eRsId]),
1077f4786785SAidan Dodds                 uint64_t(args[eRsData]), uint64_t(args[eRsLength]));
10784640cde1SColin Riley 
1079f4786785SAidan Dodds     addr_t script_addr = addr_t(args[eRsScript]);
1080b9c1b51eSKate Stone     if (m_scriptMappings.find(script_addr) != m_scriptMappings.end()) {
10814640cde1SColin Riley       auto rsm = m_scriptMappings[script_addr];
1082b9c1b51eSKate Stone       if (uint64_t(args[eRsId]) < rsm->m_globals.size()) {
1083f4786785SAidan Dodds         auto rsg = rsm->m_globals[uint64_t(args[eRsId])];
1084b9c1b51eSKate Stone         log->Printf("%s - Setting of '%s' within '%s' inferred", __FUNCTION__,
1085b9c1b51eSKate Stone                     rsg.m_name.AsCString(),
1086f4786785SAidan Dodds                     rsm->m_module->GetFileSpec().GetFilename().AsCString());
10874640cde1SColin Riley       }
10884640cde1SColin Riley     }
10894640cde1SColin Riley   }
10904640cde1SColin Riley }
10914640cde1SColin Riley 
1092b9c1b51eSKate Stone void RenderScriptRuntime::CaptureAllocationInit(RuntimeHook *hook_info,
1093b9c1b51eSKate Stone                                                 ExecutionContext &context) {
10944640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
10954640cde1SColin Riley 
1096b9c1b51eSKate Stone   enum { eRsContext, eRsAlloc, eRsForceZero };
10974640cde1SColin Riley 
10981ee07253SSaleem Abdulrasool   std::array<ArgItem, 3> args{{
1099f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsContext
1100f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsAlloc
1101f4786785SAidan Dodds       ArgItem{ArgItem::eBool, 0},    // eRsForceZero
11021ee07253SSaleem Abdulrasool   }};
11034640cde1SColin Riley 
1104f4786785SAidan Dodds   bool success = GetArgs(context, &args[0], args.size());
110582780287SAidan Dodds   if (!success) // error case
110682780287SAidan Dodds   {
110782780287SAidan Dodds     if (log)
1108b9c1b51eSKate Stone       log->Printf("%s - error while reading the function parameters",
1109b9c1b51eSKate Stone                   __FUNCTION__);
111082780287SAidan Dodds     return; // abort
111182780287SAidan Dodds   }
11124640cde1SColin Riley 
11134640cde1SColin Riley   if (log)
1114b9c1b51eSKate Stone     log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .",
1115b9c1b51eSKate Stone                 __FUNCTION__, uint64_t(args[eRsContext]),
1116f4786785SAidan Dodds                 uint64_t(args[eRsAlloc]), uint64_t(args[eRsForceZero]));
111778f339d1SEwan Crawford 
11185d057637SLuke Drummond   AllocationDetails *alloc = CreateAllocation(uint64_t(args[eRsAlloc]));
111978f339d1SEwan Crawford   if (alloc)
1120f4786785SAidan Dodds     alloc->context = uint64_t(args[eRsContext]);
11214640cde1SColin Riley }
11224640cde1SColin Riley 
1123b9c1b51eSKate Stone void RenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook *hook_info,
1124b9c1b51eSKate Stone                                                    ExecutionContext &context) {
1125e69df382SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1126e69df382SEwan Crawford 
1127b9c1b51eSKate Stone   enum {
1128f4786785SAidan Dodds     eRsContext,
1129f4786785SAidan Dodds     eRsAlloc,
1130f4786785SAidan Dodds   };
1131e69df382SEwan Crawford 
11321ee07253SSaleem Abdulrasool   std::array<ArgItem, 2> args{{
1133f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsContext
1134f4786785SAidan Dodds       ArgItem{ArgItem::ePointer, 0}, // eRsAlloc
11351ee07253SSaleem Abdulrasool   }};
1136f4786785SAidan Dodds 
1137f4786785SAidan Dodds   bool success = GetArgs(context, &args[0], args.size());
1138b9c1b51eSKate Stone   if (!success) {
1139e69df382SEwan Crawford     if (log)
1140b9c1b51eSKate Stone       log->Printf("%s - error while reading the function parameters.",
1141b9c1b51eSKate Stone                   __FUNCTION__);
1142b3f7f69dSAidan Dodds     return;
1143e69df382SEwan Crawford   }
1144e69df382SEwan Crawford 
1145e69df382SEwan Crawford   if (log)
1146b9c1b51eSKate Stone     log->Printf("%s - 0x%" PRIx64 ", 0x%" PRIx64 ".", __FUNCTION__,
1147b9c1b51eSKate Stone                 uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc]));
1148e69df382SEwan Crawford 
1149b9c1b51eSKate Stone   for (auto iter = m_allocations.begin(); iter != m_allocations.end(); ++iter) {
1150e69df382SEwan Crawford     auto &allocation_ap = *iter; // get the unique pointer
1151b9c1b51eSKate Stone     if (allocation_ap->address.isValid() &&
1152b9c1b51eSKate Stone         *allocation_ap->address.get() == addr_t(args[eRsAlloc])) {
1153e69df382SEwan Crawford       m_allocations.erase(iter);
1154e69df382SEwan Crawford       if (log)
1155b3f7f69dSAidan Dodds         log->Printf("%s - deleted allocation entry.", __FUNCTION__);
1156e69df382SEwan Crawford       return;
1157e69df382SEwan Crawford     }
1158e69df382SEwan Crawford   }
1159e69df382SEwan Crawford 
1160e69df382SEwan Crawford   if (log)
1161b3f7f69dSAidan Dodds     log->Printf("%s - couldn't find destroyed allocation.", __FUNCTION__);
1162e69df382SEwan Crawford }
1163e69df382SEwan Crawford 
1164b9c1b51eSKate Stone void RenderScriptRuntime::CaptureScriptInit(RuntimeHook *hook_info,
1165b9c1b51eSKate Stone                                             ExecutionContext &context) {
11664640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
11674640cde1SColin Riley 
11684640cde1SColin Riley   Error error;
11694640cde1SColin Riley   Process *process = context.GetProcessPtr();
11704640cde1SColin Riley 
1171b9c1b51eSKate Stone   enum { eRsContext, eRsScript, eRsResNamePtr, eRsCachedDirPtr };
11724640cde1SColin Riley 
1173b9c1b51eSKate Stone   std::array<ArgItem, 4> args{
1174b9c1b51eSKate Stone       {ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0},
11751ee07253SSaleem Abdulrasool        ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}}};
1176f4786785SAidan Dodds   bool success = GetArgs(context, &args[0], args.size());
1177b9c1b51eSKate Stone   if (!success) {
117882780287SAidan Dodds     if (log)
1179b9c1b51eSKate Stone       log->Printf("%s - error while reading the function parameters.",
1180b9c1b51eSKate Stone                   __FUNCTION__);
118182780287SAidan Dodds     return;
118282780287SAidan Dodds   }
118382780287SAidan Dodds 
1184f4786785SAidan Dodds   std::string resname;
1185f4786785SAidan Dodds   process->ReadCStringFromMemory(addr_t(args[eRsResNamePtr]), resname, error);
1186b9c1b51eSKate Stone   if (error.Fail()) {
11874640cde1SColin Riley     if (log)
1188b9c1b51eSKate Stone       log->Printf("%s - error reading resname: %s.", __FUNCTION__,
1189b9c1b51eSKate Stone                   error.AsCString());
11904640cde1SColin Riley   }
11914640cde1SColin Riley 
1192f4786785SAidan Dodds   std::string cachedir;
1193b9c1b51eSKate Stone   process->ReadCStringFromMemory(addr_t(args[eRsCachedDirPtr]), cachedir,
1194b9c1b51eSKate Stone                                  error);
1195b9c1b51eSKate Stone   if (error.Fail()) {
11964640cde1SColin Riley     if (log)
1197b9c1b51eSKate Stone       log->Printf("%s - error reading cachedir: %s.", __FUNCTION__,
1198b9c1b51eSKate Stone                   error.AsCString());
11994640cde1SColin Riley   }
12004640cde1SColin Riley 
12014640cde1SColin Riley   if (log)
1202b9c1b51eSKate Stone     log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .",
1203b9c1b51eSKate Stone                 __FUNCTION__, uint64_t(args[eRsContext]),
1204f4786785SAidan Dodds                 uint64_t(args[eRsScript]), resname.c_str(), cachedir.c_str());
12054640cde1SColin Riley 
1206b9c1b51eSKate Stone   if (resname.size() > 0) {
12074640cde1SColin Riley     StreamString strm;
12084640cde1SColin Riley     strm.Printf("librs.%s.so", resname.c_str());
12094640cde1SColin Riley 
1210f4786785SAidan Dodds     ScriptDetails *script = LookUpScript(addr_t(args[eRsScript]), true);
1211b9c1b51eSKate Stone     if (script) {
121278f339d1SEwan Crawford       script->type = ScriptDetails::eScriptC;
121378f339d1SEwan Crawford       script->cacheDir = cachedir;
121478f339d1SEwan Crawford       script->resName = resname;
121578f339d1SEwan Crawford       script->scriptDyLib = strm.GetData();
1216f4786785SAidan Dodds       script->context = addr_t(args[eRsContext]);
121778f339d1SEwan Crawford     }
12184640cde1SColin Riley 
12194640cde1SColin Riley     if (log)
1220b9c1b51eSKate Stone       log->Printf("%s - '%s' tagged with context 0x%" PRIx64
1221b9c1b51eSKate Stone                   " and script 0x%" PRIx64 ".",
1222b9c1b51eSKate Stone                   __FUNCTION__, strm.GetData(), uint64_t(args[eRsContext]),
1223b9c1b51eSKate Stone                   uint64_t(args[eRsScript]));
1224b9c1b51eSKate Stone   } else if (log) {
1225b3f7f69dSAidan Dodds     log->Printf("%s - resource name invalid, Script not tagged.", __FUNCTION__);
12264640cde1SColin Riley   }
12274640cde1SColin Riley }
12284640cde1SColin Riley 
1229b9c1b51eSKate Stone void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module,
1230b9c1b51eSKate Stone                                            ModuleKind kind) {
12314640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
12324640cde1SColin Riley 
1233b9c1b51eSKate Stone   if (!module) {
12344640cde1SColin Riley     return;
12354640cde1SColin Riley   }
12364640cde1SColin Riley 
123782780287SAidan Dodds   Target &target = GetProcess()->GetTarget();
123882780287SAidan Dodds   llvm::Triple::ArchType targetArchType = target.GetArchitecture().GetMachine();
123982780287SAidan Dodds 
1240b3f7f69dSAidan Dodds   if (targetArchType != llvm::Triple::ArchType::x86 &&
1241b3f7f69dSAidan Dodds       targetArchType != llvm::Triple::ArchType::arm &&
1242b3f7f69dSAidan Dodds       targetArchType != llvm::Triple::ArchType::aarch64 &&
1243b3f7f69dSAidan Dodds       targetArchType != llvm::Triple::ArchType::mipsel &&
1244b3f7f69dSAidan Dodds       targetArchType != llvm::Triple::ArchType::mips64el &&
1245b9c1b51eSKate Stone       targetArchType != llvm::Triple::ArchType::x86_64) {
12464640cde1SColin Riley     if (log)
1247b3f7f69dSAidan Dodds       log->Printf("%s - unable to hook runtime functions.", __FUNCTION__);
12484640cde1SColin Riley     return;
12494640cde1SColin Riley   }
12504640cde1SColin Riley 
125182780287SAidan Dodds   uint32_t archByteSize = target.GetArchitecture().GetAddressByteSize();
12524640cde1SColin Riley 
1253b9c1b51eSKate Stone   for (size_t idx = 0; idx < s_runtimeHookCount; idx++) {
12544640cde1SColin Riley     const HookDefn *hook_defn = &s_runtimeHookDefns[idx];
1255b9c1b51eSKate Stone     if (hook_defn->kind != kind) {
12564640cde1SColin Riley       continue;
12574640cde1SColin Riley     }
12584640cde1SColin Riley 
1259b9c1b51eSKate Stone     const char *symbol_name = (archByteSize == 4) ? hook_defn->symbol_name_m32
1260b9c1b51eSKate Stone                                                   : hook_defn->symbol_name_m64;
126182780287SAidan Dodds 
1262b9c1b51eSKate Stone     const Symbol *sym = module->FindFirstSymbolWithNameAndType(
1263b9c1b51eSKate Stone         ConstString(symbol_name), eSymbolTypeCode);
1264b9c1b51eSKate Stone     if (!sym) {
1265b9c1b51eSKate Stone       if (log) {
1266b3f7f69dSAidan Dodds         log->Printf("%s - symbol '%s' related to the function %s not found",
1267b3f7f69dSAidan Dodds                     __FUNCTION__, symbol_name, hook_defn->name);
126882780287SAidan Dodds       }
126982780287SAidan Dodds       continue;
127082780287SAidan Dodds     }
12714640cde1SColin Riley 
1272358cf1eaSGreg Clayton     addr_t addr = sym->GetLoadAddress(&target);
1273b9c1b51eSKate Stone     if (addr == LLDB_INVALID_ADDRESS) {
12744640cde1SColin Riley       if (log)
1275b9c1b51eSKate Stone         log->Printf("%s - unable to resolve the address of hook function '%s' "
1276b9c1b51eSKate Stone                     "with symbol '%s'.",
1277b3f7f69dSAidan Dodds                     __FUNCTION__, hook_defn->name, symbol_name);
12784640cde1SColin Riley       continue;
1279b9c1b51eSKate Stone     } else {
128082780287SAidan Dodds       if (log)
1281b3f7f69dSAidan Dodds         log->Printf("%s - function %s, address resolved at 0x%" PRIx64,
1282b3f7f69dSAidan Dodds                     __FUNCTION__, hook_defn->name, addr);
128382780287SAidan Dodds     }
12844640cde1SColin Riley 
12854640cde1SColin Riley     RuntimeHookSP hook(new RuntimeHook());
12864640cde1SColin Riley     hook->address = addr;
12874640cde1SColin Riley     hook->defn = hook_defn;
12884640cde1SColin Riley     hook->bp_sp = target.CreateBreakpoint(addr, true, false);
12894640cde1SColin Riley     hook->bp_sp->SetCallback(HookCallback, hook.get(), true);
12904640cde1SColin Riley     m_runtimeHooks[addr] = hook;
1291b9c1b51eSKate Stone     if (log) {
1292b9c1b51eSKate Stone       log->Printf("%s - successfully hooked '%s' in '%s' version %" PRIu64
1293b9c1b51eSKate Stone                   " at 0x%" PRIx64 ".",
1294b9c1b51eSKate Stone                   __FUNCTION__, hook_defn->name,
1295b9c1b51eSKate Stone                   module->GetFileSpec().GetFilename().AsCString(),
1296b3f7f69dSAidan Dodds                   (uint64_t)hook_defn->version, (uint64_t)addr);
12974640cde1SColin Riley     }
12984640cde1SColin Riley   }
12994640cde1SColin Riley }
13004640cde1SColin Riley 
1301b9c1b51eSKate Stone void RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp) {
13024640cde1SColin Riley   if (!rsmodule_sp)
13034640cde1SColin Riley     return;
13044640cde1SColin Riley 
13054640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
13064640cde1SColin Riley 
13074640cde1SColin Riley   const ModuleSP module = rsmodule_sp->m_module;
13084640cde1SColin Riley   const FileSpec &file = module->GetPlatformFileSpec();
13094640cde1SColin Riley 
131078f339d1SEwan Crawford   // Iterate over all of the scripts that we currently know of.
131178f339d1SEwan Crawford   // Note: We cant push or pop to m_scripts here or it may invalidate rs_script.
1312b9c1b51eSKate Stone   for (const auto &rs_script : m_scripts) {
131378f339d1SEwan Crawford     // Extract the expected .so file path for this script.
131478f339d1SEwan Crawford     std::string dylib;
131578f339d1SEwan Crawford     if (!rs_script->scriptDyLib.get(dylib))
131678f339d1SEwan Crawford       continue;
131778f339d1SEwan Crawford 
131878f339d1SEwan Crawford     // Only proceed if the module that has loaded corresponds to this script.
131978f339d1SEwan Crawford     if (file.GetFilename() != ConstString(dylib.c_str()))
132078f339d1SEwan Crawford       continue;
132178f339d1SEwan Crawford 
132278f339d1SEwan Crawford     // Obtain the script address which we use as a key.
132378f339d1SEwan Crawford     lldb::addr_t script;
132478f339d1SEwan Crawford     if (!rs_script->script.get(script))
132578f339d1SEwan Crawford       continue;
132678f339d1SEwan Crawford 
132778f339d1SEwan Crawford     // If we have a script mapping for the current script.
1328b9c1b51eSKate Stone     if (m_scriptMappings.find(script) != m_scriptMappings.end()) {
132978f339d1SEwan Crawford       // if the module we have stored is different to the one we just received.
1330b9c1b51eSKate Stone       if (m_scriptMappings[script] != rsmodule_sp) {
13314640cde1SColin Riley         if (log)
1332b9c1b51eSKate Stone           log->Printf(
1333b9c1b51eSKate Stone               "%s - script %" PRIx64 " wants reassigned to new rsmodule '%s'.",
1334b9c1b51eSKate Stone               __FUNCTION__, (uint64_t)script,
1335b9c1b51eSKate Stone               rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
13364640cde1SColin Riley       }
13374640cde1SColin Riley     }
133878f339d1SEwan Crawford     // We don't have a script mapping for the current script.
1339b9c1b51eSKate Stone     else {
134078f339d1SEwan Crawford       // Obtain the script resource name.
134178f339d1SEwan Crawford       std::string resName;
134278f339d1SEwan Crawford       if (rs_script->resName.get(resName))
134378f339d1SEwan Crawford         // Set the modules resource name.
134478f339d1SEwan Crawford         rsmodule_sp->m_resname = resName;
134578f339d1SEwan Crawford       // Add Script/Module pair to map.
134678f339d1SEwan Crawford       m_scriptMappings[script] = rsmodule_sp;
13474640cde1SColin Riley       if (log)
1348b9c1b51eSKate Stone         log->Printf(
1349b9c1b51eSKate Stone             "%s - script %" PRIx64 " associated with rsmodule '%s'.",
1350b9c1b51eSKate Stone             __FUNCTION__, (uint64_t)script,
1351b9c1b51eSKate Stone             rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
13524640cde1SColin Riley     }
13534640cde1SColin Riley   }
13544640cde1SColin Riley }
13554640cde1SColin Riley 
1356b9c1b51eSKate Stone // Uses the Target API to evaluate the expression passed as a parameter to the
1357b9c1b51eSKate Stone // function
1358b9c1b51eSKate Stone // The result of that expression is returned an unsigned 64 bit int, via the
1359b9c1b51eSKate Stone // result* parameter.
136015f2bd95SEwan Crawford // Function returns true on success, and false on failure
1361b9c1b51eSKate Stone bool RenderScriptRuntime::EvalRSExpression(const char *expression,
1362b9c1b51eSKate Stone                                            StackFrame *frame_ptr,
1363b9c1b51eSKate Stone                                            uint64_t *result) {
136415f2bd95SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
136515f2bd95SEwan Crawford   if (log)
1366b3f7f69dSAidan Dodds     log->Printf("%s(%s)", __FUNCTION__, expression);
136715f2bd95SEwan Crawford 
136815f2bd95SEwan Crawford   ValueObjectSP expr_result;
13698433fdbeSAidan Dodds   EvaluateExpressionOptions options;
13708433fdbeSAidan Dodds   options.SetLanguage(lldb::eLanguageTypeC_plus_plus);
137115f2bd95SEwan Crawford   // Perform the actual expression evaluation
1372b9c1b51eSKate Stone   GetProcess()->GetTarget().EvaluateExpression(expression, frame_ptr,
1373b9c1b51eSKate Stone                                                expr_result, options);
137415f2bd95SEwan Crawford 
1375b9c1b51eSKate Stone   if (!expr_result) {
137615f2bd95SEwan Crawford     if (log)
1377b3f7f69dSAidan Dodds       log->Printf("%s: couldn't evaluate expression.", __FUNCTION__);
137815f2bd95SEwan Crawford     return false;
137915f2bd95SEwan Crawford   }
138015f2bd95SEwan Crawford 
138115f2bd95SEwan Crawford   // The result of the expression is invalid
1382b9c1b51eSKate Stone   if (!expr_result->GetError().Success()) {
138315f2bd95SEwan Crawford     Error err = expr_result->GetError();
1384b9c1b51eSKate Stone     if (err.GetError() == UserExpression::kNoResult) // Expression returned
1385b9c1b51eSKate Stone                                                      // void, so this is
1386b9c1b51eSKate Stone                                                      // actually a success
138715f2bd95SEwan Crawford     {
138815f2bd95SEwan Crawford       if (log)
1389b3f7f69dSAidan Dodds         log->Printf("%s - expression returned void.", __FUNCTION__);
139015f2bd95SEwan Crawford 
139115f2bd95SEwan Crawford       result = nullptr;
139215f2bd95SEwan Crawford       return true;
139315f2bd95SEwan Crawford     }
139415f2bd95SEwan Crawford 
139515f2bd95SEwan Crawford     if (log)
1396b3f7f69dSAidan Dodds       log->Printf("%s - error evaluating expression result: %s", __FUNCTION__,
1397b3f7f69dSAidan Dodds                   err.AsCString());
139815f2bd95SEwan Crawford     return false;
139915f2bd95SEwan Crawford   }
140015f2bd95SEwan Crawford 
140115f2bd95SEwan Crawford   bool success = false;
1402b9c1b51eSKate Stone   *result = expr_result->GetValueAsUnsigned(
1403b9c1b51eSKate Stone       0, &success); // We only read the result as an uint32_t.
140415f2bd95SEwan Crawford 
1405b9c1b51eSKate Stone   if (!success) {
140615f2bd95SEwan Crawford     if (log)
1407b9c1b51eSKate Stone       log->Printf("%s - couldn't convert expression result to uint32_t",
1408b9c1b51eSKate Stone                   __FUNCTION__);
140915f2bd95SEwan Crawford     return false;
141015f2bd95SEwan Crawford   }
141115f2bd95SEwan Crawford 
141215f2bd95SEwan Crawford   return true;
141315f2bd95SEwan Crawford }
141415f2bd95SEwan Crawford 
1415b9c1b51eSKate Stone namespace {
1416836d9651SEwan Crawford // Used to index expression format strings
1417b9c1b51eSKate Stone enum ExpressionStrings {
1418836d9651SEwan Crawford   eExprGetOffsetPtr = 0,
1419836d9651SEwan Crawford   eExprAllocGetType,
1420836d9651SEwan Crawford   eExprTypeDimX,
1421836d9651SEwan Crawford   eExprTypeDimY,
1422836d9651SEwan Crawford   eExprTypeDimZ,
1423836d9651SEwan Crawford   eExprTypeElemPtr,
1424836d9651SEwan Crawford   eExprElementType,
1425836d9651SEwan Crawford   eExprElementKind,
1426836d9651SEwan Crawford   eExprElementVec,
1427836d9651SEwan Crawford   eExprElementFieldCount,
1428836d9651SEwan Crawford   eExprSubelementsId,
1429836d9651SEwan Crawford   eExprSubelementsName,
1430ea0636b5SEwan Crawford   eExprSubelementsArrSize,
1431ea0636b5SEwan Crawford 
1432ea0636b5SEwan Crawford   _eExprLast // keep at the end, implicit size of the array runtimeExpressions
1433836d9651SEwan Crawford };
143415f2bd95SEwan Crawford 
1435ea0636b5SEwan Crawford // max length of an expanded expression
1436ea0636b5SEwan Crawford const int jit_max_expr_size = 512;
1437ea0636b5SEwan Crawford 
1438ea0636b5SEwan Crawford // Retrieve the string to JIT for the given expression
1439b9c1b51eSKate Stone const char *JITTemplate(ExpressionStrings e) {
1440ea0636b5SEwan Crawford   // Format strings containing the expressions we may need to evaluate.
1441b9c1b51eSKate Stone   static std::array<const char *, _eExprLast> runtimeExpressions = {
1442b9c1b51eSKate Stone       {// Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap)
1443b9c1b51eSKate Stone        "(int*)_"
1444b9c1b51eSKate Stone        "Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocation"
1445b9c1b51eSKate Stone        "CubemapFace"
1446577570b4SAidan Dodds        "(0x%" PRIx64 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", 0, 0)",
144715f2bd95SEwan Crawford 
144815f2bd95SEwan Crawford        // Type* rsaAllocationGetType(Context*, Allocation*)
1449577570b4SAidan Dodds        "(void*)rsaAllocationGetType(0x%" PRIx64 ", 0x%" PRIx64 ")",
145015f2bd95SEwan Crawford 
145115f2bd95SEwan Crawford        // rsaTypeGetNativeData(Context*, Type*, void* typeData, size)
1452b9c1b51eSKate Stone        // Pack the data in the following way mHal.state.dimX; mHal.state.dimY;
1453b9c1b51eSKate Stone        // mHal.state.dimZ;
145415f2bd95SEwan Crawford        // mHal.state.lodCount; mHal.state.faces; mElement; into typeData
1455b9c1b51eSKate Stone        // Need to specify 32 or 64 bit for uint_t since this differs between
1456b9c1b51eSKate Stone        // devices
1457b9c1b51eSKate Stone        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64
1458b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 6); data[0]", // X dim
1459b9c1b51eSKate Stone        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64
1460b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 6); data[1]", // Y dim
1461b9c1b51eSKate Stone        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64
1462b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 6); data[2]", // Z dim
1463b9c1b51eSKate Stone        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64
1464b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 6); data[5]", // Element ptr
146515f2bd95SEwan Crawford 
146615f2bd95SEwan Crawford        // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size)
1467b9c1b51eSKate Stone        // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into
1468b9c1b51eSKate Stone        // elemData
1469b9c1b51eSKate Stone        "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64
1470b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 5); data[0]", // Type
1471b9c1b51eSKate Stone        "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64
1472b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 5); data[1]", // Kind
1473b9c1b51eSKate Stone        "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64
1474b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 5); data[3]", // Vector Size
1475b9c1b51eSKate Stone        "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64
1476b9c1b51eSKate Stone        ", 0x%" PRIx64 ", data, 5); data[4]", // Field Count
14778b244e21SEwan Crawford 
1478b9c1b51eSKate Stone        // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t
1479b9c1b51eSKate Stone        // *ids, const char **names,
14808b244e21SEwan Crawford        // size_t *arraySizes, uint32_t dataSize)
1481b9c1b51eSKate Stone        // Needed for Allocations of structs to gather details about
1482b9c1b51eSKate Stone        // fields/Subelements
1483577570b4SAidan Dodds        // Element* of field
1484b9c1b51eSKate Stone        "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
1485b9c1b51eSKate Stone        "]; size_t arr_size[%" PRIu32 "];"
1486b9c1b51eSKate Stone        "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64
1487b9c1b51eSKate Stone        ", ids, names, arr_size, %" PRIu32 "); ids[%" PRIu32 "]",
14888b244e21SEwan Crawford 
1489577570b4SAidan Dodds        // Name of field
1490b9c1b51eSKate Stone        "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
1491b9c1b51eSKate Stone        "]; size_t arr_size[%" PRIu32 "];"
1492b9c1b51eSKate Stone        "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64
1493b9c1b51eSKate Stone        ", ids, names, arr_size, %" PRIu32 "); names[%" PRIu32 "]",
14948b244e21SEwan Crawford 
1495577570b4SAidan Dodds        // Array size of field
1496b9c1b51eSKate Stone        "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
1497b9c1b51eSKate Stone        "]; size_t arr_size[%" PRIu32 "];"
1498b9c1b51eSKate Stone        "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64
1499b9c1b51eSKate Stone        ", ids, names, arr_size, %" PRIu32 "); arr_size[%" PRIu32 "]"}};
1500ea0636b5SEwan Crawford 
1501ea0636b5SEwan Crawford   return runtimeExpressions[e];
1502ea0636b5SEwan Crawford }
1503ea0636b5SEwan Crawford } // end of the anonymous namespace
1504ea0636b5SEwan Crawford 
150515f2bd95SEwan Crawford // JITs the RS runtime for the internal data pointer of an allocation.
150615f2bd95SEwan Crawford // Is passed x,y,z coordinates for the pointer to a specific element.
150715f2bd95SEwan Crawford // Then sets the data_ptr member in Allocation with the result.
150815f2bd95SEwan Crawford // Returns true on success, false otherwise
1509b9c1b51eSKate Stone bool RenderScriptRuntime::JITDataPointer(AllocationDetails *allocation,
1510b9c1b51eSKate Stone                                          StackFrame *frame_ptr, uint32_t x,
1511b9c1b51eSKate Stone                                          uint32_t y, uint32_t z) {
151215f2bd95SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
151315f2bd95SEwan Crawford 
1514b9c1b51eSKate Stone   if (!allocation->address.isValid()) {
151515f2bd95SEwan Crawford     if (log)
1516b3f7f69dSAidan Dodds       log->Printf("%s - failed to find allocation details.", __FUNCTION__);
151715f2bd95SEwan Crawford     return false;
151815f2bd95SEwan Crawford   }
151915f2bd95SEwan Crawford 
1520ea0636b5SEwan Crawford   const char *expr_cstr = JITTemplate(eExprGetOffsetPtr);
1521ea0636b5SEwan Crawford   char buffer[jit_max_expr_size];
152215f2bd95SEwan Crawford 
1523b9c1b51eSKate Stone   int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr,
1524b9c1b51eSKate Stone                                *allocation->address.get(), x, y, z);
1525b9c1b51eSKate Stone   if (chars_written < 0) {
152615f2bd95SEwan Crawford     if (log)
1527b3f7f69dSAidan Dodds       log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
152815f2bd95SEwan Crawford     return false;
1529b9c1b51eSKate Stone   } else if (chars_written >= jit_max_expr_size) {
153015f2bd95SEwan Crawford     if (log)
1531b3f7f69dSAidan Dodds       log->Printf("%s - expression too long.", __FUNCTION__);
153215f2bd95SEwan Crawford     return false;
153315f2bd95SEwan Crawford   }
153415f2bd95SEwan Crawford 
153515f2bd95SEwan Crawford   uint64_t result = 0;
153615f2bd95SEwan Crawford   if (!EvalRSExpression(buffer, frame_ptr, &result))
153715f2bd95SEwan Crawford     return false;
153815f2bd95SEwan Crawford 
153915f2bd95SEwan Crawford   addr_t mem_ptr = static_cast<lldb::addr_t>(result);
154015f2bd95SEwan Crawford   allocation->data_ptr = mem_ptr;
154115f2bd95SEwan Crawford 
154215f2bd95SEwan Crawford   return true;
154315f2bd95SEwan Crawford }
154415f2bd95SEwan Crawford 
154515f2bd95SEwan Crawford // JITs the RS runtime for the internal pointer to the RS Type of an allocation
154615f2bd95SEwan Crawford // Then sets the type_ptr member in Allocation with the result.
154715f2bd95SEwan Crawford // Returns true on success, false otherwise
1548b9c1b51eSKate Stone bool RenderScriptRuntime::JITTypePointer(AllocationDetails *allocation,
1549b9c1b51eSKate Stone                                          StackFrame *frame_ptr) {
155015f2bd95SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
155115f2bd95SEwan Crawford 
1552b9c1b51eSKate Stone   if (!allocation->address.isValid() || !allocation->context.isValid()) {
155315f2bd95SEwan Crawford     if (log)
1554b3f7f69dSAidan Dodds       log->Printf("%s - failed to find allocation details.", __FUNCTION__);
155515f2bd95SEwan Crawford     return false;
155615f2bd95SEwan Crawford   }
155715f2bd95SEwan Crawford 
1558ea0636b5SEwan Crawford   const char *expr_cstr = JITTemplate(eExprAllocGetType);
1559ea0636b5SEwan Crawford   char buffer[jit_max_expr_size];
156015f2bd95SEwan Crawford 
1561ea0636b5SEwan Crawford   int chars_written =
1562b9c1b51eSKate Stone       snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->context.get(),
1563b9c1b51eSKate Stone                *allocation->address.get());
1564b9c1b51eSKate Stone   if (chars_written < 0) {
156515f2bd95SEwan Crawford     if (log)
1566b3f7f69dSAidan Dodds       log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
156715f2bd95SEwan Crawford     return false;
1568b9c1b51eSKate Stone   } else if (chars_written >= jit_max_expr_size) {
156915f2bd95SEwan Crawford     if (log)
1570b3f7f69dSAidan Dodds       log->Printf("%s - expression too long.", __FUNCTION__);
157115f2bd95SEwan Crawford     return false;
157215f2bd95SEwan Crawford   }
157315f2bd95SEwan Crawford 
157415f2bd95SEwan Crawford   uint64_t result = 0;
157515f2bd95SEwan Crawford   if (!EvalRSExpression(buffer, frame_ptr, &result))
157615f2bd95SEwan Crawford     return false;
157715f2bd95SEwan Crawford 
157815f2bd95SEwan Crawford   addr_t type_ptr = static_cast<lldb::addr_t>(result);
157915f2bd95SEwan Crawford   allocation->type_ptr = type_ptr;
158015f2bd95SEwan Crawford 
158115f2bd95SEwan Crawford   return true;
158215f2bd95SEwan Crawford }
158315f2bd95SEwan Crawford 
1584b9c1b51eSKate Stone // JITs the RS runtime for information about the dimensions and type of an
1585b9c1b51eSKate Stone // allocation
158615f2bd95SEwan Crawford // Then sets dimension and element_ptr members in Allocation with the result.
158715f2bd95SEwan Crawford // Returns true on success, false otherwise
1588b9c1b51eSKate Stone bool RenderScriptRuntime::JITTypePacked(AllocationDetails *allocation,
1589b9c1b51eSKate Stone                                         StackFrame *frame_ptr) {
159015f2bd95SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
159115f2bd95SEwan Crawford 
1592b9c1b51eSKate Stone   if (!allocation->type_ptr.isValid() || !allocation->context.isValid()) {
159315f2bd95SEwan Crawford     if (log)
1594b3f7f69dSAidan Dodds       log->Printf("%s - Failed to find allocation details.", __FUNCTION__);
159515f2bd95SEwan Crawford     return false;
159615f2bd95SEwan Crawford   }
159715f2bd95SEwan Crawford 
159815f2bd95SEwan Crawford   // Expression is different depending on if device is 32 or 64 bit
1599b9c1b51eSKate Stone   uint32_t archByteSize =
1600b9c1b51eSKate Stone       GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
1601b3f7f69dSAidan Dodds   const uint32_t bits = archByteSize == 4 ? 32 : 64;
160215f2bd95SEwan Crawford 
160315f2bd95SEwan Crawford   // We want 4 elements from packed data
1604b3f7f69dSAidan Dodds   const uint32_t num_exprs = 4;
1605b9c1b51eSKate Stone   assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1) &&
1606b9c1b51eSKate Stone          "Invalid number of expressions");
160715f2bd95SEwan Crawford 
1608ea0636b5SEwan Crawford   char buffer[num_exprs][jit_max_expr_size];
160915f2bd95SEwan Crawford   uint64_t results[num_exprs];
161015f2bd95SEwan Crawford 
1611b9c1b51eSKate Stone   for (uint32_t i = 0; i < num_exprs; ++i) {
1612ea0636b5SEwan Crawford     const char *expr_cstr = JITTemplate(ExpressionStrings(eExprTypeDimX + i));
1613b9c1b51eSKate Stone     int chars_written =
1614b9c1b51eSKate Stone         snprintf(buffer[i], jit_max_expr_size, expr_cstr, bits,
1615b9c1b51eSKate Stone                  *allocation->context.get(), *allocation->type_ptr.get());
1616b9c1b51eSKate Stone     if (chars_written < 0) {
161715f2bd95SEwan Crawford       if (log)
1618b3f7f69dSAidan Dodds         log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
161915f2bd95SEwan Crawford       return false;
1620b9c1b51eSKate Stone     } else if (chars_written >= jit_max_expr_size) {
162115f2bd95SEwan Crawford       if (log)
1622b3f7f69dSAidan Dodds         log->Printf("%s - expression too long.", __FUNCTION__);
162315f2bd95SEwan Crawford       return false;
162415f2bd95SEwan Crawford     }
162515f2bd95SEwan Crawford 
162615f2bd95SEwan Crawford     // Perform expression evaluation
162715f2bd95SEwan Crawford     if (!EvalRSExpression(buffer[i], frame_ptr, &results[i]))
162815f2bd95SEwan Crawford       return false;
162915f2bd95SEwan Crawford   }
163015f2bd95SEwan Crawford 
163115f2bd95SEwan Crawford   // Assign results to allocation members
163215f2bd95SEwan Crawford   AllocationDetails::Dimension dims;
163315f2bd95SEwan Crawford   dims.dim_1 = static_cast<uint32_t>(results[0]);
163415f2bd95SEwan Crawford   dims.dim_2 = static_cast<uint32_t>(results[1]);
163515f2bd95SEwan Crawford   dims.dim_3 = static_cast<uint32_t>(results[2]);
163615f2bd95SEwan Crawford   allocation->dimension = dims;
163715f2bd95SEwan Crawford 
163815f2bd95SEwan Crawford   addr_t elem_ptr = static_cast<lldb::addr_t>(results[3]);
16398b244e21SEwan Crawford   allocation->element.element_ptr = elem_ptr;
164015f2bd95SEwan Crawford 
164115f2bd95SEwan Crawford   if (log)
1642b9c1b51eSKate Stone     log->Printf("%s - dims (%" PRIu32 ", %" PRIu32 ", %" PRIu32
1643b9c1b51eSKate Stone                 ") Element*: 0x%" PRIx64 ".",
1644b9c1b51eSKate Stone                 __FUNCTION__, dims.dim_1, dims.dim_2, dims.dim_3, elem_ptr);
164515f2bd95SEwan Crawford 
164615f2bd95SEwan Crawford   return true;
164715f2bd95SEwan Crawford }
164815f2bd95SEwan Crawford 
164915f2bd95SEwan Crawford // JITs the RS runtime for information about the Element of an allocation
1650b9c1b51eSKate Stone // Then sets type, type_vec_size, field_count and type_kind members in Element
1651b9c1b51eSKate Stone // with the result.
165215f2bd95SEwan Crawford // Returns true on success, false otherwise
1653b9c1b51eSKate Stone bool RenderScriptRuntime::JITElementPacked(Element &elem,
1654b9c1b51eSKate Stone                                            const lldb::addr_t context,
1655b9c1b51eSKate Stone                                            StackFrame *frame_ptr) {
165615f2bd95SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
165715f2bd95SEwan Crawford 
1658b9c1b51eSKate Stone   if (!elem.element_ptr.isValid()) {
165915f2bd95SEwan Crawford     if (log)
1660b3f7f69dSAidan Dodds       log->Printf("%s - failed to find allocation details.", __FUNCTION__);
166115f2bd95SEwan Crawford     return false;
166215f2bd95SEwan Crawford   }
166315f2bd95SEwan Crawford 
16648b244e21SEwan Crawford   // We want 4 elements from packed data
1665b3f7f69dSAidan Dodds   const uint32_t num_exprs = 4;
1666b9c1b51eSKate Stone   assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1) &&
1667b9c1b51eSKate Stone          "Invalid number of expressions");
166815f2bd95SEwan Crawford 
1669ea0636b5SEwan Crawford   char buffer[num_exprs][jit_max_expr_size];
167015f2bd95SEwan Crawford   uint64_t results[num_exprs];
167115f2bd95SEwan Crawford 
1672b9c1b51eSKate Stone   for (uint32_t i = 0; i < num_exprs; i++) {
1673b9c1b51eSKate Stone     const char *expr_cstr =
1674b9c1b51eSKate Stone         JITTemplate(ExpressionStrings(eExprElementType + i));
1675b9c1b51eSKate Stone     int chars_written = snprintf(buffer[i], jit_max_expr_size, expr_cstr,
1676b9c1b51eSKate Stone                                  context, *elem.element_ptr.get());
1677b9c1b51eSKate Stone     if (chars_written < 0) {
167815f2bd95SEwan Crawford       if (log)
1679b3f7f69dSAidan Dodds         log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
168015f2bd95SEwan Crawford       return false;
1681b9c1b51eSKate Stone     } else if (chars_written >= jit_max_expr_size) {
168215f2bd95SEwan Crawford       if (log)
1683b3f7f69dSAidan Dodds         log->Printf("%s - expression too long.", __FUNCTION__);
168415f2bd95SEwan Crawford       return false;
168515f2bd95SEwan Crawford     }
168615f2bd95SEwan Crawford 
168715f2bd95SEwan Crawford     // Perform expression evaluation
168815f2bd95SEwan Crawford     if (!EvalRSExpression(buffer[i], frame_ptr, &results[i]))
168915f2bd95SEwan Crawford       return false;
169015f2bd95SEwan Crawford   }
169115f2bd95SEwan Crawford 
169215f2bd95SEwan Crawford   // Assign results to allocation members
16938b244e21SEwan Crawford   elem.type = static_cast<RenderScriptRuntime::Element::DataType>(results[0]);
1694b9c1b51eSKate Stone   elem.type_kind =
1695b9c1b51eSKate Stone       static_cast<RenderScriptRuntime::Element::DataKind>(results[1]);
16968b244e21SEwan Crawford   elem.type_vec_size = static_cast<uint32_t>(results[2]);
16978b244e21SEwan Crawford   elem.field_count = static_cast<uint32_t>(results[3]);
169815f2bd95SEwan Crawford 
169915f2bd95SEwan Crawford   if (log)
1700b9c1b51eSKate Stone     log->Printf("%s - data type %" PRIu32 ", pixel type %" PRIu32
1701b9c1b51eSKate Stone                 ", vector size %" PRIu32 ", field count %" PRIu32,
1702b9c1b51eSKate Stone                 __FUNCTION__, *elem.type.get(), *elem.type_kind.get(),
1703b9c1b51eSKate Stone                 *elem.type_vec_size.get(), *elem.field_count.get());
17048b244e21SEwan Crawford 
1705b9c1b51eSKate Stone   // If this Element has subelements then JIT rsaElementGetSubElements() for
1706b9c1b51eSKate Stone   // details about its fields
17078b244e21SEwan Crawford   if (*elem.field_count.get() > 0 && !JITSubelements(elem, context, frame_ptr))
17088b244e21SEwan Crawford     return false;
17098b244e21SEwan Crawford 
17108b244e21SEwan Crawford   return true;
17118b244e21SEwan Crawford }
17128b244e21SEwan Crawford 
1713b9c1b51eSKate Stone // JITs the RS runtime for information about the subelements/fields of a struct
1714b9c1b51eSKate Stone // allocation
1715b9c1b51eSKate Stone // This is necessary for infering the struct type so we can pretty print the
1716b9c1b51eSKate Stone // allocation's contents.
17178b244e21SEwan Crawford // Returns true on success, false otherwise
1718b9c1b51eSKate Stone bool RenderScriptRuntime::JITSubelements(Element &elem,
1719b9c1b51eSKate Stone                                          const lldb::addr_t context,
1720b9c1b51eSKate Stone                                          StackFrame *frame_ptr) {
17218b244e21SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
17228b244e21SEwan Crawford 
1723b9c1b51eSKate Stone   if (!elem.element_ptr.isValid() || !elem.field_count.isValid()) {
17248b244e21SEwan Crawford     if (log)
1725b3f7f69dSAidan Dodds       log->Printf("%s - failed to find allocation details.", __FUNCTION__);
17268b244e21SEwan Crawford     return false;
17278b244e21SEwan Crawford   }
17288b244e21SEwan Crawford 
17298b244e21SEwan Crawford   const short num_exprs = 3;
1730b9c1b51eSKate Stone   assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1) &&
1731b9c1b51eSKate Stone          "Invalid number of expressions");
17328b244e21SEwan Crawford 
1733ea0636b5SEwan Crawford   char expr_buffer[jit_max_expr_size];
17348b244e21SEwan Crawford   uint64_t results;
17358b244e21SEwan Crawford 
17368b244e21SEwan Crawford   // Iterate over struct fields.
17378b244e21SEwan Crawford   const uint32_t field_count = *elem.field_count.get();
1738b9c1b51eSKate Stone   for (uint32_t field_index = 0; field_index < field_count; ++field_index) {
17398b244e21SEwan Crawford     Element child;
1740b9c1b51eSKate Stone     for (uint32_t expr_index = 0; expr_index < num_exprs; ++expr_index) {
1741b9c1b51eSKate Stone       const char *expr_cstr =
1742b9c1b51eSKate Stone           JITTemplate(ExpressionStrings(eExprSubelementsId + expr_index));
1743b9c1b51eSKate Stone       int chars_written =
1744b9c1b51eSKate Stone           snprintf(expr_buffer, jit_max_expr_size, expr_cstr, field_count,
1745b9c1b51eSKate Stone                    field_count, field_count, context, *elem.element_ptr.get(),
1746b9c1b51eSKate Stone                    field_count, field_index);
1747b9c1b51eSKate Stone       if (chars_written < 0) {
17488b244e21SEwan Crawford         if (log)
1749b3f7f69dSAidan Dodds           log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
17508b244e21SEwan Crawford         return false;
1751b9c1b51eSKate Stone       } else if (chars_written >= jit_max_expr_size) {
17528b244e21SEwan Crawford         if (log)
1753b3f7f69dSAidan Dodds           log->Printf("%s - expression too long.", __FUNCTION__);
17548b244e21SEwan Crawford         return false;
17558b244e21SEwan Crawford       }
17568b244e21SEwan Crawford 
17578b244e21SEwan Crawford       // Perform expression evaluation
17588b244e21SEwan Crawford       if (!EvalRSExpression(expr_buffer, frame_ptr, &results))
17598b244e21SEwan Crawford         return false;
17608b244e21SEwan Crawford 
17618b244e21SEwan Crawford       if (log)
1762b3f7f69dSAidan Dodds         log->Printf("%s - expr result 0x%" PRIx64 ".", __FUNCTION__, results);
17638b244e21SEwan Crawford 
1764b9c1b51eSKate Stone       switch (expr_index) {
17658b244e21SEwan Crawford       case 0: // Element* of child
17668b244e21SEwan Crawford         child.element_ptr = static_cast<addr_t>(results);
17678b244e21SEwan Crawford         break;
17688b244e21SEwan Crawford       case 1: // Name of child
17698b244e21SEwan Crawford       {
17708b244e21SEwan Crawford         lldb::addr_t address = static_cast<addr_t>(results);
17718b244e21SEwan Crawford         Error err;
17728b244e21SEwan Crawford         std::string name;
17738b244e21SEwan Crawford         GetProcess()->ReadCStringFromMemory(address, name, err);
17748b244e21SEwan Crawford         if (!err.Fail())
17758b244e21SEwan Crawford           child.type_name = ConstString(name);
1776b9c1b51eSKate Stone         else {
17778b244e21SEwan Crawford           if (log)
1778b9c1b51eSKate Stone             log->Printf("%s - warning: Couldn't read field name.",
1779b9c1b51eSKate Stone                         __FUNCTION__);
17808b244e21SEwan Crawford         }
17818b244e21SEwan Crawford         break;
17828b244e21SEwan Crawford       }
17838b244e21SEwan Crawford       case 2: // Array size of child
17848b244e21SEwan Crawford         child.array_size = static_cast<uint32_t>(results);
17858b244e21SEwan Crawford         break;
17868b244e21SEwan Crawford       }
17878b244e21SEwan Crawford     }
17888b244e21SEwan Crawford 
17898b244e21SEwan Crawford     // We need to recursively JIT each Element field of the struct since
17908b244e21SEwan Crawford     // structs can be nested inside structs.
17918b244e21SEwan Crawford     if (!JITElementPacked(child, context, frame_ptr))
17928b244e21SEwan Crawford       return false;
17938b244e21SEwan Crawford     elem.children.push_back(child);
17948b244e21SEwan Crawford   }
17958b244e21SEwan Crawford 
1796b9c1b51eSKate Stone   // Try to infer the name of the struct type so we can pretty print the
1797b9c1b51eSKate Stone   // allocation contents.
17988b244e21SEwan Crawford   FindStructTypeName(elem, frame_ptr);
179915f2bd95SEwan Crawford 
180015f2bd95SEwan Crawford   return true;
180115f2bd95SEwan Crawford }
180215f2bd95SEwan Crawford 
1803a0f08674SEwan Crawford // JITs the RS runtime for the address of the last element in the allocation.
1804b9c1b51eSKate Stone // The `elem_size` parameter represents the size of a single element, including
1805b9c1b51eSKate Stone // padding.
1806a0f08674SEwan Crawford // Which is needed as an offset from the last element pointer.
1807b9c1b51eSKate Stone // Using this offset minus the starting address we can calculate the size of the
1808b9c1b51eSKate Stone // allocation.
1809a0f08674SEwan Crawford // Returns true on success, false otherwise
1810b9c1b51eSKate Stone bool RenderScriptRuntime::JITAllocationSize(AllocationDetails *allocation,
1811b9c1b51eSKate Stone                                             StackFrame *frame_ptr) {
1812a0f08674SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1813a0f08674SEwan Crawford 
1814b9c1b51eSKate Stone   if (!allocation->address.isValid() || !allocation->dimension.isValid() ||
1815b9c1b51eSKate Stone       !allocation->data_ptr.isValid() ||
1816b9c1b51eSKate Stone       !allocation->element.datum_size.isValid()) {
1817a0f08674SEwan Crawford     if (log)
1818b3f7f69dSAidan Dodds       log->Printf("%s - failed to find allocation details.", __FUNCTION__);
1819a0f08674SEwan Crawford     return false;
1820a0f08674SEwan Crawford   }
1821a0f08674SEwan Crawford 
1822a0f08674SEwan Crawford   // Find dimensions
1823b3f7f69dSAidan Dodds   uint32_t dim_x = allocation->dimension.get()->dim_1;
1824b3f7f69dSAidan Dodds   uint32_t dim_y = allocation->dimension.get()->dim_2;
1825b3f7f69dSAidan Dodds   uint32_t dim_z = allocation->dimension.get()->dim_3;
1826a0f08674SEwan Crawford 
1827b9c1b51eSKate Stone   // Our plan of jitting the last element address doesn't seem to work for
1828b9c1b51eSKate Stone   // struct Allocations
18298b244e21SEwan Crawford   // Instead try to infer the size ourselves without any inter element padding.
1830b9c1b51eSKate Stone   if (allocation->element.children.size() > 0) {
1831b9c1b51eSKate Stone     if (dim_x == 0)
1832b9c1b51eSKate Stone       dim_x = 1;
1833b9c1b51eSKate Stone     if (dim_y == 0)
1834b9c1b51eSKate Stone       dim_y = 1;
1835b9c1b51eSKate Stone     if (dim_z == 0)
1836b9c1b51eSKate Stone       dim_z = 1;
18378b244e21SEwan Crawford 
1838b9c1b51eSKate Stone     allocation->size =
1839b9c1b51eSKate Stone         dim_x * dim_y * dim_z * *allocation->element.datum_size.get();
18408b244e21SEwan Crawford 
18418b244e21SEwan Crawford     if (log)
1842b9c1b51eSKate Stone       log->Printf("%s - inferred size of struct allocation %" PRIu32 ".",
1843b9c1b51eSKate Stone                   __FUNCTION__, *allocation->size.get());
18448b244e21SEwan Crawford     return true;
18458b244e21SEwan Crawford   }
18468b244e21SEwan Crawford 
1847ea0636b5SEwan Crawford   const char *expr_cstr = JITTemplate(eExprGetOffsetPtr);
1848ea0636b5SEwan Crawford   char buffer[jit_max_expr_size];
18498b244e21SEwan Crawford 
1850a0f08674SEwan Crawford   // Calculate last element
1851a0f08674SEwan Crawford   dim_x = dim_x == 0 ? 0 : dim_x - 1;
1852a0f08674SEwan Crawford   dim_y = dim_y == 0 ? 0 : dim_y - 1;
1853a0f08674SEwan Crawford   dim_z = dim_z == 0 ? 0 : dim_z - 1;
1854a0f08674SEwan Crawford 
1855b9c1b51eSKate Stone   int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr,
1856b9c1b51eSKate Stone                                *allocation->address.get(), dim_x, dim_y, dim_z);
1857b9c1b51eSKate Stone   if (chars_written < 0) {
1858a0f08674SEwan Crawford     if (log)
1859b3f7f69dSAidan Dodds       log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
1860a0f08674SEwan Crawford     return false;
1861b9c1b51eSKate Stone   } else if (chars_written >= jit_max_expr_size) {
1862a0f08674SEwan Crawford     if (log)
1863b3f7f69dSAidan Dodds       log->Printf("%s - expression too long.", __FUNCTION__);
1864a0f08674SEwan Crawford     return false;
1865a0f08674SEwan Crawford   }
1866a0f08674SEwan Crawford 
1867a0f08674SEwan Crawford   uint64_t result = 0;
1868a0f08674SEwan Crawford   if (!EvalRSExpression(buffer, frame_ptr, &result))
1869a0f08674SEwan Crawford     return false;
1870a0f08674SEwan Crawford 
1871a0f08674SEwan Crawford   addr_t mem_ptr = static_cast<lldb::addr_t>(result);
1872a0f08674SEwan Crawford   // Find pointer to last element and add on size of an element
1873b3f7f69dSAidan Dodds   allocation->size =
1874b9c1b51eSKate Stone       static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()) +
1875b9c1b51eSKate Stone       *allocation->element.datum_size.get();
1876a0f08674SEwan Crawford 
1877a0f08674SEwan Crawford   return true;
1878a0f08674SEwan Crawford }
1879a0f08674SEwan Crawford 
1880b9c1b51eSKate Stone // JITs the RS runtime for information about the stride between rows in the
1881b9c1b51eSKate Stone // allocation.
1882a0f08674SEwan Crawford // This is done to detect padding, since allocated memory is 16-byte aligned.
1883a0f08674SEwan Crawford // Returns true on success, false otherwise
1884b9c1b51eSKate Stone bool RenderScriptRuntime::JITAllocationStride(AllocationDetails *allocation,
1885b9c1b51eSKate Stone                                               StackFrame *frame_ptr) {
1886a0f08674SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1887a0f08674SEwan Crawford 
1888b9c1b51eSKate Stone   if (!allocation->address.isValid() || !allocation->data_ptr.isValid()) {
1889a0f08674SEwan Crawford     if (log)
1890b3f7f69dSAidan Dodds       log->Printf("%s - failed to find allocation details.", __FUNCTION__);
1891a0f08674SEwan Crawford     return false;
1892a0f08674SEwan Crawford   }
1893a0f08674SEwan Crawford 
1894ea0636b5SEwan Crawford   const char *expr_cstr = JITTemplate(eExprGetOffsetPtr);
1895ea0636b5SEwan Crawford   char buffer[jit_max_expr_size];
1896a0f08674SEwan Crawford 
1897b9c1b51eSKate Stone   int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr,
1898b9c1b51eSKate Stone                                *allocation->address.get(), 0, 1, 0);
1899b9c1b51eSKate Stone   if (chars_written < 0) {
1900a0f08674SEwan Crawford     if (log)
1901b3f7f69dSAidan Dodds       log->Printf("%s - encoding error in snprintf().", __FUNCTION__);
1902a0f08674SEwan Crawford     return false;
1903b9c1b51eSKate Stone   } else if (chars_written >= jit_max_expr_size) {
1904a0f08674SEwan Crawford     if (log)
1905b3f7f69dSAidan Dodds       log->Printf("%s - expression too long.", __FUNCTION__);
1906a0f08674SEwan Crawford     return false;
1907a0f08674SEwan Crawford   }
1908a0f08674SEwan Crawford 
1909a0f08674SEwan Crawford   uint64_t result = 0;
1910a0f08674SEwan Crawford   if (!EvalRSExpression(buffer, frame_ptr, &result))
1911a0f08674SEwan Crawford     return false;
1912a0f08674SEwan Crawford 
1913a0f08674SEwan Crawford   addr_t mem_ptr = static_cast<lldb::addr_t>(result);
1914b9c1b51eSKate Stone   allocation->stride =
1915b9c1b51eSKate Stone       static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get());
1916a0f08674SEwan Crawford 
1917a0f08674SEwan Crawford   return true;
1918a0f08674SEwan Crawford }
1919a0f08674SEwan Crawford 
192015f2bd95SEwan Crawford // JIT all the current runtime info regarding an allocation
1921b9c1b51eSKate Stone bool RenderScriptRuntime::RefreshAllocation(AllocationDetails *allocation,
1922b9c1b51eSKate Stone                                             StackFrame *frame_ptr) {
192315f2bd95SEwan Crawford   // GetOffsetPointer()
192415f2bd95SEwan Crawford   if (!JITDataPointer(allocation, frame_ptr))
192515f2bd95SEwan Crawford     return false;
192615f2bd95SEwan Crawford 
192715f2bd95SEwan Crawford   // rsaAllocationGetType()
192815f2bd95SEwan Crawford   if (!JITTypePointer(allocation, frame_ptr))
192915f2bd95SEwan Crawford     return false;
193015f2bd95SEwan Crawford 
193115f2bd95SEwan Crawford   // rsaTypeGetNativeData()
193215f2bd95SEwan Crawford   if (!JITTypePacked(allocation, frame_ptr))
193315f2bd95SEwan Crawford     return false;
193415f2bd95SEwan Crawford 
193515f2bd95SEwan Crawford   // rsaElementGetNativeData()
1936b9c1b51eSKate Stone   if (!JITElementPacked(allocation->element, *allocation->context.get(),
1937b9c1b51eSKate Stone                         frame_ptr))
193815f2bd95SEwan Crawford     return false;
193915f2bd95SEwan Crawford 
19408b244e21SEwan Crawford   // Sets the datum_size member in Element
19418b244e21SEwan Crawford   SetElementSize(allocation->element);
19428b244e21SEwan Crawford 
194355232f09SEwan Crawford   // Use GetOffsetPointer() to infer size of the allocation
19448b244e21SEwan Crawford   if (!JITAllocationSize(allocation, frame_ptr))
194555232f09SEwan Crawford     return false;
194655232f09SEwan Crawford 
194755232f09SEwan Crawford   return true;
194855232f09SEwan Crawford }
194955232f09SEwan Crawford 
1950b9c1b51eSKate Stone // Function attempts to set the type_name member of the paramaterised Element
1951b9c1b51eSKate Stone // object.
19528b244e21SEwan Crawford // This string should be the name of the struct type the Element represents.
19538b244e21SEwan Crawford // We need this string for pretty printing the Element to users.
1954b9c1b51eSKate Stone void RenderScriptRuntime::FindStructTypeName(Element &elem,
1955b9c1b51eSKate Stone                                              StackFrame *frame_ptr) {
19568b244e21SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
19578b244e21SEwan Crawford 
19588b244e21SEwan Crawford   if (!elem.type_name.IsEmpty()) // Name already set
19598b244e21SEwan Crawford     return;
19608b244e21SEwan Crawford   else
1961b9c1b51eSKate Stone     elem.type_name = Element::GetFallbackStructName(); // Default type name if
1962b9c1b51eSKate Stone                                                        // we don't succeed
19638b244e21SEwan Crawford 
19648b244e21SEwan Crawford   // Find all the global variables from the script rs modules
19658b244e21SEwan Crawford   VariableList variable_list;
19668b244e21SEwan Crawford   for (auto module_sp : m_rsmodules)
196795eae423SZachary Turner     module_sp->m_module->FindGlobalVariables(
196895eae423SZachary Turner         RegularExpression(llvm::StringRef(".")), true, UINT32_MAX,
196995eae423SZachary Turner         variable_list);
19708b244e21SEwan Crawford 
1971b9c1b51eSKate Stone   // Iterate over all the global variables looking for one with a matching type
1972b9c1b51eSKate Stone   // to the Element.
1973b9c1b51eSKate Stone   // We make the assumption a match exists since there needs to be a global
1974b9c1b51eSKate Stone   // variable to reflect the
19758b244e21SEwan Crawford   // struct type back into java host code.
1976b9c1b51eSKate Stone   for (uint32_t var_index = 0; var_index < variable_list.GetSize();
1977b9c1b51eSKate Stone        ++var_index) {
19788b244e21SEwan Crawford     const VariableSP var_sp(variable_list.GetVariableAtIndex(var_index));
19798b244e21SEwan Crawford     if (!var_sp)
19808b244e21SEwan Crawford       continue;
19818b244e21SEwan Crawford 
19828b244e21SEwan Crawford     ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp);
19838b244e21SEwan Crawford     if (!valobj_sp)
19848b244e21SEwan Crawford       continue;
19858b244e21SEwan Crawford 
19868b244e21SEwan Crawford     // Find the number of variable fields.
1987b9c1b51eSKate Stone     // If it has no fields, or more fields than our Element, then it can't be
1988b9c1b51eSKate Stone     // the struct we're looking for.
1989b9c1b51eSKate Stone     // Don't check for equality since RS can add extra struct members for
1990b9c1b51eSKate Stone     // padding.
19918b244e21SEwan Crawford     size_t num_children = valobj_sp->GetNumChildren();
19928b244e21SEwan Crawford     if (num_children > elem.children.size() || num_children == 0)
19938b244e21SEwan Crawford       continue;
19948b244e21SEwan Crawford 
19958b244e21SEwan Crawford     // Iterate over children looking for members with matching field names.
19968b244e21SEwan Crawford     // If all the field names match, this is likely the struct we want.
19978b244e21SEwan Crawford     //
1998b9c1b51eSKate Stone     //   TODO: This could be made more robust by also checking children data
1999b9c1b51eSKate Stone     //   sizes, or array size
20008b244e21SEwan Crawford     bool found = true;
2001b9c1b51eSKate Stone     for (size_t child_index = 0; child_index < num_children; ++child_index) {
20028b244e21SEwan Crawford       ValueObjectSP child = valobj_sp->GetChildAtIndex(child_index, true);
2003b9c1b51eSKate Stone       if (!child ||
2004b9c1b51eSKate Stone           (child->GetName() != elem.children[child_index].type_name)) {
20058b244e21SEwan Crawford         found = false;
20068b244e21SEwan Crawford         break;
20078b244e21SEwan Crawford       }
20088b244e21SEwan Crawford     }
20098b244e21SEwan Crawford 
2010b9c1b51eSKate Stone     // RS can add extra struct members for padding in the format
2011b9c1b51eSKate Stone     // '#rs_padding_[0-9]+'
2012b9c1b51eSKate Stone     if (found && num_children < elem.children.size()) {
2013b3f7f69dSAidan Dodds       const uint32_t size_diff = elem.children.size() - num_children;
20148b244e21SEwan Crawford       if (log)
2015b9c1b51eSKate Stone         log->Printf("%s - %" PRIu32 " padding struct entries", __FUNCTION__,
2016b9c1b51eSKate Stone                     size_diff);
20178b244e21SEwan Crawford 
2018b9c1b51eSKate Stone       for (uint32_t padding_index = 0; padding_index < size_diff;
2019b9c1b51eSKate Stone            ++padding_index) {
2020b9c1b51eSKate Stone         const ConstString &name =
2021b9c1b51eSKate Stone             elem.children[num_children + padding_index].type_name;
20228b244e21SEwan Crawford         if (strcmp(name.AsCString(), "#rs_padding") < 0)
20238b244e21SEwan Crawford           found = false;
20248b244e21SEwan Crawford       }
20258b244e21SEwan Crawford     }
20268b244e21SEwan Crawford 
20278b244e21SEwan Crawford     // We've found a global var with matching type
2028b9c1b51eSKate Stone     if (found) {
20298b244e21SEwan Crawford       // Dereference since our Element type isn't a pointer.
2030b9c1b51eSKate Stone       if (valobj_sp->IsPointerType()) {
20318b244e21SEwan Crawford         Error err;
20328b244e21SEwan Crawford         ValueObjectSP deref_valobj = valobj_sp->Dereference(err);
20338b244e21SEwan Crawford         if (!err.Fail())
20348b244e21SEwan Crawford           valobj_sp = deref_valobj;
20358b244e21SEwan Crawford       }
20368b244e21SEwan Crawford 
20378b244e21SEwan Crawford       // Save name of variable in Element.
20388b244e21SEwan Crawford       elem.type_name = valobj_sp->GetTypeName();
20398b244e21SEwan Crawford       if (log)
2040b9c1b51eSKate Stone         log->Printf("%s - element name set to %s", __FUNCTION__,
2041b9c1b51eSKate Stone                     elem.type_name.AsCString());
20428b244e21SEwan Crawford 
20438b244e21SEwan Crawford       return;
20448b244e21SEwan Crawford     }
20458b244e21SEwan Crawford   }
20468b244e21SEwan Crawford }
20478b244e21SEwan Crawford 
2048b9c1b51eSKate Stone // Function sets the datum_size member of Element. Representing the size of a
2049b9c1b51eSKate Stone // single instance including padding.
20508b244e21SEwan Crawford // Assumes the relevant allocation information has already been jitted.
2051b9c1b51eSKate Stone void RenderScriptRuntime::SetElementSize(Element &elem) {
20528b244e21SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
20538b244e21SEwan Crawford   const Element::DataType type = *elem.type.get();
2054b9c1b51eSKate Stone   assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT &&
2055b9c1b51eSKate Stone          "Invalid allocation type");
205655232f09SEwan Crawford 
2057b3f7f69dSAidan Dodds   const uint32_t vec_size = *elem.type_vec_size.get();
2058b3f7f69dSAidan Dodds   uint32_t data_size = 0;
2059b3f7f69dSAidan Dodds   uint32_t padding = 0;
206055232f09SEwan Crawford 
20618b244e21SEwan Crawford   // Element is of a struct type, calculate size recursively.
2062b9c1b51eSKate Stone   if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) {
2063b9c1b51eSKate Stone     for (Element &child : elem.children) {
20648b244e21SEwan Crawford       SetElementSize(child);
2065b9c1b51eSKate Stone       const uint32_t array_size =
2066b9c1b51eSKate Stone           child.array_size.isValid() ? *child.array_size.get() : 1;
20678b244e21SEwan Crawford       data_size += *child.datum_size.get() * array_size;
20688b244e21SEwan Crawford     }
20698b244e21SEwan Crawford   }
2070b3f7f69dSAidan Dodds   // These have been packed already
2071b3f7f69dSAidan Dodds   else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 ||
2072b3f7f69dSAidan Dodds            type == Element::RS_TYPE_UNSIGNED_5_5_5_1 ||
2073b9c1b51eSKate Stone            type == Element::RS_TYPE_UNSIGNED_4_4_4_4) {
20742e920715SEwan Crawford     data_size = AllocationDetails::RSTypeToFormat[type][eElementSize];
2075b9c1b51eSKate Stone   } else if (type < Element::RS_TYPE_ELEMENT) {
2076b9c1b51eSKate Stone     data_size =
2077b9c1b51eSKate Stone         vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize];
20782e920715SEwan Crawford     if (vec_size == 3)
20792e920715SEwan Crawford       padding = AllocationDetails::RSTypeToFormat[type][eElementSize];
2080b9c1b51eSKate Stone   } else
2081b9c1b51eSKate Stone     data_size =
2082b9c1b51eSKate Stone         GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
20838b244e21SEwan Crawford 
20848b244e21SEwan Crawford   elem.padding = padding;
20858b244e21SEwan Crawford   elem.datum_size = data_size + padding;
20868b244e21SEwan Crawford   if (log)
2087b9c1b51eSKate Stone     log->Printf("%s - element size set to %" PRIu32, __FUNCTION__,
2088b9c1b51eSKate Stone                 data_size + padding);
208955232f09SEwan Crawford }
209055232f09SEwan Crawford 
2091b9c1b51eSKate Stone // Given an allocation, this function copies the allocation contents from device
2092b9c1b51eSKate Stone // into a buffer on the heap.
209355232f09SEwan Crawford // Returning a shared pointer to the buffer containing the data.
209455232f09SEwan Crawford std::shared_ptr<uint8_t>
2095b9c1b51eSKate Stone RenderScriptRuntime::GetAllocationData(AllocationDetails *allocation,
2096b9c1b51eSKate Stone                                        StackFrame *frame_ptr) {
209755232f09SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
209855232f09SEwan Crawford 
209955232f09SEwan Crawford   // JIT all the allocation details
2100b9c1b51eSKate Stone   if (allocation->shouldRefresh()) {
210155232f09SEwan Crawford     if (log)
2102b9c1b51eSKate Stone       log->Printf("%s - allocation details not calculated yet, jitting info",
2103b9c1b51eSKate Stone                   __FUNCTION__);
210455232f09SEwan Crawford 
2105b9c1b51eSKate Stone     if (!RefreshAllocation(allocation, frame_ptr)) {
210655232f09SEwan Crawford       if (log)
2107b3f7f69dSAidan Dodds         log->Printf("%s - couldn't JIT allocation details", __FUNCTION__);
210855232f09SEwan Crawford       return nullptr;
210955232f09SEwan Crawford     }
211055232f09SEwan Crawford   }
211155232f09SEwan Crawford 
2112b3f7f69dSAidan Dodds   assert(allocation->data_ptr.isValid() && allocation->element.type.isValid() &&
2113b9c1b51eSKate Stone          allocation->element.type_vec_size.isValid() &&
2114b9c1b51eSKate Stone          allocation->size.isValid() && "Allocation information not available");
211555232f09SEwan Crawford 
211655232f09SEwan Crawford   // Allocate a buffer to copy data into
2117b3f7f69dSAidan Dodds   const uint32_t size = *allocation->size.get();
211855232f09SEwan Crawford   std::shared_ptr<uint8_t> buffer(new uint8_t[size]);
2119b9c1b51eSKate Stone   if (!buffer) {
212055232f09SEwan Crawford     if (log)
2121b9c1b51eSKate Stone       log->Printf("%s - couldn't allocate a %" PRIu32 " byte buffer",
2122b9c1b51eSKate Stone                   __FUNCTION__, size);
212355232f09SEwan Crawford     return nullptr;
212455232f09SEwan Crawford   }
212555232f09SEwan Crawford 
212655232f09SEwan Crawford   // Read the inferior memory
212755232f09SEwan Crawford   Error error;
212855232f09SEwan Crawford   lldb::addr_t data_ptr = *allocation->data_ptr.get();
212955232f09SEwan Crawford   GetProcess()->ReadMemory(data_ptr, buffer.get(), size, error);
2130b9c1b51eSKate Stone   if (error.Fail()) {
213155232f09SEwan Crawford     if (log)
2132b9c1b51eSKate Stone       log->Printf("%s - '%s' Couldn't read %" PRIu32
2133b9c1b51eSKate Stone                   " bytes of allocation data from 0x%" PRIx64,
2134b3f7f69dSAidan Dodds                   __FUNCTION__, error.AsCString(), size, data_ptr);
213555232f09SEwan Crawford     return nullptr;
213655232f09SEwan Crawford   }
213755232f09SEwan Crawford 
213855232f09SEwan Crawford   return buffer;
213955232f09SEwan Crawford }
214055232f09SEwan Crawford 
214155232f09SEwan Crawford // Function copies data from a binary file into an allocation.
2142b9c1b51eSKate Stone // There is a header at the start of the file, FileHeader, before the data
2143b9c1b51eSKate Stone // content itself.
2144b9c1b51eSKate Stone // Information from this header is used to display warnings to the user about
2145b9c1b51eSKate Stone // incompatibilities
2146b9c1b51eSKate Stone bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id,
2147b9c1b51eSKate Stone                                          const char *filename,
2148b9c1b51eSKate Stone                                          StackFrame *frame_ptr) {
214955232f09SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
215055232f09SEwan Crawford 
215155232f09SEwan Crawford   // Find allocation with the given id
215255232f09SEwan Crawford   AllocationDetails *alloc = FindAllocByID(strm, alloc_id);
215355232f09SEwan Crawford   if (!alloc)
215455232f09SEwan Crawford     return false;
215555232f09SEwan Crawford 
215655232f09SEwan Crawford   if (log)
2157b9c1b51eSKate Stone     log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__,
2158b9c1b51eSKate Stone                 *alloc->address.get());
215955232f09SEwan Crawford 
216055232f09SEwan Crawford   // JIT all the allocation details
2161b9c1b51eSKate Stone   if (alloc->shouldRefresh()) {
216255232f09SEwan Crawford     if (log)
2163b9c1b51eSKate Stone       log->Printf("%s - allocation details not calculated yet, jitting info.",
2164b9c1b51eSKate Stone                   __FUNCTION__);
216555232f09SEwan Crawford 
2166b9c1b51eSKate Stone     if (!RefreshAllocation(alloc, frame_ptr)) {
216755232f09SEwan Crawford       if (log)
2168b3f7f69dSAidan Dodds         log->Printf("%s - couldn't JIT allocation details", __FUNCTION__);
21694cfc9198SSylvestre Ledru       return false;
217055232f09SEwan Crawford     }
217155232f09SEwan Crawford   }
217255232f09SEwan Crawford 
2173b9c1b51eSKate Stone   assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
2174b9c1b51eSKate Stone          alloc->element.type_vec_size.isValid() && alloc->size.isValid() &&
2175b9c1b51eSKate Stone          alloc->element.datum_size.isValid() &&
2176b9c1b51eSKate Stone          "Allocation information not available");
217755232f09SEwan Crawford 
217855232f09SEwan Crawford   // Check we can read from file
217955232f09SEwan Crawford   FileSpec file(filename, true);
2180b9c1b51eSKate Stone   if (!file.Exists()) {
218155232f09SEwan Crawford     strm.Printf("Error: File %s does not exist", filename);
218255232f09SEwan Crawford     strm.EOL();
218355232f09SEwan Crawford     return false;
218455232f09SEwan Crawford   }
218555232f09SEwan Crawford 
2186b9c1b51eSKate Stone   if (!file.Readable()) {
218755232f09SEwan Crawford     strm.Printf("Error: File %s does not have readable permissions", filename);
218855232f09SEwan Crawford     strm.EOL();
218955232f09SEwan Crawford     return false;
219055232f09SEwan Crawford   }
219155232f09SEwan Crawford 
219255232f09SEwan Crawford   // Read file into data buffer
219355232f09SEwan Crawford   DataBufferSP data_sp(file.ReadFileContents());
219455232f09SEwan Crawford 
219555232f09SEwan Crawford   // Cast start of buffer to FileHeader and use pointer to read metadata
219655232f09SEwan Crawford   void *file_buffer = data_sp->GetBytes();
2197b3f7f69dSAidan Dodds   if (file_buffer == nullptr ||
2198b9c1b51eSKate Stone       data_sp->GetByteSize() < (sizeof(AllocationDetails::FileHeader) +
2199b9c1b51eSKate Stone                                 sizeof(AllocationDetails::ElementHeader))) {
2200b9c1b51eSKate Stone     strm.Printf("Error: File %s does not contain enough data for header",
2201b9c1b51eSKate Stone                 filename);
220226e52a70SEwan Crawford     strm.EOL();
220326e52a70SEwan Crawford     return false;
220426e52a70SEwan Crawford   }
2205b9c1b51eSKate Stone   const AllocationDetails::FileHeader *file_header =
2206b9c1b51eSKate Stone       static_cast<AllocationDetails::FileHeader *>(file_buffer);
220755232f09SEwan Crawford 
220826e52a70SEwan Crawford   // Check file starts with ascii characters "RSAD"
2209b9c1b51eSKate Stone   if (memcmp(file_header->ident, "RSAD", 4)) {
2210b9c1b51eSKate Stone     strm.Printf("Error: File doesn't contain identifier for an RS allocation "
2211b9c1b51eSKate Stone                 "dump. Are you sure this is the correct file?");
221226e52a70SEwan Crawford     strm.EOL();
221326e52a70SEwan Crawford     return false;
221426e52a70SEwan Crawford   }
221526e52a70SEwan Crawford 
221626e52a70SEwan Crawford   // Look at the type of the root element in the header
221726e52a70SEwan Crawford   AllocationDetails::ElementHeader root_element_header;
2218b9c1b51eSKate Stone   memcpy(&root_element_header, static_cast<uint8_t *>(file_buffer) +
2219b9c1b51eSKate Stone                                    sizeof(AllocationDetails::FileHeader),
222026e52a70SEwan Crawford          sizeof(AllocationDetails::ElementHeader));
222155232f09SEwan Crawford 
222255232f09SEwan Crawford   if (log)
2223b9c1b51eSKate Stone     log->Printf("%s - header type %" PRIu32 ", element size %" PRIu32,
2224b9c1b51eSKate Stone                 __FUNCTION__, root_element_header.type,
2225b9c1b51eSKate Stone                 root_element_header.element_size);
222655232f09SEwan Crawford 
2227b9c1b51eSKate Stone   // Check if the target allocation and file both have the same number of bytes
2228b9c1b51eSKate Stone   // for an Element
2229b9c1b51eSKate Stone   if (*alloc->element.datum_size.get() != root_element_header.element_size) {
2230b9c1b51eSKate Stone     strm.Printf("Warning: Mismatched Element sizes - file %" PRIu32
2231b9c1b51eSKate Stone                 " bytes, allocation %" PRIu32 " bytes",
2232b9c1b51eSKate Stone                 root_element_header.element_size,
2233b9c1b51eSKate Stone                 *alloc->element.datum_size.get());
223455232f09SEwan Crawford     strm.EOL();
223555232f09SEwan Crawford   }
223655232f09SEwan Crawford 
223726e52a70SEwan Crawford   // Check if the target allocation and file both have the same type
2238b3f7f69dSAidan Dodds   const uint32_t alloc_type = static_cast<uint32_t>(*alloc->element.type.get());
2239b3f7f69dSAidan Dodds   const uint32_t file_type = root_element_header.type;
224026e52a70SEwan Crawford 
2241b9c1b51eSKate Stone   if (file_type > Element::RS_TYPE_FONT) {
224226e52a70SEwan Crawford     strm.Printf("Warning: File has unknown allocation type");
224326e52a70SEwan Crawford     strm.EOL();
2244b9c1b51eSKate Stone   } else if (alloc_type != file_type) {
2245b9c1b51eSKate Stone     // Enum value isn't monotonous, so doesn't always index RsDataTypeToString
2246b9c1b51eSKate Stone     // array
2247b3f7f69dSAidan Dodds     uint32_t printable_target_type_index = alloc_type;
2248b3f7f69dSAidan Dodds     uint32_t printable_head_type_index = file_type;
2249b9c1b51eSKate Stone     if (alloc_type >= Element::RS_TYPE_ELEMENT &&
2250b9c1b51eSKate Stone         alloc_type <= Element::RS_TYPE_FONT)
2251b9c1b51eSKate Stone       printable_target_type_index = static_cast<Element::DataType>(
2252b9c1b51eSKate Stone           (alloc_type - Element::RS_TYPE_ELEMENT) +
2253b3f7f69dSAidan Dodds           Element::RS_TYPE_MATRIX_2X2 + 1);
22542e920715SEwan Crawford 
2255b9c1b51eSKate Stone     if (file_type >= Element::RS_TYPE_ELEMENT &&
2256b9c1b51eSKate Stone         file_type <= Element::RS_TYPE_FONT)
2257b9c1b51eSKate Stone       printable_head_type_index = static_cast<Element::DataType>(
2258b9c1b51eSKate Stone           (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 +
2259b9c1b51eSKate Stone           1);
22602e920715SEwan Crawford 
2261b9c1b51eSKate Stone     const char *file_type_cstr =
2262b9c1b51eSKate Stone         AllocationDetails::RsDataTypeToString[printable_head_type_index][0];
2263b9c1b51eSKate Stone     const char *target_type_cstr =
2264b9c1b51eSKate Stone         AllocationDetails::RsDataTypeToString[printable_target_type_index][0];
226555232f09SEwan Crawford 
2266b9c1b51eSKate Stone     strm.Printf(
2267b9c1b51eSKate Stone         "Warning: Mismatched Types - file '%s' type, allocation '%s' type",
2268b9c1b51eSKate Stone         file_type_cstr, target_type_cstr);
226955232f09SEwan Crawford     strm.EOL();
227055232f09SEwan Crawford   }
227155232f09SEwan Crawford 
227226e52a70SEwan Crawford   // Advance buffer past header
227326e52a70SEwan Crawford   file_buffer = static_cast<uint8_t *>(file_buffer) + file_header->hdr_size;
227426e52a70SEwan Crawford 
227555232f09SEwan Crawford   // Calculate size of allocation data in file
227626e52a70SEwan Crawford   size_t length = data_sp->GetByteSize() - file_header->hdr_size;
227755232f09SEwan Crawford 
227855232f09SEwan Crawford   // Check if the target allocation and file both have the same total data size.
2279b3f7f69dSAidan Dodds   const uint32_t alloc_size = *alloc->size.get();
2280b9c1b51eSKate Stone   if (alloc_size != length) {
2281b9c1b51eSKate Stone     strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64
2282b9c1b51eSKate Stone                 " bytes, allocation 0x%" PRIx32 " bytes",
2283eba832beSJason Molenda                 (uint64_t)length, alloc_size);
228455232f09SEwan Crawford     strm.EOL();
2285b9c1b51eSKate Stone     length = alloc_size < length ? alloc_size
2286b9c1b51eSKate Stone                                  : length; // Set length to copy to minimum
228755232f09SEwan Crawford   }
228855232f09SEwan Crawford 
228955232f09SEwan Crawford   // Copy file data from our buffer into the target allocation.
229055232f09SEwan Crawford   lldb::addr_t alloc_data = *alloc->data_ptr.get();
229155232f09SEwan Crawford   Error error;
2292b9c1b51eSKate Stone   size_t bytes_written =
2293b9c1b51eSKate Stone       GetProcess()->WriteMemory(alloc_data, file_buffer, length, error);
2294b9c1b51eSKate Stone   if (!error.Success() || bytes_written != length) {
2295b9c1b51eSKate Stone     strm.Printf("Error: Couldn't write data to allocation %s",
2296b9c1b51eSKate Stone                 error.AsCString());
229755232f09SEwan Crawford     strm.EOL();
229855232f09SEwan Crawford     return false;
229955232f09SEwan Crawford   }
230055232f09SEwan Crawford 
2301b9c1b51eSKate Stone   strm.Printf("Contents of file '%s' read into allocation %" PRIu32, filename,
2302b9c1b51eSKate Stone               alloc->id);
230355232f09SEwan Crawford   strm.EOL();
230455232f09SEwan Crawford 
230555232f09SEwan Crawford   return true;
230655232f09SEwan Crawford }
230755232f09SEwan Crawford 
2308b9c1b51eSKate Stone // Function takes as parameters a byte buffer, which will eventually be written
2309b9c1b51eSKate Stone // to file as the element header,
2310b9c1b51eSKate Stone // an offset into that buffer, and an Element that will be saved into the buffer
2311b9c1b51eSKate Stone // at the parametrised offset.
231226e52a70SEwan Crawford // Return value is the new offset after writing the element into the buffer.
2313b9c1b51eSKate Stone // Elements are saved to the file as the ElementHeader struct followed by
2314b9c1b51eSKate Stone // offsets to the structs of all the element's
2315b3f7f69dSAidan Dodds // children.
2316b9c1b51eSKate Stone size_t RenderScriptRuntime::PopulateElementHeaders(
2317b9c1b51eSKate Stone     const std::shared_ptr<uint8_t> header_buffer, size_t offset,
2318b9c1b51eSKate Stone     const Element &elem) {
2319b9c1b51eSKate Stone   // File struct for an element header with all the relevant details copied from
2320b9c1b51eSKate Stone   // elem.
232126e52a70SEwan Crawford   // We assume members are valid already.
232226e52a70SEwan Crawford   AllocationDetails::ElementHeader elem_header;
232326e52a70SEwan Crawford   elem_header.type = *elem.type.get();
232426e52a70SEwan Crawford   elem_header.kind = *elem.type_kind.get();
232526e52a70SEwan Crawford   elem_header.element_size = *elem.datum_size.get();
232626e52a70SEwan Crawford   elem_header.vector_size = *elem.type_vec_size.get();
2327b9c1b51eSKate Stone   elem_header.array_size =
2328b9c1b51eSKate Stone       elem.array_size.isValid() ? *elem.array_size.get() : 0;
232926e52a70SEwan Crawford   const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader);
233026e52a70SEwan Crawford 
233126e52a70SEwan Crawford   // Copy struct into buffer and advance offset
2332b9c1b51eSKate Stone   // We assume that header_buffer has been checked for nullptr before this
2333b9c1b51eSKate Stone   // method is called
233426e52a70SEwan Crawford   memcpy(header_buffer.get() + offset, &elem_header, elem_header_size);
233526e52a70SEwan Crawford   offset += elem_header_size;
233626e52a70SEwan Crawford 
233726e52a70SEwan Crawford   // Starting offset of child ElementHeader struct
2338b9c1b51eSKate Stone   size_t child_offset =
2339b9c1b51eSKate Stone       offset + ((elem.children.size() + 1) * sizeof(uint32_t));
2340b9c1b51eSKate Stone   for (const RenderScriptRuntime::Element &child : elem.children) {
2341b9c1b51eSKate Stone     // Recursively populate the buffer with the element header structs of
2342b9c1b51eSKate Stone     // children.
2343b9c1b51eSKate Stone     // Then save the offsets where they were set after the parent element
2344b9c1b51eSKate Stone     // header.
234526e52a70SEwan Crawford     memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t));
234626e52a70SEwan Crawford     offset += sizeof(uint32_t);
234726e52a70SEwan Crawford 
234826e52a70SEwan Crawford     child_offset = PopulateElementHeaders(header_buffer, child_offset, child);
234926e52a70SEwan Crawford   }
235026e52a70SEwan Crawford 
235126e52a70SEwan Crawford   // Zero indicates no more children
235226e52a70SEwan Crawford   memset(header_buffer.get() + offset, 0, sizeof(uint32_t));
235326e52a70SEwan Crawford 
235426e52a70SEwan Crawford   return child_offset;
235526e52a70SEwan Crawford }
235626e52a70SEwan Crawford 
2357b9c1b51eSKate Stone // Given an Element object this function returns the total size needed in the
2358b9c1b51eSKate Stone // file header to store the element's
2359b3f7f69dSAidan Dodds // details.
2360b9c1b51eSKate Stone // Taking into account the size of the element header struct, plus the offsets
2361b9c1b51eSKate Stone // to all the element's children.
2362b9c1b51eSKate Stone // Function is recursive so that the size of all ancestors is taken into
2363b9c1b51eSKate Stone // account.
2364b9c1b51eSKate Stone size_t RenderScriptRuntime::CalculateElementHeaderSize(const Element &elem) {
2365b9c1b51eSKate Stone   size_t size = (elem.children.size() + 1) *
2366b9c1b51eSKate Stone                 sizeof(uint32_t); // Offsets to children plus zero terminator
2367b9c1b51eSKate Stone   size += sizeof(AllocationDetails::ElementHeader); // Size of header struct
2368b9c1b51eSKate Stone                                                     // with type details
236926e52a70SEwan Crawford 
237026e52a70SEwan Crawford   // Calculate recursively for all descendants
237126e52a70SEwan Crawford   for (const Element &child : elem.children)
237226e52a70SEwan Crawford     size += CalculateElementHeaderSize(child);
237326e52a70SEwan Crawford 
237426e52a70SEwan Crawford   return size;
237526e52a70SEwan Crawford }
237626e52a70SEwan Crawford 
237755232f09SEwan Crawford // Function copies allocation contents into a binary file.
237855232f09SEwan Crawford // This file can then be loaded later into a different allocation.
2379b9c1b51eSKate Stone // There is a header, FileHeader, before the allocation data containing
2380b9c1b51eSKate Stone // meta-data.
2381b9c1b51eSKate Stone bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id,
2382b9c1b51eSKate Stone                                          const char *filename,
2383b9c1b51eSKate Stone                                          StackFrame *frame_ptr) {
238455232f09SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
238555232f09SEwan Crawford 
238655232f09SEwan Crawford   // Find allocation with the given id
238755232f09SEwan Crawford   AllocationDetails *alloc = FindAllocByID(strm, alloc_id);
238855232f09SEwan Crawford   if (!alloc)
238955232f09SEwan Crawford     return false;
239055232f09SEwan Crawford 
239155232f09SEwan Crawford   if (log)
2392b9c1b51eSKate Stone     log->Printf("%s - found allocation 0x%" PRIx64 ".", __FUNCTION__,
2393b9c1b51eSKate Stone                 *alloc->address.get());
239455232f09SEwan Crawford 
239555232f09SEwan Crawford   // JIT all the allocation details
2396b9c1b51eSKate Stone   if (alloc->shouldRefresh()) {
239755232f09SEwan Crawford     if (log)
2398b9c1b51eSKate Stone       log->Printf("%s - allocation details not calculated yet, jitting info.",
2399b9c1b51eSKate Stone                   __FUNCTION__);
240055232f09SEwan Crawford 
2401b9c1b51eSKate Stone     if (!RefreshAllocation(alloc, frame_ptr)) {
240255232f09SEwan Crawford       if (log)
2403b3f7f69dSAidan Dodds         log->Printf("%s - couldn't JIT allocation details.", __FUNCTION__);
24044cfc9198SSylvestre Ledru       return false;
240555232f09SEwan Crawford     }
240655232f09SEwan Crawford   }
240755232f09SEwan Crawford 
2408b9c1b51eSKate Stone   assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
2409b9c1b51eSKate Stone          alloc->element.type_vec_size.isValid() &&
2410b9c1b51eSKate Stone          alloc->element.datum_size.get() &&
2411b9c1b51eSKate Stone          alloc->element.type_kind.isValid() && alloc->dimension.isValid() &&
2412b3f7f69dSAidan Dodds          "Allocation information not available");
241355232f09SEwan Crawford 
241455232f09SEwan Crawford   // Check we can create writable file
241555232f09SEwan Crawford   FileSpec file_spec(filename, true);
2416b9c1b51eSKate Stone   File file(file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate |
2417b9c1b51eSKate Stone                            File::eOpenOptionTruncate);
2418b9c1b51eSKate Stone   if (!file) {
241955232f09SEwan Crawford     strm.Printf("Error: Failed to open '%s' for writing", filename);
242055232f09SEwan Crawford     strm.EOL();
242155232f09SEwan Crawford     return false;
242255232f09SEwan Crawford   }
242355232f09SEwan Crawford 
242455232f09SEwan Crawford   // Read allocation into buffer of heap memory
242555232f09SEwan Crawford   const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
2426b9c1b51eSKate Stone   if (!buffer) {
242755232f09SEwan Crawford     strm.Printf("Error: Couldn't read allocation data into buffer");
242855232f09SEwan Crawford     strm.EOL();
242955232f09SEwan Crawford     return false;
243055232f09SEwan Crawford   }
243155232f09SEwan Crawford 
243255232f09SEwan Crawford   // Create the file header
243355232f09SEwan Crawford   AllocationDetails::FileHeader head;
2434b3f7f69dSAidan Dodds   memcpy(head.ident, "RSAD", 4);
24352d62328aSEwan Crawford   head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1);
24362d62328aSEwan Crawford   head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2);
24372d62328aSEwan Crawford   head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3);
243826e52a70SEwan Crawford 
243926e52a70SEwan Crawford   const size_t element_header_size = CalculateElementHeaderSize(alloc->element);
2440b9c1b51eSKate Stone   assert((sizeof(AllocationDetails::FileHeader) + element_header_size) <
2441b9c1b51eSKate Stone              UINT16_MAX &&
2442b9c1b51eSKate Stone          "Element header too large");
2443b9c1b51eSKate Stone   head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) +
2444b9c1b51eSKate Stone                                         element_header_size);
244555232f09SEwan Crawford 
244655232f09SEwan Crawford   // Write the file header
244755232f09SEwan Crawford   size_t num_bytes = sizeof(AllocationDetails::FileHeader);
244826e52a70SEwan Crawford   if (log)
2449b9c1b51eSKate Stone     log->Printf("%s - writing File Header, 0x%" PRIx64 " bytes", __FUNCTION__,
2450b9c1b51eSKate Stone                 (uint64_t)num_bytes);
245126e52a70SEwan Crawford 
245226e52a70SEwan Crawford   Error err = file.Write(&head, num_bytes);
2453b9c1b51eSKate Stone   if (!err.Success()) {
2454b9c1b51eSKate Stone     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(),
2455b9c1b51eSKate Stone                 filename);
245626e52a70SEwan Crawford     strm.EOL();
245726e52a70SEwan Crawford     return false;
245826e52a70SEwan Crawford   }
245926e52a70SEwan Crawford 
246026e52a70SEwan Crawford   // Create the headers describing the element type of the allocation.
2461b9c1b51eSKate Stone   std::shared_ptr<uint8_t> element_header_buffer(
2462b9c1b51eSKate Stone       new uint8_t[element_header_size]);
2463b9c1b51eSKate Stone   if (element_header_buffer == nullptr) {
2464b9c1b51eSKate Stone     strm.Printf("Internal Error: Couldn't allocate %" PRIu64
2465b9c1b51eSKate Stone                 " bytes on the heap",
2466b9c1b51eSKate Stone                 (uint64_t)element_header_size);
246726e52a70SEwan Crawford     strm.EOL();
246826e52a70SEwan Crawford     return false;
246926e52a70SEwan Crawford   }
247026e52a70SEwan Crawford 
247126e52a70SEwan Crawford   PopulateElementHeaders(element_header_buffer, 0, alloc->element);
247226e52a70SEwan Crawford 
247326e52a70SEwan Crawford   // Write headers for allocation element type to file
247426e52a70SEwan Crawford   num_bytes = element_header_size;
247526e52a70SEwan Crawford   if (log)
2476b9c1b51eSKate Stone     log->Printf("%s - writing element headers, 0x%" PRIx64 " bytes.",
2477b9c1b51eSKate Stone                 __FUNCTION__, (uint64_t)num_bytes);
247826e52a70SEwan Crawford 
247926e52a70SEwan Crawford   err = file.Write(element_header_buffer.get(), num_bytes);
2480b9c1b51eSKate Stone   if (!err.Success()) {
2481b9c1b51eSKate Stone     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(),
2482b9c1b51eSKate Stone                 filename);
248355232f09SEwan Crawford     strm.EOL();
248455232f09SEwan Crawford     return false;
248555232f09SEwan Crawford   }
248655232f09SEwan Crawford 
248755232f09SEwan Crawford   // Write allocation data to file
248855232f09SEwan Crawford   num_bytes = static_cast<size_t>(*alloc->size.get());
248955232f09SEwan Crawford   if (log)
2490b9c1b51eSKate Stone     log->Printf("%s - writing 0x%" PRIx64 " bytes", __FUNCTION__,
2491b9c1b51eSKate Stone                 (uint64_t)num_bytes);
249255232f09SEwan Crawford 
249355232f09SEwan Crawford   err = file.Write(buffer.get(), num_bytes);
2494b9c1b51eSKate Stone   if (!err.Success()) {
2495b9c1b51eSKate Stone     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(),
2496b9c1b51eSKate Stone                 filename);
249755232f09SEwan Crawford     strm.EOL();
249855232f09SEwan Crawford     return false;
249955232f09SEwan Crawford   }
250055232f09SEwan Crawford 
250155232f09SEwan Crawford   strm.Printf("Allocation written to file '%s'", filename);
250255232f09SEwan Crawford   strm.EOL();
250315f2bd95SEwan Crawford   return true;
250415f2bd95SEwan Crawford }
250515f2bd95SEwan Crawford 
2506b9c1b51eSKate Stone bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) {
25074640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
25084640cde1SColin Riley 
2509b9c1b51eSKate Stone   if (module_sp) {
2510b9c1b51eSKate Stone     for (const auto &rs_module : m_rsmodules) {
2511b9c1b51eSKate Stone       if (rs_module->m_module == module_sp) {
25127dc7771cSEwan Crawford         // Check if the user has enabled automatically breaking on
25137dc7771cSEwan Crawford         // all RS kernels.
25147dc7771cSEwan Crawford         if (m_breakAllKernels)
25157dc7771cSEwan Crawford           BreakOnModuleKernels(rs_module);
25167dc7771cSEwan Crawford 
25175ec532a9SColin Riley         return false;
25185ec532a9SColin Riley       }
25197dc7771cSEwan Crawford     }
2520ef20b08fSColin Riley     bool module_loaded = false;
2521b9c1b51eSKate Stone     switch (GetModuleKind(module_sp)) {
2522b9c1b51eSKate Stone     case eModuleKindKernelObj: {
25234640cde1SColin Riley       RSModuleDescriptorSP module_desc;
25244640cde1SColin Riley       module_desc.reset(new RSModuleDescriptor(module_sp));
2525b9c1b51eSKate Stone       if (module_desc->ParseRSInfo()) {
25265ec532a9SColin Riley         m_rsmodules.push_back(module_desc);
2527ef20b08fSColin Riley         module_loaded = true;
25285ec532a9SColin Riley       }
2529b9c1b51eSKate Stone       if (module_loaded) {
25304640cde1SColin Riley         FixupScriptDetails(module_desc);
25314640cde1SColin Riley       }
2532ef20b08fSColin Riley       break;
2533ef20b08fSColin Riley     }
2534b9c1b51eSKate Stone     case eModuleKindDriver: {
2535b9c1b51eSKate Stone       if (!m_libRSDriver) {
25364640cde1SColin Riley         m_libRSDriver = module_sp;
25374640cde1SColin Riley         LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver);
25384640cde1SColin Riley       }
25394640cde1SColin Riley       break;
25404640cde1SColin Riley     }
2541b9c1b51eSKate Stone     case eModuleKindImpl: {
25424640cde1SColin Riley       m_libRSCpuRef = module_sp;
25434640cde1SColin Riley       break;
25444640cde1SColin Riley     }
2545b9c1b51eSKate Stone     case eModuleKindLibRS: {
2546b9c1b51eSKate Stone       if (!m_libRS) {
25474640cde1SColin Riley         m_libRS = module_sp;
25484640cde1SColin Riley         static ConstString gDbgPresentStr("gDebuggerPresent");
2549b9c1b51eSKate Stone         const Symbol *debug_present = m_libRS->FindFirstSymbolWithNameAndType(
2550b9c1b51eSKate Stone             gDbgPresentStr, eSymbolTypeData);
2551b9c1b51eSKate Stone         if (debug_present) {
25524640cde1SColin Riley           Error error;
25534640cde1SColin Riley           uint32_t flag = 0x00000001U;
25544640cde1SColin Riley           Target &target = GetProcess()->GetTarget();
2555358cf1eaSGreg Clayton           addr_t addr = debug_present->GetLoadAddress(&target);
25564640cde1SColin Riley           GetProcess()->WriteMemory(addr, &flag, sizeof(flag), error);
2557b9c1b51eSKate Stone           if (error.Success()) {
25584640cde1SColin Riley             if (log)
2559b9c1b51eSKate Stone               log->Printf("%s - debugger present flag set on debugee.",
2560b9c1b51eSKate Stone                           __FUNCTION__);
25614640cde1SColin Riley 
25624640cde1SColin Riley             m_debuggerPresentFlagged = true;
2563b9c1b51eSKate Stone           } else if (log) {
2564b9c1b51eSKate Stone             log->Printf("%s - error writing debugger present flags '%s' ",
2565b9c1b51eSKate Stone                         __FUNCTION__, error.AsCString());
25664640cde1SColin Riley           }
2567b9c1b51eSKate Stone         } else if (log) {
2568b9c1b51eSKate Stone           log->Printf(
2569b9c1b51eSKate Stone               "%s - error writing debugger present flags - symbol not found",
2570b9c1b51eSKate Stone               __FUNCTION__);
25714640cde1SColin Riley         }
25724640cde1SColin Riley       }
25734640cde1SColin Riley       break;
25744640cde1SColin Riley     }
2575ef20b08fSColin Riley     default:
2576ef20b08fSColin Riley       break;
2577ef20b08fSColin Riley     }
2578ef20b08fSColin Riley     if (module_loaded)
2579ef20b08fSColin Riley       Update();
2580ef20b08fSColin Riley     return module_loaded;
25815ec532a9SColin Riley   }
25825ec532a9SColin Riley   return false;
25835ec532a9SColin Riley }
25845ec532a9SColin Riley 
2585b9c1b51eSKate Stone void RenderScriptRuntime::Update() {
2586b9c1b51eSKate Stone   if (m_rsmodules.size() > 0) {
2587b9c1b51eSKate Stone     if (!m_initiated) {
2588ef20b08fSColin Riley       Initiate();
2589ef20b08fSColin Riley     }
2590ef20b08fSColin Riley   }
2591ef20b08fSColin Riley }
2592ef20b08fSColin Riley 
25937f193d69SLuke Drummond bool RSModuleDescriptor::ParsePragmaCount(llvm::StringRef *lines,
25947f193d69SLuke Drummond                                           size_t n_lines) {
25957f193d69SLuke Drummond   // Skip the pragma prototype line
25967f193d69SLuke Drummond   ++lines;
25977f193d69SLuke Drummond   for (; n_lines--; ++lines) {
25987f193d69SLuke Drummond     const auto kv_pair = lines->split(" - ");
25997f193d69SLuke Drummond     m_pragmas[kv_pair.first.trim().str()] = kv_pair.second.trim().str();
26007f193d69SLuke Drummond   }
26017f193d69SLuke Drummond   return true;
26027f193d69SLuke Drummond }
26037f193d69SLuke Drummond 
26047f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportReduceCount(llvm::StringRef *lines,
26057f193d69SLuke Drummond                                                 size_t n_lines) {
26067f193d69SLuke Drummond   // The list of reduction kernels in the `.rs.info` symbol is of the form
26077f193d69SLuke Drummond   // "signature - accumulatordatasize - reduction_name - initializer_name -
26087f193d69SLuke Drummond   // accumulator_name - combiner_name -
26097f193d69SLuke Drummond   // outconverter_name - halter_name"
26107f193d69SLuke Drummond   // Where a function is not explicitly named by the user, or is not generated
26117f193d69SLuke Drummond   // by the compiler, it is named "." so the
26127f193d69SLuke Drummond   // dash separated list should always be 8 items long
26137f193d69SLuke Drummond   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
26147f193d69SLuke Drummond   // Skip the exportReduceCount line
26157f193d69SLuke Drummond   ++lines;
26167f193d69SLuke Drummond   for (; n_lines--; ++lines) {
26177f193d69SLuke Drummond     llvm::SmallVector<llvm::StringRef, 8> spec;
26187f193d69SLuke Drummond     lines->split(spec, " - ");
26197f193d69SLuke Drummond     if (spec.size() != 8) {
26207f193d69SLuke Drummond       if (spec.size() < 8) {
26217f193d69SLuke Drummond         if (log)
26227f193d69SLuke Drummond           log->Error("Error parsing RenderScript reduction spec. wrong number "
26237f193d69SLuke Drummond                      "of fields");
26247f193d69SLuke Drummond         return false;
26257f193d69SLuke Drummond       } else if (log)
26267f193d69SLuke Drummond         log->Warning("Extraneous members in reduction spec: '%s'",
26277f193d69SLuke Drummond                      lines->str().c_str());
26287f193d69SLuke Drummond     }
26297f193d69SLuke Drummond 
26307f193d69SLuke Drummond     const auto sig_s = spec[0];
26317f193d69SLuke Drummond     uint32_t sig;
26327f193d69SLuke Drummond     if (sig_s.getAsInteger(10, sig)) {
26337f193d69SLuke Drummond       if (log)
26347f193d69SLuke Drummond         log->Error("Error parsing Renderscript reduction spec: invalid kernel "
26357f193d69SLuke Drummond                    "signature: '%s'",
26367f193d69SLuke Drummond                    sig_s.str().c_str());
26377f193d69SLuke Drummond       return false;
26387f193d69SLuke Drummond     }
26397f193d69SLuke Drummond 
26407f193d69SLuke Drummond     const auto accum_data_size_s = spec[1];
26417f193d69SLuke Drummond     uint32_t accum_data_size;
26427f193d69SLuke Drummond     if (accum_data_size_s.getAsInteger(10, accum_data_size)) {
26437f193d69SLuke Drummond       if (log)
26447f193d69SLuke Drummond         log->Error("Error parsing Renderscript reduction spec: invalid "
26457f193d69SLuke Drummond                    "accumulator data size %s",
26467f193d69SLuke Drummond                    accum_data_size_s.str().c_str());
26477f193d69SLuke Drummond       return false;
26487f193d69SLuke Drummond     }
26497f193d69SLuke Drummond 
26507f193d69SLuke Drummond     if (log)
26517f193d69SLuke Drummond       log->Printf("Found RenderScript reduction '%s'", spec[2].str().c_str());
26527f193d69SLuke Drummond 
26537f193d69SLuke Drummond     m_reductions.push_back(RSReductionDescriptor(this, sig, accum_data_size,
26547f193d69SLuke Drummond                                                  spec[2], spec[3], spec[4],
26557f193d69SLuke Drummond                                                  spec[5], spec[6], spec[7]));
26567f193d69SLuke Drummond   }
26577f193d69SLuke Drummond   return true;
26587f193d69SLuke Drummond }
26597f193d69SLuke Drummond 
26607f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportForeachCount(llvm::StringRef *lines,
26617f193d69SLuke Drummond                                                  size_t n_lines) {
26627f193d69SLuke Drummond   // Skip the exportForeachCount line
26637f193d69SLuke Drummond   ++lines;
26647f193d69SLuke Drummond   for (; n_lines--; ++lines) {
26657f193d69SLuke Drummond     uint32_t slot;
26667f193d69SLuke Drummond     // `forEach` kernels are listed in the `.rs.info` packet as a "slot - name"
26677f193d69SLuke Drummond     // pair per line
26687f193d69SLuke Drummond     const auto kv_pair = lines->split(" - ");
26697f193d69SLuke Drummond     if (kv_pair.first.getAsInteger(10, slot))
26707f193d69SLuke Drummond       return false;
26717f193d69SLuke Drummond     m_kernels.push_back(RSKernelDescriptor(this, kv_pair.second, slot));
26727f193d69SLuke Drummond   }
26737f193d69SLuke Drummond   return true;
26747f193d69SLuke Drummond }
26757f193d69SLuke Drummond 
26767f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportVarCount(llvm::StringRef *lines,
26777f193d69SLuke Drummond                                              size_t n_lines) {
26787f193d69SLuke Drummond   // Skip the ExportVarCount line
26797f193d69SLuke Drummond   ++lines;
26807f193d69SLuke Drummond   for (; n_lines--; ++lines)
26817f193d69SLuke Drummond     m_globals.push_back(RSGlobalDescriptor(this, *lines));
26827f193d69SLuke Drummond   return true;
26837f193d69SLuke Drummond }
26845ec532a9SColin Riley 
2685b9c1b51eSKate Stone // The .rs.info symbol in renderscript modules contains a string which needs to
2686b9c1b51eSKate Stone // be parsed.
26875ec532a9SColin Riley // The string is basic and is parsed on a line by line basis.
2688b9c1b51eSKate Stone bool RSModuleDescriptor::ParseRSInfo() {
2689b0be30f7SAidan Dodds   assert(m_module);
26907f193d69SLuke Drummond   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2691b9c1b51eSKate Stone   const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType(
2692b9c1b51eSKate Stone       ConstString(".rs.info"), eSymbolTypeData);
2693b0be30f7SAidan Dodds   if (!info_sym)
2694b0be30f7SAidan Dodds     return false;
2695b0be30f7SAidan Dodds 
2696358cf1eaSGreg Clayton   const addr_t addr = info_sym->GetAddressRef().GetFileAddress();
2697b0be30f7SAidan Dodds   if (addr == LLDB_INVALID_ADDRESS)
2698b0be30f7SAidan Dodds     return false;
2699b0be30f7SAidan Dodds 
27005ec532a9SColin Riley   const addr_t size = info_sym->GetByteSize();
27015ec532a9SColin Riley   const FileSpec fs = m_module->GetFileSpec();
27025ec532a9SColin Riley 
2703b0be30f7SAidan Dodds   const DataBufferSP buffer = fs.ReadFileContents(addr, size);
27045ec532a9SColin Riley   if (!buffer)
27055ec532a9SColin Riley     return false;
27065ec532a9SColin Riley 
2707b0be30f7SAidan Dodds   // split rs.info. contents into lines
27087f193d69SLuke Drummond   llvm::SmallVector<llvm::StringRef, 128> info_lines;
27095ec532a9SColin Riley   {
27107f193d69SLuke Drummond     const llvm::StringRef raw_rs_info((const char *)buffer->GetBytes());
27117f193d69SLuke Drummond     raw_rs_info.split(info_lines, '\n');
27127f193d69SLuke Drummond     if (log)
27137f193d69SLuke Drummond       log->Printf("'.rs.info symbol for '%s':\n%s",
27147f193d69SLuke Drummond                   m_module->GetFileSpec().GetCString(),
27157f193d69SLuke Drummond                   raw_rs_info.str().c_str());
2716b0be30f7SAidan Dodds   }
2717b0be30f7SAidan Dodds 
27187f193d69SLuke Drummond   enum {
27197f193d69SLuke Drummond     eExportVar,
27207f193d69SLuke Drummond     eExportForEach,
27217f193d69SLuke Drummond     eExportReduce,
27227f193d69SLuke Drummond     ePragma,
27237f193d69SLuke Drummond     eBuildChecksum,
27247f193d69SLuke Drummond     eObjectSlot
27257f193d69SLuke Drummond   };
27267f193d69SLuke Drummond 
27277f193d69SLuke Drummond   static const llvm::StringMap<int> rs_info_handlers{
27287f193d69SLuke Drummond       {// The number of visible global variables in the script
27297f193d69SLuke Drummond        {"exportVarCount", eExportVar},
27307f193d69SLuke Drummond        // The number of RenderScrip `forEach` kernels __attribute__((kernel))
27317f193d69SLuke Drummond        {"exportForEachCount", eExportForEach},
27327f193d69SLuke Drummond        // The number of generalreductions: This marked in the script by `#pragma
27337f193d69SLuke Drummond        // reduce()`
27347f193d69SLuke Drummond        {"exportReduceCount", eExportReduce},
27357f193d69SLuke Drummond        // Total count of all RenderScript specific `#pragmas` used in the script
27367f193d69SLuke Drummond        {"pragmaCount", ePragma},
27377f193d69SLuke Drummond        {"objectSlotCount", eObjectSlot}}};
2738b0be30f7SAidan Dodds 
2739b0be30f7SAidan Dodds   // parse all text lines of .rs.info
2740b9c1b51eSKate Stone   for (auto line = info_lines.begin(); line != info_lines.end(); ++line) {
27417f193d69SLuke Drummond     const auto kv_pair = line->split(": ");
27427f193d69SLuke Drummond     const auto key = kv_pair.first;
27437f193d69SLuke Drummond     const auto val = kv_pair.second.trim();
27445ec532a9SColin Riley 
27457f193d69SLuke Drummond     const auto handler = rs_info_handlers.find(key);
27467f193d69SLuke Drummond     if (handler == rs_info_handlers.end())
27477f193d69SLuke Drummond       continue;
27487f193d69SLuke Drummond     // getAsInteger returns `true` on an error condition - we're only interested
27497f193d69SLuke Drummond     // in
27507f193d69SLuke Drummond     // numeric fields at the moment
27517f193d69SLuke Drummond     uint64_t n_lines;
27527f193d69SLuke Drummond     if (val.getAsInteger(10, n_lines)) {
27537f193d69SLuke Drummond       if (log)
27547f193d69SLuke Drummond         log->Debug("Failed to parse non-numeric '.rs.info' section %s",
27557f193d69SLuke Drummond                    line->str().c_str());
27567f193d69SLuke Drummond       continue;
27577f193d69SLuke Drummond     }
27587f193d69SLuke Drummond     if (info_lines.end() - (line + 1) < (ptrdiff_t)n_lines)
27597f193d69SLuke Drummond       return false;
27607f193d69SLuke Drummond 
27617f193d69SLuke Drummond     bool success = false;
27627f193d69SLuke Drummond     switch (handler->getValue()) {
27637f193d69SLuke Drummond     case eExportVar:
27647f193d69SLuke Drummond       success = ParseExportVarCount(line, n_lines);
27657f193d69SLuke Drummond       break;
27667f193d69SLuke Drummond     case eExportForEach:
27677f193d69SLuke Drummond       success = ParseExportForeachCount(line, n_lines);
27687f193d69SLuke Drummond       break;
27697f193d69SLuke Drummond     case eExportReduce:
27707f193d69SLuke Drummond       success = ParseExportReduceCount(line, n_lines);
27717f193d69SLuke Drummond       break;
27727f193d69SLuke Drummond     case ePragma:
27737f193d69SLuke Drummond       success = ParsePragmaCount(line, n_lines);
27747f193d69SLuke Drummond       break;
27757f193d69SLuke Drummond     default: {
27767f193d69SLuke Drummond       if (log)
27777f193d69SLuke Drummond         log->Printf("%s - skipping .rs.info field '%s'", __FUNCTION__,
27787f193d69SLuke Drummond                     line->str().c_str());
27797f193d69SLuke Drummond       continue;
27807f193d69SLuke Drummond     }
27817f193d69SLuke Drummond     }
27827f193d69SLuke Drummond     if (!success)
27837f193d69SLuke Drummond       return false;
27847f193d69SLuke Drummond     line += n_lines;
27857f193d69SLuke Drummond   }
27867f193d69SLuke Drummond   return info_lines.size() > 0;
27875ec532a9SColin Riley }
27885ec532a9SColin Riley 
2789b9c1b51eSKate Stone void RenderScriptRuntime::Status(Stream &strm) const {
2790b9c1b51eSKate Stone   if (m_libRS) {
27914640cde1SColin Riley     strm.Printf("Runtime Library discovered.");
27924640cde1SColin Riley     strm.EOL();
27934640cde1SColin Riley   }
2794b9c1b51eSKate Stone   if (m_libRSDriver) {
27954640cde1SColin Riley     strm.Printf("Runtime Driver discovered.");
27964640cde1SColin Riley     strm.EOL();
27974640cde1SColin Riley   }
2798b9c1b51eSKate Stone   if (m_libRSCpuRef) {
27994640cde1SColin Riley     strm.Printf("CPU Reference Implementation discovered.");
28004640cde1SColin Riley     strm.EOL();
28014640cde1SColin Riley   }
28024640cde1SColin Riley 
2803b9c1b51eSKate Stone   if (m_runtimeHooks.size()) {
28044640cde1SColin Riley     strm.Printf("Runtime functions hooked:");
28054640cde1SColin Riley     strm.EOL();
2806b9c1b51eSKate Stone     for (auto b : m_runtimeHooks) {
28074640cde1SColin Riley       strm.Indent(b.second->defn->name);
28084640cde1SColin Riley       strm.EOL();
28094640cde1SColin Riley     }
2810b9c1b51eSKate Stone   } else {
28114640cde1SColin Riley     strm.Printf("Runtime is not hooked.");
28124640cde1SColin Riley     strm.EOL();
28134640cde1SColin Riley   }
28144640cde1SColin Riley }
28154640cde1SColin Riley 
2816b9c1b51eSKate Stone void RenderScriptRuntime::DumpContexts(Stream &strm) const {
28174640cde1SColin Riley   strm.Printf("Inferred RenderScript Contexts:");
28184640cde1SColin Riley   strm.EOL();
28194640cde1SColin Riley   strm.IndentMore();
28204640cde1SColin Riley 
28214640cde1SColin Riley   std::map<addr_t, uint64_t> contextReferences;
28224640cde1SColin Riley 
282378f339d1SEwan Crawford   // Iterate over all of the currently discovered scripts.
2824b9c1b51eSKate Stone   // Note: We cant push or pop from m_scripts inside this loop or it may
2825b9c1b51eSKate Stone   // invalidate script.
2826b9c1b51eSKate Stone   for (const auto &script : m_scripts) {
282778f339d1SEwan Crawford     if (!script->context.isValid())
282878f339d1SEwan Crawford       continue;
282978f339d1SEwan Crawford     lldb::addr_t context = *script->context;
283078f339d1SEwan Crawford 
2831b9c1b51eSKate Stone     if (contextReferences.find(context) != contextReferences.end()) {
283278f339d1SEwan Crawford       contextReferences[context]++;
2833b9c1b51eSKate Stone     } else {
283478f339d1SEwan Crawford       contextReferences[context] = 1;
28354640cde1SColin Riley     }
28364640cde1SColin Riley   }
28374640cde1SColin Riley 
2838b9c1b51eSKate Stone   for (const auto &cRef : contextReferences) {
2839b9c1b51eSKate Stone     strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances",
2840b9c1b51eSKate Stone                 cRef.first, cRef.second);
28414640cde1SColin Riley     strm.EOL();
28424640cde1SColin Riley   }
28434640cde1SColin Riley   strm.IndentLess();
28444640cde1SColin Riley }
28454640cde1SColin Riley 
2846b9c1b51eSKate Stone void RenderScriptRuntime::DumpKernels(Stream &strm) const {
28474640cde1SColin Riley   strm.Printf("RenderScript Kernels:");
28484640cde1SColin Riley   strm.EOL();
28494640cde1SColin Riley   strm.IndentMore();
2850b9c1b51eSKate Stone   for (const auto &module : m_rsmodules) {
28514640cde1SColin Riley     strm.Printf("Resource '%s':", module->m_resname.c_str());
28524640cde1SColin Riley     strm.EOL();
2853b9c1b51eSKate Stone     for (const auto &kernel : module->m_kernels) {
28544640cde1SColin Riley       strm.Indent(kernel.m_name.AsCString());
28554640cde1SColin Riley       strm.EOL();
28564640cde1SColin Riley     }
28574640cde1SColin Riley   }
28584640cde1SColin Riley   strm.IndentLess();
28594640cde1SColin Riley }
28604640cde1SColin Riley 
2861a0f08674SEwan Crawford RenderScriptRuntime::AllocationDetails *
2862b9c1b51eSKate Stone RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) {
2863a0f08674SEwan Crawford   AllocationDetails *alloc = nullptr;
2864a0f08674SEwan Crawford 
2865a0f08674SEwan Crawford   // See if we can find allocation using id as an index;
2866b9c1b51eSKate Stone   if (alloc_id <= m_allocations.size() && alloc_id != 0 &&
2867b9c1b51eSKate Stone       m_allocations[alloc_id - 1]->id == alloc_id) {
2868a0f08674SEwan Crawford     alloc = m_allocations[alloc_id - 1].get();
2869a0f08674SEwan Crawford     return alloc;
2870a0f08674SEwan Crawford   }
2871a0f08674SEwan Crawford 
2872a0f08674SEwan Crawford   // Fallback to searching
2873b9c1b51eSKate Stone   for (const auto &a : m_allocations) {
2874b9c1b51eSKate Stone     if (a->id == alloc_id) {
2875a0f08674SEwan Crawford       alloc = a.get();
2876a0f08674SEwan Crawford       break;
2877a0f08674SEwan Crawford     }
2878a0f08674SEwan Crawford   }
2879a0f08674SEwan Crawford 
2880b9c1b51eSKate Stone   if (alloc == nullptr) {
2881b9c1b51eSKate Stone     strm.Printf("Error: Couldn't find allocation with id matching %" PRIu32,
2882b9c1b51eSKate Stone                 alloc_id);
2883a0f08674SEwan Crawford     strm.EOL();
2884a0f08674SEwan Crawford   }
2885a0f08674SEwan Crawford 
2886a0f08674SEwan Crawford   return alloc;
2887a0f08674SEwan Crawford }
2888a0f08674SEwan Crawford 
2889b9c1b51eSKate Stone // Prints the contents of an allocation to the output stream, which may be a
2890b9c1b51eSKate Stone // file
2891b9c1b51eSKate Stone bool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr,
2892b9c1b51eSKate Stone                                          const uint32_t id) {
2893a0f08674SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2894a0f08674SEwan Crawford 
2895a0f08674SEwan Crawford   // Check we can find the desired allocation
2896a0f08674SEwan Crawford   AllocationDetails *alloc = FindAllocByID(strm, id);
2897a0f08674SEwan Crawford   if (!alloc)
2898a0f08674SEwan Crawford     return false; // FindAllocByID() will print error message for us here
2899a0f08674SEwan Crawford 
2900a0f08674SEwan Crawford   if (log)
2901b9c1b51eSKate Stone     log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__,
2902b9c1b51eSKate Stone                 *alloc->address.get());
2903a0f08674SEwan Crawford 
2904a0f08674SEwan Crawford   // Check we have information about the allocation, if not calculate it
2905b9c1b51eSKate Stone   if (alloc->shouldRefresh()) {
2906a0f08674SEwan Crawford     if (log)
2907b9c1b51eSKate Stone       log->Printf("%s - allocation details not calculated yet, jitting info.",
2908b9c1b51eSKate Stone                   __FUNCTION__);
2909a0f08674SEwan Crawford 
2910a0f08674SEwan Crawford     // JIT all the allocation information
2911b9c1b51eSKate Stone     if (!RefreshAllocation(alloc, frame_ptr)) {
2912a0f08674SEwan Crawford       strm.Printf("Error: Couldn't JIT allocation details");
2913a0f08674SEwan Crawford       strm.EOL();
2914a0f08674SEwan Crawford       return false;
2915a0f08674SEwan Crawford     }
2916a0f08674SEwan Crawford   }
2917a0f08674SEwan Crawford 
2918a0f08674SEwan Crawford   // Establish format and size of each data element
2919b3f7f69dSAidan Dodds   const uint32_t vec_size = *alloc->element.type_vec_size.get();
29208b244e21SEwan Crawford   const Element::DataType type = *alloc->element.type.get();
2921a0f08674SEwan Crawford 
2922b9c1b51eSKate Stone   assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT &&
2923b9c1b51eSKate Stone          "Invalid allocation type");
2924a0f08674SEwan Crawford 
29252e920715SEwan Crawford   lldb::Format format;
29262e920715SEwan Crawford   if (type >= Element::RS_TYPE_ELEMENT)
29272e920715SEwan Crawford     format = eFormatHex;
29282e920715SEwan Crawford   else
2929b9c1b51eSKate Stone     format = vec_size == 1
2930b9c1b51eSKate Stone                  ? static_cast<lldb::Format>(
2931b9c1b51eSKate Stone                        AllocationDetails::RSTypeToFormat[type][eFormatSingle])
2932b9c1b51eSKate Stone                  : static_cast<lldb::Format>(
2933b9c1b51eSKate Stone                        AllocationDetails::RSTypeToFormat[type][eFormatVector]);
2934a0f08674SEwan Crawford 
2935b3f7f69dSAidan Dodds   const uint32_t data_size = *alloc->element.datum_size.get();
2936a0f08674SEwan Crawford 
2937a0f08674SEwan Crawford   if (log)
2938b9c1b51eSKate Stone     log->Printf("%s - element size %" PRIu32 " bytes, including padding",
2939b9c1b51eSKate Stone                 __FUNCTION__, data_size);
2940a0f08674SEwan Crawford 
294155232f09SEwan Crawford   // Allocate a buffer to copy data into
294255232f09SEwan Crawford   std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
2943b9c1b51eSKate Stone   if (!buffer) {
29442e920715SEwan Crawford     strm.Printf("Error: Couldn't read allocation data");
294555232f09SEwan Crawford     strm.EOL();
294655232f09SEwan Crawford     return false;
294755232f09SEwan Crawford   }
294855232f09SEwan Crawford 
2949a0f08674SEwan Crawford   // Calculate stride between rows as there may be padding at end of rows since
2950a0f08674SEwan Crawford   // allocated memory is 16-byte aligned
2951b9c1b51eSKate Stone   if (!alloc->stride.isValid()) {
2952a0f08674SEwan Crawford     if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension
2953a0f08674SEwan Crawford       alloc->stride = 0;
2954b9c1b51eSKate Stone     else if (!JITAllocationStride(alloc, frame_ptr)) {
2955a0f08674SEwan Crawford       strm.Printf("Error: Couldn't calculate allocation row stride");
2956a0f08674SEwan Crawford       strm.EOL();
2957a0f08674SEwan Crawford       return false;
2958a0f08674SEwan Crawford     }
2959a0f08674SEwan Crawford   }
2960b3f7f69dSAidan Dodds   const uint32_t stride = *alloc->stride.get();
2961b3f7f69dSAidan Dodds   const uint32_t size = *alloc->size.get(); // Size of whole allocation
2962b9c1b51eSKate Stone   const uint32_t padding =
2963b9c1b51eSKate Stone       alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0;
2964a0f08674SEwan Crawford   if (log)
2965b9c1b51eSKate Stone     log->Printf("%s - stride %" PRIu32 " bytes, size %" PRIu32
2966b9c1b51eSKate Stone                 " bytes, padding %" PRIu32,
2967b3f7f69dSAidan Dodds                 __FUNCTION__, stride, size, padding);
2968a0f08674SEwan Crawford 
2969a0f08674SEwan Crawford   // Find dimensions used to index loops, so need to be non-zero
2970b3f7f69dSAidan Dodds   uint32_t dim_x = alloc->dimension.get()->dim_1;
2971a0f08674SEwan Crawford   dim_x = dim_x == 0 ? 1 : dim_x;
2972a0f08674SEwan Crawford 
2973b3f7f69dSAidan Dodds   uint32_t dim_y = alloc->dimension.get()->dim_2;
2974a0f08674SEwan Crawford   dim_y = dim_y == 0 ? 1 : dim_y;
2975a0f08674SEwan Crawford 
2976b3f7f69dSAidan Dodds   uint32_t dim_z = alloc->dimension.get()->dim_3;
2977a0f08674SEwan Crawford   dim_z = dim_z == 0 ? 1 : dim_z;
2978a0f08674SEwan Crawford 
297955232f09SEwan Crawford   // Use data extractor to format output
2980b9c1b51eSKate Stone   const uint32_t archByteSize =
2981b9c1b51eSKate Stone       GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
2982b9c1b51eSKate Stone   DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(),
2983b9c1b51eSKate Stone                            archByteSize);
298455232f09SEwan Crawford 
2985b3f7f69dSAidan Dodds   uint32_t offset = 0;   // Offset in buffer to next element to be printed
2986b3f7f69dSAidan Dodds   uint32_t prev_row = 0; // Offset to the start of the previous row
2987a0f08674SEwan Crawford 
2988a0f08674SEwan Crawford   // Iterate over allocation dimensions, printing results to user
2989a0f08674SEwan Crawford   strm.Printf("Data (X, Y, Z):");
2990b9c1b51eSKate Stone   for (uint32_t z = 0; z < dim_z; ++z) {
2991b9c1b51eSKate Stone     for (uint32_t y = 0; y < dim_y; ++y) {
2992a0f08674SEwan Crawford       // Use stride to index start of next row.
2993a0f08674SEwan Crawford       if (!(y == 0 && z == 0))
2994a0f08674SEwan Crawford         offset = prev_row + stride;
2995a0f08674SEwan Crawford       prev_row = offset;
2996a0f08674SEwan Crawford 
2997a0f08674SEwan Crawford       // Print each element in the row individually
2998b9c1b51eSKate Stone       for (uint32_t x = 0; x < dim_x; ++x) {
2999b3f7f69dSAidan Dodds         strm.Printf("\n(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") = ", x, y, z);
3000b9c1b51eSKate Stone         if ((type == Element::RS_TYPE_NONE) &&
3001b9c1b51eSKate Stone             (alloc->element.children.size() > 0) &&
3002b9c1b51eSKate Stone             (alloc->element.type_name != Element::GetFallbackStructName())) {
30038b244e21SEwan Crawford           // Here we are dumping an Element of struct type.
3004b9c1b51eSKate Stone           // This is done using expression evaluation with the name of the
3005b9c1b51eSKate Stone           // struct type and pointer to element.
30068b244e21SEwan Crawford 
3007b9c1b51eSKate Stone           // Don't print the name of the resulting expression, since this will
3008b9c1b51eSKate Stone           // be '$[0-9]+'
30098b244e21SEwan Crawford           DumpValueObjectOptions expr_options;
30108b244e21SEwan Crawford           expr_options.SetHideName(true);
30118b244e21SEwan Crawford 
30128b244e21SEwan Crawford           // Setup expression as derefrencing a pointer cast to element address.
3013ea0636b5SEwan Crawford           char expr_char_buffer[jit_max_expr_size];
3014b9c1b51eSKate Stone           int chars_written =
3015b9c1b51eSKate Stone               snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64,
3016b9c1b51eSKate Stone                        alloc->element.type_name.AsCString(),
3017b9c1b51eSKate Stone                        *alloc->data_ptr.get() + offset);
30188b244e21SEwan Crawford 
3019b9c1b51eSKate Stone           if (chars_written < 0 || chars_written >= jit_max_expr_size) {
30208b244e21SEwan Crawford             if (log)
3021b3f7f69dSAidan Dodds               log->Printf("%s - error in snprintf().", __FUNCTION__);
30228b244e21SEwan Crawford             continue;
30238b244e21SEwan Crawford           }
30248b244e21SEwan Crawford 
30258b244e21SEwan Crawford           // Evaluate expression
30268b244e21SEwan Crawford           ValueObjectSP expr_result;
3027b9c1b51eSKate Stone           GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer,
3028b9c1b51eSKate Stone                                                        frame_ptr, expr_result);
30298b244e21SEwan Crawford 
30308b244e21SEwan Crawford           // Print the results to our stream.
30318b244e21SEwan Crawford           expr_result->Dump(strm, expr_options);
3032b9c1b51eSKate Stone         } else {
3033b9c1b51eSKate Stone           alloc_data.Dump(&strm, offset, format, data_size - padding, 1, 1,
3034b9c1b51eSKate Stone                           LLDB_INVALID_ADDRESS, 0, 0);
30358b244e21SEwan Crawford         }
30368b244e21SEwan Crawford         offset += data_size;
3037a0f08674SEwan Crawford       }
3038a0f08674SEwan Crawford     }
3039a0f08674SEwan Crawford   }
3040a0f08674SEwan Crawford   strm.EOL();
3041a0f08674SEwan Crawford 
3042a0f08674SEwan Crawford   return true;
3043a0f08674SEwan Crawford }
3044a0f08674SEwan Crawford 
3045b9c1b51eSKate Stone // Function recalculates all our cached information about allocations by jitting
3046b9c1b51eSKate Stone // the
30470d2bfcfbSEwan Crawford // RS runtime regarding each allocation we know about.
30480d2bfcfbSEwan Crawford // Returns true if all allocations could be recomputed, false otherwise.
3049b9c1b51eSKate Stone bool RenderScriptRuntime::RecomputeAllAllocations(Stream &strm,
3050b9c1b51eSKate Stone                                                   StackFrame *frame_ptr) {
30510d2bfcfbSEwan Crawford   bool success = true;
3052b9c1b51eSKate Stone   for (auto &alloc : m_allocations) {
30530d2bfcfbSEwan Crawford     // JIT current allocation information
3054b9c1b51eSKate Stone     if (!RefreshAllocation(alloc.get(), frame_ptr)) {
3055b9c1b51eSKate Stone       strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32
3056b9c1b51eSKate Stone                   "\n",
3057b9c1b51eSKate Stone                   alloc->id);
30580d2bfcfbSEwan Crawford       success = false;
30590d2bfcfbSEwan Crawford     }
30600d2bfcfbSEwan Crawford   }
30610d2bfcfbSEwan Crawford 
30620d2bfcfbSEwan Crawford   if (success)
30630d2bfcfbSEwan Crawford     strm.Printf("All allocations successfully recomputed");
30640d2bfcfbSEwan Crawford   strm.EOL();
30650d2bfcfbSEwan Crawford 
30660d2bfcfbSEwan Crawford   return success;
30670d2bfcfbSEwan Crawford }
30680d2bfcfbSEwan Crawford 
3069b649b005SEwan Crawford // Prints information regarding currently loaded allocations.
307015f2bd95SEwan Crawford // These details are gathered by jitting the runtime, which has as latency.
3071b9c1b51eSKate Stone // Index parameter specifies a single allocation ID to print, or a zero value to
3072b9c1b51eSKate Stone // print them all
3073b9c1b51eSKate Stone void RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame *frame_ptr,
3074b9c1b51eSKate Stone                                           const uint32_t index) {
307515f2bd95SEwan Crawford   strm.Printf("RenderScript Allocations:");
307615f2bd95SEwan Crawford   strm.EOL();
307715f2bd95SEwan Crawford   strm.IndentMore();
307815f2bd95SEwan Crawford 
3079b9c1b51eSKate Stone   for (auto &alloc : m_allocations) {
3080b649b005SEwan Crawford     // index will only be zero if we want to print all allocations
3081b649b005SEwan Crawford     if (index != 0 && index != alloc->id)
3082b649b005SEwan Crawford       continue;
308315f2bd95SEwan Crawford 
308415f2bd95SEwan Crawford     // JIT current allocation information
3085b9c1b51eSKate Stone     if (alloc->shouldRefresh() && !RefreshAllocation(alloc.get(), frame_ptr)) {
3086b9c1b51eSKate Stone       strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32,
3087b9c1b51eSKate Stone                   alloc->id);
3088b3f7f69dSAidan Dodds       strm.EOL();
308915f2bd95SEwan Crawford       continue;
309015f2bd95SEwan Crawford     }
309115f2bd95SEwan Crawford 
3092b3f7f69dSAidan Dodds     strm.Printf("%" PRIu32 ":", alloc->id);
3093b3f7f69dSAidan Dodds     strm.EOL();
309415f2bd95SEwan Crawford     strm.IndentMore();
309515f2bd95SEwan Crawford 
309615f2bd95SEwan Crawford     strm.Indent("Context: ");
309715f2bd95SEwan Crawford     if (!alloc->context.isValid())
309815f2bd95SEwan Crawford       strm.Printf("unknown\n");
309915f2bd95SEwan Crawford     else
310015f2bd95SEwan Crawford       strm.Printf("0x%" PRIx64 "\n", *alloc->context.get());
310115f2bd95SEwan Crawford 
310215f2bd95SEwan Crawford     strm.Indent("Address: ");
310315f2bd95SEwan Crawford     if (!alloc->address.isValid())
310415f2bd95SEwan Crawford       strm.Printf("unknown\n");
310515f2bd95SEwan Crawford     else
310615f2bd95SEwan Crawford       strm.Printf("0x%" PRIx64 "\n", *alloc->address.get());
310715f2bd95SEwan Crawford 
310815f2bd95SEwan Crawford     strm.Indent("Data pointer: ");
310915f2bd95SEwan Crawford     if (!alloc->data_ptr.isValid())
311015f2bd95SEwan Crawford       strm.Printf("unknown\n");
311115f2bd95SEwan Crawford     else
311215f2bd95SEwan Crawford       strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get());
311315f2bd95SEwan Crawford 
311415f2bd95SEwan Crawford     strm.Indent("Dimensions: ");
311515f2bd95SEwan Crawford     if (!alloc->dimension.isValid())
311615f2bd95SEwan Crawford       strm.Printf("unknown\n");
311715f2bd95SEwan Crawford     else
3118b3f7f69dSAidan Dodds       strm.Printf("(%" PRId32 ", %" PRId32 ", %" PRId32 ")\n",
3119b9c1b51eSKate Stone                   alloc->dimension.get()->dim_1, alloc->dimension.get()->dim_2,
3120b9c1b51eSKate Stone                   alloc->dimension.get()->dim_3);
312115f2bd95SEwan Crawford 
312215f2bd95SEwan Crawford     strm.Indent("Data Type: ");
3123b9c1b51eSKate Stone     if (!alloc->element.type.isValid() ||
3124b9c1b51eSKate Stone         !alloc->element.type_vec_size.isValid())
312515f2bd95SEwan Crawford       strm.Printf("unknown\n");
3126b9c1b51eSKate Stone     else {
31278b244e21SEwan Crawford       const int vector_size = *alloc->element.type_vec_size.get();
31282e920715SEwan Crawford       Element::DataType type = *alloc->element.type.get();
312915f2bd95SEwan Crawford 
31308b244e21SEwan Crawford       if (!alloc->element.type_name.IsEmpty())
31318b244e21SEwan Crawford         strm.Printf("%s\n", alloc->element.type_name.AsCString());
3132b9c1b51eSKate Stone       else {
3133b9c1b51eSKate Stone         // Enum value isn't monotonous, so doesn't always index
3134b9c1b51eSKate Stone         // RsDataTypeToString array
31352e920715SEwan Crawford         if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT)
3136b9c1b51eSKate Stone           type =
3137b9c1b51eSKate Stone               static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) +
3138b3f7f69dSAidan Dodds                                              Element::RS_TYPE_MATRIX_2X2 + 1);
31392e920715SEwan Crawford 
3140b3f7f69dSAidan Dodds         if (type >= (sizeof(AllocationDetails::RsDataTypeToString) /
3141b3f7f69dSAidan Dodds                      sizeof(AllocationDetails::RsDataTypeToString[0])) ||
3142b3f7f69dSAidan Dodds             vector_size > 4 || vector_size < 1)
314315f2bd95SEwan Crawford           strm.Printf("invalid type\n");
314415f2bd95SEwan Crawford         else
3145b9c1b51eSKate Stone           strm.Printf(
3146b9c1b51eSKate Stone               "%s\n",
3147b9c1b51eSKate Stone               AllocationDetails::RsDataTypeToString[static_cast<uint32_t>(type)]
3148b3f7f69dSAidan Dodds                                                    [vector_size - 1]);
314915f2bd95SEwan Crawford       }
31502e920715SEwan Crawford     }
315115f2bd95SEwan Crawford 
315215f2bd95SEwan Crawford     strm.Indent("Data Kind: ");
31538b244e21SEwan Crawford     if (!alloc->element.type_kind.isValid())
315415f2bd95SEwan Crawford       strm.Printf("unknown\n");
3155b9c1b51eSKate Stone     else {
31568b244e21SEwan Crawford       const Element::DataKind kind = *alloc->element.type_kind.get();
31578b244e21SEwan Crawford       if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV)
315815f2bd95SEwan Crawford         strm.Printf("invalid kind\n");
315915f2bd95SEwan Crawford       else
3160b9c1b51eSKate Stone         strm.Printf(
3161b9c1b51eSKate Stone             "%s\n",
3162b9c1b51eSKate Stone             AllocationDetails::RsDataKindToString[static_cast<uint32_t>(kind)]);
316315f2bd95SEwan Crawford     }
316415f2bd95SEwan Crawford 
316515f2bd95SEwan Crawford     strm.EOL();
316615f2bd95SEwan Crawford     strm.IndentLess();
316715f2bd95SEwan Crawford   }
316815f2bd95SEwan Crawford   strm.IndentLess();
316915f2bd95SEwan Crawford }
317015f2bd95SEwan Crawford 
31717dc7771cSEwan Crawford // Set breakpoints on every kernel found in RS module
3172b9c1b51eSKate Stone void RenderScriptRuntime::BreakOnModuleKernels(
3173b9c1b51eSKate Stone     const RSModuleDescriptorSP rsmodule_sp) {
3174b9c1b51eSKate Stone   for (const auto &kernel : rsmodule_sp->m_kernels) {
31757dc7771cSEwan Crawford     // Don't set breakpoint on 'root' kernel
31767dc7771cSEwan Crawford     if (strcmp(kernel.m_name.AsCString(), "root") == 0)
31777dc7771cSEwan Crawford       continue;
31787dc7771cSEwan Crawford 
31797dc7771cSEwan Crawford     CreateKernelBreakpoint(kernel.m_name);
31807dc7771cSEwan Crawford   }
31817dc7771cSEwan Crawford }
31827dc7771cSEwan Crawford 
31837dc7771cSEwan Crawford // Method is internally called by the 'kernel breakpoint all' command to
31847dc7771cSEwan Crawford // enable or disable breaking on all kernels.
31857dc7771cSEwan Crawford //
31867dc7771cSEwan Crawford // When do_break is true we want to enable this functionality.
31877dc7771cSEwan Crawford // When do_break is false we want to disable it.
3188b9c1b51eSKate Stone void RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) {
3189b9c1b51eSKate Stone   Log *log(
3190b9c1b51eSKate Stone       GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
31917dc7771cSEwan Crawford 
31927dc7771cSEwan Crawford   InitSearchFilter(target);
31937dc7771cSEwan Crawford 
31947dc7771cSEwan Crawford   // Set breakpoints on all the kernels
3195b9c1b51eSKate Stone   if (do_break && !m_breakAllKernels) {
31967dc7771cSEwan Crawford     m_breakAllKernels = true;
31977dc7771cSEwan Crawford 
31987dc7771cSEwan Crawford     for (const auto &module : m_rsmodules)
31997dc7771cSEwan Crawford       BreakOnModuleKernels(module);
32007dc7771cSEwan Crawford 
32017dc7771cSEwan Crawford     if (log)
3202b9c1b51eSKate Stone       log->Printf("%s(True) - breakpoints set on all currently loaded kernels.",
3203b9c1b51eSKate Stone                   __FUNCTION__);
3204b9c1b51eSKate Stone   } else if (!do_break &&
3205b9c1b51eSKate Stone              m_breakAllKernels) // Breakpoints won't be set on any new kernels.
32067dc7771cSEwan Crawford   {
32077dc7771cSEwan Crawford     m_breakAllKernels = false;
32087dc7771cSEwan Crawford 
32097dc7771cSEwan Crawford     if (log)
3210b9c1b51eSKate Stone       log->Printf("%s(False) - breakpoints no longer automatically set.",
3211b9c1b51eSKate Stone                   __FUNCTION__);
32127dc7771cSEwan Crawford   }
32137dc7771cSEwan Crawford }
32147dc7771cSEwan Crawford 
32157dc7771cSEwan Crawford // Given the name of a kernel this function creates a breakpoint using our
32167dc7771cSEwan Crawford // own breakpoint resolver, and returns the Breakpoint shared pointer.
32177dc7771cSEwan Crawford BreakpointSP
3218b9c1b51eSKate Stone RenderScriptRuntime::CreateKernelBreakpoint(const ConstString &name) {
3219b9c1b51eSKate Stone   Log *log(
3220b9c1b51eSKate Stone       GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
32217dc7771cSEwan Crawford 
3222b9c1b51eSKate Stone   if (!m_filtersp) {
32237dc7771cSEwan Crawford     if (log)
3224b3f7f69dSAidan Dodds       log->Printf("%s - error, no breakpoint search filter set.", __FUNCTION__);
32257dc7771cSEwan Crawford     return nullptr;
32267dc7771cSEwan Crawford   }
32277dc7771cSEwan Crawford 
32287dc7771cSEwan Crawford   BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name));
3229b9c1b51eSKate Stone   BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint(
3230b9c1b51eSKate Stone       m_filtersp, resolver_sp, false, false, false);
32317dc7771cSEwan Crawford 
3232b9c1b51eSKate Stone   // Give RS breakpoints a specific name, so the user can manipulate them as a
3233b9c1b51eSKate Stone   // group.
323454782db7SEwan Crawford   Error err;
323554782db7SEwan Crawford   if (!bp->AddName("RenderScriptKernel", err) && log)
3236b9c1b51eSKate Stone     log->Printf("%s - error setting break name, '%s'.", __FUNCTION__,
3237b9c1b51eSKate Stone                 err.AsCString());
323854782db7SEwan Crawford 
32397dc7771cSEwan Crawford   return bp;
32407dc7771cSEwan Crawford }
32417dc7771cSEwan Crawford 
3242b9c1b51eSKate Stone // Given an expression for a variable this function tries to calculate the
3243b9c1b51eSKate Stone // variable's value.
3244b9c1b51eSKate Stone // If this is possible it returns true and sets the uint64_t parameter to the
3245b9c1b51eSKate Stone // variables unsigned value.
3246018f5a7eSEwan Crawford // Otherwise function returns false.
3247b9c1b51eSKate Stone bool RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp,
3248b9c1b51eSKate Stone                                                 const char *var_name,
3249b9c1b51eSKate Stone                                                 uint64_t &val) {
3250018f5a7eSEwan Crawford   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE));
3251018f5a7eSEwan Crawford   Error error;
3252018f5a7eSEwan Crawford   VariableSP var_sp;
3253018f5a7eSEwan Crawford 
3254018f5a7eSEwan Crawford   // Find variable in stack frame
3255b3f7f69dSAidan Dodds   ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath(
3256b3f7f69dSAidan Dodds       var_name, eNoDynamicValues,
3257b9c1b51eSKate Stone       StackFrame::eExpressionPathOptionCheckPtrVsMember |
3258b9c1b51eSKate Stone           StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
3259b3f7f69dSAidan Dodds       var_sp, error));
3260b9c1b51eSKate Stone   if (!error.Success()) {
3261018f5a7eSEwan Crawford     if (log)
3262b9c1b51eSKate Stone       log->Printf("%s - error, couldn't find '%s' in frame", __FUNCTION__,
3263b9c1b51eSKate Stone                   var_name);
3264018f5a7eSEwan Crawford     return false;
3265018f5a7eSEwan Crawford   }
3266018f5a7eSEwan Crawford 
3267b3f7f69dSAidan Dodds   // Find the uint32_t value for the variable
3268018f5a7eSEwan Crawford   bool success = false;
3269018f5a7eSEwan Crawford   val = value_sp->GetValueAsUnsigned(0, &success);
3270b9c1b51eSKate Stone   if (!success) {
3271018f5a7eSEwan Crawford     if (log)
3272b9c1b51eSKate Stone       log->Printf("%s - error, couldn't parse '%s' as an uint32_t.",
3273b9c1b51eSKate Stone                   __FUNCTION__, var_name);
3274018f5a7eSEwan Crawford     return false;
3275018f5a7eSEwan Crawford   }
3276018f5a7eSEwan Crawford 
3277018f5a7eSEwan Crawford   return true;
3278018f5a7eSEwan Crawford }
3279018f5a7eSEwan Crawford 
3280b9c1b51eSKate Stone // Function attempts to find the current coordinate of a kernel invocation by
3281b9c1b51eSKate Stone // investigating the
3282b9c1b51eSKate Stone // values of frame variables in the .expand function. These coordinates are
3283b9c1b51eSKate Stone // returned via the coord
3284b9c1b51eSKate Stone // array reference parameter. Returns true if the coordinates could be found,
3285b9c1b51eSKate Stone // and false otherwise.
3286b9c1b51eSKate Stone bool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord,
3287b9c1b51eSKate Stone                                               Thread *thread_ptr) {
32881e05c3bcSGreg Clayton   static const std::string s_runtimeExpandSuffix(".expand");
3289b9c1b51eSKate Stone   static const std::array<const char *, 3> s_runtimeCoordVars{
3290b9c1b51eSKate Stone       {"rsIndex", "p->current.y", "p->current.z"}};
32911e05c3bcSGreg Clayton 
32924f8817c2SEwan Crawford   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE));
32934f8817c2SEwan Crawford 
3294b9c1b51eSKate Stone   if (!thread_ptr) {
32954f8817c2SEwan Crawford     if (log)
32964f8817c2SEwan Crawford       log->Printf("%s - Error, No thread pointer", __FUNCTION__);
32974f8817c2SEwan Crawford 
32984f8817c2SEwan Crawford     return false;
32994f8817c2SEwan Crawford   }
33004f8817c2SEwan Crawford 
3301b9c1b51eSKate Stone   // Walk the call stack looking for a function whose name has the suffix
3302b9c1b51eSKate Stone   // '.expand'
33034f8817c2SEwan Crawford   // and contains the variables we're looking for.
3304b9c1b51eSKate Stone   for (uint32_t i = 0; i < thread_ptr->GetStackFrameCount(); ++i) {
33054f8817c2SEwan Crawford     if (!thread_ptr->SetSelectedFrameByIndex(i))
33064f8817c2SEwan Crawford       continue;
33074f8817c2SEwan Crawford 
33084f8817c2SEwan Crawford     StackFrameSP frame_sp = thread_ptr->GetSelectedFrame();
33094f8817c2SEwan Crawford     if (!frame_sp)
33104f8817c2SEwan Crawford       continue;
33114f8817c2SEwan Crawford 
33124f8817c2SEwan Crawford     // Find the function name
33134f8817c2SEwan Crawford     const SymbolContext sym_ctx = frame_sp->GetSymbolContext(false);
33144f8817c2SEwan Crawford     const char *func_name_cstr = sym_ctx.GetFunctionName().AsCString();
33154f8817c2SEwan Crawford     if (!func_name_cstr)
33164f8817c2SEwan Crawford       continue;
33174f8817c2SEwan Crawford 
33184f8817c2SEwan Crawford     if (log)
3319b9c1b51eSKate Stone       log->Printf("%s - Inspecting function '%s'", __FUNCTION__,
3320b9c1b51eSKate Stone                   func_name_cstr);
33214f8817c2SEwan Crawford 
33224f8817c2SEwan Crawford     // Check if function name has .expand suffix
33234f8817c2SEwan Crawford     std::string func_name(func_name_cstr);
3324b9c1b51eSKate Stone     const int length_difference =
3325b9c1b51eSKate Stone         func_name.length() - s_runtimeExpandSuffix.length();
33264f8817c2SEwan Crawford     if (length_difference <= 0)
33274f8817c2SEwan Crawford       continue;
33284f8817c2SEwan Crawford 
3329b9c1b51eSKate Stone     const int32_t has_expand_suffix =
3330b9c1b51eSKate Stone         func_name.compare(length_difference, s_runtimeExpandSuffix.length(),
33311e05c3bcSGreg Clayton                           s_runtimeExpandSuffix);
33324f8817c2SEwan Crawford 
33334f8817c2SEwan Crawford     if (has_expand_suffix != 0)
33344f8817c2SEwan Crawford       continue;
33354f8817c2SEwan Crawford 
33364f8817c2SEwan Crawford     if (log)
3337b9c1b51eSKate Stone       log->Printf("%s - Found .expand function '%s'", __FUNCTION__,
3338b9c1b51eSKate Stone                   func_name_cstr);
33394f8817c2SEwan Crawford 
3340b9c1b51eSKate Stone     // Get values for variables in .expand frame that tell us the current kernel
3341b9c1b51eSKate Stone     // invocation
33424f8817c2SEwan Crawford     bool found_coord_variables = true;
33431e05c3bcSGreg Clayton     assert(s_runtimeCoordVars.size() == coord.size());
33444f8817c2SEwan Crawford 
3345b9c1b51eSKate Stone     for (uint32_t i = 0; i < coord.size(); ++i) {
33464f8817c2SEwan Crawford       uint64_t value = 0;
3347b9c1b51eSKate Stone       if (!GetFrameVarAsUnsigned(frame_sp, s_runtimeCoordVars[i], value)) {
33484f8817c2SEwan Crawford         found_coord_variables = false;
33494f8817c2SEwan Crawford         break;
33504f8817c2SEwan Crawford       }
33514f8817c2SEwan Crawford       coord[i] = value;
33524f8817c2SEwan Crawford     }
33534f8817c2SEwan Crawford 
33544f8817c2SEwan Crawford     if (found_coord_variables)
33554f8817c2SEwan Crawford       return true;
33564f8817c2SEwan Crawford   }
33574f8817c2SEwan Crawford   return false;
33584f8817c2SEwan Crawford }
33594f8817c2SEwan Crawford 
3360b9c1b51eSKate Stone // Callback when a kernel breakpoint hits and we're looking for a specific
3361b9c1b51eSKate Stone // coordinate.
3362b9c1b51eSKate Stone // Baton parameter contains a pointer to the target coordinate we want to break
3363b9c1b51eSKate Stone // on.
3364b9c1b51eSKate Stone // Function then checks the .expand frame for the current coordinate and breaks
3365b9c1b51eSKate Stone // to user if it matches.
3366018f5a7eSEwan Crawford // Parameter 'break_id' is the id of the Breakpoint which made the callback.
3367018f5a7eSEwan Crawford // Parameter 'break_loc_id' is the id for the BreakpointLocation which was hit,
3368018f5a7eSEwan Crawford // a single logical breakpoint can have multiple addresses.
3369b9c1b51eSKate Stone bool RenderScriptRuntime::KernelBreakpointHit(void *baton,
3370b9c1b51eSKate Stone                                               StoppointCallbackContext *ctx,
3371b9c1b51eSKate Stone                                               user_id_t break_id,
3372b9c1b51eSKate Stone                                               user_id_t break_loc_id) {
3373b9c1b51eSKate Stone   Log *log(
3374b9c1b51eSKate Stone       GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
3375018f5a7eSEwan Crawford 
3376b9c1b51eSKate Stone   assert(baton &&
3377b9c1b51eSKate Stone          "Error: null baton in conditional kernel breakpoint callback");
3378018f5a7eSEwan Crawford 
3379018f5a7eSEwan Crawford   // Coordinate we want to stop on
33804f8817c2SEwan Crawford   const uint32_t *target_coord = static_cast<const uint32_t *>(baton);
3381018f5a7eSEwan Crawford 
3382018f5a7eSEwan Crawford   if (log)
3383b9c1b51eSKate Stone     log->Printf("%s - Break ID %" PRIu64 ", (%" PRIu32 ", %" PRIu32 ", %" PRIu32
3384b9c1b51eSKate Stone                 ")",
3385b9c1b51eSKate Stone                 __FUNCTION__, break_id, target_coord[0], target_coord[1],
3386b9c1b51eSKate Stone                 target_coord[2]);
3387018f5a7eSEwan Crawford 
33884f8817c2SEwan Crawford   // Select current thread
3389018f5a7eSEwan Crawford   ExecutionContext context(ctx->exe_ctx_ref);
33904f8817c2SEwan Crawford   Thread *thread_ptr = context.GetThreadPtr();
33914f8817c2SEwan Crawford   assert(thread_ptr && "Null thread pointer");
33924f8817c2SEwan Crawford 
33934f8817c2SEwan Crawford   // Find current kernel invocation from .expand frame variables
33944f8817c2SEwan Crawford   RSCoordinate current_coord{}; // Zero initialise array
3395b9c1b51eSKate Stone   if (!GetKernelCoordinate(current_coord, thread_ptr)) {
3396018f5a7eSEwan Crawford     if (log)
3397b9c1b51eSKate Stone       log->Printf("%s - Error, couldn't select .expand stack frame",
3398b9c1b51eSKate Stone                   __FUNCTION__);
3399018f5a7eSEwan Crawford     return false;
3400018f5a7eSEwan Crawford   }
3401018f5a7eSEwan Crawford 
3402018f5a7eSEwan Crawford   if (log)
3403b9c1b51eSKate Stone     log->Printf("%s - (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", __FUNCTION__,
3404b9c1b51eSKate Stone                 current_coord[0], current_coord[1], current_coord[2]);
3405018f5a7eSEwan Crawford 
3406b9c1b51eSKate Stone   // Check if the current kernel invocation coordinate matches our target
3407b9c1b51eSKate Stone   // coordinate
3408b3f7f69dSAidan Dodds   if (current_coord[0] == target_coord[0] &&
3409b3f7f69dSAidan Dodds       current_coord[1] == target_coord[1] &&
3410b9c1b51eSKate Stone       current_coord[2] == target_coord[2]) {
3411018f5a7eSEwan Crawford     if (log)
3412b9c1b51eSKate Stone       log->Printf("%s, BREAKING (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")",
3413b9c1b51eSKate Stone                   __FUNCTION__, current_coord[0], current_coord[1],
3414b9c1b51eSKate Stone                   current_coord[2]);
3415018f5a7eSEwan Crawford 
3416b9c1b51eSKate Stone     BreakpointSP breakpoint_sp =
3417b9c1b51eSKate Stone         context.GetTargetPtr()->GetBreakpointByID(break_id);
3418b9c1b51eSKate Stone     assert(breakpoint_sp != nullptr &&
3419b9c1b51eSKate Stone            "Error: Couldn't find breakpoint matching break id for callback");
3420b9c1b51eSKate Stone     breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint
3421b9c1b51eSKate Stone                                       // should only be hit once.
3422018f5a7eSEwan Crawford     return true;
3423018f5a7eSEwan Crawford   }
3424018f5a7eSEwan Crawford 
3425018f5a7eSEwan Crawford   // No match on coordinate
3426018f5a7eSEwan Crawford   return false;
3427018f5a7eSEwan Crawford }
3428018f5a7eSEwan Crawford 
3429b9c1b51eSKate Stone // Tries to set a breakpoint on the start of a kernel, resolved using the kernel
3430b9c1b51eSKate Stone // name.
3431b9c1b51eSKate Stone // Argument 'coords', represents a three dimensional coordinate which can be
3432b9c1b51eSKate Stone // used to specify
3433b9c1b51eSKate Stone // a single kernel instance to break on. If this is set then we add a callback
3434b9c1b51eSKate Stone // to the breakpoint.
3435b9c1b51eSKate Stone void RenderScriptRuntime::PlaceBreakpointOnKernel(
3436b9c1b51eSKate Stone     Stream &strm, const char *name, const std::array<int, 3> coords,
3437b9c1b51eSKate Stone     Error &error, TargetSP target) {
3438b9c1b51eSKate Stone   if (!name) {
34394640cde1SColin Riley     error.SetErrorString("invalid kernel name");
34404640cde1SColin Riley     return;
34414640cde1SColin Riley   }
34424640cde1SColin Riley 
34437dc7771cSEwan Crawford   InitSearchFilter(target);
344498156583SEwan Crawford 
34454640cde1SColin Riley   ConstString kernel_name(name);
34467dc7771cSEwan Crawford   BreakpointSP bp = CreateKernelBreakpoint(kernel_name);
3447018f5a7eSEwan Crawford 
3448018f5a7eSEwan Crawford   // We have a conditional breakpoint on a specific coordinate
3449b9c1b51eSKate Stone   if (coords[0] != -1) {
3450b9c1b51eSKate Stone     strm.Printf("Conditional kernel breakpoint on coordinate %" PRId32
3451b9c1b51eSKate Stone                 ", %" PRId32 ", %" PRId32,
3452b3f7f69dSAidan Dodds                 coords[0], coords[1], coords[2]);
3453018f5a7eSEwan Crawford     strm.EOL();
3454018f5a7eSEwan Crawford 
3455018f5a7eSEwan Crawford     // Allocate memory for the baton, and copy over coordinate
34564f8817c2SEwan Crawford     uint32_t *baton = new uint32_t[coords.size()];
3457b9c1b51eSKate Stone     baton[0] = coords[0];
3458b9c1b51eSKate Stone     baton[1] = coords[1];
3459b9c1b51eSKate Stone     baton[2] = coords[2];
3460018f5a7eSEwan Crawford 
3461018f5a7eSEwan Crawford     // Create a callback that will be invoked every time the breakpoint is hit.
3462b9c1b51eSKate Stone     // The baton object passed to the handler is the target coordinate we want
3463b9c1b51eSKate Stone     // to break on.
3464018f5a7eSEwan Crawford     bp->SetCallback(KernelBreakpointHit, baton, true);
3465018f5a7eSEwan Crawford 
3466b9c1b51eSKate Stone     // Store a shared pointer to the baton, so the memory will eventually be
3467b9c1b51eSKate Stone     // cleaned up after destruction
34684f8817c2SEwan Crawford     m_conditional_breaks[bp->GetID()] = std::shared_ptr<uint32_t>(baton);
3469018f5a7eSEwan Crawford   }
3470018f5a7eSEwan Crawford 
347198156583SEwan Crawford   if (bp)
347298156583SEwan Crawford     bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false);
34734640cde1SColin Riley }
34744640cde1SColin Riley 
3475b9c1b51eSKate Stone void RenderScriptRuntime::DumpModules(Stream &strm) const {
34765ec532a9SColin Riley   strm.Printf("RenderScript Modules:");
34775ec532a9SColin Riley   strm.EOL();
34785ec532a9SColin Riley   strm.IndentMore();
3479b9c1b51eSKate Stone   for (const auto &module : m_rsmodules) {
34804640cde1SColin Riley     module->Dump(strm);
34815ec532a9SColin Riley   }
34825ec532a9SColin Riley   strm.IndentLess();
34835ec532a9SColin Riley }
34845ec532a9SColin Riley 
348578f339d1SEwan Crawford RenderScriptRuntime::ScriptDetails *
3486b9c1b51eSKate Stone RenderScriptRuntime::LookUpScript(addr_t address, bool create) {
3487b9c1b51eSKate Stone   for (const auto &s : m_scripts) {
348878f339d1SEwan Crawford     if (s->script.isValid())
348978f339d1SEwan Crawford       if (*s->script == address)
349078f339d1SEwan Crawford         return s.get();
349178f339d1SEwan Crawford   }
3492b9c1b51eSKate Stone   if (create) {
349378f339d1SEwan Crawford     std::unique_ptr<ScriptDetails> s(new ScriptDetails);
349478f339d1SEwan Crawford     s->script = address;
349578f339d1SEwan Crawford     m_scripts.push_back(std::move(s));
3496d10ca9deSEwan Crawford     return m_scripts.back().get();
349778f339d1SEwan Crawford   }
349878f339d1SEwan Crawford   return nullptr;
349978f339d1SEwan Crawford }
350078f339d1SEwan Crawford 
350178f339d1SEwan Crawford RenderScriptRuntime::AllocationDetails *
3502b9c1b51eSKate Stone RenderScriptRuntime::LookUpAllocation(addr_t address) {
3503b9c1b51eSKate Stone   for (const auto &a : m_allocations) {
350478f339d1SEwan Crawford     if (a->address.isValid())
350578f339d1SEwan Crawford       if (*a->address == address)
350678f339d1SEwan Crawford         return a.get();
350778f339d1SEwan Crawford   }
35085d057637SLuke Drummond   return nullptr;
35095d057637SLuke Drummond }
35105d057637SLuke Drummond 
35115d057637SLuke Drummond RenderScriptRuntime::AllocationDetails *
3512b9c1b51eSKate Stone RenderScriptRuntime::CreateAllocation(addr_t address) {
35135d057637SLuke Drummond   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
35145d057637SLuke Drummond 
35155d057637SLuke Drummond   // Remove any previous allocation which contains the same address
35165d057637SLuke Drummond   auto it = m_allocations.begin();
3517b9c1b51eSKate Stone   while (it != m_allocations.end()) {
3518b9c1b51eSKate Stone     if (*((*it)->address) == address) {
35195d057637SLuke Drummond       if (log)
3520b9c1b51eSKate Stone         log->Printf("%s - Removing allocation id: %d, address: 0x%" PRIx64,
3521b9c1b51eSKate Stone                     __FUNCTION__, (*it)->id, address);
35225d057637SLuke Drummond 
35235d057637SLuke Drummond       it = m_allocations.erase(it);
3524b9c1b51eSKate Stone     } else {
35255d057637SLuke Drummond       it++;
35265d057637SLuke Drummond     }
35275d057637SLuke Drummond   }
35285d057637SLuke Drummond 
352978f339d1SEwan Crawford   std::unique_ptr<AllocationDetails> a(new AllocationDetails);
353078f339d1SEwan Crawford   a->address = address;
353178f339d1SEwan Crawford   m_allocations.push_back(std::move(a));
3532d10ca9deSEwan Crawford   return m_allocations.back().get();
353378f339d1SEwan Crawford }
353478f339d1SEwan Crawford 
3535b9c1b51eSKate Stone void RSModuleDescriptor::Dump(Stream &strm) const {
35367f193d69SLuke Drummond   int indent = strm.GetIndentLevel();
35377f193d69SLuke Drummond 
35385ec532a9SColin Riley   strm.Indent();
35395ec532a9SColin Riley   m_module->GetFileSpec().Dump(&strm);
35407f193d69SLuke Drummond   strm.Indent(m_module->GetNumCompileUnits() ? "Debug info loaded."
35417f193d69SLuke Drummond                                              : "Debug info does not exist.");
35425ec532a9SColin Riley   strm.EOL();
35435ec532a9SColin Riley   strm.IndentMore();
35447f193d69SLuke Drummond 
35455ec532a9SColin Riley   strm.Indent();
3546189598edSColin Riley   strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size()));
35475ec532a9SColin Riley   strm.EOL();
35485ec532a9SColin Riley   strm.IndentMore();
3549b9c1b51eSKate Stone   for (const auto &global : m_globals) {
35505ec532a9SColin Riley     global.Dump(strm);
35515ec532a9SColin Riley   }
35525ec532a9SColin Riley   strm.IndentLess();
35537f193d69SLuke Drummond 
35545ec532a9SColin Riley   strm.Indent();
3555189598edSColin Riley   strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size()));
35565ec532a9SColin Riley   strm.EOL();
35575ec532a9SColin Riley   strm.IndentMore();
3558b9c1b51eSKate Stone   for (const auto &kernel : m_kernels) {
35595ec532a9SColin Riley     kernel.Dump(strm);
35605ec532a9SColin Riley   }
35617f193d69SLuke Drummond   strm.IndentLess();
35627f193d69SLuke Drummond 
35637f193d69SLuke Drummond   strm.Indent();
35644640cde1SColin Riley   strm.Printf("Pragmas: %" PRIu64, static_cast<uint64_t>(m_pragmas.size()));
35654640cde1SColin Riley   strm.EOL();
35664640cde1SColin Riley   strm.IndentMore();
3567b9c1b51eSKate Stone   for (const auto &key_val : m_pragmas) {
35687f193d69SLuke Drummond     strm.Indent();
35694640cde1SColin Riley     strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str());
35704640cde1SColin Riley     strm.EOL();
35714640cde1SColin Riley   }
35727f193d69SLuke Drummond   strm.IndentLess();
35737f193d69SLuke Drummond 
35747f193d69SLuke Drummond   strm.Indent();
35757f193d69SLuke Drummond   strm.Printf("Reductions: %" PRIu64,
35767f193d69SLuke Drummond               static_cast<uint64_t>(m_reductions.size()));
35777f193d69SLuke Drummond   strm.EOL();
35787f193d69SLuke Drummond   strm.IndentMore();
35797f193d69SLuke Drummond   for (const auto &reduction : m_reductions) {
35807f193d69SLuke Drummond     reduction.Dump(strm);
35817f193d69SLuke Drummond   }
35827f193d69SLuke Drummond 
35837f193d69SLuke Drummond   strm.SetIndentLevel(indent);
35845ec532a9SColin Riley }
35855ec532a9SColin Riley 
3586b9c1b51eSKate Stone void RSGlobalDescriptor::Dump(Stream &strm) const {
35875ec532a9SColin Riley   strm.Indent(m_name.AsCString());
35884640cde1SColin Riley   VariableList var_list;
35894640cde1SColin Riley   m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list);
3590b9c1b51eSKate Stone   if (var_list.GetSize() == 1) {
35914640cde1SColin Riley     auto var = var_list.GetVariableAtIndex(0);
35924640cde1SColin Riley     auto type = var->GetType();
3593b9c1b51eSKate Stone     if (type) {
35944640cde1SColin Riley       strm.Printf(" - ");
35954640cde1SColin Riley       type->DumpTypeName(&strm);
3596b9c1b51eSKate Stone     } else {
35974640cde1SColin Riley       strm.Printf(" - Unknown Type");
35984640cde1SColin Riley     }
3599b9c1b51eSKate Stone   } else {
36004640cde1SColin Riley     strm.Printf(" - variable identified, but not found in binary");
3601b9c1b51eSKate Stone     const Symbol *s = m_module->m_module->FindFirstSymbolWithNameAndType(
3602b9c1b51eSKate Stone         m_name, eSymbolTypeData);
3603b9c1b51eSKate Stone     if (s) {
36044640cde1SColin Riley       strm.Printf(" (symbol exists) ");
36054640cde1SColin Riley     }
36064640cde1SColin Riley   }
36074640cde1SColin Riley 
36085ec532a9SColin Riley   strm.EOL();
36095ec532a9SColin Riley }
36105ec532a9SColin Riley 
3611b9c1b51eSKate Stone void RSKernelDescriptor::Dump(Stream &strm) const {
36125ec532a9SColin Riley   strm.Indent(m_name.AsCString());
36135ec532a9SColin Riley   strm.EOL();
36145ec532a9SColin Riley }
36155ec532a9SColin Riley 
36167f193d69SLuke Drummond void RSReductionDescriptor::Dump(lldb_private::Stream &stream) const {
36177f193d69SLuke Drummond   stream.Indent(m_reduce_name.AsCString());
36187f193d69SLuke Drummond   stream.IndentMore();
36197f193d69SLuke Drummond   stream.EOL();
36207f193d69SLuke Drummond   stream.Indent();
36217f193d69SLuke Drummond   stream.Printf("accumulator: %s", m_accum_name.AsCString());
36227f193d69SLuke Drummond   stream.EOL();
36237f193d69SLuke Drummond   stream.Indent();
36247f193d69SLuke Drummond   stream.Printf("initializer: %s", m_init_name.AsCString());
36257f193d69SLuke Drummond   stream.EOL();
36267f193d69SLuke Drummond   stream.Indent();
36277f193d69SLuke Drummond   stream.Printf("combiner: %s", m_comb_name.AsCString());
36287f193d69SLuke Drummond   stream.EOL();
36297f193d69SLuke Drummond   stream.Indent();
36307f193d69SLuke Drummond   stream.Printf("outconverter: %s", m_outc_name.AsCString());
36317f193d69SLuke Drummond   stream.EOL();
36327f193d69SLuke Drummond   // XXX This is currently unspecified by RenderScript, and unused
36337f193d69SLuke Drummond   // stream.Indent();
36347f193d69SLuke Drummond   // stream.Printf("halter: '%s'", m_init_name.AsCString());
36357f193d69SLuke Drummond   // stream.EOL();
36367f193d69SLuke Drummond   stream.IndentLess();
36377f193d69SLuke Drummond }
36387f193d69SLuke Drummond 
3639b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed {
36405ec532a9SColin Riley public:
36415ec532a9SColin Riley   CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter)
3642b9c1b51eSKate Stone       : CommandObjectParsed(
3643b9c1b51eSKate Stone             interpreter, "renderscript module dump",
3644b9c1b51eSKate Stone             "Dumps renderscript specific information for all modules.",
3645b9c1b51eSKate Stone             "renderscript module dump",
3646b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
36475ec532a9SColin Riley 
3648222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeModuleDump() override = default;
36495ec532a9SColin Riley 
3650b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
36515ec532a9SColin Riley     RenderScriptRuntime *runtime =
3652b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3653b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
36545ec532a9SColin Riley     runtime->DumpModules(result.GetOutputStream());
36555ec532a9SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
36565ec532a9SColin Riley     return true;
36575ec532a9SColin Riley   }
36585ec532a9SColin Riley };
36595ec532a9SColin Riley 
3660b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword {
36615ec532a9SColin Riley public:
36625ec532a9SColin Riley   CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter)
3663b9c1b51eSKate Stone       : CommandObjectMultiword(interpreter, "renderscript module",
3664b9c1b51eSKate Stone                                "Commands that deal with RenderScript modules.",
3665b9c1b51eSKate Stone                                nullptr) {
3666b9c1b51eSKate Stone     LoadSubCommand(
3667b9c1b51eSKate Stone         "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump(
3668b9c1b51eSKate Stone                     interpreter)));
36695ec532a9SColin Riley   }
36705ec532a9SColin Riley 
3671222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeModule() override = default;
36725ec532a9SColin Riley };
36735ec532a9SColin Riley 
3674b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed {
36754640cde1SColin Riley public:
36764640cde1SColin Riley   CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter)
3677b9c1b51eSKate Stone       : CommandObjectParsed(
3678b9c1b51eSKate Stone             interpreter, "renderscript kernel list",
3679b3f7f69dSAidan Dodds             "Lists renderscript kernel names and associated script resources.",
3680b9c1b51eSKate Stone             "renderscript kernel list",
3681b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
36824640cde1SColin Riley 
3683222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelList() override = default;
36844640cde1SColin Riley 
3685b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
36864640cde1SColin Riley     RenderScriptRuntime *runtime =
3687b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3688b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
36894640cde1SColin Riley     runtime->DumpKernels(result.GetOutputStream());
36904640cde1SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
36914640cde1SColin Riley     return true;
36924640cde1SColin Riley   }
36934640cde1SColin Riley };
36944640cde1SColin Riley 
36951f0f5b5bSZachary Turner static OptionDefinition g_renderscript_kernel_bp_set_options[] = {
36961f0f5b5bSZachary Turner     {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument,
36971f0f5b5bSZachary Turner      nullptr, nullptr, 0, eArgTypeValue,
36981f0f5b5bSZachary Turner      "Set a breakpoint on a single invocation of the kernel with specified "
36991f0f5b5bSZachary Turner      "coordinate.\n"
37001f0f5b5bSZachary Turner      "Coordinate takes the form 'x[,y][,z] where x,y,z are positive "
37011f0f5b5bSZachary Turner      "integers representing kernel dimensions. "
37021f0f5b5bSZachary Turner      "Any unset dimensions will be defaulted to zero."}};
37031f0f5b5bSZachary Turner 
3704b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpointSet
3705b9c1b51eSKate Stone     : public CommandObjectParsed {
37064640cde1SColin Riley public:
3707b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelBreakpointSet(
3708b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3709b9c1b51eSKate Stone       : CommandObjectParsed(
3710b9c1b51eSKate Stone             interpreter, "renderscript kernel breakpoint set",
3711b3f7f69dSAidan Dodds             "Sets a breakpoint on a renderscript kernel.",
3712b3f7f69dSAidan Dodds             "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]",
3713b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
3714b9c1b51eSKate Stone                 eCommandProcessMustBePaused),
3715b9c1b51eSKate Stone         m_options() {}
37164640cde1SColin Riley 
3717222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default;
3718222b937cSEugene Zelenko 
3719b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
3720018f5a7eSEwan Crawford 
3721b9c1b51eSKate Stone   class CommandOptions : public Options {
3722018f5a7eSEwan Crawford   public:
3723e1cfbc79STodd Fiala     CommandOptions() : Options() {}
3724018f5a7eSEwan Crawford 
3725222b937cSEugene Zelenko     ~CommandOptions() override = default;
3726018f5a7eSEwan Crawford 
3727b9c1b51eSKate Stone     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
3728b9c1b51eSKate Stone                          ExecutionContext *execution_context) override {
3729018f5a7eSEwan Crawford       Error error;
3730018f5a7eSEwan Crawford       const int short_option = m_getopt_table[option_idx].val;
3731018f5a7eSEwan Crawford 
3732b9c1b51eSKate Stone       switch (short_option) {
3733018f5a7eSEwan Crawford       case 'c':
3734018f5a7eSEwan Crawford         if (!ParseCoordinate(option_arg))
3735b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
3736b9c1b51eSKate Stone               "Couldn't parse coordinate '%s', should be in format 'x,y,z'.",
3737b3f7f69dSAidan Dodds               option_arg);
3738018f5a7eSEwan Crawford         break;
3739018f5a7eSEwan Crawford       default:
3740b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
3741b9c1b51eSKate Stone                                        short_option);
3742018f5a7eSEwan Crawford         break;
3743018f5a7eSEwan Crawford       }
3744018f5a7eSEwan Crawford       return error;
3745018f5a7eSEwan Crawford     }
3746018f5a7eSEwan Crawford 
3747018f5a7eSEwan Crawford     // -c takes an argument of the form 'num[,num][,num]'.
3748018f5a7eSEwan Crawford     // Where 'id_cstr' is this argument with the whitespace trimmed.
3749018f5a7eSEwan Crawford     // Missing coordinates are defaulted to zero.
3750b9c1b51eSKate Stone     bool ParseCoordinate(const char *id_cstr) {
3751018f5a7eSEwan Crawford       RegularExpression regex;
3752018f5a7eSEwan Crawford       RegularExpression::Match regex_match(3);
3753018f5a7eSEwan Crawford 
375495eae423SZachary Turner       llvm::StringRef id_ref = llvm::StringRef::withNullAsEmpty(id_cstr);
3755018f5a7eSEwan Crawford       bool matched = false;
375695eae423SZachary Turner       if (regex.Compile(llvm::StringRef("^([0-9]+),([0-9]+),([0-9]+)$")) &&
375795eae423SZachary Turner           regex.Execute(id_ref, &regex_match))
3758018f5a7eSEwan Crawford         matched = true;
375995eae423SZachary Turner       else if (regex.Compile(llvm::StringRef("^([0-9]+),([0-9]+)$")) &&
376095eae423SZachary Turner                regex.Execute(id_ref, &regex_match))
3761018f5a7eSEwan Crawford         matched = true;
376295eae423SZachary Turner       else if (regex.Compile(llvm::StringRef("^([0-9]+)$")) &&
376395eae423SZachary Turner                regex.Execute(id_ref, &regex_match))
3764018f5a7eSEwan Crawford         matched = true;
3765b9c1b51eSKate Stone       for (uint32_t i = 0; i < 3; i++) {
3766018f5a7eSEwan Crawford         std::string group;
3767018f5a7eSEwan Crawford         if (regex_match.GetMatchAtIndex(id_cstr, i + 1, group))
3768b3f7f69dSAidan Dodds           m_coord[i] = (uint32_t)strtoul(group.c_str(), nullptr, 0);
3769018f5a7eSEwan Crawford         else
3770018f5a7eSEwan Crawford           m_coord[i] = 0;
3771018f5a7eSEwan Crawford       }
3772018f5a7eSEwan Crawford       return matched;
3773018f5a7eSEwan Crawford     }
3774018f5a7eSEwan Crawford 
3775b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
3776018f5a7eSEwan Crawford       // -1 means the -c option hasn't been set
3777018f5a7eSEwan Crawford       m_coord[0] = -1;
3778018f5a7eSEwan Crawford       m_coord[1] = -1;
3779018f5a7eSEwan Crawford       m_coord[2] = -1;
3780018f5a7eSEwan Crawford     }
3781018f5a7eSEwan Crawford 
37821f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
3783*70602439SZachary Turner       return llvm::makeArrayRef(g_renderscript_kernel_bp_set_options);
37841f0f5b5bSZachary Turner     }
3785018f5a7eSEwan Crawford 
3786018f5a7eSEwan Crawford     std::array<int, 3> m_coord;
3787018f5a7eSEwan Crawford   };
3788018f5a7eSEwan Crawford 
3789b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
37904640cde1SColin Riley     const size_t argc = command.GetArgumentCount();
3791b9c1b51eSKate Stone     if (argc < 1) {
3792b9c1b51eSKate Stone       result.AppendErrorWithFormat(
3793b9c1b51eSKate Stone           "'%s' takes 1 argument of kernel name, and an optional coordinate.",
3794b3f7f69dSAidan Dodds           m_cmd_name.c_str());
3795018f5a7eSEwan Crawford       result.SetStatus(eReturnStatusFailed);
3796018f5a7eSEwan Crawford       return false;
3797018f5a7eSEwan Crawford     }
3798018f5a7eSEwan Crawford 
37994640cde1SColin Riley     RenderScriptRuntime *runtime =
3800b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3801b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
38024640cde1SColin Riley 
38034640cde1SColin Riley     Error error;
3804b9c1b51eSKate Stone     runtime->PlaceBreakpointOnKernel(
3805b9c1b51eSKate Stone         result.GetOutputStream(), command.GetArgumentAtIndex(0),
3806b9c1b51eSKate Stone         m_options.m_coord, error, m_exe_ctx.GetTargetSP());
38074640cde1SColin Riley 
3808b9c1b51eSKate Stone     if (error.Success()) {
38094640cde1SColin Riley       result.AppendMessage("Breakpoint(s) created");
38104640cde1SColin Riley       result.SetStatus(eReturnStatusSuccessFinishResult);
38114640cde1SColin Riley       return true;
38124640cde1SColin Riley     }
38134640cde1SColin Riley     result.SetStatus(eReturnStatusFailed);
38144640cde1SColin Riley     result.AppendErrorWithFormat("Error: %s", error.AsCString());
38154640cde1SColin Riley     return false;
38164640cde1SColin Riley   }
38174640cde1SColin Riley 
3818018f5a7eSEwan Crawford private:
3819018f5a7eSEwan Crawford   CommandOptions m_options;
38204640cde1SColin Riley };
38214640cde1SColin Riley 
3822b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpointAll
3823b9c1b51eSKate Stone     : public CommandObjectParsed {
38247dc7771cSEwan Crawford public:
3825b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelBreakpointAll(
3826b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3827b3f7f69dSAidan Dodds       : CommandObjectParsed(
3828b3f7f69dSAidan Dodds             interpreter, "renderscript kernel breakpoint all",
3829b9c1b51eSKate Stone             "Automatically sets a breakpoint on all renderscript kernels that "
3830b9c1b51eSKate Stone             "are or will be loaded.\n"
3831b9c1b51eSKate Stone             "Disabling option means breakpoints will no longer be set on any "
3832b9c1b51eSKate Stone             "kernels loaded in the future, "
38337dc7771cSEwan Crawford             "but does not remove currently set breakpoints.",
38347dc7771cSEwan Crawford             "renderscript kernel breakpoint all <enable/disable>",
3835b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
3836b9c1b51eSKate Stone                 eCommandProcessMustBePaused) {}
38377dc7771cSEwan Crawford 
3838222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default;
38397dc7771cSEwan Crawford 
3840b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
38417dc7771cSEwan Crawford     const size_t argc = command.GetArgumentCount();
3842b9c1b51eSKate Stone     if (argc != 1) {
3843b9c1b51eSKate Stone       result.AppendErrorWithFormat(
3844b9c1b51eSKate Stone           "'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str());
38457dc7771cSEwan Crawford       result.SetStatus(eReturnStatusFailed);
38467dc7771cSEwan Crawford       return false;
38477dc7771cSEwan Crawford     }
38487dc7771cSEwan Crawford 
3849b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
3850b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3851b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
38527dc7771cSEwan Crawford 
38537dc7771cSEwan Crawford     bool do_break = false;
38547dc7771cSEwan Crawford     const char *argument = command.GetArgumentAtIndex(0);
3855b9c1b51eSKate Stone     if (strcmp(argument, "enable") == 0) {
38567dc7771cSEwan Crawford       do_break = true;
38577dc7771cSEwan Crawford       result.AppendMessage("Breakpoints will be set on all kernels.");
3858b9c1b51eSKate Stone     } else if (strcmp(argument, "disable") == 0) {
38597dc7771cSEwan Crawford       do_break = false;
38607dc7771cSEwan Crawford       result.AppendMessage("Breakpoints will not be set on any new kernels.");
3861b9c1b51eSKate Stone     } else {
3862b9c1b51eSKate Stone       result.AppendErrorWithFormat(
3863b9c1b51eSKate Stone           "Argument must be either 'enable' or 'disable'");
38647dc7771cSEwan Crawford       result.SetStatus(eReturnStatusFailed);
38657dc7771cSEwan Crawford       return false;
38667dc7771cSEwan Crawford     }
38677dc7771cSEwan Crawford 
38687dc7771cSEwan Crawford     runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP());
38697dc7771cSEwan Crawford 
38707dc7771cSEwan Crawford     result.SetStatus(eReturnStatusSuccessFinishResult);
38717dc7771cSEwan Crawford     return true;
38727dc7771cSEwan Crawford   }
38737dc7771cSEwan Crawford };
38747dc7771cSEwan Crawford 
3875b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelCoordinate
3876b9c1b51eSKate Stone     : public CommandObjectParsed {
38774f8817c2SEwan Crawford public:
3878b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelCoordinate(
3879b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3880b9c1b51eSKate Stone       : CommandObjectParsed(
3881b9c1b51eSKate Stone             interpreter, "renderscript kernel coordinate",
38824f8817c2SEwan Crawford             "Shows the (x,y,z) coordinate of the current kernel invocation.",
38834f8817c2SEwan Crawford             "renderscript kernel coordinate",
3884b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
3885b9c1b51eSKate Stone                 eCommandProcessMustBePaused) {}
38864f8817c2SEwan Crawford 
38874f8817c2SEwan Crawford   ~CommandObjectRenderScriptRuntimeKernelCoordinate() override = default;
38884f8817c2SEwan Crawford 
3889b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
38904f8817c2SEwan Crawford     RSCoordinate coord{}; // Zero initialize array
3891b9c1b51eSKate Stone     bool success = RenderScriptRuntime::GetKernelCoordinate(
3892b9c1b51eSKate Stone         coord, m_exe_ctx.GetThreadPtr());
38934f8817c2SEwan Crawford     Stream &stream = result.GetOutputStream();
38944f8817c2SEwan Crawford 
3895b9c1b51eSKate Stone     if (success) {
3896b9c1b51eSKate Stone       stream.Printf("Coordinate: (%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")",
3897b9c1b51eSKate Stone                     coord[0], coord[1], coord[2]);
38984f8817c2SEwan Crawford       stream.EOL();
38994f8817c2SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
3900b9c1b51eSKate Stone     } else {
39014f8817c2SEwan Crawford       stream.Printf("Error: Coordinate could not be found.");
39024f8817c2SEwan Crawford       stream.EOL();
39034f8817c2SEwan Crawford       result.SetStatus(eReturnStatusFailed);
39044f8817c2SEwan Crawford     }
39054f8817c2SEwan Crawford     return true;
39064f8817c2SEwan Crawford   }
39074f8817c2SEwan Crawford };
39084f8817c2SEwan Crawford 
3909b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpoint
3910b9c1b51eSKate Stone     : public CommandObjectMultiword {
39117dc7771cSEwan Crawford public:
3912b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelBreakpoint(
3913b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3914b9c1b51eSKate Stone       : CommandObjectMultiword(
3915b9c1b51eSKate Stone             interpreter, "renderscript kernel",
3916b9c1b51eSKate Stone             "Commands that generate breakpoints on renderscript kernels.",
3917b9c1b51eSKate Stone             nullptr) {
3918b9c1b51eSKate Stone     LoadSubCommand(
3919b9c1b51eSKate Stone         "set",
3920b9c1b51eSKate Stone         CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet(
3921b9c1b51eSKate Stone             interpreter)));
3922b9c1b51eSKate Stone     LoadSubCommand(
3923b9c1b51eSKate Stone         "all",
3924b9c1b51eSKate Stone         CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll(
3925b9c1b51eSKate Stone             interpreter)));
39267dc7771cSEwan Crawford   }
39277dc7771cSEwan Crawford 
3928222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default;
39297dc7771cSEwan Crawford };
39307dc7771cSEwan Crawford 
3931b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword {
39324640cde1SColin Riley public:
39334640cde1SColin Riley   CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter)
3934b9c1b51eSKate Stone       : CommandObjectMultiword(interpreter, "renderscript kernel",
3935b9c1b51eSKate Stone                                "Commands that deal with RenderScript kernels.",
3936b9c1b51eSKate Stone                                nullptr) {
3937b9c1b51eSKate Stone     LoadSubCommand(
3938b9c1b51eSKate Stone         "list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList(
3939b9c1b51eSKate Stone                     interpreter)));
3940b9c1b51eSKate Stone     LoadSubCommand(
3941b9c1b51eSKate Stone         "coordinate",
3942b9c1b51eSKate Stone         CommandObjectSP(
3943b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeKernelCoordinate(interpreter)));
3944b9c1b51eSKate Stone     LoadSubCommand(
3945b9c1b51eSKate Stone         "breakpoint",
3946b9c1b51eSKate Stone         CommandObjectSP(
3947b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter)));
39484640cde1SColin Riley   }
39494640cde1SColin Riley 
3950222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernel() override = default;
39514640cde1SColin Riley };
39524640cde1SColin Riley 
3953b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed {
39544640cde1SColin Riley public:
39554640cde1SColin Riley   CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter)
3956b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "renderscript context dump",
3957b9c1b51eSKate Stone                             "Dumps renderscript context information.",
3958b9c1b51eSKate Stone                             "renderscript context dump",
3959b9c1b51eSKate Stone                             eCommandRequiresProcess |
3960b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
39614640cde1SColin Riley 
3962222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeContextDump() override = default;
39634640cde1SColin Riley 
3964b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
39654640cde1SColin Riley     RenderScriptRuntime *runtime =
3966b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3967b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
39684640cde1SColin Riley     runtime->DumpContexts(result.GetOutputStream());
39694640cde1SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
39704640cde1SColin Riley     return true;
39714640cde1SColin Riley   }
39724640cde1SColin Riley };
39734640cde1SColin Riley 
39741f0f5b5bSZachary Turner static OptionDefinition g_renderscript_runtime_alloc_dump_options[] = {
39751f0f5b5bSZachary Turner     {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument,
39761f0f5b5bSZachary Turner      nullptr, nullptr, 0, eArgTypeFilename,
39771f0f5b5bSZachary Turner      "Print results to specified file instead of command line."}};
39781f0f5b5bSZachary Turner 
3979b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword {
39804640cde1SColin Riley public:
39814640cde1SColin Riley   CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter)
3982b9c1b51eSKate Stone       : CommandObjectMultiword(interpreter, "renderscript context",
3983b9c1b51eSKate Stone                                "Commands that deal with RenderScript contexts.",
3984b9c1b51eSKate Stone                                nullptr) {
3985b9c1b51eSKate Stone     LoadSubCommand(
3986b9c1b51eSKate Stone         "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump(
3987b9c1b51eSKate Stone                     interpreter)));
39884640cde1SColin Riley   }
39894640cde1SColin Riley 
3990222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeContext() override = default;
39914640cde1SColin Riley };
39924640cde1SColin Riley 
3993b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationDump
3994b9c1b51eSKate Stone     : public CommandObjectParsed {
3995a0f08674SEwan Crawford public:
3996b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationDump(
3997b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3998a0f08674SEwan Crawford       : CommandObjectParsed(interpreter, "renderscript allocation dump",
3999b9c1b51eSKate Stone                             "Displays the contents of a particular allocation",
4000b9c1b51eSKate Stone                             "renderscript allocation dump <ID>",
4001b9c1b51eSKate Stone                             eCommandRequiresProcess |
4002b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched),
4003b9c1b51eSKate Stone         m_options() {}
4004a0f08674SEwan Crawford 
4005222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationDump() override = default;
4006222b937cSEugene Zelenko 
4007b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
4008a0f08674SEwan Crawford 
4009b9c1b51eSKate Stone   class CommandOptions : public Options {
4010a0f08674SEwan Crawford   public:
4011e1cfbc79STodd Fiala     CommandOptions() : Options() {}
4012a0f08674SEwan Crawford 
4013222b937cSEugene Zelenko     ~CommandOptions() override = default;
4014a0f08674SEwan Crawford 
4015b9c1b51eSKate Stone     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
4016b9c1b51eSKate Stone                          ExecutionContext *execution_context) override {
4017a0f08674SEwan Crawford       Error error;
4018a0f08674SEwan Crawford       const int short_option = m_getopt_table[option_idx].val;
4019a0f08674SEwan Crawford 
4020b9c1b51eSKate Stone       switch (short_option) {
4021a0f08674SEwan Crawford       case 'f':
4022a0f08674SEwan Crawford         m_outfile.SetFile(option_arg, true);
4023b9c1b51eSKate Stone         if (m_outfile.Exists()) {
4024a0f08674SEwan Crawford           m_outfile.Clear();
4025b9c1b51eSKate Stone           error.SetErrorStringWithFormat("file already exists: '%s'",
4026b9c1b51eSKate Stone                                          option_arg);
4027a0f08674SEwan Crawford         }
4028a0f08674SEwan Crawford         break;
4029a0f08674SEwan Crawford       default:
4030b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
4031b9c1b51eSKate Stone                                        short_option);
4032a0f08674SEwan Crawford         break;
4033a0f08674SEwan Crawford       }
4034a0f08674SEwan Crawford       return error;
4035a0f08674SEwan Crawford     }
4036a0f08674SEwan Crawford 
4037b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
4038a0f08674SEwan Crawford       m_outfile.Clear();
4039a0f08674SEwan Crawford     }
4040a0f08674SEwan Crawford 
40411f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
4042*70602439SZachary Turner       return llvm::makeArrayRef(g_renderscript_runtime_alloc_dump_options);
40431f0f5b5bSZachary Turner     }
4044a0f08674SEwan Crawford 
4045a0f08674SEwan Crawford     FileSpec m_outfile;
4046a0f08674SEwan Crawford   };
4047a0f08674SEwan Crawford 
4048b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
4049a0f08674SEwan Crawford     const size_t argc = command.GetArgumentCount();
4050b9c1b51eSKate Stone     if (argc < 1) {
4051b9c1b51eSKate Stone       result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. "
4052b9c1b51eSKate Stone                                    "As well as an optional -f argument",
4053a0f08674SEwan Crawford                                    m_cmd_name.c_str());
4054a0f08674SEwan Crawford       result.SetStatus(eReturnStatusFailed);
4055a0f08674SEwan Crawford       return false;
4056a0f08674SEwan Crawford     }
4057a0f08674SEwan Crawford 
4058b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4059b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4060b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
4061a0f08674SEwan Crawford 
4062a0f08674SEwan Crawford     const char *id_cstr = command.GetArgumentAtIndex(0);
4063a0f08674SEwan Crawford     bool convert_complete = false;
4064b9c1b51eSKate Stone     const uint32_t id =
4065b9c1b51eSKate Stone         StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
4066b9c1b51eSKate Stone     if (!convert_complete) {
4067b9c1b51eSKate Stone       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
4068b9c1b51eSKate Stone                                    id_cstr);
4069a0f08674SEwan Crawford       result.SetStatus(eReturnStatusFailed);
4070a0f08674SEwan Crawford       return false;
4071a0f08674SEwan Crawford     }
4072a0f08674SEwan Crawford 
4073a0f08674SEwan Crawford     Stream *output_strm = nullptr;
4074a0f08674SEwan Crawford     StreamFile outfile_stream;
4075b9c1b51eSKate Stone     const FileSpec &outfile_spec =
4076b9c1b51eSKate Stone         m_options.m_outfile; // Dump allocation to file instead
4077b9c1b51eSKate Stone     if (outfile_spec) {
4078a0f08674SEwan Crawford       // Open output file
4079a0f08674SEwan Crawford       char path[256];
4080a0f08674SEwan Crawford       outfile_spec.GetPath(path, sizeof(path));
4081b9c1b51eSKate Stone       if (outfile_stream.GetFile()
4082b9c1b51eSKate Stone               .Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate)
4083b9c1b51eSKate Stone               .Success()) {
4084a0f08674SEwan Crawford         output_strm = &outfile_stream;
4085a0f08674SEwan Crawford         result.GetOutputStream().Printf("Results written to '%s'", path);
4086a0f08674SEwan Crawford         result.GetOutputStream().EOL();
4087b9c1b51eSKate Stone       } else {
4088a0f08674SEwan Crawford         result.AppendErrorWithFormat("Couldn't open file '%s'", path);
4089a0f08674SEwan Crawford         result.SetStatus(eReturnStatusFailed);
4090a0f08674SEwan Crawford         return false;
4091a0f08674SEwan Crawford       }
4092b9c1b51eSKate Stone     } else
4093a0f08674SEwan Crawford       output_strm = &result.GetOutputStream();
4094a0f08674SEwan Crawford 
4095a0f08674SEwan Crawford     assert(output_strm != nullptr);
4096b9c1b51eSKate Stone     bool success =
4097b9c1b51eSKate Stone         runtime->DumpAllocation(*output_strm, m_exe_ctx.GetFramePtr(), id);
4098a0f08674SEwan Crawford 
4099a0f08674SEwan Crawford     if (success)
4100a0f08674SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
4101a0f08674SEwan Crawford     else
4102a0f08674SEwan Crawford       result.SetStatus(eReturnStatusFailed);
4103a0f08674SEwan Crawford 
4104a0f08674SEwan Crawford     return true;
4105a0f08674SEwan Crawford   }
4106a0f08674SEwan Crawford 
4107a0f08674SEwan Crawford private:
4108a0f08674SEwan Crawford   CommandOptions m_options;
4109a0f08674SEwan Crawford };
4110a0f08674SEwan Crawford 
41111f0f5b5bSZachary Turner static OptionDefinition g_renderscript_runtime_alloc_list_options[] = {
41121f0f5b5bSZachary Turner     {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument, nullptr,
41131f0f5b5bSZachary Turner      nullptr, 0, eArgTypeIndex,
41141f0f5b5bSZachary Turner      "Only show details of a single allocation with specified id."}};
4115a0f08674SEwan Crawford 
4116b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationList
4117b9c1b51eSKate Stone     : public CommandObjectParsed {
411815f2bd95SEwan Crawford public:
4119b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationList(
4120b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4121b9c1b51eSKate Stone       : CommandObjectParsed(
4122b9c1b51eSKate Stone             interpreter, "renderscript allocation list",
4123b9c1b51eSKate Stone             "List renderscript allocations and their information.",
4124b9c1b51eSKate Stone             "renderscript allocation list",
4125b3f7f69dSAidan Dodds             eCommandRequiresProcess | eCommandProcessMustBeLaunched),
4126b9c1b51eSKate Stone         m_options() {}
412715f2bd95SEwan Crawford 
4128222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationList() override = default;
4129222b937cSEugene Zelenko 
4130b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
413115f2bd95SEwan Crawford 
4132b9c1b51eSKate Stone   class CommandOptions : public Options {
413315f2bd95SEwan Crawford   public:
4134e1cfbc79STodd Fiala     CommandOptions() : Options(), m_id(0) {}
413515f2bd95SEwan Crawford 
4136222b937cSEugene Zelenko     ~CommandOptions() override = default;
413715f2bd95SEwan Crawford 
4138b9c1b51eSKate Stone     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
4139b9c1b51eSKate Stone                          ExecutionContext *execution_context) override {
414015f2bd95SEwan Crawford       Error error;
414115f2bd95SEwan Crawford       const int short_option = m_getopt_table[option_idx].val;
414215f2bd95SEwan Crawford 
4143b9c1b51eSKate Stone       switch (short_option) {
4144b649b005SEwan Crawford       case 'i':
4145b649b005SEwan Crawford         bool success;
4146b649b005SEwan Crawford         m_id = StringConvert::ToUInt32(option_arg, 0, 0, &success);
4147b649b005SEwan Crawford         if (!success)
4148b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
4149b9c1b51eSKate Stone               "invalid integer value for option '%c'", short_option);
415015f2bd95SEwan Crawford         break;
415115f2bd95SEwan Crawford       default:
4152b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
4153b9c1b51eSKate Stone                                        short_option);
415415f2bd95SEwan Crawford         break;
415515f2bd95SEwan Crawford       }
415615f2bd95SEwan Crawford       return error;
415715f2bd95SEwan Crawford     }
415815f2bd95SEwan Crawford 
4159b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
4160b649b005SEwan Crawford       m_id = 0;
416115f2bd95SEwan Crawford     }
416215f2bd95SEwan Crawford 
41631f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
4164*70602439SZachary Turner       return llvm::makeArrayRef(g_renderscript_runtime_alloc_list_options);
41651f0f5b5bSZachary Turner     }
416615f2bd95SEwan Crawford 
4167b649b005SEwan Crawford     uint32_t m_id;
416815f2bd95SEwan Crawford   };
416915f2bd95SEwan Crawford 
4170b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
4171b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4172b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4173b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
4174b9c1b51eSKate Stone     runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(),
4175b9c1b51eSKate Stone                              m_options.m_id);
417615f2bd95SEwan Crawford     result.SetStatus(eReturnStatusSuccessFinishResult);
417715f2bd95SEwan Crawford     return true;
417815f2bd95SEwan Crawford   }
417915f2bd95SEwan Crawford 
418015f2bd95SEwan Crawford private:
418115f2bd95SEwan Crawford   CommandOptions m_options;
418215f2bd95SEwan Crawford };
418315f2bd95SEwan Crawford 
4184b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationLoad
4185b9c1b51eSKate Stone     : public CommandObjectParsed {
418655232f09SEwan Crawford public:
4187b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationLoad(
4188b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4189b3f7f69dSAidan Dodds       : CommandObjectParsed(
4190b9c1b51eSKate Stone             interpreter, "renderscript allocation load",
4191b9c1b51eSKate Stone             "Loads renderscript allocation contents from a file.",
4192b9c1b51eSKate Stone             "renderscript allocation load <ID> <filename>",
4193b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
419455232f09SEwan Crawford 
4195222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default;
419655232f09SEwan Crawford 
4197b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
419855232f09SEwan Crawford     const size_t argc = command.GetArgumentCount();
4199b9c1b51eSKate Stone     if (argc != 2) {
4200b9c1b51eSKate Stone       result.AppendErrorWithFormat(
4201b9c1b51eSKate Stone           "'%s' takes 2 arguments, an allocation ID and filename to read from.",
4202b3f7f69dSAidan Dodds           m_cmd_name.c_str());
420355232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
420455232f09SEwan Crawford       return false;
420555232f09SEwan Crawford     }
420655232f09SEwan Crawford 
4207b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4208b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4209b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
421055232f09SEwan Crawford 
421155232f09SEwan Crawford     const char *id_cstr = command.GetArgumentAtIndex(0);
421255232f09SEwan Crawford     bool convert_complete = false;
4213b9c1b51eSKate Stone     const uint32_t id =
4214b9c1b51eSKate Stone         StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
4215b9c1b51eSKate Stone     if (!convert_complete) {
4216b9c1b51eSKate Stone       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
4217b9c1b51eSKate Stone                                    id_cstr);
421855232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
421955232f09SEwan Crawford       return false;
422055232f09SEwan Crawford     }
422155232f09SEwan Crawford 
422255232f09SEwan Crawford     const char *filename = command.GetArgumentAtIndex(1);
4223b9c1b51eSKate Stone     bool success = runtime->LoadAllocation(result.GetOutputStream(), id,
4224b9c1b51eSKate Stone                                            filename, m_exe_ctx.GetFramePtr());
422555232f09SEwan Crawford 
422655232f09SEwan Crawford     if (success)
422755232f09SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
422855232f09SEwan Crawford     else
422955232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
423055232f09SEwan Crawford 
423155232f09SEwan Crawford     return true;
423255232f09SEwan Crawford   }
423355232f09SEwan Crawford };
423455232f09SEwan Crawford 
4235b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationSave
4236b9c1b51eSKate Stone     : public CommandObjectParsed {
423755232f09SEwan Crawford public:
4238b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationSave(
4239b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4240b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "renderscript allocation save",
4241b9c1b51eSKate Stone                             "Write renderscript allocation contents to a file.",
4242b9c1b51eSKate Stone                             "renderscript allocation save <ID> <filename>",
4243b9c1b51eSKate Stone                             eCommandRequiresProcess |
4244b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
424555232f09SEwan Crawford 
4246222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationSave() override = default;
424755232f09SEwan Crawford 
4248b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
424955232f09SEwan Crawford     const size_t argc = command.GetArgumentCount();
4250b9c1b51eSKate Stone     if (argc != 2) {
4251b9c1b51eSKate Stone       result.AppendErrorWithFormat(
4252b9c1b51eSKate Stone           "'%s' takes 2 arguments, an allocation ID and filename to read from.",
4253b3f7f69dSAidan Dodds           m_cmd_name.c_str());
425455232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
425555232f09SEwan Crawford       return false;
425655232f09SEwan Crawford     }
425755232f09SEwan Crawford 
4258b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4259b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4260b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
426155232f09SEwan Crawford 
426255232f09SEwan Crawford     const char *id_cstr = command.GetArgumentAtIndex(0);
426355232f09SEwan Crawford     bool convert_complete = false;
4264b9c1b51eSKate Stone     const uint32_t id =
4265b9c1b51eSKate Stone         StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
4266b9c1b51eSKate Stone     if (!convert_complete) {
4267b9c1b51eSKate Stone       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
4268b9c1b51eSKate Stone                                    id_cstr);
426955232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
427055232f09SEwan Crawford       return false;
427155232f09SEwan Crawford     }
427255232f09SEwan Crawford 
427355232f09SEwan Crawford     const char *filename = command.GetArgumentAtIndex(1);
4274b9c1b51eSKate Stone     bool success = runtime->SaveAllocation(result.GetOutputStream(), id,
4275b9c1b51eSKate Stone                                            filename, m_exe_ctx.GetFramePtr());
427655232f09SEwan Crawford 
427755232f09SEwan Crawford     if (success)
427855232f09SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
427955232f09SEwan Crawford     else
428055232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
428155232f09SEwan Crawford 
428255232f09SEwan Crawford     return true;
428355232f09SEwan Crawford   }
428455232f09SEwan Crawford };
428555232f09SEwan Crawford 
4286b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationRefresh
4287b9c1b51eSKate Stone     : public CommandObjectParsed {
42880d2bfcfbSEwan Crawford public:
4289b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationRefresh(
4290b9c1b51eSKate Stone       CommandInterpreter &interpreter)
42910d2bfcfbSEwan Crawford       : CommandObjectParsed(interpreter, "renderscript allocation refresh",
4292b9c1b51eSKate Stone                             "Recomputes the details of all allocations.",
4293b9c1b51eSKate Stone                             "renderscript allocation refresh",
4294b9c1b51eSKate Stone                             eCommandRequiresProcess |
4295b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
42960d2bfcfbSEwan Crawford 
42970d2bfcfbSEwan Crawford   ~CommandObjectRenderScriptRuntimeAllocationRefresh() override = default;
42980d2bfcfbSEwan Crawford 
4299b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
43000d2bfcfbSEwan Crawford     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4301b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4302b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
43030d2bfcfbSEwan Crawford 
4304b9c1b51eSKate Stone     bool success = runtime->RecomputeAllAllocations(result.GetOutputStream(),
4305b9c1b51eSKate Stone                                                     m_exe_ctx.GetFramePtr());
43060d2bfcfbSEwan Crawford 
4307b9c1b51eSKate Stone     if (success) {
43080d2bfcfbSEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
43090d2bfcfbSEwan Crawford       return true;
4310b9c1b51eSKate Stone     } else {
43110d2bfcfbSEwan Crawford       result.SetStatus(eReturnStatusFailed);
43120d2bfcfbSEwan Crawford       return false;
43130d2bfcfbSEwan Crawford     }
43140d2bfcfbSEwan Crawford   }
43150d2bfcfbSEwan Crawford };
43160d2bfcfbSEwan Crawford 
4317b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocation
4318b9c1b51eSKate Stone     : public CommandObjectMultiword {
431915f2bd95SEwan Crawford public:
432015f2bd95SEwan Crawford   CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter)
4321b9c1b51eSKate Stone       : CommandObjectMultiword(
4322b9c1b51eSKate Stone             interpreter, "renderscript allocation",
4323b9c1b51eSKate Stone             "Commands that deal with RenderScript allocations.", nullptr) {
4324b9c1b51eSKate Stone     LoadSubCommand(
4325b9c1b51eSKate Stone         "list",
4326b9c1b51eSKate Stone         CommandObjectSP(
4327b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationList(interpreter)));
4328b9c1b51eSKate Stone     LoadSubCommand(
4329b9c1b51eSKate Stone         "dump",
4330b9c1b51eSKate Stone         CommandObjectSP(
4331b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationDump(interpreter)));
4332b9c1b51eSKate Stone     LoadSubCommand(
4333b9c1b51eSKate Stone         "save",
4334b9c1b51eSKate Stone         CommandObjectSP(
4335b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationSave(interpreter)));
4336b9c1b51eSKate Stone     LoadSubCommand(
4337b9c1b51eSKate Stone         "load",
4338b9c1b51eSKate Stone         CommandObjectSP(
4339b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter)));
4340b9c1b51eSKate Stone     LoadSubCommand(
4341b9c1b51eSKate Stone         "refresh",
4342b9c1b51eSKate Stone         CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationRefresh(
4343b9c1b51eSKate Stone             interpreter)));
434415f2bd95SEwan Crawford   }
434515f2bd95SEwan Crawford 
4346222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocation() override = default;
434715f2bd95SEwan Crawford };
434815f2bd95SEwan Crawford 
4349b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed {
43504640cde1SColin Riley public:
43514640cde1SColin Riley   CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter)
4352b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "renderscript status",
4353b9c1b51eSKate Stone                             "Displays current RenderScript runtime status.",
4354b9c1b51eSKate Stone                             "renderscript status",
4355b9c1b51eSKate Stone                             eCommandRequiresProcess |
4356b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
43574640cde1SColin Riley 
4358222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeStatus() override = default;
43594640cde1SColin Riley 
4360b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
43614640cde1SColin Riley     RenderScriptRuntime *runtime =
4362b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4363b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
43644640cde1SColin Riley     runtime->Status(result.GetOutputStream());
43654640cde1SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
43664640cde1SColin Riley     return true;
43674640cde1SColin Riley   }
43684640cde1SColin Riley };
43694640cde1SColin Riley 
4370b9c1b51eSKate Stone class CommandObjectRenderScriptRuntime : public CommandObjectMultiword {
43715ec532a9SColin Riley public:
43725ec532a9SColin Riley   CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter)
4373b9c1b51eSKate Stone       : CommandObjectMultiword(
4374b9c1b51eSKate Stone             interpreter, "renderscript",
4375b9c1b51eSKate Stone             "Commands for operating on the RenderScript runtime.",
4376b9c1b51eSKate Stone             "renderscript <subcommand> [<subcommand-options>]") {
4377b9c1b51eSKate Stone     LoadSubCommand(
4378b9c1b51eSKate Stone         "module", CommandObjectSP(
4379b9c1b51eSKate Stone                       new CommandObjectRenderScriptRuntimeModule(interpreter)));
4380b9c1b51eSKate Stone     LoadSubCommand(
4381b9c1b51eSKate Stone         "status", CommandObjectSP(
4382b9c1b51eSKate Stone                       new CommandObjectRenderScriptRuntimeStatus(interpreter)));
4383b9c1b51eSKate Stone     LoadSubCommand(
4384b9c1b51eSKate Stone         "kernel", CommandObjectSP(
4385b9c1b51eSKate Stone                       new CommandObjectRenderScriptRuntimeKernel(interpreter)));
4386b9c1b51eSKate Stone     LoadSubCommand("context",
4387b9c1b51eSKate Stone                    CommandObjectSP(new CommandObjectRenderScriptRuntimeContext(
4388b9c1b51eSKate Stone                        interpreter)));
4389b9c1b51eSKate Stone     LoadSubCommand(
4390b9c1b51eSKate Stone         "allocation",
4391b9c1b51eSKate Stone         CommandObjectSP(
4392b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocation(interpreter)));
43935ec532a9SColin Riley   }
43945ec532a9SColin Riley 
4395222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntime() override = default;
43965ec532a9SColin Riley };
4397ef20b08fSColin Riley 
4398b9c1b51eSKate Stone void RenderScriptRuntime::Initiate() { assert(!m_initiated); }
4399ef20b08fSColin Riley 
4400ef20b08fSColin Riley RenderScriptRuntime::RenderScriptRuntime(Process *process)
4401b9c1b51eSKate Stone     : lldb_private::CPPLanguageRuntime(process), m_initiated(false),
4402b9c1b51eSKate Stone       m_debuggerPresentFlagged(false), m_breakAllKernels(false),
4403b9c1b51eSKate Stone       m_ir_passes(nullptr) {
44044640cde1SColin Riley   ModulesDidLoad(process->GetTarget().GetImages());
4405ef20b08fSColin Riley }
44064640cde1SColin Riley 
4407b9c1b51eSKate Stone lldb::CommandObjectSP RenderScriptRuntime::GetCommandObject(
4408b9c1b51eSKate Stone     lldb_private::CommandInterpreter &interpreter) {
44090a66e2f1SEnrico Granata   return CommandObjectSP(new CommandObjectRenderScriptRuntime(interpreter));
44104640cde1SColin Riley }
44114640cde1SColin Riley 
441278f339d1SEwan Crawford RenderScriptRuntime::~RenderScriptRuntime() = default;
4413