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