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 // Used to index expression format strings 1378 enum ExpressionStrings 1379 { 1380 eExprGetOffsetPtr = 0, 1381 eExprAllocGetType, 1382 eExprTypeDimX, 1383 eExprTypeDimY, 1384 eExprTypeDimZ, 1385 eExprTypeElemPtr, 1386 eExprElementType, 1387 eExprElementKind, 1388 eExprElementVec, 1389 eExprElementFieldCount, 1390 eExprSubelementsId, 1391 eExprSubelementsName, 1392 eExprSubelementsArrSize 1393 }; 1394 1395 // Format strings containing the expressions we may need to evaluate. 1396 const char runtimeExpressions[][256] = 1397 { 1398 // Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap) 1399 "(int*)_Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocationCubemapFace(0x%lx, %u, %u, %u, 0, 0)", 1400 1401 // Type* rsaAllocationGetType(Context*, Allocation*) 1402 "(void*)rsaAllocationGetType(0x%lx, 0x%lx)", 1403 1404 // rsaTypeGetNativeData(Context*, Type*, void* typeData, size) 1405 // Pack the data in the following way mHal.state.dimX; mHal.state.dimY; mHal.state.dimZ; 1406 // mHal.state.lodCount; mHal.state.faces; mElement; into typeData 1407 // Need to specify 32 or 64 bit for uint_t since this differs between devices 1408 "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[0]", // X dim 1409 "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[1]", // Y dim 1410 "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[2]", // Z dim 1411 "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[5]", // Element ptr 1412 1413 // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size) 1414 // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into elemData 1415 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[0]", // Type 1416 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[1]", // Kind 1417 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[3]", // Vector Size 1418 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[4]", // Field Count 1419 1420 // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t *ids, const char **names, 1421 // size_t *arraySizes, uint32_t dataSize) 1422 // Needed for Allocations of structs to gather details about fields/Subelements 1423 "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];" 1424 "(void*)rsaElementGetSubElements(0x%lx, 0x%lx, ids, names, arr_size, %u); ids[%u]", // Element* of field 1425 1426 "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];" 1427 "(void*)rsaElementGetSubElements(0x%lx, 0x%lx, ids, names, arr_size, %u); names[%u]", // Name of field 1428 1429 "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];" 1430 "(void*)rsaElementGetSubElements(0x%lx, 0x%lx, ids, names, arr_size, %u); arr_size[%u]" // Array size of field 1431 }; 1432 1433 // JITs the RS runtime for the internal data pointer of an allocation. 1434 // Is passed x,y,z coordinates for the pointer to a specific element. 1435 // Then sets the data_ptr member in Allocation with the result. 1436 // Returns true on success, false otherwise 1437 bool 1438 RenderScriptRuntime::JITDataPointer(AllocationDetails* allocation, StackFrame* frame_ptr, 1439 unsigned int x, unsigned int y, unsigned int z) 1440 { 1441 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1442 1443 if (!allocation->address.isValid()) 1444 { 1445 if (log) 1446 log->Printf("RenderScriptRuntime::JITDataPointer - Failed to find allocation details"); 1447 return false; 1448 } 1449 1450 const char* expr_cstr = runtimeExpressions[eExprGetOffsetPtr]; 1451 const int max_expr_size = 512; // Max expression size 1452 char buffer[max_expr_size]; 1453 1454 int chars_written = snprintf(buffer, max_expr_size, expr_cstr, *allocation->address.get(), x, y, z); 1455 if (chars_written < 0) 1456 { 1457 if (log) 1458 log->Printf("RenderScriptRuntime::JITDataPointer - Encoding error in snprintf()"); 1459 return false; 1460 } 1461 else if (chars_written >= max_expr_size) 1462 { 1463 if (log) 1464 log->Printf("RenderScriptRuntime::JITDataPointer - Expression too long"); 1465 return false; 1466 } 1467 1468 uint64_t result = 0; 1469 if (!EvalRSExpression(buffer, frame_ptr, &result)) 1470 return false; 1471 1472 addr_t mem_ptr = static_cast<lldb::addr_t>(result); 1473 allocation->data_ptr = mem_ptr; 1474 1475 return true; 1476 } 1477 1478 // JITs the RS runtime for the internal pointer to the RS Type of an allocation 1479 // Then sets the type_ptr member in Allocation with the result. 1480 // Returns true on success, false otherwise 1481 bool 1482 RenderScriptRuntime::JITTypePointer(AllocationDetails* allocation, StackFrame* frame_ptr) 1483 { 1484 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1485 1486 if (!allocation->address.isValid() || !allocation->context.isValid()) 1487 { 1488 if (log) 1489 log->Printf("RenderScriptRuntime::JITTypePointer - Failed to find allocation details"); 1490 return false; 1491 } 1492 1493 const char* expr_cstr = runtimeExpressions[eExprAllocGetType]; 1494 const int max_expr_size = 512; // Max expression size 1495 char buffer[max_expr_size]; 1496 1497 int chars_written = snprintf(buffer, max_expr_size, expr_cstr, *allocation->context.get(), *allocation->address.get()); 1498 if (chars_written < 0) 1499 { 1500 if (log) 1501 log->Printf("RenderScriptRuntime::JITDataPointer - Encoding error in snprintf()"); 1502 return false; 1503 } 1504 else if (chars_written >= max_expr_size) 1505 { 1506 if (log) 1507 log->Printf("RenderScriptRuntime::JITTypePointer - Expression too long"); 1508 return false; 1509 } 1510 1511 uint64_t result = 0; 1512 if (!EvalRSExpression(buffer, frame_ptr, &result)) 1513 return false; 1514 1515 addr_t type_ptr = static_cast<lldb::addr_t>(result); 1516 allocation->type_ptr = type_ptr; 1517 1518 return true; 1519 } 1520 1521 // JITs the RS runtime for information about the dimensions and type of an allocation 1522 // Then sets dimension and element_ptr members in Allocation with the result. 1523 // Returns true on success, false otherwise 1524 bool 1525 RenderScriptRuntime::JITTypePacked(AllocationDetails* allocation, StackFrame* frame_ptr) 1526 { 1527 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1528 1529 if (!allocation->type_ptr.isValid() || !allocation->context.isValid()) 1530 { 1531 if (log) 1532 log->Printf("RenderScriptRuntime::JITTypePacked - Failed to find allocation details"); 1533 return false; 1534 } 1535 1536 // Expression is different depending on if device is 32 or 64 bit 1537 uint32_t archByteSize = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 1538 const unsigned int bits = archByteSize == 4 ? 32 : 64; 1539 1540 // We want 4 elements from packed data 1541 const unsigned int num_exprs = 4; 1542 assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1) && "Invalid number of expressions"); 1543 1544 const int max_expr_size = 512; // Max expression size 1545 char buffer[num_exprs][max_expr_size]; 1546 uint64_t results[num_exprs]; 1547 1548 for (unsigned int i = 0; i < num_exprs; ++i) 1549 { 1550 int chars_written = snprintf(buffer[i], max_expr_size, runtimeExpressions[eExprTypeDimX + i], bits, 1551 *allocation->context.get(), *allocation->type_ptr.get()); 1552 if (chars_written < 0) 1553 { 1554 if (log) 1555 log->Printf("RenderScriptRuntime::JITDataPointer - Encoding error in snprintf()"); 1556 return false; 1557 } 1558 else if (chars_written >= max_expr_size) 1559 { 1560 if (log) 1561 log->Printf("RenderScriptRuntime::JITTypePacked - Expression too long"); 1562 return false; 1563 } 1564 1565 // Perform expression evaluation 1566 if (!EvalRSExpression(buffer[i], frame_ptr, &results[i])) 1567 return false; 1568 } 1569 1570 // Assign results to allocation members 1571 AllocationDetails::Dimension dims; 1572 dims.dim_1 = static_cast<uint32_t>(results[0]); 1573 dims.dim_2 = static_cast<uint32_t>(results[1]); 1574 dims.dim_3 = static_cast<uint32_t>(results[2]); 1575 allocation->dimension = dims; 1576 1577 addr_t elem_ptr = static_cast<lldb::addr_t>(results[3]); 1578 allocation->element.element_ptr = elem_ptr; 1579 1580 if (log) 1581 log->Printf("RenderScriptRuntime::JITTypePacked - dims (%u, %u, %u) Element*: 0x%" PRIx64, 1582 dims.dim_1, dims.dim_2, dims.dim_3, elem_ptr); 1583 1584 return true; 1585 } 1586 1587 // JITs the RS runtime for information about the Element of an allocation 1588 // Then sets type, type_vec_size, field_count and type_kind members in Element with the result. 1589 // Returns true on success, false otherwise 1590 bool 1591 RenderScriptRuntime::JITElementPacked(Element& elem, const lldb::addr_t context, StackFrame* frame_ptr) 1592 { 1593 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1594 1595 if (!elem.element_ptr.isValid()) 1596 { 1597 if (log) 1598 log->Printf("RenderScriptRuntime::JITElementPacked - Failed to find allocation details"); 1599 return false; 1600 } 1601 1602 // We want 4 elements from packed data 1603 const unsigned int num_exprs = 4; 1604 assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1) && "Invalid number of expressions"); 1605 1606 const int max_expr_size = 512; // Max expression size 1607 char buffer[num_exprs][max_expr_size]; 1608 uint64_t results[num_exprs]; 1609 1610 for (unsigned int i = 0; i < num_exprs; i++) 1611 { 1612 int chars_written = snprintf(buffer[i], max_expr_size, runtimeExpressions[eExprElementType + i], context, *elem.element_ptr.get()); 1613 if (chars_written < 0) 1614 { 1615 if (log) 1616 log->Printf("RenderScriptRuntime::JITElementPacked - Encoding error in snprintf()"); 1617 return false; 1618 } 1619 else if (chars_written >= max_expr_size) 1620 { 1621 if (log) 1622 log->Printf("RenderScriptRuntime::JITElementPacked - Expression too long"); 1623 return false; 1624 } 1625 1626 // Perform expression evaluation 1627 if (!EvalRSExpression(buffer[i], frame_ptr, &results[i])) 1628 return false; 1629 } 1630 1631 // Assign results to allocation members 1632 elem.type = static_cast<RenderScriptRuntime::Element::DataType>(results[0]); 1633 elem.type_kind = static_cast<RenderScriptRuntime::Element::DataKind>(results[1]); 1634 elem.type_vec_size = static_cast<uint32_t>(results[2]); 1635 elem.field_count = static_cast<uint32_t>(results[3]); 1636 1637 if (log) 1638 log->Printf("RenderScriptRuntime::JITElementPacked - data type %u, pixel type %u, vector size %u, field count %u", 1639 *elem.type.get(), *elem.type_kind.get(), *elem.type_vec_size.get(), *elem.field_count.get()); 1640 1641 // If this Element has subelements then JIT rsaElementGetSubElements() for details about its fields 1642 if (*elem.field_count.get() > 0 && !JITSubelements(elem, context, frame_ptr)) 1643 return false; 1644 1645 return true; 1646 } 1647 1648 // JITs the RS runtime for information about the subelements/fields of a struct allocation 1649 // This is necessary for infering the struct type so we can pretty print the allocation's contents. 1650 // Returns true on success, false otherwise 1651 bool 1652 RenderScriptRuntime::JITSubelements(Element& elem, const lldb::addr_t context, StackFrame* frame_ptr) 1653 { 1654 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1655 1656 if (!elem.element_ptr.isValid() || !elem.field_count.isValid()) 1657 { 1658 if (log) 1659 log->Printf("RenderScriptRuntime::JITSubelements - Failed to find allocation details"); 1660 return false; 1661 } 1662 1663 const short num_exprs = 3; 1664 assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1) && "Invalid number of expressions"); 1665 1666 const int max_expr_size = 512; // Max expression size 1667 char expr_buffer[max_expr_size]; 1668 uint64_t results; 1669 1670 // Iterate over struct fields. 1671 const uint32_t field_count = *elem.field_count.get(); 1672 for (unsigned int field_index = 0; field_index < field_count; ++field_index) 1673 { 1674 Element child; 1675 for (unsigned int expr_index = 0; expr_index < num_exprs; ++expr_index) 1676 { 1677 int chars_written = snprintf(expr_buffer, max_expr_size, runtimeExpressions[eExprSubelementsId + expr_index], 1678 field_count, field_count, field_count, 1679 context, *elem.element_ptr.get(), field_count, field_index); 1680 if (chars_written < 0) 1681 { 1682 if (log) 1683 log->Printf("RenderScriptRuntime::JITSubelements - Encoding error in snprintf()"); 1684 return false; 1685 } 1686 else if (chars_written >= max_expr_size) 1687 { 1688 if (log) 1689 log->Printf("RenderScriptRuntime::JITSubelements - Expression too long"); 1690 return false; 1691 } 1692 1693 // Perform expression evaluation 1694 if (!EvalRSExpression(expr_buffer, frame_ptr, &results)) 1695 return false; 1696 1697 if (log) 1698 log->Printf("RenderScriptRuntime::JITSubelements - Expr result 0x%" PRIx64, results); 1699 1700 switch(expr_index) 1701 { 1702 case 0: // Element* of child 1703 child.element_ptr = static_cast<addr_t>(results); 1704 break; 1705 case 1: // Name of child 1706 { 1707 lldb::addr_t address = static_cast<addr_t>(results); 1708 Error err; 1709 std::string name; 1710 GetProcess()->ReadCStringFromMemory(address, name, err); 1711 if (!err.Fail()) 1712 child.type_name = ConstString(name); 1713 else 1714 { 1715 if (log) 1716 log->Printf("RenderScriptRuntime::JITSubelements - Warning: Couldn't read field name"); 1717 } 1718 break; 1719 } 1720 case 2: // Array size of child 1721 child.array_size = static_cast<uint32_t>(results); 1722 break; 1723 } 1724 } 1725 1726 // We need to recursively JIT each Element field of the struct since 1727 // structs can be nested inside structs. 1728 if (!JITElementPacked(child, context, frame_ptr)) 1729 return false; 1730 elem.children.push_back(child); 1731 } 1732 1733 // Try to infer the name of the struct type so we can pretty print the allocation contents. 1734 FindStructTypeName(elem, frame_ptr); 1735 1736 return true; 1737 } 1738 1739 // JITs the RS runtime for the address of the last element in the allocation. 1740 // The `elem_size` paramter represents the size of a single element, including padding. 1741 // Which is needed as an offset from the last element pointer. 1742 // Using this offset minus the starting address we can calculate the size of the allocation. 1743 // Returns true on success, false otherwise 1744 bool 1745 RenderScriptRuntime::JITAllocationSize(AllocationDetails* allocation, StackFrame* frame_ptr) 1746 { 1747 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1748 1749 if (!allocation->address.isValid() || !allocation->dimension.isValid() 1750 || !allocation->data_ptr.isValid() || !allocation->element.datum_size.isValid()) 1751 { 1752 if (log) 1753 log->Printf("RenderScriptRuntime::JITAllocationSize - Failed to find allocation details"); 1754 return false; 1755 } 1756 1757 // Find dimensions 1758 unsigned int dim_x = allocation->dimension.get()->dim_1; 1759 unsigned int dim_y = allocation->dimension.get()->dim_2; 1760 unsigned int dim_z = allocation->dimension.get()->dim_3; 1761 1762 // Our plan of jitting the last element address doesn't seem to work for struct Allocations 1763 // Instead try to infer the size ourselves without any inter element padding. 1764 if (allocation->element.children.size() > 0) 1765 { 1766 if (dim_x == 0) dim_x = 1; 1767 if (dim_y == 0) dim_y = 1; 1768 if (dim_z == 0) dim_z = 1; 1769 1770 allocation->size = dim_x * dim_y * dim_z * *allocation->element.datum_size.get(); 1771 1772 if (log) 1773 log->Printf("RenderScriptRuntime::JITAllocationSize - Infered size of struct allocation %u", *allocation->size.get()); 1774 1775 return true; 1776 } 1777 1778 const char* expr_cstr = runtimeExpressions[eExprGetOffsetPtr]; 1779 const int max_expr_size = 512; 1780 char buffer[max_expr_size]; 1781 1782 // Calculate last element 1783 dim_x = dim_x == 0 ? 0 : dim_x - 1; 1784 dim_y = dim_y == 0 ? 0 : dim_y - 1; 1785 dim_z = dim_z == 0 ? 0 : dim_z - 1; 1786 1787 int chars_written = snprintf(buffer, max_expr_size, expr_cstr, *allocation->address.get(), 1788 dim_x, dim_y, dim_z); 1789 if (chars_written < 0) 1790 { 1791 if (log) 1792 log->Printf("RenderScriptRuntime::JITAllocationSize - Encoding error in snprintf()"); 1793 return false; 1794 } 1795 else if (chars_written >= max_expr_size) 1796 { 1797 if (log) 1798 log->Printf("RenderScriptRuntime::JITAllocationSize - Expression too long"); 1799 return false; 1800 } 1801 1802 uint64_t result = 0; 1803 if (!EvalRSExpression(buffer, frame_ptr, &result)) 1804 return false; 1805 1806 addr_t mem_ptr = static_cast<lldb::addr_t>(result); 1807 // Find pointer to last element and add on size of an element 1808 allocation->size = static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()) + *allocation->element.datum_size.get(); 1809 1810 return true; 1811 } 1812 1813 // JITs the RS runtime for information about the stride between rows in the allocation. 1814 // This is done to detect padding, since allocated memory is 16-byte aligned. 1815 // Returns true on success, false otherwise 1816 bool 1817 RenderScriptRuntime::JITAllocationStride(AllocationDetails* allocation, StackFrame* frame_ptr) 1818 { 1819 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1820 1821 if (!allocation->address.isValid() || !allocation->data_ptr.isValid()) 1822 { 1823 if (log) 1824 log->Printf("RenderScriptRuntime::JITAllocationStride - Failed to find allocation details"); 1825 return false; 1826 } 1827 1828 const char* expr_cstr = runtimeExpressions[eExprGetOffsetPtr]; 1829 const int max_expr_size = 512; // Max expression size 1830 char buffer[max_expr_size]; 1831 1832 int chars_written = snprintf(buffer, max_expr_size, expr_cstr, *allocation->address.get(), 1833 0, 1, 0); 1834 if (chars_written < 0) 1835 { 1836 if (log) 1837 log->Printf("RenderScriptRuntime::JITAllocationStride - Encoding error in snprintf()"); 1838 return false; 1839 } 1840 else if (chars_written >= max_expr_size) 1841 { 1842 if (log) 1843 log->Printf("RenderScriptRuntime::JITAllocationStride - Expression too long"); 1844 return false; 1845 } 1846 1847 uint64_t result = 0; 1848 if (!EvalRSExpression(buffer, frame_ptr, &result)) 1849 return false; 1850 1851 addr_t mem_ptr = static_cast<lldb::addr_t>(result); 1852 allocation->stride = static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()); 1853 1854 return true; 1855 } 1856 1857 // JIT all the current runtime info regarding an allocation 1858 bool 1859 RenderScriptRuntime::RefreshAllocation(AllocationDetails* allocation, StackFrame* frame_ptr) 1860 { 1861 // GetOffsetPointer() 1862 if (!JITDataPointer(allocation, frame_ptr)) 1863 return false; 1864 1865 // rsaAllocationGetType() 1866 if (!JITTypePointer(allocation, frame_ptr)) 1867 return false; 1868 1869 // rsaTypeGetNativeData() 1870 if (!JITTypePacked(allocation, frame_ptr)) 1871 return false; 1872 1873 // rsaElementGetNativeData() 1874 if (!JITElementPacked(allocation->element, *allocation->context.get(), frame_ptr)) 1875 return false; 1876 1877 // Sets the datum_size member in Element 1878 SetElementSize(allocation->element); 1879 1880 // Use GetOffsetPointer() to infer size of the allocation 1881 if (!JITAllocationSize(allocation, frame_ptr)) 1882 return false; 1883 1884 return true; 1885 } 1886 1887 // Function attempts to set the type_name member of the paramaterised Element object. 1888 // This string should be the name of the struct type the Element represents. 1889 // We need this string for pretty printing the Element to users. 1890 void 1891 RenderScriptRuntime::FindStructTypeName(Element& elem, StackFrame* frame_ptr) 1892 { 1893 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1894 1895 if (!elem.type_name.IsEmpty()) // Name already set 1896 return; 1897 else 1898 elem.type_name = Element::GetFallbackStructName(); // Default type name if we don't succeed 1899 1900 // Find all the global variables from the script rs modules 1901 VariableList variable_list; 1902 for (auto module_sp : m_rsmodules) 1903 module_sp->m_module->FindGlobalVariables(RegularExpression("."), true, UINT32_MAX, variable_list); 1904 1905 // Iterate over all the global variables looking for one with a matching type to the Element. 1906 // We make the assumption a match exists since there needs to be a global variable to reflect the 1907 // struct type back into java host code. 1908 for (uint32_t var_index = 0; var_index < variable_list.GetSize(); ++var_index) 1909 { 1910 const VariableSP var_sp(variable_list.GetVariableAtIndex(var_index)); 1911 if (!var_sp) 1912 continue; 1913 1914 ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp); 1915 if (!valobj_sp) 1916 continue; 1917 1918 // Find the number of variable fields. 1919 // If it has no fields, or more fields than our Element, then it can't be the struct we're looking for. 1920 // Don't check for equality since RS can add extra struct members for padding. 1921 size_t num_children = valobj_sp->GetNumChildren(); 1922 if (num_children > elem.children.size() || num_children == 0) 1923 continue; 1924 1925 // Iterate over children looking for members with matching field names. 1926 // If all the field names match, this is likely the struct we want. 1927 // 1928 // TODO: This could be made more robust by also checking children data sizes, or array size 1929 bool found = true; 1930 for (size_t child_index = 0; child_index < num_children; ++child_index) 1931 { 1932 ValueObjectSP child = valobj_sp->GetChildAtIndex(child_index, true); 1933 if (!child || (child->GetName() != elem.children[child_index].type_name)) 1934 { 1935 found = false; 1936 break; 1937 } 1938 } 1939 1940 // RS can add extra struct members for padding in the format '#rs_padding_[0-9]+' 1941 if (found && num_children < elem.children.size()) 1942 { 1943 const unsigned int size_diff = elem.children.size() - num_children; 1944 if (log) 1945 log->Printf("RenderScriptRuntime::FindStructTypeName - %u padding struct entries", size_diff); 1946 1947 for (unsigned int padding_index = 0; padding_index < size_diff; ++padding_index) 1948 { 1949 const ConstString& name = elem.children[num_children + padding_index].type_name; 1950 if (strcmp(name.AsCString(), "#rs_padding") < 0) 1951 found = false; 1952 } 1953 } 1954 1955 // We've found a global var with matching type 1956 if (found) 1957 { 1958 // Dereference since our Element type isn't a pointer. 1959 if (valobj_sp->IsPointerType()) 1960 { 1961 Error err; 1962 ValueObjectSP deref_valobj = valobj_sp->Dereference(err); 1963 if (!err.Fail()) 1964 valobj_sp = deref_valobj; 1965 } 1966 1967 // Save name of variable in Element. 1968 elem.type_name = valobj_sp->GetTypeName(); 1969 if (log) 1970 log->Printf("RenderScriptRuntime::FindStructTypeName - Element name set to %s", elem.type_name.AsCString()); 1971 1972 return; 1973 } 1974 } 1975 } 1976 1977 // Function sets the datum_size member of Element. Representing the size of a single instance including padding. 1978 // Assumes the relevant allocation information has already been jitted. 1979 void 1980 RenderScriptRuntime::SetElementSize(Element& elem) 1981 { 1982 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1983 const Element::DataType type = *elem.type.get(); 1984 assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT 1985 && "Invalid allocation type"); 1986 1987 const unsigned int vec_size = *elem.type_vec_size.get(); 1988 unsigned int data_size = 0; 1989 unsigned int padding = 0; 1990 1991 // Element is of a struct type, calculate size recursively. 1992 if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) 1993 { 1994 for (Element& child : elem.children) 1995 { 1996 SetElementSize(child); 1997 const unsigned int array_size = child.array_size.isValid() ? *child.array_size.get() : 1; 1998 data_size += *child.datum_size.get() * array_size; 1999 } 2000 } 2001 else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 || type == Element::RS_TYPE_UNSIGNED_5_5_5_1 || 2002 type == Element::RS_TYPE_UNSIGNED_4_4_4_4) // These have been packed already 2003 { 2004 data_size = AllocationDetails::RSTypeToFormat[type][eElementSize]; 2005 } 2006 else if (type < Element::RS_TYPE_ELEMENT) 2007 { 2008 data_size = vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize]; 2009 if (vec_size == 3) 2010 padding = AllocationDetails::RSTypeToFormat[type][eElementSize]; 2011 } 2012 else 2013 data_size = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 2014 2015 elem.padding = padding; 2016 elem.datum_size = data_size + padding; 2017 if (log) 2018 log->Printf("RenderScriptRuntime::SetElementSize - element size set to %u", data_size + padding); 2019 } 2020 2021 // Given an allocation, this function copies the allocation contents from device into a buffer on the heap. 2022 // Returning a shared pointer to the buffer containing the data. 2023 std::shared_ptr<uint8_t> 2024 RenderScriptRuntime::GetAllocationData(AllocationDetails* allocation, StackFrame* frame_ptr) 2025 { 2026 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2027 2028 // JIT all the allocation details 2029 if (allocation->shouldRefresh()) 2030 { 2031 if (log) 2032 log->Printf("RenderScriptRuntime::GetAllocationData - Allocation details not calculated yet, jitting info"); 2033 2034 if (!RefreshAllocation(allocation, frame_ptr)) 2035 { 2036 if (log) 2037 log->Printf("RenderScriptRuntime::GetAllocationData - Couldn't JIT allocation details"); 2038 return nullptr; 2039 } 2040 } 2041 2042 assert(allocation->data_ptr.isValid() && allocation->element.type.isValid() && allocation->element.type_vec_size.isValid() 2043 && allocation->size.isValid() && "Allocation information not available"); 2044 2045 // Allocate a buffer to copy data into 2046 const unsigned int size = *allocation->size.get(); 2047 std::shared_ptr<uint8_t> buffer(new uint8_t[size]); 2048 if (!buffer) 2049 { 2050 if (log) 2051 log->Printf("RenderScriptRuntime::GetAllocationData - Couldn't allocate a %u byte buffer", size); 2052 return nullptr; 2053 } 2054 2055 // Read the inferior memory 2056 Error error; 2057 lldb::addr_t data_ptr = *allocation->data_ptr.get(); 2058 GetProcess()->ReadMemory(data_ptr, buffer.get(), size, error); 2059 if (error.Fail()) 2060 { 2061 if (log) 2062 log->Printf("RenderScriptRuntime::GetAllocationData - '%s' Couldn't read %u bytes of allocation data from 0x%" PRIx64, 2063 error.AsCString(), size, data_ptr); 2064 return nullptr; 2065 } 2066 2067 return buffer; 2068 } 2069 2070 // Function copies data from a binary file into an allocation. 2071 // There is a header at the start of the file, FileHeader, before the data content itself. 2072 // Information from this header is used to display warnings to the user about incompatabilities 2073 bool 2074 RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, const char* filename, StackFrame* frame_ptr) 2075 { 2076 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2077 2078 // Find allocation with the given id 2079 AllocationDetails* alloc = FindAllocByID(strm, alloc_id); 2080 if (!alloc) 2081 return false; 2082 2083 if (log) 2084 log->Printf("RenderScriptRuntime::LoadAllocation - Found allocation 0x%" PRIx64, *alloc->address.get()); 2085 2086 // JIT all the allocation details 2087 if (alloc->shouldRefresh()) 2088 { 2089 if (log) 2090 log->Printf("RenderScriptRuntime::LoadAllocation - Allocation details not calculated yet, jitting info"); 2091 2092 if (!RefreshAllocation(alloc, frame_ptr)) 2093 { 2094 if (log) 2095 log->Printf("RenderScriptRuntime::LoadAllocation - Couldn't JIT allocation details"); 2096 return false; 2097 } 2098 } 2099 2100 assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && alloc->element.type_vec_size.isValid() 2101 && alloc->size.isValid() && alloc->element.datum_size.isValid() && "Allocation information not available"); 2102 2103 // Check we can read from file 2104 FileSpec file(filename, true); 2105 if (!file.Exists()) 2106 { 2107 strm.Printf("Error: File %s does not exist", filename); 2108 strm.EOL(); 2109 return false; 2110 } 2111 2112 if (!file.Readable()) 2113 { 2114 strm.Printf("Error: File %s does not have readable permissions", filename); 2115 strm.EOL(); 2116 return false; 2117 } 2118 2119 // Read file into data buffer 2120 DataBufferSP data_sp(file.ReadFileContents()); 2121 2122 // Cast start of buffer to FileHeader and use pointer to read metadata 2123 void* file_buffer = data_sp->GetBytes(); 2124 if (file_buffer == NULL || data_sp->GetByteSize() < 2125 (sizeof(AllocationDetails::FileHeader) + sizeof(AllocationDetails::ElementHeader))) 2126 { 2127 strm.Printf("Error: File %s does not contain enough data for header", filename); 2128 strm.EOL(); 2129 return false; 2130 } 2131 const AllocationDetails::FileHeader* file_header = static_cast<AllocationDetails::FileHeader*>(file_buffer); 2132 2133 // Check file starts with ascii characters "RSAD" 2134 if (file_header->ident[0] != 'R' || file_header->ident[1] != 'S' || file_header->ident[2] != 'A' 2135 || file_header->ident[3] != 'D') 2136 { 2137 strm.Printf("Error: File doesn't contain identifier for an RS allocation dump. Are you sure this is the correct file?"); 2138 strm.EOL(); 2139 return false; 2140 } 2141 2142 // Look at the type of the root element in the header 2143 AllocationDetails::ElementHeader root_element_header; 2144 memcpy(&root_element_header, static_cast<uint8_t*>(file_buffer) + sizeof(AllocationDetails::FileHeader), 2145 sizeof(AllocationDetails::ElementHeader)); 2146 2147 if (log) 2148 log->Printf("RenderScriptRuntime::LoadAllocation - header type %u, element size %u", 2149 root_element_header.type, root_element_header.element_size); 2150 2151 // Check if the target allocation and file both have the same number of bytes for an Element 2152 if (*alloc->element.datum_size.get() != root_element_header.element_size) 2153 { 2154 strm.Printf("Warning: Mismatched Element sizes - file %u bytes, allocation %u bytes", 2155 root_element_header.element_size, *alloc->element.datum_size.get()); 2156 strm.EOL(); 2157 } 2158 2159 // Check if the target allocation and file both have the same type 2160 const unsigned int alloc_type = static_cast<unsigned int>(*alloc->element.type.get()); 2161 const unsigned int file_type = root_element_header.type; 2162 2163 if (file_type > Element::RS_TYPE_FONT) 2164 { 2165 strm.Printf("Warning: File has unknown allocation type"); 2166 strm.EOL(); 2167 } 2168 else if (alloc_type != file_type) 2169 { 2170 // Enum value isn't monotonous, so doesn't always index RsDataTypeToString array 2171 unsigned int printable_target_type_index = alloc_type; 2172 unsigned int printable_head_type_index = file_type; 2173 if (alloc_type >= Element::RS_TYPE_ELEMENT && alloc_type <= Element::RS_TYPE_FONT) 2174 printable_target_type_index = static_cast<Element::DataType>( 2175 (alloc_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1); 2176 2177 if (file_type >= Element::RS_TYPE_ELEMENT && file_type <= Element::RS_TYPE_FONT) 2178 printable_head_type_index = static_cast<Element::DataType>( 2179 (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1); 2180 2181 const char* file_type_cstr = AllocationDetails::RsDataTypeToString[printable_head_type_index][0]; 2182 const char* target_type_cstr = AllocationDetails::RsDataTypeToString[printable_target_type_index][0]; 2183 2184 strm.Printf("Warning: Mismatched Types - file '%s' type, allocation '%s' type", 2185 file_type_cstr, target_type_cstr); 2186 strm.EOL(); 2187 } 2188 2189 // Advance buffer past header 2190 file_buffer = static_cast<uint8_t*>(file_buffer) + file_header->hdr_size; 2191 2192 // Calculate size of allocation data in file 2193 size_t length = data_sp->GetByteSize() - file_header->hdr_size; 2194 2195 // Check if the target allocation and file both have the same total data size. 2196 const unsigned int alloc_size = *alloc->size.get(); 2197 if (alloc_size != length) 2198 { 2199 strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64 " bytes, allocation 0x%x bytes", 2200 (uint64_t) length, alloc_size); 2201 strm.EOL(); 2202 length = alloc_size < length ? alloc_size : length; // Set length to copy to minimum 2203 } 2204 2205 // Copy file data from our buffer into the target allocation. 2206 lldb::addr_t alloc_data = *alloc->data_ptr.get(); 2207 Error error; 2208 size_t bytes_written = GetProcess()->WriteMemory(alloc_data, file_buffer, length, error); 2209 if (!error.Success() || bytes_written != length) 2210 { 2211 strm.Printf("Error: Couldn't write data to allocation %s", error.AsCString()); 2212 strm.EOL(); 2213 return false; 2214 } 2215 2216 strm.Printf("Contents of file '%s' read into allocation %u", filename, alloc->id); 2217 strm.EOL(); 2218 2219 return true; 2220 } 2221 2222 // Function takes as parameters a byte buffer, which will eventually be written to file as the element header, 2223 // an offset into that buffer, and an Element that will be saved into the buffer at the parametrised offset. 2224 // Return value is the new offset after writing the element into the buffer. 2225 // Elements are saved to the file as the ElementHeader struct followed by offsets to the structs of all the element's children. 2226 size_t 2227 RenderScriptRuntime::PopulateElementHeaders(const std::shared_ptr<uint8_t> header_buffer, size_t offset, const Element& elem) 2228 { 2229 // File struct for an element header with all the relevant details copied from elem. 2230 // We assume members are valid already. 2231 AllocationDetails::ElementHeader elem_header; 2232 elem_header.type = *elem.type.get(); 2233 elem_header.kind = *elem.type_kind.get(); 2234 elem_header.element_size = *elem.datum_size.get(); 2235 elem_header.vector_size = *elem.type_vec_size.get(); 2236 elem_header.array_size = elem.array_size.isValid() ? *elem.array_size.get() : 0; 2237 const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader); 2238 2239 // Copy struct into buffer and advance offset 2240 // We assume that header_buffer has been checked for NULL before this method is called 2241 memcpy(header_buffer.get() + offset, &elem_header, elem_header_size); 2242 offset += elem_header_size; 2243 2244 // Starting offset of child ElementHeader struct 2245 size_t child_offset = offset + ((elem.children.size() + 1) * sizeof(uint32_t)); 2246 for (const RenderScriptRuntime::Element& child : elem.children) 2247 { 2248 // Recursively populate the buffer with the element header structs of children. 2249 // Then save the offsets where they were set after the parent element header. 2250 memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t)); 2251 offset += sizeof(uint32_t); 2252 2253 child_offset = PopulateElementHeaders(header_buffer, child_offset, child); 2254 } 2255 2256 // Zero indicates no more children 2257 memset(header_buffer.get() + offset, 0, sizeof(uint32_t)); 2258 2259 return child_offset; 2260 } 2261 2262 // Given an Element object this function returns the total size needed in the file header to store the element's details. 2263 // Taking into account the size of the element header struct, plus the offsets to all the element's children. 2264 // Function is recursive so that the size of all ancestors is taken into account. 2265 size_t 2266 RenderScriptRuntime::CalculateElementHeaderSize(const Element& elem) 2267 { 2268 size_t size = (elem.children.size() + 1) * sizeof(uint32_t); // Offsets to children plus zero terminator 2269 size += sizeof(AllocationDetails::ElementHeader); // Size of header struct with type details 2270 2271 // Calculate recursively for all descendants 2272 for (const Element& child : elem.children) 2273 size += CalculateElementHeaderSize(child); 2274 2275 return size; 2276 } 2277 2278 // Function copies allocation contents into a binary file. 2279 // This file can then be loaded later into a different allocation. 2280 // There is a header, FileHeader, before the allocation data containing meta-data. 2281 bool 2282 RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, const char* filename, StackFrame* frame_ptr) 2283 { 2284 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2285 2286 // Find allocation with the given id 2287 AllocationDetails* alloc = FindAllocByID(strm, alloc_id); 2288 if (!alloc) 2289 return false; 2290 2291 if (log) 2292 log->Printf("RenderScriptRuntime::SaveAllocation - Found allocation 0x%" PRIx64, *alloc->address.get()); 2293 2294 // JIT all the allocation details 2295 if (alloc->shouldRefresh()) 2296 { 2297 if (log) 2298 log->Printf("RenderScriptRuntime::SaveAllocation - Allocation details not calculated yet, jitting info"); 2299 2300 if (!RefreshAllocation(alloc, frame_ptr)) 2301 { 2302 if (log) 2303 log->Printf("RenderScriptRuntime::SaveAllocation - Couldn't JIT allocation details"); 2304 return false; 2305 } 2306 } 2307 2308 assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && alloc->element.type_vec_size.isValid() && alloc->element.datum_size.get() 2309 && alloc->element.type_kind.isValid() && alloc->dimension.isValid() && "Allocation information not available"); 2310 2311 // Check we can create writable file 2312 FileSpec file_spec(filename, true); 2313 File file(file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate | File::eOpenOptionTruncate); 2314 if (!file) 2315 { 2316 strm.Printf("Error: Failed to open '%s' for writing", filename); 2317 strm.EOL(); 2318 return false; 2319 } 2320 2321 // Read allocation into buffer of heap memory 2322 const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); 2323 if (!buffer) 2324 { 2325 strm.Printf("Error: Couldn't read allocation data into buffer"); 2326 strm.EOL(); 2327 return false; 2328 } 2329 2330 // Create the file header 2331 AllocationDetails::FileHeader head; 2332 head.ident[0] = 'R'; head.ident[1] = 'S'; head.ident[2] = 'A'; head.ident[3] = 'D'; 2333 head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1); 2334 head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2); 2335 head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3); 2336 2337 const size_t element_header_size = CalculateElementHeaderSize(alloc->element); 2338 assert((sizeof(AllocationDetails::FileHeader) + element_header_size) < UINT16_MAX && "Element header too large"); 2339 head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) + element_header_size); 2340 2341 // Write the file header 2342 size_t num_bytes = sizeof(AllocationDetails::FileHeader); 2343 if (log) 2344 log->Printf("RenderScriptRuntime::SaveAllocation - Writing File Header, 0x%zX bytes", num_bytes); 2345 2346 Error err = file.Write(&head, num_bytes); 2347 if (!err.Success()) 2348 { 2349 strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename); 2350 strm.EOL(); 2351 return false; 2352 } 2353 2354 // Create the headers describing the element type of the allocation. 2355 std::shared_ptr<uint8_t> element_header_buffer(new uint8_t[element_header_size]); 2356 if (element_header_buffer == nullptr) 2357 { 2358 strm.Printf("Internal Error: Couldn't allocate %zu bytes on the heap", element_header_size); 2359 strm.EOL(); 2360 return false; 2361 } 2362 2363 PopulateElementHeaders(element_header_buffer, 0, alloc->element); 2364 2365 // Write headers for allocation element type to file 2366 num_bytes = element_header_size; 2367 if (log) 2368 log->Printf("RenderScriptRuntime::SaveAllocation - Writing Element Headers, 0x%zX bytes", num_bytes); 2369 2370 err = file.Write(element_header_buffer.get(), num_bytes); 2371 if (!err.Success()) 2372 { 2373 strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename); 2374 strm.EOL(); 2375 return false; 2376 } 2377 2378 // Write allocation data to file 2379 num_bytes = static_cast<size_t>(*alloc->size.get()); 2380 if (log) 2381 log->Printf("RenderScriptRuntime::SaveAllocation - Writing 0x%zX bytes", num_bytes); 2382 2383 err = file.Write(buffer.get(), num_bytes); 2384 if (!err.Success()) 2385 { 2386 strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename); 2387 strm.EOL(); 2388 return false; 2389 } 2390 2391 strm.Printf("Allocation written to file '%s'", filename); 2392 strm.EOL(); 2393 return true; 2394 } 2395 2396 bool 2397 RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) 2398 { 2399 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2400 2401 if (module_sp) 2402 { 2403 for (const auto &rs_module : m_rsmodules) 2404 { 2405 if (rs_module->m_module == module_sp) 2406 { 2407 // Check if the user has enabled automatically breaking on 2408 // all RS kernels. 2409 if (m_breakAllKernels) 2410 BreakOnModuleKernels(rs_module); 2411 2412 return false; 2413 } 2414 } 2415 bool module_loaded = false; 2416 switch (GetModuleKind(module_sp)) 2417 { 2418 case eModuleKindKernelObj: 2419 { 2420 RSModuleDescriptorSP module_desc; 2421 module_desc.reset(new RSModuleDescriptor(module_sp)); 2422 if (module_desc->ParseRSInfo()) 2423 { 2424 m_rsmodules.push_back(module_desc); 2425 module_loaded = true; 2426 } 2427 if (module_loaded) 2428 { 2429 FixupScriptDetails(module_desc); 2430 } 2431 break; 2432 } 2433 case eModuleKindDriver: 2434 { 2435 if (!m_libRSDriver) 2436 { 2437 m_libRSDriver = module_sp; 2438 LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver); 2439 } 2440 break; 2441 } 2442 case eModuleKindImpl: 2443 { 2444 m_libRSCpuRef = module_sp; 2445 break; 2446 } 2447 case eModuleKindLibRS: 2448 { 2449 if (!m_libRS) 2450 { 2451 m_libRS = module_sp; 2452 static ConstString gDbgPresentStr("gDebuggerPresent"); 2453 const Symbol* debug_present = m_libRS->FindFirstSymbolWithNameAndType(gDbgPresentStr, eSymbolTypeData); 2454 if (debug_present) 2455 { 2456 Error error; 2457 uint32_t flag = 0x00000001U; 2458 Target &target = GetProcess()->GetTarget(); 2459 addr_t addr = debug_present->GetLoadAddress(&target); 2460 GetProcess()->WriteMemory(addr, &flag, sizeof(flag), error); 2461 if(error.Success()) 2462 { 2463 if (log) 2464 log->Printf ("RenderScriptRuntime::LoadModule - Debugger present flag set on debugee"); 2465 2466 m_debuggerPresentFlagged = true; 2467 } 2468 else if (log) 2469 { 2470 log->Printf ("RenderScriptRuntime::LoadModule - Error writing debugger present flags '%s' ", error.AsCString()); 2471 } 2472 } 2473 else if (log) 2474 { 2475 log->Printf ("RenderScriptRuntime::LoadModule - Error writing debugger present flags - symbol not found"); 2476 } 2477 } 2478 break; 2479 } 2480 default: 2481 break; 2482 } 2483 if (module_loaded) 2484 Update(); 2485 return module_loaded; 2486 } 2487 return false; 2488 } 2489 2490 void 2491 RenderScriptRuntime::Update() 2492 { 2493 if (m_rsmodules.size() > 0) 2494 { 2495 if (!m_initiated) 2496 { 2497 Initiate(); 2498 } 2499 } 2500 } 2501 2502 // The maximum line length of an .rs.info packet 2503 #define MAXLINE 500 2504 2505 // The .rs.info symbol in renderscript modules contains a string which needs to be parsed. 2506 // The string is basic and is parsed on a line by line basis. 2507 bool 2508 RSModuleDescriptor::ParseRSInfo() 2509 { 2510 const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData); 2511 if (info_sym) 2512 { 2513 const addr_t addr = info_sym->GetAddressRef().GetFileAddress(); 2514 const addr_t size = info_sym->GetByteSize(); 2515 const FileSpec fs = m_module->GetFileSpec(); 2516 2517 DataBufferSP buffer = fs.ReadFileContents(addr, size); 2518 2519 if (!buffer) 2520 return false; 2521 2522 std::string info((const char *)buffer->GetBytes()); 2523 2524 std::vector<std::string> info_lines; 2525 size_t lpos = info.find('\n'); 2526 while (lpos != std::string::npos) 2527 { 2528 info_lines.push_back(info.substr(0, lpos)); 2529 info = info.substr(lpos + 1); 2530 lpos = info.find('\n'); 2531 } 2532 size_t offset = 0; 2533 while (offset < info_lines.size()) 2534 { 2535 std::string line = info_lines[offset]; 2536 // Parse directives 2537 uint32_t numDefns = 0; 2538 if (sscanf(line.c_str(), "exportVarCount: %u", &numDefns) == 1) 2539 { 2540 while (numDefns--) 2541 m_globals.push_back(RSGlobalDescriptor(this, info_lines[++offset].c_str())); 2542 } 2543 else if (sscanf(line.c_str(), "exportFuncCount: %u", &numDefns) == 1) 2544 { 2545 } 2546 else if (sscanf(line.c_str(), "exportForEachCount: %u", &numDefns) == 1) 2547 { 2548 char name[MAXLINE]; 2549 while (numDefns--) 2550 { 2551 uint32_t slot = 0; 2552 name[0] = '\0'; 2553 if (sscanf(info_lines[++offset].c_str(), "%u - %s", &slot, &name[0]) == 2) 2554 { 2555 m_kernels.push_back(RSKernelDescriptor(this, name, slot)); 2556 } 2557 } 2558 } 2559 else if (sscanf(line.c_str(), "pragmaCount: %u", &numDefns) == 1) 2560 { 2561 char name[MAXLINE]; 2562 char value[MAXLINE]; 2563 while (numDefns--) 2564 { 2565 name[0] = '\0'; 2566 value[0] = '\0'; 2567 if (sscanf(info_lines[++offset].c_str(), "%s - %s", &name[0], &value[0]) != 0 2568 && (name[0] != '\0')) 2569 { 2570 m_pragmas[std::string(name)] = value; 2571 } 2572 } 2573 } 2574 else if (sscanf(line.c_str(), "objectSlotCount: %u", &numDefns) == 1) 2575 { 2576 } 2577 2578 offset++; 2579 } 2580 return m_kernels.size() > 0; 2581 } 2582 return false; 2583 } 2584 2585 bool 2586 RenderScriptRuntime::ProbeModules(const ModuleList module_list) 2587 { 2588 bool rs_found = false; 2589 size_t num_modules = module_list.GetSize(); 2590 for (size_t i = 0; i < num_modules; i++) 2591 { 2592 auto module = module_list.GetModuleAtIndex(i); 2593 rs_found |= LoadModule(module); 2594 } 2595 return rs_found; 2596 } 2597 2598 void 2599 RenderScriptRuntime::Status(Stream &strm) const 2600 { 2601 if (m_libRS) 2602 { 2603 strm.Printf("Runtime Library discovered."); 2604 strm.EOL(); 2605 } 2606 if (m_libRSDriver) 2607 { 2608 strm.Printf("Runtime Driver discovered."); 2609 strm.EOL(); 2610 } 2611 if (m_libRSCpuRef) 2612 { 2613 strm.Printf("CPU Reference Implementation discovered."); 2614 strm.EOL(); 2615 } 2616 2617 if (m_runtimeHooks.size()) 2618 { 2619 strm.Printf("Runtime functions hooked:"); 2620 strm.EOL(); 2621 for (auto b : m_runtimeHooks) 2622 { 2623 strm.Indent(b.second->defn->name); 2624 strm.EOL(); 2625 } 2626 } 2627 else 2628 { 2629 strm.Printf("Runtime is not hooked."); 2630 strm.EOL(); 2631 } 2632 } 2633 2634 void 2635 RenderScriptRuntime::DumpContexts(Stream &strm) const 2636 { 2637 strm.Printf("Inferred RenderScript Contexts:"); 2638 strm.EOL(); 2639 strm.IndentMore(); 2640 2641 std::map<addr_t, uint64_t> contextReferences; 2642 2643 // Iterate over all of the currently discovered scripts. 2644 // Note: We cant push or pop from m_scripts inside this loop or it may invalidate script. 2645 for (const auto & script : m_scripts) 2646 { 2647 if (!script->context.isValid()) 2648 continue; 2649 lldb::addr_t context = *script->context; 2650 2651 if (contextReferences.find(context) != contextReferences.end()) 2652 { 2653 contextReferences[context]++; 2654 } 2655 else 2656 { 2657 contextReferences[context] = 1; 2658 } 2659 } 2660 2661 for (const auto& cRef : contextReferences) 2662 { 2663 strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances", cRef.first, cRef.second); 2664 strm.EOL(); 2665 } 2666 strm.IndentLess(); 2667 } 2668 2669 void 2670 RenderScriptRuntime::DumpKernels(Stream &strm) const 2671 { 2672 strm.Printf("RenderScript Kernels:"); 2673 strm.EOL(); 2674 strm.IndentMore(); 2675 for (const auto &module : m_rsmodules) 2676 { 2677 strm.Printf("Resource '%s':",module->m_resname.c_str()); 2678 strm.EOL(); 2679 for (const auto &kernel : module->m_kernels) 2680 { 2681 strm.Indent(kernel.m_name.AsCString()); 2682 strm.EOL(); 2683 } 2684 } 2685 strm.IndentLess(); 2686 } 2687 2688 RenderScriptRuntime::AllocationDetails* 2689 RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) 2690 { 2691 AllocationDetails* alloc = nullptr; 2692 2693 // See if we can find allocation using id as an index; 2694 if (alloc_id <= m_allocations.size() && alloc_id != 0 2695 && m_allocations[alloc_id-1]->id == alloc_id) 2696 { 2697 alloc = m_allocations[alloc_id-1].get(); 2698 return alloc; 2699 } 2700 2701 // Fallback to searching 2702 for (const auto & a : m_allocations) 2703 { 2704 if (a->id == alloc_id) 2705 { 2706 alloc = a.get(); 2707 break; 2708 } 2709 } 2710 2711 if (alloc == nullptr) 2712 { 2713 strm.Printf("Error: Couldn't find allocation with id matching %u", alloc_id); 2714 strm.EOL(); 2715 } 2716 2717 return alloc; 2718 } 2719 2720 // Prints the contents of an allocation to the output stream, which may be a file 2721 bool 2722 RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame* frame_ptr, const uint32_t id) 2723 { 2724 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2725 2726 // Check we can find the desired allocation 2727 AllocationDetails* alloc = FindAllocByID(strm, id); 2728 if (!alloc) 2729 return false; // FindAllocByID() will print error message for us here 2730 2731 if (log) 2732 log->Printf("RenderScriptRuntime::DumpAllocation - Found allocation 0x%" PRIx64, *alloc->address.get()); 2733 2734 // Check we have information about the allocation, if not calculate it 2735 if (alloc->shouldRefresh()) 2736 { 2737 if (log) 2738 log->Printf("RenderScriptRuntime::DumpAllocation - Allocation details not calculated yet, jitting info"); 2739 2740 // JIT all the allocation information 2741 if (!RefreshAllocation(alloc, frame_ptr)) 2742 { 2743 strm.Printf("Error: Couldn't JIT allocation details"); 2744 strm.EOL(); 2745 return false; 2746 } 2747 } 2748 2749 // Establish format and size of each data element 2750 const unsigned int vec_size = *alloc->element.type_vec_size.get(); 2751 const Element::DataType type = *alloc->element.type.get(); 2752 2753 assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT 2754 && "Invalid allocation type"); 2755 2756 lldb::Format format; 2757 if (type >= Element::RS_TYPE_ELEMENT) 2758 format = eFormatHex; 2759 else 2760 format = vec_size == 1 ? static_cast<lldb::Format>(AllocationDetails::RSTypeToFormat[type][eFormatSingle]) 2761 : static_cast<lldb::Format>(AllocationDetails::RSTypeToFormat[type][eFormatVector]); 2762 2763 const unsigned int data_size = *alloc->element.datum_size.get(); 2764 2765 if (log) 2766 log->Printf("RenderScriptRuntime::DumpAllocation - Element size %u bytes, including padding", data_size); 2767 2768 // Allocate a buffer to copy data into 2769 std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); 2770 if (!buffer) 2771 { 2772 strm.Printf("Error: Couldn't read allocation data"); 2773 strm.EOL(); 2774 return false; 2775 } 2776 2777 // Calculate stride between rows as there may be padding at end of rows since 2778 // allocated memory is 16-byte aligned 2779 if (!alloc->stride.isValid()) 2780 { 2781 if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension 2782 alloc->stride = 0; 2783 else if (!JITAllocationStride(alloc, frame_ptr)) 2784 { 2785 strm.Printf("Error: Couldn't calculate allocation row stride"); 2786 strm.EOL(); 2787 return false; 2788 } 2789 } 2790 const unsigned int stride = *alloc->stride.get(); 2791 const unsigned int size = *alloc->size.get(); // Size of whole allocation 2792 const unsigned int padding = alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0; 2793 if (log) 2794 log->Printf("RenderScriptRuntime::DumpAllocation - stride %u bytes, size %u bytes, padding %u", stride, size, padding); 2795 2796 // Find dimensions used to index loops, so need to be non-zero 2797 unsigned int dim_x = alloc->dimension.get()->dim_1; 2798 dim_x = dim_x == 0 ? 1 : dim_x; 2799 2800 unsigned int dim_y = alloc->dimension.get()->dim_2; 2801 dim_y = dim_y == 0 ? 1 : dim_y; 2802 2803 unsigned int dim_z = alloc->dimension.get()->dim_3; 2804 dim_z = dim_z == 0 ? 1 : dim_z; 2805 2806 // Use data extractor to format output 2807 const uint32_t archByteSize = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 2808 DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(), archByteSize); 2809 2810 unsigned int offset = 0; // Offset in buffer to next element to be printed 2811 unsigned int prev_row = 0; // Offset to the start of the previous row 2812 2813 // Iterate over allocation dimensions, printing results to user 2814 strm.Printf("Data (X, Y, Z):"); 2815 for (unsigned int z = 0; z < dim_z; ++z) 2816 { 2817 for (unsigned int y = 0; y < dim_y; ++y) 2818 { 2819 // Use stride to index start of next row. 2820 if (!(y==0 && z==0)) 2821 offset = prev_row + stride; 2822 prev_row = offset; 2823 2824 // Print each element in the row individually 2825 for (unsigned int x = 0; x < dim_x; ++x) 2826 { 2827 strm.Printf("\n(%u, %u, %u) = ", x, y, z); 2828 if ((type == Element::RS_TYPE_NONE) && (alloc->element.children.size() > 0) && 2829 (alloc->element.type_name != Element::GetFallbackStructName())) 2830 { 2831 // Here we are dumping an Element of struct type. 2832 // This is done using expression evaluation with the name of the struct type and pointer to element. 2833 2834 // Don't print the name of the resulting expression, since this will be '$[0-9]+' 2835 DumpValueObjectOptions expr_options; 2836 expr_options.SetHideName(true); 2837 2838 // Setup expression as derefrencing a pointer cast to element address. 2839 const int max_expr_size = 512; 2840 char expr_char_buffer[max_expr_size]; 2841 int chars_written = snprintf(expr_char_buffer, max_expr_size, "*(%s*) 0x%" PRIx64, 2842 alloc->element.type_name.AsCString(), *alloc->data_ptr.get() + offset); 2843 2844 if (chars_written < 0 || chars_written >= max_expr_size) 2845 { 2846 if (log) 2847 log->Printf("RenderScriptRuntime::DumpAllocation- Error in snprintf()"); 2848 continue; 2849 } 2850 2851 // Evaluate expression 2852 ValueObjectSP expr_result; 2853 GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer, frame_ptr, expr_result); 2854 2855 // Print the results to our stream. 2856 expr_result->Dump(strm, expr_options); 2857 } 2858 else 2859 { 2860 alloc_data.Dump(&strm, offset, format, data_size - padding, 1, 1, LLDB_INVALID_ADDRESS, 0, 0); 2861 } 2862 offset += data_size; 2863 } 2864 } 2865 } 2866 strm.EOL(); 2867 2868 return true; 2869 } 2870 2871 // Prints infomation regarding all the currently loaded allocations. 2872 // These details are gathered by jitting the runtime, which has as latency. 2873 void 2874 RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame* frame_ptr, bool recompute) 2875 { 2876 strm.Printf("RenderScript Allocations:"); 2877 strm.EOL(); 2878 strm.IndentMore(); 2879 2880 for (auto &alloc : m_allocations) 2881 { 2882 // JIT the allocation info if we haven't done it, or the user forces us to. 2883 bool do_refresh = alloc->shouldRefresh() || recompute; 2884 2885 // JIT current allocation information 2886 if (do_refresh && !RefreshAllocation(alloc.get(), frame_ptr)) 2887 { 2888 strm.Printf("Error: Couldn't evaluate details for allocation %u\n", alloc->id); 2889 continue; 2890 } 2891 2892 strm.Printf("%u:\n",alloc->id); 2893 strm.IndentMore(); 2894 2895 strm.Indent("Context: "); 2896 if (!alloc->context.isValid()) 2897 strm.Printf("unknown\n"); 2898 else 2899 strm.Printf("0x%" PRIx64 "\n", *alloc->context.get()); 2900 2901 strm.Indent("Address: "); 2902 if (!alloc->address.isValid()) 2903 strm.Printf("unknown\n"); 2904 else 2905 strm.Printf("0x%" PRIx64 "\n", *alloc->address.get()); 2906 2907 strm.Indent("Data pointer: "); 2908 if (!alloc->data_ptr.isValid()) 2909 strm.Printf("unknown\n"); 2910 else 2911 strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get()); 2912 2913 strm.Indent("Dimensions: "); 2914 if (!alloc->dimension.isValid()) 2915 strm.Printf("unknown\n"); 2916 else 2917 strm.Printf("(%d, %d, %d)\n", alloc->dimension.get()->dim_1, 2918 alloc->dimension.get()->dim_2, 2919 alloc->dimension.get()->dim_3); 2920 2921 strm.Indent("Data Type: "); 2922 if (!alloc->element.type.isValid() || !alloc->element.type_vec_size.isValid()) 2923 strm.Printf("unknown\n"); 2924 else 2925 { 2926 const int vector_size = *alloc->element.type_vec_size.get(); 2927 Element::DataType type = *alloc->element.type.get(); 2928 2929 if (!alloc->element.type_name.IsEmpty()) 2930 strm.Printf("%s\n", alloc->element.type_name.AsCString()); 2931 else 2932 { 2933 // Enum value isn't monotonous, so doesn't always index RsDataTypeToString array 2934 if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT) 2935 type = static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1); 2936 2937 if (type >= (sizeof(AllocationDetails::RsDataTypeToString) / sizeof(AllocationDetails::RsDataTypeToString[0])) 2938 || vector_size > 4 || vector_size < 1) 2939 strm.Printf("invalid type\n"); 2940 else 2941 strm.Printf("%s\n", AllocationDetails::RsDataTypeToString[static_cast<unsigned int>(type)][vector_size-1]); 2942 } 2943 } 2944 2945 strm.Indent("Data Kind: "); 2946 if (!alloc->element.type_kind.isValid()) 2947 strm.Printf("unknown\n"); 2948 else 2949 { 2950 const Element::DataKind kind = *alloc->element.type_kind.get(); 2951 if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV) 2952 strm.Printf("invalid kind\n"); 2953 else 2954 strm.Printf("%s\n", AllocationDetails::RsDataKindToString[static_cast<unsigned int>(kind)]); 2955 } 2956 2957 strm.EOL(); 2958 strm.IndentLess(); 2959 } 2960 strm.IndentLess(); 2961 } 2962 2963 // Set breakpoints on every kernel found in RS module 2964 void 2965 RenderScriptRuntime::BreakOnModuleKernels(const RSModuleDescriptorSP rsmodule_sp) 2966 { 2967 for (const auto &kernel : rsmodule_sp->m_kernels) 2968 { 2969 // Don't set breakpoint on 'root' kernel 2970 if (strcmp(kernel.m_name.AsCString(), "root") == 0) 2971 continue; 2972 2973 CreateKernelBreakpoint(kernel.m_name); 2974 } 2975 } 2976 2977 // Method is internally called by the 'kernel breakpoint all' command to 2978 // enable or disable breaking on all kernels. 2979 // 2980 // When do_break is true we want to enable this functionality. 2981 // When do_break is false we want to disable it. 2982 void 2983 RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) 2984 { 2985 Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 2986 2987 InitSearchFilter(target); 2988 2989 // Set breakpoints on all the kernels 2990 if (do_break && !m_breakAllKernels) 2991 { 2992 m_breakAllKernels = true; 2993 2994 for (const auto &module : m_rsmodules) 2995 BreakOnModuleKernels(module); 2996 2997 if (log) 2998 log->Printf("RenderScriptRuntime::SetBreakAllKernels(True)" 2999 "- breakpoints set on all currently loaded kernels"); 3000 } 3001 else if (!do_break && m_breakAllKernels) // Breakpoints won't be set on any new kernels. 3002 { 3003 m_breakAllKernels = false; 3004 3005 if (log) 3006 log->Printf("RenderScriptRuntime::SetBreakAllKernels(False) - breakpoints no longer automatically set"); 3007 } 3008 } 3009 3010 // Given the name of a kernel this function creates a breakpoint using our 3011 // own breakpoint resolver, and returns the Breakpoint shared pointer. 3012 BreakpointSP 3013 RenderScriptRuntime::CreateKernelBreakpoint(const ConstString& name) 3014 { 3015 Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3016 3017 if (!m_filtersp) 3018 { 3019 if (log) 3020 log->Printf("RenderScriptRuntime::CreateKernelBreakpoint - Error: No breakpoint search filter set"); 3021 return nullptr; 3022 } 3023 3024 BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name)); 3025 BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint(m_filtersp, resolver_sp, false, false, false); 3026 3027 // Give RS breakpoints a specific name, so the user can manipulate them as a group. 3028 Error err; 3029 if (!bp->AddName("RenderScriptKernel", err) && log) 3030 log->Printf("RenderScriptRuntime::CreateKernelBreakpoint: Error setting break name, %s", err.AsCString()); 3031 3032 return bp; 3033 } 3034 3035 // Given an expression for a variable this function tries to calculate the variable's value. 3036 // If this is possible it returns true and sets the uint64_t parameter to the variables unsigned value. 3037 // Otherwise function returns false. 3038 bool 3039 RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp, const char* var_name, uint64_t& val) 3040 { 3041 Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 3042 Error error; 3043 VariableSP var_sp; 3044 3045 // Find variable in stack frame 3046 ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath(var_name, 3047 eNoDynamicValues, 3048 StackFrame::eExpressionPathOptionCheckPtrVsMember | 3049 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, 3050 var_sp, 3051 error)); 3052 if (!error.Success()) 3053 { 3054 if (log) 3055 log->Printf("RenderScriptRuntime::GetFrameVarAsUnsigned - Error, couldn't find '%s' in frame", var_name); 3056 3057 return false; 3058 } 3059 3060 // Find the unsigned int value for the variable 3061 bool success = false; 3062 val = value_sp->GetValueAsUnsigned(0, &success); 3063 if (!success) 3064 { 3065 if (log) 3066 log->Printf("RenderScriptRuntime::GetFrameVarAsUnsigned - Error, couldn't parse '%s' as an unsigned int", var_name); 3067 3068 return false; 3069 } 3070 3071 return true; 3072 } 3073 3074 // Callback when a kernel breakpoint hits and we're looking for a specific coordinate. 3075 // Baton parameter contains a pointer to the target coordinate we want to break on. 3076 // Function then checks the .expand frame for the current coordinate and breaks to user if it matches. 3077 // Parameter 'break_id' is the id of the Breakpoint which made the callback. 3078 // Parameter 'break_loc_id' is the id for the BreakpointLocation which was hit, 3079 // a single logical breakpoint can have multiple addresses. 3080 bool 3081 RenderScriptRuntime::KernelBreakpointHit(void *baton, StoppointCallbackContext *ctx, 3082 user_id_t break_id, user_id_t break_loc_id) 3083 { 3084 Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3085 3086 assert(baton && "Error: null baton in conditional kernel breakpoint callback"); 3087 3088 // Coordinate we want to stop on 3089 const int* target_coord = static_cast<const int*>(baton); 3090 3091 if (log) 3092 log->Printf("RenderScriptRuntime::KernelBreakpointHit - Break ID %" PRIu64 ", target coord (%d, %d, %d)", 3093 break_id, target_coord[0], target_coord[1], target_coord[2]); 3094 3095 // Go up one stack frame to .expand kernel 3096 ExecutionContext context(ctx->exe_ctx_ref); 3097 ThreadSP thread_sp = context.GetThreadSP(); 3098 if (!thread_sp->SetSelectedFrameByIndex(1)) 3099 { 3100 if (log) 3101 log->Printf("RenderScriptRuntime::KernelBreakpointHit - Error, couldn't go up stack frame"); 3102 3103 return false; 3104 } 3105 3106 StackFrameSP frame_sp = thread_sp->GetSelectedFrame(); 3107 if (!frame_sp) 3108 { 3109 if (log) 3110 log->Printf("RenderScriptRuntime::KernelBreakpointHit - Error, couldn't select .expand stack frame"); 3111 3112 return false; 3113 } 3114 3115 // Get values for variables in .expand frame that tell us the current kernel invocation 3116 const char* coord_expressions[] = {"rsIndex", "p->current.y", "p->current.z"}; 3117 uint64_t current_coord[3] = {0, 0, 0}; 3118 3119 for(int i = 0; i < 3; ++i) 3120 { 3121 if (!GetFrameVarAsUnsigned(frame_sp, coord_expressions[i], current_coord[i])) 3122 return false; 3123 3124 if (log) 3125 log->Printf("RenderScriptRuntime::KernelBreakpointHit, %s = %" PRIu64, coord_expressions[i], current_coord[i]); 3126 } 3127 3128 // Check if the current kernel invocation coordinate matches our target coordinate 3129 if (current_coord[0] == static_cast<uint64_t>(target_coord[0]) && 3130 current_coord[1] == static_cast<uint64_t>(target_coord[1]) && 3131 current_coord[2] == static_cast<uint64_t>(target_coord[2])) 3132 { 3133 if (log) 3134 log->Printf("RenderScriptRuntime::KernelBreakpointHit, BREAKING %" PRIu64 ", %" PRIu64 ", %" PRIu64, 3135 current_coord[0], current_coord[1], current_coord[2]); 3136 3137 BreakpointSP breakpoint_sp = context.GetTargetPtr()->GetBreakpointByID(break_id); 3138 assert(breakpoint_sp != nullptr && "Error: Couldn't find breakpoint matching break id for callback"); 3139 breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint should only be hit once. 3140 return true; 3141 } 3142 3143 // No match on coordinate 3144 return false; 3145 } 3146 3147 // Tries to set a breakpoint on the start of a kernel, resolved using the kernel name. 3148 // Argument 'coords', represents a three dimensional coordinate which can be used to specify 3149 // a single kernel instance to break on. If this is set then we add a callback to the breakpoint. 3150 void 3151 RenderScriptRuntime::PlaceBreakpointOnKernel(Stream &strm, const char* name, const std::array<int,3> coords, 3152 Error& error, TargetSP target) 3153 { 3154 if (!name) 3155 { 3156 error.SetErrorString("invalid kernel name"); 3157 return; 3158 } 3159 3160 InitSearchFilter(target); 3161 3162 ConstString kernel_name(name); 3163 BreakpointSP bp = CreateKernelBreakpoint(kernel_name); 3164 3165 // We have a conditional breakpoint on a specific coordinate 3166 if (coords[0] != -1) 3167 { 3168 strm.Printf("Conditional kernel breakpoint on coordinate %d, %d, %d", coords[0], coords[1], coords[2]); 3169 strm.EOL(); 3170 3171 // Allocate memory for the baton, and copy over coordinate 3172 int* baton = new int[3]; 3173 baton[0] = coords[0]; baton[1] = coords[1]; baton[2] = coords[2]; 3174 3175 // Create a callback that will be invoked everytime the breakpoint is hit. 3176 // The baton object passed to the handler is the target coordinate we want to break on. 3177 bp->SetCallback(KernelBreakpointHit, baton, true); 3178 3179 // Store a shared pointer to the baton, so the memory will eventually be cleaned up after destruction 3180 m_conditional_breaks[bp->GetID()] = std::shared_ptr<int>(baton); 3181 } 3182 3183 if (bp) 3184 bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false); 3185 } 3186 3187 void 3188 RenderScriptRuntime::DumpModules(Stream &strm) const 3189 { 3190 strm.Printf("RenderScript Modules:"); 3191 strm.EOL(); 3192 strm.IndentMore(); 3193 for (const auto &module : m_rsmodules) 3194 { 3195 module->Dump(strm); 3196 } 3197 strm.IndentLess(); 3198 } 3199 3200 RenderScriptRuntime::ScriptDetails* 3201 RenderScriptRuntime::LookUpScript(addr_t address, bool create) 3202 { 3203 for (const auto & s : m_scripts) 3204 { 3205 if (s->script.isValid()) 3206 if (*s->script == address) 3207 return s.get(); 3208 } 3209 if (create) 3210 { 3211 std::unique_ptr<ScriptDetails> s(new ScriptDetails); 3212 s->script = address; 3213 m_scripts.push_back(std::move(s)); 3214 return m_scripts.back().get(); 3215 } 3216 return nullptr; 3217 } 3218 3219 RenderScriptRuntime::AllocationDetails* 3220 RenderScriptRuntime::LookUpAllocation(addr_t address, bool create) 3221 { 3222 for (const auto & a : m_allocations) 3223 { 3224 if (a->address.isValid()) 3225 if (*a->address == address) 3226 return a.get(); 3227 } 3228 if (create) 3229 { 3230 std::unique_ptr<AllocationDetails> a(new AllocationDetails); 3231 a->address = address; 3232 m_allocations.push_back(std::move(a)); 3233 return m_allocations.back().get(); 3234 } 3235 return nullptr; 3236 } 3237 3238 void 3239 RSModuleDescriptor::Dump(Stream &strm) const 3240 { 3241 strm.Indent(); 3242 m_module->GetFileSpec().Dump(&strm); 3243 if(m_module->GetNumCompileUnits()) 3244 { 3245 strm.Indent("Debug info loaded."); 3246 } 3247 else 3248 { 3249 strm.Indent("Debug info does not exist."); 3250 } 3251 strm.EOL(); 3252 strm.IndentMore(); 3253 strm.Indent(); 3254 strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size())); 3255 strm.EOL(); 3256 strm.IndentMore(); 3257 for (const auto &global : m_globals) 3258 { 3259 global.Dump(strm); 3260 } 3261 strm.IndentLess(); 3262 strm.Indent(); 3263 strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size())); 3264 strm.EOL(); 3265 strm.IndentMore(); 3266 for (const auto &kernel : m_kernels) 3267 { 3268 kernel.Dump(strm); 3269 } 3270 strm.Printf("Pragmas: %" PRIu64 , static_cast<uint64_t>(m_pragmas.size())); 3271 strm.EOL(); 3272 strm.IndentMore(); 3273 for (const auto &key_val : m_pragmas) 3274 { 3275 strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str()); 3276 strm.EOL(); 3277 } 3278 strm.IndentLess(4); 3279 } 3280 3281 void 3282 RSGlobalDescriptor::Dump(Stream &strm) const 3283 { 3284 strm.Indent(m_name.AsCString()); 3285 VariableList var_list; 3286 m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list); 3287 if (var_list.GetSize() == 1) 3288 { 3289 auto var = var_list.GetVariableAtIndex(0); 3290 auto type = var->GetType(); 3291 if(type) 3292 { 3293 strm.Printf(" - "); 3294 type->DumpTypeName(&strm); 3295 } 3296 else 3297 { 3298 strm.Printf(" - Unknown Type"); 3299 } 3300 } 3301 else 3302 { 3303 strm.Printf(" - variable identified, but not found in binary"); 3304 const Symbol* s = m_module->m_module->FindFirstSymbolWithNameAndType(m_name, eSymbolTypeData); 3305 if (s) 3306 { 3307 strm.Printf(" (symbol exists) "); 3308 } 3309 } 3310 3311 strm.EOL(); 3312 } 3313 3314 void 3315 RSKernelDescriptor::Dump(Stream &strm) const 3316 { 3317 strm.Indent(m_name.AsCString()); 3318 strm.EOL(); 3319 } 3320 3321 class CommandObjectRenderScriptRuntimeModuleProbe : public CommandObjectParsed 3322 { 3323 public: 3324 CommandObjectRenderScriptRuntimeModuleProbe(CommandInterpreter &interpreter) 3325 : CommandObjectParsed(interpreter, "renderscript module probe", 3326 "Initiates a Probe of all loaded modules for kernels and other renderscript objects.", 3327 "renderscript module probe", 3328 eCommandRequiresTarget | eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3329 { 3330 } 3331 3332 ~CommandObjectRenderScriptRuntimeModuleProbe() override = default; 3333 3334 bool 3335 DoExecute(Args &command, CommandReturnObject &result) override 3336 { 3337 const size_t argc = command.GetArgumentCount(); 3338 if (argc == 0) 3339 { 3340 Target *target = m_exe_ctx.GetTargetPtr(); 3341 RenderScriptRuntime *runtime = 3342 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3343 auto module_list = target->GetImages(); 3344 bool new_rs_details = runtime->ProbeModules(module_list); 3345 if (new_rs_details) 3346 { 3347 result.AppendMessage("New renderscript modules added to runtime model."); 3348 } 3349 result.SetStatus(eReturnStatusSuccessFinishResult); 3350 return true; 3351 } 3352 3353 result.AppendErrorWithFormat("'%s' takes no arguments", m_cmd_name.c_str()); 3354 result.SetStatus(eReturnStatusFailed); 3355 return false; 3356 } 3357 }; 3358 3359 class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed 3360 { 3361 public: 3362 CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter) 3363 : CommandObjectParsed(interpreter, "renderscript module dump", 3364 "Dumps renderscript specific information for all modules.", "renderscript module dump", 3365 eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3366 { 3367 } 3368 3369 ~CommandObjectRenderScriptRuntimeModuleDump() override = default; 3370 3371 bool 3372 DoExecute(Args &command, CommandReturnObject &result) override 3373 { 3374 RenderScriptRuntime *runtime = 3375 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3376 runtime->DumpModules(result.GetOutputStream()); 3377 result.SetStatus(eReturnStatusSuccessFinishResult); 3378 return true; 3379 } 3380 }; 3381 3382 class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword 3383 { 3384 public: 3385 CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter) 3386 : CommandObjectMultiword(interpreter, "renderscript module", "Commands that deal with renderscript modules.", 3387 NULL) 3388 { 3389 LoadSubCommand("probe", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleProbe(interpreter))); 3390 LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump(interpreter))); 3391 } 3392 3393 ~CommandObjectRenderScriptRuntimeModule() override = default; 3394 }; 3395 3396 class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed 3397 { 3398 public: 3399 CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter) 3400 : CommandObjectParsed(interpreter, "renderscript kernel list", 3401 "Lists renderscript kernel names and associated script resources.", "renderscript kernel list", 3402 eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3403 { 3404 } 3405 3406 ~CommandObjectRenderScriptRuntimeKernelList() override = default; 3407 3408 bool 3409 DoExecute(Args &command, CommandReturnObject &result) override 3410 { 3411 RenderScriptRuntime *runtime = 3412 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3413 runtime->DumpKernels(result.GetOutputStream()); 3414 result.SetStatus(eReturnStatusSuccessFinishResult); 3415 return true; 3416 } 3417 }; 3418 3419 class CommandObjectRenderScriptRuntimeKernelBreakpointSet : public CommandObjectParsed 3420 { 3421 public: 3422 CommandObjectRenderScriptRuntimeKernelBreakpointSet(CommandInterpreter &interpreter) 3423 : CommandObjectParsed(interpreter, "renderscript kernel breakpoint set", 3424 "Sets a breakpoint on a renderscript kernel.", "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]", 3425 eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), m_options(interpreter) 3426 { 3427 } 3428 3429 ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default; 3430 3431 Options* 3432 GetOptions() override 3433 { 3434 return &m_options; 3435 } 3436 3437 class CommandOptions : public Options 3438 { 3439 public: 3440 CommandOptions(CommandInterpreter &interpreter) : Options(interpreter) 3441 { 3442 } 3443 3444 ~CommandOptions() override = default; 3445 3446 Error 3447 SetOptionValue(uint32_t option_idx, const char *option_arg) override 3448 { 3449 Error error; 3450 const int short_option = m_getopt_table[option_idx].val; 3451 3452 switch (short_option) 3453 { 3454 case 'c': 3455 if (!ParseCoordinate(option_arg)) 3456 error.SetErrorStringWithFormat("Couldn't parse coordinate '%s', should be in format 'x,y,z'.", option_arg); 3457 break; 3458 default: 3459 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 3460 break; 3461 } 3462 return error; 3463 } 3464 3465 // -c takes an argument of the form 'num[,num][,num]'. 3466 // Where 'id_cstr' is this argument with the whitespace trimmed. 3467 // Missing coordinates are defaulted to zero. 3468 bool 3469 ParseCoordinate(const char* id_cstr) 3470 { 3471 RegularExpression regex; 3472 RegularExpression::Match regex_match(3); 3473 3474 bool matched = false; 3475 if(regex.Compile("^([0-9]+),([0-9]+),([0-9]+)$") && regex.Execute(id_cstr, ®ex_match)) 3476 matched = true; 3477 else if(regex.Compile("^([0-9]+),([0-9]+)$") && regex.Execute(id_cstr, ®ex_match)) 3478 matched = true; 3479 else if(regex.Compile("^([0-9]+)$") && regex.Execute(id_cstr, ®ex_match)) 3480 matched = true; 3481 for(uint32_t i = 0; i < 3; i++) 3482 { 3483 std::string group; 3484 if(regex_match.GetMatchAtIndex(id_cstr, i + 1, group)) 3485 m_coord[i] = (uint32_t)strtoul(group.c_str(), NULL, 0); 3486 else 3487 m_coord[i] = 0; 3488 } 3489 return matched; 3490 } 3491 3492 void 3493 OptionParsingStarting() override 3494 { 3495 // -1 means the -c option hasn't been set 3496 m_coord[0] = -1; 3497 m_coord[1] = -1; 3498 m_coord[2] = -1; 3499 } 3500 3501 const OptionDefinition* 3502 GetDefinitions() override 3503 { 3504 return g_option_table; 3505 } 3506 3507 static OptionDefinition g_option_table[]; 3508 std::array<int,3> m_coord; 3509 }; 3510 3511 bool 3512 DoExecute(Args &command, CommandReturnObject &result) override 3513 { 3514 const size_t argc = command.GetArgumentCount(); 3515 if (argc < 1) 3516 { 3517 result.AppendErrorWithFormat("'%s' takes 1 argument of kernel name, and an optional coordinate.", m_cmd_name.c_str()); 3518 result.SetStatus(eReturnStatusFailed); 3519 return false; 3520 } 3521 3522 RenderScriptRuntime *runtime = 3523 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3524 3525 Error error; 3526 runtime->PlaceBreakpointOnKernel(result.GetOutputStream(), command.GetArgumentAtIndex(0), m_options.m_coord, 3527 error, m_exe_ctx.GetTargetSP()); 3528 3529 if (error.Success()) 3530 { 3531 result.AppendMessage("Breakpoint(s) created"); 3532 result.SetStatus(eReturnStatusSuccessFinishResult); 3533 return true; 3534 } 3535 result.SetStatus(eReturnStatusFailed); 3536 result.AppendErrorWithFormat("Error: %s", error.AsCString()); 3537 return false; 3538 } 3539 3540 private: 3541 CommandOptions m_options; 3542 }; 3543 3544 OptionDefinition 3545 CommandObjectRenderScriptRuntimeKernelBreakpointSet::CommandOptions::g_option_table[] = 3546 { 3547 { LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeValue, 3548 "Set a breakpoint on a single invocation of the kernel with specified coordinate.\n" 3549 "Coordinate takes the form 'x[,y][,z] where x,y,z are positive integers representing kernel dimensions. " 3550 "Any unset dimensions will be defaulted to zero."}, 3551 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 3552 }; 3553 3554 class CommandObjectRenderScriptRuntimeKernelBreakpointAll : public CommandObjectParsed 3555 { 3556 public: 3557 CommandObjectRenderScriptRuntimeKernelBreakpointAll(CommandInterpreter &interpreter) 3558 : CommandObjectParsed(interpreter, "renderscript kernel breakpoint all", 3559 "Automatically sets a breakpoint on all renderscript kernels that are or will be loaded.\n" 3560 "Disabling option means breakpoints will no longer be set on any kernels loaded in the future, " 3561 "but does not remove currently set breakpoints.", 3562 "renderscript kernel breakpoint all <enable/disable>", 3563 eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) 3564 { 3565 } 3566 3567 ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default; 3568 3569 bool 3570 DoExecute(Args &command, CommandReturnObject &result) override 3571 { 3572 const size_t argc = command.GetArgumentCount(); 3573 if (argc != 1) 3574 { 3575 result.AppendErrorWithFormat("'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str()); 3576 result.SetStatus(eReturnStatusFailed); 3577 return false; 3578 } 3579 3580 RenderScriptRuntime *runtime = 3581 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 3582 3583 bool do_break = false; 3584 const char* argument = command.GetArgumentAtIndex(0); 3585 if (strcmp(argument, "enable") == 0) 3586 { 3587 do_break = true; 3588 result.AppendMessage("Breakpoints will be set on all kernels."); 3589 } 3590 else if (strcmp(argument, "disable") == 0) 3591 { 3592 do_break = false; 3593 result.AppendMessage("Breakpoints will not be set on any new kernels."); 3594 } 3595 else 3596 { 3597 result.AppendErrorWithFormat("Argument must be either 'enable' or 'disable'"); 3598 result.SetStatus(eReturnStatusFailed); 3599 return false; 3600 } 3601 3602 runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP()); 3603 3604 result.SetStatus(eReturnStatusSuccessFinishResult); 3605 return true; 3606 } 3607 }; 3608 3609 class CommandObjectRenderScriptRuntimeKernelBreakpoint : public CommandObjectMultiword 3610 { 3611 public: 3612 CommandObjectRenderScriptRuntimeKernelBreakpoint(CommandInterpreter &interpreter) 3613 : CommandObjectMultiword(interpreter, "renderscript kernel", "Commands that generate breakpoints on renderscript kernels.", 3614 nullptr) 3615 { 3616 LoadSubCommand("set", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet(interpreter))); 3617 LoadSubCommand("all", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll(interpreter))); 3618 } 3619 3620 ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default; 3621 }; 3622 3623 class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword 3624 { 3625 public: 3626 CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter) 3627 : CommandObjectMultiword(interpreter, "renderscript kernel", "Commands that deal with renderscript kernels.", 3628 NULL) 3629 { 3630 LoadSubCommand("list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList(interpreter))); 3631 LoadSubCommand("breakpoint", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter))); 3632 } 3633 3634 ~CommandObjectRenderScriptRuntimeKernel() override = default; 3635 }; 3636 3637 class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed 3638 { 3639 public: 3640 CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter) 3641 : CommandObjectParsed(interpreter, "renderscript context dump", 3642 "Dumps renderscript context information.", "renderscript context dump", 3643 eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3644 { 3645 } 3646 3647 ~CommandObjectRenderScriptRuntimeContextDump() override = default; 3648 3649 bool 3650 DoExecute(Args &command, CommandReturnObject &result) override 3651 { 3652 RenderScriptRuntime *runtime = 3653 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3654 runtime->DumpContexts(result.GetOutputStream()); 3655 result.SetStatus(eReturnStatusSuccessFinishResult); 3656 return true; 3657 } 3658 }; 3659 3660 class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword 3661 { 3662 public: 3663 CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter) 3664 : CommandObjectMultiword(interpreter, "renderscript context", "Commands that deal with renderscript contexts.", 3665 NULL) 3666 { 3667 LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump(interpreter))); 3668 } 3669 3670 ~CommandObjectRenderScriptRuntimeContext() override = default; 3671 }; 3672 3673 class CommandObjectRenderScriptRuntimeAllocationDump : public CommandObjectParsed 3674 { 3675 public: 3676 CommandObjectRenderScriptRuntimeAllocationDump(CommandInterpreter &interpreter) 3677 : CommandObjectParsed(interpreter, "renderscript allocation dump", 3678 "Displays the contents of a particular allocation", "renderscript allocation dump <ID>", 3679 eCommandRequiresProcess | eCommandProcessMustBeLaunched), m_options(interpreter) 3680 { 3681 } 3682 3683 ~CommandObjectRenderScriptRuntimeAllocationDump() override = default; 3684 3685 Options* 3686 GetOptions() override 3687 { 3688 return &m_options; 3689 } 3690 3691 class CommandOptions : public Options 3692 { 3693 public: 3694 CommandOptions(CommandInterpreter &interpreter) : Options(interpreter) 3695 { 3696 } 3697 3698 ~CommandOptions() override = default; 3699 3700 Error 3701 SetOptionValue(uint32_t option_idx, const char *option_arg) override 3702 { 3703 Error error; 3704 const int short_option = m_getopt_table[option_idx].val; 3705 3706 switch (short_option) 3707 { 3708 case 'f': 3709 m_outfile.SetFile(option_arg, true); 3710 if (m_outfile.Exists()) 3711 { 3712 m_outfile.Clear(); 3713 error.SetErrorStringWithFormat("file already exists: '%s'", option_arg); 3714 } 3715 break; 3716 default: 3717 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 3718 break; 3719 } 3720 return error; 3721 } 3722 3723 void 3724 OptionParsingStarting() override 3725 { 3726 m_outfile.Clear(); 3727 } 3728 3729 const OptionDefinition* 3730 GetDefinitions() override 3731 { 3732 return g_option_table; 3733 } 3734 3735 static OptionDefinition g_option_table[]; 3736 FileSpec m_outfile; 3737 }; 3738 3739 bool 3740 DoExecute(Args &command, CommandReturnObject &result) override 3741 { 3742 const size_t argc = command.GetArgumentCount(); 3743 if (argc < 1) 3744 { 3745 result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. As well as an optional -f argument", 3746 m_cmd_name.c_str()); 3747 result.SetStatus(eReturnStatusFailed); 3748 return false; 3749 } 3750 3751 RenderScriptRuntime *runtime = 3752 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 3753 3754 const char* id_cstr = command.GetArgumentAtIndex(0); 3755 bool convert_complete = false; 3756 const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 3757 if (!convert_complete) 3758 { 3759 result.AppendErrorWithFormat("invalid allocation id argument '%s'", id_cstr); 3760 result.SetStatus(eReturnStatusFailed); 3761 return false; 3762 } 3763 3764 Stream* output_strm = nullptr; 3765 StreamFile outfile_stream; 3766 const FileSpec &outfile_spec = m_options.m_outfile; // Dump allocation to file instead 3767 if (outfile_spec) 3768 { 3769 // Open output file 3770 char path[256]; 3771 outfile_spec.GetPath(path, sizeof(path)); 3772 if (outfile_stream.GetFile().Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate).Success()) 3773 { 3774 output_strm = &outfile_stream; 3775 result.GetOutputStream().Printf("Results written to '%s'", path); 3776 result.GetOutputStream().EOL(); 3777 } 3778 else 3779 { 3780 result.AppendErrorWithFormat("Couldn't open file '%s'", path); 3781 result.SetStatus(eReturnStatusFailed); 3782 return false; 3783 } 3784 } 3785 else 3786 output_strm = &result.GetOutputStream(); 3787 3788 assert(output_strm != nullptr); 3789 bool success = runtime->DumpAllocation(*output_strm, m_exe_ctx.GetFramePtr(), id); 3790 3791 if (success) 3792 result.SetStatus(eReturnStatusSuccessFinishResult); 3793 else 3794 result.SetStatus(eReturnStatusFailed); 3795 3796 return true; 3797 } 3798 3799 private: 3800 CommandOptions m_options; 3801 }; 3802 3803 OptionDefinition 3804 CommandObjectRenderScriptRuntimeAllocationDump::CommandOptions::g_option_table[] = 3805 { 3806 { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, 3807 "Print results to specified file instead of command line."}, 3808 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 3809 }; 3810 3811 class CommandObjectRenderScriptRuntimeAllocationList : public CommandObjectParsed 3812 { 3813 public: 3814 CommandObjectRenderScriptRuntimeAllocationList(CommandInterpreter &interpreter) 3815 : CommandObjectParsed(interpreter, "renderscript allocation list", 3816 "List renderscript allocations and their information.", "renderscript allocation list", 3817 eCommandRequiresProcess | eCommandProcessMustBeLaunched), m_options(interpreter) 3818 { 3819 } 3820 3821 ~CommandObjectRenderScriptRuntimeAllocationList() override = default; 3822 3823 Options* 3824 GetOptions() override 3825 { 3826 return &m_options; 3827 } 3828 3829 class CommandOptions : public Options 3830 { 3831 public: 3832 CommandOptions(CommandInterpreter &interpreter) : Options(interpreter), m_refresh(false) 3833 { 3834 } 3835 3836 ~CommandOptions() override = default; 3837 3838 Error 3839 SetOptionValue(uint32_t option_idx, const char *option_arg) override 3840 { 3841 Error error; 3842 const int short_option = m_getopt_table[option_idx].val; 3843 3844 switch (short_option) 3845 { 3846 case 'r': 3847 m_refresh = true; 3848 break; 3849 default: 3850 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 3851 break; 3852 } 3853 return error; 3854 } 3855 3856 void 3857 OptionParsingStarting() override 3858 { 3859 m_refresh = false; 3860 } 3861 3862 const OptionDefinition* 3863 GetDefinitions() override 3864 { 3865 return g_option_table; 3866 } 3867 3868 static OptionDefinition g_option_table[]; 3869 bool m_refresh; 3870 }; 3871 3872 bool 3873 DoExecute(Args &command, CommandReturnObject &result) override 3874 { 3875 RenderScriptRuntime *runtime = 3876 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 3877 runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(), m_options.m_refresh); 3878 result.SetStatus(eReturnStatusSuccessFinishResult); 3879 return true; 3880 } 3881 3882 private: 3883 CommandOptions m_options; 3884 }; 3885 3886 OptionDefinition 3887 CommandObjectRenderScriptRuntimeAllocationList::CommandOptions::g_option_table[] = 3888 { 3889 { LLDB_OPT_SET_1, false, "refresh", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 3890 "Recompute allocation details."}, 3891 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 3892 }; 3893 3894 class CommandObjectRenderScriptRuntimeAllocationLoad : public CommandObjectParsed 3895 { 3896 public: 3897 CommandObjectRenderScriptRuntimeAllocationLoad(CommandInterpreter &interpreter) 3898 : CommandObjectParsed(interpreter, "renderscript allocation load", 3899 "Loads renderscript allocation contents from a file.", "renderscript allocation load <ID> <filename>", 3900 eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3901 { 3902 } 3903 3904 ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default; 3905 3906 bool 3907 DoExecute(Args &command, CommandReturnObject &result) override 3908 { 3909 const size_t argc = command.GetArgumentCount(); 3910 if (argc != 2) 3911 { 3912 result.AppendErrorWithFormat("'%s' takes 2 arguments, an allocation ID and filename to read from.", m_cmd_name.c_str()); 3913 result.SetStatus(eReturnStatusFailed); 3914 return false; 3915 } 3916 3917 RenderScriptRuntime *runtime = 3918 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 3919 3920 const char* id_cstr = command.GetArgumentAtIndex(0); 3921 bool convert_complete = false; 3922 const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 3923 if (!convert_complete) 3924 { 3925 result.AppendErrorWithFormat ("invalid allocation id argument '%s'", id_cstr); 3926 result.SetStatus (eReturnStatusFailed); 3927 return false; 3928 } 3929 3930 const char* filename = command.GetArgumentAtIndex(1); 3931 bool success = runtime->LoadAllocation(result.GetOutputStream(), id, filename, m_exe_ctx.GetFramePtr()); 3932 3933 if (success) 3934 result.SetStatus(eReturnStatusSuccessFinishResult); 3935 else 3936 result.SetStatus(eReturnStatusFailed); 3937 3938 return true; 3939 } 3940 }; 3941 3942 class CommandObjectRenderScriptRuntimeAllocationSave : public CommandObjectParsed 3943 { 3944 public: 3945 CommandObjectRenderScriptRuntimeAllocationSave(CommandInterpreter &interpreter) 3946 : CommandObjectParsed(interpreter, "renderscript allocation save", 3947 "Write renderscript allocation contents to a file.", "renderscript allocation save <ID> <filename>", 3948 eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3949 { 3950 } 3951 3952 ~CommandObjectRenderScriptRuntimeAllocationSave() override = default; 3953 3954 bool 3955 DoExecute(Args &command, CommandReturnObject &result) override 3956 { 3957 const size_t argc = command.GetArgumentCount(); 3958 if (argc != 2) 3959 { 3960 result.AppendErrorWithFormat("'%s' takes 2 arguments, an allocation ID and filename to read from.", m_cmd_name.c_str()); 3961 result.SetStatus(eReturnStatusFailed); 3962 return false; 3963 } 3964 3965 RenderScriptRuntime *runtime = 3966 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 3967 3968 const char* id_cstr = command.GetArgumentAtIndex(0); 3969 bool convert_complete = false; 3970 const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 3971 if (!convert_complete) 3972 { 3973 result.AppendErrorWithFormat ("invalid allocation id argument '%s'", id_cstr); 3974 result.SetStatus (eReturnStatusFailed); 3975 return false; 3976 } 3977 3978 const char* filename = command.GetArgumentAtIndex(1); 3979 bool success = runtime->SaveAllocation(result.GetOutputStream(), id, filename, m_exe_ctx.GetFramePtr()); 3980 3981 if (success) 3982 result.SetStatus(eReturnStatusSuccessFinishResult); 3983 else 3984 result.SetStatus(eReturnStatusFailed); 3985 3986 return true; 3987 } 3988 }; 3989 3990 class CommandObjectRenderScriptRuntimeAllocation : public CommandObjectMultiword 3991 { 3992 public: 3993 CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter) 3994 : CommandObjectMultiword(interpreter, "renderscript allocation", "Commands that deal with renderscript allocations.", 3995 NULL) 3996 { 3997 LoadSubCommand("list", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationList(interpreter))); 3998 LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationDump(interpreter))); 3999 LoadSubCommand("save", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationSave(interpreter))); 4000 LoadSubCommand("load", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter))); 4001 } 4002 4003 ~CommandObjectRenderScriptRuntimeAllocation() override = default; 4004 }; 4005 4006 class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed 4007 { 4008 public: 4009 CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter) 4010 : CommandObjectParsed(interpreter, "renderscript status", 4011 "Displays current renderscript runtime status.", "renderscript status", 4012 eCommandRequiresProcess | eCommandProcessMustBeLaunched) 4013 { 4014 } 4015 4016 ~CommandObjectRenderScriptRuntimeStatus() override = default; 4017 4018 bool 4019 DoExecute(Args &command, CommandReturnObject &result) override 4020 { 4021 RenderScriptRuntime *runtime = 4022 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 4023 runtime->Status(result.GetOutputStream()); 4024 result.SetStatus(eReturnStatusSuccessFinishResult); 4025 return true; 4026 } 4027 }; 4028 4029 class CommandObjectRenderScriptRuntime : public CommandObjectMultiword 4030 { 4031 public: 4032 CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter) 4033 : CommandObjectMultiword(interpreter, "renderscript", "A set of commands for operating on renderscript.", 4034 "renderscript <subcommand> [<subcommand-options>]") 4035 { 4036 LoadSubCommand("module", CommandObjectSP(new CommandObjectRenderScriptRuntimeModule(interpreter))); 4037 LoadSubCommand("status", CommandObjectSP(new CommandObjectRenderScriptRuntimeStatus(interpreter))); 4038 LoadSubCommand("kernel", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernel(interpreter))); 4039 LoadSubCommand("context", CommandObjectSP(new CommandObjectRenderScriptRuntimeContext(interpreter))); 4040 LoadSubCommand("allocation", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocation(interpreter))); 4041 } 4042 4043 ~CommandObjectRenderScriptRuntime() override = default; 4044 }; 4045 4046 void 4047 RenderScriptRuntime::Initiate() 4048 { 4049 assert(!m_initiated); 4050 } 4051 4052 RenderScriptRuntime::RenderScriptRuntime(Process *process) 4053 : lldb_private::CPPLanguageRuntime(process), m_initiated(false), m_debuggerPresentFlagged(false), 4054 m_breakAllKernels(false) 4055 { 4056 ModulesDidLoad(process->GetTarget().GetImages()); 4057 } 4058 4059 lldb::CommandObjectSP 4060 RenderScriptRuntime::GetCommandObject(lldb_private::CommandInterpreter& interpreter) 4061 { 4062 static CommandObjectSP command_object; 4063 if(!command_object) 4064 { 4065 command_object.reset(new CommandObjectRenderScriptRuntime(interpreter)); 4066 } 4067 return command_object; 4068 } 4069 4070 RenderScriptRuntime::~RenderScriptRuntime() = default; 4071