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