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
13*7f193d69SLuke Drummond #include "llvm/ADT/StringMap.h"
14*7f193d69SLuke 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)
1967b9c1b51eSKate Stone     module_sp->m_module->FindGlobalVariables(RegularExpression("."), true,
1968b9c1b51eSKate Stone                                              UINT32_MAX, variable_list);
19698b244e21SEwan Crawford 
1970b9c1b51eSKate Stone   // Iterate over all the global variables looking for one with a matching type
1971b9c1b51eSKate Stone   // to the Element.
1972b9c1b51eSKate Stone   // We make the assumption a match exists since there needs to be a global
1973b9c1b51eSKate Stone   // variable to reflect the
19748b244e21SEwan Crawford   // struct type back into java host code.
1975b9c1b51eSKate Stone   for (uint32_t var_index = 0; var_index < variable_list.GetSize();
1976b9c1b51eSKate Stone        ++var_index) {
19778b244e21SEwan Crawford     const VariableSP var_sp(variable_list.GetVariableAtIndex(var_index));
19788b244e21SEwan Crawford     if (!var_sp)
19798b244e21SEwan Crawford       continue;
19808b244e21SEwan Crawford 
19818b244e21SEwan Crawford     ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp);
19828b244e21SEwan Crawford     if (!valobj_sp)
19838b244e21SEwan Crawford       continue;
19848b244e21SEwan Crawford 
19858b244e21SEwan Crawford     // Find the number of variable fields.
1986b9c1b51eSKate Stone     // If it has no fields, or more fields than our Element, then it can't be
1987b9c1b51eSKate Stone     // the struct we're looking for.
1988b9c1b51eSKate Stone     // Don't check for equality since RS can add extra struct members for
1989b9c1b51eSKate Stone     // padding.
19908b244e21SEwan Crawford     size_t num_children = valobj_sp->GetNumChildren();
19918b244e21SEwan Crawford     if (num_children > elem.children.size() || num_children == 0)
19928b244e21SEwan Crawford       continue;
19938b244e21SEwan Crawford 
19948b244e21SEwan Crawford     // Iterate over children looking for members with matching field names.
19958b244e21SEwan Crawford     // If all the field names match, this is likely the struct we want.
19968b244e21SEwan Crawford     //
1997b9c1b51eSKate Stone     //   TODO: This could be made more robust by also checking children data
1998b9c1b51eSKate Stone     //   sizes, or array size
19998b244e21SEwan Crawford     bool found = true;
2000b9c1b51eSKate Stone     for (size_t child_index = 0; child_index < num_children; ++child_index) {
20018b244e21SEwan Crawford       ValueObjectSP child = valobj_sp->GetChildAtIndex(child_index, true);
2002b9c1b51eSKate Stone       if (!child ||
2003b9c1b51eSKate Stone           (child->GetName() != elem.children[child_index].type_name)) {
20048b244e21SEwan Crawford         found = false;
20058b244e21SEwan Crawford         break;
20068b244e21SEwan Crawford       }
20078b244e21SEwan Crawford     }
20088b244e21SEwan Crawford 
2009b9c1b51eSKate Stone     // RS can add extra struct members for padding in the format
2010b9c1b51eSKate Stone     // '#rs_padding_[0-9]+'
2011b9c1b51eSKate Stone     if (found && num_children < elem.children.size()) {
2012b3f7f69dSAidan Dodds       const uint32_t size_diff = elem.children.size() - num_children;
20138b244e21SEwan Crawford       if (log)
2014b9c1b51eSKate Stone         log->Printf("%s - %" PRIu32 " padding struct entries", __FUNCTION__,
2015b9c1b51eSKate Stone                     size_diff);
20168b244e21SEwan Crawford 
2017b9c1b51eSKate Stone       for (uint32_t padding_index = 0; padding_index < size_diff;
2018b9c1b51eSKate Stone            ++padding_index) {
2019b9c1b51eSKate Stone         const ConstString &name =
2020b9c1b51eSKate Stone             elem.children[num_children + padding_index].type_name;
20218b244e21SEwan Crawford         if (strcmp(name.AsCString(), "#rs_padding") < 0)
20228b244e21SEwan Crawford           found = false;
20238b244e21SEwan Crawford       }
20248b244e21SEwan Crawford     }
20258b244e21SEwan Crawford 
20268b244e21SEwan Crawford     // We've found a global var with matching type
2027b9c1b51eSKate Stone     if (found) {
20288b244e21SEwan Crawford       // Dereference since our Element type isn't a pointer.
2029b9c1b51eSKate Stone       if (valobj_sp->IsPointerType()) {
20308b244e21SEwan Crawford         Error err;
20318b244e21SEwan Crawford         ValueObjectSP deref_valobj = valobj_sp->Dereference(err);
20328b244e21SEwan Crawford         if (!err.Fail())
20338b244e21SEwan Crawford           valobj_sp = deref_valobj;
20348b244e21SEwan Crawford       }
20358b244e21SEwan Crawford 
20368b244e21SEwan Crawford       // Save name of variable in Element.
20378b244e21SEwan Crawford       elem.type_name = valobj_sp->GetTypeName();
20388b244e21SEwan Crawford       if (log)
2039b9c1b51eSKate Stone         log->Printf("%s - element name set to %s", __FUNCTION__,
2040b9c1b51eSKate Stone                     elem.type_name.AsCString());
20418b244e21SEwan Crawford 
20428b244e21SEwan Crawford       return;
20438b244e21SEwan Crawford     }
20448b244e21SEwan Crawford   }
20458b244e21SEwan Crawford }
20468b244e21SEwan Crawford 
2047b9c1b51eSKate Stone // Function sets the datum_size member of Element. Representing the size of a
2048b9c1b51eSKate Stone // single instance including padding.
20498b244e21SEwan Crawford // Assumes the relevant allocation information has already been jitted.
2050b9c1b51eSKate Stone void RenderScriptRuntime::SetElementSize(Element &elem) {
20518b244e21SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
20528b244e21SEwan Crawford   const Element::DataType type = *elem.type.get();
2053b9c1b51eSKate Stone   assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT &&
2054b9c1b51eSKate Stone          "Invalid allocation type");
205555232f09SEwan Crawford 
2056b3f7f69dSAidan Dodds   const uint32_t vec_size = *elem.type_vec_size.get();
2057b3f7f69dSAidan Dodds   uint32_t data_size = 0;
2058b3f7f69dSAidan Dodds   uint32_t padding = 0;
205955232f09SEwan Crawford 
20608b244e21SEwan Crawford   // Element is of a struct type, calculate size recursively.
2061b9c1b51eSKate Stone   if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) {
2062b9c1b51eSKate Stone     for (Element &child : elem.children) {
20638b244e21SEwan Crawford       SetElementSize(child);
2064b9c1b51eSKate Stone       const uint32_t array_size =
2065b9c1b51eSKate Stone           child.array_size.isValid() ? *child.array_size.get() : 1;
20668b244e21SEwan Crawford       data_size += *child.datum_size.get() * array_size;
20678b244e21SEwan Crawford     }
20688b244e21SEwan Crawford   }
2069b3f7f69dSAidan Dodds   // These have been packed already
2070b3f7f69dSAidan Dodds   else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 ||
2071b3f7f69dSAidan Dodds            type == Element::RS_TYPE_UNSIGNED_5_5_5_1 ||
2072b9c1b51eSKate Stone            type == Element::RS_TYPE_UNSIGNED_4_4_4_4) {
20732e920715SEwan Crawford     data_size = AllocationDetails::RSTypeToFormat[type][eElementSize];
2074b9c1b51eSKate Stone   } else if (type < Element::RS_TYPE_ELEMENT) {
2075b9c1b51eSKate Stone     data_size =
2076b9c1b51eSKate Stone         vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize];
20772e920715SEwan Crawford     if (vec_size == 3)
20782e920715SEwan Crawford       padding = AllocationDetails::RSTypeToFormat[type][eElementSize];
2079b9c1b51eSKate Stone   } else
2080b9c1b51eSKate Stone     data_size =
2081b9c1b51eSKate Stone         GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
20828b244e21SEwan Crawford 
20838b244e21SEwan Crawford   elem.padding = padding;
20848b244e21SEwan Crawford   elem.datum_size = data_size + padding;
20858b244e21SEwan Crawford   if (log)
2086b9c1b51eSKate Stone     log->Printf("%s - element size set to %" PRIu32, __FUNCTION__,
2087b9c1b51eSKate Stone                 data_size + padding);
208855232f09SEwan Crawford }
208955232f09SEwan Crawford 
2090b9c1b51eSKate Stone // Given an allocation, this function copies the allocation contents from device
2091b9c1b51eSKate Stone // into a buffer on the heap.
209255232f09SEwan Crawford // Returning a shared pointer to the buffer containing the data.
209355232f09SEwan Crawford std::shared_ptr<uint8_t>
2094b9c1b51eSKate Stone RenderScriptRuntime::GetAllocationData(AllocationDetails *allocation,
2095b9c1b51eSKate Stone                                        StackFrame *frame_ptr) {
209655232f09SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
209755232f09SEwan Crawford 
209855232f09SEwan Crawford   // JIT all the allocation details
2099b9c1b51eSKate Stone   if (allocation->shouldRefresh()) {
210055232f09SEwan Crawford     if (log)
2101b9c1b51eSKate Stone       log->Printf("%s - allocation details not calculated yet, jitting info",
2102b9c1b51eSKate Stone                   __FUNCTION__);
210355232f09SEwan Crawford 
2104b9c1b51eSKate Stone     if (!RefreshAllocation(allocation, frame_ptr)) {
210555232f09SEwan Crawford       if (log)
2106b3f7f69dSAidan Dodds         log->Printf("%s - couldn't JIT allocation details", __FUNCTION__);
210755232f09SEwan Crawford       return nullptr;
210855232f09SEwan Crawford     }
210955232f09SEwan Crawford   }
211055232f09SEwan Crawford 
2111b3f7f69dSAidan Dodds   assert(allocation->data_ptr.isValid() && allocation->element.type.isValid() &&
2112b9c1b51eSKate Stone          allocation->element.type_vec_size.isValid() &&
2113b9c1b51eSKate Stone          allocation->size.isValid() && "Allocation information not available");
211455232f09SEwan Crawford 
211555232f09SEwan Crawford   // Allocate a buffer to copy data into
2116b3f7f69dSAidan Dodds   const uint32_t size = *allocation->size.get();
211755232f09SEwan Crawford   std::shared_ptr<uint8_t> buffer(new uint8_t[size]);
2118b9c1b51eSKate Stone   if (!buffer) {
211955232f09SEwan Crawford     if (log)
2120b9c1b51eSKate Stone       log->Printf("%s - couldn't allocate a %" PRIu32 " byte buffer",
2121b9c1b51eSKate Stone                   __FUNCTION__, size);
212255232f09SEwan Crawford     return nullptr;
212355232f09SEwan Crawford   }
212455232f09SEwan Crawford 
212555232f09SEwan Crawford   // Read the inferior memory
212655232f09SEwan Crawford   Error error;
212755232f09SEwan Crawford   lldb::addr_t data_ptr = *allocation->data_ptr.get();
212855232f09SEwan Crawford   GetProcess()->ReadMemory(data_ptr, buffer.get(), size, error);
2129b9c1b51eSKate Stone   if (error.Fail()) {
213055232f09SEwan Crawford     if (log)
2131b9c1b51eSKate Stone       log->Printf("%s - '%s' Couldn't read %" PRIu32
2132b9c1b51eSKate Stone                   " bytes of allocation data from 0x%" PRIx64,
2133b3f7f69dSAidan Dodds                   __FUNCTION__, error.AsCString(), size, data_ptr);
213455232f09SEwan Crawford     return nullptr;
213555232f09SEwan Crawford   }
213655232f09SEwan Crawford 
213755232f09SEwan Crawford   return buffer;
213855232f09SEwan Crawford }
213955232f09SEwan Crawford 
214055232f09SEwan Crawford // Function copies data from a binary file into an allocation.
2141b9c1b51eSKate Stone // There is a header at the start of the file, FileHeader, before the data
2142b9c1b51eSKate Stone // content itself.
2143b9c1b51eSKate Stone // Information from this header is used to display warnings to the user about
2144b9c1b51eSKate Stone // incompatibilities
2145b9c1b51eSKate Stone bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id,
2146b9c1b51eSKate Stone                                          const char *filename,
2147b9c1b51eSKate Stone                                          StackFrame *frame_ptr) {
214855232f09SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
214955232f09SEwan Crawford 
215055232f09SEwan Crawford   // Find allocation with the given id
215155232f09SEwan Crawford   AllocationDetails *alloc = FindAllocByID(strm, alloc_id);
215255232f09SEwan Crawford   if (!alloc)
215355232f09SEwan Crawford     return false;
215455232f09SEwan Crawford 
215555232f09SEwan Crawford   if (log)
2156b9c1b51eSKate Stone     log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__,
2157b9c1b51eSKate Stone                 *alloc->address.get());
215855232f09SEwan Crawford 
215955232f09SEwan Crawford   // JIT all the allocation details
2160b9c1b51eSKate Stone   if (alloc->shouldRefresh()) {
216155232f09SEwan Crawford     if (log)
2162b9c1b51eSKate Stone       log->Printf("%s - allocation details not calculated yet, jitting info.",
2163b9c1b51eSKate Stone                   __FUNCTION__);
216455232f09SEwan Crawford 
2165b9c1b51eSKate Stone     if (!RefreshAllocation(alloc, frame_ptr)) {
216655232f09SEwan Crawford       if (log)
2167b3f7f69dSAidan Dodds         log->Printf("%s - couldn't JIT allocation details", __FUNCTION__);
21684cfc9198SSylvestre Ledru       return false;
216955232f09SEwan Crawford     }
217055232f09SEwan Crawford   }
217155232f09SEwan Crawford 
2172b9c1b51eSKate Stone   assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
2173b9c1b51eSKate Stone          alloc->element.type_vec_size.isValid() && alloc->size.isValid() &&
2174b9c1b51eSKate Stone          alloc->element.datum_size.isValid() &&
2175b9c1b51eSKate Stone          "Allocation information not available");
217655232f09SEwan Crawford 
217755232f09SEwan Crawford   // Check we can read from file
217855232f09SEwan Crawford   FileSpec file(filename, true);
2179b9c1b51eSKate Stone   if (!file.Exists()) {
218055232f09SEwan Crawford     strm.Printf("Error: File %s does not exist", filename);
218155232f09SEwan Crawford     strm.EOL();
218255232f09SEwan Crawford     return false;
218355232f09SEwan Crawford   }
218455232f09SEwan Crawford 
2185b9c1b51eSKate Stone   if (!file.Readable()) {
218655232f09SEwan Crawford     strm.Printf("Error: File %s does not have readable permissions", filename);
218755232f09SEwan Crawford     strm.EOL();
218855232f09SEwan Crawford     return false;
218955232f09SEwan Crawford   }
219055232f09SEwan Crawford 
219155232f09SEwan Crawford   // Read file into data buffer
219255232f09SEwan Crawford   DataBufferSP data_sp(file.ReadFileContents());
219355232f09SEwan Crawford 
219455232f09SEwan Crawford   // Cast start of buffer to FileHeader and use pointer to read metadata
219555232f09SEwan Crawford   void *file_buffer = data_sp->GetBytes();
2196b3f7f69dSAidan Dodds   if (file_buffer == nullptr ||
2197b9c1b51eSKate Stone       data_sp->GetByteSize() < (sizeof(AllocationDetails::FileHeader) +
2198b9c1b51eSKate Stone                                 sizeof(AllocationDetails::ElementHeader))) {
2199b9c1b51eSKate Stone     strm.Printf("Error: File %s does not contain enough data for header",
2200b9c1b51eSKate Stone                 filename);
220126e52a70SEwan Crawford     strm.EOL();
220226e52a70SEwan Crawford     return false;
220326e52a70SEwan Crawford   }
2204b9c1b51eSKate Stone   const AllocationDetails::FileHeader *file_header =
2205b9c1b51eSKate Stone       static_cast<AllocationDetails::FileHeader *>(file_buffer);
220655232f09SEwan Crawford 
220726e52a70SEwan Crawford   // Check file starts with ascii characters "RSAD"
2208b9c1b51eSKate Stone   if (memcmp(file_header->ident, "RSAD", 4)) {
2209b9c1b51eSKate Stone     strm.Printf("Error: File doesn't contain identifier for an RS allocation "
2210b9c1b51eSKate Stone                 "dump. Are you sure this is the correct file?");
221126e52a70SEwan Crawford     strm.EOL();
221226e52a70SEwan Crawford     return false;
221326e52a70SEwan Crawford   }
221426e52a70SEwan Crawford 
221526e52a70SEwan Crawford   // Look at the type of the root element in the header
221626e52a70SEwan Crawford   AllocationDetails::ElementHeader root_element_header;
2217b9c1b51eSKate Stone   memcpy(&root_element_header, static_cast<uint8_t *>(file_buffer) +
2218b9c1b51eSKate Stone                                    sizeof(AllocationDetails::FileHeader),
221926e52a70SEwan Crawford          sizeof(AllocationDetails::ElementHeader));
222055232f09SEwan Crawford 
222155232f09SEwan Crawford   if (log)
2222b9c1b51eSKate Stone     log->Printf("%s - header type %" PRIu32 ", element size %" PRIu32,
2223b9c1b51eSKate Stone                 __FUNCTION__, root_element_header.type,
2224b9c1b51eSKate Stone                 root_element_header.element_size);
222555232f09SEwan Crawford 
2226b9c1b51eSKate Stone   // Check if the target allocation and file both have the same number of bytes
2227b9c1b51eSKate Stone   // for an Element
2228b9c1b51eSKate Stone   if (*alloc->element.datum_size.get() != root_element_header.element_size) {
2229b9c1b51eSKate Stone     strm.Printf("Warning: Mismatched Element sizes - file %" PRIu32
2230b9c1b51eSKate Stone                 " bytes, allocation %" PRIu32 " bytes",
2231b9c1b51eSKate Stone                 root_element_header.element_size,
2232b9c1b51eSKate Stone                 *alloc->element.datum_size.get());
223355232f09SEwan Crawford     strm.EOL();
223455232f09SEwan Crawford   }
223555232f09SEwan Crawford 
223626e52a70SEwan Crawford   // Check if the target allocation and file both have the same type
2237b3f7f69dSAidan Dodds   const uint32_t alloc_type = static_cast<uint32_t>(*alloc->element.type.get());
2238b3f7f69dSAidan Dodds   const uint32_t file_type = root_element_header.type;
223926e52a70SEwan Crawford 
2240b9c1b51eSKate Stone   if (file_type > Element::RS_TYPE_FONT) {
224126e52a70SEwan Crawford     strm.Printf("Warning: File has unknown allocation type");
224226e52a70SEwan Crawford     strm.EOL();
2243b9c1b51eSKate Stone   } else if (alloc_type != file_type) {
2244b9c1b51eSKate Stone     // Enum value isn't monotonous, so doesn't always index RsDataTypeToString
2245b9c1b51eSKate Stone     // array
2246b3f7f69dSAidan Dodds     uint32_t printable_target_type_index = alloc_type;
2247b3f7f69dSAidan Dodds     uint32_t printable_head_type_index = file_type;
2248b9c1b51eSKate Stone     if (alloc_type >= Element::RS_TYPE_ELEMENT &&
2249b9c1b51eSKate Stone         alloc_type <= Element::RS_TYPE_FONT)
2250b9c1b51eSKate Stone       printable_target_type_index = static_cast<Element::DataType>(
2251b9c1b51eSKate Stone           (alloc_type - Element::RS_TYPE_ELEMENT) +
2252b3f7f69dSAidan Dodds           Element::RS_TYPE_MATRIX_2X2 + 1);
22532e920715SEwan Crawford 
2254b9c1b51eSKate Stone     if (file_type >= Element::RS_TYPE_ELEMENT &&
2255b9c1b51eSKate Stone         file_type <= Element::RS_TYPE_FONT)
2256b9c1b51eSKate Stone       printable_head_type_index = static_cast<Element::DataType>(
2257b9c1b51eSKate Stone           (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 +
2258b9c1b51eSKate Stone           1);
22592e920715SEwan Crawford 
2260b9c1b51eSKate Stone     const char *file_type_cstr =
2261b9c1b51eSKate Stone         AllocationDetails::RsDataTypeToString[printable_head_type_index][0];
2262b9c1b51eSKate Stone     const char *target_type_cstr =
2263b9c1b51eSKate Stone         AllocationDetails::RsDataTypeToString[printable_target_type_index][0];
226455232f09SEwan Crawford 
2265b9c1b51eSKate Stone     strm.Printf(
2266b9c1b51eSKate Stone         "Warning: Mismatched Types - file '%s' type, allocation '%s' type",
2267b9c1b51eSKate Stone         file_type_cstr, target_type_cstr);
226855232f09SEwan Crawford     strm.EOL();
226955232f09SEwan Crawford   }
227055232f09SEwan Crawford 
227126e52a70SEwan Crawford   // Advance buffer past header
227226e52a70SEwan Crawford   file_buffer = static_cast<uint8_t *>(file_buffer) + file_header->hdr_size;
227326e52a70SEwan Crawford 
227455232f09SEwan Crawford   // Calculate size of allocation data in file
227526e52a70SEwan Crawford   size_t length = data_sp->GetByteSize() - file_header->hdr_size;
227655232f09SEwan Crawford 
227755232f09SEwan Crawford   // Check if the target allocation and file both have the same total data size.
2278b3f7f69dSAidan Dodds   const uint32_t alloc_size = *alloc->size.get();
2279b9c1b51eSKate Stone   if (alloc_size != length) {
2280b9c1b51eSKate Stone     strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64
2281b9c1b51eSKate Stone                 " bytes, allocation 0x%" PRIx32 " bytes",
2282eba832beSJason Molenda                 (uint64_t)length, alloc_size);
228355232f09SEwan Crawford     strm.EOL();
2284b9c1b51eSKate Stone     length = alloc_size < length ? alloc_size
2285b9c1b51eSKate Stone                                  : length; // Set length to copy to minimum
228655232f09SEwan Crawford   }
228755232f09SEwan Crawford 
228855232f09SEwan Crawford   // Copy file data from our buffer into the target allocation.
228955232f09SEwan Crawford   lldb::addr_t alloc_data = *alloc->data_ptr.get();
229055232f09SEwan Crawford   Error error;
2291b9c1b51eSKate Stone   size_t bytes_written =
2292b9c1b51eSKate Stone       GetProcess()->WriteMemory(alloc_data, file_buffer, length, error);
2293b9c1b51eSKate Stone   if (!error.Success() || bytes_written != length) {
2294b9c1b51eSKate Stone     strm.Printf("Error: Couldn't write data to allocation %s",
2295b9c1b51eSKate Stone                 error.AsCString());
229655232f09SEwan Crawford     strm.EOL();
229755232f09SEwan Crawford     return false;
229855232f09SEwan Crawford   }
229955232f09SEwan Crawford 
2300b9c1b51eSKate Stone   strm.Printf("Contents of file '%s' read into allocation %" PRIu32, filename,
2301b9c1b51eSKate Stone               alloc->id);
230255232f09SEwan Crawford   strm.EOL();
230355232f09SEwan Crawford 
230455232f09SEwan Crawford   return true;
230555232f09SEwan Crawford }
230655232f09SEwan Crawford 
2307b9c1b51eSKate Stone // Function takes as parameters a byte buffer, which will eventually be written
2308b9c1b51eSKate Stone // to file as the element header,
2309b9c1b51eSKate Stone // an offset into that buffer, and an Element that will be saved into the buffer
2310b9c1b51eSKate Stone // at the parametrised offset.
231126e52a70SEwan Crawford // Return value is the new offset after writing the element into the buffer.
2312b9c1b51eSKate Stone // Elements are saved to the file as the ElementHeader struct followed by
2313b9c1b51eSKate Stone // offsets to the structs of all the element's
2314b3f7f69dSAidan Dodds // children.
2315b9c1b51eSKate Stone size_t RenderScriptRuntime::PopulateElementHeaders(
2316b9c1b51eSKate Stone     const std::shared_ptr<uint8_t> header_buffer, size_t offset,
2317b9c1b51eSKate Stone     const Element &elem) {
2318b9c1b51eSKate Stone   // File struct for an element header with all the relevant details copied from
2319b9c1b51eSKate Stone   // elem.
232026e52a70SEwan Crawford   // We assume members are valid already.
232126e52a70SEwan Crawford   AllocationDetails::ElementHeader elem_header;
232226e52a70SEwan Crawford   elem_header.type = *elem.type.get();
232326e52a70SEwan Crawford   elem_header.kind = *elem.type_kind.get();
232426e52a70SEwan Crawford   elem_header.element_size = *elem.datum_size.get();
232526e52a70SEwan Crawford   elem_header.vector_size = *elem.type_vec_size.get();
2326b9c1b51eSKate Stone   elem_header.array_size =
2327b9c1b51eSKate Stone       elem.array_size.isValid() ? *elem.array_size.get() : 0;
232826e52a70SEwan Crawford   const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader);
232926e52a70SEwan Crawford 
233026e52a70SEwan Crawford   // Copy struct into buffer and advance offset
2331b9c1b51eSKate Stone   // We assume that header_buffer has been checked for nullptr before this
2332b9c1b51eSKate Stone   // method is called
233326e52a70SEwan Crawford   memcpy(header_buffer.get() + offset, &elem_header, elem_header_size);
233426e52a70SEwan Crawford   offset += elem_header_size;
233526e52a70SEwan Crawford 
233626e52a70SEwan Crawford   // Starting offset of child ElementHeader struct
2337b9c1b51eSKate Stone   size_t child_offset =
2338b9c1b51eSKate Stone       offset + ((elem.children.size() + 1) * sizeof(uint32_t));
2339b9c1b51eSKate Stone   for (const RenderScriptRuntime::Element &child : elem.children) {
2340b9c1b51eSKate Stone     // Recursively populate the buffer with the element header structs of
2341b9c1b51eSKate Stone     // children.
2342b9c1b51eSKate Stone     // Then save the offsets where they were set after the parent element
2343b9c1b51eSKate Stone     // header.
234426e52a70SEwan Crawford     memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t));
234526e52a70SEwan Crawford     offset += sizeof(uint32_t);
234626e52a70SEwan Crawford 
234726e52a70SEwan Crawford     child_offset = PopulateElementHeaders(header_buffer, child_offset, child);
234826e52a70SEwan Crawford   }
234926e52a70SEwan Crawford 
235026e52a70SEwan Crawford   // Zero indicates no more children
235126e52a70SEwan Crawford   memset(header_buffer.get() + offset, 0, sizeof(uint32_t));
235226e52a70SEwan Crawford 
235326e52a70SEwan Crawford   return child_offset;
235426e52a70SEwan Crawford }
235526e52a70SEwan Crawford 
2356b9c1b51eSKate Stone // Given an Element object this function returns the total size needed in the
2357b9c1b51eSKate Stone // file header to store the element's
2358b3f7f69dSAidan Dodds // details.
2359b9c1b51eSKate Stone // Taking into account the size of the element header struct, plus the offsets
2360b9c1b51eSKate Stone // to all the element's children.
2361b9c1b51eSKate Stone // Function is recursive so that the size of all ancestors is taken into
2362b9c1b51eSKate Stone // account.
2363b9c1b51eSKate Stone size_t RenderScriptRuntime::CalculateElementHeaderSize(const Element &elem) {
2364b9c1b51eSKate Stone   size_t size = (elem.children.size() + 1) *
2365b9c1b51eSKate Stone                 sizeof(uint32_t); // Offsets to children plus zero terminator
2366b9c1b51eSKate Stone   size += sizeof(AllocationDetails::ElementHeader); // Size of header struct
2367b9c1b51eSKate Stone                                                     // with type details
236826e52a70SEwan Crawford 
236926e52a70SEwan Crawford   // Calculate recursively for all descendants
237026e52a70SEwan Crawford   for (const Element &child : elem.children)
237126e52a70SEwan Crawford     size += CalculateElementHeaderSize(child);
237226e52a70SEwan Crawford 
237326e52a70SEwan Crawford   return size;
237426e52a70SEwan Crawford }
237526e52a70SEwan Crawford 
237655232f09SEwan Crawford // Function copies allocation contents into a binary file.
237755232f09SEwan Crawford // This file can then be loaded later into a different allocation.
2378b9c1b51eSKate Stone // There is a header, FileHeader, before the allocation data containing
2379b9c1b51eSKate Stone // meta-data.
2380b9c1b51eSKate Stone bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id,
2381b9c1b51eSKate Stone                                          const char *filename,
2382b9c1b51eSKate Stone                                          StackFrame *frame_ptr) {
238355232f09SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
238455232f09SEwan Crawford 
238555232f09SEwan Crawford   // Find allocation with the given id
238655232f09SEwan Crawford   AllocationDetails *alloc = FindAllocByID(strm, alloc_id);
238755232f09SEwan Crawford   if (!alloc)
238855232f09SEwan Crawford     return false;
238955232f09SEwan Crawford 
239055232f09SEwan Crawford   if (log)
2391b9c1b51eSKate Stone     log->Printf("%s - found allocation 0x%" PRIx64 ".", __FUNCTION__,
2392b9c1b51eSKate Stone                 *alloc->address.get());
239355232f09SEwan Crawford 
239455232f09SEwan Crawford   // JIT all the allocation details
2395b9c1b51eSKate Stone   if (alloc->shouldRefresh()) {
239655232f09SEwan Crawford     if (log)
2397b9c1b51eSKate Stone       log->Printf("%s - allocation details not calculated yet, jitting info.",
2398b9c1b51eSKate Stone                   __FUNCTION__);
239955232f09SEwan Crawford 
2400b9c1b51eSKate Stone     if (!RefreshAllocation(alloc, frame_ptr)) {
240155232f09SEwan Crawford       if (log)
2402b3f7f69dSAidan Dodds         log->Printf("%s - couldn't JIT allocation details.", __FUNCTION__);
24034cfc9198SSylvestre Ledru       return false;
240455232f09SEwan Crawford     }
240555232f09SEwan Crawford   }
240655232f09SEwan Crawford 
2407b9c1b51eSKate Stone   assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
2408b9c1b51eSKate Stone          alloc->element.type_vec_size.isValid() &&
2409b9c1b51eSKate Stone          alloc->element.datum_size.get() &&
2410b9c1b51eSKate Stone          alloc->element.type_kind.isValid() && alloc->dimension.isValid() &&
2411b3f7f69dSAidan Dodds          "Allocation information not available");
241255232f09SEwan Crawford 
241355232f09SEwan Crawford   // Check we can create writable file
241455232f09SEwan Crawford   FileSpec file_spec(filename, true);
2415b9c1b51eSKate Stone   File file(file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate |
2416b9c1b51eSKate Stone                            File::eOpenOptionTruncate);
2417b9c1b51eSKate Stone   if (!file) {
241855232f09SEwan Crawford     strm.Printf("Error: Failed to open '%s' for writing", filename);
241955232f09SEwan Crawford     strm.EOL();
242055232f09SEwan Crawford     return false;
242155232f09SEwan Crawford   }
242255232f09SEwan Crawford 
242355232f09SEwan Crawford   // Read allocation into buffer of heap memory
242455232f09SEwan Crawford   const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
2425b9c1b51eSKate Stone   if (!buffer) {
242655232f09SEwan Crawford     strm.Printf("Error: Couldn't read allocation data into buffer");
242755232f09SEwan Crawford     strm.EOL();
242855232f09SEwan Crawford     return false;
242955232f09SEwan Crawford   }
243055232f09SEwan Crawford 
243155232f09SEwan Crawford   // Create the file header
243255232f09SEwan Crawford   AllocationDetails::FileHeader head;
2433b3f7f69dSAidan Dodds   memcpy(head.ident, "RSAD", 4);
24342d62328aSEwan Crawford   head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1);
24352d62328aSEwan Crawford   head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2);
24362d62328aSEwan Crawford   head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3);
243726e52a70SEwan Crawford 
243826e52a70SEwan Crawford   const size_t element_header_size = CalculateElementHeaderSize(alloc->element);
2439b9c1b51eSKate Stone   assert((sizeof(AllocationDetails::FileHeader) + element_header_size) <
2440b9c1b51eSKate Stone              UINT16_MAX &&
2441b9c1b51eSKate Stone          "Element header too large");
2442b9c1b51eSKate Stone   head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) +
2443b9c1b51eSKate Stone                                         element_header_size);
244455232f09SEwan Crawford 
244555232f09SEwan Crawford   // Write the file header
244655232f09SEwan Crawford   size_t num_bytes = sizeof(AllocationDetails::FileHeader);
244726e52a70SEwan Crawford   if (log)
2448b9c1b51eSKate Stone     log->Printf("%s - writing File Header, 0x%" PRIx64 " bytes", __FUNCTION__,
2449b9c1b51eSKate Stone                 (uint64_t)num_bytes);
245026e52a70SEwan Crawford 
245126e52a70SEwan Crawford   Error err = file.Write(&head, num_bytes);
2452b9c1b51eSKate Stone   if (!err.Success()) {
2453b9c1b51eSKate Stone     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(),
2454b9c1b51eSKate Stone                 filename);
245526e52a70SEwan Crawford     strm.EOL();
245626e52a70SEwan Crawford     return false;
245726e52a70SEwan Crawford   }
245826e52a70SEwan Crawford 
245926e52a70SEwan Crawford   // Create the headers describing the element type of the allocation.
2460b9c1b51eSKate Stone   std::shared_ptr<uint8_t> element_header_buffer(
2461b9c1b51eSKate Stone       new uint8_t[element_header_size]);
2462b9c1b51eSKate Stone   if (element_header_buffer == nullptr) {
2463b9c1b51eSKate Stone     strm.Printf("Internal Error: Couldn't allocate %" PRIu64
2464b9c1b51eSKate Stone                 " bytes on the heap",
2465b9c1b51eSKate Stone                 (uint64_t)element_header_size);
246626e52a70SEwan Crawford     strm.EOL();
246726e52a70SEwan Crawford     return false;
246826e52a70SEwan Crawford   }
246926e52a70SEwan Crawford 
247026e52a70SEwan Crawford   PopulateElementHeaders(element_header_buffer, 0, alloc->element);
247126e52a70SEwan Crawford 
247226e52a70SEwan Crawford   // Write headers for allocation element type to file
247326e52a70SEwan Crawford   num_bytes = element_header_size;
247426e52a70SEwan Crawford   if (log)
2475b9c1b51eSKate Stone     log->Printf("%s - writing element headers, 0x%" PRIx64 " bytes.",
2476b9c1b51eSKate Stone                 __FUNCTION__, (uint64_t)num_bytes);
247726e52a70SEwan Crawford 
247826e52a70SEwan Crawford   err = file.Write(element_header_buffer.get(), num_bytes);
2479b9c1b51eSKate Stone   if (!err.Success()) {
2480b9c1b51eSKate Stone     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(),
2481b9c1b51eSKate Stone                 filename);
248255232f09SEwan Crawford     strm.EOL();
248355232f09SEwan Crawford     return false;
248455232f09SEwan Crawford   }
248555232f09SEwan Crawford 
248655232f09SEwan Crawford   // Write allocation data to file
248755232f09SEwan Crawford   num_bytes = static_cast<size_t>(*alloc->size.get());
248855232f09SEwan Crawford   if (log)
2489b9c1b51eSKate Stone     log->Printf("%s - writing 0x%" PRIx64 " bytes", __FUNCTION__,
2490b9c1b51eSKate Stone                 (uint64_t)num_bytes);
249155232f09SEwan Crawford 
249255232f09SEwan Crawford   err = file.Write(buffer.get(), num_bytes);
2493b9c1b51eSKate Stone   if (!err.Success()) {
2494b9c1b51eSKate Stone     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(),
2495b9c1b51eSKate Stone                 filename);
249655232f09SEwan Crawford     strm.EOL();
249755232f09SEwan Crawford     return false;
249855232f09SEwan Crawford   }
249955232f09SEwan Crawford 
250055232f09SEwan Crawford   strm.Printf("Allocation written to file '%s'", filename);
250155232f09SEwan Crawford   strm.EOL();
250215f2bd95SEwan Crawford   return true;
250315f2bd95SEwan Crawford }
250415f2bd95SEwan Crawford 
2505b9c1b51eSKate Stone bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) {
25064640cde1SColin Riley   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
25074640cde1SColin Riley 
2508b9c1b51eSKate Stone   if (module_sp) {
2509b9c1b51eSKate Stone     for (const auto &rs_module : m_rsmodules) {
2510b9c1b51eSKate Stone       if (rs_module->m_module == module_sp) {
25117dc7771cSEwan Crawford         // Check if the user has enabled automatically breaking on
25127dc7771cSEwan Crawford         // all RS kernels.
25137dc7771cSEwan Crawford         if (m_breakAllKernels)
25147dc7771cSEwan Crawford           BreakOnModuleKernels(rs_module);
25157dc7771cSEwan Crawford 
25165ec532a9SColin Riley         return false;
25175ec532a9SColin Riley       }
25187dc7771cSEwan Crawford     }
2519ef20b08fSColin Riley     bool module_loaded = false;
2520b9c1b51eSKate Stone     switch (GetModuleKind(module_sp)) {
2521b9c1b51eSKate Stone     case eModuleKindKernelObj: {
25224640cde1SColin Riley       RSModuleDescriptorSP module_desc;
25234640cde1SColin Riley       module_desc.reset(new RSModuleDescriptor(module_sp));
2524b9c1b51eSKate Stone       if (module_desc->ParseRSInfo()) {
25255ec532a9SColin Riley         m_rsmodules.push_back(module_desc);
2526ef20b08fSColin Riley         module_loaded = true;
25275ec532a9SColin Riley       }
2528b9c1b51eSKate Stone       if (module_loaded) {
25294640cde1SColin Riley         FixupScriptDetails(module_desc);
25304640cde1SColin Riley       }
2531ef20b08fSColin Riley       break;
2532ef20b08fSColin Riley     }
2533b9c1b51eSKate Stone     case eModuleKindDriver: {
2534b9c1b51eSKate Stone       if (!m_libRSDriver) {
25354640cde1SColin Riley         m_libRSDriver = module_sp;
25364640cde1SColin Riley         LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver);
25374640cde1SColin Riley       }
25384640cde1SColin Riley       break;
25394640cde1SColin Riley     }
2540b9c1b51eSKate Stone     case eModuleKindImpl: {
25414640cde1SColin Riley       m_libRSCpuRef = module_sp;
25424640cde1SColin Riley       break;
25434640cde1SColin Riley     }
2544b9c1b51eSKate Stone     case eModuleKindLibRS: {
2545b9c1b51eSKate Stone       if (!m_libRS) {
25464640cde1SColin Riley         m_libRS = module_sp;
25474640cde1SColin Riley         static ConstString gDbgPresentStr("gDebuggerPresent");
2548b9c1b51eSKate Stone         const Symbol *debug_present = m_libRS->FindFirstSymbolWithNameAndType(
2549b9c1b51eSKate Stone             gDbgPresentStr, eSymbolTypeData);
2550b9c1b51eSKate Stone         if (debug_present) {
25514640cde1SColin Riley           Error error;
25524640cde1SColin Riley           uint32_t flag = 0x00000001U;
25534640cde1SColin Riley           Target &target = GetProcess()->GetTarget();
2554358cf1eaSGreg Clayton           addr_t addr = debug_present->GetLoadAddress(&target);
25554640cde1SColin Riley           GetProcess()->WriteMemory(addr, &flag, sizeof(flag), error);
2556b9c1b51eSKate Stone           if (error.Success()) {
25574640cde1SColin Riley             if (log)
2558b9c1b51eSKate Stone               log->Printf("%s - debugger present flag set on debugee.",
2559b9c1b51eSKate Stone                           __FUNCTION__);
25604640cde1SColin Riley 
25614640cde1SColin Riley             m_debuggerPresentFlagged = true;
2562b9c1b51eSKate Stone           } else if (log) {
2563b9c1b51eSKate Stone             log->Printf("%s - error writing debugger present flags '%s' ",
2564b9c1b51eSKate Stone                         __FUNCTION__, error.AsCString());
25654640cde1SColin Riley           }
2566b9c1b51eSKate Stone         } else if (log) {
2567b9c1b51eSKate Stone           log->Printf(
2568b9c1b51eSKate Stone               "%s - error writing debugger present flags - symbol not found",
2569b9c1b51eSKate Stone               __FUNCTION__);
25704640cde1SColin Riley         }
25714640cde1SColin Riley       }
25724640cde1SColin Riley       break;
25734640cde1SColin Riley     }
2574ef20b08fSColin Riley     default:
2575ef20b08fSColin Riley       break;
2576ef20b08fSColin Riley     }
2577ef20b08fSColin Riley     if (module_loaded)
2578ef20b08fSColin Riley       Update();
2579ef20b08fSColin Riley     return module_loaded;
25805ec532a9SColin Riley   }
25815ec532a9SColin Riley   return false;
25825ec532a9SColin Riley }
25835ec532a9SColin Riley 
2584b9c1b51eSKate Stone void RenderScriptRuntime::Update() {
2585b9c1b51eSKate Stone   if (m_rsmodules.size() > 0) {
2586b9c1b51eSKate Stone     if (!m_initiated) {
2587ef20b08fSColin Riley       Initiate();
2588ef20b08fSColin Riley     }
2589ef20b08fSColin Riley   }
2590ef20b08fSColin Riley }
2591ef20b08fSColin Riley 
2592*7f193d69SLuke Drummond bool RSModuleDescriptor::ParsePragmaCount(llvm::StringRef *lines,
2593*7f193d69SLuke Drummond                                           size_t n_lines) {
2594*7f193d69SLuke Drummond   // Skip the pragma prototype line
2595*7f193d69SLuke Drummond   ++lines;
2596*7f193d69SLuke Drummond   for (; n_lines--; ++lines) {
2597*7f193d69SLuke Drummond     const auto kv_pair = lines->split(" - ");
2598*7f193d69SLuke Drummond     m_pragmas[kv_pair.first.trim().str()] = kv_pair.second.trim().str();
2599*7f193d69SLuke Drummond   }
2600*7f193d69SLuke Drummond   return true;
2601*7f193d69SLuke Drummond }
2602*7f193d69SLuke Drummond 
2603*7f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportReduceCount(llvm::StringRef *lines,
2604*7f193d69SLuke Drummond                                                 size_t n_lines) {
2605*7f193d69SLuke Drummond   // The list of reduction kernels in the `.rs.info` symbol is of the form
2606*7f193d69SLuke Drummond   // "signature - accumulatordatasize - reduction_name - initializer_name -
2607*7f193d69SLuke Drummond   // accumulator_name - combiner_name -
2608*7f193d69SLuke Drummond   // outconverter_name - halter_name"
2609*7f193d69SLuke Drummond   // Where a function is not explicitly named by the user, or is not generated
2610*7f193d69SLuke Drummond   // by the compiler, it is named "." so the
2611*7f193d69SLuke Drummond   // dash separated list should always be 8 items long
2612*7f193d69SLuke Drummond   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
2613*7f193d69SLuke Drummond   // Skip the exportReduceCount line
2614*7f193d69SLuke Drummond   ++lines;
2615*7f193d69SLuke Drummond   for (; n_lines--; ++lines) {
2616*7f193d69SLuke Drummond     llvm::SmallVector<llvm::StringRef, 8> spec;
2617*7f193d69SLuke Drummond     lines->split(spec, " - ");
2618*7f193d69SLuke Drummond     if (spec.size() != 8) {
2619*7f193d69SLuke Drummond       if (spec.size() < 8) {
2620*7f193d69SLuke Drummond         if (log)
2621*7f193d69SLuke Drummond           log->Error("Error parsing RenderScript reduction spec. wrong number "
2622*7f193d69SLuke Drummond                      "of fields");
2623*7f193d69SLuke Drummond         return false;
2624*7f193d69SLuke Drummond       } else if (log)
2625*7f193d69SLuke Drummond         log->Warning("Extraneous members in reduction spec: '%s'",
2626*7f193d69SLuke Drummond                      lines->str().c_str());
2627*7f193d69SLuke Drummond     }
2628*7f193d69SLuke Drummond 
2629*7f193d69SLuke Drummond     const auto sig_s = spec[0];
2630*7f193d69SLuke Drummond     uint32_t sig;
2631*7f193d69SLuke Drummond     if (sig_s.getAsInteger(10, sig)) {
2632*7f193d69SLuke Drummond       if (log)
2633*7f193d69SLuke Drummond         log->Error("Error parsing Renderscript reduction spec: invalid kernel "
2634*7f193d69SLuke Drummond                    "signature: '%s'",
2635*7f193d69SLuke Drummond                    sig_s.str().c_str());
2636*7f193d69SLuke Drummond       return false;
2637*7f193d69SLuke Drummond     }
2638*7f193d69SLuke Drummond 
2639*7f193d69SLuke Drummond     const auto accum_data_size_s = spec[1];
2640*7f193d69SLuke Drummond     uint32_t accum_data_size;
2641*7f193d69SLuke Drummond     if (accum_data_size_s.getAsInteger(10, accum_data_size)) {
2642*7f193d69SLuke Drummond       if (log)
2643*7f193d69SLuke Drummond         log->Error("Error parsing Renderscript reduction spec: invalid "
2644*7f193d69SLuke Drummond                    "accumulator data size %s",
2645*7f193d69SLuke Drummond                    accum_data_size_s.str().c_str());
2646*7f193d69SLuke Drummond       return false;
2647*7f193d69SLuke Drummond     }
2648*7f193d69SLuke Drummond 
2649*7f193d69SLuke Drummond     if (log)
2650*7f193d69SLuke Drummond       log->Printf("Found RenderScript reduction '%s'", spec[2].str().c_str());
2651*7f193d69SLuke Drummond 
2652*7f193d69SLuke Drummond     m_reductions.push_back(RSReductionDescriptor(this, sig, accum_data_size,
2653*7f193d69SLuke Drummond                                                  spec[2], spec[3], spec[4],
2654*7f193d69SLuke Drummond                                                  spec[5], spec[6], spec[7]));
2655*7f193d69SLuke Drummond   }
2656*7f193d69SLuke Drummond   return true;
2657*7f193d69SLuke Drummond }
2658*7f193d69SLuke Drummond 
2659*7f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportForeachCount(llvm::StringRef *lines,
2660*7f193d69SLuke Drummond                                                  size_t n_lines) {
2661*7f193d69SLuke Drummond   // Skip the exportForeachCount line
2662*7f193d69SLuke Drummond   ++lines;
2663*7f193d69SLuke Drummond   for (; n_lines--; ++lines) {
2664*7f193d69SLuke Drummond     uint32_t slot;
2665*7f193d69SLuke Drummond     // `forEach` kernels are listed in the `.rs.info` packet as a "slot - name"
2666*7f193d69SLuke Drummond     // pair per line
2667*7f193d69SLuke Drummond     const auto kv_pair = lines->split(" - ");
2668*7f193d69SLuke Drummond     if (kv_pair.first.getAsInteger(10, slot))
2669*7f193d69SLuke Drummond       return false;
2670*7f193d69SLuke Drummond     m_kernels.push_back(RSKernelDescriptor(this, kv_pair.second, slot));
2671*7f193d69SLuke Drummond   }
2672*7f193d69SLuke Drummond   return true;
2673*7f193d69SLuke Drummond }
2674*7f193d69SLuke Drummond 
2675*7f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportVarCount(llvm::StringRef *lines,
2676*7f193d69SLuke Drummond                                              size_t n_lines) {
2677*7f193d69SLuke Drummond   // Skip the ExportVarCount line
2678*7f193d69SLuke Drummond   ++lines;
2679*7f193d69SLuke Drummond   for (; n_lines--; ++lines)
2680*7f193d69SLuke Drummond     m_globals.push_back(RSGlobalDescriptor(this, *lines));
2681*7f193d69SLuke Drummond   return true;
2682*7f193d69SLuke Drummond }
26835ec532a9SColin Riley 
2684b9c1b51eSKate Stone // The .rs.info symbol in renderscript modules contains a string which needs to
2685b9c1b51eSKate Stone // be parsed.
26865ec532a9SColin Riley // The string is basic and is parsed on a line by line basis.
2687b9c1b51eSKate Stone bool RSModuleDescriptor::ParseRSInfo() {
2688b0be30f7SAidan Dodds   assert(m_module);
2689*7f193d69SLuke Drummond   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2690b9c1b51eSKate Stone   const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType(
2691b9c1b51eSKate Stone       ConstString(".rs.info"), eSymbolTypeData);
2692b0be30f7SAidan Dodds   if (!info_sym)
2693b0be30f7SAidan Dodds     return false;
2694b0be30f7SAidan Dodds 
2695358cf1eaSGreg Clayton   const addr_t addr = info_sym->GetAddressRef().GetFileAddress();
2696b0be30f7SAidan Dodds   if (addr == LLDB_INVALID_ADDRESS)
2697b0be30f7SAidan Dodds     return false;
2698b0be30f7SAidan Dodds 
26995ec532a9SColin Riley   const addr_t size = info_sym->GetByteSize();
27005ec532a9SColin Riley   const FileSpec fs = m_module->GetFileSpec();
27015ec532a9SColin Riley 
2702b0be30f7SAidan Dodds   const DataBufferSP buffer = fs.ReadFileContents(addr, size);
27035ec532a9SColin Riley   if (!buffer)
27045ec532a9SColin Riley     return false;
27055ec532a9SColin Riley 
2706b0be30f7SAidan Dodds   // split rs.info. contents into lines
2707*7f193d69SLuke Drummond   llvm::SmallVector<llvm::StringRef, 128> info_lines;
27085ec532a9SColin Riley   {
2709*7f193d69SLuke Drummond     const llvm::StringRef raw_rs_info((const char *)buffer->GetBytes());
2710*7f193d69SLuke Drummond     raw_rs_info.split(info_lines, '\n');
2711*7f193d69SLuke Drummond     if (log)
2712*7f193d69SLuke Drummond       log->Printf("'.rs.info symbol for '%s':\n%s",
2713*7f193d69SLuke Drummond                   m_module->GetFileSpec().GetCString(),
2714*7f193d69SLuke Drummond                   raw_rs_info.str().c_str());
2715b0be30f7SAidan Dodds   }
2716b0be30f7SAidan Dodds 
2717*7f193d69SLuke Drummond   enum {
2718*7f193d69SLuke Drummond     eExportVar,
2719*7f193d69SLuke Drummond     eExportForEach,
2720*7f193d69SLuke Drummond     eExportReduce,
2721*7f193d69SLuke Drummond     ePragma,
2722*7f193d69SLuke Drummond     eBuildChecksum,
2723*7f193d69SLuke Drummond     eObjectSlot
2724*7f193d69SLuke Drummond   };
2725*7f193d69SLuke Drummond 
2726*7f193d69SLuke Drummond   static const llvm::StringMap<int> rs_info_handlers{
2727*7f193d69SLuke Drummond       {// The number of visible global variables in the script
2728*7f193d69SLuke Drummond        {"exportVarCount", eExportVar},
2729*7f193d69SLuke Drummond        // The number of RenderScrip `forEach` kernels __attribute__((kernel))
2730*7f193d69SLuke Drummond        {"exportForEachCount", eExportForEach},
2731*7f193d69SLuke Drummond        // The number of generalreductions: This marked in the script by `#pragma
2732*7f193d69SLuke Drummond        // reduce()`
2733*7f193d69SLuke Drummond        {"exportReduceCount", eExportReduce},
2734*7f193d69SLuke Drummond        // Total count of all RenderScript specific `#pragmas` used in the script
2735*7f193d69SLuke Drummond        {"pragmaCount", ePragma},
2736*7f193d69SLuke Drummond        {"objectSlotCount", eObjectSlot}}};
2737b0be30f7SAidan Dodds 
2738b0be30f7SAidan Dodds   // parse all text lines of .rs.info
2739b9c1b51eSKate Stone   for (auto line = info_lines.begin(); line != info_lines.end(); ++line) {
2740*7f193d69SLuke Drummond     const auto kv_pair = line->split(": ");
2741*7f193d69SLuke Drummond     const auto key = kv_pair.first;
2742*7f193d69SLuke Drummond     const auto val = kv_pair.second.trim();
27435ec532a9SColin Riley 
2744*7f193d69SLuke Drummond     const auto handler = rs_info_handlers.find(key);
2745*7f193d69SLuke Drummond     if (handler == rs_info_handlers.end())
2746*7f193d69SLuke Drummond       continue;
2747*7f193d69SLuke Drummond     // getAsInteger returns `true` on an error condition - we're only interested
2748*7f193d69SLuke Drummond     // in
2749*7f193d69SLuke Drummond     // numeric fields at the moment
2750*7f193d69SLuke Drummond     uint64_t n_lines;
2751*7f193d69SLuke Drummond     if (val.getAsInteger(10, n_lines)) {
2752*7f193d69SLuke Drummond       if (log)
2753*7f193d69SLuke Drummond         log->Debug("Failed to parse non-numeric '.rs.info' section %s",
2754*7f193d69SLuke Drummond                    line->str().c_str());
2755*7f193d69SLuke Drummond       continue;
2756*7f193d69SLuke Drummond     }
2757*7f193d69SLuke Drummond     if (info_lines.end() - (line + 1) < (ptrdiff_t)n_lines)
2758*7f193d69SLuke Drummond       return false;
2759*7f193d69SLuke Drummond 
2760*7f193d69SLuke Drummond     bool success = false;
2761*7f193d69SLuke Drummond     switch (handler->getValue()) {
2762*7f193d69SLuke Drummond     case eExportVar:
2763*7f193d69SLuke Drummond       success = ParseExportVarCount(line, n_lines);
2764*7f193d69SLuke Drummond       break;
2765*7f193d69SLuke Drummond     case eExportForEach:
2766*7f193d69SLuke Drummond       success = ParseExportForeachCount(line, n_lines);
2767*7f193d69SLuke Drummond       break;
2768*7f193d69SLuke Drummond     case eExportReduce:
2769*7f193d69SLuke Drummond       success = ParseExportReduceCount(line, n_lines);
2770*7f193d69SLuke Drummond       break;
2771*7f193d69SLuke Drummond     case ePragma:
2772*7f193d69SLuke Drummond       success = ParsePragmaCount(line, n_lines);
2773*7f193d69SLuke Drummond       break;
2774*7f193d69SLuke Drummond     default: {
2775*7f193d69SLuke Drummond       if (log)
2776*7f193d69SLuke Drummond         log->Printf("%s - skipping .rs.info field '%s'", __FUNCTION__,
2777*7f193d69SLuke Drummond                     line->str().c_str());
2778*7f193d69SLuke Drummond       continue;
2779*7f193d69SLuke Drummond     }
2780*7f193d69SLuke Drummond     }
2781*7f193d69SLuke Drummond     if (!success)
2782*7f193d69SLuke Drummond       return false;
2783*7f193d69SLuke Drummond     line += n_lines;
2784*7f193d69SLuke Drummond   }
2785*7f193d69SLuke Drummond   return info_lines.size() > 0;
27865ec532a9SColin Riley }
27875ec532a9SColin Riley 
2788b9c1b51eSKate Stone void RenderScriptRuntime::Status(Stream &strm) const {
2789b9c1b51eSKate Stone   if (m_libRS) {
27904640cde1SColin Riley     strm.Printf("Runtime Library discovered.");
27914640cde1SColin Riley     strm.EOL();
27924640cde1SColin Riley   }
2793b9c1b51eSKate Stone   if (m_libRSDriver) {
27944640cde1SColin Riley     strm.Printf("Runtime Driver discovered.");
27954640cde1SColin Riley     strm.EOL();
27964640cde1SColin Riley   }
2797b9c1b51eSKate Stone   if (m_libRSCpuRef) {
27984640cde1SColin Riley     strm.Printf("CPU Reference Implementation discovered.");
27994640cde1SColin Riley     strm.EOL();
28004640cde1SColin Riley   }
28014640cde1SColin Riley 
2802b9c1b51eSKate Stone   if (m_runtimeHooks.size()) {
28034640cde1SColin Riley     strm.Printf("Runtime functions hooked:");
28044640cde1SColin Riley     strm.EOL();
2805b9c1b51eSKate Stone     for (auto b : m_runtimeHooks) {
28064640cde1SColin Riley       strm.Indent(b.second->defn->name);
28074640cde1SColin Riley       strm.EOL();
28084640cde1SColin Riley     }
2809b9c1b51eSKate Stone   } else {
28104640cde1SColin Riley     strm.Printf("Runtime is not hooked.");
28114640cde1SColin Riley     strm.EOL();
28124640cde1SColin Riley   }
28134640cde1SColin Riley }
28144640cde1SColin Riley 
2815b9c1b51eSKate Stone void RenderScriptRuntime::DumpContexts(Stream &strm) const {
28164640cde1SColin Riley   strm.Printf("Inferred RenderScript Contexts:");
28174640cde1SColin Riley   strm.EOL();
28184640cde1SColin Riley   strm.IndentMore();
28194640cde1SColin Riley 
28204640cde1SColin Riley   std::map<addr_t, uint64_t> contextReferences;
28214640cde1SColin Riley 
282278f339d1SEwan Crawford   // Iterate over all of the currently discovered scripts.
2823b9c1b51eSKate Stone   // Note: We cant push or pop from m_scripts inside this loop or it may
2824b9c1b51eSKate Stone   // invalidate script.
2825b9c1b51eSKate Stone   for (const auto &script : m_scripts) {
282678f339d1SEwan Crawford     if (!script->context.isValid())
282778f339d1SEwan Crawford       continue;
282878f339d1SEwan Crawford     lldb::addr_t context = *script->context;
282978f339d1SEwan Crawford 
2830b9c1b51eSKate Stone     if (contextReferences.find(context) != contextReferences.end()) {
283178f339d1SEwan Crawford       contextReferences[context]++;
2832b9c1b51eSKate Stone     } else {
283378f339d1SEwan Crawford       contextReferences[context] = 1;
28344640cde1SColin Riley     }
28354640cde1SColin Riley   }
28364640cde1SColin Riley 
2837b9c1b51eSKate Stone   for (const auto &cRef : contextReferences) {
2838b9c1b51eSKate Stone     strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances",
2839b9c1b51eSKate Stone                 cRef.first, cRef.second);
28404640cde1SColin Riley     strm.EOL();
28414640cde1SColin Riley   }
28424640cde1SColin Riley   strm.IndentLess();
28434640cde1SColin Riley }
28444640cde1SColin Riley 
2845b9c1b51eSKate Stone void RenderScriptRuntime::DumpKernels(Stream &strm) const {
28464640cde1SColin Riley   strm.Printf("RenderScript Kernels:");
28474640cde1SColin Riley   strm.EOL();
28484640cde1SColin Riley   strm.IndentMore();
2849b9c1b51eSKate Stone   for (const auto &module : m_rsmodules) {
28504640cde1SColin Riley     strm.Printf("Resource '%s':", module->m_resname.c_str());
28514640cde1SColin Riley     strm.EOL();
2852b9c1b51eSKate Stone     for (const auto &kernel : module->m_kernels) {
28534640cde1SColin Riley       strm.Indent(kernel.m_name.AsCString());
28544640cde1SColin Riley       strm.EOL();
28554640cde1SColin Riley     }
28564640cde1SColin Riley   }
28574640cde1SColin Riley   strm.IndentLess();
28584640cde1SColin Riley }
28594640cde1SColin Riley 
2860a0f08674SEwan Crawford RenderScriptRuntime::AllocationDetails *
2861b9c1b51eSKate Stone RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) {
2862a0f08674SEwan Crawford   AllocationDetails *alloc = nullptr;
2863a0f08674SEwan Crawford 
2864a0f08674SEwan Crawford   // See if we can find allocation using id as an index;
2865b9c1b51eSKate Stone   if (alloc_id <= m_allocations.size() && alloc_id != 0 &&
2866b9c1b51eSKate Stone       m_allocations[alloc_id - 1]->id == alloc_id) {
2867a0f08674SEwan Crawford     alloc = m_allocations[alloc_id - 1].get();
2868a0f08674SEwan Crawford     return alloc;
2869a0f08674SEwan Crawford   }
2870a0f08674SEwan Crawford 
2871a0f08674SEwan Crawford   // Fallback to searching
2872b9c1b51eSKate Stone   for (const auto &a : m_allocations) {
2873b9c1b51eSKate Stone     if (a->id == alloc_id) {
2874a0f08674SEwan Crawford       alloc = a.get();
2875a0f08674SEwan Crawford       break;
2876a0f08674SEwan Crawford     }
2877a0f08674SEwan Crawford   }
2878a0f08674SEwan Crawford 
2879b9c1b51eSKate Stone   if (alloc == nullptr) {
2880b9c1b51eSKate Stone     strm.Printf("Error: Couldn't find allocation with id matching %" PRIu32,
2881b9c1b51eSKate Stone                 alloc_id);
2882a0f08674SEwan Crawford     strm.EOL();
2883a0f08674SEwan Crawford   }
2884a0f08674SEwan Crawford 
2885a0f08674SEwan Crawford   return alloc;
2886a0f08674SEwan Crawford }
2887a0f08674SEwan Crawford 
2888b9c1b51eSKate Stone // Prints the contents of an allocation to the output stream, which may be a
2889b9c1b51eSKate Stone // file
2890b9c1b51eSKate Stone bool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr,
2891b9c1b51eSKate Stone                                          const uint32_t id) {
2892a0f08674SEwan Crawford   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2893a0f08674SEwan Crawford 
2894a0f08674SEwan Crawford   // Check we can find the desired allocation
2895a0f08674SEwan Crawford   AllocationDetails *alloc = FindAllocByID(strm, id);
2896a0f08674SEwan Crawford   if (!alloc)
2897a0f08674SEwan Crawford     return false; // FindAllocByID() will print error message for us here
2898a0f08674SEwan Crawford 
2899a0f08674SEwan Crawford   if (log)
2900b9c1b51eSKate Stone     log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__,
2901b9c1b51eSKate Stone                 *alloc->address.get());
2902a0f08674SEwan Crawford 
2903a0f08674SEwan Crawford   // Check we have information about the allocation, if not calculate it
2904b9c1b51eSKate Stone   if (alloc->shouldRefresh()) {
2905a0f08674SEwan Crawford     if (log)
2906b9c1b51eSKate Stone       log->Printf("%s - allocation details not calculated yet, jitting info.",
2907b9c1b51eSKate Stone                   __FUNCTION__);
2908a0f08674SEwan Crawford 
2909a0f08674SEwan Crawford     // JIT all the allocation information
2910b9c1b51eSKate Stone     if (!RefreshAllocation(alloc, frame_ptr)) {
2911a0f08674SEwan Crawford       strm.Printf("Error: Couldn't JIT allocation details");
2912a0f08674SEwan Crawford       strm.EOL();
2913a0f08674SEwan Crawford       return false;
2914a0f08674SEwan Crawford     }
2915a0f08674SEwan Crawford   }
2916a0f08674SEwan Crawford 
2917a0f08674SEwan Crawford   // Establish format and size of each data element
2918b3f7f69dSAidan Dodds   const uint32_t vec_size = *alloc->element.type_vec_size.get();
29198b244e21SEwan Crawford   const Element::DataType type = *alloc->element.type.get();
2920a0f08674SEwan Crawford 
2921b9c1b51eSKate Stone   assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT &&
2922b9c1b51eSKate Stone          "Invalid allocation type");
2923a0f08674SEwan Crawford 
29242e920715SEwan Crawford   lldb::Format format;
29252e920715SEwan Crawford   if (type >= Element::RS_TYPE_ELEMENT)
29262e920715SEwan Crawford     format = eFormatHex;
29272e920715SEwan Crawford   else
2928b9c1b51eSKate Stone     format = vec_size == 1
2929b9c1b51eSKate Stone                  ? static_cast<lldb::Format>(
2930b9c1b51eSKate Stone                        AllocationDetails::RSTypeToFormat[type][eFormatSingle])
2931b9c1b51eSKate Stone                  : static_cast<lldb::Format>(
2932b9c1b51eSKate Stone                        AllocationDetails::RSTypeToFormat[type][eFormatVector]);
2933a0f08674SEwan Crawford 
2934b3f7f69dSAidan Dodds   const uint32_t data_size = *alloc->element.datum_size.get();
2935a0f08674SEwan Crawford 
2936a0f08674SEwan Crawford   if (log)
2937b9c1b51eSKate Stone     log->Printf("%s - element size %" PRIu32 " bytes, including padding",
2938b9c1b51eSKate Stone                 __FUNCTION__, data_size);
2939a0f08674SEwan Crawford 
294055232f09SEwan Crawford   // Allocate a buffer to copy data into
294155232f09SEwan Crawford   std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
2942b9c1b51eSKate Stone   if (!buffer) {
29432e920715SEwan Crawford     strm.Printf("Error: Couldn't read allocation data");
294455232f09SEwan Crawford     strm.EOL();
294555232f09SEwan Crawford     return false;
294655232f09SEwan Crawford   }
294755232f09SEwan Crawford 
2948a0f08674SEwan Crawford   // Calculate stride between rows as there may be padding at end of rows since
2949a0f08674SEwan Crawford   // allocated memory is 16-byte aligned
2950b9c1b51eSKate Stone   if (!alloc->stride.isValid()) {
2951a0f08674SEwan Crawford     if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension
2952a0f08674SEwan Crawford       alloc->stride = 0;
2953b9c1b51eSKate Stone     else if (!JITAllocationStride(alloc, frame_ptr)) {
2954a0f08674SEwan Crawford       strm.Printf("Error: Couldn't calculate allocation row stride");
2955a0f08674SEwan Crawford       strm.EOL();
2956a0f08674SEwan Crawford       return false;
2957a0f08674SEwan Crawford     }
2958a0f08674SEwan Crawford   }
2959b3f7f69dSAidan Dodds   const uint32_t stride = *alloc->stride.get();
2960b3f7f69dSAidan Dodds   const uint32_t size = *alloc->size.get(); // Size of whole allocation
2961b9c1b51eSKate Stone   const uint32_t padding =
2962b9c1b51eSKate Stone       alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0;
2963a0f08674SEwan Crawford   if (log)
2964b9c1b51eSKate Stone     log->Printf("%s - stride %" PRIu32 " bytes, size %" PRIu32
2965b9c1b51eSKate Stone                 " bytes, padding %" PRIu32,
2966b3f7f69dSAidan Dodds                 __FUNCTION__, stride, size, padding);
2967a0f08674SEwan Crawford 
2968a0f08674SEwan Crawford   // Find dimensions used to index loops, so need to be non-zero
2969b3f7f69dSAidan Dodds   uint32_t dim_x = alloc->dimension.get()->dim_1;
2970a0f08674SEwan Crawford   dim_x = dim_x == 0 ? 1 : dim_x;
2971a0f08674SEwan Crawford 
2972b3f7f69dSAidan Dodds   uint32_t dim_y = alloc->dimension.get()->dim_2;
2973a0f08674SEwan Crawford   dim_y = dim_y == 0 ? 1 : dim_y;
2974a0f08674SEwan Crawford 
2975b3f7f69dSAidan Dodds   uint32_t dim_z = alloc->dimension.get()->dim_3;
2976a0f08674SEwan Crawford   dim_z = dim_z == 0 ? 1 : dim_z;
2977a0f08674SEwan Crawford 
297855232f09SEwan Crawford   // Use data extractor to format output
2979b9c1b51eSKate Stone   const uint32_t archByteSize =
2980b9c1b51eSKate Stone       GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
2981b9c1b51eSKate Stone   DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(),
2982b9c1b51eSKate Stone                            archByteSize);
298355232f09SEwan Crawford 
2984b3f7f69dSAidan Dodds   uint32_t offset = 0;   // Offset in buffer to next element to be printed
2985b3f7f69dSAidan Dodds   uint32_t prev_row = 0; // Offset to the start of the previous row
2986a0f08674SEwan Crawford 
2987a0f08674SEwan Crawford   // Iterate over allocation dimensions, printing results to user
2988a0f08674SEwan Crawford   strm.Printf("Data (X, Y, Z):");
2989b9c1b51eSKate Stone   for (uint32_t z = 0; z < dim_z; ++z) {
2990b9c1b51eSKate Stone     for (uint32_t y = 0; y < dim_y; ++y) {
2991a0f08674SEwan Crawford       // Use stride to index start of next row.
2992a0f08674SEwan Crawford       if (!(y == 0 && z == 0))
2993a0f08674SEwan Crawford         offset = prev_row + stride;
2994a0f08674SEwan Crawford       prev_row = offset;
2995a0f08674SEwan Crawford 
2996a0f08674SEwan Crawford       // Print each element in the row individually
2997b9c1b51eSKate Stone       for (uint32_t x = 0; x < dim_x; ++x) {
2998b3f7f69dSAidan Dodds         strm.Printf("\n(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") = ", x, y, z);
2999b9c1b51eSKate Stone         if ((type == Element::RS_TYPE_NONE) &&
3000b9c1b51eSKate Stone             (alloc->element.children.size() > 0) &&
3001b9c1b51eSKate Stone             (alloc->element.type_name != Element::GetFallbackStructName())) {
30028b244e21SEwan Crawford           // Here we are dumping an Element of struct type.
3003b9c1b51eSKate Stone           // This is done using expression evaluation with the name of the
3004b9c1b51eSKate Stone           // struct type and pointer to element.
30058b244e21SEwan Crawford 
3006b9c1b51eSKate Stone           // Don't print the name of the resulting expression, since this will
3007b9c1b51eSKate Stone           // be '$[0-9]+'
30088b244e21SEwan Crawford           DumpValueObjectOptions expr_options;
30098b244e21SEwan Crawford           expr_options.SetHideName(true);
30108b244e21SEwan Crawford 
30118b244e21SEwan Crawford           // Setup expression as derefrencing a pointer cast to element address.
3012ea0636b5SEwan Crawford           char expr_char_buffer[jit_max_expr_size];
3013b9c1b51eSKate Stone           int chars_written =
3014b9c1b51eSKate Stone               snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64,
3015b9c1b51eSKate Stone                        alloc->element.type_name.AsCString(),
3016b9c1b51eSKate Stone                        *alloc->data_ptr.get() + offset);
30178b244e21SEwan Crawford 
3018b9c1b51eSKate Stone           if (chars_written < 0 || chars_written >= jit_max_expr_size) {
30198b244e21SEwan Crawford             if (log)
3020b3f7f69dSAidan Dodds               log->Printf("%s - error in snprintf().", __FUNCTION__);
30218b244e21SEwan Crawford             continue;
30228b244e21SEwan Crawford           }
30238b244e21SEwan Crawford 
30248b244e21SEwan Crawford           // Evaluate expression
30258b244e21SEwan Crawford           ValueObjectSP expr_result;
3026b9c1b51eSKate Stone           GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer,
3027b9c1b51eSKate Stone                                                        frame_ptr, expr_result);
30288b244e21SEwan Crawford 
30298b244e21SEwan Crawford           // Print the results to our stream.
30308b244e21SEwan Crawford           expr_result->Dump(strm, expr_options);
3031b9c1b51eSKate Stone         } else {
3032b9c1b51eSKate Stone           alloc_data.Dump(&strm, offset, format, data_size - padding, 1, 1,
3033b9c1b51eSKate Stone                           LLDB_INVALID_ADDRESS, 0, 0);
30348b244e21SEwan Crawford         }
30358b244e21SEwan Crawford         offset += data_size;
3036a0f08674SEwan Crawford       }
3037a0f08674SEwan Crawford     }
3038a0f08674SEwan Crawford   }
3039a0f08674SEwan Crawford   strm.EOL();
3040a0f08674SEwan Crawford 
3041a0f08674SEwan Crawford   return true;
3042a0f08674SEwan Crawford }
3043a0f08674SEwan Crawford 
3044b9c1b51eSKate Stone // Function recalculates all our cached information about allocations by jitting
3045b9c1b51eSKate Stone // the
30460d2bfcfbSEwan Crawford // RS runtime regarding each allocation we know about.
30470d2bfcfbSEwan Crawford // Returns true if all allocations could be recomputed, false otherwise.
3048b9c1b51eSKate Stone bool RenderScriptRuntime::RecomputeAllAllocations(Stream &strm,
3049b9c1b51eSKate Stone                                                   StackFrame *frame_ptr) {
30500d2bfcfbSEwan Crawford   bool success = true;
3051b9c1b51eSKate Stone   for (auto &alloc : m_allocations) {
30520d2bfcfbSEwan Crawford     // JIT current allocation information
3053b9c1b51eSKate Stone     if (!RefreshAllocation(alloc.get(), frame_ptr)) {
3054b9c1b51eSKate Stone       strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32
3055b9c1b51eSKate Stone                   "\n",
3056b9c1b51eSKate Stone                   alloc->id);
30570d2bfcfbSEwan Crawford       success = false;
30580d2bfcfbSEwan Crawford     }
30590d2bfcfbSEwan Crawford   }
30600d2bfcfbSEwan Crawford 
30610d2bfcfbSEwan Crawford   if (success)
30620d2bfcfbSEwan Crawford     strm.Printf("All allocations successfully recomputed");
30630d2bfcfbSEwan Crawford   strm.EOL();
30640d2bfcfbSEwan Crawford 
30650d2bfcfbSEwan Crawford   return success;
30660d2bfcfbSEwan Crawford }
30670d2bfcfbSEwan Crawford 
3068b649b005SEwan Crawford // Prints information regarding currently loaded allocations.
306915f2bd95SEwan Crawford // These details are gathered by jitting the runtime, which has as latency.
3070b9c1b51eSKate Stone // Index parameter specifies a single allocation ID to print, or a zero value to
3071b9c1b51eSKate Stone // print them all
3072b9c1b51eSKate Stone void RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame *frame_ptr,
3073b9c1b51eSKate Stone                                           const uint32_t index) {
307415f2bd95SEwan Crawford   strm.Printf("RenderScript Allocations:");
307515f2bd95SEwan Crawford   strm.EOL();
307615f2bd95SEwan Crawford   strm.IndentMore();
307715f2bd95SEwan Crawford 
3078b9c1b51eSKate Stone   for (auto &alloc : m_allocations) {
3079b649b005SEwan Crawford     // index will only be zero if we want to print all allocations
3080b649b005SEwan Crawford     if (index != 0 && index != alloc->id)
3081b649b005SEwan Crawford       continue;
308215f2bd95SEwan Crawford 
308315f2bd95SEwan Crawford     // JIT current allocation information
3084b9c1b51eSKate Stone     if (alloc->shouldRefresh() && !RefreshAllocation(alloc.get(), frame_ptr)) {
3085b9c1b51eSKate Stone       strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32,
3086b9c1b51eSKate Stone                   alloc->id);
3087b3f7f69dSAidan Dodds       strm.EOL();
308815f2bd95SEwan Crawford       continue;
308915f2bd95SEwan Crawford     }
309015f2bd95SEwan Crawford 
3091b3f7f69dSAidan Dodds     strm.Printf("%" PRIu32 ":", alloc->id);
3092b3f7f69dSAidan Dodds     strm.EOL();
309315f2bd95SEwan Crawford     strm.IndentMore();
309415f2bd95SEwan Crawford 
309515f2bd95SEwan Crawford     strm.Indent("Context: ");
309615f2bd95SEwan Crawford     if (!alloc->context.isValid())
309715f2bd95SEwan Crawford       strm.Printf("unknown\n");
309815f2bd95SEwan Crawford     else
309915f2bd95SEwan Crawford       strm.Printf("0x%" PRIx64 "\n", *alloc->context.get());
310015f2bd95SEwan Crawford 
310115f2bd95SEwan Crawford     strm.Indent("Address: ");
310215f2bd95SEwan Crawford     if (!alloc->address.isValid())
310315f2bd95SEwan Crawford       strm.Printf("unknown\n");
310415f2bd95SEwan Crawford     else
310515f2bd95SEwan Crawford       strm.Printf("0x%" PRIx64 "\n", *alloc->address.get());
310615f2bd95SEwan Crawford 
310715f2bd95SEwan Crawford     strm.Indent("Data pointer: ");
310815f2bd95SEwan Crawford     if (!alloc->data_ptr.isValid())
310915f2bd95SEwan Crawford       strm.Printf("unknown\n");
311015f2bd95SEwan Crawford     else
311115f2bd95SEwan Crawford       strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get());
311215f2bd95SEwan Crawford 
311315f2bd95SEwan Crawford     strm.Indent("Dimensions: ");
311415f2bd95SEwan Crawford     if (!alloc->dimension.isValid())
311515f2bd95SEwan Crawford       strm.Printf("unknown\n");
311615f2bd95SEwan Crawford     else
3117b3f7f69dSAidan Dodds       strm.Printf("(%" PRId32 ", %" PRId32 ", %" PRId32 ")\n",
3118b9c1b51eSKate Stone                   alloc->dimension.get()->dim_1, alloc->dimension.get()->dim_2,
3119b9c1b51eSKate Stone                   alloc->dimension.get()->dim_3);
312015f2bd95SEwan Crawford 
312115f2bd95SEwan Crawford     strm.Indent("Data Type: ");
3122b9c1b51eSKate Stone     if (!alloc->element.type.isValid() ||
3123b9c1b51eSKate Stone         !alloc->element.type_vec_size.isValid())
312415f2bd95SEwan Crawford       strm.Printf("unknown\n");
3125b9c1b51eSKate Stone     else {
31268b244e21SEwan Crawford       const int vector_size = *alloc->element.type_vec_size.get();
31272e920715SEwan Crawford       Element::DataType type = *alloc->element.type.get();
312815f2bd95SEwan Crawford 
31298b244e21SEwan Crawford       if (!alloc->element.type_name.IsEmpty())
31308b244e21SEwan Crawford         strm.Printf("%s\n", alloc->element.type_name.AsCString());
3131b9c1b51eSKate Stone       else {
3132b9c1b51eSKate Stone         // Enum value isn't monotonous, so doesn't always index
3133b9c1b51eSKate Stone         // RsDataTypeToString array
31342e920715SEwan Crawford         if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT)
3135b9c1b51eSKate Stone           type =
3136b9c1b51eSKate Stone               static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) +
3137b3f7f69dSAidan Dodds                                              Element::RS_TYPE_MATRIX_2X2 + 1);
31382e920715SEwan Crawford 
3139b3f7f69dSAidan Dodds         if (type >= (sizeof(AllocationDetails::RsDataTypeToString) /
3140b3f7f69dSAidan Dodds                      sizeof(AllocationDetails::RsDataTypeToString[0])) ||
3141b3f7f69dSAidan Dodds             vector_size > 4 || vector_size < 1)
314215f2bd95SEwan Crawford           strm.Printf("invalid type\n");
314315f2bd95SEwan Crawford         else
3144b9c1b51eSKate Stone           strm.Printf(
3145b9c1b51eSKate Stone               "%s\n",
3146b9c1b51eSKate Stone               AllocationDetails::RsDataTypeToString[static_cast<uint32_t>(type)]
3147b3f7f69dSAidan Dodds                                                    [vector_size - 1]);
314815f2bd95SEwan Crawford       }
31492e920715SEwan Crawford     }
315015f2bd95SEwan Crawford 
315115f2bd95SEwan Crawford     strm.Indent("Data Kind: ");
31528b244e21SEwan Crawford     if (!alloc->element.type_kind.isValid())
315315f2bd95SEwan Crawford       strm.Printf("unknown\n");
3154b9c1b51eSKate Stone     else {
31558b244e21SEwan Crawford       const Element::DataKind kind = *alloc->element.type_kind.get();
31568b244e21SEwan Crawford       if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV)
315715f2bd95SEwan Crawford         strm.Printf("invalid kind\n");
315815f2bd95SEwan Crawford       else
3159b9c1b51eSKate Stone         strm.Printf(
3160b9c1b51eSKate Stone             "%s\n",
3161b9c1b51eSKate Stone             AllocationDetails::RsDataKindToString[static_cast<uint32_t>(kind)]);
316215f2bd95SEwan Crawford     }
316315f2bd95SEwan Crawford 
316415f2bd95SEwan Crawford     strm.EOL();
316515f2bd95SEwan Crawford     strm.IndentLess();
316615f2bd95SEwan Crawford   }
316715f2bd95SEwan Crawford   strm.IndentLess();
316815f2bd95SEwan Crawford }
316915f2bd95SEwan Crawford 
31707dc7771cSEwan Crawford // Set breakpoints on every kernel found in RS module
3171b9c1b51eSKate Stone void RenderScriptRuntime::BreakOnModuleKernels(
3172b9c1b51eSKate Stone     const RSModuleDescriptorSP rsmodule_sp) {
3173b9c1b51eSKate Stone   for (const auto &kernel : rsmodule_sp->m_kernels) {
31747dc7771cSEwan Crawford     // Don't set breakpoint on 'root' kernel
31757dc7771cSEwan Crawford     if (strcmp(kernel.m_name.AsCString(), "root") == 0)
31767dc7771cSEwan Crawford       continue;
31777dc7771cSEwan Crawford 
31787dc7771cSEwan Crawford     CreateKernelBreakpoint(kernel.m_name);
31797dc7771cSEwan Crawford   }
31807dc7771cSEwan Crawford }
31817dc7771cSEwan Crawford 
31827dc7771cSEwan Crawford // Method is internally called by the 'kernel breakpoint all' command to
31837dc7771cSEwan Crawford // enable or disable breaking on all kernels.
31847dc7771cSEwan Crawford //
31857dc7771cSEwan Crawford // When do_break is true we want to enable this functionality.
31867dc7771cSEwan Crawford // When do_break is false we want to disable it.
3187b9c1b51eSKate Stone void RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) {
3188b9c1b51eSKate Stone   Log *log(
3189b9c1b51eSKate Stone       GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
31907dc7771cSEwan Crawford 
31917dc7771cSEwan Crawford   InitSearchFilter(target);
31927dc7771cSEwan Crawford 
31937dc7771cSEwan Crawford   // Set breakpoints on all the kernels
3194b9c1b51eSKate Stone   if (do_break && !m_breakAllKernels) {
31957dc7771cSEwan Crawford     m_breakAllKernels = true;
31967dc7771cSEwan Crawford 
31977dc7771cSEwan Crawford     for (const auto &module : m_rsmodules)
31987dc7771cSEwan Crawford       BreakOnModuleKernels(module);
31997dc7771cSEwan Crawford 
32007dc7771cSEwan Crawford     if (log)
3201b9c1b51eSKate Stone       log->Printf("%s(True) - breakpoints set on all currently loaded kernels.",
3202b9c1b51eSKate Stone                   __FUNCTION__);
3203b9c1b51eSKate Stone   } else if (!do_break &&
3204b9c1b51eSKate Stone              m_breakAllKernels) // Breakpoints won't be set on any new kernels.
32057dc7771cSEwan Crawford   {
32067dc7771cSEwan Crawford     m_breakAllKernels = false;
32077dc7771cSEwan Crawford 
32087dc7771cSEwan Crawford     if (log)
3209b9c1b51eSKate Stone       log->Printf("%s(False) - breakpoints no longer automatically set.",
3210b9c1b51eSKate Stone                   __FUNCTION__);
32117dc7771cSEwan Crawford   }
32127dc7771cSEwan Crawford }
32137dc7771cSEwan Crawford 
32147dc7771cSEwan Crawford // Given the name of a kernel this function creates a breakpoint using our
32157dc7771cSEwan Crawford // own breakpoint resolver, and returns the Breakpoint shared pointer.
32167dc7771cSEwan Crawford BreakpointSP
3217b9c1b51eSKate Stone RenderScriptRuntime::CreateKernelBreakpoint(const ConstString &name) {
3218b9c1b51eSKate Stone   Log *log(
3219b9c1b51eSKate Stone       GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
32207dc7771cSEwan Crawford 
3221b9c1b51eSKate Stone   if (!m_filtersp) {
32227dc7771cSEwan Crawford     if (log)
3223b3f7f69dSAidan Dodds       log->Printf("%s - error, no breakpoint search filter set.", __FUNCTION__);
32247dc7771cSEwan Crawford     return nullptr;
32257dc7771cSEwan Crawford   }
32267dc7771cSEwan Crawford 
32277dc7771cSEwan Crawford   BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name));
3228b9c1b51eSKate Stone   BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint(
3229b9c1b51eSKate Stone       m_filtersp, resolver_sp, false, false, false);
32307dc7771cSEwan Crawford 
3231b9c1b51eSKate Stone   // Give RS breakpoints a specific name, so the user can manipulate them as a
3232b9c1b51eSKate Stone   // group.
323354782db7SEwan Crawford   Error err;
323454782db7SEwan Crawford   if (!bp->AddName("RenderScriptKernel", err) && log)
3235b9c1b51eSKate Stone     log->Printf("%s - error setting break name, '%s'.", __FUNCTION__,
3236b9c1b51eSKate Stone                 err.AsCString());
323754782db7SEwan Crawford 
32387dc7771cSEwan Crawford   return bp;
32397dc7771cSEwan Crawford }
32407dc7771cSEwan Crawford 
3241b9c1b51eSKate Stone // Given an expression for a variable this function tries to calculate the
3242b9c1b51eSKate Stone // variable's value.
3243b9c1b51eSKate Stone // If this is possible it returns true and sets the uint64_t parameter to the
3244b9c1b51eSKate Stone // variables unsigned value.
3245018f5a7eSEwan Crawford // Otherwise function returns false.
3246b9c1b51eSKate Stone bool RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp,
3247b9c1b51eSKate Stone                                                 const char *var_name,
3248b9c1b51eSKate Stone                                                 uint64_t &val) {
3249018f5a7eSEwan Crawford   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE));
3250018f5a7eSEwan Crawford   Error error;
3251018f5a7eSEwan Crawford   VariableSP var_sp;
3252018f5a7eSEwan Crawford 
3253018f5a7eSEwan Crawford   // Find variable in stack frame
3254b3f7f69dSAidan Dodds   ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath(
3255b3f7f69dSAidan Dodds       var_name, eNoDynamicValues,
3256b9c1b51eSKate Stone       StackFrame::eExpressionPathOptionCheckPtrVsMember |
3257b9c1b51eSKate Stone           StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
3258b3f7f69dSAidan Dodds       var_sp, error));
3259b9c1b51eSKate Stone   if (!error.Success()) {
3260018f5a7eSEwan Crawford     if (log)
3261b9c1b51eSKate Stone       log->Printf("%s - error, couldn't find '%s' in frame", __FUNCTION__,
3262b9c1b51eSKate Stone                   var_name);
3263018f5a7eSEwan Crawford     return false;
3264018f5a7eSEwan Crawford   }
3265018f5a7eSEwan Crawford 
3266b3f7f69dSAidan Dodds   // Find the uint32_t value for the variable
3267018f5a7eSEwan Crawford   bool success = false;
3268018f5a7eSEwan Crawford   val = value_sp->GetValueAsUnsigned(0, &success);
3269b9c1b51eSKate Stone   if (!success) {
3270018f5a7eSEwan Crawford     if (log)
3271b9c1b51eSKate Stone       log->Printf("%s - error, couldn't parse '%s' as an uint32_t.",
3272b9c1b51eSKate Stone                   __FUNCTION__, var_name);
3273018f5a7eSEwan Crawford     return false;
3274018f5a7eSEwan Crawford   }
3275018f5a7eSEwan Crawford 
3276018f5a7eSEwan Crawford   return true;
3277018f5a7eSEwan Crawford }
3278018f5a7eSEwan Crawford 
3279b9c1b51eSKate Stone // Function attempts to find the current coordinate of a kernel invocation by
3280b9c1b51eSKate Stone // investigating the
3281b9c1b51eSKate Stone // values of frame variables in the .expand function. These coordinates are
3282b9c1b51eSKate Stone // returned via the coord
3283b9c1b51eSKate Stone // array reference parameter. Returns true if the coordinates could be found,
3284b9c1b51eSKate Stone // and false otherwise.
3285b9c1b51eSKate Stone bool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord,
3286b9c1b51eSKate Stone                                               Thread *thread_ptr) {
32871e05c3bcSGreg Clayton   static const std::string s_runtimeExpandSuffix(".expand");
3288b9c1b51eSKate Stone   static const std::array<const char *, 3> s_runtimeCoordVars{
3289b9c1b51eSKate Stone       {"rsIndex", "p->current.y", "p->current.z"}};
32901e05c3bcSGreg Clayton 
32914f8817c2SEwan Crawford   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE));
32924f8817c2SEwan Crawford 
3293b9c1b51eSKate Stone   if (!thread_ptr) {
32944f8817c2SEwan Crawford     if (log)
32954f8817c2SEwan Crawford       log->Printf("%s - Error, No thread pointer", __FUNCTION__);
32964f8817c2SEwan Crawford 
32974f8817c2SEwan Crawford     return false;
32984f8817c2SEwan Crawford   }
32994f8817c2SEwan Crawford 
3300b9c1b51eSKate Stone   // Walk the call stack looking for a function whose name has the suffix
3301b9c1b51eSKate Stone   // '.expand'
33024f8817c2SEwan Crawford   // and contains the variables we're looking for.
3303b9c1b51eSKate Stone   for (uint32_t i = 0; i < thread_ptr->GetStackFrameCount(); ++i) {
33044f8817c2SEwan Crawford     if (!thread_ptr->SetSelectedFrameByIndex(i))
33054f8817c2SEwan Crawford       continue;
33064f8817c2SEwan Crawford 
33074f8817c2SEwan Crawford     StackFrameSP frame_sp = thread_ptr->GetSelectedFrame();
33084f8817c2SEwan Crawford     if (!frame_sp)
33094f8817c2SEwan Crawford       continue;
33104f8817c2SEwan Crawford 
33114f8817c2SEwan Crawford     // Find the function name
33124f8817c2SEwan Crawford     const SymbolContext sym_ctx = frame_sp->GetSymbolContext(false);
33134f8817c2SEwan Crawford     const char *func_name_cstr = sym_ctx.GetFunctionName().AsCString();
33144f8817c2SEwan Crawford     if (!func_name_cstr)
33154f8817c2SEwan Crawford       continue;
33164f8817c2SEwan Crawford 
33174f8817c2SEwan Crawford     if (log)
3318b9c1b51eSKate Stone       log->Printf("%s - Inspecting function '%s'", __FUNCTION__,
3319b9c1b51eSKate Stone                   func_name_cstr);
33204f8817c2SEwan Crawford 
33214f8817c2SEwan Crawford     // Check if function name has .expand suffix
33224f8817c2SEwan Crawford     std::string func_name(func_name_cstr);
3323b9c1b51eSKate Stone     const int length_difference =
3324b9c1b51eSKate Stone         func_name.length() - s_runtimeExpandSuffix.length();
33254f8817c2SEwan Crawford     if (length_difference <= 0)
33264f8817c2SEwan Crawford       continue;
33274f8817c2SEwan Crawford 
3328b9c1b51eSKate Stone     const int32_t has_expand_suffix =
3329b9c1b51eSKate Stone         func_name.compare(length_difference, s_runtimeExpandSuffix.length(),
33301e05c3bcSGreg Clayton                           s_runtimeExpandSuffix);
33314f8817c2SEwan Crawford 
33324f8817c2SEwan Crawford     if (has_expand_suffix != 0)
33334f8817c2SEwan Crawford       continue;
33344f8817c2SEwan Crawford 
33354f8817c2SEwan Crawford     if (log)
3336b9c1b51eSKate Stone       log->Printf("%s - Found .expand function '%s'", __FUNCTION__,
3337b9c1b51eSKate Stone                   func_name_cstr);
33384f8817c2SEwan Crawford 
3339b9c1b51eSKate Stone     // Get values for variables in .expand frame that tell us the current kernel
3340b9c1b51eSKate Stone     // invocation
33414f8817c2SEwan Crawford     bool found_coord_variables = true;
33421e05c3bcSGreg Clayton     assert(s_runtimeCoordVars.size() == coord.size());
33434f8817c2SEwan Crawford 
3344b9c1b51eSKate Stone     for (uint32_t i = 0; i < coord.size(); ++i) {
33454f8817c2SEwan Crawford       uint64_t value = 0;
3346b9c1b51eSKate Stone       if (!GetFrameVarAsUnsigned(frame_sp, s_runtimeCoordVars[i], value)) {
33474f8817c2SEwan Crawford         found_coord_variables = false;
33484f8817c2SEwan Crawford         break;
33494f8817c2SEwan Crawford       }
33504f8817c2SEwan Crawford       coord[i] = value;
33514f8817c2SEwan Crawford     }
33524f8817c2SEwan Crawford 
33534f8817c2SEwan Crawford     if (found_coord_variables)
33544f8817c2SEwan Crawford       return true;
33554f8817c2SEwan Crawford   }
33564f8817c2SEwan Crawford   return false;
33574f8817c2SEwan Crawford }
33584f8817c2SEwan Crawford 
3359b9c1b51eSKate Stone // Callback when a kernel breakpoint hits and we're looking for a specific
3360b9c1b51eSKate Stone // coordinate.
3361b9c1b51eSKate Stone // Baton parameter contains a pointer to the target coordinate we want to break
3362b9c1b51eSKate Stone // on.
3363b9c1b51eSKate Stone // Function then checks the .expand frame for the current coordinate and breaks
3364b9c1b51eSKate Stone // to user if it matches.
3365018f5a7eSEwan Crawford // Parameter 'break_id' is the id of the Breakpoint which made the callback.
3366018f5a7eSEwan Crawford // Parameter 'break_loc_id' is the id for the BreakpointLocation which was hit,
3367018f5a7eSEwan Crawford // a single logical breakpoint can have multiple addresses.
3368b9c1b51eSKate Stone bool RenderScriptRuntime::KernelBreakpointHit(void *baton,
3369b9c1b51eSKate Stone                                               StoppointCallbackContext *ctx,
3370b9c1b51eSKate Stone                                               user_id_t break_id,
3371b9c1b51eSKate Stone                                               user_id_t break_loc_id) {
3372b9c1b51eSKate Stone   Log *log(
3373b9c1b51eSKate Stone       GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
3374018f5a7eSEwan Crawford 
3375b9c1b51eSKate Stone   assert(baton &&
3376b9c1b51eSKate Stone          "Error: null baton in conditional kernel breakpoint callback");
3377018f5a7eSEwan Crawford 
3378018f5a7eSEwan Crawford   // Coordinate we want to stop on
33794f8817c2SEwan Crawford   const uint32_t *target_coord = static_cast<const uint32_t *>(baton);
3380018f5a7eSEwan Crawford 
3381018f5a7eSEwan Crawford   if (log)
3382b9c1b51eSKate Stone     log->Printf("%s - Break ID %" PRIu64 ", (%" PRIu32 ", %" PRIu32 ", %" PRIu32
3383b9c1b51eSKate Stone                 ")",
3384b9c1b51eSKate Stone                 __FUNCTION__, break_id, target_coord[0], target_coord[1],
3385b9c1b51eSKate Stone                 target_coord[2]);
3386018f5a7eSEwan Crawford 
33874f8817c2SEwan Crawford   // Select current thread
3388018f5a7eSEwan Crawford   ExecutionContext context(ctx->exe_ctx_ref);
33894f8817c2SEwan Crawford   Thread *thread_ptr = context.GetThreadPtr();
33904f8817c2SEwan Crawford   assert(thread_ptr && "Null thread pointer");
33914f8817c2SEwan Crawford 
33924f8817c2SEwan Crawford   // Find current kernel invocation from .expand frame variables
33934f8817c2SEwan Crawford   RSCoordinate current_coord{}; // Zero initialise array
3394b9c1b51eSKate Stone   if (!GetKernelCoordinate(current_coord, thread_ptr)) {
3395018f5a7eSEwan Crawford     if (log)
3396b9c1b51eSKate Stone       log->Printf("%s - Error, couldn't select .expand stack frame",
3397b9c1b51eSKate Stone                   __FUNCTION__);
3398018f5a7eSEwan Crawford     return false;
3399018f5a7eSEwan Crawford   }
3400018f5a7eSEwan Crawford 
3401018f5a7eSEwan Crawford   if (log)
3402b9c1b51eSKate Stone     log->Printf("%s - (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", __FUNCTION__,
3403b9c1b51eSKate Stone                 current_coord[0], current_coord[1], current_coord[2]);
3404018f5a7eSEwan Crawford 
3405b9c1b51eSKate Stone   // Check if the current kernel invocation coordinate matches our target
3406b9c1b51eSKate Stone   // coordinate
3407b3f7f69dSAidan Dodds   if (current_coord[0] == target_coord[0] &&
3408b3f7f69dSAidan Dodds       current_coord[1] == target_coord[1] &&
3409b9c1b51eSKate Stone       current_coord[2] == target_coord[2]) {
3410018f5a7eSEwan Crawford     if (log)
3411b9c1b51eSKate Stone       log->Printf("%s, BREAKING (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")",
3412b9c1b51eSKate Stone                   __FUNCTION__, current_coord[0], current_coord[1],
3413b9c1b51eSKate Stone                   current_coord[2]);
3414018f5a7eSEwan Crawford 
3415b9c1b51eSKate Stone     BreakpointSP breakpoint_sp =
3416b9c1b51eSKate Stone         context.GetTargetPtr()->GetBreakpointByID(break_id);
3417b9c1b51eSKate Stone     assert(breakpoint_sp != nullptr &&
3418b9c1b51eSKate Stone            "Error: Couldn't find breakpoint matching break id for callback");
3419b9c1b51eSKate Stone     breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint
3420b9c1b51eSKate Stone                                       // should only be hit once.
3421018f5a7eSEwan Crawford     return true;
3422018f5a7eSEwan Crawford   }
3423018f5a7eSEwan Crawford 
3424018f5a7eSEwan Crawford   // No match on coordinate
3425018f5a7eSEwan Crawford   return false;
3426018f5a7eSEwan Crawford }
3427018f5a7eSEwan Crawford 
3428b9c1b51eSKate Stone // Tries to set a breakpoint on the start of a kernel, resolved using the kernel
3429b9c1b51eSKate Stone // name.
3430b9c1b51eSKate Stone // Argument 'coords', represents a three dimensional coordinate which can be
3431b9c1b51eSKate Stone // used to specify
3432b9c1b51eSKate Stone // a single kernel instance to break on. If this is set then we add a callback
3433b9c1b51eSKate Stone // to the breakpoint.
3434b9c1b51eSKate Stone void RenderScriptRuntime::PlaceBreakpointOnKernel(
3435b9c1b51eSKate Stone     Stream &strm, const char *name, const std::array<int, 3> coords,
3436b9c1b51eSKate Stone     Error &error, TargetSP target) {
3437b9c1b51eSKate Stone   if (!name) {
34384640cde1SColin Riley     error.SetErrorString("invalid kernel name");
34394640cde1SColin Riley     return;
34404640cde1SColin Riley   }
34414640cde1SColin Riley 
34427dc7771cSEwan Crawford   InitSearchFilter(target);
344398156583SEwan Crawford 
34444640cde1SColin Riley   ConstString kernel_name(name);
34457dc7771cSEwan Crawford   BreakpointSP bp = CreateKernelBreakpoint(kernel_name);
3446018f5a7eSEwan Crawford 
3447018f5a7eSEwan Crawford   // We have a conditional breakpoint on a specific coordinate
3448b9c1b51eSKate Stone   if (coords[0] != -1) {
3449b9c1b51eSKate Stone     strm.Printf("Conditional kernel breakpoint on coordinate %" PRId32
3450b9c1b51eSKate Stone                 ", %" PRId32 ", %" PRId32,
3451b3f7f69dSAidan Dodds                 coords[0], coords[1], coords[2]);
3452018f5a7eSEwan Crawford     strm.EOL();
3453018f5a7eSEwan Crawford 
3454018f5a7eSEwan Crawford     // Allocate memory for the baton, and copy over coordinate
34554f8817c2SEwan Crawford     uint32_t *baton = new uint32_t[coords.size()];
3456b9c1b51eSKate Stone     baton[0] = coords[0];
3457b9c1b51eSKate Stone     baton[1] = coords[1];
3458b9c1b51eSKate Stone     baton[2] = coords[2];
3459018f5a7eSEwan Crawford 
3460018f5a7eSEwan Crawford     // Create a callback that will be invoked every time the breakpoint is hit.
3461b9c1b51eSKate Stone     // The baton object passed to the handler is the target coordinate we want
3462b9c1b51eSKate Stone     // to break on.
3463018f5a7eSEwan Crawford     bp->SetCallback(KernelBreakpointHit, baton, true);
3464018f5a7eSEwan Crawford 
3465b9c1b51eSKate Stone     // Store a shared pointer to the baton, so the memory will eventually be
3466b9c1b51eSKate Stone     // cleaned up after destruction
34674f8817c2SEwan Crawford     m_conditional_breaks[bp->GetID()] = std::shared_ptr<uint32_t>(baton);
3468018f5a7eSEwan Crawford   }
3469018f5a7eSEwan Crawford 
347098156583SEwan Crawford   if (bp)
347198156583SEwan Crawford     bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false);
34724640cde1SColin Riley }
34734640cde1SColin Riley 
3474b9c1b51eSKate Stone void RenderScriptRuntime::DumpModules(Stream &strm) const {
34755ec532a9SColin Riley   strm.Printf("RenderScript Modules:");
34765ec532a9SColin Riley   strm.EOL();
34775ec532a9SColin Riley   strm.IndentMore();
3478b9c1b51eSKate Stone   for (const auto &module : m_rsmodules) {
34794640cde1SColin Riley     module->Dump(strm);
34805ec532a9SColin Riley   }
34815ec532a9SColin Riley   strm.IndentLess();
34825ec532a9SColin Riley }
34835ec532a9SColin Riley 
348478f339d1SEwan Crawford RenderScriptRuntime::ScriptDetails *
3485b9c1b51eSKate Stone RenderScriptRuntime::LookUpScript(addr_t address, bool create) {
3486b9c1b51eSKate Stone   for (const auto &s : m_scripts) {
348778f339d1SEwan Crawford     if (s->script.isValid())
348878f339d1SEwan Crawford       if (*s->script == address)
348978f339d1SEwan Crawford         return s.get();
349078f339d1SEwan Crawford   }
3491b9c1b51eSKate Stone   if (create) {
349278f339d1SEwan Crawford     std::unique_ptr<ScriptDetails> s(new ScriptDetails);
349378f339d1SEwan Crawford     s->script = address;
349478f339d1SEwan Crawford     m_scripts.push_back(std::move(s));
3495d10ca9deSEwan Crawford     return m_scripts.back().get();
349678f339d1SEwan Crawford   }
349778f339d1SEwan Crawford   return nullptr;
349878f339d1SEwan Crawford }
349978f339d1SEwan Crawford 
350078f339d1SEwan Crawford RenderScriptRuntime::AllocationDetails *
3501b9c1b51eSKate Stone RenderScriptRuntime::LookUpAllocation(addr_t address) {
3502b9c1b51eSKate Stone   for (const auto &a : m_allocations) {
350378f339d1SEwan Crawford     if (a->address.isValid())
350478f339d1SEwan Crawford       if (*a->address == address)
350578f339d1SEwan Crawford         return a.get();
350678f339d1SEwan Crawford   }
35075d057637SLuke Drummond   return nullptr;
35085d057637SLuke Drummond }
35095d057637SLuke Drummond 
35105d057637SLuke Drummond RenderScriptRuntime::AllocationDetails *
3511b9c1b51eSKate Stone RenderScriptRuntime::CreateAllocation(addr_t address) {
35125d057637SLuke Drummond   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
35135d057637SLuke Drummond 
35145d057637SLuke Drummond   // Remove any previous allocation which contains the same address
35155d057637SLuke Drummond   auto it = m_allocations.begin();
3516b9c1b51eSKate Stone   while (it != m_allocations.end()) {
3517b9c1b51eSKate Stone     if (*((*it)->address) == address) {
35185d057637SLuke Drummond       if (log)
3519b9c1b51eSKate Stone         log->Printf("%s - Removing allocation id: %d, address: 0x%" PRIx64,
3520b9c1b51eSKate Stone                     __FUNCTION__, (*it)->id, address);
35215d057637SLuke Drummond 
35225d057637SLuke Drummond       it = m_allocations.erase(it);
3523b9c1b51eSKate Stone     } else {
35245d057637SLuke Drummond       it++;
35255d057637SLuke Drummond     }
35265d057637SLuke Drummond   }
35275d057637SLuke Drummond 
352878f339d1SEwan Crawford   std::unique_ptr<AllocationDetails> a(new AllocationDetails);
352978f339d1SEwan Crawford   a->address = address;
353078f339d1SEwan Crawford   m_allocations.push_back(std::move(a));
3531d10ca9deSEwan Crawford   return m_allocations.back().get();
353278f339d1SEwan Crawford }
353378f339d1SEwan Crawford 
3534b9c1b51eSKate Stone void RSModuleDescriptor::Dump(Stream &strm) const {
3535*7f193d69SLuke Drummond   int indent = strm.GetIndentLevel();
3536*7f193d69SLuke Drummond 
35375ec532a9SColin Riley   strm.Indent();
35385ec532a9SColin Riley   m_module->GetFileSpec().Dump(&strm);
3539*7f193d69SLuke Drummond   strm.Indent(m_module->GetNumCompileUnits() ? "Debug info loaded."
3540*7f193d69SLuke Drummond                                              : "Debug info does not exist.");
35415ec532a9SColin Riley   strm.EOL();
35425ec532a9SColin Riley   strm.IndentMore();
3543*7f193d69SLuke Drummond 
35445ec532a9SColin Riley   strm.Indent();
3545189598edSColin Riley   strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size()));
35465ec532a9SColin Riley   strm.EOL();
35475ec532a9SColin Riley   strm.IndentMore();
3548b9c1b51eSKate Stone   for (const auto &global : m_globals) {
35495ec532a9SColin Riley     global.Dump(strm);
35505ec532a9SColin Riley   }
35515ec532a9SColin Riley   strm.IndentLess();
3552*7f193d69SLuke Drummond 
35535ec532a9SColin Riley   strm.Indent();
3554189598edSColin Riley   strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size()));
35555ec532a9SColin Riley   strm.EOL();
35565ec532a9SColin Riley   strm.IndentMore();
3557b9c1b51eSKate Stone   for (const auto &kernel : m_kernels) {
35585ec532a9SColin Riley     kernel.Dump(strm);
35595ec532a9SColin Riley   }
3560*7f193d69SLuke Drummond   strm.IndentLess();
3561*7f193d69SLuke Drummond 
3562*7f193d69SLuke Drummond   strm.Indent();
35634640cde1SColin Riley   strm.Printf("Pragmas: %" PRIu64, static_cast<uint64_t>(m_pragmas.size()));
35644640cde1SColin Riley   strm.EOL();
35654640cde1SColin Riley   strm.IndentMore();
3566b9c1b51eSKate Stone   for (const auto &key_val : m_pragmas) {
3567*7f193d69SLuke Drummond     strm.Indent();
35684640cde1SColin Riley     strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str());
35694640cde1SColin Riley     strm.EOL();
35704640cde1SColin Riley   }
3571*7f193d69SLuke Drummond   strm.IndentLess();
3572*7f193d69SLuke Drummond 
3573*7f193d69SLuke Drummond   strm.Indent();
3574*7f193d69SLuke Drummond   strm.Printf("Reductions: %" PRIu64,
3575*7f193d69SLuke Drummond               static_cast<uint64_t>(m_reductions.size()));
3576*7f193d69SLuke Drummond   strm.EOL();
3577*7f193d69SLuke Drummond   strm.IndentMore();
3578*7f193d69SLuke Drummond   for (const auto &reduction : m_reductions) {
3579*7f193d69SLuke Drummond     reduction.Dump(strm);
3580*7f193d69SLuke Drummond   }
3581*7f193d69SLuke Drummond 
3582*7f193d69SLuke Drummond   strm.SetIndentLevel(indent);
35835ec532a9SColin Riley }
35845ec532a9SColin Riley 
3585b9c1b51eSKate Stone void RSGlobalDescriptor::Dump(Stream &strm) const {
35865ec532a9SColin Riley   strm.Indent(m_name.AsCString());
35874640cde1SColin Riley   VariableList var_list;
35884640cde1SColin Riley   m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list);
3589b9c1b51eSKate Stone   if (var_list.GetSize() == 1) {
35904640cde1SColin Riley     auto var = var_list.GetVariableAtIndex(0);
35914640cde1SColin Riley     auto type = var->GetType();
3592b9c1b51eSKate Stone     if (type) {
35934640cde1SColin Riley       strm.Printf(" - ");
35944640cde1SColin Riley       type->DumpTypeName(&strm);
3595b9c1b51eSKate Stone     } else {
35964640cde1SColin Riley       strm.Printf(" - Unknown Type");
35974640cde1SColin Riley     }
3598b9c1b51eSKate Stone   } else {
35994640cde1SColin Riley     strm.Printf(" - variable identified, but not found in binary");
3600b9c1b51eSKate Stone     const Symbol *s = m_module->m_module->FindFirstSymbolWithNameAndType(
3601b9c1b51eSKate Stone         m_name, eSymbolTypeData);
3602b9c1b51eSKate Stone     if (s) {
36034640cde1SColin Riley       strm.Printf(" (symbol exists) ");
36044640cde1SColin Riley     }
36054640cde1SColin Riley   }
36064640cde1SColin Riley 
36075ec532a9SColin Riley   strm.EOL();
36085ec532a9SColin Riley }
36095ec532a9SColin Riley 
3610b9c1b51eSKate Stone void RSKernelDescriptor::Dump(Stream &strm) const {
36115ec532a9SColin Riley   strm.Indent(m_name.AsCString());
36125ec532a9SColin Riley   strm.EOL();
36135ec532a9SColin Riley }
36145ec532a9SColin Riley 
3615*7f193d69SLuke Drummond void RSReductionDescriptor::Dump(lldb_private::Stream &stream) const {
3616*7f193d69SLuke Drummond   stream.Indent(m_reduce_name.AsCString());
3617*7f193d69SLuke Drummond   stream.IndentMore();
3618*7f193d69SLuke Drummond   stream.EOL();
3619*7f193d69SLuke Drummond   stream.Indent();
3620*7f193d69SLuke Drummond   stream.Printf("accumulator: %s", m_accum_name.AsCString());
3621*7f193d69SLuke Drummond   stream.EOL();
3622*7f193d69SLuke Drummond   stream.Indent();
3623*7f193d69SLuke Drummond   stream.Printf("initializer: %s", m_init_name.AsCString());
3624*7f193d69SLuke Drummond   stream.EOL();
3625*7f193d69SLuke Drummond   stream.Indent();
3626*7f193d69SLuke Drummond   stream.Printf("combiner: %s", m_comb_name.AsCString());
3627*7f193d69SLuke Drummond   stream.EOL();
3628*7f193d69SLuke Drummond   stream.Indent();
3629*7f193d69SLuke Drummond   stream.Printf("outconverter: %s", m_outc_name.AsCString());
3630*7f193d69SLuke Drummond   stream.EOL();
3631*7f193d69SLuke Drummond   // XXX This is currently unspecified by RenderScript, and unused
3632*7f193d69SLuke Drummond   // stream.Indent();
3633*7f193d69SLuke Drummond   // stream.Printf("halter: '%s'", m_init_name.AsCString());
3634*7f193d69SLuke Drummond   // stream.EOL();
3635*7f193d69SLuke Drummond   stream.IndentLess();
3636*7f193d69SLuke Drummond }
3637*7f193d69SLuke Drummond 
3638b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed {
36395ec532a9SColin Riley public:
36405ec532a9SColin Riley   CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter)
3641b9c1b51eSKate Stone       : CommandObjectParsed(
3642b9c1b51eSKate Stone             interpreter, "renderscript module dump",
3643b9c1b51eSKate Stone             "Dumps renderscript specific information for all modules.",
3644b9c1b51eSKate Stone             "renderscript module dump",
3645b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
36465ec532a9SColin Riley 
3647222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeModuleDump() override = default;
36485ec532a9SColin Riley 
3649b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
36505ec532a9SColin Riley     RenderScriptRuntime *runtime =
3651b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3652b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
36535ec532a9SColin Riley     runtime->DumpModules(result.GetOutputStream());
36545ec532a9SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
36555ec532a9SColin Riley     return true;
36565ec532a9SColin Riley   }
36575ec532a9SColin Riley };
36585ec532a9SColin Riley 
3659b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword {
36605ec532a9SColin Riley public:
36615ec532a9SColin Riley   CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter)
3662b9c1b51eSKate Stone       : CommandObjectMultiword(interpreter, "renderscript module",
3663b9c1b51eSKate Stone                                "Commands that deal with RenderScript modules.",
3664b9c1b51eSKate Stone                                nullptr) {
3665b9c1b51eSKate Stone     LoadSubCommand(
3666b9c1b51eSKate Stone         "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump(
3667b9c1b51eSKate Stone                     interpreter)));
36685ec532a9SColin Riley   }
36695ec532a9SColin Riley 
3670222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeModule() override = default;
36715ec532a9SColin Riley };
36725ec532a9SColin Riley 
3673b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed {
36744640cde1SColin Riley public:
36754640cde1SColin Riley   CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter)
3676b9c1b51eSKate Stone       : CommandObjectParsed(
3677b9c1b51eSKate Stone             interpreter, "renderscript kernel list",
3678b3f7f69dSAidan Dodds             "Lists renderscript kernel names and associated script resources.",
3679b9c1b51eSKate Stone             "renderscript kernel list",
3680b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
36814640cde1SColin Riley 
3682222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelList() override = default;
36834640cde1SColin Riley 
3684b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
36854640cde1SColin Riley     RenderScriptRuntime *runtime =
3686b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3687b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
36884640cde1SColin Riley     runtime->DumpKernels(result.GetOutputStream());
36894640cde1SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
36904640cde1SColin Riley     return true;
36914640cde1SColin Riley   }
36924640cde1SColin Riley };
36934640cde1SColin Riley 
3694b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpointSet
3695b9c1b51eSKate Stone     : public CommandObjectParsed {
36964640cde1SColin Riley public:
3697b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelBreakpointSet(
3698b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3699b9c1b51eSKate Stone       : CommandObjectParsed(
3700b9c1b51eSKate Stone             interpreter, "renderscript kernel breakpoint set",
3701b3f7f69dSAidan Dodds             "Sets a breakpoint on a renderscript kernel.",
3702b3f7f69dSAidan Dodds             "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]",
3703b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
3704b9c1b51eSKate Stone                 eCommandProcessMustBePaused),
3705b9c1b51eSKate Stone         m_options() {}
37064640cde1SColin Riley 
3707222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default;
3708222b937cSEugene Zelenko 
3709b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
3710018f5a7eSEwan Crawford 
3711b9c1b51eSKate Stone   class CommandOptions : public Options {
3712018f5a7eSEwan Crawford   public:
3713e1cfbc79STodd Fiala     CommandOptions() : Options() {}
3714018f5a7eSEwan Crawford 
3715222b937cSEugene Zelenko     ~CommandOptions() override = default;
3716018f5a7eSEwan Crawford 
3717b9c1b51eSKate Stone     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
3718b9c1b51eSKate Stone                          ExecutionContext *execution_context) override {
3719018f5a7eSEwan Crawford       Error error;
3720018f5a7eSEwan Crawford       const int short_option = m_getopt_table[option_idx].val;
3721018f5a7eSEwan Crawford 
3722b9c1b51eSKate Stone       switch (short_option) {
3723018f5a7eSEwan Crawford       case 'c':
3724018f5a7eSEwan Crawford         if (!ParseCoordinate(option_arg))
3725b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
3726b9c1b51eSKate Stone               "Couldn't parse coordinate '%s', should be in format 'x,y,z'.",
3727b3f7f69dSAidan Dodds               option_arg);
3728018f5a7eSEwan Crawford         break;
3729018f5a7eSEwan Crawford       default:
3730b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
3731b9c1b51eSKate Stone                                        short_option);
3732018f5a7eSEwan Crawford         break;
3733018f5a7eSEwan Crawford       }
3734018f5a7eSEwan Crawford       return error;
3735018f5a7eSEwan Crawford     }
3736018f5a7eSEwan Crawford 
3737018f5a7eSEwan Crawford     // -c takes an argument of the form 'num[,num][,num]'.
3738018f5a7eSEwan Crawford     // Where 'id_cstr' is this argument with the whitespace trimmed.
3739018f5a7eSEwan Crawford     // Missing coordinates are defaulted to zero.
3740b9c1b51eSKate Stone     bool ParseCoordinate(const char *id_cstr) {
3741018f5a7eSEwan Crawford       RegularExpression regex;
3742018f5a7eSEwan Crawford       RegularExpression::Match regex_match(3);
3743018f5a7eSEwan Crawford 
3744018f5a7eSEwan Crawford       bool matched = false;
3745b9c1b51eSKate Stone       if (regex.Compile("^([0-9]+),([0-9]+),([0-9]+)$") &&
3746b9c1b51eSKate Stone           regex.Execute(id_cstr, &regex_match))
3747018f5a7eSEwan Crawford         matched = true;
3748b9c1b51eSKate Stone       else if (regex.Compile("^([0-9]+),([0-9]+)$") &&
3749b9c1b51eSKate Stone                regex.Execute(id_cstr, &regex_match))
3750018f5a7eSEwan Crawford         matched = true;
3751b9c1b51eSKate Stone       else if (regex.Compile("^([0-9]+)$") &&
3752b9c1b51eSKate Stone                regex.Execute(id_cstr, &regex_match))
3753018f5a7eSEwan Crawford         matched = true;
3754b9c1b51eSKate Stone       for (uint32_t i = 0; i < 3; i++) {
3755018f5a7eSEwan Crawford         std::string group;
3756018f5a7eSEwan Crawford         if (regex_match.GetMatchAtIndex(id_cstr, i + 1, group))
3757b3f7f69dSAidan Dodds           m_coord[i] = (uint32_t)strtoul(group.c_str(), nullptr, 0);
3758018f5a7eSEwan Crawford         else
3759018f5a7eSEwan Crawford           m_coord[i] = 0;
3760018f5a7eSEwan Crawford       }
3761018f5a7eSEwan Crawford       return matched;
3762018f5a7eSEwan Crawford     }
3763018f5a7eSEwan Crawford 
3764b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
3765018f5a7eSEwan Crawford       // -1 means the -c option hasn't been set
3766018f5a7eSEwan Crawford       m_coord[0] = -1;
3767018f5a7eSEwan Crawford       m_coord[1] = -1;
3768018f5a7eSEwan Crawford       m_coord[2] = -1;
3769018f5a7eSEwan Crawford     }
3770018f5a7eSEwan Crawford 
3771b9c1b51eSKate Stone     const OptionDefinition *GetDefinitions() override { return g_option_table; }
3772018f5a7eSEwan Crawford 
3773018f5a7eSEwan Crawford     static OptionDefinition g_option_table[];
3774018f5a7eSEwan Crawford     std::array<int, 3> m_coord;
3775018f5a7eSEwan Crawford   };
3776018f5a7eSEwan Crawford 
3777b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
37784640cde1SColin Riley     const size_t argc = command.GetArgumentCount();
3779b9c1b51eSKate Stone     if (argc < 1) {
3780b9c1b51eSKate Stone       result.AppendErrorWithFormat(
3781b9c1b51eSKate Stone           "'%s' takes 1 argument of kernel name, and an optional coordinate.",
3782b3f7f69dSAidan Dodds           m_cmd_name.c_str());
3783018f5a7eSEwan Crawford       result.SetStatus(eReturnStatusFailed);
3784018f5a7eSEwan Crawford       return false;
3785018f5a7eSEwan Crawford     }
3786018f5a7eSEwan Crawford 
37874640cde1SColin Riley     RenderScriptRuntime *runtime =
3788b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3789b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
37904640cde1SColin Riley 
37914640cde1SColin Riley     Error error;
3792b9c1b51eSKate Stone     runtime->PlaceBreakpointOnKernel(
3793b9c1b51eSKate Stone         result.GetOutputStream(), command.GetArgumentAtIndex(0),
3794b9c1b51eSKate Stone         m_options.m_coord, error, m_exe_ctx.GetTargetSP());
37954640cde1SColin Riley 
3796b9c1b51eSKate Stone     if (error.Success()) {
37974640cde1SColin Riley       result.AppendMessage("Breakpoint(s) created");
37984640cde1SColin Riley       result.SetStatus(eReturnStatusSuccessFinishResult);
37994640cde1SColin Riley       return true;
38004640cde1SColin Riley     }
38014640cde1SColin Riley     result.SetStatus(eReturnStatusFailed);
38024640cde1SColin Riley     result.AppendErrorWithFormat("Error: %s", error.AsCString());
38034640cde1SColin Riley     return false;
38044640cde1SColin Riley   }
38054640cde1SColin Riley 
3806018f5a7eSEwan Crawford private:
3807018f5a7eSEwan Crawford   CommandOptions m_options;
38084640cde1SColin Riley };
38094640cde1SColin Riley 
3810b9c1b51eSKate Stone OptionDefinition CommandObjectRenderScriptRuntimeKernelBreakpointSet::
3811b9c1b51eSKate Stone     CommandOptions::g_option_table[] = {
3812b9c1b51eSKate Stone         {LLDB_OPT_SET_1, false, "coordinate", 'c',
3813b9c1b51eSKate Stone          OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeValue,
3814b9c1b51eSKate Stone          "Set a breakpoint on a single invocation of the kernel with specified "
3815b9c1b51eSKate Stone          "coordinate.\n"
3816b9c1b51eSKate Stone          "Coordinate takes the form 'x[,y][,z] where x,y,z are positive "
3817b9c1b51eSKate Stone          "integers representing kernel dimensions. "
3818018f5a7eSEwan Crawford          "Any unset dimensions will be defaulted to zero."},
3819b3f7f69dSAidan Dodds         {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}};
3820018f5a7eSEwan Crawford 
3821b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpointAll
3822b9c1b51eSKate Stone     : public CommandObjectParsed {
38237dc7771cSEwan Crawford public:
3824b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelBreakpointAll(
3825b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3826b3f7f69dSAidan Dodds       : CommandObjectParsed(
3827b3f7f69dSAidan Dodds             interpreter, "renderscript kernel breakpoint all",
3828b9c1b51eSKate Stone             "Automatically sets a breakpoint on all renderscript kernels that "
3829b9c1b51eSKate Stone             "are or will be loaded.\n"
3830b9c1b51eSKate Stone             "Disabling option means breakpoints will no longer be set on any "
3831b9c1b51eSKate Stone             "kernels loaded in the future, "
38327dc7771cSEwan Crawford             "but does not remove currently set breakpoints.",
38337dc7771cSEwan Crawford             "renderscript kernel breakpoint all <enable/disable>",
3834b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
3835b9c1b51eSKate Stone                 eCommandProcessMustBePaused) {}
38367dc7771cSEwan Crawford 
3837222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default;
38387dc7771cSEwan Crawford 
3839b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
38407dc7771cSEwan Crawford     const size_t argc = command.GetArgumentCount();
3841b9c1b51eSKate Stone     if (argc != 1) {
3842b9c1b51eSKate Stone       result.AppendErrorWithFormat(
3843b9c1b51eSKate Stone           "'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str());
38447dc7771cSEwan Crawford       result.SetStatus(eReturnStatusFailed);
38457dc7771cSEwan Crawford       return false;
38467dc7771cSEwan Crawford     }
38477dc7771cSEwan Crawford 
3848b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
3849b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3850b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
38517dc7771cSEwan Crawford 
38527dc7771cSEwan Crawford     bool do_break = false;
38537dc7771cSEwan Crawford     const char *argument = command.GetArgumentAtIndex(0);
3854b9c1b51eSKate Stone     if (strcmp(argument, "enable") == 0) {
38557dc7771cSEwan Crawford       do_break = true;
38567dc7771cSEwan Crawford       result.AppendMessage("Breakpoints will be set on all kernels.");
3857b9c1b51eSKate Stone     } else if (strcmp(argument, "disable") == 0) {
38587dc7771cSEwan Crawford       do_break = false;
38597dc7771cSEwan Crawford       result.AppendMessage("Breakpoints will not be set on any new kernels.");
3860b9c1b51eSKate Stone     } else {
3861b9c1b51eSKate Stone       result.AppendErrorWithFormat(
3862b9c1b51eSKate Stone           "Argument must be either 'enable' or 'disable'");
38637dc7771cSEwan Crawford       result.SetStatus(eReturnStatusFailed);
38647dc7771cSEwan Crawford       return false;
38657dc7771cSEwan Crawford     }
38667dc7771cSEwan Crawford 
38677dc7771cSEwan Crawford     runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP());
38687dc7771cSEwan Crawford 
38697dc7771cSEwan Crawford     result.SetStatus(eReturnStatusSuccessFinishResult);
38707dc7771cSEwan Crawford     return true;
38717dc7771cSEwan Crawford   }
38727dc7771cSEwan Crawford };
38737dc7771cSEwan Crawford 
3874b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelCoordinate
3875b9c1b51eSKate Stone     : public CommandObjectParsed {
38764f8817c2SEwan Crawford public:
3877b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelCoordinate(
3878b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3879b9c1b51eSKate Stone       : CommandObjectParsed(
3880b9c1b51eSKate Stone             interpreter, "renderscript kernel coordinate",
38814f8817c2SEwan Crawford             "Shows the (x,y,z) coordinate of the current kernel invocation.",
38824f8817c2SEwan Crawford             "renderscript kernel coordinate",
3883b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
3884b9c1b51eSKate Stone                 eCommandProcessMustBePaused) {}
38854f8817c2SEwan Crawford 
38864f8817c2SEwan Crawford   ~CommandObjectRenderScriptRuntimeKernelCoordinate() override = default;
38874f8817c2SEwan Crawford 
3888b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
38894f8817c2SEwan Crawford     RSCoordinate coord{}; // Zero initialize array
3890b9c1b51eSKate Stone     bool success = RenderScriptRuntime::GetKernelCoordinate(
3891b9c1b51eSKate Stone         coord, m_exe_ctx.GetThreadPtr());
38924f8817c2SEwan Crawford     Stream &stream = result.GetOutputStream();
38934f8817c2SEwan Crawford 
3894b9c1b51eSKate Stone     if (success) {
3895b9c1b51eSKate Stone       stream.Printf("Coordinate: (%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")",
3896b9c1b51eSKate Stone                     coord[0], coord[1], coord[2]);
38974f8817c2SEwan Crawford       stream.EOL();
38984f8817c2SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
3899b9c1b51eSKate Stone     } else {
39004f8817c2SEwan Crawford       stream.Printf("Error: Coordinate could not be found.");
39014f8817c2SEwan Crawford       stream.EOL();
39024f8817c2SEwan Crawford       result.SetStatus(eReturnStatusFailed);
39034f8817c2SEwan Crawford     }
39044f8817c2SEwan Crawford     return true;
39054f8817c2SEwan Crawford   }
39064f8817c2SEwan Crawford };
39074f8817c2SEwan Crawford 
3908b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpoint
3909b9c1b51eSKate Stone     : public CommandObjectMultiword {
39107dc7771cSEwan Crawford public:
3911b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeKernelBreakpoint(
3912b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3913b9c1b51eSKate Stone       : CommandObjectMultiword(
3914b9c1b51eSKate Stone             interpreter, "renderscript kernel",
3915b9c1b51eSKate Stone             "Commands that generate breakpoints on renderscript kernels.",
3916b9c1b51eSKate Stone             nullptr) {
3917b9c1b51eSKate Stone     LoadSubCommand(
3918b9c1b51eSKate Stone         "set",
3919b9c1b51eSKate Stone         CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet(
3920b9c1b51eSKate Stone             interpreter)));
3921b9c1b51eSKate Stone     LoadSubCommand(
3922b9c1b51eSKate Stone         "all",
3923b9c1b51eSKate Stone         CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll(
3924b9c1b51eSKate Stone             interpreter)));
39257dc7771cSEwan Crawford   }
39267dc7771cSEwan Crawford 
3927222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default;
39287dc7771cSEwan Crawford };
39297dc7771cSEwan Crawford 
3930b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword {
39314640cde1SColin Riley public:
39324640cde1SColin Riley   CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter)
3933b9c1b51eSKate Stone       : CommandObjectMultiword(interpreter, "renderscript kernel",
3934b9c1b51eSKate Stone                                "Commands that deal with RenderScript kernels.",
3935b9c1b51eSKate Stone                                nullptr) {
3936b9c1b51eSKate Stone     LoadSubCommand(
3937b9c1b51eSKate Stone         "list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList(
3938b9c1b51eSKate Stone                     interpreter)));
3939b9c1b51eSKate Stone     LoadSubCommand(
3940b9c1b51eSKate Stone         "coordinate",
3941b9c1b51eSKate Stone         CommandObjectSP(
3942b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeKernelCoordinate(interpreter)));
3943b9c1b51eSKate Stone     LoadSubCommand(
3944b9c1b51eSKate Stone         "breakpoint",
3945b9c1b51eSKate Stone         CommandObjectSP(
3946b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter)));
39474640cde1SColin Riley   }
39484640cde1SColin Riley 
3949222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeKernel() override = default;
39504640cde1SColin Riley };
39514640cde1SColin Riley 
3952b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed {
39534640cde1SColin Riley public:
39544640cde1SColin Riley   CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter)
3955b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "renderscript context dump",
3956b9c1b51eSKate Stone                             "Dumps renderscript context information.",
3957b9c1b51eSKate Stone                             "renderscript context dump",
3958b9c1b51eSKate Stone                             eCommandRequiresProcess |
3959b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
39604640cde1SColin Riley 
3961222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeContextDump() override = default;
39624640cde1SColin Riley 
3963b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
39644640cde1SColin Riley     RenderScriptRuntime *runtime =
3965b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
3966b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
39674640cde1SColin Riley     runtime->DumpContexts(result.GetOutputStream());
39684640cde1SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
39694640cde1SColin Riley     return true;
39704640cde1SColin Riley   }
39714640cde1SColin Riley };
39724640cde1SColin Riley 
3973b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword {
39744640cde1SColin Riley public:
39754640cde1SColin Riley   CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter)
3976b9c1b51eSKate Stone       : CommandObjectMultiword(interpreter, "renderscript context",
3977b9c1b51eSKate Stone                                "Commands that deal with RenderScript contexts.",
3978b9c1b51eSKate Stone                                nullptr) {
3979b9c1b51eSKate Stone     LoadSubCommand(
3980b9c1b51eSKate Stone         "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump(
3981b9c1b51eSKate Stone                     interpreter)));
39824640cde1SColin Riley   }
39834640cde1SColin Riley 
3984222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeContext() override = default;
39854640cde1SColin Riley };
39864640cde1SColin Riley 
3987b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationDump
3988b9c1b51eSKate Stone     : public CommandObjectParsed {
3989a0f08674SEwan Crawford public:
3990b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationDump(
3991b9c1b51eSKate Stone       CommandInterpreter &interpreter)
3992a0f08674SEwan Crawford       : CommandObjectParsed(interpreter, "renderscript allocation dump",
3993b9c1b51eSKate Stone                             "Displays the contents of a particular allocation",
3994b9c1b51eSKate Stone                             "renderscript allocation dump <ID>",
3995b9c1b51eSKate Stone                             eCommandRequiresProcess |
3996b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched),
3997b9c1b51eSKate Stone         m_options() {}
3998a0f08674SEwan Crawford 
3999222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationDump() override = default;
4000222b937cSEugene Zelenko 
4001b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
4002a0f08674SEwan Crawford 
4003b9c1b51eSKate Stone   class CommandOptions : public Options {
4004a0f08674SEwan Crawford   public:
4005e1cfbc79STodd Fiala     CommandOptions() : Options() {}
4006a0f08674SEwan Crawford 
4007222b937cSEugene Zelenko     ~CommandOptions() override = default;
4008a0f08674SEwan Crawford 
4009b9c1b51eSKate Stone     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
4010b9c1b51eSKate Stone                          ExecutionContext *execution_context) override {
4011a0f08674SEwan Crawford       Error error;
4012a0f08674SEwan Crawford       const int short_option = m_getopt_table[option_idx].val;
4013a0f08674SEwan Crawford 
4014b9c1b51eSKate Stone       switch (short_option) {
4015a0f08674SEwan Crawford       case 'f':
4016a0f08674SEwan Crawford         m_outfile.SetFile(option_arg, true);
4017b9c1b51eSKate Stone         if (m_outfile.Exists()) {
4018a0f08674SEwan Crawford           m_outfile.Clear();
4019b9c1b51eSKate Stone           error.SetErrorStringWithFormat("file already exists: '%s'",
4020b9c1b51eSKate Stone                                          option_arg);
4021a0f08674SEwan Crawford         }
4022a0f08674SEwan Crawford         break;
4023a0f08674SEwan Crawford       default:
4024b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
4025b9c1b51eSKate Stone                                        short_option);
4026a0f08674SEwan Crawford         break;
4027a0f08674SEwan Crawford       }
4028a0f08674SEwan Crawford       return error;
4029a0f08674SEwan Crawford     }
4030a0f08674SEwan Crawford 
4031b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
4032a0f08674SEwan Crawford       m_outfile.Clear();
4033a0f08674SEwan Crawford     }
4034a0f08674SEwan Crawford 
4035b9c1b51eSKate Stone     const OptionDefinition *GetDefinitions() override { return g_option_table; }
4036a0f08674SEwan Crawford 
4037a0f08674SEwan Crawford     static OptionDefinition g_option_table[];
4038a0f08674SEwan Crawford     FileSpec m_outfile;
4039a0f08674SEwan Crawford   };
4040a0f08674SEwan Crawford 
4041b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
4042a0f08674SEwan Crawford     const size_t argc = command.GetArgumentCount();
4043b9c1b51eSKate Stone     if (argc < 1) {
4044b9c1b51eSKate Stone       result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. "
4045b9c1b51eSKate Stone                                    "As well as an optional -f argument",
4046a0f08674SEwan Crawford                                    m_cmd_name.c_str());
4047a0f08674SEwan Crawford       result.SetStatus(eReturnStatusFailed);
4048a0f08674SEwan Crawford       return false;
4049a0f08674SEwan Crawford     }
4050a0f08674SEwan Crawford 
4051b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4052b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4053b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
4054a0f08674SEwan Crawford 
4055a0f08674SEwan Crawford     const char *id_cstr = command.GetArgumentAtIndex(0);
4056a0f08674SEwan Crawford     bool convert_complete = false;
4057b9c1b51eSKate Stone     const uint32_t id =
4058b9c1b51eSKate Stone         StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
4059b9c1b51eSKate Stone     if (!convert_complete) {
4060b9c1b51eSKate Stone       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
4061b9c1b51eSKate Stone                                    id_cstr);
4062a0f08674SEwan Crawford       result.SetStatus(eReturnStatusFailed);
4063a0f08674SEwan Crawford       return false;
4064a0f08674SEwan Crawford     }
4065a0f08674SEwan Crawford 
4066a0f08674SEwan Crawford     Stream *output_strm = nullptr;
4067a0f08674SEwan Crawford     StreamFile outfile_stream;
4068b9c1b51eSKate Stone     const FileSpec &outfile_spec =
4069b9c1b51eSKate Stone         m_options.m_outfile; // Dump allocation to file instead
4070b9c1b51eSKate Stone     if (outfile_spec) {
4071a0f08674SEwan Crawford       // Open output file
4072a0f08674SEwan Crawford       char path[256];
4073a0f08674SEwan Crawford       outfile_spec.GetPath(path, sizeof(path));
4074b9c1b51eSKate Stone       if (outfile_stream.GetFile()
4075b9c1b51eSKate Stone               .Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate)
4076b9c1b51eSKate Stone               .Success()) {
4077a0f08674SEwan Crawford         output_strm = &outfile_stream;
4078a0f08674SEwan Crawford         result.GetOutputStream().Printf("Results written to '%s'", path);
4079a0f08674SEwan Crawford         result.GetOutputStream().EOL();
4080b9c1b51eSKate Stone       } else {
4081a0f08674SEwan Crawford         result.AppendErrorWithFormat("Couldn't open file '%s'", path);
4082a0f08674SEwan Crawford         result.SetStatus(eReturnStatusFailed);
4083a0f08674SEwan Crawford         return false;
4084a0f08674SEwan Crawford       }
4085b9c1b51eSKate Stone     } else
4086a0f08674SEwan Crawford       output_strm = &result.GetOutputStream();
4087a0f08674SEwan Crawford 
4088a0f08674SEwan Crawford     assert(output_strm != nullptr);
4089b9c1b51eSKate Stone     bool success =
4090b9c1b51eSKate Stone         runtime->DumpAllocation(*output_strm, m_exe_ctx.GetFramePtr(), id);
4091a0f08674SEwan Crawford 
4092a0f08674SEwan Crawford     if (success)
4093a0f08674SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
4094a0f08674SEwan Crawford     else
4095a0f08674SEwan Crawford       result.SetStatus(eReturnStatusFailed);
4096a0f08674SEwan Crawford 
4097a0f08674SEwan Crawford     return true;
4098a0f08674SEwan Crawford   }
4099a0f08674SEwan Crawford 
4100a0f08674SEwan Crawford private:
4101a0f08674SEwan Crawford   CommandOptions m_options;
4102a0f08674SEwan Crawford };
4103a0f08674SEwan Crawford 
4104b9c1b51eSKate Stone OptionDefinition CommandObjectRenderScriptRuntimeAllocationDump::
4105b9c1b51eSKate Stone     CommandOptions::g_option_table[] = {
4106b9c1b51eSKate Stone         {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument,
4107b9c1b51eSKate Stone          nullptr, nullptr, 0, eArgTypeFilename,
4108a0f08674SEwan Crawford          "Print results to specified file instead of command line."},
4109b3f7f69dSAidan Dodds         {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}};
4110a0f08674SEwan Crawford 
4111b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationList
4112b9c1b51eSKate Stone     : public CommandObjectParsed {
411315f2bd95SEwan Crawford public:
4114b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationList(
4115b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4116b9c1b51eSKate Stone       : CommandObjectParsed(
4117b9c1b51eSKate Stone             interpreter, "renderscript allocation list",
4118b9c1b51eSKate Stone             "List renderscript allocations and their information.",
4119b9c1b51eSKate Stone             "renderscript allocation list",
4120b3f7f69dSAidan Dodds             eCommandRequiresProcess | eCommandProcessMustBeLaunched),
4121b9c1b51eSKate Stone         m_options() {}
412215f2bd95SEwan Crawford 
4123222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationList() override = default;
4124222b937cSEugene Zelenko 
4125b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
412615f2bd95SEwan Crawford 
4127b9c1b51eSKate Stone   class CommandOptions : public Options {
412815f2bd95SEwan Crawford   public:
4129e1cfbc79STodd Fiala     CommandOptions() : Options(), m_id(0) {}
413015f2bd95SEwan Crawford 
4131222b937cSEugene Zelenko     ~CommandOptions() override = default;
413215f2bd95SEwan Crawford 
4133b9c1b51eSKate Stone     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
4134b9c1b51eSKate Stone                          ExecutionContext *execution_context) override {
413515f2bd95SEwan Crawford       Error error;
413615f2bd95SEwan Crawford       const int short_option = m_getopt_table[option_idx].val;
413715f2bd95SEwan Crawford 
4138b9c1b51eSKate Stone       switch (short_option) {
4139b649b005SEwan Crawford       case 'i':
4140b649b005SEwan Crawford         bool success;
4141b649b005SEwan Crawford         m_id = StringConvert::ToUInt32(option_arg, 0, 0, &success);
4142b649b005SEwan Crawford         if (!success)
4143b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
4144b9c1b51eSKate Stone               "invalid integer value for option '%c'", short_option);
414515f2bd95SEwan Crawford         break;
414615f2bd95SEwan Crawford       default:
4147b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
4148b9c1b51eSKate Stone                                        short_option);
414915f2bd95SEwan Crawford         break;
415015f2bd95SEwan Crawford       }
415115f2bd95SEwan Crawford       return error;
415215f2bd95SEwan Crawford     }
415315f2bd95SEwan Crawford 
4154b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
4155b649b005SEwan Crawford       m_id = 0;
415615f2bd95SEwan Crawford     }
415715f2bd95SEwan Crawford 
4158b9c1b51eSKate Stone     const OptionDefinition *GetDefinitions() override { return g_option_table; }
415915f2bd95SEwan Crawford 
416015f2bd95SEwan Crawford     static OptionDefinition g_option_table[];
4161b649b005SEwan Crawford     uint32_t m_id;
416215f2bd95SEwan Crawford   };
416315f2bd95SEwan Crawford 
4164b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
4165b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4166b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4167b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
4168b9c1b51eSKate Stone     runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(),
4169b9c1b51eSKate Stone                              m_options.m_id);
417015f2bd95SEwan Crawford     result.SetStatus(eReturnStatusSuccessFinishResult);
417115f2bd95SEwan Crawford     return true;
417215f2bd95SEwan Crawford   }
417315f2bd95SEwan Crawford 
417415f2bd95SEwan Crawford private:
417515f2bd95SEwan Crawford   CommandOptions m_options;
417615f2bd95SEwan Crawford };
417715f2bd95SEwan Crawford 
4178b9c1b51eSKate Stone OptionDefinition CommandObjectRenderScriptRuntimeAllocationList::
4179b9c1b51eSKate Stone     CommandOptions::g_option_table[] = {
4180b9c1b51eSKate Stone         {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument,
4181b9c1b51eSKate Stone          nullptr, nullptr, 0, eArgTypeIndex,
4182b649b005SEwan Crawford          "Only show details of a single allocation with specified id."},
4183b3f7f69dSAidan Dodds         {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}};
418415f2bd95SEwan Crawford 
4185b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationLoad
4186b9c1b51eSKate Stone     : public CommandObjectParsed {
418755232f09SEwan Crawford public:
4188b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationLoad(
4189b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4190b3f7f69dSAidan Dodds       : CommandObjectParsed(
4191b9c1b51eSKate Stone             interpreter, "renderscript allocation load",
4192b9c1b51eSKate Stone             "Loads renderscript allocation contents from a file.",
4193b9c1b51eSKate Stone             "renderscript allocation load <ID> <filename>",
4194b9c1b51eSKate Stone             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
419555232f09SEwan Crawford 
4196222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default;
419755232f09SEwan Crawford 
4198b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
419955232f09SEwan Crawford     const size_t argc = command.GetArgumentCount();
4200b9c1b51eSKate Stone     if (argc != 2) {
4201b9c1b51eSKate Stone       result.AppendErrorWithFormat(
4202b9c1b51eSKate Stone           "'%s' takes 2 arguments, an allocation ID and filename to read from.",
4203b3f7f69dSAidan Dodds           m_cmd_name.c_str());
420455232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
420555232f09SEwan Crawford       return false;
420655232f09SEwan Crawford     }
420755232f09SEwan Crawford 
4208b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4209b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4210b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
421155232f09SEwan Crawford 
421255232f09SEwan Crawford     const char *id_cstr = command.GetArgumentAtIndex(0);
421355232f09SEwan Crawford     bool convert_complete = false;
4214b9c1b51eSKate Stone     const uint32_t id =
4215b9c1b51eSKate Stone         StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
4216b9c1b51eSKate Stone     if (!convert_complete) {
4217b9c1b51eSKate Stone       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
4218b9c1b51eSKate Stone                                    id_cstr);
421955232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
422055232f09SEwan Crawford       return false;
422155232f09SEwan Crawford     }
422255232f09SEwan Crawford 
422355232f09SEwan Crawford     const char *filename = command.GetArgumentAtIndex(1);
4224b9c1b51eSKate Stone     bool success = runtime->LoadAllocation(result.GetOutputStream(), id,
4225b9c1b51eSKate Stone                                            filename, m_exe_ctx.GetFramePtr());
422655232f09SEwan Crawford 
422755232f09SEwan Crawford     if (success)
422855232f09SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
422955232f09SEwan Crawford     else
423055232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
423155232f09SEwan Crawford 
423255232f09SEwan Crawford     return true;
423355232f09SEwan Crawford   }
423455232f09SEwan Crawford };
423555232f09SEwan Crawford 
4236b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationSave
4237b9c1b51eSKate Stone     : public CommandObjectParsed {
423855232f09SEwan Crawford public:
4239b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationSave(
4240b9c1b51eSKate Stone       CommandInterpreter &interpreter)
4241b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "renderscript allocation save",
4242b9c1b51eSKate Stone                             "Write renderscript allocation contents to a file.",
4243b9c1b51eSKate Stone                             "renderscript allocation save <ID> <filename>",
4244b9c1b51eSKate Stone                             eCommandRequiresProcess |
4245b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
424655232f09SEwan Crawford 
4247222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocationSave() override = default;
424855232f09SEwan Crawford 
4249b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
425055232f09SEwan Crawford     const size_t argc = command.GetArgumentCount();
4251b9c1b51eSKate Stone     if (argc != 2) {
4252b9c1b51eSKate Stone       result.AppendErrorWithFormat(
4253b9c1b51eSKate Stone           "'%s' takes 2 arguments, an allocation ID and filename to read from.",
4254b3f7f69dSAidan Dodds           m_cmd_name.c_str());
425555232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
425655232f09SEwan Crawford       return false;
425755232f09SEwan Crawford     }
425855232f09SEwan Crawford 
4259b3f7f69dSAidan Dodds     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4260b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4261b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
426255232f09SEwan Crawford 
426355232f09SEwan Crawford     const char *id_cstr = command.GetArgumentAtIndex(0);
426455232f09SEwan Crawford     bool convert_complete = false;
4265b9c1b51eSKate Stone     const uint32_t id =
4266b9c1b51eSKate Stone         StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
4267b9c1b51eSKate Stone     if (!convert_complete) {
4268b9c1b51eSKate Stone       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
4269b9c1b51eSKate Stone                                    id_cstr);
427055232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
427155232f09SEwan Crawford       return false;
427255232f09SEwan Crawford     }
427355232f09SEwan Crawford 
427455232f09SEwan Crawford     const char *filename = command.GetArgumentAtIndex(1);
4275b9c1b51eSKate Stone     bool success = runtime->SaveAllocation(result.GetOutputStream(), id,
4276b9c1b51eSKate Stone                                            filename, m_exe_ctx.GetFramePtr());
427755232f09SEwan Crawford 
427855232f09SEwan Crawford     if (success)
427955232f09SEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
428055232f09SEwan Crawford     else
428155232f09SEwan Crawford       result.SetStatus(eReturnStatusFailed);
428255232f09SEwan Crawford 
428355232f09SEwan Crawford     return true;
428455232f09SEwan Crawford   }
428555232f09SEwan Crawford };
428655232f09SEwan Crawford 
4287b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationRefresh
4288b9c1b51eSKate Stone     : public CommandObjectParsed {
42890d2bfcfbSEwan Crawford public:
4290b9c1b51eSKate Stone   CommandObjectRenderScriptRuntimeAllocationRefresh(
4291b9c1b51eSKate Stone       CommandInterpreter &interpreter)
42920d2bfcfbSEwan Crawford       : CommandObjectParsed(interpreter, "renderscript allocation refresh",
4293b9c1b51eSKate Stone                             "Recomputes the details of all allocations.",
4294b9c1b51eSKate Stone                             "renderscript allocation refresh",
4295b9c1b51eSKate Stone                             eCommandRequiresProcess |
4296b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
42970d2bfcfbSEwan Crawford 
42980d2bfcfbSEwan Crawford   ~CommandObjectRenderScriptRuntimeAllocationRefresh() override = default;
42990d2bfcfbSEwan Crawford 
4300b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
43010d2bfcfbSEwan Crawford     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4302b9c1b51eSKate Stone         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4303b9c1b51eSKate Stone             eLanguageTypeExtRenderScript));
43040d2bfcfbSEwan Crawford 
4305b9c1b51eSKate Stone     bool success = runtime->RecomputeAllAllocations(result.GetOutputStream(),
4306b9c1b51eSKate Stone                                                     m_exe_ctx.GetFramePtr());
43070d2bfcfbSEwan Crawford 
4308b9c1b51eSKate Stone     if (success) {
43090d2bfcfbSEwan Crawford       result.SetStatus(eReturnStatusSuccessFinishResult);
43100d2bfcfbSEwan Crawford       return true;
4311b9c1b51eSKate Stone     } else {
43120d2bfcfbSEwan Crawford       result.SetStatus(eReturnStatusFailed);
43130d2bfcfbSEwan Crawford       return false;
43140d2bfcfbSEwan Crawford     }
43150d2bfcfbSEwan Crawford   }
43160d2bfcfbSEwan Crawford };
43170d2bfcfbSEwan Crawford 
4318b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocation
4319b9c1b51eSKate Stone     : public CommandObjectMultiword {
432015f2bd95SEwan Crawford public:
432115f2bd95SEwan Crawford   CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter)
4322b9c1b51eSKate Stone       : CommandObjectMultiword(
4323b9c1b51eSKate Stone             interpreter, "renderscript allocation",
4324b9c1b51eSKate Stone             "Commands that deal with RenderScript allocations.", nullptr) {
4325b9c1b51eSKate Stone     LoadSubCommand(
4326b9c1b51eSKate Stone         "list",
4327b9c1b51eSKate Stone         CommandObjectSP(
4328b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationList(interpreter)));
4329b9c1b51eSKate Stone     LoadSubCommand(
4330b9c1b51eSKate Stone         "dump",
4331b9c1b51eSKate Stone         CommandObjectSP(
4332b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationDump(interpreter)));
4333b9c1b51eSKate Stone     LoadSubCommand(
4334b9c1b51eSKate Stone         "save",
4335b9c1b51eSKate Stone         CommandObjectSP(
4336b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationSave(interpreter)));
4337b9c1b51eSKate Stone     LoadSubCommand(
4338b9c1b51eSKate Stone         "load",
4339b9c1b51eSKate Stone         CommandObjectSP(
4340b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter)));
4341b9c1b51eSKate Stone     LoadSubCommand(
4342b9c1b51eSKate Stone         "refresh",
4343b9c1b51eSKate Stone         CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationRefresh(
4344b9c1b51eSKate Stone             interpreter)));
434515f2bd95SEwan Crawford   }
434615f2bd95SEwan Crawford 
4347222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeAllocation() override = default;
434815f2bd95SEwan Crawford };
434915f2bd95SEwan Crawford 
4350b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed {
43514640cde1SColin Riley public:
43524640cde1SColin Riley   CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter)
4353b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "renderscript status",
4354b9c1b51eSKate Stone                             "Displays current RenderScript runtime status.",
4355b9c1b51eSKate Stone                             "renderscript status",
4356b9c1b51eSKate Stone                             eCommandRequiresProcess |
4357b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched) {}
43584640cde1SColin Riley 
4359222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntimeStatus() override = default;
43604640cde1SColin Riley 
4361b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
43624640cde1SColin Riley     RenderScriptRuntime *runtime =
4363b9c1b51eSKate Stone         (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4364b9c1b51eSKate Stone             eLanguageTypeExtRenderScript);
43654640cde1SColin Riley     runtime->Status(result.GetOutputStream());
43664640cde1SColin Riley     result.SetStatus(eReturnStatusSuccessFinishResult);
43674640cde1SColin Riley     return true;
43684640cde1SColin Riley   }
43694640cde1SColin Riley };
43704640cde1SColin Riley 
4371b9c1b51eSKate Stone class CommandObjectRenderScriptRuntime : public CommandObjectMultiword {
43725ec532a9SColin Riley public:
43735ec532a9SColin Riley   CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter)
4374b9c1b51eSKate Stone       : CommandObjectMultiword(
4375b9c1b51eSKate Stone             interpreter, "renderscript",
4376b9c1b51eSKate Stone             "Commands for operating on the RenderScript runtime.",
4377b9c1b51eSKate Stone             "renderscript <subcommand> [<subcommand-options>]") {
4378b9c1b51eSKate Stone     LoadSubCommand(
4379b9c1b51eSKate Stone         "module", CommandObjectSP(
4380b9c1b51eSKate Stone                       new CommandObjectRenderScriptRuntimeModule(interpreter)));
4381b9c1b51eSKate Stone     LoadSubCommand(
4382b9c1b51eSKate Stone         "status", CommandObjectSP(
4383b9c1b51eSKate Stone                       new CommandObjectRenderScriptRuntimeStatus(interpreter)));
4384b9c1b51eSKate Stone     LoadSubCommand(
4385b9c1b51eSKate Stone         "kernel", CommandObjectSP(
4386b9c1b51eSKate Stone                       new CommandObjectRenderScriptRuntimeKernel(interpreter)));
4387b9c1b51eSKate Stone     LoadSubCommand("context",
4388b9c1b51eSKate Stone                    CommandObjectSP(new CommandObjectRenderScriptRuntimeContext(
4389b9c1b51eSKate Stone                        interpreter)));
4390b9c1b51eSKate Stone     LoadSubCommand(
4391b9c1b51eSKate Stone         "allocation",
4392b9c1b51eSKate Stone         CommandObjectSP(
4393b9c1b51eSKate Stone             new CommandObjectRenderScriptRuntimeAllocation(interpreter)));
43945ec532a9SColin Riley   }
43955ec532a9SColin Riley 
4396222b937cSEugene Zelenko   ~CommandObjectRenderScriptRuntime() override = default;
43975ec532a9SColin Riley };
4398ef20b08fSColin Riley 
4399b9c1b51eSKate Stone void RenderScriptRuntime::Initiate() { assert(!m_initiated); }
4400ef20b08fSColin Riley 
4401ef20b08fSColin Riley RenderScriptRuntime::RenderScriptRuntime(Process *process)
4402b9c1b51eSKate Stone     : lldb_private::CPPLanguageRuntime(process), m_initiated(false),
4403b9c1b51eSKate Stone       m_debuggerPresentFlagged(false), m_breakAllKernels(false),
4404b9c1b51eSKate Stone       m_ir_passes(nullptr) {
44054640cde1SColin Riley   ModulesDidLoad(process->GetTarget().GetImages());
4406ef20b08fSColin Riley }
44074640cde1SColin Riley 
4408b9c1b51eSKate Stone lldb::CommandObjectSP RenderScriptRuntime::GetCommandObject(
4409b9c1b51eSKate Stone     lldb_private::CommandInterpreter &interpreter) {
44100a66e2f1SEnrico Granata   return CommandObjectSP(new CommandObjectRenderScriptRuntime(interpreter));
44114640cde1SColin Riley }
44124640cde1SColin Riley 
441378f339d1SEwan Crawford RenderScriptRuntime::~RenderScriptRuntime() = default;
4414