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, &regex_match))
3449296417Sdim                matched = true;
3450296417Sdim            else if(regex.Compile("^([0-9]+),([0-9]+)$") && regex.Execute(id_cstr, &regex_match))
3451296417Sdim                matched = true;
3452296417Sdim            else if(regex.Compile("^([0-9]+)$") && regex.Execute(id_cstr, &regex_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