1 //===-- RenderScriptRuntime.cpp ---------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 // Other libraries and framework includes 13 // Project includes 14 #include "RenderScriptRuntime.h" 15 16 #include "lldb/Breakpoint/StoppointCallbackContext.h" 17 #include "lldb/Core/ConstString.h" 18 #include "lldb/Core/Debugger.h" 19 #include "lldb/Core/Error.h" 20 #include "lldb/Core/Log.h" 21 #include "lldb/Core/PluginManager.h" 22 #include "lldb/Core/RegularExpression.h" 23 #include "lldb/Core/ValueObjectVariable.h" 24 #include "lldb/DataFormatters/DumpValueObjectOptions.h" 25 #include "lldb/Expression/UserExpression.h" 26 #include "lldb/Host/StringConvert.h" 27 #include "lldb/Interpreter/Args.h" 28 #include "lldb/Interpreter/CommandInterpreter.h" 29 #include "lldb/Interpreter/CommandObjectMultiword.h" 30 #include "lldb/Interpreter/CommandReturnObject.h" 31 #include "lldb/Interpreter/Options.h" 32 #include "lldb/Symbol/Symbol.h" 33 #include "lldb/Symbol/Type.h" 34 #include "lldb/Symbol/VariableList.h" 35 #include "lldb/Target/Process.h" 36 #include "lldb/Target/RegisterContext.h" 37 #include "lldb/Target/Target.h" 38 #include "lldb/Target/Thread.h" 39 40 using namespace lldb; 41 using namespace lldb_private; 42 using namespace lldb_renderscript; 43 44 namespace { 45 46 // The empirical_type adds a basic level of validation to arbitrary data 47 // allowing us to track if data has been discovered and stored or not. 48 // An empirical_type will be marked as valid only if it has been explicitly 49 // assigned to. 50 template <typename type_t> class empirical_type { 51 public: 52 // Ctor. Contents is invalid when constructed. 53 empirical_type() : valid(false) {} 54 55 // Return true and copy contents to out if valid, else return false. 56 bool get(type_t &out) const { 57 if (valid) 58 out = data; 59 return valid; 60 } 61 62 // Return a pointer to the contents or nullptr if it was not valid. 63 const type_t *get() const { return valid ? &data : nullptr; } 64 65 // Assign data explicitly. 66 void set(const type_t in) { 67 data = in; 68 valid = true; 69 } 70 71 // Mark contents as invalid. 72 void invalidate() { valid = false; } 73 74 // Returns true if this type contains valid data. 75 bool isValid() const { return valid; } 76 77 // Assignment operator. 78 empirical_type<type_t> &operator=(const type_t in) { 79 set(in); 80 return *this; 81 } 82 83 // Dereference operator returns contents. 84 // Warning: Will assert if not valid so use only when you know data is valid. 85 const type_t &operator*() const { 86 assert(valid); 87 return data; 88 } 89 90 protected: 91 bool valid; 92 type_t data; 93 }; 94 95 // ArgItem is used by the GetArgs() function when reading function arguments 96 // from the target. 97 struct ArgItem { 98 enum { ePointer, eInt32, eInt64, eLong, eBool } type; 99 100 uint64_t value; 101 102 explicit operator uint64_t() const { return value; } 103 }; 104 105 // Context structure to be passed into GetArgsXXX(), argument reading functions 106 // below. 107 struct GetArgsCtx { 108 RegisterContext *reg_ctx; 109 Process *process; 110 }; 111 112 bool GetArgsX86(const GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 113 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 114 115 Error error; 116 117 // get the current stack pointer 118 uint64_t sp = ctx.reg_ctx->GetSP(); 119 120 for (size_t i = 0; i < num_args; ++i) { 121 ArgItem &arg = arg_list[i]; 122 // advance up the stack by one argument 123 sp += sizeof(uint32_t); 124 // get the argument type size 125 size_t arg_size = sizeof(uint32_t); 126 // read the argument from memory 127 arg.value = 0; 128 Error error; 129 size_t read = 130 ctx.process->ReadMemory(sp, &arg.value, sizeof(uint32_t), error); 131 if (read != arg_size || !error.Success()) { 132 if (log) 133 log->Printf("%s - error reading argument: %" PRIu64 " '%s'", 134 __FUNCTION__, uint64_t(i), error.AsCString()); 135 return false; 136 } 137 } 138 return true; 139 } 140 141 bool GetArgsX86_64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 142 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 143 144 // number of arguments passed in registers 145 static const uint32_t c_args_in_reg = 6; 146 // register passing order 147 static const std::array<const char *, c_args_in_reg> c_reg_names{ 148 {"rdi", "rsi", "rdx", "rcx", "r8", "r9"}}; 149 // argument type to size mapping 150 static const std::array<size_t, 5> arg_size{{ 151 8, // ePointer, 152 4, // eInt32, 153 8, // eInt64, 154 8, // eLong, 155 4, // eBool, 156 }}; 157 158 Error error; 159 160 // get the current stack pointer 161 uint64_t sp = ctx.reg_ctx->GetSP(); 162 // step over the return address 163 sp += sizeof(uint64_t); 164 165 // check the stack alignment was correct (16 byte aligned) 166 if ((sp & 0xf) != 0x0) { 167 if (log) 168 log->Printf("%s - stack misaligned", __FUNCTION__); 169 return false; 170 } 171 172 // find the start of arguments on the stack 173 uint64_t sp_offset = 0; 174 for (uint32_t i = c_args_in_reg; i < num_args; ++i) { 175 sp_offset += arg_size[arg_list[i].type]; 176 } 177 // round up to multiple of 16 178 sp_offset = (sp_offset + 0xf) & 0xf; 179 sp += sp_offset; 180 181 for (size_t i = 0; i < num_args; ++i) { 182 bool success = false; 183 ArgItem &arg = arg_list[i]; 184 // arguments passed in registers 185 if (i < c_args_in_reg) { 186 const RegisterInfo *rArg = 187 ctx.reg_ctx->GetRegisterInfoByName(c_reg_names[i]); 188 RegisterValue rVal; 189 if (ctx.reg_ctx->ReadRegister(rArg, rVal)) 190 arg.value = rVal.GetAsUInt64(0, &success); 191 } 192 // arguments passed on the stack 193 else { 194 // get the argument type size 195 const size_t size = arg_size[arg_list[i].type]; 196 // read the argument from memory 197 arg.value = 0; 198 // note: due to little endian layout reading 4 or 8 bytes will give the 199 // correct value. 200 size_t read = ctx.process->ReadMemory(sp, &arg.value, size, error); 201 success = (error.Success() && read == size); 202 // advance past this argument 203 sp -= size; 204 } 205 // fail if we couldn't read this argument 206 if (!success) { 207 if (log) 208 log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s", 209 __FUNCTION__, uint64_t(i), error.AsCString("n/a")); 210 return false; 211 } 212 } 213 return true; 214 } 215 216 bool GetArgsArm(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 217 // number of arguments passed in registers 218 static const uint32_t c_args_in_reg = 4; 219 220 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 221 222 Error error; 223 224 // get the current stack pointer 225 uint64_t sp = ctx.reg_ctx->GetSP(); 226 227 for (size_t i = 0; i < num_args; ++i) { 228 bool success = false; 229 ArgItem &arg = arg_list[i]; 230 // arguments passed in registers 231 if (i < c_args_in_reg) { 232 const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoAtIndex(i); 233 RegisterValue rVal; 234 if (ctx.reg_ctx->ReadRegister(rArg, rVal)) 235 arg.value = rVal.GetAsUInt32(0, &success); 236 } 237 // arguments passed on the stack 238 else { 239 // get the argument type size 240 const size_t arg_size = sizeof(uint32_t); 241 // clear all 64bits 242 arg.value = 0; 243 // read this argument from memory 244 size_t bytes_read = 245 ctx.process->ReadMemory(sp, &arg.value, arg_size, error); 246 success = (error.Success() && bytes_read == arg_size); 247 // advance the stack pointer 248 sp += sizeof(uint32_t); 249 } 250 // fail if we couldn't read this argument 251 if (!success) { 252 if (log) 253 log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s", 254 __FUNCTION__, uint64_t(i), error.AsCString("n/a")); 255 return false; 256 } 257 } 258 return true; 259 } 260 261 bool GetArgsAarch64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 262 // number of arguments passed in registers 263 static const uint32_t c_args_in_reg = 8; 264 265 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 266 267 for (size_t i = 0; i < num_args; ++i) { 268 bool success = false; 269 ArgItem &arg = arg_list[i]; 270 // arguments passed in registers 271 if (i < c_args_in_reg) { 272 const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoAtIndex(i); 273 RegisterValue rVal; 274 if (ctx.reg_ctx->ReadRegister(rArg, rVal)) 275 arg.value = rVal.GetAsUInt64(0, &success); 276 } 277 // arguments passed on the stack 278 else { 279 if (log) 280 log->Printf("%s - reading arguments spilled to stack not implemented", 281 __FUNCTION__); 282 } 283 // fail if we couldn't read this argument 284 if (!success) { 285 if (log) 286 log->Printf("%s - error reading argument: %" PRIu64, __FUNCTION__, 287 uint64_t(i)); 288 return false; 289 } 290 } 291 return true; 292 } 293 294 bool GetArgsMipsel(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 295 // number of arguments passed in registers 296 static const uint32_t c_args_in_reg = 4; 297 // register file offset to first argument 298 static const uint32_t c_reg_offset = 4; 299 300 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 301 302 Error error; 303 304 // find offset to arguments on the stack (+16 to skip over a0-a3 shadow space) 305 uint64_t sp = ctx.reg_ctx->GetSP() + 16; 306 307 for (size_t i = 0; i < num_args; ++i) { 308 bool success = false; 309 ArgItem &arg = arg_list[i]; 310 // arguments passed in registers 311 if (i < c_args_in_reg) { 312 const RegisterInfo *rArg = 313 ctx.reg_ctx->GetRegisterInfoAtIndex(i + c_reg_offset); 314 RegisterValue rVal; 315 if (ctx.reg_ctx->ReadRegister(rArg, rVal)) 316 arg.value = rVal.GetAsUInt64(0, &success); 317 } 318 // arguments passed on the stack 319 else { 320 const size_t arg_size = sizeof(uint32_t); 321 arg.value = 0; 322 size_t bytes_read = 323 ctx.process->ReadMemory(sp, &arg.value, arg_size, error); 324 success = (error.Success() && bytes_read == arg_size); 325 // advance the stack pointer 326 sp += arg_size; 327 } 328 // fail if we couldn't read this argument 329 if (!success) { 330 if (log) 331 log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s", 332 __FUNCTION__, uint64_t(i), error.AsCString("n/a")); 333 return false; 334 } 335 } 336 return true; 337 } 338 339 bool GetArgsMips64el(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { 340 // number of arguments passed in registers 341 static const uint32_t c_args_in_reg = 8; 342 // register file offset to first argument 343 static const uint32_t c_reg_offset = 4; 344 345 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 346 347 Error error; 348 349 // get the current stack pointer 350 uint64_t sp = ctx.reg_ctx->GetSP(); 351 352 for (size_t i = 0; i < num_args; ++i) { 353 bool success = false; 354 ArgItem &arg = arg_list[i]; 355 // arguments passed in registers 356 if (i < c_args_in_reg) { 357 const RegisterInfo *rArg = 358 ctx.reg_ctx->GetRegisterInfoAtIndex(i + c_reg_offset); 359 RegisterValue rVal; 360 if (ctx.reg_ctx->ReadRegister(rArg, rVal)) 361 arg.value = rVal.GetAsUInt64(0, &success); 362 } 363 // arguments passed on the stack 364 else { 365 // get the argument type size 366 const size_t arg_size = sizeof(uint64_t); 367 // clear all 64bits 368 arg.value = 0; 369 // read this argument from memory 370 size_t bytes_read = 371 ctx.process->ReadMemory(sp, &arg.value, arg_size, error); 372 success = (error.Success() && bytes_read == arg_size); 373 // advance the stack pointer 374 sp += arg_size; 375 } 376 // fail if we couldn't read this argument 377 if (!success) { 378 if (log) 379 log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s", 380 __FUNCTION__, uint64_t(i), error.AsCString("n/a")); 381 return false; 382 } 383 } 384 return true; 385 } 386 387 bool GetArgs(ExecutionContext &context, ArgItem *arg_list, size_t num_args) { 388 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 389 390 // verify that we have a target 391 if (!context.GetTargetPtr()) { 392 if (log) 393 log->Printf("%s - invalid target", __FUNCTION__); 394 return false; 395 } 396 397 GetArgsCtx ctx = {context.GetRegisterContext(), context.GetProcessPtr()}; 398 assert(ctx.reg_ctx && ctx.process); 399 400 // dispatch based on architecture 401 switch (context.GetTargetPtr()->GetArchitecture().GetMachine()) { 402 case llvm::Triple::ArchType::x86: 403 return GetArgsX86(ctx, arg_list, num_args); 404 405 case llvm::Triple::ArchType::x86_64: 406 return GetArgsX86_64(ctx, arg_list, num_args); 407 408 case llvm::Triple::ArchType::arm: 409 return GetArgsArm(ctx, arg_list, num_args); 410 411 case llvm::Triple::ArchType::aarch64: 412 return GetArgsAarch64(ctx, arg_list, num_args); 413 414 case llvm::Triple::ArchType::mipsel: 415 return GetArgsMipsel(ctx, arg_list, num_args); 416 417 case llvm::Triple::ArchType::mips64el: 418 return GetArgsMips64el(ctx, arg_list, num_args); 419 420 default: 421 // unsupported architecture 422 if (log) { 423 log->Printf( 424 "%s - architecture not supported: '%s'", __FUNCTION__, 425 context.GetTargetRef().GetArchitecture().GetArchitectureName()); 426 } 427 return false; 428 } 429 } 430 } // anonymous namespace 431 432 // The ScriptDetails class collects data associated with a single script 433 // instance. 434 struct RenderScriptRuntime::ScriptDetails { 435 ~ScriptDetails() = default; 436 437 enum ScriptType { eScript, eScriptC }; 438 439 // The derived type of the script. 440 empirical_type<ScriptType> type; 441 // The name of the original source file. 442 empirical_type<std::string> resName; 443 // Path to script .so file on the device. 444 empirical_type<std::string> scriptDyLib; 445 // Directory where kernel objects are cached on device. 446 empirical_type<std::string> cacheDir; 447 // Pointer to the context which owns this script. 448 empirical_type<lldb::addr_t> context; 449 // Pointer to the script object itself. 450 empirical_type<lldb::addr_t> script; 451 }; 452 453 // This Element class represents the Element object in RS, 454 // defining the type associated with an Allocation. 455 struct RenderScriptRuntime::Element { 456 // Taken from rsDefines.h 457 enum DataKind { 458 RS_KIND_USER, 459 RS_KIND_PIXEL_L = 7, 460 RS_KIND_PIXEL_A, 461 RS_KIND_PIXEL_LA, 462 RS_KIND_PIXEL_RGB, 463 RS_KIND_PIXEL_RGBA, 464 RS_KIND_PIXEL_DEPTH, 465 RS_KIND_PIXEL_YUV, 466 RS_KIND_INVALID = 100 467 }; 468 469 // Taken from rsDefines.h 470 enum DataType { 471 RS_TYPE_NONE = 0, 472 RS_TYPE_FLOAT_16, 473 RS_TYPE_FLOAT_32, 474 RS_TYPE_FLOAT_64, 475 RS_TYPE_SIGNED_8, 476 RS_TYPE_SIGNED_16, 477 RS_TYPE_SIGNED_32, 478 RS_TYPE_SIGNED_64, 479 RS_TYPE_UNSIGNED_8, 480 RS_TYPE_UNSIGNED_16, 481 RS_TYPE_UNSIGNED_32, 482 RS_TYPE_UNSIGNED_64, 483 RS_TYPE_BOOLEAN, 484 485 RS_TYPE_UNSIGNED_5_6_5, 486 RS_TYPE_UNSIGNED_5_5_5_1, 487 RS_TYPE_UNSIGNED_4_4_4_4, 488 489 RS_TYPE_MATRIX_4X4, 490 RS_TYPE_MATRIX_3X3, 491 RS_TYPE_MATRIX_2X2, 492 493 RS_TYPE_ELEMENT = 1000, 494 RS_TYPE_TYPE, 495 RS_TYPE_ALLOCATION, 496 RS_TYPE_SAMPLER, 497 RS_TYPE_SCRIPT, 498 RS_TYPE_MESH, 499 RS_TYPE_PROGRAM_FRAGMENT, 500 RS_TYPE_PROGRAM_VERTEX, 501 RS_TYPE_PROGRAM_RASTER, 502 RS_TYPE_PROGRAM_STORE, 503 RS_TYPE_FONT, 504 505 RS_TYPE_INVALID = 10000 506 }; 507 508 std::vector<Element> children; // Child Element fields for structs 509 empirical_type<lldb::addr_t> 510 element_ptr; // Pointer to the RS Element of the Type 511 empirical_type<DataType> 512 type; // Type of each data pointer stored by the allocation 513 empirical_type<DataKind> 514 type_kind; // Defines pixel type if Allocation is created from an image 515 empirical_type<uint32_t> 516 type_vec_size; // Vector size of each data point, e.g '4' for uchar4 517 empirical_type<uint32_t> field_count; // Number of Subelements 518 empirical_type<uint32_t> datum_size; // Size of a single Element with padding 519 empirical_type<uint32_t> padding; // Number of padding bytes 520 empirical_type<uint32_t> 521 array_size; // Number of items in array, only needed for strucrs 522 ConstString type_name; // Name of type, only needed for structs 523 524 static const ConstString & 525 GetFallbackStructName(); // Print this as the type name of a struct Element 526 // If we can't resolve the actual struct name 527 528 bool shouldRefresh() const { 529 const bool valid_ptr = element_ptr.isValid() && *element_ptr.get() != 0x0; 530 const bool valid_type = 531 type.isValid() && type_vec_size.isValid() && type_kind.isValid(); 532 return !valid_ptr || !valid_type || !datum_size.isValid(); 533 } 534 }; 535 536 // This AllocationDetails class collects data associated with a single 537 // allocation instance. 538 struct RenderScriptRuntime::AllocationDetails { 539 struct Dimension { 540 uint32_t dim_1; 541 uint32_t dim_2; 542 uint32_t dim_3; 543 uint32_t cubeMap; 544 545 Dimension() { 546 dim_1 = 0; 547 dim_2 = 0; 548 dim_3 = 0; 549 cubeMap = 0; 550 } 551 }; 552 553 // The FileHeader struct specifies the header we use for writing allocations 554 // to a binary file. 555 // Our format begins with the ASCII characters "RSAD", identifying the file as 556 // an allocation dump. 557 // Member variables dims and hdr_size are then written consecutively, 558 // immediately followed by an instance of 559 // the ElementHeader struct. Because Elements can contain subelements, there 560 // may be more than one instance 561 // of the ElementHeader struct. With this first instance being the root 562 // element, and the other instances being 563 // the root's descendants. To identify which instances are an ElementHeader's 564 // children, each struct 565 // is immediately followed by a sequence of consecutive offsets to the start 566 // of its child structs. 567 // These offsets are 4 bytes in size, and the 0 offset signifies no more 568 // children. 569 struct FileHeader { 570 uint8_t ident[4]; // ASCII 'RSAD' identifying the file 571 uint32_t dims[3]; // Dimensions 572 uint16_t hdr_size; // Header size in bytes, including all element headers 573 }; 574 575 struct ElementHeader { 576 uint16_t type; // DataType enum 577 uint32_t kind; // DataKind enum 578 uint32_t element_size; // Size of a single element, including padding 579 uint16_t vector_size; // Vector width 580 uint32_t array_size; // Number of elements in array 581 }; 582 583 // Monotonically increasing from 1 584 static uint32_t ID; 585 586 // Maps Allocation DataType enum and vector size to printable strings 587 // using mapping from RenderScript numerical types summary documentation 588 static const char *RsDataTypeToString[][4]; 589 590 // Maps Allocation DataKind enum to printable strings 591 static const char *RsDataKindToString[]; 592 593 // Maps allocation types to format sizes for printing. 594 static const uint32_t RSTypeToFormat[][3]; 595 596 // Give each allocation an ID as a way 597 // for commands to reference it. 598 const uint32_t id; 599 600 RenderScriptRuntime::Element element; // Allocation Element type 601 empirical_type<Dimension> dimension; // Dimensions of the Allocation 602 empirical_type<lldb::addr_t> 603 address; // Pointer to address of the RS Allocation 604 empirical_type<lldb::addr_t> 605 data_ptr; // Pointer to the data held by the Allocation 606 empirical_type<lldb::addr_t> 607 type_ptr; // Pointer to the RS Type of the Allocation 608 empirical_type<lldb::addr_t> 609 context; // Pointer to the RS Context of the Allocation 610 empirical_type<uint32_t> size; // Size of the allocation 611 empirical_type<uint32_t> stride; // Stride between rows of the allocation 612 613 // Give each allocation an id, so we can reference it in user commands. 614 AllocationDetails() : id(ID++) {} 615 616 bool shouldRefresh() const { 617 bool valid_ptrs = data_ptr.isValid() && *data_ptr.get() != 0x0; 618 valid_ptrs = valid_ptrs && type_ptr.isValid() && *type_ptr.get() != 0x0; 619 return !valid_ptrs || !dimension.isValid() || !size.isValid() || 620 element.shouldRefresh(); 621 } 622 }; 623 624 const ConstString &RenderScriptRuntime::Element::GetFallbackStructName() { 625 static const ConstString FallbackStructName("struct"); 626 return FallbackStructName; 627 } 628 629 uint32_t RenderScriptRuntime::AllocationDetails::ID = 1; 630 631 const char *RenderScriptRuntime::AllocationDetails::RsDataKindToString[] = { 632 "User", "Undefined", "Undefined", "Undefined", 633 "Undefined", "Undefined", "Undefined", // Enum jumps from 0 to 7 634 "L Pixel", "A Pixel", "LA Pixel", "RGB Pixel", 635 "RGBA Pixel", "Pixel Depth", "YUV Pixel"}; 636 637 const char *RenderScriptRuntime::AllocationDetails::RsDataTypeToString[][4] = { 638 {"None", "None", "None", "None"}, 639 {"half", "half2", "half3", "half4"}, 640 {"float", "float2", "float3", "float4"}, 641 {"double", "double2", "double3", "double4"}, 642 {"char", "char2", "char3", "char4"}, 643 {"short", "short2", "short3", "short4"}, 644 {"int", "int2", "int3", "int4"}, 645 {"long", "long2", "long3", "long4"}, 646 {"uchar", "uchar2", "uchar3", "uchar4"}, 647 {"ushort", "ushort2", "ushort3", "ushort4"}, 648 {"uint", "uint2", "uint3", "uint4"}, 649 {"ulong", "ulong2", "ulong3", "ulong4"}, 650 {"bool", "bool2", "bool3", "bool4"}, 651 {"packed_565", "packed_565", "packed_565", "packed_565"}, 652 {"packed_5551", "packed_5551", "packed_5551", "packed_5551"}, 653 {"packed_4444", "packed_4444", "packed_4444", "packed_4444"}, 654 {"rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4"}, 655 {"rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3"}, 656 {"rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2"}, 657 658 // Handlers 659 {"RS Element", "RS Element", "RS Element", "RS Element"}, 660 {"RS Type", "RS Type", "RS Type", "RS Type"}, 661 {"RS Allocation", "RS Allocation", "RS Allocation", "RS Allocation"}, 662 {"RS Sampler", "RS Sampler", "RS Sampler", "RS Sampler"}, 663 {"RS Script", "RS Script", "RS Script", "RS Script"}, 664 665 // Deprecated 666 {"RS Mesh", "RS Mesh", "RS Mesh", "RS Mesh"}, 667 {"RS Program Fragment", "RS Program Fragment", "RS Program Fragment", 668 "RS Program Fragment"}, 669 {"RS Program Vertex", "RS Program Vertex", "RS Program Vertex", 670 "RS Program Vertex"}, 671 {"RS Program Raster", "RS Program Raster", "RS Program Raster", 672 "RS Program Raster"}, 673 {"RS Program Store", "RS Program Store", "RS Program Store", 674 "RS Program Store"}, 675 {"RS Font", "RS Font", "RS Font", "RS Font"}}; 676 677 // Used as an index into the RSTypeToFormat array elements 678 enum TypeToFormatIndex { eFormatSingle = 0, eFormatVector, eElementSize }; 679 680 // { format enum of single element, format enum of element vector, size of 681 // element} 682 const uint32_t RenderScriptRuntime::AllocationDetails::RSTypeToFormat[][3] = { 683 {eFormatHex, eFormatHex, 1}, // RS_TYPE_NONE 684 {eFormatFloat, eFormatVectorOfFloat16, 2}, // RS_TYPE_FLOAT_16 685 {eFormatFloat, eFormatVectorOfFloat32, sizeof(float)}, // RS_TYPE_FLOAT_32 686 {eFormatFloat, eFormatVectorOfFloat64, sizeof(double)}, // RS_TYPE_FLOAT_64 687 {eFormatDecimal, eFormatVectorOfSInt8, sizeof(int8_t)}, // RS_TYPE_SIGNED_8 688 {eFormatDecimal, eFormatVectorOfSInt16, 689 sizeof(int16_t)}, // RS_TYPE_SIGNED_16 690 {eFormatDecimal, eFormatVectorOfSInt32, 691 sizeof(int32_t)}, // RS_TYPE_SIGNED_32 692 {eFormatDecimal, eFormatVectorOfSInt64, 693 sizeof(int64_t)}, // RS_TYPE_SIGNED_64 694 {eFormatDecimal, eFormatVectorOfUInt8, 695 sizeof(uint8_t)}, // RS_TYPE_UNSIGNED_8 696 {eFormatDecimal, eFormatVectorOfUInt16, 697 sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_16 698 {eFormatDecimal, eFormatVectorOfUInt32, 699 sizeof(uint32_t)}, // RS_TYPE_UNSIGNED_32 700 {eFormatDecimal, eFormatVectorOfUInt64, 701 sizeof(uint64_t)}, // RS_TYPE_UNSIGNED_64 702 {eFormatBoolean, eFormatBoolean, 1}, // RS_TYPE_BOOL 703 {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_6_5 704 {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_5_5_1 705 {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_4_4_4_4 706 {eFormatVectorOfFloat32, eFormatVectorOfFloat32, 707 sizeof(float) * 16}, // RS_TYPE_MATRIX_4X4 708 {eFormatVectorOfFloat32, eFormatVectorOfFloat32, 709 sizeof(float) * 9}, // RS_TYPE_MATRIX_3X3 710 {eFormatVectorOfFloat32, eFormatVectorOfFloat32, 711 sizeof(float) * 4} // RS_TYPE_MATRIX_2X2 712 }; 713 714 //------------------------------------------------------------------ 715 // Static Functions 716 //------------------------------------------------------------------ 717 LanguageRuntime * 718 RenderScriptRuntime::CreateInstance(Process *process, 719 lldb::LanguageType language) { 720 721 if (language == eLanguageTypeExtRenderScript) 722 return new RenderScriptRuntime(process); 723 else 724 return nullptr; 725 } 726 727 // Callback with a module to search for matching symbols. 728 // We first check that the module contains RS kernels. 729 // Then look for a symbol which matches our kernel name. 730 // The breakpoint address is finally set using the address of this symbol. 731 Searcher::CallbackReturn 732 RSBreakpointResolver::SearchCallback(SearchFilter &filter, 733 SymbolContext &context, Address *, bool) { 734 ModuleSP module = context.module_sp; 735 736 if (!module) 737 return Searcher::eCallbackReturnContinue; 738 739 // Is this a module containing renderscript kernels? 740 if (nullptr == 741 module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), 742 eSymbolTypeData)) 743 return Searcher::eCallbackReturnContinue; 744 745 // Attempt to set a breakpoint on the kernel name symbol within the module 746 // library. 747 // If it's not found, it's likely debug info is unavailable - try to set a 748 // breakpoint on <name>.expand. 749 750 const Symbol *kernel_sym = 751 module->FindFirstSymbolWithNameAndType(m_kernel_name, eSymbolTypeCode); 752 if (!kernel_sym) { 753 std::string kernel_name_expanded(m_kernel_name.AsCString()); 754 kernel_name_expanded.append(".expand"); 755 kernel_sym = module->FindFirstSymbolWithNameAndType( 756 ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode); 757 } 758 759 if (kernel_sym) { 760 Address bp_addr = kernel_sym->GetAddress(); 761 if (filter.AddressPasses(bp_addr)) 762 m_breakpoint->AddLocation(bp_addr); 763 } 764 765 return Searcher::eCallbackReturnContinue; 766 } 767 768 void RenderScriptRuntime::Initialize() { 769 PluginManager::RegisterPlugin(GetPluginNameStatic(), 770 "RenderScript language support", CreateInstance, 771 GetCommandObject); 772 } 773 774 void RenderScriptRuntime::Terminate() { 775 PluginManager::UnregisterPlugin(CreateInstance); 776 } 777 778 lldb_private::ConstString RenderScriptRuntime::GetPluginNameStatic() { 779 static ConstString g_name("renderscript"); 780 return g_name; 781 } 782 783 RenderScriptRuntime::ModuleKind 784 RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp) { 785 if (module_sp) { 786 // Is this a module containing renderscript kernels? 787 const Symbol *info_sym = module_sp->FindFirstSymbolWithNameAndType( 788 ConstString(".rs.info"), eSymbolTypeData); 789 if (info_sym) { 790 return eModuleKindKernelObj; 791 } 792 793 // Is this the main RS runtime library 794 const ConstString rs_lib("libRS.so"); 795 if (module_sp->GetFileSpec().GetFilename() == rs_lib) { 796 return eModuleKindLibRS; 797 } 798 799 const ConstString rs_driverlib("libRSDriver.so"); 800 if (module_sp->GetFileSpec().GetFilename() == rs_driverlib) { 801 return eModuleKindDriver; 802 } 803 804 const ConstString rs_cpureflib("libRSCpuRef.so"); 805 if (module_sp->GetFileSpec().GetFilename() == rs_cpureflib) { 806 return eModuleKindImpl; 807 } 808 } 809 return eModuleKindIgnored; 810 } 811 812 bool RenderScriptRuntime::IsRenderScriptModule( 813 const lldb::ModuleSP &module_sp) { 814 return GetModuleKind(module_sp) != eModuleKindIgnored; 815 } 816 817 void RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list) { 818 std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); 819 820 size_t num_modules = module_list.GetSize(); 821 for (size_t i = 0; i < num_modules; i++) { 822 auto mod = module_list.GetModuleAtIndex(i); 823 if (IsRenderScriptModule(mod)) { 824 LoadModule(mod); 825 } 826 } 827 } 828 829 //------------------------------------------------------------------ 830 // PluginInterface protocol 831 //------------------------------------------------------------------ 832 lldb_private::ConstString RenderScriptRuntime::GetPluginName() { 833 return GetPluginNameStatic(); 834 } 835 836 uint32_t RenderScriptRuntime::GetPluginVersion() { return 1; } 837 838 bool RenderScriptRuntime::IsVTableName(const char *name) { return false; } 839 840 bool RenderScriptRuntime::GetDynamicTypeAndAddress( 841 ValueObject &in_value, lldb::DynamicValueType use_dynamic, 842 TypeAndOrName &class_type_or_name, Address &address, 843 Value::ValueType &value_type) { 844 return false; 845 } 846 847 TypeAndOrName 848 RenderScriptRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, 849 ValueObject &static_value) { 850 return type_and_or_name; 851 } 852 853 bool RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value) { 854 return false; 855 } 856 857 lldb::BreakpointResolverSP 858 RenderScriptRuntime::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, 859 bool throw_bp) { 860 BreakpointResolverSP resolver_sp; 861 return resolver_sp; 862 } 863 864 const RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] = 865 { 866 // rsdScript 867 {"rsdScriptInit", "_Z13rsdScriptInitPKN7android12renderscript7ContextEP" 868 "NS0_7ScriptCEPKcS7_PKhjj", 869 "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_" 870 "7ScriptCEPKcS7_PKhmj", 871 0, RenderScriptRuntime::eModuleKindDriver, 872 &lldb_private::RenderScriptRuntime::CaptureScriptInit}, 873 {"rsdScriptInvokeForEachMulti", 874 "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0" 875 "_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall", 876 "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0" 877 "_6ScriptEjPPKNS0_10AllocationEmPS6_PKvmPK12RsScriptCall", 878 0, RenderScriptRuntime::eModuleKindDriver, 879 &lldb_private::RenderScriptRuntime::CaptureScriptInvokeForEachMulti}, 880 {"rsdScriptSetGlobalVar", "_Z21rsdScriptSetGlobalVarPKN7android12render" 881 "script7ContextEPKNS0_6ScriptEjPvj", 882 "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_" 883 "6ScriptEjPvm", 884 0, RenderScriptRuntime::eModuleKindDriver, 885 &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar}, 886 887 // rsdAllocation 888 {"rsdAllocationInit", "_Z17rsdAllocationInitPKN7android12renderscript7C" 889 "ontextEPNS0_10AllocationEb", 890 "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_" 891 "10AllocationEb", 892 0, RenderScriptRuntime::eModuleKindDriver, 893 &lldb_private::RenderScriptRuntime::CaptureAllocationInit}, 894 {"rsdAllocationRead2D", 895 "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_" 896 "10AllocationEjjj23RsAllocationCubemapFacejjPvjj", 897 "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_" 898 "10AllocationEjjj23RsAllocationCubemapFacejjPvmm", 899 0, RenderScriptRuntime::eModuleKindDriver, nullptr}, 900 {"rsdAllocationDestroy", "_Z20rsdAllocationDestroyPKN7android12rendersc" 901 "ript7ContextEPNS0_10AllocationE", 902 "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_" 903 "10AllocationE", 904 0, RenderScriptRuntime::eModuleKindDriver, 905 &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy}, 906 }; 907 908 const size_t RenderScriptRuntime::s_runtimeHookCount = 909 sizeof(s_runtimeHookDefns) / sizeof(s_runtimeHookDefns[0]); 910 911 bool RenderScriptRuntime::HookCallback(void *baton, 912 StoppointCallbackContext *ctx, 913 lldb::user_id_t break_id, 914 lldb::user_id_t break_loc_id) { 915 RuntimeHook *hook_info = (RuntimeHook *)baton; 916 ExecutionContext context(ctx->exe_ctx_ref); 917 918 RenderScriptRuntime *lang_rt = 919 (RenderScriptRuntime *)context.GetProcessPtr()->GetLanguageRuntime( 920 eLanguageTypeExtRenderScript); 921 922 lang_rt->HookCallback(hook_info, context); 923 924 return false; 925 } 926 927 void RenderScriptRuntime::HookCallback(RuntimeHook *hook_info, 928 ExecutionContext &context) { 929 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 930 931 if (log) 932 log->Printf("%s - '%s'", __FUNCTION__, hook_info->defn->name); 933 934 if (hook_info->defn->grabber) { 935 (this->*(hook_info->defn->grabber))(hook_info, context); 936 } 937 } 938 939 void RenderScriptRuntime::CaptureScriptInvokeForEachMulti( 940 RuntimeHook *hook_info, ExecutionContext &context) { 941 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 942 943 enum { 944 eRsContext = 0, 945 eRsScript, 946 eRsSlot, 947 eRsAIns, 948 eRsInLen, 949 eRsAOut, 950 eRsUsr, 951 eRsUsrLen, 952 eRsSc, 953 }; 954 955 std::array<ArgItem, 9> args{{ 956 ArgItem{ArgItem::ePointer, 0}, // const Context *rsc 957 ArgItem{ArgItem::ePointer, 0}, // Script *s 958 ArgItem{ArgItem::eInt32, 0}, // uint32_t slot 959 ArgItem{ArgItem::ePointer, 0}, // const Allocation **aIns 960 ArgItem{ArgItem::eInt32, 0}, // size_t inLen 961 ArgItem{ArgItem::ePointer, 0}, // Allocation *aout 962 ArgItem{ArgItem::ePointer, 0}, // const void *usr 963 ArgItem{ArgItem::eInt32, 0}, // size_t usrLen 964 ArgItem{ArgItem::ePointer, 0}, // const RsScriptCall *sc 965 }}; 966 967 bool success = GetArgs(context, &args[0], args.size()); 968 if (!success) { 969 if (log) 970 log->Printf("%s - Error while reading the function parameters", 971 __FUNCTION__); 972 return; 973 } 974 975 const uint32_t target_ptr_size = m_process->GetAddressByteSize(); 976 Error error; 977 std::vector<uint64_t> allocs; 978 979 // traverse allocation list 980 for (uint64_t i = 0; i < uint64_t(args[eRsInLen]); ++i) { 981 // calculate offest to allocation pointer 982 const addr_t addr = addr_t(args[eRsAIns]) + i * target_ptr_size; 983 984 // Note: due to little endian layout, reading 32bits or 64bits into res64 985 // will 986 // give the correct results. 987 988 uint64_t res64 = 0; 989 size_t read = m_process->ReadMemory(addr, &res64, target_ptr_size, error); 990 if (read != target_ptr_size || !error.Success()) { 991 if (log) 992 log->Printf( 993 "%s - Error while reading allocation list argument %" PRIu64, 994 __FUNCTION__, i); 995 } else { 996 allocs.push_back(res64); 997 } 998 } 999 1000 // if there is an output allocation track it 1001 if (uint64_t aOut = uint64_t(args[eRsAOut])) { 1002 allocs.push_back(aOut); 1003 } 1004 1005 // for all allocations we have found 1006 for (const uint64_t alloc_addr : allocs) { 1007 AllocationDetails *alloc = LookUpAllocation(alloc_addr); 1008 if (!alloc) 1009 alloc = CreateAllocation(alloc_addr); 1010 1011 if (alloc) { 1012 // save the allocation address 1013 if (alloc->address.isValid()) { 1014 // check the allocation address we already have matches 1015 assert(*alloc->address.get() == alloc_addr); 1016 } else { 1017 alloc->address = alloc_addr; 1018 } 1019 1020 // save the context 1021 if (log) { 1022 if (alloc->context.isValid() && 1023 *alloc->context.get() != addr_t(args[eRsContext])) 1024 log->Printf("%s - Allocation used by multiple contexts", 1025 __FUNCTION__); 1026 } 1027 alloc->context = addr_t(args[eRsContext]); 1028 } 1029 } 1030 1031 // make sure we track this script object 1032 if (lldb_private::RenderScriptRuntime::ScriptDetails *script = 1033 LookUpScript(addr_t(args[eRsScript]), true)) { 1034 if (log) { 1035 if (script->context.isValid() && 1036 *script->context.get() != addr_t(args[eRsContext])) 1037 log->Printf("%s - Script used by multiple contexts", __FUNCTION__); 1038 } 1039 script->context = addr_t(args[eRsContext]); 1040 } 1041 } 1042 1043 void RenderScriptRuntime::CaptureSetGlobalVar(RuntimeHook *hook_info, 1044 ExecutionContext &context) { 1045 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1046 1047 enum { 1048 eRsContext, 1049 eRsScript, 1050 eRsId, 1051 eRsData, 1052 eRsLength, 1053 }; 1054 1055 std::array<ArgItem, 5> args{{ 1056 ArgItem{ArgItem::ePointer, 0}, // eRsContext 1057 ArgItem{ArgItem::ePointer, 0}, // eRsScript 1058 ArgItem{ArgItem::eInt32, 0}, // eRsId 1059 ArgItem{ArgItem::ePointer, 0}, // eRsData 1060 ArgItem{ArgItem::eInt32, 0}, // eRsLength 1061 }}; 1062 1063 bool success = GetArgs(context, &args[0], args.size()); 1064 if (!success) { 1065 if (log) 1066 log->Printf("%s - error reading the function parameters.", __FUNCTION__); 1067 return; 1068 } 1069 1070 if (log) { 1071 log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64 1072 ":%" PRIu64 "bytes.", 1073 __FUNCTION__, uint64_t(args[eRsContext]), 1074 uint64_t(args[eRsScript]), uint64_t(args[eRsId]), 1075 uint64_t(args[eRsData]), uint64_t(args[eRsLength])); 1076 1077 addr_t script_addr = addr_t(args[eRsScript]); 1078 if (m_scriptMappings.find(script_addr) != m_scriptMappings.end()) { 1079 auto rsm = m_scriptMappings[script_addr]; 1080 if (uint64_t(args[eRsId]) < rsm->m_globals.size()) { 1081 auto rsg = rsm->m_globals[uint64_t(args[eRsId])]; 1082 log->Printf("%s - Setting of '%s' within '%s' inferred", __FUNCTION__, 1083 rsg.m_name.AsCString(), 1084 rsm->m_module->GetFileSpec().GetFilename().AsCString()); 1085 } 1086 } 1087 } 1088 } 1089 1090 void RenderScriptRuntime::CaptureAllocationInit(RuntimeHook *hook_info, 1091 ExecutionContext &context) { 1092 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1093 1094 enum { eRsContext, eRsAlloc, eRsForceZero }; 1095 1096 std::array<ArgItem, 3> args{{ 1097 ArgItem{ArgItem::ePointer, 0}, // eRsContext 1098 ArgItem{ArgItem::ePointer, 0}, // eRsAlloc 1099 ArgItem{ArgItem::eBool, 0}, // eRsForceZero 1100 }}; 1101 1102 bool success = GetArgs(context, &args[0], args.size()); 1103 if (!success) // error case 1104 { 1105 if (log) 1106 log->Printf("%s - error while reading the function parameters", 1107 __FUNCTION__); 1108 return; // abort 1109 } 1110 1111 if (log) 1112 log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .", 1113 __FUNCTION__, uint64_t(args[eRsContext]), 1114 uint64_t(args[eRsAlloc]), uint64_t(args[eRsForceZero])); 1115 1116 AllocationDetails *alloc = CreateAllocation(uint64_t(args[eRsAlloc])); 1117 if (alloc) 1118 alloc->context = uint64_t(args[eRsContext]); 1119 } 1120 1121 void RenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook *hook_info, 1122 ExecutionContext &context) { 1123 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1124 1125 enum { 1126 eRsContext, 1127 eRsAlloc, 1128 }; 1129 1130 std::array<ArgItem, 2> args{{ 1131 ArgItem{ArgItem::ePointer, 0}, // eRsContext 1132 ArgItem{ArgItem::ePointer, 0}, // eRsAlloc 1133 }}; 1134 1135 bool success = GetArgs(context, &args[0], args.size()); 1136 if (!success) { 1137 if (log) 1138 log->Printf("%s - error while reading the function parameters.", 1139 __FUNCTION__); 1140 return; 1141 } 1142 1143 if (log) 1144 log->Printf("%s - 0x%" PRIx64 ", 0x%" PRIx64 ".", __FUNCTION__, 1145 uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc])); 1146 1147 for (auto iter = m_allocations.begin(); iter != m_allocations.end(); ++iter) { 1148 auto &allocation_ap = *iter; // get the unique pointer 1149 if (allocation_ap->address.isValid() && 1150 *allocation_ap->address.get() == addr_t(args[eRsAlloc])) { 1151 m_allocations.erase(iter); 1152 if (log) 1153 log->Printf("%s - deleted allocation entry.", __FUNCTION__); 1154 return; 1155 } 1156 } 1157 1158 if (log) 1159 log->Printf("%s - couldn't find destroyed allocation.", __FUNCTION__); 1160 } 1161 1162 void RenderScriptRuntime::CaptureScriptInit(RuntimeHook *hook_info, 1163 ExecutionContext &context) { 1164 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1165 1166 Error error; 1167 Process *process = context.GetProcessPtr(); 1168 1169 enum { eRsContext, eRsScript, eRsResNamePtr, eRsCachedDirPtr }; 1170 1171 std::array<ArgItem, 4> args{ 1172 {ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}, 1173 ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}}}; 1174 bool success = GetArgs(context, &args[0], args.size()); 1175 if (!success) { 1176 if (log) 1177 log->Printf("%s - error while reading the function parameters.", 1178 __FUNCTION__); 1179 return; 1180 } 1181 1182 std::string resname; 1183 process->ReadCStringFromMemory(addr_t(args[eRsResNamePtr]), resname, error); 1184 if (error.Fail()) { 1185 if (log) 1186 log->Printf("%s - error reading resname: %s.", __FUNCTION__, 1187 error.AsCString()); 1188 } 1189 1190 std::string cachedir; 1191 process->ReadCStringFromMemory(addr_t(args[eRsCachedDirPtr]), cachedir, 1192 error); 1193 if (error.Fail()) { 1194 if (log) 1195 log->Printf("%s - error reading cachedir: %s.", __FUNCTION__, 1196 error.AsCString()); 1197 } 1198 1199 if (log) 1200 log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .", 1201 __FUNCTION__, uint64_t(args[eRsContext]), 1202 uint64_t(args[eRsScript]), resname.c_str(), cachedir.c_str()); 1203 1204 if (resname.size() > 0) { 1205 StreamString strm; 1206 strm.Printf("librs.%s.so", resname.c_str()); 1207 1208 ScriptDetails *script = LookUpScript(addr_t(args[eRsScript]), true); 1209 if (script) { 1210 script->type = ScriptDetails::eScriptC; 1211 script->cacheDir = cachedir; 1212 script->resName = resname; 1213 script->scriptDyLib = strm.GetData(); 1214 script->context = addr_t(args[eRsContext]); 1215 } 1216 1217 if (log) 1218 log->Printf("%s - '%s' tagged with context 0x%" PRIx64 1219 " and script 0x%" PRIx64 ".", 1220 __FUNCTION__, strm.GetData(), uint64_t(args[eRsContext]), 1221 uint64_t(args[eRsScript])); 1222 } else if (log) { 1223 log->Printf("%s - resource name invalid, Script not tagged.", __FUNCTION__); 1224 } 1225 } 1226 1227 void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, 1228 ModuleKind kind) { 1229 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1230 1231 if (!module) { 1232 return; 1233 } 1234 1235 Target &target = GetProcess()->GetTarget(); 1236 llvm::Triple::ArchType targetArchType = target.GetArchitecture().GetMachine(); 1237 1238 if (targetArchType != llvm::Triple::ArchType::x86 && 1239 targetArchType != llvm::Triple::ArchType::arm && 1240 targetArchType != llvm::Triple::ArchType::aarch64 && 1241 targetArchType != llvm::Triple::ArchType::mipsel && 1242 targetArchType != llvm::Triple::ArchType::mips64el && 1243 targetArchType != llvm::Triple::ArchType::x86_64) { 1244 if (log) 1245 log->Printf("%s - unable to hook runtime functions.", __FUNCTION__); 1246 return; 1247 } 1248 1249 uint32_t archByteSize = target.GetArchitecture().GetAddressByteSize(); 1250 1251 for (size_t idx = 0; idx < s_runtimeHookCount; idx++) { 1252 const HookDefn *hook_defn = &s_runtimeHookDefns[idx]; 1253 if (hook_defn->kind != kind) { 1254 continue; 1255 } 1256 1257 const char *symbol_name = (archByteSize == 4) ? hook_defn->symbol_name_m32 1258 : hook_defn->symbol_name_m64; 1259 1260 const Symbol *sym = module->FindFirstSymbolWithNameAndType( 1261 ConstString(symbol_name), eSymbolTypeCode); 1262 if (!sym) { 1263 if (log) { 1264 log->Printf("%s - symbol '%s' related to the function %s not found", 1265 __FUNCTION__, symbol_name, hook_defn->name); 1266 } 1267 continue; 1268 } 1269 1270 addr_t addr = sym->GetLoadAddress(&target); 1271 if (addr == LLDB_INVALID_ADDRESS) { 1272 if (log) 1273 log->Printf("%s - unable to resolve the address of hook function '%s' " 1274 "with symbol '%s'.", 1275 __FUNCTION__, hook_defn->name, symbol_name); 1276 continue; 1277 } else { 1278 if (log) 1279 log->Printf("%s - function %s, address resolved at 0x%" PRIx64, 1280 __FUNCTION__, hook_defn->name, addr); 1281 } 1282 1283 RuntimeHookSP hook(new RuntimeHook()); 1284 hook->address = addr; 1285 hook->defn = hook_defn; 1286 hook->bp_sp = target.CreateBreakpoint(addr, true, false); 1287 hook->bp_sp->SetCallback(HookCallback, hook.get(), true); 1288 m_runtimeHooks[addr] = hook; 1289 if (log) { 1290 log->Printf("%s - successfully hooked '%s' in '%s' version %" PRIu64 1291 " at 0x%" PRIx64 ".", 1292 __FUNCTION__, hook_defn->name, 1293 module->GetFileSpec().GetFilename().AsCString(), 1294 (uint64_t)hook_defn->version, (uint64_t)addr); 1295 } 1296 } 1297 } 1298 1299 void RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp) { 1300 if (!rsmodule_sp) 1301 return; 1302 1303 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1304 1305 const ModuleSP module = rsmodule_sp->m_module; 1306 const FileSpec &file = module->GetPlatformFileSpec(); 1307 1308 // Iterate over all of the scripts that we currently know of. 1309 // Note: We cant push or pop to m_scripts here or it may invalidate rs_script. 1310 for (const auto &rs_script : m_scripts) { 1311 // Extract the expected .so file path for this script. 1312 std::string dylib; 1313 if (!rs_script->scriptDyLib.get(dylib)) 1314 continue; 1315 1316 // Only proceed if the module that has loaded corresponds to this script. 1317 if (file.GetFilename() != ConstString(dylib.c_str())) 1318 continue; 1319 1320 // Obtain the script address which we use as a key. 1321 lldb::addr_t script; 1322 if (!rs_script->script.get(script)) 1323 continue; 1324 1325 // If we have a script mapping for the current script. 1326 if (m_scriptMappings.find(script) != m_scriptMappings.end()) { 1327 // if the module we have stored is different to the one we just received. 1328 if (m_scriptMappings[script] != rsmodule_sp) { 1329 if (log) 1330 log->Printf( 1331 "%s - script %" PRIx64 " wants reassigned to new rsmodule '%s'.", 1332 __FUNCTION__, (uint64_t)script, 1333 rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); 1334 } 1335 } 1336 // We don't have a script mapping for the current script. 1337 else { 1338 // Obtain the script resource name. 1339 std::string resName; 1340 if (rs_script->resName.get(resName)) 1341 // Set the modules resource name. 1342 rsmodule_sp->m_resname = resName; 1343 // Add Script/Module pair to map. 1344 m_scriptMappings[script] = rsmodule_sp; 1345 if (log) 1346 log->Printf( 1347 "%s - script %" PRIx64 " associated with rsmodule '%s'.", 1348 __FUNCTION__, (uint64_t)script, 1349 rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); 1350 } 1351 } 1352 } 1353 1354 // Uses the Target API to evaluate the expression passed as a parameter to the 1355 // function 1356 // The result of that expression is returned an unsigned 64 bit int, via the 1357 // result* parameter. 1358 // Function returns true on success, and false on failure 1359 bool RenderScriptRuntime::EvalRSExpression(const char *expression, 1360 StackFrame *frame_ptr, 1361 uint64_t *result) { 1362 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1363 if (log) 1364 log->Printf("%s(%s)", __FUNCTION__, expression); 1365 1366 ValueObjectSP expr_result; 1367 EvaluateExpressionOptions options; 1368 options.SetLanguage(lldb::eLanguageTypeC_plus_plus); 1369 // Perform the actual expression evaluation 1370 GetProcess()->GetTarget().EvaluateExpression(expression, frame_ptr, 1371 expr_result, options); 1372 1373 if (!expr_result) { 1374 if (log) 1375 log->Printf("%s: couldn't evaluate expression.", __FUNCTION__); 1376 return false; 1377 } 1378 1379 // The result of the expression is invalid 1380 if (!expr_result->GetError().Success()) { 1381 Error err = expr_result->GetError(); 1382 if (err.GetError() == UserExpression::kNoResult) // Expression returned 1383 // void, so this is 1384 // actually a success 1385 { 1386 if (log) 1387 log->Printf("%s - expression returned void.", __FUNCTION__); 1388 1389 result = nullptr; 1390 return true; 1391 } 1392 1393 if (log) 1394 log->Printf("%s - error evaluating expression result: %s", __FUNCTION__, 1395 err.AsCString()); 1396 return false; 1397 } 1398 1399 bool success = false; 1400 *result = expr_result->GetValueAsUnsigned( 1401 0, &success); // We only read the result as an uint32_t. 1402 1403 if (!success) { 1404 if (log) 1405 log->Printf("%s - couldn't convert expression result to uint32_t", 1406 __FUNCTION__); 1407 return false; 1408 } 1409 1410 return true; 1411 } 1412 1413 namespace { 1414 // Used to index expression format strings 1415 enum ExpressionStrings { 1416 eExprGetOffsetPtr = 0, 1417 eExprAllocGetType, 1418 eExprTypeDimX, 1419 eExprTypeDimY, 1420 eExprTypeDimZ, 1421 eExprTypeElemPtr, 1422 eExprElementType, 1423 eExprElementKind, 1424 eExprElementVec, 1425 eExprElementFieldCount, 1426 eExprSubelementsId, 1427 eExprSubelementsName, 1428 eExprSubelementsArrSize, 1429 1430 _eExprLast // keep at the end, implicit size of the array runtimeExpressions 1431 }; 1432 1433 // max length of an expanded expression 1434 const int jit_max_expr_size = 512; 1435 1436 // Retrieve the string to JIT for the given expression 1437 const char *JITTemplate(ExpressionStrings e) { 1438 // Format strings containing the expressions we may need to evaluate. 1439 static std::array<const char *, _eExprLast> runtimeExpressions = { 1440 {// Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap) 1441 "(int*)_" 1442 "Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocation" 1443 "CubemapFace" 1444 "(0x%" PRIx64 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", 0, 0)", 1445 1446 // Type* rsaAllocationGetType(Context*, Allocation*) 1447 "(void*)rsaAllocationGetType(0x%" PRIx64 ", 0x%" PRIx64 ")", 1448 1449 // rsaTypeGetNativeData(Context*, Type*, void* typeData, size) 1450 // Pack the data in the following way mHal.state.dimX; mHal.state.dimY; 1451 // mHal.state.dimZ; 1452 // mHal.state.lodCount; mHal.state.faces; mElement; into typeData 1453 // Need to specify 32 or 64 bit for uint_t since this differs between 1454 // devices 1455 "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 1456 ", 0x%" PRIx64 ", data, 6); data[0]", // X dim 1457 "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 1458 ", 0x%" PRIx64 ", data, 6); data[1]", // Y dim 1459 "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 1460 ", 0x%" PRIx64 ", data, 6); data[2]", // Z dim 1461 "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 1462 ", 0x%" PRIx64 ", data, 6); data[5]", // Element ptr 1463 1464 // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size) 1465 // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into 1466 // elemData 1467 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 1468 ", 0x%" PRIx64 ", data, 5); data[0]", // Type 1469 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 1470 ", 0x%" PRIx64 ", data, 5); data[1]", // Kind 1471 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 1472 ", 0x%" PRIx64 ", data, 5); data[3]", // Vector Size 1473 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 1474 ", 0x%" PRIx64 ", data, 5); data[4]", // Field Count 1475 1476 // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t 1477 // *ids, const char **names, 1478 // size_t *arraySizes, uint32_t dataSize) 1479 // Needed for Allocations of structs to gather details about 1480 // fields/Subelements 1481 // Element* of field 1482 "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 1483 "]; size_t arr_size[%" PRIu32 "];" 1484 "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64 1485 ", ids, names, arr_size, %" PRIu32 "); ids[%" PRIu32 "]", 1486 1487 // Name of field 1488 "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 1489 "]; size_t arr_size[%" PRIu32 "];" 1490 "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64 1491 ", ids, names, arr_size, %" PRIu32 "); names[%" PRIu32 "]", 1492 1493 // Array size of field 1494 "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 1495 "]; size_t arr_size[%" PRIu32 "];" 1496 "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64 1497 ", ids, names, arr_size, %" PRIu32 "); arr_size[%" PRIu32 "]"}}; 1498 1499 return runtimeExpressions[e]; 1500 } 1501 } // end of the anonymous namespace 1502 1503 // JITs the RS runtime for the internal data pointer of an allocation. 1504 // Is passed x,y,z coordinates for the pointer to a specific element. 1505 // Then sets the data_ptr member in Allocation with the result. 1506 // Returns true on success, false otherwise 1507 bool RenderScriptRuntime::JITDataPointer(AllocationDetails *allocation, 1508 StackFrame *frame_ptr, uint32_t x, 1509 uint32_t y, uint32_t z) { 1510 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1511 1512 if (!allocation->address.isValid()) { 1513 if (log) 1514 log->Printf("%s - failed to find allocation details.", __FUNCTION__); 1515 return false; 1516 } 1517 1518 const char *expr_cstr = JITTemplate(eExprGetOffsetPtr); 1519 char buffer[jit_max_expr_size]; 1520 1521 int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, 1522 *allocation->address.get(), x, y, z); 1523 if (chars_written < 0) { 1524 if (log) 1525 log->Printf("%s - encoding error in snprintf().", __FUNCTION__); 1526 return false; 1527 } else if (chars_written >= jit_max_expr_size) { 1528 if (log) 1529 log->Printf("%s - expression too long.", __FUNCTION__); 1530 return false; 1531 } 1532 1533 uint64_t result = 0; 1534 if (!EvalRSExpression(buffer, frame_ptr, &result)) 1535 return false; 1536 1537 addr_t mem_ptr = static_cast<lldb::addr_t>(result); 1538 allocation->data_ptr = mem_ptr; 1539 1540 return true; 1541 } 1542 1543 // JITs the RS runtime for the internal pointer to the RS Type of an allocation 1544 // Then sets the type_ptr member in Allocation with the result. 1545 // Returns true on success, false otherwise 1546 bool RenderScriptRuntime::JITTypePointer(AllocationDetails *allocation, 1547 StackFrame *frame_ptr) { 1548 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1549 1550 if (!allocation->address.isValid() || !allocation->context.isValid()) { 1551 if (log) 1552 log->Printf("%s - failed to find allocation details.", __FUNCTION__); 1553 return false; 1554 } 1555 1556 const char *expr_cstr = JITTemplate(eExprAllocGetType); 1557 char buffer[jit_max_expr_size]; 1558 1559 int chars_written = 1560 snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->context.get(), 1561 *allocation->address.get()); 1562 if (chars_written < 0) { 1563 if (log) 1564 log->Printf("%s - encoding error in snprintf().", __FUNCTION__); 1565 return false; 1566 } else if (chars_written >= jit_max_expr_size) { 1567 if (log) 1568 log->Printf("%s - expression too long.", __FUNCTION__); 1569 return false; 1570 } 1571 1572 uint64_t result = 0; 1573 if (!EvalRSExpression(buffer, frame_ptr, &result)) 1574 return false; 1575 1576 addr_t type_ptr = static_cast<lldb::addr_t>(result); 1577 allocation->type_ptr = type_ptr; 1578 1579 return true; 1580 } 1581 1582 // JITs the RS runtime for information about the dimensions and type of an 1583 // allocation 1584 // Then sets dimension and element_ptr members in Allocation with the result. 1585 // Returns true on success, false otherwise 1586 bool RenderScriptRuntime::JITTypePacked(AllocationDetails *allocation, 1587 StackFrame *frame_ptr) { 1588 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1589 1590 if (!allocation->type_ptr.isValid() || !allocation->context.isValid()) { 1591 if (log) 1592 log->Printf("%s - Failed to find allocation details.", __FUNCTION__); 1593 return false; 1594 } 1595 1596 // Expression is different depending on if device is 32 or 64 bit 1597 uint32_t archByteSize = 1598 GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 1599 const uint32_t bits = archByteSize == 4 ? 32 : 64; 1600 1601 // We want 4 elements from packed data 1602 const uint32_t num_exprs = 4; 1603 assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1) && 1604 "Invalid number of expressions"); 1605 1606 char buffer[num_exprs][jit_max_expr_size]; 1607 uint64_t results[num_exprs]; 1608 1609 for (uint32_t i = 0; i < num_exprs; ++i) { 1610 const char *expr_cstr = JITTemplate(ExpressionStrings(eExprTypeDimX + i)); 1611 int chars_written = 1612 snprintf(buffer[i], jit_max_expr_size, expr_cstr, bits, 1613 *allocation->context.get(), *allocation->type_ptr.get()); 1614 if (chars_written < 0) { 1615 if (log) 1616 log->Printf("%s - encoding error in snprintf().", __FUNCTION__); 1617 return false; 1618 } else if (chars_written >= jit_max_expr_size) { 1619 if (log) 1620 log->Printf("%s - expression too long.", __FUNCTION__); 1621 return false; 1622 } 1623 1624 // Perform expression evaluation 1625 if (!EvalRSExpression(buffer[i], frame_ptr, &results[i])) 1626 return false; 1627 } 1628 1629 // Assign results to allocation members 1630 AllocationDetails::Dimension dims; 1631 dims.dim_1 = static_cast<uint32_t>(results[0]); 1632 dims.dim_2 = static_cast<uint32_t>(results[1]); 1633 dims.dim_3 = static_cast<uint32_t>(results[2]); 1634 allocation->dimension = dims; 1635 1636 addr_t elem_ptr = static_cast<lldb::addr_t>(results[3]); 1637 allocation->element.element_ptr = elem_ptr; 1638 1639 if (log) 1640 log->Printf("%s - dims (%" PRIu32 ", %" PRIu32 ", %" PRIu32 1641 ") Element*: 0x%" PRIx64 ".", 1642 __FUNCTION__, dims.dim_1, dims.dim_2, dims.dim_3, elem_ptr); 1643 1644 return true; 1645 } 1646 1647 // JITs the RS runtime for information about the Element of an allocation 1648 // Then sets type, type_vec_size, field_count and type_kind members in Element 1649 // with the result. 1650 // Returns true on success, false otherwise 1651 bool RenderScriptRuntime::JITElementPacked(Element &elem, 1652 const lldb::addr_t context, 1653 StackFrame *frame_ptr) { 1654 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1655 1656 if (!elem.element_ptr.isValid()) { 1657 if (log) 1658 log->Printf("%s - failed to find allocation details.", __FUNCTION__); 1659 return false; 1660 } 1661 1662 // We want 4 elements from packed data 1663 const uint32_t num_exprs = 4; 1664 assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1) && 1665 "Invalid number of expressions"); 1666 1667 char buffer[num_exprs][jit_max_expr_size]; 1668 uint64_t results[num_exprs]; 1669 1670 for (uint32_t i = 0; i < num_exprs; i++) { 1671 const char *expr_cstr = 1672 JITTemplate(ExpressionStrings(eExprElementType + i)); 1673 int chars_written = snprintf(buffer[i], jit_max_expr_size, expr_cstr, 1674 context, *elem.element_ptr.get()); 1675 if (chars_written < 0) { 1676 if (log) 1677 log->Printf("%s - encoding error in snprintf().", __FUNCTION__); 1678 return false; 1679 } else if (chars_written >= jit_max_expr_size) { 1680 if (log) 1681 log->Printf("%s - expression too long.", __FUNCTION__); 1682 return false; 1683 } 1684 1685 // Perform expression evaluation 1686 if (!EvalRSExpression(buffer[i], frame_ptr, &results[i])) 1687 return false; 1688 } 1689 1690 // Assign results to allocation members 1691 elem.type = static_cast<RenderScriptRuntime::Element::DataType>(results[0]); 1692 elem.type_kind = 1693 static_cast<RenderScriptRuntime::Element::DataKind>(results[1]); 1694 elem.type_vec_size = static_cast<uint32_t>(results[2]); 1695 elem.field_count = static_cast<uint32_t>(results[3]); 1696 1697 if (log) 1698 log->Printf("%s - data type %" PRIu32 ", pixel type %" PRIu32 1699 ", vector size %" PRIu32 ", field count %" PRIu32, 1700 __FUNCTION__, *elem.type.get(), *elem.type_kind.get(), 1701 *elem.type_vec_size.get(), *elem.field_count.get()); 1702 1703 // If this Element has subelements then JIT rsaElementGetSubElements() for 1704 // details about its fields 1705 if (*elem.field_count.get() > 0 && !JITSubelements(elem, context, frame_ptr)) 1706 return false; 1707 1708 return true; 1709 } 1710 1711 // JITs the RS runtime for information about the subelements/fields of a struct 1712 // allocation 1713 // This is necessary for infering the struct type so we can pretty print the 1714 // allocation's contents. 1715 // Returns true on success, false otherwise 1716 bool RenderScriptRuntime::JITSubelements(Element &elem, 1717 const lldb::addr_t context, 1718 StackFrame *frame_ptr) { 1719 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1720 1721 if (!elem.element_ptr.isValid() || !elem.field_count.isValid()) { 1722 if (log) 1723 log->Printf("%s - failed to find allocation details.", __FUNCTION__); 1724 return false; 1725 } 1726 1727 const short num_exprs = 3; 1728 assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1) && 1729 "Invalid number of expressions"); 1730 1731 char expr_buffer[jit_max_expr_size]; 1732 uint64_t results; 1733 1734 // Iterate over struct fields. 1735 const uint32_t field_count = *elem.field_count.get(); 1736 for (uint32_t field_index = 0; field_index < field_count; ++field_index) { 1737 Element child; 1738 for (uint32_t expr_index = 0; expr_index < num_exprs; ++expr_index) { 1739 const char *expr_cstr = 1740 JITTemplate(ExpressionStrings(eExprSubelementsId + expr_index)); 1741 int chars_written = 1742 snprintf(expr_buffer, jit_max_expr_size, expr_cstr, field_count, 1743 field_count, field_count, context, *elem.element_ptr.get(), 1744 field_count, field_index); 1745 if (chars_written < 0) { 1746 if (log) 1747 log->Printf("%s - encoding error in snprintf().", __FUNCTION__); 1748 return false; 1749 } else if (chars_written >= jit_max_expr_size) { 1750 if (log) 1751 log->Printf("%s - expression too long.", __FUNCTION__); 1752 return false; 1753 } 1754 1755 // Perform expression evaluation 1756 if (!EvalRSExpression(expr_buffer, frame_ptr, &results)) 1757 return false; 1758 1759 if (log) 1760 log->Printf("%s - expr result 0x%" PRIx64 ".", __FUNCTION__, results); 1761 1762 switch (expr_index) { 1763 case 0: // Element* of child 1764 child.element_ptr = static_cast<addr_t>(results); 1765 break; 1766 case 1: // Name of child 1767 { 1768 lldb::addr_t address = static_cast<addr_t>(results); 1769 Error err; 1770 std::string name; 1771 GetProcess()->ReadCStringFromMemory(address, name, err); 1772 if (!err.Fail()) 1773 child.type_name = ConstString(name); 1774 else { 1775 if (log) 1776 log->Printf("%s - warning: Couldn't read field name.", 1777 __FUNCTION__); 1778 } 1779 break; 1780 } 1781 case 2: // Array size of child 1782 child.array_size = static_cast<uint32_t>(results); 1783 break; 1784 } 1785 } 1786 1787 // We need to recursively JIT each Element field of the struct since 1788 // structs can be nested inside structs. 1789 if (!JITElementPacked(child, context, frame_ptr)) 1790 return false; 1791 elem.children.push_back(child); 1792 } 1793 1794 // Try to infer the name of the struct type so we can pretty print the 1795 // allocation contents. 1796 FindStructTypeName(elem, frame_ptr); 1797 1798 return true; 1799 } 1800 1801 // JITs the RS runtime for the address of the last element in the allocation. 1802 // The `elem_size` parameter represents the size of a single element, including 1803 // padding. 1804 // Which is needed as an offset from the last element pointer. 1805 // Using this offset minus the starting address we can calculate the size of the 1806 // allocation. 1807 // Returns true on success, false otherwise 1808 bool RenderScriptRuntime::JITAllocationSize(AllocationDetails *allocation, 1809 StackFrame *frame_ptr) { 1810 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1811 1812 if (!allocation->address.isValid() || !allocation->dimension.isValid() || 1813 !allocation->data_ptr.isValid() || 1814 !allocation->element.datum_size.isValid()) { 1815 if (log) 1816 log->Printf("%s - failed to find allocation details.", __FUNCTION__); 1817 return false; 1818 } 1819 1820 // Find dimensions 1821 uint32_t dim_x = allocation->dimension.get()->dim_1; 1822 uint32_t dim_y = allocation->dimension.get()->dim_2; 1823 uint32_t dim_z = allocation->dimension.get()->dim_3; 1824 1825 // Our plan of jitting the last element address doesn't seem to work for 1826 // struct Allocations 1827 // Instead try to infer the size ourselves without any inter element padding. 1828 if (allocation->element.children.size() > 0) { 1829 if (dim_x == 0) 1830 dim_x = 1; 1831 if (dim_y == 0) 1832 dim_y = 1; 1833 if (dim_z == 0) 1834 dim_z = 1; 1835 1836 allocation->size = 1837 dim_x * dim_y * dim_z * *allocation->element.datum_size.get(); 1838 1839 if (log) 1840 log->Printf("%s - inferred size of struct allocation %" PRIu32 ".", 1841 __FUNCTION__, *allocation->size.get()); 1842 return true; 1843 } 1844 1845 const char *expr_cstr = JITTemplate(eExprGetOffsetPtr); 1846 char buffer[jit_max_expr_size]; 1847 1848 // Calculate last element 1849 dim_x = dim_x == 0 ? 0 : dim_x - 1; 1850 dim_y = dim_y == 0 ? 0 : dim_y - 1; 1851 dim_z = dim_z == 0 ? 0 : dim_z - 1; 1852 1853 int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, 1854 *allocation->address.get(), dim_x, dim_y, dim_z); 1855 if (chars_written < 0) { 1856 if (log) 1857 log->Printf("%s - encoding error in snprintf().", __FUNCTION__); 1858 return false; 1859 } else if (chars_written >= jit_max_expr_size) { 1860 if (log) 1861 log->Printf("%s - expression too long.", __FUNCTION__); 1862 return false; 1863 } 1864 1865 uint64_t result = 0; 1866 if (!EvalRSExpression(buffer, frame_ptr, &result)) 1867 return false; 1868 1869 addr_t mem_ptr = static_cast<lldb::addr_t>(result); 1870 // Find pointer to last element and add on size of an element 1871 allocation->size = 1872 static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()) + 1873 *allocation->element.datum_size.get(); 1874 1875 return true; 1876 } 1877 1878 // JITs the RS runtime for information about the stride between rows in the 1879 // allocation. 1880 // This is done to detect padding, since allocated memory is 16-byte aligned. 1881 // Returns true on success, false otherwise 1882 bool RenderScriptRuntime::JITAllocationStride(AllocationDetails *allocation, 1883 StackFrame *frame_ptr) { 1884 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1885 1886 if (!allocation->address.isValid() || !allocation->data_ptr.isValid()) { 1887 if (log) 1888 log->Printf("%s - failed to find allocation details.", __FUNCTION__); 1889 return false; 1890 } 1891 1892 const char *expr_cstr = JITTemplate(eExprGetOffsetPtr); 1893 char buffer[jit_max_expr_size]; 1894 1895 int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, 1896 *allocation->address.get(), 0, 1, 0); 1897 if (chars_written < 0) { 1898 if (log) 1899 log->Printf("%s - encoding error in snprintf().", __FUNCTION__); 1900 return false; 1901 } else if (chars_written >= jit_max_expr_size) { 1902 if (log) 1903 log->Printf("%s - expression too long.", __FUNCTION__); 1904 return false; 1905 } 1906 1907 uint64_t result = 0; 1908 if (!EvalRSExpression(buffer, frame_ptr, &result)) 1909 return false; 1910 1911 addr_t mem_ptr = static_cast<lldb::addr_t>(result); 1912 allocation->stride = 1913 static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()); 1914 1915 return true; 1916 } 1917 1918 // JIT all the current runtime info regarding an allocation 1919 bool RenderScriptRuntime::RefreshAllocation(AllocationDetails *allocation, 1920 StackFrame *frame_ptr) { 1921 // GetOffsetPointer() 1922 if (!JITDataPointer(allocation, frame_ptr)) 1923 return false; 1924 1925 // rsaAllocationGetType() 1926 if (!JITTypePointer(allocation, frame_ptr)) 1927 return false; 1928 1929 // rsaTypeGetNativeData() 1930 if (!JITTypePacked(allocation, frame_ptr)) 1931 return false; 1932 1933 // rsaElementGetNativeData() 1934 if (!JITElementPacked(allocation->element, *allocation->context.get(), 1935 frame_ptr)) 1936 return false; 1937 1938 // Sets the datum_size member in Element 1939 SetElementSize(allocation->element); 1940 1941 // Use GetOffsetPointer() to infer size of the allocation 1942 if (!JITAllocationSize(allocation, frame_ptr)) 1943 return false; 1944 1945 return true; 1946 } 1947 1948 // Function attempts to set the type_name member of the paramaterised Element 1949 // object. 1950 // This string should be the name of the struct type the Element represents. 1951 // We need this string for pretty printing the Element to users. 1952 void RenderScriptRuntime::FindStructTypeName(Element &elem, 1953 StackFrame *frame_ptr) { 1954 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1955 1956 if (!elem.type_name.IsEmpty()) // Name already set 1957 return; 1958 else 1959 elem.type_name = Element::GetFallbackStructName(); // Default type name if 1960 // we don't succeed 1961 1962 // Find all the global variables from the script rs modules 1963 VariableList variable_list; 1964 for (auto module_sp : m_rsmodules) 1965 module_sp->m_module->FindGlobalVariables(RegularExpression("."), true, 1966 UINT32_MAX, variable_list); 1967 1968 // Iterate over all the global variables looking for one with a matching type 1969 // to the Element. 1970 // We make the assumption a match exists since there needs to be a global 1971 // variable to reflect the 1972 // struct type back into java host code. 1973 for (uint32_t var_index = 0; var_index < variable_list.GetSize(); 1974 ++var_index) { 1975 const VariableSP var_sp(variable_list.GetVariableAtIndex(var_index)); 1976 if (!var_sp) 1977 continue; 1978 1979 ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp); 1980 if (!valobj_sp) 1981 continue; 1982 1983 // Find the number of variable fields. 1984 // If it has no fields, or more fields than our Element, then it can't be 1985 // the struct we're looking for. 1986 // Don't check for equality since RS can add extra struct members for 1987 // padding. 1988 size_t num_children = valobj_sp->GetNumChildren(); 1989 if (num_children > elem.children.size() || num_children == 0) 1990 continue; 1991 1992 // Iterate over children looking for members with matching field names. 1993 // If all the field names match, this is likely the struct we want. 1994 // 1995 // TODO: This could be made more robust by also checking children data 1996 // sizes, or array size 1997 bool found = true; 1998 for (size_t child_index = 0; child_index < num_children; ++child_index) { 1999 ValueObjectSP child = valobj_sp->GetChildAtIndex(child_index, true); 2000 if (!child || 2001 (child->GetName() != elem.children[child_index].type_name)) { 2002 found = false; 2003 break; 2004 } 2005 } 2006 2007 // RS can add extra struct members for padding in the format 2008 // '#rs_padding_[0-9]+' 2009 if (found && num_children < elem.children.size()) { 2010 const uint32_t size_diff = elem.children.size() - num_children; 2011 if (log) 2012 log->Printf("%s - %" PRIu32 " padding struct entries", __FUNCTION__, 2013 size_diff); 2014 2015 for (uint32_t padding_index = 0; padding_index < size_diff; 2016 ++padding_index) { 2017 const ConstString &name = 2018 elem.children[num_children + padding_index].type_name; 2019 if (strcmp(name.AsCString(), "#rs_padding") < 0) 2020 found = false; 2021 } 2022 } 2023 2024 // We've found a global var with matching type 2025 if (found) { 2026 // Dereference since our Element type isn't a pointer. 2027 if (valobj_sp->IsPointerType()) { 2028 Error err; 2029 ValueObjectSP deref_valobj = valobj_sp->Dereference(err); 2030 if (!err.Fail()) 2031 valobj_sp = deref_valobj; 2032 } 2033 2034 // Save name of variable in Element. 2035 elem.type_name = valobj_sp->GetTypeName(); 2036 if (log) 2037 log->Printf("%s - element name set to %s", __FUNCTION__, 2038 elem.type_name.AsCString()); 2039 2040 return; 2041 } 2042 } 2043 } 2044 2045 // Function sets the datum_size member of Element. Representing the size of a 2046 // single instance including padding. 2047 // Assumes the relevant allocation information has already been jitted. 2048 void RenderScriptRuntime::SetElementSize(Element &elem) { 2049 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2050 const Element::DataType type = *elem.type.get(); 2051 assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && 2052 "Invalid allocation type"); 2053 2054 const uint32_t vec_size = *elem.type_vec_size.get(); 2055 uint32_t data_size = 0; 2056 uint32_t padding = 0; 2057 2058 // Element is of a struct type, calculate size recursively. 2059 if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) { 2060 for (Element &child : elem.children) { 2061 SetElementSize(child); 2062 const uint32_t array_size = 2063 child.array_size.isValid() ? *child.array_size.get() : 1; 2064 data_size += *child.datum_size.get() * array_size; 2065 } 2066 } 2067 // These have been packed already 2068 else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 || 2069 type == Element::RS_TYPE_UNSIGNED_5_5_5_1 || 2070 type == Element::RS_TYPE_UNSIGNED_4_4_4_4) { 2071 data_size = AllocationDetails::RSTypeToFormat[type][eElementSize]; 2072 } else if (type < Element::RS_TYPE_ELEMENT) { 2073 data_size = 2074 vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize]; 2075 if (vec_size == 3) 2076 padding = AllocationDetails::RSTypeToFormat[type][eElementSize]; 2077 } else 2078 data_size = 2079 GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 2080 2081 elem.padding = padding; 2082 elem.datum_size = data_size + padding; 2083 if (log) 2084 log->Printf("%s - element size set to %" PRIu32, __FUNCTION__, 2085 data_size + padding); 2086 } 2087 2088 // Given an allocation, this function copies the allocation contents from device 2089 // into a buffer on the heap. 2090 // Returning a shared pointer to the buffer containing the data. 2091 std::shared_ptr<uint8_t> 2092 RenderScriptRuntime::GetAllocationData(AllocationDetails *allocation, 2093 StackFrame *frame_ptr) { 2094 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2095 2096 // JIT all the allocation details 2097 if (allocation->shouldRefresh()) { 2098 if (log) 2099 log->Printf("%s - allocation details not calculated yet, jitting info", 2100 __FUNCTION__); 2101 2102 if (!RefreshAllocation(allocation, frame_ptr)) { 2103 if (log) 2104 log->Printf("%s - couldn't JIT allocation details", __FUNCTION__); 2105 return nullptr; 2106 } 2107 } 2108 2109 assert(allocation->data_ptr.isValid() && allocation->element.type.isValid() && 2110 allocation->element.type_vec_size.isValid() && 2111 allocation->size.isValid() && "Allocation information not available"); 2112 2113 // Allocate a buffer to copy data into 2114 const uint32_t size = *allocation->size.get(); 2115 std::shared_ptr<uint8_t> buffer(new uint8_t[size]); 2116 if (!buffer) { 2117 if (log) 2118 log->Printf("%s - couldn't allocate a %" PRIu32 " byte buffer", 2119 __FUNCTION__, size); 2120 return nullptr; 2121 } 2122 2123 // Read the inferior memory 2124 Error error; 2125 lldb::addr_t data_ptr = *allocation->data_ptr.get(); 2126 GetProcess()->ReadMemory(data_ptr, buffer.get(), size, error); 2127 if (error.Fail()) { 2128 if (log) 2129 log->Printf("%s - '%s' Couldn't read %" PRIu32 2130 " bytes of allocation data from 0x%" PRIx64, 2131 __FUNCTION__, error.AsCString(), size, data_ptr); 2132 return nullptr; 2133 } 2134 2135 return buffer; 2136 } 2137 2138 // Function copies data from a binary file into an allocation. 2139 // There is a header at the start of the file, FileHeader, before the data 2140 // content itself. 2141 // Information from this header is used to display warnings to the user about 2142 // incompatibilities 2143 bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, 2144 const char *filename, 2145 StackFrame *frame_ptr) { 2146 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2147 2148 // Find allocation with the given id 2149 AllocationDetails *alloc = FindAllocByID(strm, alloc_id); 2150 if (!alloc) 2151 return false; 2152 2153 if (log) 2154 log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__, 2155 *alloc->address.get()); 2156 2157 // JIT all the allocation details 2158 if (alloc->shouldRefresh()) { 2159 if (log) 2160 log->Printf("%s - allocation details not calculated yet, jitting info.", 2161 __FUNCTION__); 2162 2163 if (!RefreshAllocation(alloc, frame_ptr)) { 2164 if (log) 2165 log->Printf("%s - couldn't JIT allocation details", __FUNCTION__); 2166 return false; 2167 } 2168 } 2169 2170 assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && 2171 alloc->element.type_vec_size.isValid() && alloc->size.isValid() && 2172 alloc->element.datum_size.isValid() && 2173 "Allocation information not available"); 2174 2175 // Check we can read from file 2176 FileSpec file(filename, true); 2177 if (!file.Exists()) { 2178 strm.Printf("Error: File %s does not exist", filename); 2179 strm.EOL(); 2180 return false; 2181 } 2182 2183 if (!file.Readable()) { 2184 strm.Printf("Error: File %s does not have readable permissions", filename); 2185 strm.EOL(); 2186 return false; 2187 } 2188 2189 // Read file into data buffer 2190 DataBufferSP data_sp(file.ReadFileContents()); 2191 2192 // Cast start of buffer to FileHeader and use pointer to read metadata 2193 void *file_buffer = data_sp->GetBytes(); 2194 if (file_buffer == nullptr || 2195 data_sp->GetByteSize() < (sizeof(AllocationDetails::FileHeader) + 2196 sizeof(AllocationDetails::ElementHeader))) { 2197 strm.Printf("Error: File %s does not contain enough data for header", 2198 filename); 2199 strm.EOL(); 2200 return false; 2201 } 2202 const AllocationDetails::FileHeader *file_header = 2203 static_cast<AllocationDetails::FileHeader *>(file_buffer); 2204 2205 // Check file starts with ascii characters "RSAD" 2206 if (memcmp(file_header->ident, "RSAD", 4)) { 2207 strm.Printf("Error: File doesn't contain identifier for an RS allocation " 2208 "dump. Are you sure this is the correct file?"); 2209 strm.EOL(); 2210 return false; 2211 } 2212 2213 // Look at the type of the root element in the header 2214 AllocationDetails::ElementHeader root_element_header; 2215 memcpy(&root_element_header, static_cast<uint8_t *>(file_buffer) + 2216 sizeof(AllocationDetails::FileHeader), 2217 sizeof(AllocationDetails::ElementHeader)); 2218 2219 if (log) 2220 log->Printf("%s - header type %" PRIu32 ", element size %" PRIu32, 2221 __FUNCTION__, root_element_header.type, 2222 root_element_header.element_size); 2223 2224 // Check if the target allocation and file both have the same number of bytes 2225 // for an Element 2226 if (*alloc->element.datum_size.get() != root_element_header.element_size) { 2227 strm.Printf("Warning: Mismatched Element sizes - file %" PRIu32 2228 " bytes, allocation %" PRIu32 " bytes", 2229 root_element_header.element_size, 2230 *alloc->element.datum_size.get()); 2231 strm.EOL(); 2232 } 2233 2234 // Check if the target allocation and file both have the same type 2235 const uint32_t alloc_type = static_cast<uint32_t>(*alloc->element.type.get()); 2236 const uint32_t file_type = root_element_header.type; 2237 2238 if (file_type > Element::RS_TYPE_FONT) { 2239 strm.Printf("Warning: File has unknown allocation type"); 2240 strm.EOL(); 2241 } else if (alloc_type != file_type) { 2242 // Enum value isn't monotonous, so doesn't always index RsDataTypeToString 2243 // array 2244 uint32_t printable_target_type_index = alloc_type; 2245 uint32_t printable_head_type_index = file_type; 2246 if (alloc_type >= Element::RS_TYPE_ELEMENT && 2247 alloc_type <= Element::RS_TYPE_FONT) 2248 printable_target_type_index = static_cast<Element::DataType>( 2249 (alloc_type - Element::RS_TYPE_ELEMENT) + 2250 Element::RS_TYPE_MATRIX_2X2 + 1); 2251 2252 if (file_type >= Element::RS_TYPE_ELEMENT && 2253 file_type <= Element::RS_TYPE_FONT) 2254 printable_head_type_index = static_cast<Element::DataType>( 2255 (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 2256 1); 2257 2258 const char *file_type_cstr = 2259 AllocationDetails::RsDataTypeToString[printable_head_type_index][0]; 2260 const char *target_type_cstr = 2261 AllocationDetails::RsDataTypeToString[printable_target_type_index][0]; 2262 2263 strm.Printf( 2264 "Warning: Mismatched Types - file '%s' type, allocation '%s' type", 2265 file_type_cstr, target_type_cstr); 2266 strm.EOL(); 2267 } 2268 2269 // Advance buffer past header 2270 file_buffer = static_cast<uint8_t *>(file_buffer) + file_header->hdr_size; 2271 2272 // Calculate size of allocation data in file 2273 size_t length = data_sp->GetByteSize() - file_header->hdr_size; 2274 2275 // Check if the target allocation and file both have the same total data size. 2276 const uint32_t alloc_size = *alloc->size.get(); 2277 if (alloc_size != length) { 2278 strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64 2279 " bytes, allocation 0x%" PRIx32 " bytes", 2280 (uint64_t)length, alloc_size); 2281 strm.EOL(); 2282 length = alloc_size < length ? alloc_size 2283 : length; // Set length to copy to minimum 2284 } 2285 2286 // Copy file data from our buffer into the target allocation. 2287 lldb::addr_t alloc_data = *alloc->data_ptr.get(); 2288 Error error; 2289 size_t bytes_written = 2290 GetProcess()->WriteMemory(alloc_data, file_buffer, length, error); 2291 if (!error.Success() || bytes_written != length) { 2292 strm.Printf("Error: Couldn't write data to allocation %s", 2293 error.AsCString()); 2294 strm.EOL(); 2295 return false; 2296 } 2297 2298 strm.Printf("Contents of file '%s' read into allocation %" PRIu32, filename, 2299 alloc->id); 2300 strm.EOL(); 2301 2302 return true; 2303 } 2304 2305 // Function takes as parameters a byte buffer, which will eventually be written 2306 // to file as the element header, 2307 // an offset into that buffer, and an Element that will be saved into the buffer 2308 // at the parametrised offset. 2309 // Return value is the new offset after writing the element into the buffer. 2310 // Elements are saved to the file as the ElementHeader struct followed by 2311 // offsets to the structs of all the element's 2312 // children. 2313 size_t RenderScriptRuntime::PopulateElementHeaders( 2314 const std::shared_ptr<uint8_t> header_buffer, size_t offset, 2315 const Element &elem) { 2316 // File struct for an element header with all the relevant details copied from 2317 // elem. 2318 // We assume members are valid already. 2319 AllocationDetails::ElementHeader elem_header; 2320 elem_header.type = *elem.type.get(); 2321 elem_header.kind = *elem.type_kind.get(); 2322 elem_header.element_size = *elem.datum_size.get(); 2323 elem_header.vector_size = *elem.type_vec_size.get(); 2324 elem_header.array_size = 2325 elem.array_size.isValid() ? *elem.array_size.get() : 0; 2326 const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader); 2327 2328 // Copy struct into buffer and advance offset 2329 // We assume that header_buffer has been checked for nullptr before this 2330 // method is called 2331 memcpy(header_buffer.get() + offset, &elem_header, elem_header_size); 2332 offset += elem_header_size; 2333 2334 // Starting offset of child ElementHeader struct 2335 size_t child_offset = 2336 offset + ((elem.children.size() + 1) * sizeof(uint32_t)); 2337 for (const RenderScriptRuntime::Element &child : elem.children) { 2338 // Recursively populate the buffer with the element header structs of 2339 // children. 2340 // Then save the offsets where they were set after the parent element 2341 // header. 2342 memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t)); 2343 offset += sizeof(uint32_t); 2344 2345 child_offset = PopulateElementHeaders(header_buffer, child_offset, child); 2346 } 2347 2348 // Zero indicates no more children 2349 memset(header_buffer.get() + offset, 0, sizeof(uint32_t)); 2350 2351 return child_offset; 2352 } 2353 2354 // Given an Element object this function returns the total size needed in the 2355 // file header to store the element's 2356 // details. 2357 // Taking into account the size of the element header struct, plus the offsets 2358 // to all the element's children. 2359 // Function is recursive so that the size of all ancestors is taken into 2360 // account. 2361 size_t RenderScriptRuntime::CalculateElementHeaderSize(const Element &elem) { 2362 size_t size = (elem.children.size() + 1) * 2363 sizeof(uint32_t); // Offsets to children plus zero terminator 2364 size += sizeof(AllocationDetails::ElementHeader); // Size of header struct 2365 // with type details 2366 2367 // Calculate recursively for all descendants 2368 for (const Element &child : elem.children) 2369 size += CalculateElementHeaderSize(child); 2370 2371 return size; 2372 } 2373 2374 // Function copies allocation contents into a binary file. 2375 // This file can then be loaded later into a different allocation. 2376 // There is a header, FileHeader, before the allocation data containing 2377 // meta-data. 2378 bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, 2379 const char *filename, 2380 StackFrame *frame_ptr) { 2381 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2382 2383 // Find allocation with the given id 2384 AllocationDetails *alloc = FindAllocByID(strm, alloc_id); 2385 if (!alloc) 2386 return false; 2387 2388 if (log) 2389 log->Printf("%s - found allocation 0x%" PRIx64 ".", __FUNCTION__, 2390 *alloc->address.get()); 2391 2392 // JIT all the allocation details 2393 if (alloc->shouldRefresh()) { 2394 if (log) 2395 log->Printf("%s - allocation details not calculated yet, jitting info.", 2396 __FUNCTION__); 2397 2398 if (!RefreshAllocation(alloc, frame_ptr)) { 2399 if (log) 2400 log->Printf("%s - couldn't JIT allocation details.", __FUNCTION__); 2401 return false; 2402 } 2403 } 2404 2405 assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && 2406 alloc->element.type_vec_size.isValid() && 2407 alloc->element.datum_size.get() && 2408 alloc->element.type_kind.isValid() && alloc->dimension.isValid() && 2409 "Allocation information not available"); 2410 2411 // Check we can create writable file 2412 FileSpec file_spec(filename, true); 2413 File file(file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate | 2414 File::eOpenOptionTruncate); 2415 if (!file) { 2416 strm.Printf("Error: Failed to open '%s' for writing", filename); 2417 strm.EOL(); 2418 return false; 2419 } 2420 2421 // Read allocation into buffer of heap memory 2422 const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); 2423 if (!buffer) { 2424 strm.Printf("Error: Couldn't read allocation data into buffer"); 2425 strm.EOL(); 2426 return false; 2427 } 2428 2429 // Create the file header 2430 AllocationDetails::FileHeader head; 2431 memcpy(head.ident, "RSAD", 4); 2432 head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1); 2433 head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2); 2434 head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3); 2435 2436 const size_t element_header_size = CalculateElementHeaderSize(alloc->element); 2437 assert((sizeof(AllocationDetails::FileHeader) + element_header_size) < 2438 UINT16_MAX && 2439 "Element header too large"); 2440 head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) + 2441 element_header_size); 2442 2443 // Write the file header 2444 size_t num_bytes = sizeof(AllocationDetails::FileHeader); 2445 if (log) 2446 log->Printf("%s - writing File Header, 0x%" PRIx64 " bytes", __FUNCTION__, 2447 (uint64_t)num_bytes); 2448 2449 Error err = file.Write(&head, num_bytes); 2450 if (!err.Success()) { 2451 strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), 2452 filename); 2453 strm.EOL(); 2454 return false; 2455 } 2456 2457 // Create the headers describing the element type of the allocation. 2458 std::shared_ptr<uint8_t> element_header_buffer( 2459 new uint8_t[element_header_size]); 2460 if (element_header_buffer == nullptr) { 2461 strm.Printf("Internal Error: Couldn't allocate %" PRIu64 2462 " bytes on the heap", 2463 (uint64_t)element_header_size); 2464 strm.EOL(); 2465 return false; 2466 } 2467 2468 PopulateElementHeaders(element_header_buffer, 0, alloc->element); 2469 2470 // Write headers for allocation element type to file 2471 num_bytes = element_header_size; 2472 if (log) 2473 log->Printf("%s - writing element headers, 0x%" PRIx64 " bytes.", 2474 __FUNCTION__, (uint64_t)num_bytes); 2475 2476 err = file.Write(element_header_buffer.get(), num_bytes); 2477 if (!err.Success()) { 2478 strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), 2479 filename); 2480 strm.EOL(); 2481 return false; 2482 } 2483 2484 // Write allocation data to file 2485 num_bytes = static_cast<size_t>(*alloc->size.get()); 2486 if (log) 2487 log->Printf("%s - writing 0x%" PRIx64 " bytes", __FUNCTION__, 2488 (uint64_t)num_bytes); 2489 2490 err = file.Write(buffer.get(), num_bytes); 2491 if (!err.Success()) { 2492 strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), 2493 filename); 2494 strm.EOL(); 2495 return false; 2496 } 2497 2498 strm.Printf("Allocation written to file '%s'", filename); 2499 strm.EOL(); 2500 return true; 2501 } 2502 2503 bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) { 2504 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2505 2506 if (module_sp) { 2507 for (const auto &rs_module : m_rsmodules) { 2508 if (rs_module->m_module == module_sp) { 2509 // Check if the user has enabled automatically breaking on 2510 // all RS kernels. 2511 if (m_breakAllKernels) 2512 BreakOnModuleKernels(rs_module); 2513 2514 return false; 2515 } 2516 } 2517 bool module_loaded = false; 2518 switch (GetModuleKind(module_sp)) { 2519 case eModuleKindKernelObj: { 2520 RSModuleDescriptorSP module_desc; 2521 module_desc.reset(new RSModuleDescriptor(module_sp)); 2522 if (module_desc->ParseRSInfo()) { 2523 m_rsmodules.push_back(module_desc); 2524 module_loaded = true; 2525 } 2526 if (module_loaded) { 2527 FixupScriptDetails(module_desc); 2528 } 2529 break; 2530 } 2531 case eModuleKindDriver: { 2532 if (!m_libRSDriver) { 2533 m_libRSDriver = module_sp; 2534 LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver); 2535 } 2536 break; 2537 } 2538 case eModuleKindImpl: { 2539 m_libRSCpuRef = module_sp; 2540 break; 2541 } 2542 case eModuleKindLibRS: { 2543 if (!m_libRS) { 2544 m_libRS = module_sp; 2545 static ConstString gDbgPresentStr("gDebuggerPresent"); 2546 const Symbol *debug_present = m_libRS->FindFirstSymbolWithNameAndType( 2547 gDbgPresentStr, eSymbolTypeData); 2548 if (debug_present) { 2549 Error error; 2550 uint32_t flag = 0x00000001U; 2551 Target &target = GetProcess()->GetTarget(); 2552 addr_t addr = debug_present->GetLoadAddress(&target); 2553 GetProcess()->WriteMemory(addr, &flag, sizeof(flag), error); 2554 if (error.Success()) { 2555 if (log) 2556 log->Printf("%s - debugger present flag set on debugee.", 2557 __FUNCTION__); 2558 2559 m_debuggerPresentFlagged = true; 2560 } else if (log) { 2561 log->Printf("%s - error writing debugger present flags '%s' ", 2562 __FUNCTION__, error.AsCString()); 2563 } 2564 } else if (log) { 2565 log->Printf( 2566 "%s - error writing debugger present flags - symbol not found", 2567 __FUNCTION__); 2568 } 2569 } 2570 break; 2571 } 2572 default: 2573 break; 2574 } 2575 if (module_loaded) 2576 Update(); 2577 return module_loaded; 2578 } 2579 return false; 2580 } 2581 2582 void RenderScriptRuntime::Update() { 2583 if (m_rsmodules.size() > 0) { 2584 if (!m_initiated) { 2585 Initiate(); 2586 } 2587 } 2588 } 2589 2590 // The maximum line length of an .rs.info packet 2591 #define MAXLINE 500 2592 #define STRINGIFY(x) #x 2593 #define MAXLINESTR_(x) "%" STRINGIFY(x) "s" 2594 #define MAXLINESTR MAXLINESTR_(MAXLINE) 2595 2596 // The .rs.info symbol in renderscript modules contains a string which needs to 2597 // be parsed. 2598 // The string is basic and is parsed on a line by line basis. 2599 bool RSModuleDescriptor::ParseRSInfo() { 2600 assert(m_module); 2601 const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType( 2602 ConstString(".rs.info"), eSymbolTypeData); 2603 if (!info_sym) 2604 return false; 2605 2606 const addr_t addr = info_sym->GetAddressRef().GetFileAddress(); 2607 if (addr == LLDB_INVALID_ADDRESS) 2608 return false; 2609 2610 const addr_t size = info_sym->GetByteSize(); 2611 const FileSpec fs = m_module->GetFileSpec(); 2612 2613 const DataBufferSP buffer = fs.ReadFileContents(addr, size); 2614 if (!buffer) 2615 return false; 2616 2617 // split rs.info. contents into lines 2618 std::vector<std::string> info_lines; 2619 { 2620 const std::string info((const char *)buffer->GetBytes()); 2621 for (size_t tail = 0; tail < info.size();) { 2622 // find next new line or end of string 2623 size_t head = info.find('\n', tail); 2624 head = (head == std::string::npos) ? info.size() : head; 2625 std::string line = info.substr(tail, head - tail); 2626 // add to line list 2627 info_lines.push_back(line); 2628 tail = head + 1; 2629 } 2630 } 2631 2632 std::array<char, MAXLINE> name{{'\0'}}; 2633 std::array<char, MAXLINE> value{{'\0'}}; 2634 2635 // parse all text lines of .rs.info 2636 for (auto line = info_lines.begin(); line != info_lines.end(); ++line) { 2637 uint32_t numDefns = 0; 2638 if (sscanf(line->c_str(), "exportVarCount: %" PRIu32 "", &numDefns) == 1) { 2639 while (numDefns--) 2640 m_globals.push_back(RSGlobalDescriptor(this, (++line)->c_str())); 2641 } else if (sscanf(line->c_str(), "exportForEachCount: %" PRIu32 "", 2642 &numDefns) == 1) { 2643 while (numDefns--) { 2644 uint32_t slot = 0; 2645 name[0] = '\0'; 2646 static const char *fmt_s = "%" PRIu32 " - " MAXLINESTR; 2647 if (sscanf((++line)->c_str(), fmt_s, &slot, name.data()) == 2) { 2648 if (name[0] != '\0') 2649 m_kernels.push_back(RSKernelDescriptor(this, name.data(), slot)); 2650 } 2651 } 2652 } else if (sscanf(line->c_str(), "pragmaCount: %" PRIu32 "", &numDefns) == 2653 1) { 2654 while (numDefns--) { 2655 name[0] = value[0] = '\0'; 2656 static const char *fmt_s = MAXLINESTR " - " MAXLINESTR; 2657 if (sscanf((++line)->c_str(), fmt_s, name.data(), value.data()) != 0) { 2658 if (name[0] != '\0') 2659 m_pragmas[std::string(name.data())] = value.data(); 2660 } 2661 } 2662 } else { 2663 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2664 if (log) { 2665 log->Printf("%s - skipping .rs.info field '%s'", __FUNCTION__, 2666 line->c_str()); 2667 } 2668 } 2669 } 2670 2671 // 'root' kernel should always be present 2672 return m_kernels.size() > 0; 2673 } 2674 2675 void RenderScriptRuntime::Status(Stream &strm) const { 2676 if (m_libRS) { 2677 strm.Printf("Runtime Library discovered."); 2678 strm.EOL(); 2679 } 2680 if (m_libRSDriver) { 2681 strm.Printf("Runtime Driver discovered."); 2682 strm.EOL(); 2683 } 2684 if (m_libRSCpuRef) { 2685 strm.Printf("CPU Reference Implementation discovered."); 2686 strm.EOL(); 2687 } 2688 2689 if (m_runtimeHooks.size()) { 2690 strm.Printf("Runtime functions hooked:"); 2691 strm.EOL(); 2692 for (auto b : m_runtimeHooks) { 2693 strm.Indent(b.second->defn->name); 2694 strm.EOL(); 2695 } 2696 } else { 2697 strm.Printf("Runtime is not hooked."); 2698 strm.EOL(); 2699 } 2700 } 2701 2702 void RenderScriptRuntime::DumpContexts(Stream &strm) const { 2703 strm.Printf("Inferred RenderScript Contexts:"); 2704 strm.EOL(); 2705 strm.IndentMore(); 2706 2707 std::map<addr_t, uint64_t> contextReferences; 2708 2709 // Iterate over all of the currently discovered scripts. 2710 // Note: We cant push or pop from m_scripts inside this loop or it may 2711 // invalidate script. 2712 for (const auto &script : m_scripts) { 2713 if (!script->context.isValid()) 2714 continue; 2715 lldb::addr_t context = *script->context; 2716 2717 if (contextReferences.find(context) != contextReferences.end()) { 2718 contextReferences[context]++; 2719 } else { 2720 contextReferences[context] = 1; 2721 } 2722 } 2723 2724 for (const auto &cRef : contextReferences) { 2725 strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances", 2726 cRef.first, cRef.second); 2727 strm.EOL(); 2728 } 2729 strm.IndentLess(); 2730 } 2731 2732 void RenderScriptRuntime::DumpKernels(Stream &strm) const { 2733 strm.Printf("RenderScript Kernels:"); 2734 strm.EOL(); 2735 strm.IndentMore(); 2736 for (const auto &module : m_rsmodules) { 2737 strm.Printf("Resource '%s':", module->m_resname.c_str()); 2738 strm.EOL(); 2739 for (const auto &kernel : module->m_kernels) { 2740 strm.Indent(kernel.m_name.AsCString()); 2741 strm.EOL(); 2742 } 2743 } 2744 strm.IndentLess(); 2745 } 2746 2747 RenderScriptRuntime::AllocationDetails * 2748 RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) { 2749 AllocationDetails *alloc = nullptr; 2750 2751 // See if we can find allocation using id as an index; 2752 if (alloc_id <= m_allocations.size() && alloc_id != 0 && 2753 m_allocations[alloc_id - 1]->id == alloc_id) { 2754 alloc = m_allocations[alloc_id - 1].get(); 2755 return alloc; 2756 } 2757 2758 // Fallback to searching 2759 for (const auto &a : m_allocations) { 2760 if (a->id == alloc_id) { 2761 alloc = a.get(); 2762 break; 2763 } 2764 } 2765 2766 if (alloc == nullptr) { 2767 strm.Printf("Error: Couldn't find allocation with id matching %" PRIu32, 2768 alloc_id); 2769 strm.EOL(); 2770 } 2771 2772 return alloc; 2773 } 2774 2775 // Prints the contents of an allocation to the output stream, which may be a 2776 // file 2777 bool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr, 2778 const uint32_t id) { 2779 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2780 2781 // Check we can find the desired allocation 2782 AllocationDetails *alloc = FindAllocByID(strm, id); 2783 if (!alloc) 2784 return false; // FindAllocByID() will print error message for us here 2785 2786 if (log) 2787 log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__, 2788 *alloc->address.get()); 2789 2790 // Check we have information about the allocation, if not calculate it 2791 if (alloc->shouldRefresh()) { 2792 if (log) 2793 log->Printf("%s - allocation details not calculated yet, jitting info.", 2794 __FUNCTION__); 2795 2796 // JIT all the allocation information 2797 if (!RefreshAllocation(alloc, frame_ptr)) { 2798 strm.Printf("Error: Couldn't JIT allocation details"); 2799 strm.EOL(); 2800 return false; 2801 } 2802 } 2803 2804 // Establish format and size of each data element 2805 const uint32_t vec_size = *alloc->element.type_vec_size.get(); 2806 const Element::DataType type = *alloc->element.type.get(); 2807 2808 assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && 2809 "Invalid allocation type"); 2810 2811 lldb::Format format; 2812 if (type >= Element::RS_TYPE_ELEMENT) 2813 format = eFormatHex; 2814 else 2815 format = vec_size == 1 2816 ? static_cast<lldb::Format>( 2817 AllocationDetails::RSTypeToFormat[type][eFormatSingle]) 2818 : static_cast<lldb::Format>( 2819 AllocationDetails::RSTypeToFormat[type][eFormatVector]); 2820 2821 const uint32_t data_size = *alloc->element.datum_size.get(); 2822 2823 if (log) 2824 log->Printf("%s - element size %" PRIu32 " bytes, including padding", 2825 __FUNCTION__, data_size); 2826 2827 // Allocate a buffer to copy data into 2828 std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); 2829 if (!buffer) { 2830 strm.Printf("Error: Couldn't read allocation data"); 2831 strm.EOL(); 2832 return false; 2833 } 2834 2835 // Calculate stride between rows as there may be padding at end of rows since 2836 // allocated memory is 16-byte aligned 2837 if (!alloc->stride.isValid()) { 2838 if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension 2839 alloc->stride = 0; 2840 else if (!JITAllocationStride(alloc, frame_ptr)) { 2841 strm.Printf("Error: Couldn't calculate allocation row stride"); 2842 strm.EOL(); 2843 return false; 2844 } 2845 } 2846 const uint32_t stride = *alloc->stride.get(); 2847 const uint32_t size = *alloc->size.get(); // Size of whole allocation 2848 const uint32_t padding = 2849 alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0; 2850 if (log) 2851 log->Printf("%s - stride %" PRIu32 " bytes, size %" PRIu32 2852 " bytes, padding %" PRIu32, 2853 __FUNCTION__, stride, size, padding); 2854 2855 // Find dimensions used to index loops, so need to be non-zero 2856 uint32_t dim_x = alloc->dimension.get()->dim_1; 2857 dim_x = dim_x == 0 ? 1 : dim_x; 2858 2859 uint32_t dim_y = alloc->dimension.get()->dim_2; 2860 dim_y = dim_y == 0 ? 1 : dim_y; 2861 2862 uint32_t dim_z = alloc->dimension.get()->dim_3; 2863 dim_z = dim_z == 0 ? 1 : dim_z; 2864 2865 // Use data extractor to format output 2866 const uint32_t archByteSize = 2867 GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 2868 DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(), 2869 archByteSize); 2870 2871 uint32_t offset = 0; // Offset in buffer to next element to be printed 2872 uint32_t prev_row = 0; // Offset to the start of the previous row 2873 2874 // Iterate over allocation dimensions, printing results to user 2875 strm.Printf("Data (X, Y, Z):"); 2876 for (uint32_t z = 0; z < dim_z; ++z) { 2877 for (uint32_t y = 0; y < dim_y; ++y) { 2878 // Use stride to index start of next row. 2879 if (!(y == 0 && z == 0)) 2880 offset = prev_row + stride; 2881 prev_row = offset; 2882 2883 // Print each element in the row individually 2884 for (uint32_t x = 0; x < dim_x; ++x) { 2885 strm.Printf("\n(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") = ", x, y, z); 2886 if ((type == Element::RS_TYPE_NONE) && 2887 (alloc->element.children.size() > 0) && 2888 (alloc->element.type_name != Element::GetFallbackStructName())) { 2889 // Here we are dumping an Element of struct type. 2890 // This is done using expression evaluation with the name of the 2891 // struct type and pointer to element. 2892 2893 // Don't print the name of the resulting expression, since this will 2894 // be '$[0-9]+' 2895 DumpValueObjectOptions expr_options; 2896 expr_options.SetHideName(true); 2897 2898 // Setup expression as derefrencing a pointer cast to element address. 2899 char expr_char_buffer[jit_max_expr_size]; 2900 int chars_written = 2901 snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64, 2902 alloc->element.type_name.AsCString(), 2903 *alloc->data_ptr.get() + offset); 2904 2905 if (chars_written < 0 || chars_written >= jit_max_expr_size) { 2906 if (log) 2907 log->Printf("%s - error in snprintf().", __FUNCTION__); 2908 continue; 2909 } 2910 2911 // Evaluate expression 2912 ValueObjectSP expr_result; 2913 GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer, 2914 frame_ptr, expr_result); 2915 2916 // Print the results to our stream. 2917 expr_result->Dump(strm, expr_options); 2918 } else { 2919 alloc_data.Dump(&strm, offset, format, data_size - padding, 1, 1, 2920 LLDB_INVALID_ADDRESS, 0, 0); 2921 } 2922 offset += data_size; 2923 } 2924 } 2925 } 2926 strm.EOL(); 2927 2928 return true; 2929 } 2930 2931 // Function recalculates all our cached information about allocations by jitting 2932 // the 2933 // RS runtime regarding each allocation we know about. 2934 // Returns true if all allocations could be recomputed, false otherwise. 2935 bool RenderScriptRuntime::RecomputeAllAllocations(Stream &strm, 2936 StackFrame *frame_ptr) { 2937 bool success = true; 2938 for (auto &alloc : m_allocations) { 2939 // JIT current allocation information 2940 if (!RefreshAllocation(alloc.get(), frame_ptr)) { 2941 strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32 2942 "\n", 2943 alloc->id); 2944 success = false; 2945 } 2946 } 2947 2948 if (success) 2949 strm.Printf("All allocations successfully recomputed"); 2950 strm.EOL(); 2951 2952 return success; 2953 } 2954 2955 // Prints information regarding currently loaded allocations. 2956 // These details are gathered by jitting the runtime, which has as latency. 2957 // Index parameter specifies a single allocation ID to print, or a zero value to 2958 // print them all 2959 void RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame *frame_ptr, 2960 const uint32_t index) { 2961 strm.Printf("RenderScript Allocations:"); 2962 strm.EOL(); 2963 strm.IndentMore(); 2964 2965 for (auto &alloc : m_allocations) { 2966 // index will only be zero if we want to print all allocations 2967 if (index != 0 && index != alloc->id) 2968 continue; 2969 2970 // JIT current allocation information 2971 if (alloc->shouldRefresh() && !RefreshAllocation(alloc.get(), frame_ptr)) { 2972 strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32, 2973 alloc->id); 2974 strm.EOL(); 2975 continue; 2976 } 2977 2978 strm.Printf("%" PRIu32 ":", alloc->id); 2979 strm.EOL(); 2980 strm.IndentMore(); 2981 2982 strm.Indent("Context: "); 2983 if (!alloc->context.isValid()) 2984 strm.Printf("unknown\n"); 2985 else 2986 strm.Printf("0x%" PRIx64 "\n", *alloc->context.get()); 2987 2988 strm.Indent("Address: "); 2989 if (!alloc->address.isValid()) 2990 strm.Printf("unknown\n"); 2991 else 2992 strm.Printf("0x%" PRIx64 "\n", *alloc->address.get()); 2993 2994 strm.Indent("Data pointer: "); 2995 if (!alloc->data_ptr.isValid()) 2996 strm.Printf("unknown\n"); 2997 else 2998 strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get()); 2999 3000 strm.Indent("Dimensions: "); 3001 if (!alloc->dimension.isValid()) 3002 strm.Printf("unknown\n"); 3003 else 3004 strm.Printf("(%" PRId32 ", %" PRId32 ", %" PRId32 ")\n", 3005 alloc->dimension.get()->dim_1, alloc->dimension.get()->dim_2, 3006 alloc->dimension.get()->dim_3); 3007 3008 strm.Indent("Data Type: "); 3009 if (!alloc->element.type.isValid() || 3010 !alloc->element.type_vec_size.isValid()) 3011 strm.Printf("unknown\n"); 3012 else { 3013 const int vector_size = *alloc->element.type_vec_size.get(); 3014 Element::DataType type = *alloc->element.type.get(); 3015 3016 if (!alloc->element.type_name.IsEmpty()) 3017 strm.Printf("%s\n", alloc->element.type_name.AsCString()); 3018 else { 3019 // Enum value isn't monotonous, so doesn't always index 3020 // RsDataTypeToString array 3021 if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT) 3022 type = 3023 static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) + 3024 Element::RS_TYPE_MATRIX_2X2 + 1); 3025 3026 if (type >= (sizeof(AllocationDetails::RsDataTypeToString) / 3027 sizeof(AllocationDetails::RsDataTypeToString[0])) || 3028 vector_size > 4 || vector_size < 1) 3029 strm.Printf("invalid type\n"); 3030 else 3031 strm.Printf( 3032 "%s\n", 3033 AllocationDetails::RsDataTypeToString[static_cast<uint32_t>(type)] 3034 [vector_size - 1]); 3035 } 3036 } 3037 3038 strm.Indent("Data Kind: "); 3039 if (!alloc->element.type_kind.isValid()) 3040 strm.Printf("unknown\n"); 3041 else { 3042 const Element::DataKind kind = *alloc->element.type_kind.get(); 3043 if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV) 3044 strm.Printf("invalid kind\n"); 3045 else 3046 strm.Printf( 3047 "%s\n", 3048 AllocationDetails::RsDataKindToString[static_cast<uint32_t>(kind)]); 3049 } 3050 3051 strm.EOL(); 3052 strm.IndentLess(); 3053 } 3054 strm.IndentLess(); 3055 } 3056 3057 // Set breakpoints on every kernel found in RS module 3058 void RenderScriptRuntime::BreakOnModuleKernels( 3059 const RSModuleDescriptorSP rsmodule_sp) { 3060 for (const auto &kernel : rsmodule_sp->m_kernels) { 3061 // Don't set breakpoint on 'root' kernel 3062 if (strcmp(kernel.m_name.AsCString(), "root") == 0) 3063 continue; 3064 3065 CreateKernelBreakpoint(kernel.m_name); 3066 } 3067 } 3068 3069 // Method is internally called by the 'kernel breakpoint all' command to 3070 // enable or disable breaking on all kernels. 3071 // 3072 // When do_break is true we want to enable this functionality. 3073 // When do_break is false we want to disable it. 3074 void RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) { 3075 Log *log( 3076 GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3077 3078 InitSearchFilter(target); 3079 3080 // Set breakpoints on all the kernels 3081 if (do_break && !m_breakAllKernels) { 3082 m_breakAllKernels = true; 3083 3084 for (const auto &module : m_rsmodules) 3085 BreakOnModuleKernels(module); 3086 3087 if (log) 3088 log->Printf("%s(True) - breakpoints set on all currently loaded kernels.", 3089 __FUNCTION__); 3090 } else if (!do_break && 3091 m_breakAllKernels) // Breakpoints won't be set on any new kernels. 3092 { 3093 m_breakAllKernels = false; 3094 3095 if (log) 3096 log->Printf("%s(False) - breakpoints no longer automatically set.", 3097 __FUNCTION__); 3098 } 3099 } 3100 3101 // Given the name of a kernel this function creates a breakpoint using our 3102 // own breakpoint resolver, and returns the Breakpoint shared pointer. 3103 BreakpointSP 3104 RenderScriptRuntime::CreateKernelBreakpoint(const ConstString &name) { 3105 Log *log( 3106 GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3107 3108 if (!m_filtersp) { 3109 if (log) 3110 log->Printf("%s - error, no breakpoint search filter set.", __FUNCTION__); 3111 return nullptr; 3112 } 3113 3114 BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name)); 3115 BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint( 3116 m_filtersp, resolver_sp, false, false, false); 3117 3118 // Give RS breakpoints a specific name, so the user can manipulate them as a 3119 // group. 3120 Error err; 3121 if (!bp->AddName("RenderScriptKernel", err) && log) 3122 log->Printf("%s - error setting break name, '%s'.", __FUNCTION__, 3123 err.AsCString()); 3124 3125 return bp; 3126 } 3127 3128 // Given an expression for a variable this function tries to calculate the 3129 // variable's value. 3130 // If this is possible it returns true and sets the uint64_t parameter to the 3131 // variables unsigned value. 3132 // Otherwise function returns false. 3133 bool RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp, 3134 const char *var_name, 3135 uint64_t &val) { 3136 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 3137 Error error; 3138 VariableSP var_sp; 3139 3140 // Find variable in stack frame 3141 ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath( 3142 var_name, eNoDynamicValues, 3143 StackFrame::eExpressionPathOptionCheckPtrVsMember | 3144 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, 3145 var_sp, error)); 3146 if (!error.Success()) { 3147 if (log) 3148 log->Printf("%s - error, couldn't find '%s' in frame", __FUNCTION__, 3149 var_name); 3150 return false; 3151 } 3152 3153 // Find the uint32_t value for the variable 3154 bool success = false; 3155 val = value_sp->GetValueAsUnsigned(0, &success); 3156 if (!success) { 3157 if (log) 3158 log->Printf("%s - error, couldn't parse '%s' as an uint32_t.", 3159 __FUNCTION__, var_name); 3160 return false; 3161 } 3162 3163 return true; 3164 } 3165 3166 // Function attempts to find the current coordinate of a kernel invocation by 3167 // investigating the 3168 // values of frame variables in the .expand function. These coordinates are 3169 // returned via the coord 3170 // array reference parameter. Returns true if the coordinates could be found, 3171 // and false otherwise. 3172 bool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord, 3173 Thread *thread_ptr) { 3174 static const std::string s_runtimeExpandSuffix(".expand"); 3175 static const std::array<const char *, 3> s_runtimeCoordVars{ 3176 {"rsIndex", "p->current.y", "p->current.z"}}; 3177 3178 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 3179 3180 if (!thread_ptr) { 3181 if (log) 3182 log->Printf("%s - Error, No thread pointer", __FUNCTION__); 3183 3184 return false; 3185 } 3186 3187 // Walk the call stack looking for a function whose name has the suffix 3188 // '.expand' 3189 // and contains the variables we're looking for. 3190 for (uint32_t i = 0; i < thread_ptr->GetStackFrameCount(); ++i) { 3191 if (!thread_ptr->SetSelectedFrameByIndex(i)) 3192 continue; 3193 3194 StackFrameSP frame_sp = thread_ptr->GetSelectedFrame(); 3195 if (!frame_sp) 3196 continue; 3197 3198 // Find the function name 3199 const SymbolContext sym_ctx = frame_sp->GetSymbolContext(false); 3200 const char *func_name_cstr = sym_ctx.GetFunctionName().AsCString(); 3201 if (!func_name_cstr) 3202 continue; 3203 3204 if (log) 3205 log->Printf("%s - Inspecting function '%s'", __FUNCTION__, 3206 func_name_cstr); 3207 3208 // Check if function name has .expand suffix 3209 std::string func_name(func_name_cstr); 3210 const int length_difference = 3211 func_name.length() - s_runtimeExpandSuffix.length(); 3212 if (length_difference <= 0) 3213 continue; 3214 3215 const int32_t has_expand_suffix = 3216 func_name.compare(length_difference, s_runtimeExpandSuffix.length(), 3217 s_runtimeExpandSuffix); 3218 3219 if (has_expand_suffix != 0) 3220 continue; 3221 3222 if (log) 3223 log->Printf("%s - Found .expand function '%s'", __FUNCTION__, 3224 func_name_cstr); 3225 3226 // Get values for variables in .expand frame that tell us the current kernel 3227 // invocation 3228 bool found_coord_variables = true; 3229 assert(s_runtimeCoordVars.size() == coord.size()); 3230 3231 for (uint32_t i = 0; i < coord.size(); ++i) { 3232 uint64_t value = 0; 3233 if (!GetFrameVarAsUnsigned(frame_sp, s_runtimeCoordVars[i], value)) { 3234 found_coord_variables = false; 3235 break; 3236 } 3237 coord[i] = value; 3238 } 3239 3240 if (found_coord_variables) 3241 return true; 3242 } 3243 return false; 3244 } 3245 3246 // Callback when a kernel breakpoint hits and we're looking for a specific 3247 // coordinate. 3248 // Baton parameter contains a pointer to the target coordinate we want to break 3249 // on. 3250 // Function then checks the .expand frame for the current coordinate and breaks 3251 // to user if it matches. 3252 // Parameter 'break_id' is the id of the Breakpoint which made the callback. 3253 // Parameter 'break_loc_id' is the id for the BreakpointLocation which was hit, 3254 // a single logical breakpoint can have multiple addresses. 3255 bool RenderScriptRuntime::KernelBreakpointHit(void *baton, 3256 StoppointCallbackContext *ctx, 3257 user_id_t break_id, 3258 user_id_t break_loc_id) { 3259 Log *log( 3260 GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3261 3262 assert(baton && 3263 "Error: null baton in conditional kernel breakpoint callback"); 3264 3265 // Coordinate we want to stop on 3266 const uint32_t *target_coord = static_cast<const uint32_t *>(baton); 3267 3268 if (log) 3269 log->Printf("%s - Break ID %" PRIu64 ", (%" PRIu32 ", %" PRIu32 ", %" PRIu32 3270 ")", 3271 __FUNCTION__, break_id, target_coord[0], target_coord[1], 3272 target_coord[2]); 3273 3274 // Select current thread 3275 ExecutionContext context(ctx->exe_ctx_ref); 3276 Thread *thread_ptr = context.GetThreadPtr(); 3277 assert(thread_ptr && "Null thread pointer"); 3278 3279 // Find current kernel invocation from .expand frame variables 3280 RSCoordinate current_coord{}; // Zero initialise array 3281 if (!GetKernelCoordinate(current_coord, thread_ptr)) { 3282 if (log) 3283 log->Printf("%s - Error, couldn't select .expand stack frame", 3284 __FUNCTION__); 3285 return false; 3286 } 3287 3288 if (log) 3289 log->Printf("%s - (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", __FUNCTION__, 3290 current_coord[0], current_coord[1], current_coord[2]); 3291 3292 // Check if the current kernel invocation coordinate matches our target 3293 // coordinate 3294 if (current_coord[0] == target_coord[0] && 3295 current_coord[1] == target_coord[1] && 3296 current_coord[2] == target_coord[2]) { 3297 if (log) 3298 log->Printf("%s, BREAKING (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", 3299 __FUNCTION__, current_coord[0], current_coord[1], 3300 current_coord[2]); 3301 3302 BreakpointSP breakpoint_sp = 3303 context.GetTargetPtr()->GetBreakpointByID(break_id); 3304 assert(breakpoint_sp != nullptr && 3305 "Error: Couldn't find breakpoint matching break id for callback"); 3306 breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint 3307 // should only be hit once. 3308 return true; 3309 } 3310 3311 // No match on coordinate 3312 return false; 3313 } 3314 3315 // Tries to set a breakpoint on the start of a kernel, resolved using the kernel 3316 // name. 3317 // Argument 'coords', represents a three dimensional coordinate which can be 3318 // used to specify 3319 // a single kernel instance to break on. If this is set then we add a callback 3320 // to the breakpoint. 3321 void RenderScriptRuntime::PlaceBreakpointOnKernel( 3322 Stream &strm, const char *name, const std::array<int, 3> coords, 3323 Error &error, TargetSP target) { 3324 if (!name) { 3325 error.SetErrorString("invalid kernel name"); 3326 return; 3327 } 3328 3329 InitSearchFilter(target); 3330 3331 ConstString kernel_name(name); 3332 BreakpointSP bp = CreateKernelBreakpoint(kernel_name); 3333 3334 // We have a conditional breakpoint on a specific coordinate 3335 if (coords[0] != -1) { 3336 strm.Printf("Conditional kernel breakpoint on coordinate %" PRId32 3337 ", %" PRId32 ", %" PRId32, 3338 coords[0], coords[1], coords[2]); 3339 strm.EOL(); 3340 3341 // Allocate memory for the baton, and copy over coordinate 3342 uint32_t *baton = new uint32_t[coords.size()]; 3343 baton[0] = coords[0]; 3344 baton[1] = coords[1]; 3345 baton[2] = coords[2]; 3346 3347 // Create a callback that will be invoked every time the breakpoint is hit. 3348 // The baton object passed to the handler is the target coordinate we want 3349 // to break on. 3350 bp->SetCallback(KernelBreakpointHit, baton, true); 3351 3352 // Store a shared pointer to the baton, so the memory will eventually be 3353 // cleaned up after destruction 3354 m_conditional_breaks[bp->GetID()] = std::shared_ptr<uint32_t>(baton); 3355 } 3356 3357 if (bp) 3358 bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false); 3359 } 3360 3361 void RenderScriptRuntime::DumpModules(Stream &strm) const { 3362 strm.Printf("RenderScript Modules:"); 3363 strm.EOL(); 3364 strm.IndentMore(); 3365 for (const auto &module : m_rsmodules) { 3366 module->Dump(strm); 3367 } 3368 strm.IndentLess(); 3369 } 3370 3371 RenderScriptRuntime::ScriptDetails * 3372 RenderScriptRuntime::LookUpScript(addr_t address, bool create) { 3373 for (const auto &s : m_scripts) { 3374 if (s->script.isValid()) 3375 if (*s->script == address) 3376 return s.get(); 3377 } 3378 if (create) { 3379 std::unique_ptr<ScriptDetails> s(new ScriptDetails); 3380 s->script = address; 3381 m_scripts.push_back(std::move(s)); 3382 return m_scripts.back().get(); 3383 } 3384 return nullptr; 3385 } 3386 3387 RenderScriptRuntime::AllocationDetails * 3388 RenderScriptRuntime::LookUpAllocation(addr_t address) { 3389 for (const auto &a : m_allocations) { 3390 if (a->address.isValid()) 3391 if (*a->address == address) 3392 return a.get(); 3393 } 3394 return nullptr; 3395 } 3396 3397 RenderScriptRuntime::AllocationDetails * 3398 RenderScriptRuntime::CreateAllocation(addr_t address) { 3399 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 3400 3401 // Remove any previous allocation which contains the same address 3402 auto it = m_allocations.begin(); 3403 while (it != m_allocations.end()) { 3404 if (*((*it)->address) == address) { 3405 if (log) 3406 log->Printf("%s - Removing allocation id: %d, address: 0x%" PRIx64, 3407 __FUNCTION__, (*it)->id, address); 3408 3409 it = m_allocations.erase(it); 3410 } else { 3411 it++; 3412 } 3413 } 3414 3415 std::unique_ptr<AllocationDetails> a(new AllocationDetails); 3416 a->address = address; 3417 m_allocations.push_back(std::move(a)); 3418 return m_allocations.back().get(); 3419 } 3420 3421 void RSModuleDescriptor::Dump(Stream &strm) const { 3422 strm.Indent(); 3423 m_module->GetFileSpec().Dump(&strm); 3424 if (m_module->GetNumCompileUnits()) { 3425 strm.Indent("Debug info loaded."); 3426 } else { 3427 strm.Indent("Debug info does not exist."); 3428 } 3429 strm.EOL(); 3430 strm.IndentMore(); 3431 strm.Indent(); 3432 strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size())); 3433 strm.EOL(); 3434 strm.IndentMore(); 3435 for (const auto &global : m_globals) { 3436 global.Dump(strm); 3437 } 3438 strm.IndentLess(); 3439 strm.Indent(); 3440 strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size())); 3441 strm.EOL(); 3442 strm.IndentMore(); 3443 for (const auto &kernel : m_kernels) { 3444 kernel.Dump(strm); 3445 } 3446 strm.Printf("Pragmas: %" PRIu64, static_cast<uint64_t>(m_pragmas.size())); 3447 strm.EOL(); 3448 strm.IndentMore(); 3449 for (const auto &key_val : m_pragmas) { 3450 strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str()); 3451 strm.EOL(); 3452 } 3453 strm.IndentLess(4); 3454 } 3455 3456 void RSGlobalDescriptor::Dump(Stream &strm) const { 3457 strm.Indent(m_name.AsCString()); 3458 VariableList var_list; 3459 m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list); 3460 if (var_list.GetSize() == 1) { 3461 auto var = var_list.GetVariableAtIndex(0); 3462 auto type = var->GetType(); 3463 if (type) { 3464 strm.Printf(" - "); 3465 type->DumpTypeName(&strm); 3466 } else { 3467 strm.Printf(" - Unknown Type"); 3468 } 3469 } else { 3470 strm.Printf(" - variable identified, but not found in binary"); 3471 const Symbol *s = m_module->m_module->FindFirstSymbolWithNameAndType( 3472 m_name, eSymbolTypeData); 3473 if (s) { 3474 strm.Printf(" (symbol exists) "); 3475 } 3476 } 3477 3478 strm.EOL(); 3479 } 3480 3481 void RSKernelDescriptor::Dump(Stream &strm) const { 3482 strm.Indent(m_name.AsCString()); 3483 strm.EOL(); 3484 } 3485 3486 class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed { 3487 public: 3488 CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter) 3489 : CommandObjectParsed( 3490 interpreter, "renderscript module dump", 3491 "Dumps renderscript specific information for all modules.", 3492 "renderscript module dump", 3493 eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} 3494 3495 ~CommandObjectRenderScriptRuntimeModuleDump() override = default; 3496 3497 bool DoExecute(Args &command, CommandReturnObject &result) override { 3498 RenderScriptRuntime *runtime = 3499 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3500 eLanguageTypeExtRenderScript); 3501 runtime->DumpModules(result.GetOutputStream()); 3502 result.SetStatus(eReturnStatusSuccessFinishResult); 3503 return true; 3504 } 3505 }; 3506 3507 class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword { 3508 public: 3509 CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter) 3510 : CommandObjectMultiword(interpreter, "renderscript module", 3511 "Commands that deal with RenderScript modules.", 3512 nullptr) { 3513 LoadSubCommand( 3514 "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump( 3515 interpreter))); 3516 } 3517 3518 ~CommandObjectRenderScriptRuntimeModule() override = default; 3519 }; 3520 3521 class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed { 3522 public: 3523 CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter) 3524 : CommandObjectParsed( 3525 interpreter, "renderscript kernel list", 3526 "Lists renderscript kernel names and associated script resources.", 3527 "renderscript kernel list", 3528 eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} 3529 3530 ~CommandObjectRenderScriptRuntimeKernelList() override = default; 3531 3532 bool DoExecute(Args &command, CommandReturnObject &result) override { 3533 RenderScriptRuntime *runtime = 3534 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3535 eLanguageTypeExtRenderScript); 3536 runtime->DumpKernels(result.GetOutputStream()); 3537 result.SetStatus(eReturnStatusSuccessFinishResult); 3538 return true; 3539 } 3540 }; 3541 3542 class CommandObjectRenderScriptRuntimeKernelBreakpointSet 3543 : public CommandObjectParsed { 3544 public: 3545 CommandObjectRenderScriptRuntimeKernelBreakpointSet( 3546 CommandInterpreter &interpreter) 3547 : CommandObjectParsed( 3548 interpreter, "renderscript kernel breakpoint set", 3549 "Sets a breakpoint on a renderscript kernel.", 3550 "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]", 3551 eCommandRequiresProcess | eCommandProcessMustBeLaunched | 3552 eCommandProcessMustBePaused), 3553 m_options() {} 3554 3555 ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default; 3556 3557 Options *GetOptions() override { return &m_options; } 3558 3559 class CommandOptions : public Options { 3560 public: 3561 CommandOptions() : Options() {} 3562 3563 ~CommandOptions() override = default; 3564 3565 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 3566 ExecutionContext *execution_context) override { 3567 Error error; 3568 const int short_option = m_getopt_table[option_idx].val; 3569 3570 switch (short_option) { 3571 case 'c': 3572 if (!ParseCoordinate(option_arg)) 3573 error.SetErrorStringWithFormat( 3574 "Couldn't parse coordinate '%s', should be in format 'x,y,z'.", 3575 option_arg); 3576 break; 3577 default: 3578 error.SetErrorStringWithFormat("unrecognized option '%c'", 3579 short_option); 3580 break; 3581 } 3582 return error; 3583 } 3584 3585 // -c takes an argument of the form 'num[,num][,num]'. 3586 // Where 'id_cstr' is this argument with the whitespace trimmed. 3587 // Missing coordinates are defaulted to zero. 3588 bool ParseCoordinate(const char *id_cstr) { 3589 RegularExpression regex; 3590 RegularExpression::Match regex_match(3); 3591 3592 bool matched = false; 3593 if (regex.Compile("^([0-9]+),([0-9]+),([0-9]+)$") && 3594 regex.Execute(id_cstr, ®ex_match)) 3595 matched = true; 3596 else if (regex.Compile("^([0-9]+),([0-9]+)$") && 3597 regex.Execute(id_cstr, ®ex_match)) 3598 matched = true; 3599 else if (regex.Compile("^([0-9]+)$") && 3600 regex.Execute(id_cstr, ®ex_match)) 3601 matched = true; 3602 for (uint32_t i = 0; i < 3; i++) { 3603 std::string group; 3604 if (regex_match.GetMatchAtIndex(id_cstr, i + 1, group)) 3605 m_coord[i] = (uint32_t)strtoul(group.c_str(), nullptr, 0); 3606 else 3607 m_coord[i] = 0; 3608 } 3609 return matched; 3610 } 3611 3612 void OptionParsingStarting(ExecutionContext *execution_context) override { 3613 // -1 means the -c option hasn't been set 3614 m_coord[0] = -1; 3615 m_coord[1] = -1; 3616 m_coord[2] = -1; 3617 } 3618 3619 const OptionDefinition *GetDefinitions() override { return g_option_table; } 3620 3621 static OptionDefinition g_option_table[]; 3622 std::array<int, 3> m_coord; 3623 }; 3624 3625 bool DoExecute(Args &command, CommandReturnObject &result) override { 3626 const size_t argc = command.GetArgumentCount(); 3627 if (argc < 1) { 3628 result.AppendErrorWithFormat( 3629 "'%s' takes 1 argument of kernel name, and an optional coordinate.", 3630 m_cmd_name.c_str()); 3631 result.SetStatus(eReturnStatusFailed); 3632 return false; 3633 } 3634 3635 RenderScriptRuntime *runtime = 3636 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3637 eLanguageTypeExtRenderScript); 3638 3639 Error error; 3640 runtime->PlaceBreakpointOnKernel( 3641 result.GetOutputStream(), command.GetArgumentAtIndex(0), 3642 m_options.m_coord, error, m_exe_ctx.GetTargetSP()); 3643 3644 if (error.Success()) { 3645 result.AppendMessage("Breakpoint(s) created"); 3646 result.SetStatus(eReturnStatusSuccessFinishResult); 3647 return true; 3648 } 3649 result.SetStatus(eReturnStatusFailed); 3650 result.AppendErrorWithFormat("Error: %s", error.AsCString()); 3651 return false; 3652 } 3653 3654 private: 3655 CommandOptions m_options; 3656 }; 3657 3658 OptionDefinition CommandObjectRenderScriptRuntimeKernelBreakpointSet:: 3659 CommandOptions::g_option_table[] = { 3660 {LLDB_OPT_SET_1, false, "coordinate", 'c', 3661 OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeValue, 3662 "Set a breakpoint on a single invocation of the kernel with specified " 3663 "coordinate.\n" 3664 "Coordinate takes the form 'x[,y][,z] where x,y,z are positive " 3665 "integers representing kernel dimensions. " 3666 "Any unset dimensions will be defaulted to zero."}, 3667 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; 3668 3669 class CommandObjectRenderScriptRuntimeKernelBreakpointAll 3670 : public CommandObjectParsed { 3671 public: 3672 CommandObjectRenderScriptRuntimeKernelBreakpointAll( 3673 CommandInterpreter &interpreter) 3674 : CommandObjectParsed( 3675 interpreter, "renderscript kernel breakpoint all", 3676 "Automatically sets a breakpoint on all renderscript kernels that " 3677 "are or will be loaded.\n" 3678 "Disabling option means breakpoints will no longer be set on any " 3679 "kernels loaded in the future, " 3680 "but does not remove currently set breakpoints.", 3681 "renderscript kernel breakpoint all <enable/disable>", 3682 eCommandRequiresProcess | eCommandProcessMustBeLaunched | 3683 eCommandProcessMustBePaused) {} 3684 3685 ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default; 3686 3687 bool DoExecute(Args &command, CommandReturnObject &result) override { 3688 const size_t argc = command.GetArgumentCount(); 3689 if (argc != 1) { 3690 result.AppendErrorWithFormat( 3691 "'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str()); 3692 result.SetStatus(eReturnStatusFailed); 3693 return false; 3694 } 3695 3696 RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 3697 m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3698 eLanguageTypeExtRenderScript)); 3699 3700 bool do_break = false; 3701 const char *argument = command.GetArgumentAtIndex(0); 3702 if (strcmp(argument, "enable") == 0) { 3703 do_break = true; 3704 result.AppendMessage("Breakpoints will be set on all kernels."); 3705 } else if (strcmp(argument, "disable") == 0) { 3706 do_break = false; 3707 result.AppendMessage("Breakpoints will not be set on any new kernels."); 3708 } else { 3709 result.AppendErrorWithFormat( 3710 "Argument must be either 'enable' or 'disable'"); 3711 result.SetStatus(eReturnStatusFailed); 3712 return false; 3713 } 3714 3715 runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP()); 3716 3717 result.SetStatus(eReturnStatusSuccessFinishResult); 3718 return true; 3719 } 3720 }; 3721 3722 class CommandObjectRenderScriptRuntimeKernelCoordinate 3723 : public CommandObjectParsed { 3724 public: 3725 CommandObjectRenderScriptRuntimeKernelCoordinate( 3726 CommandInterpreter &interpreter) 3727 : CommandObjectParsed( 3728 interpreter, "renderscript kernel coordinate", 3729 "Shows the (x,y,z) coordinate of the current kernel invocation.", 3730 "renderscript kernel coordinate", 3731 eCommandRequiresProcess | eCommandProcessMustBeLaunched | 3732 eCommandProcessMustBePaused) {} 3733 3734 ~CommandObjectRenderScriptRuntimeKernelCoordinate() override = default; 3735 3736 bool DoExecute(Args &command, CommandReturnObject &result) override { 3737 RSCoordinate coord{}; // Zero initialize array 3738 bool success = RenderScriptRuntime::GetKernelCoordinate( 3739 coord, m_exe_ctx.GetThreadPtr()); 3740 Stream &stream = result.GetOutputStream(); 3741 3742 if (success) { 3743 stream.Printf("Coordinate: (%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")", 3744 coord[0], coord[1], coord[2]); 3745 stream.EOL(); 3746 result.SetStatus(eReturnStatusSuccessFinishResult); 3747 } else { 3748 stream.Printf("Error: Coordinate could not be found."); 3749 stream.EOL(); 3750 result.SetStatus(eReturnStatusFailed); 3751 } 3752 return true; 3753 } 3754 }; 3755 3756 class CommandObjectRenderScriptRuntimeKernelBreakpoint 3757 : public CommandObjectMultiword { 3758 public: 3759 CommandObjectRenderScriptRuntimeKernelBreakpoint( 3760 CommandInterpreter &interpreter) 3761 : CommandObjectMultiword( 3762 interpreter, "renderscript kernel", 3763 "Commands that generate breakpoints on renderscript kernels.", 3764 nullptr) { 3765 LoadSubCommand( 3766 "set", 3767 CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet( 3768 interpreter))); 3769 LoadSubCommand( 3770 "all", 3771 CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll( 3772 interpreter))); 3773 } 3774 3775 ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default; 3776 }; 3777 3778 class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword { 3779 public: 3780 CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter) 3781 : CommandObjectMultiword(interpreter, "renderscript kernel", 3782 "Commands that deal with RenderScript kernels.", 3783 nullptr) { 3784 LoadSubCommand( 3785 "list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList( 3786 interpreter))); 3787 LoadSubCommand( 3788 "coordinate", 3789 CommandObjectSP( 3790 new CommandObjectRenderScriptRuntimeKernelCoordinate(interpreter))); 3791 LoadSubCommand( 3792 "breakpoint", 3793 CommandObjectSP( 3794 new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter))); 3795 } 3796 3797 ~CommandObjectRenderScriptRuntimeKernel() override = default; 3798 }; 3799 3800 class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed { 3801 public: 3802 CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter) 3803 : CommandObjectParsed(interpreter, "renderscript context dump", 3804 "Dumps renderscript context information.", 3805 "renderscript context dump", 3806 eCommandRequiresProcess | 3807 eCommandProcessMustBeLaunched) {} 3808 3809 ~CommandObjectRenderScriptRuntimeContextDump() override = default; 3810 3811 bool DoExecute(Args &command, CommandReturnObject &result) override { 3812 RenderScriptRuntime *runtime = 3813 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3814 eLanguageTypeExtRenderScript); 3815 runtime->DumpContexts(result.GetOutputStream()); 3816 result.SetStatus(eReturnStatusSuccessFinishResult); 3817 return true; 3818 } 3819 }; 3820 3821 class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword { 3822 public: 3823 CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter) 3824 : CommandObjectMultiword(interpreter, "renderscript context", 3825 "Commands that deal with RenderScript contexts.", 3826 nullptr) { 3827 LoadSubCommand( 3828 "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump( 3829 interpreter))); 3830 } 3831 3832 ~CommandObjectRenderScriptRuntimeContext() override = default; 3833 }; 3834 3835 class CommandObjectRenderScriptRuntimeAllocationDump 3836 : public CommandObjectParsed { 3837 public: 3838 CommandObjectRenderScriptRuntimeAllocationDump( 3839 CommandInterpreter &interpreter) 3840 : CommandObjectParsed(interpreter, "renderscript allocation dump", 3841 "Displays the contents of a particular allocation", 3842 "renderscript allocation dump <ID>", 3843 eCommandRequiresProcess | 3844 eCommandProcessMustBeLaunched), 3845 m_options() {} 3846 3847 ~CommandObjectRenderScriptRuntimeAllocationDump() override = default; 3848 3849 Options *GetOptions() override { return &m_options; } 3850 3851 class CommandOptions : public Options { 3852 public: 3853 CommandOptions() : Options() {} 3854 3855 ~CommandOptions() override = default; 3856 3857 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 3858 ExecutionContext *execution_context) override { 3859 Error error; 3860 const int short_option = m_getopt_table[option_idx].val; 3861 3862 switch (short_option) { 3863 case 'f': 3864 m_outfile.SetFile(option_arg, true); 3865 if (m_outfile.Exists()) { 3866 m_outfile.Clear(); 3867 error.SetErrorStringWithFormat("file already exists: '%s'", 3868 option_arg); 3869 } 3870 break; 3871 default: 3872 error.SetErrorStringWithFormat("unrecognized option '%c'", 3873 short_option); 3874 break; 3875 } 3876 return error; 3877 } 3878 3879 void OptionParsingStarting(ExecutionContext *execution_context) override { 3880 m_outfile.Clear(); 3881 } 3882 3883 const OptionDefinition *GetDefinitions() override { return g_option_table; } 3884 3885 static OptionDefinition g_option_table[]; 3886 FileSpec m_outfile; 3887 }; 3888 3889 bool DoExecute(Args &command, CommandReturnObject &result) override { 3890 const size_t argc = command.GetArgumentCount(); 3891 if (argc < 1) { 3892 result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. " 3893 "As well as an optional -f argument", 3894 m_cmd_name.c_str()); 3895 result.SetStatus(eReturnStatusFailed); 3896 return false; 3897 } 3898 3899 RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 3900 m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 3901 eLanguageTypeExtRenderScript)); 3902 3903 const char *id_cstr = command.GetArgumentAtIndex(0); 3904 bool convert_complete = false; 3905 const uint32_t id = 3906 StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 3907 if (!convert_complete) { 3908 result.AppendErrorWithFormat("invalid allocation id argument '%s'", 3909 id_cstr); 3910 result.SetStatus(eReturnStatusFailed); 3911 return false; 3912 } 3913 3914 Stream *output_strm = nullptr; 3915 StreamFile outfile_stream; 3916 const FileSpec &outfile_spec = 3917 m_options.m_outfile; // Dump allocation to file instead 3918 if (outfile_spec) { 3919 // Open output file 3920 char path[256]; 3921 outfile_spec.GetPath(path, sizeof(path)); 3922 if (outfile_stream.GetFile() 3923 .Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate) 3924 .Success()) { 3925 output_strm = &outfile_stream; 3926 result.GetOutputStream().Printf("Results written to '%s'", path); 3927 result.GetOutputStream().EOL(); 3928 } else { 3929 result.AppendErrorWithFormat("Couldn't open file '%s'", path); 3930 result.SetStatus(eReturnStatusFailed); 3931 return false; 3932 } 3933 } else 3934 output_strm = &result.GetOutputStream(); 3935 3936 assert(output_strm != nullptr); 3937 bool success = 3938 runtime->DumpAllocation(*output_strm, m_exe_ctx.GetFramePtr(), id); 3939 3940 if (success) 3941 result.SetStatus(eReturnStatusSuccessFinishResult); 3942 else 3943 result.SetStatus(eReturnStatusFailed); 3944 3945 return true; 3946 } 3947 3948 private: 3949 CommandOptions m_options; 3950 }; 3951 3952 OptionDefinition CommandObjectRenderScriptRuntimeAllocationDump:: 3953 CommandOptions::g_option_table[] = { 3954 {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, 3955 nullptr, nullptr, 0, eArgTypeFilename, 3956 "Print results to specified file instead of command line."}, 3957 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; 3958 3959 class CommandObjectRenderScriptRuntimeAllocationList 3960 : public CommandObjectParsed { 3961 public: 3962 CommandObjectRenderScriptRuntimeAllocationList( 3963 CommandInterpreter &interpreter) 3964 : CommandObjectParsed( 3965 interpreter, "renderscript allocation list", 3966 "List renderscript allocations and their information.", 3967 "renderscript allocation list", 3968 eCommandRequiresProcess | eCommandProcessMustBeLaunched), 3969 m_options() {} 3970 3971 ~CommandObjectRenderScriptRuntimeAllocationList() override = default; 3972 3973 Options *GetOptions() override { return &m_options; } 3974 3975 class CommandOptions : public Options { 3976 public: 3977 CommandOptions() : Options(), m_id(0) {} 3978 3979 ~CommandOptions() override = default; 3980 3981 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 3982 ExecutionContext *execution_context) override { 3983 Error error; 3984 const int short_option = m_getopt_table[option_idx].val; 3985 3986 switch (short_option) { 3987 case 'i': 3988 bool success; 3989 m_id = StringConvert::ToUInt32(option_arg, 0, 0, &success); 3990 if (!success) 3991 error.SetErrorStringWithFormat( 3992 "invalid integer value for option '%c'", short_option); 3993 break; 3994 default: 3995 error.SetErrorStringWithFormat("unrecognized option '%c'", 3996 short_option); 3997 break; 3998 } 3999 return error; 4000 } 4001 4002 void OptionParsingStarting(ExecutionContext *execution_context) override { 4003 m_id = 0; 4004 } 4005 4006 const OptionDefinition *GetDefinitions() override { return g_option_table; } 4007 4008 static OptionDefinition g_option_table[]; 4009 uint32_t m_id; 4010 }; 4011 4012 bool DoExecute(Args &command, CommandReturnObject &result) override { 4013 RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4014 m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4015 eLanguageTypeExtRenderScript)); 4016 runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(), 4017 m_options.m_id); 4018 result.SetStatus(eReturnStatusSuccessFinishResult); 4019 return true; 4020 } 4021 4022 private: 4023 CommandOptions m_options; 4024 }; 4025 4026 OptionDefinition CommandObjectRenderScriptRuntimeAllocationList:: 4027 CommandOptions::g_option_table[] = { 4028 {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument, 4029 nullptr, nullptr, 0, eArgTypeIndex, 4030 "Only show details of a single allocation with specified id."}, 4031 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; 4032 4033 class CommandObjectRenderScriptRuntimeAllocationLoad 4034 : public CommandObjectParsed { 4035 public: 4036 CommandObjectRenderScriptRuntimeAllocationLoad( 4037 CommandInterpreter &interpreter) 4038 : CommandObjectParsed( 4039 interpreter, "renderscript allocation load", 4040 "Loads renderscript allocation contents from a file.", 4041 "renderscript allocation load <ID> <filename>", 4042 eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} 4043 4044 ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default; 4045 4046 bool DoExecute(Args &command, CommandReturnObject &result) override { 4047 const size_t argc = command.GetArgumentCount(); 4048 if (argc != 2) { 4049 result.AppendErrorWithFormat( 4050 "'%s' takes 2 arguments, an allocation ID and filename to read from.", 4051 m_cmd_name.c_str()); 4052 result.SetStatus(eReturnStatusFailed); 4053 return false; 4054 } 4055 4056 RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4057 m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4058 eLanguageTypeExtRenderScript)); 4059 4060 const char *id_cstr = command.GetArgumentAtIndex(0); 4061 bool convert_complete = false; 4062 const uint32_t id = 4063 StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 4064 if (!convert_complete) { 4065 result.AppendErrorWithFormat("invalid allocation id argument '%s'", 4066 id_cstr); 4067 result.SetStatus(eReturnStatusFailed); 4068 return false; 4069 } 4070 4071 const char *filename = command.GetArgumentAtIndex(1); 4072 bool success = runtime->LoadAllocation(result.GetOutputStream(), id, 4073 filename, m_exe_ctx.GetFramePtr()); 4074 4075 if (success) 4076 result.SetStatus(eReturnStatusSuccessFinishResult); 4077 else 4078 result.SetStatus(eReturnStatusFailed); 4079 4080 return true; 4081 } 4082 }; 4083 4084 class CommandObjectRenderScriptRuntimeAllocationSave 4085 : public CommandObjectParsed { 4086 public: 4087 CommandObjectRenderScriptRuntimeAllocationSave( 4088 CommandInterpreter &interpreter) 4089 : CommandObjectParsed(interpreter, "renderscript allocation save", 4090 "Write renderscript allocation contents to a file.", 4091 "renderscript allocation save <ID> <filename>", 4092 eCommandRequiresProcess | 4093 eCommandProcessMustBeLaunched) {} 4094 4095 ~CommandObjectRenderScriptRuntimeAllocationSave() override = default; 4096 4097 bool DoExecute(Args &command, CommandReturnObject &result) override { 4098 const size_t argc = command.GetArgumentCount(); 4099 if (argc != 2) { 4100 result.AppendErrorWithFormat( 4101 "'%s' takes 2 arguments, an allocation ID and filename to read from.", 4102 m_cmd_name.c_str()); 4103 result.SetStatus(eReturnStatusFailed); 4104 return false; 4105 } 4106 4107 RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4108 m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4109 eLanguageTypeExtRenderScript)); 4110 4111 const char *id_cstr = command.GetArgumentAtIndex(0); 4112 bool convert_complete = false; 4113 const uint32_t id = 4114 StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 4115 if (!convert_complete) { 4116 result.AppendErrorWithFormat("invalid allocation id argument '%s'", 4117 id_cstr); 4118 result.SetStatus(eReturnStatusFailed); 4119 return false; 4120 } 4121 4122 const char *filename = command.GetArgumentAtIndex(1); 4123 bool success = runtime->SaveAllocation(result.GetOutputStream(), id, 4124 filename, m_exe_ctx.GetFramePtr()); 4125 4126 if (success) 4127 result.SetStatus(eReturnStatusSuccessFinishResult); 4128 else 4129 result.SetStatus(eReturnStatusFailed); 4130 4131 return true; 4132 } 4133 }; 4134 4135 class CommandObjectRenderScriptRuntimeAllocationRefresh 4136 : public CommandObjectParsed { 4137 public: 4138 CommandObjectRenderScriptRuntimeAllocationRefresh( 4139 CommandInterpreter &interpreter) 4140 : CommandObjectParsed(interpreter, "renderscript allocation refresh", 4141 "Recomputes the details of all allocations.", 4142 "renderscript allocation refresh", 4143 eCommandRequiresProcess | 4144 eCommandProcessMustBeLaunched) {} 4145 4146 ~CommandObjectRenderScriptRuntimeAllocationRefresh() override = default; 4147 4148 bool DoExecute(Args &command, CommandReturnObject &result) override { 4149 RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4150 m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4151 eLanguageTypeExtRenderScript)); 4152 4153 bool success = runtime->RecomputeAllAllocations(result.GetOutputStream(), 4154 m_exe_ctx.GetFramePtr()); 4155 4156 if (success) { 4157 result.SetStatus(eReturnStatusSuccessFinishResult); 4158 return true; 4159 } else { 4160 result.SetStatus(eReturnStatusFailed); 4161 return false; 4162 } 4163 } 4164 }; 4165 4166 class CommandObjectRenderScriptRuntimeAllocation 4167 : public CommandObjectMultiword { 4168 public: 4169 CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter) 4170 : CommandObjectMultiword( 4171 interpreter, "renderscript allocation", 4172 "Commands that deal with RenderScript allocations.", nullptr) { 4173 LoadSubCommand( 4174 "list", 4175 CommandObjectSP( 4176 new CommandObjectRenderScriptRuntimeAllocationList(interpreter))); 4177 LoadSubCommand( 4178 "dump", 4179 CommandObjectSP( 4180 new CommandObjectRenderScriptRuntimeAllocationDump(interpreter))); 4181 LoadSubCommand( 4182 "save", 4183 CommandObjectSP( 4184 new CommandObjectRenderScriptRuntimeAllocationSave(interpreter))); 4185 LoadSubCommand( 4186 "load", 4187 CommandObjectSP( 4188 new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter))); 4189 LoadSubCommand( 4190 "refresh", 4191 CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationRefresh( 4192 interpreter))); 4193 } 4194 4195 ~CommandObjectRenderScriptRuntimeAllocation() override = default; 4196 }; 4197 4198 class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed { 4199 public: 4200 CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter) 4201 : CommandObjectParsed(interpreter, "renderscript status", 4202 "Displays current RenderScript runtime status.", 4203 "renderscript status", 4204 eCommandRequiresProcess | 4205 eCommandProcessMustBeLaunched) {} 4206 4207 ~CommandObjectRenderScriptRuntimeStatus() override = default; 4208 4209 bool DoExecute(Args &command, CommandReturnObject &result) override { 4210 RenderScriptRuntime *runtime = 4211 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( 4212 eLanguageTypeExtRenderScript); 4213 runtime->Status(result.GetOutputStream()); 4214 result.SetStatus(eReturnStatusSuccessFinishResult); 4215 return true; 4216 } 4217 }; 4218 4219 class CommandObjectRenderScriptRuntime : public CommandObjectMultiword { 4220 public: 4221 CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter) 4222 : CommandObjectMultiword( 4223 interpreter, "renderscript", 4224 "Commands for operating on the RenderScript runtime.", 4225 "renderscript <subcommand> [<subcommand-options>]") { 4226 LoadSubCommand( 4227 "module", CommandObjectSP( 4228 new CommandObjectRenderScriptRuntimeModule(interpreter))); 4229 LoadSubCommand( 4230 "status", CommandObjectSP( 4231 new CommandObjectRenderScriptRuntimeStatus(interpreter))); 4232 LoadSubCommand( 4233 "kernel", CommandObjectSP( 4234 new CommandObjectRenderScriptRuntimeKernel(interpreter))); 4235 LoadSubCommand("context", 4236 CommandObjectSP(new CommandObjectRenderScriptRuntimeContext( 4237 interpreter))); 4238 LoadSubCommand( 4239 "allocation", 4240 CommandObjectSP( 4241 new CommandObjectRenderScriptRuntimeAllocation(interpreter))); 4242 } 4243 4244 ~CommandObjectRenderScriptRuntime() override = default; 4245 }; 4246 4247 void RenderScriptRuntime::Initiate() { assert(!m_initiated); } 4248 4249 RenderScriptRuntime::RenderScriptRuntime(Process *process) 4250 : lldb_private::CPPLanguageRuntime(process), m_initiated(false), 4251 m_debuggerPresentFlagged(false), m_breakAllKernels(false), 4252 m_ir_passes(nullptr) { 4253 ModulesDidLoad(process->GetTarget().GetImages()); 4254 } 4255 4256 lldb::CommandObjectSP RenderScriptRuntime::GetCommandObject( 4257 lldb_private::CommandInterpreter &interpreter) { 4258 return CommandObjectSP(new CommandObjectRenderScriptRuntime(interpreter)); 4259 } 4260 4261 RenderScriptRuntime::~RenderScriptRuntime() = default; 4262