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