15ffd83dbSDimitry Andric //===-- RenderScriptRuntime.cpp -------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "RenderScriptRuntime.h"
100b57cec5SDimitry Andric #include "RenderScriptScriptGroup.h"
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "lldb/Breakpoint/StoppointCallbackContext.h"
130b57cec5SDimitry Andric #include "lldb/Core/Debugger.h"
140b57cec5SDimitry Andric #include "lldb/Core/DumpDataExtractor.h"
150b57cec5SDimitry Andric #include "lldb/Core/PluginManager.h"
160b57cec5SDimitry Andric #include "lldb/Core/ValueObjectVariable.h"
170b57cec5SDimitry Andric #include "lldb/DataFormatters/DumpValueObjectOptions.h"
180b57cec5SDimitry Andric #include "lldb/Expression/UserExpression.h"
190b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h"
200b57cec5SDimitry Andric #include "lldb/Host/StringConvert.h"
210b57cec5SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
220b57cec5SDimitry Andric #include "lldb/Interpreter/CommandObjectMultiword.h"
230b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
240b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h"
250b57cec5SDimitry Andric #include "lldb/Symbol/Function.h"
260b57cec5SDimitry Andric #include "lldb/Symbol/Symbol.h"
270b57cec5SDimitry Andric #include "lldb/Symbol/Type.h"
280b57cec5SDimitry Andric #include "lldb/Symbol/VariableList.h"
290b57cec5SDimitry Andric #include "lldb/Target/Process.h"
300b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
310b57cec5SDimitry Andric #include "lldb/Target/SectionLoadList.h"
320b57cec5SDimitry Andric #include "lldb/Target/Target.h"
330b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
340b57cec5SDimitry Andric #include "lldb/Utility/Args.h"
350b57cec5SDimitry Andric #include "lldb/Utility/ConstString.h"
360b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
370b57cec5SDimitry Andric #include "lldb/Utility/RegisterValue.h"
380b57cec5SDimitry Andric #include "lldb/Utility/RegularExpression.h"
390b57cec5SDimitry Andric #include "lldb/Utility/Status.h"
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric #include <memory>
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric using namespace lldb;
460b57cec5SDimitry Andric using namespace lldb_private;
470b57cec5SDimitry Andric using namespace lldb_renderscript;
480b57cec5SDimitry Andric 
495ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(RenderScriptRuntime)
505ffd83dbSDimitry Andric 
510b57cec5SDimitry Andric #define FMT_COORD "(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")"
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric char RenderScriptRuntime::ID = 0;
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric namespace {
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric // The empirical_type adds a basic level of validation to arbitrary data
580b57cec5SDimitry Andric // allowing us to track if data has been discovered and stored or not. An
590b57cec5SDimitry Andric // empirical_type will be marked as valid only if it has been explicitly
600b57cec5SDimitry Andric // assigned to.
610b57cec5SDimitry Andric template <typename type_t> class empirical_type {
620b57cec5SDimitry Andric public:
630b57cec5SDimitry Andric   // Ctor. Contents is invalid when constructed.
64*5f7ddb14SDimitry Andric   empirical_type() = default;
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   // Return true and copy contents to out if valid, else return false.
get(type_t & out) const670b57cec5SDimitry Andric   bool get(type_t &out) const {
680b57cec5SDimitry Andric     if (valid)
690b57cec5SDimitry Andric       out = data;
700b57cec5SDimitry Andric     return valid;
710b57cec5SDimitry Andric   }
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   // Return a pointer to the contents or nullptr if it was not valid.
get() const740b57cec5SDimitry Andric   const type_t *get() const { return valid ? &data : nullptr; }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   // Assign data explicitly.
set(const type_t in)770b57cec5SDimitry Andric   void set(const type_t in) {
780b57cec5SDimitry Andric     data = in;
790b57cec5SDimitry Andric     valid = true;
800b57cec5SDimitry Andric   }
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   // Mark contents as invalid.
invalidate()830b57cec5SDimitry Andric   void invalidate() { valid = false; }
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric   // Returns true if this type contains valid data.
isValid() const860b57cec5SDimitry Andric   bool isValid() const { return valid; }
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   // Assignment operator.
operator =(const type_t in)890b57cec5SDimitry Andric   empirical_type<type_t> &operator=(const type_t in) {
900b57cec5SDimitry Andric     set(in);
910b57cec5SDimitry Andric     return *this;
920b57cec5SDimitry Andric   }
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric   // Dereference operator returns contents.
950b57cec5SDimitry Andric   // Warning: Will assert if not valid so use only when you know data is valid.
operator *() const960b57cec5SDimitry Andric   const type_t &operator*() const {
970b57cec5SDimitry Andric     assert(valid);
980b57cec5SDimitry Andric     return data;
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric protected:
102*5f7ddb14SDimitry Andric   bool valid = false;
1030b57cec5SDimitry Andric   type_t data;
1040b57cec5SDimitry Andric };
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric // ArgItem is used by the GetArgs() function when reading function arguments
1070b57cec5SDimitry Andric // from the target.
1080b57cec5SDimitry Andric struct ArgItem {
1090b57cec5SDimitry Andric   enum { ePointer, eInt32, eInt64, eLong, eBool } type;
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   uint64_t value;
1120b57cec5SDimitry Andric 
operator uint64_t__anon7ce3118e0111::ArgItem1130b57cec5SDimitry Andric   explicit operator uint64_t() const { return value; }
1140b57cec5SDimitry Andric };
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric // Context structure to be passed into GetArgsXXX(), argument reading functions
1170b57cec5SDimitry Andric // below.
1180b57cec5SDimitry Andric struct GetArgsCtx {
1190b57cec5SDimitry Andric   RegisterContext *reg_ctx;
1200b57cec5SDimitry Andric   Process *process;
1210b57cec5SDimitry Andric };
1220b57cec5SDimitry Andric 
GetArgsX86(const GetArgsCtx & ctx,ArgItem * arg_list,size_t num_args)1230b57cec5SDimitry Andric bool GetArgsX86(const GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
1240b57cec5SDimitry Andric   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   Status err;
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   // get the current stack pointer
1290b57cec5SDimitry Andric   uint64_t sp = ctx.reg_ctx->GetSP();
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   for (size_t i = 0; i < num_args; ++i) {
1320b57cec5SDimitry Andric     ArgItem &arg = arg_list[i];
1330b57cec5SDimitry Andric     // advance up the stack by one argument
1340b57cec5SDimitry Andric     sp += sizeof(uint32_t);
1350b57cec5SDimitry Andric     // get the argument type size
1360b57cec5SDimitry Andric     size_t arg_size = sizeof(uint32_t);
1370b57cec5SDimitry Andric     // read the argument from memory
1380b57cec5SDimitry Andric     arg.value = 0;
1390b57cec5SDimitry Andric     Status err;
1400b57cec5SDimitry Andric     size_t read =
1410b57cec5SDimitry Andric         ctx.process->ReadMemory(sp, &arg.value, sizeof(uint32_t), err);
1420b57cec5SDimitry Andric     if (read != arg_size || !err.Success()) {
1439dba64beSDimitry Andric       LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 " '%s'",
1440b57cec5SDimitry Andric                 __FUNCTION__, uint64_t(i), err.AsCString());
1450b57cec5SDimitry Andric       return false;
1460b57cec5SDimitry Andric     }
1470b57cec5SDimitry Andric   }
1480b57cec5SDimitry Andric   return true;
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric 
GetArgsX86_64(GetArgsCtx & ctx,ArgItem * arg_list,size_t num_args)1510b57cec5SDimitry Andric bool GetArgsX86_64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
1520b57cec5SDimitry Andric   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   // number of arguments passed in registers
1550b57cec5SDimitry Andric   static const uint32_t args_in_reg = 6;
1560b57cec5SDimitry Andric   // register passing order
1570b57cec5SDimitry Andric   static const std::array<const char *, args_in_reg> reg_names{
1580b57cec5SDimitry Andric       {"rdi", "rsi", "rdx", "rcx", "r8", "r9"}};
1590b57cec5SDimitry Andric   // argument type to size mapping
1600b57cec5SDimitry Andric   static const std::array<size_t, 5> arg_size{{
1610b57cec5SDimitry Andric       8, // ePointer,
1620b57cec5SDimitry Andric       4, // eInt32,
1630b57cec5SDimitry Andric       8, // eInt64,
1640b57cec5SDimitry Andric       8, // eLong,
1650b57cec5SDimitry Andric       4, // eBool,
1660b57cec5SDimitry Andric   }};
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   Status err;
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   // get the current stack pointer
1710b57cec5SDimitry Andric   uint64_t sp = ctx.reg_ctx->GetSP();
1720b57cec5SDimitry Andric   // step over the return address
1730b57cec5SDimitry Andric   sp += sizeof(uint64_t);
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   // check the stack alignment was correct (16 byte aligned)
1760b57cec5SDimitry Andric   if ((sp & 0xf) != 0x0) {
1779dba64beSDimitry Andric     LLDB_LOGF(log, "%s - stack misaligned", __FUNCTION__);
1780b57cec5SDimitry Andric     return false;
1790b57cec5SDimitry Andric   }
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric   // find the start of arguments on the stack
1820b57cec5SDimitry Andric   uint64_t sp_offset = 0;
1830b57cec5SDimitry Andric   for (uint32_t i = args_in_reg; i < num_args; ++i) {
1840b57cec5SDimitry Andric     sp_offset += arg_size[arg_list[i].type];
1850b57cec5SDimitry Andric   }
1860b57cec5SDimitry Andric   // round up to multiple of 16
1870b57cec5SDimitry Andric   sp_offset = (sp_offset + 0xf) & 0xf;
1880b57cec5SDimitry Andric   sp += sp_offset;
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric   for (size_t i = 0; i < num_args; ++i) {
1910b57cec5SDimitry Andric     bool success = false;
1920b57cec5SDimitry Andric     ArgItem &arg = arg_list[i];
1930b57cec5SDimitry Andric     // arguments passed in registers
1940b57cec5SDimitry Andric     if (i < args_in_reg) {
1950b57cec5SDimitry Andric       const RegisterInfo *reg =
1960b57cec5SDimitry Andric           ctx.reg_ctx->GetRegisterInfoByName(reg_names[i]);
1970b57cec5SDimitry Andric       RegisterValue reg_val;
1980b57cec5SDimitry Andric       if (ctx.reg_ctx->ReadRegister(reg, reg_val))
1990b57cec5SDimitry Andric         arg.value = reg_val.GetAsUInt64(0, &success);
2000b57cec5SDimitry Andric     }
2010b57cec5SDimitry Andric     // arguments passed on the stack
2020b57cec5SDimitry Andric     else {
2030b57cec5SDimitry Andric       // get the argument type size
2040b57cec5SDimitry Andric       const size_t size = arg_size[arg_list[i].type];
2050b57cec5SDimitry Andric       // read the argument from memory
2060b57cec5SDimitry Andric       arg.value = 0;
2070b57cec5SDimitry Andric       // note: due to little endian layout reading 4 or 8 bytes will give the
2080b57cec5SDimitry Andric       // correct value.
2090b57cec5SDimitry Andric       size_t read = ctx.process->ReadMemory(sp, &arg.value, size, err);
2100b57cec5SDimitry Andric       success = (err.Success() && read == size);
2110b57cec5SDimitry Andric       // advance past this argument
2120b57cec5SDimitry Andric       sp -= size;
2130b57cec5SDimitry Andric     }
2140b57cec5SDimitry Andric     // fail if we couldn't read this argument
2150b57cec5SDimitry Andric     if (!success) {
2169dba64beSDimitry Andric       LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s",
2170b57cec5SDimitry Andric                 __FUNCTION__, uint64_t(i), err.AsCString("n/a"));
2180b57cec5SDimitry Andric       return false;
2190b57cec5SDimitry Andric     }
2200b57cec5SDimitry Andric   }
2210b57cec5SDimitry Andric   return true;
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric 
GetArgsArm(GetArgsCtx & ctx,ArgItem * arg_list,size_t num_args)2240b57cec5SDimitry Andric bool GetArgsArm(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
2250b57cec5SDimitry Andric   // number of arguments passed in registers
2260b57cec5SDimitry Andric   static const uint32_t args_in_reg = 4;
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric   Status err;
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   // get the current stack pointer
2330b57cec5SDimitry Andric   uint64_t sp = ctx.reg_ctx->GetSP();
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric   for (size_t i = 0; i < num_args; ++i) {
2360b57cec5SDimitry Andric     bool success = false;
2370b57cec5SDimitry Andric     ArgItem &arg = arg_list[i];
2380b57cec5SDimitry Andric     // arguments passed in registers
2390b57cec5SDimitry Andric     if (i < args_in_reg) {
2400b57cec5SDimitry Andric       const RegisterInfo *reg = ctx.reg_ctx->GetRegisterInfoAtIndex(i);
2410b57cec5SDimitry Andric       RegisterValue reg_val;
2420b57cec5SDimitry Andric       if (ctx.reg_ctx->ReadRegister(reg, reg_val))
2430b57cec5SDimitry Andric         arg.value = reg_val.GetAsUInt32(0, &success);
2440b57cec5SDimitry Andric     }
2450b57cec5SDimitry Andric     // arguments passed on the stack
2460b57cec5SDimitry Andric     else {
2470b57cec5SDimitry Andric       // get the argument type size
2480b57cec5SDimitry Andric       const size_t arg_size = sizeof(uint32_t);
2490b57cec5SDimitry Andric       // clear all 64bits
2500b57cec5SDimitry Andric       arg.value = 0;
2510b57cec5SDimitry Andric       // read this argument from memory
2520b57cec5SDimitry Andric       size_t bytes_read =
2530b57cec5SDimitry Andric           ctx.process->ReadMemory(sp, &arg.value, arg_size, err);
2540b57cec5SDimitry Andric       success = (err.Success() && bytes_read == arg_size);
2550b57cec5SDimitry Andric       // advance the stack pointer
2560b57cec5SDimitry Andric       sp += sizeof(uint32_t);
2570b57cec5SDimitry Andric     }
2580b57cec5SDimitry Andric     // fail if we couldn't read this argument
2590b57cec5SDimitry Andric     if (!success) {
2609dba64beSDimitry Andric       LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s",
2610b57cec5SDimitry Andric                 __FUNCTION__, uint64_t(i), err.AsCString("n/a"));
2620b57cec5SDimitry Andric       return false;
2630b57cec5SDimitry Andric     }
2640b57cec5SDimitry Andric   }
2650b57cec5SDimitry Andric   return true;
2660b57cec5SDimitry Andric }
2670b57cec5SDimitry Andric 
GetArgsAarch64(GetArgsCtx & ctx,ArgItem * arg_list,size_t num_args)2680b57cec5SDimitry Andric bool GetArgsAarch64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
2690b57cec5SDimitry Andric   // number of arguments passed in registers
2700b57cec5SDimitry Andric   static const uint32_t args_in_reg = 8;
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric   for (size_t i = 0; i < num_args; ++i) {
2750b57cec5SDimitry Andric     bool success = false;
2760b57cec5SDimitry Andric     ArgItem &arg = arg_list[i];
2770b57cec5SDimitry Andric     // arguments passed in registers
2780b57cec5SDimitry Andric     if (i < args_in_reg) {
2790b57cec5SDimitry Andric       const RegisterInfo *reg = ctx.reg_ctx->GetRegisterInfoAtIndex(i);
2800b57cec5SDimitry Andric       RegisterValue reg_val;
2810b57cec5SDimitry Andric       if (ctx.reg_ctx->ReadRegister(reg, reg_val))
2820b57cec5SDimitry Andric         arg.value = reg_val.GetAsUInt64(0, &success);
2830b57cec5SDimitry Andric     }
2840b57cec5SDimitry Andric     // arguments passed on the stack
2850b57cec5SDimitry Andric     else {
2869dba64beSDimitry Andric       LLDB_LOGF(log, "%s - reading arguments spilled to stack not implemented",
2870b57cec5SDimitry Andric                 __FUNCTION__);
2880b57cec5SDimitry Andric     }
2890b57cec5SDimitry Andric     // fail if we couldn't read this argument
2900b57cec5SDimitry Andric     if (!success) {
2919dba64beSDimitry Andric       LLDB_LOGF(log, "%s - error reading argument: %" PRIu64, __FUNCTION__,
2920b57cec5SDimitry Andric                 uint64_t(i));
2930b57cec5SDimitry Andric       return false;
2940b57cec5SDimitry Andric     }
2950b57cec5SDimitry Andric   }
2960b57cec5SDimitry Andric   return true;
2970b57cec5SDimitry Andric }
2980b57cec5SDimitry Andric 
GetArgsMipsel(GetArgsCtx & ctx,ArgItem * arg_list,size_t num_args)2990b57cec5SDimitry Andric bool GetArgsMipsel(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
3000b57cec5SDimitry Andric   // number of arguments passed in registers
3010b57cec5SDimitry Andric   static const uint32_t args_in_reg = 4;
3020b57cec5SDimitry Andric   // register file offset to first argument
3030b57cec5SDimitry Andric   static const uint32_t reg_offset = 4;
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
3060b57cec5SDimitry Andric 
3070b57cec5SDimitry Andric   Status err;
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric   // find offset to arguments on the stack (+16 to skip over a0-a3 shadow
3100b57cec5SDimitry Andric   // space)
3110b57cec5SDimitry Andric   uint64_t sp = ctx.reg_ctx->GetSP() + 16;
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   for (size_t i = 0; i < num_args; ++i) {
3140b57cec5SDimitry Andric     bool success = false;
3150b57cec5SDimitry Andric     ArgItem &arg = arg_list[i];
3160b57cec5SDimitry Andric     // arguments passed in registers
3170b57cec5SDimitry Andric     if (i < args_in_reg) {
3180b57cec5SDimitry Andric       const RegisterInfo *reg =
3190b57cec5SDimitry Andric           ctx.reg_ctx->GetRegisterInfoAtIndex(i + reg_offset);
3200b57cec5SDimitry Andric       RegisterValue reg_val;
3210b57cec5SDimitry Andric       if (ctx.reg_ctx->ReadRegister(reg, reg_val))
3220b57cec5SDimitry Andric         arg.value = reg_val.GetAsUInt64(0, &success);
3230b57cec5SDimitry Andric     }
3240b57cec5SDimitry Andric     // arguments passed on the stack
3250b57cec5SDimitry Andric     else {
3260b57cec5SDimitry Andric       const size_t arg_size = sizeof(uint32_t);
3270b57cec5SDimitry Andric       arg.value = 0;
3280b57cec5SDimitry Andric       size_t bytes_read =
3290b57cec5SDimitry Andric           ctx.process->ReadMemory(sp, &arg.value, arg_size, err);
3300b57cec5SDimitry Andric       success = (err.Success() && bytes_read == arg_size);
3310b57cec5SDimitry Andric       // advance the stack pointer
3320b57cec5SDimitry Andric       sp += arg_size;
3330b57cec5SDimitry Andric     }
3340b57cec5SDimitry Andric     // fail if we couldn't read this argument
3350b57cec5SDimitry Andric     if (!success) {
3369dba64beSDimitry Andric       LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s",
3370b57cec5SDimitry Andric                 __FUNCTION__, uint64_t(i), err.AsCString("n/a"));
3380b57cec5SDimitry Andric       return false;
3390b57cec5SDimitry Andric     }
3400b57cec5SDimitry Andric   }
3410b57cec5SDimitry Andric   return true;
3420b57cec5SDimitry Andric }
3430b57cec5SDimitry Andric 
GetArgsMips64el(GetArgsCtx & ctx,ArgItem * arg_list,size_t num_args)3440b57cec5SDimitry Andric bool GetArgsMips64el(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
3450b57cec5SDimitry Andric   // number of arguments passed in registers
3460b57cec5SDimitry Andric   static const uint32_t args_in_reg = 8;
3470b57cec5SDimitry Andric   // register file offset to first argument
3480b57cec5SDimitry Andric   static const uint32_t reg_offset = 4;
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
3510b57cec5SDimitry Andric 
3520b57cec5SDimitry Andric   Status err;
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric   // get the current stack pointer
3550b57cec5SDimitry Andric   uint64_t sp = ctx.reg_ctx->GetSP();
3560b57cec5SDimitry Andric 
3570b57cec5SDimitry Andric   for (size_t i = 0; i < num_args; ++i) {
3580b57cec5SDimitry Andric     bool success = false;
3590b57cec5SDimitry Andric     ArgItem &arg = arg_list[i];
3600b57cec5SDimitry Andric     // arguments passed in registers
3610b57cec5SDimitry Andric     if (i < args_in_reg) {
3620b57cec5SDimitry Andric       const RegisterInfo *reg =
3630b57cec5SDimitry Andric           ctx.reg_ctx->GetRegisterInfoAtIndex(i + reg_offset);
3640b57cec5SDimitry Andric       RegisterValue reg_val;
3650b57cec5SDimitry Andric       if (ctx.reg_ctx->ReadRegister(reg, reg_val))
3660b57cec5SDimitry Andric         arg.value = reg_val.GetAsUInt64(0, &success);
3670b57cec5SDimitry Andric     }
3680b57cec5SDimitry Andric     // arguments passed on the stack
3690b57cec5SDimitry Andric     else {
3700b57cec5SDimitry Andric       // get the argument type size
3710b57cec5SDimitry Andric       const size_t arg_size = sizeof(uint64_t);
3720b57cec5SDimitry Andric       // clear all 64bits
3730b57cec5SDimitry Andric       arg.value = 0;
3740b57cec5SDimitry Andric       // read this argument from memory
3750b57cec5SDimitry Andric       size_t bytes_read =
3760b57cec5SDimitry Andric           ctx.process->ReadMemory(sp, &arg.value, arg_size, err);
3770b57cec5SDimitry Andric       success = (err.Success() && bytes_read == arg_size);
3780b57cec5SDimitry Andric       // advance the stack pointer
3790b57cec5SDimitry Andric       sp += arg_size;
3800b57cec5SDimitry Andric     }
3810b57cec5SDimitry Andric     // fail if we couldn't read this argument
3820b57cec5SDimitry Andric     if (!success) {
3839dba64beSDimitry Andric       LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s",
3840b57cec5SDimitry Andric                 __FUNCTION__, uint64_t(i), err.AsCString("n/a"));
3850b57cec5SDimitry Andric       return false;
3860b57cec5SDimitry Andric     }
3870b57cec5SDimitry Andric   }
3880b57cec5SDimitry Andric   return true;
3890b57cec5SDimitry Andric }
3900b57cec5SDimitry Andric 
GetArgs(ExecutionContext & exe_ctx,ArgItem * arg_list,size_t num_args)3910b57cec5SDimitry Andric bool GetArgs(ExecutionContext &exe_ctx, ArgItem *arg_list, size_t num_args) {
3920b57cec5SDimitry Andric   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric   // verify that we have a target
3950b57cec5SDimitry Andric   if (!exe_ctx.GetTargetPtr()) {
3969dba64beSDimitry Andric     LLDB_LOGF(log, "%s - invalid target", __FUNCTION__);
3970b57cec5SDimitry Andric     return false;
3980b57cec5SDimitry Andric   }
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric   GetArgsCtx ctx = {exe_ctx.GetRegisterContext(), exe_ctx.GetProcessPtr()};
4010b57cec5SDimitry Andric   assert(ctx.reg_ctx && ctx.process);
4020b57cec5SDimitry Andric 
4030b57cec5SDimitry Andric   // dispatch based on architecture
4040b57cec5SDimitry Andric   switch (exe_ctx.GetTargetPtr()->GetArchitecture().GetMachine()) {
4050b57cec5SDimitry Andric   case llvm::Triple::ArchType::x86:
4060b57cec5SDimitry Andric     return GetArgsX86(ctx, arg_list, num_args);
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric   case llvm::Triple::ArchType::x86_64:
4090b57cec5SDimitry Andric     return GetArgsX86_64(ctx, arg_list, num_args);
4100b57cec5SDimitry Andric 
4110b57cec5SDimitry Andric   case llvm::Triple::ArchType::arm:
4120b57cec5SDimitry Andric     return GetArgsArm(ctx, arg_list, num_args);
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric   case llvm::Triple::ArchType::aarch64:
4150b57cec5SDimitry Andric     return GetArgsAarch64(ctx, arg_list, num_args);
4160b57cec5SDimitry Andric 
4170b57cec5SDimitry Andric   case llvm::Triple::ArchType::mipsel:
4180b57cec5SDimitry Andric     return GetArgsMipsel(ctx, arg_list, num_args);
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric   case llvm::Triple::ArchType::mips64el:
4210b57cec5SDimitry Andric     return GetArgsMips64el(ctx, arg_list, num_args);
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric   default:
4240b57cec5SDimitry Andric     // unsupported architecture
4250b57cec5SDimitry Andric     if (log) {
4269dba64beSDimitry Andric       LLDB_LOGF(log, "%s - architecture not supported: '%s'", __FUNCTION__,
4270b57cec5SDimitry Andric                 exe_ctx.GetTargetRef().GetArchitecture().GetArchitectureName());
4280b57cec5SDimitry Andric     }
4290b57cec5SDimitry Andric     return false;
4300b57cec5SDimitry Andric   }
4310b57cec5SDimitry Andric }
4320b57cec5SDimitry Andric 
IsRenderScriptScriptModule(ModuleSP module)4330b57cec5SDimitry Andric bool IsRenderScriptScriptModule(ModuleSP module) {
4340b57cec5SDimitry Andric   if (!module)
4350b57cec5SDimitry Andric     return false;
4360b57cec5SDimitry Andric   return module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"),
4370b57cec5SDimitry Andric                                                 eSymbolTypeData) != nullptr;
4380b57cec5SDimitry Andric }
4390b57cec5SDimitry Andric 
ParseCoordinate(llvm::StringRef coord_s,RSCoordinate & coord)4400b57cec5SDimitry Andric bool ParseCoordinate(llvm::StringRef coord_s, RSCoordinate &coord) {
4410b57cec5SDimitry Andric   // takes an argument of the form 'num[,num][,num]'. Where 'coord_s' is a
4420b57cec5SDimitry Andric   // comma separated 1,2 or 3-dimensional coordinate with the whitespace
4430b57cec5SDimitry Andric   // trimmed. Missing coordinates are defaulted to zero. If parsing of any
4440b57cec5SDimitry Andric   // elements fails the contents of &coord are undefined and `false` is
4450b57cec5SDimitry Andric   // returned, `true` otherwise
4460b57cec5SDimitry Andric 
4479dba64beSDimitry Andric   llvm::SmallVector<llvm::StringRef, 4> matches;
4480b57cec5SDimitry Andric 
4499dba64beSDimitry Andric   if (!RegularExpression("^([0-9]+),([0-9]+),([0-9]+)$")
4509dba64beSDimitry Andric            .Execute(coord_s, &matches) &&
4519dba64beSDimitry Andric       !RegularExpression("^([0-9]+),([0-9]+)$").Execute(coord_s, &matches) &&
4529dba64beSDimitry Andric       !RegularExpression("^([0-9]+)$").Execute(coord_s, &matches))
4530b57cec5SDimitry Andric     return false;
4540b57cec5SDimitry Andric 
4559dba64beSDimitry Andric   auto get_index = [&](size_t idx, uint32_t &i) -> bool {
4560b57cec5SDimitry Andric     std::string group;
4570b57cec5SDimitry Andric     errno = 0;
4589dba64beSDimitry Andric     if (idx + 1 < matches.size()) {
4599dba64beSDimitry Andric       return !llvm::StringRef(matches[idx + 1]).getAsInteger<uint32_t>(10, i);
4609dba64beSDimitry Andric     }
4610b57cec5SDimitry Andric     return true;
4620b57cec5SDimitry Andric   };
4630b57cec5SDimitry Andric 
4640b57cec5SDimitry Andric   return get_index(0, coord.x) && get_index(1, coord.y) &&
4650b57cec5SDimitry Andric          get_index(2, coord.z);
4660b57cec5SDimitry Andric }
4670b57cec5SDimitry Andric 
SkipPrologue(lldb::ModuleSP & module,Address & addr)4680b57cec5SDimitry Andric bool SkipPrologue(lldb::ModuleSP &module, Address &addr) {
4690b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
4700b57cec5SDimitry Andric   SymbolContext sc;
4710b57cec5SDimitry Andric   uint32_t resolved_flags =
4720b57cec5SDimitry Andric       module->ResolveSymbolContextForAddress(addr, eSymbolContextFunction, sc);
4730b57cec5SDimitry Andric   if (resolved_flags & eSymbolContextFunction) {
4740b57cec5SDimitry Andric     if (sc.function) {
4750b57cec5SDimitry Andric       const uint32_t offset = sc.function->GetPrologueByteSize();
4760b57cec5SDimitry Andric       ConstString name = sc.GetFunctionName();
4770b57cec5SDimitry Andric       if (offset)
4780b57cec5SDimitry Andric         addr.Slide(offset);
4799dba64beSDimitry Andric       LLDB_LOGF(log, "%s: Prologue offset for %s is %" PRIu32, __FUNCTION__,
4800b57cec5SDimitry Andric                 name.AsCString(), offset);
4810b57cec5SDimitry Andric     }
4820b57cec5SDimitry Andric     return true;
4830b57cec5SDimitry Andric   } else
4840b57cec5SDimitry Andric     return false;
4850b57cec5SDimitry Andric }
4860b57cec5SDimitry Andric } // anonymous namespace
4870b57cec5SDimitry Andric 
4880b57cec5SDimitry Andric // The ScriptDetails class collects data associated with a single script
4890b57cec5SDimitry Andric // instance.
4900b57cec5SDimitry Andric struct RenderScriptRuntime::ScriptDetails {
4910b57cec5SDimitry Andric   ~ScriptDetails() = default;
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric   enum ScriptType { eScript, eScriptC };
4940b57cec5SDimitry Andric 
4950b57cec5SDimitry Andric   // The derived type of the script.
4960b57cec5SDimitry Andric   empirical_type<ScriptType> type;
4970b57cec5SDimitry Andric   // The name of the original source file.
4980b57cec5SDimitry Andric   empirical_type<std::string> res_name;
4990b57cec5SDimitry Andric   // Path to script .so file on the device.
5000b57cec5SDimitry Andric   empirical_type<std::string> shared_lib;
5010b57cec5SDimitry Andric   // Directory where kernel objects are cached on device.
5020b57cec5SDimitry Andric   empirical_type<std::string> cache_dir;
5030b57cec5SDimitry Andric   // Pointer to the context which owns this script.
5040b57cec5SDimitry Andric   empirical_type<lldb::addr_t> context;
5050b57cec5SDimitry Andric   // Pointer to the script object itself.
5060b57cec5SDimitry Andric   empirical_type<lldb::addr_t> script;
5070b57cec5SDimitry Andric };
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric // This Element class represents the Element object in RS, defining the type
5100b57cec5SDimitry Andric // associated with an Allocation.
5110b57cec5SDimitry Andric struct RenderScriptRuntime::Element {
5120b57cec5SDimitry Andric   // Taken from rsDefines.h
5130b57cec5SDimitry Andric   enum DataKind {
5140b57cec5SDimitry Andric     RS_KIND_USER,
5150b57cec5SDimitry Andric     RS_KIND_PIXEL_L = 7,
5160b57cec5SDimitry Andric     RS_KIND_PIXEL_A,
5170b57cec5SDimitry Andric     RS_KIND_PIXEL_LA,
5180b57cec5SDimitry Andric     RS_KIND_PIXEL_RGB,
5190b57cec5SDimitry Andric     RS_KIND_PIXEL_RGBA,
5200b57cec5SDimitry Andric     RS_KIND_PIXEL_DEPTH,
5210b57cec5SDimitry Andric     RS_KIND_PIXEL_YUV,
5220b57cec5SDimitry Andric     RS_KIND_INVALID = 100
5230b57cec5SDimitry Andric   };
5240b57cec5SDimitry Andric 
5250b57cec5SDimitry Andric   // Taken from rsDefines.h
5260b57cec5SDimitry Andric   enum DataType {
5270b57cec5SDimitry Andric     RS_TYPE_NONE = 0,
5280b57cec5SDimitry Andric     RS_TYPE_FLOAT_16,
5290b57cec5SDimitry Andric     RS_TYPE_FLOAT_32,
5300b57cec5SDimitry Andric     RS_TYPE_FLOAT_64,
5310b57cec5SDimitry Andric     RS_TYPE_SIGNED_8,
5320b57cec5SDimitry Andric     RS_TYPE_SIGNED_16,
5330b57cec5SDimitry Andric     RS_TYPE_SIGNED_32,
5340b57cec5SDimitry Andric     RS_TYPE_SIGNED_64,
5350b57cec5SDimitry Andric     RS_TYPE_UNSIGNED_8,
5360b57cec5SDimitry Andric     RS_TYPE_UNSIGNED_16,
5370b57cec5SDimitry Andric     RS_TYPE_UNSIGNED_32,
5380b57cec5SDimitry Andric     RS_TYPE_UNSIGNED_64,
5390b57cec5SDimitry Andric     RS_TYPE_BOOLEAN,
5400b57cec5SDimitry Andric 
5410b57cec5SDimitry Andric     RS_TYPE_UNSIGNED_5_6_5,
5420b57cec5SDimitry Andric     RS_TYPE_UNSIGNED_5_5_5_1,
5430b57cec5SDimitry Andric     RS_TYPE_UNSIGNED_4_4_4_4,
5440b57cec5SDimitry Andric 
5450b57cec5SDimitry Andric     RS_TYPE_MATRIX_4X4,
5460b57cec5SDimitry Andric     RS_TYPE_MATRIX_3X3,
5470b57cec5SDimitry Andric     RS_TYPE_MATRIX_2X2,
5480b57cec5SDimitry Andric 
5490b57cec5SDimitry Andric     RS_TYPE_ELEMENT = 1000,
5500b57cec5SDimitry Andric     RS_TYPE_TYPE,
5510b57cec5SDimitry Andric     RS_TYPE_ALLOCATION,
5520b57cec5SDimitry Andric     RS_TYPE_SAMPLER,
5530b57cec5SDimitry Andric     RS_TYPE_SCRIPT,
5540b57cec5SDimitry Andric     RS_TYPE_MESH,
5550b57cec5SDimitry Andric     RS_TYPE_PROGRAM_FRAGMENT,
5560b57cec5SDimitry Andric     RS_TYPE_PROGRAM_VERTEX,
5570b57cec5SDimitry Andric     RS_TYPE_PROGRAM_RASTER,
5580b57cec5SDimitry Andric     RS_TYPE_PROGRAM_STORE,
5590b57cec5SDimitry Andric     RS_TYPE_FONT,
5600b57cec5SDimitry Andric 
5610b57cec5SDimitry Andric     RS_TYPE_INVALID = 10000
5620b57cec5SDimitry Andric   };
5630b57cec5SDimitry Andric 
5640b57cec5SDimitry Andric   std::vector<Element> children; // Child Element fields for structs
5650b57cec5SDimitry Andric   empirical_type<lldb::addr_t>
5660b57cec5SDimitry Andric       element_ptr; // Pointer to the RS Element of the Type
5670b57cec5SDimitry Andric   empirical_type<DataType>
5680b57cec5SDimitry Andric       type; // Type of each data pointer stored by the allocation
5690b57cec5SDimitry Andric   empirical_type<DataKind>
5700b57cec5SDimitry Andric       type_kind; // Defines pixel type if Allocation is created from an image
5710b57cec5SDimitry Andric   empirical_type<uint32_t>
5720b57cec5SDimitry Andric       type_vec_size; // Vector size of each data point, e.g '4' for uchar4
5730b57cec5SDimitry Andric   empirical_type<uint32_t> field_count; // Number of Subelements
5740b57cec5SDimitry Andric   empirical_type<uint32_t> datum_size;  // Size of a single Element with padding
5750b57cec5SDimitry Andric   empirical_type<uint32_t> padding;     // Number of padding bytes
5760b57cec5SDimitry Andric   empirical_type<uint32_t>
5770b57cec5SDimitry Andric       array_size;        // Number of items in array, only needed for structs
5780b57cec5SDimitry Andric   ConstString type_name; // Name of type, only needed for structs
5790b57cec5SDimitry Andric 
5800b57cec5SDimitry Andric   static ConstString
5810b57cec5SDimitry Andric   GetFallbackStructName(); // Print this as the type name of a struct Element
5820b57cec5SDimitry Andric                            // If we can't resolve the actual struct name
5830b57cec5SDimitry Andric 
ShouldRefreshRenderScriptRuntime::Element5840b57cec5SDimitry Andric   bool ShouldRefresh() const {
5850b57cec5SDimitry Andric     const bool valid_ptr = element_ptr.isValid() && *element_ptr.get() != 0x0;
5860b57cec5SDimitry Andric     const bool valid_type =
5870b57cec5SDimitry Andric         type.isValid() && type_vec_size.isValid() && type_kind.isValid();
5880b57cec5SDimitry Andric     return !valid_ptr || !valid_type || !datum_size.isValid();
5890b57cec5SDimitry Andric   }
5900b57cec5SDimitry Andric };
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric // This AllocationDetails class collects data associated with a single
5930b57cec5SDimitry Andric // allocation instance.
5940b57cec5SDimitry Andric struct RenderScriptRuntime::AllocationDetails {
5950b57cec5SDimitry Andric   struct Dimension {
5960b57cec5SDimitry Andric     uint32_t dim_1;
5970b57cec5SDimitry Andric     uint32_t dim_2;
5980b57cec5SDimitry Andric     uint32_t dim_3;
5990b57cec5SDimitry Andric     uint32_t cube_map;
6000b57cec5SDimitry Andric 
DimensionRenderScriptRuntime::AllocationDetails::Dimension6010b57cec5SDimitry Andric     Dimension() {
6020b57cec5SDimitry Andric       dim_1 = 0;
6030b57cec5SDimitry Andric       dim_2 = 0;
6040b57cec5SDimitry Andric       dim_3 = 0;
6050b57cec5SDimitry Andric       cube_map = 0;
6060b57cec5SDimitry Andric     }
6070b57cec5SDimitry Andric   };
6080b57cec5SDimitry Andric 
6090b57cec5SDimitry Andric   // The FileHeader struct specifies the header we use for writing allocations
6100b57cec5SDimitry Andric   // to a binary file. Our format begins with the ASCII characters "RSAD",
6110b57cec5SDimitry Andric   // identifying the file as an allocation dump. Member variables dims and
6120b57cec5SDimitry Andric   // hdr_size are then written consecutively, immediately followed by an
6130b57cec5SDimitry Andric   // instance of the ElementHeader struct. Because Elements can contain
6140b57cec5SDimitry Andric   // subelements, there may be more than one instance of the ElementHeader
6150b57cec5SDimitry Andric   // struct. With this first instance being the root element, and the other
6160b57cec5SDimitry Andric   // instances being the root's descendants. To identify which instances are an
6170b57cec5SDimitry Andric   // ElementHeader's children, each struct is immediately followed by a
6180b57cec5SDimitry Andric   // sequence of consecutive offsets to the start of its child structs. These
6190b57cec5SDimitry Andric   // offsets are
6200b57cec5SDimitry Andric   // 4 bytes in size, and the 0 offset signifies no more children.
6210b57cec5SDimitry Andric   struct FileHeader {
6220b57cec5SDimitry Andric     uint8_t ident[4];  // ASCII 'RSAD' identifying the file
6230b57cec5SDimitry Andric     uint32_t dims[3];  // Dimensions
6240b57cec5SDimitry Andric     uint16_t hdr_size; // Header size in bytes, including all element headers
6250b57cec5SDimitry Andric   };
6260b57cec5SDimitry Andric 
6270b57cec5SDimitry Andric   struct ElementHeader {
6280b57cec5SDimitry Andric     uint16_t type;         // DataType enum
6290b57cec5SDimitry Andric     uint32_t kind;         // DataKind enum
6300b57cec5SDimitry Andric     uint32_t element_size; // Size of a single element, including padding
6310b57cec5SDimitry Andric     uint16_t vector_size;  // Vector width
6320b57cec5SDimitry Andric     uint32_t array_size;   // Number of elements in array
6330b57cec5SDimitry Andric   };
6340b57cec5SDimitry Andric 
6350b57cec5SDimitry Andric   // Monotonically increasing from 1
6360b57cec5SDimitry Andric   static uint32_t ID;
6370b57cec5SDimitry Andric 
6380b57cec5SDimitry Andric   // Maps Allocation DataType enum and vector size to printable strings using
6390b57cec5SDimitry Andric   // mapping from RenderScript numerical types summary documentation
6400b57cec5SDimitry Andric   static const char *RsDataTypeToString[][4];
6410b57cec5SDimitry Andric 
6420b57cec5SDimitry Andric   // Maps Allocation DataKind enum to printable strings
6430b57cec5SDimitry Andric   static const char *RsDataKindToString[];
6440b57cec5SDimitry Andric 
6450b57cec5SDimitry Andric   // Maps allocation types to format sizes for printing.
6460b57cec5SDimitry Andric   static const uint32_t RSTypeToFormat[][3];
6470b57cec5SDimitry Andric 
6480b57cec5SDimitry Andric   // Give each allocation an ID as a way
6490b57cec5SDimitry Andric   // for commands to reference it.
6500b57cec5SDimitry Andric   const uint32_t id;
6510b57cec5SDimitry Andric 
6520b57cec5SDimitry Andric   // Allocation Element type
6530b57cec5SDimitry Andric   RenderScriptRuntime::Element element;
6540b57cec5SDimitry Andric   // Dimensions of the Allocation
6550b57cec5SDimitry Andric   empirical_type<Dimension> dimension;
6560b57cec5SDimitry Andric   // Pointer to address of the RS Allocation
6570b57cec5SDimitry Andric   empirical_type<lldb::addr_t> address;
6580b57cec5SDimitry Andric   // Pointer to the data held by the Allocation
6590b57cec5SDimitry Andric   empirical_type<lldb::addr_t> data_ptr;
6600b57cec5SDimitry Andric   // Pointer to the RS Type of the Allocation
6610b57cec5SDimitry Andric   empirical_type<lldb::addr_t> type_ptr;
6620b57cec5SDimitry Andric   // Pointer to the RS Context of the Allocation
6630b57cec5SDimitry Andric   empirical_type<lldb::addr_t> context;
6640b57cec5SDimitry Andric   // Size of the allocation
6650b57cec5SDimitry Andric   empirical_type<uint32_t> size;
6660b57cec5SDimitry Andric   // Stride between rows of the allocation
6670b57cec5SDimitry Andric   empirical_type<uint32_t> stride;
6680b57cec5SDimitry Andric 
6690b57cec5SDimitry Andric   // Give each allocation an id, so we can reference it in user commands.
AllocationDetailsRenderScriptRuntime::AllocationDetails6700b57cec5SDimitry Andric   AllocationDetails() : id(ID++) {}
6710b57cec5SDimitry Andric 
ShouldRefreshRenderScriptRuntime::AllocationDetails6720b57cec5SDimitry Andric   bool ShouldRefresh() const {
6730b57cec5SDimitry Andric     bool valid_ptrs = data_ptr.isValid() && *data_ptr.get() != 0x0;
6740b57cec5SDimitry Andric     valid_ptrs = valid_ptrs && type_ptr.isValid() && *type_ptr.get() != 0x0;
6750b57cec5SDimitry Andric     return !valid_ptrs || !dimension.isValid() || !size.isValid() ||
6760b57cec5SDimitry Andric            element.ShouldRefresh();
6770b57cec5SDimitry Andric   }
6780b57cec5SDimitry Andric };
6790b57cec5SDimitry Andric 
GetFallbackStructName()6800b57cec5SDimitry Andric ConstString RenderScriptRuntime::Element::GetFallbackStructName() {
6810b57cec5SDimitry Andric   static const ConstString FallbackStructName("struct");
6820b57cec5SDimitry Andric   return FallbackStructName;
6830b57cec5SDimitry Andric }
6840b57cec5SDimitry Andric 
6850b57cec5SDimitry Andric uint32_t RenderScriptRuntime::AllocationDetails::ID = 1;
6860b57cec5SDimitry Andric 
6870b57cec5SDimitry Andric const char *RenderScriptRuntime::AllocationDetails::RsDataKindToString[] = {
6880b57cec5SDimitry Andric     "User",       "Undefined",   "Undefined", "Undefined",
6890b57cec5SDimitry Andric     "Undefined",  "Undefined",   "Undefined", // Enum jumps from 0 to 7
6900b57cec5SDimitry Andric     "L Pixel",    "A Pixel",     "LA Pixel",  "RGB Pixel",
6910b57cec5SDimitry Andric     "RGBA Pixel", "Pixel Depth", "YUV Pixel"};
6920b57cec5SDimitry Andric 
6930b57cec5SDimitry Andric const char *RenderScriptRuntime::AllocationDetails::RsDataTypeToString[][4] = {
6940b57cec5SDimitry Andric     {"None", "None", "None", "None"},
6950b57cec5SDimitry Andric     {"half", "half2", "half3", "half4"},
6960b57cec5SDimitry Andric     {"float", "float2", "float3", "float4"},
6970b57cec5SDimitry Andric     {"double", "double2", "double3", "double4"},
6980b57cec5SDimitry Andric     {"char", "char2", "char3", "char4"},
6990b57cec5SDimitry Andric     {"short", "short2", "short3", "short4"},
7000b57cec5SDimitry Andric     {"int", "int2", "int3", "int4"},
7010b57cec5SDimitry Andric     {"long", "long2", "long3", "long4"},
7020b57cec5SDimitry Andric     {"uchar", "uchar2", "uchar3", "uchar4"},
7030b57cec5SDimitry Andric     {"ushort", "ushort2", "ushort3", "ushort4"},
7040b57cec5SDimitry Andric     {"uint", "uint2", "uint3", "uint4"},
7050b57cec5SDimitry Andric     {"ulong", "ulong2", "ulong3", "ulong4"},
7060b57cec5SDimitry Andric     {"bool", "bool2", "bool3", "bool4"},
7070b57cec5SDimitry Andric     {"packed_565", "packed_565", "packed_565", "packed_565"},
7080b57cec5SDimitry Andric     {"packed_5551", "packed_5551", "packed_5551", "packed_5551"},
7090b57cec5SDimitry Andric     {"packed_4444", "packed_4444", "packed_4444", "packed_4444"},
7100b57cec5SDimitry Andric     {"rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4"},
7110b57cec5SDimitry Andric     {"rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3"},
7120b57cec5SDimitry Andric     {"rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2"},
7130b57cec5SDimitry Andric 
7140b57cec5SDimitry Andric     // Handlers
7150b57cec5SDimitry Andric     {"RS Element", "RS Element", "RS Element", "RS Element"},
7160b57cec5SDimitry Andric     {"RS Type", "RS Type", "RS Type", "RS Type"},
7170b57cec5SDimitry Andric     {"RS Allocation", "RS Allocation", "RS Allocation", "RS Allocation"},
7180b57cec5SDimitry Andric     {"RS Sampler", "RS Sampler", "RS Sampler", "RS Sampler"},
7190b57cec5SDimitry Andric     {"RS Script", "RS Script", "RS Script", "RS Script"},
7200b57cec5SDimitry Andric 
7210b57cec5SDimitry Andric     // Deprecated
7220b57cec5SDimitry Andric     {"RS Mesh", "RS Mesh", "RS Mesh", "RS Mesh"},
7230b57cec5SDimitry Andric     {"RS Program Fragment", "RS Program Fragment", "RS Program Fragment",
7240b57cec5SDimitry Andric      "RS Program Fragment"},
7250b57cec5SDimitry Andric     {"RS Program Vertex", "RS Program Vertex", "RS Program Vertex",
7260b57cec5SDimitry Andric      "RS Program Vertex"},
7270b57cec5SDimitry Andric     {"RS Program Raster", "RS Program Raster", "RS Program Raster",
7280b57cec5SDimitry Andric      "RS Program Raster"},
7290b57cec5SDimitry Andric     {"RS Program Store", "RS Program Store", "RS Program Store",
7300b57cec5SDimitry Andric      "RS Program Store"},
7310b57cec5SDimitry Andric     {"RS Font", "RS Font", "RS Font", "RS Font"}};
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric // Used as an index into the RSTypeToFormat array elements
7340b57cec5SDimitry Andric enum TypeToFormatIndex { eFormatSingle = 0, eFormatVector, eElementSize };
7350b57cec5SDimitry Andric 
7360b57cec5SDimitry Andric // { format enum of single element, format enum of element vector, size of
7370b57cec5SDimitry Andric // element}
7380b57cec5SDimitry Andric const uint32_t RenderScriptRuntime::AllocationDetails::RSTypeToFormat[][3] = {
7390b57cec5SDimitry Andric     // RS_TYPE_NONE
7400b57cec5SDimitry Andric     {eFormatHex, eFormatHex, 1},
7410b57cec5SDimitry Andric     // RS_TYPE_FLOAT_16
7420b57cec5SDimitry Andric     {eFormatFloat, eFormatVectorOfFloat16, 2},
7430b57cec5SDimitry Andric     // RS_TYPE_FLOAT_32
7440b57cec5SDimitry Andric     {eFormatFloat, eFormatVectorOfFloat32, sizeof(float)},
7450b57cec5SDimitry Andric     // RS_TYPE_FLOAT_64
7460b57cec5SDimitry Andric     {eFormatFloat, eFormatVectorOfFloat64, sizeof(double)},
7470b57cec5SDimitry Andric     // RS_TYPE_SIGNED_8
7480b57cec5SDimitry Andric     {eFormatDecimal, eFormatVectorOfSInt8, sizeof(int8_t)},
7490b57cec5SDimitry Andric     // RS_TYPE_SIGNED_16
7500b57cec5SDimitry Andric     {eFormatDecimal, eFormatVectorOfSInt16, sizeof(int16_t)},
7510b57cec5SDimitry Andric     // RS_TYPE_SIGNED_32
7520b57cec5SDimitry Andric     {eFormatDecimal, eFormatVectorOfSInt32, sizeof(int32_t)},
7530b57cec5SDimitry Andric     // RS_TYPE_SIGNED_64
7540b57cec5SDimitry Andric     {eFormatDecimal, eFormatVectorOfSInt64, sizeof(int64_t)},
7550b57cec5SDimitry Andric     // RS_TYPE_UNSIGNED_8
7560b57cec5SDimitry Andric     {eFormatDecimal, eFormatVectorOfUInt8, sizeof(uint8_t)},
7570b57cec5SDimitry Andric     // RS_TYPE_UNSIGNED_16
7580b57cec5SDimitry Andric     {eFormatDecimal, eFormatVectorOfUInt16, sizeof(uint16_t)},
7590b57cec5SDimitry Andric     // RS_TYPE_UNSIGNED_32
7600b57cec5SDimitry Andric     {eFormatDecimal, eFormatVectorOfUInt32, sizeof(uint32_t)},
7610b57cec5SDimitry Andric     // RS_TYPE_UNSIGNED_64
7620b57cec5SDimitry Andric     {eFormatDecimal, eFormatVectorOfUInt64, sizeof(uint64_t)},
7630b57cec5SDimitry Andric     // RS_TYPE_BOOL
7640b57cec5SDimitry Andric     {eFormatBoolean, eFormatBoolean, 1},
7650b57cec5SDimitry Andric     // RS_TYPE_UNSIGNED_5_6_5
7660b57cec5SDimitry Andric     {eFormatHex, eFormatHex, sizeof(uint16_t)},
7670b57cec5SDimitry Andric     // RS_TYPE_UNSIGNED_5_5_5_1
7680b57cec5SDimitry Andric     {eFormatHex, eFormatHex, sizeof(uint16_t)},
7690b57cec5SDimitry Andric     // RS_TYPE_UNSIGNED_4_4_4_4
7700b57cec5SDimitry Andric     {eFormatHex, eFormatHex, sizeof(uint16_t)},
7710b57cec5SDimitry Andric     // RS_TYPE_MATRIX_4X4
7720b57cec5SDimitry Andric     {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 16},
7730b57cec5SDimitry Andric     // RS_TYPE_MATRIX_3X3
7740b57cec5SDimitry Andric     {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 9},
7750b57cec5SDimitry Andric     // RS_TYPE_MATRIX_2X2
7760b57cec5SDimitry Andric     {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 4}};
7770b57cec5SDimitry Andric 
7780b57cec5SDimitry Andric // Static Functions
7790b57cec5SDimitry Andric LanguageRuntime *
CreateInstance(Process * process,lldb::LanguageType language)7800b57cec5SDimitry Andric RenderScriptRuntime::CreateInstance(Process *process,
7810b57cec5SDimitry Andric                                     lldb::LanguageType language) {
7820b57cec5SDimitry Andric 
7830b57cec5SDimitry Andric   if (language == eLanguageTypeExtRenderScript)
7840b57cec5SDimitry Andric     return new RenderScriptRuntime(process);
7850b57cec5SDimitry Andric   else
7860b57cec5SDimitry Andric     return nullptr;
7870b57cec5SDimitry Andric }
7880b57cec5SDimitry Andric 
7890b57cec5SDimitry Andric // Callback with a module to search for matching symbols. We first check that
7900b57cec5SDimitry Andric // the module contains RS kernels. Then look for a symbol which matches our
7910b57cec5SDimitry Andric // kernel name. The breakpoint address is finally set using the address of this
7920b57cec5SDimitry Andric // symbol.
7930b57cec5SDimitry Andric Searcher::CallbackReturn
SearchCallback(SearchFilter & filter,SymbolContext & context,Address *)7940b57cec5SDimitry Andric RSBreakpointResolver::SearchCallback(SearchFilter &filter,
7959dba64beSDimitry Andric                                      SymbolContext &context, Address *) {
7965ffd83dbSDimitry Andric   BreakpointSP breakpoint_sp = GetBreakpoint();
7975ffd83dbSDimitry Andric   assert(breakpoint_sp);
7985ffd83dbSDimitry Andric 
7990b57cec5SDimitry Andric   ModuleSP module = context.module_sp;
8000b57cec5SDimitry Andric 
8010b57cec5SDimitry Andric   if (!module || !IsRenderScriptScriptModule(module))
8020b57cec5SDimitry Andric     return Searcher::eCallbackReturnContinue;
8030b57cec5SDimitry Andric 
8040b57cec5SDimitry Andric   // Attempt to set a breakpoint on the kernel name symbol within the module
8050b57cec5SDimitry Andric   // library. If it's not found, it's likely debug info is unavailable - try to
8060b57cec5SDimitry Andric   // set a breakpoint on <name>.expand.
8070b57cec5SDimitry Andric   const Symbol *kernel_sym =
8080b57cec5SDimitry Andric       module->FindFirstSymbolWithNameAndType(m_kernel_name, eSymbolTypeCode);
8090b57cec5SDimitry Andric   if (!kernel_sym) {
8100b57cec5SDimitry Andric     std::string kernel_name_expanded(m_kernel_name.AsCString());
8110b57cec5SDimitry Andric     kernel_name_expanded.append(".expand");
8120b57cec5SDimitry Andric     kernel_sym = module->FindFirstSymbolWithNameAndType(
8130b57cec5SDimitry Andric         ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode);
8140b57cec5SDimitry Andric   }
8150b57cec5SDimitry Andric 
8160b57cec5SDimitry Andric   if (kernel_sym) {
8170b57cec5SDimitry Andric     Address bp_addr = kernel_sym->GetAddress();
8180b57cec5SDimitry Andric     if (filter.AddressPasses(bp_addr))
8195ffd83dbSDimitry Andric       breakpoint_sp->AddLocation(bp_addr);
8200b57cec5SDimitry Andric   }
8210b57cec5SDimitry Andric 
8220b57cec5SDimitry Andric   return Searcher::eCallbackReturnContinue;
8230b57cec5SDimitry Andric }
8240b57cec5SDimitry Andric 
8250b57cec5SDimitry Andric Searcher::CallbackReturn
SearchCallback(lldb_private::SearchFilter & filter,lldb_private::SymbolContext & context,Address *)8260b57cec5SDimitry Andric RSReduceBreakpointResolver::SearchCallback(lldb_private::SearchFilter &filter,
8270b57cec5SDimitry Andric                                            lldb_private::SymbolContext &context,
8289dba64beSDimitry Andric                                            Address *) {
8295ffd83dbSDimitry Andric   BreakpointSP breakpoint_sp = GetBreakpoint();
8305ffd83dbSDimitry Andric   assert(breakpoint_sp);
8315ffd83dbSDimitry Andric 
8320b57cec5SDimitry Andric   // We need to have access to the list of reductions currently parsed, as
8330b57cec5SDimitry Andric   // reduce names don't actually exist as symbols in a module. They are only
8340b57cec5SDimitry Andric   // identifiable by parsing the .rs.info packet, or finding the expand symbol.
8350b57cec5SDimitry Andric   // We therefore need access to the list of parsed rs modules to properly
8360b57cec5SDimitry Andric   // resolve reduction names.
8370b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
8380b57cec5SDimitry Andric   ModuleSP module = context.module_sp;
8390b57cec5SDimitry Andric 
8400b57cec5SDimitry Andric   if (!module || !IsRenderScriptScriptModule(module))
8410b57cec5SDimitry Andric     return Searcher::eCallbackReturnContinue;
8420b57cec5SDimitry Andric 
8430b57cec5SDimitry Andric   if (!m_rsmodules)
8440b57cec5SDimitry Andric     return Searcher::eCallbackReturnContinue;
8450b57cec5SDimitry Andric 
8460b57cec5SDimitry Andric   for (const auto &module_desc : *m_rsmodules) {
8470b57cec5SDimitry Andric     if (module_desc->m_module != module)
8480b57cec5SDimitry Andric       continue;
8490b57cec5SDimitry Andric 
8500b57cec5SDimitry Andric     for (const auto &reduction : module_desc->m_reductions) {
8510b57cec5SDimitry Andric       if (reduction.m_reduce_name != m_reduce_name)
8520b57cec5SDimitry Andric         continue;
8530b57cec5SDimitry Andric 
8540b57cec5SDimitry Andric       std::array<std::pair<ConstString, int>, 5> funcs{
8550b57cec5SDimitry Andric           {{reduction.m_init_name, eKernelTypeInit},
8560b57cec5SDimitry Andric            {reduction.m_accum_name, eKernelTypeAccum},
8570b57cec5SDimitry Andric            {reduction.m_comb_name, eKernelTypeComb},
8580b57cec5SDimitry Andric            {reduction.m_outc_name, eKernelTypeOutC},
8590b57cec5SDimitry Andric            {reduction.m_halter_name, eKernelTypeHalter}}};
8600b57cec5SDimitry Andric 
8610b57cec5SDimitry Andric       for (const auto &kernel : funcs) {
8620b57cec5SDimitry Andric         // Skip constituent functions that don't match our spec
8630b57cec5SDimitry Andric         if (!(m_kernel_types & kernel.second))
8640b57cec5SDimitry Andric           continue;
8650b57cec5SDimitry Andric 
8660b57cec5SDimitry Andric         const auto kernel_name = kernel.first;
8670b57cec5SDimitry Andric         const auto symbol = module->FindFirstSymbolWithNameAndType(
8680b57cec5SDimitry Andric             kernel_name, eSymbolTypeCode);
8690b57cec5SDimitry Andric         if (!symbol)
8700b57cec5SDimitry Andric           continue;
8710b57cec5SDimitry Andric 
8720b57cec5SDimitry Andric         auto address = symbol->GetAddress();
8730b57cec5SDimitry Andric         if (filter.AddressPasses(address)) {
8740b57cec5SDimitry Andric           bool new_bp;
8750b57cec5SDimitry Andric           if (!SkipPrologue(module, address)) {
8769dba64beSDimitry Andric             LLDB_LOGF(log, "%s: Error trying to skip prologue", __FUNCTION__);
8770b57cec5SDimitry Andric           }
8785ffd83dbSDimitry Andric           breakpoint_sp->AddLocation(address, &new_bp);
8799dba64beSDimitry Andric           LLDB_LOGF(log, "%s: %s reduction breakpoint on %s in %s",
8809dba64beSDimitry Andric                     __FUNCTION__, new_bp ? "new" : "existing",
8819dba64beSDimitry Andric                     kernel_name.GetCString(),
8820b57cec5SDimitry Andric                     address.GetModule()->GetFileSpec().GetCString());
8830b57cec5SDimitry Andric         }
8840b57cec5SDimitry Andric       }
8850b57cec5SDimitry Andric     }
8860b57cec5SDimitry Andric   }
8870b57cec5SDimitry Andric   return eCallbackReturnContinue;
8880b57cec5SDimitry Andric }
8890b57cec5SDimitry Andric 
SearchCallback(SearchFilter & filter,SymbolContext & context,Address * addr)8900b57cec5SDimitry Andric Searcher::CallbackReturn RSScriptGroupBreakpointResolver::SearchCallback(
8919dba64beSDimitry Andric     SearchFilter &filter, SymbolContext &context, Address *addr) {
8920b57cec5SDimitry Andric 
8935ffd83dbSDimitry Andric   BreakpointSP breakpoint_sp = GetBreakpoint();
8945ffd83dbSDimitry Andric   if (!breakpoint_sp)
8950b57cec5SDimitry Andric     return eCallbackReturnContinue;
8960b57cec5SDimitry Andric 
8970b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
8980b57cec5SDimitry Andric   ModuleSP &module = context.module_sp;
8990b57cec5SDimitry Andric 
9000b57cec5SDimitry Andric   if (!module || !IsRenderScriptScriptModule(module))
9010b57cec5SDimitry Andric     return Searcher::eCallbackReturnContinue;
9020b57cec5SDimitry Andric 
9030b57cec5SDimitry Andric   std::vector<std::string> names;
9045ffd83dbSDimitry Andric   Breakpoint& breakpoint = *breakpoint_sp;
9055ffd83dbSDimitry Andric   breakpoint.GetNames(names);
9060b57cec5SDimitry Andric   if (names.empty())
9070b57cec5SDimitry Andric     return eCallbackReturnContinue;
9080b57cec5SDimitry Andric 
9090b57cec5SDimitry Andric   for (auto &name : names) {
9100b57cec5SDimitry Andric     const RSScriptGroupDescriptorSP sg = FindScriptGroup(ConstString(name));
9110b57cec5SDimitry Andric     if (!sg) {
9129dba64beSDimitry Andric       LLDB_LOGF(log, "%s: could not find script group for %s", __FUNCTION__,
9130b57cec5SDimitry Andric                 name.c_str());
9140b57cec5SDimitry Andric       continue;
9150b57cec5SDimitry Andric     }
9160b57cec5SDimitry Andric 
9179dba64beSDimitry Andric     LLDB_LOGF(log, "%s: Found ScriptGroup for %s", __FUNCTION__, name.c_str());
9180b57cec5SDimitry Andric 
9190b57cec5SDimitry Andric     for (const RSScriptGroupDescriptor::Kernel &k : sg->m_kernels) {
9200b57cec5SDimitry Andric       if (log) {
9219dba64beSDimitry Andric         LLDB_LOGF(log, "%s: Adding breakpoint for %s", __FUNCTION__,
9220b57cec5SDimitry Andric                   k.m_name.AsCString());
9239dba64beSDimitry Andric         LLDB_LOGF(log, "%s: Kernel address 0x%" PRIx64, __FUNCTION__, k.m_addr);
9240b57cec5SDimitry Andric       }
9250b57cec5SDimitry Andric 
9260b57cec5SDimitry Andric       const lldb_private::Symbol *sym =
9270b57cec5SDimitry Andric           module->FindFirstSymbolWithNameAndType(k.m_name, eSymbolTypeCode);
9280b57cec5SDimitry Andric       if (!sym) {
9299dba64beSDimitry Andric         LLDB_LOGF(log, "%s: Unable to find symbol for %s", __FUNCTION__,
9300b57cec5SDimitry Andric                   k.m_name.AsCString());
9310b57cec5SDimitry Andric         continue;
9320b57cec5SDimitry Andric       }
9330b57cec5SDimitry Andric 
9340b57cec5SDimitry Andric       if (log) {
9359dba64beSDimitry Andric         LLDB_LOGF(log, "%s: Found symbol name is %s", __FUNCTION__,
9360b57cec5SDimitry Andric                   sym->GetName().AsCString());
9370b57cec5SDimitry Andric       }
9380b57cec5SDimitry Andric 
9390b57cec5SDimitry Andric       auto address = sym->GetAddress();
9400b57cec5SDimitry Andric       if (!SkipPrologue(module, address)) {
9419dba64beSDimitry Andric         LLDB_LOGF(log, "%s: Error trying to skip prologue", __FUNCTION__);
9420b57cec5SDimitry Andric       }
9430b57cec5SDimitry Andric 
9440b57cec5SDimitry Andric       bool new_bp;
9455ffd83dbSDimitry Andric       breakpoint.AddLocation(address, &new_bp);
9460b57cec5SDimitry Andric 
9479dba64beSDimitry Andric       LLDB_LOGF(log, "%s: Placed %sbreakpoint on %s", __FUNCTION__,
9480b57cec5SDimitry Andric                 new_bp ? "new " : "", k.m_name.AsCString());
9490b57cec5SDimitry Andric 
9500b57cec5SDimitry Andric       // exit after placing the first breakpoint if we do not intend to stop on
9510b57cec5SDimitry Andric       // all kernels making up this script group
9520b57cec5SDimitry Andric       if (!m_stop_on_all)
9530b57cec5SDimitry Andric         break;
9540b57cec5SDimitry Andric     }
9550b57cec5SDimitry Andric   }
9560b57cec5SDimitry Andric 
9570b57cec5SDimitry Andric   return eCallbackReturnContinue;
9580b57cec5SDimitry Andric }
9590b57cec5SDimitry Andric 
Initialize()9600b57cec5SDimitry Andric void RenderScriptRuntime::Initialize() {
9610b57cec5SDimitry Andric   PluginManager::RegisterPlugin(GetPluginNameStatic(),
9620b57cec5SDimitry Andric                                 "RenderScript language support", CreateInstance,
9630b57cec5SDimitry Andric                                 GetCommandObject);
9640b57cec5SDimitry Andric }
9650b57cec5SDimitry Andric 
Terminate()9660b57cec5SDimitry Andric void RenderScriptRuntime::Terminate() {
9670b57cec5SDimitry Andric   PluginManager::UnregisterPlugin(CreateInstance);
9680b57cec5SDimitry Andric }
9690b57cec5SDimitry Andric 
GetPluginNameStatic()9700b57cec5SDimitry Andric lldb_private::ConstString RenderScriptRuntime::GetPluginNameStatic() {
9710b57cec5SDimitry Andric   static ConstString plugin_name("renderscript");
9720b57cec5SDimitry Andric   return plugin_name;
9730b57cec5SDimitry Andric }
9740b57cec5SDimitry Andric 
9750b57cec5SDimitry Andric RenderScriptRuntime::ModuleKind
GetModuleKind(const lldb::ModuleSP & module_sp)9760b57cec5SDimitry Andric RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp) {
9770b57cec5SDimitry Andric   if (module_sp) {
9780b57cec5SDimitry Andric     if (IsRenderScriptScriptModule(module_sp))
9790b57cec5SDimitry Andric       return eModuleKindKernelObj;
9800b57cec5SDimitry Andric 
9810b57cec5SDimitry Andric     // Is this the main RS runtime library
9820b57cec5SDimitry Andric     const ConstString rs_lib("libRS.so");
9830b57cec5SDimitry Andric     if (module_sp->GetFileSpec().GetFilename() == rs_lib) {
9840b57cec5SDimitry Andric       return eModuleKindLibRS;
9850b57cec5SDimitry Andric     }
9860b57cec5SDimitry Andric 
9870b57cec5SDimitry Andric     const ConstString rs_driverlib("libRSDriver.so");
9880b57cec5SDimitry Andric     if (module_sp->GetFileSpec().GetFilename() == rs_driverlib) {
9890b57cec5SDimitry Andric       return eModuleKindDriver;
9900b57cec5SDimitry Andric     }
9910b57cec5SDimitry Andric 
9920b57cec5SDimitry Andric     const ConstString rs_cpureflib("libRSCpuRef.so");
9930b57cec5SDimitry Andric     if (module_sp->GetFileSpec().GetFilename() == rs_cpureflib) {
9940b57cec5SDimitry Andric       return eModuleKindImpl;
9950b57cec5SDimitry Andric     }
9960b57cec5SDimitry Andric   }
9970b57cec5SDimitry Andric   return eModuleKindIgnored;
9980b57cec5SDimitry Andric }
9990b57cec5SDimitry Andric 
IsRenderScriptModule(const lldb::ModuleSP & module_sp)10000b57cec5SDimitry Andric bool RenderScriptRuntime::IsRenderScriptModule(
10010b57cec5SDimitry Andric     const lldb::ModuleSP &module_sp) {
10020b57cec5SDimitry Andric   return GetModuleKind(module_sp) != eModuleKindIgnored;
10030b57cec5SDimitry Andric }
10040b57cec5SDimitry Andric 
ModulesDidLoad(const ModuleList & module_list)10050b57cec5SDimitry Andric void RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list) {
10060b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
10070b57cec5SDimitry Andric 
10080b57cec5SDimitry Andric   size_t num_modules = module_list.GetSize();
10090b57cec5SDimitry Andric   for (size_t i = 0; i < num_modules; i++) {
10100b57cec5SDimitry Andric     auto mod = module_list.GetModuleAtIndex(i);
10110b57cec5SDimitry Andric     if (IsRenderScriptModule(mod)) {
10120b57cec5SDimitry Andric       LoadModule(mod);
10130b57cec5SDimitry Andric     }
10140b57cec5SDimitry Andric   }
10150b57cec5SDimitry Andric }
10160b57cec5SDimitry Andric 
10170b57cec5SDimitry Andric // PluginInterface protocol
GetPluginName()10180b57cec5SDimitry Andric lldb_private::ConstString RenderScriptRuntime::GetPluginName() {
10190b57cec5SDimitry Andric   return GetPluginNameStatic();
10200b57cec5SDimitry Andric }
10210b57cec5SDimitry Andric 
GetPluginVersion()10220b57cec5SDimitry Andric uint32_t RenderScriptRuntime::GetPluginVersion() { return 1; }
10230b57cec5SDimitry Andric 
GetDynamicTypeAndAddress(ValueObject & in_value,lldb::DynamicValueType use_dynamic,TypeAndOrName & class_type_or_name,Address & address,Value::ValueType & value_type)10240b57cec5SDimitry Andric bool RenderScriptRuntime::GetDynamicTypeAndAddress(
10250b57cec5SDimitry Andric     ValueObject &in_value, lldb::DynamicValueType use_dynamic,
10260b57cec5SDimitry Andric     TypeAndOrName &class_type_or_name, Address &address,
10270b57cec5SDimitry Andric     Value::ValueType &value_type) {
10280b57cec5SDimitry Andric   return false;
10290b57cec5SDimitry Andric }
10300b57cec5SDimitry Andric 
10310b57cec5SDimitry Andric TypeAndOrName
FixUpDynamicType(const TypeAndOrName & type_and_or_name,ValueObject & static_value)10320b57cec5SDimitry Andric RenderScriptRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
10330b57cec5SDimitry Andric                                       ValueObject &static_value) {
10340b57cec5SDimitry Andric   return type_and_or_name;
10350b57cec5SDimitry Andric }
10360b57cec5SDimitry Andric 
CouldHaveDynamicValue(ValueObject & in_value)10370b57cec5SDimitry Andric bool RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
10380b57cec5SDimitry Andric   return false;
10390b57cec5SDimitry Andric }
10400b57cec5SDimitry Andric 
10410b57cec5SDimitry Andric lldb::BreakpointResolverSP
CreateExceptionResolver(const lldb::BreakpointSP & bp,bool catch_bp,bool throw_bp)10425ffd83dbSDimitry Andric RenderScriptRuntime::CreateExceptionResolver(const lldb::BreakpointSP &bp,
10435ffd83dbSDimitry Andric                                              bool catch_bp, bool throw_bp) {
10440b57cec5SDimitry Andric   BreakpointResolverSP resolver_sp;
10450b57cec5SDimitry Andric   return resolver_sp;
10460b57cec5SDimitry Andric }
10470b57cec5SDimitry Andric 
10480b57cec5SDimitry Andric const RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] =
10490b57cec5SDimitry Andric     {
10500b57cec5SDimitry Andric         // rsdScript
10510b57cec5SDimitry Andric         {"rsdScriptInit", "_Z13rsdScriptInitPKN7android12renderscript7ContextEP"
10520b57cec5SDimitry Andric                           "NS0_7ScriptCEPKcS7_PKhjj",
10530b57cec5SDimitry Andric          "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_"
10540b57cec5SDimitry Andric          "7ScriptCEPKcS7_PKhmj",
10550b57cec5SDimitry Andric          0, RenderScriptRuntime::eModuleKindDriver,
10560b57cec5SDimitry Andric          &lldb_private::RenderScriptRuntime::CaptureScriptInit},
10570b57cec5SDimitry Andric         {"rsdScriptInvokeForEachMulti",
10580b57cec5SDimitry Andric          "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0"
10590b57cec5SDimitry Andric          "_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall",
10600b57cec5SDimitry Andric          "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0"
10610b57cec5SDimitry Andric          "_6ScriptEjPPKNS0_10AllocationEmPS6_PKvmPK12RsScriptCall",
10620b57cec5SDimitry Andric          0, RenderScriptRuntime::eModuleKindDriver,
10630b57cec5SDimitry Andric          &lldb_private::RenderScriptRuntime::CaptureScriptInvokeForEachMulti},
10640b57cec5SDimitry Andric         {"rsdScriptSetGlobalVar", "_Z21rsdScriptSetGlobalVarPKN7android12render"
10650b57cec5SDimitry Andric                                   "script7ContextEPKNS0_6ScriptEjPvj",
10660b57cec5SDimitry Andric          "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_"
10670b57cec5SDimitry Andric          "6ScriptEjPvm",
10680b57cec5SDimitry Andric          0, RenderScriptRuntime::eModuleKindDriver,
10690b57cec5SDimitry Andric          &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar},
10700b57cec5SDimitry Andric 
10710b57cec5SDimitry Andric         // rsdAllocation
10720b57cec5SDimitry Andric         {"rsdAllocationInit", "_Z17rsdAllocationInitPKN7android12renderscript7C"
10730b57cec5SDimitry Andric                               "ontextEPNS0_10AllocationEb",
10740b57cec5SDimitry Andric          "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_"
10750b57cec5SDimitry Andric          "10AllocationEb",
10760b57cec5SDimitry Andric          0, RenderScriptRuntime::eModuleKindDriver,
10770b57cec5SDimitry Andric          &lldb_private::RenderScriptRuntime::CaptureAllocationInit},
10780b57cec5SDimitry Andric         {"rsdAllocationRead2D",
10790b57cec5SDimitry Andric          "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_"
10800b57cec5SDimitry Andric          "10AllocationEjjj23RsAllocationCubemapFacejjPvjj",
10810b57cec5SDimitry Andric          "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_"
10820b57cec5SDimitry Andric          "10AllocationEjjj23RsAllocationCubemapFacejjPvmm",
10830b57cec5SDimitry Andric          0, RenderScriptRuntime::eModuleKindDriver, nullptr},
10840b57cec5SDimitry Andric         {"rsdAllocationDestroy", "_Z20rsdAllocationDestroyPKN7android12rendersc"
10850b57cec5SDimitry Andric                                  "ript7ContextEPNS0_10AllocationE",
10860b57cec5SDimitry Andric          "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_"
10870b57cec5SDimitry Andric          "10AllocationE",
10880b57cec5SDimitry Andric          0, RenderScriptRuntime::eModuleKindDriver,
10890b57cec5SDimitry Andric          &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy},
10900b57cec5SDimitry Andric 
10910b57cec5SDimitry Andric         // renderscript script groups
10920b57cec5SDimitry Andric         {"rsdDebugHintScriptGroup2", "_ZN7android12renderscript21debugHintScrip"
10930b57cec5SDimitry Andric                                      "tGroup2EPKcjPKPFvPK24RsExpandKernelDriver"
10940b57cec5SDimitry Andric                                      "InfojjjEj",
10950b57cec5SDimitry Andric          "_ZN7android12renderscript21debugHintScriptGroup2EPKcjPKPFvPK24RsExpan"
10960b57cec5SDimitry Andric          "dKernelDriverInfojjjEj",
10970b57cec5SDimitry Andric          0, RenderScriptRuntime::eModuleKindImpl,
10980b57cec5SDimitry Andric          &lldb_private::RenderScriptRuntime::CaptureDebugHintScriptGroup2}};
10990b57cec5SDimitry Andric 
11000b57cec5SDimitry Andric const size_t RenderScriptRuntime::s_runtimeHookCount =
11010b57cec5SDimitry Andric     sizeof(s_runtimeHookDefns) / sizeof(s_runtimeHookDefns[0]);
11020b57cec5SDimitry Andric 
HookCallback(void * baton,StoppointCallbackContext * ctx,lldb::user_id_t break_id,lldb::user_id_t break_loc_id)11030b57cec5SDimitry Andric bool RenderScriptRuntime::HookCallback(void *baton,
11040b57cec5SDimitry Andric                                        StoppointCallbackContext *ctx,
11050b57cec5SDimitry Andric                                        lldb::user_id_t break_id,
11060b57cec5SDimitry Andric                                        lldb::user_id_t break_loc_id) {
11070b57cec5SDimitry Andric   RuntimeHook *hook = (RuntimeHook *)baton;
11080b57cec5SDimitry Andric   ExecutionContext exe_ctx(ctx->exe_ctx_ref);
11090b57cec5SDimitry Andric 
11100b57cec5SDimitry Andric   RenderScriptRuntime *lang_rt = llvm::cast<RenderScriptRuntime>(
11110b57cec5SDimitry Andric       exe_ctx.GetProcessPtr()->GetLanguageRuntime(
11120b57cec5SDimitry Andric           eLanguageTypeExtRenderScript));
11130b57cec5SDimitry Andric 
11140b57cec5SDimitry Andric   lang_rt->HookCallback(hook, exe_ctx);
11150b57cec5SDimitry Andric 
11160b57cec5SDimitry Andric   return false;
11170b57cec5SDimitry Andric }
11180b57cec5SDimitry Andric 
HookCallback(RuntimeHook * hook,ExecutionContext & exe_ctx)11190b57cec5SDimitry Andric void RenderScriptRuntime::HookCallback(RuntimeHook *hook,
11200b57cec5SDimitry Andric                                        ExecutionContext &exe_ctx) {
11210b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
11220b57cec5SDimitry Andric 
11239dba64beSDimitry Andric   LLDB_LOGF(log, "%s - '%s'", __FUNCTION__, hook->defn->name);
11240b57cec5SDimitry Andric 
11250b57cec5SDimitry Andric   if (hook->defn->grabber) {
11260b57cec5SDimitry Andric     (this->*(hook->defn->grabber))(hook, exe_ctx);
11270b57cec5SDimitry Andric   }
11280b57cec5SDimitry Andric }
11290b57cec5SDimitry Andric 
CaptureDebugHintScriptGroup2(RuntimeHook * hook_info,ExecutionContext & context)11300b57cec5SDimitry Andric void RenderScriptRuntime::CaptureDebugHintScriptGroup2(
11310b57cec5SDimitry Andric     RuntimeHook *hook_info, ExecutionContext &context) {
11320b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
11330b57cec5SDimitry Andric 
11340b57cec5SDimitry Andric   enum {
11350b57cec5SDimitry Andric     eGroupName = 0,
11360b57cec5SDimitry Andric     eGroupNameSize,
11370b57cec5SDimitry Andric     eKernel,
11380b57cec5SDimitry Andric     eKernelCount,
11390b57cec5SDimitry Andric   };
11400b57cec5SDimitry Andric 
11410b57cec5SDimitry Andric   std::array<ArgItem, 4> args{{
11420b57cec5SDimitry Andric       {ArgItem::ePointer, 0}, // const char         *groupName
11430b57cec5SDimitry Andric       {ArgItem::eInt32, 0},   // const uint32_t      groupNameSize
11440b57cec5SDimitry Andric       {ArgItem::ePointer, 0}, // const ExpandFuncTy *kernel
11450b57cec5SDimitry Andric       {ArgItem::eInt32, 0},   // const uint32_t      kernelCount
11460b57cec5SDimitry Andric   }};
11470b57cec5SDimitry Andric 
11480b57cec5SDimitry Andric   if (!GetArgs(context, args.data(), args.size())) {
11499dba64beSDimitry Andric     LLDB_LOGF(log, "%s - Error while reading the function parameters",
11500b57cec5SDimitry Andric               __FUNCTION__);
11510b57cec5SDimitry Andric     return;
11520b57cec5SDimitry Andric   } else if (log) {
11539dba64beSDimitry Andric     LLDB_LOGF(log, "%s - groupName    : 0x%" PRIx64, __FUNCTION__,
11540b57cec5SDimitry Andric               addr_t(args[eGroupName]));
11559dba64beSDimitry Andric     LLDB_LOGF(log, "%s - groupNameSize: %" PRIu64, __FUNCTION__,
11560b57cec5SDimitry Andric               uint64_t(args[eGroupNameSize]));
11579dba64beSDimitry Andric     LLDB_LOGF(log, "%s - kernel       : 0x%" PRIx64, __FUNCTION__,
11580b57cec5SDimitry Andric               addr_t(args[eKernel]));
11599dba64beSDimitry Andric     LLDB_LOGF(log, "%s - kernelCount  : %" PRIu64, __FUNCTION__,
11600b57cec5SDimitry Andric               uint64_t(args[eKernelCount]));
11610b57cec5SDimitry Andric   }
11620b57cec5SDimitry Andric 
11630b57cec5SDimitry Andric   // parse script group name
11640b57cec5SDimitry Andric   ConstString group_name;
11650b57cec5SDimitry Andric   {
11660b57cec5SDimitry Andric     Status err;
11670b57cec5SDimitry Andric     const uint64_t len = uint64_t(args[eGroupNameSize]);
11680b57cec5SDimitry Andric     std::unique_ptr<char[]> buffer(new char[uint32_t(len + 1)]);
11690b57cec5SDimitry Andric     m_process->ReadMemory(addr_t(args[eGroupName]), buffer.get(), len, err);
11700b57cec5SDimitry Andric     buffer.get()[len] = '\0';
11710b57cec5SDimitry Andric     if (!err.Success()) {
11729dba64beSDimitry Andric       LLDB_LOGF(log, "Error reading scriptgroup name from target");
11730b57cec5SDimitry Andric       return;
11740b57cec5SDimitry Andric     } else {
11759dba64beSDimitry Andric       LLDB_LOGF(log, "Extracted scriptgroup name %s", buffer.get());
11760b57cec5SDimitry Andric     }
11770b57cec5SDimitry Andric     // write back the script group name
11780b57cec5SDimitry Andric     group_name.SetCString(buffer.get());
11790b57cec5SDimitry Andric   }
11800b57cec5SDimitry Andric 
11810b57cec5SDimitry Andric   // create or access existing script group
11820b57cec5SDimitry Andric   RSScriptGroupDescriptorSP group;
11830b57cec5SDimitry Andric   {
11840b57cec5SDimitry Andric     // search for existing script group
11850b57cec5SDimitry Andric     for (auto sg : m_scriptGroups) {
11860b57cec5SDimitry Andric       if (sg->m_name == group_name) {
11870b57cec5SDimitry Andric         group = sg;
11880b57cec5SDimitry Andric         break;
11890b57cec5SDimitry Andric       }
11900b57cec5SDimitry Andric     }
11910b57cec5SDimitry Andric     if (!group) {
11920b57cec5SDimitry Andric       group = std::make_shared<RSScriptGroupDescriptor>();
11930b57cec5SDimitry Andric       group->m_name = group_name;
11940b57cec5SDimitry Andric       m_scriptGroups.push_back(group);
11950b57cec5SDimitry Andric     } else {
11960b57cec5SDimitry Andric       // already have this script group
11979dba64beSDimitry Andric       LLDB_LOGF(log, "Attempt to add duplicate script group %s",
11980b57cec5SDimitry Andric                 group_name.AsCString());
11990b57cec5SDimitry Andric       return;
12000b57cec5SDimitry Andric     }
12010b57cec5SDimitry Andric   }
12020b57cec5SDimitry Andric   assert(group);
12030b57cec5SDimitry Andric 
12040b57cec5SDimitry Andric   const uint32_t target_ptr_size = m_process->GetAddressByteSize();
12050b57cec5SDimitry Andric   std::vector<addr_t> kernels;
12060b57cec5SDimitry Andric   // parse kernel addresses in script group
12070b57cec5SDimitry Andric   for (uint64_t i = 0; i < uint64_t(args[eKernelCount]); ++i) {
12080b57cec5SDimitry Andric     RSScriptGroupDescriptor::Kernel kernel;
12090b57cec5SDimitry Andric     // extract script group kernel addresses from the target
12100b57cec5SDimitry Andric     const addr_t ptr_addr = addr_t(args[eKernel]) + i * target_ptr_size;
12110b57cec5SDimitry Andric     uint64_t kernel_addr = 0;
12120b57cec5SDimitry Andric     Status err;
12130b57cec5SDimitry Andric     size_t read =
12140b57cec5SDimitry Andric         m_process->ReadMemory(ptr_addr, &kernel_addr, target_ptr_size, err);
12150b57cec5SDimitry Andric     if (!err.Success() || read != target_ptr_size) {
12169dba64beSDimitry Andric       LLDB_LOGF(log, "Error parsing kernel address %" PRIu64 " in script group",
12170b57cec5SDimitry Andric                 i);
12180b57cec5SDimitry Andric       return;
12190b57cec5SDimitry Andric     }
12209dba64beSDimitry Andric     LLDB_LOGF(log, "Extracted scriptgroup kernel address - 0x%" PRIx64,
12210b57cec5SDimitry Andric               kernel_addr);
12220b57cec5SDimitry Andric     kernel.m_addr = kernel_addr;
12230b57cec5SDimitry Andric 
12240b57cec5SDimitry Andric     // try to resolve the associated kernel name
12250b57cec5SDimitry Andric     if (!ResolveKernelName(kernel.m_addr, kernel.m_name)) {
12269dba64beSDimitry Andric       LLDB_LOGF(log, "Parsed scriptgroup kernel %" PRIu64 " - 0x%" PRIx64, i,
12270b57cec5SDimitry Andric                 kernel_addr);
12280b57cec5SDimitry Andric       return;
12290b57cec5SDimitry Andric     }
12300b57cec5SDimitry Andric 
12310b57cec5SDimitry Andric     // try to find the non '.expand' function
12320b57cec5SDimitry Andric     {
12330b57cec5SDimitry Andric       const llvm::StringRef expand(".expand");
12340b57cec5SDimitry Andric       const llvm::StringRef name_ref = kernel.m_name.GetStringRef();
12350b57cec5SDimitry Andric       if (name_ref.endswith(expand)) {
12360b57cec5SDimitry Andric         const ConstString base_kernel(name_ref.drop_back(expand.size()));
12370b57cec5SDimitry Andric         // verify this function is a valid kernel
12380b57cec5SDimitry Andric         if (IsKnownKernel(base_kernel)) {
12390b57cec5SDimitry Andric           kernel.m_name = base_kernel;
12409dba64beSDimitry Andric           LLDB_LOGF(log, "%s - found non expand version '%s'", __FUNCTION__,
12410b57cec5SDimitry Andric                     base_kernel.GetCString());
12420b57cec5SDimitry Andric         }
12430b57cec5SDimitry Andric       }
12440b57cec5SDimitry Andric     }
12450b57cec5SDimitry Andric     // add to a list of script group kernels we know about
12460b57cec5SDimitry Andric     group->m_kernels.push_back(kernel);
12470b57cec5SDimitry Andric   }
12480b57cec5SDimitry Andric 
12490b57cec5SDimitry Andric   // Resolve any pending scriptgroup breakpoints
12500b57cec5SDimitry Andric   {
12510b57cec5SDimitry Andric     Target &target = m_process->GetTarget();
12520b57cec5SDimitry Andric     const BreakpointList &list = target.GetBreakpointList();
12530b57cec5SDimitry Andric     const size_t num_breakpoints = list.GetSize();
12549dba64beSDimitry Andric     LLDB_LOGF(log, "Resolving %zu breakpoints", num_breakpoints);
12550b57cec5SDimitry Andric     for (size_t i = 0; i < num_breakpoints; ++i) {
12560b57cec5SDimitry Andric       const BreakpointSP bp = list.GetBreakpointAtIndex(i);
12570b57cec5SDimitry Andric       if (bp) {
12580b57cec5SDimitry Andric         if (bp->MatchesName(group_name.AsCString())) {
12599dba64beSDimitry Andric           LLDB_LOGF(log, "Found breakpoint with name %s",
12600b57cec5SDimitry Andric                     group_name.AsCString());
12610b57cec5SDimitry Andric           bp->ResolveBreakpoint();
12620b57cec5SDimitry Andric         }
12630b57cec5SDimitry Andric       }
12640b57cec5SDimitry Andric     }
12650b57cec5SDimitry Andric   }
12660b57cec5SDimitry Andric }
12670b57cec5SDimitry Andric 
CaptureScriptInvokeForEachMulti(RuntimeHook * hook,ExecutionContext & exe_ctx)12680b57cec5SDimitry Andric void RenderScriptRuntime::CaptureScriptInvokeForEachMulti(
12690b57cec5SDimitry Andric     RuntimeHook *hook, ExecutionContext &exe_ctx) {
12700b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
12710b57cec5SDimitry Andric 
12720b57cec5SDimitry Andric   enum {
12730b57cec5SDimitry Andric     eRsContext = 0,
12740b57cec5SDimitry Andric     eRsScript,
12750b57cec5SDimitry Andric     eRsSlot,
12760b57cec5SDimitry Andric     eRsAIns,
12770b57cec5SDimitry Andric     eRsInLen,
12780b57cec5SDimitry Andric     eRsAOut,
12790b57cec5SDimitry Andric     eRsUsr,
12800b57cec5SDimitry Andric     eRsUsrLen,
12810b57cec5SDimitry Andric     eRsSc,
12820b57cec5SDimitry Andric   };
12830b57cec5SDimitry Andric 
12840b57cec5SDimitry Andric   std::array<ArgItem, 9> args{{
12850b57cec5SDimitry Andric       ArgItem{ArgItem::ePointer, 0}, // const Context       *rsc
12860b57cec5SDimitry Andric       ArgItem{ArgItem::ePointer, 0}, // Script              *s
12870b57cec5SDimitry Andric       ArgItem{ArgItem::eInt32, 0},   // uint32_t             slot
12880b57cec5SDimitry Andric       ArgItem{ArgItem::ePointer, 0}, // const Allocation   **aIns
12890b57cec5SDimitry Andric       ArgItem{ArgItem::eInt32, 0},   // size_t               inLen
12900b57cec5SDimitry Andric       ArgItem{ArgItem::ePointer, 0}, // Allocation          *aout
12910b57cec5SDimitry Andric       ArgItem{ArgItem::ePointer, 0}, // const void          *usr
12920b57cec5SDimitry Andric       ArgItem{ArgItem::eInt32, 0},   // size_t               usrLen
12930b57cec5SDimitry Andric       ArgItem{ArgItem::ePointer, 0}, // const RsScriptCall  *sc
12940b57cec5SDimitry Andric   }};
12950b57cec5SDimitry Andric 
12960b57cec5SDimitry Andric   bool success = GetArgs(exe_ctx, &args[0], args.size());
12970b57cec5SDimitry Andric   if (!success) {
12989dba64beSDimitry Andric     LLDB_LOGF(log, "%s - Error while reading the function parameters",
12990b57cec5SDimitry Andric               __FUNCTION__);
13000b57cec5SDimitry Andric     return;
13010b57cec5SDimitry Andric   }
13020b57cec5SDimitry Andric 
13030b57cec5SDimitry Andric   const uint32_t target_ptr_size = m_process->GetAddressByteSize();
13040b57cec5SDimitry Andric   Status err;
13050b57cec5SDimitry Andric   std::vector<uint64_t> allocs;
13060b57cec5SDimitry Andric 
13070b57cec5SDimitry Andric   // traverse allocation list
13080b57cec5SDimitry Andric   for (uint64_t i = 0; i < uint64_t(args[eRsInLen]); ++i) {
13090b57cec5SDimitry Andric     // calculate offest to allocation pointer
13100b57cec5SDimitry Andric     const addr_t addr = addr_t(args[eRsAIns]) + i * target_ptr_size;
13110b57cec5SDimitry Andric 
13120b57cec5SDimitry Andric     // Note: due to little endian layout, reading 32bits or 64bits into res
13130b57cec5SDimitry Andric     // will give the correct results.
13140b57cec5SDimitry Andric     uint64_t result = 0;
13150b57cec5SDimitry Andric     size_t read = m_process->ReadMemory(addr, &result, target_ptr_size, err);
13160b57cec5SDimitry Andric     if (read != target_ptr_size || !err.Success()) {
13179dba64beSDimitry Andric       LLDB_LOGF(log,
13180b57cec5SDimitry Andric                 "%s - Error while reading allocation list argument %" PRIu64,
13190b57cec5SDimitry Andric                 __FUNCTION__, i);
13200b57cec5SDimitry Andric     } else {
13210b57cec5SDimitry Andric       allocs.push_back(result);
13220b57cec5SDimitry Andric     }
13230b57cec5SDimitry Andric   }
13240b57cec5SDimitry Andric 
13250b57cec5SDimitry Andric   // if there is an output allocation track it
13260b57cec5SDimitry Andric   if (uint64_t alloc_out = uint64_t(args[eRsAOut])) {
13270b57cec5SDimitry Andric     allocs.push_back(alloc_out);
13280b57cec5SDimitry Andric   }
13290b57cec5SDimitry Andric 
13300b57cec5SDimitry Andric   // for all allocations we have found
13310b57cec5SDimitry Andric   for (const uint64_t alloc_addr : allocs) {
13320b57cec5SDimitry Andric     AllocationDetails *alloc = LookUpAllocation(alloc_addr);
13330b57cec5SDimitry Andric     if (!alloc)
13340b57cec5SDimitry Andric       alloc = CreateAllocation(alloc_addr);
13350b57cec5SDimitry Andric 
13360b57cec5SDimitry Andric     if (alloc) {
13370b57cec5SDimitry Andric       // save the allocation address
13380b57cec5SDimitry Andric       if (alloc->address.isValid()) {
13390b57cec5SDimitry Andric         // check the allocation address we already have matches
13400b57cec5SDimitry Andric         assert(*alloc->address.get() == alloc_addr);
13410b57cec5SDimitry Andric       } else {
13420b57cec5SDimitry Andric         alloc->address = alloc_addr;
13430b57cec5SDimitry Andric       }
13440b57cec5SDimitry Andric 
13450b57cec5SDimitry Andric       // save the context
13460b57cec5SDimitry Andric       if (log) {
13470b57cec5SDimitry Andric         if (alloc->context.isValid() &&
13480b57cec5SDimitry Andric             *alloc->context.get() != addr_t(args[eRsContext]))
13499dba64beSDimitry Andric           LLDB_LOGF(log, "%s - Allocation used by multiple contexts",
13500b57cec5SDimitry Andric                     __FUNCTION__);
13510b57cec5SDimitry Andric       }
13520b57cec5SDimitry Andric       alloc->context = addr_t(args[eRsContext]);
13530b57cec5SDimitry Andric     }
13540b57cec5SDimitry Andric   }
13550b57cec5SDimitry Andric 
13560b57cec5SDimitry Andric   // make sure we track this script object
13570b57cec5SDimitry Andric   if (lldb_private::RenderScriptRuntime::ScriptDetails *script =
13580b57cec5SDimitry Andric           LookUpScript(addr_t(args[eRsScript]), true)) {
13590b57cec5SDimitry Andric     if (log) {
13600b57cec5SDimitry Andric       if (script->context.isValid() &&
13610b57cec5SDimitry Andric           *script->context.get() != addr_t(args[eRsContext]))
13629dba64beSDimitry Andric         LLDB_LOGF(log, "%s - Script used by multiple contexts", __FUNCTION__);
13630b57cec5SDimitry Andric     }
13640b57cec5SDimitry Andric     script->context = addr_t(args[eRsContext]);
13650b57cec5SDimitry Andric   }
13660b57cec5SDimitry Andric }
13670b57cec5SDimitry Andric 
CaptureSetGlobalVar(RuntimeHook * hook,ExecutionContext & context)13680b57cec5SDimitry Andric void RenderScriptRuntime::CaptureSetGlobalVar(RuntimeHook *hook,
13690b57cec5SDimitry Andric                                               ExecutionContext &context) {
13700b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
13710b57cec5SDimitry Andric 
13720b57cec5SDimitry Andric   enum {
13730b57cec5SDimitry Andric     eRsContext,
13740b57cec5SDimitry Andric     eRsScript,
13750b57cec5SDimitry Andric     eRsId,
13760b57cec5SDimitry Andric     eRsData,
13770b57cec5SDimitry Andric     eRsLength,
13780b57cec5SDimitry Andric   };
13790b57cec5SDimitry Andric 
13800b57cec5SDimitry Andric   std::array<ArgItem, 5> args{{
13810b57cec5SDimitry Andric       ArgItem{ArgItem::ePointer, 0}, // eRsContext
13820b57cec5SDimitry Andric       ArgItem{ArgItem::ePointer, 0}, // eRsScript
13830b57cec5SDimitry Andric       ArgItem{ArgItem::eInt32, 0},   // eRsId
13840b57cec5SDimitry Andric       ArgItem{ArgItem::ePointer, 0}, // eRsData
13850b57cec5SDimitry Andric       ArgItem{ArgItem::eInt32, 0},   // eRsLength
13860b57cec5SDimitry Andric   }};
13870b57cec5SDimitry Andric 
13880b57cec5SDimitry Andric   bool success = GetArgs(context, &args[0], args.size());
13890b57cec5SDimitry Andric   if (!success) {
13909dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error reading the function parameters.", __FUNCTION__);
13910b57cec5SDimitry Andric     return;
13920b57cec5SDimitry Andric   }
13930b57cec5SDimitry Andric 
13940b57cec5SDimitry Andric   if (log) {
13959dba64beSDimitry Andric     LLDB_LOGF(log,
13969dba64beSDimitry Andric               "%s - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64
13970b57cec5SDimitry Andric               ":%" PRIu64 "bytes.",
13980b57cec5SDimitry Andric               __FUNCTION__, uint64_t(args[eRsContext]),
13990b57cec5SDimitry Andric               uint64_t(args[eRsScript]), uint64_t(args[eRsId]),
14000b57cec5SDimitry Andric               uint64_t(args[eRsData]), uint64_t(args[eRsLength]));
14010b57cec5SDimitry Andric 
14020b57cec5SDimitry Andric     addr_t script_addr = addr_t(args[eRsScript]);
14030b57cec5SDimitry Andric     if (m_scriptMappings.find(script_addr) != m_scriptMappings.end()) {
14040b57cec5SDimitry Andric       auto rsm = m_scriptMappings[script_addr];
14050b57cec5SDimitry Andric       if (uint64_t(args[eRsId]) < rsm->m_globals.size()) {
14060b57cec5SDimitry Andric         auto rsg = rsm->m_globals[uint64_t(args[eRsId])];
14079dba64beSDimitry Andric         LLDB_LOGF(log, "%s - Setting of '%s' within '%s' inferred",
14089dba64beSDimitry Andric                   __FUNCTION__, rsg.m_name.AsCString(),
14090b57cec5SDimitry Andric                   rsm->m_module->GetFileSpec().GetFilename().AsCString());
14100b57cec5SDimitry Andric       }
14110b57cec5SDimitry Andric     }
14120b57cec5SDimitry Andric   }
14130b57cec5SDimitry Andric }
14140b57cec5SDimitry Andric 
CaptureAllocationInit(RuntimeHook * hook,ExecutionContext & exe_ctx)14150b57cec5SDimitry Andric void RenderScriptRuntime::CaptureAllocationInit(RuntimeHook *hook,
14160b57cec5SDimitry Andric                                                 ExecutionContext &exe_ctx) {
14170b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
14180b57cec5SDimitry Andric 
14190b57cec5SDimitry Andric   enum { eRsContext, eRsAlloc, eRsForceZero };
14200b57cec5SDimitry Andric 
14210b57cec5SDimitry Andric   std::array<ArgItem, 3> args{{
14220b57cec5SDimitry Andric       ArgItem{ArgItem::ePointer, 0}, // eRsContext
14230b57cec5SDimitry Andric       ArgItem{ArgItem::ePointer, 0}, // eRsAlloc
14240b57cec5SDimitry Andric       ArgItem{ArgItem::eBool, 0},    // eRsForceZero
14250b57cec5SDimitry Andric   }};
14260b57cec5SDimitry Andric 
14270b57cec5SDimitry Andric   bool success = GetArgs(exe_ctx, &args[0], args.size());
14280b57cec5SDimitry Andric   if (!success) {
14299dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error while reading the function parameters",
14300b57cec5SDimitry Andric               __FUNCTION__);
14310b57cec5SDimitry Andric     return;
14320b57cec5SDimitry Andric   }
14330b57cec5SDimitry Andric 
14349dba64beSDimitry Andric   LLDB_LOGF(log, "%s - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .",
14359dba64beSDimitry Andric             __FUNCTION__, uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc]),
14369dba64beSDimitry Andric             uint64_t(args[eRsForceZero]));
14370b57cec5SDimitry Andric 
14380b57cec5SDimitry Andric   AllocationDetails *alloc = CreateAllocation(uint64_t(args[eRsAlloc]));
14390b57cec5SDimitry Andric   if (alloc)
14400b57cec5SDimitry Andric     alloc->context = uint64_t(args[eRsContext]);
14410b57cec5SDimitry Andric }
14420b57cec5SDimitry Andric 
CaptureAllocationDestroy(RuntimeHook * hook,ExecutionContext & exe_ctx)14430b57cec5SDimitry Andric void RenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook *hook,
14440b57cec5SDimitry Andric                                                    ExecutionContext &exe_ctx) {
14450b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
14460b57cec5SDimitry Andric 
14470b57cec5SDimitry Andric   enum {
14480b57cec5SDimitry Andric     eRsContext,
14490b57cec5SDimitry Andric     eRsAlloc,
14500b57cec5SDimitry Andric   };
14510b57cec5SDimitry Andric 
14520b57cec5SDimitry Andric   std::array<ArgItem, 2> args{{
14530b57cec5SDimitry Andric       ArgItem{ArgItem::ePointer, 0}, // eRsContext
14540b57cec5SDimitry Andric       ArgItem{ArgItem::ePointer, 0}, // eRsAlloc
14550b57cec5SDimitry Andric   }};
14560b57cec5SDimitry Andric 
14570b57cec5SDimitry Andric   bool success = GetArgs(exe_ctx, &args[0], args.size());
14580b57cec5SDimitry Andric   if (!success) {
14599dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error while reading the function parameters.",
14600b57cec5SDimitry Andric               __FUNCTION__);
14610b57cec5SDimitry Andric     return;
14620b57cec5SDimitry Andric   }
14630b57cec5SDimitry Andric 
14649dba64beSDimitry Andric   LLDB_LOGF(log, "%s - 0x%" PRIx64 ", 0x%" PRIx64 ".", __FUNCTION__,
14650b57cec5SDimitry Andric             uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc]));
14660b57cec5SDimitry Andric 
14670b57cec5SDimitry Andric   for (auto iter = m_allocations.begin(); iter != m_allocations.end(); ++iter) {
14680b57cec5SDimitry Andric     auto &allocation_up = *iter; // get the unique pointer
14690b57cec5SDimitry Andric     if (allocation_up->address.isValid() &&
14700b57cec5SDimitry Andric         *allocation_up->address.get() == addr_t(args[eRsAlloc])) {
14710b57cec5SDimitry Andric       m_allocations.erase(iter);
14729dba64beSDimitry Andric       LLDB_LOGF(log, "%s - deleted allocation entry.", __FUNCTION__);
14730b57cec5SDimitry Andric       return;
14740b57cec5SDimitry Andric     }
14750b57cec5SDimitry Andric   }
14760b57cec5SDimitry Andric 
14779dba64beSDimitry Andric   LLDB_LOGF(log, "%s - couldn't find destroyed allocation.", __FUNCTION__);
14780b57cec5SDimitry Andric }
14790b57cec5SDimitry Andric 
CaptureScriptInit(RuntimeHook * hook,ExecutionContext & exe_ctx)14800b57cec5SDimitry Andric void RenderScriptRuntime::CaptureScriptInit(RuntimeHook *hook,
14810b57cec5SDimitry Andric                                             ExecutionContext &exe_ctx) {
14820b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
14830b57cec5SDimitry Andric 
14840b57cec5SDimitry Andric   Status err;
14850b57cec5SDimitry Andric   Process *process = exe_ctx.GetProcessPtr();
14860b57cec5SDimitry Andric 
14870b57cec5SDimitry Andric   enum { eRsContext, eRsScript, eRsResNamePtr, eRsCachedDirPtr };
14880b57cec5SDimitry Andric 
14890b57cec5SDimitry Andric   std::array<ArgItem, 4> args{
14900b57cec5SDimitry Andric       {ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0},
14910b57cec5SDimitry Andric        ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}}};
14920b57cec5SDimitry Andric   bool success = GetArgs(exe_ctx, &args[0], args.size());
14930b57cec5SDimitry Andric   if (!success) {
14949dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error while reading the function parameters.",
14950b57cec5SDimitry Andric               __FUNCTION__);
14960b57cec5SDimitry Andric     return;
14970b57cec5SDimitry Andric   }
14980b57cec5SDimitry Andric 
14990b57cec5SDimitry Andric   std::string res_name;
15000b57cec5SDimitry Andric   process->ReadCStringFromMemory(addr_t(args[eRsResNamePtr]), res_name, err);
15010b57cec5SDimitry Andric   if (err.Fail()) {
15029dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error reading res_name: %s.", __FUNCTION__,
15030b57cec5SDimitry Andric               err.AsCString());
15040b57cec5SDimitry Andric   }
15050b57cec5SDimitry Andric 
15060b57cec5SDimitry Andric   std::string cache_dir;
15070b57cec5SDimitry Andric   process->ReadCStringFromMemory(addr_t(args[eRsCachedDirPtr]), cache_dir, err);
15080b57cec5SDimitry Andric   if (err.Fail()) {
15099dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error reading cache_dir: %s.", __FUNCTION__,
15100b57cec5SDimitry Andric               err.AsCString());
15110b57cec5SDimitry Andric   }
15120b57cec5SDimitry Andric 
15139dba64beSDimitry Andric   LLDB_LOGF(log, "%s - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .",
15149dba64beSDimitry Andric             __FUNCTION__, uint64_t(args[eRsContext]), uint64_t(args[eRsScript]),
15159dba64beSDimitry Andric             res_name.c_str(), cache_dir.c_str());
15160b57cec5SDimitry Andric 
15170b57cec5SDimitry Andric   if (res_name.size() > 0) {
15180b57cec5SDimitry Andric     StreamString strm;
15190b57cec5SDimitry Andric     strm.Printf("librs.%s.so", res_name.c_str());
15200b57cec5SDimitry Andric 
15210b57cec5SDimitry Andric     ScriptDetails *script = LookUpScript(addr_t(args[eRsScript]), true);
15220b57cec5SDimitry Andric     if (script) {
15230b57cec5SDimitry Andric       script->type = ScriptDetails::eScriptC;
15240b57cec5SDimitry Andric       script->cache_dir = cache_dir;
15250b57cec5SDimitry Andric       script->res_name = res_name;
15265ffd83dbSDimitry Andric       script->shared_lib = std::string(strm.GetString());
15270b57cec5SDimitry Andric       script->context = addr_t(args[eRsContext]);
15280b57cec5SDimitry Andric     }
15290b57cec5SDimitry Andric 
15309dba64beSDimitry Andric     LLDB_LOGF(log,
15319dba64beSDimitry Andric               "%s - '%s' tagged with context 0x%" PRIx64
15320b57cec5SDimitry Andric               " and script 0x%" PRIx64 ".",
15330b57cec5SDimitry Andric               __FUNCTION__, strm.GetData(), uint64_t(args[eRsContext]),
15340b57cec5SDimitry Andric               uint64_t(args[eRsScript]));
15350b57cec5SDimitry Andric   } else if (log) {
15369dba64beSDimitry Andric     LLDB_LOGF(log, "%s - resource name invalid, Script not tagged.",
15379dba64beSDimitry Andric               __FUNCTION__);
15380b57cec5SDimitry Andric   }
15390b57cec5SDimitry Andric }
15400b57cec5SDimitry Andric 
LoadRuntimeHooks(lldb::ModuleSP module,ModuleKind kind)15410b57cec5SDimitry Andric void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module,
15420b57cec5SDimitry Andric                                            ModuleKind kind) {
15430b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
15440b57cec5SDimitry Andric 
15450b57cec5SDimitry Andric   if (!module) {
15460b57cec5SDimitry Andric     return;
15470b57cec5SDimitry Andric   }
15480b57cec5SDimitry Andric 
15490b57cec5SDimitry Andric   Target &target = GetProcess()->GetTarget();
15500b57cec5SDimitry Andric   const llvm::Triple::ArchType machine = target.GetArchitecture().GetMachine();
15510b57cec5SDimitry Andric 
15520b57cec5SDimitry Andric   if (machine != llvm::Triple::ArchType::x86 &&
15530b57cec5SDimitry Andric       machine != llvm::Triple::ArchType::arm &&
15540b57cec5SDimitry Andric       machine != llvm::Triple::ArchType::aarch64 &&
15550b57cec5SDimitry Andric       machine != llvm::Triple::ArchType::mipsel &&
15560b57cec5SDimitry Andric       machine != llvm::Triple::ArchType::mips64el &&
15570b57cec5SDimitry Andric       machine != llvm::Triple::ArchType::x86_64) {
15589dba64beSDimitry Andric     LLDB_LOGF(log, "%s - unable to hook runtime functions.", __FUNCTION__);
15590b57cec5SDimitry Andric     return;
15600b57cec5SDimitry Andric   }
15610b57cec5SDimitry Andric 
15620b57cec5SDimitry Andric   const uint32_t target_ptr_size =
15630b57cec5SDimitry Andric       target.GetArchitecture().GetAddressByteSize();
15640b57cec5SDimitry Andric 
15650b57cec5SDimitry Andric   std::array<bool, s_runtimeHookCount> hook_placed;
15660b57cec5SDimitry Andric   hook_placed.fill(false);
15670b57cec5SDimitry Andric 
15680b57cec5SDimitry Andric   for (size_t idx = 0; idx < s_runtimeHookCount; idx++) {
15690b57cec5SDimitry Andric     const HookDefn *hook_defn = &s_runtimeHookDefns[idx];
15700b57cec5SDimitry Andric     if (hook_defn->kind != kind) {
15710b57cec5SDimitry Andric       continue;
15720b57cec5SDimitry Andric     }
15730b57cec5SDimitry Andric 
15740b57cec5SDimitry Andric     const char *symbol_name = (target_ptr_size == 4)
15750b57cec5SDimitry Andric                                   ? hook_defn->symbol_name_m32
15760b57cec5SDimitry Andric                                   : hook_defn->symbol_name_m64;
15770b57cec5SDimitry Andric 
15780b57cec5SDimitry Andric     const Symbol *sym = module->FindFirstSymbolWithNameAndType(
15790b57cec5SDimitry Andric         ConstString(symbol_name), eSymbolTypeCode);
15800b57cec5SDimitry Andric     if (!sym) {
15810b57cec5SDimitry Andric       if (log) {
15829dba64beSDimitry Andric         LLDB_LOGF(log, "%s - symbol '%s' related to the function %s not found",
15830b57cec5SDimitry Andric                   __FUNCTION__, symbol_name, hook_defn->name);
15840b57cec5SDimitry Andric       }
15850b57cec5SDimitry Andric       continue;
15860b57cec5SDimitry Andric     }
15870b57cec5SDimitry Andric 
15880b57cec5SDimitry Andric     addr_t addr = sym->GetLoadAddress(&target);
15890b57cec5SDimitry Andric     if (addr == LLDB_INVALID_ADDRESS) {
15909dba64beSDimitry Andric       LLDB_LOGF(log,
15919dba64beSDimitry Andric                 "%s - unable to resolve the address of hook function '%s' "
15920b57cec5SDimitry Andric                 "with symbol '%s'.",
15930b57cec5SDimitry Andric                 __FUNCTION__, hook_defn->name, symbol_name);
15940b57cec5SDimitry Andric       continue;
15950b57cec5SDimitry Andric     } else {
15969dba64beSDimitry Andric       LLDB_LOGF(log, "%s - function %s, address resolved at 0x%" PRIx64,
15970b57cec5SDimitry Andric                 __FUNCTION__, hook_defn->name, addr);
15980b57cec5SDimitry Andric     }
15990b57cec5SDimitry Andric 
16000b57cec5SDimitry Andric     RuntimeHookSP hook(new RuntimeHook());
16010b57cec5SDimitry Andric     hook->address = addr;
16020b57cec5SDimitry Andric     hook->defn = hook_defn;
16030b57cec5SDimitry Andric     hook->bp_sp = target.CreateBreakpoint(addr, true, false);
16040b57cec5SDimitry Andric     hook->bp_sp->SetCallback(HookCallback, hook.get(), true);
16050b57cec5SDimitry Andric     m_runtimeHooks[addr] = hook;
16060b57cec5SDimitry Andric     if (log) {
16079dba64beSDimitry Andric       LLDB_LOGF(log,
16089dba64beSDimitry Andric                 "%s - successfully hooked '%s' in '%s' version %" PRIu64
16090b57cec5SDimitry Andric                 " at 0x%" PRIx64 ".",
16100b57cec5SDimitry Andric                 __FUNCTION__, hook_defn->name,
16110b57cec5SDimitry Andric                 module->GetFileSpec().GetFilename().AsCString(),
16120b57cec5SDimitry Andric                 (uint64_t)hook_defn->version, (uint64_t)addr);
16130b57cec5SDimitry Andric     }
16140b57cec5SDimitry Andric     hook_placed[idx] = true;
16150b57cec5SDimitry Andric   }
16160b57cec5SDimitry Andric 
16170b57cec5SDimitry Andric   // log any unhooked function
16180b57cec5SDimitry Andric   if (log) {
16190b57cec5SDimitry Andric     for (size_t i = 0; i < hook_placed.size(); ++i) {
16200b57cec5SDimitry Andric       if (hook_placed[i])
16210b57cec5SDimitry Andric         continue;
16220b57cec5SDimitry Andric       const HookDefn &hook_defn = s_runtimeHookDefns[i];
16230b57cec5SDimitry Andric       if (hook_defn.kind != kind)
16240b57cec5SDimitry Andric         continue;
16259dba64beSDimitry Andric       LLDB_LOGF(log, "%s - function %s was not hooked", __FUNCTION__,
16260b57cec5SDimitry Andric                 hook_defn.name);
16270b57cec5SDimitry Andric     }
16280b57cec5SDimitry Andric   }
16290b57cec5SDimitry Andric }
16300b57cec5SDimitry Andric 
FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp)16310b57cec5SDimitry Andric void RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp) {
16320b57cec5SDimitry Andric   if (!rsmodule_sp)
16330b57cec5SDimitry Andric     return;
16340b57cec5SDimitry Andric 
16350b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
16360b57cec5SDimitry Andric 
16370b57cec5SDimitry Andric   const ModuleSP module = rsmodule_sp->m_module;
16380b57cec5SDimitry Andric   const FileSpec &file = module->GetPlatformFileSpec();
16390b57cec5SDimitry Andric 
16400b57cec5SDimitry Andric   // Iterate over all of the scripts that we currently know of. Note: We cant
16410b57cec5SDimitry Andric   // push or pop to m_scripts here or it may invalidate rs_script.
16420b57cec5SDimitry Andric   for (const auto &rs_script : m_scripts) {
16430b57cec5SDimitry Andric     // Extract the expected .so file path for this script.
16440b57cec5SDimitry Andric     std::string shared_lib;
16450b57cec5SDimitry Andric     if (!rs_script->shared_lib.get(shared_lib))
16460b57cec5SDimitry Andric       continue;
16470b57cec5SDimitry Andric 
16480b57cec5SDimitry Andric     // Only proceed if the module that has loaded corresponds to this script.
16490b57cec5SDimitry Andric     if (file.GetFilename() != ConstString(shared_lib.c_str()))
16500b57cec5SDimitry Andric       continue;
16510b57cec5SDimitry Andric 
16520b57cec5SDimitry Andric     // Obtain the script address which we use as a key.
16530b57cec5SDimitry Andric     lldb::addr_t script;
16540b57cec5SDimitry Andric     if (!rs_script->script.get(script))
16550b57cec5SDimitry Andric       continue;
16560b57cec5SDimitry Andric 
16570b57cec5SDimitry Andric     // If we have a script mapping for the current script.
16580b57cec5SDimitry Andric     if (m_scriptMappings.find(script) != m_scriptMappings.end()) {
16590b57cec5SDimitry Andric       // if the module we have stored is different to the one we just received.
16600b57cec5SDimitry Andric       if (m_scriptMappings[script] != rsmodule_sp) {
16619dba64beSDimitry Andric         LLDB_LOGF(
16629dba64beSDimitry Andric             log,
16630b57cec5SDimitry Andric             "%s - script %" PRIx64 " wants reassigned to new rsmodule '%s'.",
16640b57cec5SDimitry Andric             __FUNCTION__, (uint64_t)script,
16650b57cec5SDimitry Andric             rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
16660b57cec5SDimitry Andric       }
16670b57cec5SDimitry Andric     }
16680b57cec5SDimitry Andric     // We don't have a script mapping for the current script.
16690b57cec5SDimitry Andric     else {
16700b57cec5SDimitry Andric       // Obtain the script resource name.
16710b57cec5SDimitry Andric       std::string res_name;
16720b57cec5SDimitry Andric       if (rs_script->res_name.get(res_name))
16730b57cec5SDimitry Andric         // Set the modules resource name.
16740b57cec5SDimitry Andric         rsmodule_sp->m_resname = res_name;
16750b57cec5SDimitry Andric       // Add Script/Module pair to map.
16760b57cec5SDimitry Andric       m_scriptMappings[script] = rsmodule_sp;
16779dba64beSDimitry Andric       LLDB_LOGF(log, "%s - script %" PRIx64 " associated with rsmodule '%s'.",
16780b57cec5SDimitry Andric                 __FUNCTION__, (uint64_t)script,
16790b57cec5SDimitry Andric                 rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
16800b57cec5SDimitry Andric     }
16810b57cec5SDimitry Andric   }
16820b57cec5SDimitry Andric }
16830b57cec5SDimitry Andric 
16840b57cec5SDimitry Andric // Uses the Target API to evaluate the expression passed as a parameter to the
16850b57cec5SDimitry Andric // function The result of that expression is returned an unsigned 64 bit int,
16860b57cec5SDimitry Andric // via the result* parameter. Function returns true on success, and false on
16870b57cec5SDimitry Andric // failure
EvalRSExpression(const char * expr,StackFrame * frame_ptr,uint64_t * result)16880b57cec5SDimitry Andric bool RenderScriptRuntime::EvalRSExpression(const char *expr,
16890b57cec5SDimitry Andric                                            StackFrame *frame_ptr,
16900b57cec5SDimitry Andric                                            uint64_t *result) {
16910b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
16929dba64beSDimitry Andric   LLDB_LOGF(log, "%s(%s)", __FUNCTION__, expr);
16930b57cec5SDimitry Andric 
16940b57cec5SDimitry Andric   ValueObjectSP expr_result;
16950b57cec5SDimitry Andric   EvaluateExpressionOptions options;
16960b57cec5SDimitry Andric   options.SetLanguage(lldb::eLanguageTypeC_plus_plus);
16970b57cec5SDimitry Andric   // Perform the actual expression evaluation
16980b57cec5SDimitry Andric   auto &target = GetProcess()->GetTarget();
16990b57cec5SDimitry Andric   target.EvaluateExpression(expr, frame_ptr, expr_result, options);
17000b57cec5SDimitry Andric 
17010b57cec5SDimitry Andric   if (!expr_result) {
17029dba64beSDimitry Andric     LLDB_LOGF(log, "%s: couldn't evaluate expression.", __FUNCTION__);
17030b57cec5SDimitry Andric     return false;
17040b57cec5SDimitry Andric   }
17050b57cec5SDimitry Andric 
17060b57cec5SDimitry Andric   // The result of the expression is invalid
17070b57cec5SDimitry Andric   if (!expr_result->GetError().Success()) {
17080b57cec5SDimitry Andric     Status err = expr_result->GetError();
17090b57cec5SDimitry Andric     // Expression returned is void, so this is actually a success
17100b57cec5SDimitry Andric     if (err.GetError() == UserExpression::kNoResult) {
17119dba64beSDimitry Andric       LLDB_LOGF(log, "%s - expression returned void.", __FUNCTION__);
17120b57cec5SDimitry Andric 
17130b57cec5SDimitry Andric       result = nullptr;
17140b57cec5SDimitry Andric       return true;
17150b57cec5SDimitry Andric     }
17160b57cec5SDimitry Andric 
17179dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error evaluating expression result: %s", __FUNCTION__,
17180b57cec5SDimitry Andric               err.AsCString());
17190b57cec5SDimitry Andric     return false;
17200b57cec5SDimitry Andric   }
17210b57cec5SDimitry Andric 
17220b57cec5SDimitry Andric   bool success = false;
17230b57cec5SDimitry Andric   // We only read the result as an uint32_t.
17240b57cec5SDimitry Andric   *result = expr_result->GetValueAsUnsigned(0, &success);
17250b57cec5SDimitry Andric 
17260b57cec5SDimitry Andric   if (!success) {
17279dba64beSDimitry Andric     LLDB_LOGF(log, "%s - couldn't convert expression result to uint32_t",
17280b57cec5SDimitry Andric               __FUNCTION__);
17290b57cec5SDimitry Andric     return false;
17300b57cec5SDimitry Andric   }
17310b57cec5SDimitry Andric 
17320b57cec5SDimitry Andric   return true;
17330b57cec5SDimitry Andric }
17340b57cec5SDimitry Andric 
17350b57cec5SDimitry Andric namespace {
17360b57cec5SDimitry Andric // Used to index expression format strings
17370b57cec5SDimitry Andric enum ExpressionStrings {
17380b57cec5SDimitry Andric   eExprGetOffsetPtr = 0,
17390b57cec5SDimitry Andric   eExprAllocGetType,
17400b57cec5SDimitry Andric   eExprTypeDimX,
17410b57cec5SDimitry Andric   eExprTypeDimY,
17420b57cec5SDimitry Andric   eExprTypeDimZ,
17430b57cec5SDimitry Andric   eExprTypeElemPtr,
17440b57cec5SDimitry Andric   eExprElementType,
17450b57cec5SDimitry Andric   eExprElementKind,
17460b57cec5SDimitry Andric   eExprElementVec,
17470b57cec5SDimitry Andric   eExprElementFieldCount,
17480b57cec5SDimitry Andric   eExprSubelementsId,
17490b57cec5SDimitry Andric   eExprSubelementsName,
17500b57cec5SDimitry Andric   eExprSubelementsArrSize,
17510b57cec5SDimitry Andric 
17520b57cec5SDimitry Andric   _eExprLast // keep at the end, implicit size of the array runtime_expressions
17530b57cec5SDimitry Andric };
17540b57cec5SDimitry Andric 
17550b57cec5SDimitry Andric // max length of an expanded expression
17560b57cec5SDimitry Andric const int jit_max_expr_size = 512;
17570b57cec5SDimitry Andric 
17580b57cec5SDimitry Andric // Retrieve the string to JIT for the given expression
17590b57cec5SDimitry Andric #define JIT_TEMPLATE_CONTEXT "void* ctxt = (void*)rsDebugGetContextWrapper(0x%" PRIx64 "); "
JITTemplate(ExpressionStrings e)17600b57cec5SDimitry Andric const char *JITTemplate(ExpressionStrings e) {
17610b57cec5SDimitry Andric   // Format strings containing the expressions we may need to evaluate.
17620b57cec5SDimitry Andric   static std::array<const char *, _eExprLast> runtime_expressions = {
17630b57cec5SDimitry Andric       {// Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap)
17640b57cec5SDimitry Andric        "(int*)_"
17650b57cec5SDimitry Andric        "Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocation"
17660b57cec5SDimitry Andric        "CubemapFace"
17670b57cec5SDimitry Andric        "(0x%" PRIx64 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", 0, 0)", // eExprGetOffsetPtr
17680b57cec5SDimitry Andric 
17690b57cec5SDimitry Andric        // Type* rsaAllocationGetType(Context*, Allocation*)
17700b57cec5SDimitry Andric        JIT_TEMPLATE_CONTEXT "(void*)rsaAllocationGetType(ctxt, 0x%" PRIx64 ")", // eExprAllocGetType
17710b57cec5SDimitry Andric 
17720b57cec5SDimitry Andric        // rsaTypeGetNativeData(Context*, Type*, void* typeData, size) Pack the
17730b57cec5SDimitry Andric        // data in the following way mHal.state.dimX; mHal.state.dimY;
17740b57cec5SDimitry Andric        // mHal.state.dimZ; mHal.state.lodCount; mHal.state.faces; mElement;
17750b57cec5SDimitry Andric        // into typeData Need to specify 32 or 64 bit for uint_t since this
17760b57cec5SDimitry Andric        // differs between devices
17770b57cec5SDimitry Andric        JIT_TEMPLATE_CONTEXT
17780b57cec5SDimitry Andric        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
17790b57cec5SDimitry Andric        ", 0x%" PRIx64 ", data, 6); data[0]", // eExprTypeDimX
17800b57cec5SDimitry Andric        JIT_TEMPLATE_CONTEXT
17810b57cec5SDimitry Andric        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
17820b57cec5SDimitry Andric        ", 0x%" PRIx64 ", data, 6); data[1]", // eExprTypeDimY
17830b57cec5SDimitry Andric        JIT_TEMPLATE_CONTEXT
17840b57cec5SDimitry Andric        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
17850b57cec5SDimitry Andric        ", 0x%" PRIx64 ", data, 6); data[2]", // eExprTypeDimZ
17860b57cec5SDimitry Andric        JIT_TEMPLATE_CONTEXT
17870b57cec5SDimitry Andric        "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
17880b57cec5SDimitry Andric        ", 0x%" PRIx64 ", data, 6); data[5]", // eExprTypeElemPtr
17890b57cec5SDimitry Andric 
17900b57cec5SDimitry Andric        // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size)
17910b57cec5SDimitry Andric        // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into
17920b57cec5SDimitry Andric        // elemData
17930b57cec5SDimitry Andric        JIT_TEMPLATE_CONTEXT
17940b57cec5SDimitry Andric        "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
17950b57cec5SDimitry Andric        ", 0x%" PRIx64 ", data, 5); data[0]", // eExprElementType
17960b57cec5SDimitry Andric        JIT_TEMPLATE_CONTEXT
17970b57cec5SDimitry Andric        "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
17980b57cec5SDimitry Andric        ", 0x%" PRIx64 ", data, 5); data[1]", // eExprElementKind
17990b57cec5SDimitry Andric        JIT_TEMPLATE_CONTEXT
18000b57cec5SDimitry Andric        "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
18010b57cec5SDimitry Andric        ", 0x%" PRIx64 ", data, 5); data[3]", // eExprElementVec
18020b57cec5SDimitry Andric        JIT_TEMPLATE_CONTEXT
18030b57cec5SDimitry Andric        "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
18040b57cec5SDimitry Andric        ", 0x%" PRIx64 ", data, 5); data[4]", // eExprElementFieldCount
18050b57cec5SDimitry Andric 
18060b57cec5SDimitry Andric        // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t
18070b57cec5SDimitry Andric        // *ids, const char **names, size_t *arraySizes, uint32_t dataSize)
18080b57cec5SDimitry Andric        // Needed for Allocations of structs to gather details about
18090b57cec5SDimitry Andric        // fields/Subelements Element* of field
18100b57cec5SDimitry Andric        JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
18110b57cec5SDimitry Andric        "]; size_t arr_size[%" PRIu32 "];"
18120b57cec5SDimitry Andric        "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64
18130b57cec5SDimitry Andric        ", ids, names, arr_size, %" PRIu32 "); ids[%" PRIu32 "]", // eExprSubelementsId
18140b57cec5SDimitry Andric 
18150b57cec5SDimitry Andric        // Name of field
18160b57cec5SDimitry Andric        JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
18170b57cec5SDimitry Andric        "]; size_t arr_size[%" PRIu32 "];"
18180b57cec5SDimitry Andric        "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64
18190b57cec5SDimitry Andric        ", ids, names, arr_size, %" PRIu32 "); names[%" PRIu32 "]", // eExprSubelementsName
18200b57cec5SDimitry Andric 
18210b57cec5SDimitry Andric        // Array size of field
18220b57cec5SDimitry Andric        JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
18230b57cec5SDimitry Andric        "]; size_t arr_size[%" PRIu32 "];"
18240b57cec5SDimitry Andric        "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64
18250b57cec5SDimitry Andric        ", ids, names, arr_size, %" PRIu32 "); arr_size[%" PRIu32 "]"}}; // eExprSubelementsArrSize
18260b57cec5SDimitry Andric 
18270b57cec5SDimitry Andric   return runtime_expressions[e];
18280b57cec5SDimitry Andric }
18290b57cec5SDimitry Andric } // end of the anonymous namespace
18300b57cec5SDimitry Andric 
18310b57cec5SDimitry Andric // JITs the RS runtime for the internal data pointer of an allocation. Is
18320b57cec5SDimitry Andric // passed x,y,z coordinates for the pointer to a specific element. Then sets
18330b57cec5SDimitry Andric // the data_ptr member in Allocation with the result. Returns true on success,
18340b57cec5SDimitry Andric // false otherwise
JITDataPointer(AllocationDetails * alloc,StackFrame * frame_ptr,uint32_t x,uint32_t y,uint32_t z)18350b57cec5SDimitry Andric bool RenderScriptRuntime::JITDataPointer(AllocationDetails *alloc,
18360b57cec5SDimitry Andric                                          StackFrame *frame_ptr, uint32_t x,
18370b57cec5SDimitry Andric                                          uint32_t y, uint32_t z) {
18380b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
18390b57cec5SDimitry Andric 
18400b57cec5SDimitry Andric   if (!alloc->address.isValid()) {
18419dba64beSDimitry Andric     LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
18420b57cec5SDimitry Andric     return false;
18430b57cec5SDimitry Andric   }
18440b57cec5SDimitry Andric 
18450b57cec5SDimitry Andric   const char *fmt_str = JITTemplate(eExprGetOffsetPtr);
18460b57cec5SDimitry Andric   char expr_buf[jit_max_expr_size];
18470b57cec5SDimitry Andric 
18480b57cec5SDimitry Andric   int written = snprintf(expr_buf, jit_max_expr_size, fmt_str,
18490b57cec5SDimitry Andric                          *alloc->address.get(), x, y, z);
18500b57cec5SDimitry Andric   if (written < 0) {
18519dba64beSDimitry Andric     LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
18520b57cec5SDimitry Andric     return false;
18530b57cec5SDimitry Andric   } else if (written >= jit_max_expr_size) {
18549dba64beSDimitry Andric     LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
18550b57cec5SDimitry Andric     return false;
18560b57cec5SDimitry Andric   }
18570b57cec5SDimitry Andric 
18580b57cec5SDimitry Andric   uint64_t result = 0;
18590b57cec5SDimitry Andric   if (!EvalRSExpression(expr_buf, frame_ptr, &result))
18600b57cec5SDimitry Andric     return false;
18610b57cec5SDimitry Andric 
18620b57cec5SDimitry Andric   addr_t data_ptr = static_cast<lldb::addr_t>(result);
18630b57cec5SDimitry Andric   alloc->data_ptr = data_ptr;
18640b57cec5SDimitry Andric 
18650b57cec5SDimitry Andric   return true;
18660b57cec5SDimitry Andric }
18670b57cec5SDimitry Andric 
18680b57cec5SDimitry Andric // JITs the RS runtime for the internal pointer to the RS Type of an allocation
18690b57cec5SDimitry Andric // Then sets the type_ptr member in Allocation with the result. Returns true on
18700b57cec5SDimitry Andric // success, false otherwise
JITTypePointer(AllocationDetails * alloc,StackFrame * frame_ptr)18710b57cec5SDimitry Andric bool RenderScriptRuntime::JITTypePointer(AllocationDetails *alloc,
18720b57cec5SDimitry Andric                                          StackFrame *frame_ptr) {
18730b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
18740b57cec5SDimitry Andric 
18750b57cec5SDimitry Andric   if (!alloc->address.isValid() || !alloc->context.isValid()) {
18769dba64beSDimitry Andric     LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
18770b57cec5SDimitry Andric     return false;
18780b57cec5SDimitry Andric   }
18790b57cec5SDimitry Andric 
18800b57cec5SDimitry Andric   const char *fmt_str = JITTemplate(eExprAllocGetType);
18810b57cec5SDimitry Andric   char expr_buf[jit_max_expr_size];
18820b57cec5SDimitry Andric 
18830b57cec5SDimitry Andric   int written = snprintf(expr_buf, jit_max_expr_size, fmt_str,
18840b57cec5SDimitry Andric                          *alloc->context.get(), *alloc->address.get());
18850b57cec5SDimitry Andric   if (written < 0) {
18869dba64beSDimitry Andric     LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
18870b57cec5SDimitry Andric     return false;
18880b57cec5SDimitry Andric   } else if (written >= jit_max_expr_size) {
18899dba64beSDimitry Andric     LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
18900b57cec5SDimitry Andric     return false;
18910b57cec5SDimitry Andric   }
18920b57cec5SDimitry Andric 
18930b57cec5SDimitry Andric   uint64_t result = 0;
18940b57cec5SDimitry Andric   if (!EvalRSExpression(expr_buf, frame_ptr, &result))
18950b57cec5SDimitry Andric     return false;
18960b57cec5SDimitry Andric 
18970b57cec5SDimitry Andric   addr_t type_ptr = static_cast<lldb::addr_t>(result);
18980b57cec5SDimitry Andric   alloc->type_ptr = type_ptr;
18990b57cec5SDimitry Andric 
19000b57cec5SDimitry Andric   return true;
19010b57cec5SDimitry Andric }
19020b57cec5SDimitry Andric 
19030b57cec5SDimitry Andric // JITs the RS runtime for information about the dimensions and type of an
19040b57cec5SDimitry Andric // allocation Then sets dimension and element_ptr members in Allocation with
19050b57cec5SDimitry Andric // the result. Returns true on success, false otherwise
JITTypePacked(AllocationDetails * alloc,StackFrame * frame_ptr)19060b57cec5SDimitry Andric bool RenderScriptRuntime::JITTypePacked(AllocationDetails *alloc,
19070b57cec5SDimitry Andric                                         StackFrame *frame_ptr) {
19080b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
19090b57cec5SDimitry Andric 
19100b57cec5SDimitry Andric   if (!alloc->type_ptr.isValid() || !alloc->context.isValid()) {
19119dba64beSDimitry Andric     LLDB_LOGF(log, "%s - Failed to find allocation details.", __FUNCTION__);
19120b57cec5SDimitry Andric     return false;
19130b57cec5SDimitry Andric   }
19140b57cec5SDimitry Andric 
19150b57cec5SDimitry Andric   // Expression is different depending on if device is 32 or 64 bit
19160b57cec5SDimitry Andric   uint32_t target_ptr_size =
19170b57cec5SDimitry Andric       GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
19180b57cec5SDimitry Andric   const uint32_t bits = target_ptr_size == 4 ? 32 : 64;
19190b57cec5SDimitry Andric 
19200b57cec5SDimitry Andric   // We want 4 elements from packed data
19210b57cec5SDimitry Andric   const uint32_t num_exprs = 4;
19220b57cec5SDimitry Andric   static_assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1),
19230b57cec5SDimitry Andric                 "Invalid number of expressions");
19240b57cec5SDimitry Andric 
19250b57cec5SDimitry Andric   char expr_bufs[num_exprs][jit_max_expr_size];
19260b57cec5SDimitry Andric   uint64_t results[num_exprs];
19270b57cec5SDimitry Andric 
19280b57cec5SDimitry Andric   for (uint32_t i = 0; i < num_exprs; ++i) {
19290b57cec5SDimitry Andric     const char *fmt_str = JITTemplate(ExpressionStrings(eExprTypeDimX + i));
19300b57cec5SDimitry Andric     int written = snprintf(expr_bufs[i], jit_max_expr_size, fmt_str,
19310b57cec5SDimitry Andric                            *alloc->context.get(), bits, *alloc->type_ptr.get());
19320b57cec5SDimitry Andric     if (written < 0) {
19339dba64beSDimitry Andric       LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
19340b57cec5SDimitry Andric       return false;
19350b57cec5SDimitry Andric     } else if (written >= jit_max_expr_size) {
19369dba64beSDimitry Andric       LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
19370b57cec5SDimitry Andric       return false;
19380b57cec5SDimitry Andric     }
19390b57cec5SDimitry Andric 
19400b57cec5SDimitry Andric     // Perform expression evaluation
19410b57cec5SDimitry Andric     if (!EvalRSExpression(expr_bufs[i], frame_ptr, &results[i]))
19420b57cec5SDimitry Andric       return false;
19430b57cec5SDimitry Andric   }
19440b57cec5SDimitry Andric 
19450b57cec5SDimitry Andric   // Assign results to allocation members
19460b57cec5SDimitry Andric   AllocationDetails::Dimension dims;
19470b57cec5SDimitry Andric   dims.dim_1 = static_cast<uint32_t>(results[0]);
19480b57cec5SDimitry Andric   dims.dim_2 = static_cast<uint32_t>(results[1]);
19490b57cec5SDimitry Andric   dims.dim_3 = static_cast<uint32_t>(results[2]);
19500b57cec5SDimitry Andric   alloc->dimension = dims;
19510b57cec5SDimitry Andric 
19520b57cec5SDimitry Andric   addr_t element_ptr = static_cast<lldb::addr_t>(results[3]);
19530b57cec5SDimitry Andric   alloc->element.element_ptr = element_ptr;
19540b57cec5SDimitry Andric 
19559dba64beSDimitry Andric   LLDB_LOGF(log,
19569dba64beSDimitry Andric             "%s - dims (%" PRIu32 ", %" PRIu32 ", %" PRIu32
19570b57cec5SDimitry Andric             ") Element*: 0x%" PRIx64 ".",
19580b57cec5SDimitry Andric             __FUNCTION__, dims.dim_1, dims.dim_2, dims.dim_3, element_ptr);
19590b57cec5SDimitry Andric 
19600b57cec5SDimitry Andric   return true;
19610b57cec5SDimitry Andric }
19620b57cec5SDimitry Andric 
19630b57cec5SDimitry Andric // JITs the RS runtime for information about the Element of an allocation Then
19640b57cec5SDimitry Andric // sets type, type_vec_size, field_count and type_kind members in Element with
19650b57cec5SDimitry Andric // the result. Returns true on success, false otherwise
JITElementPacked(Element & elem,const lldb::addr_t context,StackFrame * frame_ptr)19660b57cec5SDimitry Andric bool RenderScriptRuntime::JITElementPacked(Element &elem,
19670b57cec5SDimitry Andric                                            const lldb::addr_t context,
19680b57cec5SDimitry Andric                                            StackFrame *frame_ptr) {
19690b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
19700b57cec5SDimitry Andric 
19710b57cec5SDimitry Andric   if (!elem.element_ptr.isValid()) {
19729dba64beSDimitry Andric     LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
19730b57cec5SDimitry Andric     return false;
19740b57cec5SDimitry Andric   }
19750b57cec5SDimitry Andric 
19760b57cec5SDimitry Andric   // We want 4 elements from packed data
19770b57cec5SDimitry Andric   const uint32_t num_exprs = 4;
19780b57cec5SDimitry Andric   static_assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1),
19790b57cec5SDimitry Andric                 "Invalid number of expressions");
19800b57cec5SDimitry Andric 
19810b57cec5SDimitry Andric   char expr_bufs[num_exprs][jit_max_expr_size];
19820b57cec5SDimitry Andric   uint64_t results[num_exprs];
19830b57cec5SDimitry Andric 
19840b57cec5SDimitry Andric   for (uint32_t i = 0; i < num_exprs; i++) {
19850b57cec5SDimitry Andric     const char *fmt_str = JITTemplate(ExpressionStrings(eExprElementType + i));
19860b57cec5SDimitry Andric     int written = snprintf(expr_bufs[i], jit_max_expr_size, fmt_str, context,
19870b57cec5SDimitry Andric                            *elem.element_ptr.get());
19880b57cec5SDimitry Andric     if (written < 0) {
19899dba64beSDimitry Andric       LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
19900b57cec5SDimitry Andric       return false;
19910b57cec5SDimitry Andric     } else if (written >= jit_max_expr_size) {
19929dba64beSDimitry Andric       LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
19930b57cec5SDimitry Andric       return false;
19940b57cec5SDimitry Andric     }
19950b57cec5SDimitry Andric 
19960b57cec5SDimitry Andric     // Perform expression evaluation
19970b57cec5SDimitry Andric     if (!EvalRSExpression(expr_bufs[i], frame_ptr, &results[i]))
19980b57cec5SDimitry Andric       return false;
19990b57cec5SDimitry Andric   }
20000b57cec5SDimitry Andric 
20010b57cec5SDimitry Andric   // Assign results to allocation members
20020b57cec5SDimitry Andric   elem.type = static_cast<RenderScriptRuntime::Element::DataType>(results[0]);
20030b57cec5SDimitry Andric   elem.type_kind =
20040b57cec5SDimitry Andric       static_cast<RenderScriptRuntime::Element::DataKind>(results[1]);
20050b57cec5SDimitry Andric   elem.type_vec_size = static_cast<uint32_t>(results[2]);
20060b57cec5SDimitry Andric   elem.field_count = static_cast<uint32_t>(results[3]);
20070b57cec5SDimitry Andric 
20089dba64beSDimitry Andric   LLDB_LOGF(log,
20099dba64beSDimitry Andric             "%s - data type %" PRIu32 ", pixel type %" PRIu32
20100b57cec5SDimitry Andric             ", vector size %" PRIu32 ", field count %" PRIu32,
20110b57cec5SDimitry Andric             __FUNCTION__, *elem.type.get(), *elem.type_kind.get(),
20120b57cec5SDimitry Andric             *elem.type_vec_size.get(), *elem.field_count.get());
20130b57cec5SDimitry Andric 
20140b57cec5SDimitry Andric   // If this Element has subelements then JIT rsaElementGetSubElements() for
20150b57cec5SDimitry Andric   // details about its fields
20160b57cec5SDimitry Andric   return !(*elem.field_count.get() > 0 &&
20170b57cec5SDimitry Andric            !JITSubelements(elem, context, frame_ptr));
20180b57cec5SDimitry Andric }
20190b57cec5SDimitry Andric 
20200b57cec5SDimitry Andric // JITs the RS runtime for information about the subelements/fields of a struct
20210b57cec5SDimitry Andric // allocation This is necessary for infering the struct type so we can pretty
20220b57cec5SDimitry Andric // print the allocation's contents. Returns true on success, false otherwise
JITSubelements(Element & elem,const lldb::addr_t context,StackFrame * frame_ptr)20230b57cec5SDimitry Andric bool RenderScriptRuntime::JITSubelements(Element &elem,
20240b57cec5SDimitry Andric                                          const lldb::addr_t context,
20250b57cec5SDimitry Andric                                          StackFrame *frame_ptr) {
20260b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
20270b57cec5SDimitry Andric 
20280b57cec5SDimitry Andric   if (!elem.element_ptr.isValid() || !elem.field_count.isValid()) {
20299dba64beSDimitry Andric     LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
20300b57cec5SDimitry Andric     return false;
20310b57cec5SDimitry Andric   }
20320b57cec5SDimitry Andric 
20330b57cec5SDimitry Andric   const short num_exprs = 3;
20340b57cec5SDimitry Andric   static_assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1),
20350b57cec5SDimitry Andric                 "Invalid number of expressions");
20360b57cec5SDimitry Andric 
20370b57cec5SDimitry Andric   char expr_buffer[jit_max_expr_size];
20380b57cec5SDimitry Andric   uint64_t results;
20390b57cec5SDimitry Andric 
20400b57cec5SDimitry Andric   // Iterate over struct fields.
20410b57cec5SDimitry Andric   const uint32_t field_count = *elem.field_count.get();
20420b57cec5SDimitry Andric   for (uint32_t field_index = 0; field_index < field_count; ++field_index) {
20430b57cec5SDimitry Andric     Element child;
20440b57cec5SDimitry Andric     for (uint32_t expr_index = 0; expr_index < num_exprs; ++expr_index) {
20450b57cec5SDimitry Andric       const char *fmt_str =
20460b57cec5SDimitry Andric           JITTemplate(ExpressionStrings(eExprSubelementsId + expr_index));
20470b57cec5SDimitry Andric       int written = snprintf(expr_buffer, jit_max_expr_size, fmt_str,
20480b57cec5SDimitry Andric                              context, field_count, field_count, field_count,
20490b57cec5SDimitry Andric                              *elem.element_ptr.get(), field_count, field_index);
20500b57cec5SDimitry Andric       if (written < 0) {
20519dba64beSDimitry Andric         LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
20520b57cec5SDimitry Andric         return false;
20530b57cec5SDimitry Andric       } else if (written >= jit_max_expr_size) {
20549dba64beSDimitry Andric         LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
20550b57cec5SDimitry Andric         return false;
20560b57cec5SDimitry Andric       }
20570b57cec5SDimitry Andric 
20580b57cec5SDimitry Andric       // Perform expression evaluation
20590b57cec5SDimitry Andric       if (!EvalRSExpression(expr_buffer, frame_ptr, &results))
20600b57cec5SDimitry Andric         return false;
20610b57cec5SDimitry Andric 
20629dba64beSDimitry Andric       LLDB_LOGF(log, "%s - expr result 0x%" PRIx64 ".", __FUNCTION__, results);
20630b57cec5SDimitry Andric 
20640b57cec5SDimitry Andric       switch (expr_index) {
20650b57cec5SDimitry Andric       case 0: // Element* of child
20660b57cec5SDimitry Andric         child.element_ptr = static_cast<addr_t>(results);
20670b57cec5SDimitry Andric         break;
20680b57cec5SDimitry Andric       case 1: // Name of child
20690b57cec5SDimitry Andric       {
20700b57cec5SDimitry Andric         lldb::addr_t address = static_cast<addr_t>(results);
20710b57cec5SDimitry Andric         Status err;
20720b57cec5SDimitry Andric         std::string name;
20730b57cec5SDimitry Andric         GetProcess()->ReadCStringFromMemory(address, name, err);
20740b57cec5SDimitry Andric         if (!err.Fail())
20750b57cec5SDimitry Andric           child.type_name = ConstString(name);
20760b57cec5SDimitry Andric         else {
20779dba64beSDimitry Andric           LLDB_LOGF(log, "%s - warning: Couldn't read field name.",
20780b57cec5SDimitry Andric                     __FUNCTION__);
20790b57cec5SDimitry Andric         }
20800b57cec5SDimitry Andric         break;
20810b57cec5SDimitry Andric       }
20820b57cec5SDimitry Andric       case 2: // Array size of child
20830b57cec5SDimitry Andric         child.array_size = static_cast<uint32_t>(results);
20840b57cec5SDimitry Andric         break;
20850b57cec5SDimitry Andric       }
20860b57cec5SDimitry Andric     }
20870b57cec5SDimitry Andric 
20880b57cec5SDimitry Andric     // We need to recursively JIT each Element field of the struct since
20890b57cec5SDimitry Andric     // structs can be nested inside structs.
20900b57cec5SDimitry Andric     if (!JITElementPacked(child, context, frame_ptr))
20910b57cec5SDimitry Andric       return false;
20920b57cec5SDimitry Andric     elem.children.push_back(child);
20930b57cec5SDimitry Andric   }
20940b57cec5SDimitry Andric 
20950b57cec5SDimitry Andric   // Try to infer the name of the struct type so we can pretty print the
20960b57cec5SDimitry Andric   // allocation contents.
20970b57cec5SDimitry Andric   FindStructTypeName(elem, frame_ptr);
20980b57cec5SDimitry Andric 
20990b57cec5SDimitry Andric   return true;
21000b57cec5SDimitry Andric }
21010b57cec5SDimitry Andric 
21020b57cec5SDimitry Andric // JITs the RS runtime for the address of the last element in the allocation.
21030b57cec5SDimitry Andric // The `elem_size` parameter represents the size of a single element, including
21040b57cec5SDimitry Andric // padding. Which is needed as an offset from the last element pointer. Using
21050b57cec5SDimitry Andric // this offset minus the starting address we can calculate the size of the
21060b57cec5SDimitry Andric // allocation. Returns true on success, false otherwise
JITAllocationSize(AllocationDetails * alloc,StackFrame * frame_ptr)21070b57cec5SDimitry Andric bool RenderScriptRuntime::JITAllocationSize(AllocationDetails *alloc,
21080b57cec5SDimitry Andric                                             StackFrame *frame_ptr) {
21090b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
21100b57cec5SDimitry Andric 
21110b57cec5SDimitry Andric   if (!alloc->address.isValid() || !alloc->dimension.isValid() ||
21120b57cec5SDimitry Andric       !alloc->data_ptr.isValid() || !alloc->element.datum_size.isValid()) {
21139dba64beSDimitry Andric     LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
21140b57cec5SDimitry Andric     return false;
21150b57cec5SDimitry Andric   }
21160b57cec5SDimitry Andric 
21170b57cec5SDimitry Andric   // Find dimensions
21180b57cec5SDimitry Andric   uint32_t dim_x = alloc->dimension.get()->dim_1;
21190b57cec5SDimitry Andric   uint32_t dim_y = alloc->dimension.get()->dim_2;
21200b57cec5SDimitry Andric   uint32_t dim_z = alloc->dimension.get()->dim_3;
21210b57cec5SDimitry Andric 
21220b57cec5SDimitry Andric   // Our plan of jitting the last element address doesn't seem to work for
21230b57cec5SDimitry Andric   // struct Allocations` Instead try to infer the size ourselves without any
21240b57cec5SDimitry Andric   // inter element padding.
21250b57cec5SDimitry Andric   if (alloc->element.children.size() > 0) {
21260b57cec5SDimitry Andric     if (dim_x == 0)
21270b57cec5SDimitry Andric       dim_x = 1;
21280b57cec5SDimitry Andric     if (dim_y == 0)
21290b57cec5SDimitry Andric       dim_y = 1;
21300b57cec5SDimitry Andric     if (dim_z == 0)
21310b57cec5SDimitry Andric       dim_z = 1;
21320b57cec5SDimitry Andric 
21330b57cec5SDimitry Andric     alloc->size = dim_x * dim_y * dim_z * *alloc->element.datum_size.get();
21340b57cec5SDimitry Andric 
21359dba64beSDimitry Andric     LLDB_LOGF(log, "%s - inferred size of struct allocation %" PRIu32 ".",
21360b57cec5SDimitry Andric               __FUNCTION__, *alloc->size.get());
21370b57cec5SDimitry Andric     return true;
21380b57cec5SDimitry Andric   }
21390b57cec5SDimitry Andric 
21400b57cec5SDimitry Andric   const char *fmt_str = JITTemplate(eExprGetOffsetPtr);
21410b57cec5SDimitry Andric   char expr_buf[jit_max_expr_size];
21420b57cec5SDimitry Andric 
21430b57cec5SDimitry Andric   // Calculate last element
21440b57cec5SDimitry Andric   dim_x = dim_x == 0 ? 0 : dim_x - 1;
21450b57cec5SDimitry Andric   dim_y = dim_y == 0 ? 0 : dim_y - 1;
21460b57cec5SDimitry Andric   dim_z = dim_z == 0 ? 0 : dim_z - 1;
21470b57cec5SDimitry Andric 
21480b57cec5SDimitry Andric   int written = snprintf(expr_buf, jit_max_expr_size, fmt_str,
21490b57cec5SDimitry Andric                          *alloc->address.get(), dim_x, dim_y, dim_z);
21500b57cec5SDimitry Andric   if (written < 0) {
21519dba64beSDimitry Andric     LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
21520b57cec5SDimitry Andric     return false;
21530b57cec5SDimitry Andric   } else if (written >= jit_max_expr_size) {
21549dba64beSDimitry Andric     LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
21550b57cec5SDimitry Andric     return false;
21560b57cec5SDimitry Andric   }
21570b57cec5SDimitry Andric 
21580b57cec5SDimitry Andric   uint64_t result = 0;
21590b57cec5SDimitry Andric   if (!EvalRSExpression(expr_buf, frame_ptr, &result))
21600b57cec5SDimitry Andric     return false;
21610b57cec5SDimitry Andric 
21620b57cec5SDimitry Andric   addr_t mem_ptr = static_cast<lldb::addr_t>(result);
21630b57cec5SDimitry Andric   // Find pointer to last element and add on size of an element
21640b57cec5SDimitry Andric   alloc->size = static_cast<uint32_t>(mem_ptr - *alloc->data_ptr.get()) +
21650b57cec5SDimitry Andric                 *alloc->element.datum_size.get();
21660b57cec5SDimitry Andric 
21670b57cec5SDimitry Andric   return true;
21680b57cec5SDimitry Andric }
21690b57cec5SDimitry Andric 
21700b57cec5SDimitry Andric // JITs the RS runtime for information about the stride between rows in the
21710b57cec5SDimitry Andric // allocation. This is done to detect padding, since allocated memory is
21720b57cec5SDimitry Andric // 16-byte aligned. Returns true on success, false otherwise
JITAllocationStride(AllocationDetails * alloc,StackFrame * frame_ptr)21730b57cec5SDimitry Andric bool RenderScriptRuntime::JITAllocationStride(AllocationDetails *alloc,
21740b57cec5SDimitry Andric                                               StackFrame *frame_ptr) {
21750b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
21760b57cec5SDimitry Andric 
21770b57cec5SDimitry Andric   if (!alloc->address.isValid() || !alloc->data_ptr.isValid()) {
21789dba64beSDimitry Andric     LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
21790b57cec5SDimitry Andric     return false;
21800b57cec5SDimitry Andric   }
21810b57cec5SDimitry Andric 
21820b57cec5SDimitry Andric   const char *fmt_str = JITTemplate(eExprGetOffsetPtr);
21830b57cec5SDimitry Andric   char expr_buf[jit_max_expr_size];
21840b57cec5SDimitry Andric 
21850b57cec5SDimitry Andric   int written = snprintf(expr_buf, jit_max_expr_size, fmt_str,
21860b57cec5SDimitry Andric                          *alloc->address.get(), 0, 1, 0);
21870b57cec5SDimitry Andric   if (written < 0) {
21889dba64beSDimitry Andric     LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
21890b57cec5SDimitry Andric     return false;
21900b57cec5SDimitry Andric   } else if (written >= jit_max_expr_size) {
21919dba64beSDimitry Andric     LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
21920b57cec5SDimitry Andric     return false;
21930b57cec5SDimitry Andric   }
21940b57cec5SDimitry Andric 
21950b57cec5SDimitry Andric   uint64_t result = 0;
21960b57cec5SDimitry Andric   if (!EvalRSExpression(expr_buf, frame_ptr, &result))
21970b57cec5SDimitry Andric     return false;
21980b57cec5SDimitry Andric 
21990b57cec5SDimitry Andric   addr_t mem_ptr = static_cast<lldb::addr_t>(result);
22000b57cec5SDimitry Andric   alloc->stride = static_cast<uint32_t>(mem_ptr - *alloc->data_ptr.get());
22010b57cec5SDimitry Andric 
22020b57cec5SDimitry Andric   return true;
22030b57cec5SDimitry Andric }
22040b57cec5SDimitry Andric 
22050b57cec5SDimitry Andric // JIT all the current runtime info regarding an allocation
RefreshAllocation(AllocationDetails * alloc,StackFrame * frame_ptr)22060b57cec5SDimitry Andric bool RenderScriptRuntime::RefreshAllocation(AllocationDetails *alloc,
22070b57cec5SDimitry Andric                                             StackFrame *frame_ptr) {
22080b57cec5SDimitry Andric   // GetOffsetPointer()
22090b57cec5SDimitry Andric   if (!JITDataPointer(alloc, frame_ptr))
22100b57cec5SDimitry Andric     return false;
22110b57cec5SDimitry Andric 
22120b57cec5SDimitry Andric   // rsaAllocationGetType()
22130b57cec5SDimitry Andric   if (!JITTypePointer(alloc, frame_ptr))
22140b57cec5SDimitry Andric     return false;
22150b57cec5SDimitry Andric 
22160b57cec5SDimitry Andric   // rsaTypeGetNativeData()
22170b57cec5SDimitry Andric   if (!JITTypePacked(alloc, frame_ptr))
22180b57cec5SDimitry Andric     return false;
22190b57cec5SDimitry Andric 
22200b57cec5SDimitry Andric   // rsaElementGetNativeData()
22210b57cec5SDimitry Andric   if (!JITElementPacked(alloc->element, *alloc->context.get(), frame_ptr))
22220b57cec5SDimitry Andric     return false;
22230b57cec5SDimitry Andric 
22240b57cec5SDimitry Andric   // Sets the datum_size member in Element
22250b57cec5SDimitry Andric   SetElementSize(alloc->element);
22260b57cec5SDimitry Andric 
22270b57cec5SDimitry Andric   // Use GetOffsetPointer() to infer size of the allocation
22280b57cec5SDimitry Andric   return JITAllocationSize(alloc, frame_ptr);
22290b57cec5SDimitry Andric }
22300b57cec5SDimitry Andric 
2231*5f7ddb14SDimitry Andric // Function attempts to set the type_name member of the parameterised Element
22320b57cec5SDimitry Andric // object. This string should be the name of the struct type the Element
22330b57cec5SDimitry Andric // represents. We need this string for pretty printing the Element to users.
FindStructTypeName(Element & elem,StackFrame * frame_ptr)22340b57cec5SDimitry Andric void RenderScriptRuntime::FindStructTypeName(Element &elem,
22350b57cec5SDimitry Andric                                              StackFrame *frame_ptr) {
22360b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
22370b57cec5SDimitry Andric 
22380b57cec5SDimitry Andric   if (!elem.type_name.IsEmpty()) // Name already set
22390b57cec5SDimitry Andric     return;
22400b57cec5SDimitry Andric   else
22410b57cec5SDimitry Andric     elem.type_name = Element::GetFallbackStructName(); // Default type name if
22420b57cec5SDimitry Andric                                                        // we don't succeed
22430b57cec5SDimitry Andric 
22440b57cec5SDimitry Andric   // Find all the global variables from the script rs modules
22450b57cec5SDimitry Andric   VariableList var_list;
22460b57cec5SDimitry Andric   for (auto module_sp : m_rsmodules)
22470b57cec5SDimitry Andric     module_sp->m_module->FindGlobalVariables(
22480b57cec5SDimitry Andric         RegularExpression(llvm::StringRef(".")), UINT32_MAX, var_list);
22490b57cec5SDimitry Andric 
22500b57cec5SDimitry Andric   // Iterate over all the global variables looking for one with a matching type
22510b57cec5SDimitry Andric   // to the Element. We make the assumption a match exists since there needs to
22520b57cec5SDimitry Andric   // be a global variable to reflect the struct type back into java host code.
2253480093f4SDimitry Andric   for (const VariableSP &var_sp : var_list) {
22540b57cec5SDimitry Andric     if (!var_sp)
22550b57cec5SDimitry Andric       continue;
22560b57cec5SDimitry Andric 
22570b57cec5SDimitry Andric     ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp);
22580b57cec5SDimitry Andric     if (!valobj_sp)
22590b57cec5SDimitry Andric       continue;
22600b57cec5SDimitry Andric 
22610b57cec5SDimitry Andric     // Find the number of variable fields.
22620b57cec5SDimitry Andric     // If it has no fields, or more fields than our Element, then it can't be
22630b57cec5SDimitry Andric     // the struct we're looking for. Don't check for equality since RS can add
22640b57cec5SDimitry Andric     // extra struct members for padding.
22650b57cec5SDimitry Andric     size_t num_children = valobj_sp->GetNumChildren();
22660b57cec5SDimitry Andric     if (num_children > elem.children.size() || num_children == 0)
22670b57cec5SDimitry Andric       continue;
22680b57cec5SDimitry Andric 
22690b57cec5SDimitry Andric     // Iterate over children looking for members with matching field names. If
22700b57cec5SDimitry Andric     // all the field names match, this is likely the struct we want.
22710b57cec5SDimitry Andric     //   TODO: This could be made more robust by also checking children data
22720b57cec5SDimitry Andric     //   sizes, or array size
22730b57cec5SDimitry Andric     bool found = true;
22740b57cec5SDimitry Andric     for (size_t i = 0; i < num_children; ++i) {
22750b57cec5SDimitry Andric       ValueObjectSP child = valobj_sp->GetChildAtIndex(i, true);
22760b57cec5SDimitry Andric       if (!child || (child->GetName() != elem.children[i].type_name)) {
22770b57cec5SDimitry Andric         found = false;
22780b57cec5SDimitry Andric         break;
22790b57cec5SDimitry Andric       }
22800b57cec5SDimitry Andric     }
22810b57cec5SDimitry Andric 
22820b57cec5SDimitry Andric     // RS can add extra struct members for padding in the format
22830b57cec5SDimitry Andric     // '#rs_padding_[0-9]+'
22840b57cec5SDimitry Andric     if (found && num_children < elem.children.size()) {
22850b57cec5SDimitry Andric       const uint32_t size_diff = elem.children.size() - num_children;
22869dba64beSDimitry Andric       LLDB_LOGF(log, "%s - %" PRIu32 " padding struct entries", __FUNCTION__,
22870b57cec5SDimitry Andric                 size_diff);
22880b57cec5SDimitry Andric 
22890b57cec5SDimitry Andric       for (uint32_t i = 0; i < size_diff; ++i) {
22900b57cec5SDimitry Andric         ConstString name = elem.children[num_children + i].type_name;
22910b57cec5SDimitry Andric         if (strcmp(name.AsCString(), "#rs_padding") < 0)
22920b57cec5SDimitry Andric           found = false;
22930b57cec5SDimitry Andric       }
22940b57cec5SDimitry Andric     }
22950b57cec5SDimitry Andric 
22960b57cec5SDimitry Andric     // We've found a global variable with matching type
22970b57cec5SDimitry Andric     if (found) {
22980b57cec5SDimitry Andric       // Dereference since our Element type isn't a pointer.
22990b57cec5SDimitry Andric       if (valobj_sp->IsPointerType()) {
23000b57cec5SDimitry Andric         Status err;
23010b57cec5SDimitry Andric         ValueObjectSP deref_valobj = valobj_sp->Dereference(err);
23020b57cec5SDimitry Andric         if (!err.Fail())
23030b57cec5SDimitry Andric           valobj_sp = deref_valobj;
23040b57cec5SDimitry Andric       }
23050b57cec5SDimitry Andric 
23060b57cec5SDimitry Andric       // Save name of variable in Element.
23070b57cec5SDimitry Andric       elem.type_name = valobj_sp->GetTypeName();
23089dba64beSDimitry Andric       LLDB_LOGF(log, "%s - element name set to %s", __FUNCTION__,
23090b57cec5SDimitry Andric                 elem.type_name.AsCString());
23100b57cec5SDimitry Andric 
23110b57cec5SDimitry Andric       return;
23120b57cec5SDimitry Andric     }
23130b57cec5SDimitry Andric   }
23140b57cec5SDimitry Andric }
23150b57cec5SDimitry Andric 
23160b57cec5SDimitry Andric // Function sets the datum_size member of Element. Representing the size of a
23170b57cec5SDimitry Andric // single instance including padding. Assumes the relevant allocation
23180b57cec5SDimitry Andric // information has already been jitted.
SetElementSize(Element & elem)23190b57cec5SDimitry Andric void RenderScriptRuntime::SetElementSize(Element &elem) {
23200b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
23210b57cec5SDimitry Andric   const Element::DataType type = *elem.type.get();
23220b57cec5SDimitry Andric   assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT &&
23230b57cec5SDimitry Andric          "Invalid allocation type");
23240b57cec5SDimitry Andric 
23250b57cec5SDimitry Andric   const uint32_t vec_size = *elem.type_vec_size.get();
23260b57cec5SDimitry Andric   uint32_t data_size = 0;
23270b57cec5SDimitry Andric   uint32_t padding = 0;
23280b57cec5SDimitry Andric 
23290b57cec5SDimitry Andric   // Element is of a struct type, calculate size recursively.
23300b57cec5SDimitry Andric   if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) {
23310b57cec5SDimitry Andric     for (Element &child : elem.children) {
23320b57cec5SDimitry Andric       SetElementSize(child);
23330b57cec5SDimitry Andric       const uint32_t array_size =
23340b57cec5SDimitry Andric           child.array_size.isValid() ? *child.array_size.get() : 1;
23350b57cec5SDimitry Andric       data_size += *child.datum_size.get() * array_size;
23360b57cec5SDimitry Andric     }
23370b57cec5SDimitry Andric   }
23380b57cec5SDimitry Andric   // These have been packed already
23390b57cec5SDimitry Andric   else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 ||
23400b57cec5SDimitry Andric            type == Element::RS_TYPE_UNSIGNED_5_5_5_1 ||
23410b57cec5SDimitry Andric            type == Element::RS_TYPE_UNSIGNED_4_4_4_4) {
23420b57cec5SDimitry Andric     data_size = AllocationDetails::RSTypeToFormat[type][eElementSize];
23430b57cec5SDimitry Andric   } else if (type < Element::RS_TYPE_ELEMENT) {
23440b57cec5SDimitry Andric     data_size =
23450b57cec5SDimitry Andric         vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize];
23460b57cec5SDimitry Andric     if (vec_size == 3)
23470b57cec5SDimitry Andric       padding = AllocationDetails::RSTypeToFormat[type][eElementSize];
23480b57cec5SDimitry Andric   } else
23490b57cec5SDimitry Andric     data_size =
23500b57cec5SDimitry Andric         GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
23510b57cec5SDimitry Andric 
23520b57cec5SDimitry Andric   elem.padding = padding;
23530b57cec5SDimitry Andric   elem.datum_size = data_size + padding;
23549dba64beSDimitry Andric   LLDB_LOGF(log, "%s - element size set to %" PRIu32, __FUNCTION__,
23550b57cec5SDimitry Andric             data_size + padding);
23560b57cec5SDimitry Andric }
23570b57cec5SDimitry Andric 
23580b57cec5SDimitry Andric // Given an allocation, this function copies the allocation contents from
23590b57cec5SDimitry Andric // device into a buffer on the heap. Returning a shared pointer to the buffer
23600b57cec5SDimitry Andric // containing the data.
23610b57cec5SDimitry Andric std::shared_ptr<uint8_t>
GetAllocationData(AllocationDetails * alloc,StackFrame * frame_ptr)23620b57cec5SDimitry Andric RenderScriptRuntime::GetAllocationData(AllocationDetails *alloc,
23630b57cec5SDimitry Andric                                        StackFrame *frame_ptr) {
23640b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
23650b57cec5SDimitry Andric 
23660b57cec5SDimitry Andric   // JIT all the allocation details
23670b57cec5SDimitry Andric   if (alloc->ShouldRefresh()) {
23689dba64beSDimitry Andric     LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info",
23690b57cec5SDimitry Andric               __FUNCTION__);
23700b57cec5SDimitry Andric 
23710b57cec5SDimitry Andric     if (!RefreshAllocation(alloc, frame_ptr)) {
23729dba64beSDimitry Andric       LLDB_LOGF(log, "%s - couldn't JIT allocation details", __FUNCTION__);
23730b57cec5SDimitry Andric       return nullptr;
23740b57cec5SDimitry Andric     }
23750b57cec5SDimitry Andric   }
23760b57cec5SDimitry Andric 
23770b57cec5SDimitry Andric   assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
23780b57cec5SDimitry Andric          alloc->element.type_vec_size.isValid() && alloc->size.isValid() &&
23790b57cec5SDimitry Andric          "Allocation information not available");
23800b57cec5SDimitry Andric 
23810b57cec5SDimitry Andric   // Allocate a buffer to copy data into
23820b57cec5SDimitry Andric   const uint32_t size = *alloc->size.get();
23830b57cec5SDimitry Andric   std::shared_ptr<uint8_t> buffer(new uint8_t[size]);
23840b57cec5SDimitry Andric   if (!buffer) {
23859dba64beSDimitry Andric     LLDB_LOGF(log, "%s - couldn't allocate a %" PRIu32 " byte buffer",
23860b57cec5SDimitry Andric               __FUNCTION__, size);
23870b57cec5SDimitry Andric     return nullptr;
23880b57cec5SDimitry Andric   }
23890b57cec5SDimitry Andric 
23900b57cec5SDimitry Andric   // Read the inferior memory
23910b57cec5SDimitry Andric   Status err;
23920b57cec5SDimitry Andric   lldb::addr_t data_ptr = *alloc->data_ptr.get();
23930b57cec5SDimitry Andric   GetProcess()->ReadMemory(data_ptr, buffer.get(), size, err);
23940b57cec5SDimitry Andric   if (err.Fail()) {
23959dba64beSDimitry Andric     LLDB_LOGF(log,
23969dba64beSDimitry Andric               "%s - '%s' Couldn't read %" PRIu32
23970b57cec5SDimitry Andric               " bytes of allocation data from 0x%" PRIx64,
23980b57cec5SDimitry Andric               __FUNCTION__, err.AsCString(), size, data_ptr);
23990b57cec5SDimitry Andric     return nullptr;
24000b57cec5SDimitry Andric   }
24010b57cec5SDimitry Andric 
24020b57cec5SDimitry Andric   return buffer;
24030b57cec5SDimitry Andric }
24040b57cec5SDimitry Andric 
24050b57cec5SDimitry Andric // Function copies data from a binary file into an allocation. There is a
24060b57cec5SDimitry Andric // header at the start of the file, FileHeader, before the data content itself.
24070b57cec5SDimitry Andric // Information from this header is used to display warnings to the user about
24080b57cec5SDimitry Andric // incompatibilities
LoadAllocation(Stream & strm,const uint32_t alloc_id,const char * path,StackFrame * frame_ptr)24090b57cec5SDimitry Andric bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id,
24100b57cec5SDimitry Andric                                          const char *path,
24110b57cec5SDimitry Andric                                          StackFrame *frame_ptr) {
24120b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
24130b57cec5SDimitry Andric 
24140b57cec5SDimitry Andric   // Find allocation with the given id
24150b57cec5SDimitry Andric   AllocationDetails *alloc = FindAllocByID(strm, alloc_id);
24160b57cec5SDimitry Andric   if (!alloc)
24170b57cec5SDimitry Andric     return false;
24180b57cec5SDimitry Andric 
24199dba64beSDimitry Andric   LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64, __FUNCTION__,
24200b57cec5SDimitry Andric             *alloc->address.get());
24210b57cec5SDimitry Andric 
24220b57cec5SDimitry Andric   // JIT all the allocation details
24230b57cec5SDimitry Andric   if (alloc->ShouldRefresh()) {
24249dba64beSDimitry Andric     LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.",
24250b57cec5SDimitry Andric               __FUNCTION__);
24260b57cec5SDimitry Andric 
24270b57cec5SDimitry Andric     if (!RefreshAllocation(alloc, frame_ptr)) {
24289dba64beSDimitry Andric       LLDB_LOGF(log, "%s - couldn't JIT allocation details", __FUNCTION__);
24290b57cec5SDimitry Andric       return false;
24300b57cec5SDimitry Andric     }
24310b57cec5SDimitry Andric   }
24320b57cec5SDimitry Andric 
24330b57cec5SDimitry Andric   assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
24340b57cec5SDimitry Andric          alloc->element.type_vec_size.isValid() && alloc->size.isValid() &&
24350b57cec5SDimitry Andric          alloc->element.datum_size.isValid() &&
24360b57cec5SDimitry Andric          "Allocation information not available");
24370b57cec5SDimitry Andric 
24380b57cec5SDimitry Andric   // Check we can read from file
24390b57cec5SDimitry Andric   FileSpec file(path);
24400b57cec5SDimitry Andric   FileSystem::Instance().Resolve(file);
24410b57cec5SDimitry Andric   if (!FileSystem::Instance().Exists(file)) {
24420b57cec5SDimitry Andric     strm.Printf("Error: File %s does not exist", path);
24430b57cec5SDimitry Andric     strm.EOL();
24440b57cec5SDimitry Andric     return false;
24450b57cec5SDimitry Andric   }
24460b57cec5SDimitry Andric 
24470b57cec5SDimitry Andric   if (!FileSystem::Instance().Readable(file)) {
24480b57cec5SDimitry Andric     strm.Printf("Error: File %s does not have readable permissions", path);
24490b57cec5SDimitry Andric     strm.EOL();
24500b57cec5SDimitry Andric     return false;
24510b57cec5SDimitry Andric   }
24520b57cec5SDimitry Andric 
24530b57cec5SDimitry Andric   // Read file into data buffer
24540b57cec5SDimitry Andric   auto data_sp = FileSystem::Instance().CreateDataBuffer(file.GetPath());
24550b57cec5SDimitry Andric 
24560b57cec5SDimitry Andric   // Cast start of buffer to FileHeader and use pointer to read metadata
24570b57cec5SDimitry Andric   void *file_buf = data_sp->GetBytes();
24580b57cec5SDimitry Andric   if (file_buf == nullptr ||
24590b57cec5SDimitry Andric       data_sp->GetByteSize() < (sizeof(AllocationDetails::FileHeader) +
24600b57cec5SDimitry Andric                                 sizeof(AllocationDetails::ElementHeader))) {
24610b57cec5SDimitry Andric     strm.Printf("Error: File %s does not contain enough data for header", path);
24620b57cec5SDimitry Andric     strm.EOL();
24630b57cec5SDimitry Andric     return false;
24640b57cec5SDimitry Andric   }
24650b57cec5SDimitry Andric   const AllocationDetails::FileHeader *file_header =
24660b57cec5SDimitry Andric       static_cast<AllocationDetails::FileHeader *>(file_buf);
24670b57cec5SDimitry Andric 
24680b57cec5SDimitry Andric   // Check file starts with ascii characters "RSAD"
24690b57cec5SDimitry Andric   if (memcmp(file_header->ident, "RSAD", 4)) {
24700b57cec5SDimitry Andric     strm.Printf("Error: File doesn't contain identifier for an RS allocation "
24710b57cec5SDimitry Andric                 "dump. Are you sure this is the correct file?");
24720b57cec5SDimitry Andric     strm.EOL();
24730b57cec5SDimitry Andric     return false;
24740b57cec5SDimitry Andric   }
24750b57cec5SDimitry Andric 
24760b57cec5SDimitry Andric   // Look at the type of the root element in the header
24770b57cec5SDimitry Andric   AllocationDetails::ElementHeader root_el_hdr;
24780b57cec5SDimitry Andric   memcpy(&root_el_hdr, static_cast<uint8_t *>(file_buf) +
24790b57cec5SDimitry Andric                            sizeof(AllocationDetails::FileHeader),
24800b57cec5SDimitry Andric          sizeof(AllocationDetails::ElementHeader));
24810b57cec5SDimitry Andric 
24829dba64beSDimitry Andric   LLDB_LOGF(log, "%s - header type %" PRIu32 ", element size %" PRIu32,
24830b57cec5SDimitry Andric             __FUNCTION__, root_el_hdr.type, root_el_hdr.element_size);
24840b57cec5SDimitry Andric 
24850b57cec5SDimitry Andric   // Check if the target allocation and file both have the same number of bytes
24860b57cec5SDimitry Andric   // for an Element
24870b57cec5SDimitry Andric   if (*alloc->element.datum_size.get() != root_el_hdr.element_size) {
24880b57cec5SDimitry Andric     strm.Printf("Warning: Mismatched Element sizes - file %" PRIu32
24890b57cec5SDimitry Andric                 " bytes, allocation %" PRIu32 " bytes",
24900b57cec5SDimitry Andric                 root_el_hdr.element_size, *alloc->element.datum_size.get());
24910b57cec5SDimitry Andric     strm.EOL();
24920b57cec5SDimitry Andric   }
24930b57cec5SDimitry Andric 
24940b57cec5SDimitry Andric   // Check if the target allocation and file both have the same type
24950b57cec5SDimitry Andric   const uint32_t alloc_type = static_cast<uint32_t>(*alloc->element.type.get());
24960b57cec5SDimitry Andric   const uint32_t file_type = root_el_hdr.type;
24970b57cec5SDimitry Andric 
24980b57cec5SDimitry Andric   if (file_type > Element::RS_TYPE_FONT) {
24990b57cec5SDimitry Andric     strm.Printf("Warning: File has unknown allocation type");
25000b57cec5SDimitry Andric     strm.EOL();
25010b57cec5SDimitry Andric   } else if (alloc_type != file_type) {
25020b57cec5SDimitry Andric     // Enum value isn't monotonous, so doesn't always index RsDataTypeToString
25030b57cec5SDimitry Andric     // array
25040b57cec5SDimitry Andric     uint32_t target_type_name_idx = alloc_type;
25050b57cec5SDimitry Andric     uint32_t head_type_name_idx = file_type;
25060b57cec5SDimitry Andric     if (alloc_type >= Element::RS_TYPE_ELEMENT &&
25070b57cec5SDimitry Andric         alloc_type <= Element::RS_TYPE_FONT)
25080b57cec5SDimitry Andric       target_type_name_idx = static_cast<Element::DataType>(
25090b57cec5SDimitry Andric           (alloc_type - Element::RS_TYPE_ELEMENT) +
25100b57cec5SDimitry Andric           Element::RS_TYPE_MATRIX_2X2 + 1);
25110b57cec5SDimitry Andric 
25120b57cec5SDimitry Andric     if (file_type >= Element::RS_TYPE_ELEMENT &&
25130b57cec5SDimitry Andric         file_type <= Element::RS_TYPE_FONT)
25140b57cec5SDimitry Andric       head_type_name_idx = static_cast<Element::DataType>(
25150b57cec5SDimitry Andric           (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 +
25160b57cec5SDimitry Andric           1);
25170b57cec5SDimitry Andric 
25180b57cec5SDimitry Andric     const char *head_type_name =
25190b57cec5SDimitry Andric         AllocationDetails::RsDataTypeToString[head_type_name_idx][0];
25200b57cec5SDimitry Andric     const char *target_type_name =
25210b57cec5SDimitry Andric         AllocationDetails::RsDataTypeToString[target_type_name_idx][0];
25220b57cec5SDimitry Andric 
25230b57cec5SDimitry Andric     strm.Printf(
25240b57cec5SDimitry Andric         "Warning: Mismatched Types - file '%s' type, allocation '%s' type",
25250b57cec5SDimitry Andric         head_type_name, target_type_name);
25260b57cec5SDimitry Andric     strm.EOL();
25270b57cec5SDimitry Andric   }
25280b57cec5SDimitry Andric 
25290b57cec5SDimitry Andric   // Advance buffer past header
25300b57cec5SDimitry Andric   file_buf = static_cast<uint8_t *>(file_buf) + file_header->hdr_size;
25310b57cec5SDimitry Andric 
25320b57cec5SDimitry Andric   // Calculate size of allocation data in file
25330b57cec5SDimitry Andric   size_t size = data_sp->GetByteSize() - file_header->hdr_size;
25340b57cec5SDimitry Andric 
25350b57cec5SDimitry Andric   // Check if the target allocation and file both have the same total data
25360b57cec5SDimitry Andric   // size.
25370b57cec5SDimitry Andric   const uint32_t alloc_size = *alloc->size.get();
25380b57cec5SDimitry Andric   if (alloc_size != size) {
25390b57cec5SDimitry Andric     strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64
25400b57cec5SDimitry Andric                 " bytes, allocation 0x%" PRIx32 " bytes",
25410b57cec5SDimitry Andric                 (uint64_t)size, alloc_size);
25420b57cec5SDimitry Andric     strm.EOL();
25430b57cec5SDimitry Andric     // Set length to copy to minimum
25440b57cec5SDimitry Andric     size = alloc_size < size ? alloc_size : size;
25450b57cec5SDimitry Andric   }
25460b57cec5SDimitry Andric 
25470b57cec5SDimitry Andric   // Copy file data from our buffer into the target allocation.
25480b57cec5SDimitry Andric   lldb::addr_t alloc_data = *alloc->data_ptr.get();
25490b57cec5SDimitry Andric   Status err;
25500b57cec5SDimitry Andric   size_t written = GetProcess()->WriteMemory(alloc_data, file_buf, size, err);
25510b57cec5SDimitry Andric   if (!err.Success() || written != size) {
25520b57cec5SDimitry Andric     strm.Printf("Error: Couldn't write data to allocation %s", err.AsCString());
25530b57cec5SDimitry Andric     strm.EOL();
25540b57cec5SDimitry Andric     return false;
25550b57cec5SDimitry Andric   }
25560b57cec5SDimitry Andric 
25570b57cec5SDimitry Andric   strm.Printf("Contents of file '%s' read into allocation %" PRIu32, path,
25580b57cec5SDimitry Andric               alloc->id);
25590b57cec5SDimitry Andric   strm.EOL();
25600b57cec5SDimitry Andric 
25610b57cec5SDimitry Andric   return true;
25620b57cec5SDimitry Andric }
25630b57cec5SDimitry Andric 
25640b57cec5SDimitry Andric // Function takes as parameters a byte buffer, which will eventually be written
25650b57cec5SDimitry Andric // to file as the element header, an offset into that buffer, and an Element
25660b57cec5SDimitry Andric // that will be saved into the buffer at the parametrised offset. Return value
25670b57cec5SDimitry Andric // is the new offset after writing the element into the buffer. Elements are
25680b57cec5SDimitry Andric // saved to the file as the ElementHeader struct followed by offsets to the
25690b57cec5SDimitry Andric // structs of all the element's children.
PopulateElementHeaders(const std::shared_ptr<uint8_t> header_buffer,size_t offset,const Element & elem)25700b57cec5SDimitry Andric size_t RenderScriptRuntime::PopulateElementHeaders(
25710b57cec5SDimitry Andric     const std::shared_ptr<uint8_t> header_buffer, size_t offset,
25720b57cec5SDimitry Andric     const Element &elem) {
25730b57cec5SDimitry Andric   // File struct for an element header with all the relevant details copied
25740b57cec5SDimitry Andric   // from elem. We assume members are valid already.
25750b57cec5SDimitry Andric   AllocationDetails::ElementHeader elem_header;
25760b57cec5SDimitry Andric   elem_header.type = *elem.type.get();
25770b57cec5SDimitry Andric   elem_header.kind = *elem.type_kind.get();
25780b57cec5SDimitry Andric   elem_header.element_size = *elem.datum_size.get();
25790b57cec5SDimitry Andric   elem_header.vector_size = *elem.type_vec_size.get();
25800b57cec5SDimitry Andric   elem_header.array_size =
25810b57cec5SDimitry Andric       elem.array_size.isValid() ? *elem.array_size.get() : 0;
25820b57cec5SDimitry Andric   const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader);
25830b57cec5SDimitry Andric 
25840b57cec5SDimitry Andric   // Copy struct into buffer and advance offset We assume that header_buffer
25850b57cec5SDimitry Andric   // has been checked for nullptr before this method is called
25860b57cec5SDimitry Andric   memcpy(header_buffer.get() + offset, &elem_header, elem_header_size);
25870b57cec5SDimitry Andric   offset += elem_header_size;
25880b57cec5SDimitry Andric 
25890b57cec5SDimitry Andric   // Starting offset of child ElementHeader struct
25900b57cec5SDimitry Andric   size_t child_offset =
25910b57cec5SDimitry Andric       offset + ((elem.children.size() + 1) * sizeof(uint32_t));
25920b57cec5SDimitry Andric   for (const RenderScriptRuntime::Element &child : elem.children) {
25930b57cec5SDimitry Andric     // Recursively populate the buffer with the element header structs of
25940b57cec5SDimitry Andric     // children. Then save the offsets where they were set after the parent
25950b57cec5SDimitry Andric     // element header.
25960b57cec5SDimitry Andric     memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t));
25970b57cec5SDimitry Andric     offset += sizeof(uint32_t);
25980b57cec5SDimitry Andric 
25990b57cec5SDimitry Andric     child_offset = PopulateElementHeaders(header_buffer, child_offset, child);
26000b57cec5SDimitry Andric   }
26010b57cec5SDimitry Andric 
26020b57cec5SDimitry Andric   // Zero indicates no more children
26030b57cec5SDimitry Andric   memset(header_buffer.get() + offset, 0, sizeof(uint32_t));
26040b57cec5SDimitry Andric 
26050b57cec5SDimitry Andric   return child_offset;
26060b57cec5SDimitry Andric }
26070b57cec5SDimitry Andric 
26080b57cec5SDimitry Andric // Given an Element object this function returns the total size needed in the
26090b57cec5SDimitry Andric // file header to store the element's details. Taking into account the size of
26100b57cec5SDimitry Andric // the element header struct, plus the offsets to all the element's children.
26110b57cec5SDimitry Andric // Function is recursive so that the size of all ancestors is taken into
26120b57cec5SDimitry Andric // account.
CalculateElementHeaderSize(const Element & elem)26130b57cec5SDimitry Andric size_t RenderScriptRuntime::CalculateElementHeaderSize(const Element &elem) {
26140b57cec5SDimitry Andric   // Offsets to children plus zero terminator
26150b57cec5SDimitry Andric   size_t size = (elem.children.size() + 1) * sizeof(uint32_t);
26160b57cec5SDimitry Andric   // Size of header struct with type details
26170b57cec5SDimitry Andric   size += sizeof(AllocationDetails::ElementHeader);
26180b57cec5SDimitry Andric 
26190b57cec5SDimitry Andric   // Calculate recursively for all descendants
26200b57cec5SDimitry Andric   for (const Element &child : elem.children)
26210b57cec5SDimitry Andric     size += CalculateElementHeaderSize(child);
26220b57cec5SDimitry Andric 
26230b57cec5SDimitry Andric   return size;
26240b57cec5SDimitry Andric }
26250b57cec5SDimitry Andric 
26260b57cec5SDimitry Andric // Function copies allocation contents into a binary file. This file can then
26270b57cec5SDimitry Andric // be loaded later into a different allocation. There is a header, FileHeader,
26280b57cec5SDimitry Andric // before the allocation data containing meta-data.
SaveAllocation(Stream & strm,const uint32_t alloc_id,const char * path,StackFrame * frame_ptr)26290b57cec5SDimitry Andric bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id,
26300b57cec5SDimitry Andric                                          const char *path,
26310b57cec5SDimitry Andric                                          StackFrame *frame_ptr) {
26320b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
26330b57cec5SDimitry Andric 
26340b57cec5SDimitry Andric   // Find allocation with the given id
26350b57cec5SDimitry Andric   AllocationDetails *alloc = FindAllocByID(strm, alloc_id);
26360b57cec5SDimitry Andric   if (!alloc)
26370b57cec5SDimitry Andric     return false;
26380b57cec5SDimitry Andric 
26399dba64beSDimitry Andric   LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64 ".", __FUNCTION__,
26400b57cec5SDimitry Andric             *alloc->address.get());
26410b57cec5SDimitry Andric 
26420b57cec5SDimitry Andric   // JIT all the allocation details
26430b57cec5SDimitry Andric   if (alloc->ShouldRefresh()) {
26449dba64beSDimitry Andric     LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.",
26450b57cec5SDimitry Andric               __FUNCTION__);
26460b57cec5SDimitry Andric 
26470b57cec5SDimitry Andric     if (!RefreshAllocation(alloc, frame_ptr)) {
26489dba64beSDimitry Andric       LLDB_LOGF(log, "%s - couldn't JIT allocation details.", __FUNCTION__);
26490b57cec5SDimitry Andric       return false;
26500b57cec5SDimitry Andric     }
26510b57cec5SDimitry Andric   }
26520b57cec5SDimitry Andric 
26530b57cec5SDimitry Andric   assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
26540b57cec5SDimitry Andric          alloc->element.type_vec_size.isValid() &&
26550b57cec5SDimitry Andric          alloc->element.datum_size.get() &&
26560b57cec5SDimitry Andric          alloc->element.type_kind.isValid() && alloc->dimension.isValid() &&
26570b57cec5SDimitry Andric          "Allocation information not available");
26580b57cec5SDimitry Andric 
26590b57cec5SDimitry Andric   // Check we can create writable file
26600b57cec5SDimitry Andric   FileSpec file_spec(path);
26610b57cec5SDimitry Andric   FileSystem::Instance().Resolve(file_spec);
26629dba64beSDimitry Andric   auto file = FileSystem::Instance().Open(
26639dba64beSDimitry Andric       file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate |
26640b57cec5SDimitry Andric                      File::eOpenOptionTruncate);
26650b57cec5SDimitry Andric 
26660b57cec5SDimitry Andric   if (!file) {
26679dba64beSDimitry Andric     std::string error = llvm::toString(file.takeError());
26689dba64beSDimitry Andric     strm.Printf("Error: Failed to open '%s' for writing: %s", path,
26699dba64beSDimitry Andric                 error.c_str());
26700b57cec5SDimitry Andric     strm.EOL();
26710b57cec5SDimitry Andric     return false;
26720b57cec5SDimitry Andric   }
26730b57cec5SDimitry Andric 
26740b57cec5SDimitry Andric   // Read allocation into buffer of heap memory
26750b57cec5SDimitry Andric   const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
26760b57cec5SDimitry Andric   if (!buffer) {
26770b57cec5SDimitry Andric     strm.Printf("Error: Couldn't read allocation data into buffer");
26780b57cec5SDimitry Andric     strm.EOL();
26790b57cec5SDimitry Andric     return false;
26800b57cec5SDimitry Andric   }
26810b57cec5SDimitry Andric 
26820b57cec5SDimitry Andric   // Create the file header
26830b57cec5SDimitry Andric   AllocationDetails::FileHeader head;
26840b57cec5SDimitry Andric   memcpy(head.ident, "RSAD", 4);
26850b57cec5SDimitry Andric   head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1);
26860b57cec5SDimitry Andric   head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2);
26870b57cec5SDimitry Andric   head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3);
26880b57cec5SDimitry Andric 
26890b57cec5SDimitry Andric   const size_t element_header_size = CalculateElementHeaderSize(alloc->element);
26900b57cec5SDimitry Andric   assert((sizeof(AllocationDetails::FileHeader) + element_header_size) <
26910b57cec5SDimitry Andric              UINT16_MAX &&
26920b57cec5SDimitry Andric          "Element header too large");
26930b57cec5SDimitry Andric   head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) +
26940b57cec5SDimitry Andric                                         element_header_size);
26950b57cec5SDimitry Andric 
26960b57cec5SDimitry Andric   // Write the file header
26970b57cec5SDimitry Andric   size_t num_bytes = sizeof(AllocationDetails::FileHeader);
26989dba64beSDimitry Andric   LLDB_LOGF(log, "%s - writing File Header, 0x%" PRIx64 " bytes", __FUNCTION__,
26990b57cec5SDimitry Andric             (uint64_t)num_bytes);
27000b57cec5SDimitry Andric 
27019dba64beSDimitry Andric   Status err = file.get()->Write(&head, num_bytes);
27020b57cec5SDimitry Andric   if (!err.Success()) {
27030b57cec5SDimitry Andric     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path);
27040b57cec5SDimitry Andric     strm.EOL();
27050b57cec5SDimitry Andric     return false;
27060b57cec5SDimitry Andric   }
27070b57cec5SDimitry Andric 
27080b57cec5SDimitry Andric   // Create the headers describing the element type of the allocation.
27090b57cec5SDimitry Andric   std::shared_ptr<uint8_t> element_header_buffer(
27100b57cec5SDimitry Andric       new uint8_t[element_header_size]);
27110b57cec5SDimitry Andric   if (element_header_buffer == nullptr) {
27120b57cec5SDimitry Andric     strm.Printf("Internal Error: Couldn't allocate %" PRIu64
27130b57cec5SDimitry Andric                 " bytes on the heap",
27140b57cec5SDimitry Andric                 (uint64_t)element_header_size);
27150b57cec5SDimitry Andric     strm.EOL();
27160b57cec5SDimitry Andric     return false;
27170b57cec5SDimitry Andric   }
27180b57cec5SDimitry Andric 
27190b57cec5SDimitry Andric   PopulateElementHeaders(element_header_buffer, 0, alloc->element);
27200b57cec5SDimitry Andric 
27210b57cec5SDimitry Andric   // Write headers for allocation element type to file
27220b57cec5SDimitry Andric   num_bytes = element_header_size;
27239dba64beSDimitry Andric   LLDB_LOGF(log, "%s - writing element headers, 0x%" PRIx64 " bytes.",
27240b57cec5SDimitry Andric             __FUNCTION__, (uint64_t)num_bytes);
27250b57cec5SDimitry Andric 
27269dba64beSDimitry Andric   err = file.get()->Write(element_header_buffer.get(), num_bytes);
27270b57cec5SDimitry Andric   if (!err.Success()) {
27280b57cec5SDimitry Andric     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path);
27290b57cec5SDimitry Andric     strm.EOL();
27300b57cec5SDimitry Andric     return false;
27310b57cec5SDimitry Andric   }
27320b57cec5SDimitry Andric 
27330b57cec5SDimitry Andric   // Write allocation data to file
27340b57cec5SDimitry Andric   num_bytes = static_cast<size_t>(*alloc->size.get());
27359dba64beSDimitry Andric   LLDB_LOGF(log, "%s - writing 0x%" PRIx64 " bytes", __FUNCTION__,
27360b57cec5SDimitry Andric             (uint64_t)num_bytes);
27370b57cec5SDimitry Andric 
27389dba64beSDimitry Andric   err = file.get()->Write(buffer.get(), num_bytes);
27390b57cec5SDimitry Andric   if (!err.Success()) {
27400b57cec5SDimitry Andric     strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path);
27410b57cec5SDimitry Andric     strm.EOL();
27420b57cec5SDimitry Andric     return false;
27430b57cec5SDimitry Andric   }
27440b57cec5SDimitry Andric 
27450b57cec5SDimitry Andric   strm.Printf("Allocation written to file '%s'", path);
27460b57cec5SDimitry Andric   strm.EOL();
27470b57cec5SDimitry Andric   return true;
27480b57cec5SDimitry Andric }
27490b57cec5SDimitry Andric 
LoadModule(const lldb::ModuleSP & module_sp)27500b57cec5SDimitry Andric bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) {
27510b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
27520b57cec5SDimitry Andric 
27530b57cec5SDimitry Andric   if (module_sp) {
27540b57cec5SDimitry Andric     for (const auto &rs_module : m_rsmodules) {
27550b57cec5SDimitry Andric       if (rs_module->m_module == module_sp) {
27560b57cec5SDimitry Andric         // Check if the user has enabled automatically breaking on all RS
27570b57cec5SDimitry Andric         // kernels.
27580b57cec5SDimitry Andric         if (m_breakAllKernels)
27590b57cec5SDimitry Andric           BreakOnModuleKernels(rs_module);
27600b57cec5SDimitry Andric 
27610b57cec5SDimitry Andric         return false;
27620b57cec5SDimitry Andric       }
27630b57cec5SDimitry Andric     }
27640b57cec5SDimitry Andric     bool module_loaded = false;
27650b57cec5SDimitry Andric     switch (GetModuleKind(module_sp)) {
27660b57cec5SDimitry Andric     case eModuleKindKernelObj: {
27670b57cec5SDimitry Andric       RSModuleDescriptorSP module_desc;
27680b57cec5SDimitry Andric       module_desc = std::make_shared<RSModuleDescriptor>(module_sp);
27690b57cec5SDimitry Andric       if (module_desc->ParseRSInfo()) {
27700b57cec5SDimitry Andric         m_rsmodules.push_back(module_desc);
27710b57cec5SDimitry Andric         module_desc->WarnIfVersionMismatch(GetProcess()
27720b57cec5SDimitry Andric                                                ->GetTarget()
27730b57cec5SDimitry Andric                                                .GetDebugger()
27740b57cec5SDimitry Andric                                                .GetAsyncOutputStream()
27750b57cec5SDimitry Andric                                                .get());
27760b57cec5SDimitry Andric         module_loaded = true;
27770b57cec5SDimitry Andric       }
27780b57cec5SDimitry Andric       if (module_loaded) {
27790b57cec5SDimitry Andric         FixupScriptDetails(module_desc);
27800b57cec5SDimitry Andric       }
27810b57cec5SDimitry Andric       break;
27820b57cec5SDimitry Andric     }
27830b57cec5SDimitry Andric     case eModuleKindDriver: {
27840b57cec5SDimitry Andric       if (!m_libRSDriver) {
27850b57cec5SDimitry Andric         m_libRSDriver = module_sp;
27860b57cec5SDimitry Andric         LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver);
27870b57cec5SDimitry Andric       }
27880b57cec5SDimitry Andric       break;
27890b57cec5SDimitry Andric     }
27900b57cec5SDimitry Andric     case eModuleKindImpl: {
27910b57cec5SDimitry Andric       if (!m_libRSCpuRef) {
27920b57cec5SDimitry Andric         m_libRSCpuRef = module_sp;
27930b57cec5SDimitry Andric         LoadRuntimeHooks(m_libRSCpuRef, RenderScriptRuntime::eModuleKindImpl);
27940b57cec5SDimitry Andric       }
27950b57cec5SDimitry Andric       break;
27960b57cec5SDimitry Andric     }
27970b57cec5SDimitry Andric     case eModuleKindLibRS: {
27980b57cec5SDimitry Andric       if (!m_libRS) {
27990b57cec5SDimitry Andric         m_libRS = module_sp;
28000b57cec5SDimitry Andric         static ConstString gDbgPresentStr("gDebuggerPresent");
28010b57cec5SDimitry Andric         const Symbol *debug_present = m_libRS->FindFirstSymbolWithNameAndType(
28020b57cec5SDimitry Andric             gDbgPresentStr, eSymbolTypeData);
28030b57cec5SDimitry Andric         if (debug_present) {
28040b57cec5SDimitry Andric           Status err;
28050b57cec5SDimitry Andric           uint32_t flag = 0x00000001U;
28060b57cec5SDimitry Andric           Target &target = GetProcess()->GetTarget();
28070b57cec5SDimitry Andric           addr_t addr = debug_present->GetLoadAddress(&target);
28080b57cec5SDimitry Andric           GetProcess()->WriteMemory(addr, &flag, sizeof(flag), err);
28090b57cec5SDimitry Andric           if (err.Success()) {
28109dba64beSDimitry Andric             LLDB_LOGF(log, "%s - debugger present flag set on debugee.",
28110b57cec5SDimitry Andric                       __FUNCTION__);
28120b57cec5SDimitry Andric 
28130b57cec5SDimitry Andric             m_debuggerPresentFlagged = true;
28140b57cec5SDimitry Andric           } else if (log) {
28159dba64beSDimitry Andric             LLDB_LOGF(log, "%s - error writing debugger present flags '%s' ",
28160b57cec5SDimitry Andric                       __FUNCTION__, err.AsCString());
28170b57cec5SDimitry Andric           }
28180b57cec5SDimitry Andric         } else if (log) {
28199dba64beSDimitry Andric           LLDB_LOGF(
28209dba64beSDimitry Andric               log,
28210b57cec5SDimitry Andric               "%s - error writing debugger present flags - symbol not found",
28220b57cec5SDimitry Andric               __FUNCTION__);
28230b57cec5SDimitry Andric         }
28240b57cec5SDimitry Andric       }
28250b57cec5SDimitry Andric       break;
28260b57cec5SDimitry Andric     }
28270b57cec5SDimitry Andric     default:
28280b57cec5SDimitry Andric       break;
28290b57cec5SDimitry Andric     }
28300b57cec5SDimitry Andric     if (module_loaded)
28310b57cec5SDimitry Andric       Update();
28320b57cec5SDimitry Andric     return module_loaded;
28330b57cec5SDimitry Andric   }
28340b57cec5SDimitry Andric   return false;
28350b57cec5SDimitry Andric }
28360b57cec5SDimitry Andric 
Update()28370b57cec5SDimitry Andric void RenderScriptRuntime::Update() {
28380b57cec5SDimitry Andric   if (m_rsmodules.size() > 0) {
28390b57cec5SDimitry Andric     if (!m_initiated) {
28400b57cec5SDimitry Andric       Initiate();
28410b57cec5SDimitry Andric     }
28420b57cec5SDimitry Andric   }
28430b57cec5SDimitry Andric }
28440b57cec5SDimitry Andric 
WarnIfVersionMismatch(lldb_private::Stream * s) const28450b57cec5SDimitry Andric void RSModuleDescriptor::WarnIfVersionMismatch(lldb_private::Stream *s) const {
28460b57cec5SDimitry Andric   if (!s)
28470b57cec5SDimitry Andric     return;
28480b57cec5SDimitry Andric 
28490b57cec5SDimitry Andric   if (m_slang_version.empty() || m_bcc_version.empty()) {
28500b57cec5SDimitry Andric     s->PutCString("WARNING: Unknown bcc or slang (llvm-rs-cc) version; debug "
28510b57cec5SDimitry Andric                   "experience may be unreliable");
28520b57cec5SDimitry Andric     s->EOL();
28530b57cec5SDimitry Andric   } else if (m_slang_version != m_bcc_version) {
28540b57cec5SDimitry Andric     s->Printf("WARNING: The debug info emitted by the slang frontend "
28550b57cec5SDimitry Andric               "(llvm-rs-cc) used to build this module (%s) does not match the "
28560b57cec5SDimitry Andric               "version of bcc used to generate the debug information (%s). "
28570b57cec5SDimitry Andric               "This is an unsupported configuration and may result in a poor "
28580b57cec5SDimitry Andric               "debugging experience; proceed with caution",
28590b57cec5SDimitry Andric               m_slang_version.c_str(), m_bcc_version.c_str());
28600b57cec5SDimitry Andric     s->EOL();
28610b57cec5SDimitry Andric   }
28620b57cec5SDimitry Andric }
28630b57cec5SDimitry Andric 
ParsePragmaCount(llvm::StringRef * lines,size_t n_lines)28640b57cec5SDimitry Andric bool RSModuleDescriptor::ParsePragmaCount(llvm::StringRef *lines,
28650b57cec5SDimitry Andric                                           size_t n_lines) {
28660b57cec5SDimitry Andric   // Skip the pragma prototype line
28670b57cec5SDimitry Andric   ++lines;
28680b57cec5SDimitry Andric   for (; n_lines--; ++lines) {
28690b57cec5SDimitry Andric     const auto kv_pair = lines->split(" - ");
28700b57cec5SDimitry Andric     m_pragmas[kv_pair.first.trim().str()] = kv_pair.second.trim().str();
28710b57cec5SDimitry Andric   }
28720b57cec5SDimitry Andric   return true;
28730b57cec5SDimitry Andric }
28740b57cec5SDimitry Andric 
ParseExportReduceCount(llvm::StringRef * lines,size_t n_lines)28750b57cec5SDimitry Andric bool RSModuleDescriptor::ParseExportReduceCount(llvm::StringRef *lines,
28760b57cec5SDimitry Andric                                                 size_t n_lines) {
28770b57cec5SDimitry Andric   // The list of reduction kernels in the `.rs.info` symbol is of the form
28780b57cec5SDimitry Andric   // "signature - accumulatordatasize - reduction_name - initializer_name -
28790b57cec5SDimitry Andric   // accumulator_name - combiner_name - outconverter_name - halter_name" Where
28800b57cec5SDimitry Andric   // a function is not explicitly named by the user, or is not generated by the
28810b57cec5SDimitry Andric   // compiler, it is named "." so the dash separated list should always be 8
28820b57cec5SDimitry Andric   // items long
28830b57cec5SDimitry Andric   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
28840b57cec5SDimitry Andric   // Skip the exportReduceCount line
28850b57cec5SDimitry Andric   ++lines;
28860b57cec5SDimitry Andric   for (; n_lines--; ++lines) {
28870b57cec5SDimitry Andric     llvm::SmallVector<llvm::StringRef, 8> spec;
28880b57cec5SDimitry Andric     lines->split(spec, " - ");
28890b57cec5SDimitry Andric     if (spec.size() != 8) {
28900b57cec5SDimitry Andric       if (spec.size() < 8) {
28910b57cec5SDimitry Andric         if (log)
28920b57cec5SDimitry Andric           log->Error("Error parsing RenderScript reduction spec. wrong number "
28930b57cec5SDimitry Andric                      "of fields");
28940b57cec5SDimitry Andric         return false;
28950b57cec5SDimitry Andric       } else if (log)
28960b57cec5SDimitry Andric         log->Warning("Extraneous members in reduction spec: '%s'",
28970b57cec5SDimitry Andric                      lines->str().c_str());
28980b57cec5SDimitry Andric     }
28990b57cec5SDimitry Andric 
29000b57cec5SDimitry Andric     const auto sig_s = spec[0];
29010b57cec5SDimitry Andric     uint32_t sig;
29020b57cec5SDimitry Andric     if (sig_s.getAsInteger(10, sig)) {
29030b57cec5SDimitry Andric       if (log)
29040b57cec5SDimitry Andric         log->Error("Error parsing Renderscript reduction spec: invalid kernel "
29050b57cec5SDimitry Andric                    "signature: '%s'",
29060b57cec5SDimitry Andric                    sig_s.str().c_str());
29070b57cec5SDimitry Andric       return false;
29080b57cec5SDimitry Andric     }
29090b57cec5SDimitry Andric 
29100b57cec5SDimitry Andric     const auto accum_data_size_s = spec[1];
29110b57cec5SDimitry Andric     uint32_t accum_data_size;
29120b57cec5SDimitry Andric     if (accum_data_size_s.getAsInteger(10, accum_data_size)) {
29130b57cec5SDimitry Andric       if (log)
29140b57cec5SDimitry Andric         log->Error("Error parsing Renderscript reduction spec: invalid "
29150b57cec5SDimitry Andric                    "accumulator data size %s",
29160b57cec5SDimitry Andric                    accum_data_size_s.str().c_str());
29170b57cec5SDimitry Andric       return false;
29180b57cec5SDimitry Andric     }
29190b57cec5SDimitry Andric 
29209dba64beSDimitry Andric     LLDB_LOGF(log, "Found RenderScript reduction '%s'", spec[2].str().c_str());
29210b57cec5SDimitry Andric 
29220b57cec5SDimitry Andric     m_reductions.push_back(RSReductionDescriptor(this, sig, accum_data_size,
29230b57cec5SDimitry Andric                                                  spec[2], spec[3], spec[4],
29240b57cec5SDimitry Andric                                                  spec[5], spec[6], spec[7]));
29250b57cec5SDimitry Andric   }
29260b57cec5SDimitry Andric   return true;
29270b57cec5SDimitry Andric }
29280b57cec5SDimitry Andric 
ParseVersionInfo(llvm::StringRef * lines,size_t n_lines)29290b57cec5SDimitry Andric bool RSModuleDescriptor::ParseVersionInfo(llvm::StringRef *lines,
29300b57cec5SDimitry Andric                                           size_t n_lines) {
29310b57cec5SDimitry Andric   // Skip the versionInfo line
29320b57cec5SDimitry Andric   ++lines;
29330b57cec5SDimitry Andric   for (; n_lines--; ++lines) {
29340b57cec5SDimitry Andric     // We're only interested in bcc and slang versions, and ignore all other
29350b57cec5SDimitry Andric     // versionInfo lines
29360b57cec5SDimitry Andric     const auto kv_pair = lines->split(" - ");
29370b57cec5SDimitry Andric     if (kv_pair.first == "slang")
29380b57cec5SDimitry Andric       m_slang_version = kv_pair.second.str();
29390b57cec5SDimitry Andric     else if (kv_pair.first == "bcc")
29400b57cec5SDimitry Andric       m_bcc_version = kv_pair.second.str();
29410b57cec5SDimitry Andric   }
29420b57cec5SDimitry Andric   return true;
29430b57cec5SDimitry Andric }
29440b57cec5SDimitry Andric 
ParseExportForeachCount(llvm::StringRef * lines,size_t n_lines)29450b57cec5SDimitry Andric bool RSModuleDescriptor::ParseExportForeachCount(llvm::StringRef *lines,
29460b57cec5SDimitry Andric                                                  size_t n_lines) {
29470b57cec5SDimitry Andric   // Skip the exportForeachCount line
29480b57cec5SDimitry Andric   ++lines;
29490b57cec5SDimitry Andric   for (; n_lines--; ++lines) {
29500b57cec5SDimitry Andric     uint32_t slot;
29510b57cec5SDimitry Andric     // `forEach` kernels are listed in the `.rs.info` packet as a "slot - name"
29520b57cec5SDimitry Andric     // pair per line
29530b57cec5SDimitry Andric     const auto kv_pair = lines->split(" - ");
29540b57cec5SDimitry Andric     if (kv_pair.first.getAsInteger(10, slot))
29550b57cec5SDimitry Andric       return false;
29560b57cec5SDimitry Andric     m_kernels.push_back(RSKernelDescriptor(this, kv_pair.second, slot));
29570b57cec5SDimitry Andric   }
29580b57cec5SDimitry Andric   return true;
29590b57cec5SDimitry Andric }
29600b57cec5SDimitry Andric 
ParseExportVarCount(llvm::StringRef * lines,size_t n_lines)29610b57cec5SDimitry Andric bool RSModuleDescriptor::ParseExportVarCount(llvm::StringRef *lines,
29620b57cec5SDimitry Andric                                              size_t n_lines) {
29630b57cec5SDimitry Andric   // Skip the ExportVarCount line
29640b57cec5SDimitry Andric   ++lines;
29650b57cec5SDimitry Andric   for (; n_lines--; ++lines)
29660b57cec5SDimitry Andric     m_globals.push_back(RSGlobalDescriptor(this, *lines));
29670b57cec5SDimitry Andric   return true;
29680b57cec5SDimitry Andric }
29690b57cec5SDimitry Andric 
29700b57cec5SDimitry Andric // The .rs.info symbol in renderscript modules contains a string which needs to
29710b57cec5SDimitry Andric // be parsed. The string is basic and is parsed on a line by line basis.
ParseRSInfo()29720b57cec5SDimitry Andric bool RSModuleDescriptor::ParseRSInfo() {
29730b57cec5SDimitry Andric   assert(m_module);
29740b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
29750b57cec5SDimitry Andric   const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType(
29760b57cec5SDimitry Andric       ConstString(".rs.info"), eSymbolTypeData);
29770b57cec5SDimitry Andric   if (!info_sym)
29780b57cec5SDimitry Andric     return false;
29790b57cec5SDimitry Andric 
29800b57cec5SDimitry Andric   const addr_t addr = info_sym->GetAddressRef().GetFileAddress();
29810b57cec5SDimitry Andric   if (addr == LLDB_INVALID_ADDRESS)
29820b57cec5SDimitry Andric     return false;
29830b57cec5SDimitry Andric 
29840b57cec5SDimitry Andric   const addr_t size = info_sym->GetByteSize();
29850b57cec5SDimitry Andric   const FileSpec fs = m_module->GetFileSpec();
29860b57cec5SDimitry Andric 
29870b57cec5SDimitry Andric   auto buffer =
29880b57cec5SDimitry Andric       FileSystem::Instance().CreateDataBuffer(fs.GetPath(), size, addr);
29890b57cec5SDimitry Andric   if (!buffer)
29900b57cec5SDimitry Andric     return false;
29910b57cec5SDimitry Andric 
29920b57cec5SDimitry Andric   // split rs.info. contents into lines
29930b57cec5SDimitry Andric   llvm::SmallVector<llvm::StringRef, 128> info_lines;
29940b57cec5SDimitry Andric   {
29950b57cec5SDimitry Andric     const llvm::StringRef raw_rs_info((const char *)buffer->GetBytes());
29960b57cec5SDimitry Andric     raw_rs_info.split(info_lines, '\n');
29979dba64beSDimitry Andric     LLDB_LOGF(log, "'.rs.info symbol for '%s':\n%s",
29989dba64beSDimitry Andric               m_module->GetFileSpec().GetCString(), raw_rs_info.str().c_str());
29990b57cec5SDimitry Andric   }
30000b57cec5SDimitry Andric 
30010b57cec5SDimitry Andric   enum {
30020b57cec5SDimitry Andric     eExportVar,
30030b57cec5SDimitry Andric     eExportForEach,
30040b57cec5SDimitry Andric     eExportReduce,
30050b57cec5SDimitry Andric     ePragma,
30060b57cec5SDimitry Andric     eBuildChecksum,
30070b57cec5SDimitry Andric     eObjectSlot,
30080b57cec5SDimitry Andric     eVersionInfo,
30090b57cec5SDimitry Andric   };
30100b57cec5SDimitry Andric 
30110b57cec5SDimitry Andric   const auto rs_info_handler = [](llvm::StringRef name) -> int {
30120b57cec5SDimitry Andric     return llvm::StringSwitch<int>(name)
30130b57cec5SDimitry Andric         // The number of visible global variables in the script
30140b57cec5SDimitry Andric         .Case("exportVarCount", eExportVar)
30150b57cec5SDimitry Andric         // The number of RenderScrip `forEach` kernels __attribute__((kernel))
30160b57cec5SDimitry Andric         .Case("exportForEachCount", eExportForEach)
30170b57cec5SDimitry Andric         // The number of generalreductions: This marked in the script by
30180b57cec5SDimitry Andric         // `#pragma reduce()`
30190b57cec5SDimitry Andric         .Case("exportReduceCount", eExportReduce)
30200b57cec5SDimitry Andric         // Total count of all RenderScript specific `#pragmas` used in the
30210b57cec5SDimitry Andric         // script
30220b57cec5SDimitry Andric         .Case("pragmaCount", ePragma)
30230b57cec5SDimitry Andric         .Case("objectSlotCount", eObjectSlot)
30240b57cec5SDimitry Andric         .Case("versionInfo", eVersionInfo)
30250b57cec5SDimitry Andric         .Default(-1);
30260b57cec5SDimitry Andric   };
30270b57cec5SDimitry Andric 
30280b57cec5SDimitry Andric   // parse all text lines of .rs.info
30290b57cec5SDimitry Andric   for (auto line = info_lines.begin(); line != info_lines.end(); ++line) {
30300b57cec5SDimitry Andric     const auto kv_pair = line->split(": ");
30310b57cec5SDimitry Andric     const auto key = kv_pair.first;
30320b57cec5SDimitry Andric     const auto val = kv_pair.second.trim();
30330b57cec5SDimitry Andric 
30340b57cec5SDimitry Andric     const auto handler = rs_info_handler(key);
30350b57cec5SDimitry Andric     if (handler == -1)
30360b57cec5SDimitry Andric       continue;
30370b57cec5SDimitry Andric     // getAsInteger returns `true` on an error condition - we're only
30380b57cec5SDimitry Andric     // interested in numeric fields at the moment
30390b57cec5SDimitry Andric     uint64_t n_lines;
30400b57cec5SDimitry Andric     if (val.getAsInteger(10, n_lines)) {
30410b57cec5SDimitry Andric       LLDB_LOGV(log, "Failed to parse non-numeric '.rs.info' section {0}",
30420b57cec5SDimitry Andric                 line->str());
30430b57cec5SDimitry Andric       continue;
30440b57cec5SDimitry Andric     }
30450b57cec5SDimitry Andric     if (info_lines.end() - (line + 1) < (ptrdiff_t)n_lines)
30460b57cec5SDimitry Andric       return false;
30470b57cec5SDimitry Andric 
30480b57cec5SDimitry Andric     bool success = false;
30490b57cec5SDimitry Andric     switch (handler) {
30500b57cec5SDimitry Andric     case eExportVar:
30510b57cec5SDimitry Andric       success = ParseExportVarCount(line, n_lines);
30520b57cec5SDimitry Andric       break;
30530b57cec5SDimitry Andric     case eExportForEach:
30540b57cec5SDimitry Andric       success = ParseExportForeachCount(line, n_lines);
30550b57cec5SDimitry Andric       break;
30560b57cec5SDimitry Andric     case eExportReduce:
30570b57cec5SDimitry Andric       success = ParseExportReduceCount(line, n_lines);
30580b57cec5SDimitry Andric       break;
30590b57cec5SDimitry Andric     case ePragma:
30600b57cec5SDimitry Andric       success = ParsePragmaCount(line, n_lines);
30610b57cec5SDimitry Andric       break;
30620b57cec5SDimitry Andric     case eVersionInfo:
30630b57cec5SDimitry Andric       success = ParseVersionInfo(line, n_lines);
30640b57cec5SDimitry Andric       break;
30650b57cec5SDimitry Andric     default: {
30669dba64beSDimitry Andric       LLDB_LOGF(log, "%s - skipping .rs.info field '%s'", __FUNCTION__,
30670b57cec5SDimitry Andric                 line->str().c_str());
30680b57cec5SDimitry Andric       continue;
30690b57cec5SDimitry Andric     }
30700b57cec5SDimitry Andric     }
30710b57cec5SDimitry Andric     if (!success)
30720b57cec5SDimitry Andric       return false;
30730b57cec5SDimitry Andric     line += n_lines;
30740b57cec5SDimitry Andric   }
30750b57cec5SDimitry Andric   return info_lines.size() > 0;
30760b57cec5SDimitry Andric }
30770b57cec5SDimitry Andric 
DumpStatus(Stream & strm) const30780b57cec5SDimitry Andric void RenderScriptRuntime::DumpStatus(Stream &strm) const {
30790b57cec5SDimitry Andric   if (m_libRS) {
30800b57cec5SDimitry Andric     strm.Printf("Runtime Library discovered.");
30810b57cec5SDimitry Andric     strm.EOL();
30820b57cec5SDimitry Andric   }
30830b57cec5SDimitry Andric   if (m_libRSDriver) {
30840b57cec5SDimitry Andric     strm.Printf("Runtime Driver discovered.");
30850b57cec5SDimitry Andric     strm.EOL();
30860b57cec5SDimitry Andric   }
30870b57cec5SDimitry Andric   if (m_libRSCpuRef) {
30880b57cec5SDimitry Andric     strm.Printf("CPU Reference Implementation discovered.");
30890b57cec5SDimitry Andric     strm.EOL();
30900b57cec5SDimitry Andric   }
30910b57cec5SDimitry Andric 
30920b57cec5SDimitry Andric   if (m_runtimeHooks.size()) {
30930b57cec5SDimitry Andric     strm.Printf("Runtime functions hooked:");
30940b57cec5SDimitry Andric     strm.EOL();
30950b57cec5SDimitry Andric     for (auto b : m_runtimeHooks) {
30960b57cec5SDimitry Andric       strm.Indent(b.second->defn->name);
30970b57cec5SDimitry Andric       strm.EOL();
30980b57cec5SDimitry Andric     }
30990b57cec5SDimitry Andric   } else {
31000b57cec5SDimitry Andric     strm.Printf("Runtime is not hooked.");
31010b57cec5SDimitry Andric     strm.EOL();
31020b57cec5SDimitry Andric   }
31030b57cec5SDimitry Andric }
31040b57cec5SDimitry Andric 
DumpContexts(Stream & strm) const31050b57cec5SDimitry Andric void RenderScriptRuntime::DumpContexts(Stream &strm) const {
31060b57cec5SDimitry Andric   strm.Printf("Inferred RenderScript Contexts:");
31070b57cec5SDimitry Andric   strm.EOL();
31080b57cec5SDimitry Andric   strm.IndentMore();
31090b57cec5SDimitry Andric 
31100b57cec5SDimitry Andric   std::map<addr_t, uint64_t> contextReferences;
31110b57cec5SDimitry Andric 
31120b57cec5SDimitry Andric   // Iterate over all of the currently discovered scripts. Note: We cant push
31130b57cec5SDimitry Andric   // or pop from m_scripts inside this loop or it may invalidate script.
31140b57cec5SDimitry Andric   for (const auto &script : m_scripts) {
31150b57cec5SDimitry Andric     if (!script->context.isValid())
31160b57cec5SDimitry Andric       continue;
31170b57cec5SDimitry Andric     lldb::addr_t context = *script->context;
31180b57cec5SDimitry Andric 
31190b57cec5SDimitry Andric     if (contextReferences.find(context) != contextReferences.end()) {
31200b57cec5SDimitry Andric       contextReferences[context]++;
31210b57cec5SDimitry Andric     } else {
31220b57cec5SDimitry Andric       contextReferences[context] = 1;
31230b57cec5SDimitry Andric     }
31240b57cec5SDimitry Andric   }
31250b57cec5SDimitry Andric 
31260b57cec5SDimitry Andric   for (const auto &cRef : contextReferences) {
31270b57cec5SDimitry Andric     strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances",
31280b57cec5SDimitry Andric                 cRef.first, cRef.second);
31290b57cec5SDimitry Andric     strm.EOL();
31300b57cec5SDimitry Andric   }
31310b57cec5SDimitry Andric   strm.IndentLess();
31320b57cec5SDimitry Andric }
31330b57cec5SDimitry Andric 
DumpKernels(Stream & strm) const31340b57cec5SDimitry Andric void RenderScriptRuntime::DumpKernels(Stream &strm) const {
31350b57cec5SDimitry Andric   strm.Printf("RenderScript Kernels:");
31360b57cec5SDimitry Andric   strm.EOL();
31370b57cec5SDimitry Andric   strm.IndentMore();
31380b57cec5SDimitry Andric   for (const auto &module : m_rsmodules) {
31390b57cec5SDimitry Andric     strm.Printf("Resource '%s':", module->m_resname.c_str());
31400b57cec5SDimitry Andric     strm.EOL();
31410b57cec5SDimitry Andric     for (const auto &kernel : module->m_kernels) {
31425ffd83dbSDimitry Andric       strm.Indent(kernel.m_name.GetStringRef());
31430b57cec5SDimitry Andric       strm.EOL();
31440b57cec5SDimitry Andric     }
31450b57cec5SDimitry Andric   }
31460b57cec5SDimitry Andric   strm.IndentLess();
31470b57cec5SDimitry Andric }
31480b57cec5SDimitry Andric 
31490b57cec5SDimitry Andric RenderScriptRuntime::AllocationDetails *
FindAllocByID(Stream & strm,const uint32_t alloc_id)31500b57cec5SDimitry Andric RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) {
31510b57cec5SDimitry Andric   AllocationDetails *alloc = nullptr;
31520b57cec5SDimitry Andric 
31530b57cec5SDimitry Andric   // See if we can find allocation using id as an index;
31540b57cec5SDimitry Andric   if (alloc_id <= m_allocations.size() && alloc_id != 0 &&
31550b57cec5SDimitry Andric       m_allocations[alloc_id - 1]->id == alloc_id) {
31560b57cec5SDimitry Andric     alloc = m_allocations[alloc_id - 1].get();
31570b57cec5SDimitry Andric     return alloc;
31580b57cec5SDimitry Andric   }
31590b57cec5SDimitry Andric 
31600b57cec5SDimitry Andric   // Fallback to searching
31610b57cec5SDimitry Andric   for (const auto &a : m_allocations) {
31620b57cec5SDimitry Andric     if (a->id == alloc_id) {
31630b57cec5SDimitry Andric       alloc = a.get();
31640b57cec5SDimitry Andric       break;
31650b57cec5SDimitry Andric     }
31660b57cec5SDimitry Andric   }
31670b57cec5SDimitry Andric 
31680b57cec5SDimitry Andric   if (alloc == nullptr) {
31690b57cec5SDimitry Andric     strm.Printf("Error: Couldn't find allocation with id matching %" PRIu32,
31700b57cec5SDimitry Andric                 alloc_id);
31710b57cec5SDimitry Andric     strm.EOL();
31720b57cec5SDimitry Andric   }
31730b57cec5SDimitry Andric 
31740b57cec5SDimitry Andric   return alloc;
31750b57cec5SDimitry Andric }
31760b57cec5SDimitry Andric 
31770b57cec5SDimitry Andric // Prints the contents of an allocation to the output stream, which may be a
31780b57cec5SDimitry Andric // file
DumpAllocation(Stream & strm,StackFrame * frame_ptr,const uint32_t id)31790b57cec5SDimitry Andric bool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr,
31800b57cec5SDimitry Andric                                          const uint32_t id) {
31810b57cec5SDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
31820b57cec5SDimitry Andric 
31830b57cec5SDimitry Andric   // Check we can find the desired allocation
31840b57cec5SDimitry Andric   AllocationDetails *alloc = FindAllocByID(strm, id);
31850b57cec5SDimitry Andric   if (!alloc)
31860b57cec5SDimitry Andric     return false; // FindAllocByID() will print error message for us here
31870b57cec5SDimitry Andric 
31889dba64beSDimitry Andric   LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64, __FUNCTION__,
31890b57cec5SDimitry Andric             *alloc->address.get());
31900b57cec5SDimitry Andric 
31910b57cec5SDimitry Andric   // Check we have information about the allocation, if not calculate it
31920b57cec5SDimitry Andric   if (alloc->ShouldRefresh()) {
31939dba64beSDimitry Andric     LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.",
31940b57cec5SDimitry Andric               __FUNCTION__);
31950b57cec5SDimitry Andric 
31960b57cec5SDimitry Andric     // JIT all the allocation information
31970b57cec5SDimitry Andric     if (!RefreshAllocation(alloc, frame_ptr)) {
31980b57cec5SDimitry Andric       strm.Printf("Error: Couldn't JIT allocation details");
31990b57cec5SDimitry Andric       strm.EOL();
32000b57cec5SDimitry Andric       return false;
32010b57cec5SDimitry Andric     }
32020b57cec5SDimitry Andric   }
32030b57cec5SDimitry Andric 
32040b57cec5SDimitry Andric   // Establish format and size of each data element
32050b57cec5SDimitry Andric   const uint32_t vec_size = *alloc->element.type_vec_size.get();
32060b57cec5SDimitry Andric   const Element::DataType type = *alloc->element.type.get();
32070b57cec5SDimitry Andric 
32080b57cec5SDimitry Andric   assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT &&
32090b57cec5SDimitry Andric          "Invalid allocation type");
32100b57cec5SDimitry Andric 
32110b57cec5SDimitry Andric   lldb::Format format;
32120b57cec5SDimitry Andric   if (type >= Element::RS_TYPE_ELEMENT)
32130b57cec5SDimitry Andric     format = eFormatHex;
32140b57cec5SDimitry Andric   else
32150b57cec5SDimitry Andric     format = vec_size == 1
32160b57cec5SDimitry Andric                  ? static_cast<lldb::Format>(
32170b57cec5SDimitry Andric                        AllocationDetails::RSTypeToFormat[type][eFormatSingle])
32180b57cec5SDimitry Andric                  : static_cast<lldb::Format>(
32190b57cec5SDimitry Andric                        AllocationDetails::RSTypeToFormat[type][eFormatVector]);
32200b57cec5SDimitry Andric 
32210b57cec5SDimitry Andric   const uint32_t data_size = *alloc->element.datum_size.get();
32220b57cec5SDimitry Andric 
32239dba64beSDimitry Andric   LLDB_LOGF(log, "%s - element size %" PRIu32 " bytes, including padding",
32240b57cec5SDimitry Andric             __FUNCTION__, data_size);
32250b57cec5SDimitry Andric 
32260b57cec5SDimitry Andric   // Allocate a buffer to copy data into
32270b57cec5SDimitry Andric   std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
32280b57cec5SDimitry Andric   if (!buffer) {
32290b57cec5SDimitry Andric     strm.Printf("Error: Couldn't read allocation data");
32300b57cec5SDimitry Andric     strm.EOL();
32310b57cec5SDimitry Andric     return false;
32320b57cec5SDimitry Andric   }
32330b57cec5SDimitry Andric 
32340b57cec5SDimitry Andric   // Calculate stride between rows as there may be padding at end of rows since
32350b57cec5SDimitry Andric   // allocated memory is 16-byte aligned
32360b57cec5SDimitry Andric   if (!alloc->stride.isValid()) {
32370b57cec5SDimitry Andric     if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension
32380b57cec5SDimitry Andric       alloc->stride = 0;
32390b57cec5SDimitry Andric     else if (!JITAllocationStride(alloc, frame_ptr)) {
32400b57cec5SDimitry Andric       strm.Printf("Error: Couldn't calculate allocation row stride");
32410b57cec5SDimitry Andric       strm.EOL();
32420b57cec5SDimitry Andric       return false;
32430b57cec5SDimitry Andric     }
32440b57cec5SDimitry Andric   }
32450b57cec5SDimitry Andric   const uint32_t stride = *alloc->stride.get();
32460b57cec5SDimitry Andric   const uint32_t size = *alloc->size.get(); // Size of whole allocation
32470b57cec5SDimitry Andric   const uint32_t padding =
32480b57cec5SDimitry Andric       alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0;
32499dba64beSDimitry Andric   LLDB_LOGF(log,
32509dba64beSDimitry Andric             "%s - stride %" PRIu32 " bytes, size %" PRIu32
32510b57cec5SDimitry Andric             " bytes, padding %" PRIu32,
32520b57cec5SDimitry Andric             __FUNCTION__, stride, size, padding);
32530b57cec5SDimitry Andric 
32540b57cec5SDimitry Andric   // Find dimensions used to index loops, so need to be non-zero
32550b57cec5SDimitry Andric   uint32_t dim_x = alloc->dimension.get()->dim_1;
32560b57cec5SDimitry Andric   dim_x = dim_x == 0 ? 1 : dim_x;
32570b57cec5SDimitry Andric 
32580b57cec5SDimitry Andric   uint32_t dim_y = alloc->dimension.get()->dim_2;
32590b57cec5SDimitry Andric   dim_y = dim_y == 0 ? 1 : dim_y;
32600b57cec5SDimitry Andric 
32610b57cec5SDimitry Andric   uint32_t dim_z = alloc->dimension.get()->dim_3;
32620b57cec5SDimitry Andric   dim_z = dim_z == 0 ? 1 : dim_z;
32630b57cec5SDimitry Andric 
32640b57cec5SDimitry Andric   // Use data extractor to format output
32650b57cec5SDimitry Andric   const uint32_t target_ptr_size =
32660b57cec5SDimitry Andric       GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
32670b57cec5SDimitry Andric   DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(),
32680b57cec5SDimitry Andric                            target_ptr_size);
32690b57cec5SDimitry Andric 
32700b57cec5SDimitry Andric   uint32_t offset = 0;   // Offset in buffer to next element to be printed
32710b57cec5SDimitry Andric   uint32_t prev_row = 0; // Offset to the start of the previous row
32720b57cec5SDimitry Andric 
32730b57cec5SDimitry Andric   // Iterate over allocation dimensions, printing results to user
32740b57cec5SDimitry Andric   strm.Printf("Data (X, Y, Z):");
32750b57cec5SDimitry Andric   for (uint32_t z = 0; z < dim_z; ++z) {
32760b57cec5SDimitry Andric     for (uint32_t y = 0; y < dim_y; ++y) {
32770b57cec5SDimitry Andric       // Use stride to index start of next row.
32780b57cec5SDimitry Andric       if (!(y == 0 && z == 0))
32790b57cec5SDimitry Andric         offset = prev_row + stride;
32800b57cec5SDimitry Andric       prev_row = offset;
32810b57cec5SDimitry Andric 
32820b57cec5SDimitry Andric       // Print each element in the row individually
32830b57cec5SDimitry Andric       for (uint32_t x = 0; x < dim_x; ++x) {
32840b57cec5SDimitry Andric         strm.Printf("\n(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") = ", x, y, z);
32850b57cec5SDimitry Andric         if ((type == Element::RS_TYPE_NONE) &&
32860b57cec5SDimitry Andric             (alloc->element.children.size() > 0) &&
32870b57cec5SDimitry Andric             (alloc->element.type_name != Element::GetFallbackStructName())) {
32880b57cec5SDimitry Andric           // Here we are dumping an Element of struct type. This is done using
32890b57cec5SDimitry Andric           // expression evaluation with the name of the struct type and pointer
32900b57cec5SDimitry Andric           // to element. Don't print the name of the resulting expression,
32910b57cec5SDimitry Andric           // since this will be '$[0-9]+'
32920b57cec5SDimitry Andric           DumpValueObjectOptions expr_options;
32930b57cec5SDimitry Andric           expr_options.SetHideName(true);
32940b57cec5SDimitry Andric 
32950b57cec5SDimitry Andric           // Setup expression as dereferencing a pointer cast to element
32960b57cec5SDimitry Andric           // address.
32970b57cec5SDimitry Andric           char expr_char_buffer[jit_max_expr_size];
32980b57cec5SDimitry Andric           int written =
32990b57cec5SDimitry Andric               snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64,
33000b57cec5SDimitry Andric                        alloc->element.type_name.AsCString(),
33010b57cec5SDimitry Andric                        *alloc->data_ptr.get() + offset);
33020b57cec5SDimitry Andric 
33030b57cec5SDimitry Andric           if (written < 0 || written >= jit_max_expr_size) {
33049dba64beSDimitry Andric             LLDB_LOGF(log, "%s - error in snprintf().", __FUNCTION__);
33050b57cec5SDimitry Andric             continue;
33060b57cec5SDimitry Andric           }
33070b57cec5SDimitry Andric 
33080b57cec5SDimitry Andric           // Evaluate expression
33090b57cec5SDimitry Andric           ValueObjectSP expr_result;
33100b57cec5SDimitry Andric           GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer,
33110b57cec5SDimitry Andric                                                        frame_ptr, expr_result);
33120b57cec5SDimitry Andric 
33130b57cec5SDimitry Andric           // Print the results to our stream.
33140b57cec5SDimitry Andric           expr_result->Dump(strm, expr_options);
33150b57cec5SDimitry Andric         } else {
33160b57cec5SDimitry Andric           DumpDataExtractor(alloc_data, &strm, offset, format,
33170b57cec5SDimitry Andric                             data_size - padding, 1, 1, LLDB_INVALID_ADDRESS, 0,
33180b57cec5SDimitry Andric                             0);
33190b57cec5SDimitry Andric         }
33200b57cec5SDimitry Andric         offset += data_size;
33210b57cec5SDimitry Andric       }
33220b57cec5SDimitry Andric     }
33230b57cec5SDimitry Andric   }
33240b57cec5SDimitry Andric   strm.EOL();
33250b57cec5SDimitry Andric 
33260b57cec5SDimitry Andric   return true;
33270b57cec5SDimitry Andric }
33280b57cec5SDimitry Andric 
33290b57cec5SDimitry Andric // Function recalculates all our cached information about allocations by
33300b57cec5SDimitry Andric // jitting the RS runtime regarding each allocation we know about. Returns true
33310b57cec5SDimitry Andric // if all allocations could be recomputed, false otherwise.
RecomputeAllAllocations(Stream & strm,StackFrame * frame_ptr)33320b57cec5SDimitry Andric bool RenderScriptRuntime::RecomputeAllAllocations(Stream &strm,
33330b57cec5SDimitry Andric                                                   StackFrame *frame_ptr) {
33340b57cec5SDimitry Andric   bool success = true;
33350b57cec5SDimitry Andric   for (auto &alloc : m_allocations) {
33360b57cec5SDimitry Andric     // JIT current allocation information
33370b57cec5SDimitry Andric     if (!RefreshAllocation(alloc.get(), frame_ptr)) {
33380b57cec5SDimitry Andric       strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32
33390b57cec5SDimitry Andric                   "\n",
33400b57cec5SDimitry Andric                   alloc->id);
33410b57cec5SDimitry Andric       success = false;
33420b57cec5SDimitry Andric     }
33430b57cec5SDimitry Andric   }
33440b57cec5SDimitry Andric 
33450b57cec5SDimitry Andric   if (success)
33460b57cec5SDimitry Andric     strm.Printf("All allocations successfully recomputed");
33470b57cec5SDimitry Andric   strm.EOL();
33480b57cec5SDimitry Andric 
33490b57cec5SDimitry Andric   return success;
33500b57cec5SDimitry Andric }
33510b57cec5SDimitry Andric 
33520b57cec5SDimitry Andric // Prints information regarding currently loaded allocations. These details are
33530b57cec5SDimitry Andric // gathered by jitting the runtime, which has as latency. Index parameter
33540b57cec5SDimitry Andric // specifies a single allocation ID to print, or a zero value to print them all
ListAllocations(Stream & strm,StackFrame * frame_ptr,const uint32_t index)33550b57cec5SDimitry Andric void RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame *frame_ptr,
33560b57cec5SDimitry Andric                                           const uint32_t index) {
33570b57cec5SDimitry Andric   strm.Printf("RenderScript Allocations:");
33580b57cec5SDimitry Andric   strm.EOL();
33590b57cec5SDimitry Andric   strm.IndentMore();
33600b57cec5SDimitry Andric 
33610b57cec5SDimitry Andric   for (auto &alloc : m_allocations) {
33620b57cec5SDimitry Andric     // index will only be zero if we want to print all allocations
33630b57cec5SDimitry Andric     if (index != 0 && index != alloc->id)
33640b57cec5SDimitry Andric       continue;
33650b57cec5SDimitry Andric 
33660b57cec5SDimitry Andric     // JIT current allocation information
33670b57cec5SDimitry Andric     if (alloc->ShouldRefresh() && !RefreshAllocation(alloc.get(), frame_ptr)) {
33680b57cec5SDimitry Andric       strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32,
33690b57cec5SDimitry Andric                   alloc->id);
33700b57cec5SDimitry Andric       strm.EOL();
33710b57cec5SDimitry Andric       continue;
33720b57cec5SDimitry Andric     }
33730b57cec5SDimitry Andric 
33740b57cec5SDimitry Andric     strm.Printf("%" PRIu32 ":", alloc->id);
33750b57cec5SDimitry Andric     strm.EOL();
33760b57cec5SDimitry Andric     strm.IndentMore();
33770b57cec5SDimitry Andric 
33780b57cec5SDimitry Andric     strm.Indent("Context: ");
33790b57cec5SDimitry Andric     if (!alloc->context.isValid())
33800b57cec5SDimitry Andric       strm.Printf("unknown\n");
33810b57cec5SDimitry Andric     else
33820b57cec5SDimitry Andric       strm.Printf("0x%" PRIx64 "\n", *alloc->context.get());
33830b57cec5SDimitry Andric 
33840b57cec5SDimitry Andric     strm.Indent("Address: ");
33850b57cec5SDimitry Andric     if (!alloc->address.isValid())
33860b57cec5SDimitry Andric       strm.Printf("unknown\n");
33870b57cec5SDimitry Andric     else
33880b57cec5SDimitry Andric       strm.Printf("0x%" PRIx64 "\n", *alloc->address.get());
33890b57cec5SDimitry Andric 
33900b57cec5SDimitry Andric     strm.Indent("Data pointer: ");
33910b57cec5SDimitry Andric     if (!alloc->data_ptr.isValid())
33920b57cec5SDimitry Andric       strm.Printf("unknown\n");
33930b57cec5SDimitry Andric     else
33940b57cec5SDimitry Andric       strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get());
33950b57cec5SDimitry Andric 
33960b57cec5SDimitry Andric     strm.Indent("Dimensions: ");
33970b57cec5SDimitry Andric     if (!alloc->dimension.isValid())
33980b57cec5SDimitry Andric       strm.Printf("unknown\n");
33990b57cec5SDimitry Andric     else
34000b57cec5SDimitry Andric       strm.Printf("(%" PRId32 ", %" PRId32 ", %" PRId32 ")\n",
34010b57cec5SDimitry Andric                   alloc->dimension.get()->dim_1, alloc->dimension.get()->dim_2,
34020b57cec5SDimitry Andric                   alloc->dimension.get()->dim_3);
34030b57cec5SDimitry Andric 
34040b57cec5SDimitry Andric     strm.Indent("Data Type: ");
34050b57cec5SDimitry Andric     if (!alloc->element.type.isValid() ||
34060b57cec5SDimitry Andric         !alloc->element.type_vec_size.isValid())
34070b57cec5SDimitry Andric       strm.Printf("unknown\n");
34080b57cec5SDimitry Andric     else {
34090b57cec5SDimitry Andric       const int vector_size = *alloc->element.type_vec_size.get();
34100b57cec5SDimitry Andric       Element::DataType type = *alloc->element.type.get();
34110b57cec5SDimitry Andric 
34120b57cec5SDimitry Andric       if (!alloc->element.type_name.IsEmpty())
34130b57cec5SDimitry Andric         strm.Printf("%s\n", alloc->element.type_name.AsCString());
34140b57cec5SDimitry Andric       else {
34150b57cec5SDimitry Andric         // Enum value isn't monotonous, so doesn't always index
34160b57cec5SDimitry Andric         // RsDataTypeToString array
34170b57cec5SDimitry Andric         if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT)
34180b57cec5SDimitry Andric           type =
34190b57cec5SDimitry Andric               static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) +
34200b57cec5SDimitry Andric                                              Element::RS_TYPE_MATRIX_2X2 + 1);
34210b57cec5SDimitry Andric 
34220b57cec5SDimitry Andric         if (type >= (sizeof(AllocationDetails::RsDataTypeToString) /
34230b57cec5SDimitry Andric                      sizeof(AllocationDetails::RsDataTypeToString[0])) ||
34240b57cec5SDimitry Andric             vector_size > 4 || vector_size < 1)
34250b57cec5SDimitry Andric           strm.Printf("invalid type\n");
34260b57cec5SDimitry Andric         else
34270b57cec5SDimitry Andric           strm.Printf(
34280b57cec5SDimitry Andric               "%s\n",
34290b57cec5SDimitry Andric               AllocationDetails::RsDataTypeToString[static_cast<uint32_t>(type)]
34300b57cec5SDimitry Andric                                                    [vector_size - 1]);
34310b57cec5SDimitry Andric       }
34320b57cec5SDimitry Andric     }
34330b57cec5SDimitry Andric 
34340b57cec5SDimitry Andric     strm.Indent("Data Kind: ");
34350b57cec5SDimitry Andric     if (!alloc->element.type_kind.isValid())
34360b57cec5SDimitry Andric       strm.Printf("unknown\n");
34370b57cec5SDimitry Andric     else {
34380b57cec5SDimitry Andric       const Element::DataKind kind = *alloc->element.type_kind.get();
34390b57cec5SDimitry Andric       if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV)
34400b57cec5SDimitry Andric         strm.Printf("invalid kind\n");
34410b57cec5SDimitry Andric       else
34420b57cec5SDimitry Andric         strm.Printf(
34430b57cec5SDimitry Andric             "%s\n",
34440b57cec5SDimitry Andric             AllocationDetails::RsDataKindToString[static_cast<uint32_t>(kind)]);
34450b57cec5SDimitry Andric     }
34460b57cec5SDimitry Andric 
34470b57cec5SDimitry Andric     strm.EOL();
34480b57cec5SDimitry Andric     strm.IndentLess();
34490b57cec5SDimitry Andric   }
34500b57cec5SDimitry Andric   strm.IndentLess();
34510b57cec5SDimitry Andric }
34520b57cec5SDimitry Andric 
34530b57cec5SDimitry Andric // Set breakpoints on every kernel found in RS module
BreakOnModuleKernels(const RSModuleDescriptorSP rsmodule_sp)34540b57cec5SDimitry Andric void RenderScriptRuntime::BreakOnModuleKernels(
34550b57cec5SDimitry Andric     const RSModuleDescriptorSP rsmodule_sp) {
34560b57cec5SDimitry Andric   for (const auto &kernel : rsmodule_sp->m_kernels) {
34570b57cec5SDimitry Andric     // Don't set breakpoint on 'root' kernel
34580b57cec5SDimitry Andric     if (strcmp(kernel.m_name.AsCString(), "root") == 0)
34590b57cec5SDimitry Andric       continue;
34600b57cec5SDimitry Andric 
34610b57cec5SDimitry Andric     CreateKernelBreakpoint(kernel.m_name);
34620b57cec5SDimitry Andric   }
34630b57cec5SDimitry Andric }
34640b57cec5SDimitry Andric 
34650b57cec5SDimitry Andric // Method is internally called by the 'kernel breakpoint all' command to enable
34660b57cec5SDimitry Andric // or disable breaking on all kernels. When do_break is true we want to enable
34670b57cec5SDimitry Andric // this functionality. When do_break is false we want to disable it.
SetBreakAllKernels(bool do_break,TargetSP target)34680b57cec5SDimitry Andric void RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) {
34690b57cec5SDimitry Andric   Log *log(
34700b57cec5SDimitry Andric       GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
34710b57cec5SDimitry Andric 
34720b57cec5SDimitry Andric   InitSearchFilter(target);
34730b57cec5SDimitry Andric 
34740b57cec5SDimitry Andric   // Set breakpoints on all the kernels
34750b57cec5SDimitry Andric   if (do_break && !m_breakAllKernels) {
34760b57cec5SDimitry Andric     m_breakAllKernels = true;
34770b57cec5SDimitry Andric 
34780b57cec5SDimitry Andric     for (const auto &module : m_rsmodules)
34790b57cec5SDimitry Andric       BreakOnModuleKernels(module);
34800b57cec5SDimitry Andric 
34819dba64beSDimitry Andric     LLDB_LOGF(log,
34829dba64beSDimitry Andric               "%s(True) - breakpoints set on all currently loaded kernels.",
34830b57cec5SDimitry Andric               __FUNCTION__);
34840b57cec5SDimitry Andric   } else if (!do_break &&
34850b57cec5SDimitry Andric              m_breakAllKernels) // Breakpoints won't be set on any new kernels.
34860b57cec5SDimitry Andric   {
34870b57cec5SDimitry Andric     m_breakAllKernels = false;
34880b57cec5SDimitry Andric 
34899dba64beSDimitry Andric     LLDB_LOGF(log, "%s(False) - breakpoints no longer automatically set.",
34900b57cec5SDimitry Andric               __FUNCTION__);
34910b57cec5SDimitry Andric   }
34920b57cec5SDimitry Andric }
34930b57cec5SDimitry Andric 
34940b57cec5SDimitry Andric // Given the name of a kernel this function creates a breakpoint using our own
34950b57cec5SDimitry Andric // breakpoint resolver, and returns the Breakpoint shared pointer.
34960b57cec5SDimitry Andric BreakpointSP
CreateKernelBreakpoint(ConstString name)34970b57cec5SDimitry Andric RenderScriptRuntime::CreateKernelBreakpoint(ConstString name) {
34980b57cec5SDimitry Andric   Log *log(
34990b57cec5SDimitry Andric       GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
35000b57cec5SDimitry Andric 
35010b57cec5SDimitry Andric   if (!m_filtersp) {
35029dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error, no breakpoint search filter set.",
35039dba64beSDimitry Andric               __FUNCTION__);
35040b57cec5SDimitry Andric     return nullptr;
35050b57cec5SDimitry Andric   }
35060b57cec5SDimitry Andric 
35070b57cec5SDimitry Andric   BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name));
35080b57cec5SDimitry Andric   Target &target = GetProcess()->GetTarget();
35090b57cec5SDimitry Andric   BreakpointSP bp = target.CreateBreakpoint(
35100b57cec5SDimitry Andric       m_filtersp, resolver_sp, false, false, false);
35110b57cec5SDimitry Andric 
35120b57cec5SDimitry Andric   // Give RS breakpoints a specific name, so the user can manipulate them as a
35130b57cec5SDimitry Andric   // group.
35140b57cec5SDimitry Andric   Status err;
35150b57cec5SDimitry Andric   target.AddNameToBreakpoint(bp, "RenderScriptKernel", err);
35160b57cec5SDimitry Andric   if (err.Fail() && log)
35179dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error setting break name, '%s'.", __FUNCTION__,
35180b57cec5SDimitry Andric               err.AsCString());
35190b57cec5SDimitry Andric 
35200b57cec5SDimitry Andric   return bp;
35210b57cec5SDimitry Andric }
35220b57cec5SDimitry Andric 
35230b57cec5SDimitry Andric BreakpointSP
CreateReductionBreakpoint(ConstString name,int kernel_types)35240b57cec5SDimitry Andric RenderScriptRuntime::CreateReductionBreakpoint(ConstString name,
35250b57cec5SDimitry Andric                                                int kernel_types) {
35260b57cec5SDimitry Andric   Log *log(
35270b57cec5SDimitry Andric       GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
35280b57cec5SDimitry Andric 
35290b57cec5SDimitry Andric   if (!m_filtersp) {
35309dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error, no breakpoint search filter set.",
35319dba64beSDimitry Andric               __FUNCTION__);
35320b57cec5SDimitry Andric     return nullptr;
35330b57cec5SDimitry Andric   }
35340b57cec5SDimitry Andric 
35350b57cec5SDimitry Andric   BreakpointResolverSP resolver_sp(new RSReduceBreakpointResolver(
35360b57cec5SDimitry Andric       nullptr, name, &m_rsmodules, kernel_types));
35370b57cec5SDimitry Andric   Target &target = GetProcess()->GetTarget();
35380b57cec5SDimitry Andric   BreakpointSP bp = target.CreateBreakpoint(
35390b57cec5SDimitry Andric       m_filtersp, resolver_sp, false, false, false);
35400b57cec5SDimitry Andric 
35410b57cec5SDimitry Andric   // Give RS breakpoints a specific name, so the user can manipulate them as a
35420b57cec5SDimitry Andric   // group.
35430b57cec5SDimitry Andric   Status err;
35440b57cec5SDimitry Andric   target.AddNameToBreakpoint(bp, "RenderScriptReduction", err);
35450b57cec5SDimitry Andric   if (err.Fail() && log)
35469dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error setting break name, '%s'.", __FUNCTION__,
35470b57cec5SDimitry Andric               err.AsCString());
35480b57cec5SDimitry Andric 
35490b57cec5SDimitry Andric   return bp;
35500b57cec5SDimitry Andric }
35510b57cec5SDimitry Andric 
35520b57cec5SDimitry Andric // Given an expression for a variable this function tries to calculate the
35530b57cec5SDimitry Andric // variable's value. If this is possible it returns true and sets the uint64_t
35540b57cec5SDimitry Andric // parameter to the variables unsigned value. Otherwise function returns false.
GetFrameVarAsUnsigned(const StackFrameSP frame_sp,const char * var_name,uint64_t & val)35550b57cec5SDimitry Andric bool RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp,
35560b57cec5SDimitry Andric                                                 const char *var_name,
35570b57cec5SDimitry Andric                                                 uint64_t &val) {
35580b57cec5SDimitry Andric   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE));
35590b57cec5SDimitry Andric   Status err;
35600b57cec5SDimitry Andric   VariableSP var_sp;
35610b57cec5SDimitry Andric 
35620b57cec5SDimitry Andric   // Find variable in stack frame
35630b57cec5SDimitry Andric   ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath(
35640b57cec5SDimitry Andric       var_name, eNoDynamicValues,
35650b57cec5SDimitry Andric       StackFrame::eExpressionPathOptionCheckPtrVsMember |
35660b57cec5SDimitry Andric           StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
35670b57cec5SDimitry Andric       var_sp, err));
35680b57cec5SDimitry Andric   if (!err.Success()) {
35699dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error, couldn't find '%s' in frame", __FUNCTION__,
35700b57cec5SDimitry Andric               var_name);
35710b57cec5SDimitry Andric     return false;
35720b57cec5SDimitry Andric   }
35730b57cec5SDimitry Andric 
35740b57cec5SDimitry Andric   // Find the uint32_t value for the variable
35750b57cec5SDimitry Andric   bool success = false;
35760b57cec5SDimitry Andric   val = value_sp->GetValueAsUnsigned(0, &success);
35770b57cec5SDimitry Andric   if (!success) {
35789dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error, couldn't parse '%s' as an uint32_t.",
35790b57cec5SDimitry Andric               __FUNCTION__, var_name);
35800b57cec5SDimitry Andric     return false;
35810b57cec5SDimitry Andric   }
35820b57cec5SDimitry Andric 
35830b57cec5SDimitry Andric   return true;
35840b57cec5SDimitry Andric }
35850b57cec5SDimitry Andric 
35860b57cec5SDimitry Andric // Function attempts to find the current coordinate of a kernel invocation by
35870b57cec5SDimitry Andric // investigating the values of frame variables in the .expand function. These
35880b57cec5SDimitry Andric // coordinates are returned via the coord array reference parameter. Returns
35890b57cec5SDimitry Andric // true if the coordinates could be found, and false otherwise.
GetKernelCoordinate(RSCoordinate & coord,Thread * thread_ptr)35900b57cec5SDimitry Andric bool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord,
35910b57cec5SDimitry Andric                                               Thread *thread_ptr) {
35920b57cec5SDimitry Andric   static const char *const x_expr = "rsIndex";
35930b57cec5SDimitry Andric   static const char *const y_expr = "p->current.y";
35940b57cec5SDimitry Andric   static const char *const z_expr = "p->current.z";
35950b57cec5SDimitry Andric 
35960b57cec5SDimitry Andric   Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE));
35970b57cec5SDimitry Andric 
35980b57cec5SDimitry Andric   if (!thread_ptr) {
35999dba64beSDimitry Andric     LLDB_LOGF(log, "%s - Error, No thread pointer", __FUNCTION__);
36000b57cec5SDimitry Andric 
36010b57cec5SDimitry Andric     return false;
36020b57cec5SDimitry Andric   }
36030b57cec5SDimitry Andric 
36040b57cec5SDimitry Andric   // Walk the call stack looking for a function whose name has the suffix
36050b57cec5SDimitry Andric   // '.expand' and contains the variables we're looking for.
36060b57cec5SDimitry Andric   for (uint32_t i = 0; i < thread_ptr->GetStackFrameCount(); ++i) {
36070b57cec5SDimitry Andric     if (!thread_ptr->SetSelectedFrameByIndex(i))
36080b57cec5SDimitry Andric       continue;
36090b57cec5SDimitry Andric 
36100b57cec5SDimitry Andric     StackFrameSP frame_sp = thread_ptr->GetSelectedFrame();
36110b57cec5SDimitry Andric     if (!frame_sp)
36120b57cec5SDimitry Andric       continue;
36130b57cec5SDimitry Andric 
36140b57cec5SDimitry Andric     // Find the function name
36150b57cec5SDimitry Andric     const SymbolContext sym_ctx =
36160b57cec5SDimitry Andric         frame_sp->GetSymbolContext(eSymbolContextFunction);
36170b57cec5SDimitry Andric     const ConstString func_name = sym_ctx.GetFunctionName();
36180b57cec5SDimitry Andric     if (!func_name)
36190b57cec5SDimitry Andric       continue;
36200b57cec5SDimitry Andric 
36219dba64beSDimitry Andric     LLDB_LOGF(log, "%s - Inspecting function '%s'", __FUNCTION__,
36220b57cec5SDimitry Andric               func_name.GetCString());
36230b57cec5SDimitry Andric 
36240b57cec5SDimitry Andric     // Check if function name has .expand suffix
36250b57cec5SDimitry Andric     if (!func_name.GetStringRef().endswith(".expand"))
36260b57cec5SDimitry Andric       continue;
36270b57cec5SDimitry Andric 
36289dba64beSDimitry Andric     LLDB_LOGF(log, "%s - Found .expand function '%s'", __FUNCTION__,
36290b57cec5SDimitry Andric               func_name.GetCString());
36300b57cec5SDimitry Andric 
36310b57cec5SDimitry Andric     // Get values for variables in .expand frame that tell us the current
36320b57cec5SDimitry Andric     // kernel invocation
36330b57cec5SDimitry Andric     uint64_t x, y, z;
36340b57cec5SDimitry Andric     bool found = GetFrameVarAsUnsigned(frame_sp, x_expr, x) &&
36350b57cec5SDimitry Andric                  GetFrameVarAsUnsigned(frame_sp, y_expr, y) &&
36360b57cec5SDimitry Andric                  GetFrameVarAsUnsigned(frame_sp, z_expr, z);
36370b57cec5SDimitry Andric 
36380b57cec5SDimitry Andric     if (found) {
36390b57cec5SDimitry Andric       // The RenderScript runtime uses uint32_t for these vars. If they're not
36400b57cec5SDimitry Andric       // within bounds, our frame parsing is garbage
36410b57cec5SDimitry Andric       assert(x <= UINT32_MAX && y <= UINT32_MAX && z <= UINT32_MAX);
36420b57cec5SDimitry Andric       coord.x = (uint32_t)x;
36430b57cec5SDimitry Andric       coord.y = (uint32_t)y;
36440b57cec5SDimitry Andric       coord.z = (uint32_t)z;
36450b57cec5SDimitry Andric       return true;
36460b57cec5SDimitry Andric     }
36470b57cec5SDimitry Andric   }
36480b57cec5SDimitry Andric   return false;
36490b57cec5SDimitry Andric }
36500b57cec5SDimitry Andric 
36510b57cec5SDimitry Andric // Callback when a kernel breakpoint hits and we're looking for a specific
36520b57cec5SDimitry Andric // coordinate. Baton parameter contains a pointer to the target coordinate we
36530b57cec5SDimitry Andric // want to break on. Function then checks the .expand frame for the current
36540b57cec5SDimitry Andric // coordinate and breaks to user if it matches. Parameter 'break_id' is the id
36550b57cec5SDimitry Andric // of the Breakpoint which made the callback. Parameter 'break_loc_id' is the
36560b57cec5SDimitry Andric // id for the BreakpointLocation which was hit, a single logical breakpoint can
36570b57cec5SDimitry Andric // have multiple addresses.
KernelBreakpointHit(void * baton,StoppointCallbackContext * ctx,user_id_t break_id,user_id_t break_loc_id)36580b57cec5SDimitry Andric bool RenderScriptRuntime::KernelBreakpointHit(void *baton,
36590b57cec5SDimitry Andric                                               StoppointCallbackContext *ctx,
36600b57cec5SDimitry Andric                                               user_id_t break_id,
36610b57cec5SDimitry Andric                                               user_id_t break_loc_id) {
36620b57cec5SDimitry Andric   Log *log(
36630b57cec5SDimitry Andric       GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
36640b57cec5SDimitry Andric 
36650b57cec5SDimitry Andric   assert(baton &&
36660b57cec5SDimitry Andric          "Error: null baton in conditional kernel breakpoint callback");
36670b57cec5SDimitry Andric 
36680b57cec5SDimitry Andric   // Coordinate we want to stop on
36690b57cec5SDimitry Andric   RSCoordinate target_coord = *static_cast<RSCoordinate *>(baton);
36700b57cec5SDimitry Andric 
36719dba64beSDimitry Andric   LLDB_LOGF(log, "%s - Break ID %" PRIu64 ", " FMT_COORD, __FUNCTION__,
36729dba64beSDimitry Andric             break_id, target_coord.x, target_coord.y, target_coord.z);
36730b57cec5SDimitry Andric 
36740b57cec5SDimitry Andric   // Select current thread
36750b57cec5SDimitry Andric   ExecutionContext context(ctx->exe_ctx_ref);
36760b57cec5SDimitry Andric   Thread *thread_ptr = context.GetThreadPtr();
36770b57cec5SDimitry Andric   assert(thread_ptr && "Null thread pointer");
36780b57cec5SDimitry Andric 
36790b57cec5SDimitry Andric   // Find current kernel invocation from .expand frame variables
36800b57cec5SDimitry Andric   RSCoordinate current_coord{};
36810b57cec5SDimitry Andric   if (!GetKernelCoordinate(current_coord, thread_ptr)) {
36829dba64beSDimitry Andric     LLDB_LOGF(log, "%s - Error, couldn't select .expand stack frame",
36830b57cec5SDimitry Andric               __FUNCTION__);
36840b57cec5SDimitry Andric     return false;
36850b57cec5SDimitry Andric   }
36860b57cec5SDimitry Andric 
36879dba64beSDimitry Andric   LLDB_LOGF(log, "%s - " FMT_COORD, __FUNCTION__, current_coord.x,
36880b57cec5SDimitry Andric             current_coord.y, current_coord.z);
36890b57cec5SDimitry Andric 
36900b57cec5SDimitry Andric   // Check if the current kernel invocation coordinate matches our target
36910b57cec5SDimitry Andric   // coordinate
36920b57cec5SDimitry Andric   if (target_coord == current_coord) {
36939dba64beSDimitry Andric     LLDB_LOGF(log, "%s, BREAKING " FMT_COORD, __FUNCTION__, current_coord.x,
36940b57cec5SDimitry Andric               current_coord.y, current_coord.z);
36950b57cec5SDimitry Andric 
36960b57cec5SDimitry Andric     BreakpointSP breakpoint_sp =
36970b57cec5SDimitry Andric         context.GetTargetPtr()->GetBreakpointByID(break_id);
36980b57cec5SDimitry Andric     assert(breakpoint_sp != nullptr &&
36990b57cec5SDimitry Andric            "Error: Couldn't find breakpoint matching break id for callback");
37000b57cec5SDimitry Andric     breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint
37010b57cec5SDimitry Andric                                       // should only be hit once.
37020b57cec5SDimitry Andric     return true;
37030b57cec5SDimitry Andric   }
37040b57cec5SDimitry Andric 
37050b57cec5SDimitry Andric   // No match on coordinate
37060b57cec5SDimitry Andric   return false;
37070b57cec5SDimitry Andric }
37080b57cec5SDimitry Andric 
SetConditional(BreakpointSP bp,Stream & messages,const RSCoordinate & coord)37090b57cec5SDimitry Andric void RenderScriptRuntime::SetConditional(BreakpointSP bp, Stream &messages,
37100b57cec5SDimitry Andric                                          const RSCoordinate &coord) {
37110b57cec5SDimitry Andric   messages.Printf("Conditional kernel breakpoint on coordinate " FMT_COORD,
37120b57cec5SDimitry Andric                   coord.x, coord.y, coord.z);
37130b57cec5SDimitry Andric   messages.EOL();
37140b57cec5SDimitry Andric 
37150b57cec5SDimitry Andric   // Allocate memory for the baton, and copy over coordinate
37160b57cec5SDimitry Andric   RSCoordinate *baton = new RSCoordinate(coord);
37170b57cec5SDimitry Andric 
37180b57cec5SDimitry Andric   // Create a callback that will be invoked every time the breakpoint is hit.
37190b57cec5SDimitry Andric   // The baton object passed to the handler is the target coordinate we want to
37200b57cec5SDimitry Andric   // break on.
37210b57cec5SDimitry Andric   bp->SetCallback(KernelBreakpointHit, baton, true);
37220b57cec5SDimitry Andric 
37230b57cec5SDimitry Andric   // Store a shared pointer to the baton, so the memory will eventually be
37240b57cec5SDimitry Andric   // cleaned up after destruction
37250b57cec5SDimitry Andric   m_conditional_breaks[bp->GetID()] = std::unique_ptr<RSCoordinate>(baton);
37260b57cec5SDimitry Andric }
37270b57cec5SDimitry Andric 
37280b57cec5SDimitry Andric // Tries to set a breakpoint on the start of a kernel, resolved using the
37290b57cec5SDimitry Andric // kernel name. Argument 'coords', represents a three dimensional coordinate
37300b57cec5SDimitry Andric // which can be used to specify a single kernel instance to break on. If this
37310b57cec5SDimitry Andric // is set then we add a callback to the breakpoint.
PlaceBreakpointOnKernel(TargetSP target,Stream & messages,const char * name,const RSCoordinate * coord)37320b57cec5SDimitry Andric bool RenderScriptRuntime::PlaceBreakpointOnKernel(TargetSP target,
37330b57cec5SDimitry Andric                                                   Stream &messages,
37340b57cec5SDimitry Andric                                                   const char *name,
37350b57cec5SDimitry Andric                                                   const RSCoordinate *coord) {
37360b57cec5SDimitry Andric   if (!name)
37370b57cec5SDimitry Andric     return false;
37380b57cec5SDimitry Andric 
37390b57cec5SDimitry Andric   InitSearchFilter(target);
37400b57cec5SDimitry Andric 
37410b57cec5SDimitry Andric   ConstString kernel_name(name);
37420b57cec5SDimitry Andric   BreakpointSP bp = CreateKernelBreakpoint(kernel_name);
37430b57cec5SDimitry Andric   if (!bp)
37440b57cec5SDimitry Andric     return false;
37450b57cec5SDimitry Andric 
37460b57cec5SDimitry Andric   // We have a conditional breakpoint on a specific coordinate
37470b57cec5SDimitry Andric   if (coord)
37480b57cec5SDimitry Andric     SetConditional(bp, messages, *coord);
37490b57cec5SDimitry Andric 
37500b57cec5SDimitry Andric   bp->GetDescription(&messages, lldb::eDescriptionLevelInitial, false);
37510b57cec5SDimitry Andric 
37520b57cec5SDimitry Andric   return true;
37530b57cec5SDimitry Andric }
37540b57cec5SDimitry Andric 
37550b57cec5SDimitry Andric BreakpointSP
CreateScriptGroupBreakpoint(ConstString name,bool stop_on_all)37560b57cec5SDimitry Andric RenderScriptRuntime::CreateScriptGroupBreakpoint(ConstString name,
37570b57cec5SDimitry Andric                                                  bool stop_on_all) {
37580b57cec5SDimitry Andric   Log *log(
37590b57cec5SDimitry Andric       GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
37600b57cec5SDimitry Andric 
37610b57cec5SDimitry Andric   if (!m_filtersp) {
37629dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error, no breakpoint search filter set.",
37639dba64beSDimitry Andric               __FUNCTION__);
37640b57cec5SDimitry Andric     return nullptr;
37650b57cec5SDimitry Andric   }
37660b57cec5SDimitry Andric 
37670b57cec5SDimitry Andric   BreakpointResolverSP resolver_sp(new RSScriptGroupBreakpointResolver(
37680b57cec5SDimitry Andric       nullptr, name, m_scriptGroups, stop_on_all));
37690b57cec5SDimitry Andric   Target &target = GetProcess()->GetTarget();
37700b57cec5SDimitry Andric   BreakpointSP bp = target.CreateBreakpoint(
37710b57cec5SDimitry Andric       m_filtersp, resolver_sp, false, false, false);
37720b57cec5SDimitry Andric   // Give RS breakpoints a specific name, so the user can manipulate them as a
37730b57cec5SDimitry Andric   // group.
37740b57cec5SDimitry Andric   Status err;
37750b57cec5SDimitry Andric   target.AddNameToBreakpoint(bp, name.GetCString(), err);
37760b57cec5SDimitry Andric   if (err.Fail() && log)
37779dba64beSDimitry Andric     LLDB_LOGF(log, "%s - error setting break name, '%s'.", __FUNCTION__,
37780b57cec5SDimitry Andric               err.AsCString());
37790b57cec5SDimitry Andric   // ask the breakpoint to resolve itself
37800b57cec5SDimitry Andric   bp->ResolveBreakpoint();
37810b57cec5SDimitry Andric   return bp;
37820b57cec5SDimitry Andric }
37830b57cec5SDimitry Andric 
PlaceBreakpointOnScriptGroup(TargetSP target,Stream & strm,ConstString name,bool multi)37840b57cec5SDimitry Andric bool RenderScriptRuntime::PlaceBreakpointOnScriptGroup(TargetSP target,
37850b57cec5SDimitry Andric                                                        Stream &strm,
37860b57cec5SDimitry Andric                                                        ConstString name,
37870b57cec5SDimitry Andric                                                        bool multi) {
37880b57cec5SDimitry Andric   InitSearchFilter(target);
37890b57cec5SDimitry Andric   BreakpointSP bp = CreateScriptGroupBreakpoint(name, multi);
37900b57cec5SDimitry Andric   if (bp)
37910b57cec5SDimitry Andric     bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false);
37920b57cec5SDimitry Andric   return bool(bp);
37930b57cec5SDimitry Andric }
37940b57cec5SDimitry Andric 
PlaceBreakpointOnReduction(TargetSP target,Stream & messages,const char * reduce_name,const RSCoordinate * coord,int kernel_types)37950b57cec5SDimitry Andric bool RenderScriptRuntime::PlaceBreakpointOnReduction(TargetSP target,
37960b57cec5SDimitry Andric                                                      Stream &messages,
37970b57cec5SDimitry Andric                                                      const char *reduce_name,
37980b57cec5SDimitry Andric                                                      const RSCoordinate *coord,
37990b57cec5SDimitry Andric                                                      int kernel_types) {
38000b57cec5SDimitry Andric   if (!reduce_name)
38010b57cec5SDimitry Andric     return false;
38020b57cec5SDimitry Andric 
38030b57cec5SDimitry Andric   InitSearchFilter(target);
38040b57cec5SDimitry Andric   BreakpointSP bp =
38050b57cec5SDimitry Andric       CreateReductionBreakpoint(ConstString(reduce_name), kernel_types);
38060b57cec5SDimitry Andric   if (!bp)
38070b57cec5SDimitry Andric     return false;
38080b57cec5SDimitry Andric 
38090b57cec5SDimitry Andric   if (coord)
38100b57cec5SDimitry Andric     SetConditional(bp, messages, *coord);
38110b57cec5SDimitry Andric 
38120b57cec5SDimitry Andric   bp->GetDescription(&messages, lldb::eDescriptionLevelInitial, false);
38130b57cec5SDimitry Andric 
38140b57cec5SDimitry Andric   return true;
38150b57cec5SDimitry Andric }
38160b57cec5SDimitry Andric 
DumpModules(Stream & strm) const38170b57cec5SDimitry Andric void RenderScriptRuntime::DumpModules(Stream &strm) const {
38180b57cec5SDimitry Andric   strm.Printf("RenderScript Modules:");
38190b57cec5SDimitry Andric   strm.EOL();
38200b57cec5SDimitry Andric   strm.IndentMore();
38210b57cec5SDimitry Andric   for (const auto &module : m_rsmodules) {
38220b57cec5SDimitry Andric     module->Dump(strm);
38230b57cec5SDimitry Andric   }
38240b57cec5SDimitry Andric   strm.IndentLess();
38250b57cec5SDimitry Andric }
38260b57cec5SDimitry Andric 
38270b57cec5SDimitry Andric RenderScriptRuntime::ScriptDetails *
LookUpScript(addr_t address,bool create)38280b57cec5SDimitry Andric RenderScriptRuntime::LookUpScript(addr_t address, bool create) {
38290b57cec5SDimitry Andric   for (const auto &s : m_scripts) {
38300b57cec5SDimitry Andric     if (s->script.isValid())
38310b57cec5SDimitry Andric       if (*s->script == address)
38320b57cec5SDimitry Andric         return s.get();
38330b57cec5SDimitry Andric   }
38340b57cec5SDimitry Andric   if (create) {
38350b57cec5SDimitry Andric     std::unique_ptr<ScriptDetails> s(new ScriptDetails);
38360b57cec5SDimitry Andric     s->script = address;
38370b57cec5SDimitry Andric     m_scripts.push_back(std::move(s));
38380b57cec5SDimitry Andric     return m_scripts.back().get();
38390b57cec5SDimitry Andric   }
38400b57cec5SDimitry Andric   return nullptr;
38410b57cec5SDimitry Andric }
38420b57cec5SDimitry Andric 
38430b57cec5SDimitry Andric RenderScriptRuntime::AllocationDetails *
LookUpAllocation(addr_t address)38440b57cec5SDimitry Andric RenderScriptRuntime::LookUpAllocation(addr_t address) {
38450b57cec5SDimitry Andric   for (const auto &a : m_allocations) {
38460b57cec5SDimitry Andric     if (a->address.isValid())
38470b57cec5SDimitry Andric       if (*a->address == address)
38480b57cec5SDimitry Andric         return a.get();
38490b57cec5SDimitry Andric   }
38500b57cec5SDimitry Andric   return nullptr;
38510b57cec5SDimitry Andric }
38520b57cec5SDimitry Andric 
38530b57cec5SDimitry Andric RenderScriptRuntime::AllocationDetails *
CreateAllocation(addr_t address)38540b57cec5SDimitry Andric RenderScriptRuntime::CreateAllocation(addr_t address) {
38550b57cec5SDimitry Andric   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
38560b57cec5SDimitry Andric 
38570b57cec5SDimitry Andric   // Remove any previous allocation which contains the same address
38580b57cec5SDimitry Andric   auto it = m_allocations.begin();
38590b57cec5SDimitry Andric   while (it != m_allocations.end()) {
38600b57cec5SDimitry Andric     if (*((*it)->address) == address) {
38619dba64beSDimitry Andric       LLDB_LOGF(log, "%s - Removing allocation id: %d, address: 0x%" PRIx64,
38620b57cec5SDimitry Andric                 __FUNCTION__, (*it)->id, address);
38630b57cec5SDimitry Andric 
38640b57cec5SDimitry Andric       it = m_allocations.erase(it);
38650b57cec5SDimitry Andric     } else {
38660b57cec5SDimitry Andric       it++;
38670b57cec5SDimitry Andric     }
38680b57cec5SDimitry Andric   }
38690b57cec5SDimitry Andric 
38700b57cec5SDimitry Andric   std::unique_ptr<AllocationDetails> a(new AllocationDetails);
38710b57cec5SDimitry Andric   a->address = address;
38720b57cec5SDimitry Andric   m_allocations.push_back(std::move(a));
38730b57cec5SDimitry Andric   return m_allocations.back().get();
38740b57cec5SDimitry Andric }
38750b57cec5SDimitry Andric 
ResolveKernelName(lldb::addr_t kernel_addr,ConstString & name)38760b57cec5SDimitry Andric bool RenderScriptRuntime::ResolveKernelName(lldb::addr_t kernel_addr,
38770b57cec5SDimitry Andric                                             ConstString &name) {
38780b57cec5SDimitry Andric   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
38790b57cec5SDimitry Andric 
38800b57cec5SDimitry Andric   Target &target = GetProcess()->GetTarget();
38810b57cec5SDimitry Andric   Address resolved;
38820b57cec5SDimitry Andric   // RenderScript module
38830b57cec5SDimitry Andric   if (!target.GetSectionLoadList().ResolveLoadAddress(kernel_addr, resolved)) {
38849dba64beSDimitry Andric     LLDB_LOGF(log, "%s: unable to resolve 0x%" PRIx64 " to a loaded symbol",
38850b57cec5SDimitry Andric               __FUNCTION__, kernel_addr);
38860b57cec5SDimitry Andric     return false;
38870b57cec5SDimitry Andric   }
38880b57cec5SDimitry Andric 
38890b57cec5SDimitry Andric   Symbol *sym = resolved.CalculateSymbolContextSymbol();
38900b57cec5SDimitry Andric   if (!sym)
38910b57cec5SDimitry Andric     return false;
38920b57cec5SDimitry Andric 
38930b57cec5SDimitry Andric   name = sym->GetName();
38940b57cec5SDimitry Andric   assert(IsRenderScriptModule(resolved.CalculateSymbolContextModule()));
38959dba64beSDimitry Andric   LLDB_LOGF(log, "%s: 0x%" PRIx64 " resolved to the symbol '%s'", __FUNCTION__,
38960b57cec5SDimitry Andric             kernel_addr, name.GetCString());
38970b57cec5SDimitry Andric   return true;
38980b57cec5SDimitry Andric }
38990b57cec5SDimitry Andric 
Dump(Stream & strm) const39000b57cec5SDimitry Andric void RSModuleDescriptor::Dump(Stream &strm) const {
39010b57cec5SDimitry Andric   int indent = strm.GetIndentLevel();
39020b57cec5SDimitry Andric 
39030b57cec5SDimitry Andric   strm.Indent();
3904480093f4SDimitry Andric   m_module->GetFileSpec().Dump(strm.AsRawOstream());
39050b57cec5SDimitry Andric   strm.Indent(m_module->GetNumCompileUnits() ? "Debug info loaded."
39060b57cec5SDimitry Andric                                              : "Debug info does not exist.");
39070b57cec5SDimitry Andric   strm.EOL();
39080b57cec5SDimitry Andric   strm.IndentMore();
39090b57cec5SDimitry Andric 
39100b57cec5SDimitry Andric   strm.Indent();
39110b57cec5SDimitry Andric   strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size()));
39120b57cec5SDimitry Andric   strm.EOL();
39130b57cec5SDimitry Andric   strm.IndentMore();
39140b57cec5SDimitry Andric   for (const auto &global : m_globals) {
39150b57cec5SDimitry Andric     global.Dump(strm);
39160b57cec5SDimitry Andric   }
39170b57cec5SDimitry Andric   strm.IndentLess();
39180b57cec5SDimitry Andric 
39190b57cec5SDimitry Andric   strm.Indent();
39200b57cec5SDimitry Andric   strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size()));
39210b57cec5SDimitry Andric   strm.EOL();
39220b57cec5SDimitry Andric   strm.IndentMore();
39230b57cec5SDimitry Andric   for (const auto &kernel : m_kernels) {
39240b57cec5SDimitry Andric     kernel.Dump(strm);
39250b57cec5SDimitry Andric   }
39260b57cec5SDimitry Andric   strm.IndentLess();
39270b57cec5SDimitry Andric 
39280b57cec5SDimitry Andric   strm.Indent();
39290b57cec5SDimitry Andric   strm.Printf("Pragmas: %" PRIu64, static_cast<uint64_t>(m_pragmas.size()));
39300b57cec5SDimitry Andric   strm.EOL();
39310b57cec5SDimitry Andric   strm.IndentMore();
39320b57cec5SDimitry Andric   for (const auto &key_val : m_pragmas) {
39330b57cec5SDimitry Andric     strm.Indent();
39340b57cec5SDimitry Andric     strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str());
39350b57cec5SDimitry Andric     strm.EOL();
39360b57cec5SDimitry Andric   }
39370b57cec5SDimitry Andric   strm.IndentLess();
39380b57cec5SDimitry Andric 
39390b57cec5SDimitry Andric   strm.Indent();
39400b57cec5SDimitry Andric   strm.Printf("Reductions: %" PRIu64,
39410b57cec5SDimitry Andric               static_cast<uint64_t>(m_reductions.size()));
39420b57cec5SDimitry Andric   strm.EOL();
39430b57cec5SDimitry Andric   strm.IndentMore();
39440b57cec5SDimitry Andric   for (const auto &reduction : m_reductions) {
39450b57cec5SDimitry Andric     reduction.Dump(strm);
39460b57cec5SDimitry Andric   }
39470b57cec5SDimitry Andric 
39480b57cec5SDimitry Andric   strm.SetIndentLevel(indent);
39490b57cec5SDimitry Andric }
39500b57cec5SDimitry Andric 
Dump(Stream & strm) const39510b57cec5SDimitry Andric void RSGlobalDescriptor::Dump(Stream &strm) const {
39525ffd83dbSDimitry Andric   strm.Indent(m_name.GetStringRef());
39530b57cec5SDimitry Andric   VariableList var_list;
39545ffd83dbSDimitry Andric   m_module->m_module->FindGlobalVariables(m_name, CompilerDeclContext(), 1U,
39555ffd83dbSDimitry Andric                                           var_list);
39560b57cec5SDimitry Andric   if (var_list.GetSize() == 1) {
39570b57cec5SDimitry Andric     auto var = var_list.GetVariableAtIndex(0);
39580b57cec5SDimitry Andric     auto type = var->GetType();
39590b57cec5SDimitry Andric     if (type) {
39600b57cec5SDimitry Andric       strm.Printf(" - ");
39610b57cec5SDimitry Andric       type->DumpTypeName(&strm);
39620b57cec5SDimitry Andric     } else {
39630b57cec5SDimitry Andric       strm.Printf(" - Unknown Type");
39640b57cec5SDimitry Andric     }
39650b57cec5SDimitry Andric   } else {
39660b57cec5SDimitry Andric     strm.Printf(" - variable identified, but not found in binary");
39670b57cec5SDimitry Andric     const Symbol *s = m_module->m_module->FindFirstSymbolWithNameAndType(
39680b57cec5SDimitry Andric         m_name, eSymbolTypeData);
39690b57cec5SDimitry Andric     if (s) {
39700b57cec5SDimitry Andric       strm.Printf(" (symbol exists) ");
39710b57cec5SDimitry Andric     }
39720b57cec5SDimitry Andric   }
39730b57cec5SDimitry Andric 
39740b57cec5SDimitry Andric   strm.EOL();
39750b57cec5SDimitry Andric }
39760b57cec5SDimitry Andric 
Dump(Stream & strm) const39770b57cec5SDimitry Andric void RSKernelDescriptor::Dump(Stream &strm) const {
39785ffd83dbSDimitry Andric   strm.Indent(m_name.GetStringRef());
39790b57cec5SDimitry Andric   strm.EOL();
39800b57cec5SDimitry Andric }
39810b57cec5SDimitry Andric 
Dump(lldb_private::Stream & stream) const39820b57cec5SDimitry Andric void RSReductionDescriptor::Dump(lldb_private::Stream &stream) const {
39835ffd83dbSDimitry Andric   stream.Indent(m_reduce_name.GetStringRef());
39840b57cec5SDimitry Andric   stream.IndentMore();
39850b57cec5SDimitry Andric   stream.EOL();
39860b57cec5SDimitry Andric   stream.Indent();
39870b57cec5SDimitry Andric   stream.Printf("accumulator: %s", m_accum_name.AsCString());
39880b57cec5SDimitry Andric   stream.EOL();
39890b57cec5SDimitry Andric   stream.Indent();
39900b57cec5SDimitry Andric   stream.Printf("initializer: %s", m_init_name.AsCString());
39910b57cec5SDimitry Andric   stream.EOL();
39920b57cec5SDimitry Andric   stream.Indent();
39930b57cec5SDimitry Andric   stream.Printf("combiner: %s", m_comb_name.AsCString());
39940b57cec5SDimitry Andric   stream.EOL();
39950b57cec5SDimitry Andric   stream.Indent();
39960b57cec5SDimitry Andric   stream.Printf("outconverter: %s", m_outc_name.AsCString());
39970b57cec5SDimitry Andric   stream.EOL();
39980b57cec5SDimitry Andric   // XXX This is currently unspecified by RenderScript, and unused
39990b57cec5SDimitry Andric   // stream.Indent();
40000b57cec5SDimitry Andric   // stream.Printf("halter: '%s'", m_init_name.AsCString());
40010b57cec5SDimitry Andric   // stream.EOL();
40020b57cec5SDimitry Andric   stream.IndentLess();
40030b57cec5SDimitry Andric }
40040b57cec5SDimitry Andric 
40050b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed {
40060b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter & interpreter)40070b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter)
40080b57cec5SDimitry Andric       : CommandObjectParsed(
40090b57cec5SDimitry Andric             interpreter, "renderscript module dump",
40100b57cec5SDimitry Andric             "Dumps renderscript specific information for all modules.",
40110b57cec5SDimitry Andric             "renderscript module dump",
40120b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
40130b57cec5SDimitry Andric 
40140b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeModuleDump() override = default;
40150b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)40160b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
40170b57cec5SDimitry Andric     RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>(
40180b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
40190b57cec5SDimitry Andric             eLanguageTypeExtRenderScript));
40200b57cec5SDimitry Andric     runtime->DumpModules(result.GetOutputStream());
40210b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
40220b57cec5SDimitry Andric     return true;
40230b57cec5SDimitry Andric   }
40240b57cec5SDimitry Andric };
40250b57cec5SDimitry Andric 
40260b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword {
40270b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeModule(CommandInterpreter & interpreter)40280b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter)
40290b57cec5SDimitry Andric       : CommandObjectMultiword(interpreter, "renderscript module",
40300b57cec5SDimitry Andric                                "Commands that deal with RenderScript modules.",
40310b57cec5SDimitry Andric                                nullptr) {
40320b57cec5SDimitry Andric     LoadSubCommand(
40330b57cec5SDimitry Andric         "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump(
40340b57cec5SDimitry Andric                     interpreter)));
40350b57cec5SDimitry Andric   }
40360b57cec5SDimitry Andric 
40370b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeModule() override = default;
40380b57cec5SDimitry Andric };
40390b57cec5SDimitry Andric 
40400b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed {
40410b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter & interpreter)40420b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter)
40430b57cec5SDimitry Andric       : CommandObjectParsed(
40440b57cec5SDimitry Andric             interpreter, "renderscript kernel list",
40450b57cec5SDimitry Andric             "Lists renderscript kernel names and associated script resources.",
40460b57cec5SDimitry Andric             "renderscript kernel list",
40470b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
40480b57cec5SDimitry Andric 
40490b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeKernelList() override = default;
40500b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)40510b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
40520b57cec5SDimitry Andric     RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>(
40530b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
40540b57cec5SDimitry Andric             eLanguageTypeExtRenderScript));
40550b57cec5SDimitry Andric     runtime->DumpKernels(result.GetOutputStream());
40560b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
40570b57cec5SDimitry Andric     return true;
40580b57cec5SDimitry Andric   }
40590b57cec5SDimitry Andric };
40600b57cec5SDimitry Andric 
40610b57cec5SDimitry Andric static constexpr OptionDefinition g_renderscript_reduction_bp_set_options[] = {
40620b57cec5SDimitry Andric     {LLDB_OPT_SET_1, false, "function-role", 't',
40630b57cec5SDimitry Andric      OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOneLiner,
40640b57cec5SDimitry Andric      "Break on a comma separated set of reduction kernel types "
40650b57cec5SDimitry Andric      "(accumulator,outcoverter,combiner,initializer"},
40660b57cec5SDimitry Andric     {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument,
40670b57cec5SDimitry Andric      nullptr, {}, 0, eArgTypeValue,
40680b57cec5SDimitry Andric      "Set a breakpoint on a single invocation of the kernel with specified "
40690b57cec5SDimitry Andric      "coordinate.\n"
40700b57cec5SDimitry Andric      "Coordinate takes the form 'x[,y][,z] where x,y,z are positive "
40710b57cec5SDimitry Andric      "integers representing kernel dimensions. "
40720b57cec5SDimitry Andric      "Any unset dimensions will be defaulted to zero."}};
40730b57cec5SDimitry Andric 
40740b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeReductionBreakpointSet
40750b57cec5SDimitry Andric     : public CommandObjectParsed {
40760b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeReductionBreakpointSet(CommandInterpreter & interpreter)40770b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeReductionBreakpointSet(
40780b57cec5SDimitry Andric       CommandInterpreter &interpreter)
40790b57cec5SDimitry Andric       : CommandObjectParsed(
40800b57cec5SDimitry Andric             interpreter, "renderscript reduction breakpoint set",
40810b57cec5SDimitry Andric             "Set a breakpoint on named RenderScript general reductions",
40820b57cec5SDimitry Andric             "renderscript reduction breakpoint set  <kernel_name> [-t "
40830b57cec5SDimitry Andric             "<reduction_kernel_type,...>]",
40840b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
40850b57cec5SDimitry Andric                 eCommandProcessMustBePaused),
40860b57cec5SDimitry Andric         m_options(){};
40870b57cec5SDimitry Andric 
40880b57cec5SDimitry Andric   class CommandOptions : public Options {
40890b57cec5SDimitry Andric   public:
CommandOptions()4090*5f7ddb14SDimitry Andric     CommandOptions() : Options() {}
40910b57cec5SDimitry Andric 
40920b57cec5SDimitry Andric     ~CommandOptions() override = default;
40930b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * exe_ctx)40940b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
40950b57cec5SDimitry Andric                           ExecutionContext *exe_ctx) override {
40960b57cec5SDimitry Andric       Status err;
40970b57cec5SDimitry Andric       StreamString err_str;
40980b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
40990b57cec5SDimitry Andric       switch (short_option) {
41000b57cec5SDimitry Andric       case 't':
41010b57cec5SDimitry Andric         if (!ParseReductionTypes(option_arg, err_str))
41020b57cec5SDimitry Andric           err.SetErrorStringWithFormat(
41030b57cec5SDimitry Andric               "Unable to deduce reduction types for %s: %s",
41040b57cec5SDimitry Andric               option_arg.str().c_str(), err_str.GetData());
41050b57cec5SDimitry Andric         break;
41060b57cec5SDimitry Andric       case 'c': {
41070b57cec5SDimitry Andric         auto coord = RSCoordinate{};
41080b57cec5SDimitry Andric         if (!ParseCoordinate(option_arg, coord))
41090b57cec5SDimitry Andric           err.SetErrorStringWithFormat("unable to parse coordinate for %s",
41100b57cec5SDimitry Andric                                        option_arg.str().c_str());
41110b57cec5SDimitry Andric         else {
41120b57cec5SDimitry Andric           m_have_coord = true;
41130b57cec5SDimitry Andric           m_coord = coord;
41140b57cec5SDimitry Andric         }
41150b57cec5SDimitry Andric         break;
41160b57cec5SDimitry Andric       }
41170b57cec5SDimitry Andric       default:
41180b57cec5SDimitry Andric         err.SetErrorStringWithFormat("Invalid option '-%c'", short_option);
41190b57cec5SDimitry Andric       }
41200b57cec5SDimitry Andric       return err;
41210b57cec5SDimitry Andric     }
41220b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * exe_ctx)41230b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *exe_ctx) override {
41240b57cec5SDimitry Andric       m_have_coord = false;
41250b57cec5SDimitry Andric     }
41260b57cec5SDimitry Andric 
GetDefinitions()41270b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
41280b57cec5SDimitry Andric       return llvm::makeArrayRef(g_renderscript_reduction_bp_set_options);
41290b57cec5SDimitry Andric     }
41300b57cec5SDimitry Andric 
ParseReductionTypes(llvm::StringRef option_val,StreamString & err_str)41310b57cec5SDimitry Andric     bool ParseReductionTypes(llvm::StringRef option_val,
41320b57cec5SDimitry Andric                              StreamString &err_str) {
41330b57cec5SDimitry Andric       m_kernel_types = RSReduceBreakpointResolver::eKernelTypeNone;
41340b57cec5SDimitry Andric       const auto reduce_name_to_type = [](llvm::StringRef name) -> int {
41350b57cec5SDimitry Andric         return llvm::StringSwitch<int>(name)
41360b57cec5SDimitry Andric             .Case("accumulator", RSReduceBreakpointResolver::eKernelTypeAccum)
41370b57cec5SDimitry Andric             .Case("initializer", RSReduceBreakpointResolver::eKernelTypeInit)
41380b57cec5SDimitry Andric             .Case("outconverter", RSReduceBreakpointResolver::eKernelTypeOutC)
41390b57cec5SDimitry Andric             .Case("combiner", RSReduceBreakpointResolver::eKernelTypeComb)
41400b57cec5SDimitry Andric             .Case("all", RSReduceBreakpointResolver::eKernelTypeAll)
41410b57cec5SDimitry Andric             // Currently not exposed by the runtime
41420b57cec5SDimitry Andric             // .Case("halter", RSReduceBreakpointResolver::eKernelTypeHalter)
41430b57cec5SDimitry Andric             .Default(0);
41440b57cec5SDimitry Andric       };
41450b57cec5SDimitry Andric 
41460b57cec5SDimitry Andric       // Matching a comma separated list of known words is fairly
41470b57cec5SDimitry Andric       // straightforward with PCRE, but we're using ERE, so we end up with a
41480b57cec5SDimitry Andric       // little ugliness...
41490b57cec5SDimitry Andric       RegularExpression match_type_list(
41500b57cec5SDimitry Andric           llvm::StringRef("^([[:alpha:]]+)(,[[:alpha:]]+){0,4}$"));
41510b57cec5SDimitry Andric 
41520b57cec5SDimitry Andric       assert(match_type_list.IsValid());
41530b57cec5SDimitry Andric 
41549dba64beSDimitry Andric       if (!match_type_list.Execute(option_val)) {
41550b57cec5SDimitry Andric         err_str.PutCString(
41560b57cec5SDimitry Andric             "a comma-separated list of kernel types is required");
41570b57cec5SDimitry Andric         return false;
41580b57cec5SDimitry Andric       }
41590b57cec5SDimitry Andric 
41600b57cec5SDimitry Andric       // splitting on commas is much easier with llvm::StringRef than regex
41610b57cec5SDimitry Andric       llvm::SmallVector<llvm::StringRef, 5> type_names;
41620b57cec5SDimitry Andric       llvm::StringRef(option_val).split(type_names, ',');
41630b57cec5SDimitry Andric 
41640b57cec5SDimitry Andric       for (const auto &name : type_names) {
41650b57cec5SDimitry Andric         const int type = reduce_name_to_type(name);
41660b57cec5SDimitry Andric         if (!type) {
41670b57cec5SDimitry Andric           err_str.Printf("unknown kernel type name %s", name.str().c_str());
41680b57cec5SDimitry Andric           return false;
41690b57cec5SDimitry Andric         }
41700b57cec5SDimitry Andric         m_kernel_types |= type;
41710b57cec5SDimitry Andric       }
41720b57cec5SDimitry Andric 
41730b57cec5SDimitry Andric       return true;
41740b57cec5SDimitry Andric     }
41750b57cec5SDimitry Andric 
4176*5f7ddb14SDimitry Andric     int m_kernel_types = RSReduceBreakpointResolver::eKernelTypeAll;
41770b57cec5SDimitry Andric     llvm::StringRef m_reduce_name;
41780b57cec5SDimitry Andric     RSCoordinate m_coord;
41790b57cec5SDimitry Andric     bool m_have_coord;
41800b57cec5SDimitry Andric   };
41810b57cec5SDimitry Andric 
GetOptions()41820b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
41830b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)41840b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
41850b57cec5SDimitry Andric     const size_t argc = command.GetArgumentCount();
41860b57cec5SDimitry Andric     if (argc < 1) {
41870b57cec5SDimitry Andric       result.AppendErrorWithFormat("'%s' takes 1 argument of reduction name, "
41880b57cec5SDimitry Andric                                    "and an optional kernel type list",
41890b57cec5SDimitry Andric                                    m_cmd_name.c_str());
41900b57cec5SDimitry Andric       return false;
41910b57cec5SDimitry Andric     }
41920b57cec5SDimitry Andric 
41930b57cec5SDimitry Andric     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
41940b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
41950b57cec5SDimitry Andric             eLanguageTypeExtRenderScript));
41960b57cec5SDimitry Andric 
41970b57cec5SDimitry Andric     auto &outstream = result.GetOutputStream();
41980b57cec5SDimitry Andric     auto name = command.GetArgumentAtIndex(0);
41990b57cec5SDimitry Andric     auto &target = m_exe_ctx.GetTargetSP();
42000b57cec5SDimitry Andric     auto coord = m_options.m_have_coord ? &m_options.m_coord : nullptr;
42010b57cec5SDimitry Andric     if (!runtime->PlaceBreakpointOnReduction(target, outstream, name, coord,
42020b57cec5SDimitry Andric                                              m_options.m_kernel_types)) {
42030b57cec5SDimitry Andric       result.AppendError("Error: unable to place breakpoint on reduction");
42040b57cec5SDimitry Andric       return false;
42050b57cec5SDimitry Andric     }
42060b57cec5SDimitry Andric     result.AppendMessage("Breakpoint(s) created");
42070b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
42080b57cec5SDimitry Andric     return true;
42090b57cec5SDimitry Andric   }
42100b57cec5SDimitry Andric 
42110b57cec5SDimitry Andric private:
42120b57cec5SDimitry Andric   CommandOptions m_options;
42130b57cec5SDimitry Andric };
42140b57cec5SDimitry Andric 
42150b57cec5SDimitry Andric static constexpr OptionDefinition g_renderscript_kernel_bp_set_options[] = {
42160b57cec5SDimitry Andric     {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument,
42170b57cec5SDimitry Andric      nullptr, {}, 0, eArgTypeValue,
42180b57cec5SDimitry Andric      "Set a breakpoint on a single invocation of the kernel with specified "
42190b57cec5SDimitry Andric      "coordinate.\n"
42200b57cec5SDimitry Andric      "Coordinate takes the form 'x[,y][,z] where x,y,z are positive "
42210b57cec5SDimitry Andric      "integers representing kernel dimensions. "
42220b57cec5SDimitry Andric      "Any unset dimensions will be defaulted to zero."}};
42230b57cec5SDimitry Andric 
42240b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeKernelBreakpointSet
42250b57cec5SDimitry Andric     : public CommandObjectParsed {
42260b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeKernelBreakpointSet(CommandInterpreter & interpreter)42270b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeKernelBreakpointSet(
42280b57cec5SDimitry Andric       CommandInterpreter &interpreter)
42290b57cec5SDimitry Andric       : CommandObjectParsed(
42300b57cec5SDimitry Andric             interpreter, "renderscript kernel breakpoint set",
42310b57cec5SDimitry Andric             "Sets a breakpoint on a renderscript kernel.",
42320b57cec5SDimitry Andric             "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]",
42330b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
42340b57cec5SDimitry Andric                 eCommandProcessMustBePaused),
42350b57cec5SDimitry Andric         m_options() {}
42360b57cec5SDimitry Andric 
42370b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default;
42380b57cec5SDimitry Andric 
GetOptions()42390b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
42400b57cec5SDimitry Andric 
42410b57cec5SDimitry Andric   class CommandOptions : public Options {
42420b57cec5SDimitry Andric   public:
CommandOptions()42430b57cec5SDimitry Andric     CommandOptions() : Options() {}
42440b57cec5SDimitry Andric 
42450b57cec5SDimitry Andric     ~CommandOptions() override = default;
42460b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * exe_ctx)42470b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
42480b57cec5SDimitry Andric                           ExecutionContext *exe_ctx) override {
42490b57cec5SDimitry Andric       Status err;
42500b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
42510b57cec5SDimitry Andric 
42520b57cec5SDimitry Andric       switch (short_option) {
42530b57cec5SDimitry Andric       case 'c': {
42540b57cec5SDimitry Andric         auto coord = RSCoordinate{};
42550b57cec5SDimitry Andric         if (!ParseCoordinate(option_arg, coord))
42560b57cec5SDimitry Andric           err.SetErrorStringWithFormat(
42570b57cec5SDimitry Andric               "Couldn't parse coordinate '%s', should be in format 'x,y,z'.",
42580b57cec5SDimitry Andric               option_arg.str().c_str());
42590b57cec5SDimitry Andric         else {
42600b57cec5SDimitry Andric           m_have_coord = true;
42610b57cec5SDimitry Andric           m_coord = coord;
42620b57cec5SDimitry Andric         }
42630b57cec5SDimitry Andric         break;
42640b57cec5SDimitry Andric       }
42650b57cec5SDimitry Andric       default:
42660b57cec5SDimitry Andric         err.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
42670b57cec5SDimitry Andric         break;
42680b57cec5SDimitry Andric       }
42690b57cec5SDimitry Andric       return err;
42700b57cec5SDimitry Andric     }
42710b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * exe_ctx)42720b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *exe_ctx) override {
42730b57cec5SDimitry Andric       m_have_coord = false;
42740b57cec5SDimitry Andric     }
42750b57cec5SDimitry Andric 
GetDefinitions()42760b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
42770b57cec5SDimitry Andric       return llvm::makeArrayRef(g_renderscript_kernel_bp_set_options);
42780b57cec5SDimitry Andric     }
42790b57cec5SDimitry Andric 
42800b57cec5SDimitry Andric     RSCoordinate m_coord;
42810b57cec5SDimitry Andric     bool m_have_coord;
42820b57cec5SDimitry Andric   };
42830b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)42840b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
42850b57cec5SDimitry Andric     const size_t argc = command.GetArgumentCount();
42860b57cec5SDimitry Andric     if (argc < 1) {
42870b57cec5SDimitry Andric       result.AppendErrorWithFormat(
42880b57cec5SDimitry Andric           "'%s' takes 1 argument of kernel name, and an optional coordinate.",
42890b57cec5SDimitry Andric           m_cmd_name.c_str());
42900b57cec5SDimitry Andric       return false;
42910b57cec5SDimitry Andric     }
42920b57cec5SDimitry Andric 
42930b57cec5SDimitry Andric     RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>(
42940b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
42950b57cec5SDimitry Andric             eLanguageTypeExtRenderScript));
42960b57cec5SDimitry Andric 
42970b57cec5SDimitry Andric     auto &outstream = result.GetOutputStream();
42980b57cec5SDimitry Andric     auto &target = m_exe_ctx.GetTargetSP();
42990b57cec5SDimitry Andric     auto name = command.GetArgumentAtIndex(0);
43000b57cec5SDimitry Andric     auto coord = m_options.m_have_coord ? &m_options.m_coord : nullptr;
43010b57cec5SDimitry Andric     if (!runtime->PlaceBreakpointOnKernel(target, outstream, name, coord)) {
43020b57cec5SDimitry Andric       result.AppendErrorWithFormat(
43030b57cec5SDimitry Andric           "Error: unable to set breakpoint on kernel '%s'", name);
43040b57cec5SDimitry Andric       return false;
43050b57cec5SDimitry Andric     }
43060b57cec5SDimitry Andric 
43070b57cec5SDimitry Andric     result.AppendMessage("Breakpoint(s) created");
43080b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
43090b57cec5SDimitry Andric     return true;
43100b57cec5SDimitry Andric   }
43110b57cec5SDimitry Andric 
43120b57cec5SDimitry Andric private:
43130b57cec5SDimitry Andric   CommandOptions m_options;
43140b57cec5SDimitry Andric };
43150b57cec5SDimitry Andric 
43160b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeKernelBreakpointAll
43170b57cec5SDimitry Andric     : public CommandObjectParsed {
43180b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeKernelBreakpointAll(CommandInterpreter & interpreter)43190b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeKernelBreakpointAll(
43200b57cec5SDimitry Andric       CommandInterpreter &interpreter)
43210b57cec5SDimitry Andric       : CommandObjectParsed(
43220b57cec5SDimitry Andric             interpreter, "renderscript kernel breakpoint all",
43230b57cec5SDimitry Andric             "Automatically sets a breakpoint on all renderscript kernels that "
43240b57cec5SDimitry Andric             "are or will be loaded.\n"
43250b57cec5SDimitry Andric             "Disabling option means breakpoints will no longer be set on any "
43260b57cec5SDimitry Andric             "kernels loaded in the future, "
43270b57cec5SDimitry Andric             "but does not remove currently set breakpoints.",
43280b57cec5SDimitry Andric             "renderscript kernel breakpoint all <enable/disable>",
43290b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
43300b57cec5SDimitry Andric                 eCommandProcessMustBePaused) {}
43310b57cec5SDimitry Andric 
43320b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default;
43330b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)43340b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
43350b57cec5SDimitry Andric     const size_t argc = command.GetArgumentCount();
43360b57cec5SDimitry Andric     if (argc != 1) {
43370b57cec5SDimitry Andric       result.AppendErrorWithFormat(
43380b57cec5SDimitry Andric           "'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str());
43390b57cec5SDimitry Andric       return false;
43400b57cec5SDimitry Andric     }
43410b57cec5SDimitry Andric 
43420b57cec5SDimitry Andric     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
43430b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
43440b57cec5SDimitry Andric             eLanguageTypeExtRenderScript));
43450b57cec5SDimitry Andric 
43460b57cec5SDimitry Andric     bool do_break = false;
43470b57cec5SDimitry Andric     const char *argument = command.GetArgumentAtIndex(0);
43480b57cec5SDimitry Andric     if (strcmp(argument, "enable") == 0) {
43490b57cec5SDimitry Andric       do_break = true;
43500b57cec5SDimitry Andric       result.AppendMessage("Breakpoints will be set on all kernels.");
43510b57cec5SDimitry Andric     } else if (strcmp(argument, "disable") == 0) {
43520b57cec5SDimitry Andric       do_break = false;
43530b57cec5SDimitry Andric       result.AppendMessage("Breakpoints will not be set on any new kernels.");
43540b57cec5SDimitry Andric     } else {
43550b57cec5SDimitry Andric       result.AppendErrorWithFormat(
43560b57cec5SDimitry Andric           "Argument must be either 'enable' or 'disable'");
43570b57cec5SDimitry Andric       return false;
43580b57cec5SDimitry Andric     }
43590b57cec5SDimitry Andric 
43600b57cec5SDimitry Andric     runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP());
43610b57cec5SDimitry Andric 
43620b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
43630b57cec5SDimitry Andric     return true;
43640b57cec5SDimitry Andric   }
43650b57cec5SDimitry Andric };
43660b57cec5SDimitry Andric 
43670b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeReductionBreakpoint
43680b57cec5SDimitry Andric     : public CommandObjectMultiword {
43690b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeReductionBreakpoint(CommandInterpreter & interpreter)43700b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeReductionBreakpoint(
43710b57cec5SDimitry Andric       CommandInterpreter &interpreter)
43720b57cec5SDimitry Andric       : CommandObjectMultiword(interpreter, "renderscript reduction breakpoint",
43730b57cec5SDimitry Andric                                "Commands that manipulate breakpoints on "
43740b57cec5SDimitry Andric                                "renderscript general reductions.",
43750b57cec5SDimitry Andric                                nullptr) {
43760b57cec5SDimitry Andric     LoadSubCommand(
43770b57cec5SDimitry Andric         "set", CommandObjectSP(
43780b57cec5SDimitry Andric                    new CommandObjectRenderScriptRuntimeReductionBreakpointSet(
43790b57cec5SDimitry Andric                        interpreter)));
43800b57cec5SDimitry Andric   }
43810b57cec5SDimitry Andric 
43820b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeReductionBreakpoint() override = default;
43830b57cec5SDimitry Andric };
43840b57cec5SDimitry Andric 
43850b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeKernelCoordinate
43860b57cec5SDimitry Andric     : public CommandObjectParsed {
43870b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeKernelCoordinate(CommandInterpreter & interpreter)43880b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeKernelCoordinate(
43890b57cec5SDimitry Andric       CommandInterpreter &interpreter)
43900b57cec5SDimitry Andric       : CommandObjectParsed(
43910b57cec5SDimitry Andric             interpreter, "renderscript kernel coordinate",
43920b57cec5SDimitry Andric             "Shows the (x,y,z) coordinate of the current kernel invocation.",
43930b57cec5SDimitry Andric             "renderscript kernel coordinate",
43940b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandProcessMustBeLaunched |
43950b57cec5SDimitry Andric                 eCommandProcessMustBePaused) {}
43960b57cec5SDimitry Andric 
43970b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeKernelCoordinate() override = default;
43980b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)43990b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
44000b57cec5SDimitry Andric     RSCoordinate coord{};
44010b57cec5SDimitry Andric     bool success = RenderScriptRuntime::GetKernelCoordinate(
44020b57cec5SDimitry Andric         coord, m_exe_ctx.GetThreadPtr());
44030b57cec5SDimitry Andric     Stream &stream = result.GetOutputStream();
44040b57cec5SDimitry Andric 
44050b57cec5SDimitry Andric     if (success) {
44060b57cec5SDimitry Andric       stream.Printf("Coordinate: " FMT_COORD, coord.x, coord.y, coord.z);
44070b57cec5SDimitry Andric       stream.EOL();
44080b57cec5SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishResult);
44090b57cec5SDimitry Andric     } else {
44100b57cec5SDimitry Andric       stream.Printf("Error: Coordinate could not be found.");
44110b57cec5SDimitry Andric       stream.EOL();
44120b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
44130b57cec5SDimitry Andric     }
44140b57cec5SDimitry Andric     return true;
44150b57cec5SDimitry Andric   }
44160b57cec5SDimitry Andric };
44170b57cec5SDimitry Andric 
44180b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeKernelBreakpoint
44190b57cec5SDimitry Andric     : public CommandObjectMultiword {
44200b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeKernelBreakpoint(CommandInterpreter & interpreter)44210b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeKernelBreakpoint(
44220b57cec5SDimitry Andric       CommandInterpreter &interpreter)
44230b57cec5SDimitry Andric       : CommandObjectMultiword(
44240b57cec5SDimitry Andric             interpreter, "renderscript kernel",
44250b57cec5SDimitry Andric             "Commands that generate breakpoints on renderscript kernels.",
44260b57cec5SDimitry Andric             nullptr) {
44270b57cec5SDimitry Andric     LoadSubCommand(
44280b57cec5SDimitry Andric         "set",
44290b57cec5SDimitry Andric         CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet(
44300b57cec5SDimitry Andric             interpreter)));
44310b57cec5SDimitry Andric     LoadSubCommand(
44320b57cec5SDimitry Andric         "all",
44330b57cec5SDimitry Andric         CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll(
44340b57cec5SDimitry Andric             interpreter)));
44350b57cec5SDimitry Andric   }
44360b57cec5SDimitry Andric 
44370b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default;
44380b57cec5SDimitry Andric };
44390b57cec5SDimitry Andric 
44400b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword {
44410b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeKernel(CommandInterpreter & interpreter)44420b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter)
44430b57cec5SDimitry Andric       : CommandObjectMultiword(interpreter, "renderscript kernel",
44440b57cec5SDimitry Andric                                "Commands that deal with RenderScript kernels.",
44450b57cec5SDimitry Andric                                nullptr) {
44460b57cec5SDimitry Andric     LoadSubCommand(
44470b57cec5SDimitry Andric         "list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList(
44480b57cec5SDimitry Andric                     interpreter)));
44490b57cec5SDimitry Andric     LoadSubCommand(
44500b57cec5SDimitry Andric         "coordinate",
44510b57cec5SDimitry Andric         CommandObjectSP(
44520b57cec5SDimitry Andric             new CommandObjectRenderScriptRuntimeKernelCoordinate(interpreter)));
44530b57cec5SDimitry Andric     LoadSubCommand(
44540b57cec5SDimitry Andric         "breakpoint",
44550b57cec5SDimitry Andric         CommandObjectSP(
44560b57cec5SDimitry Andric             new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter)));
44570b57cec5SDimitry Andric   }
44580b57cec5SDimitry Andric 
44590b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeKernel() override = default;
44600b57cec5SDimitry Andric };
44610b57cec5SDimitry Andric 
44620b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed {
44630b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter & interpreter)44640b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter)
44650b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "renderscript context dump",
44660b57cec5SDimitry Andric                             "Dumps renderscript context information.",
44670b57cec5SDimitry Andric                             "renderscript context dump",
44680b57cec5SDimitry Andric                             eCommandRequiresProcess |
44690b57cec5SDimitry Andric                                 eCommandProcessMustBeLaunched) {}
44700b57cec5SDimitry Andric 
44710b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeContextDump() override = default;
44720b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)44730b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
44740b57cec5SDimitry Andric     RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>(
44750b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
44760b57cec5SDimitry Andric             eLanguageTypeExtRenderScript));
44770b57cec5SDimitry Andric     runtime->DumpContexts(result.GetOutputStream());
44780b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
44790b57cec5SDimitry Andric     return true;
44800b57cec5SDimitry Andric   }
44810b57cec5SDimitry Andric };
44820b57cec5SDimitry Andric 
44830b57cec5SDimitry Andric static constexpr OptionDefinition g_renderscript_runtime_alloc_dump_options[] = {
44840b57cec5SDimitry Andric     {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument,
44850b57cec5SDimitry Andric      nullptr, {}, 0, eArgTypeFilename,
44860b57cec5SDimitry Andric      "Print results to specified file instead of command line."}};
44870b57cec5SDimitry Andric 
44880b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword {
44890b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeContext(CommandInterpreter & interpreter)44900b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter)
44910b57cec5SDimitry Andric       : CommandObjectMultiword(interpreter, "renderscript context",
44920b57cec5SDimitry Andric                                "Commands that deal with RenderScript contexts.",
44930b57cec5SDimitry Andric                                nullptr) {
44940b57cec5SDimitry Andric     LoadSubCommand(
44950b57cec5SDimitry Andric         "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump(
44960b57cec5SDimitry Andric                     interpreter)));
44970b57cec5SDimitry Andric   }
44980b57cec5SDimitry Andric 
44990b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeContext() override = default;
45000b57cec5SDimitry Andric };
45010b57cec5SDimitry Andric 
45020b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeAllocationDump
45030b57cec5SDimitry Andric     : public CommandObjectParsed {
45040b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeAllocationDump(CommandInterpreter & interpreter)45050b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeAllocationDump(
45060b57cec5SDimitry Andric       CommandInterpreter &interpreter)
45070b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "renderscript allocation dump",
45080b57cec5SDimitry Andric                             "Displays the contents of a particular allocation",
45090b57cec5SDimitry Andric                             "renderscript allocation dump <ID>",
45100b57cec5SDimitry Andric                             eCommandRequiresProcess |
45110b57cec5SDimitry Andric                                 eCommandProcessMustBeLaunched),
45120b57cec5SDimitry Andric         m_options() {}
45130b57cec5SDimitry Andric 
45140b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeAllocationDump() override = default;
45150b57cec5SDimitry Andric 
GetOptions()45160b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
45170b57cec5SDimitry Andric 
45180b57cec5SDimitry Andric   class CommandOptions : public Options {
45190b57cec5SDimitry Andric   public:
CommandOptions()45200b57cec5SDimitry Andric     CommandOptions() : Options() {}
45210b57cec5SDimitry Andric 
45220b57cec5SDimitry Andric     ~CommandOptions() override = default;
45230b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * exe_ctx)45240b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
45250b57cec5SDimitry Andric                           ExecutionContext *exe_ctx) override {
45260b57cec5SDimitry Andric       Status err;
45270b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
45280b57cec5SDimitry Andric 
45290b57cec5SDimitry Andric       switch (short_option) {
45300b57cec5SDimitry Andric       case 'f':
45310b57cec5SDimitry Andric         m_outfile.SetFile(option_arg, FileSpec::Style::native);
45320b57cec5SDimitry Andric         FileSystem::Instance().Resolve(m_outfile);
45330b57cec5SDimitry Andric         if (FileSystem::Instance().Exists(m_outfile)) {
45340b57cec5SDimitry Andric           m_outfile.Clear();
45350b57cec5SDimitry Andric           err.SetErrorStringWithFormat("file already exists: '%s'",
45360b57cec5SDimitry Andric                                        option_arg.str().c_str());
45370b57cec5SDimitry Andric         }
45380b57cec5SDimitry Andric         break;
45390b57cec5SDimitry Andric       default:
45400b57cec5SDimitry Andric         err.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
45410b57cec5SDimitry Andric         break;
45420b57cec5SDimitry Andric       }
45430b57cec5SDimitry Andric       return err;
45440b57cec5SDimitry Andric     }
45450b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * exe_ctx)45460b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *exe_ctx) override {
45470b57cec5SDimitry Andric       m_outfile.Clear();
45480b57cec5SDimitry Andric     }
45490b57cec5SDimitry Andric 
GetDefinitions()45500b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
45510b57cec5SDimitry Andric       return llvm::makeArrayRef(g_renderscript_runtime_alloc_dump_options);
45520b57cec5SDimitry Andric     }
45530b57cec5SDimitry Andric 
45540b57cec5SDimitry Andric     FileSpec m_outfile;
45550b57cec5SDimitry Andric   };
45560b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)45570b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
45580b57cec5SDimitry Andric     const size_t argc = command.GetArgumentCount();
45590b57cec5SDimitry Andric     if (argc < 1) {
45600b57cec5SDimitry Andric       result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. "
45610b57cec5SDimitry Andric                                    "As well as an optional -f argument",
45620b57cec5SDimitry Andric                                    m_cmd_name.c_str());
45630b57cec5SDimitry Andric       return false;
45640b57cec5SDimitry Andric     }
45650b57cec5SDimitry Andric 
45660b57cec5SDimitry Andric     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
45670b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
45680b57cec5SDimitry Andric             eLanguageTypeExtRenderScript));
45690b57cec5SDimitry Andric 
45700b57cec5SDimitry Andric     const char *id_cstr = command.GetArgumentAtIndex(0);
45710b57cec5SDimitry Andric     bool success = false;
45720b57cec5SDimitry Andric     const uint32_t id =
45730b57cec5SDimitry Andric         StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &success);
45740b57cec5SDimitry Andric     if (!success) {
45750b57cec5SDimitry Andric       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
45760b57cec5SDimitry Andric                                    id_cstr);
45770b57cec5SDimitry Andric       return false;
45780b57cec5SDimitry Andric     }
45790b57cec5SDimitry Andric 
45809dba64beSDimitry Andric     Stream *output_stream_p = nullptr;
45819dba64beSDimitry Andric     std::unique_ptr<Stream> output_stream_storage;
45829dba64beSDimitry Andric 
45830b57cec5SDimitry Andric     const FileSpec &outfile_spec =
45840b57cec5SDimitry Andric         m_options.m_outfile; // Dump allocation to file instead
45850b57cec5SDimitry Andric     if (outfile_spec) {
45860b57cec5SDimitry Andric       // Open output file
45870b57cec5SDimitry Andric       std::string path = outfile_spec.GetPath();
45889dba64beSDimitry Andric       auto file = FileSystem::Instance().Open(
45899dba64beSDimitry Andric           outfile_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate);
45909dba64beSDimitry Andric       if (file) {
45919dba64beSDimitry Andric         output_stream_storage =
45929dba64beSDimitry Andric             std::make_unique<StreamFile>(std::move(file.get()));
45939dba64beSDimitry Andric         output_stream_p = output_stream_storage.get();
45940b57cec5SDimitry Andric         result.GetOutputStream().Printf("Results written to '%s'",
45950b57cec5SDimitry Andric                                         path.c_str());
45960b57cec5SDimitry Andric         result.GetOutputStream().EOL();
45970b57cec5SDimitry Andric       } else {
45989dba64beSDimitry Andric         std::string error = llvm::toString(file.takeError());
45999dba64beSDimitry Andric         result.AppendErrorWithFormat("Couldn't open file '%s': %s",
46009dba64beSDimitry Andric                                      path.c_str(), error.c_str());
46010b57cec5SDimitry Andric         return false;
46020b57cec5SDimitry Andric       }
46030b57cec5SDimitry Andric     } else
46049dba64beSDimitry Andric       output_stream_p = &result.GetOutputStream();
46050b57cec5SDimitry Andric 
46069dba64beSDimitry Andric     assert(output_stream_p != nullptr);
46070b57cec5SDimitry Andric     bool dumped =
46089dba64beSDimitry Andric         runtime->DumpAllocation(*output_stream_p, m_exe_ctx.GetFramePtr(), id);
46090b57cec5SDimitry Andric 
46100b57cec5SDimitry Andric     if (dumped)
46110b57cec5SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishResult);
46120b57cec5SDimitry Andric     else
46130b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
46140b57cec5SDimitry Andric 
46150b57cec5SDimitry Andric     return true;
46160b57cec5SDimitry Andric   }
46170b57cec5SDimitry Andric 
46180b57cec5SDimitry Andric private:
46190b57cec5SDimitry Andric   CommandOptions m_options;
46200b57cec5SDimitry Andric };
46210b57cec5SDimitry Andric 
46220b57cec5SDimitry Andric static constexpr OptionDefinition g_renderscript_runtime_alloc_list_options[] = {
46230b57cec5SDimitry Andric     {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument, nullptr,
46240b57cec5SDimitry Andric      {}, 0, eArgTypeIndex,
46250b57cec5SDimitry Andric      "Only show details of a single allocation with specified id."}};
46260b57cec5SDimitry Andric 
46270b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeAllocationList
46280b57cec5SDimitry Andric     : public CommandObjectParsed {
46290b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeAllocationList(CommandInterpreter & interpreter)46300b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeAllocationList(
46310b57cec5SDimitry Andric       CommandInterpreter &interpreter)
46320b57cec5SDimitry Andric       : CommandObjectParsed(
46330b57cec5SDimitry Andric             interpreter, "renderscript allocation list",
46340b57cec5SDimitry Andric             "List renderscript allocations and their information.",
46350b57cec5SDimitry Andric             "renderscript allocation list",
46360b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandProcessMustBeLaunched),
46370b57cec5SDimitry Andric         m_options() {}
46380b57cec5SDimitry Andric 
46390b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeAllocationList() override = default;
46400b57cec5SDimitry Andric 
GetOptions()46410b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
46420b57cec5SDimitry Andric 
46430b57cec5SDimitry Andric   class CommandOptions : public Options {
46440b57cec5SDimitry Andric   public:
CommandOptions()4645*5f7ddb14SDimitry Andric     CommandOptions() : Options() {}
46460b57cec5SDimitry Andric 
46470b57cec5SDimitry Andric     ~CommandOptions() override = default;
46480b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * exe_ctx)46490b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
46500b57cec5SDimitry Andric                           ExecutionContext *exe_ctx) override {
46510b57cec5SDimitry Andric       Status err;
46520b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
46530b57cec5SDimitry Andric 
46540b57cec5SDimitry Andric       switch (short_option) {
46550b57cec5SDimitry Andric       case 'i':
46560b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, m_id))
46570b57cec5SDimitry Andric           err.SetErrorStringWithFormat("invalid integer value for option '%c'",
46580b57cec5SDimitry Andric                                        short_option);
46590b57cec5SDimitry Andric         break;
46600b57cec5SDimitry Andric       default:
46610b57cec5SDimitry Andric         err.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
46620b57cec5SDimitry Andric         break;
46630b57cec5SDimitry Andric       }
46640b57cec5SDimitry Andric       return err;
46650b57cec5SDimitry Andric     }
46660b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * exe_ctx)46670b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *exe_ctx) override { m_id = 0; }
46680b57cec5SDimitry Andric 
GetDefinitions()46690b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
46700b57cec5SDimitry Andric       return llvm::makeArrayRef(g_renderscript_runtime_alloc_list_options);
46710b57cec5SDimitry Andric     }
46720b57cec5SDimitry Andric 
4673*5f7ddb14SDimitry Andric     uint32_t m_id = 0;
46740b57cec5SDimitry Andric   };
46750b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)46760b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
46770b57cec5SDimitry Andric     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
46780b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
46790b57cec5SDimitry Andric             eLanguageTypeExtRenderScript));
46800b57cec5SDimitry Andric     runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(),
46810b57cec5SDimitry Andric                              m_options.m_id);
46820b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
46830b57cec5SDimitry Andric     return true;
46840b57cec5SDimitry Andric   }
46850b57cec5SDimitry Andric 
46860b57cec5SDimitry Andric private:
46870b57cec5SDimitry Andric   CommandOptions m_options;
46880b57cec5SDimitry Andric };
46890b57cec5SDimitry Andric 
46900b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeAllocationLoad
46910b57cec5SDimitry Andric     : public CommandObjectParsed {
46920b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeAllocationLoad(CommandInterpreter & interpreter)46930b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeAllocationLoad(
46940b57cec5SDimitry Andric       CommandInterpreter &interpreter)
46950b57cec5SDimitry Andric       : CommandObjectParsed(
46960b57cec5SDimitry Andric             interpreter, "renderscript allocation load",
46970b57cec5SDimitry Andric             "Loads renderscript allocation contents from a file.",
46980b57cec5SDimitry Andric             "renderscript allocation load <ID> <filename>",
46990b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
47000b57cec5SDimitry Andric 
47010b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default;
47020b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)47030b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
47040b57cec5SDimitry Andric     const size_t argc = command.GetArgumentCount();
47050b57cec5SDimitry Andric     if (argc != 2) {
47060b57cec5SDimitry Andric       result.AppendErrorWithFormat(
47070b57cec5SDimitry Andric           "'%s' takes 2 arguments, an allocation ID and filename to read from.",
47080b57cec5SDimitry Andric           m_cmd_name.c_str());
47090b57cec5SDimitry Andric       return false;
47100b57cec5SDimitry Andric     }
47110b57cec5SDimitry Andric 
47120b57cec5SDimitry Andric     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
47130b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
47140b57cec5SDimitry Andric             eLanguageTypeExtRenderScript));
47150b57cec5SDimitry Andric 
47160b57cec5SDimitry Andric     const char *id_cstr = command.GetArgumentAtIndex(0);
47170b57cec5SDimitry Andric     bool success = false;
47180b57cec5SDimitry Andric     const uint32_t id =
47190b57cec5SDimitry Andric         StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &success);
47200b57cec5SDimitry Andric     if (!success) {
47210b57cec5SDimitry Andric       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
47220b57cec5SDimitry Andric                                    id_cstr);
47230b57cec5SDimitry Andric       return false;
47240b57cec5SDimitry Andric     }
47250b57cec5SDimitry Andric 
47260b57cec5SDimitry Andric     const char *path = command.GetArgumentAtIndex(1);
47270b57cec5SDimitry Andric     bool loaded = runtime->LoadAllocation(result.GetOutputStream(), id, path,
47280b57cec5SDimitry Andric                                           m_exe_ctx.GetFramePtr());
47290b57cec5SDimitry Andric 
47300b57cec5SDimitry Andric     if (loaded)
47310b57cec5SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishResult);
47320b57cec5SDimitry Andric     else
47330b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
47340b57cec5SDimitry Andric 
47350b57cec5SDimitry Andric     return true;
47360b57cec5SDimitry Andric   }
47370b57cec5SDimitry Andric };
47380b57cec5SDimitry Andric 
47390b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeAllocationSave
47400b57cec5SDimitry Andric     : public CommandObjectParsed {
47410b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeAllocationSave(CommandInterpreter & interpreter)47420b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeAllocationSave(
47430b57cec5SDimitry Andric       CommandInterpreter &interpreter)
47440b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "renderscript allocation save",
47450b57cec5SDimitry Andric                             "Write renderscript allocation contents to a file.",
47460b57cec5SDimitry Andric                             "renderscript allocation save <ID> <filename>",
47470b57cec5SDimitry Andric                             eCommandRequiresProcess |
47480b57cec5SDimitry Andric                                 eCommandProcessMustBeLaunched) {}
47490b57cec5SDimitry Andric 
47500b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeAllocationSave() override = default;
47510b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)47520b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
47530b57cec5SDimitry Andric     const size_t argc = command.GetArgumentCount();
47540b57cec5SDimitry Andric     if (argc != 2) {
47550b57cec5SDimitry Andric       result.AppendErrorWithFormat(
47560b57cec5SDimitry Andric           "'%s' takes 2 arguments, an allocation ID and filename to read from.",
47570b57cec5SDimitry Andric           m_cmd_name.c_str());
47580b57cec5SDimitry Andric       return false;
47590b57cec5SDimitry Andric     }
47600b57cec5SDimitry Andric 
47610b57cec5SDimitry Andric     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
47620b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
47630b57cec5SDimitry Andric             eLanguageTypeExtRenderScript));
47640b57cec5SDimitry Andric 
47650b57cec5SDimitry Andric     const char *id_cstr = command.GetArgumentAtIndex(0);
47660b57cec5SDimitry Andric     bool success = false;
47670b57cec5SDimitry Andric     const uint32_t id =
47680b57cec5SDimitry Andric         StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &success);
47690b57cec5SDimitry Andric     if (!success) {
47700b57cec5SDimitry Andric       result.AppendErrorWithFormat("invalid allocation id argument '%s'",
47710b57cec5SDimitry Andric                                    id_cstr);
47720b57cec5SDimitry Andric       return false;
47730b57cec5SDimitry Andric     }
47740b57cec5SDimitry Andric 
47750b57cec5SDimitry Andric     const char *path = command.GetArgumentAtIndex(1);
47760b57cec5SDimitry Andric     bool saved = runtime->SaveAllocation(result.GetOutputStream(), id, path,
47770b57cec5SDimitry Andric                                          m_exe_ctx.GetFramePtr());
47780b57cec5SDimitry Andric 
47790b57cec5SDimitry Andric     if (saved)
47800b57cec5SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishResult);
47810b57cec5SDimitry Andric     else
47820b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
47830b57cec5SDimitry Andric 
47840b57cec5SDimitry Andric     return true;
47850b57cec5SDimitry Andric   }
47860b57cec5SDimitry Andric };
47870b57cec5SDimitry Andric 
47880b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeAllocationRefresh
47890b57cec5SDimitry Andric     : public CommandObjectParsed {
47900b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeAllocationRefresh(CommandInterpreter & interpreter)47910b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeAllocationRefresh(
47920b57cec5SDimitry Andric       CommandInterpreter &interpreter)
47930b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "renderscript allocation refresh",
47940b57cec5SDimitry Andric                             "Recomputes the details of all allocations.",
47950b57cec5SDimitry Andric                             "renderscript allocation refresh",
47960b57cec5SDimitry Andric                             eCommandRequiresProcess |
47970b57cec5SDimitry Andric                                 eCommandProcessMustBeLaunched) {}
47980b57cec5SDimitry Andric 
47990b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeAllocationRefresh() override = default;
48000b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)48010b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
48020b57cec5SDimitry Andric     RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
48030b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
48040b57cec5SDimitry Andric             eLanguageTypeExtRenderScript));
48050b57cec5SDimitry Andric 
48060b57cec5SDimitry Andric     bool success = runtime->RecomputeAllAllocations(result.GetOutputStream(),
48070b57cec5SDimitry Andric                                                     m_exe_ctx.GetFramePtr());
48080b57cec5SDimitry Andric 
48090b57cec5SDimitry Andric     if (success) {
48100b57cec5SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishResult);
48110b57cec5SDimitry Andric       return true;
48120b57cec5SDimitry Andric     } else {
48130b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
48140b57cec5SDimitry Andric       return false;
48150b57cec5SDimitry Andric     }
48160b57cec5SDimitry Andric   }
48170b57cec5SDimitry Andric };
48180b57cec5SDimitry Andric 
48190b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeAllocation
48200b57cec5SDimitry Andric     : public CommandObjectMultiword {
48210b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter & interpreter)48220b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter)
48230b57cec5SDimitry Andric       : CommandObjectMultiword(
48240b57cec5SDimitry Andric             interpreter, "renderscript allocation",
48250b57cec5SDimitry Andric             "Commands that deal with RenderScript allocations.", nullptr) {
48260b57cec5SDimitry Andric     LoadSubCommand(
48270b57cec5SDimitry Andric         "list",
48280b57cec5SDimitry Andric         CommandObjectSP(
48290b57cec5SDimitry Andric             new CommandObjectRenderScriptRuntimeAllocationList(interpreter)));
48300b57cec5SDimitry Andric     LoadSubCommand(
48310b57cec5SDimitry Andric         "dump",
48320b57cec5SDimitry Andric         CommandObjectSP(
48330b57cec5SDimitry Andric             new CommandObjectRenderScriptRuntimeAllocationDump(interpreter)));
48340b57cec5SDimitry Andric     LoadSubCommand(
48350b57cec5SDimitry Andric         "save",
48360b57cec5SDimitry Andric         CommandObjectSP(
48370b57cec5SDimitry Andric             new CommandObjectRenderScriptRuntimeAllocationSave(interpreter)));
48380b57cec5SDimitry Andric     LoadSubCommand(
48390b57cec5SDimitry Andric         "load",
48400b57cec5SDimitry Andric         CommandObjectSP(
48410b57cec5SDimitry Andric             new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter)));
48420b57cec5SDimitry Andric     LoadSubCommand(
48430b57cec5SDimitry Andric         "refresh",
48440b57cec5SDimitry Andric         CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationRefresh(
48450b57cec5SDimitry Andric             interpreter)));
48460b57cec5SDimitry Andric   }
48470b57cec5SDimitry Andric 
48480b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeAllocation() override = default;
48490b57cec5SDimitry Andric };
48500b57cec5SDimitry Andric 
48510b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed {
48520b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeStatus(CommandInterpreter & interpreter)48530b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter)
48540b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "renderscript status",
48550b57cec5SDimitry Andric                             "Displays current RenderScript runtime status.",
48560b57cec5SDimitry Andric                             "renderscript status",
48570b57cec5SDimitry Andric                             eCommandRequiresProcess |
48580b57cec5SDimitry Andric                                 eCommandProcessMustBeLaunched) {}
48590b57cec5SDimitry Andric 
48600b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeStatus() override = default;
48610b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)48620b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
48630b57cec5SDimitry Andric     RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>(
48640b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
48650b57cec5SDimitry Andric             eLanguageTypeExtRenderScript));
48660b57cec5SDimitry Andric     runtime->DumpStatus(result.GetOutputStream());
48670b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
48680b57cec5SDimitry Andric     return true;
48690b57cec5SDimitry Andric   }
48700b57cec5SDimitry Andric };
48710b57cec5SDimitry Andric 
48720b57cec5SDimitry Andric class CommandObjectRenderScriptRuntimeReduction
48730b57cec5SDimitry Andric     : public CommandObjectMultiword {
48740b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntimeReduction(CommandInterpreter & interpreter)48750b57cec5SDimitry Andric   CommandObjectRenderScriptRuntimeReduction(CommandInterpreter &interpreter)
48760b57cec5SDimitry Andric       : CommandObjectMultiword(interpreter, "renderscript reduction",
48770b57cec5SDimitry Andric                                "Commands that handle general reduction kernels",
48780b57cec5SDimitry Andric                                nullptr) {
48790b57cec5SDimitry Andric     LoadSubCommand(
48800b57cec5SDimitry Andric         "breakpoint",
48810b57cec5SDimitry Andric         CommandObjectSP(new CommandObjectRenderScriptRuntimeReductionBreakpoint(
48820b57cec5SDimitry Andric             interpreter)));
48830b57cec5SDimitry Andric   }
48840b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntimeReduction() override = default;
48850b57cec5SDimitry Andric };
48860b57cec5SDimitry Andric 
48870b57cec5SDimitry Andric class CommandObjectRenderScriptRuntime : public CommandObjectMultiword {
48880b57cec5SDimitry Andric public:
CommandObjectRenderScriptRuntime(CommandInterpreter & interpreter)48890b57cec5SDimitry Andric   CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter)
48900b57cec5SDimitry Andric       : CommandObjectMultiword(
48910b57cec5SDimitry Andric             interpreter, "renderscript",
48920b57cec5SDimitry Andric             "Commands for operating on the RenderScript runtime.",
48930b57cec5SDimitry Andric             "renderscript <subcommand> [<subcommand-options>]") {
48940b57cec5SDimitry Andric     LoadSubCommand(
48950b57cec5SDimitry Andric         "module", CommandObjectSP(
48960b57cec5SDimitry Andric                       new CommandObjectRenderScriptRuntimeModule(interpreter)));
48970b57cec5SDimitry Andric     LoadSubCommand(
48980b57cec5SDimitry Andric         "status", CommandObjectSP(
48990b57cec5SDimitry Andric                       new CommandObjectRenderScriptRuntimeStatus(interpreter)));
49000b57cec5SDimitry Andric     LoadSubCommand(
49010b57cec5SDimitry Andric         "kernel", CommandObjectSP(
49020b57cec5SDimitry Andric                       new CommandObjectRenderScriptRuntimeKernel(interpreter)));
49030b57cec5SDimitry Andric     LoadSubCommand("context",
49040b57cec5SDimitry Andric                    CommandObjectSP(new CommandObjectRenderScriptRuntimeContext(
49050b57cec5SDimitry Andric                        interpreter)));
49060b57cec5SDimitry Andric     LoadSubCommand(
49070b57cec5SDimitry Andric         "allocation",
49080b57cec5SDimitry Andric         CommandObjectSP(
49090b57cec5SDimitry Andric             new CommandObjectRenderScriptRuntimeAllocation(interpreter)));
49100b57cec5SDimitry Andric     LoadSubCommand("scriptgroup",
49110b57cec5SDimitry Andric                    NewCommandObjectRenderScriptScriptGroup(interpreter));
49120b57cec5SDimitry Andric     LoadSubCommand(
49130b57cec5SDimitry Andric         "reduction",
49140b57cec5SDimitry Andric         CommandObjectSP(
49150b57cec5SDimitry Andric             new CommandObjectRenderScriptRuntimeReduction(interpreter)));
49160b57cec5SDimitry Andric   }
49170b57cec5SDimitry Andric 
49180b57cec5SDimitry Andric   ~CommandObjectRenderScriptRuntime() override = default;
49190b57cec5SDimitry Andric };
49200b57cec5SDimitry Andric 
Initiate()49210b57cec5SDimitry Andric void RenderScriptRuntime::Initiate() { assert(!m_initiated); }
49220b57cec5SDimitry Andric 
RenderScriptRuntime(Process * process)49230b57cec5SDimitry Andric RenderScriptRuntime::RenderScriptRuntime(Process *process)
49240b57cec5SDimitry Andric     : lldb_private::CPPLanguageRuntime(process), m_initiated(false),
49250b57cec5SDimitry Andric       m_debuggerPresentFlagged(false), m_breakAllKernels(false),
49260b57cec5SDimitry Andric       m_ir_passes(nullptr) {
49270b57cec5SDimitry Andric   ModulesDidLoad(process->GetTarget().GetImages());
49280b57cec5SDimitry Andric }
49290b57cec5SDimitry Andric 
GetCommandObject(lldb_private::CommandInterpreter & interpreter)49300b57cec5SDimitry Andric lldb::CommandObjectSP RenderScriptRuntime::GetCommandObject(
49310b57cec5SDimitry Andric     lldb_private::CommandInterpreter &interpreter) {
49320b57cec5SDimitry Andric   return CommandObjectSP(new CommandObjectRenderScriptRuntime(interpreter));
49330b57cec5SDimitry Andric }
49340b57cec5SDimitry Andric 
49350b57cec5SDimitry Andric RenderScriptRuntime::~RenderScriptRuntime() = default;
4936