1285101Semaste//===-- RenderScriptRuntime.cpp ---------------------------------*- C++ -*-===// 2285101Semaste// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6285101Semaste// 7285101Semaste//===----------------------------------------------------------------------===// 8285101Semaste 9285101Semaste#include "RenderScriptRuntime.h" 10314564Sdim#include "RenderScriptScriptGroup.h" 11285101Semaste 12309124Sdim#include "lldb/Breakpoint/StoppointCallbackContext.h" 13285101Semaste#include "lldb/Core/Debugger.h" 14321369Sdim#include "lldb/Core/DumpDataExtractor.h" 15285101Semaste#include "lldb/Core/PluginManager.h" 16296417Sdim#include "lldb/Core/ValueObjectVariable.h" 17296417Sdim#include "lldb/DataFormatters/DumpValueObjectOptions.h" 18309124Sdim#include "lldb/Expression/UserExpression.h" 19321369Sdim#include "lldb/Host/OptionParser.h" 20296417Sdim#include "lldb/Host/StringConvert.h" 21309124Sdim#include "lldb/Interpreter/CommandInterpreter.h" 22309124Sdim#include "lldb/Interpreter/CommandObjectMultiword.h" 23309124Sdim#include "lldb/Interpreter/CommandReturnObject.h" 24309124Sdim#include "lldb/Interpreter/Options.h" 25314564Sdim#include "lldb/Symbol/Function.h" 26285101Semaste#include "lldb/Symbol/Symbol.h" 27285101Semaste#include "lldb/Symbol/Type.h" 28309124Sdim#include "lldb/Symbol/VariableList.h" 29285101Semaste#include "lldb/Target/Process.h" 30309124Sdim#include "lldb/Target/RegisterContext.h" 31314564Sdim#include "lldb/Target/SectionLoadList.h" 32285101Semaste#include "lldb/Target/Target.h" 33296417Sdim#include "lldb/Target/Thread.h" 34341825Sdim#include "lldb/Utility/Args.h" 35321369Sdim#include "lldb/Utility/ConstString.h" 36321369Sdim#include "lldb/Utility/Log.h" 37344779Sdim#include "lldb/Utility/RegisterValue.h" 38321369Sdim#include "lldb/Utility/RegularExpression.h" 39321369Sdim#include "lldb/Utility/Status.h" 40285101Semaste 41353358Sdim#include "llvm/ADT/StringSwitch.h" 42353358Sdim 43353358Sdim#include <memory> 44353358Sdim 45285101Semasteusing namespace lldb; 46285101Semasteusing namespace lldb_private; 47296417Sdimusing namespace lldb_renderscript; 48285101Semaste 49314564Sdim#define FMT_COORD "(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")" 50296417Sdim 51353358Sdimchar RenderScriptRuntime::ID = 0; 52353358Sdim 53314564Sdimnamespace { 54314564Sdim 55296417Sdim// The empirical_type adds a basic level of validation to arbitrary data 56314564Sdim// allowing us to track if data has been discovered and stored or not. An 57314564Sdim// empirical_type will be marked as valid only if it has been explicitly 58314564Sdim// assigned to. 59314564Sdimtemplate <typename type_t> class empirical_type { 60296417Sdimpublic: 61314564Sdim // Ctor. Contents is invalid when constructed. 62314564Sdim empirical_type() : valid(false) {} 63296417Sdim 64314564Sdim // Return true and copy contents to out if valid, else return false. 65314564Sdim bool get(type_t &out) const { 66314564Sdim if (valid) 67314564Sdim out = data; 68314564Sdim return valid; 69314564Sdim } 70296417Sdim 71314564Sdim // Return a pointer to the contents or nullptr if it was not valid. 72314564Sdim const type_t *get() const { return valid ? &data : nullptr; } 73296417Sdim 74314564Sdim // Assign data explicitly. 75314564Sdim void set(const type_t in) { 76314564Sdim data = in; 77314564Sdim valid = true; 78314564Sdim } 79296417Sdim 80314564Sdim // Mark contents as invalid. 81314564Sdim void invalidate() { valid = false; } 82296417Sdim 83314564Sdim // Returns true if this type contains valid data. 84314564Sdim bool isValid() const { return valid; } 85296417Sdim 86314564Sdim // Assignment operator. 87314564Sdim empirical_type<type_t> &operator=(const type_t in) { 88314564Sdim set(in); 89314564Sdim return *this; 90314564Sdim } 91296417Sdim 92314564Sdim // Dereference operator returns contents. 93314564Sdim // Warning: Will assert if not valid so use only when you know data is valid. 94314564Sdim const type_t &operator*() const { 95314564Sdim assert(valid); 96314564Sdim return data; 97314564Sdim } 98296417Sdim 99296417Sdimprotected: 100314564Sdim bool valid; 101314564Sdim type_t data; 102296417Sdim}; 103296417Sdim 104314564Sdim// ArgItem is used by the GetArgs() function when reading function arguments 105314564Sdim// from the target. 106314564Sdimstruct ArgItem { 107314564Sdim enum { ePointer, eInt32, eInt64, eLong, eBool } type; 108309124Sdim 109314564Sdim uint64_t value; 110309124Sdim 111314564Sdim explicit operator uint64_t() const { return value; } 112309124Sdim}; 113309124Sdim 114314564Sdim// Context structure to be passed into GetArgsXXX(), argument reading functions 115314564Sdim// below. 116314564Sdimstruct GetArgsCtx { 117314564Sdim RegisterContext *reg_ctx; 118314564Sdim Process *process; 119309124Sdim}; 120309124Sdim 121314564Sdimbool GetArgsX86(const GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 122314564Sdim Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 123309124Sdim 124321369Sdim Status err; 125309124Sdim 126314564Sdim // get the current stack pointer 127314564Sdim uint64_t sp = ctx.reg_ctx->GetSP(); 128309124Sdim 129314564Sdim for (size_t i = 0; i < num_args; ++i) { 130314564Sdim ArgItem &arg = arg_list[i]; 131314564Sdim // advance up the stack by one argument 132314564Sdim sp += sizeof(uint32_t); 133314564Sdim // get the argument type size 134314564Sdim size_t arg_size = sizeof(uint32_t); 135314564Sdim // read the argument from memory 136314564Sdim arg.value = 0; 137321369Sdim Status err; 138314564Sdim size_t read = 139314564Sdim ctx.process->ReadMemory(sp, &arg.value, sizeof(uint32_t), err); 140314564Sdim if (read != arg_size || !err.Success()) { 141360784Sdim LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 " '%s'", 142360784Sdim __FUNCTION__, uint64_t(i), err.AsCString()); 143314564Sdim return false; 144309124Sdim } 145314564Sdim } 146314564Sdim return true; 147309124Sdim} 148309124Sdim 149314564Sdimbool GetArgsX86_64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 150314564Sdim Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 151309124Sdim 152314564Sdim // number of arguments passed in registers 153314564Sdim static const uint32_t args_in_reg = 6; 154314564Sdim // register passing order 155314564Sdim static const std::array<const char *, args_in_reg> reg_names{ 156314564Sdim {"rdi", "rsi", "rdx", "rcx", "r8", "r9"}}; 157314564Sdim // argument type to size mapping 158314564Sdim static const std::array<size_t, 5> arg_size{{ 159314564Sdim 8, // ePointer, 160314564Sdim 4, // eInt32, 161314564Sdim 8, // eInt64, 162314564Sdim 8, // eLong, 163314564Sdim 4, // eBool, 164314564Sdim }}; 165309124Sdim 166321369Sdim Status err; 167309124Sdim 168314564Sdim // get the current stack pointer 169314564Sdim uint64_t sp = ctx.reg_ctx->GetSP(); 170314564Sdim // step over the return address 171314564Sdim sp += sizeof(uint64_t); 172309124Sdim 173314564Sdim // check the stack alignment was correct (16 byte aligned) 174314564Sdim if ((sp & 0xf) != 0x0) { 175360784Sdim LLDB_LOGF(log, "%s - stack misaligned", __FUNCTION__); 176314564Sdim return false; 177314564Sdim } 178309124Sdim 179314564Sdim // find the start of arguments on the stack 180314564Sdim uint64_t sp_offset = 0; 181314564Sdim for (uint32_t i = args_in_reg; i < num_args; ++i) { 182314564Sdim sp_offset += arg_size[arg_list[i].type]; 183314564Sdim } 184314564Sdim // round up to multiple of 16 185314564Sdim sp_offset = (sp_offset + 0xf) & 0xf; 186314564Sdim sp += sp_offset; 187309124Sdim 188314564Sdim for (size_t i = 0; i < num_args; ++i) { 189314564Sdim bool success = false; 190314564Sdim ArgItem &arg = arg_list[i]; 191314564Sdim // arguments passed in registers 192314564Sdim if (i < args_in_reg) { 193314564Sdim const RegisterInfo *reg = 194314564Sdim ctx.reg_ctx->GetRegisterInfoByName(reg_names[i]); 195314564Sdim RegisterValue reg_val; 196314564Sdim if (ctx.reg_ctx->ReadRegister(reg, reg_val)) 197314564Sdim arg.value = reg_val.GetAsUInt64(0, &success); 198309124Sdim } 199314564Sdim // arguments passed on the stack 200314564Sdim else { 201314564Sdim // get the argument type size 202314564Sdim const size_t size = arg_size[arg_list[i].type]; 203314564Sdim // read the argument from memory 204314564Sdim arg.value = 0; 205314564Sdim // note: due to little endian layout reading 4 or 8 bytes will give the 206314564Sdim // correct value. 207314564Sdim size_t read = ctx.process->ReadMemory(sp, &arg.value, size, err); 208314564Sdim success = (err.Success() && read == size); 209314564Sdim // advance past this argument 210314564Sdim sp -= size; 211314564Sdim } 212314564Sdim // fail if we couldn't read this argument 213314564Sdim if (!success) { 214360784Sdim LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s", 215360784Sdim __FUNCTION__, uint64_t(i), err.AsCString("n/a")); 216314564Sdim return false; 217314564Sdim } 218314564Sdim } 219314564Sdim return true; 220309124Sdim} 221309124Sdim 222314564Sdimbool GetArgsArm(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 223314564Sdim // number of arguments passed in registers 224314564Sdim static const uint32_t args_in_reg = 4; 225309124Sdim 226314564Sdim Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 227309124Sdim 228321369Sdim Status err; 229309124Sdim 230314564Sdim // get the current stack pointer 231314564Sdim uint64_t sp = ctx.reg_ctx->GetSP(); 232309124Sdim 233314564Sdim for (size_t i = 0; i < num_args; ++i) { 234314564Sdim bool success = false; 235314564Sdim ArgItem &arg = arg_list[i]; 236314564Sdim // arguments passed in registers 237314564Sdim if (i < args_in_reg) { 238314564Sdim const RegisterInfo *reg = ctx.reg_ctx->GetRegisterInfoAtIndex(i); 239314564Sdim RegisterValue reg_val; 240314564Sdim if (ctx.reg_ctx->ReadRegister(reg, reg_val)) 241314564Sdim arg.value = reg_val.GetAsUInt32(0, &success); 242309124Sdim } 243314564Sdim // arguments passed on the stack 244314564Sdim else { 245314564Sdim // get the argument type size 246314564Sdim const size_t arg_size = sizeof(uint32_t); 247314564Sdim // clear all 64bits 248314564Sdim arg.value = 0; 249314564Sdim // read this argument from memory 250314564Sdim size_t bytes_read = 251314564Sdim ctx.process->ReadMemory(sp, &arg.value, arg_size, err); 252314564Sdim success = (err.Success() && bytes_read == arg_size); 253314564Sdim // advance the stack pointer 254314564Sdim sp += sizeof(uint32_t); 255314564Sdim } 256314564Sdim // fail if we couldn't read this argument 257314564Sdim if (!success) { 258360784Sdim LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s", 259360784Sdim __FUNCTION__, uint64_t(i), err.AsCString("n/a")); 260314564Sdim return false; 261314564Sdim } 262314564Sdim } 263314564Sdim return true; 264309124Sdim} 265309124Sdim 266314564Sdimbool GetArgsAarch64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 267314564Sdim // number of arguments passed in registers 268314564Sdim static const uint32_t args_in_reg = 8; 269309124Sdim 270314564Sdim Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 271309124Sdim 272314564Sdim for (size_t i = 0; i < num_args; ++i) { 273314564Sdim bool success = false; 274314564Sdim ArgItem &arg = arg_list[i]; 275314564Sdim // arguments passed in registers 276314564Sdim if (i < args_in_reg) { 277314564Sdim const RegisterInfo *reg = ctx.reg_ctx->GetRegisterInfoAtIndex(i); 278314564Sdim RegisterValue reg_val; 279314564Sdim if (ctx.reg_ctx->ReadRegister(reg, reg_val)) 280314564Sdim arg.value = reg_val.GetAsUInt64(0, &success); 281309124Sdim } 282314564Sdim // arguments passed on the stack 283314564Sdim else { 284360784Sdim LLDB_LOGF(log, "%s - reading arguments spilled to stack not implemented", 285360784Sdim __FUNCTION__); 286314564Sdim } 287314564Sdim // fail if we couldn't read this argument 288314564Sdim if (!success) { 289360784Sdim LLDB_LOGF(log, "%s - error reading argument: %" PRIu64, __FUNCTION__, 290360784Sdim uint64_t(i)); 291314564Sdim return false; 292314564Sdim } 293314564Sdim } 294314564Sdim return true; 295309124Sdim} 296309124Sdim 297314564Sdimbool GetArgsMipsel(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 298314564Sdim // number of arguments passed in registers 299314564Sdim static const uint32_t args_in_reg = 4; 300314564Sdim // register file offset to first argument 301314564Sdim static const uint32_t reg_offset = 4; 302309124Sdim 303314564Sdim Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 304309124Sdim 305321369Sdim Status err; 306309124Sdim 307341825Sdim // find offset to arguments on the stack (+16 to skip over a0-a3 shadow 308341825Sdim // space) 309314564Sdim uint64_t sp = ctx.reg_ctx->GetSP() + 16; 310309124Sdim 311314564Sdim for (size_t i = 0; i < num_args; ++i) { 312314564Sdim bool success = false; 313314564Sdim ArgItem &arg = arg_list[i]; 314314564Sdim // arguments passed in registers 315314564Sdim if (i < args_in_reg) { 316314564Sdim const RegisterInfo *reg = 317314564Sdim ctx.reg_ctx->GetRegisterInfoAtIndex(i + reg_offset); 318314564Sdim RegisterValue reg_val; 319314564Sdim if (ctx.reg_ctx->ReadRegister(reg, reg_val)) 320314564Sdim arg.value = reg_val.GetAsUInt64(0, &success); 321309124Sdim } 322314564Sdim // arguments passed on the stack 323314564Sdim else { 324314564Sdim const size_t arg_size = sizeof(uint32_t); 325314564Sdim arg.value = 0; 326314564Sdim size_t bytes_read = 327314564Sdim ctx.process->ReadMemory(sp, &arg.value, arg_size, err); 328314564Sdim success = (err.Success() && bytes_read == arg_size); 329314564Sdim // advance the stack pointer 330314564Sdim sp += arg_size; 331314564Sdim } 332314564Sdim // fail if we couldn't read this argument 333314564Sdim if (!success) { 334360784Sdim LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s", 335360784Sdim __FUNCTION__, uint64_t(i), err.AsCString("n/a")); 336314564Sdim return false; 337314564Sdim } 338314564Sdim } 339314564Sdim return true; 340309124Sdim} 341309124Sdim 342314564Sdimbool GetArgsMips64el(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 343314564Sdim // number of arguments passed in registers 344314564Sdim static const uint32_t args_in_reg = 8; 345314564Sdim // register file offset to first argument 346314564Sdim static const uint32_t reg_offset = 4; 347309124Sdim 348314564Sdim Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 349309124Sdim 350321369Sdim Status err; 351309124Sdim 352314564Sdim // get the current stack pointer 353314564Sdim uint64_t sp = ctx.reg_ctx->GetSP(); 354309124Sdim 355314564Sdim for (size_t i = 0; i < num_args; ++i) { 356314564Sdim bool success = false; 357314564Sdim ArgItem &arg = arg_list[i]; 358314564Sdim // arguments passed in registers 359314564Sdim if (i < args_in_reg) { 360314564Sdim const RegisterInfo *reg = 361314564Sdim ctx.reg_ctx->GetRegisterInfoAtIndex(i + reg_offset); 362314564Sdim RegisterValue reg_val; 363314564Sdim if (ctx.reg_ctx->ReadRegister(reg, reg_val)) 364314564Sdim arg.value = reg_val.GetAsUInt64(0, &success); 365309124Sdim } 366314564Sdim // arguments passed on the stack 367314564Sdim else { 368314564Sdim // get the argument type size 369314564Sdim const size_t arg_size = sizeof(uint64_t); 370314564Sdim // clear all 64bits 371314564Sdim arg.value = 0; 372314564Sdim // read this argument from memory 373314564Sdim size_t bytes_read = 374314564Sdim ctx.process->ReadMemory(sp, &arg.value, arg_size, err); 375314564Sdim success = (err.Success() && bytes_read == arg_size); 376314564Sdim // advance the stack pointer 377314564Sdim sp += arg_size; 378314564Sdim } 379314564Sdim // fail if we couldn't read this argument 380314564Sdim if (!success) { 381360784Sdim LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s", 382360784Sdim __FUNCTION__, uint64_t(i), err.AsCString("n/a")); 383314564Sdim return false; 384314564Sdim } 385314564Sdim } 386314564Sdim return true; 387309124Sdim} 388309124Sdim 389314564Sdimbool GetArgs(ExecutionContext &exe_ctx, ArgItem *arg_list, size_t num_args) { 390314564Sdim Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 391309124Sdim 392314564Sdim // verify that we have a target 393314564Sdim if (!exe_ctx.GetTargetPtr()) { 394360784Sdim LLDB_LOGF(log, "%s - invalid target", __FUNCTION__); 395314564Sdim return false; 396314564Sdim } 397314564Sdim 398314564Sdim GetArgsCtx ctx = {exe_ctx.GetRegisterContext(), exe_ctx.GetProcessPtr()}; 399314564Sdim assert(ctx.reg_ctx && ctx.process); 400314564Sdim 401314564Sdim // dispatch based on architecture 402314564Sdim switch (exe_ctx.GetTargetPtr()->GetArchitecture().GetMachine()) { 403314564Sdim case llvm::Triple::ArchType::x86: 404314564Sdim return GetArgsX86(ctx, arg_list, num_args); 405314564Sdim 406314564Sdim case llvm::Triple::ArchType::x86_64: 407314564Sdim return GetArgsX86_64(ctx, arg_list, num_args); 408314564Sdim 409314564Sdim case llvm::Triple::ArchType::arm: 410314564Sdim return GetArgsArm(ctx, arg_list, num_args); 411314564Sdim 412314564Sdim case llvm::Triple::ArchType::aarch64: 413314564Sdim return GetArgsAarch64(ctx, arg_list, num_args); 414314564Sdim 415314564Sdim case llvm::Triple::ArchType::mipsel: 416314564Sdim return GetArgsMipsel(ctx, arg_list, num_args); 417314564Sdim 418314564Sdim case llvm::Triple::ArchType::mips64el: 419314564Sdim return GetArgsMips64el(ctx, arg_list, num_args); 420314564Sdim 421314564Sdim default: 422314564Sdim // unsupported architecture 423314564Sdim if (log) { 424360784Sdim LLDB_LOGF(log, "%s - architecture not supported: '%s'", __FUNCTION__, 425360784Sdim exe_ctx.GetTargetRef().GetArchitecture().GetArchitectureName()); 426309124Sdim } 427314564Sdim return false; 428314564Sdim } 429314564Sdim} 430309124Sdim 431314564Sdimbool IsRenderScriptScriptModule(ModuleSP module) { 432314564Sdim if (!module) 433314564Sdim return false; 434314564Sdim return module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), 435314564Sdim eSymbolTypeData) != nullptr; 436314564Sdim} 437309124Sdim 438314564Sdimbool ParseCoordinate(llvm::StringRef coord_s, RSCoordinate &coord) { 439341825Sdim // takes an argument of the form 'num[,num][,num]'. Where 'coord_s' is a 440341825Sdim // comma separated 1,2 or 3-dimensional coordinate with the whitespace 441341825Sdim // trimmed. Missing coordinates are defaulted to zero. If parsing of any 442341825Sdim // elements fails the contents of &coord are undefined and `false` is 443341825Sdim // returned, `true` otherwise 444309124Sdim 445360784Sdim llvm::SmallVector<llvm::StringRef, 4> matches; 446309124Sdim 447360784Sdim if (!RegularExpression("^([0-9]+),([0-9]+),([0-9]+)$") 448360784Sdim .Execute(coord_s, &matches) && 449360784Sdim !RegularExpression("^([0-9]+),([0-9]+)$").Execute(coord_s, &matches) && 450360784Sdim !RegularExpression("^([0-9]+)$").Execute(coord_s, &matches)) 451314564Sdim return false; 452309124Sdim 453360784Sdim auto get_index = [&](size_t idx, uint32_t &i) -> bool { 454314564Sdim std::string group; 455314564Sdim errno = 0; 456360784Sdim if (idx + 1 < matches.size()) { 457360784Sdim return !llvm::StringRef(matches[idx + 1]).getAsInteger<uint32_t>(10, i); 458360784Sdim } 459314564Sdim return true; 460314564Sdim }; 461309124Sdim 462314564Sdim return get_index(0, coord.x) && get_index(1, coord.y) && 463314564Sdim get_index(2, coord.z); 464314564Sdim} 465309124Sdim 466314564Sdimbool SkipPrologue(lldb::ModuleSP &module, Address &addr) { 467314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 468314564Sdim SymbolContext sc; 469314564Sdim uint32_t resolved_flags = 470314564Sdim module->ResolveSymbolContextForAddress(addr, eSymbolContextFunction, sc); 471314564Sdim if (resolved_flags & eSymbolContextFunction) { 472314564Sdim if (sc.function) { 473314564Sdim const uint32_t offset = sc.function->GetPrologueByteSize(); 474314564Sdim ConstString name = sc.GetFunctionName(); 475314564Sdim if (offset) 476314564Sdim addr.Slide(offset); 477360784Sdim LLDB_LOGF(log, "%s: Prologue offset for %s is %" PRIu32, __FUNCTION__, 478360784Sdim name.AsCString(), offset); 479309124Sdim } 480314564Sdim return true; 481314564Sdim } else 482314564Sdim return false; 483309124Sdim} 484296417Sdim} // anonymous namespace 485296417Sdim 486314564Sdim// The ScriptDetails class collects data associated with a single script 487314564Sdim// instance. 488314564Sdimstruct RenderScriptRuntime::ScriptDetails { 489314564Sdim ~ScriptDetails() = default; 490296417Sdim 491314564Sdim enum ScriptType { eScript, eScriptC }; 492296417Sdim 493314564Sdim // The derived type of the script. 494314564Sdim empirical_type<ScriptType> type; 495314564Sdim // The name of the original source file. 496314564Sdim empirical_type<std::string> res_name; 497314564Sdim // Path to script .so file on the device. 498314564Sdim empirical_type<std::string> shared_lib; 499314564Sdim // Directory where kernel objects are cached on device. 500314564Sdim empirical_type<std::string> cache_dir; 501314564Sdim // Pointer to the context which owns this script. 502314564Sdim empirical_type<lldb::addr_t> context; 503314564Sdim // Pointer to the script object itself. 504314564Sdim empirical_type<lldb::addr_t> script; 505296417Sdim}; 506296417Sdim 507314564Sdim// This Element class represents the Element object in RS, defining the type 508314564Sdim// associated with an Allocation. 509314564Sdimstruct RenderScriptRuntime::Element { 510314564Sdim // Taken from rsDefines.h 511314564Sdim enum DataKind { 512314564Sdim RS_KIND_USER, 513314564Sdim RS_KIND_PIXEL_L = 7, 514314564Sdim RS_KIND_PIXEL_A, 515314564Sdim RS_KIND_PIXEL_LA, 516314564Sdim RS_KIND_PIXEL_RGB, 517314564Sdim RS_KIND_PIXEL_RGBA, 518314564Sdim RS_KIND_PIXEL_DEPTH, 519314564Sdim RS_KIND_PIXEL_YUV, 520314564Sdim RS_KIND_INVALID = 100 521314564Sdim }; 522296417Sdim 523314564Sdim // Taken from rsDefines.h 524314564Sdim enum DataType { 525314564Sdim RS_TYPE_NONE = 0, 526314564Sdim RS_TYPE_FLOAT_16, 527314564Sdim RS_TYPE_FLOAT_32, 528314564Sdim RS_TYPE_FLOAT_64, 529314564Sdim RS_TYPE_SIGNED_8, 530314564Sdim RS_TYPE_SIGNED_16, 531314564Sdim RS_TYPE_SIGNED_32, 532314564Sdim RS_TYPE_SIGNED_64, 533314564Sdim RS_TYPE_UNSIGNED_8, 534314564Sdim RS_TYPE_UNSIGNED_16, 535314564Sdim RS_TYPE_UNSIGNED_32, 536314564Sdim RS_TYPE_UNSIGNED_64, 537314564Sdim RS_TYPE_BOOLEAN, 538296417Sdim 539314564Sdim RS_TYPE_UNSIGNED_5_6_5, 540314564Sdim RS_TYPE_UNSIGNED_5_5_5_1, 541314564Sdim RS_TYPE_UNSIGNED_4_4_4_4, 542296417Sdim 543314564Sdim RS_TYPE_MATRIX_4X4, 544314564Sdim RS_TYPE_MATRIX_3X3, 545314564Sdim RS_TYPE_MATRIX_2X2, 546296417Sdim 547314564Sdim RS_TYPE_ELEMENT = 1000, 548314564Sdim RS_TYPE_TYPE, 549314564Sdim RS_TYPE_ALLOCATION, 550314564Sdim RS_TYPE_SAMPLER, 551314564Sdim RS_TYPE_SCRIPT, 552314564Sdim RS_TYPE_MESH, 553314564Sdim RS_TYPE_PROGRAM_FRAGMENT, 554314564Sdim RS_TYPE_PROGRAM_VERTEX, 555314564Sdim RS_TYPE_PROGRAM_RASTER, 556314564Sdim RS_TYPE_PROGRAM_STORE, 557314564Sdim RS_TYPE_FONT, 558296417Sdim 559314564Sdim RS_TYPE_INVALID = 10000 560314564Sdim }; 561296417Sdim 562314564Sdim std::vector<Element> children; // Child Element fields for structs 563314564Sdim empirical_type<lldb::addr_t> 564314564Sdim element_ptr; // Pointer to the RS Element of the Type 565314564Sdim empirical_type<DataType> 566314564Sdim type; // Type of each data pointer stored by the allocation 567314564Sdim empirical_type<DataKind> 568314564Sdim type_kind; // Defines pixel type if Allocation is created from an image 569314564Sdim empirical_type<uint32_t> 570314564Sdim type_vec_size; // Vector size of each data point, e.g '4' for uchar4 571314564Sdim empirical_type<uint32_t> field_count; // Number of Subelements 572314564Sdim empirical_type<uint32_t> datum_size; // Size of a single Element with padding 573314564Sdim empirical_type<uint32_t> padding; // Number of padding bytes 574314564Sdim empirical_type<uint32_t> 575341825Sdim array_size; // Number of items in array, only needed for structs 576314564Sdim ConstString type_name; // Name of type, only needed for structs 577296417Sdim 578353358Sdim static ConstString 579314564Sdim GetFallbackStructName(); // Print this as the type name of a struct Element 580314564Sdim // If we can't resolve the actual struct name 581296417Sdim 582314564Sdim bool ShouldRefresh() const { 583314564Sdim const bool valid_ptr = element_ptr.isValid() && *element_ptr.get() != 0x0; 584314564Sdim const bool valid_type = 585314564Sdim type.isValid() && type_vec_size.isValid() && type_kind.isValid(); 586314564Sdim return !valid_ptr || !valid_type || !datum_size.isValid(); 587314564Sdim } 588296417Sdim}; 589296417Sdim 590296417Sdim// This AllocationDetails class collects data associated with a single 591296417Sdim// allocation instance. 592314564Sdimstruct RenderScriptRuntime::AllocationDetails { 593314564Sdim struct Dimension { 594314564Sdim uint32_t dim_1; 595314564Sdim uint32_t dim_2; 596314564Sdim uint32_t dim_3; 597314564Sdim uint32_t cube_map; 598296417Sdim 599314564Sdim Dimension() { 600314564Sdim dim_1 = 0; 601314564Sdim dim_2 = 0; 602314564Sdim dim_3 = 0; 603314564Sdim cube_map = 0; 604314564Sdim } 605314564Sdim }; 606296417Sdim 607314564Sdim // The FileHeader struct specifies the header we use for writing allocations 608314564Sdim // to a binary file. Our format begins with the ASCII characters "RSAD", 609314564Sdim // identifying the file as an allocation dump. Member variables dims and 610314564Sdim // hdr_size are then written consecutively, immediately followed by an 611314564Sdim // instance of the ElementHeader struct. Because Elements can contain 612314564Sdim // subelements, there may be more than one instance of the ElementHeader 613314564Sdim // struct. With this first instance being the root element, and the other 614314564Sdim // instances being the root's descendants. To identify which instances are an 615341825Sdim // ElementHeader's children, each struct is immediately followed by a 616341825Sdim // sequence of consecutive offsets to the start of its child structs. These 617341825Sdim // offsets are 618314564Sdim // 4 bytes in size, and the 0 offset signifies no more children. 619314564Sdim struct FileHeader { 620314564Sdim uint8_t ident[4]; // ASCII 'RSAD' identifying the file 621314564Sdim uint32_t dims[3]; // Dimensions 622314564Sdim uint16_t hdr_size; // Header size in bytes, including all element headers 623314564Sdim }; 624296417Sdim 625314564Sdim struct ElementHeader { 626314564Sdim uint16_t type; // DataType enum 627314564Sdim uint32_t kind; // DataKind enum 628314564Sdim uint32_t element_size; // Size of a single element, including padding 629314564Sdim uint16_t vector_size; // Vector width 630314564Sdim uint32_t array_size; // Number of elements in array 631314564Sdim }; 632296417Sdim 633314564Sdim // Monotonically increasing from 1 634314564Sdim static uint32_t ID; 635296417Sdim 636341825Sdim // Maps Allocation DataType enum and vector size to printable strings using 637341825Sdim // mapping from RenderScript numerical types summary documentation 638314564Sdim static const char *RsDataTypeToString[][4]; 639296417Sdim 640314564Sdim // Maps Allocation DataKind enum to printable strings 641314564Sdim static const char *RsDataKindToString[]; 642296417Sdim 643314564Sdim // Maps allocation types to format sizes for printing. 644314564Sdim static const uint32_t RSTypeToFormat[][3]; 645296417Sdim 646314564Sdim // Give each allocation an ID as a way 647314564Sdim // for commands to reference it. 648314564Sdim const uint32_t id; 649296417Sdim 650314564Sdim // Allocation Element type 651314564Sdim RenderScriptRuntime::Element element; 652314564Sdim // Dimensions of the Allocation 653314564Sdim empirical_type<Dimension> dimension; 654314564Sdim // Pointer to address of the RS Allocation 655314564Sdim empirical_type<lldb::addr_t> address; 656314564Sdim // Pointer to the data held by the Allocation 657314564Sdim empirical_type<lldb::addr_t> data_ptr; 658314564Sdim // Pointer to the RS Type of the Allocation 659314564Sdim empirical_type<lldb::addr_t> type_ptr; 660314564Sdim // Pointer to the RS Context of the Allocation 661314564Sdim empirical_type<lldb::addr_t> context; 662314564Sdim // Size of the allocation 663314564Sdim empirical_type<uint32_t> size; 664314564Sdim // Stride between rows of the allocation 665314564Sdim empirical_type<uint32_t> stride; 666296417Sdim 667314564Sdim // Give each allocation an id, so we can reference it in user commands. 668314564Sdim AllocationDetails() : id(ID++) {} 669296417Sdim 670314564Sdim bool ShouldRefresh() const { 671314564Sdim bool valid_ptrs = data_ptr.isValid() && *data_ptr.get() != 0x0; 672314564Sdim valid_ptrs = valid_ptrs && type_ptr.isValid() && *type_ptr.get() != 0x0; 673314564Sdim return !valid_ptrs || !dimension.isValid() || !size.isValid() || 674314564Sdim element.ShouldRefresh(); 675314564Sdim } 676296417Sdim}; 677296417Sdim 678353358SdimConstString RenderScriptRuntime::Element::GetFallbackStructName() { 679314564Sdim static const ConstString FallbackStructName("struct"); 680314564Sdim return FallbackStructName; 681296417Sdim} 682296417Sdim 683309124Sdimuint32_t RenderScriptRuntime::AllocationDetails::ID = 1; 684296417Sdim 685309124Sdimconst char *RenderScriptRuntime::AllocationDetails::RsDataKindToString[] = { 686314564Sdim "User", "Undefined", "Undefined", "Undefined", 687314564Sdim "Undefined", "Undefined", "Undefined", // Enum jumps from 0 to 7 688309124Sdim "L Pixel", "A Pixel", "LA Pixel", "RGB Pixel", 689309124Sdim "RGBA Pixel", "Pixel Depth", "YUV Pixel"}; 690296417Sdim 691309124Sdimconst char *RenderScriptRuntime::AllocationDetails::RsDataTypeToString[][4] = { 692296417Sdim {"None", "None", "None", "None"}, 693296417Sdim {"half", "half2", "half3", "half4"}, 694296417Sdim {"float", "float2", "float3", "float4"}, 695296417Sdim {"double", "double2", "double3", "double4"}, 696296417Sdim {"char", "char2", "char3", "char4"}, 697296417Sdim {"short", "short2", "short3", "short4"}, 698296417Sdim {"int", "int2", "int3", "int4"}, 699296417Sdim {"long", "long2", "long3", "long4"}, 700296417Sdim {"uchar", "uchar2", "uchar3", "uchar4"}, 701296417Sdim {"ushort", "ushort2", "ushort3", "ushort4"}, 702296417Sdim {"uint", "uint2", "uint3", "uint4"}, 703296417Sdim {"ulong", "ulong2", "ulong3", "ulong4"}, 704296417Sdim {"bool", "bool2", "bool3", "bool4"}, 705296417Sdim {"packed_565", "packed_565", "packed_565", "packed_565"}, 706296417Sdim {"packed_5551", "packed_5551", "packed_5551", "packed_5551"}, 707296417Sdim {"packed_4444", "packed_4444", "packed_4444", "packed_4444"}, 708296417Sdim {"rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4"}, 709296417Sdim {"rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3"}, 710296417Sdim {"rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2"}, 711296417Sdim 712296417Sdim // Handlers 713296417Sdim {"RS Element", "RS Element", "RS Element", "RS Element"}, 714296417Sdim {"RS Type", "RS Type", "RS Type", "RS Type"}, 715296417Sdim {"RS Allocation", "RS Allocation", "RS Allocation", "RS Allocation"}, 716296417Sdim {"RS Sampler", "RS Sampler", "RS Sampler", "RS Sampler"}, 717296417Sdim {"RS Script", "RS Script", "RS Script", "RS Script"}, 718296417Sdim 719296417Sdim // Deprecated 720296417Sdim {"RS Mesh", "RS Mesh", "RS Mesh", "RS Mesh"}, 721314564Sdim {"RS Program Fragment", "RS Program Fragment", "RS Program Fragment", 722314564Sdim "RS Program Fragment"}, 723314564Sdim {"RS Program Vertex", "RS Program Vertex", "RS Program Vertex", 724314564Sdim "RS Program Vertex"}, 725314564Sdim {"RS Program Raster", "RS Program Raster", "RS Program Raster", 726314564Sdim "RS Program Raster"}, 727314564Sdim {"RS Program Store", "RS Program Store", "RS Program Store", 728314564Sdim "RS Program Store"}, 729309124Sdim {"RS Font", "RS Font", "RS Font", "RS Font"}}; 730296417Sdim 731296417Sdim// Used as an index into the RSTypeToFormat array elements 732314564Sdimenum TypeToFormatIndex { eFormatSingle = 0, eFormatVector, eElementSize }; 733296417Sdim 734314564Sdim// { format enum of single element, format enum of element vector, size of 735314564Sdim// element} 736309124Sdimconst uint32_t RenderScriptRuntime::AllocationDetails::RSTypeToFormat[][3] = { 737314564Sdim // RS_TYPE_NONE 738314564Sdim {eFormatHex, eFormatHex, 1}, 739314564Sdim // RS_TYPE_FLOAT_16 740314564Sdim {eFormatFloat, eFormatVectorOfFloat16, 2}, 741314564Sdim // RS_TYPE_FLOAT_32 742314564Sdim {eFormatFloat, eFormatVectorOfFloat32, sizeof(float)}, 743314564Sdim // RS_TYPE_FLOAT_64 744314564Sdim {eFormatFloat, eFormatVectorOfFloat64, sizeof(double)}, 745314564Sdim // RS_TYPE_SIGNED_8 746314564Sdim {eFormatDecimal, eFormatVectorOfSInt8, sizeof(int8_t)}, 747314564Sdim // RS_TYPE_SIGNED_16 748314564Sdim {eFormatDecimal, eFormatVectorOfSInt16, sizeof(int16_t)}, 749314564Sdim // RS_TYPE_SIGNED_32 750314564Sdim {eFormatDecimal, eFormatVectorOfSInt32, sizeof(int32_t)}, 751314564Sdim // RS_TYPE_SIGNED_64 752314564Sdim {eFormatDecimal, eFormatVectorOfSInt64, sizeof(int64_t)}, 753314564Sdim // RS_TYPE_UNSIGNED_8 754314564Sdim {eFormatDecimal, eFormatVectorOfUInt8, sizeof(uint8_t)}, 755314564Sdim // RS_TYPE_UNSIGNED_16 756314564Sdim {eFormatDecimal, eFormatVectorOfUInt16, sizeof(uint16_t)}, 757314564Sdim // RS_TYPE_UNSIGNED_32 758314564Sdim {eFormatDecimal, eFormatVectorOfUInt32, sizeof(uint32_t)}, 759314564Sdim // RS_TYPE_UNSIGNED_64 760314564Sdim {eFormatDecimal, eFormatVectorOfUInt64, sizeof(uint64_t)}, 761314564Sdim // RS_TYPE_BOOL 762314564Sdim {eFormatBoolean, eFormatBoolean, 1}, 763314564Sdim // RS_TYPE_UNSIGNED_5_6_5 764314564Sdim {eFormatHex, eFormatHex, sizeof(uint16_t)}, 765314564Sdim // RS_TYPE_UNSIGNED_5_5_5_1 766314564Sdim {eFormatHex, eFormatHex, sizeof(uint16_t)}, 767314564Sdim // RS_TYPE_UNSIGNED_4_4_4_4 768314564Sdim {eFormatHex, eFormatHex, sizeof(uint16_t)}, 769314564Sdim // RS_TYPE_MATRIX_4X4 770314564Sdim {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 16}, 771314564Sdim // RS_TYPE_MATRIX_3X3 772314564Sdim {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 9}, 773314564Sdim // RS_TYPE_MATRIX_2X2 774314564Sdim {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 4}}; 775296417Sdim 776285101Semaste// Static Functions 777285101SemasteLanguageRuntime * 778314564SdimRenderScriptRuntime::CreateInstance(Process *process, 779314564Sdim lldb::LanguageType language) { 780285101Semaste 781314564Sdim if (language == eLanguageTypeExtRenderScript) 782314564Sdim return new RenderScriptRuntime(process); 783314564Sdim else 784314564Sdim return nullptr; 785285101Semaste} 786285101Semaste 787314564Sdim// Callback with a module to search for matching symbols. We first check that 788314564Sdim// the module contains RS kernels. Then look for a symbol which matches our 789314564Sdim// kernel name. The breakpoint address is finally set using the address of this 790314564Sdim// symbol. 791296417SdimSearcher::CallbackReturn 792314564SdimRSBreakpointResolver::SearchCallback(SearchFilter &filter, 793360784Sdim SymbolContext &context, Address *) { 794314564Sdim ModuleSP module = context.module_sp; 795296417Sdim 796314564Sdim if (!module || !IsRenderScriptScriptModule(module)) 797314564Sdim return Searcher::eCallbackReturnContinue; 798296417Sdim 799314564Sdim // Attempt to set a breakpoint on the kernel name symbol within the module 800314564Sdim // library. If it's not found, it's likely debug info is unavailable - try to 801314564Sdim // set a breakpoint on <name>.expand. 802314564Sdim const Symbol *kernel_sym = 803314564Sdim module->FindFirstSymbolWithNameAndType(m_kernel_name, eSymbolTypeCode); 804314564Sdim if (!kernel_sym) { 805314564Sdim std::string kernel_name_expanded(m_kernel_name.AsCString()); 806314564Sdim kernel_name_expanded.append(".expand"); 807314564Sdim kernel_sym = module->FindFirstSymbolWithNameAndType( 808314564Sdim ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode); 809314564Sdim } 810296417Sdim 811314564Sdim if (kernel_sym) { 812314564Sdim Address bp_addr = kernel_sym->GetAddress(); 813314564Sdim if (filter.AddressPasses(bp_addr)) 814314564Sdim m_breakpoint->AddLocation(bp_addr); 815314564Sdim } 816296417Sdim 817314564Sdim return Searcher::eCallbackReturnContinue; 818314564Sdim} 819314564Sdim 820314564SdimSearcher::CallbackReturn 821314564SdimRSReduceBreakpointResolver::SearchCallback(lldb_private::SearchFilter &filter, 822314564Sdim lldb_private::SymbolContext &context, 823360784Sdim Address *) { 824314564Sdim // We need to have access to the list of reductions currently parsed, as 825341825Sdim // reduce names don't actually exist as symbols in a module. They are only 826341825Sdim // identifiable by parsing the .rs.info packet, or finding the expand symbol. 827341825Sdim // We therefore need access to the list of parsed rs modules to properly 828341825Sdim // resolve reduction names. 829314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); 830314564Sdim ModuleSP module = context.module_sp; 831314564Sdim 832314564Sdim if (!module || !IsRenderScriptScriptModule(module)) 833314564Sdim return Searcher::eCallbackReturnContinue; 834314564Sdim 835314564Sdim if (!m_rsmodules) 836314564Sdim return Searcher::eCallbackReturnContinue; 837314564Sdim 838314564Sdim for (const auto &module_desc : *m_rsmodules) { 839314564Sdim if (module_desc->m_module != module) 840314564Sdim continue; 841314564Sdim 842314564Sdim for (const auto &reduction : module_desc->m_reductions) { 843314564Sdim if (reduction.m_reduce_name != m_reduce_name) 844314564Sdim continue; 845314564Sdim 846314564Sdim std::array<std::pair<ConstString, int>, 5> funcs{ 847314564Sdim {{reduction.m_init_name, eKernelTypeInit}, 848314564Sdim {reduction.m_accum_name, eKernelTypeAccum}, 849314564Sdim {reduction.m_comb_name, eKernelTypeComb}, 850314564Sdim {reduction.m_outc_name, eKernelTypeOutC}, 851314564Sdim {reduction.m_halter_name, eKernelTypeHalter}}}; 852314564Sdim 853314564Sdim for (const auto &kernel : funcs) { 854314564Sdim // Skip constituent functions that don't match our spec 855314564Sdim if (!(m_kernel_types & kernel.second)) 856314564Sdim continue; 857314564Sdim 858314564Sdim const auto kernel_name = kernel.first; 859314564Sdim const auto symbol = module->FindFirstSymbolWithNameAndType( 860314564Sdim kernel_name, eSymbolTypeCode); 861314564Sdim if (!symbol) 862314564Sdim continue; 863314564Sdim 864314564Sdim auto address = symbol->GetAddress(); 865314564Sdim if (filter.AddressPasses(address)) { 866314564Sdim bool new_bp; 867314564Sdim if (!SkipPrologue(module, address)) { 868360784Sdim LLDB_LOGF(log, "%s: Error trying to skip prologue", __FUNCTION__); 869314564Sdim } 870314564Sdim m_breakpoint->AddLocation(address, &new_bp); 871360784Sdim LLDB_LOGF(log, "%s: %s reduction breakpoint on %s in %s", 872360784Sdim __FUNCTION__, new_bp ? "new" : "existing", 873360784Sdim kernel_name.GetCString(), 874360784Sdim address.GetModule()->GetFileSpec().GetCString()); 875314564Sdim } 876314564Sdim } 877296417Sdim } 878314564Sdim } 879314564Sdim return eCallbackReturnContinue; 880314564Sdim} 881296417Sdim 882314564SdimSearcher::CallbackReturn RSScriptGroupBreakpointResolver::SearchCallback( 883360784Sdim SearchFilter &filter, SymbolContext &context, Address *addr) { 884314564Sdim 885314564Sdim if (!m_breakpoint) 886314564Sdim return eCallbackReturnContinue; 887314564Sdim 888314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); 889314564Sdim ModuleSP &module = context.module_sp; 890314564Sdim 891314564Sdim if (!module || !IsRenderScriptScriptModule(module)) 892314564Sdim return Searcher::eCallbackReturnContinue; 893314564Sdim 894314564Sdim std::vector<std::string> names; 895314564Sdim m_breakpoint->GetNames(names); 896314564Sdim if (names.empty()) 897314564Sdim return eCallbackReturnContinue; 898314564Sdim 899314564Sdim for (auto &name : names) { 900314564Sdim const RSScriptGroupDescriptorSP sg = FindScriptGroup(ConstString(name)); 901314564Sdim if (!sg) { 902360784Sdim LLDB_LOGF(log, "%s: could not find script group for %s", __FUNCTION__, 903360784Sdim name.c_str()); 904314564Sdim continue; 905296417Sdim } 906296417Sdim 907360784Sdim LLDB_LOGF(log, "%s: Found ScriptGroup for %s", __FUNCTION__, name.c_str()); 908314564Sdim 909314564Sdim for (const RSScriptGroupDescriptor::Kernel &k : sg->m_kernels) { 910314564Sdim if (log) { 911360784Sdim LLDB_LOGF(log, "%s: Adding breakpoint for %s", __FUNCTION__, 912360784Sdim k.m_name.AsCString()); 913360784Sdim LLDB_LOGF(log, "%s: Kernel address 0x%" PRIx64, __FUNCTION__, k.m_addr); 914314564Sdim } 915314564Sdim 916314564Sdim const lldb_private::Symbol *sym = 917314564Sdim module->FindFirstSymbolWithNameAndType(k.m_name, eSymbolTypeCode); 918314564Sdim if (!sym) { 919360784Sdim LLDB_LOGF(log, "%s: Unable to find symbol for %s", __FUNCTION__, 920360784Sdim k.m_name.AsCString()); 921314564Sdim continue; 922314564Sdim } 923314564Sdim 924314564Sdim if (log) { 925360784Sdim LLDB_LOGF(log, "%s: Found symbol name is %s", __FUNCTION__, 926360784Sdim sym->GetName().AsCString()); 927314564Sdim } 928314564Sdim 929314564Sdim auto address = sym->GetAddress(); 930314564Sdim if (!SkipPrologue(module, address)) { 931360784Sdim LLDB_LOGF(log, "%s: Error trying to skip prologue", __FUNCTION__); 932314564Sdim } 933314564Sdim 934314564Sdim bool new_bp; 935314564Sdim m_breakpoint->AddLocation(address, &new_bp); 936314564Sdim 937360784Sdim LLDB_LOGF(log, "%s: Placed %sbreakpoint on %s", __FUNCTION__, 938360784Sdim new_bp ? "new " : "", k.m_name.AsCString()); 939314564Sdim 940341825Sdim // exit after placing the first breakpoint if we do not intend to stop on 941341825Sdim // all kernels making up this script group 942314564Sdim if (!m_stop_on_all) 943314564Sdim break; 944314564Sdim } 945314564Sdim } 946314564Sdim 947314564Sdim return eCallbackReturnContinue; 948296417Sdim} 949296417Sdim 950314564Sdimvoid RenderScriptRuntime::Initialize() { 951314564Sdim PluginManager::RegisterPlugin(GetPluginNameStatic(), 952314564Sdim "RenderScript language support", CreateInstance, 953314564Sdim GetCommandObject); 954285101Semaste} 955285101Semaste 956314564Sdimvoid RenderScriptRuntime::Terminate() { 957314564Sdim PluginManager::UnregisterPlugin(CreateInstance); 958285101Semaste} 959285101Semaste 960314564Sdimlldb_private::ConstString RenderScriptRuntime::GetPluginNameStatic() { 961314564Sdim static ConstString plugin_name("renderscript"); 962314564Sdim return plugin_name; 963285101Semaste} 964285101Semaste 965296417SdimRenderScriptRuntime::ModuleKind 966314564SdimRenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp) { 967314564Sdim if (module_sp) { 968314564Sdim if (IsRenderScriptScriptModule(module_sp)) 969314564Sdim return eModuleKindKernelObj; 970285101Semaste 971314564Sdim // Is this the main RS runtime library 972314564Sdim const ConstString rs_lib("libRS.so"); 973314564Sdim if (module_sp->GetFileSpec().GetFilename() == rs_lib) { 974314564Sdim return eModuleKindLibRS; 975314564Sdim } 976285101Semaste 977314564Sdim const ConstString rs_driverlib("libRSDriver.so"); 978314564Sdim if (module_sp->GetFileSpec().GetFilename() == rs_driverlib) { 979314564Sdim return eModuleKindDriver; 980314564Sdim } 981285101Semaste 982314564Sdim const ConstString rs_cpureflib("libRSCpuRef.so"); 983314564Sdim if (module_sp->GetFileSpec().GetFilename() == rs_cpureflib) { 984314564Sdim return eModuleKindImpl; 985285101Semaste } 986314564Sdim } 987314564Sdim return eModuleKindIgnored; 988285101Semaste} 989285101Semaste 990314564Sdimbool RenderScriptRuntime::IsRenderScriptModule( 991314564Sdim const lldb::ModuleSP &module_sp) { 992314564Sdim return GetModuleKind(module_sp) != eModuleKindIgnored; 993285101Semaste} 994285101Semaste 995314564Sdimvoid RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list) { 996314564Sdim std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); 997285101Semaste 998314564Sdim size_t num_modules = module_list.GetSize(); 999314564Sdim for (size_t i = 0; i < num_modules; i++) { 1000314564Sdim auto mod = module_list.GetModuleAtIndex(i); 1001314564Sdim if (IsRenderScriptModule(mod)) { 1002314564Sdim LoadModule(mod); 1003285101Semaste } 1004314564Sdim } 1005285101Semaste} 1006285101Semaste 1007285101Semaste// PluginInterface protocol 1008314564Sdimlldb_private::ConstString RenderScriptRuntime::GetPluginName() { 1009314564Sdim return GetPluginNameStatic(); 1010285101Semaste} 1011285101Semaste 1012314564Sdimuint32_t RenderScriptRuntime::GetPluginVersion() { return 1; } 1013285101Semaste 1014314564Sdimbool RenderScriptRuntime::GetDynamicTypeAndAddress( 1015314564Sdim ValueObject &in_value, lldb::DynamicValueType use_dynamic, 1016314564Sdim TypeAndOrName &class_type_or_name, Address &address, 1017314564Sdim Value::ValueType &value_type) { 1018314564Sdim return false; 1019285101Semaste} 1020285101Semaste 1021296417SdimTypeAndOrName 1022314564SdimRenderScriptRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, 1023314564Sdim ValueObject &static_value) { 1024314564Sdim return type_and_or_name; 1025296417Sdim} 1026296417Sdim 1027314564Sdimbool RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value) { 1028314564Sdim return false; 1029285101Semaste} 1030285101Semaste 1031285101Semastelldb::BreakpointResolverSP 1032314564SdimRenderScriptRuntime::CreateExceptionResolver(Breakpoint *bp, bool catch_bp, 1033314564Sdim bool throw_bp) { 1034314564Sdim BreakpointResolverSP resolver_sp; 1035314564Sdim return resolver_sp; 1036285101Semaste} 1037285101Semaste 1038314564Sdimconst RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] = 1039296417Sdim { 1040314564Sdim // rsdScript 1041314564Sdim {"rsdScriptInit", "_Z13rsdScriptInitPKN7android12renderscript7ContextEP" 1042314564Sdim "NS0_7ScriptCEPKcS7_PKhjj", 1043314564Sdim "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_" 1044314564Sdim "7ScriptCEPKcS7_PKhmj", 1045314564Sdim 0, RenderScriptRuntime::eModuleKindDriver, 1046314564Sdim &lldb_private::RenderScriptRuntime::CaptureScriptInit}, 1047314564Sdim {"rsdScriptInvokeForEachMulti", 1048314564Sdim "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0" 1049314564Sdim "_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall", 1050314564Sdim "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0" 1051314564Sdim "_6ScriptEjPPKNS0_10AllocationEmPS6_PKvmPK12RsScriptCall", 1052314564Sdim 0, RenderScriptRuntime::eModuleKindDriver, 1053314564Sdim &lldb_private::RenderScriptRuntime::CaptureScriptInvokeForEachMulti}, 1054314564Sdim {"rsdScriptSetGlobalVar", "_Z21rsdScriptSetGlobalVarPKN7android12render" 1055314564Sdim "script7ContextEPKNS0_6ScriptEjPvj", 1056314564Sdim "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_" 1057314564Sdim "6ScriptEjPvm", 1058314564Sdim 0, RenderScriptRuntime::eModuleKindDriver, 1059314564Sdim &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar}, 1060285101Semaste 1061314564Sdim // rsdAllocation 1062314564Sdim {"rsdAllocationInit", "_Z17rsdAllocationInitPKN7android12renderscript7C" 1063314564Sdim "ontextEPNS0_10AllocationEb", 1064314564Sdim "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_" 1065314564Sdim "10AllocationEb", 1066314564Sdim 0, RenderScriptRuntime::eModuleKindDriver, 1067314564Sdim &lldb_private::RenderScriptRuntime::CaptureAllocationInit}, 1068314564Sdim {"rsdAllocationRead2D", 1069314564Sdim "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_" 1070314564Sdim "10AllocationEjjj23RsAllocationCubemapFacejjPvjj", 1071314564Sdim "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_" 1072314564Sdim "10AllocationEjjj23RsAllocationCubemapFacejjPvmm", 1073314564Sdim 0, RenderScriptRuntime::eModuleKindDriver, nullptr}, 1074314564Sdim {"rsdAllocationDestroy", "_Z20rsdAllocationDestroyPKN7android12rendersc" 1075314564Sdim "ript7ContextEPNS0_10AllocationE", 1076314564Sdim "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_" 1077314564Sdim "10AllocationE", 1078314564Sdim 0, RenderScriptRuntime::eModuleKindDriver, 1079314564Sdim &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy}, 1080296417Sdim 1081314564Sdim // renderscript script groups 1082314564Sdim {"rsdDebugHintScriptGroup2", "_ZN7android12renderscript21debugHintScrip" 1083314564Sdim "tGroup2EPKcjPKPFvPK24RsExpandKernelDriver" 1084314564Sdim "InfojjjEj", 1085314564Sdim "_ZN7android12renderscript21debugHintScriptGroup2EPKcjPKPFvPK24RsExpan" 1086314564Sdim "dKernelDriverInfojjjEj", 1087314564Sdim 0, RenderScriptRuntime::eModuleKindImpl, 1088314564Sdim &lldb_private::RenderScriptRuntime::CaptureDebugHintScriptGroup2}}; 1089285101Semaste 1090314564Sdimconst size_t RenderScriptRuntime::s_runtimeHookCount = 1091314564Sdim sizeof(s_runtimeHookDefns) / sizeof(s_runtimeHookDefns[0]); 1092285101Semaste 1093314564Sdimbool RenderScriptRuntime::HookCallback(void *baton, 1094314564Sdim StoppointCallbackContext *ctx, 1095314564Sdim lldb::user_id_t break_id, 1096314564Sdim lldb::user_id_t break_loc_id) { 1097314564Sdim RuntimeHook *hook = (RuntimeHook *)baton; 1098314564Sdim ExecutionContext exe_ctx(ctx->exe_ctx_ref); 1099285101Semaste 1100353358Sdim RenderScriptRuntime *lang_rt = llvm::cast<RenderScriptRuntime>( 1101353358Sdim exe_ctx.GetProcessPtr()->GetLanguageRuntime( 1102353358Sdim eLanguageTypeExtRenderScript)); 1103296417Sdim 1104314564Sdim lang_rt->HookCallback(hook, exe_ctx); 1105314564Sdim 1106314564Sdim return false; 1107285101Semaste} 1108285101Semaste 1109314564Sdimvoid RenderScriptRuntime::HookCallback(RuntimeHook *hook, 1110314564Sdim ExecutionContext &exe_ctx) { 1111314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1112285101Semaste 1113360784Sdim LLDB_LOGF(log, "%s - '%s'", __FUNCTION__, hook->defn->name); 1114285101Semaste 1115314564Sdim if (hook->defn->grabber) { 1116314564Sdim (this->*(hook->defn->grabber))(hook, exe_ctx); 1117314564Sdim } 1118285101Semaste} 1119285101Semaste 1120314564Sdimvoid RenderScriptRuntime::CaptureDebugHintScriptGroup2( 1121314564Sdim RuntimeHook *hook_info, ExecutionContext &context) { 1122314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1123285101Semaste 1124314564Sdim enum { 1125314564Sdim eGroupName = 0, 1126314564Sdim eGroupNameSize, 1127314564Sdim eKernel, 1128314564Sdim eKernelCount, 1129314564Sdim }; 1130285101Semaste 1131314564Sdim std::array<ArgItem, 4> args{{ 1132314564Sdim {ArgItem::ePointer, 0}, // const char *groupName 1133314564Sdim {ArgItem::eInt32, 0}, // const uint32_t groupNameSize 1134314564Sdim {ArgItem::ePointer, 0}, // const ExpandFuncTy *kernel 1135314564Sdim {ArgItem::eInt32, 0}, // const uint32_t kernelCount 1136314564Sdim }}; 1137285101Semaste 1138314564Sdim if (!GetArgs(context, args.data(), args.size())) { 1139360784Sdim LLDB_LOGF(log, "%s - Error while reading the function parameters", 1140360784Sdim __FUNCTION__); 1141314564Sdim return; 1142314564Sdim } else if (log) { 1143360784Sdim LLDB_LOGF(log, "%s - groupName : 0x%" PRIx64, __FUNCTION__, 1144360784Sdim addr_t(args[eGroupName])); 1145360784Sdim LLDB_LOGF(log, "%s - groupNameSize: %" PRIu64, __FUNCTION__, 1146360784Sdim uint64_t(args[eGroupNameSize])); 1147360784Sdim LLDB_LOGF(log, "%s - kernel : 0x%" PRIx64, __FUNCTION__, 1148360784Sdim addr_t(args[eKernel])); 1149360784Sdim LLDB_LOGF(log, "%s - kernelCount : %" PRIu64, __FUNCTION__, 1150360784Sdim uint64_t(args[eKernelCount])); 1151314564Sdim } 1152314564Sdim 1153314564Sdim // parse script group name 1154314564Sdim ConstString group_name; 1155314564Sdim { 1156321369Sdim Status err; 1157314564Sdim const uint64_t len = uint64_t(args[eGroupNameSize]); 1158314564Sdim std::unique_ptr<char[]> buffer(new char[uint32_t(len + 1)]); 1159314564Sdim m_process->ReadMemory(addr_t(args[eGroupName]), buffer.get(), len, err); 1160314564Sdim buffer.get()[len] = '\0'; 1161314564Sdim if (!err.Success()) { 1162360784Sdim LLDB_LOGF(log, "Error reading scriptgroup name from target"); 1163314564Sdim return; 1164314564Sdim } else { 1165360784Sdim LLDB_LOGF(log, "Extracted scriptgroup name %s", buffer.get()); 1166296417Sdim } 1167314564Sdim // write back the script group name 1168314564Sdim group_name.SetCString(buffer.get()); 1169314564Sdim } 1170296417Sdim 1171314564Sdim // create or access existing script group 1172314564Sdim RSScriptGroupDescriptorSP group; 1173314564Sdim { 1174314564Sdim // search for existing script group 1175314564Sdim for (auto sg : m_scriptGroups) { 1176314564Sdim if (sg->m_name == group_name) { 1177314564Sdim group = sg; 1178314564Sdim break; 1179314564Sdim } 1180314564Sdim } 1181314564Sdim if (!group) { 1182353358Sdim group = std::make_shared<RSScriptGroupDescriptor>(); 1183314564Sdim group->m_name = group_name; 1184314564Sdim m_scriptGroups.push_back(group); 1185314564Sdim } else { 1186314564Sdim // already have this script group 1187360784Sdim LLDB_LOGF(log, "Attempt to add duplicate script group %s", 1188360784Sdim group_name.AsCString()); 1189314564Sdim return; 1190314564Sdim } 1191314564Sdim } 1192314564Sdim assert(group); 1193309124Sdim 1194314564Sdim const uint32_t target_ptr_size = m_process->GetAddressByteSize(); 1195314564Sdim std::vector<addr_t> kernels; 1196314564Sdim // parse kernel addresses in script group 1197314564Sdim for (uint64_t i = 0; i < uint64_t(args[eKernelCount]); ++i) { 1198314564Sdim RSScriptGroupDescriptor::Kernel kernel; 1199314564Sdim // extract script group kernel addresses from the target 1200314564Sdim const addr_t ptr_addr = addr_t(args[eKernel]) + i * target_ptr_size; 1201314564Sdim uint64_t kernel_addr = 0; 1202321369Sdim Status err; 1203314564Sdim size_t read = 1204314564Sdim m_process->ReadMemory(ptr_addr, &kernel_addr, target_ptr_size, err); 1205314564Sdim if (!err.Success() || read != target_ptr_size) { 1206360784Sdim LLDB_LOGF(log, "Error parsing kernel address %" PRIu64 " in script group", 1207360784Sdim i); 1208314564Sdim return; 1209309124Sdim } 1210360784Sdim LLDB_LOGF(log, "Extracted scriptgroup kernel address - 0x%" PRIx64, 1211360784Sdim kernel_addr); 1212314564Sdim kernel.m_addr = kernel_addr; 1213309124Sdim 1214314564Sdim // try to resolve the associated kernel name 1215314564Sdim if (!ResolveKernelName(kernel.m_addr, kernel.m_name)) { 1216360784Sdim LLDB_LOGF(log, "Parsed scriptgroup kernel %" PRIu64 " - 0x%" PRIx64, i, 1217360784Sdim kernel_addr); 1218314564Sdim return; 1219309124Sdim } 1220309124Sdim 1221314564Sdim // try to find the non '.expand' function 1222309124Sdim { 1223314564Sdim const llvm::StringRef expand(".expand"); 1224314564Sdim const llvm::StringRef name_ref = kernel.m_name.GetStringRef(); 1225314564Sdim if (name_ref.endswith(expand)) { 1226314564Sdim const ConstString base_kernel(name_ref.drop_back(expand.size())); 1227314564Sdim // verify this function is a valid kernel 1228314564Sdim if (IsKnownKernel(base_kernel)) { 1229314564Sdim kernel.m_name = base_kernel; 1230360784Sdim LLDB_LOGF(log, "%s - found non expand version '%s'", __FUNCTION__, 1231360784Sdim base_kernel.GetCString()); 1232296417Sdim } 1233314564Sdim } 1234285101Semaste } 1235314564Sdim // add to a list of script group kernels we know about 1236314564Sdim group->m_kernels.push_back(kernel); 1237314564Sdim } 1238296417Sdim 1239314564Sdim // Resolve any pending scriptgroup breakpoints 1240314564Sdim { 1241314564Sdim Target &target = m_process->GetTarget(); 1242314564Sdim const BreakpointList &list = target.GetBreakpointList(); 1243314564Sdim const size_t num_breakpoints = list.GetSize(); 1244360784Sdim LLDB_LOGF(log, "Resolving %zu breakpoints", num_breakpoints); 1245314564Sdim for (size_t i = 0; i < num_breakpoints; ++i) { 1246314564Sdim const BreakpointSP bp = list.GetBreakpointAtIndex(i); 1247314564Sdim if (bp) { 1248314564Sdim if (bp->MatchesName(group_name.AsCString())) { 1249360784Sdim LLDB_LOGF(log, "Found breakpoint with name %s", 1250360784Sdim group_name.AsCString()); 1251314564Sdim bp->ResolveBreakpoint(); 1252309124Sdim } 1253314564Sdim } 1254296417Sdim } 1255314564Sdim } 1256285101Semaste} 1257285101Semaste 1258314564Sdimvoid RenderScriptRuntime::CaptureScriptInvokeForEachMulti( 1259314564Sdim RuntimeHook *hook, ExecutionContext &exe_ctx) { 1260314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1261296417Sdim 1262314564Sdim enum { 1263314564Sdim eRsContext = 0, 1264314564Sdim eRsScript, 1265314564Sdim eRsSlot, 1266314564Sdim eRsAIns, 1267314564Sdim eRsInLen, 1268314564Sdim eRsAOut, 1269314564Sdim eRsUsr, 1270314564Sdim eRsUsrLen, 1271314564Sdim eRsSc, 1272314564Sdim }; 1273285101Semaste 1274314564Sdim std::array<ArgItem, 9> args{{ 1275314564Sdim ArgItem{ArgItem::ePointer, 0}, // const Context *rsc 1276314564Sdim ArgItem{ArgItem::ePointer, 0}, // Script *s 1277314564Sdim ArgItem{ArgItem::eInt32, 0}, // uint32_t slot 1278314564Sdim ArgItem{ArgItem::ePointer, 0}, // const Allocation **aIns 1279314564Sdim ArgItem{ArgItem::eInt32, 0}, // size_t inLen 1280314564Sdim ArgItem{ArgItem::ePointer, 0}, // Allocation *aout 1281314564Sdim ArgItem{ArgItem::ePointer, 0}, // const void *usr 1282314564Sdim ArgItem{ArgItem::eInt32, 0}, // size_t usrLen 1283314564Sdim ArgItem{ArgItem::ePointer, 0}, // const RsScriptCall *sc 1284314564Sdim }}; 1285285101Semaste 1286314564Sdim bool success = GetArgs(exe_ctx, &args[0], args.size()); 1287314564Sdim if (!success) { 1288360784Sdim LLDB_LOGF(log, "%s - Error while reading the function parameters", 1289360784Sdim __FUNCTION__); 1290314564Sdim return; 1291314564Sdim } 1292314564Sdim 1293314564Sdim const uint32_t target_ptr_size = m_process->GetAddressByteSize(); 1294321369Sdim Status err; 1295314564Sdim std::vector<uint64_t> allocs; 1296314564Sdim 1297314564Sdim // traverse allocation list 1298314564Sdim for (uint64_t i = 0; i < uint64_t(args[eRsInLen]); ++i) { 1299314564Sdim // calculate offest to allocation pointer 1300314564Sdim const addr_t addr = addr_t(args[eRsAIns]) + i * target_ptr_size; 1301314564Sdim 1302314564Sdim // Note: due to little endian layout, reading 32bits or 64bits into res 1303314564Sdim // will give the correct results. 1304314564Sdim uint64_t result = 0; 1305314564Sdim size_t read = m_process->ReadMemory(addr, &result, target_ptr_size, err); 1306314564Sdim if (read != target_ptr_size || !err.Success()) { 1307360784Sdim LLDB_LOGF(log, 1308360784Sdim "%s - Error while reading allocation list argument %" PRIu64, 1309360784Sdim __FUNCTION__, i); 1310314564Sdim } else { 1311314564Sdim allocs.push_back(result); 1312296417Sdim } 1313314564Sdim } 1314296417Sdim 1315314564Sdim // if there is an output allocation track it 1316314564Sdim if (uint64_t alloc_out = uint64_t(args[eRsAOut])) { 1317314564Sdim allocs.push_back(alloc_out); 1318314564Sdim } 1319285101Semaste 1320314564Sdim // for all allocations we have found 1321314564Sdim for (const uint64_t alloc_addr : allocs) { 1322314564Sdim AllocationDetails *alloc = LookUpAllocation(alloc_addr); 1323314564Sdim if (!alloc) 1324314564Sdim alloc = CreateAllocation(alloc_addr); 1325314564Sdim 1326314564Sdim if (alloc) { 1327314564Sdim // save the allocation address 1328314564Sdim if (alloc->address.isValid()) { 1329314564Sdim // check the allocation address we already have matches 1330314564Sdim assert(*alloc->address.get() == alloc_addr); 1331314564Sdim } else { 1332314564Sdim alloc->address = alloc_addr; 1333314564Sdim } 1334314564Sdim 1335314564Sdim // save the context 1336314564Sdim if (log) { 1337314564Sdim if (alloc->context.isValid() && 1338314564Sdim *alloc->context.get() != addr_t(args[eRsContext])) 1339360784Sdim LLDB_LOGF(log, "%s - Allocation used by multiple contexts", 1340360784Sdim __FUNCTION__); 1341314564Sdim } 1342314564Sdim alloc->context = addr_t(args[eRsContext]); 1343285101Semaste } 1344314564Sdim } 1345314564Sdim 1346314564Sdim // make sure we track this script object 1347314564Sdim if (lldb_private::RenderScriptRuntime::ScriptDetails *script = 1348314564Sdim LookUpScript(addr_t(args[eRsScript]), true)) { 1349314564Sdim if (log) { 1350314564Sdim if (script->context.isValid() && 1351314564Sdim *script->context.get() != addr_t(args[eRsContext])) 1352360784Sdim LLDB_LOGF(log, "%s - Script used by multiple contexts", __FUNCTION__); 1353314564Sdim } 1354314564Sdim script->context = addr_t(args[eRsContext]); 1355314564Sdim } 1356285101Semaste} 1357285101Semaste 1358314564Sdimvoid RenderScriptRuntime::CaptureSetGlobalVar(RuntimeHook *hook, 1359314564Sdim ExecutionContext &context) { 1360314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1361296417Sdim 1362314564Sdim enum { 1363314564Sdim eRsContext, 1364314564Sdim eRsScript, 1365314564Sdim eRsId, 1366314564Sdim eRsData, 1367314564Sdim eRsLength, 1368314564Sdim }; 1369285101Semaste 1370314564Sdim std::array<ArgItem, 5> args{{ 1371314564Sdim ArgItem{ArgItem::ePointer, 0}, // eRsContext 1372314564Sdim ArgItem{ArgItem::ePointer, 0}, // eRsScript 1373314564Sdim ArgItem{ArgItem::eInt32, 0}, // eRsId 1374314564Sdim ArgItem{ArgItem::ePointer, 0}, // eRsData 1375314564Sdim ArgItem{ArgItem::eInt32, 0}, // eRsLength 1376314564Sdim }}; 1377285101Semaste 1378314564Sdim bool success = GetArgs(context, &args[0], args.size()); 1379314564Sdim if (!success) { 1380360784Sdim LLDB_LOGF(log, "%s - error reading the function parameters.", __FUNCTION__); 1381314564Sdim return; 1382314564Sdim } 1383314564Sdim 1384314564Sdim if (log) { 1385360784Sdim LLDB_LOGF(log, 1386360784Sdim "%s - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64 1387360784Sdim ":%" PRIu64 "bytes.", 1388360784Sdim __FUNCTION__, uint64_t(args[eRsContext]), 1389360784Sdim uint64_t(args[eRsScript]), uint64_t(args[eRsId]), 1390360784Sdim uint64_t(args[eRsData]), uint64_t(args[eRsLength])); 1391314564Sdim 1392314564Sdim addr_t script_addr = addr_t(args[eRsScript]); 1393314564Sdim if (m_scriptMappings.find(script_addr) != m_scriptMappings.end()) { 1394314564Sdim auto rsm = m_scriptMappings[script_addr]; 1395314564Sdim if (uint64_t(args[eRsId]) < rsm->m_globals.size()) { 1396314564Sdim auto rsg = rsm->m_globals[uint64_t(args[eRsId])]; 1397360784Sdim LLDB_LOGF(log, "%s - Setting of '%s' within '%s' inferred", 1398360784Sdim __FUNCTION__, rsg.m_name.AsCString(), 1399360784Sdim rsm->m_module->GetFileSpec().GetFilename().AsCString()); 1400314564Sdim } 1401296417Sdim } 1402314564Sdim } 1403314564Sdim} 1404296417Sdim 1405314564Sdimvoid RenderScriptRuntime::CaptureAllocationInit(RuntimeHook *hook, 1406314564Sdim ExecutionContext &exe_ctx) { 1407314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1408314564Sdim 1409314564Sdim enum { eRsContext, eRsAlloc, eRsForceZero }; 1410314564Sdim 1411314564Sdim std::array<ArgItem, 3> args{{ 1412314564Sdim ArgItem{ArgItem::ePointer, 0}, // eRsContext 1413314564Sdim ArgItem{ArgItem::ePointer, 0}, // eRsAlloc 1414314564Sdim ArgItem{ArgItem::eBool, 0}, // eRsForceZero 1415314564Sdim }}; 1416314564Sdim 1417314564Sdim bool success = GetArgs(exe_ctx, &args[0], args.size()); 1418314564Sdim if (!success) { 1419360784Sdim LLDB_LOGF(log, "%s - error while reading the function parameters", 1420360784Sdim __FUNCTION__); 1421314564Sdim return; 1422314564Sdim } 1423296417Sdim 1424360784Sdim LLDB_LOGF(log, "%s - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .", 1425360784Sdim __FUNCTION__, uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc]), 1426360784Sdim uint64_t(args[eRsForceZero])); 1427314564Sdim 1428314564Sdim AllocationDetails *alloc = CreateAllocation(uint64_t(args[eRsAlloc])); 1429314564Sdim if (alloc) 1430314564Sdim alloc->context = uint64_t(args[eRsContext]); 1431285101Semaste} 1432285101Semaste 1433314564Sdimvoid RenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook *hook, 1434314564Sdim ExecutionContext &exe_ctx) { 1435314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1436296417Sdim 1437314564Sdim enum { 1438314564Sdim eRsContext, 1439314564Sdim eRsAlloc, 1440314564Sdim }; 1441296417Sdim 1442314564Sdim std::array<ArgItem, 2> args{{ 1443314564Sdim ArgItem{ArgItem::ePointer, 0}, // eRsContext 1444314564Sdim ArgItem{ArgItem::ePointer, 0}, // eRsAlloc 1445314564Sdim }}; 1446309124Sdim 1447314564Sdim bool success = GetArgs(exe_ctx, &args[0], args.size()); 1448314564Sdim if (!success) { 1449360784Sdim LLDB_LOGF(log, "%s - error while reading the function parameters.", 1450360784Sdim __FUNCTION__); 1451314564Sdim return; 1452314564Sdim } 1453296417Sdim 1454360784Sdim LLDB_LOGF(log, "%s - 0x%" PRIx64 ", 0x%" PRIx64 ".", __FUNCTION__, 1455360784Sdim uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc])); 1456314564Sdim 1457314564Sdim for (auto iter = m_allocations.begin(); iter != m_allocations.end(); ++iter) { 1458353358Sdim auto &allocation_up = *iter; // get the unique pointer 1459353358Sdim if (allocation_up->address.isValid() && 1460353358Sdim *allocation_up->address.get() == addr_t(args[eRsAlloc])) { 1461314564Sdim m_allocations.erase(iter); 1462360784Sdim LLDB_LOGF(log, "%s - deleted allocation entry.", __FUNCTION__); 1463314564Sdim return; 1464296417Sdim } 1465314564Sdim } 1466296417Sdim 1467360784Sdim LLDB_LOGF(log, "%s - couldn't find destroyed allocation.", __FUNCTION__); 1468296417Sdim} 1469296417Sdim 1470314564Sdimvoid RenderScriptRuntime::CaptureScriptInit(RuntimeHook *hook, 1471314564Sdim ExecutionContext &exe_ctx) { 1472314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1473285101Semaste 1474321369Sdim Status err; 1475314564Sdim Process *process = exe_ctx.GetProcessPtr(); 1476285101Semaste 1477314564Sdim enum { eRsContext, eRsScript, eRsResNamePtr, eRsCachedDirPtr }; 1478285101Semaste 1479314564Sdim std::array<ArgItem, 4> args{ 1480314564Sdim {ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}, 1481314564Sdim ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}}}; 1482314564Sdim bool success = GetArgs(exe_ctx, &args[0], args.size()); 1483314564Sdim if (!success) { 1484360784Sdim LLDB_LOGF(log, "%s - error while reading the function parameters.", 1485360784Sdim __FUNCTION__); 1486314564Sdim return; 1487314564Sdim } 1488296417Sdim 1489314564Sdim std::string res_name; 1490314564Sdim process->ReadCStringFromMemory(addr_t(args[eRsResNamePtr]), res_name, err); 1491314564Sdim if (err.Fail()) { 1492360784Sdim LLDB_LOGF(log, "%s - error reading res_name: %s.", __FUNCTION__, 1493360784Sdim err.AsCString()); 1494314564Sdim } 1495285101Semaste 1496314564Sdim std::string cache_dir; 1497314564Sdim process->ReadCStringFromMemory(addr_t(args[eRsCachedDirPtr]), cache_dir, err); 1498314564Sdim if (err.Fail()) { 1499360784Sdim LLDB_LOGF(log, "%s - error reading cache_dir: %s.", __FUNCTION__, 1500360784Sdim err.AsCString()); 1501314564Sdim } 1502285101Semaste 1503360784Sdim LLDB_LOGF(log, "%s - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .", 1504360784Sdim __FUNCTION__, uint64_t(args[eRsContext]), uint64_t(args[eRsScript]), 1505360784Sdim res_name.c_str(), cache_dir.c_str()); 1506285101Semaste 1507314564Sdim if (res_name.size() > 0) { 1508314564Sdim StreamString strm; 1509314564Sdim strm.Printf("librs.%s.so", res_name.c_str()); 1510285101Semaste 1511314564Sdim ScriptDetails *script = LookUpScript(addr_t(args[eRsScript]), true); 1512314564Sdim if (script) { 1513314564Sdim script->type = ScriptDetails::eScriptC; 1514314564Sdim script->cache_dir = cache_dir; 1515314564Sdim script->res_name = res_name; 1516314564Sdim script->shared_lib = strm.GetString(); 1517314564Sdim script->context = addr_t(args[eRsContext]); 1518296417Sdim } 1519314564Sdim 1520360784Sdim LLDB_LOGF(log, 1521360784Sdim "%s - '%s' tagged with context 0x%" PRIx64 1522360784Sdim " and script 0x%" PRIx64 ".", 1523360784Sdim __FUNCTION__, strm.GetData(), uint64_t(args[eRsContext]), 1524360784Sdim uint64_t(args[eRsScript])); 1525314564Sdim } else if (log) { 1526360784Sdim LLDB_LOGF(log, "%s - resource name invalid, Script not tagged.", 1527360784Sdim __FUNCTION__); 1528314564Sdim } 1529285101Semaste} 1530285101Semaste 1531314564Sdimvoid RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, 1532314564Sdim ModuleKind kind) { 1533314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1534285101Semaste 1535314564Sdim if (!module) { 1536314564Sdim return; 1537314564Sdim } 1538285101Semaste 1539314564Sdim Target &target = GetProcess()->GetTarget(); 1540314564Sdim const llvm::Triple::ArchType machine = target.GetArchitecture().GetMachine(); 1541296417Sdim 1542314564Sdim if (machine != llvm::Triple::ArchType::x86 && 1543314564Sdim machine != llvm::Triple::ArchType::arm && 1544314564Sdim machine != llvm::Triple::ArchType::aarch64 && 1545314564Sdim machine != llvm::Triple::ArchType::mipsel && 1546314564Sdim machine != llvm::Triple::ArchType::mips64el && 1547314564Sdim machine != llvm::Triple::ArchType::x86_64) { 1548360784Sdim LLDB_LOGF(log, "%s - unable to hook runtime functions.", __FUNCTION__); 1549314564Sdim return; 1550314564Sdim } 1551285101Semaste 1552314564Sdim const uint32_t target_ptr_size = 1553314564Sdim target.GetArchitecture().GetAddressByteSize(); 1554285101Semaste 1555314564Sdim std::array<bool, s_runtimeHookCount> hook_placed; 1556314564Sdim hook_placed.fill(false); 1557285101Semaste 1558314564Sdim for (size_t idx = 0; idx < s_runtimeHookCount; idx++) { 1559314564Sdim const HookDefn *hook_defn = &s_runtimeHookDefns[idx]; 1560314564Sdim if (hook_defn->kind != kind) { 1561314564Sdim continue; 1562314564Sdim } 1563285101Semaste 1564314564Sdim const char *symbol_name = (target_ptr_size == 4) 1565314564Sdim ? hook_defn->symbol_name_m32 1566314564Sdim : hook_defn->symbol_name_m64; 1567296417Sdim 1568314564Sdim const Symbol *sym = module->FindFirstSymbolWithNameAndType( 1569314564Sdim ConstString(symbol_name), eSymbolTypeCode); 1570314564Sdim if (!sym) { 1571314564Sdim if (log) { 1572360784Sdim LLDB_LOGF(log, "%s - symbol '%s' related to the function %s not found", 1573360784Sdim __FUNCTION__, symbol_name, hook_defn->name); 1574314564Sdim } 1575314564Sdim continue; 1576314564Sdim } 1577285101Semaste 1578314564Sdim addr_t addr = sym->GetLoadAddress(&target); 1579314564Sdim if (addr == LLDB_INVALID_ADDRESS) { 1580360784Sdim LLDB_LOGF(log, 1581360784Sdim "%s - unable to resolve the address of hook function '%s' " 1582360784Sdim "with symbol '%s'.", 1583360784Sdim __FUNCTION__, hook_defn->name, symbol_name); 1584314564Sdim continue; 1585314564Sdim } else { 1586360784Sdim LLDB_LOGF(log, "%s - function %s, address resolved at 0x%" PRIx64, 1587360784Sdim __FUNCTION__, hook_defn->name, addr); 1588285101Semaste } 1589314564Sdim 1590314564Sdim RuntimeHookSP hook(new RuntimeHook()); 1591314564Sdim hook->address = addr; 1592314564Sdim hook->defn = hook_defn; 1593314564Sdim hook->bp_sp = target.CreateBreakpoint(addr, true, false); 1594314564Sdim hook->bp_sp->SetCallback(HookCallback, hook.get(), true); 1595314564Sdim m_runtimeHooks[addr] = hook; 1596314564Sdim if (log) { 1597360784Sdim LLDB_LOGF(log, 1598360784Sdim "%s - successfully hooked '%s' in '%s' version %" PRIu64 1599360784Sdim " at 0x%" PRIx64 ".", 1600360784Sdim __FUNCTION__, hook_defn->name, 1601360784Sdim module->GetFileSpec().GetFilename().AsCString(), 1602360784Sdim (uint64_t)hook_defn->version, (uint64_t)addr); 1603314564Sdim } 1604314564Sdim hook_placed[idx] = true; 1605314564Sdim } 1606314564Sdim 1607314564Sdim // log any unhooked function 1608314564Sdim if (log) { 1609314564Sdim for (size_t i = 0; i < hook_placed.size(); ++i) { 1610314564Sdim if (hook_placed[i]) 1611314564Sdim continue; 1612314564Sdim const HookDefn &hook_defn = s_runtimeHookDefns[i]; 1613314564Sdim if (hook_defn.kind != kind) 1614314564Sdim continue; 1615360784Sdim LLDB_LOGF(log, "%s - function %s was not hooked", __FUNCTION__, 1616360784Sdim hook_defn.name); 1617314564Sdim } 1618314564Sdim } 1619285101Semaste} 1620285101Semaste 1621314564Sdimvoid RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp) { 1622314564Sdim if (!rsmodule_sp) 1623314564Sdim return; 1624285101Semaste 1625314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1626285101Semaste 1627314564Sdim const ModuleSP module = rsmodule_sp->m_module; 1628314564Sdim const FileSpec &file = module->GetPlatformFileSpec(); 1629296417Sdim 1630341825Sdim // Iterate over all of the scripts that we currently know of. Note: We cant 1631341825Sdim // push or pop to m_scripts here or it may invalidate rs_script. 1632314564Sdim for (const auto &rs_script : m_scripts) { 1633314564Sdim // Extract the expected .so file path for this script. 1634314564Sdim std::string shared_lib; 1635314564Sdim if (!rs_script->shared_lib.get(shared_lib)) 1636314564Sdim continue; 1637296417Sdim 1638314564Sdim // Only proceed if the module that has loaded corresponds to this script. 1639314564Sdim if (file.GetFilename() != ConstString(shared_lib.c_str())) 1640314564Sdim continue; 1641296417Sdim 1642314564Sdim // Obtain the script address which we use as a key. 1643314564Sdim lldb::addr_t script; 1644314564Sdim if (!rs_script->script.get(script)) 1645314564Sdim continue; 1646296417Sdim 1647314564Sdim // If we have a script mapping for the current script. 1648314564Sdim if (m_scriptMappings.find(script) != m_scriptMappings.end()) { 1649314564Sdim // if the module we have stored is different to the one we just received. 1650314564Sdim if (m_scriptMappings[script] != rsmodule_sp) { 1651360784Sdim LLDB_LOGF( 1652360784Sdim log, 1653360784Sdim "%s - script %" PRIx64 " wants reassigned to new rsmodule '%s'.", 1654360784Sdim __FUNCTION__, (uint64_t)script, 1655360784Sdim rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); 1656314564Sdim } 1657296417Sdim } 1658314564Sdim // We don't have a script mapping for the current script. 1659314564Sdim else { 1660314564Sdim // Obtain the script resource name. 1661314564Sdim std::string res_name; 1662314564Sdim if (rs_script->res_name.get(res_name)) 1663314564Sdim // Set the modules resource name. 1664314564Sdim rsmodule_sp->m_resname = res_name; 1665314564Sdim // Add Script/Module pair to map. 1666314564Sdim m_scriptMappings[script] = rsmodule_sp; 1667360784Sdim LLDB_LOGF(log, "%s - script %" PRIx64 " associated with rsmodule '%s'.", 1668360784Sdim __FUNCTION__, (uint64_t)script, 1669360784Sdim rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); 1670314564Sdim } 1671314564Sdim } 1672296417Sdim} 1673296417Sdim 1674314564Sdim// Uses the Target API to evaluate the expression passed as a parameter to the 1675314564Sdim// function The result of that expression is returned an unsigned 64 bit int, 1676314564Sdim// via the result* parameter. Function returns true on success, and false on 1677314564Sdim// failure 1678314564Sdimbool RenderScriptRuntime::EvalRSExpression(const char *expr, 1679314564Sdim StackFrame *frame_ptr, 1680314564Sdim uint64_t *result) { 1681314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1682360784Sdim LLDB_LOGF(log, "%s(%s)", __FUNCTION__, expr); 1683314564Sdim 1684314564Sdim ValueObjectSP expr_result; 1685314564Sdim EvaluateExpressionOptions options; 1686314564Sdim options.SetLanguage(lldb::eLanguageTypeC_plus_plus); 1687314564Sdim // Perform the actual expression evaluation 1688314564Sdim auto &target = GetProcess()->GetTarget(); 1689314564Sdim target.EvaluateExpression(expr, frame_ptr, expr_result, options); 1690314564Sdim 1691314564Sdim if (!expr_result) { 1692360784Sdim LLDB_LOGF(log, "%s: couldn't evaluate expression.", __FUNCTION__); 1693314564Sdim return false; 1694314564Sdim } 1695296417Sdim 1696314564Sdim // The result of the expression is invalid 1697314564Sdim if (!expr_result->GetError().Success()) { 1698321369Sdim Status err = expr_result->GetError(); 1699314564Sdim // Expression returned is void, so this is actually a success 1700314564Sdim if (err.GetError() == UserExpression::kNoResult) { 1701360784Sdim LLDB_LOGF(log, "%s - expression returned void.", __FUNCTION__); 1702296417Sdim 1703314564Sdim result = nullptr; 1704314564Sdim return true; 1705296417Sdim } 1706296417Sdim 1707360784Sdim LLDB_LOGF(log, "%s - error evaluating expression result: %s", __FUNCTION__, 1708360784Sdim err.AsCString()); 1709314564Sdim return false; 1710314564Sdim } 1711296417Sdim 1712314564Sdim bool success = false; 1713314564Sdim // We only read the result as an uint32_t. 1714314564Sdim *result = expr_result->GetValueAsUnsigned(0, &success); 1715296417Sdim 1716314564Sdim if (!success) { 1717360784Sdim LLDB_LOGF(log, "%s - couldn't convert expression result to uint32_t", 1718360784Sdim __FUNCTION__); 1719314564Sdim return false; 1720314564Sdim } 1721296417Sdim 1722314564Sdim return true; 1723296417Sdim} 1724296417Sdim 1725314564Sdimnamespace { 1726309124Sdim// Used to index expression format strings 1727314564Sdimenum ExpressionStrings { 1728314564Sdim eExprGetOffsetPtr = 0, 1729314564Sdim eExprAllocGetType, 1730314564Sdim eExprTypeDimX, 1731314564Sdim eExprTypeDimY, 1732314564Sdim eExprTypeDimZ, 1733314564Sdim eExprTypeElemPtr, 1734314564Sdim eExprElementType, 1735314564Sdim eExprElementKind, 1736314564Sdim eExprElementVec, 1737314564Sdim eExprElementFieldCount, 1738314564Sdim eExprSubelementsId, 1739314564Sdim eExprSubelementsName, 1740314564Sdim eExprSubelementsArrSize, 1741296417Sdim 1742314564Sdim _eExprLast // keep at the end, implicit size of the array runtime_expressions 1743309124Sdim}; 1744309124Sdim 1745309124Sdim// max length of an expanded expression 1746309124Sdimconst int jit_max_expr_size = 512; 1747309124Sdim 1748309124Sdim// Retrieve the string to JIT for the given expression 1749321369Sdim#define JIT_TEMPLATE_CONTEXT "void* ctxt = (void*)rsDebugGetContextWrapper(0x%" PRIx64 "); " 1750314564Sdimconst char *JITTemplate(ExpressionStrings e) { 1751314564Sdim // Format strings containing the expressions we may need to evaluate. 1752314564Sdim static std::array<const char *, _eExprLast> runtime_expressions = { 1753314564Sdim {// Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap) 1754314564Sdim "(int*)_" 1755314564Sdim "Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocation" 1756314564Sdim "CubemapFace" 1757321369Sdim "(0x%" PRIx64 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", 0, 0)", // eExprGetOffsetPtr 1758296417Sdim 1759314564Sdim // Type* rsaAllocationGetType(Context*, Allocation*) 1760321369Sdim JIT_TEMPLATE_CONTEXT "(void*)rsaAllocationGetType(ctxt, 0x%" PRIx64 ")", // eExprAllocGetType 1761296417Sdim 1762314564Sdim // rsaTypeGetNativeData(Context*, Type*, void* typeData, size) Pack the 1763314564Sdim // data in the following way mHal.state.dimX; mHal.state.dimY; 1764341825Sdim // mHal.state.dimZ; mHal.state.lodCount; mHal.state.faces; mElement; 1765341825Sdim // into typeData Need to specify 32 or 64 bit for uint_t since this 1766341825Sdim // differs between devices 1767321369Sdim JIT_TEMPLATE_CONTEXT 1768321369Sdim "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt" 1769321369Sdim ", 0x%" PRIx64 ", data, 6); data[0]", // eExprTypeDimX 1770321369Sdim JIT_TEMPLATE_CONTEXT 1771321369Sdim "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt" 1772321369Sdim ", 0x%" PRIx64 ", data, 6); data[1]", // eExprTypeDimY 1773321369Sdim JIT_TEMPLATE_CONTEXT 1774321369Sdim "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt" 1775321369Sdim ", 0x%" PRIx64 ", data, 6); data[2]", // eExprTypeDimZ 1776321369Sdim JIT_TEMPLATE_CONTEXT 1777321369Sdim "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt" 1778321369Sdim ", 0x%" PRIx64 ", data, 6); data[5]", // eExprTypeElemPtr 1779296417Sdim 1780314564Sdim // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size) 1781314564Sdim // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into 1782314564Sdim // elemData 1783321369Sdim JIT_TEMPLATE_CONTEXT 1784321369Sdim "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt" 1785321369Sdim ", 0x%" PRIx64 ", data, 5); data[0]", // eExprElementType 1786321369Sdim JIT_TEMPLATE_CONTEXT 1787321369Sdim "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt" 1788321369Sdim ", 0x%" PRIx64 ", data, 5); data[1]", // eExprElementKind 1789321369Sdim JIT_TEMPLATE_CONTEXT 1790321369Sdim "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt" 1791321369Sdim ", 0x%" PRIx64 ", data, 5); data[3]", // eExprElementVec 1792321369Sdim JIT_TEMPLATE_CONTEXT 1793321369Sdim "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt" 1794321369Sdim ", 0x%" PRIx64 ", data, 5); data[4]", // eExprElementFieldCount 1795296417Sdim 1796314564Sdim // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t 1797314564Sdim // *ids, const char **names, size_t *arraySizes, uint32_t dataSize) 1798314564Sdim // Needed for Allocations of structs to gather details about 1799314564Sdim // fields/Subelements Element* of field 1800321369Sdim JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 1801314564Sdim "]; size_t arr_size[%" PRIu32 "];" 1802321369Sdim "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64 1803321369Sdim ", ids, names, arr_size, %" PRIu32 "); ids[%" PRIu32 "]", // eExprSubelementsId 1804296417Sdim 1805314564Sdim // Name of field 1806321369Sdim JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 1807314564Sdim "]; size_t arr_size[%" PRIu32 "];" 1808321369Sdim "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64 1809321369Sdim ", ids, names, arr_size, %" PRIu32 "); names[%" PRIu32 "]", // eExprSubelementsName 1810296417Sdim 1811314564Sdim // Array size of field 1812321369Sdim JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 1813314564Sdim "]; size_t arr_size[%" PRIu32 "];" 1814321369Sdim "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64 1815321369Sdim ", ids, names, arr_size, %" PRIu32 "); arr_size[%" PRIu32 "]"}}; // eExprSubelementsArrSize 1816296417Sdim 1817314564Sdim return runtime_expressions[e]; 1818309124Sdim} 1819296417Sdim} // end of the anonymous namespace 1820296417Sdim 1821341825Sdim// JITs the RS runtime for the internal data pointer of an allocation. Is 1822341825Sdim// passed x,y,z coordinates for the pointer to a specific element. Then sets 1823341825Sdim// the data_ptr member in Allocation with the result. Returns true on success, 1824341825Sdim// false otherwise 1825314564Sdimbool RenderScriptRuntime::JITDataPointer(AllocationDetails *alloc, 1826314564Sdim StackFrame *frame_ptr, uint32_t x, 1827314564Sdim uint32_t y, uint32_t z) { 1828314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1829296417Sdim 1830314564Sdim if (!alloc->address.isValid()) { 1831360784Sdim LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__); 1832314564Sdim return false; 1833314564Sdim } 1834296417Sdim 1835314564Sdim const char *fmt_str = JITTemplate(eExprGetOffsetPtr); 1836314564Sdim char expr_buf[jit_max_expr_size]; 1837296417Sdim 1838314564Sdim int written = snprintf(expr_buf, jit_max_expr_size, fmt_str, 1839314564Sdim *alloc->address.get(), x, y, z); 1840314564Sdim if (written < 0) { 1841360784Sdim LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__); 1842314564Sdim return false; 1843314564Sdim } else if (written >= jit_max_expr_size) { 1844360784Sdim LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__); 1845314564Sdim return false; 1846314564Sdim } 1847296417Sdim 1848314564Sdim uint64_t result = 0; 1849314564Sdim if (!EvalRSExpression(expr_buf, frame_ptr, &result)) 1850314564Sdim return false; 1851296417Sdim 1852314564Sdim addr_t data_ptr = static_cast<lldb::addr_t>(result); 1853314564Sdim alloc->data_ptr = data_ptr; 1854296417Sdim 1855314564Sdim return true; 1856296417Sdim} 1857296417Sdim 1858296417Sdim// JITs the RS runtime for the internal pointer to the RS Type of an allocation 1859314564Sdim// Then sets the type_ptr member in Allocation with the result. Returns true on 1860314564Sdim// success, false otherwise 1861314564Sdimbool RenderScriptRuntime::JITTypePointer(AllocationDetails *alloc, 1862314564Sdim StackFrame *frame_ptr) { 1863314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1864296417Sdim 1865314564Sdim if (!alloc->address.isValid() || !alloc->context.isValid()) { 1866360784Sdim LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__); 1867314564Sdim return false; 1868314564Sdim } 1869296417Sdim 1870314564Sdim const char *fmt_str = JITTemplate(eExprAllocGetType); 1871314564Sdim char expr_buf[jit_max_expr_size]; 1872296417Sdim 1873314564Sdim int written = snprintf(expr_buf, jit_max_expr_size, fmt_str, 1874314564Sdim *alloc->context.get(), *alloc->address.get()); 1875314564Sdim if (written < 0) { 1876360784Sdim LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__); 1877314564Sdim return false; 1878314564Sdim } else if (written >= jit_max_expr_size) { 1879360784Sdim LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__); 1880314564Sdim return false; 1881314564Sdim } 1882296417Sdim 1883314564Sdim uint64_t result = 0; 1884314564Sdim if (!EvalRSExpression(expr_buf, frame_ptr, &result)) 1885314564Sdim return false; 1886296417Sdim 1887314564Sdim addr_t type_ptr = static_cast<lldb::addr_t>(result); 1888314564Sdim alloc->type_ptr = type_ptr; 1889296417Sdim 1890314564Sdim return true; 1891296417Sdim} 1892296417Sdim 1893314564Sdim// JITs the RS runtime for information about the dimensions and type of an 1894341825Sdim// allocation Then sets dimension and element_ptr members in Allocation with 1895341825Sdim// the result. Returns true on success, false otherwise 1896314564Sdimbool RenderScriptRuntime::JITTypePacked(AllocationDetails *alloc, 1897314564Sdim StackFrame *frame_ptr) { 1898314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1899296417Sdim 1900314564Sdim if (!alloc->type_ptr.isValid() || !alloc->context.isValid()) { 1901360784Sdim LLDB_LOGF(log, "%s - Failed to find allocation details.", __FUNCTION__); 1902314564Sdim return false; 1903314564Sdim } 1904296417Sdim 1905314564Sdim // Expression is different depending on if device is 32 or 64 bit 1906314564Sdim uint32_t target_ptr_size = 1907314564Sdim GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 1908314564Sdim const uint32_t bits = target_ptr_size == 4 ? 32 : 64; 1909296417Sdim 1910314564Sdim // We want 4 elements from packed data 1911314564Sdim const uint32_t num_exprs = 4; 1912353358Sdim static_assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1), 1913353358Sdim "Invalid number of expressions"); 1914296417Sdim 1915314564Sdim char expr_bufs[num_exprs][jit_max_expr_size]; 1916314564Sdim uint64_t results[num_exprs]; 1917296417Sdim 1918314564Sdim for (uint32_t i = 0; i < num_exprs; ++i) { 1919314564Sdim const char *fmt_str = JITTemplate(ExpressionStrings(eExprTypeDimX + i)); 1920321369Sdim int written = snprintf(expr_bufs[i], jit_max_expr_size, fmt_str, 1921321369Sdim *alloc->context.get(), bits, *alloc->type_ptr.get()); 1922314564Sdim if (written < 0) { 1923360784Sdim LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__); 1924314564Sdim return false; 1925314564Sdim } else if (written >= jit_max_expr_size) { 1926360784Sdim LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__); 1927314564Sdim return false; 1928296417Sdim } 1929296417Sdim 1930314564Sdim // Perform expression evaluation 1931314564Sdim if (!EvalRSExpression(expr_bufs[i], frame_ptr, &results[i])) 1932314564Sdim return false; 1933314564Sdim } 1934296417Sdim 1935314564Sdim // Assign results to allocation members 1936314564Sdim AllocationDetails::Dimension dims; 1937314564Sdim dims.dim_1 = static_cast<uint32_t>(results[0]); 1938314564Sdim dims.dim_2 = static_cast<uint32_t>(results[1]); 1939314564Sdim dims.dim_3 = static_cast<uint32_t>(results[2]); 1940314564Sdim alloc->dimension = dims; 1941296417Sdim 1942314564Sdim addr_t element_ptr = static_cast<lldb::addr_t>(results[3]); 1943314564Sdim alloc->element.element_ptr = element_ptr; 1944296417Sdim 1945360784Sdim LLDB_LOGF(log, 1946360784Sdim "%s - dims (%" PRIu32 ", %" PRIu32 ", %" PRIu32 1947360784Sdim ") Element*: 0x%" PRIx64 ".", 1948360784Sdim __FUNCTION__, dims.dim_1, dims.dim_2, dims.dim_3, element_ptr); 1949314564Sdim 1950314564Sdim return true; 1951296417Sdim} 1952296417Sdim 1953314564Sdim// JITs the RS runtime for information about the Element of an allocation Then 1954314564Sdim// sets type, type_vec_size, field_count and type_kind members in Element with 1955314564Sdim// the result. Returns true on success, false otherwise 1956314564Sdimbool RenderScriptRuntime::JITElementPacked(Element &elem, 1957314564Sdim const lldb::addr_t context, 1958314564Sdim StackFrame *frame_ptr) { 1959314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1960296417Sdim 1961314564Sdim if (!elem.element_ptr.isValid()) { 1962360784Sdim LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__); 1963314564Sdim return false; 1964314564Sdim } 1965296417Sdim 1966314564Sdim // We want 4 elements from packed data 1967314564Sdim const uint32_t num_exprs = 4; 1968353358Sdim static_assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1), 1969353358Sdim "Invalid number of expressions"); 1970296417Sdim 1971314564Sdim char expr_bufs[num_exprs][jit_max_expr_size]; 1972314564Sdim uint64_t results[num_exprs]; 1973296417Sdim 1974314564Sdim for (uint32_t i = 0; i < num_exprs; i++) { 1975314564Sdim const char *fmt_str = JITTemplate(ExpressionStrings(eExprElementType + i)); 1976314564Sdim int written = snprintf(expr_bufs[i], jit_max_expr_size, fmt_str, context, 1977314564Sdim *elem.element_ptr.get()); 1978314564Sdim if (written < 0) { 1979360784Sdim LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__); 1980314564Sdim return false; 1981314564Sdim } else if (written >= jit_max_expr_size) { 1982360784Sdim LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__); 1983314564Sdim return false; 1984296417Sdim } 1985296417Sdim 1986314564Sdim // Perform expression evaluation 1987314564Sdim if (!EvalRSExpression(expr_bufs[i], frame_ptr, &results[i])) 1988314564Sdim return false; 1989314564Sdim } 1990296417Sdim 1991314564Sdim // Assign results to allocation members 1992314564Sdim elem.type = static_cast<RenderScriptRuntime::Element::DataType>(results[0]); 1993314564Sdim elem.type_kind = 1994314564Sdim static_cast<RenderScriptRuntime::Element::DataKind>(results[1]); 1995314564Sdim elem.type_vec_size = static_cast<uint32_t>(results[2]); 1996314564Sdim elem.field_count = static_cast<uint32_t>(results[3]); 1997296417Sdim 1998360784Sdim LLDB_LOGF(log, 1999360784Sdim "%s - data type %" PRIu32 ", pixel type %" PRIu32 2000360784Sdim ", vector size %" PRIu32 ", field count %" PRIu32, 2001360784Sdim __FUNCTION__, *elem.type.get(), *elem.type_kind.get(), 2002360784Sdim *elem.type_vec_size.get(), *elem.field_count.get()); 2003296417Sdim 2004314564Sdim // If this Element has subelements then JIT rsaElementGetSubElements() for 2005314564Sdim // details about its fields 2006344779Sdim return !(*elem.field_count.get() > 0 && 2007344779Sdim !JITSubelements(elem, context, frame_ptr)); 2008296417Sdim} 2009296417Sdim 2010314564Sdim// JITs the RS runtime for information about the subelements/fields of a struct 2011314564Sdim// allocation This is necessary for infering the struct type so we can pretty 2012314564Sdim// print the allocation's contents. Returns true on success, false otherwise 2013314564Sdimbool RenderScriptRuntime::JITSubelements(Element &elem, 2014314564Sdim const lldb::addr_t context, 2015314564Sdim StackFrame *frame_ptr) { 2016314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2017296417Sdim 2018314564Sdim if (!elem.element_ptr.isValid() || !elem.field_count.isValid()) { 2019360784Sdim LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__); 2020314564Sdim return false; 2021314564Sdim } 2022296417Sdim 2023314564Sdim const short num_exprs = 3; 2024353358Sdim static_assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1), 2025353358Sdim "Invalid number of expressions"); 2026296417Sdim 2027314564Sdim char expr_buffer[jit_max_expr_size]; 2028314564Sdim uint64_t results; 2029296417Sdim 2030314564Sdim // Iterate over struct fields. 2031314564Sdim const uint32_t field_count = *elem.field_count.get(); 2032314564Sdim for (uint32_t field_index = 0; field_index < field_count; ++field_index) { 2033314564Sdim Element child; 2034314564Sdim for (uint32_t expr_index = 0; expr_index < num_exprs; ++expr_index) { 2035314564Sdim const char *fmt_str = 2036314564Sdim JITTemplate(ExpressionStrings(eExprSubelementsId + expr_index)); 2037314564Sdim int written = snprintf(expr_buffer, jit_max_expr_size, fmt_str, 2038321369Sdim context, field_count, field_count, field_count, 2039314564Sdim *elem.element_ptr.get(), field_count, field_index); 2040314564Sdim if (written < 0) { 2041360784Sdim LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__); 2042314564Sdim return false; 2043314564Sdim } else if (written >= jit_max_expr_size) { 2044360784Sdim LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__); 2045314564Sdim return false; 2046314564Sdim } 2047296417Sdim 2048314564Sdim // Perform expression evaluation 2049314564Sdim if (!EvalRSExpression(expr_buffer, frame_ptr, &results)) 2050314564Sdim return false; 2051296417Sdim 2052360784Sdim LLDB_LOGF(log, "%s - expr result 0x%" PRIx64 ".", __FUNCTION__, results); 2053296417Sdim 2054314564Sdim switch (expr_index) { 2055314564Sdim case 0: // Element* of child 2056314564Sdim child.element_ptr = static_cast<addr_t>(results); 2057314564Sdim break; 2058314564Sdim case 1: // Name of child 2059314564Sdim { 2060314564Sdim lldb::addr_t address = static_cast<addr_t>(results); 2061321369Sdim Status err; 2062314564Sdim std::string name; 2063314564Sdim GetProcess()->ReadCStringFromMemory(address, name, err); 2064314564Sdim if (!err.Fail()) 2065314564Sdim child.type_name = ConstString(name); 2066314564Sdim else { 2067360784Sdim LLDB_LOGF(log, "%s - warning: Couldn't read field name.", 2068360784Sdim __FUNCTION__); 2069296417Sdim } 2070314564Sdim break; 2071314564Sdim } 2072314564Sdim case 2: // Array size of child 2073314564Sdim child.array_size = static_cast<uint32_t>(results); 2074314564Sdim break; 2075314564Sdim } 2076296417Sdim } 2077296417Sdim 2078314564Sdim // We need to recursively JIT each Element field of the struct since 2079314564Sdim // structs can be nested inside structs. 2080314564Sdim if (!JITElementPacked(child, context, frame_ptr)) 2081314564Sdim return false; 2082314564Sdim elem.children.push_back(child); 2083314564Sdim } 2084296417Sdim 2085314564Sdim // Try to infer the name of the struct type so we can pretty print the 2086314564Sdim // allocation contents. 2087314564Sdim FindStructTypeName(elem, frame_ptr); 2088314564Sdim 2089314564Sdim return true; 2090296417Sdim} 2091296417Sdim 2092296417Sdim// JITs the RS runtime for the address of the last element in the allocation. 2093314564Sdim// The `elem_size` parameter represents the size of a single element, including 2094314564Sdim// padding. Which is needed as an offset from the last element pointer. Using 2095314564Sdim// this offset minus the starting address we can calculate the size of the 2096314564Sdim// allocation. Returns true on success, false otherwise 2097314564Sdimbool RenderScriptRuntime::JITAllocationSize(AllocationDetails *alloc, 2098314564Sdim StackFrame *frame_ptr) { 2099314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2100296417Sdim 2101314564Sdim if (!alloc->address.isValid() || !alloc->dimension.isValid() || 2102314564Sdim !alloc->data_ptr.isValid() || !alloc->element.datum_size.isValid()) { 2103360784Sdim LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__); 2104314564Sdim return false; 2105314564Sdim } 2106296417Sdim 2107314564Sdim // Find dimensions 2108314564Sdim uint32_t dim_x = alloc->dimension.get()->dim_1; 2109314564Sdim uint32_t dim_y = alloc->dimension.get()->dim_2; 2110314564Sdim uint32_t dim_z = alloc->dimension.get()->dim_3; 2111296417Sdim 2112314564Sdim // Our plan of jitting the last element address doesn't seem to work for 2113314564Sdim // struct Allocations` Instead try to infer the size ourselves without any 2114314564Sdim // inter element padding. 2115314564Sdim if (alloc->element.children.size() > 0) { 2116314564Sdim if (dim_x == 0) 2117314564Sdim dim_x = 1; 2118314564Sdim if (dim_y == 0) 2119314564Sdim dim_y = 1; 2120314564Sdim if (dim_z == 0) 2121314564Sdim dim_z = 1; 2122296417Sdim 2123314564Sdim alloc->size = dim_x * dim_y * dim_z * *alloc->element.datum_size.get(); 2124296417Sdim 2125360784Sdim LLDB_LOGF(log, "%s - inferred size of struct allocation %" PRIu32 ".", 2126360784Sdim __FUNCTION__, *alloc->size.get()); 2127314564Sdim return true; 2128314564Sdim } 2129296417Sdim 2130314564Sdim const char *fmt_str = JITTemplate(eExprGetOffsetPtr); 2131314564Sdim char expr_buf[jit_max_expr_size]; 2132296417Sdim 2133314564Sdim // Calculate last element 2134314564Sdim dim_x = dim_x == 0 ? 0 : dim_x - 1; 2135314564Sdim dim_y = dim_y == 0 ? 0 : dim_y - 1; 2136314564Sdim dim_z = dim_z == 0 ? 0 : dim_z - 1; 2137296417Sdim 2138314564Sdim int written = snprintf(expr_buf, jit_max_expr_size, fmt_str, 2139314564Sdim *alloc->address.get(), dim_x, dim_y, dim_z); 2140314564Sdim if (written < 0) { 2141360784Sdim LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__); 2142314564Sdim return false; 2143314564Sdim } else if (written >= jit_max_expr_size) { 2144360784Sdim LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__); 2145314564Sdim return false; 2146314564Sdim } 2147296417Sdim 2148314564Sdim uint64_t result = 0; 2149314564Sdim if (!EvalRSExpression(expr_buf, frame_ptr, &result)) 2150314564Sdim return false; 2151296417Sdim 2152314564Sdim addr_t mem_ptr = static_cast<lldb::addr_t>(result); 2153314564Sdim // Find pointer to last element and add on size of an element 2154314564Sdim alloc->size = static_cast<uint32_t>(mem_ptr - *alloc->data_ptr.get()) + 2155314564Sdim *alloc->element.datum_size.get(); 2156296417Sdim 2157314564Sdim return true; 2158296417Sdim} 2159296417Sdim 2160314564Sdim// JITs the RS runtime for information about the stride between rows in the 2161341825Sdim// allocation. This is done to detect padding, since allocated memory is 2162341825Sdim// 16-byte aligned. Returns true on success, false otherwise 2163314564Sdimbool RenderScriptRuntime::JITAllocationStride(AllocationDetails *alloc, 2164314564Sdim StackFrame *frame_ptr) { 2165314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2166296417Sdim 2167314564Sdim if (!alloc->address.isValid() || !alloc->data_ptr.isValid()) { 2168360784Sdim LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__); 2169314564Sdim return false; 2170314564Sdim } 2171296417Sdim 2172314564Sdim const char *fmt_str = JITTemplate(eExprGetOffsetPtr); 2173314564Sdim char expr_buf[jit_max_expr_size]; 2174296417Sdim 2175314564Sdim int written = snprintf(expr_buf, jit_max_expr_size, fmt_str, 2176314564Sdim *alloc->address.get(), 0, 1, 0); 2177314564Sdim if (written < 0) { 2178360784Sdim LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__); 2179314564Sdim return false; 2180314564Sdim } else if (written >= jit_max_expr_size) { 2181360784Sdim LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__); 2182314564Sdim return false; 2183314564Sdim } 2184296417Sdim 2185314564Sdim uint64_t result = 0; 2186314564Sdim if (!EvalRSExpression(expr_buf, frame_ptr, &result)) 2187314564Sdim return false; 2188296417Sdim 2189314564Sdim addr_t mem_ptr = static_cast<lldb::addr_t>(result); 2190314564Sdim alloc->stride = static_cast<uint32_t>(mem_ptr - *alloc->data_ptr.get()); 2191296417Sdim 2192314564Sdim return true; 2193296417Sdim} 2194296417Sdim 2195296417Sdim// JIT all the current runtime info regarding an allocation 2196314564Sdimbool RenderScriptRuntime::RefreshAllocation(AllocationDetails *alloc, 2197314564Sdim StackFrame *frame_ptr) { 2198314564Sdim // GetOffsetPointer() 2199314564Sdim if (!JITDataPointer(alloc, frame_ptr)) 2200314564Sdim return false; 2201296417Sdim 2202314564Sdim // rsaAllocationGetType() 2203314564Sdim if (!JITTypePointer(alloc, frame_ptr)) 2204314564Sdim return false; 2205296417Sdim 2206314564Sdim // rsaTypeGetNativeData() 2207314564Sdim if (!JITTypePacked(alloc, frame_ptr)) 2208314564Sdim return false; 2209296417Sdim 2210314564Sdim // rsaElementGetNativeData() 2211314564Sdim if (!JITElementPacked(alloc->element, *alloc->context.get(), frame_ptr)) 2212314564Sdim return false; 2213296417Sdim 2214314564Sdim // Sets the datum_size member in Element 2215314564Sdim SetElementSize(alloc->element); 2216296417Sdim 2217314564Sdim // Use GetOffsetPointer() to infer size of the allocation 2218344779Sdim return JITAllocationSize(alloc, frame_ptr); 2219296417Sdim} 2220296417Sdim 2221314564Sdim// Function attempts to set the type_name member of the paramaterised Element 2222341825Sdim// object. This string should be the name of the struct type the Element 2223341825Sdim// represents. We need this string for pretty printing the Element to users. 2224314564Sdimvoid RenderScriptRuntime::FindStructTypeName(Element &elem, 2225314564Sdim StackFrame *frame_ptr) { 2226314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2227296417Sdim 2228314564Sdim if (!elem.type_name.IsEmpty()) // Name already set 2229314564Sdim return; 2230314564Sdim else 2231314564Sdim elem.type_name = Element::GetFallbackStructName(); // Default type name if 2232314564Sdim // we don't succeed 2233296417Sdim 2234314564Sdim // Find all the global variables from the script rs modules 2235314564Sdim VariableList var_list; 2236314564Sdim for (auto module_sp : m_rsmodules) 2237314564Sdim module_sp->m_module->FindGlobalVariables( 2238341825Sdim RegularExpression(llvm::StringRef(".")), UINT32_MAX, var_list); 2239296417Sdim 2240314564Sdim // Iterate over all the global variables looking for one with a matching type 2241341825Sdim // to the Element. We make the assumption a match exists since there needs to 2242341825Sdim // be a global variable to reflect the struct type back into java host code. 2243360784Sdim for (const VariableSP &var_sp : var_list) { 2244314564Sdim if (!var_sp) 2245314564Sdim continue; 2246296417Sdim 2247314564Sdim ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp); 2248314564Sdim if (!valobj_sp) 2249314564Sdim continue; 2250296417Sdim 2251314564Sdim // Find the number of variable fields. 2252314564Sdim // If it has no fields, or more fields than our Element, then it can't be 2253341825Sdim // the struct we're looking for. Don't check for equality since RS can add 2254341825Sdim // extra struct members for padding. 2255314564Sdim size_t num_children = valobj_sp->GetNumChildren(); 2256314564Sdim if (num_children > elem.children.size() || num_children == 0) 2257314564Sdim continue; 2258296417Sdim 2259341825Sdim // Iterate over children looking for members with matching field names. If 2260341825Sdim // all the field names match, this is likely the struct we want. 2261314564Sdim // TODO: This could be made more robust by also checking children data 2262314564Sdim // sizes, or array size 2263314564Sdim bool found = true; 2264314564Sdim for (size_t i = 0; i < num_children; ++i) { 2265314564Sdim ValueObjectSP child = valobj_sp->GetChildAtIndex(i, true); 2266314564Sdim if (!child || (child->GetName() != elem.children[i].type_name)) { 2267314564Sdim found = false; 2268314564Sdim break; 2269314564Sdim } 2270314564Sdim } 2271296417Sdim 2272314564Sdim // RS can add extra struct members for padding in the format 2273314564Sdim // '#rs_padding_[0-9]+' 2274314564Sdim if (found && num_children < elem.children.size()) { 2275314564Sdim const uint32_t size_diff = elem.children.size() - num_children; 2276360784Sdim LLDB_LOGF(log, "%s - %" PRIu32 " padding struct entries", __FUNCTION__, 2277360784Sdim size_diff); 2278296417Sdim 2279314564Sdim for (uint32_t i = 0; i < size_diff; ++i) { 2280353358Sdim ConstString name = elem.children[num_children + i].type_name; 2281314564Sdim if (strcmp(name.AsCString(), "#rs_padding") < 0) 2282314564Sdim found = false; 2283314564Sdim } 2284314564Sdim } 2285296417Sdim 2286314564Sdim // We've found a global variable with matching type 2287314564Sdim if (found) { 2288314564Sdim // Dereference since our Element type isn't a pointer. 2289314564Sdim if (valobj_sp->IsPointerType()) { 2290321369Sdim Status err; 2291314564Sdim ValueObjectSP deref_valobj = valobj_sp->Dereference(err); 2292314564Sdim if (!err.Fail()) 2293314564Sdim valobj_sp = deref_valobj; 2294314564Sdim } 2295296417Sdim 2296314564Sdim // Save name of variable in Element. 2297314564Sdim elem.type_name = valobj_sp->GetTypeName(); 2298360784Sdim LLDB_LOGF(log, "%s - element name set to %s", __FUNCTION__, 2299360784Sdim elem.type_name.AsCString()); 2300296417Sdim 2301314564Sdim return; 2302285101Semaste } 2303314564Sdim } 2304285101Semaste} 2305285101Semaste 2306314564Sdim// Function sets the datum_size member of Element. Representing the size of a 2307341825Sdim// single instance including padding. Assumes the relevant allocation 2308341825Sdim// information has already been jitted. 2309314564Sdimvoid RenderScriptRuntime::SetElementSize(Element &elem) { 2310314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2311314564Sdim const Element::DataType type = *elem.type.get(); 2312314564Sdim assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && 2313314564Sdim "Invalid allocation type"); 2314296417Sdim 2315314564Sdim const uint32_t vec_size = *elem.type_vec_size.get(); 2316314564Sdim uint32_t data_size = 0; 2317314564Sdim uint32_t padding = 0; 2318296417Sdim 2319314564Sdim // Element is of a struct type, calculate size recursively. 2320314564Sdim if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) { 2321314564Sdim for (Element &child : elem.children) { 2322314564Sdim SetElementSize(child); 2323314564Sdim const uint32_t array_size = 2324314564Sdim child.array_size.isValid() ? *child.array_size.get() : 1; 2325314564Sdim data_size += *child.datum_size.get() * array_size; 2326296417Sdim } 2327314564Sdim } 2328314564Sdim // These have been packed already 2329314564Sdim else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 || 2330314564Sdim type == Element::RS_TYPE_UNSIGNED_5_5_5_1 || 2331314564Sdim type == Element::RS_TYPE_UNSIGNED_4_4_4_4) { 2332314564Sdim data_size = AllocationDetails::RSTypeToFormat[type][eElementSize]; 2333314564Sdim } else if (type < Element::RS_TYPE_ELEMENT) { 2334314564Sdim data_size = 2335314564Sdim vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize]; 2336314564Sdim if (vec_size == 3) 2337314564Sdim padding = AllocationDetails::RSTypeToFormat[type][eElementSize]; 2338314564Sdim } else 2339314564Sdim data_size = 2340314564Sdim GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 2341296417Sdim 2342314564Sdim elem.padding = padding; 2343314564Sdim elem.datum_size = data_size + padding; 2344360784Sdim LLDB_LOGF(log, "%s - element size set to %" PRIu32, __FUNCTION__, 2345360784Sdim data_size + padding); 2346296417Sdim} 2347296417Sdim 2348341825Sdim// Given an allocation, this function copies the allocation contents from 2349341825Sdim// device into a buffer on the heap. Returning a shared pointer to the buffer 2350341825Sdim// containing the data. 2351296417Sdimstd::shared_ptr<uint8_t> 2352314564SdimRenderScriptRuntime::GetAllocationData(AllocationDetails *alloc, 2353314564Sdim StackFrame *frame_ptr) { 2354314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2355296417Sdim 2356314564Sdim // JIT all the allocation details 2357314564Sdim if (alloc->ShouldRefresh()) { 2358360784Sdim LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info", 2359360784Sdim __FUNCTION__); 2360296417Sdim 2361314564Sdim if (!RefreshAllocation(alloc, frame_ptr)) { 2362360784Sdim LLDB_LOGF(log, "%s - couldn't JIT allocation details", __FUNCTION__); 2363314564Sdim return nullptr; 2364296417Sdim } 2365314564Sdim } 2366296417Sdim 2367314564Sdim assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && 2368314564Sdim alloc->element.type_vec_size.isValid() && alloc->size.isValid() && 2369314564Sdim "Allocation information not available"); 2370296417Sdim 2371314564Sdim // Allocate a buffer to copy data into 2372314564Sdim const uint32_t size = *alloc->size.get(); 2373314564Sdim std::shared_ptr<uint8_t> buffer(new uint8_t[size]); 2374314564Sdim if (!buffer) { 2375360784Sdim LLDB_LOGF(log, "%s - couldn't allocate a %" PRIu32 " byte buffer", 2376360784Sdim __FUNCTION__, size); 2377314564Sdim return nullptr; 2378314564Sdim } 2379296417Sdim 2380314564Sdim // Read the inferior memory 2381321369Sdim Status err; 2382314564Sdim lldb::addr_t data_ptr = *alloc->data_ptr.get(); 2383314564Sdim GetProcess()->ReadMemory(data_ptr, buffer.get(), size, err); 2384314564Sdim if (err.Fail()) { 2385360784Sdim LLDB_LOGF(log, 2386360784Sdim "%s - '%s' Couldn't read %" PRIu32 2387360784Sdim " bytes of allocation data from 0x%" PRIx64, 2388360784Sdim __FUNCTION__, err.AsCString(), size, data_ptr); 2389314564Sdim return nullptr; 2390314564Sdim } 2391296417Sdim 2392314564Sdim return buffer; 2393296417Sdim} 2394296417Sdim 2395341825Sdim// Function copies data from a binary file into an allocation. There is a 2396341825Sdim// header at the start of the file, FileHeader, before the data content itself. 2397314564Sdim// Information from this header is used to display warnings to the user about 2398314564Sdim// incompatibilities 2399314564Sdimbool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, 2400314564Sdim const char *path, 2401314564Sdim StackFrame *frame_ptr) { 2402314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2403296417Sdim 2404314564Sdim // Find allocation with the given id 2405314564Sdim AllocationDetails *alloc = FindAllocByID(strm, alloc_id); 2406314564Sdim if (!alloc) 2407314564Sdim return false; 2408296417Sdim 2409360784Sdim LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64, __FUNCTION__, 2410360784Sdim *alloc->address.get()); 2411314564Sdim 2412314564Sdim // JIT all the allocation details 2413314564Sdim if (alloc->ShouldRefresh()) { 2414360784Sdim LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.", 2415360784Sdim __FUNCTION__); 2416296417Sdim 2417314564Sdim if (!RefreshAllocation(alloc, frame_ptr)) { 2418360784Sdim LLDB_LOGF(log, "%s - couldn't JIT allocation details", __FUNCTION__); 2419314564Sdim return false; 2420296417Sdim } 2421314564Sdim } 2422296417Sdim 2423314564Sdim assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && 2424314564Sdim alloc->element.type_vec_size.isValid() && alloc->size.isValid() && 2425314564Sdim alloc->element.datum_size.isValid() && 2426314564Sdim "Allocation information not available"); 2427296417Sdim 2428314564Sdim // Check we can read from file 2429344779Sdim FileSpec file(path); 2430344779Sdim FileSystem::Instance().Resolve(file); 2431344779Sdim if (!FileSystem::Instance().Exists(file)) { 2432314564Sdim strm.Printf("Error: File %s does not exist", path); 2433314564Sdim strm.EOL(); 2434314564Sdim return false; 2435314564Sdim } 2436296417Sdim 2437344779Sdim if (!FileSystem::Instance().Readable(file)) { 2438314564Sdim strm.Printf("Error: File %s does not have readable permissions", path); 2439314564Sdim strm.EOL(); 2440314564Sdim return false; 2441314564Sdim } 2442296417Sdim 2443314564Sdim // Read file into data buffer 2444344779Sdim auto data_sp = FileSystem::Instance().CreateDataBuffer(file.GetPath()); 2445296417Sdim 2446314564Sdim // Cast start of buffer to FileHeader and use pointer to read metadata 2447314564Sdim void *file_buf = data_sp->GetBytes(); 2448314564Sdim if (file_buf == nullptr || 2449314564Sdim data_sp->GetByteSize() < (sizeof(AllocationDetails::FileHeader) + 2450314564Sdim sizeof(AllocationDetails::ElementHeader))) { 2451314564Sdim strm.Printf("Error: File %s does not contain enough data for header", path); 2452314564Sdim strm.EOL(); 2453314564Sdim return false; 2454314564Sdim } 2455314564Sdim const AllocationDetails::FileHeader *file_header = 2456314564Sdim static_cast<AllocationDetails::FileHeader *>(file_buf); 2457296417Sdim 2458314564Sdim // Check file starts with ascii characters "RSAD" 2459314564Sdim if (memcmp(file_header->ident, "RSAD", 4)) { 2460314564Sdim strm.Printf("Error: File doesn't contain identifier for an RS allocation " 2461314564Sdim "dump. Are you sure this is the correct file?"); 2462314564Sdim strm.EOL(); 2463314564Sdim return false; 2464314564Sdim } 2465296417Sdim 2466314564Sdim // Look at the type of the root element in the header 2467314564Sdim AllocationDetails::ElementHeader root_el_hdr; 2468314564Sdim memcpy(&root_el_hdr, static_cast<uint8_t *>(file_buf) + 2469314564Sdim sizeof(AllocationDetails::FileHeader), 2470314564Sdim sizeof(AllocationDetails::ElementHeader)); 2471296417Sdim 2472360784Sdim LLDB_LOGF(log, "%s - header type %" PRIu32 ", element size %" PRIu32, 2473360784Sdim __FUNCTION__, root_el_hdr.type, root_el_hdr.element_size); 2474296417Sdim 2475314564Sdim // Check if the target allocation and file both have the same number of bytes 2476314564Sdim // for an Element 2477314564Sdim if (*alloc->element.datum_size.get() != root_el_hdr.element_size) { 2478314564Sdim strm.Printf("Warning: Mismatched Element sizes - file %" PRIu32 2479314564Sdim " bytes, allocation %" PRIu32 " bytes", 2480314564Sdim root_el_hdr.element_size, *alloc->element.datum_size.get()); 2481314564Sdim strm.EOL(); 2482314564Sdim } 2483296417Sdim 2484314564Sdim // Check if the target allocation and file both have the same type 2485314564Sdim const uint32_t alloc_type = static_cast<uint32_t>(*alloc->element.type.get()); 2486314564Sdim const uint32_t file_type = root_el_hdr.type; 2487296417Sdim 2488314564Sdim if (file_type > Element::RS_TYPE_FONT) { 2489314564Sdim strm.Printf("Warning: File has unknown allocation type"); 2490314564Sdim strm.EOL(); 2491314564Sdim } else if (alloc_type != file_type) { 2492314564Sdim // Enum value isn't monotonous, so doesn't always index RsDataTypeToString 2493314564Sdim // array 2494314564Sdim uint32_t target_type_name_idx = alloc_type; 2495314564Sdim uint32_t head_type_name_idx = file_type; 2496314564Sdim if (alloc_type >= Element::RS_TYPE_ELEMENT && 2497314564Sdim alloc_type <= Element::RS_TYPE_FONT) 2498314564Sdim target_type_name_idx = static_cast<Element::DataType>( 2499314564Sdim (alloc_type - Element::RS_TYPE_ELEMENT) + 2500314564Sdim Element::RS_TYPE_MATRIX_2X2 + 1); 2501296417Sdim 2502314564Sdim if (file_type >= Element::RS_TYPE_ELEMENT && 2503314564Sdim file_type <= Element::RS_TYPE_FONT) 2504314564Sdim head_type_name_idx = static_cast<Element::DataType>( 2505314564Sdim (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 2506314564Sdim 1); 2507296417Sdim 2508314564Sdim const char *head_type_name = 2509314564Sdim AllocationDetails::RsDataTypeToString[head_type_name_idx][0]; 2510314564Sdim const char *target_type_name = 2511314564Sdim AllocationDetails::RsDataTypeToString[target_type_name_idx][0]; 2512296417Sdim 2513314564Sdim strm.Printf( 2514314564Sdim "Warning: Mismatched Types - file '%s' type, allocation '%s' type", 2515314564Sdim head_type_name, target_type_name); 2516314564Sdim strm.EOL(); 2517314564Sdim } 2518296417Sdim 2519314564Sdim // Advance buffer past header 2520314564Sdim file_buf = static_cast<uint8_t *>(file_buf) + file_header->hdr_size; 2521296417Sdim 2522314564Sdim // Calculate size of allocation data in file 2523314564Sdim size_t size = data_sp->GetByteSize() - file_header->hdr_size; 2524296417Sdim 2525341825Sdim // Check if the target allocation and file both have the same total data 2526341825Sdim // size. 2527314564Sdim const uint32_t alloc_size = *alloc->size.get(); 2528314564Sdim if (alloc_size != size) { 2529314564Sdim strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64 2530314564Sdim " bytes, allocation 0x%" PRIx32 " bytes", 2531314564Sdim (uint64_t)size, alloc_size); 2532314564Sdim strm.EOL(); 2533314564Sdim // Set length to copy to minimum 2534314564Sdim size = alloc_size < size ? alloc_size : size; 2535314564Sdim } 2536296417Sdim 2537314564Sdim // Copy file data from our buffer into the target allocation. 2538314564Sdim lldb::addr_t alloc_data = *alloc->data_ptr.get(); 2539321369Sdim Status err; 2540314564Sdim size_t written = GetProcess()->WriteMemory(alloc_data, file_buf, size, err); 2541314564Sdim if (!err.Success() || written != size) { 2542314564Sdim strm.Printf("Error: Couldn't write data to allocation %s", err.AsCString()); 2543296417Sdim strm.EOL(); 2544314564Sdim return false; 2545314564Sdim } 2546296417Sdim 2547314564Sdim strm.Printf("Contents of file '%s' read into allocation %" PRIu32, path, 2548314564Sdim alloc->id); 2549314564Sdim strm.EOL(); 2550314564Sdim 2551314564Sdim return true; 2552296417Sdim} 2553296417Sdim 2554314564Sdim// Function takes as parameters a byte buffer, which will eventually be written 2555314564Sdim// to file as the element header, an offset into that buffer, and an Element 2556341825Sdim// that will be saved into the buffer at the parametrised offset. Return value 2557341825Sdim// is the new offset after writing the element into the buffer. Elements are 2558341825Sdim// saved to the file as the ElementHeader struct followed by offsets to the 2559341825Sdim// structs of all the element's children. 2560314564Sdimsize_t RenderScriptRuntime::PopulateElementHeaders( 2561314564Sdim const std::shared_ptr<uint8_t> header_buffer, size_t offset, 2562314564Sdim const Element &elem) { 2563341825Sdim // File struct for an element header with all the relevant details copied 2564341825Sdim // from elem. We assume members are valid already. 2565314564Sdim AllocationDetails::ElementHeader elem_header; 2566314564Sdim elem_header.type = *elem.type.get(); 2567314564Sdim elem_header.kind = *elem.type_kind.get(); 2568314564Sdim elem_header.element_size = *elem.datum_size.get(); 2569314564Sdim elem_header.vector_size = *elem.type_vec_size.get(); 2570314564Sdim elem_header.array_size = 2571314564Sdim elem.array_size.isValid() ? *elem.array_size.get() : 0; 2572314564Sdim const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader); 2573296417Sdim 2574341825Sdim // Copy struct into buffer and advance offset We assume that header_buffer 2575341825Sdim // has been checked for nullptr before this method is called 2576314564Sdim memcpy(header_buffer.get() + offset, &elem_header, elem_header_size); 2577314564Sdim offset += elem_header_size; 2578296417Sdim 2579314564Sdim // Starting offset of child ElementHeader struct 2580314564Sdim size_t child_offset = 2581314564Sdim offset + ((elem.children.size() + 1) * sizeof(uint32_t)); 2582314564Sdim for (const RenderScriptRuntime::Element &child : elem.children) { 2583314564Sdim // Recursively populate the buffer with the element header structs of 2584314564Sdim // children. Then save the offsets where they were set after the parent 2585314564Sdim // element header. 2586314564Sdim memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t)); 2587314564Sdim offset += sizeof(uint32_t); 2588296417Sdim 2589314564Sdim child_offset = PopulateElementHeaders(header_buffer, child_offset, child); 2590314564Sdim } 2591296417Sdim 2592314564Sdim // Zero indicates no more children 2593314564Sdim memset(header_buffer.get() + offset, 0, sizeof(uint32_t)); 2594296417Sdim 2595314564Sdim return child_offset; 2596296417Sdim} 2597296417Sdim 2598314564Sdim// Given an Element object this function returns the total size needed in the 2599314564Sdim// file header to store the element's details. Taking into account the size of 2600314564Sdim// the element header struct, plus the offsets to all the element's children. 2601314564Sdim// Function is recursive so that the size of all ancestors is taken into 2602314564Sdim// account. 2603314564Sdimsize_t RenderScriptRuntime::CalculateElementHeaderSize(const Element &elem) { 2604314564Sdim // Offsets to children plus zero terminator 2605314564Sdim size_t size = (elem.children.size() + 1) * sizeof(uint32_t); 2606314564Sdim // Size of header struct with type details 2607314564Sdim size += sizeof(AllocationDetails::ElementHeader); 2608296417Sdim 2609314564Sdim // Calculate recursively for all descendants 2610314564Sdim for (const Element &child : elem.children) 2611314564Sdim size += CalculateElementHeaderSize(child); 2612296417Sdim 2613314564Sdim return size; 2614296417Sdim} 2615296417Sdim 2616341825Sdim// Function copies allocation contents into a binary file. This file can then 2617341825Sdim// be loaded later into a different allocation. There is a header, FileHeader, 2618314564Sdim// before the allocation data containing meta-data. 2619314564Sdimbool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, 2620314564Sdim const char *path, 2621314564Sdim StackFrame *frame_ptr) { 2622314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2623296417Sdim 2624314564Sdim // Find allocation with the given id 2625314564Sdim AllocationDetails *alloc = FindAllocByID(strm, alloc_id); 2626314564Sdim if (!alloc) 2627314564Sdim return false; 2628296417Sdim 2629360784Sdim LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64 ".", __FUNCTION__, 2630360784Sdim *alloc->address.get()); 2631314564Sdim 2632314564Sdim // JIT all the allocation details 2633314564Sdim if (alloc->ShouldRefresh()) { 2634360784Sdim LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.", 2635360784Sdim __FUNCTION__); 2636296417Sdim 2637314564Sdim if (!RefreshAllocation(alloc, frame_ptr)) { 2638360784Sdim LLDB_LOGF(log, "%s - couldn't JIT allocation details.", __FUNCTION__); 2639314564Sdim return false; 2640296417Sdim } 2641314564Sdim } 2642296417Sdim 2643314564Sdim assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && 2644314564Sdim alloc->element.type_vec_size.isValid() && 2645314564Sdim alloc->element.datum_size.get() && 2646314564Sdim alloc->element.type_kind.isValid() && alloc->dimension.isValid() && 2647314564Sdim "Allocation information not available"); 2648296417Sdim 2649314564Sdim // Check we can create writable file 2650344779Sdim FileSpec file_spec(path); 2651344779Sdim FileSystem::Instance().Resolve(file_spec); 2652360784Sdim auto file = FileSystem::Instance().Open( 2653360784Sdim file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate | 2654360784Sdim File::eOpenOptionTruncate); 2655344779Sdim 2656314564Sdim if (!file) { 2657360784Sdim std::string error = llvm::toString(file.takeError()); 2658360784Sdim strm.Printf("Error: Failed to open '%s' for writing: %s", path, 2659360784Sdim error.c_str()); 2660314564Sdim strm.EOL(); 2661314564Sdim return false; 2662314564Sdim } 2663296417Sdim 2664314564Sdim // Read allocation into buffer of heap memory 2665314564Sdim const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); 2666314564Sdim if (!buffer) { 2667314564Sdim strm.Printf("Error: Couldn't read allocation data into buffer"); 2668314564Sdim strm.EOL(); 2669314564Sdim return false; 2670314564Sdim } 2671296417Sdim 2672314564Sdim // Create the file header 2673314564Sdim AllocationDetails::FileHeader head; 2674314564Sdim memcpy(head.ident, "RSAD", 4); 2675314564Sdim head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1); 2676314564Sdim head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2); 2677314564Sdim head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3); 2678296417Sdim 2679314564Sdim const size_t element_header_size = CalculateElementHeaderSize(alloc->element); 2680314564Sdim assert((sizeof(AllocationDetails::FileHeader) + element_header_size) < 2681314564Sdim UINT16_MAX && 2682314564Sdim "Element header too large"); 2683314564Sdim head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) + 2684314564Sdim element_header_size); 2685296417Sdim 2686314564Sdim // Write the file header 2687314564Sdim size_t num_bytes = sizeof(AllocationDetails::FileHeader); 2688360784Sdim LLDB_LOGF(log, "%s - writing File Header, 0x%" PRIx64 " bytes", __FUNCTION__, 2689360784Sdim (uint64_t)num_bytes); 2690296417Sdim 2691360784Sdim Status err = file.get()->Write(&head, num_bytes); 2692314564Sdim if (!err.Success()) { 2693314564Sdim strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path); 2694314564Sdim strm.EOL(); 2695314564Sdim return false; 2696314564Sdim } 2697296417Sdim 2698314564Sdim // Create the headers describing the element type of the allocation. 2699314564Sdim std::shared_ptr<uint8_t> element_header_buffer( 2700314564Sdim new uint8_t[element_header_size]); 2701314564Sdim if (element_header_buffer == nullptr) { 2702314564Sdim strm.Printf("Internal Error: Couldn't allocate %" PRIu64 2703314564Sdim " bytes on the heap", 2704314564Sdim (uint64_t)element_header_size); 2705314564Sdim strm.EOL(); 2706314564Sdim return false; 2707314564Sdim } 2708296417Sdim 2709314564Sdim PopulateElementHeaders(element_header_buffer, 0, alloc->element); 2710296417Sdim 2711314564Sdim // Write headers for allocation element type to file 2712314564Sdim num_bytes = element_header_size; 2713360784Sdim LLDB_LOGF(log, "%s - writing element headers, 0x%" PRIx64 " bytes.", 2714360784Sdim __FUNCTION__, (uint64_t)num_bytes); 2715296417Sdim 2716360784Sdim err = file.get()->Write(element_header_buffer.get(), num_bytes); 2717314564Sdim if (!err.Success()) { 2718314564Sdim strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path); 2719314564Sdim strm.EOL(); 2720314564Sdim return false; 2721314564Sdim } 2722296417Sdim 2723314564Sdim // Write allocation data to file 2724314564Sdim num_bytes = static_cast<size_t>(*alloc->size.get()); 2725360784Sdim LLDB_LOGF(log, "%s - writing 0x%" PRIx64 " bytes", __FUNCTION__, 2726360784Sdim (uint64_t)num_bytes); 2727296417Sdim 2728360784Sdim err = file.get()->Write(buffer.get(), num_bytes); 2729314564Sdim if (!err.Success()) { 2730314564Sdim strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path); 2731314564Sdim strm.EOL(); 2732314564Sdim return false; 2733314564Sdim } 2734296417Sdim 2735314564Sdim strm.Printf("Allocation written to file '%s'", path); 2736314564Sdim strm.EOL(); 2737314564Sdim return true; 2738296417Sdim} 2739296417Sdim 2740314564Sdimbool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) { 2741314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2742285101Semaste 2743314564Sdim if (module_sp) { 2744314564Sdim for (const auto &rs_module : m_rsmodules) { 2745314564Sdim if (rs_module->m_module == module_sp) { 2746341825Sdim // Check if the user has enabled automatically breaking on all RS 2747341825Sdim // kernels. 2748314564Sdim if (m_breakAllKernels) 2749314564Sdim BreakOnModuleKernels(rs_module); 2750296417Sdim 2751314564Sdim return false; 2752314564Sdim } 2753314564Sdim } 2754314564Sdim bool module_loaded = false; 2755314564Sdim switch (GetModuleKind(module_sp)) { 2756314564Sdim case eModuleKindKernelObj: { 2757314564Sdim RSModuleDescriptorSP module_desc; 2758353358Sdim module_desc = std::make_shared<RSModuleDescriptor>(module_sp); 2759314564Sdim if (module_desc->ParseRSInfo()) { 2760314564Sdim m_rsmodules.push_back(module_desc); 2761314564Sdim module_desc->WarnIfVersionMismatch(GetProcess() 2762314564Sdim ->GetTarget() 2763314564Sdim .GetDebugger() 2764314564Sdim .GetAsyncOutputStream() 2765314564Sdim .get()); 2766314564Sdim module_loaded = true; 2767314564Sdim } 2768314564Sdim if (module_loaded) { 2769314564Sdim FixupScriptDetails(module_desc); 2770314564Sdim } 2771314564Sdim break; 2772314564Sdim } 2773314564Sdim case eModuleKindDriver: { 2774314564Sdim if (!m_libRSDriver) { 2775314564Sdim m_libRSDriver = module_sp; 2776314564Sdim LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver); 2777314564Sdim } 2778314564Sdim break; 2779314564Sdim } 2780314564Sdim case eModuleKindImpl: { 2781314564Sdim if (!m_libRSCpuRef) { 2782314564Sdim m_libRSCpuRef = module_sp; 2783314564Sdim LoadRuntimeHooks(m_libRSCpuRef, RenderScriptRuntime::eModuleKindImpl); 2784314564Sdim } 2785314564Sdim break; 2786314564Sdim } 2787314564Sdim case eModuleKindLibRS: { 2788314564Sdim if (!m_libRS) { 2789314564Sdim m_libRS = module_sp; 2790314564Sdim static ConstString gDbgPresentStr("gDebuggerPresent"); 2791314564Sdim const Symbol *debug_present = m_libRS->FindFirstSymbolWithNameAndType( 2792314564Sdim gDbgPresentStr, eSymbolTypeData); 2793314564Sdim if (debug_present) { 2794321369Sdim Status err; 2795314564Sdim uint32_t flag = 0x00000001U; 2796314564Sdim Target &target = GetProcess()->GetTarget(); 2797314564Sdim addr_t addr = debug_present->GetLoadAddress(&target); 2798314564Sdim GetProcess()->WriteMemory(addr, &flag, sizeof(flag), err); 2799314564Sdim if (err.Success()) { 2800360784Sdim LLDB_LOGF(log, "%s - debugger present flag set on debugee.", 2801360784Sdim __FUNCTION__); 2802285101Semaste 2803314564Sdim m_debuggerPresentFlagged = true; 2804314564Sdim } else if (log) { 2805360784Sdim LLDB_LOGF(log, "%s - error writing debugger present flags '%s' ", 2806360784Sdim __FUNCTION__, err.AsCString()); 2807314564Sdim } 2808314564Sdim } else if (log) { 2809360784Sdim LLDB_LOGF( 2810360784Sdim log, 2811314564Sdim "%s - error writing debugger present flags - symbol not found", 2812314564Sdim __FUNCTION__); 2813285101Semaste } 2814314564Sdim } 2815314564Sdim break; 2816285101Semaste } 2817314564Sdim default: 2818314564Sdim break; 2819314564Sdim } 2820314564Sdim if (module_loaded) 2821314564Sdim Update(); 2822314564Sdim return module_loaded; 2823314564Sdim } 2824314564Sdim return false; 2825285101Semaste} 2826285101Semaste 2827314564Sdimvoid RenderScriptRuntime::Update() { 2828314564Sdim if (m_rsmodules.size() > 0) { 2829314564Sdim if (!m_initiated) { 2830314564Sdim Initiate(); 2831285101Semaste } 2832314564Sdim } 2833285101Semaste} 2834285101Semaste 2835314564Sdimvoid RSModuleDescriptor::WarnIfVersionMismatch(lldb_private::Stream *s) const { 2836314564Sdim if (!s) 2837314564Sdim return; 2838285101Semaste 2839314564Sdim if (m_slang_version.empty() || m_bcc_version.empty()) { 2840314564Sdim s->PutCString("WARNING: Unknown bcc or slang (llvm-rs-cc) version; debug " 2841314564Sdim "experience may be unreliable"); 2842314564Sdim s->EOL(); 2843314564Sdim } else if (m_slang_version != m_bcc_version) { 2844314564Sdim s->Printf("WARNING: The debug info emitted by the slang frontend " 2845314564Sdim "(llvm-rs-cc) used to build this module (%s) does not match the " 2846314564Sdim "version of bcc used to generate the debug information (%s). " 2847314564Sdim "This is an unsupported configuration and may result in a poor " 2848314564Sdim "debugging experience; proceed with caution", 2849314564Sdim m_slang_version.c_str(), m_bcc_version.c_str()); 2850314564Sdim s->EOL(); 2851314564Sdim } 2852314564Sdim} 2853285101Semaste 2854314564Sdimbool RSModuleDescriptor::ParsePragmaCount(llvm::StringRef *lines, 2855314564Sdim size_t n_lines) { 2856314564Sdim // Skip the pragma prototype line 2857314564Sdim ++lines; 2858314564Sdim for (; n_lines--; ++lines) { 2859314564Sdim const auto kv_pair = lines->split(" - "); 2860314564Sdim m_pragmas[kv_pair.first.trim().str()] = kv_pair.second.trim().str(); 2861314564Sdim } 2862314564Sdim return true; 2863314564Sdim} 2864285101Semaste 2865314564Sdimbool RSModuleDescriptor::ParseExportReduceCount(llvm::StringRef *lines, 2866314564Sdim size_t n_lines) { 2867314564Sdim // The list of reduction kernels in the `.rs.info` symbol is of the form 2868314564Sdim // "signature - accumulatordatasize - reduction_name - initializer_name - 2869341825Sdim // accumulator_name - combiner_name - outconverter_name - halter_name" Where 2870341825Sdim // a function is not explicitly named by the user, or is not generated by the 2871341825Sdim // compiler, it is named "." so the dash separated list should always be 8 2872341825Sdim // items long 2873314564Sdim Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 2874314564Sdim // Skip the exportReduceCount line 2875314564Sdim ++lines; 2876314564Sdim for (; n_lines--; ++lines) { 2877314564Sdim llvm::SmallVector<llvm::StringRef, 8> spec; 2878314564Sdim lines->split(spec, " - "); 2879314564Sdim if (spec.size() != 8) { 2880314564Sdim if (spec.size() < 8) { 2881314564Sdim if (log) 2882314564Sdim log->Error("Error parsing RenderScript reduction spec. wrong number " 2883314564Sdim "of fields"); 2884309124Sdim return false; 2885314564Sdim } else if (log) 2886314564Sdim log->Warning("Extraneous members in reduction spec: '%s'", 2887314564Sdim lines->str().c_str()); 2888314564Sdim } 2889285101Semaste 2890314564Sdim const auto sig_s = spec[0]; 2891314564Sdim uint32_t sig; 2892314564Sdim if (sig_s.getAsInteger(10, sig)) { 2893314564Sdim if (log) 2894314564Sdim log->Error("Error parsing Renderscript reduction spec: invalid kernel " 2895314564Sdim "signature: '%s'", 2896314564Sdim sig_s.str().c_str()); 2897314564Sdim return false; 2898309124Sdim } 2899309124Sdim 2900314564Sdim const auto accum_data_size_s = spec[1]; 2901314564Sdim uint32_t accum_data_size; 2902314564Sdim if (accum_data_size_s.getAsInteger(10, accum_data_size)) { 2903314564Sdim if (log) 2904314564Sdim log->Error("Error parsing Renderscript reduction spec: invalid " 2905314564Sdim "accumulator data size %s", 2906314564Sdim accum_data_size_s.str().c_str()); 2907314564Sdim return false; 2908285101Semaste } 2909285101Semaste 2910360784Sdim LLDB_LOGF(log, "Found RenderScript reduction '%s'", spec[2].str().c_str()); 2911314564Sdim 2912314564Sdim m_reductions.push_back(RSReductionDescriptor(this, sig, accum_data_size, 2913314564Sdim spec[2], spec[3], spec[4], 2914314564Sdim spec[5], spec[6], spec[7])); 2915314564Sdim } 2916314564Sdim return true; 2917285101Semaste} 2918285101Semaste 2919314564Sdimbool RSModuleDescriptor::ParseVersionInfo(llvm::StringRef *lines, 2920314564Sdim size_t n_lines) { 2921314564Sdim // Skip the versionInfo line 2922314564Sdim ++lines; 2923314564Sdim for (; n_lines--; ++lines) { 2924314564Sdim // We're only interested in bcc and slang versions, and ignore all other 2925314564Sdim // versionInfo lines 2926314564Sdim const auto kv_pair = lines->split(" - "); 2927314564Sdim if (kv_pair.first == "slang") 2928314564Sdim m_slang_version = kv_pair.second.str(); 2929314564Sdim else if (kv_pair.first == "bcc") 2930314564Sdim m_bcc_version = kv_pair.second.str(); 2931314564Sdim } 2932314564Sdim return true; 2933314564Sdim} 2934314564Sdim 2935314564Sdimbool RSModuleDescriptor::ParseExportForeachCount(llvm::StringRef *lines, 2936314564Sdim size_t n_lines) { 2937314564Sdim // Skip the exportForeachCount line 2938314564Sdim ++lines; 2939314564Sdim for (; n_lines--; ++lines) { 2940314564Sdim uint32_t slot; 2941314564Sdim // `forEach` kernels are listed in the `.rs.info` packet as a "slot - name" 2942314564Sdim // pair per line 2943314564Sdim const auto kv_pair = lines->split(" - "); 2944314564Sdim if (kv_pair.first.getAsInteger(10, slot)) 2945314564Sdim return false; 2946314564Sdim m_kernels.push_back(RSKernelDescriptor(this, kv_pair.second, slot)); 2947314564Sdim } 2948314564Sdim return true; 2949314564Sdim} 2950314564Sdim 2951314564Sdimbool RSModuleDescriptor::ParseExportVarCount(llvm::StringRef *lines, 2952314564Sdim size_t n_lines) { 2953314564Sdim // Skip the ExportVarCount line 2954314564Sdim ++lines; 2955314564Sdim for (; n_lines--; ++lines) 2956314564Sdim m_globals.push_back(RSGlobalDescriptor(this, *lines)); 2957314564Sdim return true; 2958314564Sdim} 2959314564Sdim 2960314564Sdim// The .rs.info symbol in renderscript modules contains a string which needs to 2961341825Sdim// be parsed. The string is basic and is parsed on a line by line basis. 2962314564Sdimbool RSModuleDescriptor::ParseRSInfo() { 2963314564Sdim assert(m_module); 2964314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2965314564Sdim const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType( 2966314564Sdim ConstString(".rs.info"), eSymbolTypeData); 2967314564Sdim if (!info_sym) 2968314564Sdim return false; 2969314564Sdim 2970314564Sdim const addr_t addr = info_sym->GetAddressRef().GetFileAddress(); 2971314564Sdim if (addr == LLDB_INVALID_ADDRESS) 2972314564Sdim return false; 2973314564Sdim 2974314564Sdim const addr_t size = info_sym->GetByteSize(); 2975314564Sdim const FileSpec fs = m_module->GetFileSpec(); 2976314564Sdim 2977344779Sdim auto buffer = 2978344779Sdim FileSystem::Instance().CreateDataBuffer(fs.GetPath(), size, addr); 2979314564Sdim if (!buffer) 2980314564Sdim return false; 2981314564Sdim 2982314564Sdim // split rs.info. contents into lines 2983314564Sdim llvm::SmallVector<llvm::StringRef, 128> info_lines; 2984314564Sdim { 2985314564Sdim const llvm::StringRef raw_rs_info((const char *)buffer->GetBytes()); 2986314564Sdim raw_rs_info.split(info_lines, '\n'); 2987360784Sdim LLDB_LOGF(log, "'.rs.info symbol for '%s':\n%s", 2988360784Sdim m_module->GetFileSpec().GetCString(), raw_rs_info.str().c_str()); 2989314564Sdim } 2990314564Sdim 2991314564Sdim enum { 2992314564Sdim eExportVar, 2993314564Sdim eExportForEach, 2994314564Sdim eExportReduce, 2995314564Sdim ePragma, 2996314564Sdim eBuildChecksum, 2997314564Sdim eObjectSlot, 2998314564Sdim eVersionInfo, 2999314564Sdim }; 3000314564Sdim 3001314564Sdim const auto rs_info_handler = [](llvm::StringRef name) -> int { 3002314564Sdim return llvm::StringSwitch<int>(name) 3003314564Sdim // The number of visible global variables in the script 3004314564Sdim .Case("exportVarCount", eExportVar) 3005314564Sdim // The number of RenderScrip `forEach` kernels __attribute__((kernel)) 3006314564Sdim .Case("exportForEachCount", eExportForEach) 3007314564Sdim // The number of generalreductions: This marked in the script by 3008314564Sdim // `#pragma reduce()` 3009314564Sdim .Case("exportReduceCount", eExportReduce) 3010314564Sdim // Total count of all RenderScript specific `#pragmas` used in the 3011314564Sdim // script 3012314564Sdim .Case("pragmaCount", ePragma) 3013314564Sdim .Case("objectSlotCount", eObjectSlot) 3014314564Sdim .Case("versionInfo", eVersionInfo) 3015314564Sdim .Default(-1); 3016314564Sdim }; 3017314564Sdim 3018314564Sdim // parse all text lines of .rs.info 3019314564Sdim for (auto line = info_lines.begin(); line != info_lines.end(); ++line) { 3020314564Sdim const auto kv_pair = line->split(": "); 3021314564Sdim const auto key = kv_pair.first; 3022314564Sdim const auto val = kv_pair.second.trim(); 3023314564Sdim 3024314564Sdim const auto handler = rs_info_handler(key); 3025314564Sdim if (handler == -1) 3026314564Sdim continue; 3027341825Sdim // getAsInteger returns `true` on an error condition - we're only 3028341825Sdim // interested in numeric fields at the moment 3029314564Sdim uint64_t n_lines; 3030314564Sdim if (val.getAsInteger(10, n_lines)) { 3031321369Sdim LLDB_LOGV(log, "Failed to parse non-numeric '.rs.info' section {0}", 3032321369Sdim line->str()); 3033314564Sdim continue; 3034285101Semaste } 3035314564Sdim if (info_lines.end() - (line + 1) < (ptrdiff_t)n_lines) 3036314564Sdim return false; 3037296417Sdim 3038314564Sdim bool success = false; 3039314564Sdim switch (handler) { 3040314564Sdim case eExportVar: 3041314564Sdim success = ParseExportVarCount(line, n_lines); 3042314564Sdim break; 3043314564Sdim case eExportForEach: 3044314564Sdim success = ParseExportForeachCount(line, n_lines); 3045314564Sdim break; 3046314564Sdim case eExportReduce: 3047314564Sdim success = ParseExportReduceCount(line, n_lines); 3048314564Sdim break; 3049314564Sdim case ePragma: 3050314564Sdim success = ParsePragmaCount(line, n_lines); 3051314564Sdim break; 3052314564Sdim case eVersionInfo: 3053314564Sdim success = ParseVersionInfo(line, n_lines); 3054314564Sdim break; 3055314564Sdim default: { 3056360784Sdim LLDB_LOGF(log, "%s - skipping .rs.info field '%s'", __FUNCTION__, 3057360784Sdim line->str().c_str()); 3058314564Sdim continue; 3059296417Sdim } 3060285101Semaste } 3061314564Sdim if (!success) 3062314564Sdim return false; 3063314564Sdim line += n_lines; 3064314564Sdim } 3065314564Sdim return info_lines.size() > 0; 3066285101Semaste} 3067285101Semaste 3068321369Sdimvoid RenderScriptRuntime::DumpStatus(Stream &strm) const { 3069314564Sdim if (m_libRS) { 3070314564Sdim strm.Printf("Runtime Library discovered."); 3071285101Semaste strm.EOL(); 3072314564Sdim } 3073314564Sdim if (m_libRSDriver) { 3074314564Sdim strm.Printf("Runtime Driver discovered."); 3075314564Sdim strm.EOL(); 3076314564Sdim } 3077314564Sdim if (m_libRSCpuRef) { 3078314564Sdim strm.Printf("CPU Reference Implementation discovered."); 3079314564Sdim strm.EOL(); 3080314564Sdim } 3081285101Semaste 3082314564Sdim if (m_runtimeHooks.size()) { 3083314564Sdim strm.Printf("Runtime functions hooked:"); 3084314564Sdim strm.EOL(); 3085314564Sdim for (auto b : m_runtimeHooks) { 3086314564Sdim strm.Indent(b.second->defn->name); 3087314564Sdim strm.EOL(); 3088314564Sdim } 3089314564Sdim } else { 3090314564Sdim strm.Printf("Runtime is not hooked."); 3091314564Sdim strm.EOL(); 3092314564Sdim } 3093314564Sdim} 3094285101Semaste 3095314564Sdimvoid RenderScriptRuntime::DumpContexts(Stream &strm) const { 3096314564Sdim strm.Printf("Inferred RenderScript Contexts:"); 3097314564Sdim strm.EOL(); 3098314564Sdim strm.IndentMore(); 3099296417Sdim 3100314564Sdim std::map<addr_t, uint64_t> contextReferences; 3101314564Sdim 3102341825Sdim // Iterate over all of the currently discovered scripts. Note: We cant push 3103341825Sdim // or pop from m_scripts inside this loop or it may invalidate script. 3104314564Sdim for (const auto &script : m_scripts) { 3105314564Sdim if (!script->context.isValid()) 3106314564Sdim continue; 3107314564Sdim lldb::addr_t context = *script->context; 3108314564Sdim 3109314564Sdim if (contextReferences.find(context) != contextReferences.end()) { 3110314564Sdim contextReferences[context]++; 3111314564Sdim } else { 3112314564Sdim contextReferences[context] = 1; 3113285101Semaste } 3114314564Sdim } 3115285101Semaste 3116314564Sdim for (const auto &cRef : contextReferences) { 3117314564Sdim strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances", 3118314564Sdim cRef.first, cRef.second); 3119314564Sdim strm.EOL(); 3120314564Sdim } 3121314564Sdim strm.IndentLess(); 3122285101Semaste} 3123285101Semaste 3124314564Sdimvoid RenderScriptRuntime::DumpKernels(Stream &strm) const { 3125314564Sdim strm.Printf("RenderScript Kernels:"); 3126314564Sdim strm.EOL(); 3127314564Sdim strm.IndentMore(); 3128314564Sdim for (const auto &module : m_rsmodules) { 3129314564Sdim strm.Printf("Resource '%s':", module->m_resname.c_str()); 3130285101Semaste strm.EOL(); 3131314564Sdim for (const auto &kernel : module->m_kernels) { 3132314564Sdim strm.Indent(kernel.m_name.AsCString()); 3133314564Sdim strm.EOL(); 3134285101Semaste } 3135314564Sdim } 3136314564Sdim strm.IndentLess(); 3137285101Semaste} 3138285101Semaste 3139309124SdimRenderScriptRuntime::AllocationDetails * 3140314564SdimRenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) { 3141314564Sdim AllocationDetails *alloc = nullptr; 3142296417Sdim 3143314564Sdim // See if we can find allocation using id as an index; 3144314564Sdim if (alloc_id <= m_allocations.size() && alloc_id != 0 && 3145314564Sdim m_allocations[alloc_id - 1]->id == alloc_id) { 3146314564Sdim alloc = m_allocations[alloc_id - 1].get(); 3147314564Sdim return alloc; 3148314564Sdim } 3149285101Semaste 3150314564Sdim // Fallback to searching 3151314564Sdim for (const auto &a : m_allocations) { 3152314564Sdim if (a->id == alloc_id) { 3153314564Sdim alloc = a.get(); 3154314564Sdim break; 3155296417Sdim } 3156314564Sdim } 3157296417Sdim 3158314564Sdim if (alloc == nullptr) { 3159314564Sdim strm.Printf("Error: Couldn't find allocation with id matching %" PRIu32, 3160314564Sdim alloc_id); 3161314564Sdim strm.EOL(); 3162314564Sdim } 3163296417Sdim 3164314564Sdim return alloc; 3165296417Sdim} 3166296417Sdim 3167314564Sdim// Prints the contents of an allocation to the output stream, which may be a 3168314564Sdim// file 3169314564Sdimbool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr, 3170314564Sdim const uint32_t id) { 3171314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 3172296417Sdim 3173314564Sdim // Check we can find the desired allocation 3174314564Sdim AllocationDetails *alloc = FindAllocByID(strm, id); 3175314564Sdim if (!alloc) 3176314564Sdim return false; // FindAllocByID() will print error message for us here 3177296417Sdim 3178360784Sdim LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64, __FUNCTION__, 3179360784Sdim *alloc->address.get()); 3180314564Sdim 3181314564Sdim // Check we have information about the allocation, if not calculate it 3182314564Sdim if (alloc->ShouldRefresh()) { 3183360784Sdim LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.", 3184360784Sdim __FUNCTION__); 3185296417Sdim 3186314564Sdim // JIT all the allocation information 3187314564Sdim if (!RefreshAllocation(alloc, frame_ptr)) { 3188314564Sdim strm.Printf("Error: Couldn't JIT allocation details"); 3189314564Sdim strm.EOL(); 3190314564Sdim return false; 3191296417Sdim } 3192314564Sdim } 3193285101Semaste 3194314564Sdim // Establish format and size of each data element 3195314564Sdim const uint32_t vec_size = *alloc->element.type_vec_size.get(); 3196314564Sdim const Element::DataType type = *alloc->element.type.get(); 3197285101Semaste 3198314564Sdim assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && 3199314564Sdim "Invalid allocation type"); 3200296417Sdim 3201314564Sdim lldb::Format format; 3202314564Sdim if (type >= Element::RS_TYPE_ELEMENT) 3203314564Sdim format = eFormatHex; 3204314564Sdim else 3205314564Sdim format = vec_size == 1 3206314564Sdim ? static_cast<lldb::Format>( 3207314564Sdim AllocationDetails::RSTypeToFormat[type][eFormatSingle]) 3208314564Sdim : static_cast<lldb::Format>( 3209314564Sdim AllocationDetails::RSTypeToFormat[type][eFormatVector]); 3210296417Sdim 3211314564Sdim const uint32_t data_size = *alloc->element.datum_size.get(); 3212296417Sdim 3213360784Sdim LLDB_LOGF(log, "%s - element size %" PRIu32 " bytes, including padding", 3214360784Sdim __FUNCTION__, data_size); 3215296417Sdim 3216314564Sdim // Allocate a buffer to copy data into 3217314564Sdim std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); 3218314564Sdim if (!buffer) { 3219314564Sdim strm.Printf("Error: Couldn't read allocation data"); 3220314564Sdim strm.EOL(); 3221314564Sdim return false; 3222314564Sdim } 3223296417Sdim 3224314564Sdim // Calculate stride between rows as there may be padding at end of rows since 3225314564Sdim // allocated memory is 16-byte aligned 3226314564Sdim if (!alloc->stride.isValid()) { 3227314564Sdim if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension 3228314564Sdim alloc->stride = 0; 3229314564Sdim else if (!JITAllocationStride(alloc, frame_ptr)) { 3230314564Sdim strm.Printf("Error: Couldn't calculate allocation row stride"); 3231314564Sdim strm.EOL(); 3232314564Sdim return false; 3233296417Sdim } 3234314564Sdim } 3235314564Sdim const uint32_t stride = *alloc->stride.get(); 3236314564Sdim const uint32_t size = *alloc->size.get(); // Size of whole allocation 3237314564Sdim const uint32_t padding = 3238314564Sdim alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0; 3239360784Sdim LLDB_LOGF(log, 3240360784Sdim "%s - stride %" PRIu32 " bytes, size %" PRIu32 3241360784Sdim " bytes, padding %" PRIu32, 3242360784Sdim __FUNCTION__, stride, size, padding); 3243296417Sdim 3244314564Sdim // Find dimensions used to index loops, so need to be non-zero 3245314564Sdim uint32_t dim_x = alloc->dimension.get()->dim_1; 3246314564Sdim dim_x = dim_x == 0 ? 1 : dim_x; 3247296417Sdim 3248314564Sdim uint32_t dim_y = alloc->dimension.get()->dim_2; 3249314564Sdim dim_y = dim_y == 0 ? 1 : dim_y; 3250296417Sdim 3251314564Sdim uint32_t dim_z = alloc->dimension.get()->dim_3; 3252314564Sdim dim_z = dim_z == 0 ? 1 : dim_z; 3253296417Sdim 3254314564Sdim // Use data extractor to format output 3255314564Sdim const uint32_t target_ptr_size = 3256314564Sdim GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 3257314564Sdim DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(), 3258314564Sdim target_ptr_size); 3259296417Sdim 3260314564Sdim uint32_t offset = 0; // Offset in buffer to next element to be printed 3261314564Sdim uint32_t prev_row = 0; // Offset to the start of the previous row 3262296417Sdim 3263314564Sdim // Iterate over allocation dimensions, printing results to user 3264314564Sdim strm.Printf("Data (X, Y, Z):"); 3265314564Sdim for (uint32_t z = 0; z < dim_z; ++z) { 3266314564Sdim for (uint32_t y = 0; y < dim_y; ++y) { 3267314564Sdim // Use stride to index start of next row. 3268314564Sdim if (!(y == 0 && z == 0)) 3269314564Sdim offset = prev_row + stride; 3270314564Sdim prev_row = offset; 3271296417Sdim 3272314564Sdim // Print each element in the row individually 3273314564Sdim for (uint32_t x = 0; x < dim_x; ++x) { 3274314564Sdim strm.Printf("\n(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") = ", x, y, z); 3275314564Sdim if ((type == Element::RS_TYPE_NONE) && 3276314564Sdim (alloc->element.children.size() > 0) && 3277314564Sdim (alloc->element.type_name != Element::GetFallbackStructName())) { 3278341825Sdim // Here we are dumping an Element of struct type. This is done using 3279341825Sdim // expression evaluation with the name of the struct type and pointer 3280341825Sdim // to element. Don't print the name of the resulting expression, 3281341825Sdim // since this will be '$[0-9]+' 3282314564Sdim DumpValueObjectOptions expr_options; 3283314564Sdim expr_options.SetHideName(true); 3284285101Semaste 3285341825Sdim // Setup expression as dereferencing a pointer cast to element 3286341825Sdim // address. 3287314564Sdim char expr_char_buffer[jit_max_expr_size]; 3288314564Sdim int written = 3289314564Sdim snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64, 3290314564Sdim alloc->element.type_name.AsCString(), 3291314564Sdim *alloc->data_ptr.get() + offset); 3292296417Sdim 3293314564Sdim if (written < 0 || written >= jit_max_expr_size) { 3294360784Sdim LLDB_LOGF(log, "%s - error in snprintf().", __FUNCTION__); 3295314564Sdim continue; 3296314564Sdim } 3297296417Sdim 3298314564Sdim // Evaluate expression 3299314564Sdim ValueObjectSP expr_result; 3300314564Sdim GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer, 3301314564Sdim frame_ptr, expr_result); 3302296417Sdim 3303314564Sdim // Print the results to our stream. 3304314564Sdim expr_result->Dump(strm, expr_options); 3305314564Sdim } else { 3306321369Sdim DumpDataExtractor(alloc_data, &strm, offset, format, 3307321369Sdim data_size - padding, 1, 1, LLDB_INVALID_ADDRESS, 0, 3308321369Sdim 0); 3309296417Sdim } 3310314564Sdim offset += data_size; 3311314564Sdim } 3312296417Sdim } 3313314564Sdim } 3314314564Sdim strm.EOL(); 3315285101Semaste 3316314564Sdim return true; 3317296417Sdim} 3318285101Semaste 3319341825Sdim// Function recalculates all our cached information about allocations by 3320341825Sdim// jitting the RS runtime regarding each allocation we know about. Returns true 3321341825Sdim// if all allocations could be recomputed, false otherwise. 3322314564Sdimbool RenderScriptRuntime::RecomputeAllAllocations(Stream &strm, 3323314564Sdim StackFrame *frame_ptr) { 3324314564Sdim bool success = true; 3325314564Sdim for (auto &alloc : m_allocations) { 3326314564Sdim // JIT current allocation information 3327314564Sdim if (!RefreshAllocation(alloc.get(), frame_ptr)) { 3328314564Sdim strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32 3329314564Sdim "\n", 3330314564Sdim alloc->id); 3331314564Sdim success = false; 3332309124Sdim } 3333314564Sdim } 3334309124Sdim 3335314564Sdim if (success) 3336314564Sdim strm.Printf("All allocations successfully recomputed"); 3337314564Sdim strm.EOL(); 3338309124Sdim 3339314564Sdim return success; 3340309124Sdim} 3341309124Sdim 3342314564Sdim// Prints information regarding currently loaded allocations. These details are 3343314564Sdim// gathered by jitting the runtime, which has as latency. Index parameter 3344314564Sdim// specifies a single allocation ID to print, or a zero value to print them all 3345314564Sdimvoid RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame *frame_ptr, 3346314564Sdim const uint32_t index) { 3347314564Sdim strm.Printf("RenderScript Allocations:"); 3348314564Sdim strm.EOL(); 3349314564Sdim strm.IndentMore(); 3350296417Sdim 3351314564Sdim for (auto &alloc : m_allocations) { 3352314564Sdim // index will only be zero if we want to print all allocations 3353314564Sdim if (index != 0 && index != alloc->id) 3354314564Sdim continue; 3355296417Sdim 3356314564Sdim // JIT current allocation information 3357314564Sdim if (alloc->ShouldRefresh() && !RefreshAllocation(alloc.get(), frame_ptr)) { 3358314564Sdim strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32, 3359314564Sdim alloc->id); 3360314564Sdim strm.EOL(); 3361314564Sdim continue; 3362314564Sdim } 3363296417Sdim 3364314564Sdim strm.Printf("%" PRIu32 ":", alloc->id); 3365314564Sdim strm.EOL(); 3366314564Sdim strm.IndentMore(); 3367296417Sdim 3368314564Sdim strm.Indent("Context: "); 3369314564Sdim if (!alloc->context.isValid()) 3370314564Sdim strm.Printf("unknown\n"); 3371314564Sdim else 3372314564Sdim strm.Printf("0x%" PRIx64 "\n", *alloc->context.get()); 3373296417Sdim 3374314564Sdim strm.Indent("Address: "); 3375314564Sdim if (!alloc->address.isValid()) 3376314564Sdim strm.Printf("unknown\n"); 3377314564Sdim else 3378314564Sdim strm.Printf("0x%" PRIx64 "\n", *alloc->address.get()); 3379296417Sdim 3380314564Sdim strm.Indent("Data pointer: "); 3381314564Sdim if (!alloc->data_ptr.isValid()) 3382314564Sdim strm.Printf("unknown\n"); 3383314564Sdim else 3384314564Sdim strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get()); 3385296417Sdim 3386314564Sdim strm.Indent("Dimensions: "); 3387314564Sdim if (!alloc->dimension.isValid()) 3388314564Sdim strm.Printf("unknown\n"); 3389314564Sdim else 3390314564Sdim strm.Printf("(%" PRId32 ", %" PRId32 ", %" PRId32 ")\n", 3391314564Sdim alloc->dimension.get()->dim_1, alloc->dimension.get()->dim_2, 3392314564Sdim alloc->dimension.get()->dim_3); 3393296417Sdim 3394314564Sdim strm.Indent("Data Type: "); 3395314564Sdim if (!alloc->element.type.isValid() || 3396314564Sdim !alloc->element.type_vec_size.isValid()) 3397314564Sdim strm.Printf("unknown\n"); 3398314564Sdim else { 3399314564Sdim const int vector_size = *alloc->element.type_vec_size.get(); 3400314564Sdim Element::DataType type = *alloc->element.type.get(); 3401296417Sdim 3402314564Sdim if (!alloc->element.type_name.IsEmpty()) 3403314564Sdim strm.Printf("%s\n", alloc->element.type_name.AsCString()); 3404314564Sdim else { 3405314564Sdim // Enum value isn't monotonous, so doesn't always index 3406314564Sdim // RsDataTypeToString array 3407314564Sdim if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT) 3408314564Sdim type = 3409314564Sdim static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) + 3410314564Sdim Element::RS_TYPE_MATRIX_2X2 + 1); 3411296417Sdim 3412314564Sdim if (type >= (sizeof(AllocationDetails::RsDataTypeToString) / 3413314564Sdim sizeof(AllocationDetails::RsDataTypeToString[0])) || 3414314564Sdim vector_size > 4 || vector_size < 1) 3415314564Sdim strm.Printf("invalid type\n"); 3416296417Sdim else 3417314564Sdim strm.Printf( 3418314564Sdim "%s\n", 3419314564Sdim AllocationDetails::RsDataTypeToString[static_cast<uint32_t>(type)] 3420314564Sdim [vector_size - 1]); 3421314564Sdim } 3422314564Sdim } 3423296417Sdim 3424314564Sdim strm.Indent("Data Kind: "); 3425314564Sdim if (!alloc->element.type_kind.isValid()) 3426314564Sdim strm.Printf("unknown\n"); 3427314564Sdim else { 3428314564Sdim const Element::DataKind kind = *alloc->element.type_kind.get(); 3429314564Sdim if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV) 3430314564Sdim strm.Printf("invalid kind\n"); 3431314564Sdim else 3432314564Sdim strm.Printf( 3433314564Sdim "%s\n", 3434314564Sdim AllocationDetails::RsDataKindToString[static_cast<uint32_t>(kind)]); 3435285101Semaste } 3436314564Sdim 3437314564Sdim strm.EOL(); 3438296417Sdim strm.IndentLess(); 3439314564Sdim } 3440314564Sdim strm.IndentLess(); 3441296417Sdim} 3442285101Semaste 3443296417Sdim// Set breakpoints on every kernel found in RS module 3444314564Sdimvoid RenderScriptRuntime::BreakOnModuleKernels( 3445314564Sdim const RSModuleDescriptorSP rsmodule_sp) { 3446314564Sdim for (const auto &kernel : rsmodule_sp->m_kernels) { 3447314564Sdim // Don't set breakpoint on 'root' kernel 3448314564Sdim if (strcmp(kernel.m_name.AsCString(), "root") == 0) 3449314564Sdim continue; 3450296417Sdim 3451314564Sdim CreateKernelBreakpoint(kernel.m_name); 3452314564Sdim } 3453285101Semaste} 3454285101Semaste 3455314564Sdim// Method is internally called by the 'kernel breakpoint all' command to enable 3456314564Sdim// or disable breaking on all kernels. When do_break is true we want to enable 3457314564Sdim// this functionality. When do_break is false we want to disable it. 3458314564Sdimvoid RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) { 3459314564Sdim Log *log( 3460314564Sdim GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3461296417Sdim 3462314564Sdim InitSearchFilter(target); 3463296417Sdim 3464314564Sdim // Set breakpoints on all the kernels 3465314564Sdim if (do_break && !m_breakAllKernels) { 3466314564Sdim m_breakAllKernels = true; 3467296417Sdim 3468314564Sdim for (const auto &module : m_rsmodules) 3469314564Sdim BreakOnModuleKernels(module); 3470296417Sdim 3471360784Sdim LLDB_LOGF(log, 3472360784Sdim "%s(True) - breakpoints set on all currently loaded kernels.", 3473360784Sdim __FUNCTION__); 3474314564Sdim } else if (!do_break && 3475314564Sdim m_breakAllKernels) // Breakpoints won't be set on any new kernels. 3476314564Sdim { 3477314564Sdim m_breakAllKernels = false; 3478296417Sdim 3479360784Sdim LLDB_LOGF(log, "%s(False) - breakpoints no longer automatically set.", 3480360784Sdim __FUNCTION__); 3481314564Sdim } 3482296417Sdim} 3483296417Sdim 3484341825Sdim// Given the name of a kernel this function creates a breakpoint using our own 3485341825Sdim// breakpoint resolver, and returns the Breakpoint shared pointer. 3486296417SdimBreakpointSP 3487353358SdimRenderScriptRuntime::CreateKernelBreakpoint(ConstString name) { 3488314564Sdim Log *log( 3489314564Sdim GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3490296417Sdim 3491314564Sdim if (!m_filtersp) { 3492360784Sdim LLDB_LOGF(log, "%s - error, no breakpoint search filter set.", 3493360784Sdim __FUNCTION__); 3494314564Sdim return nullptr; 3495314564Sdim } 3496296417Sdim 3497314564Sdim BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name)); 3498327952Sdim Target &target = GetProcess()->GetTarget(); 3499327952Sdim BreakpointSP bp = target.CreateBreakpoint( 3500314564Sdim m_filtersp, resolver_sp, false, false, false); 3501296417Sdim 3502314564Sdim // Give RS breakpoints a specific name, so the user can manipulate them as a 3503314564Sdim // group. 3504321369Sdim Status err; 3505327952Sdim target.AddNameToBreakpoint(bp, "RenderScriptKernel", err); 3506327952Sdim if (err.Fail() && log) 3507360784Sdim LLDB_LOGF(log, "%s - error setting break name, '%s'.", __FUNCTION__, 3508360784Sdim err.AsCString()); 3509296417Sdim 3510314564Sdim return bp; 3511296417Sdim} 3512296417Sdim 3513314564SdimBreakpointSP 3514353358SdimRenderScriptRuntime::CreateReductionBreakpoint(ConstString name, 3515314564Sdim int kernel_types) { 3516314564Sdim Log *log( 3517314564Sdim GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3518296417Sdim 3519314564Sdim if (!m_filtersp) { 3520360784Sdim LLDB_LOGF(log, "%s - error, no breakpoint search filter set.", 3521360784Sdim __FUNCTION__); 3522314564Sdim return nullptr; 3523314564Sdim } 3524296417Sdim 3525314564Sdim BreakpointResolverSP resolver_sp(new RSReduceBreakpointResolver( 3526314564Sdim nullptr, name, &m_rsmodules, kernel_types)); 3527327952Sdim Target &target = GetProcess()->GetTarget(); 3528327952Sdim BreakpointSP bp = target.CreateBreakpoint( 3529314564Sdim m_filtersp, resolver_sp, false, false, false); 3530296417Sdim 3531314564Sdim // Give RS breakpoints a specific name, so the user can manipulate them as a 3532314564Sdim // group. 3533321369Sdim Status err; 3534327952Sdim target.AddNameToBreakpoint(bp, "RenderScriptReduction", err); 3535327952Sdim if (err.Fail() && log) 3536360784Sdim LLDB_LOGF(log, "%s - error setting break name, '%s'.", __FUNCTION__, 3537360784Sdim err.AsCString()); 3538314564Sdim 3539314564Sdim return bp; 3540296417Sdim} 3541296417Sdim 3542314564Sdim// Given an expression for a variable this function tries to calculate the 3543314564Sdim// variable's value. If this is possible it returns true and sets the uint64_t 3544314564Sdim// parameter to the variables unsigned value. Otherwise function returns false. 3545314564Sdimbool RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp, 3546314564Sdim const char *var_name, 3547314564Sdim uint64_t &val) { 3548314564Sdim Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 3549321369Sdim Status err; 3550314564Sdim VariableSP var_sp; 3551309124Sdim 3552314564Sdim // Find variable in stack frame 3553314564Sdim ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath( 3554314564Sdim var_name, eNoDynamicValues, 3555314564Sdim StackFrame::eExpressionPathOptionCheckPtrVsMember | 3556314564Sdim StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, 3557314564Sdim var_sp, err)); 3558314564Sdim if (!err.Success()) { 3559360784Sdim LLDB_LOGF(log, "%s - error, couldn't find '%s' in frame", __FUNCTION__, 3560360784Sdim var_name); 3561314564Sdim return false; 3562314564Sdim } 3563309124Sdim 3564314564Sdim // Find the uint32_t value for the variable 3565314564Sdim bool success = false; 3566314564Sdim val = value_sp->GetValueAsUnsigned(0, &success); 3567314564Sdim if (!success) { 3568360784Sdim LLDB_LOGF(log, "%s - error, couldn't parse '%s' as an uint32_t.", 3569360784Sdim __FUNCTION__, var_name); 3570314564Sdim return false; 3571314564Sdim } 3572309124Sdim 3573314564Sdim return true; 3574314564Sdim} 3575309124Sdim 3576314564Sdim// Function attempts to find the current coordinate of a kernel invocation by 3577314564Sdim// investigating the values of frame variables in the .expand function. These 3578314564Sdim// coordinates are returned via the coord array reference parameter. Returns 3579314564Sdim// true if the coordinates could be found, and false otherwise. 3580314564Sdimbool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord, 3581314564Sdim Thread *thread_ptr) { 3582314564Sdim static const char *const x_expr = "rsIndex"; 3583314564Sdim static const char *const y_expr = "p->current.y"; 3584314564Sdim static const char *const z_expr = "p->current.z"; 3585309124Sdim 3586314564Sdim Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 3587309124Sdim 3588314564Sdim if (!thread_ptr) { 3589360784Sdim LLDB_LOGF(log, "%s - Error, No thread pointer", __FUNCTION__); 3590309124Sdim 3591314564Sdim return false; 3592314564Sdim } 3593309124Sdim 3594314564Sdim // Walk the call stack looking for a function whose name has the suffix 3595314564Sdim // '.expand' and contains the variables we're looking for. 3596314564Sdim for (uint32_t i = 0; i < thread_ptr->GetStackFrameCount(); ++i) { 3597314564Sdim if (!thread_ptr->SetSelectedFrameByIndex(i)) 3598314564Sdim continue; 3599309124Sdim 3600314564Sdim StackFrameSP frame_sp = thread_ptr->GetSelectedFrame(); 3601314564Sdim if (!frame_sp) 3602314564Sdim continue; 3603309124Sdim 3604314564Sdim // Find the function name 3605344779Sdim const SymbolContext sym_ctx = 3606344779Sdim frame_sp->GetSymbolContext(eSymbolContextFunction); 3607314564Sdim const ConstString func_name = sym_ctx.GetFunctionName(); 3608314564Sdim if (!func_name) 3609314564Sdim continue; 3610309124Sdim 3611360784Sdim LLDB_LOGF(log, "%s - Inspecting function '%s'", __FUNCTION__, 3612360784Sdim func_name.GetCString()); 3613309124Sdim 3614314564Sdim // Check if function name has .expand suffix 3615314564Sdim if (!func_name.GetStringRef().endswith(".expand")) 3616314564Sdim continue; 3617309124Sdim 3618360784Sdim LLDB_LOGF(log, "%s - Found .expand function '%s'", __FUNCTION__, 3619360784Sdim func_name.GetCString()); 3620309124Sdim 3621341825Sdim // Get values for variables in .expand frame that tell us the current 3622341825Sdim // kernel invocation 3623314564Sdim uint64_t x, y, z; 3624314564Sdim bool found = GetFrameVarAsUnsigned(frame_sp, x_expr, x) && 3625314564Sdim GetFrameVarAsUnsigned(frame_sp, y_expr, y) && 3626314564Sdim GetFrameVarAsUnsigned(frame_sp, z_expr, z); 3627314564Sdim 3628314564Sdim if (found) { 3629314564Sdim // The RenderScript runtime uses uint32_t for these vars. If they're not 3630314564Sdim // within bounds, our frame parsing is garbage 3631314564Sdim assert(x <= UINT32_MAX && y <= UINT32_MAX && z <= UINT32_MAX); 3632314564Sdim coord.x = (uint32_t)x; 3633314564Sdim coord.y = (uint32_t)y; 3634314564Sdim coord.z = (uint32_t)z; 3635314564Sdim return true; 3636309124Sdim } 3637314564Sdim } 3638314564Sdim return false; 3639309124Sdim} 3640309124Sdim 3641314564Sdim// Callback when a kernel breakpoint hits and we're looking for a specific 3642314564Sdim// coordinate. Baton parameter contains a pointer to the target coordinate we 3643341825Sdim// want to break on. Function then checks the .expand frame for the current 3644341825Sdim// coordinate and breaks to user if it matches. Parameter 'break_id' is the id 3645341825Sdim// of the Breakpoint which made the callback. Parameter 'break_loc_id' is the 3646341825Sdim// id for the BreakpointLocation which was hit, a single logical breakpoint can 3647341825Sdim// have multiple addresses. 3648314564Sdimbool RenderScriptRuntime::KernelBreakpointHit(void *baton, 3649314564Sdim StoppointCallbackContext *ctx, 3650314564Sdim user_id_t break_id, 3651314564Sdim user_id_t break_loc_id) { 3652314564Sdim Log *log( 3653314564Sdim GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3654296417Sdim 3655314564Sdim assert(baton && 3656314564Sdim "Error: null baton in conditional kernel breakpoint callback"); 3657296417Sdim 3658314564Sdim // Coordinate we want to stop on 3659314564Sdim RSCoordinate target_coord = *static_cast<RSCoordinate *>(baton); 3660296417Sdim 3661360784Sdim LLDB_LOGF(log, "%s - Break ID %" PRIu64 ", " FMT_COORD, __FUNCTION__, 3662360784Sdim break_id, target_coord.x, target_coord.y, target_coord.z); 3663314564Sdim 3664314564Sdim // Select current thread 3665314564Sdim ExecutionContext context(ctx->exe_ctx_ref); 3666314564Sdim Thread *thread_ptr = context.GetThreadPtr(); 3667314564Sdim assert(thread_ptr && "Null thread pointer"); 3668314564Sdim 3669314564Sdim // Find current kernel invocation from .expand frame variables 3670314564Sdim RSCoordinate current_coord{}; 3671314564Sdim if (!GetKernelCoordinate(current_coord, thread_ptr)) { 3672360784Sdim LLDB_LOGF(log, "%s - Error, couldn't select .expand stack frame", 3673360784Sdim __FUNCTION__); 3674314564Sdim return false; 3675314564Sdim } 3676296417Sdim 3677360784Sdim LLDB_LOGF(log, "%s - " FMT_COORD, __FUNCTION__, current_coord.x, 3678360784Sdim current_coord.y, current_coord.z); 3679296417Sdim 3680314564Sdim // Check if the current kernel invocation coordinate matches our target 3681314564Sdim // coordinate 3682314564Sdim if (target_coord == current_coord) { 3683360784Sdim LLDB_LOGF(log, "%s, BREAKING " FMT_COORD, __FUNCTION__, current_coord.x, 3684360784Sdim current_coord.y, current_coord.z); 3685296417Sdim 3686314564Sdim BreakpointSP breakpoint_sp = 3687314564Sdim context.GetTargetPtr()->GetBreakpointByID(break_id); 3688314564Sdim assert(breakpoint_sp != nullptr && 3689314564Sdim "Error: Couldn't find breakpoint matching break id for callback"); 3690314564Sdim breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint 3691314564Sdim // should only be hit once. 3692314564Sdim return true; 3693314564Sdim } 3694296417Sdim 3695314564Sdim // No match on coordinate 3696314564Sdim return false; 3697314564Sdim} 3698296417Sdim 3699314564Sdimvoid RenderScriptRuntime::SetConditional(BreakpointSP bp, Stream &messages, 3700314564Sdim const RSCoordinate &coord) { 3701314564Sdim messages.Printf("Conditional kernel breakpoint on coordinate " FMT_COORD, 3702314564Sdim coord.x, coord.y, coord.z); 3703314564Sdim messages.EOL(); 3704314564Sdim 3705314564Sdim // Allocate memory for the baton, and copy over coordinate 3706314564Sdim RSCoordinate *baton = new RSCoordinate(coord); 3707314564Sdim 3708314564Sdim // Create a callback that will be invoked every time the breakpoint is hit. 3709314564Sdim // The baton object passed to the handler is the target coordinate we want to 3710314564Sdim // break on. 3711314564Sdim bp->SetCallback(KernelBreakpointHit, baton, true); 3712314564Sdim 3713314564Sdim // Store a shared pointer to the baton, so the memory will eventually be 3714314564Sdim // cleaned up after destruction 3715314564Sdim m_conditional_breaks[bp->GetID()] = std::unique_ptr<RSCoordinate>(baton); 3716314564Sdim} 3717314564Sdim 3718341825Sdim// Tries to set a breakpoint on the start of a kernel, resolved using the 3719341825Sdim// kernel name. Argument 'coords', represents a three dimensional coordinate 3720341825Sdim// which can be used to specify a single kernel instance to break on. If this 3721341825Sdim// is set then we add a callback to the breakpoint. 3722314564Sdimbool RenderScriptRuntime::PlaceBreakpointOnKernel(TargetSP target, 3723314564Sdim Stream &messages, 3724314564Sdim const char *name, 3725314564Sdim const RSCoordinate *coord) { 3726314564Sdim if (!name) 3727296417Sdim return false; 3728314564Sdim 3729314564Sdim InitSearchFilter(target); 3730314564Sdim 3731314564Sdim ConstString kernel_name(name); 3732314564Sdim BreakpointSP bp = CreateKernelBreakpoint(kernel_name); 3733314564Sdim if (!bp) 3734314564Sdim return false; 3735314564Sdim 3736314564Sdim // We have a conditional breakpoint on a specific coordinate 3737314564Sdim if (coord) 3738314564Sdim SetConditional(bp, messages, *coord); 3739314564Sdim 3740314564Sdim bp->GetDescription(&messages, lldb::eDescriptionLevelInitial, false); 3741314564Sdim 3742314564Sdim return true; 3743296417Sdim} 3744296417Sdim 3745314564SdimBreakpointSP 3746353358SdimRenderScriptRuntime::CreateScriptGroupBreakpoint(ConstString name, 3747314564Sdim bool stop_on_all) { 3748314564Sdim Log *log( 3749314564Sdim GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3750296417Sdim 3751314564Sdim if (!m_filtersp) { 3752360784Sdim LLDB_LOGF(log, "%s - error, no breakpoint search filter set.", 3753360784Sdim __FUNCTION__); 3754314564Sdim return nullptr; 3755314564Sdim } 3756296417Sdim 3757314564Sdim BreakpointResolverSP resolver_sp(new RSScriptGroupBreakpointResolver( 3758314564Sdim nullptr, name, m_scriptGroups, stop_on_all)); 3759327952Sdim Target &target = GetProcess()->GetTarget(); 3760327952Sdim BreakpointSP bp = target.CreateBreakpoint( 3761314564Sdim m_filtersp, resolver_sp, false, false, false); 3762314564Sdim // Give RS breakpoints a specific name, so the user can manipulate them as a 3763314564Sdim // group. 3764321369Sdim Status err; 3765327952Sdim target.AddNameToBreakpoint(bp, name.GetCString(), err); 3766327952Sdim if (err.Fail() && log) 3767360784Sdim LLDB_LOGF(log, "%s - error setting break name, '%s'.", __FUNCTION__, 3768360784Sdim err.AsCString()); 3769314564Sdim // ask the breakpoint to resolve itself 3770314564Sdim bp->ResolveBreakpoint(); 3771314564Sdim return bp; 3772314564Sdim} 3773296417Sdim 3774314564Sdimbool RenderScriptRuntime::PlaceBreakpointOnScriptGroup(TargetSP target, 3775314564Sdim Stream &strm, 3776353358Sdim ConstString name, 3777314564Sdim bool multi) { 3778314564Sdim InitSearchFilter(target); 3779314564Sdim BreakpointSP bp = CreateScriptGroupBreakpoint(name, multi); 3780314564Sdim if (bp) 3781314564Sdim bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false); 3782314564Sdim return bool(bp); 3783314564Sdim} 3784296417Sdim 3785314564Sdimbool RenderScriptRuntime::PlaceBreakpointOnReduction(TargetSP target, 3786314564Sdim Stream &messages, 3787314564Sdim const char *reduce_name, 3788314564Sdim const RSCoordinate *coord, 3789314564Sdim int kernel_types) { 3790314564Sdim if (!reduce_name) 3791314564Sdim return false; 3792296417Sdim 3793314564Sdim InitSearchFilter(target); 3794314564Sdim BreakpointSP bp = 3795314564Sdim CreateReductionBreakpoint(ConstString(reduce_name), kernel_types); 3796314564Sdim if (!bp) 3797314564Sdim return false; 3798296417Sdim 3799314564Sdim if (coord) 3800314564Sdim SetConditional(bp, messages, *coord); 3801296417Sdim 3802314564Sdim bp->GetDescription(&messages, lldb::eDescriptionLevelInitial, false); 3803314564Sdim 3804314564Sdim return true; 3805296417Sdim} 3806296417Sdim 3807314564Sdimvoid RenderScriptRuntime::DumpModules(Stream &strm) const { 3808314564Sdim strm.Printf("RenderScript Modules:"); 3809314564Sdim strm.EOL(); 3810314564Sdim strm.IndentMore(); 3811314564Sdim for (const auto &module : m_rsmodules) { 3812314564Sdim module->Dump(strm); 3813314564Sdim } 3814314564Sdim strm.IndentLess(); 3815285101Semaste} 3816285101Semaste 3817309124SdimRenderScriptRuntime::ScriptDetails * 3818314564SdimRenderScriptRuntime::LookUpScript(addr_t address, bool create) { 3819314564Sdim for (const auto &s : m_scripts) { 3820314564Sdim if (s->script.isValid()) 3821314564Sdim if (*s->script == address) 3822314564Sdim return s.get(); 3823314564Sdim } 3824314564Sdim if (create) { 3825314564Sdim std::unique_ptr<ScriptDetails> s(new ScriptDetails); 3826314564Sdim s->script = address; 3827314564Sdim m_scripts.push_back(std::move(s)); 3828314564Sdim return m_scripts.back().get(); 3829314564Sdim } 3830314564Sdim return nullptr; 3831296417Sdim} 3832296417Sdim 3833309124SdimRenderScriptRuntime::AllocationDetails * 3834314564SdimRenderScriptRuntime::LookUpAllocation(addr_t address) { 3835314564Sdim for (const auto &a : m_allocations) { 3836314564Sdim if (a->address.isValid()) 3837314564Sdim if (*a->address == address) 3838314564Sdim return a.get(); 3839314564Sdim } 3840314564Sdim return nullptr; 3841314564Sdim} 3842314564Sdim 3843314564SdimRenderScriptRuntime::AllocationDetails * 3844314564SdimRenderScriptRuntime::CreateAllocation(addr_t address) { 3845314564Sdim Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 3846314564Sdim 3847314564Sdim // Remove any previous allocation which contains the same address 3848314564Sdim auto it = m_allocations.begin(); 3849314564Sdim while (it != m_allocations.end()) { 3850314564Sdim if (*((*it)->address) == address) { 3851360784Sdim LLDB_LOGF(log, "%s - Removing allocation id: %d, address: 0x%" PRIx64, 3852360784Sdim __FUNCTION__, (*it)->id, address); 3853314564Sdim 3854314564Sdim it = m_allocations.erase(it); 3855314564Sdim } else { 3856314564Sdim it++; 3857296417Sdim } 3858314564Sdim } 3859314564Sdim 3860314564Sdim std::unique_ptr<AllocationDetails> a(new AllocationDetails); 3861314564Sdim a->address = address; 3862314564Sdim m_allocations.push_back(std::move(a)); 3863314564Sdim return m_allocations.back().get(); 3864296417Sdim} 3865296417Sdim 3866314564Sdimbool RenderScriptRuntime::ResolveKernelName(lldb::addr_t kernel_addr, 3867314564Sdim ConstString &name) { 3868314564Sdim Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS); 3869314564Sdim 3870314564Sdim Target &target = GetProcess()->GetTarget(); 3871314564Sdim Address resolved; 3872314564Sdim // RenderScript module 3873314564Sdim if (!target.GetSectionLoadList().ResolveLoadAddress(kernel_addr, resolved)) { 3874360784Sdim LLDB_LOGF(log, "%s: unable to resolve 0x%" PRIx64 " to a loaded symbol", 3875360784Sdim __FUNCTION__, kernel_addr); 3876314564Sdim return false; 3877314564Sdim } 3878314564Sdim 3879314564Sdim Symbol *sym = resolved.CalculateSymbolContextSymbol(); 3880314564Sdim if (!sym) 3881314564Sdim return false; 3882314564Sdim 3883314564Sdim name = sym->GetName(); 3884314564Sdim assert(IsRenderScriptModule(resolved.CalculateSymbolContextModule())); 3885360784Sdim LLDB_LOGF(log, "%s: 0x%" PRIx64 " resolved to the symbol '%s'", __FUNCTION__, 3886360784Sdim kernel_addr, name.GetCString()); 3887314564Sdim return true; 3888314564Sdim} 3889314564Sdim 3890314564Sdimvoid RSModuleDescriptor::Dump(Stream &strm) const { 3891314564Sdim int indent = strm.GetIndentLevel(); 3892314564Sdim 3893314564Sdim strm.Indent(); 3894360784Sdim m_module->GetFileSpec().Dump(strm.AsRawOstream()); 3895314564Sdim strm.Indent(m_module->GetNumCompileUnits() ? "Debug info loaded." 3896314564Sdim : "Debug info does not exist."); 3897314564Sdim strm.EOL(); 3898314564Sdim strm.IndentMore(); 3899314564Sdim 3900314564Sdim strm.Indent(); 3901314564Sdim strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size())); 3902314564Sdim strm.EOL(); 3903314564Sdim strm.IndentMore(); 3904314564Sdim for (const auto &global : m_globals) { 3905314564Sdim global.Dump(strm); 3906314564Sdim } 3907314564Sdim strm.IndentLess(); 3908314564Sdim 3909314564Sdim strm.Indent(); 3910314564Sdim strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size())); 3911314564Sdim strm.EOL(); 3912314564Sdim strm.IndentMore(); 3913314564Sdim for (const auto &kernel : m_kernels) { 3914314564Sdim kernel.Dump(strm); 3915314564Sdim } 3916314564Sdim strm.IndentLess(); 3917314564Sdim 3918314564Sdim strm.Indent(); 3919314564Sdim strm.Printf("Pragmas: %" PRIu64, static_cast<uint64_t>(m_pragmas.size())); 3920314564Sdim strm.EOL(); 3921314564Sdim strm.IndentMore(); 3922314564Sdim for (const auto &key_val : m_pragmas) { 3923285101Semaste strm.Indent(); 3924314564Sdim strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str()); 3925285101Semaste strm.EOL(); 3926314564Sdim } 3927314564Sdim strm.IndentLess(); 3928314564Sdim 3929314564Sdim strm.Indent(); 3930314564Sdim strm.Printf("Reductions: %" PRIu64, 3931314564Sdim static_cast<uint64_t>(m_reductions.size())); 3932314564Sdim strm.EOL(); 3933314564Sdim strm.IndentMore(); 3934314564Sdim for (const auto &reduction : m_reductions) { 3935314564Sdim reduction.Dump(strm); 3936314564Sdim } 3937314564Sdim 3938314564Sdim strm.SetIndentLevel(indent); 3939285101Semaste} 3940285101Semaste 3941314564Sdimvoid RSGlobalDescriptor::Dump(Stream &strm) const { 3942314564Sdim strm.Indent(m_name.AsCString()); 3943314564Sdim VariableList var_list; 3944341825Sdim m_module->m_module->FindGlobalVariables(m_name, nullptr, 1U, var_list); 3945314564Sdim if (var_list.GetSize() == 1) { 3946314564Sdim auto var = var_list.GetVariableAtIndex(0); 3947314564Sdim auto type = var->GetType(); 3948314564Sdim if (type) { 3949314564Sdim strm.Printf(" - "); 3950314564Sdim type->DumpTypeName(&strm); 3951314564Sdim } else { 3952314564Sdim strm.Printf(" - Unknown Type"); 3953285101Semaste } 3954314564Sdim } else { 3955314564Sdim strm.Printf(" - variable identified, but not found in binary"); 3956314564Sdim const Symbol *s = m_module->m_module->FindFirstSymbolWithNameAndType( 3957314564Sdim m_name, eSymbolTypeData); 3958314564Sdim if (s) { 3959314564Sdim strm.Printf(" (symbol exists) "); 3960285101Semaste } 3961314564Sdim } 3962285101Semaste 3963314564Sdim strm.EOL(); 3964285101Semaste} 3965285101Semaste 3966314564Sdimvoid RSKernelDescriptor::Dump(Stream &strm) const { 3967314564Sdim strm.Indent(m_name.AsCString()); 3968314564Sdim strm.EOL(); 3969285101Semaste} 3970285101Semaste 3971314564Sdimvoid RSReductionDescriptor::Dump(lldb_private::Stream &stream) const { 3972314564Sdim stream.Indent(m_reduce_name.AsCString()); 3973314564Sdim stream.IndentMore(); 3974314564Sdim stream.EOL(); 3975314564Sdim stream.Indent(); 3976314564Sdim stream.Printf("accumulator: %s", m_accum_name.AsCString()); 3977314564Sdim stream.EOL(); 3978314564Sdim stream.Indent(); 3979314564Sdim stream.Printf("initializer: %s", m_init_name.AsCString()); 3980314564Sdim stream.EOL(); 3981314564Sdim stream.Indent(); 3982314564Sdim stream.Printf("combiner: %s", m_comb_name.AsCString()); 3983314564Sdim stream.EOL(); 3984314564Sdim stream.Indent(); 3985314564Sdim stream.Printf("outconverter: %s", m_outc_name.AsCString()); 3986314564Sdim stream.EOL(); 3987314564Sdim // XXX This is currently unspecified by RenderScript, and unused 3988314564Sdim // stream.Indent(); 3989314564Sdim // stream.Printf("halter: '%s'", m_init_name.AsCString()); 3990314564Sdim // stream.EOL(); 3991314564Sdim stream.IndentLess(); 3992314564Sdim} 3993314564Sdim 3994314564Sdimclass CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed { 3995296417Sdimpublic: 3996314564Sdim CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter) 3997314564Sdim : CommandObjectParsed( 3998314564Sdim interpreter, "renderscript module dump", 3999314564Sdim "Dumps renderscript specific information for all modules.", 4000314564Sdim "renderscript module dump", 4001314564Sdim eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} 4002285101Semaste 4003314564Sdim ~CommandObjectRenderScriptRuntimeModuleDump() override = default; 4004285101Semaste 4005314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 4006353358Sdim RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>( 4007353358Sdim m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4008353358Sdim eLanguageTypeExtRenderScript)); 4009314564Sdim runtime->DumpModules(result.GetOutputStream()); 4010314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 4011314564Sdim return true; 4012314564Sdim } 4013285101Semaste}; 4014285101Semaste 4015314564Sdimclass CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword { 4016296417Sdimpublic: 4017314564Sdim CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter) 4018314564Sdim : CommandObjectMultiword(interpreter, "renderscript module", 4019314564Sdim "Commands that deal with RenderScript modules.", 4020314564Sdim nullptr) { 4021314564Sdim LoadSubCommand( 4022314564Sdim "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump( 4023314564Sdim interpreter))); 4024314564Sdim } 4025285101Semaste 4026314564Sdim ~CommandObjectRenderScriptRuntimeModule() override = default; 4027285101Semaste}; 4028285101Semaste 4029314564Sdimclass CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed { 4030296417Sdimpublic: 4031314564Sdim CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter) 4032314564Sdim : CommandObjectParsed( 4033314564Sdim interpreter, "renderscript kernel list", 4034314564Sdim "Lists renderscript kernel names and associated script resources.", 4035314564Sdim "renderscript kernel list", 4036314564Sdim eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} 4037285101Semaste 4038314564Sdim ~CommandObjectRenderScriptRuntimeKernelList() override = default; 4039285101Semaste 4040314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 4041353358Sdim RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>( 4042353358Sdim m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4043353358Sdim eLanguageTypeExtRenderScript)); 4044314564Sdim runtime->DumpKernels(result.GetOutputStream()); 4045314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 4046314564Sdim return true; 4047314564Sdim } 4048285101Semaste}; 4049285101Semaste 4050344779Sdimstatic constexpr OptionDefinition g_renderscript_reduction_bp_set_options[] = { 4051314564Sdim {LLDB_OPT_SET_1, false, "function-role", 't', 4052344779Sdim OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOneLiner, 4053314564Sdim "Break on a comma separated set of reduction kernel types " 4054314564Sdim "(accumulator,outcoverter,combiner,initializer"}, 4055314564Sdim {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument, 4056344779Sdim nullptr, {}, 0, eArgTypeValue, 4057314564Sdim "Set a breakpoint on a single invocation of the kernel with specified " 4058314564Sdim "coordinate.\n" 4059314564Sdim "Coordinate takes the form 'x[,y][,z] where x,y,z are positive " 4060314564Sdim "integers representing kernel dimensions. " 4061314564Sdim "Any unset dimensions will be defaulted to zero."}}; 4062314564Sdim 4063314564Sdimclass CommandObjectRenderScriptRuntimeReductionBreakpointSet 4064314564Sdim : public CommandObjectParsed { 4065296417Sdimpublic: 4066314564Sdim CommandObjectRenderScriptRuntimeReductionBreakpointSet( 4067314564Sdim CommandInterpreter &interpreter) 4068314564Sdim : CommandObjectParsed( 4069314564Sdim interpreter, "renderscript reduction breakpoint set", 4070314564Sdim "Set a breakpoint on named RenderScript general reductions", 4071314564Sdim "renderscript reduction breakpoint set <kernel_name> [-t " 4072314564Sdim "<reduction_kernel_type,...>]", 4073314564Sdim eCommandRequiresProcess | eCommandProcessMustBeLaunched | 4074314564Sdim eCommandProcessMustBePaused), 4075314564Sdim m_options(){}; 4076314564Sdim 4077314564Sdim class CommandOptions : public Options { 4078314564Sdim public: 4079314564Sdim CommandOptions() 4080314564Sdim : Options(), 4081314564Sdim m_kernel_types(RSReduceBreakpointResolver::eKernelTypeAll) {} 4082314564Sdim 4083314564Sdim ~CommandOptions() override = default; 4084314564Sdim 4085321369Sdim Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 4086321369Sdim ExecutionContext *exe_ctx) override { 4087321369Sdim Status err; 4088314564Sdim StreamString err_str; 4089314564Sdim const int short_option = m_getopt_table[option_idx].val; 4090314564Sdim switch (short_option) { 4091314564Sdim case 't': 4092314564Sdim if (!ParseReductionTypes(option_arg, err_str)) 4093314564Sdim err.SetErrorStringWithFormat( 4094314564Sdim "Unable to deduce reduction types for %s: %s", 4095314564Sdim option_arg.str().c_str(), err_str.GetData()); 4096314564Sdim break; 4097314564Sdim case 'c': { 4098314564Sdim auto coord = RSCoordinate{}; 4099314564Sdim if (!ParseCoordinate(option_arg, coord)) 4100314564Sdim err.SetErrorStringWithFormat("unable to parse coordinate for %s", 4101314564Sdim option_arg.str().c_str()); 4102314564Sdim else { 4103314564Sdim m_have_coord = true; 4104314564Sdim m_coord = coord; 4105314564Sdim } 4106314564Sdim break; 4107314564Sdim } 4108314564Sdim default: 4109314564Sdim err.SetErrorStringWithFormat("Invalid option '-%c'", short_option); 4110314564Sdim } 4111314564Sdim return err; 4112285101Semaste } 4113285101Semaste 4114314564Sdim void OptionParsingStarting(ExecutionContext *exe_ctx) override { 4115314564Sdim m_have_coord = false; 4116314564Sdim } 4117285101Semaste 4118314564Sdim llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 4119314564Sdim return llvm::makeArrayRef(g_renderscript_reduction_bp_set_options); 4120296417Sdim } 4121296417Sdim 4122314564Sdim bool ParseReductionTypes(llvm::StringRef option_val, 4123314564Sdim StreamString &err_str) { 4124314564Sdim m_kernel_types = RSReduceBreakpointResolver::eKernelTypeNone; 4125314564Sdim const auto reduce_name_to_type = [](llvm::StringRef name) -> int { 4126314564Sdim return llvm::StringSwitch<int>(name) 4127314564Sdim .Case("accumulator", RSReduceBreakpointResolver::eKernelTypeAccum) 4128314564Sdim .Case("initializer", RSReduceBreakpointResolver::eKernelTypeInit) 4129314564Sdim .Case("outconverter", RSReduceBreakpointResolver::eKernelTypeOutC) 4130314564Sdim .Case("combiner", RSReduceBreakpointResolver::eKernelTypeComb) 4131314564Sdim .Case("all", RSReduceBreakpointResolver::eKernelTypeAll) 4132314564Sdim // Currently not exposed by the runtime 4133314564Sdim // .Case("halter", RSReduceBreakpointResolver::eKernelTypeHalter) 4134314564Sdim .Default(0); 4135314564Sdim }; 4136285101Semaste 4137314564Sdim // Matching a comma separated list of known words is fairly 4138341825Sdim // straightforward with PCRE, but we're using ERE, so we end up with a 4139341825Sdim // little ugliness... 4140314564Sdim RegularExpression match_type_list( 4141314564Sdim llvm::StringRef("^([[:alpha:]]+)(,[[:alpha:]]+){0,4}$")); 4142296417Sdim 4143314564Sdim assert(match_type_list.IsValid()); 4144285101Semaste 4145360784Sdim if (!match_type_list.Execute(option_val)) { 4146314564Sdim err_str.PutCString( 4147314564Sdim "a comma-separated list of kernel types is required"); 4148314564Sdim return false; 4149314564Sdim } 4150296417Sdim 4151314564Sdim // splitting on commas is much easier with llvm::StringRef than regex 4152314564Sdim llvm::SmallVector<llvm::StringRef, 5> type_names; 4153314564Sdim llvm::StringRef(option_val).split(type_names, ','); 4154296417Sdim 4155314564Sdim for (const auto &name : type_names) { 4156314564Sdim const int type = reduce_name_to_type(name); 4157314564Sdim if (!type) { 4158314564Sdim err_str.Printf("unknown kernel type name %s", name.str().c_str()); 4159314564Sdim return false; 4160296417Sdim } 4161314564Sdim m_kernel_types |= type; 4162314564Sdim } 4163296417Sdim 4164314564Sdim return true; 4165314564Sdim } 4166296417Sdim 4167314564Sdim int m_kernel_types; 4168314564Sdim llvm::StringRef m_reduce_name; 4169314564Sdim RSCoordinate m_coord; 4170314564Sdim bool m_have_coord; 4171314564Sdim }; 4172296417Sdim 4173314564Sdim Options *GetOptions() override { return &m_options; } 4174296417Sdim 4175314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 4176314564Sdim const size_t argc = command.GetArgumentCount(); 4177314564Sdim if (argc < 1) { 4178314564Sdim result.AppendErrorWithFormat("'%s' takes 1 argument of reduction name, " 4179314564Sdim "and an optional kernel type list", 4180314564Sdim m_cmd_name.c_str()); 4181314564Sdim result.SetStatus(eReturnStatusFailed); 4182314564Sdim return false; 4183314564Sdim } 4184285101Semaste 4185314564Sdim RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4186314564Sdim m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4187314564Sdim eLanguageTypeExtRenderScript)); 4188296417Sdim 4189314564Sdim auto &outstream = result.GetOutputStream(); 4190314564Sdim auto name = command.GetArgumentAtIndex(0); 4191314564Sdim auto &target = m_exe_ctx.GetTargetSP(); 4192314564Sdim auto coord = m_options.m_have_coord ? &m_options.m_coord : nullptr; 4193314564Sdim if (!runtime->PlaceBreakpointOnReduction(target, outstream, name, coord, 4194314564Sdim m_options.m_kernel_types)) { 4195314564Sdim result.SetStatus(eReturnStatusFailed); 4196314564Sdim result.AppendError("Error: unable to place breakpoint on reduction"); 4197314564Sdim return false; 4198285101Semaste } 4199314564Sdim result.AppendMessage("Breakpoint(s) created"); 4200314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 4201314564Sdim return true; 4202314564Sdim } 4203296417Sdim 4204296417Sdimprivate: 4205314564Sdim CommandOptions m_options; 4206285101Semaste}; 4207285101Semaste 4208344779Sdimstatic constexpr OptionDefinition g_renderscript_kernel_bp_set_options[] = { 4209314564Sdim {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument, 4210344779Sdim nullptr, {}, 0, eArgTypeValue, 4211314564Sdim "Set a breakpoint on a single invocation of the kernel with specified " 4212314564Sdim "coordinate.\n" 4213314564Sdim "Coordinate takes the form 'x[,y][,z] where x,y,z are positive " 4214314564Sdim "integers representing kernel dimensions. " 4215314564Sdim "Any unset dimensions will be defaulted to zero."}}; 4216296417Sdim 4217314564Sdimclass CommandObjectRenderScriptRuntimeKernelBreakpointSet 4218314564Sdim : public CommandObjectParsed { 4219296417Sdimpublic: 4220314564Sdim CommandObjectRenderScriptRuntimeKernelBreakpointSet( 4221314564Sdim CommandInterpreter &interpreter) 4222314564Sdim : CommandObjectParsed( 4223314564Sdim interpreter, "renderscript kernel breakpoint set", 4224314564Sdim "Sets a breakpoint on a renderscript kernel.", 4225314564Sdim "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]", 4226314564Sdim eCommandRequiresProcess | eCommandProcessMustBeLaunched | 4227314564Sdim eCommandProcessMustBePaused), 4228314564Sdim m_options() {} 4229296417Sdim 4230314564Sdim ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default; 4231296417Sdim 4232314564Sdim Options *GetOptions() override { return &m_options; } 4233296417Sdim 4234314564Sdim class CommandOptions : public Options { 4235314564Sdim public: 4236314564Sdim CommandOptions() : Options() {} 4237296417Sdim 4238314564Sdim ~CommandOptions() override = default; 4239314564Sdim 4240321369Sdim Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 4241321369Sdim ExecutionContext *exe_ctx) override { 4242321369Sdim Status err; 4243314564Sdim const int short_option = m_getopt_table[option_idx].val; 4244314564Sdim 4245314564Sdim switch (short_option) { 4246314564Sdim case 'c': { 4247314564Sdim auto coord = RSCoordinate{}; 4248314564Sdim if (!ParseCoordinate(option_arg, coord)) 4249314564Sdim err.SetErrorStringWithFormat( 4250314564Sdim "Couldn't parse coordinate '%s', should be in format 'x,y,z'.", 4251314564Sdim option_arg.str().c_str()); 4252314564Sdim else { 4253314564Sdim m_have_coord = true; 4254314564Sdim m_coord = coord; 4255296417Sdim } 4256314564Sdim break; 4257314564Sdim } 4258314564Sdim default: 4259314564Sdim err.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 4260314564Sdim break; 4261314564Sdim } 4262314564Sdim return err; 4263314564Sdim } 4264296417Sdim 4265314564Sdim void OptionParsingStarting(ExecutionContext *exe_ctx) override { 4266314564Sdim m_have_coord = false; 4267314564Sdim } 4268296417Sdim 4269314564Sdim llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 4270314564Sdim return llvm::makeArrayRef(g_renderscript_kernel_bp_set_options); 4271296417Sdim } 4272296417Sdim 4273314564Sdim RSCoordinate m_coord; 4274314564Sdim bool m_have_coord; 4275314564Sdim }; 4276314564Sdim 4277314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 4278314564Sdim const size_t argc = command.GetArgumentCount(); 4279314564Sdim if (argc < 1) { 4280314564Sdim result.AppendErrorWithFormat( 4281314564Sdim "'%s' takes 1 argument of kernel name, and an optional coordinate.", 4282314564Sdim m_cmd_name.c_str()); 4283314564Sdim result.SetStatus(eReturnStatusFailed); 4284314564Sdim return false; 4285309124Sdim } 4286309124Sdim 4287353358Sdim RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>( 4288353358Sdim m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4289353358Sdim eLanguageTypeExtRenderScript)); 4290309124Sdim 4291314564Sdim auto &outstream = result.GetOutputStream(); 4292314564Sdim auto &target = m_exe_ctx.GetTargetSP(); 4293314564Sdim auto name = command.GetArgumentAtIndex(0); 4294314564Sdim auto coord = m_options.m_have_coord ? &m_options.m_coord : nullptr; 4295314564Sdim if (!runtime->PlaceBreakpointOnKernel(target, outstream, name, coord)) { 4296314564Sdim result.SetStatus(eReturnStatusFailed); 4297314564Sdim result.AppendErrorWithFormat( 4298314564Sdim "Error: unable to set breakpoint on kernel '%s'", name); 4299314564Sdim return false; 4300314564Sdim } 4301309124Sdim 4302314564Sdim result.AppendMessage("Breakpoint(s) created"); 4303314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 4304314564Sdim return true; 4305314564Sdim } 4306314564Sdim 4307314564Sdimprivate: 4308314564Sdim CommandOptions m_options; 4309309124Sdim}; 4310309124Sdim 4311314564Sdimclass CommandObjectRenderScriptRuntimeKernelBreakpointAll 4312314564Sdim : public CommandObjectParsed { 4313296417Sdimpublic: 4314314564Sdim CommandObjectRenderScriptRuntimeKernelBreakpointAll( 4315314564Sdim CommandInterpreter &interpreter) 4316314564Sdim : CommandObjectParsed( 4317314564Sdim interpreter, "renderscript kernel breakpoint all", 4318314564Sdim "Automatically sets a breakpoint on all renderscript kernels that " 4319314564Sdim "are or will be loaded.\n" 4320314564Sdim "Disabling option means breakpoints will no longer be set on any " 4321314564Sdim "kernels loaded in the future, " 4322314564Sdim "but does not remove currently set breakpoints.", 4323314564Sdim "renderscript kernel breakpoint all <enable/disable>", 4324314564Sdim eCommandRequiresProcess | eCommandProcessMustBeLaunched | 4325314564Sdim eCommandProcessMustBePaused) {} 4326314564Sdim 4327314564Sdim ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default; 4328314564Sdim 4329314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 4330314564Sdim const size_t argc = command.GetArgumentCount(); 4331314564Sdim if (argc != 1) { 4332314564Sdim result.AppendErrorWithFormat( 4333314564Sdim "'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str()); 4334314564Sdim result.SetStatus(eReturnStatusFailed); 4335314564Sdim return false; 4336296417Sdim } 4337296417Sdim 4338314564Sdim RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4339314564Sdim m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4340314564Sdim eLanguageTypeExtRenderScript)); 4341314564Sdim 4342314564Sdim bool do_break = false; 4343314564Sdim const char *argument = command.GetArgumentAtIndex(0); 4344314564Sdim if (strcmp(argument, "enable") == 0) { 4345314564Sdim do_break = true; 4346314564Sdim result.AppendMessage("Breakpoints will be set on all kernels."); 4347314564Sdim } else if (strcmp(argument, "disable") == 0) { 4348314564Sdim do_break = false; 4349314564Sdim result.AppendMessage("Breakpoints will not be set on any new kernels."); 4350314564Sdim } else { 4351314564Sdim result.AppendErrorWithFormat( 4352314564Sdim "Argument must be either 'enable' or 'disable'"); 4353314564Sdim result.SetStatus(eReturnStatusFailed); 4354314564Sdim return false; 4355314564Sdim } 4356314564Sdim 4357314564Sdim runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP()); 4358314564Sdim 4359314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 4360314564Sdim return true; 4361314564Sdim } 4362296417Sdim}; 4363296417Sdim 4364314564Sdimclass CommandObjectRenderScriptRuntimeReductionBreakpoint 4365314564Sdim : public CommandObjectMultiword { 4366296417Sdimpublic: 4367314564Sdim CommandObjectRenderScriptRuntimeReductionBreakpoint( 4368314564Sdim CommandInterpreter &interpreter) 4369314564Sdim : CommandObjectMultiword(interpreter, "renderscript reduction breakpoint", 4370314564Sdim "Commands that manipulate breakpoints on " 4371314564Sdim "renderscript general reductions.", 4372314564Sdim nullptr) { 4373314564Sdim LoadSubCommand( 4374314564Sdim "set", CommandObjectSP( 4375314564Sdim new CommandObjectRenderScriptRuntimeReductionBreakpointSet( 4376314564Sdim interpreter))); 4377314564Sdim } 4378285101Semaste 4379314564Sdim ~CommandObjectRenderScriptRuntimeReductionBreakpoint() override = default; 4380285101Semaste}; 4381285101Semaste 4382314564Sdimclass CommandObjectRenderScriptRuntimeKernelCoordinate 4383314564Sdim : public CommandObjectParsed { 4384296417Sdimpublic: 4385314564Sdim CommandObjectRenderScriptRuntimeKernelCoordinate( 4386314564Sdim CommandInterpreter &interpreter) 4387314564Sdim : CommandObjectParsed( 4388314564Sdim interpreter, "renderscript kernel coordinate", 4389314564Sdim "Shows the (x,y,z) coordinate of the current kernel invocation.", 4390314564Sdim "renderscript kernel coordinate", 4391314564Sdim eCommandRequiresProcess | eCommandProcessMustBeLaunched | 4392314564Sdim eCommandProcessMustBePaused) {} 4393285101Semaste 4394314564Sdim ~CommandObjectRenderScriptRuntimeKernelCoordinate() override = default; 4395285101Semaste 4396314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 4397314564Sdim RSCoordinate coord{}; 4398314564Sdim bool success = RenderScriptRuntime::GetKernelCoordinate( 4399314564Sdim coord, m_exe_ctx.GetThreadPtr()); 4400314564Sdim Stream &stream = result.GetOutputStream(); 4401314564Sdim 4402314564Sdim if (success) { 4403314564Sdim stream.Printf("Coordinate: " FMT_COORD, coord.x, coord.y, coord.z); 4404314564Sdim stream.EOL(); 4405314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 4406314564Sdim } else { 4407314564Sdim stream.Printf("Error: Coordinate could not be found."); 4408314564Sdim stream.EOL(); 4409314564Sdim result.SetStatus(eReturnStatusFailed); 4410285101Semaste } 4411314564Sdim return true; 4412314564Sdim } 4413285101Semaste}; 4414285101Semaste 4415314564Sdimclass CommandObjectRenderScriptRuntimeKernelBreakpoint 4416314564Sdim : public CommandObjectMultiword { 4417296417Sdimpublic: 4418314564Sdim CommandObjectRenderScriptRuntimeKernelBreakpoint( 4419314564Sdim CommandInterpreter &interpreter) 4420314564Sdim : CommandObjectMultiword( 4421314564Sdim interpreter, "renderscript kernel", 4422314564Sdim "Commands that generate breakpoints on renderscript kernels.", 4423314564Sdim nullptr) { 4424314564Sdim LoadSubCommand( 4425314564Sdim "set", 4426314564Sdim CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet( 4427314564Sdim interpreter))); 4428314564Sdim LoadSubCommand( 4429314564Sdim "all", 4430314564Sdim CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll( 4431314564Sdim interpreter))); 4432314564Sdim } 4433285101Semaste 4434314564Sdim ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default; 4435285101Semaste}; 4436285101Semaste 4437314564Sdimclass CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword { 4438296417Sdimpublic: 4439314564Sdim CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter) 4440314564Sdim : CommandObjectMultiword(interpreter, "renderscript kernel", 4441314564Sdim "Commands that deal with RenderScript kernels.", 4442314564Sdim nullptr) { 4443314564Sdim LoadSubCommand( 4444314564Sdim "list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList( 4445314564Sdim interpreter))); 4446314564Sdim LoadSubCommand( 4447314564Sdim "coordinate", 4448314564Sdim CommandObjectSP( 4449314564Sdim new CommandObjectRenderScriptRuntimeKernelCoordinate(interpreter))); 4450314564Sdim LoadSubCommand( 4451314564Sdim "breakpoint", 4452314564Sdim CommandObjectSP( 4453314564Sdim new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter))); 4454314564Sdim } 4455296417Sdim 4456314564Sdim ~CommandObjectRenderScriptRuntimeKernel() override = default; 4457314564Sdim}; 4458296417Sdim 4459314564Sdimclass CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed { 4460314564Sdimpublic: 4461314564Sdim CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter) 4462314564Sdim : CommandObjectParsed(interpreter, "renderscript context dump", 4463314564Sdim "Dumps renderscript context information.", 4464314564Sdim "renderscript context dump", 4465314564Sdim eCommandRequiresProcess | 4466314564Sdim eCommandProcessMustBeLaunched) {} 4467296417Sdim 4468314564Sdim ~CommandObjectRenderScriptRuntimeContextDump() override = default; 4469296417Sdim 4470314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 4471353358Sdim RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>( 4472353358Sdim m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4473353358Sdim eLanguageTypeExtRenderScript)); 4474314564Sdim runtime->DumpContexts(result.GetOutputStream()); 4475314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 4476314564Sdim return true; 4477314564Sdim } 4478314564Sdim}; 4479296417Sdim 4480344779Sdimstatic constexpr OptionDefinition g_renderscript_runtime_alloc_dump_options[] = { 4481314564Sdim {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, 4482344779Sdim nullptr, {}, 0, eArgTypeFilename, 4483314564Sdim "Print results to specified file instead of command line."}}; 4484296417Sdim 4485314564Sdimclass CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword { 4486314564Sdimpublic: 4487314564Sdim CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter) 4488314564Sdim : CommandObjectMultiword(interpreter, "renderscript context", 4489314564Sdim "Commands that deal with RenderScript contexts.", 4490314564Sdim nullptr) { 4491314564Sdim LoadSubCommand( 4492314564Sdim "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump( 4493314564Sdim interpreter))); 4494314564Sdim } 4495296417Sdim 4496314564Sdim ~CommandObjectRenderScriptRuntimeContext() override = default; 4497314564Sdim}; 4498296417Sdim 4499314564Sdimclass CommandObjectRenderScriptRuntimeAllocationDump 4500314564Sdim : public CommandObjectParsed { 4501314564Sdimpublic: 4502314564Sdim CommandObjectRenderScriptRuntimeAllocationDump( 4503314564Sdim CommandInterpreter &interpreter) 4504314564Sdim : CommandObjectParsed(interpreter, "renderscript allocation dump", 4505314564Sdim "Displays the contents of a particular allocation", 4506314564Sdim "renderscript allocation dump <ID>", 4507314564Sdim eCommandRequiresProcess | 4508314564Sdim eCommandProcessMustBeLaunched), 4509314564Sdim m_options() {} 4510296417Sdim 4511314564Sdim ~CommandObjectRenderScriptRuntimeAllocationDump() override = default; 4512296417Sdim 4513314564Sdim Options *GetOptions() override { return &m_options; } 4514296417Sdim 4515314564Sdim class CommandOptions : public Options { 4516314564Sdim public: 4517314564Sdim CommandOptions() : Options() {} 4518296417Sdim 4519314564Sdim ~CommandOptions() override = default; 4520296417Sdim 4521321369Sdim Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 4522321369Sdim ExecutionContext *exe_ctx) override { 4523321369Sdim Status err; 4524314564Sdim const int short_option = m_getopt_table[option_idx].val; 4525314564Sdim 4526314564Sdim switch (short_option) { 4527314564Sdim case 'f': 4528344779Sdim m_outfile.SetFile(option_arg, FileSpec::Style::native); 4529344779Sdim FileSystem::Instance().Resolve(m_outfile); 4530344779Sdim if (FileSystem::Instance().Exists(m_outfile)) { 4531314564Sdim m_outfile.Clear(); 4532314564Sdim err.SetErrorStringWithFormat("file already exists: '%s'", 4533314564Sdim option_arg.str().c_str()); 4534296417Sdim } 4535314564Sdim break; 4536314564Sdim default: 4537314564Sdim err.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 4538314564Sdim break; 4539314564Sdim } 4540314564Sdim return err; 4541314564Sdim } 4542296417Sdim 4543314564Sdim void OptionParsingStarting(ExecutionContext *exe_ctx) override { 4544314564Sdim m_outfile.Clear(); 4545314564Sdim } 4546296417Sdim 4547314564Sdim llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 4548314564Sdim return llvm::makeArrayRef(g_renderscript_runtime_alloc_dump_options); 4549314564Sdim } 4550296417Sdim 4551314564Sdim FileSpec m_outfile; 4552314564Sdim }; 4553314564Sdim 4554314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 4555314564Sdim const size_t argc = command.GetArgumentCount(); 4556314564Sdim if (argc < 1) { 4557314564Sdim result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. " 4558314564Sdim "As well as an optional -f argument", 4559314564Sdim m_cmd_name.c_str()); 4560314564Sdim result.SetStatus(eReturnStatusFailed); 4561314564Sdim return false; 4562296417Sdim } 4563296417Sdim 4564314564Sdim RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4565314564Sdim m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4566314564Sdim eLanguageTypeExtRenderScript)); 4567314564Sdim 4568314564Sdim const char *id_cstr = command.GetArgumentAtIndex(0); 4569314564Sdim bool success = false; 4570314564Sdim const uint32_t id = 4571314564Sdim StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &success); 4572314564Sdim if (!success) { 4573314564Sdim result.AppendErrorWithFormat("invalid allocation id argument '%s'", 4574314564Sdim id_cstr); 4575314564Sdim result.SetStatus(eReturnStatusFailed); 4576314564Sdim return false; 4577314564Sdim } 4578314564Sdim 4579360784Sdim Stream *output_stream_p = nullptr; 4580360784Sdim std::unique_ptr<Stream> output_stream_storage; 4581360784Sdim 4582314564Sdim const FileSpec &outfile_spec = 4583314564Sdim m_options.m_outfile; // Dump allocation to file instead 4584314564Sdim if (outfile_spec) { 4585314564Sdim // Open output file 4586344779Sdim std::string path = outfile_spec.GetPath(); 4587360784Sdim auto file = FileSystem::Instance().Open( 4588360784Sdim outfile_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate); 4589360784Sdim if (file) { 4590360784Sdim output_stream_storage = 4591360784Sdim std::make_unique<StreamFile>(std::move(file.get())); 4592360784Sdim output_stream_p = output_stream_storage.get(); 4593344779Sdim result.GetOutputStream().Printf("Results written to '%s'", 4594344779Sdim path.c_str()); 4595314564Sdim result.GetOutputStream().EOL(); 4596314564Sdim } else { 4597360784Sdim std::string error = llvm::toString(file.takeError()); 4598360784Sdim result.AppendErrorWithFormat("Couldn't open file '%s': %s", 4599360784Sdim path.c_str(), error.c_str()); 4600314564Sdim result.SetStatus(eReturnStatusFailed); 4601314564Sdim return false; 4602314564Sdim } 4603314564Sdim } else 4604360784Sdim output_stream_p = &result.GetOutputStream(); 4605314564Sdim 4606360784Sdim assert(output_stream_p != nullptr); 4607314564Sdim bool dumped = 4608360784Sdim runtime->DumpAllocation(*output_stream_p, m_exe_ctx.GetFramePtr(), id); 4609314564Sdim 4610314564Sdim if (dumped) 4611314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 4612314564Sdim else 4613314564Sdim result.SetStatus(eReturnStatusFailed); 4614314564Sdim 4615314564Sdim return true; 4616314564Sdim } 4617314564Sdim 4618296417Sdimprivate: 4619314564Sdim CommandOptions m_options; 4620296417Sdim}; 4621296417Sdim 4622344779Sdimstatic constexpr OptionDefinition g_renderscript_runtime_alloc_list_options[] = { 4623314564Sdim {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument, nullptr, 4624344779Sdim {}, 0, eArgTypeIndex, 4625314564Sdim "Only show details of a single allocation with specified id."}}; 4626296417Sdim 4627314564Sdimclass CommandObjectRenderScriptRuntimeAllocationList 4628314564Sdim : public CommandObjectParsed { 4629296417Sdimpublic: 4630314564Sdim CommandObjectRenderScriptRuntimeAllocationList( 4631314564Sdim CommandInterpreter &interpreter) 4632314564Sdim : CommandObjectParsed( 4633314564Sdim interpreter, "renderscript allocation list", 4634314564Sdim "List renderscript allocations and their information.", 4635314564Sdim "renderscript allocation list", 4636314564Sdim eCommandRequiresProcess | eCommandProcessMustBeLaunched), 4637314564Sdim m_options() {} 4638296417Sdim 4639314564Sdim ~CommandObjectRenderScriptRuntimeAllocationList() override = default; 4640296417Sdim 4641314564Sdim Options *GetOptions() override { return &m_options; } 4642296417Sdim 4643314564Sdim class CommandOptions : public Options { 4644314564Sdim public: 4645314564Sdim CommandOptions() : Options(), m_id(0) {} 4646296417Sdim 4647314564Sdim ~CommandOptions() override = default; 4648296417Sdim 4649321369Sdim Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 4650321369Sdim ExecutionContext *exe_ctx) override { 4651321369Sdim Status err; 4652314564Sdim const int short_option = m_getopt_table[option_idx].val; 4653296417Sdim 4654314564Sdim switch (short_option) { 4655314564Sdim case 'i': 4656314564Sdim if (option_arg.getAsInteger(0, m_id)) 4657314564Sdim err.SetErrorStringWithFormat("invalid integer value for option '%c'", 4658314564Sdim short_option); 4659314564Sdim break; 4660314564Sdim default: 4661314564Sdim err.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 4662314564Sdim break; 4663314564Sdim } 4664314564Sdim return err; 4665314564Sdim } 4666296417Sdim 4667314564Sdim void OptionParsingStarting(ExecutionContext *exe_ctx) override { m_id = 0; } 4668296417Sdim 4669314564Sdim llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 4670314564Sdim return llvm::makeArrayRef(g_renderscript_runtime_alloc_list_options); 4671314564Sdim } 4672296417Sdim 4673314564Sdim uint32_t m_id; 4674314564Sdim }; 4675296417Sdim 4676314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 4677314564Sdim RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4678314564Sdim m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4679314564Sdim eLanguageTypeExtRenderScript)); 4680314564Sdim runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(), 4681314564Sdim m_options.m_id); 4682314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 4683314564Sdim return true; 4684314564Sdim } 4685296417Sdim 4686296417Sdimprivate: 4687314564Sdim CommandOptions m_options; 4688296417Sdim}; 4689296417Sdim 4690314564Sdimclass CommandObjectRenderScriptRuntimeAllocationLoad 4691314564Sdim : public CommandObjectParsed { 4692296417Sdimpublic: 4693314564Sdim CommandObjectRenderScriptRuntimeAllocationLoad( 4694314564Sdim CommandInterpreter &interpreter) 4695314564Sdim : CommandObjectParsed( 4696314564Sdim interpreter, "renderscript allocation load", 4697314564Sdim "Loads renderscript allocation contents from a file.", 4698314564Sdim "renderscript allocation load <ID> <filename>", 4699314564Sdim eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} 4700296417Sdim 4701314564Sdim ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default; 4702296417Sdim 4703314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 4704314564Sdim const size_t argc = command.GetArgumentCount(); 4705314564Sdim if (argc != 2) { 4706314564Sdim result.AppendErrorWithFormat( 4707314564Sdim "'%s' takes 2 arguments, an allocation ID and filename to read from.", 4708314564Sdim m_cmd_name.c_str()); 4709314564Sdim result.SetStatus(eReturnStatusFailed); 4710314564Sdim return false; 4711314564Sdim } 4712296417Sdim 4713314564Sdim RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4714314564Sdim m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4715314564Sdim eLanguageTypeExtRenderScript)); 4716296417Sdim 4717314564Sdim const char *id_cstr = command.GetArgumentAtIndex(0); 4718314564Sdim bool success = false; 4719314564Sdim const uint32_t id = 4720314564Sdim StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &success); 4721314564Sdim if (!success) { 4722314564Sdim result.AppendErrorWithFormat("invalid allocation id argument '%s'", 4723314564Sdim id_cstr); 4724314564Sdim result.SetStatus(eReturnStatusFailed); 4725314564Sdim return false; 4726314564Sdim } 4727296417Sdim 4728314564Sdim const char *path = command.GetArgumentAtIndex(1); 4729314564Sdim bool loaded = runtime->LoadAllocation(result.GetOutputStream(), id, path, 4730314564Sdim m_exe_ctx.GetFramePtr()); 4731296417Sdim 4732314564Sdim if (loaded) 4733314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 4734314564Sdim else 4735314564Sdim result.SetStatus(eReturnStatusFailed); 4736296417Sdim 4737314564Sdim return true; 4738314564Sdim } 4739296417Sdim}; 4740296417Sdim 4741314564Sdimclass CommandObjectRenderScriptRuntimeAllocationSave 4742314564Sdim : public CommandObjectParsed { 4743296417Sdimpublic: 4744314564Sdim CommandObjectRenderScriptRuntimeAllocationSave( 4745314564Sdim CommandInterpreter &interpreter) 4746314564Sdim : CommandObjectParsed(interpreter, "renderscript allocation save", 4747314564Sdim "Write renderscript allocation contents to a file.", 4748314564Sdim "renderscript allocation save <ID> <filename>", 4749314564Sdim eCommandRequiresProcess | 4750314564Sdim eCommandProcessMustBeLaunched) {} 4751296417Sdim 4752314564Sdim ~CommandObjectRenderScriptRuntimeAllocationSave() override = default; 4753296417Sdim 4754314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 4755314564Sdim const size_t argc = command.GetArgumentCount(); 4756314564Sdim if (argc != 2) { 4757314564Sdim result.AppendErrorWithFormat( 4758314564Sdim "'%s' takes 2 arguments, an allocation ID and filename to read from.", 4759314564Sdim m_cmd_name.c_str()); 4760314564Sdim result.SetStatus(eReturnStatusFailed); 4761314564Sdim return false; 4762314564Sdim } 4763296417Sdim 4764314564Sdim RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4765314564Sdim m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4766314564Sdim eLanguageTypeExtRenderScript)); 4767296417Sdim 4768314564Sdim const char *id_cstr = command.GetArgumentAtIndex(0); 4769314564Sdim bool success = false; 4770314564Sdim const uint32_t id = 4771314564Sdim StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &success); 4772314564Sdim if (!success) { 4773314564Sdim result.AppendErrorWithFormat("invalid allocation id argument '%s'", 4774314564Sdim id_cstr); 4775314564Sdim result.SetStatus(eReturnStatusFailed); 4776314564Sdim return false; 4777314564Sdim } 4778296417Sdim 4779314564Sdim const char *path = command.GetArgumentAtIndex(1); 4780314564Sdim bool saved = runtime->SaveAllocation(result.GetOutputStream(), id, path, 4781314564Sdim m_exe_ctx.GetFramePtr()); 4782296417Sdim 4783314564Sdim if (saved) 4784314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 4785314564Sdim else 4786314564Sdim result.SetStatus(eReturnStatusFailed); 4787296417Sdim 4788314564Sdim return true; 4789314564Sdim } 4790296417Sdim}; 4791296417Sdim 4792314564Sdimclass CommandObjectRenderScriptRuntimeAllocationRefresh 4793314564Sdim : public CommandObjectParsed { 4794309124Sdimpublic: 4795314564Sdim CommandObjectRenderScriptRuntimeAllocationRefresh( 4796314564Sdim CommandInterpreter &interpreter) 4797314564Sdim : CommandObjectParsed(interpreter, "renderscript allocation refresh", 4798314564Sdim "Recomputes the details of all allocations.", 4799314564Sdim "renderscript allocation refresh", 4800314564Sdim eCommandRequiresProcess | 4801314564Sdim eCommandProcessMustBeLaunched) {} 4802309124Sdim 4803314564Sdim ~CommandObjectRenderScriptRuntimeAllocationRefresh() override = default; 4804309124Sdim 4805314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 4806314564Sdim RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4807314564Sdim m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4808314564Sdim eLanguageTypeExtRenderScript)); 4809309124Sdim 4810314564Sdim bool success = runtime->RecomputeAllAllocations(result.GetOutputStream(), 4811314564Sdim m_exe_ctx.GetFramePtr()); 4812309124Sdim 4813314564Sdim if (success) { 4814314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 4815314564Sdim return true; 4816314564Sdim } else { 4817314564Sdim result.SetStatus(eReturnStatusFailed); 4818314564Sdim return false; 4819309124Sdim } 4820314564Sdim } 4821309124Sdim}; 4822309124Sdim 4823314564Sdimclass CommandObjectRenderScriptRuntimeAllocation 4824314564Sdim : public CommandObjectMultiword { 4825296417Sdimpublic: 4826314564Sdim CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter) 4827314564Sdim : CommandObjectMultiword( 4828314564Sdim interpreter, "renderscript allocation", 4829314564Sdim "Commands that deal with RenderScript allocations.", nullptr) { 4830314564Sdim LoadSubCommand( 4831314564Sdim "list", 4832314564Sdim CommandObjectSP( 4833314564Sdim new CommandObjectRenderScriptRuntimeAllocationList(interpreter))); 4834314564Sdim LoadSubCommand( 4835314564Sdim "dump", 4836314564Sdim CommandObjectSP( 4837314564Sdim new CommandObjectRenderScriptRuntimeAllocationDump(interpreter))); 4838314564Sdim LoadSubCommand( 4839314564Sdim "save", 4840314564Sdim CommandObjectSP( 4841314564Sdim new CommandObjectRenderScriptRuntimeAllocationSave(interpreter))); 4842314564Sdim LoadSubCommand( 4843314564Sdim "load", 4844314564Sdim CommandObjectSP( 4845314564Sdim new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter))); 4846314564Sdim LoadSubCommand( 4847314564Sdim "refresh", 4848314564Sdim CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationRefresh( 4849314564Sdim interpreter))); 4850314564Sdim } 4851296417Sdim 4852314564Sdim ~CommandObjectRenderScriptRuntimeAllocation() override = default; 4853296417Sdim}; 4854296417Sdim 4855314564Sdimclass CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed { 4856296417Sdimpublic: 4857314564Sdim CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter) 4858314564Sdim : CommandObjectParsed(interpreter, "renderscript status", 4859314564Sdim "Displays current RenderScript runtime status.", 4860314564Sdim "renderscript status", 4861314564Sdim eCommandRequiresProcess | 4862314564Sdim eCommandProcessMustBeLaunched) {} 4863285101Semaste 4864314564Sdim ~CommandObjectRenderScriptRuntimeStatus() override = default; 4865285101Semaste 4866314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 4867353358Sdim RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>( 4868353358Sdim m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4869353358Sdim eLanguageTypeExtRenderScript)); 4870321369Sdim runtime->DumpStatus(result.GetOutputStream()); 4871314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 4872314564Sdim return true; 4873314564Sdim } 4874285101Semaste}; 4875285101Semaste 4876314564Sdimclass CommandObjectRenderScriptRuntimeReduction 4877314564Sdim : public CommandObjectMultiword { 4878296417Sdimpublic: 4879314564Sdim CommandObjectRenderScriptRuntimeReduction(CommandInterpreter &interpreter) 4880314564Sdim : CommandObjectMultiword(interpreter, "renderscript reduction", 4881314564Sdim "Commands that handle general reduction kernels", 4882314564Sdim nullptr) { 4883314564Sdim LoadSubCommand( 4884314564Sdim "breakpoint", 4885314564Sdim CommandObjectSP(new CommandObjectRenderScriptRuntimeReductionBreakpoint( 4886314564Sdim interpreter))); 4887314564Sdim } 4888314564Sdim ~CommandObjectRenderScriptRuntimeReduction() override = default; 4889314564Sdim}; 4890285101Semaste 4891314564Sdimclass CommandObjectRenderScriptRuntime : public CommandObjectMultiword { 4892314564Sdimpublic: 4893314564Sdim CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter) 4894314564Sdim : CommandObjectMultiword( 4895314564Sdim interpreter, "renderscript", 4896314564Sdim "Commands for operating on the RenderScript runtime.", 4897314564Sdim "renderscript <subcommand> [<subcommand-options>]") { 4898314564Sdim LoadSubCommand( 4899314564Sdim "module", CommandObjectSP( 4900314564Sdim new CommandObjectRenderScriptRuntimeModule(interpreter))); 4901314564Sdim LoadSubCommand( 4902314564Sdim "status", CommandObjectSP( 4903314564Sdim new CommandObjectRenderScriptRuntimeStatus(interpreter))); 4904314564Sdim LoadSubCommand( 4905314564Sdim "kernel", CommandObjectSP( 4906314564Sdim new CommandObjectRenderScriptRuntimeKernel(interpreter))); 4907314564Sdim LoadSubCommand("context", 4908314564Sdim CommandObjectSP(new CommandObjectRenderScriptRuntimeContext( 4909314564Sdim interpreter))); 4910314564Sdim LoadSubCommand( 4911314564Sdim "allocation", 4912314564Sdim CommandObjectSP( 4913314564Sdim new CommandObjectRenderScriptRuntimeAllocation(interpreter))); 4914314564Sdim LoadSubCommand("scriptgroup", 4915314564Sdim NewCommandObjectRenderScriptScriptGroup(interpreter)); 4916314564Sdim LoadSubCommand( 4917314564Sdim "reduction", 4918314564Sdim CommandObjectSP( 4919314564Sdim new CommandObjectRenderScriptRuntimeReduction(interpreter))); 4920314564Sdim } 4921314564Sdim 4922314564Sdim ~CommandObjectRenderScriptRuntime() override = default; 4923285101Semaste}; 4924285101Semaste 4925314564Sdimvoid RenderScriptRuntime::Initiate() { assert(!m_initiated); } 4926285101Semaste 4927285101SemasteRenderScriptRuntime::RenderScriptRuntime(Process *process) 4928314564Sdim : lldb_private::CPPLanguageRuntime(process), m_initiated(false), 4929314564Sdim m_debuggerPresentFlagged(false), m_breakAllKernels(false), 4930314564Sdim m_ir_passes(nullptr) { 4931314564Sdim ModulesDidLoad(process->GetTarget().GetImages()); 4932285101Semaste} 4933285101Semaste 4934314564Sdimlldb::CommandObjectSP RenderScriptRuntime::GetCommandObject( 4935314564Sdim lldb_private::CommandInterpreter &interpreter) { 4936314564Sdim return CommandObjectSP(new CommandObjectRenderScriptRuntime(interpreter)); 4937285101Semaste} 4938285101Semaste 4939296417SdimRenderScriptRuntime::~RenderScriptRuntime() = default; 4940