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 137f193d69SLuke Drummond #include "llvm/ADT/StringMap.h" 147f193d69SLuke 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) 196795eae423SZachary Turner module_sp->m_module->FindGlobalVariables( 196895eae423SZachary Turner RegularExpression(llvm::StringRef(".")), true, UINT32_MAX, 196995eae423SZachary Turner variable_list); 19708b244e21SEwan Crawford 1971b9c1b51eSKate Stone // Iterate over all the global variables looking for one with a matching type 1972b9c1b51eSKate Stone // to the Element. 1973b9c1b51eSKate Stone // We make the assumption a match exists since there needs to be a global 1974b9c1b51eSKate Stone // variable to reflect the 19758b244e21SEwan Crawford // struct type back into java host code. 1976b9c1b51eSKate Stone for (uint32_t var_index = 0; var_index < variable_list.GetSize(); 1977b9c1b51eSKate Stone ++var_index) { 19788b244e21SEwan Crawford const VariableSP var_sp(variable_list.GetVariableAtIndex(var_index)); 19798b244e21SEwan Crawford if (!var_sp) 19808b244e21SEwan Crawford continue; 19818b244e21SEwan Crawford 19828b244e21SEwan Crawford ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp); 19838b244e21SEwan Crawford if (!valobj_sp) 19848b244e21SEwan Crawford continue; 19858b244e21SEwan Crawford 19868b244e21SEwan Crawford // Find the number of variable fields. 1987b9c1b51eSKate Stone // If it has no fields, or more fields than our Element, then it can't be 1988b9c1b51eSKate Stone // the struct we're looking for. 1989b9c1b51eSKate Stone // Don't check for equality since RS can add extra struct members for 1990b9c1b51eSKate Stone // padding. 19918b244e21SEwan Crawford size_t num_children = valobj_sp->GetNumChildren(); 19928b244e21SEwan Crawford if (num_children > elem.children.size() || num_children == 0) 19938b244e21SEwan Crawford continue; 19948b244e21SEwan Crawford 19958b244e21SEwan Crawford // Iterate over children looking for members with matching field names. 19968b244e21SEwan Crawford // If all the field names match, this is likely the struct we want. 19978b244e21SEwan Crawford // 1998b9c1b51eSKate Stone // TODO: This could be made more robust by also checking children data 1999b9c1b51eSKate Stone // sizes, or array size 20008b244e21SEwan Crawford bool found = true; 2001b9c1b51eSKate Stone for (size_t child_index = 0; child_index < num_children; ++child_index) { 20028b244e21SEwan Crawford ValueObjectSP child = valobj_sp->GetChildAtIndex(child_index, true); 2003b9c1b51eSKate Stone if (!child || 2004b9c1b51eSKate Stone (child->GetName() != elem.children[child_index].type_name)) { 20058b244e21SEwan Crawford found = false; 20068b244e21SEwan Crawford break; 20078b244e21SEwan Crawford } 20088b244e21SEwan Crawford } 20098b244e21SEwan Crawford 2010b9c1b51eSKate Stone // RS can add extra struct members for padding in the format 2011b9c1b51eSKate Stone // '#rs_padding_[0-9]+' 2012b9c1b51eSKate Stone if (found && num_children < elem.children.size()) { 2013b3f7f69dSAidan Dodds const uint32_t size_diff = elem.children.size() - num_children; 20148b244e21SEwan Crawford if (log) 2015b9c1b51eSKate Stone log->Printf("%s - %" PRIu32 " padding struct entries", __FUNCTION__, 2016b9c1b51eSKate Stone size_diff); 20178b244e21SEwan Crawford 2018b9c1b51eSKate Stone for (uint32_t padding_index = 0; padding_index < size_diff; 2019b9c1b51eSKate Stone ++padding_index) { 2020b9c1b51eSKate Stone const ConstString &name = 2021b9c1b51eSKate Stone elem.children[num_children + padding_index].type_name; 20228b244e21SEwan Crawford if (strcmp(name.AsCString(), "#rs_padding") < 0) 20238b244e21SEwan Crawford found = false; 20248b244e21SEwan Crawford } 20258b244e21SEwan Crawford } 20268b244e21SEwan Crawford 20278b244e21SEwan Crawford // We've found a global var with matching type 2028b9c1b51eSKate Stone if (found) { 20298b244e21SEwan Crawford // Dereference since our Element type isn't a pointer. 2030b9c1b51eSKate Stone if (valobj_sp->IsPointerType()) { 20318b244e21SEwan Crawford Error err; 20328b244e21SEwan Crawford ValueObjectSP deref_valobj = valobj_sp->Dereference(err); 20338b244e21SEwan Crawford if (!err.Fail()) 20348b244e21SEwan Crawford valobj_sp = deref_valobj; 20358b244e21SEwan Crawford } 20368b244e21SEwan Crawford 20378b244e21SEwan Crawford // Save name of variable in Element. 20388b244e21SEwan Crawford elem.type_name = valobj_sp->GetTypeName(); 20398b244e21SEwan Crawford if (log) 2040b9c1b51eSKate Stone log->Printf("%s - element name set to %s", __FUNCTION__, 2041b9c1b51eSKate Stone elem.type_name.AsCString()); 20428b244e21SEwan Crawford 20438b244e21SEwan Crawford return; 20448b244e21SEwan Crawford } 20458b244e21SEwan Crawford } 20468b244e21SEwan Crawford } 20478b244e21SEwan Crawford 2048b9c1b51eSKate Stone // Function sets the datum_size member of Element. Representing the size of a 2049b9c1b51eSKate Stone // single instance including padding. 20508b244e21SEwan Crawford // Assumes the relevant allocation information has already been jitted. 2051b9c1b51eSKate Stone void RenderScriptRuntime::SetElementSize(Element &elem) { 20528b244e21SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 20538b244e21SEwan Crawford const Element::DataType type = *elem.type.get(); 2054b9c1b51eSKate Stone assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && 2055b9c1b51eSKate Stone "Invalid allocation type"); 205655232f09SEwan Crawford 2057b3f7f69dSAidan Dodds const uint32_t vec_size = *elem.type_vec_size.get(); 2058b3f7f69dSAidan Dodds uint32_t data_size = 0; 2059b3f7f69dSAidan Dodds uint32_t padding = 0; 206055232f09SEwan Crawford 20618b244e21SEwan Crawford // Element is of a struct type, calculate size recursively. 2062b9c1b51eSKate Stone if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) { 2063b9c1b51eSKate Stone for (Element &child : elem.children) { 20648b244e21SEwan Crawford SetElementSize(child); 2065b9c1b51eSKate Stone const uint32_t array_size = 2066b9c1b51eSKate Stone child.array_size.isValid() ? *child.array_size.get() : 1; 20678b244e21SEwan Crawford data_size += *child.datum_size.get() * array_size; 20688b244e21SEwan Crawford } 20698b244e21SEwan Crawford } 2070b3f7f69dSAidan Dodds // These have been packed already 2071b3f7f69dSAidan Dodds else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 || 2072b3f7f69dSAidan Dodds type == Element::RS_TYPE_UNSIGNED_5_5_5_1 || 2073b9c1b51eSKate Stone type == Element::RS_TYPE_UNSIGNED_4_4_4_4) { 20742e920715SEwan Crawford data_size = AllocationDetails::RSTypeToFormat[type][eElementSize]; 2075b9c1b51eSKate Stone } else if (type < Element::RS_TYPE_ELEMENT) { 2076b9c1b51eSKate Stone data_size = 2077b9c1b51eSKate Stone vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize]; 20782e920715SEwan Crawford if (vec_size == 3) 20792e920715SEwan Crawford padding = AllocationDetails::RSTypeToFormat[type][eElementSize]; 2080b9c1b51eSKate Stone } else 2081b9c1b51eSKate Stone data_size = 2082b9c1b51eSKate Stone GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 20838b244e21SEwan Crawford 20848b244e21SEwan Crawford elem.padding = padding; 20858b244e21SEwan Crawford elem.datum_size = data_size + padding; 20868b244e21SEwan Crawford if (log) 2087b9c1b51eSKate Stone log->Printf("%s - element size set to %" PRIu32, __FUNCTION__, 2088b9c1b51eSKate Stone data_size + padding); 208955232f09SEwan Crawford } 209055232f09SEwan Crawford 2091b9c1b51eSKate Stone // Given an allocation, this function copies the allocation contents from device 2092b9c1b51eSKate Stone // into a buffer on the heap. 209355232f09SEwan Crawford // Returning a shared pointer to the buffer containing the data. 209455232f09SEwan Crawford std::shared_ptr<uint8_t> 2095b9c1b51eSKate Stone RenderScriptRuntime::GetAllocationData(AllocationDetails *allocation, 2096b9c1b51eSKate Stone StackFrame *frame_ptr) { 209755232f09SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 209855232f09SEwan Crawford 209955232f09SEwan Crawford // JIT all the allocation details 2100b9c1b51eSKate Stone if (allocation->shouldRefresh()) { 210155232f09SEwan Crawford if (log) 2102b9c1b51eSKate Stone log->Printf("%s - allocation details not calculated yet, jitting info", 2103b9c1b51eSKate Stone __FUNCTION__); 210455232f09SEwan Crawford 2105b9c1b51eSKate Stone if (!RefreshAllocation(allocation, frame_ptr)) { 210655232f09SEwan Crawford if (log) 2107b3f7f69dSAidan Dodds log->Printf("%s - couldn't JIT allocation details", __FUNCTION__); 210855232f09SEwan Crawford return nullptr; 210955232f09SEwan Crawford } 211055232f09SEwan Crawford } 211155232f09SEwan Crawford 2112b3f7f69dSAidan Dodds assert(allocation->data_ptr.isValid() && allocation->element.type.isValid() && 2113b9c1b51eSKate Stone allocation->element.type_vec_size.isValid() && 2114b9c1b51eSKate Stone allocation->size.isValid() && "Allocation information not available"); 211555232f09SEwan Crawford 211655232f09SEwan Crawford // Allocate a buffer to copy data into 2117b3f7f69dSAidan Dodds const uint32_t size = *allocation->size.get(); 211855232f09SEwan Crawford std::shared_ptr<uint8_t> buffer(new uint8_t[size]); 2119b9c1b51eSKate Stone if (!buffer) { 212055232f09SEwan Crawford if (log) 2121b9c1b51eSKate Stone log->Printf("%s - couldn't allocate a %" PRIu32 " byte buffer", 2122b9c1b51eSKate Stone __FUNCTION__, size); 212355232f09SEwan Crawford return nullptr; 212455232f09SEwan Crawford } 212555232f09SEwan Crawford 212655232f09SEwan Crawford // Read the inferior memory 212755232f09SEwan Crawford Error error; 212855232f09SEwan Crawford lldb::addr_t data_ptr = *allocation->data_ptr.get(); 212955232f09SEwan Crawford GetProcess()->ReadMemory(data_ptr, buffer.get(), size, error); 2130b9c1b51eSKate Stone if (error.Fail()) { 213155232f09SEwan Crawford if (log) 2132b9c1b51eSKate Stone log->Printf("%s - '%s' Couldn't read %" PRIu32 2133b9c1b51eSKate Stone " bytes of allocation data from 0x%" PRIx64, 2134b3f7f69dSAidan Dodds __FUNCTION__, error.AsCString(), size, data_ptr); 213555232f09SEwan Crawford return nullptr; 213655232f09SEwan Crawford } 213755232f09SEwan Crawford 213855232f09SEwan Crawford return buffer; 213955232f09SEwan Crawford } 214055232f09SEwan Crawford 214155232f09SEwan Crawford // Function copies data from a binary file into an allocation. 2142b9c1b51eSKate Stone // There is a header at the start of the file, FileHeader, before the data 2143b9c1b51eSKate Stone // content itself. 2144b9c1b51eSKate Stone // Information from this header is used to display warnings to the user about 2145b9c1b51eSKate Stone // incompatibilities 2146b9c1b51eSKate Stone bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, 2147b9c1b51eSKate Stone const char *filename, 2148b9c1b51eSKate Stone StackFrame *frame_ptr) { 214955232f09SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 215055232f09SEwan Crawford 215155232f09SEwan Crawford // Find allocation with the given id 215255232f09SEwan Crawford AllocationDetails *alloc = FindAllocByID(strm, alloc_id); 215355232f09SEwan Crawford if (!alloc) 215455232f09SEwan Crawford return false; 215555232f09SEwan Crawford 215655232f09SEwan Crawford if (log) 2157b9c1b51eSKate Stone log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__, 2158b9c1b51eSKate Stone *alloc->address.get()); 215955232f09SEwan Crawford 216055232f09SEwan Crawford // JIT all the allocation details 2161b9c1b51eSKate Stone if (alloc->shouldRefresh()) { 216255232f09SEwan Crawford if (log) 2163b9c1b51eSKate Stone log->Printf("%s - allocation details not calculated yet, jitting info.", 2164b9c1b51eSKate Stone __FUNCTION__); 216555232f09SEwan Crawford 2166b9c1b51eSKate Stone if (!RefreshAllocation(alloc, frame_ptr)) { 216755232f09SEwan Crawford if (log) 2168b3f7f69dSAidan Dodds log->Printf("%s - couldn't JIT allocation details", __FUNCTION__); 21694cfc9198SSylvestre Ledru return false; 217055232f09SEwan Crawford } 217155232f09SEwan Crawford } 217255232f09SEwan Crawford 2173b9c1b51eSKate Stone assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && 2174b9c1b51eSKate Stone alloc->element.type_vec_size.isValid() && alloc->size.isValid() && 2175b9c1b51eSKate Stone alloc->element.datum_size.isValid() && 2176b9c1b51eSKate Stone "Allocation information not available"); 217755232f09SEwan Crawford 217855232f09SEwan Crawford // Check we can read from file 217955232f09SEwan Crawford FileSpec file(filename, true); 2180b9c1b51eSKate Stone if (!file.Exists()) { 218155232f09SEwan Crawford strm.Printf("Error: File %s does not exist", filename); 218255232f09SEwan Crawford strm.EOL(); 218355232f09SEwan Crawford return false; 218455232f09SEwan Crawford } 218555232f09SEwan Crawford 2186b9c1b51eSKate Stone if (!file.Readable()) { 218755232f09SEwan Crawford strm.Printf("Error: File %s does not have readable permissions", filename); 218855232f09SEwan Crawford strm.EOL(); 218955232f09SEwan Crawford return false; 219055232f09SEwan Crawford } 219155232f09SEwan Crawford 219255232f09SEwan Crawford // Read file into data buffer 219355232f09SEwan Crawford DataBufferSP data_sp(file.ReadFileContents()); 219455232f09SEwan Crawford 219555232f09SEwan Crawford // Cast start of buffer to FileHeader and use pointer to read metadata 219655232f09SEwan Crawford void *file_buffer = data_sp->GetBytes(); 2197b3f7f69dSAidan Dodds if (file_buffer == nullptr || 2198b9c1b51eSKate Stone data_sp->GetByteSize() < (sizeof(AllocationDetails::FileHeader) + 2199b9c1b51eSKate Stone sizeof(AllocationDetails::ElementHeader))) { 2200b9c1b51eSKate Stone strm.Printf("Error: File %s does not contain enough data for header", 2201b9c1b51eSKate Stone filename); 220226e52a70SEwan Crawford strm.EOL(); 220326e52a70SEwan Crawford return false; 220426e52a70SEwan Crawford } 2205b9c1b51eSKate Stone const AllocationDetails::FileHeader *file_header = 2206b9c1b51eSKate Stone static_cast<AllocationDetails::FileHeader *>(file_buffer); 220755232f09SEwan Crawford 220826e52a70SEwan Crawford // Check file starts with ascii characters "RSAD" 2209b9c1b51eSKate Stone if (memcmp(file_header->ident, "RSAD", 4)) { 2210b9c1b51eSKate Stone strm.Printf("Error: File doesn't contain identifier for an RS allocation " 2211b9c1b51eSKate Stone "dump. Are you sure this is the correct file?"); 221226e52a70SEwan Crawford strm.EOL(); 221326e52a70SEwan Crawford return false; 221426e52a70SEwan Crawford } 221526e52a70SEwan Crawford 221626e52a70SEwan Crawford // Look at the type of the root element in the header 221726e52a70SEwan Crawford AllocationDetails::ElementHeader root_element_header; 2218b9c1b51eSKate Stone memcpy(&root_element_header, static_cast<uint8_t *>(file_buffer) + 2219b9c1b51eSKate Stone sizeof(AllocationDetails::FileHeader), 222026e52a70SEwan Crawford sizeof(AllocationDetails::ElementHeader)); 222155232f09SEwan Crawford 222255232f09SEwan Crawford if (log) 2223b9c1b51eSKate Stone log->Printf("%s - header type %" PRIu32 ", element size %" PRIu32, 2224b9c1b51eSKate Stone __FUNCTION__, root_element_header.type, 2225b9c1b51eSKate Stone root_element_header.element_size); 222655232f09SEwan Crawford 2227b9c1b51eSKate Stone // Check if the target allocation and file both have the same number of bytes 2228b9c1b51eSKate Stone // for an Element 2229b9c1b51eSKate Stone if (*alloc->element.datum_size.get() != root_element_header.element_size) { 2230b9c1b51eSKate Stone strm.Printf("Warning: Mismatched Element sizes - file %" PRIu32 2231b9c1b51eSKate Stone " bytes, allocation %" PRIu32 " bytes", 2232b9c1b51eSKate Stone root_element_header.element_size, 2233b9c1b51eSKate Stone *alloc->element.datum_size.get()); 223455232f09SEwan Crawford strm.EOL(); 223555232f09SEwan Crawford } 223655232f09SEwan Crawford 223726e52a70SEwan Crawford // Check if the target allocation and file both have the same type 2238b3f7f69dSAidan Dodds const uint32_t alloc_type = static_cast<uint32_t>(*alloc->element.type.get()); 2239b3f7f69dSAidan Dodds const uint32_t file_type = root_element_header.type; 224026e52a70SEwan Crawford 2241b9c1b51eSKate Stone if (file_type > Element::RS_TYPE_FONT) { 224226e52a70SEwan Crawford strm.Printf("Warning: File has unknown allocation type"); 224326e52a70SEwan Crawford strm.EOL(); 2244b9c1b51eSKate Stone } else if (alloc_type != file_type) { 2245b9c1b51eSKate Stone // Enum value isn't monotonous, so doesn't always index RsDataTypeToString 2246b9c1b51eSKate Stone // array 2247b3f7f69dSAidan Dodds uint32_t printable_target_type_index = alloc_type; 2248b3f7f69dSAidan Dodds uint32_t printable_head_type_index = file_type; 2249b9c1b51eSKate Stone if (alloc_type >= Element::RS_TYPE_ELEMENT && 2250b9c1b51eSKate Stone alloc_type <= Element::RS_TYPE_FONT) 2251b9c1b51eSKate Stone printable_target_type_index = static_cast<Element::DataType>( 2252b9c1b51eSKate Stone (alloc_type - Element::RS_TYPE_ELEMENT) + 2253b3f7f69dSAidan Dodds Element::RS_TYPE_MATRIX_2X2 + 1); 22542e920715SEwan Crawford 2255b9c1b51eSKate Stone if (file_type >= Element::RS_TYPE_ELEMENT && 2256b9c1b51eSKate Stone file_type <= Element::RS_TYPE_FONT) 2257b9c1b51eSKate Stone printable_head_type_index = static_cast<Element::DataType>( 2258b9c1b51eSKate Stone (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 2259b9c1b51eSKate Stone 1); 22602e920715SEwan Crawford 2261b9c1b51eSKate Stone const char *file_type_cstr = 2262b9c1b51eSKate Stone AllocationDetails::RsDataTypeToString[printable_head_type_index][0]; 2263b9c1b51eSKate Stone const char *target_type_cstr = 2264b9c1b51eSKate Stone AllocationDetails::RsDataTypeToString[printable_target_type_index][0]; 226555232f09SEwan Crawford 2266b9c1b51eSKate Stone strm.Printf( 2267b9c1b51eSKate Stone "Warning: Mismatched Types - file '%s' type, allocation '%s' type", 2268b9c1b51eSKate Stone file_type_cstr, target_type_cstr); 226955232f09SEwan Crawford strm.EOL(); 227055232f09SEwan Crawford } 227155232f09SEwan Crawford 227226e52a70SEwan Crawford // Advance buffer past header 227326e52a70SEwan Crawford file_buffer = static_cast<uint8_t *>(file_buffer) + file_header->hdr_size; 227426e52a70SEwan Crawford 227555232f09SEwan Crawford // Calculate size of allocation data in file 227626e52a70SEwan Crawford size_t length = data_sp->GetByteSize() - file_header->hdr_size; 227755232f09SEwan Crawford 227855232f09SEwan Crawford // Check if the target allocation and file both have the same total data size. 2279b3f7f69dSAidan Dodds const uint32_t alloc_size = *alloc->size.get(); 2280b9c1b51eSKate Stone if (alloc_size != length) { 2281b9c1b51eSKate Stone strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64 2282b9c1b51eSKate Stone " bytes, allocation 0x%" PRIx32 " bytes", 2283eba832beSJason Molenda (uint64_t)length, alloc_size); 228455232f09SEwan Crawford strm.EOL(); 2285b9c1b51eSKate Stone length = alloc_size < length ? alloc_size 2286b9c1b51eSKate Stone : length; // Set length to copy to minimum 228755232f09SEwan Crawford } 228855232f09SEwan Crawford 228955232f09SEwan Crawford // Copy file data from our buffer into the target allocation. 229055232f09SEwan Crawford lldb::addr_t alloc_data = *alloc->data_ptr.get(); 229155232f09SEwan Crawford Error error; 2292b9c1b51eSKate Stone size_t bytes_written = 2293b9c1b51eSKate Stone GetProcess()->WriteMemory(alloc_data, file_buffer, length, error); 2294b9c1b51eSKate Stone if (!error.Success() || bytes_written != length) { 2295b9c1b51eSKate Stone strm.Printf("Error: Couldn't write data to allocation %s", 2296b9c1b51eSKate Stone error.AsCString()); 229755232f09SEwan Crawford strm.EOL(); 229855232f09SEwan Crawford return false; 229955232f09SEwan Crawford } 230055232f09SEwan Crawford 2301b9c1b51eSKate Stone strm.Printf("Contents of file '%s' read into allocation %" PRIu32, filename, 2302b9c1b51eSKate Stone alloc->id); 230355232f09SEwan Crawford strm.EOL(); 230455232f09SEwan Crawford 230555232f09SEwan Crawford return true; 230655232f09SEwan Crawford } 230755232f09SEwan Crawford 2308b9c1b51eSKate Stone // Function takes as parameters a byte buffer, which will eventually be written 2309b9c1b51eSKate Stone // to file as the element header, 2310b9c1b51eSKate Stone // an offset into that buffer, and an Element that will be saved into the buffer 2311b9c1b51eSKate Stone // at the parametrised offset. 231226e52a70SEwan Crawford // Return value is the new offset after writing the element into the buffer. 2313b9c1b51eSKate Stone // Elements are saved to the file as the ElementHeader struct followed by 2314b9c1b51eSKate Stone // offsets to the structs of all the element's 2315b3f7f69dSAidan Dodds // children. 2316b9c1b51eSKate Stone size_t RenderScriptRuntime::PopulateElementHeaders( 2317b9c1b51eSKate Stone const std::shared_ptr<uint8_t> header_buffer, size_t offset, 2318b9c1b51eSKate Stone const Element &elem) { 2319b9c1b51eSKate Stone // File struct for an element header with all the relevant details copied from 2320b9c1b51eSKate Stone // elem. 232126e52a70SEwan Crawford // We assume members are valid already. 232226e52a70SEwan Crawford AllocationDetails::ElementHeader elem_header; 232326e52a70SEwan Crawford elem_header.type = *elem.type.get(); 232426e52a70SEwan Crawford elem_header.kind = *elem.type_kind.get(); 232526e52a70SEwan Crawford elem_header.element_size = *elem.datum_size.get(); 232626e52a70SEwan Crawford elem_header.vector_size = *elem.type_vec_size.get(); 2327b9c1b51eSKate Stone elem_header.array_size = 2328b9c1b51eSKate Stone elem.array_size.isValid() ? *elem.array_size.get() : 0; 232926e52a70SEwan Crawford const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader); 233026e52a70SEwan Crawford 233126e52a70SEwan Crawford // Copy struct into buffer and advance offset 2332b9c1b51eSKate Stone // We assume that header_buffer has been checked for nullptr before this 2333b9c1b51eSKate Stone // method is called 233426e52a70SEwan Crawford memcpy(header_buffer.get() + offset, &elem_header, elem_header_size); 233526e52a70SEwan Crawford offset += elem_header_size; 233626e52a70SEwan Crawford 233726e52a70SEwan Crawford // Starting offset of child ElementHeader struct 2338b9c1b51eSKate Stone size_t child_offset = 2339b9c1b51eSKate Stone offset + ((elem.children.size() + 1) * sizeof(uint32_t)); 2340b9c1b51eSKate Stone for (const RenderScriptRuntime::Element &child : elem.children) { 2341b9c1b51eSKate Stone // Recursively populate the buffer with the element header structs of 2342b9c1b51eSKate Stone // children. 2343b9c1b51eSKate Stone // Then save the offsets where they were set after the parent element 2344b9c1b51eSKate Stone // header. 234526e52a70SEwan Crawford memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t)); 234626e52a70SEwan Crawford offset += sizeof(uint32_t); 234726e52a70SEwan Crawford 234826e52a70SEwan Crawford child_offset = PopulateElementHeaders(header_buffer, child_offset, child); 234926e52a70SEwan Crawford } 235026e52a70SEwan Crawford 235126e52a70SEwan Crawford // Zero indicates no more children 235226e52a70SEwan Crawford memset(header_buffer.get() + offset, 0, sizeof(uint32_t)); 235326e52a70SEwan Crawford 235426e52a70SEwan Crawford return child_offset; 235526e52a70SEwan Crawford } 235626e52a70SEwan Crawford 2357b9c1b51eSKate Stone // Given an Element object this function returns the total size needed in the 2358b9c1b51eSKate Stone // file header to store the element's 2359b3f7f69dSAidan Dodds // details. 2360b9c1b51eSKate Stone // Taking into account the size of the element header struct, plus the offsets 2361b9c1b51eSKate Stone // to all the element's children. 2362b9c1b51eSKate Stone // Function is recursive so that the size of all ancestors is taken into 2363b9c1b51eSKate Stone // account. 2364b9c1b51eSKate Stone size_t RenderScriptRuntime::CalculateElementHeaderSize(const Element &elem) { 2365b9c1b51eSKate Stone size_t size = (elem.children.size() + 1) * 2366b9c1b51eSKate Stone sizeof(uint32_t); // Offsets to children plus zero terminator 2367b9c1b51eSKate Stone size += sizeof(AllocationDetails::ElementHeader); // Size of header struct 2368b9c1b51eSKate Stone // with type details 236926e52a70SEwan Crawford 237026e52a70SEwan Crawford // Calculate recursively for all descendants 237126e52a70SEwan Crawford for (const Element &child : elem.children) 237226e52a70SEwan Crawford size += CalculateElementHeaderSize(child); 237326e52a70SEwan Crawford 237426e52a70SEwan Crawford return size; 237526e52a70SEwan Crawford } 237626e52a70SEwan Crawford 237755232f09SEwan Crawford // Function copies allocation contents into a binary file. 237855232f09SEwan Crawford // This file can then be loaded later into a different allocation. 2379b9c1b51eSKate Stone // There is a header, FileHeader, before the allocation data containing 2380b9c1b51eSKate Stone // meta-data. 2381b9c1b51eSKate Stone bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, 2382b9c1b51eSKate Stone const char *filename, 2383b9c1b51eSKate Stone StackFrame *frame_ptr) { 238455232f09SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 238555232f09SEwan Crawford 238655232f09SEwan Crawford // Find allocation with the given id 238755232f09SEwan Crawford AllocationDetails *alloc = FindAllocByID(strm, alloc_id); 238855232f09SEwan Crawford if (!alloc) 238955232f09SEwan Crawford return false; 239055232f09SEwan Crawford 239155232f09SEwan Crawford if (log) 2392b9c1b51eSKate Stone log->Printf("%s - found allocation 0x%" PRIx64 ".", __FUNCTION__, 2393b9c1b51eSKate Stone *alloc->address.get()); 239455232f09SEwan Crawford 239555232f09SEwan Crawford // JIT all the allocation details 2396b9c1b51eSKate Stone if (alloc->shouldRefresh()) { 239755232f09SEwan Crawford if (log) 2398b9c1b51eSKate Stone log->Printf("%s - allocation details not calculated yet, jitting info.", 2399b9c1b51eSKate Stone __FUNCTION__); 240055232f09SEwan Crawford 2401b9c1b51eSKate Stone if (!RefreshAllocation(alloc, frame_ptr)) { 240255232f09SEwan Crawford if (log) 2403b3f7f69dSAidan Dodds log->Printf("%s - couldn't JIT allocation details.", __FUNCTION__); 24044cfc9198SSylvestre Ledru return false; 240555232f09SEwan Crawford } 240655232f09SEwan Crawford } 240755232f09SEwan Crawford 2408b9c1b51eSKate Stone assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && 2409b9c1b51eSKate Stone alloc->element.type_vec_size.isValid() && 2410b9c1b51eSKate Stone alloc->element.datum_size.get() && 2411b9c1b51eSKate Stone alloc->element.type_kind.isValid() && alloc->dimension.isValid() && 2412b3f7f69dSAidan Dodds "Allocation information not available"); 241355232f09SEwan Crawford 241455232f09SEwan Crawford // Check we can create writable file 241555232f09SEwan Crawford FileSpec file_spec(filename, true); 2416b9c1b51eSKate Stone File file(file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate | 2417b9c1b51eSKate Stone File::eOpenOptionTruncate); 2418b9c1b51eSKate Stone if (!file) { 241955232f09SEwan Crawford strm.Printf("Error: Failed to open '%s' for writing", filename); 242055232f09SEwan Crawford strm.EOL(); 242155232f09SEwan Crawford return false; 242255232f09SEwan Crawford } 242355232f09SEwan Crawford 242455232f09SEwan Crawford // Read allocation into buffer of heap memory 242555232f09SEwan Crawford const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); 2426b9c1b51eSKate Stone if (!buffer) { 242755232f09SEwan Crawford strm.Printf("Error: Couldn't read allocation data into buffer"); 242855232f09SEwan Crawford strm.EOL(); 242955232f09SEwan Crawford return false; 243055232f09SEwan Crawford } 243155232f09SEwan Crawford 243255232f09SEwan Crawford // Create the file header 243355232f09SEwan Crawford AllocationDetails::FileHeader head; 2434b3f7f69dSAidan Dodds memcpy(head.ident, "RSAD", 4); 24352d62328aSEwan Crawford head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1); 24362d62328aSEwan Crawford head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2); 24372d62328aSEwan Crawford head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3); 243826e52a70SEwan Crawford 243926e52a70SEwan Crawford const size_t element_header_size = CalculateElementHeaderSize(alloc->element); 2440b9c1b51eSKate Stone assert((sizeof(AllocationDetails::FileHeader) + element_header_size) < 2441b9c1b51eSKate Stone UINT16_MAX && 2442b9c1b51eSKate Stone "Element header too large"); 2443b9c1b51eSKate Stone head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) + 2444b9c1b51eSKate Stone element_header_size); 244555232f09SEwan Crawford 244655232f09SEwan Crawford // Write the file header 244755232f09SEwan Crawford size_t num_bytes = sizeof(AllocationDetails::FileHeader); 244826e52a70SEwan Crawford if (log) 2449b9c1b51eSKate Stone log->Printf("%s - writing File Header, 0x%" PRIx64 " bytes", __FUNCTION__, 2450b9c1b51eSKate Stone (uint64_t)num_bytes); 245126e52a70SEwan Crawford 245226e52a70SEwan Crawford Error err = file.Write(&head, num_bytes); 2453b9c1b51eSKate Stone if (!err.Success()) { 2454b9c1b51eSKate Stone strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), 2455b9c1b51eSKate Stone filename); 245626e52a70SEwan Crawford strm.EOL(); 245726e52a70SEwan Crawford return false; 245826e52a70SEwan Crawford } 245926e52a70SEwan Crawford 246026e52a70SEwan Crawford // Create the headers describing the element type of the allocation. 2461b9c1b51eSKate Stone std::shared_ptr<uint8_t> element_header_buffer( 2462b9c1b51eSKate Stone new uint8_t[element_header_size]); 2463b9c1b51eSKate Stone if (element_header_buffer == nullptr) { 2464b9c1b51eSKate Stone strm.Printf("Internal Error: Couldn't allocate %" PRIu64 2465b9c1b51eSKate Stone " bytes on the heap", 2466b9c1b51eSKate Stone (uint64_t)element_header_size); 246726e52a70SEwan Crawford strm.EOL(); 246826e52a70SEwan Crawford return false; 246926e52a70SEwan Crawford } 247026e52a70SEwan Crawford 247126e52a70SEwan Crawford PopulateElementHeaders(element_header_buffer, 0, alloc->element); 247226e52a70SEwan Crawford 247326e52a70SEwan Crawford // Write headers for allocation element type to file 247426e52a70SEwan Crawford num_bytes = element_header_size; 247526e52a70SEwan Crawford if (log) 2476b9c1b51eSKate Stone log->Printf("%s - writing element headers, 0x%" PRIx64 " bytes.", 2477b9c1b51eSKate Stone __FUNCTION__, (uint64_t)num_bytes); 247826e52a70SEwan Crawford 247926e52a70SEwan Crawford err = file.Write(element_header_buffer.get(), num_bytes); 2480b9c1b51eSKate Stone if (!err.Success()) { 2481b9c1b51eSKate Stone strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), 2482b9c1b51eSKate Stone filename); 248355232f09SEwan Crawford strm.EOL(); 248455232f09SEwan Crawford return false; 248555232f09SEwan Crawford } 248655232f09SEwan Crawford 248755232f09SEwan Crawford // Write allocation data to file 248855232f09SEwan Crawford num_bytes = static_cast<size_t>(*alloc->size.get()); 248955232f09SEwan Crawford if (log) 2490b9c1b51eSKate Stone log->Printf("%s - writing 0x%" PRIx64 " bytes", __FUNCTION__, 2491b9c1b51eSKate Stone (uint64_t)num_bytes); 249255232f09SEwan Crawford 249355232f09SEwan Crawford err = file.Write(buffer.get(), num_bytes); 2494b9c1b51eSKate Stone if (!err.Success()) { 2495b9c1b51eSKate Stone strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), 2496b9c1b51eSKate Stone filename); 249755232f09SEwan Crawford strm.EOL(); 249855232f09SEwan Crawford return false; 249955232f09SEwan Crawford } 250055232f09SEwan Crawford 250155232f09SEwan Crawford strm.Printf("Allocation written to file '%s'", filename); 250255232f09SEwan Crawford strm.EOL(); 250315f2bd95SEwan Crawford return true; 250415f2bd95SEwan Crawford } 250515f2bd95SEwan Crawford 2506b9c1b51eSKate Stone bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) { 25074640cde1SColin Riley Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 25084640cde1SColin Riley 2509b9c1b51eSKate Stone if (module_sp) { 2510b9c1b51eSKate Stone for (const auto &rs_module : m_rsmodules) { 2511b9c1b51eSKate Stone if (rs_module->m_module == module_sp) { 25127dc7771cSEwan Crawford // Check if the user has enabled automatically breaking on 25137dc7771cSEwan Crawford // all RS kernels. 25147dc7771cSEwan Crawford if (m_breakAllKernels) 25157dc7771cSEwan Crawford BreakOnModuleKernels(rs_module); 25167dc7771cSEwan Crawford 25175ec532a9SColin Riley return false; 25185ec532a9SColin Riley } 25197dc7771cSEwan Crawford } 2520ef20b08fSColin Riley bool module_loaded = false; 2521b9c1b51eSKate Stone switch (GetModuleKind(module_sp)) { 2522b9c1b51eSKate Stone case eModuleKindKernelObj: { 25234640cde1SColin Riley RSModuleDescriptorSP module_desc; 25244640cde1SColin Riley module_desc.reset(new RSModuleDescriptor(module_sp)); 2525b9c1b51eSKate Stone if (module_desc->ParseRSInfo()) { 25265ec532a9SColin Riley m_rsmodules.push_back(module_desc); 2527ef20b08fSColin Riley module_loaded = true; 25285ec532a9SColin Riley } 2529b9c1b51eSKate Stone if (module_loaded) { 25304640cde1SColin Riley FixupScriptDetails(module_desc); 25314640cde1SColin Riley } 2532ef20b08fSColin Riley break; 2533ef20b08fSColin Riley } 2534b9c1b51eSKate Stone case eModuleKindDriver: { 2535b9c1b51eSKate Stone if (!m_libRSDriver) { 25364640cde1SColin Riley m_libRSDriver = module_sp; 25374640cde1SColin Riley LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver); 25384640cde1SColin Riley } 25394640cde1SColin Riley break; 25404640cde1SColin Riley } 2541b9c1b51eSKate Stone case eModuleKindImpl: { 25424640cde1SColin Riley m_libRSCpuRef = module_sp; 25434640cde1SColin Riley break; 25444640cde1SColin Riley } 2545b9c1b51eSKate Stone case eModuleKindLibRS: { 2546b9c1b51eSKate Stone if (!m_libRS) { 25474640cde1SColin Riley m_libRS = module_sp; 25484640cde1SColin Riley static ConstString gDbgPresentStr("gDebuggerPresent"); 2549b9c1b51eSKate Stone const Symbol *debug_present = m_libRS->FindFirstSymbolWithNameAndType( 2550b9c1b51eSKate Stone gDbgPresentStr, eSymbolTypeData); 2551b9c1b51eSKate Stone if (debug_present) { 25524640cde1SColin Riley Error error; 25534640cde1SColin Riley uint32_t flag = 0x00000001U; 25544640cde1SColin Riley Target &target = GetProcess()->GetTarget(); 2555358cf1eaSGreg Clayton addr_t addr = debug_present->GetLoadAddress(&target); 25564640cde1SColin Riley GetProcess()->WriteMemory(addr, &flag, sizeof(flag), error); 2557b9c1b51eSKate Stone if (error.Success()) { 25584640cde1SColin Riley if (log) 2559b9c1b51eSKate Stone log->Printf("%s - debugger present flag set on debugee.", 2560b9c1b51eSKate Stone __FUNCTION__); 25614640cde1SColin Riley 25624640cde1SColin Riley m_debuggerPresentFlagged = true; 2563b9c1b51eSKate Stone } else if (log) { 2564b9c1b51eSKate Stone log->Printf("%s - error writing debugger present flags '%s' ", 2565b9c1b51eSKate Stone __FUNCTION__, error.AsCString()); 25664640cde1SColin Riley } 2567b9c1b51eSKate Stone } else if (log) { 2568b9c1b51eSKate Stone log->Printf( 2569b9c1b51eSKate Stone "%s - error writing debugger present flags - symbol not found", 2570b9c1b51eSKate Stone __FUNCTION__); 25714640cde1SColin Riley } 25724640cde1SColin Riley } 25734640cde1SColin Riley break; 25744640cde1SColin Riley } 2575ef20b08fSColin Riley default: 2576ef20b08fSColin Riley break; 2577ef20b08fSColin Riley } 2578ef20b08fSColin Riley if (module_loaded) 2579ef20b08fSColin Riley Update(); 2580ef20b08fSColin Riley return module_loaded; 25815ec532a9SColin Riley } 25825ec532a9SColin Riley return false; 25835ec532a9SColin Riley } 25845ec532a9SColin Riley 2585b9c1b51eSKate Stone void RenderScriptRuntime::Update() { 2586b9c1b51eSKate Stone if (m_rsmodules.size() > 0) { 2587b9c1b51eSKate Stone if (!m_initiated) { 2588ef20b08fSColin Riley Initiate(); 2589ef20b08fSColin Riley } 2590ef20b08fSColin Riley } 2591ef20b08fSColin Riley } 2592ef20b08fSColin Riley 25937f193d69SLuke Drummond bool RSModuleDescriptor::ParsePragmaCount(llvm::StringRef *lines, 25947f193d69SLuke Drummond size_t n_lines) { 25957f193d69SLuke Drummond // Skip the pragma prototype line 25967f193d69SLuke Drummond ++lines; 25977f193d69SLuke Drummond for (; n_lines--; ++lines) { 25987f193d69SLuke Drummond const auto kv_pair = lines->split(" - "); 25997f193d69SLuke Drummond m_pragmas[kv_pair.first.trim().str()] = kv_pair.second.trim().str(); 26007f193d69SLuke Drummond } 26017f193d69SLuke Drummond return true; 26027f193d69SLuke Drummond } 26037f193d69SLuke Drummond 26047f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportReduceCount(llvm::StringRef *lines, 26057f193d69SLuke Drummond size_t n_lines) { 26067f193d69SLuke Drummond // The list of reduction kernels in the `.rs.info` symbol is of the form 26077f193d69SLuke Drummond // "signature - accumulatordatasize - reduction_name - initializer_name - 26087f193d69SLuke Drummond // accumulator_name - combiner_name - 26097f193d69SLuke Drummond // outconverter_name - halter_name" 26107f193d69SLuke Drummond // Where a function is not explicitly named by the user, or is not generated 26117f193d69SLuke Drummond // by the compiler, it is named "." so the 26127f193d69SLuke Drummond // dash separated list should always be 8 items long 26137f193d69SLuke Drummond Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 26147f193d69SLuke Drummond // Skip the exportReduceCount line 26157f193d69SLuke Drummond ++lines; 26167f193d69SLuke Drummond for (; n_lines--; ++lines) { 26177f193d69SLuke Drummond llvm::SmallVector<llvm::StringRef, 8> spec; 26187f193d69SLuke Drummond lines->split(spec, " - "); 26197f193d69SLuke Drummond if (spec.size() != 8) { 26207f193d69SLuke Drummond if (spec.size() < 8) { 26217f193d69SLuke Drummond if (log) 26227f193d69SLuke Drummond log->Error("Error parsing RenderScript reduction spec. wrong number " 26237f193d69SLuke Drummond "of fields"); 26247f193d69SLuke Drummond return false; 26257f193d69SLuke Drummond } else if (log) 26267f193d69SLuke Drummond log->Warning("Extraneous members in reduction spec: '%s'", 26277f193d69SLuke Drummond lines->str().c_str()); 26287f193d69SLuke Drummond } 26297f193d69SLuke Drummond 26307f193d69SLuke Drummond const auto sig_s = spec[0]; 26317f193d69SLuke Drummond uint32_t sig; 26327f193d69SLuke Drummond if (sig_s.getAsInteger(10, sig)) { 26337f193d69SLuke Drummond if (log) 26347f193d69SLuke Drummond log->Error("Error parsing Renderscript reduction spec: invalid kernel " 26357f193d69SLuke Drummond "signature: '%s'", 26367f193d69SLuke Drummond sig_s.str().c_str()); 26377f193d69SLuke Drummond return false; 26387f193d69SLuke Drummond } 26397f193d69SLuke Drummond 26407f193d69SLuke Drummond const auto accum_data_size_s = spec[1]; 26417f193d69SLuke Drummond uint32_t accum_data_size; 26427f193d69SLuke Drummond if (accum_data_size_s.getAsInteger(10, accum_data_size)) { 26437f193d69SLuke Drummond if (log) 26447f193d69SLuke Drummond log->Error("Error parsing Renderscript reduction spec: invalid " 26457f193d69SLuke Drummond "accumulator data size %s", 26467f193d69SLuke Drummond accum_data_size_s.str().c_str()); 26477f193d69SLuke Drummond return false; 26487f193d69SLuke Drummond } 26497f193d69SLuke Drummond 26507f193d69SLuke Drummond if (log) 26517f193d69SLuke Drummond log->Printf("Found RenderScript reduction '%s'", spec[2].str().c_str()); 26527f193d69SLuke Drummond 26537f193d69SLuke Drummond m_reductions.push_back(RSReductionDescriptor(this, sig, accum_data_size, 26547f193d69SLuke Drummond spec[2], spec[3], spec[4], 26557f193d69SLuke Drummond spec[5], spec[6], spec[7])); 26567f193d69SLuke Drummond } 26577f193d69SLuke Drummond return true; 26587f193d69SLuke Drummond } 26597f193d69SLuke Drummond 26607f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportForeachCount(llvm::StringRef *lines, 26617f193d69SLuke Drummond size_t n_lines) { 26627f193d69SLuke Drummond // Skip the exportForeachCount line 26637f193d69SLuke Drummond ++lines; 26647f193d69SLuke Drummond for (; n_lines--; ++lines) { 26657f193d69SLuke Drummond uint32_t slot; 26667f193d69SLuke Drummond // `forEach` kernels are listed in the `.rs.info` packet as a "slot - name" 26677f193d69SLuke Drummond // pair per line 26687f193d69SLuke Drummond const auto kv_pair = lines->split(" - "); 26697f193d69SLuke Drummond if (kv_pair.first.getAsInteger(10, slot)) 26707f193d69SLuke Drummond return false; 26717f193d69SLuke Drummond m_kernels.push_back(RSKernelDescriptor(this, kv_pair.second, slot)); 26727f193d69SLuke Drummond } 26737f193d69SLuke Drummond return true; 26747f193d69SLuke Drummond } 26757f193d69SLuke Drummond 26767f193d69SLuke Drummond bool RSModuleDescriptor::ParseExportVarCount(llvm::StringRef *lines, 26777f193d69SLuke Drummond size_t n_lines) { 26787f193d69SLuke Drummond // Skip the ExportVarCount line 26797f193d69SLuke Drummond ++lines; 26807f193d69SLuke Drummond for (; n_lines--; ++lines) 26817f193d69SLuke Drummond m_globals.push_back(RSGlobalDescriptor(this, *lines)); 26827f193d69SLuke Drummond return true; 26837f193d69SLuke Drummond } 26845ec532a9SColin Riley 2685b9c1b51eSKate Stone // The .rs.info symbol in renderscript modules contains a string which needs to 2686b9c1b51eSKate Stone // be parsed. 26875ec532a9SColin Riley // The string is basic and is parsed on a line by line basis. 2688b9c1b51eSKate Stone bool RSModuleDescriptor::ParseRSInfo() { 2689b0be30f7SAidan Dodds assert(m_module); 26907f193d69SLuke Drummond Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2691b9c1b51eSKate Stone const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType( 2692b9c1b51eSKate Stone ConstString(".rs.info"), eSymbolTypeData); 2693b0be30f7SAidan Dodds if (!info_sym) 2694b0be30f7SAidan Dodds return false; 2695b0be30f7SAidan Dodds 2696358cf1eaSGreg Clayton const addr_t addr = info_sym->GetAddressRef().GetFileAddress(); 2697b0be30f7SAidan Dodds if (addr == LLDB_INVALID_ADDRESS) 2698b0be30f7SAidan Dodds return false; 2699b0be30f7SAidan Dodds 27005ec532a9SColin Riley const addr_t size = info_sym->GetByteSize(); 27015ec532a9SColin Riley const FileSpec fs = m_module->GetFileSpec(); 27025ec532a9SColin Riley 2703b0be30f7SAidan Dodds const DataBufferSP buffer = fs.ReadFileContents(addr, size); 27045ec532a9SColin Riley if (!buffer) 27055ec532a9SColin Riley return false; 27065ec532a9SColin Riley 2707b0be30f7SAidan Dodds // split rs.info. contents into lines 27087f193d69SLuke Drummond llvm::SmallVector<llvm::StringRef, 128> info_lines; 27095ec532a9SColin Riley { 27107f193d69SLuke Drummond const llvm::StringRef raw_rs_info((const char *)buffer->GetBytes()); 27117f193d69SLuke Drummond raw_rs_info.split(info_lines, '\n'); 27127f193d69SLuke Drummond if (log) 27137f193d69SLuke Drummond log->Printf("'.rs.info symbol for '%s':\n%s", 27147f193d69SLuke Drummond m_module->GetFileSpec().GetCString(), 27157f193d69SLuke Drummond raw_rs_info.str().c_str()); 2716b0be30f7SAidan Dodds } 2717b0be30f7SAidan Dodds 27187f193d69SLuke Drummond enum { 27197f193d69SLuke Drummond eExportVar, 27207f193d69SLuke Drummond eExportForEach, 27217f193d69SLuke Drummond eExportReduce, 27227f193d69SLuke Drummond ePragma, 27237f193d69SLuke Drummond eBuildChecksum, 27247f193d69SLuke Drummond eObjectSlot 27257f193d69SLuke Drummond }; 27267f193d69SLuke Drummond 27277f193d69SLuke Drummond static const llvm::StringMap<int> rs_info_handlers{ 27287f193d69SLuke Drummond {// The number of visible global variables in the script 27297f193d69SLuke Drummond {"exportVarCount", eExportVar}, 27307f193d69SLuke Drummond // The number of RenderScrip `forEach` kernels __attribute__((kernel)) 27317f193d69SLuke Drummond {"exportForEachCount", eExportForEach}, 27327f193d69SLuke Drummond // The number of generalreductions: This marked in the script by `#pragma 27337f193d69SLuke Drummond // reduce()` 27347f193d69SLuke Drummond {"exportReduceCount", eExportReduce}, 27357f193d69SLuke Drummond // Total count of all RenderScript specific `#pragmas` used in the script 27367f193d69SLuke Drummond {"pragmaCount", ePragma}, 27377f193d69SLuke Drummond {"objectSlotCount", eObjectSlot}}}; 2738b0be30f7SAidan Dodds 2739b0be30f7SAidan Dodds // parse all text lines of .rs.info 2740b9c1b51eSKate Stone for (auto line = info_lines.begin(); line != info_lines.end(); ++line) { 27417f193d69SLuke Drummond const auto kv_pair = line->split(": "); 27427f193d69SLuke Drummond const auto key = kv_pair.first; 27437f193d69SLuke Drummond const auto val = kv_pair.second.trim(); 27445ec532a9SColin Riley 27457f193d69SLuke Drummond const auto handler = rs_info_handlers.find(key); 27467f193d69SLuke Drummond if (handler == rs_info_handlers.end()) 27477f193d69SLuke Drummond continue; 27487f193d69SLuke Drummond // getAsInteger returns `true` on an error condition - we're only interested 27497f193d69SLuke Drummond // in 27507f193d69SLuke Drummond // numeric fields at the moment 27517f193d69SLuke Drummond uint64_t n_lines; 27527f193d69SLuke Drummond if (val.getAsInteger(10, n_lines)) { 27537f193d69SLuke Drummond if (log) 27547f193d69SLuke Drummond log->Debug("Failed to parse non-numeric '.rs.info' section %s", 27557f193d69SLuke Drummond line->str().c_str()); 27567f193d69SLuke Drummond continue; 27577f193d69SLuke Drummond } 27587f193d69SLuke Drummond if (info_lines.end() - (line + 1) < (ptrdiff_t)n_lines) 27597f193d69SLuke Drummond return false; 27607f193d69SLuke Drummond 27617f193d69SLuke Drummond bool success = false; 27627f193d69SLuke Drummond switch (handler->getValue()) { 27637f193d69SLuke Drummond case eExportVar: 27647f193d69SLuke Drummond success = ParseExportVarCount(line, n_lines); 27657f193d69SLuke Drummond break; 27667f193d69SLuke Drummond case eExportForEach: 27677f193d69SLuke Drummond success = ParseExportForeachCount(line, n_lines); 27687f193d69SLuke Drummond break; 27697f193d69SLuke Drummond case eExportReduce: 27707f193d69SLuke Drummond success = ParseExportReduceCount(line, n_lines); 27717f193d69SLuke Drummond break; 27727f193d69SLuke Drummond case ePragma: 27737f193d69SLuke Drummond success = ParsePragmaCount(line, n_lines); 27747f193d69SLuke Drummond break; 27757f193d69SLuke Drummond default: { 27767f193d69SLuke Drummond if (log) 27777f193d69SLuke Drummond log->Printf("%s - skipping .rs.info field '%s'", __FUNCTION__, 27787f193d69SLuke Drummond line->str().c_str()); 27797f193d69SLuke Drummond continue; 27807f193d69SLuke Drummond } 27817f193d69SLuke Drummond } 27827f193d69SLuke Drummond if (!success) 27837f193d69SLuke Drummond return false; 27847f193d69SLuke Drummond line += n_lines; 27857f193d69SLuke Drummond } 27867f193d69SLuke Drummond return info_lines.size() > 0; 27875ec532a9SColin Riley } 27885ec532a9SColin Riley 2789b9c1b51eSKate Stone void RenderScriptRuntime::Status(Stream &strm) const { 2790b9c1b51eSKate Stone if (m_libRS) { 27914640cde1SColin Riley strm.Printf("Runtime Library discovered."); 27924640cde1SColin Riley strm.EOL(); 27934640cde1SColin Riley } 2794b9c1b51eSKate Stone if (m_libRSDriver) { 27954640cde1SColin Riley strm.Printf("Runtime Driver discovered."); 27964640cde1SColin Riley strm.EOL(); 27974640cde1SColin Riley } 2798b9c1b51eSKate Stone if (m_libRSCpuRef) { 27994640cde1SColin Riley strm.Printf("CPU Reference Implementation discovered."); 28004640cde1SColin Riley strm.EOL(); 28014640cde1SColin Riley } 28024640cde1SColin Riley 2803b9c1b51eSKate Stone if (m_runtimeHooks.size()) { 28044640cde1SColin Riley strm.Printf("Runtime functions hooked:"); 28054640cde1SColin Riley strm.EOL(); 2806b9c1b51eSKate Stone for (auto b : m_runtimeHooks) { 28074640cde1SColin Riley strm.Indent(b.second->defn->name); 28084640cde1SColin Riley strm.EOL(); 28094640cde1SColin Riley } 2810b9c1b51eSKate Stone } else { 28114640cde1SColin Riley strm.Printf("Runtime is not hooked."); 28124640cde1SColin Riley strm.EOL(); 28134640cde1SColin Riley } 28144640cde1SColin Riley } 28154640cde1SColin Riley 2816b9c1b51eSKate Stone void RenderScriptRuntime::DumpContexts(Stream &strm) const { 28174640cde1SColin Riley strm.Printf("Inferred RenderScript Contexts:"); 28184640cde1SColin Riley strm.EOL(); 28194640cde1SColin Riley strm.IndentMore(); 28204640cde1SColin Riley 28214640cde1SColin Riley std::map<addr_t, uint64_t> contextReferences; 28224640cde1SColin Riley 282378f339d1SEwan Crawford // Iterate over all of the currently discovered scripts. 2824b9c1b51eSKate Stone // Note: We cant push or pop from m_scripts inside this loop or it may 2825b9c1b51eSKate Stone // invalidate script. 2826b9c1b51eSKate Stone for (const auto &script : m_scripts) { 282778f339d1SEwan Crawford if (!script->context.isValid()) 282878f339d1SEwan Crawford continue; 282978f339d1SEwan Crawford lldb::addr_t context = *script->context; 283078f339d1SEwan Crawford 2831b9c1b51eSKate Stone if (contextReferences.find(context) != contextReferences.end()) { 283278f339d1SEwan Crawford contextReferences[context]++; 2833b9c1b51eSKate Stone } else { 283478f339d1SEwan Crawford contextReferences[context] = 1; 28354640cde1SColin Riley } 28364640cde1SColin Riley } 28374640cde1SColin Riley 2838b9c1b51eSKate Stone for (const auto &cRef : contextReferences) { 2839b9c1b51eSKate Stone strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances", 2840b9c1b51eSKate Stone cRef.first, cRef.second); 28414640cde1SColin Riley strm.EOL(); 28424640cde1SColin Riley } 28434640cde1SColin Riley strm.IndentLess(); 28444640cde1SColin Riley } 28454640cde1SColin Riley 2846b9c1b51eSKate Stone void RenderScriptRuntime::DumpKernels(Stream &strm) const { 28474640cde1SColin Riley strm.Printf("RenderScript Kernels:"); 28484640cde1SColin Riley strm.EOL(); 28494640cde1SColin Riley strm.IndentMore(); 2850b9c1b51eSKate Stone for (const auto &module : m_rsmodules) { 28514640cde1SColin Riley strm.Printf("Resource '%s':", module->m_resname.c_str()); 28524640cde1SColin Riley strm.EOL(); 2853b9c1b51eSKate Stone for (const auto &kernel : module->m_kernels) { 28544640cde1SColin Riley strm.Indent(kernel.m_name.AsCString()); 28554640cde1SColin Riley strm.EOL(); 28564640cde1SColin Riley } 28574640cde1SColin Riley } 28584640cde1SColin Riley strm.IndentLess(); 28594640cde1SColin Riley } 28604640cde1SColin Riley 2861a0f08674SEwan Crawford RenderScriptRuntime::AllocationDetails * 2862b9c1b51eSKate Stone RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) { 2863a0f08674SEwan Crawford AllocationDetails *alloc = nullptr; 2864a0f08674SEwan Crawford 2865a0f08674SEwan Crawford // See if we can find allocation using id as an index; 2866b9c1b51eSKate Stone if (alloc_id <= m_allocations.size() && alloc_id != 0 && 2867b9c1b51eSKate Stone m_allocations[alloc_id - 1]->id == alloc_id) { 2868a0f08674SEwan Crawford alloc = m_allocations[alloc_id - 1].get(); 2869a0f08674SEwan Crawford return alloc; 2870a0f08674SEwan Crawford } 2871a0f08674SEwan Crawford 2872a0f08674SEwan Crawford // Fallback to searching 2873b9c1b51eSKate Stone for (const auto &a : m_allocations) { 2874b9c1b51eSKate Stone if (a->id == alloc_id) { 2875a0f08674SEwan Crawford alloc = a.get(); 2876a0f08674SEwan Crawford break; 2877a0f08674SEwan Crawford } 2878a0f08674SEwan Crawford } 2879a0f08674SEwan Crawford 2880b9c1b51eSKate Stone if (alloc == nullptr) { 2881b9c1b51eSKate Stone strm.Printf("Error: Couldn't find allocation with id matching %" PRIu32, 2882b9c1b51eSKate Stone alloc_id); 2883a0f08674SEwan Crawford strm.EOL(); 2884a0f08674SEwan Crawford } 2885a0f08674SEwan Crawford 2886a0f08674SEwan Crawford return alloc; 2887a0f08674SEwan Crawford } 2888a0f08674SEwan Crawford 2889b9c1b51eSKate Stone // Prints the contents of an allocation to the output stream, which may be a 2890b9c1b51eSKate Stone // file 2891b9c1b51eSKate Stone bool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr, 2892b9c1b51eSKate Stone const uint32_t id) { 2893a0f08674SEwan Crawford Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2894a0f08674SEwan Crawford 2895a0f08674SEwan Crawford // Check we can find the desired allocation 2896a0f08674SEwan Crawford AllocationDetails *alloc = FindAllocByID(strm, id); 2897a0f08674SEwan Crawford if (!alloc) 2898a0f08674SEwan Crawford return false; // FindAllocByID() will print error message for us here 2899a0f08674SEwan Crawford 2900a0f08674SEwan Crawford if (log) 2901b9c1b51eSKate Stone log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__, 2902b9c1b51eSKate Stone *alloc->address.get()); 2903a0f08674SEwan Crawford 2904a0f08674SEwan Crawford // Check we have information about the allocation, if not calculate it 2905b9c1b51eSKate Stone if (alloc->shouldRefresh()) { 2906a0f08674SEwan Crawford if (log) 2907b9c1b51eSKate Stone log->Printf("%s - allocation details not calculated yet, jitting info.", 2908b9c1b51eSKate Stone __FUNCTION__); 2909a0f08674SEwan Crawford 2910a0f08674SEwan Crawford // JIT all the allocation information 2911b9c1b51eSKate Stone if (!RefreshAllocation(alloc, frame_ptr)) { 2912a0f08674SEwan Crawford strm.Printf("Error: Couldn't JIT allocation details"); 2913a0f08674SEwan Crawford strm.EOL(); 2914a0f08674SEwan Crawford return false; 2915a0f08674SEwan Crawford } 2916a0f08674SEwan Crawford } 2917a0f08674SEwan Crawford 2918a0f08674SEwan Crawford // Establish format and size of each data element 2919b3f7f69dSAidan Dodds const uint32_t vec_size = *alloc->element.type_vec_size.get(); 29208b244e21SEwan Crawford const Element::DataType type = *alloc->element.type.get(); 2921a0f08674SEwan Crawford 2922b9c1b51eSKate Stone assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && 2923b9c1b51eSKate Stone "Invalid allocation type"); 2924a0f08674SEwan Crawford 29252e920715SEwan Crawford lldb::Format format; 29262e920715SEwan Crawford if (type >= Element::RS_TYPE_ELEMENT) 29272e920715SEwan Crawford format = eFormatHex; 29282e920715SEwan Crawford else 2929b9c1b51eSKate Stone format = vec_size == 1 2930b9c1b51eSKate Stone ? static_cast<lldb::Format>( 2931b9c1b51eSKate Stone AllocationDetails::RSTypeToFormat[type][eFormatSingle]) 2932b9c1b51eSKate Stone : static_cast<lldb::Format>( 2933b9c1b51eSKate Stone AllocationDetails::RSTypeToFormat[type][eFormatVector]); 2934a0f08674SEwan Crawford 2935b3f7f69dSAidan Dodds const uint32_t data_size = *alloc->element.datum_size.get(); 2936a0f08674SEwan Crawford 2937a0f08674SEwan Crawford if (log) 2938b9c1b51eSKate Stone log->Printf("%s - element size %" PRIu32 " bytes, including padding", 2939b9c1b51eSKate Stone __FUNCTION__, data_size); 2940a0f08674SEwan Crawford 294155232f09SEwan Crawford // Allocate a buffer to copy data into 294255232f09SEwan Crawford std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); 2943b9c1b51eSKate Stone if (!buffer) { 29442e920715SEwan Crawford strm.Printf("Error: Couldn't read allocation data"); 294555232f09SEwan Crawford strm.EOL(); 294655232f09SEwan Crawford return false; 294755232f09SEwan Crawford } 294855232f09SEwan Crawford 2949a0f08674SEwan Crawford // Calculate stride between rows as there may be padding at end of rows since 2950a0f08674SEwan Crawford // allocated memory is 16-byte aligned 2951b9c1b51eSKate Stone if (!alloc->stride.isValid()) { 2952a0f08674SEwan Crawford if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension 2953a0f08674SEwan Crawford alloc->stride = 0; 2954b9c1b51eSKate Stone else if (!JITAllocationStride(alloc, frame_ptr)) { 2955a0f08674SEwan Crawford strm.Printf("Error: Couldn't calculate allocation row stride"); 2956a0f08674SEwan Crawford strm.EOL(); 2957a0f08674SEwan Crawford return false; 2958a0f08674SEwan Crawford } 2959a0f08674SEwan Crawford } 2960b3f7f69dSAidan Dodds const uint32_t stride = *alloc->stride.get(); 2961b3f7f69dSAidan Dodds const uint32_t size = *alloc->size.get(); // Size of whole allocation 2962b9c1b51eSKate Stone const uint32_t padding = 2963b9c1b51eSKate Stone alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0; 2964a0f08674SEwan Crawford if (log) 2965b9c1b51eSKate Stone log->Printf("%s - stride %" PRIu32 " bytes, size %" PRIu32 2966b9c1b51eSKate Stone " bytes, padding %" PRIu32, 2967b3f7f69dSAidan Dodds __FUNCTION__, stride, size, padding); 2968a0f08674SEwan Crawford 2969a0f08674SEwan Crawford // Find dimensions used to index loops, so need to be non-zero 2970b3f7f69dSAidan Dodds uint32_t dim_x = alloc->dimension.get()->dim_1; 2971a0f08674SEwan Crawford dim_x = dim_x == 0 ? 1 : dim_x; 2972a0f08674SEwan Crawford 2973b3f7f69dSAidan Dodds uint32_t dim_y = alloc->dimension.get()->dim_2; 2974a0f08674SEwan Crawford dim_y = dim_y == 0 ? 1 : dim_y; 2975a0f08674SEwan Crawford 2976b3f7f69dSAidan Dodds uint32_t dim_z = alloc->dimension.get()->dim_3; 2977a0f08674SEwan Crawford dim_z = dim_z == 0 ? 1 : dim_z; 2978a0f08674SEwan Crawford 297955232f09SEwan Crawford // Use data extractor to format output 2980b9c1b51eSKate Stone const uint32_t archByteSize = 2981b9c1b51eSKate Stone GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 2982b9c1b51eSKate Stone DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(), 2983b9c1b51eSKate Stone archByteSize); 298455232f09SEwan Crawford 2985b3f7f69dSAidan Dodds uint32_t offset = 0; // Offset in buffer to next element to be printed 2986b3f7f69dSAidan Dodds uint32_t prev_row = 0; // Offset to the start of the previous row 2987a0f08674SEwan Crawford 2988a0f08674SEwan Crawford // Iterate over allocation dimensions, printing results to user 2989a0f08674SEwan Crawford strm.Printf("Data (X, Y, Z):"); 2990b9c1b51eSKate Stone for (uint32_t z = 0; z < dim_z; ++z) { 2991b9c1b51eSKate Stone for (uint32_t y = 0; y < dim_y; ++y) { 2992a0f08674SEwan Crawford // Use stride to index start of next row. 2993a0f08674SEwan Crawford if (!(y == 0 && z == 0)) 2994a0f08674SEwan Crawford offset = prev_row + stride; 2995a0f08674SEwan Crawford prev_row = offset; 2996a0f08674SEwan Crawford 2997a0f08674SEwan Crawford // Print each element in the row individually 2998b9c1b51eSKate Stone for (uint32_t x = 0; x < dim_x; ++x) { 2999b3f7f69dSAidan Dodds strm.Printf("\n(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") = ", x, y, z); 3000b9c1b51eSKate Stone if ((type == Element::RS_TYPE_NONE) && 3001b9c1b51eSKate Stone (alloc->element.children.size() > 0) && 3002b9c1b51eSKate Stone (alloc->element.type_name != Element::GetFallbackStructName())) { 30038b244e21SEwan Crawford // Here we are dumping an Element of struct type. 3004b9c1b51eSKate Stone // This is done using expression evaluation with the name of the 3005b9c1b51eSKate Stone // struct type and pointer to element. 30068b244e21SEwan Crawford 3007b9c1b51eSKate Stone // Don't print the name of the resulting expression, since this will 3008b9c1b51eSKate Stone // be '$[0-9]+' 30098b244e21SEwan Crawford DumpValueObjectOptions expr_options; 30108b244e21SEwan Crawford expr_options.SetHideName(true); 30118b244e21SEwan Crawford 30128b244e21SEwan Crawford // Setup expression as derefrencing a pointer cast to element address. 3013ea0636b5SEwan Crawford char expr_char_buffer[jit_max_expr_size]; 3014b9c1b51eSKate Stone int chars_written = 3015b9c1b51eSKate Stone snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64, 3016b9c1b51eSKate Stone alloc->element.type_name.AsCString(), 3017b9c1b51eSKate Stone *alloc->data_ptr.get() + offset); 30188b244e21SEwan Crawford 3019b9c1b51eSKate Stone if (chars_written < 0 || chars_written >= jit_max_expr_size) { 30208b244e21SEwan Crawford if (log) 3021b3f7f69dSAidan Dodds log->Printf("%s - error in snprintf().", __FUNCTION__); 30228b244e21SEwan Crawford continue; 30238b244e21SEwan Crawford } 30248b244e21SEwan Crawford 30258b244e21SEwan Crawford // Evaluate expression 30268b244e21SEwan Crawford ValueObjectSP expr_result; 3027b9c1b51eSKate Stone GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer, 3028b9c1b51eSKate Stone frame_ptr, expr_result); 30298b244e21SEwan Crawford 30308b244e21SEwan Crawford // Print the results to our stream. 30318b244e21SEwan Crawford expr_result->Dump(strm, expr_options); 3032b9c1b51eSKate Stone } else { 3033b9c1b51eSKate Stone alloc_data.Dump(&strm, offset, format, data_size - padding, 1, 1, 3034b9c1b51eSKate Stone LLDB_INVALID_ADDRESS, 0, 0); 30358b244e21SEwan Crawford } 30368b244e21SEwan Crawford offset += data_size; 3037a0f08674SEwan Crawford } 3038a0f08674SEwan Crawford } 3039a0f08674SEwan Crawford } 3040a0f08674SEwan Crawford strm.EOL(); 3041a0f08674SEwan Crawford 3042a0f08674SEwan Crawford return true; 3043a0f08674SEwan Crawford } 3044a0f08674SEwan Crawford 3045b9c1b51eSKate Stone // Function recalculates all our cached information about allocations by jitting 3046b9c1b51eSKate Stone // the 30470d2bfcfbSEwan Crawford // RS runtime regarding each allocation we know about. 30480d2bfcfbSEwan Crawford // Returns true if all allocations could be recomputed, false otherwise. 3049b9c1b51eSKate Stone bool RenderScriptRuntime::RecomputeAllAllocations(Stream &strm, 3050b9c1b51eSKate Stone StackFrame *frame_ptr) { 30510d2bfcfbSEwan Crawford bool success = true; 3052b9c1b51eSKate Stone for (auto &alloc : m_allocations) { 30530d2bfcfbSEwan Crawford // JIT current allocation information 3054b9c1b51eSKate Stone if (!RefreshAllocation(alloc.get(), frame_ptr)) { 3055b9c1b51eSKate Stone strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32 3056b9c1b51eSKate Stone "\n", 3057b9c1b51eSKate Stone alloc->id); 30580d2bfcfbSEwan Crawford success = false; 30590d2bfcfbSEwan Crawford } 30600d2bfcfbSEwan Crawford } 30610d2bfcfbSEwan Crawford 30620d2bfcfbSEwan Crawford if (success) 30630d2bfcfbSEwan Crawford strm.Printf("All allocations successfully recomputed"); 30640d2bfcfbSEwan Crawford strm.EOL(); 30650d2bfcfbSEwan Crawford 30660d2bfcfbSEwan Crawford return success; 30670d2bfcfbSEwan Crawford } 30680d2bfcfbSEwan Crawford 3069b649b005SEwan Crawford // Prints information regarding currently loaded allocations. 307015f2bd95SEwan Crawford // These details are gathered by jitting the runtime, which has as latency. 3071b9c1b51eSKate Stone // Index parameter specifies a single allocation ID to print, or a zero value to 3072b9c1b51eSKate Stone // print them all 3073b9c1b51eSKate Stone void RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame *frame_ptr, 3074b9c1b51eSKate Stone const uint32_t index) { 307515f2bd95SEwan Crawford strm.Printf("RenderScript Allocations:"); 307615f2bd95SEwan Crawford strm.EOL(); 307715f2bd95SEwan Crawford strm.IndentMore(); 307815f2bd95SEwan Crawford 3079b9c1b51eSKate Stone for (auto &alloc : m_allocations) { 3080b649b005SEwan Crawford // index will only be zero if we want to print all allocations 3081b649b005SEwan Crawford if (index != 0 && index != alloc->id) 3082b649b005SEwan Crawford continue; 308315f2bd95SEwan Crawford 308415f2bd95SEwan Crawford // JIT current allocation information 3085b9c1b51eSKate Stone if (alloc->shouldRefresh() && !RefreshAllocation(alloc.get(), frame_ptr)) { 3086b9c1b51eSKate Stone strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32, 3087b9c1b51eSKate Stone alloc->id); 3088b3f7f69dSAidan Dodds strm.EOL(); 308915f2bd95SEwan Crawford continue; 309015f2bd95SEwan Crawford } 309115f2bd95SEwan Crawford 3092b3f7f69dSAidan Dodds strm.Printf("%" PRIu32 ":", alloc->id); 3093b3f7f69dSAidan Dodds strm.EOL(); 309415f2bd95SEwan Crawford strm.IndentMore(); 309515f2bd95SEwan Crawford 309615f2bd95SEwan Crawford strm.Indent("Context: "); 309715f2bd95SEwan Crawford if (!alloc->context.isValid()) 309815f2bd95SEwan Crawford strm.Printf("unknown\n"); 309915f2bd95SEwan Crawford else 310015f2bd95SEwan Crawford strm.Printf("0x%" PRIx64 "\n", *alloc->context.get()); 310115f2bd95SEwan Crawford 310215f2bd95SEwan Crawford strm.Indent("Address: "); 310315f2bd95SEwan Crawford if (!alloc->address.isValid()) 310415f2bd95SEwan Crawford strm.Printf("unknown\n"); 310515f2bd95SEwan Crawford else 310615f2bd95SEwan Crawford strm.Printf("0x%" PRIx64 "\n", *alloc->address.get()); 310715f2bd95SEwan Crawford 310815f2bd95SEwan Crawford strm.Indent("Data pointer: "); 310915f2bd95SEwan Crawford if (!alloc->data_ptr.isValid()) 311015f2bd95SEwan Crawford strm.Printf("unknown\n"); 311115f2bd95SEwan Crawford else 311215f2bd95SEwan Crawford strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get()); 311315f2bd95SEwan Crawford 311415f2bd95SEwan Crawford strm.Indent("Dimensions: "); 311515f2bd95SEwan Crawford if (!alloc->dimension.isValid()) 311615f2bd95SEwan Crawford strm.Printf("unknown\n"); 311715f2bd95SEwan Crawford else 3118b3f7f69dSAidan Dodds strm.Printf("(%" PRId32 ", %" PRId32 ", %" PRId32 ")\n", 3119b9c1b51eSKate Stone alloc->dimension.get()->dim_1, alloc->dimension.get()->dim_2, 3120b9c1b51eSKate Stone alloc->dimension.get()->dim_3); 312115f2bd95SEwan Crawford 312215f2bd95SEwan Crawford strm.Indent("Data Type: "); 3123b9c1b51eSKate Stone if (!alloc->element.type.isValid() || 3124b9c1b51eSKate Stone !alloc->element.type_vec_size.isValid()) 312515f2bd95SEwan Crawford strm.Printf("unknown\n"); 3126b9c1b51eSKate Stone else { 31278b244e21SEwan Crawford const int vector_size = *alloc->element.type_vec_size.get(); 31282e920715SEwan Crawford Element::DataType type = *alloc->element.type.get(); 312915f2bd95SEwan Crawford 31308b244e21SEwan Crawford if (!alloc->element.type_name.IsEmpty()) 31318b244e21SEwan Crawford strm.Printf("%s\n", alloc->element.type_name.AsCString()); 3132b9c1b51eSKate Stone else { 3133b9c1b51eSKate Stone // Enum value isn't monotonous, so doesn't always index 3134b9c1b51eSKate Stone // RsDataTypeToString array 31352e920715SEwan Crawford if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT) 3136b9c1b51eSKate Stone type = 3137b9c1b51eSKate Stone static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) + 3138b3f7f69dSAidan Dodds Element::RS_TYPE_MATRIX_2X2 + 1); 31392e920715SEwan Crawford 3140b3f7f69dSAidan Dodds if (type >= (sizeof(AllocationDetails::RsDataTypeToString) / 3141b3f7f69dSAidan Dodds sizeof(AllocationDetails::RsDataTypeToString[0])) || 3142b3f7f69dSAidan Dodds vector_size > 4 || vector_size < 1) 314315f2bd95SEwan Crawford strm.Printf("invalid type\n"); 314415f2bd95SEwan Crawford else 3145b9c1b51eSKate Stone strm.Printf( 3146b9c1b51eSKate Stone "%s\n", 3147b9c1b51eSKate Stone AllocationDetails::RsDataTypeToString[static_cast<uint32_t>(type)] 3148b3f7f69dSAidan Dodds [vector_size - 1]); 314915f2bd95SEwan Crawford } 31502e920715SEwan Crawford } 315115f2bd95SEwan Crawford 315215f2bd95SEwan Crawford strm.Indent("Data Kind: "); 31538b244e21SEwan Crawford if (!alloc->element.type_kind.isValid()) 315415f2bd95SEwan Crawford strm.Printf("unknown\n"); 3155b9c1b51eSKate Stone else { 31568b244e21SEwan Crawford const Element::DataKind kind = *alloc->element.type_kind.get(); 31578b244e21SEwan Crawford if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV) 315815f2bd95SEwan Crawford strm.Printf("invalid kind\n"); 315915f2bd95SEwan Crawford else 3160b9c1b51eSKate Stone strm.Printf( 3161b9c1b51eSKate Stone "%s\n", 3162b9c1b51eSKate Stone AllocationDetails::RsDataKindToString[static_cast<uint32_t>(kind)]); 316315f2bd95SEwan Crawford } 316415f2bd95SEwan Crawford 316515f2bd95SEwan Crawford strm.EOL(); 316615f2bd95SEwan Crawford strm.IndentLess(); 316715f2bd95SEwan Crawford } 316815f2bd95SEwan Crawford strm.IndentLess(); 316915f2bd95SEwan Crawford } 317015f2bd95SEwan Crawford 31717dc7771cSEwan Crawford // Set breakpoints on every kernel found in RS module 3172b9c1b51eSKate Stone void RenderScriptRuntime::BreakOnModuleKernels( 3173b9c1b51eSKate Stone const RSModuleDescriptorSP rsmodule_sp) { 3174b9c1b51eSKate Stone for (const auto &kernel : rsmodule_sp->m_kernels) { 31757dc7771cSEwan Crawford // Don't set breakpoint on 'root' kernel 31767dc7771cSEwan Crawford if (strcmp(kernel.m_name.AsCString(), "root") == 0) 31777dc7771cSEwan Crawford continue; 31787dc7771cSEwan Crawford 31797dc7771cSEwan Crawford CreateKernelBreakpoint(kernel.m_name); 31807dc7771cSEwan Crawford } 31817dc7771cSEwan Crawford } 31827dc7771cSEwan Crawford 31837dc7771cSEwan Crawford // Method is internally called by the 'kernel breakpoint all' command to 31847dc7771cSEwan Crawford // enable or disable breaking on all kernels. 31857dc7771cSEwan Crawford // 31867dc7771cSEwan Crawford // When do_break is true we want to enable this functionality. 31877dc7771cSEwan Crawford // When do_break is false we want to disable it. 3188b9c1b51eSKate Stone void RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) { 3189b9c1b51eSKate Stone Log *log( 3190b9c1b51eSKate Stone GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 31917dc7771cSEwan Crawford 31927dc7771cSEwan Crawford InitSearchFilter(target); 31937dc7771cSEwan Crawford 31947dc7771cSEwan Crawford // Set breakpoints on all the kernels 3195b9c1b51eSKate Stone if (do_break && !m_breakAllKernels) { 31967dc7771cSEwan Crawford m_breakAllKernels = true; 31977dc7771cSEwan Crawford 31987dc7771cSEwan Crawford for (const auto &module : m_rsmodules) 31997dc7771cSEwan Crawford BreakOnModuleKernels(module); 32007dc7771cSEwan Crawford 32017dc7771cSEwan Crawford if (log) 3202b9c1b51eSKate Stone log->Printf("%s(True) - breakpoints set on all currently loaded kernels.", 3203b9c1b51eSKate Stone __FUNCTION__); 3204b9c1b51eSKate Stone } else if (!do_break && 3205b9c1b51eSKate Stone m_breakAllKernels) // Breakpoints won't be set on any new kernels. 32067dc7771cSEwan Crawford { 32077dc7771cSEwan Crawford m_breakAllKernels = false; 32087dc7771cSEwan Crawford 32097dc7771cSEwan Crawford if (log) 3210b9c1b51eSKate Stone log->Printf("%s(False) - breakpoints no longer automatically set.", 3211b9c1b51eSKate Stone __FUNCTION__); 32127dc7771cSEwan Crawford } 32137dc7771cSEwan Crawford } 32147dc7771cSEwan Crawford 32157dc7771cSEwan Crawford // Given the name of a kernel this function creates a breakpoint using our 32167dc7771cSEwan Crawford // own breakpoint resolver, and returns the Breakpoint shared pointer. 32177dc7771cSEwan Crawford BreakpointSP 3218b9c1b51eSKate Stone RenderScriptRuntime::CreateKernelBreakpoint(const ConstString &name) { 3219b9c1b51eSKate Stone Log *log( 3220b9c1b51eSKate Stone GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 32217dc7771cSEwan Crawford 3222b9c1b51eSKate Stone if (!m_filtersp) { 32237dc7771cSEwan Crawford if (log) 3224b3f7f69dSAidan Dodds log->Printf("%s - error, no breakpoint search filter set.", __FUNCTION__); 32257dc7771cSEwan Crawford return nullptr; 32267dc7771cSEwan Crawford } 32277dc7771cSEwan Crawford 32287dc7771cSEwan Crawford BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name)); 3229b9c1b51eSKate Stone BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint( 3230b9c1b51eSKate Stone m_filtersp, resolver_sp, false, false, false); 32317dc7771cSEwan Crawford 3232b9c1b51eSKate Stone // Give RS breakpoints a specific name, so the user can manipulate them as a 3233b9c1b51eSKate Stone // group. 323454782db7SEwan Crawford Error err; 323554782db7SEwan Crawford if (!bp->AddName("RenderScriptKernel", err) && log) 3236b9c1b51eSKate Stone log->Printf("%s - error setting break name, '%s'.", __FUNCTION__, 3237b9c1b51eSKate Stone err.AsCString()); 323854782db7SEwan Crawford 32397dc7771cSEwan Crawford return bp; 32407dc7771cSEwan Crawford } 32417dc7771cSEwan Crawford 3242b9c1b51eSKate Stone // Given an expression for a variable this function tries to calculate the 3243b9c1b51eSKate Stone // variable's value. 3244b9c1b51eSKate Stone // If this is possible it returns true and sets the uint64_t parameter to the 3245b9c1b51eSKate Stone // variables unsigned value. 3246018f5a7eSEwan Crawford // Otherwise function returns false. 3247b9c1b51eSKate Stone bool RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp, 3248b9c1b51eSKate Stone const char *var_name, 3249b9c1b51eSKate Stone uint64_t &val) { 3250018f5a7eSEwan Crawford Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 3251018f5a7eSEwan Crawford Error error; 3252018f5a7eSEwan Crawford VariableSP var_sp; 3253018f5a7eSEwan Crawford 3254018f5a7eSEwan Crawford // Find variable in stack frame 3255b3f7f69dSAidan Dodds ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath( 3256b3f7f69dSAidan Dodds var_name, eNoDynamicValues, 3257b9c1b51eSKate Stone StackFrame::eExpressionPathOptionCheckPtrVsMember | 3258b9c1b51eSKate Stone StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, 3259b3f7f69dSAidan Dodds var_sp, error)); 3260b9c1b51eSKate Stone if (!error.Success()) { 3261018f5a7eSEwan Crawford if (log) 3262b9c1b51eSKate Stone log->Printf("%s - error, couldn't find '%s' in frame", __FUNCTION__, 3263b9c1b51eSKate Stone var_name); 3264018f5a7eSEwan Crawford return false; 3265018f5a7eSEwan Crawford } 3266018f5a7eSEwan Crawford 3267b3f7f69dSAidan Dodds // Find the uint32_t value for the variable 3268018f5a7eSEwan Crawford bool success = false; 3269018f5a7eSEwan Crawford val = value_sp->GetValueAsUnsigned(0, &success); 3270b9c1b51eSKate Stone if (!success) { 3271018f5a7eSEwan Crawford if (log) 3272b9c1b51eSKate Stone log->Printf("%s - error, couldn't parse '%s' as an uint32_t.", 3273b9c1b51eSKate Stone __FUNCTION__, var_name); 3274018f5a7eSEwan Crawford return false; 3275018f5a7eSEwan Crawford } 3276018f5a7eSEwan Crawford 3277018f5a7eSEwan Crawford return true; 3278018f5a7eSEwan Crawford } 3279018f5a7eSEwan Crawford 3280b9c1b51eSKate Stone // Function attempts to find the current coordinate of a kernel invocation by 3281b9c1b51eSKate Stone // investigating the 3282b9c1b51eSKate Stone // values of frame variables in the .expand function. These coordinates are 3283b9c1b51eSKate Stone // returned via the coord 3284b9c1b51eSKate Stone // array reference parameter. Returns true if the coordinates could be found, 3285b9c1b51eSKate Stone // and false otherwise. 3286b9c1b51eSKate Stone bool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord, 3287b9c1b51eSKate Stone Thread *thread_ptr) { 32881e05c3bcSGreg Clayton static const std::string s_runtimeExpandSuffix(".expand"); 3289b9c1b51eSKate Stone static const std::array<const char *, 3> s_runtimeCoordVars{ 3290b9c1b51eSKate Stone {"rsIndex", "p->current.y", "p->current.z"}}; 32911e05c3bcSGreg Clayton 32924f8817c2SEwan Crawford Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 32934f8817c2SEwan Crawford 3294b9c1b51eSKate Stone if (!thread_ptr) { 32954f8817c2SEwan Crawford if (log) 32964f8817c2SEwan Crawford log->Printf("%s - Error, No thread pointer", __FUNCTION__); 32974f8817c2SEwan Crawford 32984f8817c2SEwan Crawford return false; 32994f8817c2SEwan Crawford } 33004f8817c2SEwan Crawford 3301b9c1b51eSKate Stone // Walk the call stack looking for a function whose name has the suffix 3302b9c1b51eSKate Stone // '.expand' 33034f8817c2SEwan Crawford // and contains the variables we're looking for. 3304b9c1b51eSKate Stone for (uint32_t i = 0; i < thread_ptr->GetStackFrameCount(); ++i) { 33054f8817c2SEwan Crawford if (!thread_ptr->SetSelectedFrameByIndex(i)) 33064f8817c2SEwan Crawford continue; 33074f8817c2SEwan Crawford 33084f8817c2SEwan Crawford StackFrameSP frame_sp = thread_ptr->GetSelectedFrame(); 33094f8817c2SEwan Crawford if (!frame_sp) 33104f8817c2SEwan Crawford continue; 33114f8817c2SEwan Crawford 33124f8817c2SEwan Crawford // Find the function name 33134f8817c2SEwan Crawford const SymbolContext sym_ctx = frame_sp->GetSymbolContext(false); 33144f8817c2SEwan Crawford const char *func_name_cstr = sym_ctx.GetFunctionName().AsCString(); 33154f8817c2SEwan Crawford if (!func_name_cstr) 33164f8817c2SEwan Crawford continue; 33174f8817c2SEwan Crawford 33184f8817c2SEwan Crawford if (log) 3319b9c1b51eSKate Stone log->Printf("%s - Inspecting function '%s'", __FUNCTION__, 3320b9c1b51eSKate Stone func_name_cstr); 33214f8817c2SEwan Crawford 33224f8817c2SEwan Crawford // Check if function name has .expand suffix 33234f8817c2SEwan Crawford std::string func_name(func_name_cstr); 3324b9c1b51eSKate Stone const int length_difference = 3325b9c1b51eSKate Stone func_name.length() - s_runtimeExpandSuffix.length(); 33264f8817c2SEwan Crawford if (length_difference <= 0) 33274f8817c2SEwan Crawford continue; 33284f8817c2SEwan Crawford 3329b9c1b51eSKate Stone const int32_t has_expand_suffix = 3330b9c1b51eSKate Stone func_name.compare(length_difference, s_runtimeExpandSuffix.length(), 33311e05c3bcSGreg Clayton s_runtimeExpandSuffix); 33324f8817c2SEwan Crawford 33334f8817c2SEwan Crawford if (has_expand_suffix != 0) 33344f8817c2SEwan Crawford continue; 33354f8817c2SEwan Crawford 33364f8817c2SEwan Crawford if (log) 3337b9c1b51eSKate Stone log->Printf("%s - Found .expand function '%s'", __FUNCTION__, 3338b9c1b51eSKate Stone func_name_cstr); 33394f8817c2SEwan Crawford 3340b9c1b51eSKate Stone // Get values for variables in .expand frame that tell us the current kernel 3341b9c1b51eSKate Stone // invocation 33424f8817c2SEwan Crawford bool found_coord_variables = true; 33431e05c3bcSGreg Clayton assert(s_runtimeCoordVars.size() == coord.size()); 33444f8817c2SEwan Crawford 3345b9c1b51eSKate Stone for (uint32_t i = 0; i < coord.size(); ++i) { 33464f8817c2SEwan Crawford uint64_t value = 0; 3347b9c1b51eSKate Stone if (!GetFrameVarAsUnsigned(frame_sp, s_runtimeCoordVars[i], value)) { 33484f8817c2SEwan Crawford found_coord_variables = false; 33494f8817c2SEwan Crawford break; 33504f8817c2SEwan Crawford } 33514f8817c2SEwan Crawford coord[i] = value; 33524f8817c2SEwan Crawford } 33534f8817c2SEwan Crawford 33544f8817c2SEwan Crawford if (found_coord_variables) 33554f8817c2SEwan Crawford return true; 33564f8817c2SEwan Crawford } 33574f8817c2SEwan Crawford return false; 33584f8817c2SEwan Crawford } 33594f8817c2SEwan Crawford 3360b9c1b51eSKate Stone // Callback when a kernel breakpoint hits and we're looking for a specific 3361b9c1b51eSKate Stone // coordinate. 3362b9c1b51eSKate Stone // Baton parameter contains a pointer to the target coordinate we want to break 3363b9c1b51eSKate Stone // on. 3364b9c1b51eSKate Stone // Function then checks the .expand frame for the current coordinate and breaks 3365b9c1b51eSKate Stone // to user if it matches. 3366018f5a7eSEwan Crawford // Parameter 'break_id' is the id of the Breakpoint which made the callback. 3367018f5a7eSEwan Crawford // Parameter 'break_loc_id' is the id for the BreakpointLocation which was hit, 3368018f5a7eSEwan Crawford // a single logical breakpoint can have multiple addresses. 3369b9c1b51eSKate Stone bool RenderScriptRuntime::KernelBreakpointHit(void *baton, 3370b9c1b51eSKate Stone StoppointCallbackContext *ctx, 3371b9c1b51eSKate Stone user_id_t break_id, 3372b9c1b51eSKate Stone user_id_t break_loc_id) { 3373b9c1b51eSKate Stone Log *log( 3374b9c1b51eSKate Stone GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3375018f5a7eSEwan Crawford 3376b9c1b51eSKate Stone assert(baton && 3377b9c1b51eSKate Stone "Error: null baton in conditional kernel breakpoint callback"); 3378018f5a7eSEwan Crawford 3379018f5a7eSEwan Crawford // Coordinate we want to stop on 33804f8817c2SEwan Crawford const uint32_t *target_coord = static_cast<const uint32_t *>(baton); 3381018f5a7eSEwan Crawford 3382018f5a7eSEwan Crawford if (log) 3383b9c1b51eSKate Stone log->Printf("%s - Break ID %" PRIu64 ", (%" PRIu32 ", %" PRIu32 ", %" PRIu32 3384b9c1b51eSKate Stone ")", 3385b9c1b51eSKate Stone __FUNCTION__, break_id, target_coord[0], target_coord[1], 3386b9c1b51eSKate Stone target_coord[2]); 3387018f5a7eSEwan Crawford 33884f8817c2SEwan Crawford // Select current thread 3389018f5a7eSEwan Crawford ExecutionContext context(ctx->exe_ctx_ref); 33904f8817c2SEwan Crawford Thread *thread_ptr = context.GetThreadPtr(); 33914f8817c2SEwan Crawford assert(thread_ptr && "Null thread pointer"); 33924f8817c2SEwan Crawford 33934f8817c2SEwan Crawford // Find current kernel invocation from .expand frame variables 33944f8817c2SEwan Crawford RSCoordinate current_coord{}; // Zero initialise array 3395b9c1b51eSKate Stone if (!GetKernelCoordinate(current_coord, thread_ptr)) { 3396018f5a7eSEwan Crawford if (log) 3397b9c1b51eSKate Stone log->Printf("%s - Error, couldn't select .expand stack frame", 3398b9c1b51eSKate Stone __FUNCTION__); 3399018f5a7eSEwan Crawford return false; 3400018f5a7eSEwan Crawford } 3401018f5a7eSEwan Crawford 3402018f5a7eSEwan Crawford if (log) 3403b9c1b51eSKate Stone log->Printf("%s - (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", __FUNCTION__, 3404b9c1b51eSKate Stone current_coord[0], current_coord[1], current_coord[2]); 3405018f5a7eSEwan Crawford 3406b9c1b51eSKate Stone // Check if the current kernel invocation coordinate matches our target 3407b9c1b51eSKate Stone // coordinate 3408b3f7f69dSAidan Dodds if (current_coord[0] == target_coord[0] && 3409b3f7f69dSAidan Dodds current_coord[1] == target_coord[1] && 3410b9c1b51eSKate Stone current_coord[2] == target_coord[2]) { 3411018f5a7eSEwan Crawford if (log) 3412b9c1b51eSKate Stone log->Printf("%s, BREAKING (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", 3413b9c1b51eSKate Stone __FUNCTION__, current_coord[0], current_coord[1], 3414b9c1b51eSKate Stone current_coord[2]); 3415018f5a7eSEwan Crawford 3416b9c1b51eSKate Stone BreakpointSP breakpoint_sp = 3417b9c1b51eSKate Stone context.GetTargetPtr()->GetBreakpointByID(break_id); 3418b9c1b51eSKate Stone assert(breakpoint_sp != nullptr && 3419b9c1b51eSKate Stone "Error: Couldn't find breakpoint matching break id for callback"); 3420b9c1b51eSKate Stone breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint 3421b9c1b51eSKate Stone // should only be hit once. 3422018f5a7eSEwan Crawford return true; 3423018f5a7eSEwan Crawford } 3424018f5a7eSEwan Crawford 3425018f5a7eSEwan Crawford // No match on coordinate 3426018f5a7eSEwan Crawford return false; 3427018f5a7eSEwan Crawford } 3428018f5a7eSEwan Crawford 3429b9c1b51eSKate Stone // Tries to set a breakpoint on the start of a kernel, resolved using the kernel 3430b9c1b51eSKate Stone // name. 3431b9c1b51eSKate Stone // Argument 'coords', represents a three dimensional coordinate which can be 3432b9c1b51eSKate Stone // used to specify 3433b9c1b51eSKate Stone // a single kernel instance to break on. If this is set then we add a callback 3434b9c1b51eSKate Stone // to the breakpoint. 3435b9c1b51eSKate Stone void RenderScriptRuntime::PlaceBreakpointOnKernel( 3436b9c1b51eSKate Stone Stream &strm, const char *name, const std::array<int, 3> coords, 3437b9c1b51eSKate Stone Error &error, TargetSP target) { 3438b9c1b51eSKate Stone if (!name) { 34394640cde1SColin Riley error.SetErrorString("invalid kernel name"); 34404640cde1SColin Riley return; 34414640cde1SColin Riley } 34424640cde1SColin Riley 34437dc7771cSEwan Crawford InitSearchFilter(target); 344498156583SEwan Crawford 34454640cde1SColin Riley ConstString kernel_name(name); 34467dc7771cSEwan Crawford BreakpointSP bp = CreateKernelBreakpoint(kernel_name); 3447018f5a7eSEwan Crawford 3448018f5a7eSEwan Crawford // We have a conditional breakpoint on a specific coordinate 3449b9c1b51eSKate Stone if (coords[0] != -1) { 3450b9c1b51eSKate Stone strm.Printf("Conditional kernel breakpoint on coordinate %" PRId32 3451b9c1b51eSKate Stone ", %" PRId32 ", %" PRId32, 3452b3f7f69dSAidan Dodds coords[0], coords[1], coords[2]); 3453018f5a7eSEwan Crawford strm.EOL(); 3454018f5a7eSEwan Crawford 3455018f5a7eSEwan Crawford // Allocate memory for the baton, and copy over coordinate 34564f8817c2SEwan Crawford uint32_t *baton = new uint32_t[coords.size()]; 3457b9c1b51eSKate Stone baton[0] = coords[0]; 3458b9c1b51eSKate Stone baton[1] = coords[1]; 3459b9c1b51eSKate Stone baton[2] = coords[2]; 3460018f5a7eSEwan Crawford 3461018f5a7eSEwan Crawford // Create a callback that will be invoked every time the breakpoint is hit. 3462b9c1b51eSKate Stone // The baton object passed to the handler is the target coordinate we want 3463b9c1b51eSKate Stone // to break on. 3464018f5a7eSEwan Crawford bp->SetCallback(KernelBreakpointHit, baton, true); 3465018f5a7eSEwan Crawford 3466b9c1b51eSKate Stone // Store a shared pointer to the baton, so the memory will eventually be 3467b9c1b51eSKate Stone // cleaned up after destruction 34684f8817c2SEwan Crawford m_conditional_breaks[bp->GetID()] = std::shared_ptr<uint32_t>(baton); 3469018f5a7eSEwan Crawford } 3470018f5a7eSEwan Crawford 347198156583SEwan Crawford if (bp) 347298156583SEwan Crawford bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false); 34734640cde1SColin Riley } 34744640cde1SColin Riley 3475b9c1b51eSKate Stone void RenderScriptRuntime::DumpModules(Stream &strm) const { 34765ec532a9SColin Riley strm.Printf("RenderScript Modules:"); 34775ec532a9SColin Riley strm.EOL(); 34785ec532a9SColin Riley strm.IndentMore(); 3479b9c1b51eSKate Stone for (const auto &module : m_rsmodules) { 34804640cde1SColin Riley module->Dump(strm); 34815ec532a9SColin Riley } 34825ec532a9SColin Riley strm.IndentLess(); 34835ec532a9SColin Riley } 34845ec532a9SColin Riley 348578f339d1SEwan Crawford RenderScriptRuntime::ScriptDetails * 3486b9c1b51eSKate Stone RenderScriptRuntime::LookUpScript(addr_t address, bool create) { 3487b9c1b51eSKate Stone for (const auto &s : m_scripts) { 348878f339d1SEwan Crawford if (s->script.isValid()) 348978f339d1SEwan Crawford if (*s->script == address) 349078f339d1SEwan Crawford return s.get(); 349178f339d1SEwan Crawford } 3492b9c1b51eSKate Stone if (create) { 349378f339d1SEwan Crawford std::unique_ptr<ScriptDetails> s(new ScriptDetails); 349478f339d1SEwan Crawford s->script = address; 349578f339d1SEwan Crawford m_scripts.push_back(std::move(s)); 3496d10ca9deSEwan Crawford return m_scripts.back().get(); 349778f339d1SEwan Crawford } 349878f339d1SEwan Crawford return nullptr; 349978f339d1SEwan Crawford } 350078f339d1SEwan Crawford 350178f339d1SEwan Crawford RenderScriptRuntime::AllocationDetails * 3502b9c1b51eSKate Stone RenderScriptRuntime::LookUpAllocation(addr_t address) { 3503b9c1b51eSKate Stone for (const auto &a : m_allocations) { 350478f339d1SEwan Crawford if (a->address.isValid()) 350578f339d1SEwan Crawford if (*a->address == address) 350678f339d1SEwan Crawford return a.get(); 350778f339d1SEwan Crawford } 35085d057637SLuke Drummond return nullptr; 35095d057637SLuke Drummond } 35105d057637SLuke Drummond 35115d057637SLuke Drummond RenderScriptRuntime::AllocationDetails * 3512b9c1b51eSKate Stone RenderScriptRuntime::CreateAllocation(addr_t address) { 35135d057637SLuke Drummond Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 35145d057637SLuke Drummond 35155d057637SLuke Drummond // Remove any previous allocation which contains the same address 35165d057637SLuke Drummond auto it = m_allocations.begin(); 3517b9c1b51eSKate Stone while (it != m_allocations.end()) { 3518b9c1b51eSKate Stone if (*((*it)->address) == address) { 35195d057637SLuke Drummond if (log) 3520b9c1b51eSKate Stone log->Printf("%s - Removing allocation id: %d, address: 0x%" PRIx64, 3521b9c1b51eSKate Stone __FUNCTION__, (*it)->id, address); 35225d057637SLuke Drummond 35235d057637SLuke Drummond it = m_allocations.erase(it); 3524b9c1b51eSKate Stone } else { 35255d057637SLuke Drummond it++; 35265d057637SLuke Drummond } 35275d057637SLuke Drummond } 35285d057637SLuke Drummond 352978f339d1SEwan Crawford std::unique_ptr<AllocationDetails> a(new AllocationDetails); 353078f339d1SEwan Crawford a->address = address; 353178f339d1SEwan Crawford m_allocations.push_back(std::move(a)); 3532d10ca9deSEwan Crawford return m_allocations.back().get(); 353378f339d1SEwan Crawford } 353478f339d1SEwan Crawford 3535b9c1b51eSKate Stone void RSModuleDescriptor::Dump(Stream &strm) const { 35367f193d69SLuke Drummond int indent = strm.GetIndentLevel(); 35377f193d69SLuke Drummond 35385ec532a9SColin Riley strm.Indent(); 35395ec532a9SColin Riley m_module->GetFileSpec().Dump(&strm); 35407f193d69SLuke Drummond strm.Indent(m_module->GetNumCompileUnits() ? "Debug info loaded." 35417f193d69SLuke Drummond : "Debug info does not exist."); 35425ec532a9SColin Riley strm.EOL(); 35435ec532a9SColin Riley strm.IndentMore(); 35447f193d69SLuke Drummond 35455ec532a9SColin Riley strm.Indent(); 3546189598edSColin Riley strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size())); 35475ec532a9SColin Riley strm.EOL(); 35485ec532a9SColin Riley strm.IndentMore(); 3549b9c1b51eSKate Stone for (const auto &global : m_globals) { 35505ec532a9SColin Riley global.Dump(strm); 35515ec532a9SColin Riley } 35525ec532a9SColin Riley strm.IndentLess(); 35537f193d69SLuke Drummond 35545ec532a9SColin Riley strm.Indent(); 3555189598edSColin Riley strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size())); 35565ec532a9SColin Riley strm.EOL(); 35575ec532a9SColin Riley strm.IndentMore(); 3558b9c1b51eSKate Stone for (const auto &kernel : m_kernels) { 35595ec532a9SColin Riley kernel.Dump(strm); 35605ec532a9SColin Riley } 35617f193d69SLuke Drummond strm.IndentLess(); 35627f193d69SLuke Drummond 35637f193d69SLuke Drummond strm.Indent(); 35644640cde1SColin Riley strm.Printf("Pragmas: %" PRIu64, static_cast<uint64_t>(m_pragmas.size())); 35654640cde1SColin Riley strm.EOL(); 35664640cde1SColin Riley strm.IndentMore(); 3567b9c1b51eSKate Stone for (const auto &key_val : m_pragmas) { 35687f193d69SLuke Drummond strm.Indent(); 35694640cde1SColin Riley strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str()); 35704640cde1SColin Riley strm.EOL(); 35714640cde1SColin Riley } 35727f193d69SLuke Drummond strm.IndentLess(); 35737f193d69SLuke Drummond 35747f193d69SLuke Drummond strm.Indent(); 35757f193d69SLuke Drummond strm.Printf("Reductions: %" PRIu64, 35767f193d69SLuke Drummond static_cast<uint64_t>(m_reductions.size())); 35777f193d69SLuke Drummond strm.EOL(); 35787f193d69SLuke Drummond strm.IndentMore(); 35797f193d69SLuke Drummond for (const auto &reduction : m_reductions) { 35807f193d69SLuke Drummond reduction.Dump(strm); 35817f193d69SLuke Drummond } 35827f193d69SLuke Drummond 35837f193d69SLuke Drummond strm.SetIndentLevel(indent); 35845ec532a9SColin Riley } 35855ec532a9SColin Riley 3586b9c1b51eSKate Stone void RSGlobalDescriptor::Dump(Stream &strm) const { 35875ec532a9SColin Riley strm.Indent(m_name.AsCString()); 35884640cde1SColin Riley VariableList var_list; 35894640cde1SColin Riley m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list); 3590b9c1b51eSKate Stone if (var_list.GetSize() == 1) { 35914640cde1SColin Riley auto var = var_list.GetVariableAtIndex(0); 35924640cde1SColin Riley auto type = var->GetType(); 3593b9c1b51eSKate Stone if (type) { 35944640cde1SColin Riley strm.Printf(" - "); 35954640cde1SColin Riley type->DumpTypeName(&strm); 3596b9c1b51eSKate Stone } else { 35974640cde1SColin Riley strm.Printf(" - Unknown Type"); 35984640cde1SColin Riley } 3599b9c1b51eSKate Stone } else { 36004640cde1SColin Riley strm.Printf(" - variable identified, but not found in binary"); 3601b9c1b51eSKate Stone const Symbol *s = m_module->m_module->FindFirstSymbolWithNameAndType( 3602b9c1b51eSKate Stone m_name, eSymbolTypeData); 3603b9c1b51eSKate Stone if (s) { 36044640cde1SColin Riley strm.Printf(" (symbol exists) "); 36054640cde1SColin Riley } 36064640cde1SColin Riley } 36074640cde1SColin Riley 36085ec532a9SColin Riley strm.EOL(); 36095ec532a9SColin Riley } 36105ec532a9SColin Riley 3611b9c1b51eSKate Stone void RSKernelDescriptor::Dump(Stream &strm) const { 36125ec532a9SColin Riley strm.Indent(m_name.AsCString()); 36135ec532a9SColin Riley strm.EOL(); 36145ec532a9SColin Riley } 36155ec532a9SColin Riley 36167f193d69SLuke Drummond void RSReductionDescriptor::Dump(lldb_private::Stream &stream) const { 36177f193d69SLuke Drummond stream.Indent(m_reduce_name.AsCString()); 36187f193d69SLuke Drummond stream.IndentMore(); 36197f193d69SLuke Drummond stream.EOL(); 36207f193d69SLuke Drummond stream.Indent(); 36217f193d69SLuke Drummond stream.Printf("accumulator: %s", m_accum_name.AsCString()); 36227f193d69SLuke Drummond stream.EOL(); 36237f193d69SLuke Drummond stream.Indent(); 36247f193d69SLuke Drummond stream.Printf("initializer: %s", m_init_name.AsCString()); 36257f193d69SLuke Drummond stream.EOL(); 36267f193d69SLuke Drummond stream.Indent(); 36277f193d69SLuke Drummond stream.Printf("combiner: %s", m_comb_name.AsCString()); 36287f193d69SLuke Drummond stream.EOL(); 36297f193d69SLuke Drummond stream.Indent(); 36307f193d69SLuke Drummond stream.Printf("outconverter: %s", m_outc_name.AsCString()); 36317f193d69SLuke Drummond stream.EOL(); 36327f193d69SLuke Drummond // XXX This is currently unspecified by RenderScript, and unused 36337f193d69SLuke Drummond // stream.Indent(); 36347f193d69SLuke Drummond // stream.Printf("halter: '%s'", m_init_name.AsCString()); 36357f193d69SLuke Drummond // stream.EOL(); 36367f193d69SLuke Drummond stream.IndentLess(); 36377f193d69SLuke Drummond } 36387f193d69SLuke Drummond 3639b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed { 36405ec532a9SColin Riley public: 36415ec532a9SColin Riley CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter) 3642b9c1b51eSKate Stone : CommandObjectParsed( 3643b9c1b51eSKate Stone interpreter, "renderscript module dump", 3644b9c1b51eSKate Stone "Dumps renderscript specific information for all modules.", 3645b9c1b51eSKate Stone "renderscript module dump", 3646b9c1b51eSKate Stone eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} 36475ec532a9SColin Riley 3648222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeModuleDump() override = default; 36495ec532a9SColin Riley 3650b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 36515ec532a9SColin Riley RenderScriptRuntime *runtime = 3652b9c1b51eSKate Stone (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3653b9c1b51eSKate Stone eLanguageTypeExtRenderScript); 36545ec532a9SColin Riley runtime->DumpModules(result.GetOutputStream()); 36555ec532a9SColin Riley result.SetStatus(eReturnStatusSuccessFinishResult); 36565ec532a9SColin Riley return true; 36575ec532a9SColin Riley } 36585ec532a9SColin Riley }; 36595ec532a9SColin Riley 3660b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword { 36615ec532a9SColin Riley public: 36625ec532a9SColin Riley CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter) 3663b9c1b51eSKate Stone : CommandObjectMultiword(interpreter, "renderscript module", 3664b9c1b51eSKate Stone "Commands that deal with RenderScript modules.", 3665b9c1b51eSKate Stone nullptr) { 3666b9c1b51eSKate Stone LoadSubCommand( 3667b9c1b51eSKate Stone "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump( 3668b9c1b51eSKate Stone interpreter))); 36695ec532a9SColin Riley } 36705ec532a9SColin Riley 3671222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeModule() override = default; 36725ec532a9SColin Riley }; 36735ec532a9SColin Riley 3674b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed { 36754640cde1SColin Riley public: 36764640cde1SColin Riley CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter) 3677b9c1b51eSKate Stone : CommandObjectParsed( 3678b9c1b51eSKate Stone interpreter, "renderscript kernel list", 3679b3f7f69dSAidan Dodds "Lists renderscript kernel names and associated script resources.", 3680b9c1b51eSKate Stone "renderscript kernel list", 3681b9c1b51eSKate Stone eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} 36824640cde1SColin Riley 3683222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeKernelList() override = default; 36844640cde1SColin Riley 3685b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 36864640cde1SColin Riley RenderScriptRuntime *runtime = 3687b9c1b51eSKate Stone (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3688b9c1b51eSKate Stone eLanguageTypeExtRenderScript); 36894640cde1SColin Riley runtime->DumpKernels(result.GetOutputStream()); 36904640cde1SColin Riley result.SetStatus(eReturnStatusSuccessFinishResult); 36914640cde1SColin Riley return true; 36924640cde1SColin Riley } 36934640cde1SColin Riley }; 36944640cde1SColin Riley 3695*1f0f5b5bSZachary Turner static OptionDefinition g_renderscript_kernel_bp_set_options[] = { 3696*1f0f5b5bSZachary Turner {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument, 3697*1f0f5b5bSZachary Turner nullptr, nullptr, 0, eArgTypeValue, 3698*1f0f5b5bSZachary Turner "Set a breakpoint on a single invocation of the kernel with specified " 3699*1f0f5b5bSZachary Turner "coordinate.\n" 3700*1f0f5b5bSZachary Turner "Coordinate takes the form 'x[,y][,z] where x,y,z are positive " 3701*1f0f5b5bSZachary Turner "integers representing kernel dimensions. " 3702*1f0f5b5bSZachary Turner "Any unset dimensions will be defaulted to zero."}}; 3703*1f0f5b5bSZachary Turner 3704b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpointSet 3705b9c1b51eSKate Stone : public CommandObjectParsed { 37064640cde1SColin Riley public: 3707b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeKernelBreakpointSet( 3708b9c1b51eSKate Stone CommandInterpreter &interpreter) 3709b9c1b51eSKate Stone : CommandObjectParsed( 3710b9c1b51eSKate Stone interpreter, "renderscript kernel breakpoint set", 3711b3f7f69dSAidan Dodds "Sets a breakpoint on a renderscript kernel.", 3712b3f7f69dSAidan Dodds "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]", 3713b9c1b51eSKate Stone eCommandRequiresProcess | eCommandProcessMustBeLaunched | 3714b9c1b51eSKate Stone eCommandProcessMustBePaused), 3715b9c1b51eSKate Stone m_options() {} 37164640cde1SColin Riley 3717222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default; 3718222b937cSEugene Zelenko 3719b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 3720018f5a7eSEwan Crawford 3721b9c1b51eSKate Stone class CommandOptions : public Options { 3722018f5a7eSEwan Crawford public: 3723e1cfbc79STodd Fiala CommandOptions() : Options() {} 3724018f5a7eSEwan Crawford 3725222b937cSEugene Zelenko ~CommandOptions() override = default; 3726018f5a7eSEwan Crawford 3727b9c1b51eSKate Stone Error SetOptionValue(uint32_t option_idx, const char *option_arg, 3728b9c1b51eSKate Stone ExecutionContext *execution_context) override { 3729018f5a7eSEwan Crawford Error error; 3730018f5a7eSEwan Crawford const int short_option = m_getopt_table[option_idx].val; 3731018f5a7eSEwan Crawford 3732b9c1b51eSKate Stone switch (short_option) { 3733018f5a7eSEwan Crawford case 'c': 3734018f5a7eSEwan Crawford if (!ParseCoordinate(option_arg)) 3735b9c1b51eSKate Stone error.SetErrorStringWithFormat( 3736b9c1b51eSKate Stone "Couldn't parse coordinate '%s', should be in format 'x,y,z'.", 3737b3f7f69dSAidan Dodds option_arg); 3738018f5a7eSEwan Crawford break; 3739018f5a7eSEwan Crawford default: 3740b9c1b51eSKate Stone error.SetErrorStringWithFormat("unrecognized option '%c'", 3741b9c1b51eSKate Stone short_option); 3742018f5a7eSEwan Crawford break; 3743018f5a7eSEwan Crawford } 3744018f5a7eSEwan Crawford return error; 3745018f5a7eSEwan Crawford } 3746018f5a7eSEwan Crawford 3747018f5a7eSEwan Crawford // -c takes an argument of the form 'num[,num][,num]'. 3748018f5a7eSEwan Crawford // Where 'id_cstr' is this argument with the whitespace trimmed. 3749018f5a7eSEwan Crawford // Missing coordinates are defaulted to zero. 3750b9c1b51eSKate Stone bool ParseCoordinate(const char *id_cstr) { 3751018f5a7eSEwan Crawford RegularExpression regex; 3752018f5a7eSEwan Crawford RegularExpression::Match regex_match(3); 3753018f5a7eSEwan Crawford 375495eae423SZachary Turner llvm::StringRef id_ref = llvm::StringRef::withNullAsEmpty(id_cstr); 3755018f5a7eSEwan Crawford bool matched = false; 375695eae423SZachary Turner if (regex.Compile(llvm::StringRef("^([0-9]+),([0-9]+),([0-9]+)$")) && 375795eae423SZachary Turner regex.Execute(id_ref, ®ex_match)) 3758018f5a7eSEwan Crawford matched = true; 375995eae423SZachary Turner else if (regex.Compile(llvm::StringRef("^([0-9]+),([0-9]+)$")) && 376095eae423SZachary Turner regex.Execute(id_ref, ®ex_match)) 3761018f5a7eSEwan Crawford matched = true; 376295eae423SZachary Turner else if (regex.Compile(llvm::StringRef("^([0-9]+)$")) && 376395eae423SZachary Turner regex.Execute(id_ref, ®ex_match)) 3764018f5a7eSEwan Crawford matched = true; 3765b9c1b51eSKate Stone for (uint32_t i = 0; i < 3; i++) { 3766018f5a7eSEwan Crawford std::string group; 3767018f5a7eSEwan Crawford if (regex_match.GetMatchAtIndex(id_cstr, i + 1, group)) 3768b3f7f69dSAidan Dodds m_coord[i] = (uint32_t)strtoul(group.c_str(), nullptr, 0); 3769018f5a7eSEwan Crawford else 3770018f5a7eSEwan Crawford m_coord[i] = 0; 3771018f5a7eSEwan Crawford } 3772018f5a7eSEwan Crawford return matched; 3773018f5a7eSEwan Crawford } 3774018f5a7eSEwan Crawford 3775b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 3776018f5a7eSEwan Crawford // -1 means the -c option hasn't been set 3777018f5a7eSEwan Crawford m_coord[0] = -1; 3778018f5a7eSEwan Crawford m_coord[1] = -1; 3779018f5a7eSEwan Crawford m_coord[2] = -1; 3780018f5a7eSEwan Crawford } 3781018f5a7eSEwan Crawford 3782*1f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 3783*1f0f5b5bSZachary Turner return g_renderscript_kernel_bp_set_options; 3784*1f0f5b5bSZachary Turner } 3785018f5a7eSEwan Crawford 3786018f5a7eSEwan Crawford std::array<int, 3> m_coord; 3787018f5a7eSEwan Crawford }; 3788018f5a7eSEwan Crawford 3789b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 37904640cde1SColin Riley const size_t argc = command.GetArgumentCount(); 3791b9c1b51eSKate Stone if (argc < 1) { 3792b9c1b51eSKate Stone result.AppendErrorWithFormat( 3793b9c1b51eSKate Stone "'%s' takes 1 argument of kernel name, and an optional coordinate.", 3794b3f7f69dSAidan Dodds m_cmd_name.c_str()); 3795018f5a7eSEwan Crawford result.SetStatus(eReturnStatusFailed); 3796018f5a7eSEwan Crawford return false; 3797018f5a7eSEwan Crawford } 3798018f5a7eSEwan Crawford 37994640cde1SColin Riley RenderScriptRuntime *runtime = 3800b9c1b51eSKate Stone (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3801b9c1b51eSKate Stone eLanguageTypeExtRenderScript); 38024640cde1SColin Riley 38034640cde1SColin Riley Error error; 3804b9c1b51eSKate Stone runtime->PlaceBreakpointOnKernel( 3805b9c1b51eSKate Stone result.GetOutputStream(), command.GetArgumentAtIndex(0), 3806b9c1b51eSKate Stone m_options.m_coord, error, m_exe_ctx.GetTargetSP()); 38074640cde1SColin Riley 3808b9c1b51eSKate Stone if (error.Success()) { 38094640cde1SColin Riley result.AppendMessage("Breakpoint(s) created"); 38104640cde1SColin Riley result.SetStatus(eReturnStatusSuccessFinishResult); 38114640cde1SColin Riley return true; 38124640cde1SColin Riley } 38134640cde1SColin Riley result.SetStatus(eReturnStatusFailed); 38144640cde1SColin Riley result.AppendErrorWithFormat("Error: %s", error.AsCString()); 38154640cde1SColin Riley return false; 38164640cde1SColin Riley } 38174640cde1SColin Riley 3818018f5a7eSEwan Crawford private: 3819018f5a7eSEwan Crawford CommandOptions m_options; 38204640cde1SColin Riley }; 38214640cde1SColin Riley 3822b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpointAll 3823b9c1b51eSKate Stone : public CommandObjectParsed { 38247dc7771cSEwan Crawford public: 3825b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeKernelBreakpointAll( 3826b9c1b51eSKate Stone CommandInterpreter &interpreter) 3827b3f7f69dSAidan Dodds : CommandObjectParsed( 3828b3f7f69dSAidan Dodds interpreter, "renderscript kernel breakpoint all", 3829b9c1b51eSKate Stone "Automatically sets a breakpoint on all renderscript kernels that " 3830b9c1b51eSKate Stone "are or will be loaded.\n" 3831b9c1b51eSKate Stone "Disabling option means breakpoints will no longer be set on any " 3832b9c1b51eSKate Stone "kernels loaded in the future, " 38337dc7771cSEwan Crawford "but does not remove currently set breakpoints.", 38347dc7771cSEwan Crawford "renderscript kernel breakpoint all <enable/disable>", 3835b9c1b51eSKate Stone eCommandRequiresProcess | eCommandProcessMustBeLaunched | 3836b9c1b51eSKate Stone eCommandProcessMustBePaused) {} 38377dc7771cSEwan Crawford 3838222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default; 38397dc7771cSEwan Crawford 3840b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 38417dc7771cSEwan Crawford const size_t argc = command.GetArgumentCount(); 3842b9c1b51eSKate Stone if (argc != 1) { 3843b9c1b51eSKate Stone result.AppendErrorWithFormat( 3844b9c1b51eSKate Stone "'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str()); 38457dc7771cSEwan Crawford result.SetStatus(eReturnStatusFailed); 38467dc7771cSEwan Crawford return false; 38477dc7771cSEwan Crawford } 38487dc7771cSEwan Crawford 3849b3f7f69dSAidan Dodds RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 3850b9c1b51eSKate Stone m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3851b9c1b51eSKate Stone eLanguageTypeExtRenderScript)); 38527dc7771cSEwan Crawford 38537dc7771cSEwan Crawford bool do_break = false; 38547dc7771cSEwan Crawford const char *argument = command.GetArgumentAtIndex(0); 3855b9c1b51eSKate Stone if (strcmp(argument, "enable") == 0) { 38567dc7771cSEwan Crawford do_break = true; 38577dc7771cSEwan Crawford result.AppendMessage("Breakpoints will be set on all kernels."); 3858b9c1b51eSKate Stone } else if (strcmp(argument, "disable") == 0) { 38597dc7771cSEwan Crawford do_break = false; 38607dc7771cSEwan Crawford result.AppendMessage("Breakpoints will not be set on any new kernels."); 3861b9c1b51eSKate Stone } else { 3862b9c1b51eSKate Stone result.AppendErrorWithFormat( 3863b9c1b51eSKate Stone "Argument must be either 'enable' or 'disable'"); 38647dc7771cSEwan Crawford result.SetStatus(eReturnStatusFailed); 38657dc7771cSEwan Crawford return false; 38667dc7771cSEwan Crawford } 38677dc7771cSEwan Crawford 38687dc7771cSEwan Crawford runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP()); 38697dc7771cSEwan Crawford 38707dc7771cSEwan Crawford result.SetStatus(eReturnStatusSuccessFinishResult); 38717dc7771cSEwan Crawford return true; 38727dc7771cSEwan Crawford } 38737dc7771cSEwan Crawford }; 38747dc7771cSEwan Crawford 3875b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelCoordinate 3876b9c1b51eSKate Stone : public CommandObjectParsed { 38774f8817c2SEwan Crawford public: 3878b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeKernelCoordinate( 3879b9c1b51eSKate Stone CommandInterpreter &interpreter) 3880b9c1b51eSKate Stone : CommandObjectParsed( 3881b9c1b51eSKate Stone interpreter, "renderscript kernel coordinate", 38824f8817c2SEwan Crawford "Shows the (x,y,z) coordinate of the current kernel invocation.", 38834f8817c2SEwan Crawford "renderscript kernel coordinate", 3884b9c1b51eSKate Stone eCommandRequiresProcess | eCommandProcessMustBeLaunched | 3885b9c1b51eSKate Stone eCommandProcessMustBePaused) {} 38864f8817c2SEwan Crawford 38874f8817c2SEwan Crawford ~CommandObjectRenderScriptRuntimeKernelCoordinate() override = default; 38884f8817c2SEwan Crawford 3889b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 38904f8817c2SEwan Crawford RSCoordinate coord{}; // Zero initialize array 3891b9c1b51eSKate Stone bool success = RenderScriptRuntime::GetKernelCoordinate( 3892b9c1b51eSKate Stone coord, m_exe_ctx.GetThreadPtr()); 38934f8817c2SEwan Crawford Stream &stream = result.GetOutputStream(); 38944f8817c2SEwan Crawford 3895b9c1b51eSKate Stone if (success) { 3896b9c1b51eSKate Stone stream.Printf("Coordinate: (%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")", 3897b9c1b51eSKate Stone coord[0], coord[1], coord[2]); 38984f8817c2SEwan Crawford stream.EOL(); 38994f8817c2SEwan Crawford result.SetStatus(eReturnStatusSuccessFinishResult); 3900b9c1b51eSKate Stone } else { 39014f8817c2SEwan Crawford stream.Printf("Error: Coordinate could not be found."); 39024f8817c2SEwan Crawford stream.EOL(); 39034f8817c2SEwan Crawford result.SetStatus(eReturnStatusFailed); 39044f8817c2SEwan Crawford } 39054f8817c2SEwan Crawford return true; 39064f8817c2SEwan Crawford } 39074f8817c2SEwan Crawford }; 39084f8817c2SEwan Crawford 3909b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernelBreakpoint 3910b9c1b51eSKate Stone : public CommandObjectMultiword { 39117dc7771cSEwan Crawford public: 3912b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeKernelBreakpoint( 3913b9c1b51eSKate Stone CommandInterpreter &interpreter) 3914b9c1b51eSKate Stone : CommandObjectMultiword( 3915b9c1b51eSKate Stone interpreter, "renderscript kernel", 3916b9c1b51eSKate Stone "Commands that generate breakpoints on renderscript kernels.", 3917b9c1b51eSKate Stone nullptr) { 3918b9c1b51eSKate Stone LoadSubCommand( 3919b9c1b51eSKate Stone "set", 3920b9c1b51eSKate Stone CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet( 3921b9c1b51eSKate Stone interpreter))); 3922b9c1b51eSKate Stone LoadSubCommand( 3923b9c1b51eSKate Stone "all", 3924b9c1b51eSKate Stone CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll( 3925b9c1b51eSKate Stone interpreter))); 39267dc7771cSEwan Crawford } 39277dc7771cSEwan Crawford 3928222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default; 39297dc7771cSEwan Crawford }; 39307dc7771cSEwan Crawford 3931b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword { 39324640cde1SColin Riley public: 39334640cde1SColin Riley CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter) 3934b9c1b51eSKate Stone : CommandObjectMultiword(interpreter, "renderscript kernel", 3935b9c1b51eSKate Stone "Commands that deal with RenderScript kernels.", 3936b9c1b51eSKate Stone nullptr) { 3937b9c1b51eSKate Stone LoadSubCommand( 3938b9c1b51eSKate Stone "list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList( 3939b9c1b51eSKate Stone interpreter))); 3940b9c1b51eSKate Stone LoadSubCommand( 3941b9c1b51eSKate Stone "coordinate", 3942b9c1b51eSKate Stone CommandObjectSP( 3943b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeKernelCoordinate(interpreter))); 3944b9c1b51eSKate Stone LoadSubCommand( 3945b9c1b51eSKate Stone "breakpoint", 3946b9c1b51eSKate Stone CommandObjectSP( 3947b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter))); 39484640cde1SColin Riley } 39494640cde1SColin Riley 3950222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeKernel() override = default; 39514640cde1SColin Riley }; 39524640cde1SColin Riley 3953b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed { 39544640cde1SColin Riley public: 39554640cde1SColin Riley CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter) 3956b9c1b51eSKate Stone : CommandObjectParsed(interpreter, "renderscript context dump", 3957b9c1b51eSKate Stone "Dumps renderscript context information.", 3958b9c1b51eSKate Stone "renderscript context dump", 3959b9c1b51eSKate Stone eCommandRequiresProcess | 3960b9c1b51eSKate Stone eCommandProcessMustBeLaunched) {} 39614640cde1SColin Riley 3962222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeContextDump() override = default; 39634640cde1SColin Riley 3964b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 39654640cde1SColin Riley RenderScriptRuntime *runtime = 3966b9c1b51eSKate Stone (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3967b9c1b51eSKate Stone eLanguageTypeExtRenderScript); 39684640cde1SColin Riley runtime->DumpContexts(result.GetOutputStream()); 39694640cde1SColin Riley result.SetStatus(eReturnStatusSuccessFinishResult); 39704640cde1SColin Riley return true; 39714640cde1SColin Riley } 39724640cde1SColin Riley }; 39734640cde1SColin Riley 3974*1f0f5b5bSZachary Turner static OptionDefinition g_renderscript_runtime_alloc_dump_options[] = { 3975*1f0f5b5bSZachary Turner {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, 3976*1f0f5b5bSZachary Turner nullptr, nullptr, 0, eArgTypeFilename, 3977*1f0f5b5bSZachary Turner "Print results to specified file instead of command line."}}; 3978*1f0f5b5bSZachary Turner 3979b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword { 39804640cde1SColin Riley public: 39814640cde1SColin Riley CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter) 3982b9c1b51eSKate Stone : CommandObjectMultiword(interpreter, "renderscript context", 3983b9c1b51eSKate Stone "Commands that deal with RenderScript contexts.", 3984b9c1b51eSKate Stone nullptr) { 3985b9c1b51eSKate Stone LoadSubCommand( 3986b9c1b51eSKate Stone "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump( 3987b9c1b51eSKate Stone interpreter))); 39884640cde1SColin Riley } 39894640cde1SColin Riley 3990222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeContext() override = default; 39914640cde1SColin Riley }; 39924640cde1SColin Riley 3993b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationDump 3994b9c1b51eSKate Stone : public CommandObjectParsed { 3995a0f08674SEwan Crawford public: 3996b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeAllocationDump( 3997b9c1b51eSKate Stone CommandInterpreter &interpreter) 3998a0f08674SEwan Crawford : CommandObjectParsed(interpreter, "renderscript allocation dump", 3999b9c1b51eSKate Stone "Displays the contents of a particular allocation", 4000b9c1b51eSKate Stone "renderscript allocation dump <ID>", 4001b9c1b51eSKate Stone eCommandRequiresProcess | 4002b9c1b51eSKate Stone eCommandProcessMustBeLaunched), 4003b9c1b51eSKate Stone m_options() {} 4004a0f08674SEwan Crawford 4005222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeAllocationDump() override = default; 4006222b937cSEugene Zelenko 4007b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 4008a0f08674SEwan Crawford 4009b9c1b51eSKate Stone class CommandOptions : public Options { 4010a0f08674SEwan Crawford public: 4011e1cfbc79STodd Fiala CommandOptions() : Options() {} 4012a0f08674SEwan Crawford 4013222b937cSEugene Zelenko ~CommandOptions() override = default; 4014a0f08674SEwan Crawford 4015b9c1b51eSKate Stone Error SetOptionValue(uint32_t option_idx, const char *option_arg, 4016b9c1b51eSKate Stone ExecutionContext *execution_context) override { 4017a0f08674SEwan Crawford Error error; 4018a0f08674SEwan Crawford const int short_option = m_getopt_table[option_idx].val; 4019a0f08674SEwan Crawford 4020b9c1b51eSKate Stone switch (short_option) { 4021a0f08674SEwan Crawford case 'f': 4022a0f08674SEwan Crawford m_outfile.SetFile(option_arg, true); 4023b9c1b51eSKate Stone if (m_outfile.Exists()) { 4024a0f08674SEwan Crawford m_outfile.Clear(); 4025b9c1b51eSKate Stone error.SetErrorStringWithFormat("file already exists: '%s'", 4026b9c1b51eSKate Stone option_arg); 4027a0f08674SEwan Crawford } 4028a0f08674SEwan Crawford break; 4029a0f08674SEwan Crawford default: 4030b9c1b51eSKate Stone error.SetErrorStringWithFormat("unrecognized option '%c'", 4031b9c1b51eSKate Stone short_option); 4032a0f08674SEwan Crawford break; 4033a0f08674SEwan Crawford } 4034a0f08674SEwan Crawford return error; 4035a0f08674SEwan Crawford } 4036a0f08674SEwan Crawford 4037b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 4038a0f08674SEwan Crawford m_outfile.Clear(); 4039a0f08674SEwan Crawford } 4040a0f08674SEwan Crawford 4041*1f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 4042*1f0f5b5bSZachary Turner return g_renderscript_runtime_alloc_dump_options; 4043*1f0f5b5bSZachary Turner } 4044a0f08674SEwan Crawford 4045a0f08674SEwan Crawford FileSpec m_outfile; 4046a0f08674SEwan Crawford }; 4047a0f08674SEwan Crawford 4048b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 4049a0f08674SEwan Crawford const size_t argc = command.GetArgumentCount(); 4050b9c1b51eSKate Stone if (argc < 1) { 4051b9c1b51eSKate Stone result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. " 4052b9c1b51eSKate Stone "As well as an optional -f argument", 4053a0f08674SEwan Crawford m_cmd_name.c_str()); 4054a0f08674SEwan Crawford result.SetStatus(eReturnStatusFailed); 4055a0f08674SEwan Crawford return false; 4056a0f08674SEwan Crawford } 4057a0f08674SEwan Crawford 4058b3f7f69dSAidan Dodds RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4059b9c1b51eSKate Stone m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4060b9c1b51eSKate Stone eLanguageTypeExtRenderScript)); 4061a0f08674SEwan Crawford 4062a0f08674SEwan Crawford const char *id_cstr = command.GetArgumentAtIndex(0); 4063a0f08674SEwan Crawford bool convert_complete = false; 4064b9c1b51eSKate Stone const uint32_t id = 4065b9c1b51eSKate Stone StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 4066b9c1b51eSKate Stone if (!convert_complete) { 4067b9c1b51eSKate Stone result.AppendErrorWithFormat("invalid allocation id argument '%s'", 4068b9c1b51eSKate Stone id_cstr); 4069a0f08674SEwan Crawford result.SetStatus(eReturnStatusFailed); 4070a0f08674SEwan Crawford return false; 4071a0f08674SEwan Crawford } 4072a0f08674SEwan Crawford 4073a0f08674SEwan Crawford Stream *output_strm = nullptr; 4074a0f08674SEwan Crawford StreamFile outfile_stream; 4075b9c1b51eSKate Stone const FileSpec &outfile_spec = 4076b9c1b51eSKate Stone m_options.m_outfile; // Dump allocation to file instead 4077b9c1b51eSKate Stone if (outfile_spec) { 4078a0f08674SEwan Crawford // Open output file 4079a0f08674SEwan Crawford char path[256]; 4080a0f08674SEwan Crawford outfile_spec.GetPath(path, sizeof(path)); 4081b9c1b51eSKate Stone if (outfile_stream.GetFile() 4082b9c1b51eSKate Stone .Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate) 4083b9c1b51eSKate Stone .Success()) { 4084a0f08674SEwan Crawford output_strm = &outfile_stream; 4085a0f08674SEwan Crawford result.GetOutputStream().Printf("Results written to '%s'", path); 4086a0f08674SEwan Crawford result.GetOutputStream().EOL(); 4087b9c1b51eSKate Stone } else { 4088a0f08674SEwan Crawford result.AppendErrorWithFormat("Couldn't open file '%s'", path); 4089a0f08674SEwan Crawford result.SetStatus(eReturnStatusFailed); 4090a0f08674SEwan Crawford return false; 4091a0f08674SEwan Crawford } 4092b9c1b51eSKate Stone } else 4093a0f08674SEwan Crawford output_strm = &result.GetOutputStream(); 4094a0f08674SEwan Crawford 4095a0f08674SEwan Crawford assert(output_strm != nullptr); 4096b9c1b51eSKate Stone bool success = 4097b9c1b51eSKate Stone runtime->DumpAllocation(*output_strm, m_exe_ctx.GetFramePtr(), id); 4098a0f08674SEwan Crawford 4099a0f08674SEwan Crawford if (success) 4100a0f08674SEwan Crawford result.SetStatus(eReturnStatusSuccessFinishResult); 4101a0f08674SEwan Crawford else 4102a0f08674SEwan Crawford result.SetStatus(eReturnStatusFailed); 4103a0f08674SEwan Crawford 4104a0f08674SEwan Crawford return true; 4105a0f08674SEwan Crawford } 4106a0f08674SEwan Crawford 4107a0f08674SEwan Crawford private: 4108a0f08674SEwan Crawford CommandOptions m_options; 4109a0f08674SEwan Crawford }; 4110a0f08674SEwan Crawford 4111*1f0f5b5bSZachary Turner static OptionDefinition g_renderscript_runtime_alloc_list_options[] = { 4112*1f0f5b5bSZachary Turner {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument, nullptr, 4113*1f0f5b5bSZachary Turner nullptr, 0, eArgTypeIndex, 4114*1f0f5b5bSZachary Turner "Only show details of a single allocation with specified id."}}; 4115a0f08674SEwan Crawford 4116b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationList 4117b9c1b51eSKate Stone : public CommandObjectParsed { 411815f2bd95SEwan Crawford public: 4119b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeAllocationList( 4120b9c1b51eSKate Stone CommandInterpreter &interpreter) 4121b9c1b51eSKate Stone : CommandObjectParsed( 4122b9c1b51eSKate Stone interpreter, "renderscript allocation list", 4123b9c1b51eSKate Stone "List renderscript allocations and their information.", 4124b9c1b51eSKate Stone "renderscript allocation list", 4125b3f7f69dSAidan Dodds eCommandRequiresProcess | eCommandProcessMustBeLaunched), 4126b9c1b51eSKate Stone m_options() {} 412715f2bd95SEwan Crawford 4128222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeAllocationList() override = default; 4129222b937cSEugene Zelenko 4130b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 413115f2bd95SEwan Crawford 4132b9c1b51eSKate Stone class CommandOptions : public Options { 413315f2bd95SEwan Crawford public: 4134e1cfbc79STodd Fiala CommandOptions() : Options(), m_id(0) {} 413515f2bd95SEwan Crawford 4136222b937cSEugene Zelenko ~CommandOptions() override = default; 413715f2bd95SEwan Crawford 4138b9c1b51eSKate Stone Error SetOptionValue(uint32_t option_idx, const char *option_arg, 4139b9c1b51eSKate Stone ExecutionContext *execution_context) override { 414015f2bd95SEwan Crawford Error error; 414115f2bd95SEwan Crawford const int short_option = m_getopt_table[option_idx].val; 414215f2bd95SEwan Crawford 4143b9c1b51eSKate Stone switch (short_option) { 4144b649b005SEwan Crawford case 'i': 4145b649b005SEwan Crawford bool success; 4146b649b005SEwan Crawford m_id = StringConvert::ToUInt32(option_arg, 0, 0, &success); 4147b649b005SEwan Crawford if (!success) 4148b9c1b51eSKate Stone error.SetErrorStringWithFormat( 4149b9c1b51eSKate Stone "invalid integer value for option '%c'", short_option); 415015f2bd95SEwan Crawford break; 415115f2bd95SEwan Crawford default: 4152b9c1b51eSKate Stone error.SetErrorStringWithFormat("unrecognized option '%c'", 4153b9c1b51eSKate Stone short_option); 415415f2bd95SEwan Crawford break; 415515f2bd95SEwan Crawford } 415615f2bd95SEwan Crawford return error; 415715f2bd95SEwan Crawford } 415815f2bd95SEwan Crawford 4159b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 4160b649b005SEwan Crawford m_id = 0; 416115f2bd95SEwan Crawford } 416215f2bd95SEwan Crawford 4163*1f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 4164*1f0f5b5bSZachary Turner return g_renderscript_runtime_alloc_list_options; 4165*1f0f5b5bSZachary Turner } 416615f2bd95SEwan Crawford 4167b649b005SEwan Crawford uint32_t m_id; 416815f2bd95SEwan Crawford }; 416915f2bd95SEwan Crawford 4170b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 4171b3f7f69dSAidan Dodds RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4172b9c1b51eSKate Stone m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4173b9c1b51eSKate Stone eLanguageTypeExtRenderScript)); 4174b9c1b51eSKate Stone runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(), 4175b9c1b51eSKate Stone m_options.m_id); 417615f2bd95SEwan Crawford result.SetStatus(eReturnStatusSuccessFinishResult); 417715f2bd95SEwan Crawford return true; 417815f2bd95SEwan Crawford } 417915f2bd95SEwan Crawford 418015f2bd95SEwan Crawford private: 418115f2bd95SEwan Crawford CommandOptions m_options; 418215f2bd95SEwan Crawford }; 418315f2bd95SEwan Crawford 4184b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationLoad 4185b9c1b51eSKate Stone : public CommandObjectParsed { 418655232f09SEwan Crawford public: 4187b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeAllocationLoad( 4188b9c1b51eSKate Stone CommandInterpreter &interpreter) 4189b3f7f69dSAidan Dodds : CommandObjectParsed( 4190b9c1b51eSKate Stone interpreter, "renderscript allocation load", 4191b9c1b51eSKate Stone "Loads renderscript allocation contents from a file.", 4192b9c1b51eSKate Stone "renderscript allocation load <ID> <filename>", 4193b9c1b51eSKate Stone eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} 419455232f09SEwan Crawford 4195222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default; 419655232f09SEwan Crawford 4197b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 419855232f09SEwan Crawford const size_t argc = command.GetArgumentCount(); 4199b9c1b51eSKate Stone if (argc != 2) { 4200b9c1b51eSKate Stone result.AppendErrorWithFormat( 4201b9c1b51eSKate Stone "'%s' takes 2 arguments, an allocation ID and filename to read from.", 4202b3f7f69dSAidan Dodds m_cmd_name.c_str()); 420355232f09SEwan Crawford result.SetStatus(eReturnStatusFailed); 420455232f09SEwan Crawford return false; 420555232f09SEwan Crawford } 420655232f09SEwan Crawford 4207b3f7f69dSAidan Dodds RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4208b9c1b51eSKate Stone m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4209b9c1b51eSKate Stone eLanguageTypeExtRenderScript)); 421055232f09SEwan Crawford 421155232f09SEwan Crawford const char *id_cstr = command.GetArgumentAtIndex(0); 421255232f09SEwan Crawford bool convert_complete = false; 4213b9c1b51eSKate Stone const uint32_t id = 4214b9c1b51eSKate Stone StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 4215b9c1b51eSKate Stone if (!convert_complete) { 4216b9c1b51eSKate Stone result.AppendErrorWithFormat("invalid allocation id argument '%s'", 4217b9c1b51eSKate Stone id_cstr); 421855232f09SEwan Crawford result.SetStatus(eReturnStatusFailed); 421955232f09SEwan Crawford return false; 422055232f09SEwan Crawford } 422155232f09SEwan Crawford 422255232f09SEwan Crawford const char *filename = command.GetArgumentAtIndex(1); 4223b9c1b51eSKate Stone bool success = runtime->LoadAllocation(result.GetOutputStream(), id, 4224b9c1b51eSKate Stone filename, m_exe_ctx.GetFramePtr()); 422555232f09SEwan Crawford 422655232f09SEwan Crawford if (success) 422755232f09SEwan Crawford result.SetStatus(eReturnStatusSuccessFinishResult); 422855232f09SEwan Crawford else 422955232f09SEwan Crawford result.SetStatus(eReturnStatusFailed); 423055232f09SEwan Crawford 423155232f09SEwan Crawford return true; 423255232f09SEwan Crawford } 423355232f09SEwan Crawford }; 423455232f09SEwan Crawford 4235b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationSave 4236b9c1b51eSKate Stone : public CommandObjectParsed { 423755232f09SEwan Crawford public: 4238b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeAllocationSave( 4239b9c1b51eSKate Stone CommandInterpreter &interpreter) 4240b9c1b51eSKate Stone : CommandObjectParsed(interpreter, "renderscript allocation save", 4241b9c1b51eSKate Stone "Write renderscript allocation contents to a file.", 4242b9c1b51eSKate Stone "renderscript allocation save <ID> <filename>", 4243b9c1b51eSKate Stone eCommandRequiresProcess | 4244b9c1b51eSKate Stone eCommandProcessMustBeLaunched) {} 424555232f09SEwan Crawford 4246222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeAllocationSave() override = default; 424755232f09SEwan Crawford 4248b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 424955232f09SEwan Crawford const size_t argc = command.GetArgumentCount(); 4250b9c1b51eSKate Stone if (argc != 2) { 4251b9c1b51eSKate Stone result.AppendErrorWithFormat( 4252b9c1b51eSKate Stone "'%s' takes 2 arguments, an allocation ID and filename to read from.", 4253b3f7f69dSAidan Dodds m_cmd_name.c_str()); 425455232f09SEwan Crawford result.SetStatus(eReturnStatusFailed); 425555232f09SEwan Crawford return false; 425655232f09SEwan Crawford } 425755232f09SEwan Crawford 4258b3f7f69dSAidan Dodds RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4259b9c1b51eSKate Stone m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4260b9c1b51eSKate Stone eLanguageTypeExtRenderScript)); 426155232f09SEwan Crawford 426255232f09SEwan Crawford const char *id_cstr = command.GetArgumentAtIndex(0); 426355232f09SEwan Crawford bool convert_complete = false; 4264b9c1b51eSKate Stone const uint32_t id = 4265b9c1b51eSKate Stone StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 4266b9c1b51eSKate Stone if (!convert_complete) { 4267b9c1b51eSKate Stone result.AppendErrorWithFormat("invalid allocation id argument '%s'", 4268b9c1b51eSKate Stone id_cstr); 426955232f09SEwan Crawford result.SetStatus(eReturnStatusFailed); 427055232f09SEwan Crawford return false; 427155232f09SEwan Crawford } 427255232f09SEwan Crawford 427355232f09SEwan Crawford const char *filename = command.GetArgumentAtIndex(1); 4274b9c1b51eSKate Stone bool success = runtime->SaveAllocation(result.GetOutputStream(), id, 4275b9c1b51eSKate Stone filename, m_exe_ctx.GetFramePtr()); 427655232f09SEwan Crawford 427755232f09SEwan Crawford if (success) 427855232f09SEwan Crawford result.SetStatus(eReturnStatusSuccessFinishResult); 427955232f09SEwan Crawford else 428055232f09SEwan Crawford result.SetStatus(eReturnStatusFailed); 428155232f09SEwan Crawford 428255232f09SEwan Crawford return true; 428355232f09SEwan Crawford } 428455232f09SEwan Crawford }; 428555232f09SEwan Crawford 4286b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocationRefresh 4287b9c1b51eSKate Stone : public CommandObjectParsed { 42880d2bfcfbSEwan Crawford public: 4289b9c1b51eSKate Stone CommandObjectRenderScriptRuntimeAllocationRefresh( 4290b9c1b51eSKate Stone CommandInterpreter &interpreter) 42910d2bfcfbSEwan Crawford : CommandObjectParsed(interpreter, "renderscript allocation refresh", 4292b9c1b51eSKate Stone "Recomputes the details of all allocations.", 4293b9c1b51eSKate Stone "renderscript allocation refresh", 4294b9c1b51eSKate Stone eCommandRequiresProcess | 4295b9c1b51eSKate Stone eCommandProcessMustBeLaunched) {} 42960d2bfcfbSEwan Crawford 42970d2bfcfbSEwan Crawford ~CommandObjectRenderScriptRuntimeAllocationRefresh() override = default; 42980d2bfcfbSEwan Crawford 4299b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 43000d2bfcfbSEwan Crawford RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4301b9c1b51eSKate Stone m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4302b9c1b51eSKate Stone eLanguageTypeExtRenderScript)); 43030d2bfcfbSEwan Crawford 4304b9c1b51eSKate Stone bool success = runtime->RecomputeAllAllocations(result.GetOutputStream(), 4305b9c1b51eSKate Stone m_exe_ctx.GetFramePtr()); 43060d2bfcfbSEwan Crawford 4307b9c1b51eSKate Stone if (success) { 43080d2bfcfbSEwan Crawford result.SetStatus(eReturnStatusSuccessFinishResult); 43090d2bfcfbSEwan Crawford return true; 4310b9c1b51eSKate Stone } else { 43110d2bfcfbSEwan Crawford result.SetStatus(eReturnStatusFailed); 43120d2bfcfbSEwan Crawford return false; 43130d2bfcfbSEwan Crawford } 43140d2bfcfbSEwan Crawford } 43150d2bfcfbSEwan Crawford }; 43160d2bfcfbSEwan Crawford 4317b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeAllocation 4318b9c1b51eSKate Stone : public CommandObjectMultiword { 431915f2bd95SEwan Crawford public: 432015f2bd95SEwan Crawford CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter) 4321b9c1b51eSKate Stone : CommandObjectMultiword( 4322b9c1b51eSKate Stone interpreter, "renderscript allocation", 4323b9c1b51eSKate Stone "Commands that deal with RenderScript allocations.", nullptr) { 4324b9c1b51eSKate Stone LoadSubCommand( 4325b9c1b51eSKate Stone "list", 4326b9c1b51eSKate Stone CommandObjectSP( 4327b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeAllocationList(interpreter))); 4328b9c1b51eSKate Stone LoadSubCommand( 4329b9c1b51eSKate Stone "dump", 4330b9c1b51eSKate Stone CommandObjectSP( 4331b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeAllocationDump(interpreter))); 4332b9c1b51eSKate Stone LoadSubCommand( 4333b9c1b51eSKate Stone "save", 4334b9c1b51eSKate Stone CommandObjectSP( 4335b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeAllocationSave(interpreter))); 4336b9c1b51eSKate Stone LoadSubCommand( 4337b9c1b51eSKate Stone "load", 4338b9c1b51eSKate Stone CommandObjectSP( 4339b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter))); 4340b9c1b51eSKate Stone LoadSubCommand( 4341b9c1b51eSKate Stone "refresh", 4342b9c1b51eSKate Stone CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationRefresh( 4343b9c1b51eSKate Stone interpreter))); 434415f2bd95SEwan Crawford } 434515f2bd95SEwan Crawford 4346222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeAllocation() override = default; 434715f2bd95SEwan Crawford }; 434815f2bd95SEwan Crawford 4349b9c1b51eSKate Stone class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed { 43504640cde1SColin Riley public: 43514640cde1SColin Riley CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter) 4352b9c1b51eSKate Stone : CommandObjectParsed(interpreter, "renderscript status", 4353b9c1b51eSKate Stone "Displays current RenderScript runtime status.", 4354b9c1b51eSKate Stone "renderscript status", 4355b9c1b51eSKate Stone eCommandRequiresProcess | 4356b9c1b51eSKate Stone eCommandProcessMustBeLaunched) {} 43574640cde1SColin Riley 4358222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntimeStatus() override = default; 43594640cde1SColin Riley 4360b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 43614640cde1SColin Riley RenderScriptRuntime *runtime = 4362b9c1b51eSKate Stone (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4363b9c1b51eSKate Stone eLanguageTypeExtRenderScript); 43644640cde1SColin Riley runtime->Status(result.GetOutputStream()); 43654640cde1SColin Riley result.SetStatus(eReturnStatusSuccessFinishResult); 43664640cde1SColin Riley return true; 43674640cde1SColin Riley } 43684640cde1SColin Riley }; 43694640cde1SColin Riley 4370b9c1b51eSKate Stone class CommandObjectRenderScriptRuntime : public CommandObjectMultiword { 43715ec532a9SColin Riley public: 43725ec532a9SColin Riley CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter) 4373b9c1b51eSKate Stone : CommandObjectMultiword( 4374b9c1b51eSKate Stone interpreter, "renderscript", 4375b9c1b51eSKate Stone "Commands for operating on the RenderScript runtime.", 4376b9c1b51eSKate Stone "renderscript <subcommand> [<subcommand-options>]") { 4377b9c1b51eSKate Stone LoadSubCommand( 4378b9c1b51eSKate Stone "module", CommandObjectSP( 4379b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeModule(interpreter))); 4380b9c1b51eSKate Stone LoadSubCommand( 4381b9c1b51eSKate Stone "status", CommandObjectSP( 4382b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeStatus(interpreter))); 4383b9c1b51eSKate Stone LoadSubCommand( 4384b9c1b51eSKate Stone "kernel", CommandObjectSP( 4385b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeKernel(interpreter))); 4386b9c1b51eSKate Stone LoadSubCommand("context", 4387b9c1b51eSKate Stone CommandObjectSP(new CommandObjectRenderScriptRuntimeContext( 4388b9c1b51eSKate Stone interpreter))); 4389b9c1b51eSKate Stone LoadSubCommand( 4390b9c1b51eSKate Stone "allocation", 4391b9c1b51eSKate Stone CommandObjectSP( 4392b9c1b51eSKate Stone new CommandObjectRenderScriptRuntimeAllocation(interpreter))); 43935ec532a9SColin Riley } 43945ec532a9SColin Riley 4395222b937cSEugene Zelenko ~CommandObjectRenderScriptRuntime() override = default; 43965ec532a9SColin Riley }; 4397ef20b08fSColin Riley 4398b9c1b51eSKate Stone void RenderScriptRuntime::Initiate() { assert(!m_initiated); } 4399ef20b08fSColin Riley 4400ef20b08fSColin Riley RenderScriptRuntime::RenderScriptRuntime(Process *process) 4401b9c1b51eSKate Stone : lldb_private::CPPLanguageRuntime(process), m_initiated(false), 4402b9c1b51eSKate Stone m_debuggerPresentFlagged(false), m_breakAllKernels(false), 4403b9c1b51eSKate Stone m_ir_passes(nullptr) { 44044640cde1SColin Riley ModulesDidLoad(process->GetTarget().GetImages()); 4405ef20b08fSColin Riley } 44064640cde1SColin Riley 4407b9c1b51eSKate Stone lldb::CommandObjectSP RenderScriptRuntime::GetCommandObject( 4408b9c1b51eSKate Stone lldb_private::CommandInterpreter &interpreter) { 44090a66e2f1SEnrico Granata return CommandObjectSP(new CommandObjectRenderScriptRuntime(interpreter)); 44104640cde1SColin Riley } 44114640cde1SColin Riley 441278f339d1SEwan Crawford RenderScriptRuntime::~RenderScriptRuntime() = default; 4413