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