15ec532a9SColin Riley //===-- RenderScriptRuntime.cpp ---------------------------------*- C++ -*-===// 25ec532a9SColin Riley // 35ec532a9SColin Riley // The LLVM Compiler Infrastructure 45ec532a9SColin Riley // 55ec532a9SColin Riley // This file is distributed under the University of Illinois Open Source 65ec532a9SColin Riley // License. See LICENSE.TXT for details. 75ec532a9SColin Riley // 85ec532a9SColin Riley //===----------------------------------------------------------------------===// 95ec532a9SColin Riley 10222b937cSEugene Zelenko // C Includes 11222b937cSEugene Zelenko // C++ Includes 12222b937cSEugene Zelenko // Other libraries and framework includes 13*7f193d69SLuke Drummond #include "llvm/ADT/StringMap.h" 14*7f193d69SLuke Drummond 15222b937cSEugene Zelenko // Project includes 165ec532a9SColin Riley #include "RenderScriptRuntime.h" 175ec532a9SColin Riley 18b3f7f69dSAidan Dodds #include "lldb/Breakpoint/StoppointCallbackContext.h" 195ec532a9SColin Riley #include "lldb/Core/ConstString.h" 205ec532a9SColin Riley #include "lldb/Core/Debugger.h" 215ec532a9SColin Riley #include "lldb/Core/Error.h" 225ec532a9SColin Riley #include "lldb/Core/Log.h" 235ec532a9SColin Riley #include "lldb/Core/PluginManager.h" 24018f5a7eSEwan Crawford #include "lldb/Core/RegularExpression.h" 25b3f7f69dSAidan Dodds #include "lldb/Core/ValueObjectVariable.h" 268b244e21SEwan Crawford #include "lldb/DataFormatters/DumpValueObjectOptions.h" 27b3f7f69dSAidan Dodds #include "lldb/Expression/UserExpression.h" 28a0f08674SEwan Crawford #include "lldb/Host/StringConvert.h" 29b3f7f69dSAidan Dodds #include "lldb/Interpreter/Args.h" 30b3f7f69dSAidan Dodds #include "lldb/Interpreter/CommandInterpreter.h" 31b3f7f69dSAidan Dodds #include "lldb/Interpreter/CommandObjectMultiword.h" 32b3f7f69dSAidan Dodds #include "lldb/Interpreter/CommandReturnObject.h" 33b3f7f69dSAidan Dodds #include "lldb/Interpreter/Options.h" 345ec532a9SColin Riley #include "lldb/Symbol/Symbol.h" 354640cde1SColin Riley #include "lldb/Symbol/Type.h" 36b3f7f69dSAidan Dodds #include "lldb/Symbol/VariableList.h" 375ec532a9SColin Riley #include "lldb/Target/Process.h" 38b3f7f69dSAidan Dodds #include "lldb/Target/RegisterContext.h" 395ec532a9SColin Riley #include "lldb/Target/Target.h" 40018f5a7eSEwan Crawford #include "lldb/Target/Thread.h" 415ec532a9SColin Riley 425ec532a9SColin Riley using namespace lldb; 435ec532a9SColin Riley using namespace lldb_private; 4498156583SEwan Crawford using namespace lldb_renderscript; 455ec532a9SColin Riley 46b9c1b51eSKate Stone namespace { 4778f339d1SEwan Crawford 4878f339d1SEwan Crawford // The empirical_type adds a basic level of validation to arbitrary data 4978f339d1SEwan Crawford // allowing us to track if data has been discovered and stored or not. 50b9c1b51eSKate Stone // An empirical_type will be marked as valid only if it has been explicitly 51b9c1b51eSKate Stone // assigned to. 52b9c1b51eSKate Stone template <typename type_t> class empirical_type { 5378f339d1SEwan Crawford public: 5478f339d1SEwan Crawford // Ctor. Contents is invalid when constructed. 55b3f7f69dSAidan Dodds empirical_type() : valid(false) {} 5678f339d1SEwan Crawford 5778f339d1SEwan Crawford // Return true and copy contents to out if valid, else return false. 58b9c1b51eSKate Stone bool get(type_t &out) const { 5978f339d1SEwan Crawford if (valid) 6078f339d1SEwan Crawford out = data; 6178f339d1SEwan Crawford return valid; 6278f339d1SEwan Crawford } 6378f339d1SEwan Crawford 6478f339d1SEwan Crawford // Return a pointer to the contents or nullptr if it was not valid. 65b9c1b51eSKate Stone const type_t *get() const { return valid ? &data : nullptr; } 6678f339d1SEwan Crawford 6778f339d1SEwan Crawford // Assign data explicitly. 68b9c1b51eSKate Stone void set(const type_t in) { 6978f339d1SEwan Crawford data = in; 7078f339d1SEwan Crawford valid = true; 7178f339d1SEwan Crawford } 7278f339d1SEwan Crawford 7378f339d1SEwan Crawford // Mark contents as invalid. 74b9c1b51eSKate Stone void invalidate() { valid = false; } 7578f339d1SEwan Crawford 7678f339d1SEwan Crawford // Returns true if this type contains valid data. 77b9c1b51eSKate Stone bool isValid() const { return valid; } 7878f339d1SEwan Crawford 7978f339d1SEwan Crawford // Assignment operator. 80b9c1b51eSKate Stone empirical_type<type_t> &operator=(const type_t in) { 8178f339d1SEwan Crawford set(in); 8278f339d1SEwan Crawford return *this; 8378f339d1SEwan Crawford } 8478f339d1SEwan Crawford 8578f339d1SEwan Crawford // Dereference operator returns contents. 8678f339d1SEwan Crawford // Warning: Will assert if not valid so use only when you know data is valid. 87b9c1b51eSKate Stone const type_t &operator*() const { 8878f339d1SEwan Crawford assert(valid); 8978f339d1SEwan Crawford return data; 9078f339d1SEwan Crawford } 9178f339d1SEwan Crawford 9278f339d1SEwan Crawford protected: 9378f339d1SEwan Crawford bool valid; 9478f339d1SEwan Crawford type_t data; 9578f339d1SEwan Crawford }; 9678f339d1SEwan Crawford 97b9c1b51eSKate Stone // ArgItem is used by the GetArgs() function when reading function arguments 98b9c1b51eSKate Stone // from the target. 99b9c1b51eSKate Stone struct ArgItem { 100b9c1b51eSKate Stone enum { ePointer, eInt32, eInt64, eLong, eBool } type; 101f4786785SAidan Dodds 102f4786785SAidan Dodds uint64_t value; 103f4786785SAidan Dodds 104f4786785SAidan Dodds explicit operator uint64_t() const { return value; } 105f4786785SAidan Dodds }; 106f4786785SAidan Dodds 107b9c1b51eSKate Stone // Context structure to be passed into GetArgsXXX(), argument reading functions 108b9c1b51eSKate Stone // below. 109b9c1b51eSKate Stone struct GetArgsCtx { 110f4786785SAidan Dodds RegisterContext *reg_ctx; 111f4786785SAidan Dodds Process *process; 112f4786785SAidan Dodds }; 113f4786785SAidan Dodds 114b9c1b51eSKate Stone bool GetArgsX86(const GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 115f4786785SAidan Dodds Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 116f4786785SAidan Dodds 11767dc3e15SAidan Dodds Error error; 11867dc3e15SAidan Dodds 119f4786785SAidan Dodds // get the current stack pointer 120f4786785SAidan Dodds uint64_t sp = ctx.reg_ctx->GetSP(); 121f4786785SAidan Dodds 122b9c1b51eSKate Stone for (size_t i = 0; i < num_args; ++i) { 123f4786785SAidan Dodds ArgItem &arg = arg_list[i]; 124f4786785SAidan Dodds // advance up the stack by one argument 125f4786785SAidan Dodds sp += sizeof(uint32_t); 126f4786785SAidan Dodds // get the argument type size 127f4786785SAidan Dodds size_t arg_size = sizeof(uint32_t); 128f4786785SAidan Dodds // read the argument from memory 129f4786785SAidan Dodds arg.value = 0; 130f4786785SAidan Dodds Error error; 131b9c1b51eSKate Stone size_t read = 132b9c1b51eSKate Stone ctx.process->ReadMemory(sp, &arg.value, sizeof(uint32_t), error); 133b9c1b51eSKate Stone if (read != arg_size || !error.Success()) { 134f4786785SAidan Dodds if (log) 135b9c1b51eSKate Stone log->Printf("%s - error reading argument: %" PRIu64 " '%s'", 136b9c1b51eSKate Stone __FUNCTION__, uint64_t(i), error.AsCString()); 137f4786785SAidan Dodds return false; 138f4786785SAidan Dodds } 139f4786785SAidan Dodds } 140f4786785SAidan Dodds return true; 141f4786785SAidan Dodds } 142f4786785SAidan Dodds 143b9c1b51eSKate Stone bool GetArgsX86_64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 144f4786785SAidan Dodds Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 145f4786785SAidan Dodds 146f4786785SAidan Dodds // number of arguments passed in registers 147f4786785SAidan Dodds static const uint32_t c_args_in_reg = 6; 148f4786785SAidan Dodds // register passing order 149b9c1b51eSKate Stone static const std::array<const char *, c_args_in_reg> c_reg_names{ 150b9c1b51eSKate Stone {"rdi", "rsi", "rdx", "rcx", "r8", "r9"}}; 151f4786785SAidan Dodds // argument type to size mapping 1521ee07253SSaleem Abdulrasool static const std::array<size_t, 5> arg_size{{ 153f4786785SAidan Dodds 8, // ePointer, 154f4786785SAidan Dodds 4, // eInt32, 155f4786785SAidan Dodds 8, // eInt64, 156f4786785SAidan Dodds 8, // eLong, 157f4786785SAidan Dodds 4, // eBool, 1581ee07253SSaleem Abdulrasool }}; 159f4786785SAidan Dodds 16017e07c0aSAidan Dodds Error error; 16117e07c0aSAidan Dodds 162f4786785SAidan Dodds // get the current stack pointer 163f4786785SAidan Dodds uint64_t sp = ctx.reg_ctx->GetSP(); 164f4786785SAidan Dodds // step over the return address 165f4786785SAidan Dodds sp += sizeof(uint64_t); 166f4786785SAidan Dodds 167f4786785SAidan Dodds // check the stack alignment was correct (16 byte aligned) 168b9c1b51eSKate Stone if ((sp & 0xf) != 0x0) { 169f4786785SAidan Dodds if (log) 170f4786785SAidan Dodds log->Printf("%s - stack misaligned", __FUNCTION__); 171f4786785SAidan Dodds return false; 172f4786785SAidan Dodds } 173f4786785SAidan Dodds 174f4786785SAidan Dodds // find the start of arguments on the stack 175f4786785SAidan Dodds uint64_t sp_offset = 0; 176b9c1b51eSKate Stone for (uint32_t i = c_args_in_reg; i < num_args; ++i) { 177f4786785SAidan Dodds sp_offset += arg_size[arg_list[i].type]; 178f4786785SAidan Dodds } 179f4786785SAidan Dodds // round up to multiple of 16 180f4786785SAidan Dodds sp_offset = (sp_offset + 0xf) & 0xf; 181f4786785SAidan Dodds sp += sp_offset; 182f4786785SAidan Dodds 183b9c1b51eSKate Stone for (size_t i = 0; i < num_args; ++i) { 184f4786785SAidan Dodds bool success = false; 185f4786785SAidan Dodds ArgItem &arg = arg_list[i]; 186f4786785SAidan Dodds // arguments passed in registers 187b9c1b51eSKate Stone if (i < c_args_in_reg) { 188b9c1b51eSKate Stone const RegisterInfo *rArg = 189b9c1b51eSKate Stone ctx.reg_ctx->GetRegisterInfoByName(c_reg_names[i]); 190f4786785SAidan Dodds RegisterValue rVal; 191f4786785SAidan Dodds if (ctx.reg_ctx->ReadRegister(rArg, rVal)) 192f4786785SAidan Dodds arg.value = rVal.GetAsUInt64(0, &success); 193f4786785SAidan Dodds } 194f4786785SAidan Dodds // arguments passed on the stack 195b9c1b51eSKate Stone else { 196f4786785SAidan Dodds // get the argument type size 197f4786785SAidan Dodds const size_t size = arg_size[arg_list[i].type]; 198f4786785SAidan Dodds // read the argument from memory 199f4786785SAidan Dodds arg.value = 0; 200b9c1b51eSKate Stone // note: due to little endian layout reading 4 or 8 bytes will give the 201b9c1b51eSKate Stone // correct value. 202f4786785SAidan Dodds size_t read = ctx.process->ReadMemory(sp, &arg.value, size, error); 203f4786785SAidan Dodds success = (error.Success() && read == size); 204f4786785SAidan Dodds // advance past this argument 205f4786785SAidan Dodds sp -= size; 206f4786785SAidan Dodds } 207f4786785SAidan Dodds // fail if we couldn't read this argument 208b9c1b51eSKate Stone if (!success) { 209f4786785SAidan Dodds if (log) 21017e07c0aSAidan Dodds log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s", 21117e07c0aSAidan Dodds __FUNCTION__, uint64_t(i), error.AsCString("n/a")); 212f4786785SAidan Dodds return false; 213f4786785SAidan Dodds } 214f4786785SAidan Dodds } 215f4786785SAidan Dodds return true; 216f4786785SAidan Dodds } 217f4786785SAidan Dodds 218b9c1b51eSKate Stone bool GetArgsArm(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 219f4786785SAidan Dodds // number of arguments passed in registers 220f4786785SAidan Dodds static const uint32_t c_args_in_reg = 4; 221f4786785SAidan Dodds 222f4786785SAidan Dodds Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 223f4786785SAidan Dodds 22417e07c0aSAidan Dodds Error error; 22517e07c0aSAidan Dodds 226f4786785SAidan Dodds // get the current stack pointer 227f4786785SAidan Dodds uint64_t sp = ctx.reg_ctx->GetSP(); 228f4786785SAidan Dodds 229b9c1b51eSKate Stone for (size_t i = 0; i < num_args; ++i) { 230f4786785SAidan Dodds bool success = false; 231f4786785SAidan Dodds ArgItem &arg = arg_list[i]; 232f4786785SAidan Dodds // arguments passed in registers 233b9c1b51eSKate Stone if (i < c_args_in_reg) { 234f4786785SAidan Dodds const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoAtIndex(i); 235f4786785SAidan Dodds RegisterValue rVal; 236f4786785SAidan Dodds if (ctx.reg_ctx->ReadRegister(rArg, rVal)) 237f4786785SAidan Dodds arg.value = rVal.GetAsUInt32(0, &success); 238f4786785SAidan Dodds } 239f4786785SAidan Dodds // arguments passed on the stack 240b9c1b51eSKate Stone else { 241f4786785SAidan Dodds // get the argument type size 242f4786785SAidan Dodds const size_t arg_size = sizeof(uint32_t); 243f4786785SAidan Dodds // clear all 64bits 244f4786785SAidan Dodds arg.value = 0; 245f4786785SAidan Dodds // read this argument from memory 246b9c1b51eSKate Stone size_t bytes_read = 247b9c1b51eSKate Stone ctx.process->ReadMemory(sp, &arg.value, arg_size, error); 248f4786785SAidan Dodds success = (error.Success() && bytes_read == arg_size); 249f4786785SAidan Dodds // advance the stack pointer 250f4786785SAidan Dodds sp += sizeof(uint32_t); 251f4786785SAidan Dodds } 252f4786785SAidan Dodds // fail if we couldn't read this argument 253b9c1b51eSKate Stone if (!success) { 254f4786785SAidan Dodds if (log) 25517e07c0aSAidan Dodds log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s", 25617e07c0aSAidan Dodds __FUNCTION__, uint64_t(i), error.AsCString("n/a")); 257f4786785SAidan Dodds return false; 258f4786785SAidan Dodds } 259f4786785SAidan Dodds } 260f4786785SAidan Dodds return true; 261f4786785SAidan Dodds } 262f4786785SAidan Dodds 263b9c1b51eSKate Stone bool GetArgsAarch64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 264f4786785SAidan Dodds // number of arguments passed in registers 265f4786785SAidan Dodds static const uint32_t c_args_in_reg = 8; 266f4786785SAidan Dodds 267f4786785SAidan Dodds Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 268f4786785SAidan Dodds 269b9c1b51eSKate Stone for (size_t i = 0; i < num_args; ++i) { 270f4786785SAidan Dodds bool success = false; 271f4786785SAidan Dodds ArgItem &arg = arg_list[i]; 272f4786785SAidan Dodds // arguments passed in registers 273b9c1b51eSKate Stone if (i < c_args_in_reg) { 274f4786785SAidan Dodds const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoAtIndex(i); 275f4786785SAidan Dodds RegisterValue rVal; 276f4786785SAidan Dodds if (ctx.reg_ctx->ReadRegister(rArg, rVal)) 277f4786785SAidan Dodds arg.value = rVal.GetAsUInt64(0, &success); 278f4786785SAidan Dodds } 279f4786785SAidan Dodds // arguments passed on the stack 280b9c1b51eSKate Stone else { 281f4786785SAidan Dodds if (log) 282b9c1b51eSKate Stone log->Printf("%s - reading arguments spilled to stack not implemented", 283b9c1b51eSKate Stone __FUNCTION__); 284f4786785SAidan Dodds } 285f4786785SAidan Dodds // fail if we couldn't read this argument 286b9c1b51eSKate Stone if (!success) { 287f4786785SAidan Dodds if (log) 288f4786785SAidan Dodds log->Printf("%s - error reading argument: %" PRIu64, __FUNCTION__, 289f4786785SAidan Dodds uint64_t(i)); 290f4786785SAidan Dodds return false; 291f4786785SAidan Dodds } 292f4786785SAidan Dodds } 293f4786785SAidan Dodds return true; 294f4786785SAidan Dodds } 295f4786785SAidan Dodds 296b9c1b51eSKate Stone bool GetArgsMipsel(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 297f4786785SAidan Dodds // number of arguments passed in registers 298f4786785SAidan Dodds static const uint32_t c_args_in_reg = 4; 299f4786785SAidan Dodds // register file offset to first argument 300f4786785SAidan Dodds static const uint32_t c_reg_offset = 4; 301f4786785SAidan Dodds 302f4786785SAidan Dodds Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 303f4786785SAidan Dodds 30417e07c0aSAidan Dodds Error error; 30517e07c0aSAidan Dodds 30617e07c0aSAidan Dodds // find offset to arguments on the stack (+16 to skip over a0-a3 shadow space) 30717e07c0aSAidan Dodds uint64_t sp = ctx.reg_ctx->GetSP() + 16; 30817e07c0aSAidan Dodds 309b9c1b51eSKate Stone for (size_t i = 0; i < num_args; ++i) { 310f4786785SAidan Dodds bool success = false; 311f4786785SAidan Dodds ArgItem &arg = arg_list[i]; 312f4786785SAidan Dodds // arguments passed in registers 313b9c1b51eSKate Stone if (i < c_args_in_reg) { 314b9c1b51eSKate Stone const RegisterInfo *rArg = 315b9c1b51eSKate Stone ctx.reg_ctx->GetRegisterInfoAtIndex(i + c_reg_offset); 316f4786785SAidan Dodds RegisterValue rVal; 317f4786785SAidan Dodds if (ctx.reg_ctx->ReadRegister(rArg, rVal)) 318f4786785SAidan Dodds arg.value = rVal.GetAsUInt64(0, &success); 319f4786785SAidan Dodds } 320f4786785SAidan Dodds // arguments passed on the stack 321b9c1b51eSKate Stone else { 3226dd4b579SAidan Dodds const size_t arg_size = sizeof(uint32_t); 3236dd4b579SAidan Dodds arg.value = 0; 324b9c1b51eSKate Stone size_t bytes_read = 325b9c1b51eSKate Stone ctx.process->ReadMemory(sp, &arg.value, arg_size, error); 3266dd4b579SAidan Dodds success = (error.Success() && bytes_read == arg_size); 32767dc3e15SAidan Dodds // advance the stack pointer 32867dc3e15SAidan Dodds sp += arg_size; 329f4786785SAidan Dodds } 330f4786785SAidan Dodds // fail if we couldn't read this argument 331b9c1b51eSKate Stone if (!success) { 332f4786785SAidan Dodds if (log) 33367dc3e15SAidan Dodds log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s", 33467dc3e15SAidan Dodds __FUNCTION__, uint64_t(i), error.AsCString("n/a")); 335f4786785SAidan Dodds return false; 336f4786785SAidan Dodds } 337f4786785SAidan Dodds } 338f4786785SAidan Dodds return true; 339f4786785SAidan Dodds } 340f4786785SAidan Dodds 341b9c1b51eSKate Stone bool GetArgsMips64el(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 342f4786785SAidan Dodds // number of arguments passed in registers 343f4786785SAidan Dodds static const uint32_t c_args_in_reg = 8; 344f4786785SAidan Dodds // register file offset to first argument 345f4786785SAidan Dodds static const uint32_t c_reg_offset = 4; 346f4786785SAidan Dodds 347f4786785SAidan Dodds Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 348f4786785SAidan Dodds 34917e07c0aSAidan Dodds Error error; 35017e07c0aSAidan Dodds 351f4786785SAidan Dodds // get the current stack pointer 352f4786785SAidan Dodds uint64_t sp = ctx.reg_ctx->GetSP(); 353f4786785SAidan Dodds 354b9c1b51eSKate Stone for (size_t i = 0; i < num_args; ++i) { 355f4786785SAidan Dodds bool success = false; 356f4786785SAidan Dodds ArgItem &arg = arg_list[i]; 357f4786785SAidan Dodds // arguments passed in registers 358b9c1b51eSKate Stone if (i < c_args_in_reg) { 359b9c1b51eSKate Stone const RegisterInfo *rArg = 360b9c1b51eSKate Stone ctx.reg_ctx->GetRegisterInfoAtIndex(i + c_reg_offset); 361f4786785SAidan Dodds RegisterValue rVal; 362f4786785SAidan Dodds if (ctx.reg_ctx->ReadRegister(rArg, rVal)) 36372f77525SAidan Dodds arg.value = rVal.GetAsUInt64(0, &success); 364f4786785SAidan Dodds } 365f4786785SAidan Dodds // arguments passed on the stack 366b9c1b51eSKate Stone else { 367f4786785SAidan Dodds // get the argument type size 368f4786785SAidan Dodds const size_t arg_size = sizeof(uint64_t); 369f4786785SAidan Dodds // clear all 64bits 370f4786785SAidan Dodds arg.value = 0; 371f4786785SAidan Dodds // read this argument from memory 372b9c1b51eSKate Stone size_t bytes_read = 373b9c1b51eSKate Stone ctx.process->ReadMemory(sp, &arg.value, arg_size, error); 374f4786785SAidan Dodds success = (error.Success() && bytes_read == arg_size); 375f4786785SAidan Dodds // advance the stack pointer 376f4786785SAidan Dodds sp += arg_size; 377f4786785SAidan Dodds } 378f4786785SAidan Dodds // fail if we couldn't read this argument 379b9c1b51eSKate Stone if (!success) { 380f4786785SAidan Dodds if (log) 38117e07c0aSAidan Dodds log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s", 38217e07c0aSAidan Dodds __FUNCTION__, uint64_t(i), error.AsCString("n/a")); 383f4786785SAidan Dodds return false; 384f4786785SAidan Dodds } 385f4786785SAidan Dodds } 386f4786785SAidan Dodds return true; 387f4786785SAidan Dodds } 388f4786785SAidan Dodds 389b9c1b51eSKate Stone bool GetArgs(ExecutionContext &context, ArgItem *arg_list, size_t num_args) { 390f4786785SAidan Dodds Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 391f4786785SAidan Dodds 392f4786785SAidan Dodds // verify that we have a target 393b9c1b51eSKate Stone if (!context.GetTargetPtr()) { 394f4786785SAidan Dodds if (log) 395f4786785SAidan Dodds log->Printf("%s - invalid target", __FUNCTION__); 396f4786785SAidan Dodds return false; 397f4786785SAidan Dodds } 398f4786785SAidan Dodds 399f4786785SAidan Dodds GetArgsCtx ctx = {context.GetRegisterContext(), context.GetProcessPtr()}; 400f4786785SAidan Dodds assert(ctx.reg_ctx && ctx.process); 401f4786785SAidan Dodds 402f4786785SAidan Dodds // dispatch based on architecture 403b9c1b51eSKate Stone switch (context.GetTargetPtr()->GetArchitecture().GetMachine()) { 404f4786785SAidan Dodds case llvm::Triple::ArchType::x86: 405f4786785SAidan Dodds return GetArgsX86(ctx, arg_list, num_args); 406f4786785SAidan Dodds 407f4786785SAidan Dodds case llvm::Triple::ArchType::x86_64: 408f4786785SAidan Dodds return GetArgsX86_64(ctx, arg_list, num_args); 409f4786785SAidan Dodds 410f4786785SAidan Dodds case llvm::Triple::ArchType::arm: 411f4786785SAidan Dodds return GetArgsArm(ctx, arg_list, num_args); 412f4786785SAidan Dodds 413f4786785SAidan Dodds case llvm::Triple::ArchType::aarch64: 414f4786785SAidan Dodds return GetArgsAarch64(ctx, arg_list, num_args); 415f4786785SAidan Dodds 416f4786785SAidan Dodds case llvm::Triple::ArchType::mipsel: 417f4786785SAidan Dodds return GetArgsMipsel(ctx, arg_list, num_args); 418f4786785SAidan Dodds 419f4786785SAidan Dodds case llvm::Triple::ArchType::mips64el: 420f4786785SAidan Dodds return GetArgsMips64el(ctx, arg_list, num_args); 421f4786785SAidan Dodds 422f4786785SAidan Dodds default: 423f4786785SAidan Dodds // unsupported architecture 424b9c1b51eSKate Stone if (log) { 425b9c1b51eSKate Stone log->Printf( 426b9c1b51eSKate Stone "%s - architecture not supported: '%s'", __FUNCTION__, 427f4786785SAidan Dodds context.GetTargetRef().GetArchitecture().GetArchitectureName()); 428f4786785SAidan Dodds } 429f4786785SAidan Dodds return false; 430f4786785SAidan Dodds } 431f4786785SAidan Dodds } 432222b937cSEugene Zelenko } // anonymous namespace 43378f339d1SEwan Crawford 434b9c1b51eSKate Stone // The ScriptDetails class collects data associated with a single script 435b9c1b51eSKate Stone // instance. 436b9c1b51eSKate Stone struct RenderScriptRuntime::ScriptDetails { 437222b937cSEugene Zelenko ~ScriptDetails() = default; 43878f339d1SEwan Crawford 439b9c1b51eSKate Stone enum ScriptType { eScript, eScriptC }; 44078f339d1SEwan Crawford 44178f339d1SEwan Crawford // The derived type of the script. 44278f339d1SEwan Crawford empirical_type<ScriptType> type; 44378f339d1SEwan Crawford // The name of the original source file. 44478f339d1SEwan Crawford empirical_type<std::string> resName; 44578f339d1SEwan Crawford // Path to script .so file on the device. 44678f339d1SEwan Crawford empirical_type<std::string> scriptDyLib; 44778f339d1SEwan Crawford // Directory where kernel objects are cached on device. 44878f339d1SEwan Crawford empirical_type<std::string> cacheDir; 44978f339d1SEwan Crawford // Pointer to the context which owns this script. 45078f339d1SEwan Crawford empirical_type<lldb::addr_t> context; 45178f339d1SEwan Crawford // Pointer to the script object itself. 45278f339d1SEwan Crawford empirical_type<lldb::addr_t> script; 45378f339d1SEwan Crawford }; 45478f339d1SEwan Crawford 4558b244e21SEwan Crawford // This Element class represents the Element object in RS, 4568b244e21SEwan Crawford // defining the type associated with an Allocation. 457b9c1b51eSKate Stone struct RenderScriptRuntime::Element { 45815f2bd95SEwan Crawford // Taken from rsDefines.h 459b9c1b51eSKate Stone enum DataKind { 46015f2bd95SEwan Crawford RS_KIND_USER, 46115f2bd95SEwan Crawford RS_KIND_PIXEL_L = 7, 46215f2bd95SEwan Crawford RS_KIND_PIXEL_A, 46315f2bd95SEwan Crawford RS_KIND_PIXEL_LA, 46415f2bd95SEwan Crawford RS_KIND_PIXEL_RGB, 46515f2bd95SEwan Crawford RS_KIND_PIXEL_RGBA, 46615f2bd95SEwan Crawford RS_KIND_PIXEL_DEPTH, 46715f2bd95SEwan Crawford RS_KIND_PIXEL_YUV, 46815f2bd95SEwan Crawford RS_KIND_INVALID = 100 46915f2bd95SEwan Crawford }; 47078f339d1SEwan Crawford 47115f2bd95SEwan Crawford // Taken from rsDefines.h 472b9c1b51eSKate Stone enum DataType { 47315f2bd95SEwan Crawford RS_TYPE_NONE = 0, 47415f2bd95SEwan Crawford RS_TYPE_FLOAT_16, 47515f2bd95SEwan Crawford RS_TYPE_FLOAT_32, 47615f2bd95SEwan Crawford RS_TYPE_FLOAT_64, 47715f2bd95SEwan Crawford RS_TYPE_SIGNED_8, 47815f2bd95SEwan Crawford RS_TYPE_SIGNED_16, 47915f2bd95SEwan Crawford RS_TYPE_SIGNED_32, 48015f2bd95SEwan Crawford RS_TYPE_SIGNED_64, 48115f2bd95SEwan Crawford RS_TYPE_UNSIGNED_8, 48215f2bd95SEwan Crawford RS_TYPE_UNSIGNED_16, 48315f2bd95SEwan Crawford RS_TYPE_UNSIGNED_32, 48415f2bd95SEwan Crawford RS_TYPE_UNSIGNED_64, 4852e920715SEwan Crawford RS_TYPE_BOOLEAN, 4862e920715SEwan Crawford 4872e920715SEwan Crawford RS_TYPE_UNSIGNED_5_6_5, 4882e920715SEwan Crawford RS_TYPE_UNSIGNED_5_5_5_1, 4892e920715SEwan Crawford RS_TYPE_UNSIGNED_4_4_4_4, 4902e920715SEwan Crawford 4912e920715SEwan Crawford RS_TYPE_MATRIX_4X4, 4922e920715SEwan Crawford RS_TYPE_MATRIX_3X3, 4932e920715SEwan Crawford RS_TYPE_MATRIX_2X2, 4942e920715SEwan Crawford 4952e920715SEwan Crawford RS_TYPE_ELEMENT = 1000, 4962e920715SEwan Crawford RS_TYPE_TYPE, 4972e920715SEwan Crawford RS_TYPE_ALLOCATION, 4982e920715SEwan Crawford RS_TYPE_SAMPLER, 4992e920715SEwan Crawford RS_TYPE_SCRIPT, 5002e920715SEwan Crawford RS_TYPE_MESH, 5012e920715SEwan Crawford RS_TYPE_PROGRAM_FRAGMENT, 5022e920715SEwan Crawford RS_TYPE_PROGRAM_VERTEX, 5032e920715SEwan Crawford RS_TYPE_PROGRAM_RASTER, 5042e920715SEwan Crawford RS_TYPE_PROGRAM_STORE, 5052e920715SEwan Crawford RS_TYPE_FONT, 5062e920715SEwan Crawford 5072e920715SEwan Crawford RS_TYPE_INVALID = 10000 50878f339d1SEwan Crawford }; 50978f339d1SEwan Crawford 5108b244e21SEwan Crawford std::vector<Element> children; // Child Element fields for structs 511b9c1b51eSKate Stone empirical_type<lldb::addr_t> 512b9c1b51eSKate Stone element_ptr; // Pointer to the RS Element of the Type 513b9c1b51eSKate Stone empirical_type<DataType> 514b9c1b51eSKate Stone type; // Type of each data pointer stored by the allocation 515b9c1b51eSKate Stone empirical_type<DataKind> 516b9c1b51eSKate Stone type_kind; // Defines pixel type if Allocation is created from an image 517b9c1b51eSKate Stone empirical_type<uint32_t> 518b9c1b51eSKate Stone type_vec_size; // Vector size of each data point, e.g '4' for uchar4 5198b244e21SEwan Crawford empirical_type<uint32_t> field_count; // Number of Subelements 5208b244e21SEwan Crawford empirical_type<uint32_t> datum_size; // Size of a single Element with padding 5218b244e21SEwan Crawford empirical_type<uint32_t> padding; // Number of padding bytes 522b9c1b51eSKate Stone empirical_type<uint32_t> 523b9c1b51eSKate Stone array_size; // Number of items in array, only needed for strucrs 5248b244e21SEwan Crawford ConstString type_name; // Name of type, only needed for structs 5258b244e21SEwan Crawford 526b3f7f69dSAidan Dodds static const ConstString & 527b3f7f69dSAidan Dodds GetFallbackStructName(); // Print this as the type name of a struct Element 5288b244e21SEwan Crawford // If we can't resolve the actual struct name 5298b59062aSEwan Crawford 530b9c1b51eSKate Stone bool shouldRefresh() const { 5318b59062aSEwan Crawford const bool valid_ptr = element_ptr.isValid() && *element_ptr.get() != 0x0; 532b9c1b51eSKate Stone const bool valid_type = 533b9c1b51eSKate Stone type.isValid() && type_vec_size.isValid() && type_kind.isValid(); 5348b59062aSEwan Crawford return !valid_ptr || !valid_type || !datum_size.isValid(); 5358b59062aSEwan Crawford } 5368b244e21SEwan Crawford }; 5378b244e21SEwan Crawford 5388b244e21SEwan Crawford // This AllocationDetails class collects data associated with a single 5398b244e21SEwan Crawford // allocation instance. 540b9c1b51eSKate Stone struct RenderScriptRuntime::AllocationDetails { 541b9c1b51eSKate Stone struct Dimension { 54215f2bd95SEwan Crawford uint32_t dim_1; 54315f2bd95SEwan Crawford uint32_t dim_2; 54415f2bd95SEwan Crawford uint32_t dim_3; 54515f2bd95SEwan Crawford uint32_t cubeMap; 54615f2bd95SEwan Crawford 547b9c1b51eSKate Stone Dimension() { 54815f2bd95SEwan Crawford dim_1 = 0; 54915f2bd95SEwan Crawford dim_2 = 0; 55015f2bd95SEwan Crawford dim_3 = 0; 55115f2bd95SEwan Crawford cubeMap = 0; 55215f2bd95SEwan Crawford } 55378f339d1SEwan Crawford }; 55478f339d1SEwan Crawford 555b9c1b51eSKate Stone // The FileHeader struct specifies the header we use for writing allocations 556b9c1b51eSKate Stone // to a binary file. 557b9c1b51eSKate Stone // Our format begins with the ASCII characters "RSAD", identifying the file as 558b9c1b51eSKate Stone // an allocation dump. 559b9c1b51eSKate Stone // Member variables dims and hdr_size are then written consecutively, 560b9c1b51eSKate Stone // immediately followed by an instance of 561b9c1b51eSKate Stone // the ElementHeader struct. Because Elements can contain subelements, there 562b9c1b51eSKate Stone // may be more than one instance 563b9c1b51eSKate Stone // of the ElementHeader struct. With this first instance being the root 564b9c1b51eSKate Stone // element, and the other instances being 565b9c1b51eSKate Stone // the root's descendants. To identify which instances are an ElementHeader's 566b9c1b51eSKate Stone // children, each struct 567b9c1b51eSKate Stone // is immediately followed by a sequence of consecutive offsets to the start 568b9c1b51eSKate Stone // of its child structs. 569b9c1b51eSKate Stone // These offsets are 4 bytes in size, and the 0 offset signifies no more 570b9c1b51eSKate Stone // children. 571b9c1b51eSKate Stone struct FileHeader { 57255232f09SEwan Crawford uint8_t ident[4]; // ASCII 'RSAD' identifying the file 57326e52a70SEwan Crawford uint32_t dims[3]; // Dimensions 57426e52a70SEwan Crawford uint16_t hdr_size; // Header size in bytes, including all element headers 57526e52a70SEwan Crawford }; 57626e52a70SEwan Crawford 577b9c1b51eSKate Stone struct ElementHeader { 57855232f09SEwan Crawford uint16_t type; // DataType enum 57955232f09SEwan Crawford uint32_t kind; // DataKind enum 58055232f09SEwan Crawford uint32_t element_size; // Size of a single element, including padding 58126e52a70SEwan Crawford uint16_t vector_size; // Vector width 58226e52a70SEwan Crawford uint32_t array_size; // Number of elements in array 58355232f09SEwan Crawford }; 58455232f09SEwan Crawford 58515f2bd95SEwan Crawford // Monotonically increasing from 1 586b3f7f69dSAidan Dodds static uint32_t ID; 58715f2bd95SEwan Crawford 58815f2bd95SEwan Crawford // Maps Allocation DataType enum and vector size to printable strings 58915f2bd95SEwan Crawford // using mapping from RenderScript numerical types summary documentation 59015f2bd95SEwan Crawford static const char *RsDataTypeToString[][4]; 59115f2bd95SEwan Crawford 59215f2bd95SEwan Crawford // Maps Allocation DataKind enum to printable strings 59315f2bd95SEwan Crawford static const char *RsDataKindToString[]; 59415f2bd95SEwan Crawford 595a0f08674SEwan Crawford // Maps allocation types to format sizes for printing. 596b3f7f69dSAidan Dodds static const uint32_t RSTypeToFormat[][3]; 597a0f08674SEwan Crawford 59815f2bd95SEwan Crawford // Give each allocation an ID as a way 59915f2bd95SEwan Crawford // for commands to reference it. 600b3f7f69dSAidan Dodds const uint32_t id; 60115f2bd95SEwan Crawford 6028b244e21SEwan Crawford RenderScriptRuntime::Element element; // Allocation Element type 60315f2bd95SEwan Crawford empirical_type<Dimension> dimension; // Dimensions of the Allocation 604b9c1b51eSKate Stone empirical_type<lldb::addr_t> 605b9c1b51eSKate Stone address; // Pointer to address of the RS Allocation 606b9c1b51eSKate Stone empirical_type<lldb::addr_t> 607b9c1b51eSKate Stone data_ptr; // Pointer to the data held by the Allocation 608b9c1b51eSKate Stone empirical_type<lldb::addr_t> 609b9c1b51eSKate Stone type_ptr; // Pointer to the RS Type of the Allocation 610b9c1b51eSKate Stone empirical_type<lldb::addr_t> 611b9c1b51eSKate Stone context; // Pointer to the RS Context of the Allocation 612a0f08674SEwan Crawford empirical_type<uint32_t> size; // Size of the allocation 613a0f08674SEwan Crawford empirical_type<uint32_t> stride; // Stride between rows of the allocation 61415f2bd95SEwan Crawford 61515f2bd95SEwan Crawford // Give each allocation an id, so we can reference it in user commands. 616b3f7f69dSAidan Dodds AllocationDetails() : id(ID++) {} 6178b59062aSEwan Crawford 618b9c1b51eSKate Stone bool shouldRefresh() const { 6198b59062aSEwan Crawford bool valid_ptrs = data_ptr.isValid() && *data_ptr.get() != 0x0; 6208b59062aSEwan Crawford valid_ptrs = valid_ptrs && type_ptr.isValid() && *type_ptr.get() != 0x0; 621b9c1b51eSKate Stone return !valid_ptrs || !dimension.isValid() || !size.isValid() || 622b9c1b51eSKate Stone element.shouldRefresh(); 6238b59062aSEwan Crawford } 62415f2bd95SEwan Crawford }; 62515f2bd95SEwan Crawford 626b9c1b51eSKate Stone const ConstString &RenderScriptRuntime::Element::GetFallbackStructName() { 627fe06b5adSAdrian McCarthy static const ConstString FallbackStructName("struct"); 628fe06b5adSAdrian McCarthy return FallbackStructName; 629fe06b5adSAdrian McCarthy } 6308b244e21SEwan Crawford 631b3f7f69dSAidan Dodds uint32_t RenderScriptRuntime::AllocationDetails::ID = 1; 63215f2bd95SEwan Crawford 633b3f7f69dSAidan Dodds const char *RenderScriptRuntime::AllocationDetails::RsDataKindToString[] = { 634b9c1b51eSKate Stone "User", "Undefined", "Undefined", "Undefined", 635b9c1b51eSKate Stone "Undefined", "Undefined", "Undefined", // Enum jumps from 0 to 7 636b3f7f69dSAidan Dodds "L Pixel", "A Pixel", "LA Pixel", "RGB Pixel", 637b3f7f69dSAidan Dodds "RGBA Pixel", "Pixel Depth", "YUV Pixel"}; 63815f2bd95SEwan Crawford 639b3f7f69dSAidan Dodds const char *RenderScriptRuntime::AllocationDetails::RsDataTypeToString[][4] = { 64015f2bd95SEwan Crawford {"None", "None", "None", "None"}, 64115f2bd95SEwan Crawford {"half", "half2", "half3", "half4"}, 64215f2bd95SEwan Crawford {"float", "float2", "float3", "float4"}, 64315f2bd95SEwan Crawford {"double", "double2", "double3", "double4"}, 64415f2bd95SEwan Crawford {"char", "char2", "char3", "char4"}, 64515f2bd95SEwan Crawford {"short", "short2", "short3", "short4"}, 64615f2bd95SEwan Crawford {"int", "int2", "int3", "int4"}, 64715f2bd95SEwan Crawford {"long", "long2", "long3", "long4"}, 64815f2bd95SEwan Crawford {"uchar", "uchar2", "uchar3", "uchar4"}, 64915f2bd95SEwan Crawford {"ushort", "ushort2", "ushort3", "ushort4"}, 65015f2bd95SEwan Crawford {"uint", "uint2", "uint3", "uint4"}, 65115f2bd95SEwan Crawford {"ulong", "ulong2", "ulong3", "ulong4"}, 6522e920715SEwan Crawford {"bool", "bool2", "bool3", "bool4"}, 6532e920715SEwan Crawford {"packed_565", "packed_565", "packed_565", "packed_565"}, 6542e920715SEwan Crawford {"packed_5551", "packed_5551", "packed_5551", "packed_5551"}, 6552e920715SEwan Crawford {"packed_4444", "packed_4444", "packed_4444", "packed_4444"}, 6562e920715SEwan Crawford {"rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4"}, 6572e920715SEwan Crawford {"rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3"}, 6582e920715SEwan Crawford {"rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2"}, 6592e920715SEwan Crawford 6602e920715SEwan Crawford // Handlers 6612e920715SEwan Crawford {"RS Element", "RS Element", "RS Element", "RS Element"}, 6622e920715SEwan Crawford {"RS Type", "RS Type", "RS Type", "RS Type"}, 6632e920715SEwan Crawford {"RS Allocation", "RS Allocation", "RS Allocation", "RS Allocation"}, 6642e920715SEwan Crawford {"RS Sampler", "RS Sampler", "RS Sampler", "RS Sampler"}, 6652e920715SEwan Crawford {"RS Script", "RS Script", "RS Script", "RS Script"}, 6662e920715SEwan Crawford 6672e920715SEwan Crawford // Deprecated 6682e920715SEwan Crawford {"RS Mesh", "RS Mesh", "RS Mesh", "RS Mesh"}, 669b9c1b51eSKate Stone {"RS Program Fragment", "RS Program Fragment", "RS Program Fragment", 670b9c1b51eSKate Stone "RS Program Fragment"}, 671b9c1b51eSKate Stone {"RS Program Vertex", "RS Program Vertex", "RS Program Vertex", 672b9c1b51eSKate Stone "RS Program Vertex"}, 673b9c1b51eSKate Stone {"RS Program Raster", "RS Program Raster", "RS Program Raster", 674b9c1b51eSKate Stone "RS Program Raster"}, 675b9c1b51eSKate Stone {"RS Program Store", "RS Program Store", "RS Program Store", 676b9c1b51eSKate Stone "RS Program Store"}, 677b3f7f69dSAidan Dodds {"RS Font", "RS Font", "RS Font", "RS Font"}}; 67878f339d1SEwan Crawford 679a0f08674SEwan Crawford // Used as an index into the RSTypeToFormat array elements 680b9c1b51eSKate Stone enum TypeToFormatIndex { eFormatSingle = 0, eFormatVector, eElementSize }; 681a0f08674SEwan Crawford 682b9c1b51eSKate Stone // { format enum of single element, format enum of element vector, size of 683b9c1b51eSKate Stone // element} 684b3f7f69dSAidan Dodds const uint32_t RenderScriptRuntime::AllocationDetails::RSTypeToFormat[][3] = { 685a0f08674SEwan Crawford {eFormatHex, eFormatHex, 1}, // RS_TYPE_NONE 686a0f08674SEwan Crawford {eFormatFloat, eFormatVectorOfFloat16, 2}, // RS_TYPE_FLOAT_16 687a0f08674SEwan Crawford {eFormatFloat, eFormatVectorOfFloat32, sizeof(float)}, // RS_TYPE_FLOAT_32 688a0f08674SEwan Crawford {eFormatFloat, eFormatVectorOfFloat64, sizeof(double)}, // RS_TYPE_FLOAT_64 689a0f08674SEwan Crawford {eFormatDecimal, eFormatVectorOfSInt8, sizeof(int8_t)}, // RS_TYPE_SIGNED_8 690b9c1b51eSKate Stone {eFormatDecimal, eFormatVectorOfSInt16, 691b9c1b51eSKate Stone sizeof(int16_t)}, // RS_TYPE_SIGNED_16 692b9c1b51eSKate Stone {eFormatDecimal, eFormatVectorOfSInt32, 693b9c1b51eSKate Stone sizeof(int32_t)}, // RS_TYPE_SIGNED_32 694b9c1b51eSKate Stone {eFormatDecimal, eFormatVectorOfSInt64, 695b9c1b51eSKate Stone sizeof(int64_t)}, // RS_TYPE_SIGNED_64 696b9c1b51eSKate Stone {eFormatDecimal, eFormatVectorOfUInt8, 697b9c1b51eSKate Stone sizeof(uint8_t)}, // RS_TYPE_UNSIGNED_8 698b9c1b51eSKate Stone {eFormatDecimal, eFormatVectorOfUInt16, 699b9c1b51eSKate Stone sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_16 700b9c1b51eSKate Stone {eFormatDecimal, eFormatVectorOfUInt32, 701b9c1b51eSKate Stone sizeof(uint32_t)}, // RS_TYPE_UNSIGNED_32 702b9c1b51eSKate Stone {eFormatDecimal, eFormatVectorOfUInt64, 703b9c1b51eSKate Stone sizeof(uint64_t)}, // RS_TYPE_UNSIGNED_64 7042e920715SEwan Crawford {eFormatBoolean, eFormatBoolean, 1}, // RS_TYPE_BOOL 7052e920715SEwan Crawford {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_6_5 7062e920715SEwan Crawford {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_5_5_1 7072e920715SEwan Crawford {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_4_4_4_4 708b9c1b51eSKate Stone {eFormatVectorOfFloat32, eFormatVectorOfFloat32, 709b9c1b51eSKate Stone sizeof(float) * 16}, // RS_TYPE_MATRIX_4X4 710b9c1b51eSKate Stone {eFormatVectorOfFloat32, eFormatVectorOfFloat32, 711b9c1b51eSKate Stone sizeof(float) * 9}, // RS_TYPE_MATRIX_3X3 712b9c1b51eSKate Stone {eFormatVectorOfFloat32, eFormatVectorOfFloat32, 713b9c1b51eSKate Stone sizeof(float) * 4} // RS_TYPE_MATRIX_2X2 714a0f08674SEwan Crawford }; 715a0f08674SEwan Crawford 7165ec532a9SColin Riley //------------------------------------------------------------------ 7175ec532a9SColin Riley // Static Functions 7185ec532a9SColin Riley //------------------------------------------------------------------ 7195ec532a9SColin Riley LanguageRuntime * 720b9c1b51eSKate Stone RenderScriptRuntime::CreateInstance(Process *process, 721b9c1b51eSKate Stone lldb::LanguageType language) { 7225ec532a9SColin Riley 7235ec532a9SColin Riley if (language == eLanguageTypeExtRenderScript) 7245ec532a9SColin Riley return new RenderScriptRuntime(process); 7255ec532a9SColin Riley else 726b3f7f69dSAidan Dodds return nullptr; 7275ec532a9SColin Riley } 7285ec532a9SColin Riley 72998156583SEwan Crawford // Callback with a module to search for matching symbols. 73098156583SEwan Crawford // We first check that the module contains RS kernels. 73198156583SEwan Crawford // Then look for a symbol which matches our kernel name. 73298156583SEwan Crawford // The breakpoint address is finally set using the address of this symbol. 73398156583SEwan Crawford Searcher::CallbackReturn 734b9c1b51eSKate Stone RSBreakpointResolver::SearchCallback(SearchFilter &filter, 735b9c1b51eSKate Stone SymbolContext &context, Address *, bool) { 73698156583SEwan Crawford ModuleSP module = context.module_sp; 73798156583SEwan Crawford 73898156583SEwan Crawford if (!module) 73998156583SEwan Crawford return Searcher::eCallbackReturnContinue; 74098156583SEwan Crawford 74198156583SEwan Crawford // Is this a module containing renderscript kernels? 742b9c1b51eSKate Stone if (nullptr == 743b9c1b51eSKate Stone module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), 744b9c1b51eSKate Stone eSymbolTypeData)) 74598156583SEwan Crawford return Searcher::eCallbackReturnContinue; 74698156583SEwan Crawford 747b9c1b51eSKate Stone // Attempt to set a breakpoint on the kernel name symbol within the module 748b9c1b51eSKate Stone // library. 74998156583SEwan Crawford // If it's not found, it's likely debug info is unavailable - try to set a 75098156583SEwan Crawford // breakpoint on <name>.expand. 75198156583SEwan Crawford 752b9c1b51eSKate Stone const Symbol *kernel_sym = 753b9c1b51eSKate Stone module->FindFirstSymbolWithNameAndType(m_kernel_name, eSymbolTypeCode); 754b9c1b51eSKate Stone if (!kernel_sym) { 75598156583SEwan Crawford std::string kernel_name_expanded(m_kernel_name.AsCString()); 75698156583SEwan Crawford kernel_name_expanded.append(".expand"); 757b9c1b51eSKate Stone kernel_sym = module->FindFirstSymbolWithNameAndType( 758b9c1b51eSKate Stone ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode); 75998156583SEwan Crawford } 76098156583SEwan Crawford 761b9c1b51eSKate Stone if (kernel_sym) { 76298156583SEwan Crawford Address bp_addr = kernel_sym->GetAddress(); 76398156583SEwan Crawford if (filter.AddressPasses(bp_addr)) 76498156583SEwan Crawford m_breakpoint->AddLocation(bp_addr); 76598156583SEwan Crawford } 76698156583SEwan Crawford 76798156583SEwan Crawford return Searcher::eCallbackReturnContinue; 76898156583SEwan Crawford } 76998156583SEwan Crawford 770b9c1b51eSKate Stone void RenderScriptRuntime::Initialize() { 771b9c1b51eSKate Stone PluginManager::RegisterPlugin(GetPluginNameStatic(), 772b9c1b51eSKate Stone "RenderScript language support", CreateInstance, 773b3f7f69dSAidan Dodds GetCommandObject); 7745ec532a9SColin Riley } 7755ec532a9SColin Riley 776b9c1b51eSKate Stone void RenderScriptRuntime::Terminate() { 7775ec532a9SColin Riley PluginManager::UnregisterPlugin(CreateInstance); 7785ec532a9SColin Riley } 7795ec532a9SColin Riley 780b9c1b51eSKate Stone lldb_private::ConstString RenderScriptRuntime::GetPluginNameStatic() { 7815ec532a9SColin Riley static ConstString g_name("renderscript"); 7825ec532a9SColin Riley return g_name; 7835ec532a9SColin Riley } 7845ec532a9SColin Riley 785ef20b08fSColin Riley RenderScriptRuntime::ModuleKind 786b9c1b51eSKate Stone RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp) { 787b9c1b51eSKate Stone if (module_sp) { 788ef20b08fSColin Riley // Is this a module containing renderscript kernels? 789b9c1b51eSKate Stone const Symbol *info_sym = module_sp->FindFirstSymbolWithNameAndType( 790b9c1b51eSKate Stone ConstString(".rs.info"), eSymbolTypeData); 791b9c1b51eSKate Stone if (info_sym) { 792ef20b08fSColin Riley return eModuleKindKernelObj; 793ef20b08fSColin Riley } 7944640cde1SColin Riley 7954640cde1SColin Riley // Is this the main RS runtime library 7964640cde1SColin Riley const ConstString rs_lib("libRS.so"); 797b9c1b51eSKate Stone if (module_sp->GetFileSpec().GetFilename() == rs_lib) { 7984640cde1SColin Riley return eModuleKindLibRS; 7994640cde1SColin Riley } 8004640cde1SColin Riley 8014640cde1SColin Riley const ConstString rs_driverlib("libRSDriver.so"); 802b9c1b51eSKate Stone if (module_sp->GetFileSpec().GetFilename() == rs_driverlib) { 8034640cde1SColin Riley return eModuleKindDriver; 8044640cde1SColin Riley } 8054640cde1SColin Riley 80615f2bd95SEwan Crawford const ConstString rs_cpureflib("libRSCpuRef.so"); 807b9c1b51eSKate Stone if (module_sp->GetFileSpec().GetFilename() == rs_cpureflib) { 8084640cde1SColin Riley return eModuleKindImpl; 8094640cde1SColin Riley } 810ef20b08fSColin Riley } 811ef20b08fSColin Riley return eModuleKindIgnored; 812ef20b08fSColin Riley } 813ef20b08fSColin Riley 814b9c1b51eSKate Stone bool RenderScriptRuntime::IsRenderScriptModule( 815b9c1b51eSKate Stone const lldb::ModuleSP &module_sp) { 816ef20b08fSColin Riley return GetModuleKind(module_sp) != eModuleKindIgnored; 817ef20b08fSColin Riley } 818ef20b08fSColin Riley 819b9c1b51eSKate Stone void RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list) { 820bb19a13cSSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); 821ef20b08fSColin Riley 822ef20b08fSColin Riley size_t num_modules = module_list.GetSize(); 823b9c1b51eSKate Stone for (size_t i = 0; i < num_modules; i++) { 824ef20b08fSColin Riley auto mod = module_list.GetModuleAtIndex(i); 825b9c1b51eSKate Stone if (IsRenderScriptModule(mod)) { 826ef20b08fSColin Riley LoadModule(mod); 827ef20b08fSColin Riley } 828ef20b08fSColin Riley } 829ef20b08fSColin Riley } 830ef20b08fSColin Riley 8315ec532a9SColin Riley //------------------------------------------------------------------ 8325ec532a9SColin Riley // PluginInterface protocol 8335ec532a9SColin Riley //------------------------------------------------------------------ 834b9c1b51eSKate Stone lldb_private::ConstString RenderScriptRuntime::GetPluginName() { 8355ec532a9SColin Riley return GetPluginNameStatic(); 8365ec532a9SColin Riley } 8375ec532a9SColin Riley 838b9c1b51eSKate Stone uint32_t RenderScriptRuntime::GetPluginVersion() { return 1; } 8395ec532a9SColin Riley 840b9c1b51eSKate Stone bool RenderScriptRuntime::IsVTableName(const char *name) { return false; } 8415ec532a9SColin Riley 842b9c1b51eSKate Stone bool RenderScriptRuntime::GetDynamicTypeAndAddress( 843b9c1b51eSKate Stone ValueObject &in_value, lldb::DynamicValueType use_dynamic, 8445f57b6eeSEnrico Granata TypeAndOrName &class_type_or_name, Address &address, 845b9c1b51eSKate Stone Value::ValueType &value_type) { 8465ec532a9SColin Riley return false; 8475ec532a9SColin Riley } 8485ec532a9SColin Riley 849c74275bcSEnrico Granata TypeAndOrName 850b9c1b51eSKate Stone RenderScriptRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, 851b9c1b51eSKate Stone ValueObject &static_value) { 852c74275bcSEnrico Granata return type_and_or_name; 853c74275bcSEnrico Granata } 854c74275bcSEnrico Granata 855b9c1b51eSKate Stone bool RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value) { 8565ec532a9SColin Riley return false; 8575ec532a9SColin Riley } 8585ec532a9SColin Riley 8595ec532a9SColin Riley lldb::BreakpointResolverSP 860b9c1b51eSKate Stone RenderScriptRuntime::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, 861b9c1b51eSKate Stone bool throw_bp) { 8625ec532a9SColin Riley BreakpointResolverSP resolver_sp; 8635ec532a9SColin Riley return resolver_sp; 8645ec532a9SColin Riley } 8655ec532a9SColin Riley 866b9c1b51eSKate Stone const RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] = 867b9c1b51eSKate Stone { 8684640cde1SColin Riley // rsdScript 869b9c1b51eSKate Stone {"rsdScriptInit", "_Z13rsdScriptInitPKN7android12renderscript7ContextEP" 870b9c1b51eSKate Stone "NS0_7ScriptCEPKcS7_PKhjj", 871b9c1b51eSKate Stone "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_" 872b9c1b51eSKate Stone "7ScriptCEPKcS7_PKhmj", 873b9c1b51eSKate Stone 0, RenderScriptRuntime::eModuleKindDriver, 874b9c1b51eSKate Stone &lldb_private::RenderScriptRuntime::CaptureScriptInit}, 875b9c1b51eSKate Stone {"rsdScriptInvokeForEachMulti", 876b9c1b51eSKate Stone "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0" 877b9c1b51eSKate Stone "_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall", 878b9c1b51eSKate Stone "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0" 879b9c1b51eSKate Stone "_6ScriptEjPPKNS0_10AllocationEmPS6_PKvmPK12RsScriptCall", 880b9c1b51eSKate Stone 0, RenderScriptRuntime::eModuleKindDriver, 881b9c1b51eSKate Stone &lldb_private::RenderScriptRuntime::CaptureScriptInvokeForEachMulti}, 882b9c1b51eSKate Stone {"rsdScriptSetGlobalVar", "_Z21rsdScriptSetGlobalVarPKN7android12render" 883b9c1b51eSKate Stone "script7ContextEPKNS0_6ScriptEjPvj", 884b9c1b51eSKate Stone "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_" 885b9c1b51eSKate Stone "6ScriptEjPvm", 886b9c1b51eSKate Stone 0, RenderScriptRuntime::eModuleKindDriver, 887b9c1b51eSKate Stone &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar}, 8884640cde1SColin Riley 8894640cde1SColin Riley // rsdAllocation 890b9c1b51eSKate Stone {"rsdAllocationInit", "_Z17rsdAllocationInitPKN7android12renderscript7C" 891b9c1b51eSKate Stone "ontextEPNS0_10AllocationEb", 892b9c1b51eSKate Stone "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_" 893b9c1b51eSKate Stone "10AllocationEb", 894b9c1b51eSKate Stone 0, RenderScriptRuntime::eModuleKindDriver, 895b9c1b51eSKate Stone &lldb_private::RenderScriptRuntime::CaptureAllocationInit}, 896b9c1b51eSKate Stone {"rsdAllocationRead2D", 897b9c1b51eSKate Stone "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_" 898b9c1b51eSKate Stone "10AllocationEjjj23RsAllocationCubemapFacejjPvjj", 899b9c1b51eSKate Stone "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_" 900b9c1b51eSKate Stone "10AllocationEjjj23RsAllocationCubemapFacejjPvmm", 901b9c1b51eSKate Stone 0, RenderScriptRuntime::eModuleKindDriver, nullptr}, 902b9c1b51eSKate Stone {"rsdAllocationDestroy", "_Z20rsdAllocationDestroyPKN7android12rendersc" 903b9c1b51eSKate Stone "ript7ContextEPNS0_10AllocationE", 904b9c1b51eSKate Stone "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_" 905b9c1b51eSKate Stone "10AllocationE", 906b9c1b51eSKate Stone 0, RenderScriptRuntime::eModuleKindDriver, 907b9c1b51eSKate Stone &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy}, 9084640cde1SColin Riley }; 9094640cde1SColin Riley 910b9c1b51eSKate Stone const size_t RenderScriptRuntime::s_runtimeHookCount = 911b9c1b51eSKate Stone sizeof(s_runtimeHookDefns) / sizeof(s_runtimeHookDefns[0]); 9124640cde1SColin Riley 913b9c1b51eSKate Stone bool RenderScriptRuntime::HookCallback(void *baton, 914b9c1b51eSKate Stone StoppointCallbackContext *ctx, 915b9c1b51eSKate Stone lldb::user_id_t break_id, 916b9c1b51eSKate Stone lldb::user_id_t break_loc_id) { 9174640cde1SColin Riley RuntimeHook *hook_info = (RuntimeHook *)baton; 9184640cde1SColin Riley ExecutionContext context(ctx->exe_ctx_ref); 9194640cde1SColin Riley 920b3f7f69dSAidan Dodds RenderScriptRuntime *lang_rt = 921b9c1b51eSKate Stone (RenderScriptRuntime *)context.GetProcessPtr()->GetLanguageRuntime( 922b9c1b51eSKate Stone eLanguageTypeExtRenderScript); 9234640cde1SColin Riley 9244640cde1SColin Riley lang_rt->HookCallback(hook_info, context); 9254640cde1SColin Riley 9264640cde1SColin Riley return false; 9274640cde1SColin Riley } 9284640cde1SColin Riley 929b9c1b51eSKate Stone void RenderScriptRuntime::HookCallback(RuntimeHook *hook_info, 930b9c1b51eSKate Stone ExecutionContext &context) { 9314640cde1SColin Riley Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 9324640cde1SColin Riley 9334640cde1SColin Riley if (log) 934b3f7f69dSAidan Dodds log->Printf("%s - '%s'", __FUNCTION__, hook_info->defn->name); 9354640cde1SColin Riley 936b9c1b51eSKate Stone if (hook_info->defn->grabber) { 9374640cde1SColin Riley (this->*(hook_info->defn->grabber))(hook_info, context); 9384640cde1SColin Riley } 9394640cde1SColin Riley } 9404640cde1SColin Riley 941b9c1b51eSKate Stone void RenderScriptRuntime::CaptureScriptInvokeForEachMulti( 942b9c1b51eSKate Stone RuntimeHook *hook_info, ExecutionContext &context) { 943e09c44b6SAidan Dodds Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 944e09c44b6SAidan Dodds 945b9c1b51eSKate Stone enum { 946f4786785SAidan Dodds eRsContext = 0, 947f4786785SAidan Dodds eRsScript, 948f4786785SAidan Dodds eRsSlot, 949f4786785SAidan Dodds eRsAIns, 950f4786785SAidan Dodds eRsInLen, 951f4786785SAidan Dodds eRsAOut, 952f4786785SAidan Dodds eRsUsr, 953f4786785SAidan Dodds eRsUsrLen, 954f4786785SAidan Dodds eRsSc, 955f4786785SAidan Dodds }; 956e09c44b6SAidan Dodds 9571ee07253SSaleem Abdulrasool std::array<ArgItem, 9> args{{ 958f4786785SAidan Dodds ArgItem{ArgItem::ePointer, 0}, // const Context *rsc 959f4786785SAidan Dodds ArgItem{ArgItem::ePointer, 0}, // Script *s 960f4786785SAidan Dodds ArgItem{ArgItem::eInt32, 0}, // uint32_t slot 961f4786785SAidan Dodds ArgItem{ArgItem::ePointer, 0}, // const Allocation **aIns 962f4786785SAidan Dodds ArgItem{ArgItem::eInt32, 0}, // size_t inLen 963f4786785SAidan Dodds ArgItem{ArgItem::ePointer, 0}, // Allocation *aout 964f4786785SAidan Dodds ArgItem{ArgItem::ePointer, 0}, // const void *usr 965f4786785SAidan Dodds ArgItem{ArgItem::eInt32, 0}, // size_t usrLen 966f4786785SAidan Dodds ArgItem{ArgItem::ePointer, 0}, // const RsScriptCall *sc 9671ee07253SSaleem Abdulrasool }}; 968e09c44b6SAidan Dodds 969f4786785SAidan Dodds bool success = GetArgs(context, &args[0], args.size()); 970b9c1b51eSKate Stone if (!success) { 971e09c44b6SAidan Dodds if (log) 972b9c1b51eSKate Stone log->Printf("%s - Error while reading the function parameters", 973b9c1b51eSKate Stone __FUNCTION__); 974e09c44b6SAidan Dodds return; 975e09c44b6SAidan Dodds } 976e09c44b6SAidan Dodds 977e09c44b6SAidan Dodds const uint32_t target_ptr_size = m_process->GetAddressByteSize(); 978e09c44b6SAidan Dodds Error error; 979e09c44b6SAidan Dodds std::vector<uint64_t> allocs; 980e09c44b6SAidan Dodds 981e09c44b6SAidan Dodds // traverse allocation list 982b9c1b51eSKate Stone for (uint64_t i = 0; i < uint64_t(args[eRsInLen]); ++i) { 983e09c44b6SAidan Dodds // calculate offest to allocation pointer 984f4786785SAidan Dodds const addr_t addr = addr_t(args[eRsAIns]) + i * target_ptr_size; 985e09c44b6SAidan Dodds 986b9c1b51eSKate Stone // Note: due to little endian layout, reading 32bits or 64bits into res64 987b9c1b51eSKate Stone // will 988e09c44b6SAidan Dodds // give the correct results. 989e09c44b6SAidan Dodds 990e09c44b6SAidan Dodds uint64_t res64 = 0; 991e09c44b6SAidan Dodds size_t read = m_process->ReadMemory(addr, &res64, target_ptr_size, error); 992b9c1b51eSKate Stone if (read != target_ptr_size || !error.Success()) { 993e09c44b6SAidan Dodds if (log) 994b9c1b51eSKate Stone log->Printf( 995b9c1b51eSKate Stone "%s - Error while reading allocation list argument %" PRIu64, 996b9c1b51eSKate Stone __FUNCTION__, i); 997b9c1b51eSKate Stone } else { 998e09c44b6SAidan Dodds allocs.push_back(res64); 999e09c44b6SAidan Dodds } 1000e09c44b6SAidan Dodds } 1001e09c44b6SAidan Dodds 1002e09c44b6SAidan Dodds // if there is an output allocation track it 1003b9c1b51eSKate Stone if (uint64_t aOut = uint64_t(args[eRsAOut])) { 1004f4786785SAidan Dodds allocs.push_back(aOut); 1005e09c44b6SAidan Dodds } 1006e09c44b6SAidan Dodds 1007e09c44b6SAidan Dodds // for all allocations we have found 1008b9c1b51eSKate Stone for (const uint64_t alloc_addr : allocs) { 10095d057637SLuke Drummond AllocationDetails *alloc = LookUpAllocation(alloc_addr); 10105d057637SLuke Drummond if (!alloc) 10115d057637SLuke Drummond alloc = CreateAllocation(alloc_addr); 10125d057637SLuke Drummond 1013b9c1b51eSKate Stone if (alloc) { 1014e09c44b6SAidan Dodds // save the allocation address 1015b9c1b51eSKate Stone if (alloc->address.isValid()) { 1016e09c44b6SAidan Dodds // check the allocation address we already have matches 1017e09c44b6SAidan Dodds assert(*alloc->address.get() == alloc_addr); 1018b9c1b51eSKate Stone } else { 1019e09c44b6SAidan Dodds alloc->address = alloc_addr; 1020e09c44b6SAidan Dodds } 1021e09c44b6SAidan Dodds 1022e09c44b6SAidan Dodds // save the context 1023b9c1b51eSKate Stone if (log) { 1024b9c1b51eSKate Stone if (alloc->context.isValid() && 1025b9c1b51eSKate Stone *alloc->context.get() != addr_t(args[eRsContext])) 1026b9c1b51eSKate Stone log->Printf("%s - Allocation used by multiple contexts", 1027b9c1b51eSKate Stone __FUNCTION__); 1028e09c44b6SAidan Dodds } 1029f4786785SAidan Dodds alloc->context = addr_t(args[eRsContext]); 1030e09c44b6SAidan Dodds } 1031e09c44b6SAidan Dodds } 1032e09c44b6SAidan Dodds 1033e09c44b6SAidan Dodds // make sure we track this script object 1034b9c1b51eSKate Stone if (lldb_private::RenderScriptRuntime::ScriptDetails *script = 1035b9c1b51eSKate Stone LookUpScript(addr_t(args[eRsScript]), true)) { 1036b9c1b51eSKate Stone if (log) { 1037b9c1b51eSKate Stone if (script->context.isValid() && 1038b9c1b51eSKate Stone *script->context.get() != addr_t(args[eRsContext])) 1039b3f7f69dSAidan Dodds log->Printf("%s - Script used by multiple contexts", __FUNCTION__); 1040e09c44b6SAidan Dodds } 1041f4786785SAidan Dodds script->context = addr_t(args[eRsContext]); 1042e09c44b6SAidan Dodds } 1043e09c44b6SAidan Dodds } 1044e09c44b6SAidan Dodds 1045b9c1b51eSKate Stone void RenderScriptRuntime::CaptureSetGlobalVar(RuntimeHook *hook_info, 1046b9c1b51eSKate Stone ExecutionContext &context) { 10474640cde1SColin Riley Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 10484640cde1SColin Riley 1049b9c1b51eSKate Stone enum { 1050f4786785SAidan Dodds eRsContext, 1051f4786785SAidan Dodds eRsScript, 1052f4786785SAidan Dodds eRsId, 1053f4786785SAidan Dodds eRsData, 1054f4786785SAidan Dodds eRsLength, 1055f4786785SAidan Dodds }; 10564640cde1SColin Riley 10571ee07253SSaleem Abdulrasool std::array<ArgItem, 5> args{{ 1058f4786785SAidan Dodds ArgItem{ArgItem::ePointer, 0}, // eRsContext 1059f4786785SAidan Dodds ArgItem{ArgItem::ePointer, 0}, // eRsScript 1060f4786785SAidan Dodds ArgItem{ArgItem::eInt32, 0}, // eRsId 1061f4786785SAidan Dodds ArgItem{ArgItem::ePointer, 0}, // eRsData 1062f4786785SAidan Dodds ArgItem{ArgItem::eInt32, 0}, // eRsLength 10631ee07253SSaleem Abdulrasool }}; 10644640cde1SColin Riley 1065f4786785SAidan Dodds bool success = GetArgs(context, &args[0], args.size()); 1066b9c1b51eSKate Stone if (!success) { 106782780287SAidan Dodds if (log) 1068b3f7f69dSAidan Dodds log->Printf("%s - error reading the function parameters.", __FUNCTION__); 106982780287SAidan Dodds return; 107082780287SAidan Dodds } 10714640cde1SColin Riley 1072b9c1b51eSKate Stone if (log) { 1073b9c1b51eSKate Stone log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64 1074b9c1b51eSKate Stone ":%" PRIu64 "bytes.", 1075b9c1b51eSKate Stone __FUNCTION__, uint64_t(args[eRsContext]), 1076b9c1b51eSKate Stone uint64_t(args[eRsScript]), uint64_t(args[eRsId]), 1077f4786785SAidan Dodds uint64_t(args[eRsData]), uint64_t(args[eRsLength])); 10784640cde1SColin Riley 1079f4786785SAidan Dodds addr_t script_addr = addr_t(args[eRsScript]); 1080b9c1b51eSKate Stone if (m_scriptMappings.find(script_addr) != m_scriptMappings.end()) { 10814640cde1SColin Riley auto rsm = m_scriptMappings[script_addr]; 1082b9c1b51eSKate Stone if (uint64_t(args[eRsId]) < rsm->m_globals.size()) { 1083f4786785SAidan Dodds auto rsg = rsm->m_globals[uint64_t(args[eRsId])]; 1084b9c1b51eSKate Stone log->Printf("%s - Setting of '%s' within '%s' inferred", __FUNCTION__, 1085b9c1b51eSKate Stone rsg.m_name.AsCString(), 1086f4786785SAidan Dodds rsm->m_module->GetFileSpec().GetFilename().AsCString()); 10874640cde1SColin Riley } 10884640cde1SColin Riley } 10894640cde1SColin Riley } 10904640cde1SColin Riley } 10914640cde1SColin Riley 1092b9c1b51eSKate Stone void RenderScriptRuntime::CaptureAllocationInit(RuntimeHook *hook_info, 1093b9c1b51eSKate Stone ExecutionContext &context) { 10944640cde1SColin Riley Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 10954640cde1SColin Riley 1096b9c1b51eSKate Stone enum { eRsContext, eRsAlloc, eRsForceZero }; 10974640cde1SColin Riley 10981ee07253SSaleem Abdulrasool std::array<ArgItem, 3> args{{ 1099f4786785SAidan Dodds ArgItem{ArgItem::ePointer, 0}, // eRsContext 1100f4786785SAidan Dodds ArgItem{ArgItem::ePointer, 0}, // eRsAlloc 1101f4786785SAidan Dodds ArgItem{ArgItem::eBool, 0}, // eRsForceZero 11021ee07253SSaleem Abdulrasool }}; 11034640cde1SColin Riley 1104f4786785SAidan Dodds bool success = GetArgs(context, &args[0], args.size()); 110582780287SAidan Dodds if (!success) // error case 110682780287SAidan Dodds { 110782780287SAidan Dodds if (log) 1108b9c1b51eSKate Stone log->Printf("%s - error while reading the function parameters", 1109b9c1b51eSKate Stone __FUNCTION__); 111082780287SAidan Dodds return; // abort 111182780287SAidan Dodds } 11124640cde1SColin Riley 11134640cde1SColin Riley if (log) 1114b9c1b51eSKate Stone log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .", 1115b9c1b51eSKate Stone __FUNCTION__, uint64_t(args[eRsContext]), 1116f4786785SAidan Dodds uint64_t(args[eRsAlloc]), uint64_t(args[eRsForceZero])); 111778f339d1SEwan Crawford 11185d057637SLuke Drummond AllocationDetails *alloc = CreateAllocation(uint64_t(args[eRsAlloc])); 111978f339d1SEwan Crawford if (alloc) 1120f4786785SAidan Dodds alloc->context = uint64_t(args[eRsContext]); 11214640cde1SColin Riley } 11224640cde1SColin Riley 1123b9c1b51eSKate Stone void RenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook *hook_info, 1124b9c1b51eSKate Stone ExecutionContext &context) { 1125e69df382SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1126e69df382SEwan Crawford 1127b9c1b51eSKate Stone enum { 1128f4786785SAidan Dodds eRsContext, 1129f4786785SAidan Dodds eRsAlloc, 1130f4786785SAidan Dodds }; 1131e69df382SEwan Crawford 11321ee07253SSaleem Abdulrasool std::array<ArgItem, 2> args{{ 1133f4786785SAidan Dodds ArgItem{ArgItem::ePointer, 0}, // eRsContext 1134f4786785SAidan Dodds ArgItem{ArgItem::ePointer, 0}, // eRsAlloc 11351ee07253SSaleem Abdulrasool }}; 1136f4786785SAidan Dodds 1137f4786785SAidan Dodds bool success = GetArgs(context, &args[0], args.size()); 1138b9c1b51eSKate Stone if (!success) { 1139e69df382SEwan Crawford if (log) 1140b9c1b51eSKate Stone log->Printf("%s - error while reading the function parameters.", 1141b9c1b51eSKate Stone __FUNCTION__); 1142b3f7f69dSAidan Dodds return; 1143e69df382SEwan Crawford } 1144e69df382SEwan Crawford 1145e69df382SEwan Crawford if (log) 1146b9c1b51eSKate Stone log->Printf("%s - 0x%" PRIx64 ", 0x%" PRIx64 ".", __FUNCTION__, 1147b9c1b51eSKate Stone uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc])); 1148e69df382SEwan Crawford 1149b9c1b51eSKate Stone for (auto iter = m_allocations.begin(); iter != m_allocations.end(); ++iter) { 1150e69df382SEwan Crawford auto &allocation_ap = *iter; // get the unique pointer 1151b9c1b51eSKate Stone if (allocation_ap->address.isValid() && 1152b9c1b51eSKate Stone *allocation_ap->address.get() == addr_t(args[eRsAlloc])) { 1153e69df382SEwan Crawford m_allocations.erase(iter); 1154e69df382SEwan Crawford if (log) 1155b3f7f69dSAidan Dodds log->Printf("%s - deleted allocation entry.", __FUNCTION__); 1156e69df382SEwan Crawford return; 1157e69df382SEwan Crawford } 1158e69df382SEwan Crawford } 1159e69df382SEwan Crawford 1160e69df382SEwan Crawford if (log) 1161b3f7f69dSAidan Dodds log->Printf("%s - couldn't find destroyed allocation.", __FUNCTION__); 1162e69df382SEwan Crawford } 1163e69df382SEwan Crawford 1164b9c1b51eSKate Stone void RenderScriptRuntime::CaptureScriptInit(RuntimeHook *hook_info, 1165b9c1b51eSKate Stone ExecutionContext &context) { 11664640cde1SColin Riley Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 11674640cde1SColin Riley 11684640cde1SColin Riley Error error; 11694640cde1SColin Riley Process *process = context.GetProcessPtr(); 11704640cde1SColin Riley 1171b9c1b51eSKate Stone enum { eRsContext, eRsScript, eRsResNamePtr, eRsCachedDirPtr }; 11724640cde1SColin Riley 1173b9c1b51eSKate Stone std::array<ArgItem, 4> args{ 1174b9c1b51eSKate Stone {ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}, 11751ee07253SSaleem Abdulrasool ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}}}; 1176f4786785SAidan Dodds bool success = GetArgs(context, &args[0], args.size()); 1177b9c1b51eSKate Stone if (!success) { 117882780287SAidan Dodds if (log) 1179b9c1b51eSKate Stone log->Printf("%s - error while reading the function parameters.", 1180b9c1b51eSKate Stone __FUNCTION__); 118182780287SAidan Dodds return; 118282780287SAidan Dodds } 118382780287SAidan Dodds 1184f4786785SAidan Dodds std::string resname; 1185f4786785SAidan Dodds process->ReadCStringFromMemory(addr_t(args[eRsResNamePtr]), resname, error); 1186b9c1b51eSKate Stone if (error.Fail()) { 11874640cde1SColin Riley if (log) 1188b9c1b51eSKate Stone log->Printf("%s - error reading resname: %s.", __FUNCTION__, 1189b9c1b51eSKate Stone error.AsCString()); 11904640cde1SColin Riley } 11914640cde1SColin Riley 1192f4786785SAidan Dodds std::string cachedir; 1193b9c1b51eSKate Stone process->ReadCStringFromMemory(addr_t(args[eRsCachedDirPtr]), cachedir, 1194b9c1b51eSKate Stone error); 1195b9c1b51eSKate Stone if (error.Fail()) { 11964640cde1SColin Riley if (log) 1197b9c1b51eSKate Stone log->Printf("%s - error reading cachedir: %s.", __FUNCTION__, 1198b9c1b51eSKate Stone error.AsCString()); 11994640cde1SColin Riley } 12004640cde1SColin Riley 12014640cde1SColin Riley if (log) 1202b9c1b51eSKate Stone log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .", 1203b9c1b51eSKate Stone __FUNCTION__, uint64_t(args[eRsContext]), 1204f4786785SAidan Dodds uint64_t(args[eRsScript]), resname.c_str(), cachedir.c_str()); 12054640cde1SColin Riley 1206b9c1b51eSKate Stone if (resname.size() > 0) { 12074640cde1SColin Riley StreamString strm; 12084640cde1SColin Riley strm.Printf("librs.%s.so", resname.c_str()); 12094640cde1SColin Riley 1210f4786785SAidan Dodds ScriptDetails *script = LookUpScript(addr_t(args[eRsScript]), true); 1211b9c1b51eSKate Stone if (script) { 121278f339d1SEwan Crawford script->type = ScriptDetails::eScriptC; 121378f339d1SEwan Crawford script->cacheDir = cachedir; 121478f339d1SEwan Crawford script->resName = resname; 121578f339d1SEwan Crawford script->scriptDyLib = strm.GetData(); 1216f4786785SAidan Dodds script->context = addr_t(args[eRsContext]); 121778f339d1SEwan Crawford } 12184640cde1SColin Riley 12194640cde1SColin Riley if (log) 1220b9c1b51eSKate Stone log->Printf("%s - '%s' tagged with context 0x%" PRIx64 1221b9c1b51eSKate Stone " and script 0x%" PRIx64 ".", 1222b9c1b51eSKate Stone __FUNCTION__, strm.GetData(), uint64_t(args[eRsContext]), 1223b9c1b51eSKate Stone uint64_t(args[eRsScript])); 1224b9c1b51eSKate Stone } else if (log) { 1225b3f7f69dSAidan Dodds log->Printf("%s - resource name invalid, Script not tagged.", __FUNCTION__); 12264640cde1SColin Riley } 12274640cde1SColin Riley } 12284640cde1SColin Riley 1229b9c1b51eSKate Stone void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, 1230b9c1b51eSKate Stone ModuleKind kind) { 12314640cde1SColin Riley Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 12324640cde1SColin Riley 1233b9c1b51eSKate Stone if (!module) { 12344640cde1SColin Riley return; 12354640cde1SColin Riley } 12364640cde1SColin Riley 123782780287SAidan Dodds Target &target = GetProcess()->GetTarget(); 123882780287SAidan Dodds llvm::Triple::ArchType targetArchType = target.GetArchitecture().GetMachine(); 123982780287SAidan Dodds 1240b3f7f69dSAidan Dodds if (targetArchType != llvm::Triple::ArchType::x86 && 1241b3f7f69dSAidan Dodds targetArchType != llvm::Triple::ArchType::arm && 1242b3f7f69dSAidan Dodds targetArchType != llvm::Triple::ArchType::aarch64 && 1243b3f7f69dSAidan Dodds targetArchType != llvm::Triple::ArchType::mipsel && 1244b3f7f69dSAidan Dodds targetArchType != llvm::Triple::ArchType::mips64el && 1245b9c1b51eSKate Stone targetArchType != llvm::Triple::ArchType::x86_64) { 12464640cde1SColin Riley if (log) 1247b3f7f69dSAidan Dodds log->Printf("%s - unable to hook runtime functions.", __FUNCTION__); 12484640cde1SColin Riley return; 12494640cde1SColin Riley } 12504640cde1SColin Riley 125182780287SAidan Dodds uint32_t archByteSize = target.GetArchitecture().GetAddressByteSize(); 12524640cde1SColin Riley 1253b9c1b51eSKate Stone for (size_t idx = 0; idx < s_runtimeHookCount; idx++) { 12544640cde1SColin Riley const HookDefn *hook_defn = &s_runtimeHookDefns[idx]; 1255b9c1b51eSKate Stone if (hook_defn->kind != kind) { 12564640cde1SColin Riley continue; 12574640cde1SColin Riley } 12584640cde1SColin Riley 1259b9c1b51eSKate Stone const char *symbol_name = (archByteSize == 4) ? hook_defn->symbol_name_m32 1260b9c1b51eSKate Stone : hook_defn->symbol_name_m64; 126182780287SAidan Dodds 1262b9c1b51eSKate Stone const Symbol *sym = module->FindFirstSymbolWithNameAndType( 1263b9c1b51eSKate Stone ConstString(symbol_name), eSymbolTypeCode); 1264b9c1b51eSKate Stone if (!sym) { 1265b9c1b51eSKate Stone if (log) { 1266b3f7f69dSAidan Dodds log->Printf("%s - symbol '%s' related to the function %s not found", 1267b3f7f69dSAidan Dodds __FUNCTION__, symbol_name, hook_defn->name); 126882780287SAidan Dodds } 126982780287SAidan Dodds continue; 127082780287SAidan Dodds } 12714640cde1SColin Riley 1272358cf1eaSGreg Clayton addr_t addr = sym->GetLoadAddress(&target); 1273b9c1b51eSKate Stone if (addr == LLDB_INVALID_ADDRESS) { 12744640cde1SColin Riley if (log) 1275b9c1b51eSKate Stone log->Printf("%s - unable to resolve the address of hook function '%s' " 1276b9c1b51eSKate Stone "with symbol '%s'.", 1277b3f7f69dSAidan Dodds __FUNCTION__, hook_defn->name, symbol_name); 12784640cde1SColin Riley continue; 1279b9c1b51eSKate Stone } else { 128082780287SAidan Dodds if (log) 1281b3f7f69dSAidan Dodds log->Printf("%s - function %s, address resolved at 0x%" PRIx64, 1282b3f7f69dSAidan Dodds __FUNCTION__, hook_defn->name, addr); 128382780287SAidan Dodds } 12844640cde1SColin Riley 12854640cde1SColin Riley RuntimeHookSP hook(new RuntimeHook()); 12864640cde1SColin Riley hook->address = addr; 12874640cde1SColin Riley hook->defn = hook_defn; 12884640cde1SColin Riley hook->bp_sp = target.CreateBreakpoint(addr, true, false); 12894640cde1SColin Riley hook->bp_sp->SetCallback(HookCallback, hook.get(), true); 12904640cde1SColin Riley m_runtimeHooks[addr] = hook; 1291b9c1b51eSKate Stone if (log) { 1292b9c1b51eSKate Stone log->Printf("%s - successfully hooked '%s' in '%s' version %" PRIu64 1293b9c1b51eSKate Stone " at 0x%" PRIx64 ".", 1294b9c1b51eSKate Stone __FUNCTION__, hook_defn->name, 1295b9c1b51eSKate Stone module->GetFileSpec().GetFilename().AsCString(), 1296b3f7f69dSAidan Dodds (uint64_t)hook_defn->version, (uint64_t)addr); 12974640cde1SColin Riley } 12984640cde1SColin Riley } 12994640cde1SColin Riley } 13004640cde1SColin Riley 1301b9c1b51eSKate Stone void RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp) { 13024640cde1SColin Riley if (!rsmodule_sp) 13034640cde1SColin Riley return; 13044640cde1SColin Riley 13054640cde1SColin Riley Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 13064640cde1SColin Riley 13074640cde1SColin Riley const ModuleSP module = rsmodule_sp->m_module; 13084640cde1SColin Riley const FileSpec &file = module->GetPlatformFileSpec(); 13094640cde1SColin Riley 131078f339d1SEwan Crawford // Iterate over all of the scripts that we currently know of. 131178f339d1SEwan Crawford // Note: We cant push or pop to m_scripts here or it may invalidate rs_script. 1312b9c1b51eSKate Stone for (const auto &rs_script : m_scripts) { 131378f339d1SEwan Crawford // Extract the expected .so file path for this script. 131478f339d1SEwan Crawford std::string dylib; 131578f339d1SEwan Crawford if (!rs_script->scriptDyLib.get(dylib)) 131678f339d1SEwan Crawford continue; 131778f339d1SEwan Crawford 131878f339d1SEwan Crawford // Only proceed if the module that has loaded corresponds to this script. 131978f339d1SEwan Crawford if (file.GetFilename() != ConstString(dylib.c_str())) 132078f339d1SEwan Crawford continue; 132178f339d1SEwan Crawford 132278f339d1SEwan Crawford // Obtain the script address which we use as a key. 132378f339d1SEwan Crawford lldb::addr_t script; 132478f339d1SEwan Crawford if (!rs_script->script.get(script)) 132578f339d1SEwan Crawford continue; 132678f339d1SEwan Crawford 132778f339d1SEwan Crawford // If we have a script mapping for the current script. 1328b9c1b51eSKate Stone if (m_scriptMappings.find(script) != m_scriptMappings.end()) { 132978f339d1SEwan Crawford // if the module we have stored is different to the one we just received. 1330b9c1b51eSKate Stone if (m_scriptMappings[script] != rsmodule_sp) { 13314640cde1SColin Riley if (log) 1332b9c1b51eSKate Stone log->Printf( 1333b9c1b51eSKate Stone "%s - script %" PRIx64 " wants reassigned to new rsmodule '%s'.", 1334b9c1b51eSKate Stone __FUNCTION__, (uint64_t)script, 1335b9c1b51eSKate Stone rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); 13364640cde1SColin Riley } 13374640cde1SColin Riley } 133878f339d1SEwan Crawford // We don't have a script mapping for the current script. 1339b9c1b51eSKate Stone else { 134078f339d1SEwan Crawford // Obtain the script resource name. 134178f339d1SEwan Crawford std::string resName; 134278f339d1SEwan Crawford if (rs_script->resName.get(resName)) 134378f339d1SEwan Crawford // Set the modules resource name. 134478f339d1SEwan Crawford rsmodule_sp->m_resname = resName; 134578f339d1SEwan Crawford // Add Script/Module pair to map. 134678f339d1SEwan Crawford m_scriptMappings[script] = rsmodule_sp; 13474640cde1SColin Riley if (log) 1348b9c1b51eSKate Stone log->Printf( 1349b9c1b51eSKate Stone "%s - script %" PRIx64 " associated with rsmodule '%s'.", 1350b9c1b51eSKate Stone __FUNCTION__, (uint64_t)script, 1351b9c1b51eSKate Stone rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); 13524640cde1SColin Riley } 13534640cde1SColin Riley } 13544640cde1SColin Riley } 13554640cde1SColin Riley 1356b9c1b51eSKate Stone // Uses the Target API to evaluate the expression passed as a parameter to the 1357b9c1b51eSKate Stone // function 1358b9c1b51eSKate Stone // The result of that expression is returned an unsigned 64 bit int, via the 1359b9c1b51eSKate Stone // result* parameter. 136015f2bd95SEwan Crawford // Function returns true on success, and false on failure 1361b9c1b51eSKate Stone bool RenderScriptRuntime::EvalRSExpression(const char *expression, 1362b9c1b51eSKate Stone StackFrame *frame_ptr, 1363b9c1b51eSKate Stone uint64_t *result) { 136415f2bd95SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 136515f2bd95SEwan Crawford if (log) 1366b3f7f69dSAidan Dodds log->Printf("%s(%s)", __FUNCTION__, expression); 136715f2bd95SEwan Crawford 136815f2bd95SEwan Crawford ValueObjectSP expr_result; 13698433fdbeSAidan Dodds EvaluateExpressionOptions options; 13708433fdbeSAidan Dodds options.SetLanguage(lldb::eLanguageTypeC_plus_plus); 137115f2bd95SEwan Crawford // Perform the actual expression evaluation 1372b9c1b51eSKate Stone GetProcess()->GetTarget().EvaluateExpression(expression, frame_ptr, 1373b9c1b51eSKate Stone expr_result, options); 137415f2bd95SEwan Crawford 1375b9c1b51eSKate Stone if (!expr_result) { 137615f2bd95SEwan Crawford if (log) 1377b3f7f69dSAidan Dodds log->Printf("%s: couldn't evaluate expression.", __FUNCTION__); 137815f2bd95SEwan Crawford return false; 137915f2bd95SEwan Crawford } 138015f2bd95SEwan Crawford 138115f2bd95SEwan Crawford // The result of the expression is invalid 1382b9c1b51eSKate Stone if (!expr_result->GetError().Success()) { 138315f2bd95SEwan Crawford Error err = expr_result->GetError(); 1384b9c1b51eSKate Stone if (err.GetError() == UserExpression::kNoResult) // Expression returned 1385b9c1b51eSKate Stone // void, so this is 1386b9c1b51eSKate Stone // actually a success 138715f2bd95SEwan Crawford { 138815f2bd95SEwan Crawford if (log) 1389b3f7f69dSAidan Dodds log->Printf("%s - expression returned void.", __FUNCTION__); 139015f2bd95SEwan Crawford 139115f2bd95SEwan Crawford result = nullptr; 139215f2bd95SEwan Crawford return true; 139315f2bd95SEwan Crawford } 139415f2bd95SEwan Crawford 139515f2bd95SEwan Crawford if (log) 1396b3f7f69dSAidan Dodds log->Printf("%s - error evaluating expression result: %s", __FUNCTION__, 1397b3f7f69dSAidan Dodds err.AsCString()); 139815f2bd95SEwan Crawford return false; 139915f2bd95SEwan Crawford } 140015f2bd95SEwan Crawford 140115f2bd95SEwan Crawford bool success = false; 1402b9c1b51eSKate Stone *result = expr_result->GetValueAsUnsigned( 1403b9c1b51eSKate Stone 0, &success); // We only read the result as an uint32_t. 140415f2bd95SEwan Crawford 1405b9c1b51eSKate Stone if (!success) { 140615f2bd95SEwan Crawford if (log) 1407b9c1b51eSKate Stone log->Printf("%s - couldn't convert expression result to uint32_t", 1408b9c1b51eSKate Stone __FUNCTION__); 140915f2bd95SEwan Crawford return false; 141015f2bd95SEwan Crawford } 141115f2bd95SEwan Crawford 141215f2bd95SEwan Crawford return true; 141315f2bd95SEwan Crawford } 141415f2bd95SEwan Crawford 1415b9c1b51eSKate Stone namespace { 1416836d9651SEwan Crawford // Used to index expression format strings 1417b9c1b51eSKate Stone enum ExpressionStrings { 1418836d9651SEwan Crawford eExprGetOffsetPtr = 0, 1419836d9651SEwan Crawford eExprAllocGetType, 1420836d9651SEwan Crawford eExprTypeDimX, 1421836d9651SEwan Crawford eExprTypeDimY, 1422836d9651SEwan Crawford eExprTypeDimZ, 1423836d9651SEwan Crawford eExprTypeElemPtr, 1424836d9651SEwan Crawford eExprElementType, 1425836d9651SEwan Crawford eExprElementKind, 1426836d9651SEwan Crawford eExprElementVec, 1427836d9651SEwan Crawford eExprElementFieldCount, 1428836d9651SEwan Crawford eExprSubelementsId, 1429836d9651SEwan Crawford eExprSubelementsName, 1430ea0636b5SEwan Crawford eExprSubelementsArrSize, 1431ea0636b5SEwan Crawford 1432ea0636b5SEwan Crawford _eExprLast // keep at the end, implicit size of the array runtimeExpressions 1433836d9651SEwan Crawford }; 143415f2bd95SEwan Crawford 1435ea0636b5SEwan Crawford // max length of an expanded expression 1436ea0636b5SEwan Crawford const int jit_max_expr_size = 512; 1437ea0636b5SEwan Crawford 1438ea0636b5SEwan Crawford // Retrieve the string to JIT for the given expression 1439b9c1b51eSKate Stone const char *JITTemplate(ExpressionStrings e) { 1440ea0636b5SEwan Crawford // Format strings containing the expressions we may need to evaluate. 1441b9c1b51eSKate Stone static std::array<const char *, _eExprLast> runtimeExpressions = { 1442b9c1b51eSKate Stone {// Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap) 1443b9c1b51eSKate Stone "(int*)_" 1444b9c1b51eSKate Stone "Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocation" 1445b9c1b51eSKate Stone "CubemapFace" 1446577570b4SAidan Dodds "(0x%" PRIx64 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", 0, 0)", 144715f2bd95SEwan Crawford 144815f2bd95SEwan Crawford // Type* rsaAllocationGetType(Context*, Allocation*) 1449577570b4SAidan Dodds "(void*)rsaAllocationGetType(0x%" PRIx64 ", 0x%" PRIx64 ")", 145015f2bd95SEwan Crawford 145115f2bd95SEwan Crawford // rsaTypeGetNativeData(Context*, Type*, void* typeData, size) 1452b9c1b51eSKate Stone // Pack the data in the following way mHal.state.dimX; mHal.state.dimY; 1453b9c1b51eSKate Stone // mHal.state.dimZ; 145415f2bd95SEwan Crawford // mHal.state.lodCount; mHal.state.faces; mElement; into typeData 1455b9c1b51eSKate Stone // Need to specify 32 or 64 bit for uint_t since this differs between 1456b9c1b51eSKate Stone // devices 1457b9c1b51eSKate Stone "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 1458b9c1b51eSKate Stone ", 0x%" PRIx64 ", data, 6); data[0]", // X dim 1459b9c1b51eSKate Stone "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 1460b9c1b51eSKate Stone ", 0x%" PRIx64 ", data, 6); data[1]", // Y dim 1461b9c1b51eSKate Stone "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 1462b9c1b51eSKate Stone ", 0x%" PRIx64 ", data, 6); data[2]", // Z dim 1463b9c1b51eSKate Stone "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 1464b9c1b51eSKate Stone ", 0x%" PRIx64 ", data, 6); data[5]", // Element ptr 146515f2bd95SEwan Crawford 146615f2bd95SEwan Crawford // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size) 1467b9c1b51eSKate Stone // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into 1468b9c1b51eSKate Stone // elemData 1469b9c1b51eSKate Stone "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 1470b9c1b51eSKate Stone ", 0x%" PRIx64 ", data, 5); data[0]", // Type 1471b9c1b51eSKate Stone "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 1472b9c1b51eSKate Stone ", 0x%" PRIx64 ", data, 5); data[1]", // Kind 1473b9c1b51eSKate Stone "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 1474b9c1b51eSKate Stone ", 0x%" PRIx64 ", data, 5); data[3]", // Vector Size 1475b9c1b51eSKate Stone "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 1476b9c1b51eSKate Stone ", 0x%" PRIx64 ", data, 5); data[4]", // Field Count 14778b244e21SEwan Crawford 1478b9c1b51eSKate Stone // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t 1479b9c1b51eSKate Stone // *ids, const char **names, 14808b244e21SEwan Crawford // size_t *arraySizes, uint32_t dataSize) 1481b9c1b51eSKate Stone // Needed for Allocations of structs to gather details about 1482b9c1b51eSKate Stone // fields/Subelements 1483577570b4SAidan Dodds // Element* of field 1484b9c1b51eSKate Stone "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 1485b9c1b51eSKate Stone "]; size_t arr_size[%" PRIu32 "];" 1486b9c1b51eSKate Stone "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64 1487b9c1b51eSKate Stone ", ids, names, arr_size, %" PRIu32 "); ids[%" PRIu32 "]", 14888b244e21SEwan Crawford 1489577570b4SAidan Dodds // Name of field 1490b9c1b51eSKate Stone "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 1491b9c1b51eSKate Stone "]; size_t arr_size[%" PRIu32 "];" 1492b9c1b51eSKate Stone "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64 1493b9c1b51eSKate Stone ", ids, names, arr_size, %" PRIu32 "); names[%" PRIu32 "]", 14948b244e21SEwan Crawford 1495577570b4SAidan Dodds // Array size of field 1496b9c1b51eSKate Stone "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 1497b9c1b51eSKate Stone "]; size_t arr_size[%" PRIu32 "];" 1498b9c1b51eSKate Stone "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64 1499b9c1b51eSKate Stone ", ids, names, arr_size, %" PRIu32 "); arr_size[%" PRIu32 "]"}}; 1500ea0636b5SEwan Crawford 1501ea0636b5SEwan Crawford return runtimeExpressions[e]; 1502ea0636b5SEwan Crawford } 1503ea0636b5SEwan Crawford } // end of the anonymous namespace 1504ea0636b5SEwan Crawford 150515f2bd95SEwan Crawford // JITs the RS runtime for the internal data pointer of an allocation. 150615f2bd95SEwan Crawford // Is passed x,y,z coordinates for the pointer to a specific element. 150715f2bd95SEwan Crawford // Then sets the data_ptr member in Allocation with the result. 150815f2bd95SEwan Crawford // Returns true on success, false otherwise 1509b9c1b51eSKate Stone bool RenderScriptRuntime::JITDataPointer(AllocationDetails *allocation, 1510b9c1b51eSKate Stone StackFrame *frame_ptr, uint32_t x, 1511b9c1b51eSKate Stone uint32_t y, uint32_t z) { 151215f2bd95SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 151315f2bd95SEwan Crawford 1514b9c1b51eSKate Stone if (!allocation->address.isValid()) { 151515f2bd95SEwan Crawford if (log) 1516b3f7f69dSAidan Dodds log->Printf("%s - failed to find allocation details.", __FUNCTION__); 151715f2bd95SEwan Crawford return false; 151815f2bd95SEwan Crawford } 151915f2bd95SEwan Crawford 1520ea0636b5SEwan Crawford const char *expr_cstr = JITTemplate(eExprGetOffsetPtr); 1521ea0636b5SEwan Crawford char buffer[jit_max_expr_size]; 152215f2bd95SEwan Crawford 1523b9c1b51eSKate Stone int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, 1524b9c1b51eSKate Stone *allocation->address.get(), x, y, z); 1525b9c1b51eSKate Stone if (chars_written < 0) { 152615f2bd95SEwan Crawford if (log) 1527b3f7f69dSAidan Dodds log->Printf("%s - encoding error in snprintf().", __FUNCTION__); 152815f2bd95SEwan Crawford return false; 1529b9c1b51eSKate Stone } else if (chars_written >= jit_max_expr_size) { 153015f2bd95SEwan Crawford if (log) 1531b3f7f69dSAidan Dodds log->Printf("%s - expression too long.", __FUNCTION__); 153215f2bd95SEwan Crawford return false; 153315f2bd95SEwan Crawford } 153415f2bd95SEwan Crawford 153515f2bd95SEwan Crawford uint64_t result = 0; 153615f2bd95SEwan Crawford if (!EvalRSExpression(buffer, frame_ptr, &result)) 153715f2bd95SEwan Crawford return false; 153815f2bd95SEwan Crawford 153915f2bd95SEwan Crawford addr_t mem_ptr = static_cast<lldb::addr_t>(result); 154015f2bd95SEwan Crawford allocation->data_ptr = mem_ptr; 154115f2bd95SEwan Crawford 154215f2bd95SEwan Crawford return true; 154315f2bd95SEwan Crawford } 154415f2bd95SEwan Crawford 154515f2bd95SEwan Crawford // JITs the RS runtime for the internal pointer to the RS Type of an allocation 154615f2bd95SEwan Crawford // Then sets the type_ptr member in Allocation with the result. 154715f2bd95SEwan Crawford // Returns true on success, false otherwise 1548b9c1b51eSKate Stone bool RenderScriptRuntime::JITTypePointer(AllocationDetails *allocation, 1549b9c1b51eSKate Stone StackFrame *frame_ptr) { 155015f2bd95SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 155115f2bd95SEwan Crawford 1552b9c1b51eSKate Stone if (!allocation->address.isValid() || !allocation->context.isValid()) { 155315f2bd95SEwan Crawford if (log) 1554b3f7f69dSAidan Dodds log->Printf("%s - failed to find allocation details.", __FUNCTION__); 155515f2bd95SEwan Crawford return false; 155615f2bd95SEwan Crawford } 155715f2bd95SEwan Crawford 1558ea0636b5SEwan Crawford const char *expr_cstr = JITTemplate(eExprAllocGetType); 1559ea0636b5SEwan Crawford char buffer[jit_max_expr_size]; 156015f2bd95SEwan Crawford 1561ea0636b5SEwan Crawford int chars_written = 1562b9c1b51eSKate Stone snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->context.get(), 1563b9c1b51eSKate Stone *allocation->address.get()); 1564b9c1b51eSKate Stone if (chars_written < 0) { 156515f2bd95SEwan Crawford if (log) 1566b3f7f69dSAidan Dodds log->Printf("%s - encoding error in snprintf().", __FUNCTION__); 156715f2bd95SEwan Crawford return false; 1568b9c1b51eSKate Stone } else if (chars_written >= jit_max_expr_size) { 156915f2bd95SEwan Crawford if (log) 1570b3f7f69dSAidan Dodds log->Printf("%s - expression too long.", __FUNCTION__); 157115f2bd95SEwan Crawford return false; 157215f2bd95SEwan Crawford } 157315f2bd95SEwan Crawford 157415f2bd95SEwan Crawford uint64_t result = 0; 157515f2bd95SEwan Crawford if (!EvalRSExpression(buffer, frame_ptr, &result)) 157615f2bd95SEwan Crawford return false; 157715f2bd95SEwan Crawford 157815f2bd95SEwan Crawford addr_t type_ptr = static_cast<lldb::addr_t>(result); 157915f2bd95SEwan Crawford allocation->type_ptr = type_ptr; 158015f2bd95SEwan Crawford 158115f2bd95SEwan Crawford return true; 158215f2bd95SEwan Crawford } 158315f2bd95SEwan Crawford 1584b9c1b51eSKate Stone // JITs the RS runtime for information about the dimensions and type of an 1585b9c1b51eSKate Stone // allocation 158615f2bd95SEwan Crawford // Then sets dimension and element_ptr members in Allocation with the result. 158715f2bd95SEwan Crawford // Returns true on success, false otherwise 1588b9c1b51eSKate Stone bool RenderScriptRuntime::JITTypePacked(AllocationDetails *allocation, 1589b9c1b51eSKate Stone StackFrame *frame_ptr) { 159015f2bd95SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 159115f2bd95SEwan Crawford 1592b9c1b51eSKate Stone if (!allocation->type_ptr.isValid() || !allocation->context.isValid()) { 159315f2bd95SEwan Crawford if (log) 1594b3f7f69dSAidan Dodds log->Printf("%s - Failed to find allocation details.", __FUNCTION__); 159515f2bd95SEwan Crawford return false; 159615f2bd95SEwan Crawford } 159715f2bd95SEwan Crawford 159815f2bd95SEwan Crawford // Expression is different depending on if device is 32 or 64 bit 1599b9c1b51eSKate Stone uint32_t archByteSize = 1600b9c1b51eSKate Stone GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 1601b3f7f69dSAidan Dodds const uint32_t bits = archByteSize == 4 ? 32 : 64; 160215f2bd95SEwan Crawford 160315f2bd95SEwan Crawford // We want 4 elements from packed data 1604b3f7f69dSAidan Dodds const uint32_t num_exprs = 4; 1605b9c1b51eSKate Stone assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1) && 1606b9c1b51eSKate Stone "Invalid number of expressions"); 160715f2bd95SEwan Crawford 1608ea0636b5SEwan Crawford char buffer[num_exprs][jit_max_expr_size]; 160915f2bd95SEwan Crawford uint64_t results[num_exprs]; 161015f2bd95SEwan Crawford 1611b9c1b51eSKate Stone for (uint32_t i = 0; i < num_exprs; ++i) { 1612ea0636b5SEwan Crawford const char *expr_cstr = JITTemplate(ExpressionStrings(eExprTypeDimX + i)); 1613b9c1b51eSKate Stone int chars_written = 1614b9c1b51eSKate Stone snprintf(buffer[i], jit_max_expr_size, expr_cstr, bits, 1615b9c1b51eSKate Stone *allocation->context.get(), *allocation->type_ptr.get()); 1616b9c1b51eSKate Stone if (chars_written < 0) { 161715f2bd95SEwan Crawford if (log) 1618b3f7f69dSAidan Dodds log->Printf("%s - encoding error in snprintf().", __FUNCTION__); 161915f2bd95SEwan Crawford return false; 1620b9c1b51eSKate Stone } else if (chars_written >= jit_max_expr_size) { 162115f2bd95SEwan Crawford if (log) 1622b3f7f69dSAidan Dodds log->Printf("%s - expression too long.", __FUNCTION__); 162315f2bd95SEwan Crawford return false; 162415f2bd95SEwan Crawford } 162515f2bd95SEwan Crawford 162615f2bd95SEwan Crawford // Perform expression evaluation 162715f2bd95SEwan Crawford if (!EvalRSExpression(buffer[i], frame_ptr, &results[i])) 162815f2bd95SEwan Crawford return false; 162915f2bd95SEwan Crawford } 163015f2bd95SEwan Crawford 163115f2bd95SEwan Crawford // Assign results to allocation members 163215f2bd95SEwan Crawford AllocationDetails::Dimension dims; 163315f2bd95SEwan Crawford dims.dim_1 = static_cast<uint32_t>(results[0]); 163415f2bd95SEwan Crawford dims.dim_2 = static_cast<uint32_t>(results[1]); 163515f2bd95SEwan Crawford dims.dim_3 = static_cast<uint32_t>(results[2]); 163615f2bd95SEwan Crawford allocation->dimension = dims; 163715f2bd95SEwan Crawford 163815f2bd95SEwan Crawford addr_t elem_ptr = static_cast<lldb::addr_t>(results[3]); 16398b244e21SEwan Crawford allocation->element.element_ptr = elem_ptr; 164015f2bd95SEwan Crawford 164115f2bd95SEwan Crawford if (log) 1642b9c1b51eSKate Stone log->Printf("%s - dims (%" PRIu32 ", %" PRIu32 ", %" PRIu32 1643b9c1b51eSKate Stone ") Element*: 0x%" PRIx64 ".", 1644b9c1b51eSKate Stone __FUNCTION__, dims.dim_1, dims.dim_2, dims.dim_3, elem_ptr); 164515f2bd95SEwan Crawford 164615f2bd95SEwan Crawford return true; 164715f2bd95SEwan Crawford } 164815f2bd95SEwan Crawford 164915f2bd95SEwan Crawford // JITs the RS runtime for information about the Element of an allocation 1650b9c1b51eSKate Stone // Then sets type, type_vec_size, field_count and type_kind members in Element 1651b9c1b51eSKate Stone // with the result. 165215f2bd95SEwan Crawford // Returns true on success, false otherwise 1653b9c1b51eSKate Stone bool RenderScriptRuntime::JITElementPacked(Element &elem, 1654b9c1b51eSKate Stone const lldb::addr_t context, 1655b9c1b51eSKate Stone StackFrame *frame_ptr) { 165615f2bd95SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 165715f2bd95SEwan Crawford 1658b9c1b51eSKate Stone if (!elem.element_ptr.isValid()) { 165915f2bd95SEwan Crawford if (log) 1660b3f7f69dSAidan Dodds log->Printf("%s - failed to find allocation details.", __FUNCTION__); 166115f2bd95SEwan Crawford return false; 166215f2bd95SEwan Crawford } 166315f2bd95SEwan Crawford 16648b244e21SEwan Crawford // We want 4 elements from packed data 1665b3f7f69dSAidan Dodds const uint32_t num_exprs = 4; 1666b9c1b51eSKate Stone assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1) && 1667b9c1b51eSKate Stone "Invalid number of expressions"); 166815f2bd95SEwan Crawford 1669ea0636b5SEwan Crawford char buffer[num_exprs][jit_max_expr_size]; 167015f2bd95SEwan Crawford uint64_t results[num_exprs]; 167115f2bd95SEwan Crawford 1672b9c1b51eSKate Stone for (uint32_t i = 0; i < num_exprs; i++) { 1673b9c1b51eSKate Stone const char *expr_cstr = 1674b9c1b51eSKate Stone JITTemplate(ExpressionStrings(eExprElementType + i)); 1675b9c1b51eSKate Stone int chars_written = snprintf(buffer[i], jit_max_expr_size, expr_cstr, 1676b9c1b51eSKate Stone context, *elem.element_ptr.get()); 1677b9c1b51eSKate Stone if (chars_written < 0) { 167815f2bd95SEwan Crawford if (log) 1679b3f7f69dSAidan Dodds log->Printf("%s - encoding error in snprintf().", __FUNCTION__); 168015f2bd95SEwan Crawford return false; 1681b9c1b51eSKate Stone } else if (chars_written >= jit_max_expr_size) { 168215f2bd95SEwan Crawford if (log) 1683b3f7f69dSAidan Dodds log->Printf("%s - expression too long.", __FUNCTION__); 168415f2bd95SEwan Crawford return false; 168515f2bd95SEwan Crawford } 168615f2bd95SEwan Crawford 168715f2bd95SEwan Crawford // Perform expression evaluation 168815f2bd95SEwan Crawford if (!EvalRSExpression(buffer[i], frame_ptr, &results[i])) 168915f2bd95SEwan Crawford return false; 169015f2bd95SEwan Crawford } 169115f2bd95SEwan Crawford 169215f2bd95SEwan Crawford // Assign results to allocation members 16938b244e21SEwan Crawford elem.type = static_cast<RenderScriptRuntime::Element::DataType>(results[0]); 1694b9c1b51eSKate Stone elem.type_kind = 1695b9c1b51eSKate Stone static_cast<RenderScriptRuntime::Element::DataKind>(results[1]); 16968b244e21SEwan Crawford elem.type_vec_size = static_cast<uint32_t>(results[2]); 16978b244e21SEwan Crawford elem.field_count = static_cast<uint32_t>(results[3]); 169815f2bd95SEwan Crawford 169915f2bd95SEwan Crawford if (log) 1700b9c1b51eSKate Stone log->Printf("%s - data type %" PRIu32 ", pixel type %" PRIu32 1701b9c1b51eSKate Stone ", vector size %" PRIu32 ", field count %" PRIu32, 1702b9c1b51eSKate Stone __FUNCTION__, *elem.type.get(), *elem.type_kind.get(), 1703b9c1b51eSKate Stone *elem.type_vec_size.get(), *elem.field_count.get()); 17048b244e21SEwan Crawford 1705b9c1b51eSKate Stone // If this Element has subelements then JIT rsaElementGetSubElements() for 1706b9c1b51eSKate Stone // details about its fields 17078b244e21SEwan Crawford if (*elem.field_count.get() > 0 && !JITSubelements(elem, context, frame_ptr)) 17088b244e21SEwan Crawford return false; 17098b244e21SEwan Crawford 17108b244e21SEwan Crawford return true; 17118b244e21SEwan Crawford } 17128b244e21SEwan Crawford 1713b9c1b51eSKate Stone // JITs the RS runtime for information about the subelements/fields of a struct 1714b9c1b51eSKate Stone // allocation 1715b9c1b51eSKate Stone // This is necessary for infering the struct type so we can pretty print the 1716b9c1b51eSKate Stone // allocation's contents. 17178b244e21SEwan Crawford // Returns true on success, false otherwise 1718b9c1b51eSKate Stone bool RenderScriptRuntime::JITSubelements(Element &elem, 1719b9c1b51eSKate Stone const lldb::addr_t context, 1720b9c1b51eSKate Stone StackFrame *frame_ptr) { 17218b244e21SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 17228b244e21SEwan Crawford 1723b9c1b51eSKate Stone if (!elem.element_ptr.isValid() || !elem.field_count.isValid()) { 17248b244e21SEwan Crawford if (log) 1725b3f7f69dSAidan Dodds log->Printf("%s - failed to find allocation details.", __FUNCTION__); 17268b244e21SEwan Crawford return false; 17278b244e21SEwan Crawford } 17288b244e21SEwan Crawford 17298b244e21SEwan Crawford const short num_exprs = 3; 1730b9c1b51eSKate Stone assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1) && 1731b9c1b51eSKate Stone "Invalid number of expressions"); 17328b244e21SEwan Crawford 1733ea0636b5SEwan Crawford char expr_buffer[jit_max_expr_size]; 17348b244e21SEwan Crawford uint64_t results; 17358b244e21SEwan Crawford 17368b244e21SEwan Crawford // Iterate over struct fields. 17378b244e21SEwan Crawford const uint32_t field_count = *elem.field_count.get(); 1738b9c1b51eSKate Stone for (uint32_t field_index = 0; field_index < field_count; ++field_index) { 17398b244e21SEwan Crawford Element child; 1740b9c1b51eSKate Stone for (uint32_t expr_index = 0; expr_index < num_exprs; ++expr_index) { 1741b9c1b51eSKate Stone const char *expr_cstr = 1742b9c1b51eSKate Stone JITTemplate(ExpressionStrings(eExprSubelementsId + expr_index)); 1743b9c1b51eSKate Stone int chars_written = 1744b9c1b51eSKate Stone snprintf(expr_buffer, jit_max_expr_size, expr_cstr, field_count, 1745b9c1b51eSKate Stone field_count, field_count, context, *elem.element_ptr.get(), 1746b9c1b51eSKate Stone field_count, field_index); 1747b9c1b51eSKate Stone if (chars_written < 0) { 17488b244e21SEwan Crawford if (log) 1749b3f7f69dSAidan Dodds log->Printf("%s - encoding error in snprintf().", __FUNCTION__); 17508b244e21SEwan Crawford return false; 1751b9c1b51eSKate Stone } else if (chars_written >= jit_max_expr_size) { 17528b244e21SEwan Crawford if (log) 1753b3f7f69dSAidan Dodds log->Printf("%s - expression too long.", __FUNCTION__); 17548b244e21SEwan Crawford return false; 17558b244e21SEwan Crawford } 17568b244e21SEwan Crawford 17578b244e21SEwan Crawford // Perform expression evaluation 17588b244e21SEwan Crawford if (!EvalRSExpression(expr_buffer, frame_ptr, &results)) 17598b244e21SEwan Crawford return false; 17608b244e21SEwan Crawford 17618b244e21SEwan Crawford if (log) 1762b3f7f69dSAidan Dodds log->Printf("%s - expr result 0x%" PRIx64 ".", __FUNCTION__, results); 17638b244e21SEwan Crawford 1764b9c1b51eSKate Stone switch (expr_index) { 17658b244e21SEwan Crawford case 0: // Element* of child 17668b244e21SEwan Crawford child.element_ptr = static_cast<addr_t>(results); 17678b244e21SEwan Crawford break; 17688b244e21SEwan Crawford case 1: // Name of child 17698b244e21SEwan Crawford { 17708b244e21SEwan Crawford lldb::addr_t address = static_cast<addr_t>(results); 17718b244e21SEwan Crawford Error err; 17728b244e21SEwan Crawford std::string name; 17738b244e21SEwan Crawford GetProcess()->ReadCStringFromMemory(address, name, err); 17748b244e21SEwan Crawford if (!err.Fail()) 17758b244e21SEwan Crawford child.type_name = ConstString(name); 1776b9c1b51eSKate Stone else { 17778b244e21SEwan Crawford if (log) 1778b9c1b51eSKate Stone log->Printf("%s - warning: Couldn't read field name.", 1779b9c1b51eSKate Stone __FUNCTION__); 17808b244e21SEwan Crawford } 17818b244e21SEwan Crawford break; 17828b244e21SEwan Crawford } 17838b244e21SEwan Crawford case 2: // Array size of child 17848b244e21SEwan Crawford child.array_size = static_cast<uint32_t>(results); 17858b244e21SEwan Crawford break; 17868b244e21SEwan Crawford } 17878b244e21SEwan Crawford } 17888b244e21SEwan Crawford 17898b244e21SEwan Crawford // We need to recursively JIT each Element field of the struct since 17908b244e21SEwan Crawford // structs can be nested inside structs. 17918b244e21SEwan Crawford if (!JITElementPacked(child, context, frame_ptr)) 17928b244e21SEwan Crawford return false; 17938b244e21SEwan Crawford elem.children.push_back(child); 17948b244e21SEwan Crawford } 17958b244e21SEwan Crawford 1796b9c1b51eSKate Stone // Try to infer the name of the struct type so we can pretty print the 1797b9c1b51eSKate Stone // allocation contents. 17988b244e21SEwan Crawford FindStructTypeName(elem, frame_ptr); 179915f2bd95SEwan Crawford 180015f2bd95SEwan Crawford return true; 180115f2bd95SEwan Crawford } 180215f2bd95SEwan Crawford 1803a0f08674SEwan Crawford // JITs the RS runtime for the address of the last element in the allocation. 1804b9c1b51eSKate Stone // The `elem_size` parameter represents the size of a single element, including 1805b9c1b51eSKate Stone // padding. 1806a0f08674SEwan Crawford // Which is needed as an offset from the last element pointer. 1807b9c1b51eSKate Stone // Using this offset minus the starting address we can calculate the size of the 1808b9c1b51eSKate Stone // allocation. 1809a0f08674SEwan Crawford // Returns true on success, false otherwise 1810b9c1b51eSKate Stone bool RenderScriptRuntime::JITAllocationSize(AllocationDetails *allocation, 1811b9c1b51eSKate Stone StackFrame *frame_ptr) { 1812a0f08674SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1813a0f08674SEwan Crawford 1814b9c1b51eSKate Stone if (!allocation->address.isValid() || !allocation->dimension.isValid() || 1815b9c1b51eSKate Stone !allocation->data_ptr.isValid() || 1816b9c1b51eSKate Stone !allocation->element.datum_size.isValid()) { 1817a0f08674SEwan Crawford if (log) 1818b3f7f69dSAidan Dodds log->Printf("%s - failed to find allocation details.", __FUNCTION__); 1819a0f08674SEwan Crawford return false; 1820a0f08674SEwan Crawford } 1821a0f08674SEwan Crawford 1822a0f08674SEwan Crawford // Find dimensions 1823b3f7f69dSAidan Dodds uint32_t dim_x = allocation->dimension.get()->dim_1; 1824b3f7f69dSAidan Dodds uint32_t dim_y = allocation->dimension.get()->dim_2; 1825b3f7f69dSAidan Dodds uint32_t dim_z = allocation->dimension.get()->dim_3; 1826a0f08674SEwan Crawford 1827b9c1b51eSKate Stone // Our plan of jitting the last element address doesn't seem to work for 1828b9c1b51eSKate Stone // struct Allocations 18298b244e21SEwan Crawford // Instead try to infer the size ourselves without any inter element padding. 1830b9c1b51eSKate Stone if (allocation->element.children.size() > 0) { 1831b9c1b51eSKate Stone if (dim_x == 0) 1832b9c1b51eSKate Stone dim_x = 1; 1833b9c1b51eSKate Stone if (dim_y == 0) 1834b9c1b51eSKate Stone dim_y = 1; 1835b9c1b51eSKate Stone if (dim_z == 0) 1836b9c1b51eSKate Stone dim_z = 1; 18378b244e21SEwan Crawford 1838b9c1b51eSKate Stone allocation->size = 1839b9c1b51eSKate Stone dim_x * dim_y * dim_z * *allocation->element.datum_size.get(); 18408b244e21SEwan Crawford 18418b244e21SEwan Crawford if (log) 1842b9c1b51eSKate Stone log->Printf("%s - inferred size of struct allocation %" PRIu32 ".", 1843b9c1b51eSKate Stone __FUNCTION__, *allocation->size.get()); 18448b244e21SEwan Crawford return true; 18458b244e21SEwan Crawford } 18468b244e21SEwan Crawford 1847ea0636b5SEwan Crawford const char *expr_cstr = JITTemplate(eExprGetOffsetPtr); 1848ea0636b5SEwan Crawford char buffer[jit_max_expr_size]; 18498b244e21SEwan Crawford 1850a0f08674SEwan Crawford // Calculate last element 1851a0f08674SEwan Crawford dim_x = dim_x == 0 ? 0 : dim_x - 1; 1852a0f08674SEwan Crawford dim_y = dim_y == 0 ? 0 : dim_y - 1; 1853a0f08674SEwan Crawford dim_z = dim_z == 0 ? 0 : dim_z - 1; 1854a0f08674SEwan Crawford 1855b9c1b51eSKate Stone int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, 1856b9c1b51eSKate Stone *allocation->address.get(), dim_x, dim_y, dim_z); 1857b9c1b51eSKate Stone if (chars_written < 0) { 1858a0f08674SEwan Crawford if (log) 1859b3f7f69dSAidan Dodds log->Printf("%s - encoding error in snprintf().", __FUNCTION__); 1860a0f08674SEwan Crawford return false; 1861b9c1b51eSKate Stone } else if (chars_written >= jit_max_expr_size) { 1862a0f08674SEwan Crawford if (log) 1863b3f7f69dSAidan Dodds log->Printf("%s - expression too long.", __FUNCTION__); 1864a0f08674SEwan Crawford return false; 1865a0f08674SEwan Crawford } 1866a0f08674SEwan Crawford 1867a0f08674SEwan Crawford uint64_t result = 0; 1868a0f08674SEwan Crawford if (!EvalRSExpression(buffer, frame_ptr, &result)) 1869a0f08674SEwan Crawford return false; 1870a0f08674SEwan Crawford 1871a0f08674SEwan Crawford addr_t mem_ptr = static_cast<lldb::addr_t>(result); 1872a0f08674SEwan Crawford // Find pointer to last element and add on size of an element 1873b3f7f69dSAidan Dodds allocation->size = 1874b9c1b51eSKate Stone static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()) + 1875b9c1b51eSKate Stone *allocation->element.datum_size.get(); 1876a0f08674SEwan Crawford 1877a0f08674SEwan Crawford return true; 1878a0f08674SEwan Crawford } 1879a0f08674SEwan Crawford 1880b9c1b51eSKate Stone // JITs the RS runtime for information about the stride between rows in the 1881b9c1b51eSKate Stone // allocation. 1882a0f08674SEwan Crawford // This is done to detect padding, since allocated memory is 16-byte aligned. 1883a0f08674SEwan Crawford // Returns true on success, false otherwise 1884b9c1b51eSKate Stone bool RenderScriptRuntime::JITAllocationStride(AllocationDetails *allocation, 1885b9c1b51eSKate Stone StackFrame *frame_ptr) { 1886a0f08674SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1887a0f08674SEwan Crawford 1888b9c1b51eSKate Stone if (!allocation->address.isValid() || !allocation->data_ptr.isValid()) { 1889a0f08674SEwan Crawford if (log) 1890b3f7f69dSAidan Dodds log->Printf("%s - failed to find allocation details.", __FUNCTION__); 1891a0f08674SEwan Crawford return false; 1892a0f08674SEwan Crawford } 1893a0f08674SEwan Crawford 1894ea0636b5SEwan Crawford const char *expr_cstr = JITTemplate(eExprGetOffsetPtr); 1895ea0636b5SEwan Crawford char buffer[jit_max_expr_size]; 1896a0f08674SEwan Crawford 1897b9c1b51eSKate Stone int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, 1898b9c1b51eSKate Stone *allocation->address.get(), 0, 1, 0); 1899b9c1b51eSKate Stone if (chars_written < 0) { 1900a0f08674SEwan Crawford if (log) 1901b3f7f69dSAidan Dodds log->Printf("%s - encoding error in snprintf().", __FUNCTION__); 1902a0f08674SEwan Crawford return false; 1903b9c1b51eSKate Stone } else if (chars_written >= jit_max_expr_size) { 1904a0f08674SEwan Crawford if (log) 1905b3f7f69dSAidan Dodds log->Printf("%s - expression too long.", __FUNCTION__); 1906a0f08674SEwan Crawford return false; 1907a0f08674SEwan Crawford } 1908a0f08674SEwan Crawford 1909a0f08674SEwan Crawford uint64_t result = 0; 1910a0f08674SEwan Crawford if (!EvalRSExpression(buffer, frame_ptr, &result)) 1911a0f08674SEwan Crawford return false; 1912a0f08674SEwan Crawford 1913a0f08674SEwan Crawford addr_t mem_ptr = static_cast<lldb::addr_t>(result); 1914b9c1b51eSKate Stone allocation->stride = 1915b9c1b51eSKate Stone static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()); 1916a0f08674SEwan Crawford 1917a0f08674SEwan Crawford return true; 1918a0f08674SEwan Crawford } 1919a0f08674SEwan Crawford 192015f2bd95SEwan Crawford // JIT all the current runtime info regarding an allocation 1921b9c1b51eSKate Stone bool RenderScriptRuntime::RefreshAllocation(AllocationDetails *allocation, 1922b9c1b51eSKate Stone StackFrame *frame_ptr) { 192315f2bd95SEwan Crawford // GetOffsetPointer() 192415f2bd95SEwan Crawford if (!JITDataPointer(allocation, frame_ptr)) 192515f2bd95SEwan Crawford return false; 192615f2bd95SEwan Crawford 192715f2bd95SEwan Crawford // rsaAllocationGetType() 192815f2bd95SEwan Crawford if (!JITTypePointer(allocation, frame_ptr)) 192915f2bd95SEwan Crawford return false; 193015f2bd95SEwan Crawford 193115f2bd95SEwan Crawford // rsaTypeGetNativeData() 193215f2bd95SEwan Crawford if (!JITTypePacked(allocation, frame_ptr)) 193315f2bd95SEwan Crawford return false; 193415f2bd95SEwan Crawford 193515f2bd95SEwan Crawford // rsaElementGetNativeData() 1936b9c1b51eSKate Stone if (!JITElementPacked(allocation->element, *allocation->context.get(), 1937b9c1b51eSKate Stone frame_ptr)) 193815f2bd95SEwan Crawford return false; 193915f2bd95SEwan Crawford 19408b244e21SEwan Crawford // Sets the datum_size member in Element 19418b244e21SEwan Crawford SetElementSize(allocation->element); 19428b244e21SEwan Crawford 194355232f09SEwan Crawford // Use GetOffsetPointer() to infer size of the allocation 19448b244e21SEwan Crawford if (!JITAllocationSize(allocation, frame_ptr)) 194555232f09SEwan Crawford return false; 194655232f09SEwan Crawford 194755232f09SEwan Crawford return true; 194855232f09SEwan Crawford } 194955232f09SEwan Crawford 1950b9c1b51eSKate Stone // Function attempts to set the type_name member of the paramaterised Element 1951b9c1b51eSKate Stone // object. 19528b244e21SEwan Crawford // This string should be the name of the struct type the Element represents. 19538b244e21SEwan Crawford // We need this string for pretty printing the Element to users. 1954b9c1b51eSKate Stone void RenderScriptRuntime::FindStructTypeName(Element &elem, 1955b9c1b51eSKate Stone StackFrame *frame_ptr) { 19568b244e21SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 19578b244e21SEwan Crawford 19588b244e21SEwan Crawford if (!elem.type_name.IsEmpty()) // Name already set 19598b244e21SEwan Crawford return; 19608b244e21SEwan Crawford else 1961b9c1b51eSKate Stone elem.type_name = Element::GetFallbackStructName(); // Default type name if 1962b9c1b51eSKate Stone // we don't succeed 19638b244e21SEwan Crawford 19648b244e21SEwan Crawford // Find all the global variables from the script rs modules 19658b244e21SEwan Crawford VariableList variable_list; 19668b244e21SEwan Crawford for (auto module_sp : m_rsmodules) 1967b9c1b51eSKate Stone module_sp->m_module->FindGlobalVariables(RegularExpression("."), true, 1968b9c1b51eSKate Stone UINT32_MAX, variable_list); 19698b244e21SEwan Crawford 1970b9c1b51eSKate Stone // Iterate over all the global variables looking for one with a matching type 1971b9c1b51eSKate Stone // to the Element. 1972b9c1b51eSKate Stone // We make the assumption a match exists since there needs to be a global 1973b9c1b51eSKate Stone // variable to reflect the 19748b244e21SEwan Crawford // struct type back into java host code. 1975b9c1b51eSKate Stone for (uint32_t var_index = 0; var_index < variable_list.GetSize(); 1976b9c1b51eSKate Stone ++var_index) { 19778b244e21SEwan Crawford const VariableSP var_sp(variable_list.GetVariableAtIndex(var_index)); 19788b244e21SEwan Crawford if (!var_sp) 19798b244e21SEwan Crawford continue; 19808b244e21SEwan Crawford 19818b244e21SEwan Crawford ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp); 19828b244e21SEwan Crawford if (!valobj_sp) 19838b244e21SEwan Crawford continue; 19848b244e21SEwan Crawford 19858b244e21SEwan Crawford // Find the number of variable fields. 1986b9c1b51eSKate Stone // If it has no fields, or more fields than our Element, then it can't be 1987b9c1b51eSKate Stone // the struct we're looking for. 1988b9c1b51eSKate Stone // Don't check for equality since RS can add extra struct members for 1989b9c1b51eSKate Stone // padding. 19908b244e21SEwan Crawford size_t num_children = valobj_sp->GetNumChildren(); 19918b244e21SEwan Crawford if (num_children > elem.children.size() || num_children == 0) 19928b244e21SEwan Crawford continue; 19938b244e21SEwan Crawford 19948b244e21SEwan Crawford // Iterate over children looking for members with matching field names. 19958b244e21SEwan Crawford // If all the field names match, this is likely the struct we want. 19968b244e21SEwan Crawford // 1997b9c1b51eSKate Stone // TODO: This could be made more robust by also checking children data 1998b9c1b51eSKate Stone // sizes, or array size 19998b244e21SEwan Crawford bool found = true; 2000b9c1b51eSKate Stone for (size_t child_index = 0; child_index < num_children; ++child_index) { 20018b244e21SEwan Crawford ValueObjectSP child = valobj_sp->GetChildAtIndex(child_index, true); 2002b9c1b51eSKate Stone if (!child || 2003b9c1b51eSKate Stone (child->GetName() != elem.children[child_index].type_name)) { 20048b244e21SEwan Crawford found = false; 20058b244e21SEwan Crawford break; 20068b244e21SEwan Crawford } 20078b244e21SEwan Crawford } 20088b244e21SEwan Crawford 2009b9c1b51eSKate Stone // RS can add extra struct members for padding in the format 2010b9c1b51eSKate Stone // '#rs_padding_[0-9]+' 2011b9c1b51eSKate Stone if (found && num_children < elem.children.size()) { 2012b3f7f69dSAidan Dodds const uint32_t size_diff = elem.children.size() - num_children; 20138b244e21SEwan Crawford if (log) 2014b9c1b51eSKate Stone log->Printf("%s - %" PRIu32 " padding struct entries", __FUNCTION__, 2015b9c1b51eSKate Stone size_diff); 20168b244e21SEwan Crawford 2017b9c1b51eSKate Stone for (uint32_t padding_index = 0; padding_index < size_diff; 2018b9c1b51eSKate Stone ++padding_index) { 2019b9c1b51eSKate Stone const ConstString &name = 2020b9c1b51eSKate Stone elem.children[num_children + padding_index].type_name; 20218b244e21SEwan Crawford if (strcmp(name.AsCString(), "#rs_padding") < 0) 20228b244e21SEwan Crawford found = false; 20238b244e21SEwan Crawford } 20248b244e21SEwan Crawford } 20258b244e21SEwan Crawford 20268b244e21SEwan Crawford // We've found a global var with matching type 2027b9c1b51eSKate Stone if (found) { 20288b244e21SEwan Crawford // Dereference since our Element type isn't a pointer. 2029b9c1b51eSKate Stone if (valobj_sp->IsPointerType()) { 20308b244e21SEwan Crawford Error err; 20318b244e21SEwan Crawford ValueObjectSP deref_valobj = valobj_sp->Dereference(err); 20328b244e21SEwan Crawford if (!err.Fail()) 20338b244e21SEwan Crawford valobj_sp = deref_valobj; 20348b244e21SEwan Crawford } 20358b244e21SEwan Crawford 20368b244e21SEwan Crawford // Save name of variable in Element. 20378b244e21SEwan Crawford elem.type_name = valobj_sp->GetTypeName(); 20388b244e21SEwan Crawford if (log) 2039b9c1b51eSKate Stone log->Printf("%s - element name set to %s", __FUNCTION__, 2040b9c1b51eSKate Stone elem.type_name.AsCString()); 20418b244e21SEwan Crawford 20428b244e21SEwan Crawford return; 20438b244e21SEwan Crawford } 20448b244e21SEwan Crawford } 20458b244e21SEwan Crawford } 20468b244e21SEwan Crawford 2047b9c1b51eSKate Stone // Function sets the datum_size member of Element. Representing the size of a 2048b9c1b51eSKate Stone // single instance including padding. 20498b244e21SEwan Crawford // Assumes the relevant allocation information has already been jitted. 2050b9c1b51eSKate Stone void RenderScriptRuntime::SetElementSize(Element &elem) { 20518b244e21SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 20528b244e21SEwan Crawford const Element::DataType type = *elem.type.get(); 2053b9c1b51eSKate Stone assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && 2054b9c1b51eSKate Stone "Invalid allocation type"); 205555232f09SEwan Crawford 2056b3f7f69dSAidan Dodds const uint32_t vec_size = *elem.type_vec_size.get(); 2057b3f7f69dSAidan Dodds uint32_t data_size = 0; 2058b3f7f69dSAidan Dodds uint32_t padding = 0; 205955232f09SEwan Crawford 20608b244e21SEwan Crawford // Element is of a struct type, calculate size recursively. 2061b9c1b51eSKate Stone if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) { 2062b9c1b51eSKate Stone for (Element &child : elem.children) { 20638b244e21SEwan Crawford SetElementSize(child); 2064b9c1b51eSKate Stone const uint32_t array_size = 2065b9c1b51eSKate Stone child.array_size.isValid() ? *child.array_size.get() : 1; 20668b244e21SEwan Crawford data_size += *child.datum_size.get() * array_size; 20678b244e21SEwan Crawford } 20688b244e21SEwan Crawford } 2069b3f7f69dSAidan Dodds // These have been packed already 2070b3f7f69dSAidan Dodds else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 || 2071b3f7f69dSAidan Dodds type == Element::RS_TYPE_UNSIGNED_5_5_5_1 || 2072b9c1b51eSKate Stone type == Element::RS_TYPE_UNSIGNED_4_4_4_4) { 20732e920715SEwan Crawford data_size = AllocationDetails::RSTypeToFormat[type][eElementSize]; 2074b9c1b51eSKate Stone } else if (type < Element::RS_TYPE_ELEMENT) { 2075b9c1b51eSKate Stone data_size = 2076b9c1b51eSKate Stone vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize]; 20772e920715SEwan Crawford if (vec_size == 3) 20782e920715SEwan Crawford padding = AllocationDetails::RSTypeToFormat[type][eElementSize]; 2079b9c1b51eSKate Stone } else 2080b9c1b51eSKate Stone data_size = 2081b9c1b51eSKate Stone GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 20828b244e21SEwan Crawford 20838b244e21SEwan Crawford elem.padding = padding; 20848b244e21SEwan Crawford elem.datum_size = data_size + padding; 20858b244e21SEwan Crawford if (log) 2086b9c1b51eSKate Stone log->Printf("%s - element size set to %" PRIu32, __FUNCTION__, 2087b9c1b51eSKate Stone data_size + padding); 208855232f09SEwan Crawford } 208955232f09SEwan Crawford 2090b9c1b51eSKate Stone // Given an allocation, this function copies the allocation contents from device 2091b9c1b51eSKate Stone // into a buffer on the heap. 209255232f09SEwan Crawford // Returning a shared pointer to the buffer containing the data. 209355232f09SEwan Crawford std::shared_ptr<uint8_t> 2094b9c1b51eSKate Stone RenderScriptRuntime::GetAllocationData(AllocationDetails *allocation, 2095b9c1b51eSKate Stone StackFrame *frame_ptr) { 209655232f09SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 209755232f09SEwan Crawford 209855232f09SEwan Crawford // JIT all the allocation details 2099b9c1b51eSKate Stone if (allocation->shouldRefresh()) { 210055232f09SEwan Crawford if (log) 2101b9c1b51eSKate Stone log->Printf("%s - allocation details not calculated yet, jitting info", 2102b9c1b51eSKate Stone __FUNCTION__); 210355232f09SEwan Crawford 2104b9c1b51eSKate Stone if (!RefreshAllocation(allocation, frame_ptr)) { 210555232f09SEwan Crawford if (log) 2106b3f7f69dSAidan Dodds log->Printf("%s - couldn't JIT allocation details", __FUNCTION__); 210755232f09SEwan Crawford return nullptr; 210855232f09SEwan Crawford } 210955232f09SEwan Crawford } 211055232f09SEwan Crawford 2111b3f7f69dSAidan Dodds assert(allocation->data_ptr.isValid() && allocation->element.type.isValid() && 2112b9c1b51eSKate Stone allocation->element.type_vec_size.isValid() && 2113b9c1b51eSKate Stone allocation->size.isValid() && "Allocation information not available"); 211455232f09SEwan Crawford 211555232f09SEwan Crawford // Allocate a buffer to copy data into 2116b3f7f69dSAidan Dodds const uint32_t size = *allocation->size.get(); 211755232f09SEwan Crawford std::shared_ptr<uint8_t> buffer(new uint8_t[size]); 2118b9c1b51eSKate Stone if (!buffer) { 211955232f09SEwan Crawford if (log) 2120b9c1b51eSKate Stone log->Printf("%s - couldn't allocate a %" PRIu32 " byte buffer", 2121b9c1b51eSKate Stone __FUNCTION__, size); 212255232f09SEwan Crawford return nullptr; 212355232f09SEwan Crawford } 212455232f09SEwan Crawford 212555232f09SEwan Crawford // Read the inferior memory 212655232f09SEwan Crawford Error error; 212755232f09SEwan Crawford lldb::addr_t data_ptr = *allocation->data_ptr.get(); 212855232f09SEwan Crawford GetProcess()->ReadMemory(data_ptr, buffer.get(), size, error); 2129b9c1b51eSKate Stone if (error.Fail()) { 213055232f09SEwan Crawford if (log) 2131b9c1b51eSKate Stone log->Printf("%s - '%s' Couldn't read %" PRIu32 2132b9c1b51eSKate Stone " bytes of allocation data from 0x%" PRIx64, 2133b3f7f69dSAidan Dodds __FUNCTION__, error.AsCString(), size, data_ptr); 213455232f09SEwan Crawford return nullptr; 213555232f09SEwan Crawford } 213655232f09SEwan Crawford 213755232f09SEwan Crawford return buffer; 213855232f09SEwan Crawford } 213955232f09SEwan Crawford 214055232f09SEwan Crawford // Function copies data from a binary file into an allocation. 2141b9c1b51eSKate Stone // There is a header at the start of the file, FileHeader, before the data 2142b9c1b51eSKate Stone // content itself. 2143b9c1b51eSKate Stone // Information from this header is used to display warnings to the user about 2144b9c1b51eSKate Stone // incompatibilities 2145b9c1b51eSKate Stone bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, 2146b9c1b51eSKate Stone const char *filename, 2147b9c1b51eSKate Stone StackFrame *frame_ptr) { 214855232f09SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 214955232f09SEwan Crawford 215055232f09SEwan Crawford // Find allocation with the given id 215155232f09SEwan Crawford AllocationDetails *alloc = FindAllocByID(strm, alloc_id); 215255232f09SEwan Crawford if (!alloc) 215355232f09SEwan Crawford return false; 215455232f09SEwan Crawford 215555232f09SEwan Crawford if (log) 2156b9c1b51eSKate Stone log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__, 2157b9c1b51eSKate Stone *alloc->address.get()); 215855232f09SEwan Crawford 215955232f09SEwan Crawford // JIT all the allocation details 2160b9c1b51eSKate Stone if (alloc->shouldRefresh()) { 216155232f09SEwan Crawford if (log) 2162b9c1b51eSKate Stone log->Printf("%s - allocation details not calculated yet, jitting info.", 2163b9c1b51eSKate Stone __FUNCTION__); 216455232f09SEwan Crawford 2165b9c1b51eSKate Stone if (!RefreshAllocation(alloc, frame_ptr)) { 216655232f09SEwan Crawford if (log) 2167b3f7f69dSAidan Dodds log->Printf("%s - couldn't JIT allocation details", __FUNCTION__); 21684cfc9198SSylvestre Ledru return false; 216955232f09SEwan Crawford } 217055232f09SEwan Crawford } 217155232f09SEwan Crawford 2172b9c1b51eSKate Stone assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && 2173b9c1b51eSKate Stone alloc->element.type_vec_size.isValid() && alloc->size.isValid() && 2174b9c1b51eSKate Stone alloc->element.datum_size.isValid() && 2175b9c1b51eSKate Stone "Allocation information not available"); 217655232f09SEwan Crawford 217755232f09SEwan Crawford // Check we can read from file 217855232f09SEwan Crawford FileSpec file(filename, true); 2179b9c1b51eSKate Stone if (!file.Exists()) { 218055232f09SEwan Crawford strm.Printf("Error: File %s does not exist", filename); 218155232f09SEwan Crawford strm.EOL(); 218255232f09SEwan Crawford return false; 218355232f09SEwan Crawford } 218455232f09SEwan Crawford 2185b9c1b51eSKate Stone if (!file.Readable()) { 218655232f09SEwan Crawford strm.Printf("Error: File %s does not have readable permissions", filename); 218755232f09SEwan Crawford strm.EOL(); 218855232f09SEwan Crawford return false; 218955232f09SEwan Crawford } 219055232f09SEwan Crawford 219155232f09SEwan Crawford // Read file into data buffer 219255232f09SEwan Crawford DataBufferSP data_sp(file.ReadFileContents()); 219355232f09SEwan Crawford 219455232f09SEwan Crawford // Cast start of buffer to FileHeader and use pointer to read metadata 219555232f09SEwan Crawford void *file_buffer = data_sp->GetBytes(); 2196b3f7f69dSAidan Dodds if (file_buffer == nullptr || 2197b9c1b51eSKate Stone data_sp->GetByteSize() < (sizeof(AllocationDetails::FileHeader) + 2198b9c1b51eSKate Stone sizeof(AllocationDetails::ElementHeader))) { 2199b9c1b51eSKate Stone strm.Printf("Error: File %s does not contain enough data for header", 2200b9c1b51eSKate Stone filename); 220126e52a70SEwan Crawford strm.EOL(); 220226e52a70SEwan Crawford return false; 220326e52a70SEwan Crawford } 2204b9c1b51eSKate Stone const AllocationDetails::FileHeader *file_header = 2205b9c1b51eSKate Stone static_cast<AllocationDetails::FileHeader *>(file_buffer); 220655232f09SEwan Crawford 220726e52a70SEwan Crawford // Check file starts with ascii characters "RSAD" 2208b9c1b51eSKate Stone if (memcmp(file_header->ident, "RSAD", 4)) { 2209b9c1b51eSKate Stone strm.Printf("Error: File doesn't contain identifier for an RS allocation " 2210b9c1b51eSKate Stone "dump. Are you sure this is the correct file?"); 221126e52a70SEwan Crawford strm.EOL(); 221226e52a70SEwan Crawford return false; 221326e52a70SEwan Crawford } 221426e52a70SEwan Crawford 221526e52a70SEwan Crawford // Look at the type of the root element in the header 221626e52a70SEwan Crawford AllocationDetails::ElementHeader root_element_header; 2217b9c1b51eSKate Stone memcpy(&root_element_header, static_cast<uint8_t *>(file_buffer) + 2218b9c1b51eSKate Stone sizeof(AllocationDetails::FileHeader), 221926e52a70SEwan Crawford sizeof(AllocationDetails::ElementHeader)); 222055232f09SEwan Crawford 222155232f09SEwan Crawford if (log) 2222b9c1b51eSKate Stone log->Printf("%s - header type %" PRIu32 ", element size %" PRIu32, 2223b9c1b51eSKate Stone __FUNCTION__, root_element_header.type, 2224b9c1b51eSKate Stone root_element_header.element_size); 222555232f09SEwan Crawford 2226b9c1b51eSKate Stone // Check if the target allocation and file both have the same number of bytes 2227b9c1b51eSKate Stone // for an Element 2228b9c1b51eSKate Stone if (*alloc->element.datum_size.get() != root_element_header.element_size) { 2229b9c1b51eSKate Stone strm.Printf("Warning: Mismatched Element sizes - file %" PRIu32 2230b9c1b51eSKate Stone " bytes, allocation %" PRIu32 " bytes", 2231b9c1b51eSKate Stone root_element_header.element_size, 2232b9c1b51eSKate Stone *alloc->element.datum_size.get()); 223355232f09SEwan Crawford strm.EOL(); 223455232f09SEwan Crawford } 223555232f09SEwan Crawford 223626e52a70SEwan Crawford // Check if the target allocation and file both have the same type 2237b3f7f69dSAidan Dodds const uint32_t alloc_type = static_cast<uint32_t>(*alloc->element.type.get()); 2238b3f7f69dSAidan Dodds const uint32_t file_type = root_element_header.type; 223926e52a70SEwan Crawford 2240b9c1b51eSKate Stone if (file_type > Element::RS_TYPE_FONT) { 224126e52a70SEwan Crawford strm.Printf("Warning: File has unknown allocation type"); 224226e52a70SEwan Crawford strm.EOL(); 2243b9c1b51eSKate Stone } else if (alloc_type != file_type) { 2244b9c1b51eSKate Stone // Enum value isn't monotonous, so doesn't always index RsDataTypeToString 2245b9c1b51eSKate Stone // array 2246b3f7f69dSAidan Dodds uint32_t printable_target_type_index = alloc_type; 2247b3f7f69dSAidan Dodds uint32_t printable_head_type_index = file_type; 2248b9c1b51eSKate Stone if (alloc_type >= Element::RS_TYPE_ELEMENT && 2249b9c1b51eSKate Stone alloc_type <= Element::RS_TYPE_FONT) 2250b9c1b51eSKate Stone printable_target_type_index = static_cast<Element::DataType>( 2251b9c1b51eSKate Stone (alloc_type - Element::RS_TYPE_ELEMENT) + 2252b3f7f69dSAidan Dodds Element::RS_TYPE_MATRIX_2X2 + 1); 22532e920715SEwan Crawford 2254b9c1b51eSKate Stone if (file_type >= Element::RS_TYPE_ELEMENT && 2255b9c1b51eSKate Stone file_type <= Element::RS_TYPE_FONT) 2256b9c1b51eSKate Stone printable_head_type_index = static_cast<Element::DataType>( 2257b9c1b51eSKate Stone (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 2258b9c1b51eSKate Stone 1); 22592e920715SEwan Crawford 2260b9c1b51eSKate Stone const char *file_type_cstr = 2261b9c1b51eSKate Stone AllocationDetails::RsDataTypeToString[printable_head_type_index][0]; 2262b9c1b51eSKate Stone const char *target_type_cstr = 2263b9c1b51eSKate Stone AllocationDetails::RsDataTypeToString[printable_target_type_index][0]; 226455232f09SEwan Crawford 2265b9c1b51eSKate Stone strm.Printf( 2266b9c1b51eSKate Stone "Warning: Mismatched Types - file '%s' type, allocation '%s' type", 2267b9c1b51eSKate Stone file_type_cstr, target_type_cstr); 226855232f09SEwan Crawford strm.EOL(); 226955232f09SEwan Crawford } 227055232f09SEwan Crawford 227126e52a70SEwan Crawford // Advance buffer past header 227226e52a70SEwan Crawford file_buffer = static_cast<uint8_t *>(file_buffer) + file_header->hdr_size; 227326e52a70SEwan Crawford 227455232f09SEwan Crawford // Calculate size of allocation data in file 227526e52a70SEwan Crawford size_t length = data_sp->GetByteSize() - file_header->hdr_size; 227655232f09SEwan Crawford 227755232f09SEwan Crawford // Check if the target allocation and file both have the same total data size. 2278b3f7f69dSAidan Dodds const uint32_t alloc_size = *alloc->size.get(); 2279b9c1b51eSKate Stone if (alloc_size != length) { 2280b9c1b51eSKate Stone strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64 2281b9c1b51eSKate Stone " bytes, allocation 0x%" PRIx32 " bytes", 2282eba832beSJason Molenda (uint64_t)length, alloc_size); 228355232f09SEwan Crawford strm.EOL(); 2284b9c1b51eSKate Stone length = alloc_size < length ? alloc_size 2285b9c1b51eSKate Stone : length; // Set length to copy to minimum 228655232f09SEwan Crawford } 228755232f09SEwan Crawford 228855232f09SEwan Crawford // Copy file data from our buffer into the target allocation. 228955232f09SEwan Crawford lldb::addr_t alloc_data = *alloc->data_ptr.get(); 229055232f09SEwan Crawford Error error; 2291b9c1b51eSKate Stone size_t bytes_written = 2292b9c1b51eSKate Stone GetProcess()->WriteMemory(alloc_data, file_buffer, length, error); 2293b9c1b51eSKate Stone if (!error.Success() || bytes_written != length) { 2294b9c1b51eSKate Stone strm.Printf("Error: Couldn't write data to allocation %s", 2295b9c1b51eSKate Stone error.AsCString()); 229655232f09SEwan Crawford strm.EOL(); 229755232f09SEwan Crawford return false; 229855232f09SEwan Crawford } 229955232f09SEwan Crawford 2300b9c1b51eSKate Stone strm.Printf("Contents of file '%s' read into allocation %" PRIu32, filename, 2301b9c1b51eSKate Stone alloc->id); 230255232f09SEwan Crawford strm.EOL(); 230355232f09SEwan Crawford 230455232f09SEwan Crawford return true; 230555232f09SEwan Crawford } 230655232f09SEwan Crawford 2307b9c1b51eSKate Stone // Function takes as parameters a byte buffer, which will eventually be written 2308b9c1b51eSKate Stone // to file as the element header, 2309b9c1b51eSKate Stone // an offset into that buffer, and an Element that will be saved into the buffer 2310b9c1b51eSKate Stone // at the parametrised offset. 231126e52a70SEwan Crawford // Return value is the new offset after writing the element into the buffer. 2312b9c1b51eSKate Stone // Elements are saved to the file as the ElementHeader struct followed by 2313b9c1b51eSKate Stone // offsets to the structs of all the element's 2314b3f7f69dSAidan Dodds // children. 2315b9c1b51eSKate Stone size_t RenderScriptRuntime::PopulateElementHeaders( 2316b9c1b51eSKate Stone const std::shared_ptr<uint8_t> header_buffer, size_t offset, 2317b9c1b51eSKate Stone const Element &elem) { 2318b9c1b51eSKate Stone // File struct for an element header with all the relevant details copied from 2319b9c1b51eSKate Stone // elem. 232026e52a70SEwan Crawford // We assume members are valid already. 232126e52a70SEwan Crawford AllocationDetails::ElementHeader elem_header; 232226e52a70SEwan Crawford elem_header.type = *elem.type.get(); 232326e52a70SEwan Crawford elem_header.kind = *elem.type_kind.get(); 232426e52a70SEwan Crawford elem_header.element_size = *elem.datum_size.get(); 232526e52a70SEwan Crawford elem_header.vector_size = *elem.type_vec_size.get(); 2326b9c1b51eSKate Stone elem_header.array_size = 2327b9c1b51eSKate Stone elem.array_size.isValid() ? *elem.array_size.get() : 0; 232826e52a70SEwan Crawford const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader); 232926e52a70SEwan Crawford 233026e52a70SEwan Crawford // Copy struct into buffer and advance offset 2331b9c1b51eSKate Stone // We assume that header_buffer has been checked for nullptr before this 2332b9c1b51eSKate Stone // method is called 233326e52a70SEwan Crawford memcpy(header_buffer.get() + offset, &elem_header, elem_header_size); 233426e52a70SEwan Crawford offset += elem_header_size; 233526e52a70SEwan Crawford 233626e52a70SEwan Crawford // Starting offset of child ElementHeader struct 2337b9c1b51eSKate Stone size_t child_offset = 2338b9c1b51eSKate Stone offset + ((elem.children.size() + 1) * sizeof(uint32_t)); 2339b9c1b51eSKate Stone for (const RenderScriptRuntime::Element &child : elem.children) { 2340b9c1b51eSKate Stone // Recursively populate the buffer with the element header structs of 2341b9c1b51eSKate Stone // children. 2342b9c1b51eSKate Stone // Then save the offsets where they were set after the parent element 2343b9c1b51eSKate Stone // header. 234426e52a70SEwan Crawford memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t)); 234526e52a70SEwan Crawford offset += sizeof(uint32_t); 234626e52a70SEwan Crawford 234726e52a70SEwan Crawford child_offset = PopulateElementHeaders(header_buffer, child_offset, child); 234826e52a70SEwan Crawford } 234926e52a70SEwan Crawford 235026e52a70SEwan Crawford // Zero indicates no more children 235126e52a70SEwan Crawford memset(header_buffer.get() + offset, 0, sizeof(uint32_t)); 235226e52a70SEwan Crawford 235326e52a70SEwan Crawford return child_offset; 235426e52a70SEwan Crawford } 235526e52a70SEwan Crawford 2356b9c1b51eSKate Stone // Given an Element object this function returns the total size needed in the 2357b9c1b51eSKate Stone // file header to store the element's 2358b3f7f69dSAidan Dodds // details. 2359b9c1b51eSKate Stone // Taking into account the size of the element header struct, plus the offsets 2360b9c1b51eSKate Stone // to all the element's children. 2361b9c1b51eSKate Stone // Function is recursive so that the size of all ancestors is taken into 2362b9c1b51eSKate Stone // account. 2363b9c1b51eSKate Stone size_t RenderScriptRuntime::CalculateElementHeaderSize(const Element &elem) { 2364b9c1b51eSKate Stone size_t size = (elem.children.size() + 1) * 2365b9c1b51eSKate Stone sizeof(uint32_t); // Offsets to children plus zero terminator 2366b9c1b51eSKate Stone size += sizeof(AllocationDetails::ElementHeader); // Size of header struct 2367b9c1b51eSKate Stone // with type details 236826e52a70SEwan Crawford 236926e52a70SEwan Crawford // Calculate recursively for all descendants 237026e52a70SEwan Crawford for (const Element &child : elem.children) 237126e52a70SEwan Crawford size += CalculateElementHeaderSize(child); 237226e52a70SEwan Crawford 237326e52a70SEwan Crawford return size; 237426e52a70SEwan Crawford } 237526e52a70SEwan Crawford 237655232f09SEwan Crawford // Function copies allocation contents into a binary file. 237755232f09SEwan Crawford // This file can then be loaded later into a different allocation. 2378b9c1b51eSKate Stone // There is a header, FileHeader, before the allocation data containing 2379b9c1b51eSKate Stone // meta-data. 2380b9c1b51eSKate Stone bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, 2381b9c1b51eSKate Stone const char *filename, 2382b9c1b51eSKate Stone StackFrame *frame_ptr) { 238355232f09SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 238455232f09SEwan Crawford 238555232f09SEwan Crawford // Find allocation with the given id 238655232f09SEwan Crawford AllocationDetails *alloc = FindAllocByID(strm, alloc_id); 238755232f09SEwan Crawford if (!alloc) 238855232f09SEwan Crawford return false; 238955232f09SEwan Crawford 239055232f09SEwan Crawford if (log) 2391b9c1b51eSKate Stone log->Printf("%s - found allocation 0x%" PRIx64 ".", __FUNCTION__, 2392b9c1b51eSKate Stone *alloc->address.get()); 239355232f09SEwan Crawford 239455232f09SEwan Crawford // JIT all the allocation details 2395b9c1b51eSKate Stone if (alloc->shouldRefresh()) { 239655232f09SEwan Crawford if (log) 2397b9c1b51eSKate Stone log->Printf("%s - allocation details not calculated yet, jitting info.", 2398b9c1b51eSKate Stone __FUNCTION__); 239955232f09SEwan Crawford 2400b9c1b51eSKate Stone if (!RefreshAllocation(alloc, frame_ptr)) { 240155232f09SEwan Crawford if (log) 2402b3f7f69dSAidan Dodds log->Printf("%s - couldn't JIT allocation details.", __FUNCTION__); 24034cfc9198SSylvestre Ledru return false; 240455232f09SEwan Crawford } 240555232f09SEwan Crawford } 240655232f09SEwan Crawford 2407b9c1b51eSKate Stone assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && 2408b9c1b51eSKate Stone alloc->element.type_vec_size.isValid() && 2409b9c1b51eSKate Stone alloc->element.datum_size.get() && 2410b9c1b51eSKate Stone alloc->element.type_kind.isValid() && alloc->dimension.isValid() && 2411b3f7f69dSAidan Dodds "Allocation information not available"); 241255232f09SEwan Crawford 241355232f09SEwan Crawford // Check we can create writable file 241455232f09SEwan Crawford FileSpec file_spec(filename, true); 2415b9c1b51eSKate Stone File file(file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate | 2416b9c1b51eSKate Stone File::eOpenOptionTruncate); 2417b9c1b51eSKate Stone if (!file) { 241855232f09SEwan Crawford strm.Printf("Error: Failed to open '%s' for writing", filename); 241955232f09SEwan Crawford strm.EOL(); 242055232f09SEwan Crawford return false; 242155232f09SEwan Crawford } 242255232f09SEwan Crawford 242355232f09SEwan Crawford // Read allocation into buffer of heap memory 242455232f09SEwan Crawford const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); 2425b9c1b51eSKate Stone if (!buffer) { 242655232f09SEwan Crawford strm.Printf("Error: Couldn't read allocation data into buffer"); 242755232f09SEwan Crawford strm.EOL(); 242855232f09SEwan Crawford return false; 242955232f09SEwan Crawford } 243055232f09SEwan Crawford 243155232f09SEwan Crawford // Create the file header 243255232f09SEwan Crawford AllocationDetails::FileHeader head; 2433b3f7f69dSAidan Dodds memcpy(head.ident, "RSAD", 4); 24342d62328aSEwan Crawford head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1); 24352d62328aSEwan Crawford head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2); 24362d62328aSEwan Crawford head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3); 243726e52a70SEwan Crawford 243826e52a70SEwan Crawford const size_t element_header_size = CalculateElementHeaderSize(alloc->element); 2439b9c1b51eSKate Stone assert((sizeof(AllocationDetails::FileHeader) + element_header_size) < 2440b9c1b51eSKate Stone UINT16_MAX && 2441b9c1b51eSKate Stone "Element header too large"); 2442b9c1b51eSKate Stone head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) + 2443b9c1b51eSKate Stone element_header_size); 244455232f09SEwan Crawford 244555232f09SEwan Crawford // Write the file header 244655232f09SEwan Crawford size_t num_bytes = sizeof(AllocationDetails::FileHeader); 244726e52a70SEwan Crawford if (log) 2448b9c1b51eSKate Stone log->Printf("%s - writing File Header, 0x%" PRIx64 " bytes", __FUNCTION__, 2449b9c1b51eSKate Stone (uint64_t)num_bytes); 245026e52a70SEwan Crawford 245126e52a70SEwan Crawford Error err = file.Write(&head, num_bytes); 2452b9c1b51eSKate Stone if (!err.Success()) { 2453b9c1b51eSKate Stone strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), 2454b9c1b51eSKate Stone filename); 245526e52a70SEwan Crawford strm.EOL(); 245626e52a70SEwan Crawford return false; 245726e52a70SEwan Crawford } 245826e52a70SEwan Crawford 245926e52a70SEwan Crawford // Create the headers describing the element type of the allocation. 2460b9c1b51eSKate Stone std::shared_ptr<uint8_t> element_header_buffer( 2461b9c1b51eSKate Stone new uint8_t[element_header_size]); 2462b9c1b51eSKate Stone if (element_header_buffer == nullptr) { 2463b9c1b51eSKate Stone strm.Printf("Internal Error: Couldn't allocate %" PRIu64 2464b9c1b51eSKate Stone " bytes on the heap", 2465b9c1b51eSKate Stone (uint64_t)element_header_size); 246626e52a70SEwan Crawford strm.EOL(); 246726e52a70SEwan Crawford return false; 246826e52a70SEwan Crawford } 246926e52a70SEwan Crawford 247026e52a70SEwan Crawford PopulateElementHeaders(element_header_buffer, 0, alloc->element); 247126e52a70SEwan Crawford 247226e52a70SEwan Crawford // Write headers for allocation element type to file 247326e52a70SEwan Crawford num_bytes = element_header_size; 247426e52a70SEwan Crawford if (log) 2475b9c1b51eSKate Stone log->Printf("%s - writing element headers, 0x%" PRIx64 " bytes.", 2476b9c1b51eSKate Stone __FUNCTION__, (uint64_t)num_bytes); 247726e52a70SEwan Crawford 247826e52a70SEwan Crawford err = file.Write(element_header_buffer.get(), num_bytes); 2479b9c1b51eSKate Stone if (!err.Success()) { 2480b9c1b51eSKate Stone strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), 2481b9c1b51eSKate Stone filename); 248255232f09SEwan Crawford strm.EOL(); 248355232f09SEwan Crawford return false; 248455232f09SEwan Crawford } 248555232f09SEwan Crawford 248655232f09SEwan Crawford // Write allocation data to file 248755232f09SEwan Crawford num_bytes = static_cast<size_t>(*alloc->size.get()); 248855232f09SEwan Crawford if (log) 2489b9c1b51eSKate Stone log->Printf("%s - writing 0x%" PRIx64 " bytes", __FUNCTION__, 2490b9c1b51eSKate Stone (uint64_t)num_bytes); 249155232f09SEwan Crawford 249255232f09SEwan Crawford err = file.Write(buffer.get(), num_bytes); 2493b9c1b51eSKate Stone if (!err.Success()) { 2494b9c1b51eSKate Stone strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), 2495b9c1b51eSKate Stone filename); 249655232f09SEwan Crawford strm.EOL(); 249755232f09SEwan Crawford return false; 249855232f09SEwan Crawford } 249955232f09SEwan Crawford 250055232f09SEwan Crawford strm.Printf("Allocation written to file '%s'", filename); 250155232f09SEwan Crawford strm.EOL(); 250215f2bd95SEwan Crawford return true; 250315f2bd95SEwan Crawford } 250415f2bd95SEwan Crawford 2505b9c1b51eSKate Stone bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) { 25064640cde1SColin Riley Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 25074640cde1SColin Riley 2508b9c1b51eSKate Stone if (module_sp) { 2509b9c1b51eSKate Stone for (const auto &rs_module : m_rsmodules) { 2510b9c1b51eSKate Stone if (rs_module->m_module == module_sp) { 25117dc7771cSEwan Crawford // Check if the user has enabled automatically breaking on 25127dc7771cSEwan Crawford // all RS kernels. 25137dc7771cSEwan Crawford if (m_breakAllKernels) 25147dc7771cSEwan Crawford BreakOnModuleKernels(rs_module); 25157dc7771cSEwan Crawford 25165ec532a9SColin Riley return false; 25175ec532a9SColin Riley } 25187dc7771cSEwan Crawford } 2519ef20b08fSColin Riley bool module_loaded = false; 2520b9c1b51eSKate Stone switch (GetModuleKind(module_sp)) { 2521b9c1b51eSKate Stone case eModuleKindKernelObj: { 25224640cde1SColin Riley RSModuleDescriptorSP module_desc; 25234640cde1SColin Riley module_desc.reset(new RSModuleDescriptor(module_sp)); 2524b9c1b51eSKate Stone if (module_desc->ParseRSInfo()) { 25255ec532a9SColin Riley m_rsmodules.push_back(module_desc); 2526ef20b08fSColin Riley module_loaded = true; 25275ec532a9SColin Riley } 2528b9c1b51eSKate Stone if (module_loaded) { 25294640cde1SColin Riley FixupScriptDetails(module_desc); 25304640cde1SColin Riley } 2531ef20b08fSColin Riley break; 2532ef20b08fSColin Riley } 2533b9c1b51eSKate Stone case eModuleKindDriver: { 2534b9c1b51eSKate Stone if (!m_libRSDriver) { 25354640cde1SColin Riley m_libRSDriver = module_sp; 25364640cde1SColin Riley LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver); 25374640cde1SColin Riley } 25384640cde1SColin Riley break; 25394640cde1SColin Riley } 2540b9c1b51eSKate Stone case eModuleKindImpl: { 25414640cde1SColin Riley m_libRSCpuRef = module_sp; 25424640cde1SColin Riley break; 25434640cde1SColin Riley } 2544b9c1b51eSKate Stone case eModuleKindLibRS: { 2545b9c1b51eSKate Stone if (!m_libRS) { 25464640cde1SColin Riley m_libRS = module_sp; 25474640cde1SColin Riley static ConstString gDbgPresentStr("gDebuggerPresent"); 2548b9c1b51eSKate Stone const Symbol *debug_present = m_libRS->FindFirstSymbolWithNameAndType( 2549b9c1b51eSKate Stone gDbgPresentStr, eSymbolTypeData); 2550b9c1b51eSKate Stone if (debug_present) { 25514640cde1SColin Riley Error error; 25524640cde1SColin Riley uint32_t flag = 0x00000001U; 25534640cde1SColin Riley Target &target = GetProcess()->GetTarget(); 2554358cf1eaSGreg Clayton addr_t addr = debug_present->GetLoadAddress(&target); 25554640cde1SColin Riley GetProcess()->WriteMemory(addr, &flag, sizeof(flag), error); 2556b9c1b51eSKate Stone if (error.Success()) { 25574640cde1SColin Riley if (log) 2558b9c1b51eSKate Stone log->Printf("%s - debugger present flag set on debugee.", 2559b9c1b51eSKate Stone __FUNCTION__); 25604640cde1SColin Riley 25614640cde1SColin Riley m_debuggerPresentFlagged = true; 2562b9c1b51eSKate Stone } else if (log) { 2563b9c1b51eSKate Stone log->Printf("%s - error writing debugger present flags '%s' ", 2564b9c1b51eSKate Stone __FUNCTION__, error.AsCString()); 25654640cde1SColin Riley } 2566b9c1b51eSKate Stone } else if (log) { 2567b9c1b51eSKate Stone log->Printf( 2568b9c1b51eSKate Stone "%s - error writing debugger present flags - symbol not found", 2569b9c1b51eSKate Stone __FUNCTION__); 25704640cde1SColin Riley } 25714640cde1SColin Riley } 25724640cde1SColin Riley break; 25734640cde1SColin Riley } 2574ef20b08fSColin Riley default: 2575ef20b08fSColin Riley break; 2576ef20b08fSColin Riley } 2577ef20b08fSColin Riley if (module_loaded) 2578ef20b08fSColin Riley Update(); 2579ef20b08fSColin Riley return module_loaded; 25805ec532a9SColin Riley } 25815ec532a9SColin Riley return false; 25825ec532a9SColin Riley } 25835ec532a9SColin Riley 2584b9c1b51eSKate Stone void RenderScriptRuntime::Update() { 2585b9c1b51eSKate Stone if (m_rsmodules.size() > 0) { 2586b9c1b51eSKate Stone if (!m_initiated) { 2587ef20b08fSColin Riley Initiate(); 2588ef20b08fSColin Riley } 2589ef20b08fSColin Riley } 2590ef20b08fSColin Riley } 2591ef20b08fSColin Riley 2592*7f193d69SLuke Drummond bool RSModuleDescriptor::ParsePragmaCount(llvm::StringRef *lines, 2593*7f193d69SLuke Drummond size_t n_lines) { 2594*7f193d69SLuke Drummond // Skip the pragma prototype line 2595*7f193d69SLuke Drummond ++lines; 2596*7f193d69SLuke Drummond for (; n_lines--; ++lines) { 2597*7f193d69SLuke Drummond const auto kv_pair = lines->split(" - "); 2598*7f193d69SLuke Drummond m_pragmas[kv_pair.first.trim().str()] = kv_pair.second.trim().str(); 2599*7f193d69SLuke Drummond } 2600*7f193d69SLuke Drummond return true; 2601*7f193d69SLuke Drummond } 2602*7f193d69SLuke Drummond 2603*7f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportReduceCount(llvm::StringRef *lines, 2604*7f193d69SLuke Drummond size_t n_lines) { 2605*7f193d69SLuke Drummond // The list of reduction kernels in the `.rs.info` symbol is of the form 2606*7f193d69SLuke Drummond // "signature - accumulatordatasize - reduction_name - initializer_name - 2607*7f193d69SLuke Drummond // accumulator_name - combiner_name - 2608*7f193d69SLuke Drummond // outconverter_name - halter_name" 2609*7f193d69SLuke Drummond // Where a function is not explicitly named by the user, or is not generated 2610*7f193d69SLuke Drummond // by the compiler, it is named "." so the 2611*7f193d69SLuke Drummond // dash separated list should always be 8 items long 2612*7f193d69SLuke Drummond Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 2613*7f193d69SLuke Drummond // Skip the exportReduceCount line 2614*7f193d69SLuke Drummond ++lines; 2615*7f193d69SLuke Drummond for (; n_lines--; ++lines) { 2616*7f193d69SLuke Drummond llvm::SmallVector<llvm::StringRef, 8> spec; 2617*7f193d69SLuke Drummond lines->split(spec, " - "); 2618*7f193d69SLuke Drummond if (spec.size() != 8) { 2619*7f193d69SLuke Drummond if (spec.size() < 8) { 2620*7f193d69SLuke Drummond if (log) 2621*7f193d69SLuke Drummond log->Error("Error parsing RenderScript reduction spec. wrong number " 2622*7f193d69SLuke Drummond "of fields"); 2623*7f193d69SLuke Drummond return false; 2624*7f193d69SLuke Drummond } else if (log) 2625*7f193d69SLuke Drummond log->Warning("Extraneous members in reduction spec: '%s'", 2626*7f193d69SLuke Drummond lines->str().c_str()); 2627*7f193d69SLuke Drummond } 2628*7f193d69SLuke Drummond 2629*7f193d69SLuke Drummond const auto sig_s = spec[0]; 2630*7f193d69SLuke Drummond uint32_t sig; 2631*7f193d69SLuke Drummond if (sig_s.getAsInteger(10, sig)) { 2632*7f193d69SLuke Drummond if (log) 2633*7f193d69SLuke Drummond log->Error("Error parsing Renderscript reduction spec: invalid kernel " 2634*7f193d69SLuke Drummond "signature: '%s'", 2635*7f193d69SLuke Drummond sig_s.str().c_str()); 2636*7f193d69SLuke Drummond return false; 2637*7f193d69SLuke Drummond } 2638*7f193d69SLuke Drummond 2639*7f193d69SLuke Drummond const auto accum_data_size_s = spec[1]; 2640*7f193d69SLuke Drummond uint32_t accum_data_size; 2641*7f193d69SLuke Drummond if (accum_data_size_s.getAsInteger(10, accum_data_size)) { 2642*7f193d69SLuke Drummond if (log) 2643*7f193d69SLuke Drummond log->Error("Error parsing Renderscript reduction spec: invalid " 2644*7f193d69SLuke Drummond "accumulator data size %s", 2645*7f193d69SLuke Drummond accum_data_size_s.str().c_str()); 2646*7f193d69SLuke Drummond return false; 2647*7f193d69SLuke Drummond } 2648*7f193d69SLuke Drummond 2649*7f193d69SLuke Drummond if (log) 2650*7f193d69SLuke Drummond log->Printf("Found RenderScript reduction '%s'", spec[2].str().c_str()); 2651*7f193d69SLuke Drummond 2652*7f193d69SLuke Drummond m_reductions.push_back(RSReductionDescriptor(this, sig, accum_data_size, 2653*7f193d69SLuke Drummond spec[2], spec[3], spec[4], 2654*7f193d69SLuke Drummond spec[5], spec[6], spec[7])); 2655*7f193d69SLuke Drummond } 2656*7f193d69SLuke Drummond return true; 2657*7f193d69SLuke Drummond } 2658*7f193d69SLuke Drummond 2659*7f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportForeachCount(llvm::StringRef *lines, 2660*7f193d69SLuke Drummond size_t n_lines) { 2661*7f193d69SLuke Drummond // Skip the exportForeachCount line 2662*7f193d69SLuke Drummond ++lines; 2663*7f193d69SLuke Drummond for (; n_lines--; ++lines) { 2664*7f193d69SLuke Drummond uint32_t slot; 2665*7f193d69SLuke Drummond // `forEach` kernels are listed in the `.rs.info` packet as a "slot - name" 2666*7f193d69SLuke Drummond // pair per line 2667*7f193d69SLuke Drummond const auto kv_pair = lines->split(" - "); 2668*7f193d69SLuke Drummond if (kv_pair.first.getAsInteger(10, slot)) 2669*7f193d69SLuke Drummond return false; 2670*7f193d69SLuke Drummond m_kernels.push_back(RSKernelDescriptor(this, kv_pair.second, slot)); 2671*7f193d69SLuke Drummond } 2672*7f193d69SLuke Drummond return true; 2673*7f193d69SLuke Drummond } 2674*7f193d69SLuke Drummond 2675*7f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportVarCount(llvm::StringRef *lines, 2676*7f193d69SLuke Drummond size_t n_lines) { 2677*7f193d69SLuke Drummond // Skip the ExportVarCount line 2678*7f193d69SLuke Drummond ++lines; 2679*7f193d69SLuke Drummond for (; n_lines--; ++lines) 2680*7f193d69SLuke Drummond m_globals.push_back(RSGlobalDescriptor(this, *lines)); 2681*7f193d69SLuke Drummond return true; 2682*7f193d69SLuke Drummond } 26835ec532a9SColin Riley 2684b9c1b51eSKate Stone // The .rs.info symbol in renderscript modules contains a string which needs to 2685b9c1b51eSKate Stone // be parsed. 26865ec532a9SColin Riley // The string is basic and is parsed on a line by line basis. 2687b9c1b51eSKate Stone bool RSModuleDescriptor::ParseRSInfo() { 2688b0be30f7SAidan Dodds assert(m_module); 2689*7f193d69SLuke Drummond Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2690b9c1b51eSKate Stone const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType( 2691b9c1b51eSKate Stone ConstString(".rs.info"), eSymbolTypeData); 2692b0be30f7SAidan Dodds if (!info_sym) 2693b0be30f7SAidan Dodds return false; 2694b0be30f7SAidan Dodds 2695358cf1eaSGreg Clayton const addr_t addr = info_sym->GetAddressRef().GetFileAddress(); 2696b0be30f7SAidan Dodds if (addr == LLDB_INVALID_ADDRESS) 2697b0be30f7SAidan Dodds return false; 2698b0be30f7SAidan Dodds 26995ec532a9SColin Riley const addr_t size = info_sym->GetByteSize(); 27005ec532a9SColin Riley const FileSpec fs = m_module->GetFileSpec(); 27015ec532a9SColin Riley 2702b0be30f7SAidan Dodds const DataBufferSP buffer = fs.ReadFileContents(addr, size); 27035ec532a9SColin Riley if (!buffer) 27045ec532a9SColin Riley return false; 27055ec532a9SColin Riley 2706b0be30f7SAidan Dodds // split rs.info. contents into lines 2707*7f193d69SLuke Drummond llvm::SmallVector<llvm::StringRef, 128> info_lines; 27085ec532a9SColin Riley { 2709*7f193d69SLuke Drummond const llvm::StringRef raw_rs_info((const char *)buffer->GetBytes()); 2710*7f193d69SLuke Drummond raw_rs_info.split(info_lines, '\n'); 2711*7f193d69SLuke Drummond if (log) 2712*7f193d69SLuke Drummond log->Printf("'.rs.info symbol for '%s':\n%s", 2713*7f193d69SLuke Drummond m_module->GetFileSpec().GetCString(), 2714*7f193d69SLuke Drummond raw_rs_info.str().c_str()); 2715b0be30f7SAidan Dodds } 2716b0be30f7SAidan Dodds 2717*7f193d69SLuke Drummond enum { 2718*7f193d69SLuke Drummond eExportVar, 2719*7f193d69SLuke Drummond eExportForEach, 2720*7f193d69SLuke Drummond eExportReduce, 2721*7f193d69SLuke Drummond ePragma, 2722*7f193d69SLuke Drummond eBuildChecksum, 2723*7f193d69SLuke Drummond eObjectSlot 2724*7f193d69SLuke Drummond }; 2725*7f193d69SLuke Drummond 2726*7f193d69SLuke Drummond static const llvm::StringMap<int> rs_info_handlers{ 2727*7f193d69SLuke Drummond {// The number of visible global variables in the script 2728*7f193d69SLuke Drummond {"exportVarCount", eExportVar}, 2729*7f193d69SLuke Drummond // The number of RenderScrip `forEach` kernels __attribute__((kernel)) 2730*7f193d69SLuke Drummond {"exportForEachCount", eExportForEach}, 2731*7f193d69SLuke Drummond // The number of generalreductions: This marked in the script by `#pragma 2732*7f193d69SLuke Drummond // reduce()` 2733*7f193d69SLuke Drummond {"exportReduceCount", eExportReduce}, 2734*7f193d69SLuke Drummond // Total count of all RenderScript specific `#pragmas` used in the script 2735*7f193d69SLuke Drummond {"pragmaCount", ePragma}, 2736*7f193d69SLuke Drummond {"objectSlotCount", eObjectSlot}}}; 2737b0be30f7SAidan Dodds 2738b0be30f7SAidan Dodds // parse all text lines of .rs.info 2739b9c1b51eSKate Stone for (auto line = info_lines.begin(); line != info_lines.end(); ++line) { 2740*7f193d69SLuke Drummond const auto kv_pair = line->split(": "); 2741*7f193d69SLuke Drummond const auto key = kv_pair.first; 2742*7f193d69SLuke Drummond const auto val = kv_pair.second.trim(); 27435ec532a9SColin Riley 2744*7f193d69SLuke Drummond const auto handler = rs_info_handlers.find(key); 2745*7f193d69SLuke Drummond if (handler == rs_info_handlers.end()) 2746*7f193d69SLuke Drummond continue; 2747*7f193d69SLuke Drummond // getAsInteger returns `true` on an error condition - we're only interested 2748*7f193d69SLuke Drummond // in 2749*7f193d69SLuke Drummond // numeric fields at the moment 2750*7f193d69SLuke Drummond uint64_t n_lines; 2751*7f193d69SLuke Drummond if (val.getAsInteger(10, n_lines)) { 2752*7f193d69SLuke Drummond if (log) 2753*7f193d69SLuke Drummond log->Debug("Failed to parse non-numeric '.rs.info' section %s", 2754*7f193d69SLuke Drummond line->str().c_str()); 2755*7f193d69SLuke Drummond continue; 2756*7f193d69SLuke Drummond } 2757*7f193d69SLuke Drummond if (info_lines.end() - (line + 1) < (ptrdiff_t)n_lines) 2758*7f193d69SLuke Drummond return false; 2759*7f193d69SLuke Drummond 2760*7f193d69SLuke Drummond bool success = false; 2761*7f193d69SLuke Drummond switch (handler->getValue()) { 2762*7f193d69SLuke Drummond case eExportVar: 2763*7f193d69SLuke Drummond success = ParseExportVarCount(line, n_lines); 2764*7f193d69SLuke Drummond break; 2765*7f193d69SLuke Drummond case eExportForEach: 2766*7f193d69SLuke Drummond success = ParseExportForeachCount(line, n_lines); 2767*7f193d69SLuke Drummond break; 2768*7f193d69SLuke Drummond case eExportReduce: 2769*7f193d69SLuke Drummond success = ParseExportReduceCount(line, n_lines); 2770*7f193d69SLuke Drummond break; 2771*7f193d69SLuke Drummond case ePragma: 2772*7f193d69SLuke Drummond success = ParsePragmaCount(line, n_lines); 2773*7f193d69SLuke Drummond break; 2774*7f193d69SLuke Drummond default: { 2775*7f193d69SLuke Drummond if (log) 2776*7f193d69SLuke Drummond log->Printf("%s - skipping .rs.info field '%s'", __FUNCTION__, 2777*7f193d69SLuke Drummond line->str().c_str()); 2778*7f193d69SLuke Drummond continue; 2779*7f193d69SLuke Drummond } 2780*7f193d69SLuke Drummond } 2781*7f193d69SLuke Drummond if (!success) 2782*7f193d69SLuke Drummond return false; 2783*7f193d69SLuke Drummond line += n_lines; 2784*7f193d69SLuke Drummond } 2785*7f193d69SLuke Drummond return info_lines.size() > 0; 27865ec532a9SColin Riley } 27875ec532a9SColin Riley 2788b9c1b51eSKate Stone void RenderScriptRuntime::Status(Stream &strm) const { 2789b9c1b51eSKate Stone if (m_libRS) { 27904640cde1SColin Riley strm.Printf("Runtime Library discovered."); 27914640cde1SColin Riley strm.EOL(); 27924640cde1SColin Riley } 2793b9c1b51eSKate Stone if (m_libRSDriver) { 27944640cde1SColin Riley strm.Printf("Runtime Driver discovered."); 27954640cde1SColin Riley strm.EOL(); 27964640cde1SColin Riley } 2797b9c1b51eSKate Stone if (m_libRSCpuRef) { 27984640cde1SColin Riley strm.Printf("CPU Reference Implementation discovered."); 27994640cde1SColin Riley strm.EOL(); 28004640cde1SColin Riley } 28014640cde1SColin Riley 2802b9c1b51eSKate Stone if (m_runtimeHooks.size()) { 28034640cde1SColin Riley strm.Printf("Runtime functions hooked:"); 28044640cde1SColin Riley strm.EOL(); 2805b9c1b51eSKate Stone for (auto b : m_runtimeHooks) { 28064640cde1SColin Riley strm.Indent(b.second->defn->name); 28074640cde1SColin Riley strm.EOL(); 28084640cde1SColin Riley } 2809b9c1b51eSKate Stone } else { 28104640cde1SColin Riley strm.Printf("Runtime is not hooked."); 28114640cde1SColin Riley strm.EOL(); 28124640cde1SColin Riley } 28134640cde1SColin Riley } 28144640cde1SColin Riley 2815b9c1b51eSKate Stone void RenderScriptRuntime::DumpContexts(Stream &strm) const { 28164640cde1SColin Riley strm.Printf("Inferred RenderScript Contexts:"); 28174640cde1SColin Riley strm.EOL(); 28184640cde1SColin Riley strm.IndentMore(); 28194640cde1SColin Riley 28204640cde1SColin Riley std::map<addr_t, uint64_t> contextReferences; 28214640cde1SColin Riley 282278f339d1SEwan Crawford // Iterate over all of the currently discovered scripts. 2823b9c1b51eSKate Stone // Note: We cant push or pop from m_scripts inside this loop or it may 2824b9c1b51eSKate Stone // invalidate script. 2825b9c1b51eSKate Stone for (const auto &script : m_scripts) { 282678f339d1SEwan Crawford if (!script->context.isValid()) 282778f339d1SEwan Crawford continue; 282878f339d1SEwan Crawford lldb::addr_t context = *script->context; 282978f339d1SEwan Crawford 2830b9c1b51eSKate Stone if (contextReferences.find(context) != contextReferences.end()) { 283178f339d1SEwan Crawford contextReferences[context]++; 2832b9c1b51eSKate Stone } else { 283378f339d1SEwan Crawford contextReferences[context] = 1; 28344640cde1SColin Riley } 28354640cde1SColin Riley } 28364640cde1SColin Riley 2837b9c1b51eSKate Stone for (const auto &cRef : contextReferences) { 2838b9c1b51eSKate Stone strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances", 2839b9c1b51eSKate Stone cRef.first, cRef.second); 28404640cde1SColin Riley strm.EOL(); 28414640cde1SColin Riley } 28424640cde1SColin Riley strm.IndentLess(); 28434640cde1SColin Riley } 28444640cde1SColin Riley 2845b9c1b51eSKate Stone void RenderScriptRuntime::DumpKernels(Stream &strm) const { 28464640cde1SColin Riley strm.Printf("RenderScript Kernels:"); 28474640cde1SColin Riley strm.EOL(); 28484640cde1SColin Riley strm.IndentMore(); 2849b9c1b51eSKate Stone for (const auto &module : m_rsmodules) { 28504640cde1SColin Riley strm.Printf("Resource '%s':", module->m_resname.c_str()); 28514640cde1SColin Riley strm.EOL(); 2852b9c1b51eSKate Stone for (const auto &kernel : module->m_kernels) { 28534640cde1SColin Riley strm.Indent(kernel.m_name.AsCString()); 28544640cde1SColin Riley strm.EOL(); 28554640cde1SColin Riley } 28564640cde1SColin Riley } 28574640cde1SColin Riley strm.IndentLess(); 28584640cde1SColin Riley } 28594640cde1SColin Riley 2860a0f08674SEwan Crawford RenderScriptRuntime::AllocationDetails * 2861b9c1b51eSKate Stone RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) { 2862a0f08674SEwan Crawford AllocationDetails *alloc = nullptr; 2863a0f08674SEwan Crawford 2864a0f08674SEwan Crawford // See if we can find allocation using id as an index; 2865b9c1b51eSKate Stone if (alloc_id <= m_allocations.size() && alloc_id != 0 && 2866b9c1b51eSKate Stone m_allocations[alloc_id - 1]->id == alloc_id) { 2867a0f08674SEwan Crawford alloc = m_allocations[alloc_id - 1].get(); 2868a0f08674SEwan Crawford return alloc; 2869a0f08674SEwan Crawford } 2870a0f08674SEwan Crawford 2871a0f08674SEwan Crawford // Fallback to searching 2872b9c1b51eSKate Stone for (const auto &a : m_allocations) { 2873b9c1b51eSKate Stone if (a->id == alloc_id) { 2874a0f08674SEwan Crawford alloc = a.get(); 2875a0f08674SEwan Crawford break; 2876a0f08674SEwan Crawford } 2877a0f08674SEwan Crawford } 2878a0f08674SEwan Crawford 2879b9c1b51eSKate Stone if (alloc == nullptr) { 2880b9c1b51eSKate Stone strm.Printf("Error: Couldn't find allocation with id matching %" PRIu32, 2881b9c1b51eSKate Stone alloc_id); 2882a0f08674SEwan Crawford strm.EOL(); 2883a0f08674SEwan Crawford } 2884a0f08674SEwan Crawford 2885a0f08674SEwan Crawford return alloc; 2886a0f08674SEwan Crawford } 2887a0f08674SEwan Crawford 2888b9c1b51eSKate Stone // Prints the contents of an allocation to the output stream, which may be a 2889b9c1b51eSKate Stone // file 2890b9c1b51eSKate Stone bool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr, 2891b9c1b51eSKate Stone const uint32_t id) { 2892a0f08674SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2893a0f08674SEwan Crawford 2894a0f08674SEwan Crawford // Check we can find the desired allocation 2895a0f08674SEwan Crawford AllocationDetails *alloc = FindAllocByID(strm, id); 2896a0f08674SEwan Crawford if (!alloc) 2897a0f08674SEwan Crawford return false; // FindAllocByID() will print error message for us here 2898a0f08674SEwan Crawford 2899a0f08674SEwan Crawford if (log) 2900b9c1b51eSKate Stone log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__, 2901b9c1b51eSKate Stone *alloc->address.get()); 2902a0f08674SEwan Crawford 2903a0f08674SEwan Crawford // Check we have information about the allocation, if not calculate it 2904b9c1b51eSKate Stone if (alloc->shouldRefresh()) { 2905a0f08674SEwan Crawford if (log) 2906b9c1b51eSKate Stone log->Printf("%s - allocation details not calculated yet, jitting info.", 2907b9c1b51eSKate Stone __FUNCTION__); 2908a0f08674SEwan Crawford 2909a0f08674SEwan Crawford // JIT all the allocation information 2910b9c1b51eSKate Stone if (!RefreshAllocation(alloc, frame_ptr)) { 2911a0f08674SEwan Crawford strm.Printf("Error: Couldn't JIT allocation details"); 2912a0f08674SEwan Crawford strm.EOL(); 2913a0f08674SEwan Crawford return false; 2914a0f08674SEwan Crawford } 2915a0f08674SEwan Crawford } 2916a0f08674SEwan Crawford 2917a0f08674SEwan Crawford // Establish format and size of each data element 2918b3f7f69dSAidan Dodds const uint32_t vec_size = *alloc->element.type_vec_size.get(); 29198b244e21SEwan Crawford const Element::DataType type = *alloc->element.type.get(); 2920a0f08674SEwan Crawford 2921b9c1b51eSKate Stone assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && 2922b9c1b51eSKate Stone "Invalid allocation type"); 2923a0f08674SEwan Crawford 29242e920715SEwan Crawford lldb::Format format; 29252e920715SEwan Crawford if (type >= Element::RS_TYPE_ELEMENT) 29262e920715SEwan Crawford format = eFormatHex; 29272e920715SEwan Crawford else 2928b9c1b51eSKate Stone format = vec_size == 1 2929b9c1b51eSKate Stone ? static_cast<lldb::Format>( 2930b9c1b51eSKate Stone AllocationDetails::RSTypeToFormat[type][eFormatSingle]) 2931b9c1b51eSKate Stone : static_cast<lldb::Format>( 2932b9c1b51eSKate Stone AllocationDetails::RSTypeToFormat[type][eFormatVector]); 2933a0f08674SEwan Crawford 2934b3f7f69dSAidan Dodds const uint32_t data_size = *alloc->element.datum_size.get(); 2935a0f08674SEwan Crawford 2936a0f08674SEwan Crawford if (log) 2937b9c1b51eSKate Stone log->Printf("%s - element size %" PRIu32 " bytes, including padding", 2938b9c1b51eSKate Stone __FUNCTION__, data_size); 2939a0f08674SEwan Crawford 294055232f09SEwan Crawford // Allocate a buffer to copy data into 294155232f09SEwan Crawford std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); 2942b9c1b51eSKate Stone if (!buffer) { 29432e920715SEwan Crawford strm.Printf("Error: Couldn't read allocation data"); 294455232f09SEwan Crawford strm.EOL(); 294555232f09SEwan Crawford return false; 294655232f09SEwan Crawford } 294755232f09SEwan Crawford 2948a0f08674SEwan Crawford // Calculate stride between rows as there may be padding at end of rows since 2949a0f08674SEwan Crawford // allocated memory is 16-byte aligned 2950b9c1b51eSKate Stone if (!alloc->stride.isValid()) { 2951a0f08674SEwan Crawford if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension 2952a0f08674SEwan Crawford alloc->stride = 0; 2953b9c1b51eSKate Stone else if (!JITAllocationStride(alloc, frame_ptr)) { 2954a0f08674SEwan Crawford strm.Printf("Error: Couldn't calculate allocation row stride"); 2955a0f08674SEwan Crawford strm.EOL(); 2956a0f08674SEwan Crawford return false; 2957a0f08674SEwan Crawford } 2958a0f08674SEwan Crawford } 2959b3f7f69dSAidan Dodds const uint32_t stride = *alloc->stride.get(); 2960b3f7f69dSAidan Dodds const uint32_t size = *alloc->size.get(); // Size of whole allocation 2961b9c1b51eSKate Stone const uint32_t padding = 2962b9c1b51eSKate Stone alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0; 2963a0f08674SEwan Crawford if (log) 2964b9c1b51eSKate Stone log->Printf("%s - stride %" PRIu32 " bytes, size %" PRIu32 2965b9c1b51eSKate Stone " bytes, padding %" PRIu32, 2966b3f7f69dSAidan Dodds __FUNCTION__, stride, size, padding); 2967a0f08674SEwan Crawford 2968a0f08674SEwan Crawford // Find dimensions used to index loops, so need to be non-zero 2969b3f7f69dSAidan Dodds uint32_t dim_x = alloc->dimension.get()->dim_1; 2970a0f08674SEwan Crawford dim_x = dim_x == 0 ? 1 : dim_x; 2971a0f08674SEwan Crawford 2972b3f7f69dSAidan Dodds uint32_t dim_y = alloc->dimension.get()->dim_2; 2973a0f08674SEwan Crawford dim_y = dim_y == 0 ? 1 : dim_y; 2974a0f08674SEwan Crawford 2975b3f7f69dSAidan Dodds uint32_t dim_z = alloc->dimension.get()->dim_3; 2976a0f08674SEwan Crawford dim_z = dim_z == 0 ? 1 : dim_z; 2977a0f08674SEwan Crawford 297855232f09SEwan Crawford // Use data extractor to format output 2979b9c1b51eSKate Stone const uint32_t archByteSize = 2980b9c1b51eSKate Stone GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 2981b9c1b51eSKate Stone DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(), 2982b9c1b51eSKate Stone archByteSize); 298355232f09SEwan Crawford 2984b3f7f69dSAidan Dodds uint32_t offset = 0; // Offset in buffer to next element to be printed 2985b3f7f69dSAidan Dodds uint32_t prev_row = 0; // Offset to the start of the previous row 2986a0f08674SEwan Crawford 2987a0f08674SEwan Crawford // Iterate over allocation dimensions, printing results to user 2988a0f08674SEwan Crawford strm.Printf("Data (X, Y, Z):"); 2989b9c1b51eSKate Stone for (uint32_t z = 0; z < dim_z; ++z) { 2990b9c1b51eSKate Stone for (uint32_t y = 0; y < dim_y; ++y) { 2991a0f08674SEwan Crawford // Use stride to index start of next row. 2992a0f08674SEwan Crawford if (!(y == 0 && z == 0)) 2993a0f08674SEwan Crawford offset = prev_row + stride; 2994a0f08674SEwan Crawford prev_row = offset; 2995a0f08674SEwan Crawford 2996a0f08674SEwan Crawford // Print each element in the row individually 2997b9c1b51eSKate Stone for (uint32_t x = 0; x < dim_x; ++x) { 2998b3f7f69dSAidan Dodds strm.Printf("\n(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") = ", x, y, z); 2999b9c1b51eSKate Stone if ((type == Element::RS_TYPE_NONE) && 3000b9c1b51eSKate Stone (alloc->element.children.size() > 0) && 3001b9c1b51eSKate Stone (alloc->element.type_name != Element::GetFallbackStructName())) { 30028b244e21SEwan Crawford // Here we are dumping an Element of struct type. 3003b9c1b51eSKate Stone // This is done using expression evaluation with the name of the 3004b9c1b51eSKate Stone // struct type and pointer to element. 30058b244e21SEwan Crawford 3006b9c1b51eSKate Stone // Don't print the name of the resulting expression, since this will 3007b9c1b51eSKate Stone // be '$[0-9]+' 30088b244e21SEwan Crawford DumpValueObjectOptions expr_options; 30098b244e21SEwan Crawford expr_options.SetHideName(true); 30108b244e21SEwan Crawford 30118b244e21SEwan Crawford // Setup expression as derefrencing a pointer cast to element address. 3012ea0636b5SEwan Crawford char expr_char_buffer[jit_max_expr_size]; 3013b9c1b51eSKate Stone int chars_written = 3014b9c1b51eSKate Stone snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64, 3015b9c1b51eSKate Stone alloc->element.type_name.AsCString(), 3016b9c1b51eSKate Stone *alloc->data_ptr.get() + offset); 30178b244e21SEwan Crawford 3018b9c1b51eSKate Stone if (chars_written < 0 || chars_written >= jit_max_expr_size) { 30198b244e21SEwan Crawford if (log) 3020b3f7f69dSAidan Dodds log->Printf("%s - error in snprintf().", __FUNCTION__); 30218b244e21SEwan Crawford continue; 30228b244e21SEwan Crawford } 30238b244e21SEwan Crawford 30248b244e21SEwan Crawford // Evaluate expression 30258b244e21SEwan Crawford ValueObjectSP expr_result; 3026b9c1b51eSKate Stone GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer, 3027b9c1b51eSKate Stone frame_ptr, expr_result); 30288b244e21SEwan Crawford 30298b244e21SEwan Crawford // Print the results to our stream. 30308b244e21SEwan Crawford expr_result->Dump(strm, expr_options); 3031b9c1b51eSKate Stone } else { 3032b9c1b51eSKate Stone alloc_data.Dump(&strm, offset, format, data_size - padding, 1, 1, 3033b9c1b51eSKate Stone LLDB_INVALID_ADDRESS, 0, 0); 30348b244e21SEwan Crawford } 30358b244e21SEwan Crawford offset += data_size; 3036a0f08674SEwan Crawford } 3037a0f08674SEwan Crawford } 3038a0f08674SEwan Crawford } 3039a0f08674SEwan Crawford strm.EOL(); 3040a0f08674SEwan Crawford 3041a0f08674SEwan Crawford return true; 3042a0f08674SEwan Crawford } 3043a0f08674SEwan Crawford 3044b9c1b51eSKate Stone // Function recalculates all our cached information about allocations by jitting 3045b9c1b51eSKate Stone // the 30460d2bfcfbSEwan Crawford // RS runtime regarding each allocation we know about. 30470d2bfcfbSEwan Crawford // Returns true if all allocations could be recomputed, false otherwise. 3048b9c1b51eSKate Stone bool RenderScriptRuntime::RecomputeAllAllocations(Stream &strm, 3049b9c1b51eSKate Stone StackFrame *frame_ptr) { 30500d2bfcfbSEwan Crawford bool success = true; 3051b9c1b51eSKate Stone for (auto &alloc : m_allocations) { 30520d2bfcfbSEwan Crawford // JIT current allocation information 3053b9c1b51eSKate Stone if (!RefreshAllocation(alloc.get(), frame_ptr)) { 3054b9c1b51eSKate Stone strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32 3055b9c1b51eSKate Stone "\n", 3056b9c1b51eSKate Stone alloc->id); 30570d2bfcfbSEwan Crawford success = false; 30580d2bfcfbSEwan Crawford } 30590d2bfcfbSEwan Crawford } 30600d2bfcfbSEwan Crawford 30610d2bfcfbSEwan Crawford if (success) 30620d2bfcfbSEwan Crawford strm.Printf("All allocations successfully recomputed"); 30630d2bfcfbSEwan Crawford strm.EOL(); 30640d2bfcfbSEwan Crawford 30650d2bfcfbSEwan Crawford return success; 30660d2bfcfbSEwan Crawford } 30670d2bfcfbSEwan Crawford 3068b649b005SEwan Crawford // Prints information regarding currently loaded allocations. 306915f2bd95SEwan Crawford // These details are gathered by jitting the runtime, which has as latency. 3070b9c1b51eSKate Stone // Index parameter specifies a single allocation ID to print, or a zero value to 3071b9c1b51eSKate Stone // print them all 3072b9c1b51eSKate Stone void RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame *frame_ptr, 3073b9c1b51eSKate Stone const uint32_t index) { 307415f2bd95SEwan Crawford strm.Printf("RenderScript Allocations:"); 307515f2bd95SEwan Crawford strm.EOL(); 307615f2bd95SEwan Crawford strm.IndentMore(); 307715f2bd95SEwan Crawford 3078b9c1b51eSKate Stone for (auto &alloc : m_allocations) { 3079b649b005SEwan Crawford // index will only be zero if we want to print all allocations 3080b649b005SEwan Crawford if (index != 0 && index != alloc->id) 3081b649b005SEwan Crawford continue; 308215f2bd95SEwan Crawford 308315f2bd95SEwan Crawford // JIT current allocation information 3084b9c1b51eSKate Stone if (alloc->shouldRefresh() && !RefreshAllocation(alloc.get(), frame_ptr)) { 3085b9c1b51eSKate Stone strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32, 3086b9c1b51eSKate Stone alloc->id); 3087b3f7f69dSAidan Dodds strm.EOL(); 308815f2bd95SEwan Crawford continue; 308915f2bd95SEwan Crawford } 309015f2bd95SEwan Crawford 3091b3f7f69dSAidan Dodds strm.Printf("%" PRIu32 ":", alloc->id); 3092b3f7f69dSAidan Dodds strm.EOL(); 309315f2bd95SEwan Crawford strm.IndentMore(); 309415f2bd95SEwan Crawford 309515f2bd95SEwan Crawford strm.Indent("Context: "); 309615f2bd95SEwan Crawford if (!alloc->context.isValid()) 309715f2bd95SEwan Crawford strm.Printf("unknown\n"); 309815f2bd95SEwan Crawford else 309915f2bd95SEwan Crawford strm.Printf("0x%" PRIx64 "\n", *alloc->context.get()); 310015f2bd95SEwan Crawford 310115f2bd95SEwan Crawford strm.Indent("Address: "); 310215f2bd95SEwan Crawford if (!alloc->address.isValid()) 310315f2bd95SEwan Crawford strm.Printf("unknown\n"); 310415f2bd95SEwan Crawford else 310515f2bd95SEwan Crawford strm.Printf("0x%" PRIx64 "\n", *alloc->address.get()); 310615f2bd95SEwan Crawford 310715f2bd95SEwan Crawford strm.Indent("Data pointer: "); 310815f2bd95SEwan Crawford if (!alloc->data_ptr.isValid()) 310915f2bd95SEwan Crawford strm.Printf("unknown\n"); 311015f2bd95SEwan Crawford else 311115f2bd95SEwan Crawford strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get()); 311215f2bd95SEwan Crawford 311315f2bd95SEwan Crawford strm.Indent("Dimensions: "); 311415f2bd95SEwan Crawford if (!alloc->dimension.isValid()) 311515f2bd95SEwan Crawford strm.Printf("unknown\n"); 311615f2bd95SEwan Crawford else 3117b3f7f69dSAidan Dodds strm.Printf("(%" PRId32 ", %" PRId32 ", %" PRId32 ")\n", 3118b9c1b51eSKate Stone alloc->dimension.get()->dim_1, alloc->dimension.get()->dim_2, 3119b9c1b51eSKate Stone alloc->dimension.get()->dim_3); 312015f2bd95SEwan Crawford 312115f2bd95SEwan Crawford strm.Indent("Data Type: "); 3122b9c1b51eSKate Stone if (!alloc->element.type.isValid() || 3123b9c1b51eSKate Stone !alloc->element.type_vec_size.isValid()) 312415f2bd95SEwan Crawford strm.Printf("unknown\n"); 3125b9c1b51eSKate Stone else { 31268b244e21SEwan Crawford const int vector_size = *alloc->element.type_vec_size.get(); 31272e920715SEwan Crawford Element::DataType type = *alloc->element.type.get(); 312815f2bd95SEwan Crawford 31298b244e21SEwan Crawford if (!alloc->element.type_name.IsEmpty()) 31308b244e21SEwan Crawford strm.Printf("%s\n", alloc->element.type_name.AsCString()); 3131b9c1b51eSKate Stone else { 3132b9c1b51eSKate Stone // Enum value isn't monotonous, so doesn't always index 3133b9c1b51eSKate Stone // RsDataTypeToString array 31342e920715SEwan Crawford if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT) 3135b9c1b51eSKate Stone type = 3136b9c1b51eSKate Stone static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) + 3137b3f7f69dSAidan Dodds Element::RS_TYPE_MATRIX_2X2 + 1); 31382e920715SEwan Crawford 3139b3f7f69dSAidan Dodds if (type >= (sizeof(AllocationDetails::RsDataTypeToString) / 3140b3f7f69dSAidan Dodds sizeof(AllocationDetails::RsDataTypeToString[0])) || 3141b3f7f69dSAidan Dodds vector_size > 4 || vector_size < 1) 314215f2bd95SEwan Crawford strm.Printf("invalid type\n"); 314315f2bd95SEwan Crawford else 3144b9c1b51eSKate Stone strm.Printf( 3145b9c1b51eSKate Stone "%s\n", 3146b9c1b51eSKate Stone AllocationDetails::RsDataTypeToString[static_cast<uint32_t>(type)] 3147b3f7f69dSAidan Dodds [vector_size - 1]); 314815f2bd95SEwan Crawford } 31492e920715SEwan Crawford } 315015f2bd95SEwan Crawford 315115f2bd95SEwan Crawford strm.Indent("Data Kind: "); 31528b244e21SEwan Crawford if (!alloc->element.type_kind.isValid()) 315315f2bd95SEwan Crawford strm.Printf("unknown\n"); 3154b9c1b51eSKate Stone else { 31558b244e21SEwan Crawford const Element::DataKind kind = *alloc->element.type_kind.get(); 31568b244e21SEwan Crawford if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV) 315715f2bd95SEwan Crawford strm.Printf("invalid kind\n"); 315815f2bd95SEwan Crawford else 3159b9c1b51eSKate Stone strm.Printf( 3160b9c1b51eSKate Stone "%s\n", 3161b9c1b51eSKate Stone AllocationDetails::RsDataKindToString[static_cast<uint32_t>(kind)]); 316215f2bd95SEwan Crawford } 316315f2bd95SEwan Crawford 316415f2bd95SEwan Crawford strm.EOL(); 316515f2bd95SEwan Crawford strm.IndentLess(); 316615f2bd95SEwan Crawford } 316715f2bd95SEwan Crawford strm.IndentLess(); 316815f2bd95SEwan Crawford } 316915f2bd95SEwan Crawford 31707dc7771cSEwan Crawford // Set breakpoints on every kernel found in RS module 3171b9c1b51eSKate Stone void RenderScriptRuntime::BreakOnModuleKernels( 3172b9c1b51eSKate Stone const RSModuleDescriptorSP rsmodule_sp) { 3173b9c1b51eSKate Stone for (const auto &kernel : rsmodule_sp->m_kernels) { 31747dc7771cSEwan Crawford // Don't set breakpoint on 'root' kernel 31757dc7771cSEwan Crawford if (strcmp(kernel.m_name.AsCString(), "root") == 0) 31767dc7771cSEwan Crawford continue; 31777dc7771cSEwan Crawford 31787dc7771cSEwan Crawford CreateKernelBreakpoint(kernel.m_name); 31797dc7771cSEwan Crawford } 31807dc7771cSEwan Crawford } 31817dc7771cSEwan Crawford 31827dc7771cSEwan Crawford // Method is internally called by the 'kernel breakpoint all' command to 31837dc7771cSEwan Crawford // enable or disable breaking on all kernels. 31847dc7771cSEwan Crawford // 31857dc7771cSEwan Crawford // When do_break is true we want to enable this functionality. 31867dc7771cSEwan Crawford // When do_break is false we want to disable it. 3187b9c1b51eSKate Stone void RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) { 3188b9c1b51eSKate Stone Log *log( 3189b9c1b51eSKate Stone GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 31907dc7771cSEwan Crawford 31917dc7771cSEwan Crawford InitSearchFilter(target); 31927dc7771cSEwan Crawford 31937dc7771cSEwan Crawford // Set breakpoints on all the kernels 3194b9c1b51eSKate Stone if (do_break && !m_breakAllKernels) { 31957dc7771cSEwan Crawford m_breakAllKernels = true; 31967dc7771cSEwan Crawford 31977dc7771cSEwan Crawford for (const auto &module : m_rsmodules) 31987dc7771cSEwan Crawford BreakOnModuleKernels(module); 31997dc7771cSEwan Crawford 32007dc7771cSEwan Crawford if (log) 3201b9c1b51eSKate Stone log->Printf("%s(True) - breakpoints set on all currently loaded kernels.", 3202b9c1b51eSKate Stone __FUNCTION__); 3203b9c1b51eSKate Stone } else if (!do_break && 3204b9c1b51eSKate Stone m_breakAllKernels) // Breakpoints won't be set on any new kernels. 32057dc7771cSEwan Crawford { 32067dc7771cSEwan Crawford m_breakAllKernels = false; 32077dc7771cSEwan Crawford 32087dc7771cSEwan Crawford if (log) 3209b9c1b51eSKate Stone log->Printf("%s(False) - breakpoints no longer automatically set.", 3210b9c1b51eSKate Stone __FUNCTION__); 32117dc7771cSEwan Crawford } 32127dc7771cSEwan Crawford } 32137dc7771cSEwan Crawford 32147dc7771cSEwan Crawford // Given the name of a kernel this function creates a breakpoint using our 32157dc7771cSEwan Crawford // own breakpoint resolver, and returns the Breakpoint shared pointer. 32167dc7771cSEwan Crawford BreakpointSP 3217b9c1b51eSKate Stone RenderScriptRuntime::CreateKernelBreakpoint(const ConstString &name) { 3218b9c1b51eSKate Stone Log *log( 3219b9c1b51eSKate Stone GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 32207dc7771cSEwan Crawford 3221b9c1b51eSKate Stone if (!m_filtersp) { 32227dc7771cSEwan Crawford if (log) 3223b3f7f69dSAidan Dodds log->Printf("%s - error, no breakpoint search filter set.", __FUNCTION__); 32247dc7771cSEwan Crawford return nullptr; 32257dc7771cSEwan Crawford } 32267dc7771cSEwan Crawford 32277dc7771cSEwan Crawford BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name)); 3228b9c1b51eSKate Stone BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint( 3229b9c1b51eSKate Stone m_filtersp, resolver_sp, false, false, false); 32307dc7771cSEwan Crawford 3231b9c1b51eSKate Stone // Give RS breakpoints a specific name, so the user can manipulate them as a 3232b9c1b51eSKate Stone // group. 323354782db7SEwan Crawford Error err; 323454782db7SEwan Crawford if (!bp->AddName("RenderScriptKernel", err) && log) 3235b9c1b51eSKate Stone log->Printf("%s - error setting break name, '%s'.", __FUNCTION__, 3236b9c1b51eSKate Stone err.AsCString()); 323754782db7SEwan Crawford 32387dc7771cSEwan Crawford return bp; 32397dc7771cSEwan Crawford } 32407dc7771cSEwan Crawford 3241b9c1b51eSKate Stone // Given an expression for a variable this function tries to calculate the 3242b9c1b51eSKate Stone // variable's value. 3243b9c1b51eSKate Stone // If this is possible it returns true and sets the uint64_t parameter to the 3244b9c1b51eSKate Stone // variables unsigned value. 3245018f5a7eSEwan Crawford // Otherwise function returns false. 3246b9c1b51eSKate Stone bool RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp, 3247b9c1b51eSKate Stone const char *var_name, 3248b9c1b51eSKate Stone uint64_t &val) { 3249018f5a7eSEwan Crawford Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 3250018f5a7eSEwan Crawford Error error; 3251018f5a7eSEwan Crawford VariableSP var_sp; 3252018f5a7eSEwan Crawford 3253018f5a7eSEwan Crawford // Find variable in stack frame 3254b3f7f69dSAidan Dodds ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath( 3255b3f7f69dSAidan Dodds var_name, eNoDynamicValues, 3256b9c1b51eSKate Stone StackFrame::eExpressionPathOptionCheckPtrVsMember | 3257b9c1b51eSKate Stone StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, 3258b3f7f69dSAidan Dodds var_sp, error)); 3259b9c1b51eSKate Stone if (!error.Success()) { 3260018f5a7eSEwan Crawford if (log) 3261b9c1b51eSKate Stone log->Printf("%s - error, couldn't find '%s' in frame", __FUNCTION__, 3262b9c1b51eSKate Stone var_name); 3263018f5a7eSEwan Crawford return false; 3264018f5a7eSEwan Crawford } 3265018f5a7eSEwan Crawford 3266b3f7f69dSAidan Dodds // Find the uint32_t value for the variable 3267018f5a7eSEwan Crawford bool success = false; 3268018f5a7eSEwan Crawford val = value_sp->GetValueAsUnsigned(0, &success); 3269b9c1b51eSKate Stone if (!success) { 3270018f5a7eSEwan Crawford if (log) 3271b9c1b51eSKate Stone log->Printf("%s - error, couldn't parse '%s' as an uint32_t.", 3272b9c1b51eSKate Stone __FUNCTION__, var_name); 3273018f5a7eSEwan Crawford return false; 3274018f5a7eSEwan Crawford } 3275018f5a7eSEwan Crawford 3276018f5a7eSEwan Crawford return true; 3277018f5a7eSEwan Crawford } 3278018f5a7eSEwan Crawford 3279b9c1b51eSKate Stone // Function attempts to find the current coordinate of a kernel invocation by 3280b9c1b51eSKate Stone // investigating the 3281b9c1b51eSKate Stone // values of frame variables in the .expand function. These coordinates are 3282b9c1b51eSKate Stone // returned via the coord 3283b9c1b51eSKate Stone // array reference parameter. Returns true if the coordinates could be found, 3284b9c1b51eSKate Stone // and false otherwise. 3285b9c1b51eSKate Stone bool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord, 3286b9c1b51eSKate Stone Thread *thread_ptr) { 32871e05c3bcSGreg Clayton static const std::string s_runtimeExpandSuffix(".expand"); 3288b9c1b51eSKate Stone static const std::array<const char *, 3> s_runtimeCoordVars{ 3289b9c1b51eSKate Stone {"rsIndex", "p->current.y", "p->current.z"}}; 32901e05c3bcSGreg Clayton 32914f8817c2SEwan Crawford Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 32924f8817c2SEwan Crawford 3293b9c1b51eSKate Stone if (!thread_ptr) { 32944f8817c2SEwan Crawford if (log) 32954f8817c2SEwan Crawford log->Printf("%s - Error, No thread pointer", __FUNCTION__); 32964f8817c2SEwan Crawford 32974f8817c2SEwan Crawford return false; 32984f8817c2SEwan Crawford } 32994f8817c2SEwan Crawford 3300b9c1b51eSKate Stone // Walk the call stack looking for a function whose name has the suffix 3301b9c1b51eSKate Stone // '.expand' 33024f8817c2SEwan Crawford // and contains the variables we're looking for. 3303b9c1b51eSKate Stone for (uint32_t i = 0; i < thread_ptr->GetStackFrameCount(); ++i) { 33044f8817c2SEwan Crawford if (!thread_ptr->SetSelectedFrameByIndex(i)) 33054f8817c2SEwan Crawford continue; 33064f8817c2SEwan Crawford 33074f8817c2SEwan Crawford StackFrameSP frame_sp = thread_ptr->GetSelectedFrame(); 33084f8817c2SEwan Crawford if (!frame_sp) 33094f8817c2SEwan Crawford continue; 33104f8817c2SEwan Crawford 33114f8817c2SEwan Crawford // Find the function name 33124f8817c2SEwan Crawford const SymbolContext sym_ctx = frame_sp->GetSymbolContext(false); 33134f8817c2SEwan Crawford const char *func_name_cstr = sym_ctx.GetFunctionName().AsCString(); 33144f8817c2SEwan Crawford if (!func_name_cstr) 33154f8817c2SEwan Crawford continue; 33164f8817c2SEwan Crawford 33174f8817c2SEwan Crawford if (log) 3318b9c1b51eSKate Stone log->Printf("%s - Inspecting function '%s'", __FUNCTION__, 3319b9c1b51eSKate Stone func_name_cstr); 33204f8817c2SEwan Crawford 33214f8817c2SEwan Crawford // Check if function name has .expand suffix 33224f8817c2SEwan Crawford std::string func_name(func_name_cstr); 3323b9c1b51eSKate Stone const int length_difference = 3324b9c1b51eSKate Stone func_name.length() - s_runtimeExpandSuffix.length(); 33254f8817c2SEwan Crawford if (length_difference <= 0) 33264f8817c2SEwan Crawford continue; 33274f8817c2SEwan Crawford 3328b9c1b51eSKate Stone const int32_t has_expand_suffix = 3329b9c1b51eSKate Stone func_name.compare(length_difference, s_runtimeExpandSuffix.length(), 33301e05c3bcSGreg Clayton s_runtimeExpandSuffix); 33314f8817c2SEwan Crawford 33324f8817c2SEwan Crawford if (has_expand_suffix != 0) 33334f8817c2SEwan Crawford continue; 33344f8817c2SEwan Crawford 33354f8817c2SEwan Crawford if (log) 3336b9c1b51eSKate Stone log->Printf("%s - Found .expand function '%s'", __FUNCTION__, 3337b9c1b51eSKate Stone func_name_cstr); 33384f8817c2SEwan Crawford 3339b9c1b51eSKate Stone // Get values for variables in .expand frame that tell us the current kernel 3340b9c1b51eSKate Stone // invocation 33414f8817c2SEwan Crawford bool found_coord_variables = true; 33421e05c3bcSGreg Clayton assert(s_runtimeCoordVars.size() == coord.size()); 33434f8817c2SEwan Crawford 3344b9c1b51eSKate Stone for (uint32_t i = 0; i < coord.size(); ++i) { 33454f8817c2SEwan Crawford uint64_t value = 0; 3346b9c1b51eSKate Stone if (!GetFrameVarAsUnsigned(frame_sp, s_runtimeCoordVars[i], value)) { 33474f8817c2SEwan Crawford found_coord_variables = false; 33484f8817c2SEwan Crawford break; 33494f8817c2SEwan Crawford } 33504f8817c2SEwan Crawford coord[i] = value; 33514f8817c2SEwan Crawford } 33524f8817c2SEwan Crawford 33534f8817c2SEwan Crawford if (found_coord_variables) 33544f8817c2SEwan Crawford return true; 33554f8817c2SEwan Crawford } 33564f8817c2SEwan Crawford return false; 33574f8817c2SEwan Crawford } 33584f8817c2SEwan Crawford 3359b9c1b51eSKate Stone // Callback when a kernel breakpoint hits and we're looking for a specific 3360b9c1b51eSKate Stone // coordinate. 3361b9c1b51eSKate Stone // Baton parameter contains a pointer to the target coordinate we want to break 3362b9c1b51eSKate Stone // on. 3363b9c1b51eSKate Stone // Function then checks the .expand frame for the current coordinate and breaks 3364b9c1b51eSKate Stone // to user if it matches. 3365018f5a7eSEwan Crawford // Parameter 'break_id' is the id of the Breakpoint which made the callback. 3366018f5a7eSEwan Crawford // Parameter 'break_loc_id' is the id for the BreakpointLocation which was hit, 3367018f5a7eSEwan Crawford // a single logical breakpoint can have multiple addresses. 3368b9c1b51eSKate Stone bool RenderScriptRuntime::KernelBreakpointHit(void *baton, 3369b9c1b51eSKate Stone StoppointCallbackContext *ctx, 3370b9c1b51eSKate Stone user_id_t break_id, 3371b9c1b51eSKate Stone user_id_t break_loc_id) { 3372b9c1b51eSKate Stone Log *log( 3373b9c1b51eSKate Stone GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3374018f5a7eSEwan Crawford 3375b9c1b51eSKate Stone assert(baton && 3376b9c1b51eSKate Stone "Error: null baton in conditional kernel breakpoint callback"); 3377018f5a7eSEwan Crawford 3378018f5a7eSEwan Crawford // Coordinate we want to stop on 33794f8817c2SEwan Crawford const uint32_t *target_coord = static_cast<const uint32_t *>(baton); 3380018f5a7eSEwan Crawford 3381018f5a7eSEwan Crawford if (log) 3382b9c1b51eSKate Stone log->Printf("%s - Break ID %" PRIu64 ", (%" PRIu32 ", %" PRIu32 ", %" PRIu32 3383b9c1b51eSKate Stone ")", 3384b9c1b51eSKate Stone __FUNCTION__, break_id, target_coord[0], target_coord[1], 3385b9c1b51eSKate Stone target_coord[2]); 3386018f5a7eSEwan Crawford 33874f8817c2SEwan Crawford // Select current thread 3388018f5a7eSEwan Crawford ExecutionContext context(ctx->exe_ctx_ref); 33894f8817c2SEwan Crawford Thread *thread_ptr = context.GetThreadPtr(); 33904f8817c2SEwan Crawford assert(thread_ptr && "Null thread pointer"); 33914f8817c2SEwan Crawford 33924f8817c2SEwan Crawford // Find current kernel invocation from .expand frame variables 33934f8817c2SEwan Crawford RSCoordinate current_coord{}; // Zero initialise array 3394b9c1b51eSKate Stone if (!GetKernelCoordinate(current_coord, thread_ptr)) { 3395018f5a7eSEwan Crawford if (log) 3396b9c1b51eSKate Stone log->Printf("%s - Error, couldn't select .expand stack frame", 3397b9c1b51eSKate Stone __FUNCTION__); 3398018f5a7eSEwan Crawford return false; 3399018f5a7eSEwan Crawford } 3400018f5a7eSEwan Crawford 3401018f5a7eSEwan Crawford if (log) 3402b9c1b51eSKate Stone log->Printf("%s - (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", __FUNCTION__, 3403b9c1b51eSKate Stone current_coord[0], current_coord[1], current_coord[2]); 3404018f5a7eSEwan Crawford 3405b9c1b51eSKate Stone // Check if the current kernel invocation coordinate matches our target 3406b9c1b51eSKate Stone // coordinate 3407b3f7f69dSAidan Dodds if (current_coord[0] == target_coord[0] && 3408b3f7f69dSAidan Dodds current_coord[1] == target_coord[1] && 3409b9c1b51eSKate Stone current_coord[2] == target_coord[2]) { 3410018f5a7eSEwan Crawford if (log) 3411b9c1b51eSKate Stone log->Printf("%s, BREAKING (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", 3412b9c1b51eSKate Stone __FUNCTION__, current_coord[0], current_coord[1], 3413b9c1b51eSKate Stone current_coord[2]); 3414018f5a7eSEwan Crawford 3415b9c1b51eSKate Stone BreakpointSP breakpoint_sp = 3416b9c1b51eSKate Stone context.GetTargetPtr()->GetBreakpointByID(break_id); 3417b9c1b51eSKate Stone assert(breakpoint_sp != nullptr && 3418b9c1b51eSKate Stone "Error: Couldn't find breakpoint matching break id for callback"); 3419b9c1b51eSKate Stone breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint 3420b9c1b51eSKate Stone // should only be hit once. 3421018f5a7eSEwan Crawford return true; 3422018f5a7eSEwan Crawford } 3423018f5a7eSEwan Crawford 3424018f5a7eSEwan Crawford // No match on coordinate 3425018f5a7eSEwan Crawford return false; 3426018f5a7eSEwan Crawford } 3427018f5a7eSEwan Crawford 3428b9c1b51eSKate Stone // Tries to set a breakpoint on the start of a kernel, resolved using the kernel 3429b9c1b51eSKate Stone // name. 3430b9c1b51eSKate Stone // Argument 'coords', represents a three dimensional coordinate which can be 3431b9c1b51eSKate Stone // used to specify 3432b9c1b51eSKate Stone // a single kernel instance to break on. If this is set then we add a callback 3433b9c1b51eSKate Stone // to the breakpoint. 3434b9c1b51eSKate Stone void RenderScriptRuntime::PlaceBreakpointOnKernel( 3435b9c1b51eSKate Stone Stream &strm, const char *name, const std::array<int, 3> coords, 3436b9c1b51eSKate Stone Error &error, TargetSP target) { 3437b9c1b51eSKate Stone if (!name) { 34384640cde1SColin Riley error.SetErrorString("invalid kernel name"); 34394640cde1SColin Riley return; 34404640cde1SColin Riley } 34414640cde1SColin Riley 34427dc7771cSEwan Crawford InitSearchFilter(target); 344398156583SEwan Crawford 34444640cde1SColin Riley ConstString kernel_name(name); 34457dc7771cSEwan Crawford BreakpointSP bp = CreateKernelBreakpoint(kernel_name); 3446018f5a7eSEwan Crawford 3447018f5a7eSEwan Crawford // We have a conditional breakpoint on a specific coordinate 3448b9c1b51eSKate Stone if (coords[0] != -1) { 3449b9c1b51eSKate Stone strm.Printf("Conditional kernel breakpoint on coordinate %" PRId32 3450b9c1b51eSKate Stone ", %" PRId32 ", %" PRId32, 3451b3f7f69dSAidan Dodds coords[0], coords[1], coords[2]); 3452018f5a7eSEwan Crawford strm.EOL(); 3453018f5a7eSEwan Crawford 3454018f5a7eSEwan Crawford // Allocate memory for the baton, and copy over coordinate 34554f8817c2SEwan Crawford uint32_t *baton = new uint32_t[coords.size()]; 3456b9c1b51eSKate Stone baton[0] = coords[0]; 3457b9c1b51eSKate Stone baton[1] = coords[1]; 3458b9c1b51eSKate Stone baton[2] = coords[2]; 3459018f5a7eSEwan Crawford 3460018f5a7eSEwan Crawford // Create a callback that will be invoked every time the breakpoint is hit. 3461b9c1b51eSKate Stone // The baton object passed to the handler is the target coordinate we want 3462b9c1b51eSKate Stone // to break on. 3463018f5a7eSEwan Crawford bp->SetCallback(KernelBreakpointHit, baton, true); 3464018f5a7eSEwan Crawford 3465b9c1b51eSKate Stone // Store a shared pointer to the baton, so the memory will eventually be 3466b9c1b51eSKate Stone // cleaned up after destruction 34674f8817c2SEwan Crawford m_conditional_breaks[bp->GetID()] = std::shared_ptr<uint32_t>(baton); 3468018f5a7eSEwan Crawford } 3469018f5a7eSEwan Crawford 347098156583SEwan Crawford if (bp) 347198156583SEwan Crawford bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false); 34724640cde1SColin Riley } 34734640cde1SColin Riley 3474b9c1b51eSKate Stone void RenderScriptRuntime::DumpModules(Stream &strm) const { 34755ec532a9SColin Riley strm.Printf("RenderScript Modules:"); 34765ec532a9SColin Riley strm.EOL(); 34775ec532a9SColin Riley strm.IndentMore(); 3478b9c1b51eSKate Stone for (const auto &module : m_rsmodules) { 34794640cde1SColin Riley module->Dump(strm); 34805ec532a9SColin Riley } 34815ec532a9SColin Riley strm.IndentLess(); 34825ec532a9SColin Riley } 34835ec532a9SColin Riley 348478f339d1SEwan Crawford RenderScriptRuntime::ScriptDetails * 3485b9c1b51eSKate Stone RenderScriptRuntime::LookUpScript(addr_t address, bool create) { 3486b9c1b51eSKate Stone for (const auto &s : m_scripts) { 348778f339d1SEwan Crawford if (s->script.isValid()) 348878f339d1SEwan Crawford if (*s->script == address) 348978f339d1SEwan Crawford return s.get(); 349078f339d1SEwan Crawford } 3491b9c1b51eSKate Stone if (create) { 349278f339d1SEwan Crawford std::unique_ptr<ScriptDetails> s(new ScriptDetails); 349378f339d1SEwan Crawford s->script = address; 349478f339d1SEwan Crawford m_scripts.push_back(std::move(s)); 3495d10ca9deSEwan Crawford return m_scripts.back().get(); 349678f339d1SEwan Crawford } 349778f339d1SEwan Crawford return nullptr; 349878f339d1SEwan Crawford } 349978f339d1SEwan Crawford 350078f339d1SEwan Crawford RenderScriptRuntime::AllocationDetails * 3501b9c1b51eSKate Stone RenderScriptRuntime::LookUpAllocation(addr_t address) { 3502b9c1b51eSKate Stone for (const auto &a : m_allocations) { 350378f339d1SEwan Crawford if (a->address.isValid()) 350478f339d1SEwan Crawford if (*a->address == address) 350578f339d1SEwan Crawford return a.get(); 350678f339d1SEwan Crawford } 35075d057637SLuke Drummond return nullptr; 35085d057637SLuke Drummond } 35095d057637SLuke Drummond 35105d057637SLuke Drummond RenderScriptRuntime::AllocationDetails * 3511b9c1b51eSKate Stone RenderScriptRuntime::CreateAllocation(addr_t address) { 35125d057637SLuke Drummond Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 35135d057637SLuke Drummond 35145d057637SLuke Drummond // Remove any previous allocation which contains the same address 35155d057637SLuke Drummond auto it = m_allocations.begin(); 3516b9c1b51eSKate Stone while (it != m_allocations.end()) { 3517b9c1b51eSKate Stone if (*((*it)->address) == address) { 35185d057637SLuke Drummond if (log) 3519b9c1b51eSKate Stone log->Printf("%s - Removing allocation id: %d, address: 0x%" PRIx64, 3520b9c1b51eSKate Stone __FUNCTION__, (*it)->id, address); 35215d057637SLuke Drummond 35225d057637SLuke Drummond it = m_allocations.erase(it); 3523b9c1b51eSKate Stone } else { 35245d057637SLuke Drummond it++; 35255d057637SLuke Drummond } 35265d057637SLuke Drummond } 35275d057637SLuke Drummond 352878f339d1SEwan Crawford std::unique_ptr<AllocationDetails> a(new AllocationDetails); 352978f339d1SEwan Crawford a->address = address; 353078f339d1SEwan Crawford m_allocations.push_back(std::move(a)); 3531d10ca9deSEwan Crawford return m_allocations.back().get(); 353278f339d1SEwan Crawford } 353378f339d1SEwan Crawford 3534b9c1b51eSKate Stone void RSModuleDescriptor::Dump(Stream &strm) const { 3535*7f193d69SLuke Drummond int indent = strm.GetIndentLevel(); 3536*7f193d69SLuke Drummond 35375ec532a9SColin Riley strm.Indent(); 35385ec532a9SColin Riley m_module->GetFileSpec().Dump(&strm); 3539*7f193d69SLuke Drummond strm.Indent(m_module->GetNumCompileUnits() ? "Debug info loaded." 3540*7f193d69SLuke Drummond : "Debug info does not exist."); 35415ec532a9SColin Riley strm.EOL(); 35425ec532a9SColin Riley strm.IndentMore(); 3543*7f193d69SLuke Drummond 35445ec532a9SColin Riley strm.Indent(); 3545189598edSColin Riley strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size())); 35465ec532a9SColin Riley strm.EOL(); 35475ec532a9SColin Riley strm.IndentMore(); 3548b9c1b51eSKate Stone for (const auto &global : m_globals) { 35495ec532a9SColin Riley global.Dump(strm); 35505ec532a9SColin Riley } 35515ec532a9SColin Riley strm.IndentLess(); 3552*7f193d69SLuke Drummond 35535ec532a9SColin Riley strm.Indent(); 3554189598edSColin Riley strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size())); 35555ec532a9SColin Riley strm.EOL(); 35565ec532a9SColin Riley strm.IndentMore(); 3557b9c1b51eSKate Stone for (const auto &kernel : m_kernels) { 35585ec532a9SColin Riley kernel.Dump(strm); 35595ec532a9SColin Riley } 3560*7f193d69SLuke Drummond strm.IndentLess(); 3561*7f193d69SLuke Drummond 3562*7f193d69SLuke Drummond strm.Indent(); 35634640cde1SColin Riley strm.Printf("Pragmas: %" PRIu64, static_cast<uint64_t>(m_pragmas.size())); 35644640cde1SColin Riley strm.EOL(); 35654640cde1SColin Riley strm.IndentMore(); 3566b9c1b51eSKate Stone for (const auto &key_val : m_pragmas) { 3567*7f193d69SLuke Drummond strm.Indent(); 35684640cde1SColin Riley strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str()); 35694640cde1SColin Riley strm.EOL(); 35704640cde1SColin Riley } 3571*7f193d69SLuke Drummond strm.IndentLess(); 3572*7f193d69SLuke Drummond 3573*7f193d69SLuke Drummond strm.Indent(); 3574*7f193d69SLuke Drummond strm.Printf("Reductions: %" PRIu64, 3575*7f193d69SLuke Drummond static_cast<uint64_t>(m_reductions.size())); 3576*7f193d69SLuke Drummond strm.EOL(); 3577*7f193d69SLuke Drummond strm.IndentMore(); 3578*7f193d69SLuke Drummond for (const auto &reduction : m_reductions) { 3579*7f193d69SLuke Drummond reduction.Dump(strm); 3580*7f193d69SLuke Drummond } 3581*7f193d69SLuke Drummond 3582*7f193d69SLuke Drummond strm.SetIndentLevel(indent); 35835ec532a9SColin Riley } 35845ec532a9SColin Riley 3585b9c1b51eSKate Stone void RSGlobalDescriptor::Dump(Stream &strm) const { 35865ec532a9SColin Riley strm.Indent(m_name.AsCString()); 35874640cde1SColin Riley VariableList var_list; 35884640cde1SColin Riley m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list); 3589b9c1b51eSKate Stone if (var_list.GetSize() == 1) { 35904640cde1SColin Riley auto var = var_list.GetVariableAtIndex(0); 35914640cde1SColin Riley auto type = var->GetType(); 3592b9c1b51eSKate Stone if (type) { 35934640cde1SColin Riley strm.Printf(" - "); 35944640cde1SColin Riley type->DumpTypeName(&strm); 3595b9c1b51eSKate Stone } else { 35964640cde1SColin Riley strm.Printf(" - Unknown Type"); 35974640cde1SColin Riley } 3598b9c1b51eSKate Stone } else { 35994640cde1SColin Riley strm.Printf(" - variable identified, but not found in binary"); 3600b9c1b51eSKate Stone const Symbol *s = m_module->m_module->FindFirstSymbolWithNameAndType( 3601b9c1b51eSKate Stone m_name, eSymbolTypeData); 3602b9c1b51eSKate Stone if (s) { 36034640cde1SColin Riley strm.Printf(" (symbol exists) "); 36044640cde1SColin Riley } 36054640cde1SColin Riley } 36064640cde1SColin Riley 36075ec532a9SColin Riley strm.EOL(); 36085ec532a9SColin Riley } 36095ec532a9SColin Riley 3610b9c1b51eSKate Stone void RSKernelDescriptor::Dump(Stream &strm) const { 36115ec532a9SColin Riley strm.Indent(m_name.AsCString()); 36125ec532a9SColin Riley strm.EOL(); 36135ec532a9SColin Riley } 36145ec532a9SColin Riley 3615*7f193d69SLuke Drummond void RSReductionDescriptor::Dump(lldb_private::Stream &stream) const { 3616*7f193d69SLuke Drummond stream.Indent(m_reduce_name.AsCString()); 3617*7f193d69SLuke Drummond stream.IndentMore(); 3618*7f193d69SLuke Drummond stream.EOL(); 3619*7f193d69SLuke Drummond stream.Indent(); 3620*7f193d69SLuke Drummond stream.Printf("accumulator: %s", m_accum_name.AsCString()); 3621*7f193d69SLuke Drummond stream.EOL(); 3622*7f193d69SLuke Drummond stream.Indent(); 3623*7f193d69SLuke Drummond stream.Printf("initializer: %s", m_init_name.AsCString()); 3624*7f193d69SLuke Drummond stream.EOL(); 3625*7f193d69SLuke Drummond stream.Indent(); 3626*7f193d69SLuke Drummond stream.Printf("combiner: %s", m_comb_name.AsCString()); 3627*7f193d69SLuke Drummond stream.EOL(); 3628*7f193d69SLuke Drummond stream.Indent(); 3629*7f193d69SLuke Drummond stream.Printf("outconverter: %s", m_outc_name.AsCString()); 3630*7f193d69SLuke Drummond stream.EOL(); 3631*7f193d69SLuke Drummond // XXX This is currently unspecified by RenderScript, and unused 3632*7f193d69SLuke Drummond // stream.Indent(); 3633*7f193d69SLuke Drummond // stream.Printf("halter: '%s'", m_init_name.AsCString()); 3634*7f193d69SLuke Drummond // stream.EOL(); 3635*7f193d69SLuke Drummond stream.IndentLess(); 3636*7f193d69SLuke Drummond } 3637*7f193d69SLuke Drummond 3638b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed { 36395ec532a9SColin Riley public: 36405ec532a9SColin Riley CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter) 3641b9c1b51eSKate Stone : CommandObjectParsed( 3642b9c1b51eSKate Stone interpreter, "renderscript module dump", 3643b9c1b51eSKate Stone "Dumps renderscript specific information for all modules.", 3644b9c1b51eSKate Stone "renderscript module dump", 3645b9c1b51eSKate Stone eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} 36465ec532a9SColin Riley 3647222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeModuleDump() override = default; 36485ec532a9SColin Riley 3649b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 36505ec532a9SColin Riley RenderScriptRuntime *runtime = 3651b9c1b51eSKate Stone (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3652b9c1b51eSKate Stone eLanguageTypeExtRenderScript); 36535ec532a9SColin Riley runtime->DumpModules(result.GetOutputStream()); 36545ec532a9SColin Riley result.SetStatus(eReturnStatusSuccessFinishResult); 36555ec532a9SColin Riley return true; 36565ec532a9SColin Riley } 36575ec532a9SColin Riley }; 36585ec532a9SColin Riley 3659b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword { 36605ec532a9SColin Riley public: 36615ec532a9SColin Riley CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter) 3662b9c1b51eSKate Stone : CommandObjectMultiword(interpreter, "renderscript module", 3663b9c1b51eSKate Stone "Commands that deal with RenderScript modules.", 3664b9c1b51eSKate Stone nullptr) { 3665b9c1b51eSKate Stone LoadSubCommand( 3666b9c1b51eSKate Stone "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump( 3667b9c1b51eSKate Stone interpreter))); 36685ec532a9SColin Riley } 36695ec532a9SColin Riley 3670222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeModule() override = default; 36715ec532a9SColin Riley }; 36725ec532a9SColin Riley 3673b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed { 36744640cde1SColin Riley public: 36754640cde1SColin Riley CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter) 3676b9c1b51eSKate Stone : CommandObjectParsed( 3677b9c1b51eSKate Stone interpreter, "renderscript kernel list", 3678b3f7f69dSAidan Dodds "Lists renderscript kernel names and associated script resources.", 3679b9c1b51eSKate Stone "renderscript kernel list", 3680b9c1b51eSKate Stone eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} 36814640cde1SColin Riley 3682222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeKernelList() override = default; 36834640cde1SColin Riley 3684b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 36854640cde1SColin Riley RenderScriptRuntime *runtime = 3686b9c1b51eSKate Stone (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3687b9c1b51eSKate Stone eLanguageTypeExtRenderScript); 36884640cde1SColin Riley runtime->DumpKernels(result.GetOutputStream()); 36894640cde1SColin Riley result.SetStatus(eReturnStatusSuccessFinishResult); 36904640cde1SColin Riley return true; 36914640cde1SColin Riley } 36924640cde1SColin Riley }; 36934640cde1SColin Riley 3694b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpointSet 3695b9c1b51eSKate Stone : public CommandObjectParsed { 36964640cde1SColin Riley public: 3697b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeKernelBreakpointSet( 3698b9c1b51eSKate Stone CommandInterpreter &interpreter) 3699b9c1b51eSKate Stone : CommandObjectParsed( 3700b9c1b51eSKate Stone interpreter, "renderscript kernel breakpoint set", 3701b3f7f69dSAidan Dodds "Sets a breakpoint on a renderscript kernel.", 3702b3f7f69dSAidan Dodds "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]", 3703b9c1b51eSKate Stone eCommandRequiresProcess | eCommandProcessMustBeLaunched | 3704b9c1b51eSKate Stone eCommandProcessMustBePaused), 3705b9c1b51eSKate Stone m_options() {} 37064640cde1SColin Riley 3707222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default; 3708222b937cSEugene Zelenko 3709b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 3710018f5a7eSEwan Crawford 3711b9c1b51eSKate Stone class CommandOptions : public Options { 3712018f5a7eSEwan Crawford public: 3713e1cfbc79STodd Fiala CommandOptions() : Options() {} 3714018f5a7eSEwan Crawford 3715222b937cSEugene Zelenko ~CommandOptions() override = default; 3716018f5a7eSEwan Crawford 3717b9c1b51eSKate Stone Error SetOptionValue(uint32_t option_idx, const char *option_arg, 3718b9c1b51eSKate Stone ExecutionContext *execution_context) override { 3719018f5a7eSEwan Crawford Error error; 3720018f5a7eSEwan Crawford const int short_option = m_getopt_table[option_idx].val; 3721018f5a7eSEwan Crawford 3722b9c1b51eSKate Stone switch (short_option) { 3723018f5a7eSEwan Crawford case 'c': 3724018f5a7eSEwan Crawford if (!ParseCoordinate(option_arg)) 3725b9c1b51eSKate Stone error.SetErrorStringWithFormat( 3726b9c1b51eSKate Stone "Couldn't parse coordinate '%s', should be in format 'x,y,z'.", 3727b3f7f69dSAidan Dodds option_arg); 3728018f5a7eSEwan Crawford break; 3729018f5a7eSEwan Crawford default: 3730b9c1b51eSKate Stone error.SetErrorStringWithFormat("unrecognized option '%c'", 3731b9c1b51eSKate Stone short_option); 3732018f5a7eSEwan Crawford break; 3733018f5a7eSEwan Crawford } 3734018f5a7eSEwan Crawford return error; 3735018f5a7eSEwan Crawford } 3736018f5a7eSEwan Crawford 3737018f5a7eSEwan Crawford // -c takes an argument of the form 'num[,num][,num]'. 3738018f5a7eSEwan Crawford // Where 'id_cstr' is this argument with the whitespace trimmed. 3739018f5a7eSEwan Crawford // Missing coordinates are defaulted to zero. 3740b9c1b51eSKate Stone bool ParseCoordinate(const char *id_cstr) { 3741018f5a7eSEwan Crawford RegularExpression regex; 3742018f5a7eSEwan Crawford RegularExpression::Match regex_match(3); 3743018f5a7eSEwan Crawford 3744018f5a7eSEwan Crawford bool matched = false; 3745b9c1b51eSKate Stone if (regex.Compile("^([0-9]+),([0-9]+),([0-9]+)$") && 3746b9c1b51eSKate Stone regex.Execute(id_cstr, ®ex_match)) 3747018f5a7eSEwan Crawford matched = true; 3748b9c1b51eSKate Stone else if (regex.Compile("^([0-9]+),([0-9]+)$") && 3749b9c1b51eSKate Stone regex.Execute(id_cstr, ®ex_match)) 3750018f5a7eSEwan Crawford matched = true; 3751b9c1b51eSKate Stone else if (regex.Compile("^([0-9]+)$") && 3752b9c1b51eSKate Stone regex.Execute(id_cstr, ®ex_match)) 3753018f5a7eSEwan Crawford matched = true; 3754b9c1b51eSKate Stone for (uint32_t i = 0; i < 3; i++) { 3755018f5a7eSEwan Crawford std::string group; 3756018f5a7eSEwan Crawford if (regex_match.GetMatchAtIndex(id_cstr, i + 1, group)) 3757b3f7f69dSAidan Dodds m_coord[i] = (uint32_t)strtoul(group.c_str(), nullptr, 0); 3758018f5a7eSEwan Crawford else 3759018f5a7eSEwan Crawford m_coord[i] = 0; 3760018f5a7eSEwan Crawford } 3761018f5a7eSEwan Crawford return matched; 3762018f5a7eSEwan Crawford } 3763018f5a7eSEwan Crawford 3764b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 3765018f5a7eSEwan Crawford // -1 means the -c option hasn't been set 3766018f5a7eSEwan Crawford m_coord[0] = -1; 3767018f5a7eSEwan Crawford m_coord[1] = -1; 3768018f5a7eSEwan Crawford m_coord[2] = -1; 3769018f5a7eSEwan Crawford } 3770018f5a7eSEwan Crawford 3771b9c1b51eSKate Stone const OptionDefinition *GetDefinitions() override { return g_option_table; } 3772018f5a7eSEwan Crawford 3773018f5a7eSEwan Crawford static OptionDefinition g_option_table[]; 3774018f5a7eSEwan Crawford std::array<int, 3> m_coord; 3775018f5a7eSEwan Crawford }; 3776018f5a7eSEwan Crawford 3777b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 37784640cde1SColin Riley const size_t argc = command.GetArgumentCount(); 3779b9c1b51eSKate Stone if (argc < 1) { 3780b9c1b51eSKate Stone result.AppendErrorWithFormat( 3781b9c1b51eSKate Stone "'%s' takes 1 argument of kernel name, and an optional coordinate.", 3782b3f7f69dSAidan Dodds m_cmd_name.c_str()); 3783018f5a7eSEwan Crawford result.SetStatus(eReturnStatusFailed); 3784018f5a7eSEwan Crawford return false; 3785018f5a7eSEwan Crawford } 3786018f5a7eSEwan Crawford 37874640cde1SColin Riley RenderScriptRuntime *runtime = 3788b9c1b51eSKate Stone (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3789b9c1b51eSKate Stone eLanguageTypeExtRenderScript); 37904640cde1SColin Riley 37914640cde1SColin Riley Error error; 3792b9c1b51eSKate Stone runtime->PlaceBreakpointOnKernel( 3793b9c1b51eSKate Stone result.GetOutputStream(), command.GetArgumentAtIndex(0), 3794b9c1b51eSKate Stone m_options.m_coord, error, m_exe_ctx.GetTargetSP()); 37954640cde1SColin Riley 3796b9c1b51eSKate Stone if (error.Success()) { 37974640cde1SColin Riley result.AppendMessage("Breakpoint(s) created"); 37984640cde1SColin Riley result.SetStatus(eReturnStatusSuccessFinishResult); 37994640cde1SColin Riley return true; 38004640cde1SColin Riley } 38014640cde1SColin Riley result.SetStatus(eReturnStatusFailed); 38024640cde1SColin Riley result.AppendErrorWithFormat("Error: %s", error.AsCString()); 38034640cde1SColin Riley return false; 38044640cde1SColin Riley } 38054640cde1SColin Riley 3806018f5a7eSEwan Crawford private: 3807018f5a7eSEwan Crawford CommandOptions m_options; 38084640cde1SColin Riley }; 38094640cde1SColin Riley 3810b9c1b51eSKate Stone OptionDefinition CommandObjectRenderScriptRuntimeKernelBreakpointSet:: 3811b9c1b51eSKate Stone CommandOptions::g_option_table[] = { 3812b9c1b51eSKate Stone {LLDB_OPT_SET_1, false, "coordinate", 'c', 3813b9c1b51eSKate Stone OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeValue, 3814b9c1b51eSKate Stone "Set a breakpoint on a single invocation of the kernel with specified " 3815b9c1b51eSKate Stone "coordinate.\n" 3816b9c1b51eSKate Stone "Coordinate takes the form 'x[,y][,z] where x,y,z are positive " 3817b9c1b51eSKate Stone "integers representing kernel dimensions. " 3818018f5a7eSEwan Crawford "Any unset dimensions will be defaulted to zero."}, 3819b3f7f69dSAidan Dodds {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; 3820018f5a7eSEwan Crawford 3821b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpointAll 3822b9c1b51eSKate Stone : public CommandObjectParsed { 38237dc7771cSEwan Crawford public: 3824b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeKernelBreakpointAll( 3825b9c1b51eSKate Stone CommandInterpreter &interpreter) 3826b3f7f69dSAidan Dodds : CommandObjectParsed( 3827b3f7f69dSAidan Dodds interpreter, "renderscript kernel breakpoint all", 3828b9c1b51eSKate Stone "Automatically sets a breakpoint on all renderscript kernels that " 3829b9c1b51eSKate Stone "are or will be loaded.\n" 3830b9c1b51eSKate Stone "Disabling option means breakpoints will no longer be set on any " 3831b9c1b51eSKate Stone "kernels loaded in the future, " 38327dc7771cSEwan Crawford "but does not remove currently set breakpoints.", 38337dc7771cSEwan Crawford "renderscript kernel breakpoint all <enable/disable>", 3834b9c1b51eSKate Stone eCommandRequiresProcess | eCommandProcessMustBeLaunched | 3835b9c1b51eSKate Stone eCommandProcessMustBePaused) {} 38367dc7771cSEwan Crawford 3837222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default; 38387dc7771cSEwan Crawford 3839b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 38407dc7771cSEwan Crawford const size_t argc = command.GetArgumentCount(); 3841b9c1b51eSKate Stone if (argc != 1) { 3842b9c1b51eSKate Stone result.AppendErrorWithFormat( 3843b9c1b51eSKate Stone "'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str()); 38447dc7771cSEwan Crawford result.SetStatus(eReturnStatusFailed); 38457dc7771cSEwan Crawford return false; 38467dc7771cSEwan Crawford } 38477dc7771cSEwan Crawford 3848b3f7f69dSAidan Dodds RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 3849b9c1b51eSKate Stone m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3850b9c1b51eSKate Stone eLanguageTypeExtRenderScript)); 38517dc7771cSEwan Crawford 38527dc7771cSEwan Crawford bool do_break = false; 38537dc7771cSEwan Crawford const char *argument = command.GetArgumentAtIndex(0); 3854b9c1b51eSKate Stone if (strcmp(argument, "enable") == 0) { 38557dc7771cSEwan Crawford do_break = true; 38567dc7771cSEwan Crawford result.AppendMessage("Breakpoints will be set on all kernels."); 3857b9c1b51eSKate Stone } else if (strcmp(argument, "disable") == 0) { 38587dc7771cSEwan Crawford do_break = false; 38597dc7771cSEwan Crawford result.AppendMessage("Breakpoints will not be set on any new kernels."); 3860b9c1b51eSKate Stone } else { 3861b9c1b51eSKate Stone result.AppendErrorWithFormat( 3862b9c1b51eSKate Stone "Argument must be either 'enable' or 'disable'"); 38637dc7771cSEwan Crawford result.SetStatus(eReturnStatusFailed); 38647dc7771cSEwan Crawford return false; 38657dc7771cSEwan Crawford } 38667dc7771cSEwan Crawford 38677dc7771cSEwan Crawford runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP()); 38687dc7771cSEwan Crawford 38697dc7771cSEwan Crawford result.SetStatus(eReturnStatusSuccessFinishResult); 38707dc7771cSEwan Crawford return true; 38717dc7771cSEwan Crawford } 38727dc7771cSEwan Crawford }; 38737dc7771cSEwan Crawford 3874b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelCoordinate 3875b9c1b51eSKate Stone : public CommandObjectParsed { 38764f8817c2SEwan Crawford public: 3877b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeKernelCoordinate( 3878b9c1b51eSKate Stone CommandInterpreter &interpreter) 3879b9c1b51eSKate Stone : CommandObjectParsed( 3880b9c1b51eSKate Stone interpreter, "renderscript kernel coordinate", 38814f8817c2SEwan Crawford "Shows the (x,y,z) coordinate of the current kernel invocation.", 38824f8817c2SEwan Crawford "renderscript kernel coordinate", 3883b9c1b51eSKate Stone eCommandRequiresProcess | eCommandProcessMustBeLaunched | 3884b9c1b51eSKate Stone eCommandProcessMustBePaused) {} 38854f8817c2SEwan Crawford 38864f8817c2SEwan Crawford ~CommandObjectRenderScriptRuntimeKernelCoordinate() override = default; 38874f8817c2SEwan Crawford 3888b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 38894f8817c2SEwan Crawford RSCoordinate coord{}; // Zero initialize array 3890b9c1b51eSKate Stone bool success = RenderScriptRuntime::GetKernelCoordinate( 3891b9c1b51eSKate Stone coord, m_exe_ctx.GetThreadPtr()); 38924f8817c2SEwan Crawford Stream &stream = result.GetOutputStream(); 38934f8817c2SEwan Crawford 3894b9c1b51eSKate Stone if (success) { 3895b9c1b51eSKate Stone stream.Printf("Coordinate: (%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")", 3896b9c1b51eSKate Stone coord[0], coord[1], coord[2]); 38974f8817c2SEwan Crawford stream.EOL(); 38984f8817c2SEwan Crawford result.SetStatus(eReturnStatusSuccessFinishResult); 3899b9c1b51eSKate Stone } else { 39004f8817c2SEwan Crawford stream.Printf("Error: Coordinate could not be found."); 39014f8817c2SEwan Crawford stream.EOL(); 39024f8817c2SEwan Crawford result.SetStatus(eReturnStatusFailed); 39034f8817c2SEwan Crawford } 39044f8817c2SEwan Crawford return true; 39054f8817c2SEwan Crawford } 39064f8817c2SEwan Crawford }; 39074f8817c2SEwan Crawford 3908b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpoint 3909b9c1b51eSKate Stone : public CommandObjectMultiword { 39107dc7771cSEwan Crawford public: 3911b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeKernelBreakpoint( 3912b9c1b51eSKate Stone CommandInterpreter &interpreter) 3913b9c1b51eSKate Stone : CommandObjectMultiword( 3914b9c1b51eSKate Stone interpreter, "renderscript kernel", 3915b9c1b51eSKate Stone "Commands that generate breakpoints on renderscript kernels.", 3916b9c1b51eSKate Stone nullptr) { 3917b9c1b51eSKate Stone LoadSubCommand( 3918b9c1b51eSKate Stone "set", 3919b9c1b51eSKate Stone CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet( 3920b9c1b51eSKate Stone interpreter))); 3921b9c1b51eSKate Stone LoadSubCommand( 3922b9c1b51eSKate Stone "all", 3923b9c1b51eSKate Stone CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll( 3924b9c1b51eSKate Stone interpreter))); 39257dc7771cSEwan Crawford } 39267dc7771cSEwan Crawford 3927222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default; 39287dc7771cSEwan Crawford }; 39297dc7771cSEwan Crawford 3930b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword { 39314640cde1SColin Riley public: 39324640cde1SColin Riley CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter) 3933b9c1b51eSKate Stone : CommandObjectMultiword(interpreter, "renderscript kernel", 3934b9c1b51eSKate Stone "Commands that deal with RenderScript kernels.", 3935b9c1b51eSKate Stone nullptr) { 3936b9c1b51eSKate Stone LoadSubCommand( 3937b9c1b51eSKate Stone "list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList( 3938b9c1b51eSKate Stone interpreter))); 3939b9c1b51eSKate Stone LoadSubCommand( 3940b9c1b51eSKate Stone "coordinate", 3941b9c1b51eSKate Stone CommandObjectSP( 3942b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeKernelCoordinate(interpreter))); 3943b9c1b51eSKate Stone LoadSubCommand( 3944b9c1b51eSKate Stone "breakpoint", 3945b9c1b51eSKate Stone CommandObjectSP( 3946b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter))); 39474640cde1SColin Riley } 39484640cde1SColin Riley 3949222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeKernel() override = default; 39504640cde1SColin Riley }; 39514640cde1SColin Riley 3952b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed { 39534640cde1SColin Riley public: 39544640cde1SColin Riley CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter) 3955b9c1b51eSKate Stone : CommandObjectParsed(interpreter, "renderscript context dump", 3956b9c1b51eSKate Stone "Dumps renderscript context information.", 3957b9c1b51eSKate Stone "renderscript context dump", 3958b9c1b51eSKate Stone eCommandRequiresProcess | 3959b9c1b51eSKate Stone eCommandProcessMustBeLaunched) {} 39604640cde1SColin Riley 3961222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeContextDump() override = default; 39624640cde1SColin Riley 3963b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 39644640cde1SColin Riley RenderScriptRuntime *runtime = 3965b9c1b51eSKate Stone (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3966b9c1b51eSKate Stone eLanguageTypeExtRenderScript); 39674640cde1SColin Riley runtime->DumpContexts(result.GetOutputStream()); 39684640cde1SColin Riley result.SetStatus(eReturnStatusSuccessFinishResult); 39694640cde1SColin Riley return true; 39704640cde1SColin Riley } 39714640cde1SColin Riley }; 39724640cde1SColin Riley 3973b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword { 39744640cde1SColin Riley public: 39754640cde1SColin Riley CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter) 3976b9c1b51eSKate Stone : CommandObjectMultiword(interpreter, "renderscript context", 3977b9c1b51eSKate Stone "Commands that deal with RenderScript contexts.", 3978b9c1b51eSKate Stone nullptr) { 3979b9c1b51eSKate Stone LoadSubCommand( 3980b9c1b51eSKate Stone "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump( 3981b9c1b51eSKate Stone interpreter))); 39824640cde1SColin Riley } 39834640cde1SColin Riley 3984222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeContext() override = default; 39854640cde1SColin Riley }; 39864640cde1SColin Riley 3987b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationDump 3988b9c1b51eSKate Stone : public CommandObjectParsed { 3989a0f08674SEwan Crawford public: 3990b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeAllocationDump( 3991b9c1b51eSKate Stone CommandInterpreter &interpreter) 3992a0f08674SEwan Crawford : CommandObjectParsed(interpreter, "renderscript allocation dump", 3993b9c1b51eSKate Stone "Displays the contents of a particular allocation", 3994b9c1b51eSKate Stone "renderscript allocation dump <ID>", 3995b9c1b51eSKate Stone eCommandRequiresProcess | 3996b9c1b51eSKate Stone eCommandProcessMustBeLaunched), 3997b9c1b51eSKate Stone m_options() {} 3998a0f08674SEwan Crawford 3999222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeAllocationDump() override = default; 4000222b937cSEugene Zelenko 4001b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 4002a0f08674SEwan Crawford 4003b9c1b51eSKate Stone class CommandOptions : public Options { 4004a0f08674SEwan Crawford public: 4005e1cfbc79STodd Fiala CommandOptions() : Options() {} 4006a0f08674SEwan Crawford 4007222b937cSEugene Zelenko ~CommandOptions() override = default; 4008a0f08674SEwan Crawford 4009b9c1b51eSKate Stone Error SetOptionValue(uint32_t option_idx, const char *option_arg, 4010b9c1b51eSKate Stone ExecutionContext *execution_context) override { 4011a0f08674SEwan Crawford Error error; 4012a0f08674SEwan Crawford const int short_option = m_getopt_table[option_idx].val; 4013a0f08674SEwan Crawford 4014b9c1b51eSKate Stone switch (short_option) { 4015a0f08674SEwan Crawford case 'f': 4016a0f08674SEwan Crawford m_outfile.SetFile(option_arg, true); 4017b9c1b51eSKate Stone if (m_outfile.Exists()) { 4018a0f08674SEwan Crawford m_outfile.Clear(); 4019b9c1b51eSKate Stone error.SetErrorStringWithFormat("file already exists: '%s'", 4020b9c1b51eSKate Stone option_arg); 4021a0f08674SEwan Crawford } 4022a0f08674SEwan Crawford break; 4023a0f08674SEwan Crawford default: 4024b9c1b51eSKate Stone error.SetErrorStringWithFormat("unrecognized option '%c'", 4025b9c1b51eSKate Stone short_option); 4026a0f08674SEwan Crawford break; 4027a0f08674SEwan Crawford } 4028a0f08674SEwan Crawford return error; 4029a0f08674SEwan Crawford } 4030a0f08674SEwan Crawford 4031b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 4032a0f08674SEwan Crawford m_outfile.Clear(); 4033a0f08674SEwan Crawford } 4034a0f08674SEwan Crawford 4035b9c1b51eSKate Stone const OptionDefinition *GetDefinitions() override { return g_option_table; } 4036a0f08674SEwan Crawford 4037a0f08674SEwan Crawford static OptionDefinition g_option_table[]; 4038a0f08674SEwan Crawford FileSpec m_outfile; 4039a0f08674SEwan Crawford }; 4040a0f08674SEwan Crawford 4041b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 4042a0f08674SEwan Crawford const size_t argc = command.GetArgumentCount(); 4043b9c1b51eSKate Stone if (argc < 1) { 4044b9c1b51eSKate Stone result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. " 4045b9c1b51eSKate Stone "As well as an optional -f argument", 4046a0f08674SEwan Crawford m_cmd_name.c_str()); 4047a0f08674SEwan Crawford result.SetStatus(eReturnStatusFailed); 4048a0f08674SEwan Crawford return false; 4049a0f08674SEwan Crawford } 4050a0f08674SEwan Crawford 4051b3f7f69dSAidan Dodds RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4052b9c1b51eSKate Stone m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4053b9c1b51eSKate Stone eLanguageTypeExtRenderScript)); 4054a0f08674SEwan Crawford 4055a0f08674SEwan Crawford const char *id_cstr = command.GetArgumentAtIndex(0); 4056a0f08674SEwan Crawford bool convert_complete = false; 4057b9c1b51eSKate Stone const uint32_t id = 4058b9c1b51eSKate Stone StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 4059b9c1b51eSKate Stone if (!convert_complete) { 4060b9c1b51eSKate Stone result.AppendErrorWithFormat("invalid allocation id argument '%s'", 4061b9c1b51eSKate Stone id_cstr); 4062a0f08674SEwan Crawford result.SetStatus(eReturnStatusFailed); 4063a0f08674SEwan Crawford return false; 4064a0f08674SEwan Crawford } 4065a0f08674SEwan Crawford 4066a0f08674SEwan Crawford Stream *output_strm = nullptr; 4067a0f08674SEwan Crawford StreamFile outfile_stream; 4068b9c1b51eSKate Stone const FileSpec &outfile_spec = 4069b9c1b51eSKate Stone m_options.m_outfile; // Dump allocation to file instead 4070b9c1b51eSKate Stone if (outfile_spec) { 4071a0f08674SEwan Crawford // Open output file 4072a0f08674SEwan Crawford char path[256]; 4073a0f08674SEwan Crawford outfile_spec.GetPath(path, sizeof(path)); 4074b9c1b51eSKate Stone if (outfile_stream.GetFile() 4075b9c1b51eSKate Stone .Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate) 4076b9c1b51eSKate Stone .Success()) { 4077a0f08674SEwan Crawford output_strm = &outfile_stream; 4078a0f08674SEwan Crawford result.GetOutputStream().Printf("Results written to '%s'", path); 4079a0f08674SEwan Crawford result.GetOutputStream().EOL(); 4080b9c1b51eSKate Stone } else { 4081a0f08674SEwan Crawford result.AppendErrorWithFormat("Couldn't open file '%s'", path); 4082a0f08674SEwan Crawford result.SetStatus(eReturnStatusFailed); 4083a0f08674SEwan Crawford return false; 4084a0f08674SEwan Crawford } 4085b9c1b51eSKate Stone } else 4086a0f08674SEwan Crawford output_strm = &result.GetOutputStream(); 4087a0f08674SEwan Crawford 4088a0f08674SEwan Crawford assert(output_strm != nullptr); 4089b9c1b51eSKate Stone bool success = 4090b9c1b51eSKate Stone runtime->DumpAllocation(*output_strm, m_exe_ctx.GetFramePtr(), id); 4091a0f08674SEwan Crawford 4092a0f08674SEwan Crawford if (success) 4093a0f08674SEwan Crawford result.SetStatus(eReturnStatusSuccessFinishResult); 4094a0f08674SEwan Crawford else 4095a0f08674SEwan Crawford result.SetStatus(eReturnStatusFailed); 4096a0f08674SEwan Crawford 4097a0f08674SEwan Crawford return true; 4098a0f08674SEwan Crawford } 4099a0f08674SEwan Crawford 4100a0f08674SEwan Crawford private: 4101a0f08674SEwan Crawford CommandOptions m_options; 4102a0f08674SEwan Crawford }; 4103a0f08674SEwan Crawford 4104b9c1b51eSKate Stone OptionDefinition CommandObjectRenderScriptRuntimeAllocationDump:: 4105b9c1b51eSKate Stone CommandOptions::g_option_table[] = { 4106b9c1b51eSKate Stone {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, 4107b9c1b51eSKate Stone nullptr, nullptr, 0, eArgTypeFilename, 4108a0f08674SEwan Crawford "Print results to specified file instead of command line."}, 4109b3f7f69dSAidan Dodds {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; 4110a0f08674SEwan Crawford 4111b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationList 4112b9c1b51eSKate Stone : public CommandObjectParsed { 411315f2bd95SEwan Crawford public: 4114b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeAllocationList( 4115b9c1b51eSKate Stone CommandInterpreter &interpreter) 4116b9c1b51eSKate Stone : CommandObjectParsed( 4117b9c1b51eSKate Stone interpreter, "renderscript allocation list", 4118b9c1b51eSKate Stone "List renderscript allocations and their information.", 4119b9c1b51eSKate Stone "renderscript allocation list", 4120b3f7f69dSAidan Dodds eCommandRequiresProcess | eCommandProcessMustBeLaunched), 4121b9c1b51eSKate Stone m_options() {} 412215f2bd95SEwan Crawford 4123222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeAllocationList() override = default; 4124222b937cSEugene Zelenko 4125b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 412615f2bd95SEwan Crawford 4127b9c1b51eSKate Stone class CommandOptions : public Options { 412815f2bd95SEwan Crawford public: 4129e1cfbc79STodd Fiala CommandOptions() : Options(), m_id(0) {} 413015f2bd95SEwan Crawford 4131222b937cSEugene Zelenko ~CommandOptions() override = default; 413215f2bd95SEwan Crawford 4133b9c1b51eSKate Stone Error SetOptionValue(uint32_t option_idx, const char *option_arg, 4134b9c1b51eSKate Stone ExecutionContext *execution_context) override { 413515f2bd95SEwan Crawford Error error; 413615f2bd95SEwan Crawford const int short_option = m_getopt_table[option_idx].val; 413715f2bd95SEwan Crawford 4138b9c1b51eSKate Stone switch (short_option) { 4139b649b005SEwan Crawford case 'i': 4140b649b005SEwan Crawford bool success; 4141b649b005SEwan Crawford m_id = StringConvert::ToUInt32(option_arg, 0, 0, &success); 4142b649b005SEwan Crawford if (!success) 4143b9c1b51eSKate Stone error.SetErrorStringWithFormat( 4144b9c1b51eSKate Stone "invalid integer value for option '%c'", short_option); 414515f2bd95SEwan Crawford break; 414615f2bd95SEwan Crawford default: 4147b9c1b51eSKate Stone error.SetErrorStringWithFormat("unrecognized option '%c'", 4148b9c1b51eSKate Stone short_option); 414915f2bd95SEwan Crawford break; 415015f2bd95SEwan Crawford } 415115f2bd95SEwan Crawford return error; 415215f2bd95SEwan Crawford } 415315f2bd95SEwan Crawford 4154b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 4155b649b005SEwan Crawford m_id = 0; 415615f2bd95SEwan Crawford } 415715f2bd95SEwan Crawford 4158b9c1b51eSKate Stone const OptionDefinition *GetDefinitions() override { return g_option_table; } 415915f2bd95SEwan Crawford 416015f2bd95SEwan Crawford static OptionDefinition g_option_table[]; 4161b649b005SEwan Crawford uint32_t m_id; 416215f2bd95SEwan Crawford }; 416315f2bd95SEwan Crawford 4164b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 4165b3f7f69dSAidan Dodds RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4166b9c1b51eSKate Stone m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4167b9c1b51eSKate Stone eLanguageTypeExtRenderScript)); 4168b9c1b51eSKate Stone runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(), 4169b9c1b51eSKate Stone m_options.m_id); 417015f2bd95SEwan Crawford result.SetStatus(eReturnStatusSuccessFinishResult); 417115f2bd95SEwan Crawford return true; 417215f2bd95SEwan Crawford } 417315f2bd95SEwan Crawford 417415f2bd95SEwan Crawford private: 417515f2bd95SEwan Crawford CommandOptions m_options; 417615f2bd95SEwan Crawford }; 417715f2bd95SEwan Crawford 4178b9c1b51eSKate Stone OptionDefinition CommandObjectRenderScriptRuntimeAllocationList:: 4179b9c1b51eSKate Stone CommandOptions::g_option_table[] = { 4180b9c1b51eSKate Stone {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument, 4181b9c1b51eSKate Stone nullptr, nullptr, 0, eArgTypeIndex, 4182b649b005SEwan Crawford "Only show details of a single allocation with specified id."}, 4183b3f7f69dSAidan Dodds {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; 418415f2bd95SEwan Crawford 4185b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationLoad 4186b9c1b51eSKate Stone : public CommandObjectParsed { 418755232f09SEwan Crawford public: 4188b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeAllocationLoad( 4189b9c1b51eSKate Stone CommandInterpreter &interpreter) 4190b3f7f69dSAidan Dodds : CommandObjectParsed( 4191b9c1b51eSKate Stone interpreter, "renderscript allocation load", 4192b9c1b51eSKate Stone "Loads renderscript allocation contents from a file.", 4193b9c1b51eSKate Stone "renderscript allocation load <ID> <filename>", 4194b9c1b51eSKate Stone eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} 419555232f09SEwan Crawford 4196222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default; 419755232f09SEwan Crawford 4198b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 419955232f09SEwan Crawford const size_t argc = command.GetArgumentCount(); 4200b9c1b51eSKate Stone if (argc != 2) { 4201b9c1b51eSKate Stone result.AppendErrorWithFormat( 4202b9c1b51eSKate Stone "'%s' takes 2 arguments, an allocation ID and filename to read from.", 4203b3f7f69dSAidan Dodds m_cmd_name.c_str()); 420455232f09SEwan Crawford result.SetStatus(eReturnStatusFailed); 420555232f09SEwan Crawford return false; 420655232f09SEwan Crawford } 420755232f09SEwan Crawford 4208b3f7f69dSAidan Dodds RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4209b9c1b51eSKate Stone m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4210b9c1b51eSKate Stone eLanguageTypeExtRenderScript)); 421155232f09SEwan Crawford 421255232f09SEwan Crawford const char *id_cstr = command.GetArgumentAtIndex(0); 421355232f09SEwan Crawford bool convert_complete = false; 4214b9c1b51eSKate Stone const uint32_t id = 4215b9c1b51eSKate Stone StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 4216b9c1b51eSKate Stone if (!convert_complete) { 4217b9c1b51eSKate Stone result.AppendErrorWithFormat("invalid allocation id argument '%s'", 4218b9c1b51eSKate Stone id_cstr); 421955232f09SEwan Crawford result.SetStatus(eReturnStatusFailed); 422055232f09SEwan Crawford return false; 422155232f09SEwan Crawford } 422255232f09SEwan Crawford 422355232f09SEwan Crawford const char *filename = command.GetArgumentAtIndex(1); 4224b9c1b51eSKate Stone bool success = runtime->LoadAllocation(result.GetOutputStream(), id, 4225b9c1b51eSKate Stone filename, m_exe_ctx.GetFramePtr()); 422655232f09SEwan Crawford 422755232f09SEwan Crawford if (success) 422855232f09SEwan Crawford result.SetStatus(eReturnStatusSuccessFinishResult); 422955232f09SEwan Crawford else 423055232f09SEwan Crawford result.SetStatus(eReturnStatusFailed); 423155232f09SEwan Crawford 423255232f09SEwan Crawford return true; 423355232f09SEwan Crawford } 423455232f09SEwan Crawford }; 423555232f09SEwan Crawford 4236b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationSave 4237b9c1b51eSKate Stone : public CommandObjectParsed { 423855232f09SEwan Crawford public: 4239b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeAllocationSave( 4240b9c1b51eSKate Stone CommandInterpreter &interpreter) 4241b9c1b51eSKate Stone : CommandObjectParsed(interpreter, "renderscript allocation save", 4242b9c1b51eSKate Stone "Write renderscript allocation contents to a file.", 4243b9c1b51eSKate Stone "renderscript allocation save <ID> <filename>", 4244b9c1b51eSKate Stone eCommandRequiresProcess | 4245b9c1b51eSKate Stone eCommandProcessMustBeLaunched) {} 424655232f09SEwan Crawford 4247222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeAllocationSave() override = default; 424855232f09SEwan Crawford 4249b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 425055232f09SEwan Crawford const size_t argc = command.GetArgumentCount(); 4251b9c1b51eSKate Stone if (argc != 2) { 4252b9c1b51eSKate Stone result.AppendErrorWithFormat( 4253b9c1b51eSKate Stone "'%s' takes 2 arguments, an allocation ID and filename to read from.", 4254b3f7f69dSAidan Dodds m_cmd_name.c_str()); 425555232f09SEwan Crawford result.SetStatus(eReturnStatusFailed); 425655232f09SEwan Crawford return false; 425755232f09SEwan Crawford } 425855232f09SEwan Crawford 4259b3f7f69dSAidan Dodds RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4260b9c1b51eSKate Stone m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4261b9c1b51eSKate Stone eLanguageTypeExtRenderScript)); 426255232f09SEwan Crawford 426355232f09SEwan Crawford const char *id_cstr = command.GetArgumentAtIndex(0); 426455232f09SEwan Crawford bool convert_complete = false; 4265b9c1b51eSKate Stone const uint32_t id = 4266b9c1b51eSKate Stone StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 4267b9c1b51eSKate Stone if (!convert_complete) { 4268b9c1b51eSKate Stone result.AppendErrorWithFormat("invalid allocation id argument '%s'", 4269b9c1b51eSKate Stone id_cstr); 427055232f09SEwan Crawford result.SetStatus(eReturnStatusFailed); 427155232f09SEwan Crawford return false; 427255232f09SEwan Crawford } 427355232f09SEwan Crawford 427455232f09SEwan Crawford const char *filename = command.GetArgumentAtIndex(1); 4275b9c1b51eSKate Stone bool success = runtime->SaveAllocation(result.GetOutputStream(), id, 4276b9c1b51eSKate Stone filename, m_exe_ctx.GetFramePtr()); 427755232f09SEwan Crawford 427855232f09SEwan Crawford if (success) 427955232f09SEwan Crawford result.SetStatus(eReturnStatusSuccessFinishResult); 428055232f09SEwan Crawford else 428155232f09SEwan Crawford result.SetStatus(eReturnStatusFailed); 428255232f09SEwan Crawford 428355232f09SEwan Crawford return true; 428455232f09SEwan Crawford } 428555232f09SEwan Crawford }; 428655232f09SEwan Crawford 4287b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationRefresh 4288b9c1b51eSKate Stone : public CommandObjectParsed { 42890d2bfcfbSEwan Crawford public: 4290b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeAllocationRefresh( 4291b9c1b51eSKate Stone CommandInterpreter &interpreter) 42920d2bfcfbSEwan Crawford : CommandObjectParsed(interpreter, "renderscript allocation refresh", 4293b9c1b51eSKate Stone "Recomputes the details of all allocations.", 4294b9c1b51eSKate Stone "renderscript allocation refresh", 4295b9c1b51eSKate Stone eCommandRequiresProcess | 4296b9c1b51eSKate Stone eCommandProcessMustBeLaunched) {} 42970d2bfcfbSEwan Crawford 42980d2bfcfbSEwan Crawford ~CommandObjectRenderScriptRuntimeAllocationRefresh() override = default; 42990d2bfcfbSEwan Crawford 4300b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 43010d2bfcfbSEwan Crawford RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4302b9c1b51eSKate Stone m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4303b9c1b51eSKate Stone eLanguageTypeExtRenderScript)); 43040d2bfcfbSEwan Crawford 4305b9c1b51eSKate Stone bool success = runtime->RecomputeAllAllocations(result.GetOutputStream(), 4306b9c1b51eSKate Stone m_exe_ctx.GetFramePtr()); 43070d2bfcfbSEwan Crawford 4308b9c1b51eSKate Stone if (success) { 43090d2bfcfbSEwan Crawford result.SetStatus(eReturnStatusSuccessFinishResult); 43100d2bfcfbSEwan Crawford return true; 4311b9c1b51eSKate Stone } else { 43120d2bfcfbSEwan Crawford result.SetStatus(eReturnStatusFailed); 43130d2bfcfbSEwan Crawford return false; 43140d2bfcfbSEwan Crawford } 43150d2bfcfbSEwan Crawford } 43160d2bfcfbSEwan Crawford }; 43170d2bfcfbSEwan Crawford 4318b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocation 4319b9c1b51eSKate Stone : public CommandObjectMultiword { 432015f2bd95SEwan Crawford public: 432115f2bd95SEwan Crawford CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter) 4322b9c1b51eSKate Stone : CommandObjectMultiword( 4323b9c1b51eSKate Stone interpreter, "renderscript allocation", 4324b9c1b51eSKate Stone "Commands that deal with RenderScript allocations.", nullptr) { 4325b9c1b51eSKate Stone LoadSubCommand( 4326b9c1b51eSKate Stone "list", 4327b9c1b51eSKate Stone CommandObjectSP( 4328b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeAllocationList(interpreter))); 4329b9c1b51eSKate Stone LoadSubCommand( 4330b9c1b51eSKate Stone "dump", 4331b9c1b51eSKate Stone CommandObjectSP( 4332b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeAllocationDump(interpreter))); 4333b9c1b51eSKate Stone LoadSubCommand( 4334b9c1b51eSKate Stone "save", 4335b9c1b51eSKate Stone CommandObjectSP( 4336b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeAllocationSave(interpreter))); 4337b9c1b51eSKate Stone LoadSubCommand( 4338b9c1b51eSKate Stone "load", 4339b9c1b51eSKate Stone CommandObjectSP( 4340b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter))); 4341b9c1b51eSKate Stone LoadSubCommand( 4342b9c1b51eSKate Stone "refresh", 4343b9c1b51eSKate Stone CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationRefresh( 4344b9c1b51eSKate Stone interpreter))); 434515f2bd95SEwan Crawford } 434615f2bd95SEwan Crawford 4347222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeAllocation() override = default; 434815f2bd95SEwan Crawford }; 434915f2bd95SEwan Crawford 4350b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed { 43514640cde1SColin Riley public: 43524640cde1SColin Riley CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter) 4353b9c1b51eSKate Stone : CommandObjectParsed(interpreter, "renderscript status", 4354b9c1b51eSKate Stone "Displays current RenderScript runtime status.", 4355b9c1b51eSKate Stone "renderscript status", 4356b9c1b51eSKate Stone eCommandRequiresProcess | 4357b9c1b51eSKate Stone eCommandProcessMustBeLaunched) {} 43584640cde1SColin Riley 4359222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeStatus() override = default; 43604640cde1SColin Riley 4361b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 43624640cde1SColin Riley RenderScriptRuntime *runtime = 4363b9c1b51eSKate Stone (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4364b9c1b51eSKate Stone eLanguageTypeExtRenderScript); 43654640cde1SColin Riley runtime->Status(result.GetOutputStream()); 43664640cde1SColin Riley result.SetStatus(eReturnStatusSuccessFinishResult); 43674640cde1SColin Riley return true; 43684640cde1SColin Riley } 43694640cde1SColin Riley }; 43704640cde1SColin Riley 4371b9c1b51eSKate Stone class CommandObjectRenderScriptRuntime : public CommandObjectMultiword { 43725ec532a9SColin Riley public: 43735ec532a9SColin Riley CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter) 4374b9c1b51eSKate Stone : CommandObjectMultiword( 4375b9c1b51eSKate Stone interpreter, "renderscript", 4376b9c1b51eSKate Stone "Commands for operating on the RenderScript runtime.", 4377b9c1b51eSKate Stone "renderscript <subcommand> [<subcommand-options>]") { 4378b9c1b51eSKate Stone LoadSubCommand( 4379b9c1b51eSKate Stone "module", CommandObjectSP( 4380b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeModule(interpreter))); 4381b9c1b51eSKate Stone LoadSubCommand( 4382b9c1b51eSKate Stone "status", CommandObjectSP( 4383b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeStatus(interpreter))); 4384b9c1b51eSKate Stone LoadSubCommand( 4385b9c1b51eSKate Stone "kernel", CommandObjectSP( 4386b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeKernel(interpreter))); 4387b9c1b51eSKate Stone LoadSubCommand("context", 4388b9c1b51eSKate Stone CommandObjectSP(new CommandObjectRenderScriptRuntimeContext( 4389b9c1b51eSKate Stone interpreter))); 4390b9c1b51eSKate Stone LoadSubCommand( 4391b9c1b51eSKate Stone "allocation", 4392b9c1b51eSKate Stone CommandObjectSP( 4393b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeAllocation(interpreter))); 43945ec532a9SColin Riley } 43955ec532a9SColin Riley 4396222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntime() override = default; 43975ec532a9SColin Riley }; 4398ef20b08fSColin Riley 4399b9c1b51eSKate Stone void RenderScriptRuntime::Initiate() { assert(!m_initiated); } 4400ef20b08fSColin Riley 4401ef20b08fSColin Riley RenderScriptRuntime::RenderScriptRuntime(Process *process) 4402b9c1b51eSKate Stone : lldb_private::CPPLanguageRuntime(process), m_initiated(false), 4403b9c1b51eSKate Stone m_debuggerPresentFlagged(false), m_breakAllKernels(false), 4404b9c1b51eSKate Stone m_ir_passes(nullptr) { 44054640cde1SColin Riley ModulesDidLoad(process->GetTarget().GetImages()); 4406ef20b08fSColin Riley } 44074640cde1SColin Riley 4408b9c1b51eSKate Stone lldb::CommandObjectSP RenderScriptRuntime::GetCommandObject( 4409b9c1b51eSKate Stone lldb_private::CommandInterpreter &interpreter) { 44100a66e2f1SEnrico Granata return CommandObjectSP(new CommandObjectRenderScriptRuntime(interpreter)); 44114640cde1SColin Riley } 44124640cde1SColin Riley 441378f339d1SEwan Crawford RenderScriptRuntime::~RenderScriptRuntime() = default; 4414