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