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