RenderScriptRuntime.cpp revision 296417
1285101Semaste//===-- RenderScriptRuntime.cpp ---------------------------------*- C++ -*-===// 2285101Semaste// 3285101Semaste// The LLVM Compiler Infrastructure 4285101Semaste// 5285101Semaste// This file is distributed under the University of Illinois Open Source 6285101Semaste// License. See LICENSE.TXT for details. 7285101Semaste// 8285101Semaste//===----------------------------------------------------------------------===// 9285101Semaste 10296417Sdim// C Includes 11296417Sdim// C++ Includes 12296417Sdim// Other libraries and framework includes 13296417Sdim// Project includes 14285101Semaste#include "RenderScriptRuntime.h" 15285101Semaste 16285101Semaste#include "lldb/Core/ConstString.h" 17285101Semaste#include "lldb/Core/Debugger.h" 18285101Semaste#include "lldb/Core/Error.h" 19285101Semaste#include "lldb/Core/Log.h" 20285101Semaste#include "lldb/Core/PluginManager.h" 21296417Sdim#include "lldb/Core/ValueObjectVariable.h" 22296417Sdim#include "lldb/Core/RegularExpression.h" 23296417Sdim#include "lldb/DataFormatters/DumpValueObjectOptions.h" 24296417Sdim#include "lldb/Host/StringConvert.h" 25285101Semaste#include "lldb/Symbol/Symbol.h" 26285101Semaste#include "lldb/Symbol/Type.h" 27285101Semaste#include "lldb/Target/Process.h" 28285101Semaste#include "lldb/Target/Target.h" 29296417Sdim#include "lldb/Target/Thread.h" 30285101Semaste#include "lldb/Interpreter/Args.h" 31285101Semaste#include "lldb/Interpreter/Options.h" 32285101Semaste#include "lldb/Interpreter/CommandInterpreter.h" 33285101Semaste#include "lldb/Interpreter/CommandReturnObject.h" 34285101Semaste#include "lldb/Interpreter/CommandObjectMultiword.h" 35285101Semaste#include "lldb/Breakpoint/StoppointCallbackContext.h" 36285101Semaste#include "lldb/Target/RegisterContext.h" 37296417Sdim#include "lldb/Expression/UserExpression.h" 38285101Semaste#include "lldb/Symbol/VariableList.h" 39285101Semaste 40285101Semasteusing namespace lldb; 41285101Semasteusing namespace lldb_private; 42296417Sdimusing namespace lldb_renderscript; 43285101Semaste 44296417Sdimnamespace { 45296417Sdim 46296417Sdim// The empirical_type adds a basic level of validation to arbitrary data 47296417Sdim// allowing us to track if data has been discovered and stored or not. 48296417Sdim// An empirical_type will be marked as valid only if it has been explicitly assigned to. 49296417Sdimtemplate <typename type_t> 50296417Sdimclass empirical_type 51296417Sdim{ 52296417Sdimpublic: 53296417Sdim // Ctor. Contents is invalid when constructed. 54296417Sdim empirical_type() 55296417Sdim : valid(false) 56296417Sdim {} 57296417Sdim 58296417Sdim // Return true and copy contents to out if valid, else return false. 59296417Sdim bool get(type_t& out) const 60296417Sdim { 61296417Sdim if (valid) 62296417Sdim out = data; 63296417Sdim return valid; 64296417Sdim } 65296417Sdim 66296417Sdim // Return a pointer to the contents or nullptr if it was not valid. 67296417Sdim const type_t* get() const 68296417Sdim { 69296417Sdim return valid ? &data : nullptr; 70296417Sdim } 71296417Sdim 72296417Sdim // Assign data explicitly. 73296417Sdim void set(const type_t in) 74296417Sdim { 75296417Sdim data = in; 76296417Sdim valid = true; 77296417Sdim } 78296417Sdim 79296417Sdim // Mark contents as invalid. 80296417Sdim void invalidate() 81296417Sdim { 82296417Sdim valid = false; 83296417Sdim } 84296417Sdim 85296417Sdim // Returns true if this type contains valid data. 86296417Sdim bool isValid() const 87296417Sdim { 88296417Sdim return valid; 89296417Sdim } 90296417Sdim 91296417Sdim // Assignment operator. 92296417Sdim empirical_type<type_t>& operator = (const type_t in) 93296417Sdim { 94296417Sdim set(in); 95296417Sdim return *this; 96296417Sdim } 97296417Sdim 98296417Sdim // Dereference operator returns contents. 99296417Sdim // Warning: Will assert if not valid so use only when you know data is valid. 100296417Sdim const type_t& operator * () const 101296417Sdim { 102296417Sdim assert(valid); 103296417Sdim return data; 104296417Sdim } 105296417Sdim 106296417Sdimprotected: 107296417Sdim bool valid; 108296417Sdim type_t data; 109296417Sdim}; 110296417Sdim 111296417Sdim} // anonymous namespace 112296417Sdim 113296417Sdim// The ScriptDetails class collects data associated with a single script instance. 114296417Sdimstruct RenderScriptRuntime::ScriptDetails 115296417Sdim{ 116296417Sdim ~ScriptDetails() = default; 117296417Sdim 118296417Sdim enum ScriptType 119296417Sdim { 120296417Sdim eScript, 121296417Sdim eScriptC 122296417Sdim }; 123296417Sdim 124296417Sdim // The derived type of the script. 125296417Sdim empirical_type<ScriptType> type; 126296417Sdim // The name of the original source file. 127296417Sdim empirical_type<std::string> resName; 128296417Sdim // Path to script .so file on the device. 129296417Sdim empirical_type<std::string> scriptDyLib; 130296417Sdim // Directory where kernel objects are cached on device. 131296417Sdim empirical_type<std::string> cacheDir; 132296417Sdim // Pointer to the context which owns this script. 133296417Sdim empirical_type<lldb::addr_t> context; 134296417Sdim // Pointer to the script object itself. 135296417Sdim empirical_type<lldb::addr_t> script; 136296417Sdim}; 137296417Sdim 138296417Sdim// This Element class represents the Element object in RS, 139296417Sdim// defining the type associated with an Allocation. 140296417Sdimstruct RenderScriptRuntime::Element 141296417Sdim{ 142296417Sdim // Taken from rsDefines.h 143296417Sdim enum DataKind 144296417Sdim { 145296417Sdim RS_KIND_USER, 146296417Sdim RS_KIND_PIXEL_L = 7, 147296417Sdim RS_KIND_PIXEL_A, 148296417Sdim RS_KIND_PIXEL_LA, 149296417Sdim RS_KIND_PIXEL_RGB, 150296417Sdim RS_KIND_PIXEL_RGBA, 151296417Sdim RS_KIND_PIXEL_DEPTH, 152296417Sdim RS_KIND_PIXEL_YUV, 153296417Sdim RS_KIND_INVALID = 100 154296417Sdim }; 155296417Sdim 156296417Sdim // Taken from rsDefines.h 157296417Sdim enum DataType 158296417Sdim { 159296417Sdim RS_TYPE_NONE = 0, 160296417Sdim RS_TYPE_FLOAT_16, 161296417Sdim RS_TYPE_FLOAT_32, 162296417Sdim RS_TYPE_FLOAT_64, 163296417Sdim RS_TYPE_SIGNED_8, 164296417Sdim RS_TYPE_SIGNED_16, 165296417Sdim RS_TYPE_SIGNED_32, 166296417Sdim RS_TYPE_SIGNED_64, 167296417Sdim RS_TYPE_UNSIGNED_8, 168296417Sdim RS_TYPE_UNSIGNED_16, 169296417Sdim RS_TYPE_UNSIGNED_32, 170296417Sdim RS_TYPE_UNSIGNED_64, 171296417Sdim RS_TYPE_BOOLEAN, 172296417Sdim 173296417Sdim RS_TYPE_UNSIGNED_5_6_5, 174296417Sdim RS_TYPE_UNSIGNED_5_5_5_1, 175296417Sdim RS_TYPE_UNSIGNED_4_4_4_4, 176296417Sdim 177296417Sdim RS_TYPE_MATRIX_4X4, 178296417Sdim RS_TYPE_MATRIX_3X3, 179296417Sdim RS_TYPE_MATRIX_2X2, 180296417Sdim 181296417Sdim RS_TYPE_ELEMENT = 1000, 182296417Sdim RS_TYPE_TYPE, 183296417Sdim RS_TYPE_ALLOCATION, 184296417Sdim RS_TYPE_SAMPLER, 185296417Sdim RS_TYPE_SCRIPT, 186296417Sdim RS_TYPE_MESH, 187296417Sdim RS_TYPE_PROGRAM_FRAGMENT, 188296417Sdim RS_TYPE_PROGRAM_VERTEX, 189296417Sdim RS_TYPE_PROGRAM_RASTER, 190296417Sdim RS_TYPE_PROGRAM_STORE, 191296417Sdim RS_TYPE_FONT, 192296417Sdim 193296417Sdim RS_TYPE_INVALID = 10000 194296417Sdim }; 195296417Sdim 196296417Sdim std::vector<Element> children; // Child Element fields for structs 197296417Sdim empirical_type<lldb::addr_t> element_ptr; // Pointer to the RS Element of the Type 198296417Sdim empirical_type<DataType> type; // Type of each data pointer stored by the allocation 199296417Sdim empirical_type<DataKind> type_kind; // Defines pixel type if Allocation is created from an image 200296417Sdim empirical_type<uint32_t> type_vec_size; // Vector size of each data point, e.g '4' for uchar4 201296417Sdim empirical_type<uint32_t> field_count; // Number of Subelements 202296417Sdim empirical_type<uint32_t> datum_size; // Size of a single Element with padding 203296417Sdim empirical_type<uint32_t> padding; // Number of padding bytes 204296417Sdim empirical_type<uint32_t> array_size; // Number of items in array, only needed for strucrs 205296417Sdim ConstString type_name; // Name of type, only needed for structs 206296417Sdim 207296417Sdim static const ConstString &GetFallbackStructName(); // Print this as the type name of a struct Element 208296417Sdim // If we can't resolve the actual struct name 209296417Sdim 210296417Sdim bool shouldRefresh() const 211296417Sdim { 212296417Sdim const bool valid_ptr = element_ptr.isValid() && *element_ptr.get() != 0x0; 213296417Sdim const bool valid_type = type.isValid() && type_vec_size.isValid() && type_kind.isValid(); 214296417Sdim return !valid_ptr || !valid_type || !datum_size.isValid(); 215296417Sdim } 216296417Sdim}; 217296417Sdim 218296417Sdim// This AllocationDetails class collects data associated with a single 219296417Sdim// allocation instance. 220296417Sdimstruct RenderScriptRuntime::AllocationDetails 221296417Sdim{ 222296417Sdim struct Dimension 223296417Sdim { 224296417Sdim uint32_t dim_1; 225296417Sdim uint32_t dim_2; 226296417Sdim uint32_t dim_3; 227296417Sdim uint32_t cubeMap; 228296417Sdim 229296417Sdim Dimension() 230296417Sdim { 231296417Sdim dim_1 = 0; 232296417Sdim dim_2 = 0; 233296417Sdim dim_3 = 0; 234296417Sdim cubeMap = 0; 235296417Sdim } 236296417Sdim }; 237296417Sdim 238296417Sdim // The FileHeader struct specifies the header we use for writing allocations to a binary file. 239296417Sdim // Our format begins with the ASCII characters "RSAD", identifying the file as an allocation dump. 240296417Sdim // Member variables dims and hdr_size are then written consecutively, immediately followed by an instance of 241296417Sdim // the ElementHeader struct. Because Elements can contain subelements, there may be more than one instance 242296417Sdim // of the ElementHeader struct. With this first instance being the root element, and the other instances being 243296417Sdim // the root's descendants. To identify which instances are an ElementHeader's children, each struct 244296417Sdim // is immediately followed by a sequence of consecutive offsets to the start of its child structs. 245296417Sdim // These offsets are 4 bytes in size, and the 0 offset signifies no more children. 246296417Sdim struct FileHeader 247296417Sdim { 248296417Sdim uint8_t ident[4]; // ASCII 'RSAD' identifying the file 249296417Sdim uint32_t dims[3]; // Dimensions 250296417Sdim uint16_t hdr_size; // Header size in bytes, including all element headers 251296417Sdim }; 252296417Sdim 253296417Sdim struct ElementHeader 254296417Sdim { 255296417Sdim uint16_t type; // DataType enum 256296417Sdim uint32_t kind; // DataKind enum 257296417Sdim uint32_t element_size; // Size of a single element, including padding 258296417Sdim uint16_t vector_size; // Vector width 259296417Sdim uint32_t array_size; // Number of elements in array 260296417Sdim }; 261296417Sdim 262296417Sdim // Monotonically increasing from 1 263296417Sdim static unsigned int ID; 264296417Sdim 265296417Sdim // Maps Allocation DataType enum and vector size to printable strings 266296417Sdim // using mapping from RenderScript numerical types summary documentation 267296417Sdim static const char* RsDataTypeToString[][4]; 268296417Sdim 269296417Sdim // Maps Allocation DataKind enum to printable strings 270296417Sdim static const char* RsDataKindToString[]; 271296417Sdim 272296417Sdim // Maps allocation types to format sizes for printing. 273296417Sdim static const unsigned int RSTypeToFormat[][3]; 274296417Sdim 275296417Sdim // Give each allocation an ID as a way 276296417Sdim // for commands to reference it. 277296417Sdim const unsigned int id; 278296417Sdim 279296417Sdim RenderScriptRuntime::Element element; // Allocation Element type 280296417Sdim empirical_type<Dimension> dimension; // Dimensions of the Allocation 281296417Sdim empirical_type<lldb::addr_t> address; // Pointer to address of the RS Allocation 282296417Sdim empirical_type<lldb::addr_t> data_ptr; // Pointer to the data held by the Allocation 283296417Sdim empirical_type<lldb::addr_t> type_ptr; // Pointer to the RS Type of the Allocation 284296417Sdim empirical_type<lldb::addr_t> context; // Pointer to the RS Context of the Allocation 285296417Sdim empirical_type<uint32_t> size; // Size of the allocation 286296417Sdim empirical_type<uint32_t> stride; // Stride between rows of the allocation 287296417Sdim 288296417Sdim // Give each allocation an id, so we can reference it in user commands. 289296417Sdim AllocationDetails(): id(ID++) 290296417Sdim { 291296417Sdim } 292296417Sdim 293296417Sdim bool shouldRefresh() const 294296417Sdim { 295296417Sdim bool valid_ptrs = data_ptr.isValid() && *data_ptr.get() != 0x0; 296296417Sdim valid_ptrs = valid_ptrs && type_ptr.isValid() && *type_ptr.get() != 0x0; 297296417Sdim return !valid_ptrs || !dimension.isValid() || !size.isValid() || element.shouldRefresh(); 298296417Sdim } 299296417Sdim}; 300296417Sdim 301296417Sdimconst ConstString & 302296417SdimRenderScriptRuntime::Element::GetFallbackStructName() 303296417Sdim{ 304296417Sdim static const ConstString FallbackStructName("struct"); 305296417Sdim return FallbackStructName; 306296417Sdim} 307296417Sdim 308296417Sdimunsigned int RenderScriptRuntime::AllocationDetails::ID = 1; 309296417Sdim 310296417Sdimconst char* RenderScriptRuntime::AllocationDetails::RsDataKindToString[] = 311296417Sdim{ 312296417Sdim "User", 313296417Sdim "Undefined", "Undefined", "Undefined", // Enum jumps from 0 to 7 314296417Sdim "Undefined", "Undefined", "Undefined", 315296417Sdim "L Pixel", 316296417Sdim "A Pixel", 317296417Sdim "LA Pixel", 318296417Sdim "RGB Pixel", 319296417Sdim "RGBA Pixel", 320296417Sdim "Pixel Depth", 321296417Sdim "YUV Pixel" 322296417Sdim}; 323296417Sdim 324296417Sdimconst char* RenderScriptRuntime::AllocationDetails::RsDataTypeToString[][4] = 325296417Sdim{ 326296417Sdim {"None", "None", "None", "None"}, 327296417Sdim {"half", "half2", "half3", "half4"}, 328296417Sdim {"float", "float2", "float3", "float4"}, 329296417Sdim {"double", "double2", "double3", "double4"}, 330296417Sdim {"char", "char2", "char3", "char4"}, 331296417Sdim {"short", "short2", "short3", "short4"}, 332296417Sdim {"int", "int2", "int3", "int4"}, 333296417Sdim {"long", "long2", "long3", "long4"}, 334296417Sdim {"uchar", "uchar2", "uchar3", "uchar4"}, 335296417Sdim {"ushort", "ushort2", "ushort3", "ushort4"}, 336296417Sdim {"uint", "uint2", "uint3", "uint4"}, 337296417Sdim {"ulong", "ulong2", "ulong3", "ulong4"}, 338296417Sdim {"bool", "bool2", "bool3", "bool4"}, 339296417Sdim {"packed_565", "packed_565", "packed_565", "packed_565"}, 340296417Sdim {"packed_5551", "packed_5551", "packed_5551", "packed_5551"}, 341296417Sdim {"packed_4444", "packed_4444", "packed_4444", "packed_4444"}, 342296417Sdim {"rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4"}, 343296417Sdim {"rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3"}, 344296417Sdim {"rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2"}, 345296417Sdim 346296417Sdim // Handlers 347296417Sdim {"RS Element", "RS Element", "RS Element", "RS Element"}, 348296417Sdim {"RS Type", "RS Type", "RS Type", "RS Type"}, 349296417Sdim {"RS Allocation", "RS Allocation", "RS Allocation", "RS Allocation"}, 350296417Sdim {"RS Sampler", "RS Sampler", "RS Sampler", "RS Sampler"}, 351296417Sdim {"RS Script", "RS Script", "RS Script", "RS Script"}, 352296417Sdim 353296417Sdim // Deprecated 354296417Sdim {"RS Mesh", "RS Mesh", "RS Mesh", "RS Mesh"}, 355296417Sdim {"RS Program Fragment", "RS Program Fragment", "RS Program Fragment", "RS Program Fragment"}, 356296417Sdim {"RS Program Vertex", "RS Program Vertex", "RS Program Vertex", "RS Program Vertex"}, 357296417Sdim {"RS Program Raster", "RS Program Raster", "RS Program Raster", "RS Program Raster"}, 358296417Sdim {"RS Program Store", "RS Program Store", "RS Program Store", "RS Program Store"}, 359296417Sdim {"RS Font", "RS Font", "RS Font", "RS Font"} 360296417Sdim}; 361296417Sdim 362296417Sdim// Used as an index into the RSTypeToFormat array elements 363296417Sdimenum TypeToFormatIndex { 364296417Sdim eFormatSingle = 0, 365296417Sdim eFormatVector, 366296417Sdim eElementSize 367296417Sdim}; 368296417Sdim 369296417Sdim// { format enum of single element, format enum of element vector, size of element} 370296417Sdimconst unsigned int RenderScriptRuntime::AllocationDetails::RSTypeToFormat[][3] = 371296417Sdim{ 372296417Sdim {eFormatHex, eFormatHex, 1}, // RS_TYPE_NONE 373296417Sdim {eFormatFloat, eFormatVectorOfFloat16, 2}, // RS_TYPE_FLOAT_16 374296417Sdim {eFormatFloat, eFormatVectorOfFloat32, sizeof(float)}, // RS_TYPE_FLOAT_32 375296417Sdim {eFormatFloat, eFormatVectorOfFloat64, sizeof(double)}, // RS_TYPE_FLOAT_64 376296417Sdim {eFormatDecimal, eFormatVectorOfSInt8, sizeof(int8_t)}, // RS_TYPE_SIGNED_8 377296417Sdim {eFormatDecimal, eFormatVectorOfSInt16, sizeof(int16_t)}, // RS_TYPE_SIGNED_16 378296417Sdim {eFormatDecimal, eFormatVectorOfSInt32, sizeof(int32_t)}, // RS_TYPE_SIGNED_32 379296417Sdim {eFormatDecimal, eFormatVectorOfSInt64, sizeof(int64_t)}, // RS_TYPE_SIGNED_64 380296417Sdim {eFormatDecimal, eFormatVectorOfUInt8, sizeof(uint8_t)}, // RS_TYPE_UNSIGNED_8 381296417Sdim {eFormatDecimal, eFormatVectorOfUInt16, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_16 382296417Sdim {eFormatDecimal, eFormatVectorOfUInt32, sizeof(uint32_t)}, // RS_TYPE_UNSIGNED_32 383296417Sdim {eFormatDecimal, eFormatVectorOfUInt64, sizeof(uint64_t)}, // RS_TYPE_UNSIGNED_64 384296417Sdim {eFormatBoolean, eFormatBoolean, 1}, // RS_TYPE_BOOL 385296417Sdim {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_6_5 386296417Sdim {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_5_5_1 387296417Sdim {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_4_4_4_4 388296417Sdim {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 16}, // RS_TYPE_MATRIX_4X4 389296417Sdim {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 9}, // RS_TYPE_MATRIX_3X3 390296417Sdim {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 4} // RS_TYPE_MATRIX_2X2 391296417Sdim}; 392296417Sdim 393285101Semaste//------------------------------------------------------------------ 394285101Semaste// Static Functions 395285101Semaste//------------------------------------------------------------------ 396285101SemasteLanguageRuntime * 397285101SemasteRenderScriptRuntime::CreateInstance(Process *process, lldb::LanguageType language) 398285101Semaste{ 399285101Semaste 400285101Semaste if (language == eLanguageTypeExtRenderScript) 401285101Semaste return new RenderScriptRuntime(process); 402285101Semaste else 403285101Semaste return NULL; 404285101Semaste} 405285101Semaste 406296417Sdim// Callback with a module to search for matching symbols. 407296417Sdim// We first check that the module contains RS kernels. 408296417Sdim// Then look for a symbol which matches our kernel name. 409296417Sdim// The breakpoint address is finally set using the address of this symbol. 410296417SdimSearcher::CallbackReturn 411296417SdimRSBreakpointResolver::SearchCallback(SearchFilter &filter, 412296417Sdim SymbolContext &context, 413296417Sdim Address*, 414296417Sdim bool) 415296417Sdim{ 416296417Sdim ModuleSP module = context.module_sp; 417296417Sdim 418296417Sdim if (!module) 419296417Sdim return Searcher::eCallbackReturnContinue; 420296417Sdim 421296417Sdim // Is this a module containing renderscript kernels? 422296417Sdim if (nullptr == module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData)) 423296417Sdim return Searcher::eCallbackReturnContinue; 424296417Sdim 425296417Sdim // Attempt to set a breakpoint on the kernel name symbol within the module library. 426296417Sdim // If it's not found, it's likely debug info is unavailable - try to set a 427296417Sdim // breakpoint on <name>.expand. 428296417Sdim 429296417Sdim const Symbol* kernel_sym = module->FindFirstSymbolWithNameAndType(m_kernel_name, eSymbolTypeCode); 430296417Sdim if (!kernel_sym) 431296417Sdim { 432296417Sdim std::string kernel_name_expanded(m_kernel_name.AsCString()); 433296417Sdim kernel_name_expanded.append(".expand"); 434296417Sdim kernel_sym = module->FindFirstSymbolWithNameAndType(ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode); 435296417Sdim } 436296417Sdim 437296417Sdim if (kernel_sym) 438296417Sdim { 439296417Sdim Address bp_addr = kernel_sym->GetAddress(); 440296417Sdim if (filter.AddressPasses(bp_addr)) 441296417Sdim m_breakpoint->AddLocation(bp_addr); 442296417Sdim } 443296417Sdim 444296417Sdim return Searcher::eCallbackReturnContinue; 445296417Sdim} 446296417Sdim 447285101Semastevoid 448285101SemasteRenderScriptRuntime::Initialize() 449285101Semaste{ 450285101Semaste PluginManager::RegisterPlugin(GetPluginNameStatic(), "RenderScript language support", CreateInstance, GetCommandObject); 451285101Semaste} 452285101Semaste 453285101Semastevoid 454285101SemasteRenderScriptRuntime::Terminate() 455285101Semaste{ 456285101Semaste PluginManager::UnregisterPlugin(CreateInstance); 457285101Semaste} 458285101Semaste 459285101Semastelldb_private::ConstString 460285101SemasteRenderScriptRuntime::GetPluginNameStatic() 461285101Semaste{ 462285101Semaste static ConstString g_name("renderscript"); 463285101Semaste return g_name; 464285101Semaste} 465285101Semaste 466296417SdimRenderScriptRuntime::ModuleKind 467285101SemasteRenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp) 468285101Semaste{ 469285101Semaste if (module_sp) 470285101Semaste { 471285101Semaste // Is this a module containing renderscript kernels? 472285101Semaste const Symbol *info_sym = module_sp->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData); 473285101Semaste if (info_sym) 474285101Semaste { 475285101Semaste return eModuleKindKernelObj; 476285101Semaste } 477285101Semaste 478285101Semaste // Is this the main RS runtime library 479285101Semaste const ConstString rs_lib("libRS.so"); 480285101Semaste if (module_sp->GetFileSpec().GetFilename() == rs_lib) 481285101Semaste { 482285101Semaste return eModuleKindLibRS; 483285101Semaste } 484285101Semaste 485285101Semaste const ConstString rs_driverlib("libRSDriver.so"); 486285101Semaste if (module_sp->GetFileSpec().GetFilename() == rs_driverlib) 487285101Semaste { 488285101Semaste return eModuleKindDriver; 489285101Semaste } 490285101Semaste 491296417Sdim const ConstString rs_cpureflib("libRSCpuRef.so"); 492285101Semaste if (module_sp->GetFileSpec().GetFilename() == rs_cpureflib) 493285101Semaste { 494285101Semaste return eModuleKindImpl; 495285101Semaste } 496285101Semaste 497285101Semaste } 498285101Semaste return eModuleKindIgnored; 499285101Semaste} 500285101Semaste 501285101Semastebool 502285101SemasteRenderScriptRuntime::IsRenderScriptModule(const lldb::ModuleSP &module_sp) 503285101Semaste{ 504285101Semaste return GetModuleKind(module_sp) != eModuleKindIgnored; 505285101Semaste} 506285101Semaste 507296417Sdimvoid 508285101SemasteRenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list ) 509285101Semaste{ 510285101Semaste Mutex::Locker locker (module_list.GetMutex ()); 511285101Semaste 512285101Semaste size_t num_modules = module_list.GetSize(); 513285101Semaste for (size_t i = 0; i < num_modules; i++) 514285101Semaste { 515285101Semaste auto mod = module_list.GetModuleAtIndex (i); 516285101Semaste if (IsRenderScriptModule (mod)) 517285101Semaste { 518285101Semaste LoadModule(mod); 519285101Semaste } 520285101Semaste } 521285101Semaste} 522285101Semaste 523285101Semaste//------------------------------------------------------------------ 524285101Semaste// PluginInterface protocol 525285101Semaste//------------------------------------------------------------------ 526285101Semastelldb_private::ConstString 527285101SemasteRenderScriptRuntime::GetPluginName() 528285101Semaste{ 529285101Semaste return GetPluginNameStatic(); 530285101Semaste} 531285101Semaste 532285101Semasteuint32_t 533285101SemasteRenderScriptRuntime::GetPluginVersion() 534285101Semaste{ 535285101Semaste return 1; 536285101Semaste} 537285101Semaste 538285101Semastebool 539285101SemasteRenderScriptRuntime::IsVTableName(const char *name) 540285101Semaste{ 541285101Semaste return false; 542285101Semaste} 543285101Semaste 544285101Semastebool 545285101SemasteRenderScriptRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, 546296417Sdim TypeAndOrName &class_type_or_name, Address &address, 547296417Sdim Value::ValueType &value_type) 548285101Semaste{ 549285101Semaste return false; 550285101Semaste} 551285101Semaste 552296417SdimTypeAndOrName 553296417SdimRenderScriptRuntime::FixUpDynamicType (const TypeAndOrName& type_and_or_name, 554296417Sdim ValueObject& static_value) 555296417Sdim{ 556296417Sdim return type_and_or_name; 557296417Sdim} 558296417Sdim 559285101Semastebool 560285101SemasteRenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value) 561285101Semaste{ 562285101Semaste return false; 563285101Semaste} 564285101Semaste 565285101Semastelldb::BreakpointResolverSP 566285101SemasteRenderScriptRuntime::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp) 567285101Semaste{ 568285101Semaste BreakpointResolverSP resolver_sp; 569285101Semaste return resolver_sp; 570285101Semaste} 571285101Semaste 572285101Semasteconst RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] = 573285101Semaste{ 574285101Semaste //rsdScript 575296417Sdim { 576296417Sdim "rsdScriptInit", //name 577296417Sdim "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_7ScriptCEPKcS7_PKhjj", // symbol name 32 bit 578296417Sdim "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_7ScriptCEPKcS7_PKhmj", // symbol name 64 bit 579296417Sdim 0, // version 580296417Sdim RenderScriptRuntime::eModuleKindDriver, // type 581296417Sdim &lldb_private::RenderScriptRuntime::CaptureScriptInit1 // handler 582296417Sdim }, 583296417Sdim { 584296417Sdim "rsdScriptInvokeForEach", // name 585296417Sdim "_Z22rsdScriptInvokeForEachPKN7android12renderscript7ContextEPNS0_6ScriptEjPKNS0_10AllocationEPS6_PKvjPK12RsScriptCall", // symbol name 32bit 586296417Sdim "_Z22rsdScriptInvokeForEachPKN7android12renderscript7ContextEPNS0_6ScriptEjPKNS0_10AllocationEPS6_PKvmPK12RsScriptCall", // symbol name 64bit 587296417Sdim 0, // version 588296417Sdim RenderScriptRuntime::eModuleKindDriver, // type 589296417Sdim nullptr // handler 590296417Sdim }, 591296417Sdim { 592296417Sdim "rsdScriptInvokeForEachMulti", // name 593296417Sdim "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall", // symbol name 32bit 594296417Sdim "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0_6ScriptEjPPKNS0_10AllocationEmPS6_PKvmPK12RsScriptCall", // symbol name 64bit 595296417Sdim 0, // version 596296417Sdim RenderScriptRuntime::eModuleKindDriver, // type 597296417Sdim nullptr // handler 598296417Sdim }, 599296417Sdim { 600296417Sdim "rsdScriptInvokeFunction", // name 601296417Sdim "_Z23rsdScriptInvokeFunctionPKN7android12renderscript7ContextEPNS0_6ScriptEjPKvj", // symbol name 32bit 602296417Sdim "_Z23rsdScriptInvokeFunctionPKN7android12renderscript7ContextEPNS0_6ScriptEjPKvm", // symbol name 64bit 603296417Sdim 0, // version 604296417Sdim RenderScriptRuntime::eModuleKindDriver, // type 605296417Sdim nullptr // handler 606296417Sdim }, 607296417Sdim { 608296417Sdim "rsdScriptSetGlobalVar", // name 609296417Sdim "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_6ScriptEjPvj", // symbol name 32bit 610296417Sdim "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_6ScriptEjPvm", // symbol name 64bit 611296417Sdim 0, // version 612296417Sdim RenderScriptRuntime::eModuleKindDriver, // type 613296417Sdim &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar1 // handler 614296417Sdim }, 615285101Semaste 616285101Semaste //rsdAllocation 617296417Sdim { 618296417Sdim "rsdAllocationInit", // name 619296417Sdim "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_10AllocationEb", // symbol name 32bit 620296417Sdim "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_10AllocationEb", // symbol name 64bit 621296417Sdim 0, // version 622296417Sdim RenderScriptRuntime::eModuleKindDriver, // type 623296417Sdim &lldb_private::RenderScriptRuntime::CaptureAllocationInit1 // handler 624296417Sdim }, 625296417Sdim { 626296417Sdim "rsdAllocationRead2D", //name 627296417Sdim "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_10AllocationEjjj23RsAllocationCubemapFacejjPvjj", // symbol name 32bit 628296417Sdim "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_10AllocationEjjj23RsAllocationCubemapFacejjPvmm", // symbol name 64bit 629296417Sdim 0, // version 630296417Sdim RenderScriptRuntime::eModuleKindDriver, // type 631296417Sdim nullptr // handler 632296417Sdim }, 633296417Sdim { 634296417Sdim "rsdAllocationDestroy", // name 635296417Sdim "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_10AllocationE", // symbol name 32bit 636296417Sdim "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_10AllocationE", // symbol name 64bit 637296417Sdim 0, // version 638296417Sdim RenderScriptRuntime::eModuleKindDriver, // type 639296417Sdim &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy // handler 640296417Sdim }, 641285101Semaste}; 642296417Sdim 643285101Semasteconst size_t RenderScriptRuntime::s_runtimeHookCount = sizeof(s_runtimeHookDefns)/sizeof(s_runtimeHookDefns[0]); 644285101Semaste 645285101Semastebool 646285101SemasteRenderScriptRuntime::HookCallback(void *baton, StoppointCallbackContext *ctx, lldb::user_id_t break_id, lldb::user_id_t break_loc_id) 647285101Semaste{ 648285101Semaste RuntimeHook* hook_info = (RuntimeHook*)baton; 649285101Semaste ExecutionContext context(ctx->exe_ctx_ref); 650285101Semaste 651285101Semaste RenderScriptRuntime *lang_rt = (RenderScriptRuntime *)context.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 652285101Semaste 653285101Semaste lang_rt->HookCallback(hook_info, context); 654296417Sdim 655285101Semaste return false; 656285101Semaste} 657285101Semaste 658296417Sdimvoid 659285101SemasteRenderScriptRuntime::HookCallback(RuntimeHook* hook_info, ExecutionContext& context) 660285101Semaste{ 661285101Semaste Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 662285101Semaste 663296417Sdim if (log) 664285101Semaste log->Printf ("RenderScriptRuntime::HookCallback - '%s' .", hook_info->defn->name); 665285101Semaste 666296417Sdim if (hook_info->defn->grabber) 667285101Semaste { 668285101Semaste (this->*(hook_info->defn->grabber))(hook_info, context); 669285101Semaste } 670285101Semaste} 671285101Semaste 672285101Semastebool 673296417SdimRenderScriptRuntime::GetArgSimple(ExecutionContext &context, uint32_t arg, uint64_t *data) 674285101Semaste{ 675296417Sdim // Get a positional integer argument. 676296417Sdim // Given an ExecutionContext, ``context`` which should be a RenderScript 677296417Sdim // frame, get the value of the positional argument ``arg`` and save its value 678296417Sdim // to the address pointed to by ``data``. 679296417Sdim // returns true on success, false otherwise. 680296417Sdim // If unsuccessful, the value pointed to by ``data`` is undefined. Otherwise, 681296417Sdim // ``data`` will be set to the value of the the given ``arg``. 682296417Sdim // NOTE: only natural width integer arguments for the machine are supported. 683296417Sdim // Behaviour with non primitive arguments is undefined. 684285101Semaste 685285101Semaste if (!data) 686285101Semaste return false; 687285101Semaste 688296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 689285101Semaste Error error; 690285101Semaste RegisterContext* reg_ctx = context.GetRegisterContext(); 691285101Semaste Process* process = context.GetProcessPtr(); 692296417Sdim bool success = false; // return value 693285101Semaste 694296417Sdim if (!context.GetTargetPtr()) 695285101Semaste { 696296417Sdim if (log) 697296417Sdim log->Printf("RenderScriptRuntime::GetArgSimple - Invalid target"); 698296417Sdim 699296417Sdim return false; 700296417Sdim } 701296417Sdim 702296417Sdim switch (context.GetTargetPtr()->GetArchitecture().GetMachine()) 703296417Sdim { 704296417Sdim case llvm::Triple::ArchType::x86: 705285101Semaste { 706296417Sdim uint64_t sp = reg_ctx->GetSP(); 707285101Semaste uint32_t offset = (1 + arg) * sizeof(uint32_t); 708296417Sdim uint32_t result = 0; 709296417Sdim process->ReadMemory(sp + offset, &result, sizeof(uint32_t), error); 710296417Sdim if (error.Fail()) 711285101Semaste { 712296417Sdim if (log) 713296417Sdim log->Printf("RenderScriptRuntime::GetArgSimple - error reading X86 stack: %s.", error.AsCString()); 714285101Semaste } 715296417Sdim else 716296417Sdim { 717296417Sdim *data = result; 718296417Sdim success = true; 719296417Sdim } 720296417Sdim break; 721285101Semaste } 722296417Sdim case llvm::Triple::ArchType::x86_64: 723285101Semaste { 724296417Sdim // amd64 has 6 integer registers, and 8 XMM registers for parameter passing. 725296417Sdim // Surplus args are spilled onto the stack. 726296417Sdim // rdi, rsi, rdx, rcx, r8, r9, (zmm0 - 7 for vectors) 727296417Sdim // ref: AMD64 ABI Draft 0.99.6 ��� October 7, 2013 ��� 10:35; Figure 3.4. Retrieved from 728296417Sdim // http://www.x86-64.org/documentation/abi.pdf 729296417Sdim if (arg > 5) 730296417Sdim { 731296417Sdim if (log) 732296417Sdim log->Warning("X86_64 register spill is not supported."); 733296417Sdim break; 734296417Sdim } 735296417Sdim const char * regnames[] = {"rdi", "rsi", "rdx", "rcx", "r8", "r9"}; 736296417Sdim assert((sizeof(regnames) / sizeof(const char *)) > arg); 737296417Sdim const RegisterInfo *rArg = reg_ctx->GetRegisterInfoByName(regnames[arg]); 738285101Semaste RegisterValue rVal; 739296417Sdim success = reg_ctx->ReadRegister(rArg, rVal); 740296417Sdim if (success) 741296417Sdim { 742296417Sdim *data = rVal.GetAsUInt64(0u, &success); 743296417Sdim } 744296417Sdim else 745296417Sdim { 746296417Sdim if (log) 747296417Sdim log->Printf("RenderScriptRuntime::GetArgSimple - error reading x86_64 register: %d.", arg); 748296417Sdim } 749296417Sdim break; 750285101Semaste } 751296417Sdim case llvm::Triple::ArchType::arm: 752285101Semaste { 753296417Sdim // arm 32 bit 754296417Sdim // first 4 arguments are passed via registers 755296417Sdim if (arg < 4) 756285101Semaste { 757296417Sdim const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg); 758296417Sdim RegisterValue rVal; 759296417Sdim success = reg_ctx->ReadRegister(rArg, rVal); 760296417Sdim if (success) 761296417Sdim { 762296417Sdim (*data) = rVal.GetAsUInt32(0u, &success); 763296417Sdim } 764296417Sdim else 765296417Sdim { 766296417Sdim if (log) 767296417Sdim log->Printf("RenderScriptRuntime::GetArgSimple - error reading ARM register: %d.", arg); 768296417Sdim } 769296417Sdim } 770296417Sdim else 771296417Sdim { 772296417Sdim uint64_t sp = reg_ctx->GetSP(); 773285101Semaste uint32_t offset = (arg-4) * sizeof(uint32_t); 774296417Sdim uint32_t value = 0; 775296417Sdim size_t bytes_read = process->ReadMemory(sp + offset, &value, sizeof(value), error); 776296417Sdim if (error.Fail() || bytes_read != sizeof(value)) 777285101Semaste { 778296417Sdim if (log) 779296417Sdim log->Printf("RenderScriptRuntime::GetArgSimple - error reading ARM stack: %s.", error.AsCString()); 780285101Semaste } 781296417Sdim else 782296417Sdim { 783296417Sdim *data = value; 784296417Sdim success = true; 785296417Sdim } 786285101Semaste } 787296417Sdim break; 788296417Sdim } 789296417Sdim case llvm::Triple::ArchType::aarch64: 790296417Sdim { 791296417Sdim // arm 64 bit 792296417Sdim // first 8 arguments are in the registers 793296417Sdim if (arg < 8) 794296417Sdim { 795296417Sdim const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg); 796296417Sdim RegisterValue rVal; 797296417Sdim success = reg_ctx->ReadRegister(rArg, rVal); 798296417Sdim if (success) 799296417Sdim { 800296417Sdim *data = rVal.GetAsUInt64(0u, &success); 801296417Sdim } 802296417Sdim else 803296417Sdim { 804296417Sdim if (log) 805296417Sdim log->Printf("RenderScriptRuntime::GetArgSimple() - AARCH64 - Error while reading the argument #%d", arg); 806296417Sdim } 807296417Sdim } 808296417Sdim else 809296417Sdim { 810296417Sdim // @TODO: need to find the argument in the stack 811296417Sdim if (log) 812296417Sdim log->Printf("RenderScriptRuntime::GetArgSimple - AARCH64 - FOR #ARG >= 8 NOT IMPLEMENTED YET. Argument number: %d", arg); 813296417Sdim } 814296417Sdim break; 815296417Sdim } 816296417Sdim case llvm::Triple::ArchType::mipsel: 817296417Sdim { 818296417Sdim // read from the registers 819296417Sdim // first 4 arguments are passed in registers 820296417Sdim if (arg < 4){ 821296417Sdim const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg + 4); 822296417Sdim RegisterValue rVal; 823296417Sdim success = reg_ctx->ReadRegister(rArg, rVal); 824296417Sdim if (success) 825296417Sdim { 826296417Sdim *data = rVal.GetAsUInt64(0u, &success); 827296417Sdim } 828296417Sdim else 829296417Sdim { 830296417Sdim if (log) 831296417Sdim log->Printf("RenderScriptRuntime::GetArgSimple() - Mips - Error while reading the argument #%d", arg); 832296417Sdim } 833296417Sdim } 834296417Sdim // arguments > 4 are read from the stack 835296417Sdim else 836296417Sdim { 837296417Sdim uint64_t sp = reg_ctx->GetSP(); 838296417Sdim uint32_t offset = arg * sizeof(uint32_t); 839296417Sdim uint32_t value = 0; 840296417Sdim size_t bytes_read = process->ReadMemory(sp + offset, &value, sizeof(value), error); 841296417Sdim if (error.Fail() || bytes_read != sizeof(value)) 842296417Sdim { 843296417Sdim if (log) 844296417Sdim log->Printf("RenderScriptRuntime::GetArgSimple - error reading Mips stack: %s.", error.AsCString()); 845296417Sdim } 846296417Sdim else 847296417Sdim { 848296417Sdim *data = value; 849296417Sdim success = true; 850296417Sdim } 851296417Sdim } 852296417Sdim break; 853296417Sdim } 854296417Sdim case llvm::Triple::ArchType::mips64el: 855296417Sdim { 856296417Sdim // read from the registers 857296417Sdim if (arg < 8) 858296417Sdim { 859296417Sdim const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg + 4); 860296417Sdim RegisterValue rVal; 861296417Sdim success = reg_ctx->ReadRegister(rArg, rVal); 862296417Sdim if (success) 863296417Sdim { 864296417Sdim (*data) = rVal.GetAsUInt64(0u, &success); 865296417Sdim } 866296417Sdim else 867296417Sdim { 868296417Sdim if (log) 869296417Sdim log->Printf("RenderScriptRuntime::GetArgSimple - Mips64 - Error reading the argument #%d", arg); 870296417Sdim } 871296417Sdim } 872296417Sdim // arguments > 8 are read from the stack 873296417Sdim else 874296417Sdim { 875296417Sdim uint64_t sp = reg_ctx->GetSP(); 876296417Sdim uint32_t offset = (arg - 8) * sizeof(uint64_t); 877296417Sdim uint64_t value = 0; 878296417Sdim size_t bytes_read = process->ReadMemory(sp + offset, &value, sizeof(value), error); 879296417Sdim if (error.Fail() || bytes_read != sizeof(value)) 880296417Sdim { 881296417Sdim if (log) 882296417Sdim log->Printf("RenderScriptRuntime::GetArgSimple - Mips64 - Error reading Mips64 stack: %s.", error.AsCString()); 883296417Sdim } 884296417Sdim else 885296417Sdim { 886296417Sdim *data = value; 887296417Sdim success = true; 888296417Sdim } 889296417Sdim } 890296417Sdim break; 891296417Sdim } 892296417Sdim default: 893296417Sdim { 894296417Sdim // invalid architecture 895296417Sdim if (log) 896296417Sdim log->Printf("RenderScriptRuntime::GetArgSimple - Architecture not supported"); 897296417Sdim } 898285101Semaste } 899296417Sdim 900296417Sdim if (!success) 901296417Sdim { 902296417Sdim if (log) 903296417Sdim log->Printf("RenderScriptRuntime::GetArgSimple - failed to get argument at index %" PRIu32, arg); 904296417Sdim } 905296417Sdim return success; 906285101Semaste} 907285101Semaste 908296417Sdimvoid 909285101SemasteRenderScriptRuntime::CaptureSetGlobalVar1(RuntimeHook* hook_info, ExecutionContext& context) 910285101Semaste{ 911285101Semaste Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 912296417Sdim 913285101Semaste //Context, Script, int, data, length 914285101Semaste 915296417Sdim uint64_t rs_context_u64 = 0U; 916296417Sdim uint64_t rs_script_u64 = 0U; 917296417Sdim uint64_t rs_id_u64 = 0U; 918296417Sdim uint64_t rs_data_u64 = 0U; 919296417Sdim uint64_t rs_length_u64 = 0U; 920285101Semaste 921296417Sdim bool success = 922296417Sdim GetArgSimple(context, 0, &rs_context_u64) && 923296417Sdim GetArgSimple(context, 1, &rs_script_u64) && 924296417Sdim GetArgSimple(context, 2, &rs_id_u64) && 925296417Sdim GetArgSimple(context, 3, &rs_data_u64) && 926296417Sdim GetArgSimple(context, 4, &rs_length_u64); 927285101Semaste 928296417Sdim if (!success) 929285101Semaste { 930296417Sdim if (log) 931296417Sdim log->Printf("RenderScriptRuntime::CaptureSetGlobalVar1 - Error while reading the function parameters"); 932296417Sdim return; 933296417Sdim } 934296417Sdim 935296417Sdim if (log) 936296417Sdim { 937285101Semaste log->Printf ("RenderScriptRuntime::CaptureSetGlobalVar1 - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64 ":%" PRIu64 "bytes.", 938296417Sdim rs_context_u64, rs_script_u64, rs_id_u64, rs_data_u64, rs_length_u64); 939285101Semaste 940296417Sdim addr_t script_addr = (addr_t)rs_script_u64; 941285101Semaste if (m_scriptMappings.find( script_addr ) != m_scriptMappings.end()) 942285101Semaste { 943285101Semaste auto rsm = m_scriptMappings[script_addr]; 944296417Sdim if (rs_id_u64 < rsm->m_globals.size()) 945285101Semaste { 946296417Sdim auto rsg = rsm->m_globals[rs_id_u64]; 947296417Sdim log->Printf ("RenderScriptRuntime::CaptureSetGlobalVar1 - Setting of '%s' within '%s' inferred", rsg.m_name.AsCString(), 948285101Semaste rsm->m_module->GetFileSpec().GetFilename().AsCString()); 949285101Semaste } 950285101Semaste } 951285101Semaste } 952285101Semaste} 953285101Semaste 954296417Sdimvoid 955285101SemasteRenderScriptRuntime::CaptureAllocationInit1(RuntimeHook* hook_info, ExecutionContext& context) 956285101Semaste{ 957285101Semaste Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 958296417Sdim 959285101Semaste //Context, Alloc, bool 960285101Semaste 961296417Sdim uint64_t rs_context_u64 = 0U; 962296417Sdim uint64_t rs_alloc_u64 = 0U; 963296417Sdim uint64_t rs_forceZero_u64 = 0U; 964285101Semaste 965296417Sdim bool success = 966296417Sdim GetArgSimple(context, 0, &rs_context_u64) && 967296417Sdim GetArgSimple(context, 1, &rs_alloc_u64) && 968296417Sdim GetArgSimple(context, 2, &rs_forceZero_u64); 969296417Sdim if (!success) // error case 970296417Sdim { 971296417Sdim if (log) 972296417Sdim log->Printf("RenderScriptRuntime::CaptureAllocationInit1 - Error while reading the function parameters"); 973296417Sdim return; // abort 974296417Sdim } 975296417Sdim 976296417Sdim if (log) 977285101Semaste log->Printf ("RenderScriptRuntime::CaptureAllocationInit1 - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .", 978296417Sdim rs_context_u64, rs_alloc_u64, rs_forceZero_u64); 979296417Sdim 980296417Sdim AllocationDetails* alloc = LookUpAllocation(rs_alloc_u64, true); 981296417Sdim if (alloc) 982296417Sdim alloc->context = rs_context_u64; 983285101Semaste} 984285101Semaste 985296417Sdimvoid 986296417SdimRenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook* hook_info, ExecutionContext& context) 987296417Sdim{ 988296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 989296417Sdim 990296417Sdim // Context, Alloc 991296417Sdim uint64_t rs_context_u64 = 0U; 992296417Sdim uint64_t rs_alloc_u64 = 0U; 993296417Sdim 994296417Sdim bool success = GetArgSimple(context, 0, &rs_context_u64) && GetArgSimple(context, 1, &rs_alloc_u64); 995296417Sdim if (!success) // error case 996296417Sdim { 997296417Sdim if (log) 998296417Sdim log->Printf("RenderScriptRuntime::CaptureAllocationDestroy - Error while reading the function parameters"); 999296417Sdim return; // abort 1000296417Sdim } 1001296417Sdim 1002296417Sdim if (log) 1003296417Sdim log->Printf("RenderScriptRuntime::CaptureAllocationDestroy - 0x%" PRIx64 ", 0x%" PRIx64 ".", 1004296417Sdim rs_context_u64, rs_alloc_u64); 1005296417Sdim 1006296417Sdim for (auto iter = m_allocations.begin(); iter != m_allocations.end(); ++iter) 1007296417Sdim { 1008296417Sdim auto& allocation_ap = *iter; // get the unique pointer 1009296417Sdim if (allocation_ap->address.isValid() && *allocation_ap->address.get() == rs_alloc_u64) 1010296417Sdim { 1011296417Sdim m_allocations.erase(iter); 1012296417Sdim if (log) 1013296417Sdim log->Printf("RenderScriptRuntime::CaptureAllocationDestroy - Deleted allocation entry"); 1014296417Sdim return; 1015296417Sdim } 1016296417Sdim } 1017296417Sdim 1018296417Sdim if (log) 1019296417Sdim log->Printf("RenderScriptRuntime::CaptureAllocationDestroy - Couldn't find destroyed allocation"); 1020296417Sdim} 1021296417Sdim 1022296417Sdimvoid 1023285101SemasteRenderScriptRuntime::CaptureScriptInit1(RuntimeHook* hook_info, ExecutionContext& context) 1024285101Semaste{ 1025285101Semaste Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1026285101Semaste 1027285101Semaste //Context, Script, resname Str, cachedir Str 1028285101Semaste Error error; 1029285101Semaste Process* process = context.GetProcessPtr(); 1030285101Semaste 1031296417Sdim uint64_t rs_context_u64 = 0U; 1032296417Sdim uint64_t rs_script_u64 = 0U; 1033296417Sdim uint64_t rs_resnameptr_u64 = 0U; 1034296417Sdim uint64_t rs_cachedirptr_u64 = 0U; 1035285101Semaste 1036285101Semaste std::string resname; 1037285101Semaste std::string cachedir; 1038285101Semaste 1039296417Sdim // read the function parameters 1040296417Sdim bool success = 1041296417Sdim GetArgSimple(context, 0, &rs_context_u64) && 1042296417Sdim GetArgSimple(context, 1, &rs_script_u64) && 1043296417Sdim GetArgSimple(context, 2, &rs_resnameptr_u64) && 1044296417Sdim GetArgSimple(context, 3, &rs_cachedirptr_u64); 1045285101Semaste 1046296417Sdim if (!success) 1047296417Sdim { 1048296417Sdim if (log) 1049296417Sdim log->Printf("RenderScriptRuntime::CaptureScriptInit1 - Error while reading the function parameters"); 1050296417Sdim return; 1051296417Sdim } 1052296417Sdim 1053296417Sdim process->ReadCStringFromMemory((lldb::addr_t)rs_resnameptr_u64, resname, error); 1054285101Semaste if (error.Fail()) 1055285101Semaste { 1056296417Sdim if (log) 1057285101Semaste log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - error reading resname: %s.", error.AsCString()); 1058296417Sdim 1059285101Semaste } 1060285101Semaste 1061296417Sdim process->ReadCStringFromMemory((lldb::addr_t)rs_cachedirptr_u64, cachedir, error); 1062285101Semaste if (error.Fail()) 1063285101Semaste { 1064296417Sdim if (log) 1065296417Sdim log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - error reading cachedir: %s.", error.AsCString()); 1066285101Semaste } 1067296417Sdim 1068285101Semaste if (log) 1069285101Semaste log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .", 1070296417Sdim rs_context_u64, rs_script_u64, resname.c_str(), cachedir.c_str()); 1071285101Semaste 1072285101Semaste if (resname.size() > 0) 1073285101Semaste { 1074285101Semaste StreamString strm; 1075285101Semaste strm.Printf("librs.%s.so", resname.c_str()); 1076285101Semaste 1077296417Sdim ScriptDetails* script = LookUpScript(rs_script_u64, true); 1078296417Sdim if (script) 1079296417Sdim { 1080296417Sdim script->type = ScriptDetails::eScriptC; 1081296417Sdim script->cacheDir = cachedir; 1082296417Sdim script->resName = resname; 1083296417Sdim script->scriptDyLib = strm.GetData(); 1084296417Sdim script->context = addr_t(rs_context_u64); 1085296417Sdim } 1086285101Semaste 1087285101Semaste if (log) 1088285101Semaste log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - '%s' tagged with context 0x%" PRIx64 " and script 0x%" PRIx64 ".", 1089296417Sdim strm.GetData(), rs_context_u64, rs_script_u64); 1090296417Sdim } 1091285101Semaste else if (log) 1092285101Semaste { 1093285101Semaste log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - resource name invalid, Script not tagged"); 1094285101Semaste } 1095285101Semaste} 1096285101Semaste 1097285101Semastevoid 1098285101SemasteRenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, ModuleKind kind) 1099285101Semaste{ 1100285101Semaste Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1101285101Semaste 1102285101Semaste if (!module) 1103285101Semaste { 1104285101Semaste return; 1105285101Semaste } 1106285101Semaste 1107296417Sdim Target &target = GetProcess()->GetTarget(); 1108296417Sdim llvm::Triple::ArchType targetArchType = target.GetArchitecture().GetMachine(); 1109296417Sdim 1110296417Sdim if (targetArchType != llvm::Triple::ArchType::x86 1111296417Sdim && targetArchType != llvm::Triple::ArchType::arm 1112296417Sdim && targetArchType != llvm::Triple::ArchType::aarch64 1113296417Sdim && targetArchType != llvm::Triple::ArchType::mipsel 1114296417Sdim && targetArchType != llvm::Triple::ArchType::mips64el 1115296417Sdim && targetArchType != llvm::Triple::ArchType::x86_64 1116296417Sdim ) 1117285101Semaste { 1118285101Semaste if (log) 1119296417Sdim log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Unable to hook runtime. Only X86, ARM, Mips supported currently."); 1120285101Semaste 1121285101Semaste return; 1122285101Semaste } 1123285101Semaste 1124296417Sdim uint32_t archByteSize = target.GetArchitecture().GetAddressByteSize(); 1125285101Semaste 1126285101Semaste for (size_t idx = 0; idx < s_runtimeHookCount; idx++) 1127285101Semaste { 1128285101Semaste const HookDefn* hook_defn = &s_runtimeHookDefns[idx]; 1129285101Semaste if (hook_defn->kind != kind) { 1130285101Semaste continue; 1131285101Semaste } 1132285101Semaste 1133296417Sdim const char* symbol_name = (archByteSize == 4) ? hook_defn->symbol_name_m32 : hook_defn->symbol_name_m64; 1134285101Semaste 1135296417Sdim const Symbol *sym = module->FindFirstSymbolWithNameAndType(ConstString(symbol_name), eSymbolTypeCode); 1136296417Sdim if (!sym){ 1137296417Sdim if (log){ 1138296417Sdim log->Printf("RenderScriptRuntime::LoadRuntimeHooks - ERROR: Symbol '%s' related to the function %s not found", symbol_name, hook_defn->name); 1139296417Sdim } 1140296417Sdim continue; 1141296417Sdim } 1142296417Sdim 1143285101Semaste addr_t addr = sym->GetLoadAddress(&target); 1144285101Semaste if (addr == LLDB_INVALID_ADDRESS) 1145285101Semaste { 1146296417Sdim if (log) 1147296417Sdim log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Unable to resolve the address of hook function '%s' with symbol '%s'.", 1148296417Sdim hook_defn->name, symbol_name); 1149285101Semaste continue; 1150285101Semaste } 1151296417Sdim else 1152296417Sdim { 1153296417Sdim if (log) 1154296417Sdim log->Printf("RenderScriptRuntime::LoadRuntimeHooks - Function %s, address resolved at 0x%" PRIx64, hook_defn->name, addr); 1155296417Sdim } 1156285101Semaste 1157285101Semaste RuntimeHookSP hook(new RuntimeHook()); 1158285101Semaste hook->address = addr; 1159285101Semaste hook->defn = hook_defn; 1160285101Semaste hook->bp_sp = target.CreateBreakpoint(addr, true, false); 1161285101Semaste hook->bp_sp->SetCallback(HookCallback, hook.get(), true); 1162285101Semaste m_runtimeHooks[addr] = hook; 1163285101Semaste if (log) 1164285101Semaste { 1165296417Sdim log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Successfully hooked '%s' in '%s' version %" PRIu64 " at 0x%" PRIx64 ".", 1166285101Semaste hook_defn->name, module->GetFileSpec().GetFilename().AsCString(), (uint64_t)hook_defn->version, (uint64_t)addr); 1167285101Semaste } 1168285101Semaste } 1169285101Semaste} 1170285101Semaste 1171285101Semastevoid 1172285101SemasteRenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp) 1173285101Semaste{ 1174285101Semaste if (!rsmodule_sp) 1175285101Semaste return; 1176285101Semaste 1177285101Semaste Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1178285101Semaste 1179285101Semaste const ModuleSP module = rsmodule_sp->m_module; 1180285101Semaste const FileSpec& file = module->GetPlatformFileSpec(); 1181296417Sdim 1182296417Sdim // Iterate over all of the scripts that we currently know of. 1183296417Sdim // Note: We cant push or pop to m_scripts here or it may invalidate rs_script. 1184296417Sdim for (const auto & rs_script : m_scripts) 1185285101Semaste { 1186296417Sdim // Extract the expected .so file path for this script. 1187296417Sdim std::string dylib; 1188296417Sdim if (!rs_script->scriptDyLib.get(dylib)) 1189296417Sdim continue; 1190296417Sdim 1191296417Sdim // Only proceed if the module that has loaded corresponds to this script. 1192296417Sdim if (file.GetFilename() != ConstString(dylib.c_str())) 1193296417Sdim continue; 1194296417Sdim 1195296417Sdim // Obtain the script address which we use as a key. 1196296417Sdim lldb::addr_t script; 1197296417Sdim if (!rs_script->script.get(script)) 1198296417Sdim continue; 1199296417Sdim 1200296417Sdim // If we have a script mapping for the current script. 1201296417Sdim if (m_scriptMappings.find(script) != m_scriptMappings.end()) 1202285101Semaste { 1203296417Sdim // if the module we have stored is different to the one we just received. 1204296417Sdim if (m_scriptMappings[script] != rsmodule_sp) 1205285101Semaste { 1206296417Sdim if (log) 1207296417Sdim log->Printf ("RenderScriptRuntime::FixupScriptDetails - Error: script %" PRIx64 " wants reassigned to new rsmodule '%s'.", 1208296417Sdim (uint64_t)script, rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); 1209296417Sdim } 1210296417Sdim } 1211296417Sdim // We don't have a script mapping for the current script. 1212296417Sdim else 1213296417Sdim { 1214296417Sdim // Obtain the script resource name. 1215296417Sdim std::string resName; 1216296417Sdim if (rs_script->resName.get(resName)) 1217296417Sdim // Set the modules resource name. 1218296417Sdim rsmodule_sp->m_resname = resName; 1219296417Sdim // Add Script/Module pair to map. 1220296417Sdim m_scriptMappings[script] = rsmodule_sp; 1221296417Sdim if (log) 1222296417Sdim log->Printf ("RenderScriptRuntime::FixupScriptDetails - script %" PRIx64 " associated with rsmodule '%s'.", 1223296417Sdim (uint64_t)script, rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); 1224296417Sdim } 1225296417Sdim } 1226296417Sdim} 1227296417Sdim 1228296417Sdim// Uses the Target API to evaluate the expression passed as a parameter to the function 1229296417Sdim// The result of that expression is returned an unsigned 64 bit int, via the result* paramter. 1230296417Sdim// Function returns true on success, and false on failure 1231296417Sdimbool 1232296417SdimRenderScriptRuntime::EvalRSExpression(const char* expression, StackFrame* frame_ptr, uint64_t* result) 1233296417Sdim{ 1234296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1235296417Sdim if (log) 1236296417Sdim log->Printf("RenderScriptRuntime::EvalRSExpression(%s)", expression); 1237296417Sdim 1238296417Sdim ValueObjectSP expr_result; 1239296417Sdim // Perform the actual expression evaluation 1240296417Sdim GetProcess()->GetTarget().EvaluateExpression(expression, frame_ptr, expr_result); 1241296417Sdim 1242296417Sdim if (!expr_result) 1243296417Sdim { 1244296417Sdim if (log) 1245296417Sdim log->Printf("RenderScriptRuntime::EvalRSExpression - Error: Couldn't evaluate expression"); 1246296417Sdim return false; 1247296417Sdim } 1248296417Sdim 1249296417Sdim // The result of the expression is invalid 1250296417Sdim if (!expr_result->GetError().Success()) 1251296417Sdim { 1252296417Sdim Error err = expr_result->GetError(); 1253296417Sdim if (err.GetError() == UserExpression::kNoResult) // Expression returned void, so this is actually a success 1254296417Sdim { 1255296417Sdim if (log) 1256296417Sdim log->Printf("RenderScriptRuntime::EvalRSExpression - Expression returned void"); 1257296417Sdim 1258296417Sdim result = nullptr; 1259296417Sdim return true; 1260296417Sdim } 1261296417Sdim 1262296417Sdim if (log) 1263296417Sdim log->Printf("RenderScriptRuntime::EvalRSExpression - Error evaluating expression result: %s", err.AsCString()); 1264296417Sdim return false; 1265296417Sdim } 1266296417Sdim 1267296417Sdim bool success = false; 1268296417Sdim *result = expr_result->GetValueAsUnsigned(0, &success); // We only read the result as an unsigned int. 1269296417Sdim 1270296417Sdim if (!success) 1271296417Sdim { 1272296417Sdim if (log) 1273296417Sdim log->Printf("RenderScriptRuntime::EvalRSExpression - Error: Couldn't convert expression result to unsigned int"); 1274296417Sdim return false; 1275296417Sdim } 1276296417Sdim 1277296417Sdim return true; 1278296417Sdim} 1279296417Sdim 1280296417Sdimnamespace // anonymous 1281296417Sdim{ 1282296417Sdim // max length of an expanded expression 1283296417Sdim const int jit_max_expr_size = 768; 1284296417Sdim 1285296417Sdim // Format strings containing the expressions we may need to evaluate. 1286296417Sdim const char runtimeExpressions[][256] = 1287296417Sdim { 1288296417Sdim // Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap) 1289296417Sdim "(int*)_Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocationCubemapFace(0x%lx, %u, %u, %u, 0, 0)", 1290296417Sdim 1291296417Sdim // Type* rsaAllocationGetType(Context*, Allocation*) 1292296417Sdim "(void*)rsaAllocationGetType(0x%lx, 0x%lx)", 1293296417Sdim 1294296417Sdim // rsaTypeGetNativeData(Context*, Type*, void* typeData, size) 1295296417Sdim // Pack the data in the following way mHal.state.dimX; mHal.state.dimY; mHal.state.dimZ; 1296296417Sdim // mHal.state.lodCount; mHal.state.faces; mElement; into typeData 1297296417Sdim // Need to specify 32 or 64 bit for uint_t since this differs between devices 1298296417Sdim "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[0]", // X dim 1299296417Sdim "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[1]", // Y dim 1300296417Sdim "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[2]", // Z dim 1301296417Sdim "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[5]", // Element ptr 1302296417Sdim 1303296417Sdim // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size) 1304296417Sdim // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into elemData 1305296417Sdim "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[0]", // Type 1306296417Sdim "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[1]", // Kind 1307296417Sdim "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[3]", // Vector Size 1308296417Sdim "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[4]", // Field Count 1309296417Sdim 1310296417Sdim // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t *ids, const char **names, 1311296417Sdim // size_t *arraySizes, uint32_t dataSize) 1312296417Sdim // Needed for Allocations of structs to gather details about fields/Subelements 1313296417Sdim "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];" 1314296417Sdim "(void*)rsaElementGetSubElements(0x%lx, 0x%lx, ids, names, arr_size, %u); ids[%u]", // Element* of field 1315296417Sdim 1316296417Sdim "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];" 1317296417Sdim "(void*)rsaElementGetSubElements(0x%lx, 0x%lx, ids, names, arr_size, %u); names[%u]", // Name of field 1318296417Sdim 1319296417Sdim "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];" 1320296417Sdim "(void*)rsaElementGetSubElements(0x%lx, 0x%lx, ids, names, arr_size, %u); arr_size[%u]" // Array size of field 1321296417Sdim }; 1322296417Sdim 1323296417Sdim 1324296417Sdim // Temporary workaround for MIPS, until the compiler emits the JAL instruction when invoking directly the function. 1325296417Sdim // At the moment, when evaluating an expression involving a function call, the LLVM codegen for Mips emits a JAL 1326296417Sdim // instruction, which is able to jump in the range +/- 128MB with respect to the current program counter ($pc). If 1327296417Sdim // the requested function happens to reside outside the above region, the function address will be truncated and the 1328296417Sdim // function invocation will fail. This is a problem in the RS plugin as we rely on the RS API to probe the number and 1329296417Sdim // the nature of allocations. A proper solution in the MIPS compiler is currently being investigated. As temporary 1330296417Sdim // work around for this context, we'll invoke the RS API through function pointers, which cause the compiler to emit a 1331296417Sdim // register based JALR instruction. 1332296417Sdim const char runtimeExpressions_mips[][512] = 1333296417Sdim { 1334296417Sdim // Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap) 1335296417Sdim "int* (*f) (void*, int, int, int, int, int) = (int* (*) (void*, int, int, int, int, int)) " 1336296417Sdim "_Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocationCubemapFace; " 1337296417Sdim "(int*) f((void*) 0x%lx, %u, %u, %u, 0, 0)", 1338296417Sdim 1339296417Sdim // Type* rsaAllocationGetType(Context*, Allocation*) 1340296417Sdim "void* (*f) (void*, void*) = (void* (*) (void*, void*)) rsaAllocationGetType; (void*) f((void*) 0x%lx, (void*) 0x%lx)", 1341296417Sdim 1342296417Sdim // rsaTypeGetNativeData(Context*, Type*, void* typeData, size) 1343296417Sdim // Pack the data in the following way mHal.state.dimX; mHal.state.dimY; mHal.state.dimZ; 1344296417Sdim // mHal.state.lodCount; mHal.state.faces; mElement; into typeData 1345296417Sdim // Need to specify 32 or 64 bit for uint_t since this differs between devices 1346296417Sdim "uint%u_t data[6]; void* (*f)(void*, void*, uintptr_t*, uint32_t) = (void* (*)(void*, void*, uintptr_t*, uint32_t)) " 1347296417Sdim "rsaTypeGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 6); data[0]", 1348296417Sdim "uint%u_t data[6]; void* (*f)(void*, void*, uintptr_t*, uint32_t) = (void* (*)(void*, void*, uintptr_t*, uint32_t)) " 1349296417Sdim "rsaTypeGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 6); data[1]", 1350296417Sdim "uint%u_t data[6]; void* (*f)(void*, void*, uintptr_t*, uint32_t) = (void* (*)(void*, void*, uintptr_t*, uint32_t)) " 1351296417Sdim "rsaTypeGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 6); data[2]", 1352296417Sdim "uint%u_t data[6]; void* (*f)(void*, void*, uintptr_t*, uint32_t) = (void* (*)(void*, void*, uintptr_t*, uint32_t)) " 1353296417Sdim "rsaTypeGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 6); data[5]", 1354296417Sdim 1355296417Sdim // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size) 1356296417Sdim // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into elemData 1357296417Sdim "uint32_t data[5]; void* (*f)(void*, void*, uint32_t*, uint32_t) = (void* (*)(void*, void*, uint32_t*, uint32_t)) " 1358296417Sdim "rsaElementGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 5); data[0]", // Type 1359296417Sdim "uint32_t data[5]; void* (*f)(void*, void*, uint32_t*, uint32_t) = (void* (*)(void*, void*, uint32_t*, uint32_t)) " 1360296417Sdim "rsaElementGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 5); data[1]", // Kind 1361296417Sdim "uint32_t data[5]; void* (*f)(void*, void*, uint32_t*, uint32_t) = (void* (*)(void*, void*, uint32_t*, uint32_t)) " 1362296417Sdim "rsaElementGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 5); data[3]", // Vector size 1363296417Sdim "uint32_t data[5]; void* (*f)(void*, void*, uint32_t*, uint32_t) = (void* (*)(void*, void*, uint32_t*, uint32_t)) " 1364296417Sdim "rsaElementGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 5); data[4]", // Field count 1365296417Sdim 1366296417Sdim // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t *ids, const char **names, 1367296417Sdim // size_t *arraySizes, uint32_t dataSize) 1368296417Sdim // Needed for Allocations of structs to gather details about fields/Subelements 1369296417Sdim "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];" 1370296417Sdim "void* (*f) (void*, void*, uintptr_t*, const char**, size_t*, uint32_t) = " 1371296417Sdim "(void* (*) (void*, void*, uintptr_t*, const char**, size_t*, uint32_t)) rsaElementGetSubElements;" 1372296417Sdim "(void*) f((void*) 0x%lx, (void*) 0x%lx, (uintptr_t*) ids, names, arr_size, (uint32_t) %u);" 1373296417Sdim "ids[%u]", // Element* of field 1374296417Sdim "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];" 1375296417Sdim "void* (*f) (void*, void*, uintptr_t*, const char**, size_t*, uint32_t) = " 1376296417Sdim "(void* (*) (void*, void*, uintptr_t*, const char**, size_t*, uint32_t)) rsaElementGetSubElements;" 1377296417Sdim "(void*) f((void*) 0x%lx, (void*) 0x%lx, (uintptr_t*) ids, names, arr_size, (uint32_t) %u);" 1378296417Sdim "names[%u]", // Name of field 1379296417Sdim "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];" 1380296417Sdim "void* (*f) (void*, void*, uintptr_t*, const char**, size_t*, uint32_t) = " 1381296417Sdim "(void* (*) (void*, void*, uintptr_t*, const char**, size_t*, uint32_t)) rsaElementGetSubElements;" 1382296417Sdim "(void*) f((void*) 0x%lx, (void*) 0x%lx, (uintptr_t*) ids, names, arr_size, (uint32_t) %u);" 1383296417Sdim "arr_size[%u]" // Array size of field 1384296417Sdim }; 1385296417Sdim 1386296417Sdim} // end of the anonymous namespace 1387296417Sdim 1388296417Sdim 1389296417Sdim// Retrieve the string to JIT for the given expression 1390296417Sdimconst char* 1391296417SdimRenderScriptRuntime::JITTemplate(ExpressionStrings e) 1392296417Sdim{ 1393296417Sdim // be nice to your Mips friend when adding new expression strings 1394296417Sdim static_assert(sizeof(runtimeExpressions)/sizeof(runtimeExpressions[0]) == 1395296417Sdim sizeof(runtimeExpressions_mips)/sizeof(runtimeExpressions_mips[0]), 1396296417Sdim "#runtimeExpressions != #runtimeExpressions_mips"); 1397296417Sdim 1398296417Sdim assert((e >= eExprGetOffsetPtr && e <= eExprSubelementsArrSize) && 1399296417Sdim "Expression string out of bounds"); 1400296417Sdim 1401296417Sdim llvm::Triple::ArchType arch = GetTargetRef().GetArchitecture().GetMachine(); 1402296417Sdim 1403296417Sdim // mips JAL workaround 1404296417Sdim if(arch == llvm::Triple::ArchType::mips64el || arch == llvm::Triple::ArchType::mipsel) 1405296417Sdim return runtimeExpressions_mips[e]; 1406296417Sdim else 1407296417Sdim return runtimeExpressions[e]; 1408296417Sdim} 1409296417Sdim 1410296417Sdim 1411296417Sdim// JITs the RS runtime for the internal data pointer of an allocation. 1412296417Sdim// Is passed x,y,z coordinates for the pointer to a specific element. 1413296417Sdim// Then sets the data_ptr member in Allocation with the result. 1414296417Sdim// Returns true on success, false otherwise 1415296417Sdimbool 1416296417SdimRenderScriptRuntime::JITDataPointer(AllocationDetails* allocation, StackFrame* frame_ptr, 1417296417Sdim unsigned int x, unsigned int y, unsigned int z) 1418296417Sdim{ 1419296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1420296417Sdim 1421296417Sdim if (!allocation->address.isValid()) 1422296417Sdim { 1423296417Sdim if (log) 1424296417Sdim log->Printf("RenderScriptRuntime::JITDataPointer - Failed to find allocation details"); 1425296417Sdim return false; 1426296417Sdim } 1427296417Sdim 1428296417Sdim const char* expr_cstr = JITTemplate(eExprGetOffsetPtr); 1429296417Sdim char buffer[jit_max_expr_size]; 1430296417Sdim 1431296417Sdim int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->address.get(), x, y, z); 1432296417Sdim if (chars_written < 0) 1433296417Sdim { 1434296417Sdim if (log) 1435296417Sdim log->Printf("RenderScriptRuntime::JITDataPointer - Encoding error in snprintf()"); 1436296417Sdim return false; 1437296417Sdim } 1438296417Sdim else if (chars_written >= jit_max_expr_size) 1439296417Sdim { 1440296417Sdim if (log) 1441296417Sdim log->Printf("RenderScriptRuntime::JITDataPointer - Expression too long"); 1442296417Sdim return false; 1443296417Sdim } 1444296417Sdim 1445296417Sdim uint64_t result = 0; 1446296417Sdim if (!EvalRSExpression(buffer, frame_ptr, &result)) 1447296417Sdim return false; 1448296417Sdim 1449296417Sdim addr_t mem_ptr = static_cast<lldb::addr_t>(result); 1450296417Sdim allocation->data_ptr = mem_ptr; 1451296417Sdim 1452296417Sdim return true; 1453296417Sdim} 1454296417Sdim 1455296417Sdim// JITs the RS runtime for the internal pointer to the RS Type of an allocation 1456296417Sdim// Then sets the type_ptr member in Allocation with the result. 1457296417Sdim// Returns true on success, false otherwise 1458296417Sdimbool 1459296417SdimRenderScriptRuntime::JITTypePointer(AllocationDetails* allocation, StackFrame* frame_ptr) 1460296417Sdim{ 1461296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1462296417Sdim 1463296417Sdim if (!allocation->address.isValid() || !allocation->context.isValid()) 1464296417Sdim { 1465296417Sdim if (log) 1466296417Sdim log->Printf("RenderScriptRuntime::JITTypePointer - Failed to find allocation details"); 1467296417Sdim return false; 1468296417Sdim } 1469296417Sdim 1470296417Sdim const char* expr_cstr = JITTemplate(eExprAllocGetType); 1471296417Sdim char buffer[jit_max_expr_size]; 1472296417Sdim 1473296417Sdim int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->context.get(), *allocation->address.get()); 1474296417Sdim if (chars_written < 0) 1475296417Sdim { 1476296417Sdim if (log) 1477296417Sdim log->Printf("RenderScriptRuntime::JITDataPointer - Encoding error in snprintf()"); 1478296417Sdim return false; 1479296417Sdim } 1480296417Sdim else if (chars_written >= jit_max_expr_size) 1481296417Sdim { 1482296417Sdim if (log) 1483296417Sdim log->Printf("RenderScriptRuntime::JITTypePointer - Expression too long"); 1484296417Sdim return false; 1485296417Sdim } 1486296417Sdim 1487296417Sdim uint64_t result = 0; 1488296417Sdim if (!EvalRSExpression(buffer, frame_ptr, &result)) 1489296417Sdim return false; 1490296417Sdim 1491296417Sdim addr_t type_ptr = static_cast<lldb::addr_t>(result); 1492296417Sdim allocation->type_ptr = type_ptr; 1493296417Sdim 1494296417Sdim return true; 1495296417Sdim} 1496296417Sdim 1497296417Sdim// JITs the RS runtime for information about the dimensions and type of an allocation 1498296417Sdim// Then sets dimension and element_ptr members in Allocation with the result. 1499296417Sdim// Returns true on success, false otherwise 1500296417Sdimbool 1501296417SdimRenderScriptRuntime::JITTypePacked(AllocationDetails* allocation, StackFrame* frame_ptr) 1502296417Sdim{ 1503296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1504296417Sdim 1505296417Sdim if (!allocation->type_ptr.isValid() || !allocation->context.isValid()) 1506296417Sdim { 1507296417Sdim if (log) 1508296417Sdim log->Printf("RenderScriptRuntime::JITTypePacked - Failed to find allocation details"); 1509296417Sdim return false; 1510296417Sdim } 1511296417Sdim 1512296417Sdim // Expression is different depending on if device is 32 or 64 bit 1513296417Sdim uint32_t archByteSize = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 1514296417Sdim const unsigned int bits = archByteSize == 4 ? 32 : 64; 1515296417Sdim 1516296417Sdim // We want 4 elements from packed data 1517296417Sdim const unsigned int num_exprs = 4; 1518296417Sdim assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1) && "Invalid number of expressions"); 1519296417Sdim 1520296417Sdim char buffer[num_exprs][jit_max_expr_size]; 1521296417Sdim uint64_t results[num_exprs]; 1522296417Sdim 1523296417Sdim for (unsigned int i = 0; i < num_exprs; ++i) 1524296417Sdim { 1525296417Sdim const char* expr_cstr = JITTemplate((ExpressionStrings) (eExprTypeDimX + i)); 1526296417Sdim int chars_written = snprintf(buffer[i], jit_max_expr_size, expr_cstr, bits, 1527296417Sdim *allocation->context.get(), *allocation->type_ptr.get()); 1528296417Sdim if (chars_written < 0) 1529296417Sdim { 1530296417Sdim if (log) 1531296417Sdim log->Printf("RenderScriptRuntime::JITDataPointer - Encoding error in snprintf()"); 1532296417Sdim return false; 1533296417Sdim } 1534296417Sdim else if (chars_written >= jit_max_expr_size) 1535296417Sdim { 1536296417Sdim if (log) 1537296417Sdim log->Printf("RenderScriptRuntime::JITTypePacked - Expression too long"); 1538296417Sdim return false; 1539296417Sdim } 1540296417Sdim 1541296417Sdim // Perform expression evaluation 1542296417Sdim if (!EvalRSExpression(buffer[i], frame_ptr, &results[i])) 1543296417Sdim return false; 1544296417Sdim } 1545296417Sdim 1546296417Sdim // Assign results to allocation members 1547296417Sdim AllocationDetails::Dimension dims; 1548296417Sdim dims.dim_1 = static_cast<uint32_t>(results[0]); 1549296417Sdim dims.dim_2 = static_cast<uint32_t>(results[1]); 1550296417Sdim dims.dim_3 = static_cast<uint32_t>(results[2]); 1551296417Sdim allocation->dimension = dims; 1552296417Sdim 1553296417Sdim addr_t elem_ptr = static_cast<lldb::addr_t>(results[3]); 1554296417Sdim allocation->element.element_ptr = elem_ptr; 1555296417Sdim 1556296417Sdim if (log) 1557296417Sdim log->Printf("RenderScriptRuntime::JITTypePacked - dims (%u, %u, %u) Element*: 0x%" PRIx64, 1558296417Sdim dims.dim_1, dims.dim_2, dims.dim_3, elem_ptr); 1559296417Sdim 1560296417Sdim return true; 1561296417Sdim} 1562296417Sdim 1563296417Sdim// JITs the RS runtime for information about the Element of an allocation 1564296417Sdim// Then sets type, type_vec_size, field_count and type_kind members in Element with the result. 1565296417Sdim// Returns true on success, false otherwise 1566296417Sdimbool 1567296417SdimRenderScriptRuntime::JITElementPacked(Element& elem, const lldb::addr_t context, StackFrame* frame_ptr) 1568296417Sdim{ 1569296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1570296417Sdim 1571296417Sdim if (!elem.element_ptr.isValid()) 1572296417Sdim { 1573296417Sdim if (log) 1574296417Sdim log->Printf("RenderScriptRuntime::JITElementPacked - Failed to find allocation details"); 1575296417Sdim return false; 1576296417Sdim } 1577296417Sdim 1578296417Sdim // We want 4 elements from packed data 1579296417Sdim const unsigned int num_exprs = 4; 1580296417Sdim assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1) && "Invalid number of expressions"); 1581296417Sdim 1582296417Sdim char buffer[num_exprs][jit_max_expr_size]; 1583296417Sdim uint64_t results[num_exprs]; 1584296417Sdim 1585296417Sdim for (unsigned int i = 0; i < num_exprs; i++) 1586296417Sdim { 1587296417Sdim const char* expr_cstr = JITTemplate((ExpressionStrings) (eExprElementType + i)); 1588296417Sdim int chars_written = snprintf(buffer[i], jit_max_expr_size, expr_cstr, context, *elem.element_ptr.get()); 1589296417Sdim if (chars_written < 0) 1590296417Sdim { 1591296417Sdim if (log) 1592296417Sdim log->Printf("RenderScriptRuntime::JITElementPacked - Encoding error in snprintf()"); 1593296417Sdim return false; 1594296417Sdim } 1595296417Sdim else if (chars_written >= jit_max_expr_size) 1596296417Sdim { 1597296417Sdim if (log) 1598296417Sdim log->Printf("RenderScriptRuntime::JITElementPacked - Expression too long"); 1599296417Sdim return false; 1600296417Sdim } 1601296417Sdim 1602296417Sdim // Perform expression evaluation 1603296417Sdim if (!EvalRSExpression(buffer[i], frame_ptr, &results[i])) 1604296417Sdim return false; 1605296417Sdim } 1606296417Sdim 1607296417Sdim // Assign results to allocation members 1608296417Sdim elem.type = static_cast<RenderScriptRuntime::Element::DataType>(results[0]); 1609296417Sdim elem.type_kind = static_cast<RenderScriptRuntime::Element::DataKind>(results[1]); 1610296417Sdim elem.type_vec_size = static_cast<uint32_t>(results[2]); 1611296417Sdim elem.field_count = static_cast<uint32_t>(results[3]); 1612296417Sdim 1613296417Sdim if (log) 1614296417Sdim log->Printf("RenderScriptRuntime::JITElementPacked - data type %u, pixel type %u, vector size %u, field count %u", 1615296417Sdim *elem.type.get(), *elem.type_kind.get(), *elem.type_vec_size.get(), *elem.field_count.get()); 1616296417Sdim 1617296417Sdim // If this Element has subelements then JIT rsaElementGetSubElements() for details about its fields 1618296417Sdim if (*elem.field_count.get() > 0 && !JITSubelements(elem, context, frame_ptr)) 1619296417Sdim return false; 1620296417Sdim 1621296417Sdim return true; 1622296417Sdim} 1623296417Sdim 1624296417Sdim// JITs the RS runtime for information about the subelements/fields of a struct allocation 1625296417Sdim// This is necessary for infering the struct type so we can pretty print the allocation's contents. 1626296417Sdim// Returns true on success, false otherwise 1627296417Sdimbool 1628296417SdimRenderScriptRuntime::JITSubelements(Element& elem, const lldb::addr_t context, StackFrame* frame_ptr) 1629296417Sdim{ 1630296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1631296417Sdim 1632296417Sdim if (!elem.element_ptr.isValid() || !elem.field_count.isValid()) 1633296417Sdim { 1634296417Sdim if (log) 1635296417Sdim log->Printf("RenderScriptRuntime::JITSubelements - Failed to find allocation details"); 1636296417Sdim return false; 1637296417Sdim } 1638296417Sdim 1639296417Sdim const short num_exprs = 3; 1640296417Sdim assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1) && "Invalid number of expressions"); 1641296417Sdim 1642296417Sdim char expr_buffer[jit_max_expr_size]; 1643296417Sdim uint64_t results; 1644296417Sdim 1645296417Sdim // Iterate over struct fields. 1646296417Sdim const uint32_t field_count = *elem.field_count.get(); 1647296417Sdim for (unsigned int field_index = 0; field_index < field_count; ++field_index) 1648296417Sdim { 1649296417Sdim Element child; 1650296417Sdim for (unsigned int expr_index = 0; expr_index < num_exprs; ++expr_index) 1651296417Sdim { 1652296417Sdim const char* expr_cstr = JITTemplate((ExpressionStrings) (eExprSubelementsId + expr_index)); 1653296417Sdim int chars_written = snprintf(expr_buffer, jit_max_expr_size, expr_cstr, 1654296417Sdim field_count, field_count, field_count, 1655296417Sdim context, *elem.element_ptr.get(), field_count, field_index); 1656296417Sdim if (chars_written < 0) 1657296417Sdim { 1658296417Sdim if (log) 1659296417Sdim log->Printf("RenderScriptRuntime::JITSubelements - Encoding error in snprintf()"); 1660296417Sdim return false; 1661296417Sdim } 1662296417Sdim else if (chars_written >= jit_max_expr_size) 1663296417Sdim { 1664296417Sdim if (log) 1665296417Sdim log->Printf("RenderScriptRuntime::JITSubelements - Expression too long"); 1666296417Sdim return false; 1667296417Sdim } 1668296417Sdim 1669296417Sdim // Perform expression evaluation 1670296417Sdim if (!EvalRSExpression(expr_buffer, frame_ptr, &results)) 1671296417Sdim return false; 1672296417Sdim 1673296417Sdim if (log) 1674296417Sdim log->Printf("RenderScriptRuntime::JITSubelements - Expr result 0x%" PRIx64, results); 1675296417Sdim 1676296417Sdim switch(expr_index) 1677296417Sdim { 1678296417Sdim case 0: // Element* of child 1679296417Sdim child.element_ptr = static_cast<addr_t>(results); 1680296417Sdim break; 1681296417Sdim case 1: // Name of child 1682285101Semaste { 1683296417Sdim lldb::addr_t address = static_cast<addr_t>(results); 1684296417Sdim Error err; 1685296417Sdim std::string name; 1686296417Sdim GetProcess()->ReadCStringFromMemory(address, name, err); 1687296417Sdim if (!err.Fail()) 1688296417Sdim child.type_name = ConstString(name); 1689296417Sdim else 1690285101Semaste { 1691296417Sdim if (log) 1692296417Sdim log->Printf("RenderScriptRuntime::JITSubelements - Warning: Couldn't read field name"); 1693285101Semaste } 1694296417Sdim break; 1695285101Semaste } 1696296417Sdim case 2: // Array size of child 1697296417Sdim child.array_size = static_cast<uint32_t>(results); 1698296417Sdim break; 1699285101Semaste } 1700296417Sdim } 1701296417Sdim 1702296417Sdim // We need to recursively JIT each Element field of the struct since 1703296417Sdim // structs can be nested inside structs. 1704296417Sdim if (!JITElementPacked(child, context, frame_ptr)) 1705296417Sdim return false; 1706296417Sdim elem.children.push_back(child); 1707296417Sdim } 1708296417Sdim 1709296417Sdim // Try to infer the name of the struct type so we can pretty print the allocation contents. 1710296417Sdim FindStructTypeName(elem, frame_ptr); 1711296417Sdim 1712296417Sdim return true; 1713296417Sdim} 1714296417Sdim 1715296417Sdim// JITs the RS runtime for the address of the last element in the allocation. 1716296417Sdim// The `elem_size` paramter represents the size of a single element, including padding. 1717296417Sdim// Which is needed as an offset from the last element pointer. 1718296417Sdim// Using this offset minus the starting address we can calculate the size of the allocation. 1719296417Sdim// Returns true on success, false otherwise 1720296417Sdimbool 1721296417SdimRenderScriptRuntime::JITAllocationSize(AllocationDetails* allocation, StackFrame* frame_ptr) 1722296417Sdim{ 1723296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1724296417Sdim 1725296417Sdim if (!allocation->address.isValid() || !allocation->dimension.isValid() 1726296417Sdim || !allocation->data_ptr.isValid() || !allocation->element.datum_size.isValid()) 1727296417Sdim { 1728296417Sdim if (log) 1729296417Sdim log->Printf("RenderScriptRuntime::JITAllocationSize - Failed to find allocation details"); 1730296417Sdim return false; 1731296417Sdim } 1732296417Sdim 1733296417Sdim // Find dimensions 1734296417Sdim unsigned int dim_x = allocation->dimension.get()->dim_1; 1735296417Sdim unsigned int dim_y = allocation->dimension.get()->dim_2; 1736296417Sdim unsigned int dim_z = allocation->dimension.get()->dim_3; 1737296417Sdim 1738296417Sdim // Our plan of jitting the last element address doesn't seem to work for struct Allocations 1739296417Sdim // Instead try to infer the size ourselves without any inter element padding. 1740296417Sdim if (allocation->element.children.size() > 0) 1741296417Sdim { 1742296417Sdim if (dim_x == 0) dim_x = 1; 1743296417Sdim if (dim_y == 0) dim_y = 1; 1744296417Sdim if (dim_z == 0) dim_z = 1; 1745296417Sdim 1746296417Sdim allocation->size = dim_x * dim_y * dim_z * *allocation->element.datum_size.get(); 1747296417Sdim 1748296417Sdim if (log) 1749296417Sdim log->Printf("RenderScriptRuntime::JITAllocationSize - Infered size of struct allocation %u", *allocation->size.get()); 1750296417Sdim 1751296417Sdim return true; 1752296417Sdim } 1753296417Sdim 1754296417Sdim const char* expr_cstr = JITTemplate(eExprGetOffsetPtr); 1755296417Sdim char buffer[jit_max_expr_size]; 1756296417Sdim 1757296417Sdim // Calculate last element 1758296417Sdim dim_x = dim_x == 0 ? 0 : dim_x - 1; 1759296417Sdim dim_y = dim_y == 0 ? 0 : dim_y - 1; 1760296417Sdim dim_z = dim_z == 0 ? 0 : dim_z - 1; 1761296417Sdim 1762296417Sdim int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->address.get(), 1763296417Sdim dim_x, dim_y, dim_z); 1764296417Sdim if (chars_written < 0) 1765296417Sdim { 1766296417Sdim if (log) 1767296417Sdim log->Printf("RenderScriptRuntime::JITAllocationSize - Encoding error in snprintf()"); 1768296417Sdim return false; 1769296417Sdim } 1770296417Sdim else if (chars_written >= jit_max_expr_size) 1771296417Sdim { 1772296417Sdim if (log) 1773296417Sdim log->Printf("RenderScriptRuntime::JITAllocationSize - Expression too long"); 1774296417Sdim return false; 1775296417Sdim } 1776296417Sdim 1777296417Sdim uint64_t result = 0; 1778296417Sdim if (!EvalRSExpression(buffer, frame_ptr, &result)) 1779296417Sdim return false; 1780296417Sdim 1781296417Sdim addr_t mem_ptr = static_cast<lldb::addr_t>(result); 1782296417Sdim // Find pointer to last element and add on size of an element 1783296417Sdim allocation->size = static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()) + *allocation->element.datum_size.get(); 1784296417Sdim 1785296417Sdim return true; 1786296417Sdim} 1787296417Sdim 1788296417Sdim// JITs the RS runtime for information about the stride between rows in the allocation. 1789296417Sdim// This is done to detect padding, since allocated memory is 16-byte aligned. 1790296417Sdim// Returns true on success, false otherwise 1791296417Sdimbool 1792296417SdimRenderScriptRuntime::JITAllocationStride(AllocationDetails* allocation, StackFrame* frame_ptr) 1793296417Sdim{ 1794296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1795296417Sdim 1796296417Sdim if (!allocation->address.isValid() || !allocation->data_ptr.isValid()) 1797296417Sdim { 1798296417Sdim if (log) 1799296417Sdim log->Printf("RenderScriptRuntime::JITAllocationStride - Failed to find allocation details"); 1800296417Sdim return false; 1801296417Sdim } 1802296417Sdim 1803296417Sdim const char* expr_cstr = JITTemplate(eExprGetOffsetPtr); 1804296417Sdim char buffer[jit_max_expr_size]; 1805296417Sdim 1806296417Sdim int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->address.get(), 1807296417Sdim 0, 1, 0); 1808296417Sdim if (chars_written < 0) 1809296417Sdim { 1810296417Sdim if (log) 1811296417Sdim log->Printf("RenderScriptRuntime::JITAllocationStride - Encoding error in snprintf()"); 1812296417Sdim return false; 1813296417Sdim } 1814296417Sdim else if (chars_written >= jit_max_expr_size) 1815296417Sdim { 1816296417Sdim if (log) 1817296417Sdim log->Printf("RenderScriptRuntime::JITAllocationStride - Expression too long"); 1818296417Sdim return false; 1819296417Sdim } 1820296417Sdim 1821296417Sdim uint64_t result = 0; 1822296417Sdim if (!EvalRSExpression(buffer, frame_ptr, &result)) 1823296417Sdim return false; 1824296417Sdim 1825296417Sdim addr_t mem_ptr = static_cast<lldb::addr_t>(result); 1826296417Sdim allocation->stride = static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()); 1827296417Sdim 1828296417Sdim return true; 1829296417Sdim} 1830296417Sdim 1831296417Sdim// JIT all the current runtime info regarding an allocation 1832296417Sdimbool 1833296417SdimRenderScriptRuntime::RefreshAllocation(AllocationDetails* allocation, StackFrame* frame_ptr) 1834296417Sdim{ 1835296417Sdim // GetOffsetPointer() 1836296417Sdim if (!JITDataPointer(allocation, frame_ptr)) 1837296417Sdim return false; 1838296417Sdim 1839296417Sdim // rsaAllocationGetType() 1840296417Sdim if (!JITTypePointer(allocation, frame_ptr)) 1841296417Sdim return false; 1842296417Sdim 1843296417Sdim // rsaTypeGetNativeData() 1844296417Sdim if (!JITTypePacked(allocation, frame_ptr)) 1845296417Sdim return false; 1846296417Sdim 1847296417Sdim // rsaElementGetNativeData() 1848296417Sdim if (!JITElementPacked(allocation->element, *allocation->context.get(), frame_ptr)) 1849296417Sdim return false; 1850296417Sdim 1851296417Sdim // Sets the datum_size member in Element 1852296417Sdim SetElementSize(allocation->element); 1853296417Sdim 1854296417Sdim // Use GetOffsetPointer() to infer size of the allocation 1855296417Sdim if (!JITAllocationSize(allocation, frame_ptr)) 1856296417Sdim return false; 1857296417Sdim 1858296417Sdim return true; 1859296417Sdim} 1860296417Sdim 1861296417Sdim// Function attempts to set the type_name member of the paramaterised Element object. 1862296417Sdim// This string should be the name of the struct type the Element represents. 1863296417Sdim// We need this string for pretty printing the Element to users. 1864296417Sdimvoid 1865296417SdimRenderScriptRuntime::FindStructTypeName(Element& elem, StackFrame* frame_ptr) 1866296417Sdim{ 1867296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1868296417Sdim 1869296417Sdim if (!elem.type_name.IsEmpty()) // Name already set 1870296417Sdim return; 1871296417Sdim else 1872296417Sdim elem.type_name = Element::GetFallbackStructName(); // Default type name if we don't succeed 1873296417Sdim 1874296417Sdim // Find all the global variables from the script rs modules 1875296417Sdim VariableList variable_list; 1876296417Sdim for (auto module_sp : m_rsmodules) 1877296417Sdim module_sp->m_module->FindGlobalVariables(RegularExpression("."), true, UINT32_MAX, variable_list); 1878296417Sdim 1879296417Sdim // Iterate over all the global variables looking for one with a matching type to the Element. 1880296417Sdim // We make the assumption a match exists since there needs to be a global variable to reflect the 1881296417Sdim // struct type back into java host code. 1882296417Sdim for (uint32_t var_index = 0; var_index < variable_list.GetSize(); ++var_index) 1883296417Sdim { 1884296417Sdim const VariableSP var_sp(variable_list.GetVariableAtIndex(var_index)); 1885296417Sdim if (!var_sp) 1886296417Sdim continue; 1887296417Sdim 1888296417Sdim ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp); 1889296417Sdim if (!valobj_sp) 1890296417Sdim continue; 1891296417Sdim 1892296417Sdim // Find the number of variable fields. 1893296417Sdim // If it has no fields, or more fields than our Element, then it can't be the struct we're looking for. 1894296417Sdim // Don't check for equality since RS can add extra struct members for padding. 1895296417Sdim size_t num_children = valobj_sp->GetNumChildren(); 1896296417Sdim if (num_children > elem.children.size() || num_children == 0) 1897296417Sdim continue; 1898296417Sdim 1899296417Sdim // Iterate over children looking for members with matching field names. 1900296417Sdim // If all the field names match, this is likely the struct we want. 1901296417Sdim // 1902296417Sdim // TODO: This could be made more robust by also checking children data sizes, or array size 1903296417Sdim bool found = true; 1904296417Sdim for (size_t child_index = 0; child_index < num_children; ++child_index) 1905296417Sdim { 1906296417Sdim ValueObjectSP child = valobj_sp->GetChildAtIndex(child_index, true); 1907296417Sdim if (!child || (child->GetName() != elem.children[child_index].type_name)) 1908285101Semaste { 1909296417Sdim found = false; 1910296417Sdim break; 1911285101Semaste } 1912285101Semaste } 1913296417Sdim 1914296417Sdim // RS can add extra struct members for padding in the format '#rs_padding_[0-9]+' 1915296417Sdim if (found && num_children < elem.children.size()) 1916296417Sdim { 1917296417Sdim const unsigned int size_diff = elem.children.size() - num_children; 1918296417Sdim if (log) 1919296417Sdim log->Printf("RenderScriptRuntime::FindStructTypeName - %u padding struct entries", size_diff); 1920296417Sdim 1921296417Sdim for (unsigned int padding_index = 0; padding_index < size_diff; ++padding_index) 1922296417Sdim { 1923296417Sdim const ConstString& name = elem.children[num_children + padding_index].type_name; 1924296417Sdim if (strcmp(name.AsCString(), "#rs_padding") < 0) 1925296417Sdim found = false; 1926296417Sdim } 1927296417Sdim } 1928296417Sdim 1929296417Sdim // We've found a global var with matching type 1930296417Sdim if (found) 1931296417Sdim { 1932296417Sdim // Dereference since our Element type isn't a pointer. 1933296417Sdim if (valobj_sp->IsPointerType()) 1934296417Sdim { 1935296417Sdim Error err; 1936296417Sdim ValueObjectSP deref_valobj = valobj_sp->Dereference(err); 1937296417Sdim if (!err.Fail()) 1938296417Sdim valobj_sp = deref_valobj; 1939296417Sdim } 1940296417Sdim 1941296417Sdim // Save name of variable in Element. 1942296417Sdim elem.type_name = valobj_sp->GetTypeName(); 1943296417Sdim if (log) 1944296417Sdim log->Printf("RenderScriptRuntime::FindStructTypeName - Element name set to %s", elem.type_name.AsCString()); 1945296417Sdim 1946296417Sdim return; 1947296417Sdim } 1948285101Semaste } 1949285101Semaste} 1950285101Semaste 1951296417Sdim// Function sets the datum_size member of Element. Representing the size of a single instance including padding. 1952296417Sdim// Assumes the relevant allocation information has already been jitted. 1953296417Sdimvoid 1954296417SdimRenderScriptRuntime::SetElementSize(Element& elem) 1955296417Sdim{ 1956296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 1957296417Sdim const Element::DataType type = *elem.type.get(); 1958296417Sdim assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT 1959296417Sdim && "Invalid allocation type"); 1960296417Sdim 1961296417Sdim const unsigned int vec_size = *elem.type_vec_size.get(); 1962296417Sdim unsigned int data_size = 0; 1963296417Sdim unsigned int padding = 0; 1964296417Sdim 1965296417Sdim // Element is of a struct type, calculate size recursively. 1966296417Sdim if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) 1967296417Sdim { 1968296417Sdim for (Element& child : elem.children) 1969296417Sdim { 1970296417Sdim SetElementSize(child); 1971296417Sdim const unsigned int array_size = child.array_size.isValid() ? *child.array_size.get() : 1; 1972296417Sdim data_size += *child.datum_size.get() * array_size; 1973296417Sdim } 1974296417Sdim } 1975296417Sdim else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 || type == Element::RS_TYPE_UNSIGNED_5_5_5_1 || 1976296417Sdim type == Element::RS_TYPE_UNSIGNED_4_4_4_4) // These have been packed already 1977296417Sdim { 1978296417Sdim data_size = AllocationDetails::RSTypeToFormat[type][eElementSize]; 1979296417Sdim } 1980296417Sdim else if (type < Element::RS_TYPE_ELEMENT) 1981296417Sdim { 1982296417Sdim data_size = vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize]; 1983296417Sdim if (vec_size == 3) 1984296417Sdim padding = AllocationDetails::RSTypeToFormat[type][eElementSize]; 1985296417Sdim } 1986296417Sdim else 1987296417Sdim data_size = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 1988296417Sdim 1989296417Sdim elem.padding = padding; 1990296417Sdim elem.datum_size = data_size + padding; 1991296417Sdim if (log) 1992296417Sdim log->Printf("RenderScriptRuntime::SetElementSize - element size set to %u", data_size + padding); 1993296417Sdim} 1994296417Sdim 1995296417Sdim// Given an allocation, this function copies the allocation contents from device into a buffer on the heap. 1996296417Sdim// Returning a shared pointer to the buffer containing the data. 1997296417Sdimstd::shared_ptr<uint8_t> 1998296417SdimRenderScriptRuntime::GetAllocationData(AllocationDetails* allocation, StackFrame* frame_ptr) 1999296417Sdim{ 2000296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2001296417Sdim 2002296417Sdim // JIT all the allocation details 2003296417Sdim if (allocation->shouldRefresh()) 2004296417Sdim { 2005296417Sdim if (log) 2006296417Sdim log->Printf("RenderScriptRuntime::GetAllocationData - Allocation details not calculated yet, jitting info"); 2007296417Sdim 2008296417Sdim if (!RefreshAllocation(allocation, frame_ptr)) 2009296417Sdim { 2010296417Sdim if (log) 2011296417Sdim log->Printf("RenderScriptRuntime::GetAllocationData - Couldn't JIT allocation details"); 2012296417Sdim return nullptr; 2013296417Sdim } 2014296417Sdim } 2015296417Sdim 2016296417Sdim assert(allocation->data_ptr.isValid() && allocation->element.type.isValid() && allocation->element.type_vec_size.isValid() 2017296417Sdim && allocation->size.isValid() && "Allocation information not available"); 2018296417Sdim 2019296417Sdim // Allocate a buffer to copy data into 2020296417Sdim const unsigned int size = *allocation->size.get(); 2021296417Sdim std::shared_ptr<uint8_t> buffer(new uint8_t[size]); 2022296417Sdim if (!buffer) 2023296417Sdim { 2024296417Sdim if (log) 2025296417Sdim log->Printf("RenderScriptRuntime::GetAllocationData - Couldn't allocate a %u byte buffer", size); 2026296417Sdim return nullptr; 2027296417Sdim } 2028296417Sdim 2029296417Sdim // Read the inferior memory 2030296417Sdim Error error; 2031296417Sdim lldb::addr_t data_ptr = *allocation->data_ptr.get(); 2032296417Sdim GetProcess()->ReadMemory(data_ptr, buffer.get(), size, error); 2033296417Sdim if (error.Fail()) 2034296417Sdim { 2035296417Sdim if (log) 2036296417Sdim log->Printf("RenderScriptRuntime::GetAllocationData - '%s' Couldn't read %u bytes of allocation data from 0x%" PRIx64, 2037296417Sdim error.AsCString(), size, data_ptr); 2038296417Sdim return nullptr; 2039296417Sdim } 2040296417Sdim 2041296417Sdim return buffer; 2042296417Sdim} 2043296417Sdim 2044296417Sdim// Function copies data from a binary file into an allocation. 2045296417Sdim// There is a header at the start of the file, FileHeader, before the data content itself. 2046296417Sdim// Information from this header is used to display warnings to the user about incompatabilities 2047285101Semastebool 2048296417SdimRenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, const char* filename, StackFrame* frame_ptr) 2049296417Sdim{ 2050296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2051296417Sdim 2052296417Sdim // Find allocation with the given id 2053296417Sdim AllocationDetails* alloc = FindAllocByID(strm, alloc_id); 2054296417Sdim if (!alloc) 2055296417Sdim return false; 2056296417Sdim 2057296417Sdim if (log) 2058296417Sdim log->Printf("RenderScriptRuntime::LoadAllocation - Found allocation 0x%" PRIx64, *alloc->address.get()); 2059296417Sdim 2060296417Sdim // JIT all the allocation details 2061296417Sdim if (alloc->shouldRefresh()) 2062296417Sdim { 2063296417Sdim if (log) 2064296417Sdim log->Printf("RenderScriptRuntime::LoadAllocation - Allocation details not calculated yet, jitting info"); 2065296417Sdim 2066296417Sdim if (!RefreshAllocation(alloc, frame_ptr)) 2067296417Sdim { 2068296417Sdim if (log) 2069296417Sdim log->Printf("RenderScriptRuntime::LoadAllocation - Couldn't JIT allocation details"); 2070296417Sdim return false; 2071296417Sdim } 2072296417Sdim } 2073296417Sdim 2074296417Sdim assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && alloc->element.type_vec_size.isValid() 2075296417Sdim && alloc->size.isValid() && alloc->element.datum_size.isValid() && "Allocation information not available"); 2076296417Sdim 2077296417Sdim // Check we can read from file 2078296417Sdim FileSpec file(filename, true); 2079296417Sdim if (!file.Exists()) 2080296417Sdim { 2081296417Sdim strm.Printf("Error: File %s does not exist", filename); 2082296417Sdim strm.EOL(); 2083296417Sdim return false; 2084296417Sdim } 2085296417Sdim 2086296417Sdim if (!file.Readable()) 2087296417Sdim { 2088296417Sdim strm.Printf("Error: File %s does not have readable permissions", filename); 2089296417Sdim strm.EOL(); 2090296417Sdim return false; 2091296417Sdim } 2092296417Sdim 2093296417Sdim // Read file into data buffer 2094296417Sdim DataBufferSP data_sp(file.ReadFileContents()); 2095296417Sdim 2096296417Sdim // Cast start of buffer to FileHeader and use pointer to read metadata 2097296417Sdim void* file_buffer = data_sp->GetBytes(); 2098296417Sdim if (file_buffer == NULL || data_sp->GetByteSize() < 2099296417Sdim (sizeof(AllocationDetails::FileHeader) + sizeof(AllocationDetails::ElementHeader))) 2100296417Sdim { 2101296417Sdim strm.Printf("Error: File %s does not contain enough data for header", filename); 2102296417Sdim strm.EOL(); 2103296417Sdim return false; 2104296417Sdim } 2105296417Sdim const AllocationDetails::FileHeader* file_header = static_cast<AllocationDetails::FileHeader*>(file_buffer); 2106296417Sdim 2107296417Sdim // Check file starts with ascii characters "RSAD" 2108296417Sdim if (file_header->ident[0] != 'R' || file_header->ident[1] != 'S' || file_header->ident[2] != 'A' 2109296417Sdim || file_header->ident[3] != 'D') 2110296417Sdim { 2111296417Sdim strm.Printf("Error: File doesn't contain identifier for an RS allocation dump. Are you sure this is the correct file?"); 2112296417Sdim strm.EOL(); 2113296417Sdim return false; 2114296417Sdim } 2115296417Sdim 2116296417Sdim // Look at the type of the root element in the header 2117296417Sdim AllocationDetails::ElementHeader root_element_header; 2118296417Sdim memcpy(&root_element_header, static_cast<uint8_t*>(file_buffer) + sizeof(AllocationDetails::FileHeader), 2119296417Sdim sizeof(AllocationDetails::ElementHeader)); 2120296417Sdim 2121296417Sdim if (log) 2122296417Sdim log->Printf("RenderScriptRuntime::LoadAllocation - header type %u, element size %u", 2123296417Sdim root_element_header.type, root_element_header.element_size); 2124296417Sdim 2125296417Sdim // Check if the target allocation and file both have the same number of bytes for an Element 2126296417Sdim if (*alloc->element.datum_size.get() != root_element_header.element_size) 2127296417Sdim { 2128296417Sdim strm.Printf("Warning: Mismatched Element sizes - file %u bytes, allocation %u bytes", 2129296417Sdim root_element_header.element_size, *alloc->element.datum_size.get()); 2130296417Sdim strm.EOL(); 2131296417Sdim } 2132296417Sdim 2133296417Sdim // Check if the target allocation and file both have the same type 2134296417Sdim const unsigned int alloc_type = static_cast<unsigned int>(*alloc->element.type.get()); 2135296417Sdim const unsigned int file_type = root_element_header.type; 2136296417Sdim 2137296417Sdim if (file_type > Element::RS_TYPE_FONT) 2138296417Sdim { 2139296417Sdim strm.Printf("Warning: File has unknown allocation type"); 2140296417Sdim strm.EOL(); 2141296417Sdim } 2142296417Sdim else if (alloc_type != file_type) 2143296417Sdim { 2144296417Sdim // Enum value isn't monotonous, so doesn't always index RsDataTypeToString array 2145296417Sdim unsigned int printable_target_type_index = alloc_type; 2146296417Sdim unsigned int printable_head_type_index = file_type; 2147296417Sdim if (alloc_type >= Element::RS_TYPE_ELEMENT && alloc_type <= Element::RS_TYPE_FONT) 2148296417Sdim printable_target_type_index = static_cast<Element::DataType>( 2149296417Sdim (alloc_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1); 2150296417Sdim 2151296417Sdim if (file_type >= Element::RS_TYPE_ELEMENT && file_type <= Element::RS_TYPE_FONT) 2152296417Sdim printable_head_type_index = static_cast<Element::DataType>( 2153296417Sdim (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1); 2154296417Sdim 2155296417Sdim const char* file_type_cstr = AllocationDetails::RsDataTypeToString[printable_head_type_index][0]; 2156296417Sdim const char* target_type_cstr = AllocationDetails::RsDataTypeToString[printable_target_type_index][0]; 2157296417Sdim 2158296417Sdim strm.Printf("Warning: Mismatched Types - file '%s' type, allocation '%s' type", 2159296417Sdim file_type_cstr, target_type_cstr); 2160296417Sdim strm.EOL(); 2161296417Sdim } 2162296417Sdim 2163296417Sdim // Advance buffer past header 2164296417Sdim file_buffer = static_cast<uint8_t*>(file_buffer) + file_header->hdr_size; 2165296417Sdim 2166296417Sdim // Calculate size of allocation data in file 2167296417Sdim size_t length = data_sp->GetByteSize() - file_header->hdr_size; 2168296417Sdim 2169296417Sdim // Check if the target allocation and file both have the same total data size. 2170296417Sdim const unsigned int alloc_size = *alloc->size.get(); 2171296417Sdim if (alloc_size != length) 2172296417Sdim { 2173296417Sdim strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64 " bytes, allocation 0x%x bytes", 2174296417Sdim (uint64_t) length, alloc_size); 2175296417Sdim strm.EOL(); 2176296417Sdim length = alloc_size < length ? alloc_size : length; // Set length to copy to minimum 2177296417Sdim } 2178296417Sdim 2179296417Sdim // Copy file data from our buffer into the target allocation. 2180296417Sdim lldb::addr_t alloc_data = *alloc->data_ptr.get(); 2181296417Sdim Error error; 2182296417Sdim size_t bytes_written = GetProcess()->WriteMemory(alloc_data, file_buffer, length, error); 2183296417Sdim if (!error.Success() || bytes_written != length) 2184296417Sdim { 2185296417Sdim strm.Printf("Error: Couldn't write data to allocation %s", error.AsCString()); 2186296417Sdim strm.EOL(); 2187296417Sdim return false; 2188296417Sdim } 2189296417Sdim 2190296417Sdim strm.Printf("Contents of file '%s' read into allocation %u", filename, alloc->id); 2191296417Sdim strm.EOL(); 2192296417Sdim 2193296417Sdim return true; 2194296417Sdim} 2195296417Sdim 2196296417Sdim// Function takes as parameters a byte buffer, which will eventually be written to file as the element header, 2197296417Sdim// an offset into that buffer, and an Element that will be saved into the buffer at the parametrised offset. 2198296417Sdim// Return value is the new offset after writing the element into the buffer. 2199296417Sdim// Elements are saved to the file as the ElementHeader struct followed by offsets to the structs of all the element's children. 2200296417Sdimsize_t 2201296417SdimRenderScriptRuntime::PopulateElementHeaders(const std::shared_ptr<uint8_t> header_buffer, size_t offset, const Element& elem) 2202296417Sdim{ 2203296417Sdim // File struct for an element header with all the relevant details copied from elem. 2204296417Sdim // We assume members are valid already. 2205296417Sdim AllocationDetails::ElementHeader elem_header; 2206296417Sdim elem_header.type = *elem.type.get(); 2207296417Sdim elem_header.kind = *elem.type_kind.get(); 2208296417Sdim elem_header.element_size = *elem.datum_size.get(); 2209296417Sdim elem_header.vector_size = *elem.type_vec_size.get(); 2210296417Sdim elem_header.array_size = elem.array_size.isValid() ? *elem.array_size.get() : 0; 2211296417Sdim const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader); 2212296417Sdim 2213296417Sdim // Copy struct into buffer and advance offset 2214296417Sdim // We assume that header_buffer has been checked for NULL before this method is called 2215296417Sdim memcpy(header_buffer.get() + offset, &elem_header, elem_header_size); 2216296417Sdim offset += elem_header_size; 2217296417Sdim 2218296417Sdim // Starting offset of child ElementHeader struct 2219296417Sdim size_t child_offset = offset + ((elem.children.size() + 1) * sizeof(uint32_t)); 2220296417Sdim for (const RenderScriptRuntime::Element& child : elem.children) 2221296417Sdim { 2222296417Sdim // Recursively populate the buffer with the element header structs of children. 2223296417Sdim // Then save the offsets where they were set after the parent element header. 2224296417Sdim memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t)); 2225296417Sdim offset += sizeof(uint32_t); 2226296417Sdim 2227296417Sdim child_offset = PopulateElementHeaders(header_buffer, child_offset, child); 2228296417Sdim } 2229296417Sdim 2230296417Sdim // Zero indicates no more children 2231296417Sdim memset(header_buffer.get() + offset, 0, sizeof(uint32_t)); 2232296417Sdim 2233296417Sdim return child_offset; 2234296417Sdim} 2235296417Sdim 2236296417Sdim// Given an Element object this function returns the total size needed in the file header to store the element's details. 2237296417Sdim// Taking into account the size of the element header struct, plus the offsets to all the element's children. 2238296417Sdim// Function is recursive so that the size of all ancestors is taken into account. 2239296417Sdimsize_t 2240296417SdimRenderScriptRuntime::CalculateElementHeaderSize(const Element& elem) 2241296417Sdim{ 2242296417Sdim size_t size = (elem.children.size() + 1) * sizeof(uint32_t); // Offsets to children plus zero terminator 2243296417Sdim size += sizeof(AllocationDetails::ElementHeader); // Size of header struct with type details 2244296417Sdim 2245296417Sdim // Calculate recursively for all descendants 2246296417Sdim for (const Element& child : elem.children) 2247296417Sdim size += CalculateElementHeaderSize(child); 2248296417Sdim 2249296417Sdim return size; 2250296417Sdim} 2251296417Sdim 2252296417Sdim// Function copies allocation contents into a binary file. 2253296417Sdim// This file can then be loaded later into a different allocation. 2254296417Sdim// There is a header, FileHeader, before the allocation data containing meta-data. 2255296417Sdimbool 2256296417SdimRenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, const char* filename, StackFrame* frame_ptr) 2257296417Sdim{ 2258296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2259296417Sdim 2260296417Sdim // Find allocation with the given id 2261296417Sdim AllocationDetails* alloc = FindAllocByID(strm, alloc_id); 2262296417Sdim if (!alloc) 2263296417Sdim return false; 2264296417Sdim 2265296417Sdim if (log) 2266296417Sdim log->Printf("RenderScriptRuntime::SaveAllocation - Found allocation 0x%" PRIx64, *alloc->address.get()); 2267296417Sdim 2268296417Sdim // JIT all the allocation details 2269296417Sdim if (alloc->shouldRefresh()) 2270296417Sdim { 2271296417Sdim if (log) 2272296417Sdim log->Printf("RenderScriptRuntime::SaveAllocation - Allocation details not calculated yet, jitting info"); 2273296417Sdim 2274296417Sdim if (!RefreshAllocation(alloc, frame_ptr)) 2275296417Sdim { 2276296417Sdim if (log) 2277296417Sdim log->Printf("RenderScriptRuntime::SaveAllocation - Couldn't JIT allocation details"); 2278296417Sdim return false; 2279296417Sdim } 2280296417Sdim } 2281296417Sdim 2282296417Sdim assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && alloc->element.type_vec_size.isValid() && alloc->element.datum_size.get() 2283296417Sdim && alloc->element.type_kind.isValid() && alloc->dimension.isValid() && "Allocation information not available"); 2284296417Sdim 2285296417Sdim // Check we can create writable file 2286296417Sdim FileSpec file_spec(filename, true); 2287296417Sdim File file(file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate | File::eOpenOptionTruncate); 2288296417Sdim if (!file) 2289296417Sdim { 2290296417Sdim strm.Printf("Error: Failed to open '%s' for writing", filename); 2291296417Sdim strm.EOL(); 2292296417Sdim return false; 2293296417Sdim } 2294296417Sdim 2295296417Sdim // Read allocation into buffer of heap memory 2296296417Sdim const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); 2297296417Sdim if (!buffer) 2298296417Sdim { 2299296417Sdim strm.Printf("Error: Couldn't read allocation data into buffer"); 2300296417Sdim strm.EOL(); 2301296417Sdim return false; 2302296417Sdim } 2303296417Sdim 2304296417Sdim // Create the file header 2305296417Sdim AllocationDetails::FileHeader head; 2306296417Sdim head.ident[0] = 'R'; head.ident[1] = 'S'; head.ident[2] = 'A'; head.ident[3] = 'D'; 2307296417Sdim head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1); 2308296417Sdim head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2); 2309296417Sdim head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3); 2310296417Sdim 2311296417Sdim const size_t element_header_size = CalculateElementHeaderSize(alloc->element); 2312296417Sdim assert((sizeof(AllocationDetails::FileHeader) + element_header_size) < UINT16_MAX && "Element header too large"); 2313296417Sdim head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) + element_header_size); 2314296417Sdim 2315296417Sdim // Write the file header 2316296417Sdim size_t num_bytes = sizeof(AllocationDetails::FileHeader); 2317296417Sdim if (log) 2318296417Sdim log->Printf("RenderScriptRuntime::SaveAllocation - Writing File Header, 0x%zX bytes", num_bytes); 2319296417Sdim 2320296417Sdim Error err = file.Write(&head, num_bytes); 2321296417Sdim if (!err.Success()) 2322296417Sdim { 2323296417Sdim strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename); 2324296417Sdim strm.EOL(); 2325296417Sdim return false; 2326296417Sdim } 2327296417Sdim 2328296417Sdim // Create the headers describing the element type of the allocation. 2329296417Sdim std::shared_ptr<uint8_t> element_header_buffer(new uint8_t[element_header_size]); 2330296417Sdim if (element_header_buffer == nullptr) 2331296417Sdim { 2332296417Sdim strm.Printf("Internal Error: Couldn't allocate %zu bytes on the heap", element_header_size); 2333296417Sdim strm.EOL(); 2334296417Sdim return false; 2335296417Sdim } 2336296417Sdim 2337296417Sdim PopulateElementHeaders(element_header_buffer, 0, alloc->element); 2338296417Sdim 2339296417Sdim // Write headers for allocation element type to file 2340296417Sdim num_bytes = element_header_size; 2341296417Sdim if (log) 2342296417Sdim log->Printf("RenderScriptRuntime::SaveAllocation - Writing Element Headers, 0x%zX bytes", num_bytes); 2343296417Sdim 2344296417Sdim err = file.Write(element_header_buffer.get(), num_bytes); 2345296417Sdim if (!err.Success()) 2346296417Sdim { 2347296417Sdim strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename); 2348296417Sdim strm.EOL(); 2349296417Sdim return false; 2350296417Sdim } 2351296417Sdim 2352296417Sdim // Write allocation data to file 2353296417Sdim num_bytes = static_cast<size_t>(*alloc->size.get()); 2354296417Sdim if (log) 2355296417Sdim log->Printf("RenderScriptRuntime::SaveAllocation - Writing 0x%zX bytes", num_bytes); 2356296417Sdim 2357296417Sdim err = file.Write(buffer.get(), num_bytes); 2358296417Sdim if (!err.Success()) 2359296417Sdim { 2360296417Sdim strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename); 2361296417Sdim strm.EOL(); 2362296417Sdim return false; 2363296417Sdim } 2364296417Sdim 2365296417Sdim strm.Printf("Allocation written to file '%s'", filename); 2366296417Sdim strm.EOL(); 2367296417Sdim return true; 2368296417Sdim} 2369296417Sdim 2370296417Sdimbool 2371285101SemasteRenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) 2372285101Semaste{ 2373285101Semaste Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2374285101Semaste 2375285101Semaste if (module_sp) 2376285101Semaste { 2377285101Semaste for (const auto &rs_module : m_rsmodules) 2378285101Semaste { 2379285101Semaste if (rs_module->m_module == module_sp) 2380296417Sdim { 2381296417Sdim // Check if the user has enabled automatically breaking on 2382296417Sdim // all RS kernels. 2383296417Sdim if (m_breakAllKernels) 2384296417Sdim BreakOnModuleKernels(rs_module); 2385296417Sdim 2386285101Semaste return false; 2387296417Sdim } 2388285101Semaste } 2389285101Semaste bool module_loaded = false; 2390285101Semaste switch (GetModuleKind(module_sp)) 2391285101Semaste { 2392285101Semaste case eModuleKindKernelObj: 2393285101Semaste { 2394285101Semaste RSModuleDescriptorSP module_desc; 2395285101Semaste module_desc.reset(new RSModuleDescriptor(module_sp)); 2396285101Semaste if (module_desc->ParseRSInfo()) 2397285101Semaste { 2398285101Semaste m_rsmodules.push_back(module_desc); 2399285101Semaste module_loaded = true; 2400285101Semaste } 2401285101Semaste if (module_loaded) 2402285101Semaste { 2403285101Semaste FixupScriptDetails(module_desc); 2404285101Semaste } 2405285101Semaste break; 2406285101Semaste } 2407285101Semaste case eModuleKindDriver: 2408285101Semaste { 2409285101Semaste if (!m_libRSDriver) 2410285101Semaste { 2411285101Semaste m_libRSDriver = module_sp; 2412285101Semaste LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver); 2413285101Semaste } 2414285101Semaste break; 2415285101Semaste } 2416285101Semaste case eModuleKindImpl: 2417285101Semaste { 2418285101Semaste m_libRSCpuRef = module_sp; 2419285101Semaste break; 2420285101Semaste } 2421285101Semaste case eModuleKindLibRS: 2422285101Semaste { 2423296417Sdim if (!m_libRS) 2424285101Semaste { 2425285101Semaste m_libRS = module_sp; 2426285101Semaste static ConstString gDbgPresentStr("gDebuggerPresent"); 2427285101Semaste const Symbol* debug_present = m_libRS->FindFirstSymbolWithNameAndType(gDbgPresentStr, eSymbolTypeData); 2428285101Semaste if (debug_present) 2429285101Semaste { 2430285101Semaste Error error; 2431285101Semaste uint32_t flag = 0x00000001U; 2432285101Semaste Target &target = GetProcess()->GetTarget(); 2433285101Semaste addr_t addr = debug_present->GetLoadAddress(&target); 2434285101Semaste GetProcess()->WriteMemory(addr, &flag, sizeof(flag), error); 2435285101Semaste if(error.Success()) 2436285101Semaste { 2437285101Semaste if (log) 2438285101Semaste log->Printf ("RenderScriptRuntime::LoadModule - Debugger present flag set on debugee"); 2439285101Semaste 2440285101Semaste m_debuggerPresentFlagged = true; 2441285101Semaste } 2442285101Semaste else if (log) 2443285101Semaste { 2444285101Semaste log->Printf ("RenderScriptRuntime::LoadModule - Error writing debugger present flags '%s' ", error.AsCString()); 2445285101Semaste } 2446285101Semaste } 2447285101Semaste else if (log) 2448285101Semaste { 2449285101Semaste log->Printf ("RenderScriptRuntime::LoadModule - Error writing debugger present flags - symbol not found"); 2450285101Semaste } 2451285101Semaste } 2452285101Semaste break; 2453285101Semaste } 2454285101Semaste default: 2455285101Semaste break; 2456285101Semaste } 2457285101Semaste if (module_loaded) 2458296417Sdim Update(); 2459285101Semaste return module_loaded; 2460285101Semaste } 2461285101Semaste return false; 2462285101Semaste} 2463285101Semaste 2464285101Semastevoid 2465285101SemasteRenderScriptRuntime::Update() 2466285101Semaste{ 2467285101Semaste if (m_rsmodules.size() > 0) 2468285101Semaste { 2469285101Semaste if (!m_initiated) 2470285101Semaste { 2471285101Semaste Initiate(); 2472285101Semaste } 2473285101Semaste } 2474285101Semaste} 2475285101Semaste 2476285101Semaste// The maximum line length of an .rs.info packet 2477285101Semaste#define MAXLINE 500 2478285101Semaste 2479285101Semaste// The .rs.info symbol in renderscript modules contains a string which needs to be parsed. 2480285101Semaste// The string is basic and is parsed on a line by line basis. 2481285101Semastebool 2482285101SemasteRSModuleDescriptor::ParseRSInfo() 2483285101Semaste{ 2484285101Semaste const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData); 2485285101Semaste if (info_sym) 2486285101Semaste { 2487285101Semaste const addr_t addr = info_sym->GetAddressRef().GetFileAddress(); 2488285101Semaste const addr_t size = info_sym->GetByteSize(); 2489285101Semaste const FileSpec fs = m_module->GetFileSpec(); 2490285101Semaste 2491285101Semaste DataBufferSP buffer = fs.ReadFileContents(addr, size); 2492285101Semaste 2493285101Semaste if (!buffer) 2494285101Semaste return false; 2495285101Semaste 2496285101Semaste std::string info((const char *)buffer->GetBytes()); 2497285101Semaste 2498285101Semaste std::vector<std::string> info_lines; 2499296417Sdim size_t lpos = info.find('\n'); 2500285101Semaste while (lpos != std::string::npos) 2501285101Semaste { 2502285101Semaste info_lines.push_back(info.substr(0, lpos)); 2503285101Semaste info = info.substr(lpos + 1); 2504296417Sdim lpos = info.find('\n'); 2505285101Semaste } 2506285101Semaste size_t offset = 0; 2507285101Semaste while (offset < info_lines.size()) 2508285101Semaste { 2509285101Semaste std::string line = info_lines[offset]; 2510285101Semaste // Parse directives 2511285101Semaste uint32_t numDefns = 0; 2512285101Semaste if (sscanf(line.c_str(), "exportVarCount: %u", &numDefns) == 1) 2513285101Semaste { 2514285101Semaste while (numDefns--) 2515285101Semaste m_globals.push_back(RSGlobalDescriptor(this, info_lines[++offset].c_str())); 2516285101Semaste } 2517285101Semaste else if (sscanf(line.c_str(), "exportFuncCount: %u", &numDefns) == 1) 2518285101Semaste { 2519285101Semaste } 2520285101Semaste else if (sscanf(line.c_str(), "exportForEachCount: %u", &numDefns) == 1) 2521285101Semaste { 2522285101Semaste char name[MAXLINE]; 2523285101Semaste while (numDefns--) 2524285101Semaste { 2525285101Semaste uint32_t slot = 0; 2526285101Semaste name[0] = '\0'; 2527285101Semaste if (sscanf(info_lines[++offset].c_str(), "%u - %s", &slot, &name[0]) == 2) 2528285101Semaste { 2529285101Semaste m_kernels.push_back(RSKernelDescriptor(this, name, slot)); 2530285101Semaste } 2531285101Semaste } 2532296417Sdim } 2533285101Semaste else if (sscanf(line.c_str(), "pragmaCount: %u", &numDefns) == 1) 2534285101Semaste { 2535285101Semaste char name[MAXLINE]; 2536285101Semaste char value[MAXLINE]; 2537285101Semaste while (numDefns--) 2538285101Semaste { 2539285101Semaste name[0] = '\0'; 2540285101Semaste value[0] = '\0'; 2541296417Sdim if (sscanf(info_lines[++offset].c_str(), "%s - %s", &name[0], &value[0]) != 0 2542285101Semaste && (name[0] != '\0')) 2543285101Semaste { 2544285101Semaste m_pragmas[std::string(name)] = value; 2545285101Semaste } 2546285101Semaste } 2547285101Semaste } 2548285101Semaste else if (sscanf(line.c_str(), "objectSlotCount: %u", &numDefns) == 1) 2549285101Semaste { 2550285101Semaste } 2551285101Semaste 2552285101Semaste offset++; 2553285101Semaste } 2554285101Semaste return m_kernels.size() > 0; 2555285101Semaste } 2556285101Semaste return false; 2557285101Semaste} 2558285101Semaste 2559285101Semastebool 2560285101SemasteRenderScriptRuntime::ProbeModules(const ModuleList module_list) 2561285101Semaste{ 2562285101Semaste bool rs_found = false; 2563285101Semaste size_t num_modules = module_list.GetSize(); 2564285101Semaste for (size_t i = 0; i < num_modules; i++) 2565285101Semaste { 2566285101Semaste auto module = module_list.GetModuleAtIndex(i); 2567285101Semaste rs_found |= LoadModule(module); 2568285101Semaste } 2569285101Semaste return rs_found; 2570285101Semaste} 2571285101Semaste 2572285101Semastevoid 2573285101SemasteRenderScriptRuntime::Status(Stream &strm) const 2574285101Semaste{ 2575285101Semaste if (m_libRS) 2576285101Semaste { 2577285101Semaste strm.Printf("Runtime Library discovered."); 2578285101Semaste strm.EOL(); 2579285101Semaste } 2580285101Semaste if (m_libRSDriver) 2581285101Semaste { 2582285101Semaste strm.Printf("Runtime Driver discovered."); 2583285101Semaste strm.EOL(); 2584285101Semaste } 2585285101Semaste if (m_libRSCpuRef) 2586285101Semaste { 2587285101Semaste strm.Printf("CPU Reference Implementation discovered."); 2588285101Semaste strm.EOL(); 2589285101Semaste } 2590296417Sdim 2591285101Semaste if (m_runtimeHooks.size()) 2592285101Semaste { 2593285101Semaste strm.Printf("Runtime functions hooked:"); 2594285101Semaste strm.EOL(); 2595285101Semaste for (auto b : m_runtimeHooks) 2596285101Semaste { 2597285101Semaste strm.Indent(b.second->defn->name); 2598285101Semaste strm.EOL(); 2599285101Semaste } 2600296417Sdim } 2601285101Semaste else 2602285101Semaste { 2603285101Semaste strm.Printf("Runtime is not hooked."); 2604285101Semaste strm.EOL(); 2605285101Semaste } 2606285101Semaste} 2607285101Semaste 2608296417Sdimvoid 2609285101SemasteRenderScriptRuntime::DumpContexts(Stream &strm) const 2610285101Semaste{ 2611285101Semaste strm.Printf("Inferred RenderScript Contexts:"); 2612285101Semaste strm.EOL(); 2613285101Semaste strm.IndentMore(); 2614285101Semaste 2615285101Semaste std::map<addr_t, uint64_t> contextReferences; 2616285101Semaste 2617296417Sdim // Iterate over all of the currently discovered scripts. 2618296417Sdim // Note: We cant push or pop from m_scripts inside this loop or it may invalidate script. 2619296417Sdim for (const auto & script : m_scripts) 2620285101Semaste { 2621296417Sdim if (!script->context.isValid()) 2622296417Sdim continue; 2623296417Sdim lldb::addr_t context = *script->context; 2624296417Sdim 2625296417Sdim if (contextReferences.find(context) != contextReferences.end()) 2626285101Semaste { 2627296417Sdim contextReferences[context]++; 2628285101Semaste } 2629285101Semaste else 2630285101Semaste { 2631296417Sdim contextReferences[context] = 1; 2632285101Semaste } 2633285101Semaste } 2634285101Semaste 2635285101Semaste for (const auto& cRef : contextReferences) 2636285101Semaste { 2637285101Semaste strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances", cRef.first, cRef.second); 2638285101Semaste strm.EOL(); 2639285101Semaste } 2640285101Semaste strm.IndentLess(); 2641285101Semaste} 2642285101Semaste 2643296417Sdimvoid 2644285101SemasteRenderScriptRuntime::DumpKernels(Stream &strm) const 2645285101Semaste{ 2646285101Semaste strm.Printf("RenderScript Kernels:"); 2647285101Semaste strm.EOL(); 2648285101Semaste strm.IndentMore(); 2649285101Semaste for (const auto &module : m_rsmodules) 2650285101Semaste { 2651285101Semaste strm.Printf("Resource '%s':",module->m_resname.c_str()); 2652285101Semaste strm.EOL(); 2653285101Semaste for (const auto &kernel : module->m_kernels) 2654285101Semaste { 2655285101Semaste strm.Indent(kernel.m_name.AsCString()); 2656285101Semaste strm.EOL(); 2657285101Semaste } 2658285101Semaste } 2659285101Semaste strm.IndentLess(); 2660285101Semaste} 2661285101Semaste 2662296417SdimRenderScriptRuntime::AllocationDetails* 2663296417SdimRenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) 2664285101Semaste{ 2665296417Sdim AllocationDetails* alloc = nullptr; 2666296417Sdim 2667296417Sdim // See if we can find allocation using id as an index; 2668296417Sdim if (alloc_id <= m_allocations.size() && alloc_id != 0 2669296417Sdim && m_allocations[alloc_id-1]->id == alloc_id) 2670285101Semaste { 2671296417Sdim alloc = m_allocations[alloc_id-1].get(); 2672296417Sdim return alloc; 2673285101Semaste } 2674285101Semaste 2675296417Sdim // Fallback to searching 2676296417Sdim for (const auto & a : m_allocations) 2677285101Semaste { 2678296417Sdim if (a->id == alloc_id) 2679296417Sdim { 2680296417Sdim alloc = a.get(); 2681296417Sdim break; 2682296417Sdim } 2683296417Sdim } 2684296417Sdim 2685296417Sdim if (alloc == nullptr) 2686296417Sdim { 2687296417Sdim strm.Printf("Error: Couldn't find allocation with id matching %u", alloc_id); 2688296417Sdim strm.EOL(); 2689296417Sdim } 2690296417Sdim 2691296417Sdim return alloc; 2692296417Sdim} 2693296417Sdim 2694296417Sdim// Prints the contents of an allocation to the output stream, which may be a file 2695296417Sdimbool 2696296417SdimRenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame* frame_ptr, const uint32_t id) 2697296417Sdim{ 2698296417Sdim Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 2699296417Sdim 2700296417Sdim // Check we can find the desired allocation 2701296417Sdim AllocationDetails* alloc = FindAllocByID(strm, id); 2702296417Sdim if (!alloc) 2703296417Sdim return false; // FindAllocByID() will print error message for us here 2704296417Sdim 2705296417Sdim if (log) 2706296417Sdim log->Printf("RenderScriptRuntime::DumpAllocation - Found allocation 0x%" PRIx64, *alloc->address.get()); 2707296417Sdim 2708296417Sdim // Check we have information about the allocation, if not calculate it 2709296417Sdim if (alloc->shouldRefresh()) 2710296417Sdim { 2711296417Sdim if (log) 2712296417Sdim log->Printf("RenderScriptRuntime::DumpAllocation - Allocation details not calculated yet, jitting info"); 2713296417Sdim 2714296417Sdim // JIT all the allocation information 2715296417Sdim if (!RefreshAllocation(alloc, frame_ptr)) 2716285101Semaste { 2717296417Sdim strm.Printf("Error: Couldn't JIT allocation details"); 2718296417Sdim strm.EOL(); 2719296417Sdim return false; 2720296417Sdim } 2721296417Sdim } 2722285101Semaste 2723296417Sdim // Establish format and size of each data element 2724296417Sdim const unsigned int vec_size = *alloc->element.type_vec_size.get(); 2725296417Sdim const Element::DataType type = *alloc->element.type.get(); 2726285101Semaste 2727296417Sdim assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT 2728296417Sdim && "Invalid allocation type"); 2729296417Sdim 2730296417Sdim lldb::Format format; 2731296417Sdim if (type >= Element::RS_TYPE_ELEMENT) 2732296417Sdim format = eFormatHex; 2733296417Sdim else 2734296417Sdim format = vec_size == 1 ? static_cast<lldb::Format>(AllocationDetails::RSTypeToFormat[type][eFormatSingle]) 2735296417Sdim : static_cast<lldb::Format>(AllocationDetails::RSTypeToFormat[type][eFormatVector]); 2736296417Sdim 2737296417Sdim const unsigned int data_size = *alloc->element.datum_size.get(); 2738296417Sdim 2739296417Sdim if (log) 2740296417Sdim log->Printf("RenderScriptRuntime::DumpAllocation - Element size %u bytes, including padding", data_size); 2741296417Sdim 2742296417Sdim // Allocate a buffer to copy data into 2743296417Sdim std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); 2744296417Sdim if (!buffer) 2745296417Sdim { 2746296417Sdim strm.Printf("Error: Couldn't read allocation data"); 2747296417Sdim strm.EOL(); 2748296417Sdim return false; 2749296417Sdim } 2750296417Sdim 2751296417Sdim // Calculate stride between rows as there may be padding at end of rows since 2752296417Sdim // allocated memory is 16-byte aligned 2753296417Sdim if (!alloc->stride.isValid()) 2754296417Sdim { 2755296417Sdim if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension 2756296417Sdim alloc->stride = 0; 2757296417Sdim else if (!JITAllocationStride(alloc, frame_ptr)) 2758296417Sdim { 2759296417Sdim strm.Printf("Error: Couldn't calculate allocation row stride"); 2760296417Sdim strm.EOL(); 2761296417Sdim return false; 2762296417Sdim } 2763296417Sdim } 2764296417Sdim const unsigned int stride = *alloc->stride.get(); 2765296417Sdim const unsigned int size = *alloc->size.get(); // Size of whole allocation 2766296417Sdim const unsigned int padding = alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0; 2767296417Sdim if (log) 2768296417Sdim log->Printf("RenderScriptRuntime::DumpAllocation - stride %u bytes, size %u bytes, padding %u", stride, size, padding); 2769296417Sdim 2770296417Sdim // Find dimensions used to index loops, so need to be non-zero 2771296417Sdim unsigned int dim_x = alloc->dimension.get()->dim_1; 2772296417Sdim dim_x = dim_x == 0 ? 1 : dim_x; 2773296417Sdim 2774296417Sdim unsigned int dim_y = alloc->dimension.get()->dim_2; 2775296417Sdim dim_y = dim_y == 0 ? 1 : dim_y; 2776296417Sdim 2777296417Sdim unsigned int dim_z = alloc->dimension.get()->dim_3; 2778296417Sdim dim_z = dim_z == 0 ? 1 : dim_z; 2779296417Sdim 2780296417Sdim // Use data extractor to format output 2781296417Sdim const uint32_t archByteSize = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); 2782296417Sdim DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(), archByteSize); 2783296417Sdim 2784296417Sdim unsigned int offset = 0; // Offset in buffer to next element to be printed 2785296417Sdim unsigned int prev_row = 0; // Offset to the start of the previous row 2786296417Sdim 2787296417Sdim // Iterate over allocation dimensions, printing results to user 2788296417Sdim strm.Printf("Data (X, Y, Z):"); 2789296417Sdim for (unsigned int z = 0; z < dim_z; ++z) 2790296417Sdim { 2791296417Sdim for (unsigned int y = 0; y < dim_y; ++y) 2792296417Sdim { 2793296417Sdim // Use stride to index start of next row. 2794296417Sdim if (!(y==0 && z==0)) 2795296417Sdim offset = prev_row + stride; 2796296417Sdim prev_row = offset; 2797296417Sdim 2798296417Sdim // Print each element in the row individually 2799296417Sdim for (unsigned int x = 0; x < dim_x; ++x) 2800296417Sdim { 2801296417Sdim strm.Printf("\n(%u, %u, %u) = ", x, y, z); 2802296417Sdim if ((type == Element::RS_TYPE_NONE) && (alloc->element.children.size() > 0) && 2803296417Sdim (alloc->element.type_name != Element::GetFallbackStructName())) 2804285101Semaste { 2805296417Sdim // Here we are dumping an Element of struct type. 2806296417Sdim // This is done using expression evaluation with the name of the struct type and pointer to element. 2807285101Semaste 2808296417Sdim // Don't print the name of the resulting expression, since this will be '$[0-9]+' 2809296417Sdim DumpValueObjectOptions expr_options; 2810296417Sdim expr_options.SetHideName(true); 2811296417Sdim 2812296417Sdim // Setup expression as derefrencing a pointer cast to element address. 2813296417Sdim char expr_char_buffer[jit_max_expr_size]; 2814296417Sdim int chars_written = snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64, 2815296417Sdim alloc->element.type_name.AsCString(), *alloc->data_ptr.get() + offset); 2816296417Sdim 2817296417Sdim if (chars_written < 0 || chars_written >= jit_max_expr_size) 2818285101Semaste { 2819296417Sdim if (log) 2820296417Sdim log->Printf("RenderScriptRuntime::DumpAllocation- Error in snprintf()"); 2821296417Sdim continue; 2822285101Semaste } 2823296417Sdim 2824296417Sdim // Evaluate expression 2825296417Sdim ValueObjectSP expr_result; 2826296417Sdim GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer, frame_ptr, expr_result); 2827296417Sdim 2828296417Sdim // Print the results to our stream. 2829296417Sdim expr_result->Dump(strm, expr_options); 2830285101Semaste } 2831296417Sdim else 2832285101Semaste { 2833296417Sdim alloc_data.Dump(&strm, offset, format, data_size - padding, 1, 1, LLDB_INVALID_ADDRESS, 0, 0); 2834285101Semaste } 2835296417Sdim offset += data_size; 2836296417Sdim } 2837296417Sdim } 2838296417Sdim } 2839296417Sdim strm.EOL(); 2840285101Semaste 2841296417Sdim return true; 2842296417Sdim} 2843285101Semaste 2844296417Sdim// Prints infomation regarding all the currently loaded allocations. 2845296417Sdim// These details are gathered by jitting the runtime, which has as latency. 2846296417Sdimvoid 2847296417SdimRenderScriptRuntime::ListAllocations(Stream &strm, StackFrame* frame_ptr, bool recompute) 2848296417Sdim{ 2849296417Sdim strm.Printf("RenderScript Allocations:"); 2850296417Sdim strm.EOL(); 2851296417Sdim strm.IndentMore(); 2852296417Sdim 2853296417Sdim for (auto &alloc : m_allocations) 2854296417Sdim { 2855296417Sdim // JIT the allocation info if we haven't done it, or the user forces us to. 2856296417Sdim bool do_refresh = alloc->shouldRefresh() || recompute; 2857296417Sdim 2858296417Sdim // JIT current allocation information 2859296417Sdim if (do_refresh && !RefreshAllocation(alloc.get(), frame_ptr)) 2860296417Sdim { 2861296417Sdim strm.Printf("Error: Couldn't evaluate details for allocation %u\n", alloc->id); 2862296417Sdim continue; 2863296417Sdim } 2864296417Sdim 2865296417Sdim strm.Printf("%u:\n",alloc->id); 2866296417Sdim strm.IndentMore(); 2867296417Sdim 2868296417Sdim strm.Indent("Context: "); 2869296417Sdim if (!alloc->context.isValid()) 2870296417Sdim strm.Printf("unknown\n"); 2871296417Sdim else 2872296417Sdim strm.Printf("0x%" PRIx64 "\n", *alloc->context.get()); 2873296417Sdim 2874296417Sdim strm.Indent("Address: "); 2875296417Sdim if (!alloc->address.isValid()) 2876296417Sdim strm.Printf("unknown\n"); 2877296417Sdim else 2878296417Sdim strm.Printf("0x%" PRIx64 "\n", *alloc->address.get()); 2879296417Sdim 2880296417Sdim strm.Indent("Data pointer: "); 2881296417Sdim if (!alloc->data_ptr.isValid()) 2882296417Sdim strm.Printf("unknown\n"); 2883296417Sdim else 2884296417Sdim strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get()); 2885296417Sdim 2886296417Sdim strm.Indent("Dimensions: "); 2887296417Sdim if (!alloc->dimension.isValid()) 2888296417Sdim strm.Printf("unknown\n"); 2889296417Sdim else 2890296417Sdim strm.Printf("(%d, %d, %d)\n", alloc->dimension.get()->dim_1, 2891296417Sdim alloc->dimension.get()->dim_2, 2892296417Sdim alloc->dimension.get()->dim_3); 2893296417Sdim 2894296417Sdim strm.Indent("Data Type: "); 2895296417Sdim if (!alloc->element.type.isValid() || !alloc->element.type_vec_size.isValid()) 2896296417Sdim strm.Printf("unknown\n"); 2897296417Sdim else 2898296417Sdim { 2899296417Sdim const int vector_size = *alloc->element.type_vec_size.get(); 2900296417Sdim Element::DataType type = *alloc->element.type.get(); 2901296417Sdim 2902296417Sdim if (!alloc->element.type_name.IsEmpty()) 2903296417Sdim strm.Printf("%s\n", alloc->element.type_name.AsCString()); 2904296417Sdim else 2905296417Sdim { 2906296417Sdim // Enum value isn't monotonous, so doesn't always index RsDataTypeToString array 2907296417Sdim if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT) 2908296417Sdim type = static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1); 2909296417Sdim 2910296417Sdim if (type >= (sizeof(AllocationDetails::RsDataTypeToString) / sizeof(AllocationDetails::RsDataTypeToString[0])) 2911296417Sdim || vector_size > 4 || vector_size < 1) 2912296417Sdim strm.Printf("invalid type\n"); 2913296417Sdim else 2914296417Sdim strm.Printf("%s\n", AllocationDetails::RsDataTypeToString[static_cast<unsigned int>(type)][vector_size-1]); 2915285101Semaste } 2916285101Semaste } 2917296417Sdim 2918296417Sdim strm.Indent("Data Kind: "); 2919296417Sdim if (!alloc->element.type_kind.isValid()) 2920296417Sdim strm.Printf("unknown\n"); 2921296417Sdim else 2922296417Sdim { 2923296417Sdim const Element::DataKind kind = *alloc->element.type_kind.get(); 2924296417Sdim if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV) 2925296417Sdim strm.Printf("invalid kind\n"); 2926296417Sdim else 2927296417Sdim strm.Printf("%s\n", AllocationDetails::RsDataKindToString[static_cast<unsigned int>(kind)]); 2928296417Sdim } 2929296417Sdim 2930296417Sdim strm.EOL(); 2931296417Sdim strm.IndentLess(); 2932285101Semaste } 2933296417Sdim strm.IndentLess(); 2934296417Sdim} 2935285101Semaste 2936296417Sdim// Set breakpoints on every kernel found in RS module 2937296417Sdimvoid 2938296417SdimRenderScriptRuntime::BreakOnModuleKernels(const RSModuleDescriptorSP rsmodule_sp) 2939296417Sdim{ 2940296417Sdim for (const auto &kernel : rsmodule_sp->m_kernels) 2941285101Semaste { 2942296417Sdim // Don't set breakpoint on 'root' kernel 2943296417Sdim if (strcmp(kernel.m_name.AsCString(), "root") == 0) 2944296417Sdim continue; 2945296417Sdim 2946296417Sdim CreateKernelBreakpoint(kernel.m_name); 2947285101Semaste } 2948285101Semaste} 2949285101Semaste 2950296417Sdim// Method is internally called by the 'kernel breakpoint all' command to 2951296417Sdim// enable or disable breaking on all kernels. 2952296417Sdim// 2953296417Sdim// When do_break is true we want to enable this functionality. 2954296417Sdim// When do_break is false we want to disable it. 2955285101Semastevoid 2956296417SdimRenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) 2957296417Sdim{ 2958296417Sdim Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 2959296417Sdim 2960296417Sdim InitSearchFilter(target); 2961296417Sdim 2962296417Sdim // Set breakpoints on all the kernels 2963296417Sdim if (do_break && !m_breakAllKernels) 2964296417Sdim { 2965296417Sdim m_breakAllKernels = true; 2966296417Sdim 2967296417Sdim for (const auto &module : m_rsmodules) 2968296417Sdim BreakOnModuleKernels(module); 2969296417Sdim 2970296417Sdim if (log) 2971296417Sdim log->Printf("RenderScriptRuntime::SetBreakAllKernels(True)" 2972296417Sdim "- breakpoints set on all currently loaded kernels"); 2973296417Sdim } 2974296417Sdim else if (!do_break && m_breakAllKernels) // Breakpoints won't be set on any new kernels. 2975296417Sdim { 2976296417Sdim m_breakAllKernels = false; 2977296417Sdim 2978296417Sdim if (log) 2979296417Sdim log->Printf("RenderScriptRuntime::SetBreakAllKernels(False) - breakpoints no longer automatically set"); 2980296417Sdim } 2981296417Sdim} 2982296417Sdim 2983296417Sdim// Given the name of a kernel this function creates a breakpoint using our 2984296417Sdim// own breakpoint resolver, and returns the Breakpoint shared pointer. 2985296417SdimBreakpointSP 2986296417SdimRenderScriptRuntime::CreateKernelBreakpoint(const ConstString& name) 2987296417Sdim{ 2988296417Sdim Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 2989296417Sdim 2990296417Sdim if (!m_filtersp) 2991296417Sdim { 2992296417Sdim if (log) 2993296417Sdim log->Printf("RenderScriptRuntime::CreateKernelBreakpoint - Error: No breakpoint search filter set"); 2994296417Sdim return nullptr; 2995296417Sdim } 2996296417Sdim 2997296417Sdim BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name)); 2998296417Sdim BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint(m_filtersp, resolver_sp, false, false, false); 2999296417Sdim 3000296417Sdim // Give RS breakpoints a specific name, so the user can manipulate them as a group. 3001296417Sdim Error err; 3002296417Sdim if (!bp->AddName("RenderScriptKernel", err) && log) 3003296417Sdim log->Printf("RenderScriptRuntime::CreateKernelBreakpoint: Error setting break name, %s", err.AsCString()); 3004296417Sdim 3005296417Sdim return bp; 3006296417Sdim} 3007296417Sdim 3008296417Sdim// Given an expression for a variable this function tries to calculate the variable's value. 3009296417Sdim// If this is possible it returns true and sets the uint64_t parameter to the variables unsigned value. 3010296417Sdim// Otherwise function returns false. 3011296417Sdimbool 3012296417SdimRenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp, const char* var_name, uint64_t& val) 3013296417Sdim{ 3014296417Sdim Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); 3015296417Sdim Error error; 3016296417Sdim VariableSP var_sp; 3017296417Sdim 3018296417Sdim // Find variable in stack frame 3019296417Sdim ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath(var_name, 3020296417Sdim eNoDynamicValues, 3021296417Sdim StackFrame::eExpressionPathOptionCheckPtrVsMember | 3022296417Sdim StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, 3023296417Sdim var_sp, 3024296417Sdim error)); 3025296417Sdim if (!error.Success()) 3026296417Sdim { 3027296417Sdim if (log) 3028296417Sdim log->Printf("RenderScriptRuntime::GetFrameVarAsUnsigned - Error, couldn't find '%s' in frame", var_name); 3029296417Sdim 3030296417Sdim return false; 3031296417Sdim } 3032296417Sdim 3033296417Sdim // Find the unsigned int value for the variable 3034296417Sdim bool success = false; 3035296417Sdim val = value_sp->GetValueAsUnsigned(0, &success); 3036296417Sdim if (!success) 3037296417Sdim { 3038296417Sdim if (log) 3039296417Sdim log->Printf("RenderScriptRuntime::GetFrameVarAsUnsigned - Error, couldn't parse '%s' as an unsigned int", var_name); 3040296417Sdim 3041296417Sdim return false; 3042296417Sdim } 3043296417Sdim 3044296417Sdim return true; 3045296417Sdim} 3046296417Sdim 3047296417Sdim// Callback when a kernel breakpoint hits and we're looking for a specific coordinate. 3048296417Sdim// Baton parameter contains a pointer to the target coordinate we want to break on. 3049296417Sdim// Function then checks the .expand frame for the current coordinate and breaks to user if it matches. 3050296417Sdim// Parameter 'break_id' is the id of the Breakpoint which made the callback. 3051296417Sdim// Parameter 'break_loc_id' is the id for the BreakpointLocation which was hit, 3052296417Sdim// a single logical breakpoint can have multiple addresses. 3053296417Sdimbool 3054296417SdimRenderScriptRuntime::KernelBreakpointHit(void *baton, StoppointCallbackContext *ctx, 3055296417Sdim user_id_t break_id, user_id_t break_loc_id) 3056296417Sdim{ 3057296417Sdim Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); 3058296417Sdim 3059296417Sdim assert(baton && "Error: null baton in conditional kernel breakpoint callback"); 3060296417Sdim 3061296417Sdim // Coordinate we want to stop on 3062296417Sdim const int* target_coord = static_cast<const int*>(baton); 3063296417Sdim 3064296417Sdim if (log) 3065296417Sdim log->Printf("RenderScriptRuntime::KernelBreakpointHit - Break ID %" PRIu64 ", target coord (%d, %d, %d)", 3066296417Sdim break_id, target_coord[0], target_coord[1], target_coord[2]); 3067296417Sdim 3068296417Sdim // Go up one stack frame to .expand kernel 3069296417Sdim ExecutionContext context(ctx->exe_ctx_ref); 3070296417Sdim ThreadSP thread_sp = context.GetThreadSP(); 3071296417Sdim if (!thread_sp->SetSelectedFrameByIndex(1)) 3072296417Sdim { 3073296417Sdim if (log) 3074296417Sdim log->Printf("RenderScriptRuntime::KernelBreakpointHit - Error, couldn't go up stack frame"); 3075296417Sdim 3076296417Sdim return false; 3077296417Sdim } 3078296417Sdim 3079296417Sdim StackFrameSP frame_sp = thread_sp->GetSelectedFrame(); 3080296417Sdim if (!frame_sp) 3081296417Sdim { 3082296417Sdim if (log) 3083296417Sdim log->Printf("RenderScriptRuntime::KernelBreakpointHit - Error, couldn't select .expand stack frame"); 3084296417Sdim 3085296417Sdim return false; 3086296417Sdim } 3087296417Sdim 3088296417Sdim // Get values for variables in .expand frame that tell us the current kernel invocation 3089296417Sdim const char* coord_expressions[] = {"rsIndex", "p->current.y", "p->current.z"}; 3090296417Sdim uint64_t current_coord[3] = {0, 0, 0}; 3091296417Sdim 3092296417Sdim for(int i = 0; i < 3; ++i) 3093296417Sdim { 3094296417Sdim if (!GetFrameVarAsUnsigned(frame_sp, coord_expressions[i], current_coord[i])) 3095296417Sdim return false; 3096296417Sdim 3097296417Sdim if (log) 3098296417Sdim log->Printf("RenderScriptRuntime::KernelBreakpointHit, %s = %" PRIu64, coord_expressions[i], current_coord[i]); 3099296417Sdim } 3100296417Sdim 3101296417Sdim // Check if the current kernel invocation coordinate matches our target coordinate 3102296417Sdim if (current_coord[0] == static_cast<uint64_t>(target_coord[0]) && 3103296417Sdim current_coord[1] == static_cast<uint64_t>(target_coord[1]) && 3104296417Sdim current_coord[2] == static_cast<uint64_t>(target_coord[2])) 3105296417Sdim { 3106296417Sdim if (log) 3107296417Sdim log->Printf("RenderScriptRuntime::KernelBreakpointHit, BREAKING %" PRIu64 ", %" PRIu64 ", %" PRIu64, 3108296417Sdim current_coord[0], current_coord[1], current_coord[2]); 3109296417Sdim 3110296417Sdim BreakpointSP breakpoint_sp = context.GetTargetPtr()->GetBreakpointByID(break_id); 3111296417Sdim assert(breakpoint_sp != nullptr && "Error: Couldn't find breakpoint matching break id for callback"); 3112296417Sdim breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint should only be hit once. 3113296417Sdim return true; 3114296417Sdim } 3115296417Sdim 3116296417Sdim // No match on coordinate 3117296417Sdim return false; 3118296417Sdim} 3119296417Sdim 3120296417Sdim// Tries to set a breakpoint on the start of a kernel, resolved using the kernel name. 3121296417Sdim// Argument 'coords', represents a three dimensional coordinate which can be used to specify 3122296417Sdim// a single kernel instance to break on. If this is set then we add a callback to the breakpoint. 3123296417Sdimvoid 3124296417SdimRenderScriptRuntime::PlaceBreakpointOnKernel(Stream &strm, const char* name, const std::array<int,3> coords, 3125296417Sdim Error& error, TargetSP target) 3126296417Sdim{ 3127296417Sdim if (!name) 3128296417Sdim { 3129296417Sdim error.SetErrorString("invalid kernel name"); 3130296417Sdim return; 3131296417Sdim } 3132296417Sdim 3133296417Sdim InitSearchFilter(target); 3134296417Sdim 3135296417Sdim ConstString kernel_name(name); 3136296417Sdim BreakpointSP bp = CreateKernelBreakpoint(kernel_name); 3137296417Sdim 3138296417Sdim // We have a conditional breakpoint on a specific coordinate 3139296417Sdim if (coords[0] != -1) 3140296417Sdim { 3141296417Sdim strm.Printf("Conditional kernel breakpoint on coordinate %d, %d, %d", coords[0], coords[1], coords[2]); 3142296417Sdim strm.EOL(); 3143296417Sdim 3144296417Sdim // Allocate memory for the baton, and copy over coordinate 3145296417Sdim int* baton = new int[3]; 3146296417Sdim baton[0] = coords[0]; baton[1] = coords[1]; baton[2] = coords[2]; 3147296417Sdim 3148296417Sdim // Create a callback that will be invoked everytime the breakpoint is hit. 3149296417Sdim // The baton object passed to the handler is the target coordinate we want to break on. 3150296417Sdim bp->SetCallback(KernelBreakpointHit, baton, true); 3151296417Sdim 3152296417Sdim // Store a shared pointer to the baton, so the memory will eventually be cleaned up after destruction 3153296417Sdim m_conditional_breaks[bp->GetID()] = std::shared_ptr<int>(baton); 3154296417Sdim } 3155296417Sdim 3156296417Sdim if (bp) 3157296417Sdim bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false); 3158296417Sdim} 3159296417Sdim 3160296417Sdimvoid 3161285101SemasteRenderScriptRuntime::DumpModules(Stream &strm) const 3162285101Semaste{ 3163285101Semaste strm.Printf("RenderScript Modules:"); 3164285101Semaste strm.EOL(); 3165285101Semaste strm.IndentMore(); 3166285101Semaste for (const auto &module : m_rsmodules) 3167285101Semaste { 3168285101Semaste module->Dump(strm); 3169285101Semaste } 3170285101Semaste strm.IndentLess(); 3171285101Semaste} 3172285101Semaste 3173296417SdimRenderScriptRuntime::ScriptDetails* 3174296417SdimRenderScriptRuntime::LookUpScript(addr_t address, bool create) 3175296417Sdim{ 3176296417Sdim for (const auto & s : m_scripts) 3177296417Sdim { 3178296417Sdim if (s->script.isValid()) 3179296417Sdim if (*s->script == address) 3180296417Sdim return s.get(); 3181296417Sdim } 3182296417Sdim if (create) 3183296417Sdim { 3184296417Sdim std::unique_ptr<ScriptDetails> s(new ScriptDetails); 3185296417Sdim s->script = address; 3186296417Sdim m_scripts.push_back(std::move(s)); 3187296417Sdim return m_scripts.back().get(); 3188296417Sdim } 3189296417Sdim return nullptr; 3190296417Sdim} 3191296417Sdim 3192296417SdimRenderScriptRuntime::AllocationDetails* 3193296417SdimRenderScriptRuntime::LookUpAllocation(addr_t address, bool create) 3194296417Sdim{ 3195296417Sdim for (const auto & a : m_allocations) 3196296417Sdim { 3197296417Sdim if (a->address.isValid()) 3198296417Sdim if (*a->address == address) 3199296417Sdim return a.get(); 3200296417Sdim } 3201296417Sdim if (create) 3202296417Sdim { 3203296417Sdim std::unique_ptr<AllocationDetails> a(new AllocationDetails); 3204296417Sdim a->address = address; 3205296417Sdim m_allocations.push_back(std::move(a)); 3206296417Sdim return m_allocations.back().get(); 3207296417Sdim } 3208296417Sdim return nullptr; 3209296417Sdim} 3210296417Sdim 3211285101Semastevoid 3212285101SemasteRSModuleDescriptor::Dump(Stream &strm) const 3213285101Semaste{ 3214285101Semaste strm.Indent(); 3215285101Semaste m_module->GetFileSpec().Dump(&strm); 3216285101Semaste if(m_module->GetNumCompileUnits()) 3217285101Semaste { 3218285101Semaste strm.Indent("Debug info loaded."); 3219285101Semaste } 3220285101Semaste else 3221285101Semaste { 3222285101Semaste strm.Indent("Debug info does not exist."); 3223285101Semaste } 3224285101Semaste strm.EOL(); 3225285101Semaste strm.IndentMore(); 3226285101Semaste strm.Indent(); 3227285101Semaste strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size())); 3228285101Semaste strm.EOL(); 3229285101Semaste strm.IndentMore(); 3230285101Semaste for (const auto &global : m_globals) 3231285101Semaste { 3232285101Semaste global.Dump(strm); 3233285101Semaste } 3234285101Semaste strm.IndentLess(); 3235285101Semaste strm.Indent(); 3236285101Semaste strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size())); 3237285101Semaste strm.EOL(); 3238285101Semaste strm.IndentMore(); 3239285101Semaste for (const auto &kernel : m_kernels) 3240285101Semaste { 3241285101Semaste kernel.Dump(strm); 3242285101Semaste } 3243285101Semaste strm.Printf("Pragmas: %" PRIu64 , static_cast<uint64_t>(m_pragmas.size())); 3244285101Semaste strm.EOL(); 3245285101Semaste strm.IndentMore(); 3246285101Semaste for (const auto &key_val : m_pragmas) 3247285101Semaste { 3248285101Semaste strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str()); 3249285101Semaste strm.EOL(); 3250285101Semaste } 3251285101Semaste strm.IndentLess(4); 3252285101Semaste} 3253285101Semaste 3254285101Semastevoid 3255285101SemasteRSGlobalDescriptor::Dump(Stream &strm) const 3256285101Semaste{ 3257285101Semaste strm.Indent(m_name.AsCString()); 3258285101Semaste VariableList var_list; 3259285101Semaste m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list); 3260285101Semaste if (var_list.GetSize() == 1) 3261285101Semaste { 3262285101Semaste auto var = var_list.GetVariableAtIndex(0); 3263285101Semaste auto type = var->GetType(); 3264285101Semaste if(type) 3265285101Semaste { 3266285101Semaste strm.Printf(" - "); 3267285101Semaste type->DumpTypeName(&strm); 3268285101Semaste } 3269285101Semaste else 3270285101Semaste { 3271285101Semaste strm.Printf(" - Unknown Type"); 3272285101Semaste } 3273285101Semaste } 3274285101Semaste else 3275285101Semaste { 3276285101Semaste strm.Printf(" - variable identified, but not found in binary"); 3277285101Semaste const Symbol* s = m_module->m_module->FindFirstSymbolWithNameAndType(m_name, eSymbolTypeData); 3278285101Semaste if (s) 3279285101Semaste { 3280285101Semaste strm.Printf(" (symbol exists) "); 3281285101Semaste } 3282285101Semaste } 3283285101Semaste 3284285101Semaste strm.EOL(); 3285285101Semaste} 3286285101Semaste 3287285101Semastevoid 3288285101SemasteRSKernelDescriptor::Dump(Stream &strm) const 3289285101Semaste{ 3290285101Semaste strm.Indent(m_name.AsCString()); 3291285101Semaste strm.EOL(); 3292285101Semaste} 3293285101Semaste 3294285101Semasteclass CommandObjectRenderScriptRuntimeModuleProbe : public CommandObjectParsed 3295285101Semaste{ 3296296417Sdimpublic: 3297285101Semaste CommandObjectRenderScriptRuntimeModuleProbe(CommandInterpreter &interpreter) 3298285101Semaste : CommandObjectParsed(interpreter, "renderscript module probe", 3299285101Semaste "Initiates a Probe of all loaded modules for kernels and other renderscript objects.", 3300285101Semaste "renderscript module probe", 3301285101Semaste eCommandRequiresTarget | eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3302285101Semaste { 3303285101Semaste } 3304285101Semaste 3305296417Sdim ~CommandObjectRenderScriptRuntimeModuleProbe() override = default; 3306285101Semaste 3307285101Semaste bool 3308296417Sdim DoExecute(Args &command, CommandReturnObject &result) override 3309285101Semaste { 3310285101Semaste const size_t argc = command.GetArgumentCount(); 3311285101Semaste if (argc == 0) 3312285101Semaste { 3313285101Semaste Target *target = m_exe_ctx.GetTargetPtr(); 3314285101Semaste RenderScriptRuntime *runtime = 3315285101Semaste (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3316285101Semaste auto module_list = target->GetImages(); 3317285101Semaste bool new_rs_details = runtime->ProbeModules(module_list); 3318285101Semaste if (new_rs_details) 3319285101Semaste { 3320285101Semaste result.AppendMessage("New renderscript modules added to runtime model."); 3321285101Semaste } 3322285101Semaste result.SetStatus(eReturnStatusSuccessFinishResult); 3323285101Semaste return true; 3324285101Semaste } 3325285101Semaste 3326285101Semaste result.AppendErrorWithFormat("'%s' takes no arguments", m_cmd_name.c_str()); 3327285101Semaste result.SetStatus(eReturnStatusFailed); 3328285101Semaste return false; 3329285101Semaste } 3330285101Semaste}; 3331285101Semaste 3332285101Semasteclass CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed 3333285101Semaste{ 3334296417Sdimpublic: 3335285101Semaste CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter) 3336285101Semaste : CommandObjectParsed(interpreter, "renderscript module dump", 3337285101Semaste "Dumps renderscript specific information for all modules.", "renderscript module dump", 3338285101Semaste eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3339285101Semaste { 3340285101Semaste } 3341285101Semaste 3342296417Sdim ~CommandObjectRenderScriptRuntimeModuleDump() override = default; 3343285101Semaste 3344285101Semaste bool 3345296417Sdim DoExecute(Args &command, CommandReturnObject &result) override 3346285101Semaste { 3347285101Semaste RenderScriptRuntime *runtime = 3348285101Semaste (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3349285101Semaste runtime->DumpModules(result.GetOutputStream()); 3350285101Semaste result.SetStatus(eReturnStatusSuccessFinishResult); 3351285101Semaste return true; 3352285101Semaste } 3353285101Semaste}; 3354285101Semaste 3355285101Semasteclass CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword 3356285101Semaste{ 3357296417Sdimpublic: 3358285101Semaste CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter) 3359285101Semaste : CommandObjectMultiword(interpreter, "renderscript module", "Commands that deal with renderscript modules.", 3360285101Semaste NULL) 3361285101Semaste { 3362285101Semaste LoadSubCommand("probe", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleProbe(interpreter))); 3363285101Semaste LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump(interpreter))); 3364285101Semaste } 3365285101Semaste 3366296417Sdim ~CommandObjectRenderScriptRuntimeModule() override = default; 3367285101Semaste}; 3368285101Semaste 3369285101Semasteclass CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed 3370285101Semaste{ 3371296417Sdimpublic: 3372285101Semaste CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter) 3373285101Semaste : CommandObjectParsed(interpreter, "renderscript kernel list", 3374285101Semaste "Lists renderscript kernel names and associated script resources.", "renderscript kernel list", 3375285101Semaste eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3376285101Semaste { 3377285101Semaste } 3378285101Semaste 3379296417Sdim ~CommandObjectRenderScriptRuntimeKernelList() override = default; 3380285101Semaste 3381285101Semaste bool 3382296417Sdim DoExecute(Args &command, CommandReturnObject &result) override 3383285101Semaste { 3384285101Semaste RenderScriptRuntime *runtime = 3385285101Semaste (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3386285101Semaste runtime->DumpKernels(result.GetOutputStream()); 3387285101Semaste result.SetStatus(eReturnStatusSuccessFinishResult); 3388285101Semaste return true; 3389285101Semaste } 3390285101Semaste}; 3391285101Semaste 3392296417Sdimclass CommandObjectRenderScriptRuntimeKernelBreakpointSet : public CommandObjectParsed 3393285101Semaste{ 3394296417Sdimpublic: 3395296417Sdim CommandObjectRenderScriptRuntimeKernelBreakpointSet(CommandInterpreter &interpreter) 3396296417Sdim : CommandObjectParsed(interpreter, "renderscript kernel breakpoint set", 3397296417Sdim "Sets a breakpoint on a renderscript kernel.", "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]", 3398296417Sdim eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), m_options(interpreter) 3399285101Semaste { 3400285101Semaste } 3401285101Semaste 3402296417Sdim ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default; 3403285101Semaste 3404296417Sdim Options* 3405296417Sdim GetOptions() override 3406285101Semaste { 3407296417Sdim return &m_options; 3408296417Sdim } 3409296417Sdim 3410296417Sdim class CommandOptions : public Options 3411296417Sdim { 3412296417Sdim public: 3413296417Sdim CommandOptions(CommandInterpreter &interpreter) : Options(interpreter) 3414285101Semaste { 3415296417Sdim } 3416285101Semaste 3417296417Sdim ~CommandOptions() override = default; 3418296417Sdim 3419296417Sdim Error 3420296417Sdim SetOptionValue(uint32_t option_idx, const char *option_arg) override 3421296417Sdim { 3422285101Semaste Error error; 3423296417Sdim const int short_option = m_getopt_table[option_idx].val; 3424285101Semaste 3425296417Sdim switch (short_option) 3426285101Semaste { 3427296417Sdim case 'c': 3428296417Sdim if (!ParseCoordinate(option_arg)) 3429296417Sdim error.SetErrorStringWithFormat("Couldn't parse coordinate '%s', should be in format 'x,y,z'.", option_arg); 3430296417Sdim break; 3431296417Sdim default: 3432296417Sdim error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 3433296417Sdim break; 3434285101Semaste } 3435296417Sdim return error; 3436296417Sdim } 3437296417Sdim 3438296417Sdim // -c takes an argument of the form 'num[,num][,num]'. 3439296417Sdim // Where 'id_cstr' is this argument with the whitespace trimmed. 3440296417Sdim // Missing coordinates are defaulted to zero. 3441296417Sdim bool 3442296417Sdim ParseCoordinate(const char* id_cstr) 3443296417Sdim { 3444296417Sdim RegularExpression regex; 3445296417Sdim RegularExpression::Match regex_match(3); 3446296417Sdim 3447296417Sdim bool matched = false; 3448296417Sdim if(regex.Compile("^([0-9]+),([0-9]+),([0-9]+)$") && regex.Execute(id_cstr, ®ex_match)) 3449296417Sdim matched = true; 3450296417Sdim else if(regex.Compile("^([0-9]+),([0-9]+)$") && regex.Execute(id_cstr, ®ex_match)) 3451296417Sdim matched = true; 3452296417Sdim else if(regex.Compile("^([0-9]+)$") && regex.Execute(id_cstr, ®ex_match)) 3453296417Sdim matched = true; 3454296417Sdim for(uint32_t i = 0; i < 3; i++) 3455296417Sdim { 3456296417Sdim std::string group; 3457296417Sdim if(regex_match.GetMatchAtIndex(id_cstr, i + 1, group)) 3458296417Sdim m_coord[i] = (uint32_t)strtoul(group.c_str(), NULL, 0); 3459296417Sdim else 3460296417Sdim m_coord[i] = 0; 3461296417Sdim } 3462296417Sdim return matched; 3463296417Sdim } 3464296417Sdim 3465296417Sdim void 3466296417Sdim OptionParsingStarting() override 3467296417Sdim { 3468296417Sdim // -1 means the -c option hasn't been set 3469296417Sdim m_coord[0] = -1; 3470296417Sdim m_coord[1] = -1; 3471296417Sdim m_coord[2] = -1; 3472296417Sdim } 3473296417Sdim 3474296417Sdim const OptionDefinition* 3475296417Sdim GetDefinitions() override 3476296417Sdim { 3477296417Sdim return g_option_table; 3478296417Sdim } 3479296417Sdim 3480296417Sdim static OptionDefinition g_option_table[]; 3481296417Sdim std::array<int,3> m_coord; 3482296417Sdim }; 3483296417Sdim 3484296417Sdim bool 3485296417Sdim DoExecute(Args &command, CommandReturnObject &result) override 3486296417Sdim { 3487296417Sdim const size_t argc = command.GetArgumentCount(); 3488296417Sdim if (argc < 1) 3489296417Sdim { 3490296417Sdim result.AppendErrorWithFormat("'%s' takes 1 argument of kernel name, and an optional coordinate.", m_cmd_name.c_str()); 3491285101Semaste result.SetStatus(eReturnStatusFailed); 3492285101Semaste return false; 3493285101Semaste } 3494285101Semaste 3495296417Sdim RenderScriptRuntime *runtime = 3496296417Sdim (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3497296417Sdim 3498296417Sdim Error error; 3499296417Sdim runtime->PlaceBreakpointOnKernel(result.GetOutputStream(), command.GetArgumentAtIndex(0), m_options.m_coord, 3500296417Sdim error, m_exe_ctx.GetTargetSP()); 3501296417Sdim 3502296417Sdim if (error.Success()) 3503296417Sdim { 3504296417Sdim result.AppendMessage("Breakpoint(s) created"); 3505296417Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 3506296417Sdim return true; 3507296417Sdim } 3508285101Semaste result.SetStatus(eReturnStatusFailed); 3509296417Sdim result.AppendErrorWithFormat("Error: %s", error.AsCString()); 3510285101Semaste return false; 3511285101Semaste } 3512296417Sdim 3513296417Sdimprivate: 3514296417Sdim CommandOptions m_options; 3515285101Semaste}; 3516285101Semaste 3517296417SdimOptionDefinition 3518296417SdimCommandObjectRenderScriptRuntimeKernelBreakpointSet::CommandOptions::g_option_table[] = 3519296417Sdim{ 3520296417Sdim { LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeValue, 3521296417Sdim "Set a breakpoint on a single invocation of the kernel with specified coordinate.\n" 3522296417Sdim "Coordinate takes the form 'x[,y][,z] where x,y,z are positive integers representing kernel dimensions. " 3523296417Sdim "Any unset dimensions will be defaulted to zero."}, 3524296417Sdim { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 3525296417Sdim}; 3526296417Sdim 3527296417Sdimclass CommandObjectRenderScriptRuntimeKernelBreakpointAll : public CommandObjectParsed 3528296417Sdim{ 3529296417Sdimpublic: 3530296417Sdim CommandObjectRenderScriptRuntimeKernelBreakpointAll(CommandInterpreter &interpreter) 3531296417Sdim : CommandObjectParsed(interpreter, "renderscript kernel breakpoint all", 3532296417Sdim "Automatically sets a breakpoint on all renderscript kernels that are or will be loaded.\n" 3533296417Sdim "Disabling option means breakpoints will no longer be set on any kernels loaded in the future, " 3534296417Sdim "but does not remove currently set breakpoints.", 3535296417Sdim "renderscript kernel breakpoint all <enable/disable>", 3536296417Sdim eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) 3537296417Sdim { 3538296417Sdim } 3539296417Sdim 3540296417Sdim ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default; 3541296417Sdim 3542296417Sdim bool 3543296417Sdim DoExecute(Args &command, CommandReturnObject &result) override 3544296417Sdim { 3545296417Sdim const size_t argc = command.GetArgumentCount(); 3546296417Sdim if (argc != 1) 3547296417Sdim { 3548296417Sdim result.AppendErrorWithFormat("'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str()); 3549296417Sdim result.SetStatus(eReturnStatusFailed); 3550296417Sdim return false; 3551296417Sdim } 3552296417Sdim 3553296417Sdim RenderScriptRuntime *runtime = 3554296417Sdim static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 3555296417Sdim 3556296417Sdim bool do_break = false; 3557296417Sdim const char* argument = command.GetArgumentAtIndex(0); 3558296417Sdim if (strcmp(argument, "enable") == 0) 3559296417Sdim { 3560296417Sdim do_break = true; 3561296417Sdim result.AppendMessage("Breakpoints will be set on all kernels."); 3562296417Sdim } 3563296417Sdim else if (strcmp(argument, "disable") == 0) 3564296417Sdim { 3565296417Sdim do_break = false; 3566296417Sdim result.AppendMessage("Breakpoints will not be set on any new kernels."); 3567296417Sdim } 3568296417Sdim else 3569296417Sdim { 3570296417Sdim result.AppendErrorWithFormat("Argument must be either 'enable' or 'disable'"); 3571296417Sdim result.SetStatus(eReturnStatusFailed); 3572296417Sdim return false; 3573296417Sdim } 3574296417Sdim 3575296417Sdim runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP()); 3576296417Sdim 3577296417Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 3578296417Sdim return true; 3579296417Sdim } 3580296417Sdim}; 3581296417Sdim 3582296417Sdimclass CommandObjectRenderScriptRuntimeKernelBreakpoint : public CommandObjectMultiword 3583296417Sdim{ 3584296417Sdimpublic: 3585296417Sdim CommandObjectRenderScriptRuntimeKernelBreakpoint(CommandInterpreter &interpreter) 3586296417Sdim : CommandObjectMultiword(interpreter, "renderscript kernel", "Commands that generate breakpoints on renderscript kernels.", 3587296417Sdim nullptr) 3588296417Sdim { 3589296417Sdim LoadSubCommand("set", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet(interpreter))); 3590296417Sdim LoadSubCommand("all", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll(interpreter))); 3591296417Sdim } 3592296417Sdim 3593296417Sdim ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default; 3594296417Sdim}; 3595296417Sdim 3596285101Semasteclass CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword 3597285101Semaste{ 3598296417Sdimpublic: 3599285101Semaste CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter) 3600285101Semaste : CommandObjectMultiword(interpreter, "renderscript kernel", "Commands that deal with renderscript kernels.", 3601285101Semaste NULL) 3602285101Semaste { 3603285101Semaste LoadSubCommand("list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList(interpreter))); 3604285101Semaste LoadSubCommand("breakpoint", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter))); 3605285101Semaste } 3606285101Semaste 3607296417Sdim ~CommandObjectRenderScriptRuntimeKernel() override = default; 3608285101Semaste}; 3609285101Semaste 3610285101Semasteclass CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed 3611285101Semaste{ 3612296417Sdimpublic: 3613285101Semaste CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter) 3614285101Semaste : CommandObjectParsed(interpreter, "renderscript context dump", 3615285101Semaste "Dumps renderscript context information.", "renderscript context dump", 3616285101Semaste eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3617285101Semaste { 3618285101Semaste } 3619285101Semaste 3620296417Sdim ~CommandObjectRenderScriptRuntimeContextDump() override = default; 3621285101Semaste 3622285101Semaste bool 3623296417Sdim DoExecute(Args &command, CommandReturnObject &result) override 3624285101Semaste { 3625285101Semaste RenderScriptRuntime *runtime = 3626285101Semaste (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3627285101Semaste runtime->DumpContexts(result.GetOutputStream()); 3628285101Semaste result.SetStatus(eReturnStatusSuccessFinishResult); 3629285101Semaste return true; 3630285101Semaste } 3631285101Semaste}; 3632285101Semaste 3633285101Semasteclass CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword 3634285101Semaste{ 3635296417Sdimpublic: 3636285101Semaste CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter) 3637285101Semaste : CommandObjectMultiword(interpreter, "renderscript context", "Commands that deal with renderscript contexts.", 3638285101Semaste NULL) 3639285101Semaste { 3640285101Semaste LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump(interpreter))); 3641285101Semaste } 3642285101Semaste 3643296417Sdim ~CommandObjectRenderScriptRuntimeContext() override = default; 3644285101Semaste}; 3645285101Semaste 3646296417Sdimclass CommandObjectRenderScriptRuntimeAllocationDump : public CommandObjectParsed 3647296417Sdim{ 3648296417Sdimpublic: 3649296417Sdim CommandObjectRenderScriptRuntimeAllocationDump(CommandInterpreter &interpreter) 3650296417Sdim : CommandObjectParsed(interpreter, "renderscript allocation dump", 3651296417Sdim "Displays the contents of a particular allocation", "renderscript allocation dump <ID>", 3652296417Sdim eCommandRequiresProcess | eCommandProcessMustBeLaunched), m_options(interpreter) 3653296417Sdim { 3654296417Sdim } 3655296417Sdim 3656296417Sdim ~CommandObjectRenderScriptRuntimeAllocationDump() override = default; 3657296417Sdim 3658296417Sdim Options* 3659296417Sdim GetOptions() override 3660296417Sdim { 3661296417Sdim return &m_options; 3662296417Sdim } 3663296417Sdim 3664296417Sdim class CommandOptions : public Options 3665296417Sdim { 3666296417Sdim public: 3667296417Sdim CommandOptions(CommandInterpreter &interpreter) : Options(interpreter) 3668296417Sdim { 3669296417Sdim } 3670296417Sdim 3671296417Sdim ~CommandOptions() override = default; 3672296417Sdim 3673296417Sdim Error 3674296417Sdim SetOptionValue(uint32_t option_idx, const char *option_arg) override 3675296417Sdim { 3676296417Sdim Error error; 3677296417Sdim const int short_option = m_getopt_table[option_idx].val; 3678296417Sdim 3679296417Sdim switch (short_option) 3680296417Sdim { 3681296417Sdim case 'f': 3682296417Sdim m_outfile.SetFile(option_arg, true); 3683296417Sdim if (m_outfile.Exists()) 3684296417Sdim { 3685296417Sdim m_outfile.Clear(); 3686296417Sdim error.SetErrorStringWithFormat("file already exists: '%s'", option_arg); 3687296417Sdim } 3688296417Sdim break; 3689296417Sdim default: 3690296417Sdim error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 3691296417Sdim break; 3692296417Sdim } 3693296417Sdim return error; 3694296417Sdim } 3695296417Sdim 3696296417Sdim void 3697296417Sdim OptionParsingStarting() override 3698296417Sdim { 3699296417Sdim m_outfile.Clear(); 3700296417Sdim } 3701296417Sdim 3702296417Sdim const OptionDefinition* 3703296417Sdim GetDefinitions() override 3704296417Sdim { 3705296417Sdim return g_option_table; 3706296417Sdim } 3707296417Sdim 3708296417Sdim static OptionDefinition g_option_table[]; 3709296417Sdim FileSpec m_outfile; 3710296417Sdim }; 3711296417Sdim 3712296417Sdim bool 3713296417Sdim DoExecute(Args &command, CommandReturnObject &result) override 3714296417Sdim { 3715296417Sdim const size_t argc = command.GetArgumentCount(); 3716296417Sdim if (argc < 1) 3717296417Sdim { 3718296417Sdim result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. As well as an optional -f argument", 3719296417Sdim m_cmd_name.c_str()); 3720296417Sdim result.SetStatus(eReturnStatusFailed); 3721296417Sdim return false; 3722296417Sdim } 3723296417Sdim 3724296417Sdim RenderScriptRuntime *runtime = 3725296417Sdim static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 3726296417Sdim 3727296417Sdim const char* id_cstr = command.GetArgumentAtIndex(0); 3728296417Sdim bool convert_complete = false; 3729296417Sdim const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 3730296417Sdim if (!convert_complete) 3731296417Sdim { 3732296417Sdim result.AppendErrorWithFormat("invalid allocation id argument '%s'", id_cstr); 3733296417Sdim result.SetStatus(eReturnStatusFailed); 3734296417Sdim return false; 3735296417Sdim } 3736296417Sdim 3737296417Sdim Stream* output_strm = nullptr; 3738296417Sdim StreamFile outfile_stream; 3739296417Sdim const FileSpec &outfile_spec = m_options.m_outfile; // Dump allocation to file instead 3740296417Sdim if (outfile_spec) 3741296417Sdim { 3742296417Sdim // Open output file 3743296417Sdim char path[256]; 3744296417Sdim outfile_spec.GetPath(path, sizeof(path)); 3745296417Sdim if (outfile_stream.GetFile().Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate).Success()) 3746296417Sdim { 3747296417Sdim output_strm = &outfile_stream; 3748296417Sdim result.GetOutputStream().Printf("Results written to '%s'", path); 3749296417Sdim result.GetOutputStream().EOL(); 3750296417Sdim } 3751296417Sdim else 3752296417Sdim { 3753296417Sdim result.AppendErrorWithFormat("Couldn't open file '%s'", path); 3754296417Sdim result.SetStatus(eReturnStatusFailed); 3755296417Sdim return false; 3756296417Sdim } 3757296417Sdim } 3758296417Sdim else 3759296417Sdim output_strm = &result.GetOutputStream(); 3760296417Sdim 3761296417Sdim assert(output_strm != nullptr); 3762296417Sdim bool success = runtime->DumpAllocation(*output_strm, m_exe_ctx.GetFramePtr(), id); 3763296417Sdim 3764296417Sdim if (success) 3765296417Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 3766296417Sdim else 3767296417Sdim result.SetStatus(eReturnStatusFailed); 3768296417Sdim 3769296417Sdim return true; 3770296417Sdim } 3771296417Sdim 3772296417Sdimprivate: 3773296417Sdim CommandOptions m_options; 3774296417Sdim}; 3775296417Sdim 3776296417SdimOptionDefinition 3777296417SdimCommandObjectRenderScriptRuntimeAllocationDump::CommandOptions::g_option_table[] = 3778296417Sdim{ 3779296417Sdim { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, 3780296417Sdim "Print results to specified file instead of command line."}, 3781296417Sdim { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 3782296417Sdim}; 3783296417Sdim 3784296417Sdimclass CommandObjectRenderScriptRuntimeAllocationList : public CommandObjectParsed 3785296417Sdim{ 3786296417Sdimpublic: 3787296417Sdim CommandObjectRenderScriptRuntimeAllocationList(CommandInterpreter &interpreter) 3788296417Sdim : CommandObjectParsed(interpreter, "renderscript allocation list", 3789296417Sdim "List renderscript allocations and their information.", "renderscript allocation list", 3790296417Sdim eCommandRequiresProcess | eCommandProcessMustBeLaunched), m_options(interpreter) 3791296417Sdim { 3792296417Sdim } 3793296417Sdim 3794296417Sdim ~CommandObjectRenderScriptRuntimeAllocationList() override = default; 3795296417Sdim 3796296417Sdim Options* 3797296417Sdim GetOptions() override 3798296417Sdim { 3799296417Sdim return &m_options; 3800296417Sdim } 3801296417Sdim 3802296417Sdim class CommandOptions : public Options 3803296417Sdim { 3804296417Sdim public: 3805296417Sdim CommandOptions(CommandInterpreter &interpreter) : Options(interpreter), m_refresh(false) 3806296417Sdim { 3807296417Sdim } 3808296417Sdim 3809296417Sdim ~CommandOptions() override = default; 3810296417Sdim 3811296417Sdim Error 3812296417Sdim SetOptionValue(uint32_t option_idx, const char *option_arg) override 3813296417Sdim { 3814296417Sdim Error error; 3815296417Sdim const int short_option = m_getopt_table[option_idx].val; 3816296417Sdim 3817296417Sdim switch (short_option) 3818296417Sdim { 3819296417Sdim case 'r': 3820296417Sdim m_refresh = true; 3821296417Sdim break; 3822296417Sdim default: 3823296417Sdim error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); 3824296417Sdim break; 3825296417Sdim } 3826296417Sdim return error; 3827296417Sdim } 3828296417Sdim 3829296417Sdim void 3830296417Sdim OptionParsingStarting() override 3831296417Sdim { 3832296417Sdim m_refresh = false; 3833296417Sdim } 3834296417Sdim 3835296417Sdim const OptionDefinition* 3836296417Sdim GetDefinitions() override 3837296417Sdim { 3838296417Sdim return g_option_table; 3839296417Sdim } 3840296417Sdim 3841296417Sdim static OptionDefinition g_option_table[]; 3842296417Sdim bool m_refresh; 3843296417Sdim }; 3844296417Sdim 3845296417Sdim bool 3846296417Sdim DoExecute(Args &command, CommandReturnObject &result) override 3847296417Sdim { 3848296417Sdim RenderScriptRuntime *runtime = 3849296417Sdim static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 3850296417Sdim runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(), m_options.m_refresh); 3851296417Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 3852296417Sdim return true; 3853296417Sdim } 3854296417Sdim 3855296417Sdimprivate: 3856296417Sdim CommandOptions m_options; 3857296417Sdim}; 3858296417Sdim 3859296417SdimOptionDefinition 3860296417SdimCommandObjectRenderScriptRuntimeAllocationList::CommandOptions::g_option_table[] = 3861296417Sdim{ 3862296417Sdim { LLDB_OPT_SET_1, false, "refresh", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 3863296417Sdim "Recompute allocation details."}, 3864296417Sdim { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 3865296417Sdim}; 3866296417Sdim 3867296417Sdimclass CommandObjectRenderScriptRuntimeAllocationLoad : public CommandObjectParsed 3868296417Sdim{ 3869296417Sdimpublic: 3870296417Sdim CommandObjectRenderScriptRuntimeAllocationLoad(CommandInterpreter &interpreter) 3871296417Sdim : CommandObjectParsed(interpreter, "renderscript allocation load", 3872296417Sdim "Loads renderscript allocation contents from a file.", "renderscript allocation load <ID> <filename>", 3873296417Sdim eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3874296417Sdim { 3875296417Sdim } 3876296417Sdim 3877296417Sdim ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default; 3878296417Sdim 3879296417Sdim bool 3880296417Sdim DoExecute(Args &command, CommandReturnObject &result) override 3881296417Sdim { 3882296417Sdim const size_t argc = command.GetArgumentCount(); 3883296417Sdim if (argc != 2) 3884296417Sdim { 3885296417Sdim result.AppendErrorWithFormat("'%s' takes 2 arguments, an allocation ID and filename to read from.", m_cmd_name.c_str()); 3886296417Sdim result.SetStatus(eReturnStatusFailed); 3887296417Sdim return false; 3888296417Sdim } 3889296417Sdim 3890296417Sdim RenderScriptRuntime *runtime = 3891296417Sdim static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 3892296417Sdim 3893296417Sdim const char* id_cstr = command.GetArgumentAtIndex(0); 3894296417Sdim bool convert_complete = false; 3895296417Sdim const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 3896296417Sdim if (!convert_complete) 3897296417Sdim { 3898296417Sdim result.AppendErrorWithFormat ("invalid allocation id argument '%s'", id_cstr); 3899296417Sdim result.SetStatus (eReturnStatusFailed); 3900296417Sdim return false; 3901296417Sdim } 3902296417Sdim 3903296417Sdim const char* filename = command.GetArgumentAtIndex(1); 3904296417Sdim bool success = runtime->LoadAllocation(result.GetOutputStream(), id, filename, m_exe_ctx.GetFramePtr()); 3905296417Sdim 3906296417Sdim if (success) 3907296417Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 3908296417Sdim else 3909296417Sdim result.SetStatus(eReturnStatusFailed); 3910296417Sdim 3911296417Sdim return true; 3912296417Sdim } 3913296417Sdim}; 3914296417Sdim 3915296417Sdimclass CommandObjectRenderScriptRuntimeAllocationSave : public CommandObjectParsed 3916296417Sdim{ 3917296417Sdimpublic: 3918296417Sdim CommandObjectRenderScriptRuntimeAllocationSave(CommandInterpreter &interpreter) 3919296417Sdim : CommandObjectParsed(interpreter, "renderscript allocation save", 3920296417Sdim "Write renderscript allocation contents to a file.", "renderscript allocation save <ID> <filename>", 3921296417Sdim eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3922296417Sdim { 3923296417Sdim } 3924296417Sdim 3925296417Sdim ~CommandObjectRenderScriptRuntimeAllocationSave() override = default; 3926296417Sdim 3927296417Sdim bool 3928296417Sdim DoExecute(Args &command, CommandReturnObject &result) override 3929296417Sdim { 3930296417Sdim const size_t argc = command.GetArgumentCount(); 3931296417Sdim if (argc != 2) 3932296417Sdim { 3933296417Sdim result.AppendErrorWithFormat("'%s' takes 2 arguments, an allocation ID and filename to read from.", m_cmd_name.c_str()); 3934296417Sdim result.SetStatus(eReturnStatusFailed); 3935296417Sdim return false; 3936296417Sdim } 3937296417Sdim 3938296417Sdim RenderScriptRuntime *runtime = 3939296417Sdim static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); 3940296417Sdim 3941296417Sdim const char* id_cstr = command.GetArgumentAtIndex(0); 3942296417Sdim bool convert_complete = false; 3943296417Sdim const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); 3944296417Sdim if (!convert_complete) 3945296417Sdim { 3946296417Sdim result.AppendErrorWithFormat ("invalid allocation id argument '%s'", id_cstr); 3947296417Sdim result.SetStatus (eReturnStatusFailed); 3948296417Sdim return false; 3949296417Sdim } 3950296417Sdim 3951296417Sdim const char* filename = command.GetArgumentAtIndex(1); 3952296417Sdim bool success = runtime->SaveAllocation(result.GetOutputStream(), id, filename, m_exe_ctx.GetFramePtr()); 3953296417Sdim 3954296417Sdim if (success) 3955296417Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 3956296417Sdim else 3957296417Sdim result.SetStatus(eReturnStatusFailed); 3958296417Sdim 3959296417Sdim return true; 3960296417Sdim } 3961296417Sdim}; 3962296417Sdim 3963296417Sdimclass CommandObjectRenderScriptRuntimeAllocation : public CommandObjectMultiword 3964296417Sdim{ 3965296417Sdimpublic: 3966296417Sdim CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter) 3967296417Sdim : CommandObjectMultiword(interpreter, "renderscript allocation", "Commands that deal with renderscript allocations.", 3968296417Sdim NULL) 3969296417Sdim { 3970296417Sdim LoadSubCommand("list", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationList(interpreter))); 3971296417Sdim LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationDump(interpreter))); 3972296417Sdim LoadSubCommand("save", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationSave(interpreter))); 3973296417Sdim LoadSubCommand("load", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter))); 3974296417Sdim } 3975296417Sdim 3976296417Sdim ~CommandObjectRenderScriptRuntimeAllocation() override = default; 3977296417Sdim}; 3978296417Sdim 3979285101Semasteclass CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed 3980285101Semaste{ 3981296417Sdimpublic: 3982285101Semaste CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter) 3983285101Semaste : CommandObjectParsed(interpreter, "renderscript status", 3984285101Semaste "Displays current renderscript runtime status.", "renderscript status", 3985285101Semaste eCommandRequiresProcess | eCommandProcessMustBeLaunched) 3986285101Semaste { 3987285101Semaste } 3988285101Semaste 3989296417Sdim ~CommandObjectRenderScriptRuntimeStatus() override = default; 3990285101Semaste 3991285101Semaste bool 3992296417Sdim DoExecute(Args &command, CommandReturnObject &result) override 3993285101Semaste { 3994285101Semaste RenderScriptRuntime *runtime = 3995285101Semaste (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); 3996285101Semaste runtime->Status(result.GetOutputStream()); 3997285101Semaste result.SetStatus(eReturnStatusSuccessFinishResult); 3998285101Semaste return true; 3999285101Semaste } 4000285101Semaste}; 4001285101Semaste 4002285101Semasteclass CommandObjectRenderScriptRuntime : public CommandObjectMultiword 4003285101Semaste{ 4004296417Sdimpublic: 4005285101Semaste CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter) 4006285101Semaste : CommandObjectMultiword(interpreter, "renderscript", "A set of commands for operating on renderscript.", 4007285101Semaste "renderscript <subcommand> [<subcommand-options>]") 4008285101Semaste { 4009285101Semaste LoadSubCommand("module", CommandObjectSP(new CommandObjectRenderScriptRuntimeModule(interpreter))); 4010285101Semaste LoadSubCommand("status", CommandObjectSP(new CommandObjectRenderScriptRuntimeStatus(interpreter))); 4011285101Semaste LoadSubCommand("kernel", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernel(interpreter))); 4012285101Semaste LoadSubCommand("context", CommandObjectSP(new CommandObjectRenderScriptRuntimeContext(interpreter))); 4013296417Sdim LoadSubCommand("allocation", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocation(interpreter))); 4014285101Semaste } 4015285101Semaste 4016296417Sdim ~CommandObjectRenderScriptRuntime() override = default; 4017285101Semaste}; 4018285101Semaste 4019285101Semastevoid 4020285101SemasteRenderScriptRuntime::Initiate() 4021285101Semaste{ 4022285101Semaste assert(!m_initiated); 4023285101Semaste} 4024285101Semaste 4025285101SemasteRenderScriptRuntime::RenderScriptRuntime(Process *process) 4026296417Sdim : lldb_private::CPPLanguageRuntime(process), m_initiated(false), m_debuggerPresentFlagged(false), 4027296417Sdim m_breakAllKernels(false) 4028285101Semaste{ 4029285101Semaste ModulesDidLoad(process->GetTarget().GetImages()); 4030285101Semaste} 4031285101Semaste 4032285101Semastelldb::CommandObjectSP 4033285101SemasteRenderScriptRuntime::GetCommandObject(lldb_private::CommandInterpreter& interpreter) 4034285101Semaste{ 4035285101Semaste static CommandObjectSP command_object; 4036285101Semaste if(!command_object) 4037285101Semaste { 4038285101Semaste command_object.reset(new CommandObjectRenderScriptRuntime(interpreter)); 4039285101Semaste } 4040285101Semaste return command_object; 4041285101Semaste} 4042285101Semaste 4043296417SdimRenderScriptRuntime::~RenderScriptRuntime() = default; 4044