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 void 2593 RenderScriptRuntime::Status(Stream &strm) const 2594 { 2595 if (m_libRS) 2596 { 2597 strm.Printf("Runtime Library discovered."); 2598 strm.EOL(); 2599 } 2600 if (m_libRSDriver) 2601 { 2602 strm.Printf("Runtime Driver discovered."); 2603 strm.EOL(); 2604 } 2605 if (m_libRSCpuRef) 2606 { 2607 strm.Printf("CPU Reference Implementation discovered."); 2608 strm.EOL(); 2609 } 2610 2611 if (m_runtimeHooks.size()) 2612 { 2613 strm.Printf("Runtime functions hooked:"); 2614 strm.EOL(); 2615 for (auto b : m_runtimeHooks) 2616 { 2617 strm.Indent(b.second->defn->name); 2618 strm.EOL(); 2619 } 2620 } 2621 else 2622 { 2623 strm.Printf("Runtime is not hooked."); 2624 strm.EOL(); 2625 } 2626 } 2627 2628 void 2629 RenderScriptRuntime::DumpContexts(Stream &strm) const 2630 { 2631 strm.Printf("Inferred RenderScript Contexts:"); 2632 strm.EOL(); 2633 strm.IndentMore(); 2634 2635 std::map<addr_t, uint64_t> contextReferences; 2636 2637 // Iterate over all of the currently discovered scripts. 2638 // Note: We cant push or pop from m_scripts inside this loop or it may invalidate script. 2639 for (const auto &script : m_scripts) 2640 { 2641 if (!script->context.isValid()) 2642 continue; 2643 lldb::addr_t context = *script->context; 2644 2645 if (contextReferences.find(context) != contextReferences.end()) 2646 { 2647 contextReferences[context]++; 2648 } 2649 else 2650 { 2651 contextReferences[context] = 1; 2652 } 2653 } 2654 2655 for (const auto &cRef : contextReferences) 2656 { 2657 strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances", cRef.first, cRef.second); 2658 strm.EOL(); 2659 } 2660 strm.IndentLess(); 2661 } 2662 2663 void 2664 RenderScriptRuntime::DumpKernels(Stream &strm) const 2665 { 2666 strm.Printf("RenderScript Kernels:"); 2667 strm.EOL(); 2668 strm.IndentMore(); 2669 for (const auto &module : m_rsmodules) 2670 { 2671 strm.Printf("Resource '%s':", module->m_resname.c_str()); 2672 strm.EOL(); 2673 for (const auto &kernel : module->m_kernels) 2674 { 2675 strm.Indent(kernel.m_name.AsCString()); 2676 strm.EOL(); 2677 } 2678 } 2679 strm.IndentLess(); 2680 } 2681 2682 RenderScriptRuntime::AllocationDetails * 2683 RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) 2684 { 2685 AllocationDetails *alloc = nullptr; 2686 2687 // See if we can find allocation using id as an index; 2688 if (alloc_id <= m_allocations.size() && alloc_id != 0 && m_allocations[alloc_id - 1]->id == alloc_id) 2689 { 2690 alloc = m_allocations[alloc_id - 1].get(); 2691 return alloc; 2692 } 2693 2694 // Fallback to searching 2695 for (const auto &a : m_allocations) 2696 { 2697 if (a->id == alloc_id) 2698 { 2699 alloc = a.get(); 2700 break; 2701 } 2702 } 2703 2704 if (alloc == nullptr) 2705 { 2706 strm.Printf("Error: Couldn't find allocation with id matching %" PRIu32, alloc_id); 2707 strm.EOL(); 2708 } 2709 2710 return alloc; 2711 } 2712 2713 // Prints the contents of an allocation to the output stream, which may be a file 2714 bool 2715 RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr, const uint32_t id) 2716 { 2717 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2718 2719 // Check we can find the desired allocation 2720 AllocationDetails *alloc = FindAllocByID(strm, id); 2721 if (!alloc) 2722 return false; // FindAllocByID() will print error message for us here 2723 2724 if (log) 2725 log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__, *alloc->address.get()); 2726 2727 // Check we have information about the allocation, if not calculate it 2728 if (alloc->shouldRefresh()) 2729 { 2730 if (log) 2731 log->Printf("%s - allocation details not calculated yet, jitting info.", __FUNCTION__); 2732 2733 // JIT all the allocation information 2734 if (!RefreshAllocation(alloc, frame_ptr)) 2735 { 2736 strm.Printf("Error: Couldn't JIT allocation details"); 2737 strm.EOL(); 2738 return false; 2739 } 2740 } 2741 2742 // Establish format and size of each data element 2743 const uint32_t vec_size = *alloc->element.type_vec_size.get(); 2744 const Element::DataType type = *alloc->element.type.get(); 2745 2746 assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && "Invalid allocation type"); 2747 2748 lldb::Format format; 2749 if (type >= Element::RS_TYPE_ELEMENT) 2750 format = eFormatHex; 2751 else 2752 format = vec_size == 1 ? static_cast<lldb::Format>(AllocationDetails::RSTypeToFormat[type][eFormatSingle]) 2753 : static_cast<lldb::Format>(AllocationDetails::RSTypeToFormat[type][eFormatVector]); 2754 2755 const uint32_t data_size = *alloc->element.datum_size.get(); 2756 2757 if (log) 2758 log->Printf("%s - element size %" PRIu32 " bytes, including padding", __FUNCTION__, data_size); 2759 2760 // Allocate a buffer to copy data into 2761 std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); 2762 if (!buffer) 2763 { 2764 strm.Printf("Error: Couldn't read allocation data"); 2765 strm.EOL(); 2766 return false; 2767 } 2768 2769 // Calculate stride between rows as there may be padding at end of rows since 2770 // allocated memory is 16-byte aligned 2771 if (!alloc->stride.isValid()) 2772 { 2773 if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension 2774 alloc->stride = 0; 2775 else if (!JITAllocationStride(alloc, frame_ptr)) 2776 { 2777 strm.Printf("Error: Couldn't calculate allocation row stride"); 2778 strm.EOL(); 2779 return false; 2780 } 2781 } 2782 const uint32_t stride = *alloc->stride.get(); 2783 const uint32_t size = *alloc->size.get(); // Size of whole allocation 2784 const uint32_t padding = alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0; 2785 if (log) 2786 log->Printf("%s - stride %" PRIu32 " bytes, size %" PRIu32 " bytes, padding %" PRIu32, 2787 __FUNCTION__, stride, size, padding); 2788 2789 // Find dimensions used to index loops, so need to be non-zero 2790 uint32_t dim_x = alloc->dimension.get()->dim_1; 2791 dim_x = dim_x == 0 ? 1 : dim_x; 2792 2793 uint32_t dim_y = alloc->dimension.get()->dim_2; 2794 dim_y = dim_y == 0 ? 1 : dim_y; 2795 2796 uint32_t dim_z = alloc->dimension.get()->dim_3; 2797 dim_z = dim_z == 0 ? 1 : dim_z; 2798 2799 // Use data extractor to format output 2800 const uint32_t archByteSize = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 2801 DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(), archByteSize); 2802 2803 uint32_t offset = 0; // Offset in buffer to next element to be printed 2804 uint32_t prev_row = 0; // Offset to the start of the previous row 2805 2806 // Iterate over allocation dimensions, printing results to user 2807 strm.Printf("Data (X, Y, Z):"); 2808 for (uint32_t z = 0; z < dim_z; ++z) 2809 { 2810 for (uint32_t y = 0; y < dim_y; ++y) 2811 { 2812 // Use stride to index start of next row. 2813 if (!(y == 0 && z == 0)) 2814 offset = prev_row + stride; 2815 prev_row = offset; 2816 2817 // Print each element in the row individually 2818 for (uint32_t x = 0; x < dim_x; ++x) 2819 { 2820 strm.Printf("\n(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") = ", x, y, z); 2821 if ((type == Element::RS_TYPE_NONE) && (alloc->element.children.size() > 0) && 2822 (alloc->element.type_name != Element::GetFallbackStructName())) 2823 { 2824 // Here we are dumping an Element of struct type. 2825 // This is done using expression evaluation with the name of the struct type and pointer to element. 2826 2827 // Don't print the name of the resulting expression, since this will be '$[0-9]+' 2828 DumpValueObjectOptions expr_options; 2829 expr_options.SetHideName(true); 2830 2831 // Setup expression as derefrencing a pointer cast to element address. 2832 const int max_expr_size = 512; 2833 char expr_char_buffer[max_expr_size]; 2834 int chars_written = snprintf(expr_char_buffer, max_expr_size, "*(%s*) 0x%" PRIx64, 2835 alloc->element.type_name.AsCString(), *alloc->data_ptr.get() + offset); 2836 2837 if (chars_written < 0 || chars_written >= max_expr_size) 2838 { 2839 if (log) 2840 log->Printf("%s - error in snprintf().", __FUNCTION__); 2841 continue; 2842 } 2843 2844 // Evaluate expression 2845 ValueObjectSP expr_result; 2846 GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer, frame_ptr, expr_result); 2847 2848 // Print the results to our stream. 2849 expr_result->Dump(strm, expr_options); 2850 } 2851 else 2852 { 2853 alloc_data.Dump(&strm, offset, format, data_size - padding, 1, 1, LLDB_INVALID_ADDRESS, 0, 0); 2854 } 2855 offset += data_size; 2856 } 2857 } 2858 } 2859 strm.EOL(); 2860 2861 return true; 2862 } 2863 2864 // Function recalculates all our cached information about allocations by jitting the 2865 // RS runtime regarding each allocation we know about. 2866 // Returns true if all allocations could be recomputed, false otherwise. 2867 bool 2868 RenderScriptRuntime::RecomputeAllAllocations(Stream &strm, StackFrame *frame_ptr) 2869 { 2870 bool success = true; 2871 for (auto &alloc : m_allocations) 2872 { 2873 // JIT current allocation information 2874 if (!RefreshAllocation(alloc.get(), frame_ptr)) 2875 { 2876 strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32 "\n", alloc->id); 2877 success = false; 2878 } 2879 } 2880 2881 if (success) 2882 strm.Printf("All allocations successfully recomputed"); 2883 strm.EOL(); 2884 2885 return success; 2886 } 2887 2888 // Prints information regarding currently loaded allocations. 2889 // These details are gathered by jitting the runtime, which has as latency. 2890 // Index parameter specifies a single allocation ID to print, or a zero value to print them all 2891 void 2892 RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame *frame_ptr, const uint32_t index) 2893 { 2894 strm.Printf("RenderScript Allocations:"); 2895 strm.EOL(); 2896 strm.IndentMore(); 2897 2898 for (auto &alloc : m_allocations) 2899 { 2900 // index will only be zero if we want to print all allocations 2901 if (index != 0 && index != alloc->id) 2902 continue; 2903 2904 // JIT current allocation information 2905 if (alloc->shouldRefresh() && !RefreshAllocation(alloc.get(), frame_ptr)) 2906 { 2907 strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32, alloc->id); 2908 strm.EOL(); 2909 continue; 2910 } 2911 2912 strm.Printf("%" PRIu32 ":", alloc->id); 2913 strm.EOL(); 2914 strm.IndentMore(); 2915 2916 strm.Indent("Context: "); 2917 if (!alloc->context.isValid()) 2918 strm.Printf("unknown\n"); 2919 else 2920 strm.Printf("0x%" PRIx64 "\n", *alloc->context.get()); 2921 2922 strm.Indent("Address: "); 2923 if (!alloc->address.isValid()) 2924 strm.Printf("unknown\n"); 2925 else 2926 strm.Printf("0x%" PRIx64 "\n", *alloc->address.get()); 2927 2928 strm.Indent("Data pointer: "); 2929 if (!alloc->data_ptr.isValid()) 2930 strm.Printf("unknown\n"); 2931 else 2932 strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get()); 2933 2934 strm.Indent("Dimensions: "); 2935 if (!alloc->dimension.isValid()) 2936 strm.Printf("unknown\n"); 2937 else 2938 strm.Printf("(%" PRId32 ", %" PRId32 ", %" PRId32 ")\n", 2939 alloc->dimension.get()->dim_1, alloc->dimension.get()->dim_2, alloc->dimension.get()->dim_3); 2940 2941 strm.Indent("Data Type: "); 2942 if (!alloc->element.type.isValid() || !alloc->element.type_vec_size.isValid()) 2943 strm.Printf("unknown\n"); 2944 else 2945 { 2946 const int vector_size = *alloc->element.type_vec_size.get(); 2947 Element::DataType type = *alloc->element.type.get(); 2948 2949 if (!alloc->element.type_name.IsEmpty()) 2950 strm.Printf("%s\n", alloc->element.type_name.AsCString()); 2951 else 2952 { 2953 // Enum value isn't monotonous, so doesn't always index RsDataTypeToString array 2954 if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT) 2955 type = static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) + 2956 Element::RS_TYPE_MATRIX_2X2 + 1); 2957 2958 if (type >= (sizeof(AllocationDetails::RsDataTypeToString) / 2959 sizeof(AllocationDetails::RsDataTypeToString[0])) || 2960 vector_size > 4 || vector_size < 1) 2961 strm.Printf("invalid type\n"); 2962 else 2963 strm.Printf("%s\n", AllocationDetails::RsDataTypeToString[static_cast<uint32_t>(type)] 2964 [vector_size - 1]); 2965 } 2966 } 2967 2968 strm.Indent("Data Kind: "); 2969 if (!alloc->element.type_kind.isValid()) 2970 strm.Printf("unknown\n"); 2971 else 2972 { 2973 const Element::DataKind kind = *alloc->element.type_kind.get(); 2974 if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV) 2975 strm.Printf("invalid kind\n"); 2976 else 2977 strm.Printf("%s\n", AllocationDetails::RsDataKindToString[static_cast<uint32_t>(kind)]); 2978 } 2979 2980 strm.EOL(); 2981 strm.IndentLess(); 2982 } 2983 strm.IndentLess(); 2984 } 2985 2986 // Set breakpoints on every kernel found in RS module 2987 void 2988 RenderScriptRuntime::BreakOnModuleKernels(const RSModuleDescriptorSP rsmodule_sp) 2989 { 2990 for (const auto &kernel : rsmodule_sp->m_kernels) 2991 { 2992 // Don't set breakpoint on 'root' kernel 2993 if (strcmp(kernel.m_name.AsCString(), "root") == 0) 2994 continue; 2995 2996 CreateKernelBreakpoint(kernel.m_name); 2997 } 2998 } 2999 3000 // Method is internally called by the 'kernel breakpoint all' command to 3001 // enable or disable breaking on all kernels. 3002 // 3003 // When do_break is true we want to enable this functionality. 3004 // When do_break is false we want to disable it. 3005 void 3006 RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) 3007 { 3008 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3009 3010 InitSearchFilter(target); 3011 3012 // Set breakpoints on all the kernels 3013 if (do_break && !m_breakAllKernels) 3014 { 3015 m_breakAllKernels = true; 3016 3017 for (const auto &module : m_rsmodules) 3018 BreakOnModuleKernels(module); 3019 3020 if (log) 3021 log->Printf("%s(True) - breakpoints set on all currently loaded kernels.", __FUNCTION__); 3022 } 3023 else if (!do_break && m_breakAllKernels) // Breakpoints won't be set on any new kernels. 3024 { 3025 m_breakAllKernels = false; 3026 3027 if (log) 3028 log->Printf("%s(False) - breakpoints no longer automatically set.", __FUNCTION__); 3029 } 3030 } 3031 3032 // Given the name of a kernel this function creates a breakpoint using our 3033 // own breakpoint resolver, and returns the Breakpoint shared pointer. 3034 BreakpointSP 3035 RenderScriptRuntime::CreateKernelBreakpoint(const ConstString &name) 3036 { 3037 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3038 3039 if (!m_filtersp) 3040 { 3041 if (log) 3042 log->Printf("%s - error, no breakpoint search filter set.", __FUNCTION__); 3043 return nullptr; 3044 } 3045 3046 BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name)); 3047 BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint(m_filtersp, resolver_sp, false, false, false); 3048 3049 // Give RS breakpoints a specific name, so the user can manipulate them as a group. 3050 Error err; 3051 if (!bp->AddName("RenderScriptKernel", err) && log) 3052 log->Printf("%s - error setting break name, '%s'.", __FUNCTION__, err.AsCString()); 3053 3054 return bp; 3055 } 3056 3057 // Given an expression for a variable this function tries to calculate the variable's value. 3058 // If this is possible it returns true and sets the uint64_t parameter to the variables unsigned value. 3059 // Otherwise function returns false. 3060 bool 3061 RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp, const char *var_name, uint64_t &val) 3062 { 3063 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 3064 Error error; 3065 VariableSP var_sp; 3066 3067 // Find variable in stack frame 3068 ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath( 3069 var_name, eNoDynamicValues, 3070 StackFrame::eExpressionPathOptionCheckPtrVsMember | StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, 3071 var_sp, error)); 3072 if (!error.Success()) 3073 { 3074 if (log) 3075 log->Printf("%s - error, couldn't find '%s' in frame", __FUNCTION__, var_name); 3076 return false; 3077 } 3078 3079 // Find the uint32_t value for the variable 3080 bool success = false; 3081 val = value_sp->GetValueAsUnsigned(0, &success); 3082 if (!success) 3083 { 3084 if (log) 3085 log->Printf("%s - error, couldn't parse '%s' as an uint32_t.", __FUNCTION__, var_name); 3086 return false; 3087 } 3088 3089 return true; 3090 } 3091 3092 // Function attempts to find the current coordinate of a kernel invocation by investigating the 3093 // values of frame variables in the .expand function. These coordinates are returned via the coord 3094 // array reference parameter. Returns true if the coordinates could be found, and false otherwise. 3095 bool 3096 RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord, Thread *thread_ptr) 3097 { 3098 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 3099 3100 if (!thread_ptr) 3101 { 3102 if (log) 3103 log->Printf("%s - Error, No thread pointer", __FUNCTION__); 3104 3105 return false; 3106 } 3107 3108 // Walk the call stack looking for a function whose name has the suffix '.expand' 3109 // and contains the variables we're looking for. 3110 for (uint32_t i = 0; i < thread_ptr->GetStackFrameCount(); ++i) 3111 { 3112 if (!thread_ptr->SetSelectedFrameByIndex(i)) 3113 continue; 3114 3115 StackFrameSP frame_sp = thread_ptr->GetSelectedFrame(); 3116 if (!frame_sp) 3117 continue; 3118 3119 // Find the function name 3120 const SymbolContext sym_ctx = frame_sp->GetSymbolContext(false); 3121 const char *func_name_cstr = sym_ctx.GetFunctionName().AsCString(); 3122 if (!func_name_cstr) 3123 continue; 3124 3125 if (log) 3126 log->Printf("%s - Inspecting function '%s'", __FUNCTION__, func_name_cstr); 3127 3128 // Check if function name has .expand suffix 3129 std::string func_name(func_name_cstr); 3130 const int length_difference = func_name.length() - RenderScriptRuntime::s_runtimeExpandSuffix.length(); 3131 if (length_difference <= 0) 3132 continue; 3133 3134 const int32_t has_expand_suffix = func_name.compare(length_difference, 3135 RenderScriptRuntime::s_runtimeExpandSuffix.length(), 3136 RenderScriptRuntime::s_runtimeExpandSuffix); 3137 3138 if (has_expand_suffix != 0) 3139 continue; 3140 3141 if (log) 3142 log->Printf("%s - Found .expand function '%s'", __FUNCTION__, func_name_cstr); 3143 3144 // Get values for variables in .expand frame that tell us the current kernel invocation 3145 bool found_coord_variables = true; 3146 assert(RenderScriptRuntime::s_runtimeCoordVars.size() == coord.size()); 3147 3148 for (uint32_t i = 0; i < coord.size(); ++i) 3149 { 3150 uint64_t value = 0; 3151 if (!GetFrameVarAsUnsigned(frame_sp, RenderScriptRuntime::s_runtimeCoordVars[i], value)) 3152 { 3153 found_coord_variables = false; 3154 break; 3155 } 3156 coord[i] = value; 3157 } 3158 3159 if (found_coord_variables) 3160 return true; 3161 } 3162 return false; 3163 } 3164 3165 // Callback when a kernel breakpoint hits and we're looking for a specific coordinate. 3166 // Baton parameter contains a pointer to the target coordinate we want to break on. 3167 // Function then checks the .expand frame for the current coordinate and breaks to user if it matches. 3168 // Parameter 'break_id' is the id of the Breakpoint which made the callback. 3169 // Parameter 'break_loc_id' is the id for the BreakpointLocation which was hit, 3170 // a single logical breakpoint can have multiple addresses. 3171 bool 3172 RenderScriptRuntime::KernelBreakpointHit(void *baton, StoppointCallbackContext *ctx, user_id_t break_id, 3173 user_id_t break_loc_id) 3174 { 3175 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3176 3177 assert(baton && "Error: null baton in conditional kernel breakpoint callback"); 3178 3179 // Coordinate we want to stop on 3180 const uint32_t *target_coord = static_cast<const uint32_t *>(baton); 3181 3182 if (log) 3183 log->Printf("%s - Break ID %" PRIu64 ", (%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")", __FUNCTION__, break_id, 3184 target_coord[0], target_coord[1], target_coord[2]); 3185 3186 // Select current thread 3187 ExecutionContext context(ctx->exe_ctx_ref); 3188 Thread *thread_ptr = context.GetThreadPtr(); 3189 assert(thread_ptr && "Null thread pointer"); 3190 3191 // Find current kernel invocation from .expand frame variables 3192 RSCoordinate current_coord{}; // Zero initialise array 3193 if (!GetKernelCoordinate(current_coord, thread_ptr)) 3194 { 3195 if (log) 3196 log->Printf("%s - Error, couldn't select .expand stack frame", __FUNCTION__); 3197 return false; 3198 } 3199 3200 if (log) 3201 log->Printf("%s - (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", __FUNCTION__, current_coord[0], current_coord[1], 3202 current_coord[2]); 3203 3204 // Check if the current kernel invocation coordinate matches our target coordinate 3205 if (current_coord[0] == target_coord[0] && 3206 current_coord[1] == target_coord[1] && 3207 current_coord[2] == target_coord[2]) 3208 { 3209 if (log) 3210 log->Printf("%s, BREAKING (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", __FUNCTION__, current_coord[0], 3211 current_coord[1], current_coord[2]); 3212 3213 BreakpointSP breakpoint_sp = context.GetTargetPtr()->GetBreakpointByID(break_id); 3214 assert(breakpoint_sp != nullptr && "Error: Couldn't find breakpoint matching break id for callback"); 3215 breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint should only be hit once. 3216 return true; 3217 } 3218 3219 // No match on coordinate 3220 return false; 3221 } 3222 3223 // Tries to set a breakpoint on the start of a kernel, resolved using the kernel name. 3224 // Argument 'coords', represents a three dimensional coordinate which can be used to specify 3225 // a single kernel instance to break on. If this is set then we add a callback to the breakpoint. 3226 void 3227 RenderScriptRuntime::PlaceBreakpointOnKernel(Stream &strm, const char *name, const std::array<int, 3> coords, 3228 Error &error, TargetSP target) 3229 { 3230 if (!name) 3231 { 3232 error.SetErrorString("invalid kernel name"); 3233 return; 3234 } 3235 3236 InitSearchFilter(target); 3237 3238 ConstString kernel_name(name); 3239 BreakpointSP bp = CreateKernelBreakpoint(kernel_name); 3240 3241 // We have a conditional breakpoint on a specific coordinate 3242 if (coords[0] != -1) 3243 { 3244 strm.Printf("Conditional kernel breakpoint on coordinate %" PRId32 ", %" PRId32 ", %" PRId32, 3245 coords[0], coords[1], coords[2]); 3246 strm.EOL(); 3247 3248 // Allocate memory for the baton, and copy over coordinate 3249 uint32_t *baton = new uint32_t[coords.size()]; 3250 baton[0] = coords[0]; baton[1] = coords[1]; baton[2] = coords[2]; 3251 3252 // Create a callback that will be invoked everytime the breakpoint is hit. 3253 // The baton object passed to the handler is the target coordinate we want to break on. 3254 bp->SetCallback(KernelBreakpointHit, baton, true); 3255 3256 // Store a shared pointer to the baton, so the memory will eventually be cleaned up after destruction 3257 m_conditional_breaks[bp->GetID()] = std::shared_ptr<uint32_t>(baton); 3258 } 3259 3260 if (bp) 3261 bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false); 3262 } 3263 3264 void 3265 RenderScriptRuntime::DumpModules(Stream &strm) const 3266 { 3267 strm.Printf("RenderScript Modules:"); 3268 strm.EOL(); 3269 strm.IndentMore(); 3270 for (const auto &module : m_rsmodules) 3271 { 3272 module->Dump(strm); 3273 } 3274 strm.IndentLess(); 3275 } 3276 3277 RenderScriptRuntime::ScriptDetails * 3278 RenderScriptRuntime::LookUpScript(addr_t address, bool create) 3279 { 3280 for (const auto &s : m_scripts) 3281 { 3282 if (s->script.isValid()) 3283 if (*s->script == address) 3284 return s.get(); 3285 } 3286 if (create) 3287 { 3288 std::unique_ptr<ScriptDetails> s(new ScriptDetails); 3289 s->script = address; 3290 m_scripts.push_back(std::move(s)); 3291 return m_scripts.back().get(); 3292 } 3293 return nullptr; 3294 } 3295 3296 RenderScriptRuntime::AllocationDetails * 3297 RenderScriptRuntime::LookUpAllocation(addr_t address, bool create) 3298 { 3299 for (const auto &a : m_allocations) 3300 { 3301 if (a->address.isValid()) 3302 if (*a->address == address) 3303 return a.get(); 3304 } 3305 if (create) 3306 { 3307 std::unique_ptr<AllocationDetails> a(new AllocationDetails); 3308 a->address = address; 3309 m_allocations.push_back(std::move(a)); 3310 return m_allocations.back().get(); 3311 } 3312 return nullptr; 3313 } 3314 3315 void 3316 RSModuleDescriptor::Dump(Stream &strm) const 3317 { 3318 strm.Indent(); 3319 m_module->GetFileSpec().Dump(&strm); 3320 if (m_module->GetNumCompileUnits()) 3321 { 3322 strm.Indent("Debug info loaded."); 3323 } 3324 else 3325 { 3326 strm.Indent("Debug info does not exist."); 3327 } 3328 strm.EOL(); 3329 strm.IndentMore(); 3330 strm.Indent(); 3331 strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size())); 3332 strm.EOL(); 3333 strm.IndentMore(); 3334 for (const auto &global : m_globals) 3335 { 3336 global.Dump(strm); 3337 } 3338 strm.IndentLess(); 3339 strm.Indent(); 3340 strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size())); 3341 strm.EOL(); 3342 strm.IndentMore(); 3343 for (const auto &kernel : m_kernels) 3344 { 3345 kernel.Dump(strm); 3346 } 3347 strm.Printf("Pragmas: %" PRIu64, static_cast<uint64_t>(m_pragmas.size())); 3348 strm.EOL(); 3349 strm.IndentMore(); 3350 for (const auto &key_val : m_pragmas) 3351 { 3352 strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str()); 3353 strm.EOL(); 3354 } 3355 strm.IndentLess(4); 3356 } 3357 3358 void 3359 RSGlobalDescriptor::Dump(Stream &strm) const 3360 { 3361 strm.Indent(m_name.AsCString()); 3362 VariableList var_list; 3363 m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list); 3364 if (var_list.GetSize() == 1) 3365 { 3366 auto var = var_list.GetVariableAtIndex(0); 3367 auto type = var->GetType(); 3368 if (type) 3369 { 3370 strm.Printf(" - "); 3371 type->DumpTypeName(&strm); 3372 } 3373 else 3374 { 3375 strm.Printf(" - Unknown Type"); 3376 } 3377 } 3378 else 3379 { 3380 strm.Printf(" - variable identified, but not found in binary"); 3381 const Symbol *s = m_module->m_module->FindFirstSymbolWithNameAndType(m_name, eSymbolTypeData); 3382 if (s) 3383 { 3384 strm.Printf(" (symbol exists) "); 3385 } 3386 } 3387 3388 strm.EOL(); 3389 } 3390 3391 void 3392 RSKernelDescriptor::Dump(Stream &strm) const 3393 { 3394 strm.Indent(m_name.AsCString()); 3395 strm.EOL(); 3396 } 3397 3398 class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed 3399 { 3400 public: 3401 CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter) 3402 : CommandObjectParsed(interpreter, "renderscript module dump", 3403 "Dumps renderscript specific information for all modules.", "renderscript module dump", 3404 eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3405 { 3406 } 3407 3408 ~CommandObjectRenderScriptRuntimeModuleDump() override = default; 3409 3410 bool 3411 DoExecute(Args &command, CommandReturnObject &result) override 3412 { 3413 RenderScriptRuntime *runtime = 3414 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3415 runtime->DumpModules(result.GetOutputStream()); 3416 result.SetStatus(eReturnStatusSuccessFinishResult); 3417 return true; 3418 } 3419 }; 3420 3421 class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword 3422 { 3423 public: 3424 CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter) 3425 : CommandObjectMultiword(interpreter, "renderscript module", "Commands that deal with renderscript modules.", 3426 nullptr) 3427 { 3428 LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump(interpreter))); 3429 } 3430 3431 ~CommandObjectRenderScriptRuntimeModule() override = default; 3432 }; 3433 3434 class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed 3435 { 3436 public: 3437 CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter) 3438 : CommandObjectParsed(interpreter, "renderscript kernel list", 3439 "Lists renderscript kernel names and associated script resources.", 3440 "renderscript kernel list", eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3441 { 3442 } 3443 3444 ~CommandObjectRenderScriptRuntimeKernelList() override = default; 3445 3446 bool 3447 DoExecute(Args &command, CommandReturnObject &result) override 3448 { 3449 RenderScriptRuntime *runtime = 3450 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3451 runtime->DumpKernels(result.GetOutputStream()); 3452 result.SetStatus(eReturnStatusSuccessFinishResult); 3453 return true; 3454 } 3455 }; 3456 3457 class CommandObjectRenderScriptRuntimeKernelBreakpointSet : public CommandObjectParsed 3458 { 3459 public: 3460 CommandObjectRenderScriptRuntimeKernelBreakpointSet(CommandInterpreter &interpreter) 3461 : CommandObjectParsed(interpreter, "renderscript kernel breakpoint set", 3462 "Sets a breakpoint on a renderscript kernel.", 3463 "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]", 3464 eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 3465 m_options(interpreter) 3466 { 3467 } 3468 3469 ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default; 3470 3471 Options * 3472 GetOptions() override 3473 { 3474 return &m_options; 3475 } 3476 3477 class CommandOptions : public Options 3478 { 3479 public: 3480 CommandOptions(CommandInterpreter &interpreter) : Options(interpreter) {} 3481 3482 ~CommandOptions() override = default; 3483 3484 Error 3485 SetOptionValue(uint32_t option_idx, const char *option_arg) override 3486 { 3487 Error error; 3488 const int short_option = m_getopt_table[option_idx].val; 3489 3490 switch (short_option) 3491 { 3492 case 'c': 3493 if (!ParseCoordinate(option_arg)) 3494 error.SetErrorStringWithFormat("Couldn't parse coordinate '%s', should be in format 'x,y,z'.", 3495 option_arg); 3496 break; 3497 default: 3498 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 3499 break; 3500 } 3501 return error; 3502 } 3503 3504 // -c takes an argument of the form 'num[,num][,num]'. 3505 // Where 'id_cstr' is this argument with the whitespace trimmed. 3506 // Missing coordinates are defaulted to zero. 3507 bool 3508 ParseCoordinate(const char *id_cstr) 3509 { 3510 RegularExpression regex; 3511 RegularExpression::Match regex_match(3); 3512 3513 bool matched = false; 3514 if (regex.Compile("^([0-9]+),([0-9]+),([0-9]+)$") && regex.Execute(id_cstr, ®ex_match)) 3515 matched = true; 3516 else if (regex.Compile("^([0-9]+),([0-9]+)$") && regex.Execute(id_cstr, ®ex_match)) 3517 matched = true; 3518 else if (regex.Compile("^([0-9]+)$") && regex.Execute(id_cstr, ®ex_match)) 3519 matched = true; 3520 for (uint32_t i = 0; i < 3; i++) 3521 { 3522 std::string group; 3523 if (regex_match.GetMatchAtIndex(id_cstr, i + 1, group)) 3524 m_coord[i] = (uint32_t)strtoul(group.c_str(), nullptr, 0); 3525 else 3526 m_coord[i] = 0; 3527 } 3528 return matched; 3529 } 3530 3531 void 3532 OptionParsingStarting() override 3533 { 3534 // -1 means the -c option hasn't been set 3535 m_coord[0] = -1; 3536 m_coord[1] = -1; 3537 m_coord[2] = -1; 3538 } 3539 3540 const OptionDefinition * 3541 GetDefinitions() override 3542 { 3543 return g_option_table; 3544 } 3545 3546 static OptionDefinition g_option_table[]; 3547 std::array<int, 3> m_coord; 3548 }; 3549 3550 bool 3551 DoExecute(Args &command, CommandReturnObject &result) override 3552 { 3553 const size_t argc = command.GetArgumentCount(); 3554 if (argc < 1) 3555 { 3556 result.AppendErrorWithFormat("'%s' takes 1 argument of kernel name, and an optional coordinate.", 3557 m_cmd_name.c_str()); 3558 result.SetStatus(eReturnStatusFailed); 3559 return false; 3560 } 3561 3562 RenderScriptRuntime *runtime = 3563 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3564 3565 Error error; 3566 runtime->PlaceBreakpointOnKernel(result.GetOutputStream(), command.GetArgumentAtIndex(0), m_options.m_coord, 3567 error, m_exe_ctx.GetTargetSP()); 3568 3569 if (error.Success()) 3570 { 3571 result.AppendMessage("Breakpoint(s) created"); 3572 result.SetStatus(eReturnStatusSuccessFinishResult); 3573 return true; 3574 } 3575 result.SetStatus(eReturnStatusFailed); 3576 result.AppendErrorWithFormat("Error: %s", error.AsCString()); 3577 return false; 3578 } 3579 3580 private: 3581 CommandOptions m_options; 3582 }; 3583 3584 OptionDefinition CommandObjectRenderScriptRuntimeKernelBreakpointSet::CommandOptions::g_option_table[] = { 3585 {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeValue, 3586 "Set a breakpoint on a single invocation of the kernel with specified coordinate.\n" 3587 "Coordinate takes the form 'x[,y][,z] where x,y,z are positive integers representing kernel dimensions. " 3588 "Any unset dimensions will be defaulted to zero."}, 3589 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; 3590 3591 class CommandObjectRenderScriptRuntimeKernelBreakpointAll : public CommandObjectParsed 3592 { 3593 public: 3594 CommandObjectRenderScriptRuntimeKernelBreakpointAll(CommandInterpreter &interpreter) 3595 : CommandObjectParsed( 3596 interpreter, "renderscript kernel breakpoint all", 3597 "Automatically sets a breakpoint on all renderscript kernels that are or will be loaded.\n" 3598 "Disabling option means breakpoints will no longer be set on any kernels loaded in the future, " 3599 "but does not remove currently set breakpoints.", 3600 "renderscript kernel breakpoint all <enable/disable>", 3601 eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) 3602 { 3603 } 3604 3605 ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default; 3606 3607 bool 3608 DoExecute(Args &command, CommandReturnObject &result) override 3609 { 3610 const size_t argc = command.GetArgumentCount(); 3611 if (argc != 1) 3612 { 3613 result.AppendErrorWithFormat("'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str()); 3614 result.SetStatus(eReturnStatusFailed); 3615 return false; 3616 } 3617 3618 RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 3619 m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 3620 3621 bool do_break = false; 3622 const char *argument = command.GetArgumentAtIndex(0); 3623 if (strcmp(argument, "enable") == 0) 3624 { 3625 do_break = true; 3626 result.AppendMessage("Breakpoints will be set on all kernels."); 3627 } 3628 else if (strcmp(argument, "disable") == 0) 3629 { 3630 do_break = false; 3631 result.AppendMessage("Breakpoints will not be set on any new kernels."); 3632 } 3633 else 3634 { 3635 result.AppendErrorWithFormat("Argument must be either 'enable' or 'disable'"); 3636 result.SetStatus(eReturnStatusFailed); 3637 return false; 3638 } 3639 3640 runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP()); 3641 3642 result.SetStatus(eReturnStatusSuccessFinishResult); 3643 return true; 3644 } 3645 }; 3646 3647 class CommandObjectRenderScriptRuntimeKernelCoordinate : public CommandObjectParsed 3648 { 3649 public: 3650 CommandObjectRenderScriptRuntimeKernelCoordinate(CommandInterpreter &interpreter) 3651 : CommandObjectParsed(interpreter, "renderscript kernel coordinate", 3652 "Shows the (x,y,z) coordinate of the current kernel invocation.", 3653 "renderscript kernel coordinate", 3654 eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) 3655 { 3656 } 3657 3658 ~CommandObjectRenderScriptRuntimeKernelCoordinate() override = default; 3659 3660 bool 3661 DoExecute(Args &command, CommandReturnObject &result) override 3662 { 3663 RSCoordinate coord{}; // Zero initialize array 3664 bool success = RenderScriptRuntime::GetKernelCoordinate(coord, m_exe_ctx.GetThreadPtr()); 3665 Stream &stream = result.GetOutputStream(); 3666 3667 if (success) 3668 { 3669 stream.Printf("Coordinate: (%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")", coord[0], coord[1], coord[2]); 3670 stream.EOL(); 3671 result.SetStatus(eReturnStatusSuccessFinishResult); 3672 } 3673 else 3674 { 3675 stream.Printf("Error: Coordinate could not be found."); 3676 stream.EOL(); 3677 result.SetStatus(eReturnStatusFailed); 3678 } 3679 return true; 3680 } 3681 }; 3682 3683 class CommandObjectRenderScriptRuntimeKernelBreakpoint : public CommandObjectMultiword 3684 { 3685 public: 3686 CommandObjectRenderScriptRuntimeKernelBreakpoint(CommandInterpreter &interpreter) 3687 : CommandObjectMultiword(interpreter, "renderscript kernel", 3688 "Commands that generate breakpoints on renderscript kernels.", nullptr) 3689 { 3690 LoadSubCommand("set", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet(interpreter))); 3691 LoadSubCommand("all", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll(interpreter))); 3692 } 3693 3694 ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default; 3695 }; 3696 3697 class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword 3698 { 3699 public: 3700 CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter) 3701 : CommandObjectMultiword(interpreter, "renderscript kernel", "Commands that deal with renderscript kernels.", 3702 nullptr) 3703 { 3704 LoadSubCommand("list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList(interpreter))); 3705 LoadSubCommand("coordinate", 3706 CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelCoordinate(interpreter))); 3707 LoadSubCommand("breakpoint", 3708 CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter))); 3709 } 3710 3711 ~CommandObjectRenderScriptRuntimeKernel() override = default; 3712 }; 3713 3714 class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed 3715 { 3716 public: 3717 CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter) 3718 : CommandObjectParsed(interpreter, "renderscript context dump", "Dumps renderscript context information.", 3719 "renderscript context dump", eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3720 { 3721 } 3722 3723 ~CommandObjectRenderScriptRuntimeContextDump() override = default; 3724 3725 bool 3726 DoExecute(Args &command, CommandReturnObject &result) override 3727 { 3728 RenderScriptRuntime *runtime = 3729 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3730 runtime->DumpContexts(result.GetOutputStream()); 3731 result.SetStatus(eReturnStatusSuccessFinishResult); 3732 return true; 3733 } 3734 }; 3735 3736 class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword 3737 { 3738 public: 3739 CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter) 3740 : CommandObjectMultiword(interpreter, "renderscript context", "Commands that deal with renderscript contexts.", 3741 nullptr) 3742 { 3743 LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump(interpreter))); 3744 } 3745 3746 ~CommandObjectRenderScriptRuntimeContext() override = default; 3747 }; 3748 3749 class CommandObjectRenderScriptRuntimeAllocationDump : public CommandObjectParsed 3750 { 3751 public: 3752 CommandObjectRenderScriptRuntimeAllocationDump(CommandInterpreter &interpreter) 3753 : CommandObjectParsed(interpreter, "renderscript allocation dump", 3754 "Displays the contents of a particular allocation", "renderscript allocation dump <ID>", 3755 eCommandRequiresProcess | eCommandProcessMustBeLaunched), 3756 m_options(interpreter) 3757 { 3758 } 3759 3760 ~CommandObjectRenderScriptRuntimeAllocationDump() override = default; 3761 3762 Options * 3763 GetOptions() override 3764 { 3765 return &m_options; 3766 } 3767 3768 class CommandOptions : public Options 3769 { 3770 public: 3771 CommandOptions(CommandInterpreter &interpreter) : Options(interpreter) {} 3772 3773 ~CommandOptions() override = default; 3774 3775 Error 3776 SetOptionValue(uint32_t option_idx, const char *option_arg) override 3777 { 3778 Error error; 3779 const int short_option = m_getopt_table[option_idx].val; 3780 3781 switch (short_option) 3782 { 3783 case 'f': 3784 m_outfile.SetFile(option_arg, true); 3785 if (m_outfile.Exists()) 3786 { 3787 m_outfile.Clear(); 3788 error.SetErrorStringWithFormat("file already exists: '%s'", option_arg); 3789 } 3790 break; 3791 default: 3792 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 3793 break; 3794 } 3795 return error; 3796 } 3797 3798 void 3799 OptionParsingStarting() override 3800 { 3801 m_outfile.Clear(); 3802 } 3803 3804 const OptionDefinition * 3805 GetDefinitions() override 3806 { 3807 return g_option_table; 3808 } 3809 3810 static OptionDefinition g_option_table[]; 3811 FileSpec m_outfile; 3812 }; 3813 3814 bool 3815 DoExecute(Args &command, CommandReturnObject &result) override 3816 { 3817 const size_t argc = command.GetArgumentCount(); 3818 if (argc < 1) 3819 { 3820 result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. As well as an optional -f argument", 3821 m_cmd_name.c_str()); 3822 result.SetStatus(eReturnStatusFailed); 3823 return false; 3824 } 3825 3826 RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 3827 m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 3828 3829 const char *id_cstr = command.GetArgumentAtIndex(0); 3830 bool convert_complete = false; 3831 const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 3832 if (!convert_complete) 3833 { 3834 result.AppendErrorWithFormat("invalid allocation id argument '%s'", id_cstr); 3835 result.SetStatus(eReturnStatusFailed); 3836 return false; 3837 } 3838 3839 Stream *output_strm = nullptr; 3840 StreamFile outfile_stream; 3841 const FileSpec &outfile_spec = m_options.m_outfile; // Dump allocation to file instead 3842 if (outfile_spec) 3843 { 3844 // Open output file 3845 char path[256]; 3846 outfile_spec.GetPath(path, sizeof(path)); 3847 if (outfile_stream.GetFile().Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate).Success()) 3848 { 3849 output_strm = &outfile_stream; 3850 result.GetOutputStream().Printf("Results written to '%s'", path); 3851 result.GetOutputStream().EOL(); 3852 } 3853 else 3854 { 3855 result.AppendErrorWithFormat("Couldn't open file '%s'", path); 3856 result.SetStatus(eReturnStatusFailed); 3857 return false; 3858 } 3859 } 3860 else 3861 output_strm = &result.GetOutputStream(); 3862 3863 assert(output_strm != nullptr); 3864 bool success = runtime->DumpAllocation(*output_strm, m_exe_ctx.GetFramePtr(), id); 3865 3866 if (success) 3867 result.SetStatus(eReturnStatusSuccessFinishResult); 3868 else 3869 result.SetStatus(eReturnStatusFailed); 3870 3871 return true; 3872 } 3873 3874 private: 3875 CommandOptions m_options; 3876 }; 3877 3878 OptionDefinition CommandObjectRenderScriptRuntimeAllocationDump::CommandOptions::g_option_table[] = { 3879 {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFilename, 3880 "Print results to specified file instead of command line."}, 3881 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; 3882 3883 class CommandObjectRenderScriptRuntimeAllocationList : public CommandObjectParsed 3884 { 3885 public: 3886 CommandObjectRenderScriptRuntimeAllocationList(CommandInterpreter &interpreter) 3887 : CommandObjectParsed(interpreter, "renderscript allocation list", 3888 "List renderscript allocations and their information.", "renderscript allocation list", 3889 eCommandRequiresProcess | eCommandProcessMustBeLaunched), 3890 m_options(interpreter) 3891 { 3892 } 3893 3894 ~CommandObjectRenderScriptRuntimeAllocationList() override = default; 3895 3896 Options * 3897 GetOptions() override 3898 { 3899 return &m_options; 3900 } 3901 3902 class CommandOptions : public Options 3903 { 3904 public: 3905 CommandOptions(CommandInterpreter &interpreter) : Options(interpreter), m_id(0) {} 3906 3907 ~CommandOptions() override = default; 3908 3909 Error 3910 SetOptionValue(uint32_t option_idx, const char *option_arg) override 3911 { 3912 Error error; 3913 const int short_option = m_getopt_table[option_idx].val; 3914 3915 switch (short_option) 3916 { 3917 case 'i': 3918 bool success; 3919 m_id = StringConvert::ToUInt32(option_arg, 0, 0, &success); 3920 if (!success) 3921 error.SetErrorStringWithFormat("invalid integer value for option '%c'", short_option); 3922 break; 3923 default: 3924 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 3925 break; 3926 } 3927 return error; 3928 } 3929 3930 void 3931 OptionParsingStarting() override 3932 { 3933 m_id = 0; 3934 } 3935 3936 const OptionDefinition * 3937 GetDefinitions() override 3938 { 3939 return g_option_table; 3940 } 3941 3942 static OptionDefinition g_option_table[]; 3943 uint32_t m_id; 3944 }; 3945 3946 bool 3947 DoExecute(Args &command, CommandReturnObject &result) override 3948 { 3949 RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 3950 m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 3951 runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(), m_options.m_id); 3952 result.SetStatus(eReturnStatusSuccessFinishResult); 3953 return true; 3954 } 3955 3956 private: 3957 CommandOptions m_options; 3958 }; 3959 3960 OptionDefinition CommandObjectRenderScriptRuntimeAllocationList::CommandOptions::g_option_table[] = { 3961 {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeIndex, 3962 "Only show details of a single allocation with specified id."}, 3963 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; 3964 3965 class CommandObjectRenderScriptRuntimeAllocationLoad : public CommandObjectParsed 3966 { 3967 public: 3968 CommandObjectRenderScriptRuntimeAllocationLoad(CommandInterpreter &interpreter) 3969 : CommandObjectParsed( 3970 interpreter, "renderscript allocation load", "Loads renderscript allocation contents from a file.", 3971 "renderscript allocation load <ID> <filename>", eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3972 { 3973 } 3974 3975 ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default; 3976 3977 bool 3978 DoExecute(Args &command, CommandReturnObject &result) override 3979 { 3980 const size_t argc = command.GetArgumentCount(); 3981 if (argc != 2) 3982 { 3983 result.AppendErrorWithFormat("'%s' takes 2 arguments, an allocation ID and filename to read from.", 3984 m_cmd_name.c_str()); 3985 result.SetStatus(eReturnStatusFailed); 3986 return false; 3987 } 3988 3989 RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 3990 m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 3991 3992 const char *id_cstr = command.GetArgumentAtIndex(0); 3993 bool convert_complete = false; 3994 const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 3995 if (!convert_complete) 3996 { 3997 result.AppendErrorWithFormat("invalid allocation id argument '%s'", id_cstr); 3998 result.SetStatus(eReturnStatusFailed); 3999 return false; 4000 } 4001 4002 const char *filename = command.GetArgumentAtIndex(1); 4003 bool success = runtime->LoadAllocation(result.GetOutputStream(), id, filename, m_exe_ctx.GetFramePtr()); 4004 4005 if (success) 4006 result.SetStatus(eReturnStatusSuccessFinishResult); 4007 else 4008 result.SetStatus(eReturnStatusFailed); 4009 4010 return true; 4011 } 4012 }; 4013 4014 class CommandObjectRenderScriptRuntimeAllocationSave : public CommandObjectParsed 4015 { 4016 public: 4017 CommandObjectRenderScriptRuntimeAllocationSave(CommandInterpreter &interpreter) 4018 : CommandObjectParsed( 4019 interpreter, "renderscript allocation save", "Write renderscript allocation contents to a file.", 4020 "renderscript allocation save <ID> <filename>", eCommandRequiresProcess | eCommandProcessMustBeLaunched) 4021 { 4022 } 4023 4024 ~CommandObjectRenderScriptRuntimeAllocationSave() override = default; 4025 4026 bool 4027 DoExecute(Args &command, CommandReturnObject &result) override 4028 { 4029 const size_t argc = command.GetArgumentCount(); 4030 if (argc != 2) 4031 { 4032 result.AppendErrorWithFormat("'%s' takes 2 arguments, an allocation ID and filename to read from.", 4033 m_cmd_name.c_str()); 4034 result.SetStatus(eReturnStatusFailed); 4035 return false; 4036 } 4037 4038 RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4039 m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 4040 4041 const char *id_cstr = command.GetArgumentAtIndex(0); 4042 bool convert_complete = false; 4043 const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 4044 if (!convert_complete) 4045 { 4046 result.AppendErrorWithFormat("invalid allocation id argument '%s'", id_cstr); 4047 result.SetStatus(eReturnStatusFailed); 4048 return false; 4049 } 4050 4051 const char *filename = command.GetArgumentAtIndex(1); 4052 bool success = runtime->SaveAllocation(result.GetOutputStream(), id, filename, m_exe_ctx.GetFramePtr()); 4053 4054 if (success) 4055 result.SetStatus(eReturnStatusSuccessFinishResult); 4056 else 4057 result.SetStatus(eReturnStatusFailed); 4058 4059 return true; 4060 } 4061 }; 4062 4063 class CommandObjectRenderScriptRuntimeAllocationRefresh : public CommandObjectParsed 4064 { 4065 public: 4066 CommandObjectRenderScriptRuntimeAllocationRefresh(CommandInterpreter &interpreter) 4067 : CommandObjectParsed(interpreter, "renderscript allocation refresh", 4068 "Recomputes the details of all allocations.", "renderscript allocation refresh", 4069 eCommandRequiresProcess | eCommandProcessMustBeLaunched) 4070 { 4071 } 4072 4073 ~CommandObjectRenderScriptRuntimeAllocationRefresh() override = default; 4074 4075 bool 4076 DoExecute(Args &command, CommandReturnObject &result) override 4077 { 4078 RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( 4079 m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 4080 4081 bool success = runtime->RecomputeAllAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr()); 4082 4083 if (success) 4084 { 4085 result.SetStatus(eReturnStatusSuccessFinishResult); 4086 return true; 4087 } 4088 else 4089 { 4090 result.SetStatus(eReturnStatusFailed); 4091 return false; 4092 } 4093 } 4094 }; 4095 4096 class CommandObjectRenderScriptRuntimeAllocation : public CommandObjectMultiword 4097 { 4098 public: 4099 CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter) 4100 : CommandObjectMultiword(interpreter, "renderscript allocation", 4101 "Commands that deal with renderscript allocations.", nullptr) 4102 { 4103 LoadSubCommand("list", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationList(interpreter))); 4104 LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationDump(interpreter))); 4105 LoadSubCommand("save", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationSave(interpreter))); 4106 LoadSubCommand("load", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter))); 4107 LoadSubCommand("refresh", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationRefresh(interpreter))); 4108 } 4109 4110 ~CommandObjectRenderScriptRuntimeAllocation() override = default; 4111 }; 4112 4113 class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed 4114 { 4115 public: 4116 CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter) 4117 : CommandObjectParsed(interpreter, "renderscript status", "Displays current renderscript runtime status.", 4118 "renderscript status", eCommandRequiresProcess | eCommandProcessMustBeLaunched) 4119 { 4120 } 4121 4122 ~CommandObjectRenderScriptRuntimeStatus() override = default; 4123 4124 bool 4125 DoExecute(Args &command, CommandReturnObject &result) override 4126 { 4127 RenderScriptRuntime *runtime = 4128 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 4129 runtime->Status(result.GetOutputStream()); 4130 result.SetStatus(eReturnStatusSuccessFinishResult); 4131 return true; 4132 } 4133 }; 4134 4135 class CommandObjectRenderScriptRuntime : public CommandObjectMultiword 4136 { 4137 public: 4138 CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter) 4139 : CommandObjectMultiword(interpreter, "renderscript", "A set of commands for operating on renderscript.", 4140 "renderscript <subcommand> [<subcommand-options>]") 4141 { 4142 LoadSubCommand("module", CommandObjectSP(new CommandObjectRenderScriptRuntimeModule(interpreter))); 4143 LoadSubCommand("status", CommandObjectSP(new CommandObjectRenderScriptRuntimeStatus(interpreter))); 4144 LoadSubCommand("kernel", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernel(interpreter))); 4145 LoadSubCommand("context", CommandObjectSP(new CommandObjectRenderScriptRuntimeContext(interpreter))); 4146 LoadSubCommand("allocation", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocation(interpreter))); 4147 } 4148 4149 ~CommandObjectRenderScriptRuntime() override = default; 4150 }; 4151 4152 void 4153 RenderScriptRuntime::Initiate() 4154 { 4155 assert(!m_initiated); 4156 } 4157 4158 RenderScriptRuntime::RenderScriptRuntime(Process *process) 4159 : lldb_private::CPPLanguageRuntime(process), 4160 m_initiated(false), 4161 m_debuggerPresentFlagged(false), 4162 m_breakAllKernels(false) 4163 { 4164 ModulesDidLoad(process->GetTarget().GetImages()); 4165 } 4166 4167 lldb::CommandObjectSP 4168 RenderScriptRuntime::GetCommandObject(lldb_private::CommandInterpreter &interpreter) 4169 { 4170 return CommandObjectSP(new CommandObjectRenderScriptRuntime(interpreter)); 4171 } 4172 4173 RenderScriptRuntime::~RenderScriptRuntime() = default; 4174