blob: a4d24445236b1a7f78996aca75bf264ef31a571f [file] [log] [blame]
Colin Riley5ec532a2015-04-09 16:49:25 +00001//===-- RenderScriptRuntime.cpp ---------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Eugene Zelenko222b9372015-10-27 00:45:06 +000010// C Includes
11// C++ Includes
12// Other libraries and framework includes
13// Project includes
Colin Riley5ec532a2015-04-09 16:49:25 +000014#include "RenderScriptRuntime.h"
15
16#include "lldb/Core/ConstString.h"
17#include "lldb/Core/Debugger.h"
18#include "lldb/Core/Error.h"
19#include "lldb/Core/Log.h"
20#include "lldb/Core/PluginManager.h"
Ewan Crawford8b244e22015-11-30 10:29:49 +000021#include "lldb/Core/ValueObjectVariable.h"
Ewan Crawford018f5a7e2015-10-26 14:04:37 +000022#include "lldb/Core/RegularExpression.h"
Ewan Crawford8b244e22015-11-30 10:29:49 +000023#include "lldb/DataFormatters/DumpValueObjectOptions.h"
Ewan Crawforda0f08672015-10-16 08:28:47 +000024#include "lldb/Host/StringConvert.h"
Colin Riley5ec532a2015-04-09 16:49:25 +000025#include "lldb/Symbol/Symbol.h"
Colin Riley4640cde2015-06-01 18:23:41 +000026#include "lldb/Symbol/Type.h"
Colin Riley5ec532a2015-04-09 16:49:25 +000027#include "lldb/Target/Process.h"
28#include "lldb/Target/Target.h"
Ewan Crawford018f5a7e2015-10-26 14:04:37 +000029#include "lldb/Target/Thread.h"
Colin Riley5ec532a2015-04-09 16:49:25 +000030#include "lldb/Interpreter/Args.h"
31#include "lldb/Interpreter/Options.h"
32#include "lldb/Interpreter/CommandInterpreter.h"
33#include "lldb/Interpreter/CommandReturnObject.h"
34#include "lldb/Interpreter/CommandObjectMultiword.h"
Colin Riley4640cde2015-06-01 18:23:41 +000035#include "lldb/Breakpoint/StoppointCallbackContext.h"
36#include "lldb/Target/RegisterContext.h"
Ewan Crawford15f2bd92015-10-06 08:42:32 +000037#include "lldb/Expression/UserExpression.h"
Colin Riley4640cde2015-06-01 18:23:41 +000038#include "lldb/Symbol/VariableList.h"
Colin Riley5ec532a2015-04-09 16:49:25 +000039
40using namespace lldb;
41using namespace lldb_private;
Ewan Crawford98156582015-09-04 08:56:52 +000042using namespace lldb_renderscript;
Colin Riley5ec532a2015-04-09 16:49:25 +000043
Ewan Crawford78f339d2015-09-21 10:53:18 +000044namespace {
45
46// The empirical_type adds a basic level of validation to arbitrary data
47// allowing us to track if data has been discovered and stored or not.
48// An empirical_type will be marked as valid only if it has been explicitly assigned to.
49template <typename type_t>
50class empirical_type
51{
Eugene Zelenko222b9372015-10-27 00:45:06 +000052public:
Ewan Crawford78f339d2015-09-21 10:53:18 +000053 // Ctor. Contents is invalid when constructed.
54 empirical_type()
55 : valid(false)
56 {}
57
58 // Return true and copy contents to out if valid, else return false.
59 bool get(type_t& out) const
60 {
61 if (valid)
62 out = data;
63 return valid;
64 }
65
66 // Return a pointer to the contents or nullptr if it was not valid.
67 const type_t* get() const
68 {
69 return valid ? &data : nullptr;
70 }
71
72 // Assign data explicitly.
73 void set(const type_t in)
74 {
75 data = in;
76 valid = true;
77 }
78
79 // Mark contents as invalid.
80 void invalidate()
81 {
82 valid = false;
83 }
84
85 // Returns true if this type contains valid data.
86 bool isValid() const
87 {
88 return valid;
89 }
90
91 // Assignment operator.
92 empirical_type<type_t>& operator = (const type_t in)
93 {
94 set(in);
95 return *this;
96 }
97
98 // Dereference operator returns contents.
99 // Warning: Will assert if not valid so use only when you know data is valid.
100 const type_t& operator * () const
101 {
102 assert(valid);
103 return data;
104 }
105
Eugene Zelenko222b9372015-10-27 00:45:06 +0000106protected:
Ewan Crawford78f339d2015-09-21 10:53:18 +0000107 bool valid;
108 type_t data;
109};
110
Eugene Zelenko222b9372015-10-27 00:45:06 +0000111} // anonymous namespace
Ewan Crawford78f339d2015-09-21 10:53:18 +0000112
113// The ScriptDetails class collects data associated with a single script instance.
114struct RenderScriptRuntime::ScriptDetails
115{
Eugene Zelenko222b9372015-10-27 00:45:06 +0000116 ~ScriptDetails() = default;
Ewan Crawford78f339d2015-09-21 10:53:18 +0000117
118 enum ScriptType
119 {
120 eScript,
121 eScriptC
122 };
123
124 // The derived type of the script.
125 empirical_type<ScriptType> type;
126 // The name of the original source file.
127 empirical_type<std::string> resName;
128 // Path to script .so file on the device.
129 empirical_type<std::string> scriptDyLib;
130 // Directory where kernel objects are cached on device.
131 empirical_type<std::string> cacheDir;
132 // Pointer to the context which owns this script.
133 empirical_type<lldb::addr_t> context;
134 // Pointer to the script object itself.
135 empirical_type<lldb::addr_t> script;
136};
137
Ewan Crawford8b244e22015-11-30 10:29:49 +0000138// This Element class represents the Element object in RS,
139// defining the type associated with an Allocation.
140struct RenderScriptRuntime::Element
141{
142 // Taken from rsDefines.h
143 enum DataKind
144 {
145 RS_KIND_USER,
146 RS_KIND_PIXEL_L = 7,
147 RS_KIND_PIXEL_A,
148 RS_KIND_PIXEL_LA,
149 RS_KIND_PIXEL_RGB,
150 RS_KIND_PIXEL_RGBA,
151 RS_KIND_PIXEL_DEPTH,
152 RS_KIND_PIXEL_YUV,
153 RS_KIND_INVALID = 100
154 };
155
156 // Taken from rsDefines.h
157 enum DataType
158 {
159 RS_TYPE_NONE = 0,
160 RS_TYPE_FLOAT_16,
161 RS_TYPE_FLOAT_32,
162 RS_TYPE_FLOAT_64,
163 RS_TYPE_SIGNED_8,
164 RS_TYPE_SIGNED_16,
165 RS_TYPE_SIGNED_32,
166 RS_TYPE_SIGNED_64,
167 RS_TYPE_UNSIGNED_8,
168 RS_TYPE_UNSIGNED_16,
169 RS_TYPE_UNSIGNED_32,
170 RS_TYPE_UNSIGNED_64,
Ewan Crawford2e920712015-12-17 16:40:05 +0000171 RS_TYPE_BOOLEAN,
172
173 RS_TYPE_UNSIGNED_5_6_5,
174 RS_TYPE_UNSIGNED_5_5_5_1,
175 RS_TYPE_UNSIGNED_4_4_4_4,
176
177 RS_TYPE_MATRIX_4X4,
178 RS_TYPE_MATRIX_3X3,
179 RS_TYPE_MATRIX_2X2,
180
181 RS_TYPE_ELEMENT = 1000,
182 RS_TYPE_TYPE,
183 RS_TYPE_ALLOCATION,
184 RS_TYPE_SAMPLER,
185 RS_TYPE_SCRIPT,
186 RS_TYPE_MESH,
187 RS_TYPE_PROGRAM_FRAGMENT,
188 RS_TYPE_PROGRAM_VERTEX,
189 RS_TYPE_PROGRAM_RASTER,
190 RS_TYPE_PROGRAM_STORE,
191 RS_TYPE_FONT,
192
193 RS_TYPE_INVALID = 10000
Ewan Crawford8b244e22015-11-30 10:29:49 +0000194 };
195
196 std::vector<Element> children; // Child Element fields for structs
197 empirical_type<lldb::addr_t> element_ptr; // Pointer to the RS Element of the Type
198 empirical_type<DataType> type; // Type of each data pointer stored by the allocation
199 empirical_type<DataKind> type_kind; // Defines pixel type if Allocation is created from an image
200 empirical_type<uint32_t> type_vec_size; // Vector size of each data point, e.g '4' for uchar4
201 empirical_type<uint32_t> field_count; // Number of Subelements
202 empirical_type<uint32_t> datum_size; // Size of a single Element with padding
203 empirical_type<uint32_t> padding; // Number of padding bytes
204 empirical_type<uint32_t> array_size; // Number of items in array, only needed for strucrs
205 ConstString type_name; // Name of type, only needed for structs
206
Adrian McCarthyfe06b5a2015-11-30 22:18:43 +0000207 static const ConstString &GetFallbackStructName(); // Print this as the type name of a struct Element
Ewan Crawford8b244e22015-11-30 10:29:49 +0000208 // If we can't resolve the actual struct name
Ewan Crawford8b590622015-12-10 10:20:39 +0000209
210 bool shouldRefresh() const
211 {
212 const bool valid_ptr = element_ptr.isValid() && *element_ptr.get() != 0x0;
213 const bool valid_type = type.isValid() && type_vec_size.isValid() && type_kind.isValid();
214 return !valid_ptr || !valid_type || !datum_size.isValid();
215 }
Ewan Crawford8b244e22015-11-30 10:29:49 +0000216};
217
Ewan Crawford78f339d2015-09-21 10:53:18 +0000218// This AllocationDetails class collects data associated with a single
219// allocation instance.
220struct RenderScriptRuntime::AllocationDetails
221{
Ewan Crawford15f2bd92015-10-06 08:42:32 +0000222 struct Dimension
Ewan Crawford78f339d2015-09-21 10:53:18 +0000223 {
Ewan Crawford15f2bd92015-10-06 08:42:32 +0000224 uint32_t dim_1;
225 uint32_t dim_2;
226 uint32_t dim_3;
227 uint32_t cubeMap;
228
229 Dimension()
230 {
231 dim_1 = 0;
232 dim_2 = 0;
233 dim_3 = 0;
234 cubeMap = 0;
235 }
Ewan Crawford78f339d2015-09-21 10:53:18 +0000236 };
237
Ewan Crawford26e52a72016-01-07 10:19:09 +0000238 // The FileHeader struct specifies the header we use for writing allocations to a binary file.
239 // Our format begins with the ASCII characters "RSAD", identifying the file as an allocation dump.
240 // Member variables dims and hdr_size are then written consecutively, immediately followed by an instance of
241 // the ElementHeader struct. Because Elements can contain subelements, there may be more than one instance
242 // of the ElementHeader struct. With this first instance being the root element, and the other instances being
243 // the root's descendants. To identify which instances are an ElementHeader's children, each struct
244 // is immediately followed by a sequence of consecutive offsets to the start of its child structs.
245 // These offsets are 4 bytes in size, and the 0 offset signifies no more children.
Ewan Crawford55232f02015-10-21 08:50:42 +0000246 struct FileHeader
247 {
248 uint8_t ident[4]; // ASCII 'RSAD' identifying the file
Ewan Crawford55232f02015-10-21 08:50:42 +0000249 uint32_t dims[3]; // Dimensions
Ewan Crawford26e52a72016-01-07 10:19:09 +0000250 uint16_t hdr_size; // Header size in bytes, including all element headers
251 };
252
253 struct ElementHeader
254 {
255 uint16_t type; // DataType enum
256 uint32_t kind; // DataKind enum
257 uint32_t element_size; // Size of a single element, including padding
258 uint16_t vector_size; // Vector width
259 uint32_t array_size; // Number of elements in array
Ewan Crawford55232f02015-10-21 08:50:42 +0000260 };
261
Ewan Crawford15f2bd92015-10-06 08:42:32 +0000262 // Monotonically increasing from 1
263 static unsigned int ID;
264
265 // Maps Allocation DataType enum and vector size to printable strings
266 // using mapping from RenderScript numerical types summary documentation
267 static const char* RsDataTypeToString[][4];
268
269 // Maps Allocation DataKind enum to printable strings
270 static const char* RsDataKindToString[];
271
Ewan Crawforda0f08672015-10-16 08:28:47 +0000272 // Maps allocation types to format sizes for printing.
273 static const unsigned int RSTypeToFormat[][3];
274
Ewan Crawford15f2bd92015-10-06 08:42:32 +0000275 // Give each allocation an ID as a way
276 // for commands to reference it.
277 const unsigned int id;
278
Ewan Crawford8b244e22015-11-30 10:29:49 +0000279 RenderScriptRuntime::Element element; // Allocation Element type
Ewan Crawford15f2bd92015-10-06 08:42:32 +0000280 empirical_type<Dimension> dimension; // Dimensions of the Allocation
281 empirical_type<lldb::addr_t> address; // Pointer to address of the RS Allocation
282 empirical_type<lldb::addr_t> data_ptr; // Pointer to the data held by the Allocation
283 empirical_type<lldb::addr_t> type_ptr; // Pointer to the RS Type of the Allocation
Ewan Crawford15f2bd92015-10-06 08:42:32 +0000284 empirical_type<lldb::addr_t> context; // Pointer to the RS Context of the Allocation
Ewan Crawforda0f08672015-10-16 08:28:47 +0000285 empirical_type<uint32_t> size; // Size of the allocation
286 empirical_type<uint32_t> stride; // Stride between rows of the allocation
Ewan Crawford15f2bd92015-10-06 08:42:32 +0000287
288 // Give each allocation an id, so we can reference it in user commands.
289 AllocationDetails(): id(ID++)
290 {
291 }
Ewan Crawford8b590622015-12-10 10:20:39 +0000292
293 bool shouldRefresh() const
294 {
295 bool valid_ptrs = data_ptr.isValid() && *data_ptr.get() != 0x0;
296 valid_ptrs = valid_ptrs && type_ptr.isValid() && *type_ptr.get() != 0x0;
297 return !valid_ptrs || !dimension.isValid() || !size.isValid() || element.shouldRefresh();
298 }
Ewan Crawford15f2bd92015-10-06 08:42:32 +0000299};
300
Adrian McCarthyfe06b5a2015-11-30 22:18:43 +0000301const ConstString &
302RenderScriptRuntime::Element::GetFallbackStructName()
303{
304 static const ConstString FallbackStructName("struct");
305 return FallbackStructName;
306}
Ewan Crawford8b244e22015-11-30 10:29:49 +0000307
Ewan Crawford15f2bd92015-10-06 08:42:32 +0000308unsigned int RenderScriptRuntime::AllocationDetails::ID = 1;
309
310const char* RenderScriptRuntime::AllocationDetails::RsDataKindToString[] =
311{
312 "User",
313 "Undefined", "Undefined", "Undefined", // Enum jumps from 0 to 7
314 "Undefined", "Undefined", "Undefined",
315 "L Pixel",
316 "A Pixel",
317 "LA Pixel",
318 "RGB Pixel",
319 "RGBA Pixel",
320 "Pixel Depth",
321 "YUV Pixel"
322};
323
324const char* RenderScriptRuntime::AllocationDetails::RsDataTypeToString[][4] =
325{
326 {"None", "None", "None", "None"},
327 {"half", "half2", "half3", "half4"},
328 {"float", "float2", "float3", "float4"},
329 {"double", "double2", "double3", "double4"},
330 {"char", "char2", "char3", "char4"},
331 {"short", "short2", "short3", "short4"},
332 {"int", "int2", "int3", "int4"},
333 {"long", "long2", "long3", "long4"},
334 {"uchar", "uchar2", "uchar3", "uchar4"},
335 {"ushort", "ushort2", "ushort3", "ushort4"},
336 {"uint", "uint2", "uint3", "uint4"},
337 {"ulong", "ulong2", "ulong3", "ulong4"},
Ewan Crawford2e920712015-12-17 16:40:05 +0000338 {"bool", "bool2", "bool3", "bool4"},
339 {"packed_565", "packed_565", "packed_565", "packed_565"},
340 {"packed_5551", "packed_5551", "packed_5551", "packed_5551"},
341 {"packed_4444", "packed_4444", "packed_4444", "packed_4444"},
342 {"rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4"},
343 {"rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3"},
344 {"rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2"},
345
346 // Handlers
347 {"RS Element", "RS Element", "RS Element", "RS Element"},
348 {"RS Type", "RS Type", "RS Type", "RS Type"},
349 {"RS Allocation", "RS Allocation", "RS Allocation", "RS Allocation"},
350 {"RS Sampler", "RS Sampler", "RS Sampler", "RS Sampler"},
351 {"RS Script", "RS Script", "RS Script", "RS Script"},
352
353 // Deprecated
354 {"RS Mesh", "RS Mesh", "RS Mesh", "RS Mesh"},
355 {"RS Program Fragment", "RS Program Fragment", "RS Program Fragment", "RS Program Fragment"},
356 {"RS Program Vertex", "RS Program Vertex", "RS Program Vertex", "RS Program Vertex"},
357 {"RS Program Raster", "RS Program Raster", "RS Program Raster", "RS Program Raster"},
358 {"RS Program Store", "RS Program Store", "RS Program Store", "RS Program Store"},
359 {"RS Font", "RS Font", "RS Font", "RS Font"}
Ewan Crawford78f339d2015-09-21 10:53:18 +0000360};
361
Ewan Crawforda0f08672015-10-16 08:28:47 +0000362// Used as an index into the RSTypeToFormat array elements
363enum TypeToFormatIndex {
364 eFormatSingle = 0,
365 eFormatVector,
366 eElementSize
367};
368
369// { format enum of single element, format enum of element vector, size of element}
370const unsigned int RenderScriptRuntime::AllocationDetails::RSTypeToFormat[][3] =
371{
372 {eFormatHex, eFormatHex, 1}, // RS_TYPE_NONE
373 {eFormatFloat, eFormatVectorOfFloat16, 2}, // RS_TYPE_FLOAT_16
374 {eFormatFloat, eFormatVectorOfFloat32, sizeof(float)}, // RS_TYPE_FLOAT_32
375 {eFormatFloat, eFormatVectorOfFloat64, sizeof(double)}, // RS_TYPE_FLOAT_64
376 {eFormatDecimal, eFormatVectorOfSInt8, sizeof(int8_t)}, // RS_TYPE_SIGNED_8
377 {eFormatDecimal, eFormatVectorOfSInt16, sizeof(int16_t)}, // RS_TYPE_SIGNED_16
378 {eFormatDecimal, eFormatVectorOfSInt32, sizeof(int32_t)}, // RS_TYPE_SIGNED_32
379 {eFormatDecimal, eFormatVectorOfSInt64, sizeof(int64_t)}, // RS_TYPE_SIGNED_64
380 {eFormatDecimal, eFormatVectorOfUInt8, sizeof(uint8_t)}, // RS_TYPE_UNSIGNED_8
381 {eFormatDecimal, eFormatVectorOfUInt16, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_16
382 {eFormatDecimal, eFormatVectorOfUInt32, sizeof(uint32_t)}, // RS_TYPE_UNSIGNED_32
383 {eFormatDecimal, eFormatVectorOfUInt64, sizeof(uint64_t)}, // RS_TYPE_UNSIGNED_64
Ewan Crawford2e920712015-12-17 16:40:05 +0000384 {eFormatBoolean, eFormatBoolean, 1}, // RS_TYPE_BOOL
385 {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_6_5
386 {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_5_5_1
387 {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_4_4_4_4
388 {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 16}, // RS_TYPE_MATRIX_4X4
389 {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 9}, // RS_TYPE_MATRIX_3X3
390 {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 4} // RS_TYPE_MATRIX_2X2
Ewan Crawforda0f08672015-10-16 08:28:47 +0000391};
392
Colin Riley5ec532a2015-04-09 16:49:25 +0000393//------------------------------------------------------------------
394// Static Functions
395//------------------------------------------------------------------
396LanguageRuntime *
397RenderScriptRuntime::CreateInstance(Process *process, lldb::LanguageType language)
398{
399
400 if (language == eLanguageTypeExtRenderScript)
401 return new RenderScriptRuntime(process);
402 else
403 return NULL;
404}
405
Ewan Crawford98156582015-09-04 08:56:52 +0000406// Callback with a module to search for matching symbols.
407// We first check that the module contains RS kernels.
408// Then look for a symbol which matches our kernel name.
409// The breakpoint address is finally set using the address of this symbol.
410Searcher::CallbackReturn
411RSBreakpointResolver::SearchCallback(SearchFilter &filter,
412 SymbolContext &context,
413 Address*,
414 bool)
415{
416 ModuleSP module = context.module_sp;
417
418 if (!module)
419 return Searcher::eCallbackReturnContinue;
420
421 // Is this a module containing renderscript kernels?
422 if (nullptr == module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData))
423 return Searcher::eCallbackReturnContinue;
424
425 // Attempt to set a breakpoint on the kernel name symbol within the module library.
426 // If it's not found, it's likely debug info is unavailable - try to set a
427 // breakpoint on <name>.expand.
428
429 const Symbol* kernel_sym = module->FindFirstSymbolWithNameAndType(m_kernel_name, eSymbolTypeCode);
430 if (!kernel_sym)
431 {
432 std::string kernel_name_expanded(m_kernel_name.AsCString());
433 kernel_name_expanded.append(".expand");
434 kernel_sym = module->FindFirstSymbolWithNameAndType(ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode);
435 }
436
437 if (kernel_sym)
438 {
439 Address bp_addr = kernel_sym->GetAddress();
440 if (filter.AddressPasses(bp_addr))
441 m_breakpoint->AddLocation(bp_addr);
442 }
443
444 return Searcher::eCallbackReturnContinue;
445}
446
Colin Riley5ec532a2015-04-09 16:49:25 +0000447void
448RenderScriptRuntime::Initialize()
449{
Colin Riley4640cde2015-06-01 18:23:41 +0000450 PluginManager::RegisterPlugin(GetPluginNameStatic(), "RenderScript language support", CreateInstance, GetCommandObject);
Colin Riley5ec532a2015-04-09 16:49:25 +0000451}
452
453void
454RenderScriptRuntime::Terminate()
455{
456 PluginManager::UnregisterPlugin(CreateInstance);
457}
458
459lldb_private::ConstString
460RenderScriptRuntime::GetPluginNameStatic()
461{
462 static ConstString g_name("renderscript");
463 return g_name;
464}
465
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000466RenderScriptRuntime::ModuleKind
Colin Rileyef20b082015-04-14 07:39:24 +0000467RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp)
468{
469 if (module_sp)
470 {
471 // Is this a module containing renderscript kernels?
472 const Symbol *info_sym = module_sp->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData);
473 if (info_sym)
474 {
475 return eModuleKindKernelObj;
476 }
Colin Riley4640cde2015-06-01 18:23:41 +0000477
478 // Is this the main RS runtime library
479 const ConstString rs_lib("libRS.so");
480 if (module_sp->GetFileSpec().GetFilename() == rs_lib)
481 {
482 return eModuleKindLibRS;
483 }
484
485 const ConstString rs_driverlib("libRSDriver.so");
486 if (module_sp->GetFileSpec().GetFilename() == rs_driverlib)
487 {
488 return eModuleKindDriver;
489 }
490
Ewan Crawford15f2bd92015-10-06 08:42:32 +0000491 const ConstString rs_cpureflib("libRSCpuRef.so");
Colin Riley4640cde2015-06-01 18:23:41 +0000492 if (module_sp->GetFileSpec().GetFilename() == rs_cpureflib)
493 {
494 return eModuleKindImpl;
495 }
496
Colin Rileyef20b082015-04-14 07:39:24 +0000497 }
498 return eModuleKindIgnored;
499}
500
501bool
502RenderScriptRuntime::IsRenderScriptModule(const lldb::ModuleSP &module_sp)
503{
504 return GetModuleKind(module_sp) != eModuleKindIgnored;
505}
506
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000507void
Colin Rileyef20b082015-04-14 07:39:24 +0000508RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list )
509{
510 Mutex::Locker locker (module_list.GetMutex ());
511
512 size_t num_modules = module_list.GetSize();
513 for (size_t i = 0; i < num_modules; i++)
514 {
515 auto mod = module_list.GetModuleAtIndex (i);
516 if (IsRenderScriptModule (mod))
517 {
518 LoadModule(mod);
519 }
520 }
521}
522
Colin Riley5ec532a2015-04-09 16:49:25 +0000523//------------------------------------------------------------------
524// PluginInterface protocol
525//------------------------------------------------------------------
526lldb_private::ConstString
527RenderScriptRuntime::GetPluginName()
528{
529 return GetPluginNameStatic();
530}
531
532uint32_t
533RenderScriptRuntime::GetPluginVersion()
534{
535 return 1;
536}
537
538bool
539RenderScriptRuntime::IsVTableName(const char *name)
540{
541 return false;
542}
543
544bool
545RenderScriptRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic,
Enrico Granata0b6003f2015-09-17 22:56:38 +0000546 TypeAndOrName &class_type_or_name, Address &address,
547 Value::ValueType &value_type)
Colin Riley5ec532a2015-04-09 16:49:25 +0000548{
549 return false;
550}
551
Enrico Granatac74275b2015-09-22 19:45:52 +0000552TypeAndOrName
Enrico Granata7eed4872015-09-22 19:58:02 +0000553RenderScriptRuntime::FixUpDynamicType (const TypeAndOrName& type_and_or_name,
554 ValueObject& static_value)
Enrico Granatac74275b2015-09-22 19:45:52 +0000555{
556 return type_and_or_name;
557}
558
Colin Riley5ec532a2015-04-09 16:49:25 +0000559bool
560RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value)
561{
562 return false;
563}
564
565lldb::BreakpointResolverSP
566RenderScriptRuntime::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp)
567{
568 BreakpointResolverSP resolver_sp;
569 return resolver_sp;
570}
571
Colin Riley4640cde2015-06-01 18:23:41 +0000572const RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] =
573{
574 //rsdScript
Aidan Dodds82780282015-09-18 16:49:39 +0000575 {
576 "rsdScriptInit", //name
577 "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_7ScriptCEPKcS7_PKhjj", // symbol name 32 bit
578 "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_7ScriptCEPKcS7_PKhmj", // symbol name 64 bit
579 0, // version
580 RenderScriptRuntime::eModuleKindDriver, // type
581 &lldb_private::RenderScriptRuntime::CaptureScriptInit1 // handler
582 },
583 {
Aidan Dodds82780282015-09-18 16:49:39 +0000584 "rsdScriptInvokeForEachMulti", // name
585 "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall", // symbol name 32bit
586 "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0_6ScriptEjPPKNS0_10AllocationEmPS6_PKvmPK12RsScriptCall", // symbol name 64bit
587 0, // version
588 RenderScriptRuntime::eModuleKindDriver, // type
Aidan Doddse09c44b2016-01-14 15:39:28 +0000589 &lldb_private::RenderScriptRuntime::CaptureScriptInvokeForEachMulti // handler
Aidan Dodds82780282015-09-18 16:49:39 +0000590 },
591 {
592 "rsdScriptSetGlobalVar", // name
593 "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_6ScriptEjPvj", // symbol name 32bit
594 "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_6ScriptEjPvm", // symbol name 64bit
595 0, // version
596 RenderScriptRuntime::eModuleKindDriver, // type
597 &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar1 // handler
598 },
Colin Riley4640cde2015-06-01 18:23:41 +0000599
600 //rsdAllocation
Aidan Dodds82780282015-09-18 16:49:39 +0000601 {
602 "rsdAllocationInit", // name
603 "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_10AllocationEb", // symbol name 32bit
604 "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_10AllocationEb", // symbol name 64bit
605 0, // version
606 RenderScriptRuntime::eModuleKindDriver, // type
607 &lldb_private::RenderScriptRuntime::CaptureAllocationInit1 // handler
608 },
609 {
610 "rsdAllocationRead2D", //name
611 "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_10AllocationEjjj23RsAllocationCubemapFacejjPvjj", // symbol name 32bit
612 "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_10AllocationEjjj23RsAllocationCubemapFacejjPvmm", // symbol name 64bit
613 0, // version
614 RenderScriptRuntime::eModuleKindDriver, // type
615 nullptr // handler
616 },
Ewan Crawforde69df382015-12-09 16:01:58 +0000617 {
618 "rsdAllocationDestroy", // name
619 "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_10AllocationE", // symbol name 32bit
620 "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_10AllocationE", // symbol name 64bit
621 0, // version
622 RenderScriptRuntime::eModuleKindDriver, // type
623 &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy // handler
624 },
Colin Riley4640cde2015-06-01 18:23:41 +0000625};
Colin Riley4640cde2015-06-01 18:23:41 +0000626
Eugene Zelenko222b9372015-10-27 00:45:06 +0000627const size_t RenderScriptRuntime::s_runtimeHookCount = sizeof(s_runtimeHookDefns)/sizeof(s_runtimeHookDefns[0]);
Colin Riley4640cde2015-06-01 18:23:41 +0000628
629bool
630RenderScriptRuntime::HookCallback(void *baton, StoppointCallbackContext *ctx, lldb::user_id_t break_id, lldb::user_id_t break_loc_id)
631{
632 RuntimeHook* hook_info = (RuntimeHook*)baton;
633 ExecutionContext context(ctx->exe_ctx_ref);
634
635 RenderScriptRuntime *lang_rt = (RenderScriptRuntime *)context.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
636
637 lang_rt->HookCallback(hook_info, context);
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000638
Colin Riley4640cde2015-06-01 18:23:41 +0000639 return false;
640}
641
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000642void
Colin Riley4640cde2015-06-01 18:23:41 +0000643RenderScriptRuntime::HookCallback(RuntimeHook* hook_info, ExecutionContext& context)
644{
645 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
646
Aidan Dodds82780282015-09-18 16:49:39 +0000647 if (log)
Colin Riley4640cde2015-06-01 18:23:41 +0000648 log->Printf ("RenderScriptRuntime::HookCallback - '%s' .", hook_info->defn->name);
649
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000650 if (hook_info->defn->grabber)
Colin Riley4640cde2015-06-01 18:23:41 +0000651 {
652 (this->*(hook_info->defn->grabber))(hook_info, context);
653 }
654}
655
Colin Riley4640cde2015-06-01 18:23:41 +0000656bool
Aidan Dodds82780282015-09-18 16:49:39 +0000657RenderScriptRuntime::GetArgSimple(ExecutionContext &context, uint32_t arg, uint64_t *data)
Colin Riley4640cde2015-06-01 18:23:41 +0000658{
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000659 // Get a positional integer argument.
660 // Given an ExecutionContext, ``context`` which should be a RenderScript
661 // frame, get the value of the positional argument ``arg`` and save its value
662 // to the address pointed to by ``data``.
663 // returns true on success, false otherwise.
664 // If unsuccessful, the value pointed to by ``data`` is undefined. Otherwise,
665 // ``data`` will be set to the value of the the given ``arg``.
666 // NOTE: only natural width integer arguments for the machine are supported.
667 // Behaviour with non primitive arguments is undefined.
668
Colin Riley4640cde2015-06-01 18:23:41 +0000669 if (!data)
670 return false;
671
Aidan Dodds82780282015-09-18 16:49:39 +0000672 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
Colin Riley4640cde2015-06-01 18:23:41 +0000673 Error error;
674 RegisterContext* reg_ctx = context.GetRegisterContext();
675 Process* process = context.GetProcessPtr();
Aidan Dodds82780282015-09-18 16:49:39 +0000676 bool success = false; // return value
Colin Riley4640cde2015-06-01 18:23:41 +0000677
Aidan Dodds82780282015-09-18 16:49:39 +0000678 if (!context.GetTargetPtr())
Colin Riley4640cde2015-06-01 18:23:41 +0000679 {
Aidan Dodds82780282015-09-18 16:49:39 +0000680 if (log)
681 log->Printf("RenderScriptRuntime::GetArgSimple - Invalid target");
682
683 return false;
Colin Riley4640cde2015-06-01 18:23:41 +0000684 }
Aidan Dodds82780282015-09-18 16:49:39 +0000685
686 switch (context.GetTargetPtr()->GetArchitecture().GetMachine())
Colin Riley4640cde2015-06-01 18:23:41 +0000687 {
Aidan Dodds82780282015-09-18 16:49:39 +0000688 case llvm::Triple::ArchType::x86:
Colin Riley4640cde2015-06-01 18:23:41 +0000689 {
690 uint64_t sp = reg_ctx->GetSP();
Aidan Dodds82780282015-09-18 16:49:39 +0000691 uint32_t offset = (1 + arg) * sizeof(uint32_t);
692 uint32_t result = 0;
693 process->ReadMemory(sp + offset, &result, sizeof(uint32_t), error);
694 if (error.Fail())
Colin Riley4640cde2015-06-01 18:23:41 +0000695 {
Aidan Dodds82780282015-09-18 16:49:39 +0000696 if (log)
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000697 log->Printf("RenderScriptRuntime::GetArgSimple - error reading X86 stack: %s.", error.AsCString());
Aidan Dodds82780282015-09-18 16:49:39 +0000698 }
699 else
700 {
701 *data = result;
702 success = true;
703 }
Aidan Dodds82780282015-09-18 16:49:39 +0000704 break;
705 }
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000706 case llvm::Triple::ArchType::x86_64:
707 {
708 // amd64 has 6 integer registers, and 8 XMM registers for parameter passing.
709 // Surplus args are spilled onto the stack.
710 // rdi, rsi, rdx, rcx, r8, r9, (zmm0 - 7 for vectors)
711 // ref: AMD64 ABI Draft 0.99.6 – October 7, 2013 – 10:35; Figure 3.4. Retrieved from
712 // http://www.x86-64.org/documentation/abi.pdf
713 if (arg > 5)
714 {
715 if (log)
716 log->Warning("X86_64 register spill is not supported.");
717 break;
718 }
719 const char * regnames[] = {"rdi", "rsi", "rdx", "rcx", "r8", "r9"};
720 assert((sizeof(regnames) / sizeof(const char *)) > arg);
721 const RegisterInfo *rArg = reg_ctx->GetRegisterInfoByName(regnames[arg]);
722 RegisterValue rVal;
723 success = reg_ctx->ReadRegister(rArg, rVal);
724 if (success)
725 {
726 *data = rVal.GetAsUInt64(0u, &success);
727 }
728 else
729 {
730 if (log)
731 log->Printf("RenderScriptRuntime::GetArgSimple - error reading x86_64 register: %d.", arg);
732 }
733 break;
734 }
Aidan Dodds82780282015-09-18 16:49:39 +0000735 case llvm::Triple::ArchType::arm:
736 {
737 // arm 32 bit
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000738 // first 4 arguments are passed via registers
Aidan Dodds82780282015-09-18 16:49:39 +0000739 if (arg < 4)
740 {
741 const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg);
742 RegisterValue rVal;
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000743 success = reg_ctx->ReadRegister(rArg, rVal);
744 if (success)
745 {
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000746 (*data) = rVal.GetAsUInt32(0u, &success);
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000747 }
748 else
749 {
750 if (log)
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000751 log->Printf("RenderScriptRuntime::GetArgSimple - error reading ARM register: %d.", arg);
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000752 }
Aidan Dodds82780282015-09-18 16:49:39 +0000753 }
754 else
755 {
756 uint64_t sp = reg_ctx->GetSP();
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000757 uint32_t offset = (arg-4) * sizeof(uint32_t);
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000758 uint32_t value = 0;
759 size_t bytes_read = process->ReadMemory(sp + offset, &value, sizeof(value), error);
760 if (error.Fail() || bytes_read != sizeof(value))
Colin Riley4640cde2015-06-01 18:23:41 +0000761 {
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000762 if (log)
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000763 log->Printf("RenderScriptRuntime::GetArgSimple - error reading ARM stack: %s.", error.AsCString());
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000764 }
765 else
766 {
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000767 *data = value;
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000768 success = true;
Colin Riley4640cde2015-06-01 18:23:41 +0000769 }
770 }
Aidan Dodds82780282015-09-18 16:49:39 +0000771 break;
772 }
773 case llvm::Triple::ArchType::aarch64:
774 {
775 // arm 64 bit
776 // first 8 arguments are in the registers
777 if (arg < 8)
778 {
779 const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg);
780 RegisterValue rVal;
781 success = reg_ctx->ReadRegister(rArg, rVal);
782 if (success)
783 {
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000784 *data = rVal.GetAsUInt64(0u, &success);
Aidan Dodds82780282015-09-18 16:49:39 +0000785 }
786 else
787 {
788 if (log)
789 log->Printf("RenderScriptRuntime::GetArgSimple() - AARCH64 - Error while reading the argument #%d", arg);
790 }
791 }
792 else
793 {
794 // @TODO: need to find the argument in the stack
795 if (log)
796 log->Printf("RenderScriptRuntime::GetArgSimple - AARCH64 - FOR #ARG >= 8 NOT IMPLEMENTED YET. Argument number: %d", arg);
797 }
798 break;
799 }
Aidan Dodds74b396d2015-11-12 17:39:42 +0000800 case llvm::Triple::ArchType::mipsel:
801 {
Aidan Dodds74b396d2015-11-12 17:39:42 +0000802 // read from the registers
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000803 // first 4 arguments are passed in registers
Aidan Dodds74b396d2015-11-12 17:39:42 +0000804 if (arg < 4){
805 const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg + 4);
806 RegisterValue rVal;
807 success = reg_ctx->ReadRegister(rArg, rVal);
808 if (success)
809 {
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000810 *data = rVal.GetAsUInt64(0u, &success);
Aidan Dodds74b396d2015-11-12 17:39:42 +0000811 }
812 else
813 {
814 if (log)
815 log->Printf("RenderScriptRuntime::GetArgSimple() - Mips - Error while reading the argument #%d", arg);
816 }
Aidan Dodds74b396d2015-11-12 17:39:42 +0000817 }
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000818 // arguments > 4 are read from the stack
Aidan Dodds74b396d2015-11-12 17:39:42 +0000819 else
820 {
821 uint64_t sp = reg_ctx->GetSP();
822 uint32_t offset = arg * sizeof(uint32_t);
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000823 uint32_t value = 0;
824 size_t bytes_read = process->ReadMemory(sp + offset, &value, sizeof(value), error);
825 if (error.Fail() || bytes_read != sizeof(value))
Aidan Dodds74b396d2015-11-12 17:39:42 +0000826 {
827 if (log)
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000828 log->Printf("RenderScriptRuntime::GetArgSimple - error reading Mips stack: %s.", error.AsCString());
Aidan Dodds74b396d2015-11-12 17:39:42 +0000829 }
830 else
831 {
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000832 *data = value;
Aidan Dodds74b396d2015-11-12 17:39:42 +0000833 success = true;
834 }
835 }
Aidan Dodds74b396d2015-11-12 17:39:42 +0000836 break;
837 }
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000838 case llvm::Triple::ArchType::mips64el:
839 {
840 // read from the registers
841 if (arg < 8)
842 {
843 const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg + 4);
844 RegisterValue rVal;
845 success = reg_ctx->ReadRegister(rArg, rVal);
846 if (success)
847 {
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000848 (*data) = rVal.GetAsUInt64(0u, &success);
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000849 }
850 else
851 {
852 if (log)
853 log->Printf("RenderScriptRuntime::GetArgSimple - Mips64 - Error reading the argument #%d", arg);
854 }
855 }
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000856 // arguments > 8 are read from the stack
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000857 else
858 {
859 uint64_t sp = reg_ctx->GetSP();
860 uint32_t offset = (arg - 8) * sizeof(uint64_t);
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000861 uint64_t value = 0;
862 size_t bytes_read = process->ReadMemory(sp + offset, &value, sizeof(value), error);
863 if (error.Fail() || bytes_read != sizeof(value))
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000864 {
865 if (log)
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000866 log->Printf("RenderScriptRuntime::GetArgSimple - Mips64 - Error reading Mips64 stack: %s.", error.AsCString());
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000867 }
868 else
869 {
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000870 *data = value;
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000871 success = true;
872 }
873 }
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000874 break;
875 }
Aidan Dodds82780282015-09-18 16:49:39 +0000876 default:
877 {
878 // invalid architecture
879 if (log)
880 log->Printf("RenderScriptRuntime::GetArgSimple - Architecture not supported");
Aidan Dodds82780282015-09-18 16:49:39 +0000881 }
Colin Riley4640cde2015-06-01 18:23:41 +0000882 }
Aidan Dodds82780282015-09-18 16:49:39 +0000883
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000884 if (!success)
885 {
886 if (log)
887 log->Printf("RenderScriptRuntime::GetArgSimple - failed to get argument at index %" PRIu32, arg);
888 }
Aidan Dodds82780282015-09-18 16:49:39 +0000889 return success;
Colin Riley4640cde2015-06-01 18:23:41 +0000890}
891
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000892void
Aidan Doddse09c44b2016-01-14 15:39:28 +0000893RenderScriptRuntime::CaptureScriptInvokeForEachMulti(RuntimeHook* hook_info,
894 ExecutionContext& context)
895{
896 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
897
898 struct args_t
899 {
900 uint64_t context; // const Context *rsc
901 uint64_t script; // Script *s
902 uint64_t slot; // uint32_t slot
903 uint64_t aIns; // const Allocation **aIns
904 uint64_t inLen; // size_t inLen
905 uint64_t aOut; // Allocation *aout
906 uint64_t usr; // const void *usr
907 uint64_t usrLen; // size_t usrLen
908 uint64_t sc; // const RsScriptCall *sc
909 }
910 args;
911
912 bool success =
913 GetArgSimple(context, 0, &args.context) &&
914 GetArgSimple(context, 1, &args.script) &&
915 GetArgSimple(context, 2, &args.slot) &&
916 GetArgSimple(context, 3, &args.aIns) &&
917 GetArgSimple(context, 4, &args.inLen) &&
918 GetArgSimple(context, 5, &args.aOut) &&
919 GetArgSimple(context, 6, &args.usr) &&
920 GetArgSimple(context, 7, &args.usrLen) &&
921 GetArgSimple(context, 8, &args.sc);
922
923 if (!success)
924 {
925 if (log)
926 log->Printf("RenderScriptRuntime::CaptureScriptInvokeForEachMulti()"
927 " - Error while reading the function parameters");
928 return;
929 }
930
931 const uint32_t target_ptr_size = m_process->GetAddressByteSize();
932 Error error;
933 std::vector<uint64_t> allocs;
934
935 // traverse allocation list
936 for (uint64_t i = 0; i < args.inLen; ++i)
937 {
938 // calculate offest to allocation pointer
939 const lldb::addr_t addr = args.aIns + i * target_ptr_size;
940
941 // Note: due to little endian layout, reading 32bits or 64bits into res64 will
942 // give the correct results.
943
944 uint64_t res64 = 0;
945 size_t read = m_process->ReadMemory(addr, &res64, target_ptr_size, error);
946 if (read != target_ptr_size || !error.Success())
947 {
948 if (log)
949 log->Printf("RenderScriptRuntime::CaptureScriptInvokeForEachMulti()"
950 " - Error while reading allocation list argument %" PRId64, i);
951 }
952 else
953 {
954 allocs.push_back(res64);
955 }
956 }
957
958 // if there is an output allocation track it
959 if (args.aOut)
960 {
961 allocs.push_back(args.aOut);
962 }
963
964 // for all allocations we have found
965 for (const uint64_t alloc_addr : allocs)
966 {
967 AllocationDetails* alloc = LookUpAllocation(alloc_addr, true);
968 if (alloc)
969 {
970 // save the allocation address
971 if (alloc->address.isValid())
972 {
973 // check the allocation address we already have matches
974 assert(*alloc->address.get() == alloc_addr);
975 }
976 else
977 {
978 alloc->address = alloc_addr;
979 }
980
981 // save the context
982 if (log)
983 {
984 if (alloc->context.isValid() && *alloc->context.get() != args.context)
985 log->Printf("RenderScriptRuntime::CaptureScriptInvokeForEachMulti"
986 " - Allocation used by multiple contexts");
987 }
988 alloc->context = args.context;
989 }
990 }
991
992 // make sure we track this script object
993 if (lldb_private::RenderScriptRuntime::ScriptDetails * script = LookUpScript(args.script, true))
994 {
995 if (log)
996 {
997 if (script->context.isValid() && *script->context.get() != args.context)
998 log->Printf("RenderScriptRuntime::CaptureScriptInvokeForEachMulti"
999 " - Script used by multiple contexts");
1000 }
1001 script->context = args.context;
1002 }
1003}
1004
1005void
Colin Riley4640cde2015-06-01 18:23:41 +00001006RenderScriptRuntime::CaptureSetGlobalVar1(RuntimeHook* hook_info, ExecutionContext& context)
1007{
1008 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001009
Colin Riley4640cde2015-06-01 18:23:41 +00001010 //Context, Script, int, data, length
1011
Aidan Dodds82780282015-09-18 16:49:39 +00001012 uint64_t rs_context_u64 = 0U;
1013 uint64_t rs_script_u64 = 0U;
1014 uint64_t rs_id_u64 = 0U;
1015 uint64_t rs_data_u64 = 0U;
1016 uint64_t rs_length_u64 = 0U;
Colin Riley4640cde2015-06-01 18:23:41 +00001017
Aidan Dodds82780282015-09-18 16:49:39 +00001018 bool success =
1019 GetArgSimple(context, 0, &rs_context_u64) &&
1020 GetArgSimple(context, 1, &rs_script_u64) &&
1021 GetArgSimple(context, 2, &rs_id_u64) &&
1022 GetArgSimple(context, 3, &rs_data_u64) &&
1023 GetArgSimple(context, 4, &rs_length_u64);
Colin Riley4640cde2015-06-01 18:23:41 +00001024
Aidan Dodds82780282015-09-18 16:49:39 +00001025 if (!success)
1026 {
1027 if (log)
1028 log->Printf("RenderScriptRuntime::CaptureSetGlobalVar1 - Error while reading the function parameters");
1029 return;
1030 }
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001031
Aidan Dodds82780282015-09-18 16:49:39 +00001032 if (log)
Colin Riley4640cde2015-06-01 18:23:41 +00001033 {
1034 log->Printf ("RenderScriptRuntime::CaptureSetGlobalVar1 - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64 ":%" PRIu64 "bytes.",
Aidan Dodds82780282015-09-18 16:49:39 +00001035 rs_context_u64, rs_script_u64, rs_id_u64, rs_data_u64, rs_length_u64);
Colin Riley4640cde2015-06-01 18:23:41 +00001036
Aidan Dodds82780282015-09-18 16:49:39 +00001037 addr_t script_addr = (addr_t)rs_script_u64;
Colin Riley4640cde2015-06-01 18:23:41 +00001038 if (m_scriptMappings.find( script_addr ) != m_scriptMappings.end())
1039 {
1040 auto rsm = m_scriptMappings[script_addr];
Aidan Dodds82780282015-09-18 16:49:39 +00001041 if (rs_id_u64 < rsm->m_globals.size())
Colin Riley4640cde2015-06-01 18:23:41 +00001042 {
Aidan Dodds82780282015-09-18 16:49:39 +00001043 auto rsg = rsm->m_globals[rs_id_u64];
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001044 log->Printf ("RenderScriptRuntime::CaptureSetGlobalVar1 - Setting of '%s' within '%s' inferred", rsg.m_name.AsCString(),
Colin Riley4640cde2015-06-01 18:23:41 +00001045 rsm->m_module->GetFileSpec().GetFilename().AsCString());
1046 }
1047 }
1048 }
1049}
1050
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001051void
Colin Riley4640cde2015-06-01 18:23:41 +00001052RenderScriptRuntime::CaptureAllocationInit1(RuntimeHook* hook_info, ExecutionContext& context)
1053{
1054 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001055
Colin Riley4640cde2015-06-01 18:23:41 +00001056 //Context, Alloc, bool
1057
Aidan Dodds82780282015-09-18 16:49:39 +00001058 uint64_t rs_context_u64 = 0U;
1059 uint64_t rs_alloc_u64 = 0U;
1060 uint64_t rs_forceZero_u64 = 0U;
Colin Riley4640cde2015-06-01 18:23:41 +00001061
Aidan Dodds82780282015-09-18 16:49:39 +00001062 bool success =
1063 GetArgSimple(context, 0, &rs_context_u64) &&
1064 GetArgSimple(context, 1, &rs_alloc_u64) &&
1065 GetArgSimple(context, 2, &rs_forceZero_u64);
1066 if (!success) // error case
1067 {
1068 if (log)
1069 log->Printf("RenderScriptRuntime::CaptureAllocationInit1 - Error while reading the function parameters");
1070 return; // abort
1071 }
1072
1073 if (log)
Colin Riley4640cde2015-06-01 18:23:41 +00001074 log->Printf ("RenderScriptRuntime::CaptureAllocationInit1 - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .",
Aidan Dodds82780282015-09-18 16:49:39 +00001075 rs_context_u64, rs_alloc_u64, rs_forceZero_u64);
Ewan Crawford78f339d2015-09-21 10:53:18 +00001076
1077 AllocationDetails* alloc = LookUpAllocation(rs_alloc_u64, true);
1078 if (alloc)
1079 alloc->context = rs_context_u64;
Colin Riley4640cde2015-06-01 18:23:41 +00001080}
1081
Ewan Crawforde69df382015-12-09 16:01:58 +00001082void
1083RenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook* hook_info, ExecutionContext& context)
1084{
1085 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1086
1087 // Context, Alloc
1088 uint64_t rs_context_u64 = 0U;
1089 uint64_t rs_alloc_u64 = 0U;
1090
1091 bool success = GetArgSimple(context, 0, &rs_context_u64) && GetArgSimple(context, 1, &rs_alloc_u64);
1092 if (!success) // error case
1093 {
1094 if (log)
1095 log->Printf("RenderScriptRuntime::CaptureAllocationDestroy - Error while reading the function parameters");
1096 return; // abort
1097 }
1098
1099 if (log)
1100 log->Printf("RenderScriptRuntime::CaptureAllocationDestroy - 0x%" PRIx64 ", 0x%" PRIx64 ".",
1101 rs_context_u64, rs_alloc_u64);
1102
1103 for (auto iter = m_allocations.begin(); iter != m_allocations.end(); ++iter)
1104 {
1105 auto& allocation_ap = *iter; // get the unique pointer
1106 if (allocation_ap->address.isValid() && *allocation_ap->address.get() == rs_alloc_u64)
1107 {
1108 m_allocations.erase(iter);
1109 if (log)
1110 log->Printf("RenderScriptRuntime::CaptureAllocationDestroy - Deleted allocation entry");
1111 return;
1112 }
1113 }
1114
1115 if (log)
1116 log->Printf("RenderScriptRuntime::CaptureAllocationDestroy - Couldn't find destroyed allocation");
1117}
1118
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001119void
Colin Riley4640cde2015-06-01 18:23:41 +00001120RenderScriptRuntime::CaptureScriptInit1(RuntimeHook* hook_info, ExecutionContext& context)
1121{
1122 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1123
1124 //Context, Script, resname Str, cachedir Str
1125 Error error;
1126 Process* process = context.GetProcessPtr();
1127
Aidan Dodds82780282015-09-18 16:49:39 +00001128 uint64_t rs_context_u64 = 0U;
1129 uint64_t rs_script_u64 = 0U;
1130 uint64_t rs_resnameptr_u64 = 0U;
1131 uint64_t rs_cachedirptr_u64 = 0U;
Colin Riley4640cde2015-06-01 18:23:41 +00001132
1133 std::string resname;
1134 std::string cachedir;
1135
Aidan Dodds82780282015-09-18 16:49:39 +00001136 // read the function parameters
1137 bool success =
1138 GetArgSimple(context, 0, &rs_context_u64) &&
1139 GetArgSimple(context, 1, &rs_script_u64) &&
1140 GetArgSimple(context, 2, &rs_resnameptr_u64) &&
1141 GetArgSimple(context, 3, &rs_cachedirptr_u64);
Colin Riley4640cde2015-06-01 18:23:41 +00001142
Aidan Dodds82780282015-09-18 16:49:39 +00001143 if (!success)
1144 {
1145 if (log)
1146 log->Printf("RenderScriptRuntime::CaptureScriptInit1 - Error while reading the function parameters");
1147 return;
1148 }
1149
1150 process->ReadCStringFromMemory((lldb::addr_t)rs_resnameptr_u64, resname, error);
Colin Riley4640cde2015-06-01 18:23:41 +00001151 if (error.Fail())
1152 {
Aidan Dodds82780282015-09-18 16:49:39 +00001153 if (log)
Colin Riley4640cde2015-06-01 18:23:41 +00001154 log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - error reading resname: %s.", error.AsCString());
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001155
Colin Riley4640cde2015-06-01 18:23:41 +00001156 }
1157
Aidan Dodds82780282015-09-18 16:49:39 +00001158 process->ReadCStringFromMemory((lldb::addr_t)rs_cachedirptr_u64, cachedir, error);
Colin Riley4640cde2015-06-01 18:23:41 +00001159 if (error.Fail())
1160 {
Aidan Dodds82780282015-09-18 16:49:39 +00001161 if (log)
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001162 log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - error reading cachedir: %s.", error.AsCString());
Colin Riley4640cde2015-06-01 18:23:41 +00001163 }
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001164
Colin Riley4640cde2015-06-01 18:23:41 +00001165 if (log)
1166 log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .",
Aidan Dodds82780282015-09-18 16:49:39 +00001167 rs_context_u64, rs_script_u64, resname.c_str(), cachedir.c_str());
Colin Riley4640cde2015-06-01 18:23:41 +00001168
1169 if (resname.size() > 0)
1170 {
1171 StreamString strm;
1172 strm.Printf("librs.%s.so", resname.c_str());
1173
Ewan Crawford78f339d2015-09-21 10:53:18 +00001174 ScriptDetails* script = LookUpScript(rs_script_u64, true);
1175 if (script)
1176 {
1177 script->type = ScriptDetails::eScriptC;
1178 script->cacheDir = cachedir;
1179 script->resName = resname;
1180 script->scriptDyLib = strm.GetData();
1181 script->context = addr_t(rs_context_u64);
1182 }
Colin Riley4640cde2015-06-01 18:23:41 +00001183
1184 if (log)
1185 log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - '%s' tagged with context 0x%" PRIx64 " and script 0x%" PRIx64 ".",
Aidan Dodds82780282015-09-18 16:49:39 +00001186 strm.GetData(), rs_context_u64, rs_script_u64);
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001187 }
Colin Riley4640cde2015-06-01 18:23:41 +00001188 else if (log)
1189 {
1190 log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - resource name invalid, Script not tagged");
1191 }
Colin Riley4640cde2015-06-01 18:23:41 +00001192}
1193
Colin Riley4640cde2015-06-01 18:23:41 +00001194void
1195RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, ModuleKind kind)
1196{
1197 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1198
1199 if (!module)
1200 {
1201 return;
1202 }
1203
Aidan Dodds82780282015-09-18 16:49:39 +00001204 Target &target = GetProcess()->GetTarget();
1205 llvm::Triple::ArchType targetArchType = target.GetArchitecture().GetMachine();
1206
1207 if (targetArchType != llvm::Triple::ArchType::x86
1208 && targetArchType != llvm::Triple::ArchType::arm
Ewan Crawford02f1c5d2015-10-22 09:01:05 +00001209 && targetArchType != llvm::Triple::ArchType::aarch64
Aidan Dodds74b396d2015-11-12 17:39:42 +00001210 && targetArchType != llvm::Triple::ArchType::mipsel
Ewan Crawford02f1c5d2015-10-22 09:01:05 +00001211 && targetArchType != llvm::Triple::ArchType::mips64el
Ewan Crawfordcdfb1482015-12-11 13:49:21 +00001212 && targetArchType != llvm::Triple::ArchType::x86_64
Ewan Crawford02f1c5d2015-10-22 09:01:05 +00001213 )
Colin Riley4640cde2015-06-01 18:23:41 +00001214 {
1215 if (log)
Aidan Dodds74b396d2015-11-12 17:39:42 +00001216 log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Unable to hook runtime. Only X86, ARM, Mips supported currently.");
Colin Riley4640cde2015-06-01 18:23:41 +00001217
1218 return;
1219 }
1220
Aidan Dodds82780282015-09-18 16:49:39 +00001221 uint32_t archByteSize = target.GetArchitecture().GetAddressByteSize();
Colin Riley4640cde2015-06-01 18:23:41 +00001222
1223 for (size_t idx = 0; idx < s_runtimeHookCount; idx++)
1224 {
1225 const HookDefn* hook_defn = &s_runtimeHookDefns[idx];
1226 if (hook_defn->kind != kind) {
1227 continue;
1228 }
1229
Aidan Dodds82780282015-09-18 16:49:39 +00001230 const char* symbol_name = (archByteSize == 4) ? hook_defn->symbol_name_m32 : hook_defn->symbol_name_m64;
1231
1232 const Symbol *sym = module->FindFirstSymbolWithNameAndType(ConstString(symbol_name), eSymbolTypeCode);
1233 if (!sym){
1234 if (log){
1235 log->Printf("RenderScriptRuntime::LoadRuntimeHooks - ERROR: Symbol '%s' related to the function %s not found", symbol_name, hook_defn->name);
1236 }
1237 continue;
1238 }
Colin Riley4640cde2015-06-01 18:23:41 +00001239
Greg Clayton358cf1e2015-06-25 21:46:34 +00001240 addr_t addr = sym->GetLoadAddress(&target);
Colin Riley4640cde2015-06-01 18:23:41 +00001241 if (addr == LLDB_INVALID_ADDRESS)
1242 {
Aidan Dodds82780282015-09-18 16:49:39 +00001243 if (log)
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001244 log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Unable to resolve the address of hook function '%s' with symbol '%s'.",
Aidan Dodds82780282015-09-18 16:49:39 +00001245 hook_defn->name, symbol_name);
Colin Riley4640cde2015-06-01 18:23:41 +00001246 continue;
1247 }
Aidan Dodds82780282015-09-18 16:49:39 +00001248 else
1249 {
1250 if (log)
1251 log->Printf("RenderScriptRuntime::LoadRuntimeHooks - Function %s, address resolved at 0x%" PRIx64, hook_defn->name, addr);
1252 }
Colin Riley4640cde2015-06-01 18:23:41 +00001253
1254 RuntimeHookSP hook(new RuntimeHook());
1255 hook->address = addr;
1256 hook->defn = hook_defn;
1257 hook->bp_sp = target.CreateBreakpoint(addr, true, false);
1258 hook->bp_sp->SetCallback(HookCallback, hook.get(), true);
1259 m_runtimeHooks[addr] = hook;
1260 if (log)
1261 {
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001262 log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Successfully hooked '%s' in '%s' version %" PRIu64 " at 0x%" PRIx64 ".",
Colin Riley4640cde2015-06-01 18:23:41 +00001263 hook_defn->name, module->GetFileSpec().GetFilename().AsCString(), (uint64_t)hook_defn->version, (uint64_t)addr);
1264 }
1265 }
1266}
1267
1268void
1269RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp)
1270{
1271 if (!rsmodule_sp)
1272 return;
1273
1274 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1275
1276 const ModuleSP module = rsmodule_sp->m_module;
1277 const FileSpec& file = module->GetPlatformFileSpec();
Ewan Crawford78f339d2015-09-21 10:53:18 +00001278
1279 // Iterate over all of the scripts that we currently know of.
1280 // Note: We cant push or pop to m_scripts here or it may invalidate rs_script.
1281 for (const auto & rs_script : m_scripts)
Colin Riley4640cde2015-06-01 18:23:41 +00001282 {
Ewan Crawford78f339d2015-09-21 10:53:18 +00001283 // Extract the expected .so file path for this script.
1284 std::string dylib;
1285 if (!rs_script->scriptDyLib.get(dylib))
1286 continue;
1287
1288 // Only proceed if the module that has loaded corresponds to this script.
1289 if (file.GetFilename() != ConstString(dylib.c_str()))
1290 continue;
1291
1292 // Obtain the script address which we use as a key.
1293 lldb::addr_t script;
1294 if (!rs_script->script.get(script))
1295 continue;
1296
1297 // If we have a script mapping for the current script.
1298 if (m_scriptMappings.find(script) != m_scriptMappings.end())
Colin Riley4640cde2015-06-01 18:23:41 +00001299 {
Ewan Crawford78f339d2015-09-21 10:53:18 +00001300 // if the module we have stored is different to the one we just received.
1301 if (m_scriptMappings[script] != rsmodule_sp)
Colin Riley4640cde2015-06-01 18:23:41 +00001302 {
Colin Riley4640cde2015-06-01 18:23:41 +00001303 if (log)
Ewan Crawford78f339d2015-09-21 10:53:18 +00001304 log->Printf ("RenderScriptRuntime::FixupScriptDetails - Error: script %" PRIx64 " wants reassigned to new rsmodule '%s'.",
1305 (uint64_t)script, rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
Colin Riley4640cde2015-06-01 18:23:41 +00001306 }
1307 }
Ewan Crawford78f339d2015-09-21 10:53:18 +00001308 // We don't have a script mapping for the current script.
1309 else
1310 {
1311 // Obtain the script resource name.
1312 std::string resName;
1313 if (rs_script->resName.get(resName))
1314 // Set the modules resource name.
1315 rsmodule_sp->m_resname = resName;
1316 // Add Script/Module pair to map.
1317 m_scriptMappings[script] = rsmodule_sp;
1318 if (log)
1319 log->Printf ("RenderScriptRuntime::FixupScriptDetails - script %" PRIx64 " associated with rsmodule '%s'.",
1320 (uint64_t)script, rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
1321 }
Colin Riley4640cde2015-06-01 18:23:41 +00001322 }
Colin Riley4640cde2015-06-01 18:23:41 +00001323}
1324
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001325// Uses the Target API to evaluate the expression passed as a parameter to the function
1326// The result of that expression is returned an unsigned 64 bit int, via the result* paramter.
1327// Function returns true on success, and false on failure
1328bool
1329RenderScriptRuntime::EvalRSExpression(const char* expression, StackFrame* frame_ptr, uint64_t* result)
1330{
1331 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1332 if (log)
1333 log->Printf("RenderScriptRuntime::EvalRSExpression(%s)", expression);
1334
1335 ValueObjectSP expr_result;
1336 // Perform the actual expression evaluation
1337 GetProcess()->GetTarget().EvaluateExpression(expression, frame_ptr, expr_result);
1338
1339 if (!expr_result)
1340 {
1341 if (log)
1342 log->Printf("RenderScriptRuntime::EvalRSExpression - Error: Couldn't evaluate expression");
1343 return false;
1344 }
1345
1346 // The result of the expression is invalid
1347 if (!expr_result->GetError().Success())
1348 {
1349 Error err = expr_result->GetError();
1350 if (err.GetError() == UserExpression::kNoResult) // Expression returned void, so this is actually a success
1351 {
1352 if (log)
1353 log->Printf("RenderScriptRuntime::EvalRSExpression - Expression returned void");
1354
1355 result = nullptr;
1356 return true;
1357 }
1358
1359 if (log)
1360 log->Printf("RenderScriptRuntime::EvalRSExpression - Error evaluating expression result: %s", err.AsCString());
1361 return false;
1362 }
1363
1364 bool success = false;
1365 *result = expr_result->GetValueAsUnsigned(0, &success); // We only read the result as an unsigned int.
1366
1367 if (!success)
1368 {
1369 if (log)
1370 log->Printf("RenderScriptRuntime::EvalRSExpression - Error: Couldn't convert expression result to unsigned int");
1371 return false;
1372 }
1373
1374 return true;
1375}
1376
Ewan Crawford836d9652016-01-18 09:16:02 +00001377// Used to index expression format strings
1378enum ExpressionStrings
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001379{
Ewan Crawford836d9652016-01-18 09:16:02 +00001380 eExprGetOffsetPtr = 0,
1381 eExprAllocGetType,
1382 eExprTypeDimX,
1383 eExprTypeDimY,
1384 eExprTypeDimZ,
1385 eExprTypeElemPtr,
1386 eExprElementType,
1387 eExprElementKind,
1388 eExprElementVec,
1389 eExprElementFieldCount,
1390 eExprSubelementsId,
1391 eExprSubelementsName,
1392 eExprSubelementsArrSize
1393};
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001394
Ewan Crawford836d9652016-01-18 09:16:02 +00001395// Format strings containing the expressions we may need to evaluate.
1396const char runtimeExpressions[][256] =
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001397{
Ewan Crawford836d9652016-01-18 09:16:02 +00001398 // Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap)
1399 "(int*)_Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocationCubemapFace(0x%lx, %u, %u, %u, 0, 0)",
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001400
Ewan Crawford836d9652016-01-18 09:16:02 +00001401 // Type* rsaAllocationGetType(Context*, Allocation*)
1402 "(void*)rsaAllocationGetType(0x%lx, 0x%lx)",
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001403
Ewan Crawford836d9652016-01-18 09:16:02 +00001404 // rsaTypeGetNativeData(Context*, Type*, void* typeData, size)
1405 // Pack the data in the following way mHal.state.dimX; mHal.state.dimY; mHal.state.dimZ;
1406 // mHal.state.lodCount; mHal.state.faces; mElement; into typeData
1407 // Need to specify 32 or 64 bit for uint_t since this differs between devices
1408 "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[0]", // X dim
1409 "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[1]", // Y dim
1410 "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[2]", // Z dim
1411 "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[5]", // Element ptr
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001412
Ewan Crawford836d9652016-01-18 09:16:02 +00001413 // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size)
1414 // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into elemData
1415 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[0]", // Type
1416 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[1]", // Kind
1417 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[3]", // Vector Size
1418 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[4]", // Field Count
Ewan Crawford8b244e22015-11-30 10:29:49 +00001419
Ewan Crawford836d9652016-01-18 09:16:02 +00001420 // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t *ids, const char **names,
1421 // size_t *arraySizes, uint32_t dataSize)
1422 // Needed for Allocations of structs to gather details about fields/Subelements
1423 "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];"
1424 "(void*)rsaElementGetSubElements(0x%lx, 0x%lx, ids, names, arr_size, %u); ids[%u]", // Element* of field
1425
1426 "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];"
1427 "(void*)rsaElementGetSubElements(0x%lx, 0x%lx, ids, names, arr_size, %u); names[%u]", // Name of field
1428
1429 "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];"
1430 "(void*)rsaElementGetSubElements(0x%lx, 0x%lx, ids, names, arr_size, %u); arr_size[%u]" // Array size of field
1431};
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001432
1433// JITs the RS runtime for the internal data pointer of an allocation.
1434// Is passed x,y,z coordinates for the pointer to a specific element.
1435// Then sets the data_ptr member in Allocation with the result.
1436// Returns true on success, false otherwise
1437bool
1438RenderScriptRuntime::JITDataPointer(AllocationDetails* allocation, StackFrame* frame_ptr,
1439 unsigned int x, unsigned int y, unsigned int z)
1440{
1441 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1442
1443 if (!allocation->address.isValid())
1444 {
1445 if (log)
1446 log->Printf("RenderScriptRuntime::JITDataPointer - Failed to find allocation details");
1447 return false;
1448 }
1449
Ewan Crawford836d9652016-01-18 09:16:02 +00001450 const char* expr_cstr = runtimeExpressions[eExprGetOffsetPtr];
1451 const int max_expr_size = 512; // Max expression size
1452 char buffer[max_expr_size];
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001453
Ewan Crawford836d9652016-01-18 09:16:02 +00001454 int chars_written = snprintf(buffer, max_expr_size, expr_cstr, *allocation->address.get(), x, y, z);
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001455 if (chars_written < 0)
1456 {
1457 if (log)
1458 log->Printf("RenderScriptRuntime::JITDataPointer - Encoding error in snprintf()");
1459 return false;
1460 }
Ewan Crawford836d9652016-01-18 09:16:02 +00001461 else if (chars_written >= max_expr_size)
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001462 {
1463 if (log)
1464 log->Printf("RenderScriptRuntime::JITDataPointer - Expression too long");
1465 return false;
1466 }
1467
1468 uint64_t result = 0;
1469 if (!EvalRSExpression(buffer, frame_ptr, &result))
1470 return false;
1471
1472 addr_t mem_ptr = static_cast<lldb::addr_t>(result);
1473 allocation->data_ptr = mem_ptr;
1474
1475 return true;
1476}
1477
1478// JITs the RS runtime for the internal pointer to the RS Type of an allocation
1479// Then sets the type_ptr member in Allocation with the result.
1480// Returns true on success, false otherwise
1481bool
1482RenderScriptRuntime::JITTypePointer(AllocationDetails* allocation, StackFrame* frame_ptr)
1483{
1484 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1485
1486 if (!allocation->address.isValid() || !allocation->context.isValid())
1487 {
1488 if (log)
1489 log->Printf("RenderScriptRuntime::JITTypePointer - Failed to find allocation details");
1490 return false;
1491 }
1492
Ewan Crawford836d9652016-01-18 09:16:02 +00001493 const char* expr_cstr = runtimeExpressions[eExprAllocGetType];
1494 const int max_expr_size = 512; // Max expression size
1495 char buffer[max_expr_size];
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001496
Ewan Crawford836d9652016-01-18 09:16:02 +00001497 int chars_written = snprintf(buffer, max_expr_size, expr_cstr, *allocation->context.get(), *allocation->address.get());
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001498 if (chars_written < 0)
1499 {
1500 if (log)
1501 log->Printf("RenderScriptRuntime::JITDataPointer - Encoding error in snprintf()");
1502 return false;
1503 }
Ewan Crawford836d9652016-01-18 09:16:02 +00001504 else if (chars_written >= max_expr_size)
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001505 {
1506 if (log)
1507 log->Printf("RenderScriptRuntime::JITTypePointer - Expression too long");
1508 return false;
1509 }
1510
1511 uint64_t result = 0;
1512 if (!EvalRSExpression(buffer, frame_ptr, &result))
1513 return false;
1514
1515 addr_t type_ptr = static_cast<lldb::addr_t>(result);
1516 allocation->type_ptr = type_ptr;
1517
1518 return true;
1519}
1520
1521// JITs the RS runtime for information about the dimensions and type of an allocation
1522// Then sets dimension and element_ptr members in Allocation with the result.
1523// Returns true on success, false otherwise
1524bool
1525RenderScriptRuntime::JITTypePacked(AllocationDetails* allocation, StackFrame* frame_ptr)
1526{
1527 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1528
1529 if (!allocation->type_ptr.isValid() || !allocation->context.isValid())
1530 {
1531 if (log)
1532 log->Printf("RenderScriptRuntime::JITTypePacked - Failed to find allocation details");
1533 return false;
1534 }
1535
1536 // Expression is different depending on if device is 32 or 64 bit
1537 uint32_t archByteSize = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
1538 const unsigned int bits = archByteSize == 4 ? 32 : 64;
1539
1540 // We want 4 elements from packed data
1541 const unsigned int num_exprs = 4;
1542 assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1) && "Invalid number of expressions");
1543
Ewan Crawford836d9652016-01-18 09:16:02 +00001544 const int max_expr_size = 512; // Max expression size
1545 char buffer[num_exprs][max_expr_size];
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001546 uint64_t results[num_exprs];
1547
1548 for (unsigned int i = 0; i < num_exprs; ++i)
1549 {
Ewan Crawford836d9652016-01-18 09:16:02 +00001550 int chars_written = snprintf(buffer[i], max_expr_size, runtimeExpressions[eExprTypeDimX + i], bits,
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001551 *allocation->context.get(), *allocation->type_ptr.get());
1552 if (chars_written < 0)
1553 {
1554 if (log)
1555 log->Printf("RenderScriptRuntime::JITDataPointer - Encoding error in snprintf()");
1556 return false;
1557 }
Ewan Crawford836d9652016-01-18 09:16:02 +00001558 else if (chars_written >= max_expr_size)
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001559 {
1560 if (log)
1561 log->Printf("RenderScriptRuntime::JITTypePacked - Expression too long");
1562 return false;
1563 }
1564
1565 // Perform expression evaluation
1566 if (!EvalRSExpression(buffer[i], frame_ptr, &results[i]))
1567 return false;
1568 }
1569
1570 // Assign results to allocation members
1571 AllocationDetails::Dimension dims;
1572 dims.dim_1 = static_cast<uint32_t>(results[0]);
1573 dims.dim_2 = static_cast<uint32_t>(results[1]);
1574 dims.dim_3 = static_cast<uint32_t>(results[2]);
1575 allocation->dimension = dims;
1576
1577 addr_t elem_ptr = static_cast<lldb::addr_t>(results[3]);
Ewan Crawford8b244e22015-11-30 10:29:49 +00001578 allocation->element.element_ptr = elem_ptr;
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001579
1580 if (log)
1581 log->Printf("RenderScriptRuntime::JITTypePacked - dims (%u, %u, %u) Element*: 0x%" PRIx64,
1582 dims.dim_1, dims.dim_2, dims.dim_3, elem_ptr);
1583
1584 return true;
1585}
1586
1587// JITs the RS runtime for information about the Element of an allocation
Ewan Crawford8b244e22015-11-30 10:29:49 +00001588// Then sets type, type_vec_size, field_count and type_kind members in Element with the result.
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001589// Returns true on success, false otherwise
1590bool
Ewan Crawford8b244e22015-11-30 10:29:49 +00001591RenderScriptRuntime::JITElementPacked(Element& elem, const lldb::addr_t context, StackFrame* frame_ptr)
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001592{
1593 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1594
Ewan Crawford8b244e22015-11-30 10:29:49 +00001595 if (!elem.element_ptr.isValid())
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001596 {
1597 if (log)
1598 log->Printf("RenderScriptRuntime::JITElementPacked - Failed to find allocation details");
1599 return false;
1600 }
1601
Ewan Crawford8b244e22015-11-30 10:29:49 +00001602 // We want 4 elements from packed data
1603 const unsigned int num_exprs = 4;
1604 assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1) && "Invalid number of expressions");
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001605
Ewan Crawford836d9652016-01-18 09:16:02 +00001606 const int max_expr_size = 512; // Max expression size
1607 char buffer[num_exprs][max_expr_size];
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001608 uint64_t results[num_exprs];
1609
1610 for (unsigned int i = 0; i < num_exprs; i++)
1611 {
Ewan Crawford836d9652016-01-18 09:16:02 +00001612 int chars_written = snprintf(buffer[i], max_expr_size, runtimeExpressions[eExprElementType + i], context, *elem.element_ptr.get());
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001613 if (chars_written < 0)
1614 {
1615 if (log)
Ewan Crawford8b244e22015-11-30 10:29:49 +00001616 log->Printf("RenderScriptRuntime::JITElementPacked - Encoding error in snprintf()");
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001617 return false;
1618 }
Ewan Crawford836d9652016-01-18 09:16:02 +00001619 else if (chars_written >= max_expr_size)
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001620 {
1621 if (log)
1622 log->Printf("RenderScriptRuntime::JITElementPacked - Expression too long");
1623 return false;
1624 }
1625
1626 // Perform expression evaluation
1627 if (!EvalRSExpression(buffer[i], frame_ptr, &results[i]))
1628 return false;
1629 }
1630
1631 // Assign results to allocation members
Ewan Crawford8b244e22015-11-30 10:29:49 +00001632 elem.type = static_cast<RenderScriptRuntime::Element::DataType>(results[0]);
1633 elem.type_kind = static_cast<RenderScriptRuntime::Element::DataKind>(results[1]);
1634 elem.type_vec_size = static_cast<uint32_t>(results[2]);
1635 elem.field_count = static_cast<uint32_t>(results[3]);
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001636
1637 if (log)
Ewan Crawford8b244e22015-11-30 10:29:49 +00001638 log->Printf("RenderScriptRuntime::JITElementPacked - data type %u, pixel type %u, vector size %u, field count %u",
1639 *elem.type.get(), *elem.type_kind.get(), *elem.type_vec_size.get(), *elem.field_count.get());
1640
1641 // If this Element has subelements then JIT rsaElementGetSubElements() for details about its fields
1642 if (*elem.field_count.get() > 0 && !JITSubelements(elem, context, frame_ptr))
1643 return false;
1644
1645 return true;
1646}
1647
1648// JITs the RS runtime for information about the subelements/fields of a struct allocation
1649// This is necessary for infering the struct type so we can pretty print the allocation's contents.
1650// Returns true on success, false otherwise
1651bool
1652RenderScriptRuntime::JITSubelements(Element& elem, const lldb::addr_t context, StackFrame* frame_ptr)
1653{
1654 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1655
1656 if (!elem.element_ptr.isValid() || !elem.field_count.isValid())
1657 {
1658 if (log)
1659 log->Printf("RenderScriptRuntime::JITSubelements - Failed to find allocation details");
1660 return false;
1661 }
1662
1663 const short num_exprs = 3;
1664 assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1) && "Invalid number of expressions");
1665
Ewan Crawford836d9652016-01-18 09:16:02 +00001666 const int max_expr_size = 512; // Max expression size
1667 char expr_buffer[max_expr_size];
Ewan Crawford8b244e22015-11-30 10:29:49 +00001668 uint64_t results;
1669
1670 // Iterate over struct fields.
1671 const uint32_t field_count = *elem.field_count.get();
1672 for (unsigned int field_index = 0; field_index < field_count; ++field_index)
1673 {
1674 Element child;
1675 for (unsigned int expr_index = 0; expr_index < num_exprs; ++expr_index)
1676 {
Ewan Crawford836d9652016-01-18 09:16:02 +00001677 int chars_written = snprintf(expr_buffer, max_expr_size, runtimeExpressions[eExprSubelementsId + expr_index],
Ewan Crawford8b244e22015-11-30 10:29:49 +00001678 field_count, field_count, field_count,
1679 context, *elem.element_ptr.get(), field_count, field_index);
1680 if (chars_written < 0)
1681 {
1682 if (log)
1683 log->Printf("RenderScriptRuntime::JITSubelements - Encoding error in snprintf()");
1684 return false;
1685 }
Ewan Crawford836d9652016-01-18 09:16:02 +00001686 else if (chars_written >= max_expr_size)
Ewan Crawford8b244e22015-11-30 10:29:49 +00001687 {
1688 if (log)
1689 log->Printf("RenderScriptRuntime::JITSubelements - Expression too long");
1690 return false;
1691 }
1692
1693 // Perform expression evaluation
1694 if (!EvalRSExpression(expr_buffer, frame_ptr, &results))
1695 return false;
1696
1697 if (log)
1698 log->Printf("RenderScriptRuntime::JITSubelements - Expr result 0x%" PRIx64, results);
1699
1700 switch(expr_index)
1701 {
1702 case 0: // Element* of child
1703 child.element_ptr = static_cast<addr_t>(results);
1704 break;
1705 case 1: // Name of child
1706 {
1707 lldb::addr_t address = static_cast<addr_t>(results);
1708 Error err;
1709 std::string name;
1710 GetProcess()->ReadCStringFromMemory(address, name, err);
1711 if (!err.Fail())
1712 child.type_name = ConstString(name);
1713 else
1714 {
1715 if (log)
1716 log->Printf("RenderScriptRuntime::JITSubelements - Warning: Couldn't read field name");
1717 }
1718 break;
1719 }
1720 case 2: // Array size of child
1721 child.array_size = static_cast<uint32_t>(results);
1722 break;
1723 }
1724 }
1725
1726 // We need to recursively JIT each Element field of the struct since
1727 // structs can be nested inside structs.
1728 if (!JITElementPacked(child, context, frame_ptr))
1729 return false;
1730 elem.children.push_back(child);
1731 }
1732
1733 // Try to infer the name of the struct type so we can pretty print the allocation contents.
1734 FindStructTypeName(elem, frame_ptr);
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001735
1736 return true;
1737}
1738
Ewan Crawforda0f08672015-10-16 08:28:47 +00001739// JITs the RS runtime for the address of the last element in the allocation.
1740// The `elem_size` paramter represents the size of a single element, including padding.
1741// Which is needed as an offset from the last element pointer.
1742// Using this offset minus the starting address we can calculate the size of the allocation.
1743// Returns true on success, false otherwise
1744bool
Ewan Crawford8b244e22015-11-30 10:29:49 +00001745RenderScriptRuntime::JITAllocationSize(AllocationDetails* allocation, StackFrame* frame_ptr)
Ewan Crawforda0f08672015-10-16 08:28:47 +00001746{
1747 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1748
1749 if (!allocation->address.isValid() || !allocation->dimension.isValid()
Ewan Crawford8b244e22015-11-30 10:29:49 +00001750 || !allocation->data_ptr.isValid() || !allocation->element.datum_size.isValid())
Ewan Crawforda0f08672015-10-16 08:28:47 +00001751 {
1752 if (log)
1753 log->Printf("RenderScriptRuntime::JITAllocationSize - Failed to find allocation details");
1754 return false;
1755 }
1756
Ewan Crawforda0f08672015-10-16 08:28:47 +00001757 // Find dimensions
1758 unsigned int dim_x = allocation->dimension.get()->dim_1;
1759 unsigned int dim_y = allocation->dimension.get()->dim_2;
1760 unsigned int dim_z = allocation->dimension.get()->dim_3;
1761
Ewan Crawford8b244e22015-11-30 10:29:49 +00001762 // Our plan of jitting the last element address doesn't seem to work for struct Allocations
1763 // Instead try to infer the size ourselves without any inter element padding.
1764 if (allocation->element.children.size() > 0)
1765 {
1766 if (dim_x == 0) dim_x = 1;
1767 if (dim_y == 0) dim_y = 1;
1768 if (dim_z == 0) dim_z = 1;
1769
1770 allocation->size = dim_x * dim_y * dim_z * *allocation->element.datum_size.get();
1771
1772 if (log)
1773 log->Printf("RenderScriptRuntime::JITAllocationSize - Infered size of struct allocation %u", *allocation->size.get());
1774
1775 return true;
1776 }
1777
Ewan Crawford836d9652016-01-18 09:16:02 +00001778 const char* expr_cstr = runtimeExpressions[eExprGetOffsetPtr];
1779 const int max_expr_size = 512;
1780 char buffer[max_expr_size];
Ewan Crawford8b244e22015-11-30 10:29:49 +00001781
Ewan Crawforda0f08672015-10-16 08:28:47 +00001782 // Calculate last element
1783 dim_x = dim_x == 0 ? 0 : dim_x - 1;
1784 dim_y = dim_y == 0 ? 0 : dim_y - 1;
1785 dim_z = dim_z == 0 ? 0 : dim_z - 1;
1786
Ewan Crawford836d9652016-01-18 09:16:02 +00001787 int chars_written = snprintf(buffer, max_expr_size, expr_cstr, *allocation->address.get(),
Ewan Crawforda0f08672015-10-16 08:28:47 +00001788 dim_x, dim_y, dim_z);
1789 if (chars_written < 0)
1790 {
1791 if (log)
1792 log->Printf("RenderScriptRuntime::JITAllocationSize - Encoding error in snprintf()");
1793 return false;
1794 }
Ewan Crawford836d9652016-01-18 09:16:02 +00001795 else if (chars_written >= max_expr_size)
Ewan Crawforda0f08672015-10-16 08:28:47 +00001796 {
1797 if (log)
1798 log->Printf("RenderScriptRuntime::JITAllocationSize - Expression too long");
1799 return false;
1800 }
1801
1802 uint64_t result = 0;
1803 if (!EvalRSExpression(buffer, frame_ptr, &result))
1804 return false;
1805
1806 addr_t mem_ptr = static_cast<lldb::addr_t>(result);
1807 // Find pointer to last element and add on size of an element
Ewan Crawford8b244e22015-11-30 10:29:49 +00001808 allocation->size = static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()) + *allocation->element.datum_size.get();
Ewan Crawforda0f08672015-10-16 08:28:47 +00001809
1810 return true;
1811}
1812
1813// JITs the RS runtime for information about the stride between rows in the allocation.
1814// This is done to detect padding, since allocated memory is 16-byte aligned.
1815// Returns true on success, false otherwise
1816bool
1817RenderScriptRuntime::JITAllocationStride(AllocationDetails* allocation, StackFrame* frame_ptr)
1818{
1819 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1820
1821 if (!allocation->address.isValid() || !allocation->data_ptr.isValid())
1822 {
1823 if (log)
1824 log->Printf("RenderScriptRuntime::JITAllocationStride - Failed to find allocation details");
1825 return false;
1826 }
1827
Ewan Crawford836d9652016-01-18 09:16:02 +00001828 const char* expr_cstr = runtimeExpressions[eExprGetOffsetPtr];
1829 const int max_expr_size = 512; // Max expression size
1830 char buffer[max_expr_size];
Ewan Crawforda0f08672015-10-16 08:28:47 +00001831
Ewan Crawford836d9652016-01-18 09:16:02 +00001832 int chars_written = snprintf(buffer, max_expr_size, expr_cstr, *allocation->address.get(),
Ewan Crawforda0f08672015-10-16 08:28:47 +00001833 0, 1, 0);
1834 if (chars_written < 0)
1835 {
1836 if (log)
1837 log->Printf("RenderScriptRuntime::JITAllocationStride - Encoding error in snprintf()");
1838 return false;
1839 }
Ewan Crawford836d9652016-01-18 09:16:02 +00001840 else if (chars_written >= max_expr_size)
Ewan Crawforda0f08672015-10-16 08:28:47 +00001841 {
1842 if (log)
1843 log->Printf("RenderScriptRuntime::JITAllocationStride - Expression too long");
1844 return false;
1845 }
1846
1847 uint64_t result = 0;
1848 if (!EvalRSExpression(buffer, frame_ptr, &result))
1849 return false;
1850
1851 addr_t mem_ptr = static_cast<lldb::addr_t>(result);
1852 allocation->stride = static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get());
1853
1854 return true;
1855}
1856
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001857// JIT all the current runtime info regarding an allocation
1858bool
1859RenderScriptRuntime::RefreshAllocation(AllocationDetails* allocation, StackFrame* frame_ptr)
1860{
1861 // GetOffsetPointer()
1862 if (!JITDataPointer(allocation, frame_ptr))
1863 return false;
1864
1865 // rsaAllocationGetType()
1866 if (!JITTypePointer(allocation, frame_ptr))
1867 return false;
1868
1869 // rsaTypeGetNativeData()
1870 if (!JITTypePacked(allocation, frame_ptr))
1871 return false;
1872
1873 // rsaElementGetNativeData()
Ewan Crawford8b244e22015-11-30 10:29:49 +00001874 if (!JITElementPacked(allocation->element, *allocation->context.get(), frame_ptr))
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001875 return false;
1876
Ewan Crawford8b244e22015-11-30 10:29:49 +00001877 // Sets the datum_size member in Element
1878 SetElementSize(allocation->element);
1879
Ewan Crawford55232f02015-10-21 08:50:42 +00001880 // Use GetOffsetPointer() to infer size of the allocation
Ewan Crawford8b244e22015-11-30 10:29:49 +00001881 if (!JITAllocationSize(allocation, frame_ptr))
Ewan Crawford55232f02015-10-21 08:50:42 +00001882 return false;
1883
1884 return true;
1885}
1886
Ewan Crawford8b244e22015-11-30 10:29:49 +00001887// Function attempts to set the type_name member of the paramaterised Element object.
1888// This string should be the name of the struct type the Element represents.
1889// We need this string for pretty printing the Element to users.
1890void
1891RenderScriptRuntime::FindStructTypeName(Element& elem, StackFrame* frame_ptr)
Ewan Crawford55232f02015-10-21 08:50:42 +00001892{
Ewan Crawford8b244e22015-11-30 10:29:49 +00001893 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1894
1895 if (!elem.type_name.IsEmpty()) // Name already set
1896 return;
1897 else
Adrian McCarthyfe06b5a2015-11-30 22:18:43 +00001898 elem.type_name = Element::GetFallbackStructName(); // Default type name if we don't succeed
Ewan Crawford8b244e22015-11-30 10:29:49 +00001899
1900 // Find all the global variables from the script rs modules
1901 VariableList variable_list;
1902 for (auto module_sp : m_rsmodules)
1903 module_sp->m_module->FindGlobalVariables(RegularExpression("."), true, UINT32_MAX, variable_list);
1904
1905 // Iterate over all the global variables looking for one with a matching type to the Element.
1906 // We make the assumption a match exists since there needs to be a global variable to reflect the
1907 // struct type back into java host code.
1908 for (uint32_t var_index = 0; var_index < variable_list.GetSize(); ++var_index)
1909 {
1910 const VariableSP var_sp(variable_list.GetVariableAtIndex(var_index));
1911 if (!var_sp)
1912 continue;
1913
1914 ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp);
1915 if (!valobj_sp)
1916 continue;
1917
1918 // Find the number of variable fields.
1919 // If it has no fields, or more fields than our Element, then it can't be the struct we're looking for.
1920 // Don't check for equality since RS can add extra struct members for padding.
1921 size_t num_children = valobj_sp->GetNumChildren();
1922 if (num_children > elem.children.size() || num_children == 0)
1923 continue;
1924
1925 // Iterate over children looking for members with matching field names.
1926 // If all the field names match, this is likely the struct we want.
1927 //
1928 // TODO: This could be made more robust by also checking children data sizes, or array size
1929 bool found = true;
1930 for (size_t child_index = 0; child_index < num_children; ++child_index)
1931 {
1932 ValueObjectSP child = valobj_sp->GetChildAtIndex(child_index, true);
1933 if (!child || (child->GetName() != elem.children[child_index].type_name))
1934 {
1935 found = false;
1936 break;
1937 }
1938 }
1939
1940 // RS can add extra struct members for padding in the format '#rs_padding_[0-9]+'
1941 if (found && num_children < elem.children.size())
1942 {
1943 const unsigned int size_diff = elem.children.size() - num_children;
1944 if (log)
1945 log->Printf("RenderScriptRuntime::FindStructTypeName - %u padding struct entries", size_diff);
1946
1947 for (unsigned int padding_index = 0; padding_index < size_diff; ++padding_index)
1948 {
1949 const ConstString& name = elem.children[num_children + padding_index].type_name;
1950 if (strcmp(name.AsCString(), "#rs_padding") < 0)
1951 found = false;
1952 }
1953 }
1954
1955 // We've found a global var with matching type
1956 if (found)
1957 {
1958 // Dereference since our Element type isn't a pointer.
1959 if (valobj_sp->IsPointerType())
1960 {
1961 Error err;
1962 ValueObjectSP deref_valobj = valobj_sp->Dereference(err);
1963 if (!err.Fail())
1964 valobj_sp = deref_valobj;
1965 }
1966
1967 // Save name of variable in Element.
1968 elem.type_name = valobj_sp->GetTypeName();
1969 if (log)
1970 log->Printf("RenderScriptRuntime::FindStructTypeName - Element name set to %s", elem.type_name.AsCString());
1971
1972 return;
1973 }
1974 }
1975}
1976
1977// Function sets the datum_size member of Element. Representing the size of a single instance including padding.
1978// Assumes the relevant allocation information has already been jitted.
1979void
1980RenderScriptRuntime::SetElementSize(Element& elem)
1981{
1982 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1983 const Element::DataType type = *elem.type.get();
Ewan Crawford2e920712015-12-17 16:40:05 +00001984 assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT
Ewan Crawford55232f02015-10-21 08:50:42 +00001985 && "Invalid allocation type");
1986
Ewan Crawford8b244e22015-11-30 10:29:49 +00001987 const unsigned int vec_size = *elem.type_vec_size.get();
1988 unsigned int data_size = 0;
Ewan Crawford2e920712015-12-17 16:40:05 +00001989 unsigned int padding = 0;
Ewan Crawford55232f02015-10-21 08:50:42 +00001990
Ewan Crawford8b244e22015-11-30 10:29:49 +00001991 // Element is of a struct type, calculate size recursively.
1992 if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0))
1993 {
1994 for (Element& child : elem.children)
1995 {
1996 SetElementSize(child);
1997 const unsigned int array_size = child.array_size.isValid() ? *child.array_size.get() : 1;
1998 data_size += *child.datum_size.get() * array_size;
1999 }
2000 }
Ewan Crawford2e920712015-12-17 16:40:05 +00002001 else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 || type == Element::RS_TYPE_UNSIGNED_5_5_5_1 ||
2002 type == Element::RS_TYPE_UNSIGNED_4_4_4_4) // These have been packed already
2003 {
2004 data_size = AllocationDetails::RSTypeToFormat[type][eElementSize];
2005 }
2006 else if (type < Element::RS_TYPE_ELEMENT)
2007 {
Ewan Crawford8b244e22015-11-30 10:29:49 +00002008 data_size = vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize];
Ewan Crawford2e920712015-12-17 16:40:05 +00002009 if (vec_size == 3)
2010 padding = AllocationDetails::RSTypeToFormat[type][eElementSize];
2011 }
2012 else
2013 data_size = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
Ewan Crawford8b244e22015-11-30 10:29:49 +00002014
2015 elem.padding = padding;
2016 elem.datum_size = data_size + padding;
2017 if (log)
2018 log->Printf("RenderScriptRuntime::SetElementSize - element size set to %u", data_size + padding);
Ewan Crawford55232f02015-10-21 08:50:42 +00002019}
2020
2021// Given an allocation, this function copies the allocation contents from device into a buffer on the heap.
2022// Returning a shared pointer to the buffer containing the data.
2023std::shared_ptr<uint8_t>
2024RenderScriptRuntime::GetAllocationData(AllocationDetails* allocation, StackFrame* frame_ptr)
2025{
2026 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2027
2028 // JIT all the allocation details
Ewan Crawford8b590622015-12-10 10:20:39 +00002029 if (allocation->shouldRefresh())
Ewan Crawford55232f02015-10-21 08:50:42 +00002030 {
2031 if (log)
2032 log->Printf("RenderScriptRuntime::GetAllocationData - Allocation details not calculated yet, jitting info");
2033
2034 if (!RefreshAllocation(allocation, frame_ptr))
2035 {
2036 if (log)
2037 log->Printf("RenderScriptRuntime::GetAllocationData - Couldn't JIT allocation details");
2038 return nullptr;
2039 }
2040 }
2041
Ewan Crawford8b244e22015-11-30 10:29:49 +00002042 assert(allocation->data_ptr.isValid() && allocation->element.type.isValid() && allocation->element.type_vec_size.isValid()
Ewan Crawford55232f02015-10-21 08:50:42 +00002043 && allocation->size.isValid() && "Allocation information not available");
2044
2045 // Allocate a buffer to copy data into
2046 const unsigned int size = *allocation->size.get();
2047 std::shared_ptr<uint8_t> buffer(new uint8_t[size]);
2048 if (!buffer)
2049 {
2050 if (log)
2051 log->Printf("RenderScriptRuntime::GetAllocationData - Couldn't allocate a %u byte buffer", size);
2052 return nullptr;
2053 }
2054
2055 // Read the inferior memory
2056 Error error;
2057 lldb::addr_t data_ptr = *allocation->data_ptr.get();
2058 GetProcess()->ReadMemory(data_ptr, buffer.get(), size, error);
2059 if (error.Fail())
2060 {
2061 if (log)
2062 log->Printf("RenderScriptRuntime::GetAllocationData - '%s' Couldn't read %u bytes of allocation data from 0x%" PRIx64,
2063 error.AsCString(), size, data_ptr);
2064 return nullptr;
2065 }
2066
2067 return buffer;
2068}
2069
2070// Function copies data from a binary file into an allocation.
2071// There is a header at the start of the file, FileHeader, before the data content itself.
2072// Information from this header is used to display warnings to the user about incompatabilities
2073bool
2074RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, const char* filename, StackFrame* frame_ptr)
2075{
2076 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2077
2078 // Find allocation with the given id
2079 AllocationDetails* alloc = FindAllocByID(strm, alloc_id);
2080 if (!alloc)
2081 return false;
2082
2083 if (log)
2084 log->Printf("RenderScriptRuntime::LoadAllocation - Found allocation 0x%" PRIx64, *alloc->address.get());
2085
2086 // JIT all the allocation details
Ewan Crawford8b590622015-12-10 10:20:39 +00002087 if (alloc->shouldRefresh())
Ewan Crawford55232f02015-10-21 08:50:42 +00002088 {
2089 if (log)
2090 log->Printf("RenderScriptRuntime::LoadAllocation - Allocation details not calculated yet, jitting info");
2091
2092 if (!RefreshAllocation(alloc, frame_ptr))
2093 {
2094 if (log)
2095 log->Printf("RenderScriptRuntime::LoadAllocation - Couldn't JIT allocation details");
Sylvestre Ledru4cfc9192015-10-26 08:49:04 +00002096 return false;
Ewan Crawford55232f02015-10-21 08:50:42 +00002097 }
2098 }
2099
Ewan Crawford8b244e22015-11-30 10:29:49 +00002100 assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && alloc->element.type_vec_size.isValid()
2101 && alloc->size.isValid() && alloc->element.datum_size.isValid() && "Allocation information not available");
Ewan Crawford55232f02015-10-21 08:50:42 +00002102
2103 // Check we can read from file
2104 FileSpec file(filename, true);
2105 if (!file.Exists())
2106 {
2107 strm.Printf("Error: File %s does not exist", filename);
2108 strm.EOL();
2109 return false;
2110 }
2111
2112 if (!file.Readable())
2113 {
2114 strm.Printf("Error: File %s does not have readable permissions", filename);
2115 strm.EOL();
2116 return false;
2117 }
2118
2119 // Read file into data buffer
2120 DataBufferSP data_sp(file.ReadFileContents());
2121
2122 // Cast start of buffer to FileHeader and use pointer to read metadata
2123 void* file_buffer = data_sp->GetBytes();
Ewan Crawford26e52a72016-01-07 10:19:09 +00002124 if (file_buffer == NULL || data_sp->GetByteSize() <
2125 (sizeof(AllocationDetails::FileHeader) + sizeof(AllocationDetails::ElementHeader)))
2126 {
2127 strm.Printf("Error: File %s does not contain enough data for header", filename);
2128 strm.EOL();
2129 return false;
2130 }
2131 const AllocationDetails::FileHeader* file_header = static_cast<AllocationDetails::FileHeader*>(file_buffer);
Ewan Crawford55232f02015-10-21 08:50:42 +00002132
Ewan Crawford26e52a72016-01-07 10:19:09 +00002133 // Check file starts with ascii characters "RSAD"
2134 if (file_header->ident[0] != 'R' || file_header->ident[1] != 'S' || file_header->ident[2] != 'A'
2135 || file_header->ident[3] != 'D')
2136 {
2137 strm.Printf("Error: File doesn't contain identifier for an RS allocation dump. Are you sure this is the correct file?");
2138 strm.EOL();
2139 return false;
2140 }
2141
2142 // Look at the type of the root element in the header
2143 AllocationDetails::ElementHeader root_element_header;
2144 memcpy(&root_element_header, static_cast<uint8_t*>(file_buffer) + sizeof(AllocationDetails::FileHeader),
2145 sizeof(AllocationDetails::ElementHeader));
Ewan Crawford55232f02015-10-21 08:50:42 +00002146
2147 if (log)
2148 log->Printf("RenderScriptRuntime::LoadAllocation - header type %u, element size %u",
Ewan Crawford26e52a72016-01-07 10:19:09 +00002149 root_element_header.type, root_element_header.element_size);
Ewan Crawford55232f02015-10-21 08:50:42 +00002150
2151 // Check if the target allocation and file both have the same number of bytes for an Element
Ewan Crawford26e52a72016-01-07 10:19:09 +00002152 if (*alloc->element.datum_size.get() != root_element_header.element_size)
Ewan Crawford55232f02015-10-21 08:50:42 +00002153 {
2154 strm.Printf("Warning: Mismatched Element sizes - file %u bytes, allocation %u bytes",
Ewan Crawford26e52a72016-01-07 10:19:09 +00002155 root_element_header.element_size, *alloc->element.datum_size.get());
Ewan Crawford55232f02015-10-21 08:50:42 +00002156 strm.EOL();
2157 }
2158
Ewan Crawford26e52a72016-01-07 10:19:09 +00002159 // Check if the target allocation and file both have the same type
2160 const unsigned int alloc_type = static_cast<unsigned int>(*alloc->element.type.get());
2161 const unsigned int file_type = root_element_header.type;
2162
2163 if (file_type > Element::RS_TYPE_FONT)
2164 {
2165 strm.Printf("Warning: File has unknown allocation type");
2166 strm.EOL();
2167 }
2168 else if (alloc_type != file_type)
Ewan Crawford55232f02015-10-21 08:50:42 +00002169 {
Ewan Crawford2e920712015-12-17 16:40:05 +00002170 // Enum value isn't monotonous, so doesn't always index RsDataTypeToString array
Ewan Crawford26e52a72016-01-07 10:19:09 +00002171 unsigned int printable_target_type_index = alloc_type;
2172 unsigned int printable_head_type_index = file_type;
2173 if (alloc_type >= Element::RS_TYPE_ELEMENT && alloc_type <= Element::RS_TYPE_FONT)
Ewan Crawford2e920712015-12-17 16:40:05 +00002174 printable_target_type_index = static_cast<Element::DataType>(
Ewan Crawford26e52a72016-01-07 10:19:09 +00002175 (alloc_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1);
Ewan Crawford2e920712015-12-17 16:40:05 +00002176
Ewan Crawford26e52a72016-01-07 10:19:09 +00002177 if (file_type >= Element::RS_TYPE_ELEMENT && file_type <= Element::RS_TYPE_FONT)
Ewan Crawford2e920712015-12-17 16:40:05 +00002178 printable_head_type_index = static_cast<Element::DataType>(
Ewan Crawford26e52a72016-01-07 10:19:09 +00002179 (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1);
Ewan Crawford2e920712015-12-17 16:40:05 +00002180
2181 const char* file_type_cstr = AllocationDetails::RsDataTypeToString[printable_head_type_index][0];
2182 const char* target_type_cstr = AllocationDetails::RsDataTypeToString[printable_target_type_index][0];
Ewan Crawford55232f02015-10-21 08:50:42 +00002183
2184 strm.Printf("Warning: Mismatched Types - file '%s' type, allocation '%s' type",
Ewan Crawford2e920712015-12-17 16:40:05 +00002185 file_type_cstr, target_type_cstr);
Ewan Crawford55232f02015-10-21 08:50:42 +00002186 strm.EOL();
2187 }
2188
Ewan Crawford26e52a72016-01-07 10:19:09 +00002189 // Advance buffer past header
2190 file_buffer = static_cast<uint8_t*>(file_buffer) + file_header->hdr_size;
2191
Ewan Crawford55232f02015-10-21 08:50:42 +00002192 // Calculate size of allocation data in file
Ewan Crawford26e52a72016-01-07 10:19:09 +00002193 size_t length = data_sp->GetByteSize() - file_header->hdr_size;
Ewan Crawford55232f02015-10-21 08:50:42 +00002194
2195 // Check if the target allocation and file both have the same total data size.
2196 const unsigned int alloc_size = *alloc->size.get();
2197 if (alloc_size != length)
2198 {
2199 strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64 " bytes, allocation 0x%x bytes",
Jason Molendaeba832b2015-10-29 00:13:42 +00002200 (uint64_t) length, alloc_size);
Ewan Crawford55232f02015-10-21 08:50:42 +00002201 strm.EOL();
2202 length = alloc_size < length ? alloc_size : length; // Set length to copy to minimum
2203 }
2204
2205 // Copy file data from our buffer into the target allocation.
2206 lldb::addr_t alloc_data = *alloc->data_ptr.get();
2207 Error error;
2208 size_t bytes_written = GetProcess()->WriteMemory(alloc_data, file_buffer, length, error);
2209 if (!error.Success() || bytes_written != length)
2210 {
2211 strm.Printf("Error: Couldn't write data to allocation %s", error.AsCString());
2212 strm.EOL();
2213 return false;
2214 }
2215
2216 strm.Printf("Contents of file '%s' read into allocation %u", filename, alloc->id);
2217 strm.EOL();
2218
2219 return true;
2220}
2221
Ewan Crawford26e52a72016-01-07 10:19:09 +00002222// Function takes as parameters a byte buffer, which will eventually be written to file as the element header,
2223// an offset into that buffer, and an Element that will be saved into the buffer at the parametrised offset.
2224// Return value is the new offset after writing the element into the buffer.
2225// Elements are saved to the file as the ElementHeader struct followed by offsets to the structs of all the element's children.
2226size_t
2227RenderScriptRuntime::PopulateElementHeaders(const std::shared_ptr<uint8_t> header_buffer, size_t offset, const Element& elem)
2228{
2229 // File struct for an element header with all the relevant details copied from elem.
2230 // We assume members are valid already.
2231 AllocationDetails::ElementHeader elem_header;
2232 elem_header.type = *elem.type.get();
2233 elem_header.kind = *elem.type_kind.get();
2234 elem_header.element_size = *elem.datum_size.get();
2235 elem_header.vector_size = *elem.type_vec_size.get();
2236 elem_header.array_size = elem.array_size.isValid() ? *elem.array_size.get() : 0;
2237 const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader);
2238
2239 // Copy struct into buffer and advance offset
2240 // We assume that header_buffer has been checked for NULL before this method is called
2241 memcpy(header_buffer.get() + offset, &elem_header, elem_header_size);
2242 offset += elem_header_size;
2243
2244 // Starting offset of child ElementHeader struct
2245 size_t child_offset = offset + ((elem.children.size() + 1) * sizeof(uint32_t));
2246 for (const RenderScriptRuntime::Element& child : elem.children)
2247 {
2248 // Recursively populate the buffer with the element header structs of children.
2249 // Then save the offsets where they were set after the parent element header.
2250 memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t));
2251 offset += sizeof(uint32_t);
2252
2253 child_offset = PopulateElementHeaders(header_buffer, child_offset, child);
2254 }
2255
2256 // Zero indicates no more children
2257 memset(header_buffer.get() + offset, 0, sizeof(uint32_t));
2258
2259 return child_offset;
2260}
2261
2262// Given an Element object this function returns the total size needed in the file header to store the element's details.
2263// Taking into account the size of the element header struct, plus the offsets to all the element's children.
2264// Function is recursive so that the size of all ancestors is taken into account.
2265size_t
2266RenderScriptRuntime::CalculateElementHeaderSize(const Element& elem)
2267{
2268 size_t size = (elem.children.size() + 1) * sizeof(uint32_t); // Offsets to children plus zero terminator
2269 size += sizeof(AllocationDetails::ElementHeader); // Size of header struct with type details
2270
2271 // Calculate recursively for all descendants
2272 for (const Element& child : elem.children)
2273 size += CalculateElementHeaderSize(child);
2274
2275 return size;
2276}
2277
Ewan Crawford55232f02015-10-21 08:50:42 +00002278// Function copies allocation contents into a binary file.
2279// This file can then be loaded later into a different allocation.
2280// There is a header, FileHeader, before the allocation data containing meta-data.
2281bool
2282RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, const char* filename, StackFrame* frame_ptr)
2283{
2284 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2285
2286 // Find allocation with the given id
2287 AllocationDetails* alloc = FindAllocByID(strm, alloc_id);
2288 if (!alloc)
2289 return false;
2290
2291 if (log)
2292 log->Printf("RenderScriptRuntime::SaveAllocation - Found allocation 0x%" PRIx64, *alloc->address.get());
2293
2294 // JIT all the allocation details
Ewan Crawford8b590622015-12-10 10:20:39 +00002295 if (alloc->shouldRefresh())
Ewan Crawford55232f02015-10-21 08:50:42 +00002296 {
2297 if (log)
2298 log->Printf("RenderScriptRuntime::SaveAllocation - Allocation details not calculated yet, jitting info");
2299
2300 if (!RefreshAllocation(alloc, frame_ptr))
2301 {
2302 if (log)
2303 log->Printf("RenderScriptRuntime::SaveAllocation - Couldn't JIT allocation details");
Sylvestre Ledru4cfc9192015-10-26 08:49:04 +00002304 return false;
Ewan Crawford55232f02015-10-21 08:50:42 +00002305 }
2306 }
2307
Ewan Crawford8b244e22015-11-30 10:29:49 +00002308 assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && alloc->element.type_vec_size.isValid() && alloc->element.datum_size.get()
2309 && alloc->element.type_kind.isValid() && alloc->dimension.isValid() && "Allocation information not available");
Ewan Crawford55232f02015-10-21 08:50:42 +00002310
2311 // Check we can create writable file
2312 FileSpec file_spec(filename, true);
2313 File file(file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate | File::eOpenOptionTruncate);
2314 if (!file)
2315 {
2316 strm.Printf("Error: Failed to open '%s' for writing", filename);
2317 strm.EOL();
2318 return false;
2319 }
2320
2321 // Read allocation into buffer of heap memory
2322 const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
2323 if (!buffer)
2324 {
2325 strm.Printf("Error: Couldn't read allocation data into buffer");
2326 strm.EOL();
2327 return false;
2328 }
2329
2330 // Create the file header
2331 AllocationDetails::FileHeader head;
2332 head.ident[0] = 'R'; head.ident[1] = 'S'; head.ident[2] = 'A'; head.ident[3] = 'D';
Ewan Crawford2d623282015-10-21 10:27:10 +00002333 head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1);
2334 head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2);
2335 head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3);
Ewan Crawford26e52a72016-01-07 10:19:09 +00002336
2337 const size_t element_header_size = CalculateElementHeaderSize(alloc->element);
2338 assert((sizeof(AllocationDetails::FileHeader) + element_header_size) < UINT16_MAX && "Element header too large");
2339 head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) + element_header_size);
Ewan Crawford55232f02015-10-21 08:50:42 +00002340
2341 // Write the file header
2342 size_t num_bytes = sizeof(AllocationDetails::FileHeader);
Ewan Crawford26e52a72016-01-07 10:19:09 +00002343 if (log)
2344 log->Printf("RenderScriptRuntime::SaveAllocation - Writing File Header, 0x%zX bytes", num_bytes);
2345
2346 Error err = file.Write(&head, num_bytes);
2347 if (!err.Success())
2348 {
2349 strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename);
2350 strm.EOL();
2351 return false;
2352 }
2353
2354 // Create the headers describing the element type of the allocation.
2355 std::shared_ptr<uint8_t> element_header_buffer(new uint8_t[element_header_size]);
2356 if (element_header_buffer == nullptr)
2357 {
2358 strm.Printf("Internal Error: Couldn't allocate %zu bytes on the heap", element_header_size);
2359 strm.EOL();
2360 return false;
2361 }
2362
2363 PopulateElementHeaders(element_header_buffer, 0, alloc->element);
2364
2365 // Write headers for allocation element type to file
2366 num_bytes = element_header_size;
2367 if (log)
2368 log->Printf("RenderScriptRuntime::SaveAllocation - Writing Element Headers, 0x%zX bytes", num_bytes);
2369
2370 err = file.Write(element_header_buffer.get(), num_bytes);
Ewan Crawford55232f02015-10-21 08:50:42 +00002371 if (!err.Success())
2372 {
2373 strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename);
2374 strm.EOL();
2375 return false;
2376 }
2377
2378 // Write allocation data to file
2379 num_bytes = static_cast<size_t>(*alloc->size.get());
2380 if (log)
Ewan Crawford26e52a72016-01-07 10:19:09 +00002381 log->Printf("RenderScriptRuntime::SaveAllocation - Writing 0x%zX bytes", num_bytes);
Ewan Crawford55232f02015-10-21 08:50:42 +00002382
2383 err = file.Write(buffer.get(), num_bytes);
2384 if (!err.Success())
2385 {
2386 strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename);
2387 strm.EOL();
2388 return false;
2389 }
2390
2391 strm.Printf("Allocation written to file '%s'", filename);
2392 strm.EOL();
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002393 return true;
2394}
2395
Colin Riley5ec532a2015-04-09 16:49:25 +00002396bool
2397RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp)
2398{
Colin Riley4640cde2015-06-01 18:23:41 +00002399 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2400
Colin Riley5ec532a2015-04-09 16:49:25 +00002401 if (module_sp)
2402 {
2403 for (const auto &rs_module : m_rsmodules)
2404 {
Colin Riley4640cde2015-06-01 18:23:41 +00002405 if (rs_module->m_module == module_sp)
Ewan Crawford7dc77712015-09-10 10:08:48 +00002406 {
2407 // Check if the user has enabled automatically breaking on
2408 // all RS kernels.
2409 if (m_breakAllKernels)
2410 BreakOnModuleKernels(rs_module);
2411
Colin Riley5ec532a2015-04-09 16:49:25 +00002412 return false;
Ewan Crawford7dc77712015-09-10 10:08:48 +00002413 }
Colin Riley5ec532a2015-04-09 16:49:25 +00002414 }
Colin Rileyef20b082015-04-14 07:39:24 +00002415 bool module_loaded = false;
2416 switch (GetModuleKind(module_sp))
Colin Riley5ec532a2015-04-09 16:49:25 +00002417 {
Colin Rileyef20b082015-04-14 07:39:24 +00002418 case eModuleKindKernelObj:
2419 {
Colin Riley4640cde2015-06-01 18:23:41 +00002420 RSModuleDescriptorSP module_desc;
2421 module_desc.reset(new RSModuleDescriptor(module_sp));
2422 if (module_desc->ParseRSInfo())
Colin Rileyef20b082015-04-14 07:39:24 +00002423 {
2424 m_rsmodules.push_back(module_desc);
2425 module_loaded = true;
2426 }
Colin Riley4640cde2015-06-01 18:23:41 +00002427 if (module_loaded)
2428 {
2429 FixupScriptDetails(module_desc);
2430 }
Colin Rileyef20b082015-04-14 07:39:24 +00002431 break;
2432 }
2433 case eModuleKindDriver:
Colin Riley4640cde2015-06-01 18:23:41 +00002434 {
2435 if (!m_libRSDriver)
2436 {
2437 m_libRSDriver = module_sp;
2438 LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver);
2439 }
2440 break;
2441 }
Colin Rileyef20b082015-04-14 07:39:24 +00002442 case eModuleKindImpl:
Colin Riley4640cde2015-06-01 18:23:41 +00002443 {
2444 m_libRSCpuRef = module_sp;
2445 break;
2446 }
Colin Rileyef20b082015-04-14 07:39:24 +00002447 case eModuleKindLibRS:
Colin Riley4640cde2015-06-01 18:23:41 +00002448 {
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002449 if (!m_libRS)
Colin Riley4640cde2015-06-01 18:23:41 +00002450 {
2451 m_libRS = module_sp;
2452 static ConstString gDbgPresentStr("gDebuggerPresent");
2453 const Symbol* debug_present = m_libRS->FindFirstSymbolWithNameAndType(gDbgPresentStr, eSymbolTypeData);
2454 if (debug_present)
2455 {
2456 Error error;
2457 uint32_t flag = 0x00000001U;
2458 Target &target = GetProcess()->GetTarget();
Greg Clayton358cf1e2015-06-25 21:46:34 +00002459 addr_t addr = debug_present->GetLoadAddress(&target);
Colin Riley4640cde2015-06-01 18:23:41 +00002460 GetProcess()->WriteMemory(addr, &flag, sizeof(flag), error);
2461 if(error.Success())
2462 {
2463 if (log)
2464 log->Printf ("RenderScriptRuntime::LoadModule - Debugger present flag set on debugee");
2465
2466 m_debuggerPresentFlagged = true;
2467 }
2468 else if (log)
2469 {
2470 log->Printf ("RenderScriptRuntime::LoadModule - Error writing debugger present flags '%s' ", error.AsCString());
2471 }
2472 }
2473 else if (log)
2474 {
2475 log->Printf ("RenderScriptRuntime::LoadModule - Error writing debugger present flags - symbol not found");
2476 }
2477 }
2478 break;
2479 }
Colin Rileyef20b082015-04-14 07:39:24 +00002480 default:
2481 break;
Colin Riley5ec532a2015-04-09 16:49:25 +00002482 }
Colin Rileyef20b082015-04-14 07:39:24 +00002483 if (module_loaded)
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002484 Update();
Colin Rileyef20b082015-04-14 07:39:24 +00002485 return module_loaded;
Colin Riley5ec532a2015-04-09 16:49:25 +00002486 }
2487 return false;
2488}
2489
Colin Rileyef20b082015-04-14 07:39:24 +00002490void
2491RenderScriptRuntime::Update()
2492{
2493 if (m_rsmodules.size() > 0)
2494 {
2495 if (!m_initiated)
2496 {
2497 Initiate();
2498 }
2499 }
2500}
2501
Colin Riley5ec532a2015-04-09 16:49:25 +00002502// The maximum line length of an .rs.info packet
2503#define MAXLINE 500
2504
2505// The .rs.info symbol in renderscript modules contains a string which needs to be parsed.
2506// The string is basic and is parsed on a line by line basis.
2507bool
2508RSModuleDescriptor::ParseRSInfo()
2509{
2510 const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData);
2511 if (info_sym)
2512 {
Greg Clayton358cf1e2015-06-25 21:46:34 +00002513 const addr_t addr = info_sym->GetAddressRef().GetFileAddress();
Colin Riley5ec532a2015-04-09 16:49:25 +00002514 const addr_t size = info_sym->GetByteSize();
2515 const FileSpec fs = m_module->GetFileSpec();
2516
2517 DataBufferSP buffer = fs.ReadFileContents(addr, size);
2518
2519 if (!buffer)
2520 return false;
2521
2522 std::string info((const char *)buffer->GetBytes());
2523
2524 std::vector<std::string> info_lines;
Bruce Mitchenere8433cc2015-09-01 23:57:17 +00002525 size_t lpos = info.find('\n');
Colin Riley5ec532a2015-04-09 16:49:25 +00002526 while (lpos != std::string::npos)
2527 {
2528 info_lines.push_back(info.substr(0, lpos));
2529 info = info.substr(lpos + 1);
Bruce Mitchenere8433cc2015-09-01 23:57:17 +00002530 lpos = info.find('\n');
Colin Riley5ec532a2015-04-09 16:49:25 +00002531 }
2532 size_t offset = 0;
2533 while (offset < info_lines.size())
2534 {
2535 std::string line = info_lines[offset];
2536 // Parse directives
2537 uint32_t numDefns = 0;
2538 if (sscanf(line.c_str(), "exportVarCount: %u", &numDefns) == 1)
2539 {
2540 while (numDefns--)
Colin Riley4640cde2015-06-01 18:23:41 +00002541 m_globals.push_back(RSGlobalDescriptor(this, info_lines[++offset].c_str()));
Colin Riley5ec532a2015-04-09 16:49:25 +00002542 }
2543 else if (sscanf(line.c_str(), "exportFuncCount: %u", &numDefns) == 1)
2544 {
2545 }
2546 else if (sscanf(line.c_str(), "exportForEachCount: %u", &numDefns) == 1)
2547 {
2548 char name[MAXLINE];
2549 while (numDefns--)
2550 {
2551 uint32_t slot = 0;
2552 name[0] = '\0';
2553 if (sscanf(info_lines[++offset].c_str(), "%u - %s", &slot, &name[0]) == 2)
2554 {
Colin Riley4640cde2015-06-01 18:23:41 +00002555 m_kernels.push_back(RSKernelDescriptor(this, name, slot));
2556 }
2557 }
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002558 }
Colin Riley4640cde2015-06-01 18:23:41 +00002559 else if (sscanf(line.c_str(), "pragmaCount: %u", &numDefns) == 1)
2560 {
2561 char name[MAXLINE];
2562 char value[MAXLINE];
2563 while (numDefns--)
2564 {
2565 name[0] = '\0';
2566 value[0] = '\0';
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002567 if (sscanf(info_lines[++offset].c_str(), "%s - %s", &name[0], &value[0]) != 0
Colin Riley4640cde2015-06-01 18:23:41 +00002568 && (name[0] != '\0'))
2569 {
2570 m_pragmas[std::string(name)] = value;
Colin Riley5ec532a2015-04-09 16:49:25 +00002571 }
2572 }
2573 }
2574 else if (sscanf(line.c_str(), "objectSlotCount: %u", &numDefns) == 1)
2575 {
2576 }
2577
2578 offset++;
2579 }
2580 return m_kernels.size() > 0;
2581 }
2582 return false;
2583}
2584
2585bool
2586RenderScriptRuntime::ProbeModules(const ModuleList module_list)
2587{
2588 bool rs_found = false;
2589 size_t num_modules = module_list.GetSize();
2590 for (size_t i = 0; i < num_modules; i++)
2591 {
2592 auto module = module_list.GetModuleAtIndex(i);
2593 rs_found |= LoadModule(module);
2594 }
2595 return rs_found;
2596}
2597
2598void
Colin Riley4640cde2015-06-01 18:23:41 +00002599RenderScriptRuntime::Status(Stream &strm) const
2600{
2601 if (m_libRS)
2602 {
2603 strm.Printf("Runtime Library discovered.");
2604 strm.EOL();
2605 }
2606 if (m_libRSDriver)
2607 {
2608 strm.Printf("Runtime Driver discovered.");
2609 strm.EOL();
2610 }
2611 if (m_libRSCpuRef)
2612 {
2613 strm.Printf("CPU Reference Implementation discovered.");
2614 strm.EOL();
2615 }
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002616
Colin Riley4640cde2015-06-01 18:23:41 +00002617 if (m_runtimeHooks.size())
2618 {
2619 strm.Printf("Runtime functions hooked:");
2620 strm.EOL();
2621 for (auto b : m_runtimeHooks)
2622 {
2623 strm.Indent(b.second->defn->name);
2624 strm.EOL();
2625 }
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002626 }
Colin Riley4640cde2015-06-01 18:23:41 +00002627 else
2628 {
2629 strm.Printf("Runtime is not hooked.");
2630 strm.EOL();
2631 }
2632}
2633
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002634void
Colin Riley4640cde2015-06-01 18:23:41 +00002635RenderScriptRuntime::DumpContexts(Stream &strm) const
2636{
2637 strm.Printf("Inferred RenderScript Contexts:");
2638 strm.EOL();
2639 strm.IndentMore();
2640
2641 std::map<addr_t, uint64_t> contextReferences;
2642
Ewan Crawford78f339d2015-09-21 10:53:18 +00002643 // Iterate over all of the currently discovered scripts.
2644 // Note: We cant push or pop from m_scripts inside this loop or it may invalidate script.
2645 for (const auto & script : m_scripts)
Colin Riley4640cde2015-06-01 18:23:41 +00002646 {
Ewan Crawford78f339d2015-09-21 10:53:18 +00002647 if (!script->context.isValid())
2648 continue;
2649 lldb::addr_t context = *script->context;
2650
2651 if (contextReferences.find(context) != contextReferences.end())
Colin Riley4640cde2015-06-01 18:23:41 +00002652 {
Ewan Crawford78f339d2015-09-21 10:53:18 +00002653 contextReferences[context]++;
Colin Riley4640cde2015-06-01 18:23:41 +00002654 }
2655 else
2656 {
Ewan Crawford78f339d2015-09-21 10:53:18 +00002657 contextReferences[context] = 1;
Colin Riley4640cde2015-06-01 18:23:41 +00002658 }
2659 }
2660
2661 for (const auto& cRef : contextReferences)
2662 {
2663 strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances", cRef.first, cRef.second);
2664 strm.EOL();
2665 }
2666 strm.IndentLess();
2667}
2668
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002669void
Colin Riley4640cde2015-06-01 18:23:41 +00002670RenderScriptRuntime::DumpKernels(Stream &strm) const
2671{
2672 strm.Printf("RenderScript Kernels:");
2673 strm.EOL();
2674 strm.IndentMore();
2675 for (const auto &module : m_rsmodules)
2676 {
2677 strm.Printf("Resource '%s':",module->m_resname.c_str());
2678 strm.EOL();
2679 for (const auto &kernel : module->m_kernels)
2680 {
2681 strm.Indent(kernel.m_name.AsCString());
2682 strm.EOL();
2683 }
2684 }
2685 strm.IndentLess();
2686}
2687
Ewan Crawforda0f08672015-10-16 08:28:47 +00002688RenderScriptRuntime::AllocationDetails*
2689RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id)
2690{
2691 AllocationDetails* alloc = nullptr;
2692
2693 // See if we can find allocation using id as an index;
2694 if (alloc_id <= m_allocations.size() && alloc_id != 0
2695 && m_allocations[alloc_id-1]->id == alloc_id)
2696 {
2697 alloc = m_allocations[alloc_id-1].get();
2698 return alloc;
2699 }
2700
2701 // Fallback to searching
2702 for (const auto & a : m_allocations)
2703 {
2704 if (a->id == alloc_id)
2705 {
2706 alloc = a.get();
2707 break;
2708 }
2709 }
2710
2711 if (alloc == nullptr)
2712 {
2713 strm.Printf("Error: Couldn't find allocation with id matching %u", alloc_id);
2714 strm.EOL();
2715 }
2716
2717 return alloc;
2718}
2719
2720// Prints the contents of an allocation to the output stream, which may be a file
2721bool
2722RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame* frame_ptr, const uint32_t id)
2723{
2724 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2725
2726 // Check we can find the desired allocation
2727 AllocationDetails* alloc = FindAllocByID(strm, id);
2728 if (!alloc)
2729 return false; // FindAllocByID() will print error message for us here
2730
2731 if (log)
2732 log->Printf("RenderScriptRuntime::DumpAllocation - Found allocation 0x%" PRIx64, *alloc->address.get());
2733
2734 // Check we have information about the allocation, if not calculate it
Ewan Crawford8b590622015-12-10 10:20:39 +00002735 if (alloc->shouldRefresh())
Ewan Crawforda0f08672015-10-16 08:28:47 +00002736 {
2737 if (log)
2738 log->Printf("RenderScriptRuntime::DumpAllocation - Allocation details not calculated yet, jitting info");
2739
2740 // JIT all the allocation information
2741 if (!RefreshAllocation(alloc, frame_ptr))
2742 {
2743 strm.Printf("Error: Couldn't JIT allocation details");
2744 strm.EOL();
2745 return false;
2746 }
2747 }
2748
2749 // Establish format and size of each data element
Ewan Crawford8b244e22015-11-30 10:29:49 +00002750 const unsigned int vec_size = *alloc->element.type_vec_size.get();
2751 const Element::DataType type = *alloc->element.type.get();
Ewan Crawforda0f08672015-10-16 08:28:47 +00002752
Ewan Crawford2e920712015-12-17 16:40:05 +00002753 assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT
Ewan Crawforda0f08672015-10-16 08:28:47 +00002754 && "Invalid allocation type");
2755
Ewan Crawford2e920712015-12-17 16:40:05 +00002756 lldb::Format format;
2757 if (type >= Element::RS_TYPE_ELEMENT)
2758 format = eFormatHex;
2759 else
2760 format = vec_size == 1 ? static_cast<lldb::Format>(AllocationDetails::RSTypeToFormat[type][eFormatSingle])
2761 : static_cast<lldb::Format>(AllocationDetails::RSTypeToFormat[type][eFormatVector]);
Ewan Crawforda0f08672015-10-16 08:28:47 +00002762
Ewan Crawford8b244e22015-11-30 10:29:49 +00002763 const unsigned int data_size = *alloc->element.datum_size.get();
Ewan Crawforda0f08672015-10-16 08:28:47 +00002764
2765 if (log)
Ewan Crawford8b244e22015-11-30 10:29:49 +00002766 log->Printf("RenderScriptRuntime::DumpAllocation - Element size %u bytes, including padding", data_size);
Ewan Crawforda0f08672015-10-16 08:28:47 +00002767
Ewan Crawford55232f02015-10-21 08:50:42 +00002768 // Allocate a buffer to copy data into
2769 std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
2770 if (!buffer)
2771 {
Ewan Crawford2e920712015-12-17 16:40:05 +00002772 strm.Printf("Error: Couldn't read allocation data");
Ewan Crawford55232f02015-10-21 08:50:42 +00002773 strm.EOL();
2774 return false;
2775 }
2776
Ewan Crawforda0f08672015-10-16 08:28:47 +00002777 // Calculate stride between rows as there may be padding at end of rows since
2778 // allocated memory is 16-byte aligned
2779 if (!alloc->stride.isValid())
2780 {
2781 if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension
2782 alloc->stride = 0;
2783 else if (!JITAllocationStride(alloc, frame_ptr))
2784 {
2785 strm.Printf("Error: Couldn't calculate allocation row stride");
2786 strm.EOL();
2787 return false;
2788 }
2789 }
2790 const unsigned int stride = *alloc->stride.get();
Ewan Crawford8b244e22015-11-30 10:29:49 +00002791 const unsigned int size = *alloc->size.get(); // Size of whole allocation
2792 const unsigned int padding = alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0;
Ewan Crawforda0f08672015-10-16 08:28:47 +00002793 if (log)
Ewan Crawford8b244e22015-11-30 10:29:49 +00002794 log->Printf("RenderScriptRuntime::DumpAllocation - stride %u bytes, size %u bytes, padding %u", stride, size, padding);
Ewan Crawforda0f08672015-10-16 08:28:47 +00002795
Ewan Crawforda0f08672015-10-16 08:28:47 +00002796 // Find dimensions used to index loops, so need to be non-zero
2797 unsigned int dim_x = alloc->dimension.get()->dim_1;
2798 dim_x = dim_x == 0 ? 1 : dim_x;
2799
2800 unsigned int dim_y = alloc->dimension.get()->dim_2;
2801 dim_y = dim_y == 0 ? 1 : dim_y;
2802
2803 unsigned int dim_z = alloc->dimension.get()->dim_3;
2804 dim_z = dim_z == 0 ? 1 : dim_z;
2805
Ewan Crawford55232f02015-10-21 08:50:42 +00002806 // Use data extractor to format output
2807 const uint32_t archByteSize = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
2808 DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(), archByteSize);
2809
Ewan Crawforda0f08672015-10-16 08:28:47 +00002810 unsigned int offset = 0; // Offset in buffer to next element to be printed
2811 unsigned int prev_row = 0; // Offset to the start of the previous row
2812
2813 // Iterate over allocation dimensions, printing results to user
2814 strm.Printf("Data (X, Y, Z):");
2815 for (unsigned int z = 0; z < dim_z; ++z)
2816 {
2817 for (unsigned int y = 0; y < dim_y; ++y)
2818 {
2819 // Use stride to index start of next row.
2820 if (!(y==0 && z==0))
2821 offset = prev_row + stride;
2822 prev_row = offset;
2823
2824 // Print each element in the row individually
2825 for (unsigned int x = 0; x < dim_x; ++x)
2826 {
2827 strm.Printf("\n(%u, %u, %u) = ", x, y, z);
Ewan Crawford8b244e22015-11-30 10:29:49 +00002828 if ((type == Element::RS_TYPE_NONE) && (alloc->element.children.size() > 0) &&
Adrian McCarthyfe06b5a2015-11-30 22:18:43 +00002829 (alloc->element.type_name != Element::GetFallbackStructName()))
Ewan Crawford8b244e22015-11-30 10:29:49 +00002830 {
2831 // Here we are dumping an Element of struct type.
2832 // This is done using expression evaluation with the name of the struct type and pointer to element.
2833
2834 // Don't print the name of the resulting expression, since this will be '$[0-9]+'
2835 DumpValueObjectOptions expr_options;
2836 expr_options.SetHideName(true);
2837
2838 // Setup expression as derefrencing a pointer cast to element address.
Ewan Crawford836d9652016-01-18 09:16:02 +00002839 const int max_expr_size = 512;
2840 char expr_char_buffer[max_expr_size];
2841 int chars_written = snprintf(expr_char_buffer, max_expr_size, "*(%s*) 0x%" PRIx64,
Ewan Crawford8b244e22015-11-30 10:29:49 +00002842 alloc->element.type_name.AsCString(), *alloc->data_ptr.get() + offset);
2843
Ewan Crawford836d9652016-01-18 09:16:02 +00002844 if (chars_written < 0 || chars_written >= max_expr_size)
Ewan Crawford8b244e22015-11-30 10:29:49 +00002845 {
2846 if (log)
2847 log->Printf("RenderScriptRuntime::DumpAllocation- Error in snprintf()");
2848 continue;
2849 }
2850
2851 // Evaluate expression
2852 ValueObjectSP expr_result;
2853 GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer, frame_ptr, expr_result);
2854
2855 // Print the results to our stream.
2856 expr_result->Dump(strm, expr_options);
2857 }
2858 else
2859 {
2860 alloc_data.Dump(&strm, offset, format, data_size - padding, 1, 1, LLDB_INVALID_ADDRESS, 0, 0);
2861 }
2862 offset += data_size;
Ewan Crawforda0f08672015-10-16 08:28:47 +00002863 }
2864 }
2865 }
2866 strm.EOL();
2867
Ewan Crawforda0f08672015-10-16 08:28:47 +00002868 return true;
2869}
2870
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002871// Prints infomation regarding all the currently loaded allocations.
2872// These details are gathered by jitting the runtime, which has as latency.
2873void
2874RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame* frame_ptr, bool recompute)
2875{
2876 strm.Printf("RenderScript Allocations:");
2877 strm.EOL();
2878 strm.IndentMore();
2879
2880 for (auto &alloc : m_allocations)
2881 {
2882 // JIT the allocation info if we haven't done it, or the user forces us to.
Ewan Crawford8b590622015-12-10 10:20:39 +00002883 bool do_refresh = alloc->shouldRefresh() || recompute;
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002884
2885 // JIT current allocation information
2886 if (do_refresh && !RefreshAllocation(alloc.get(), frame_ptr))
2887 {
2888 strm.Printf("Error: Couldn't evaluate details for allocation %u\n", alloc->id);
2889 continue;
2890 }
2891
2892 strm.Printf("%u:\n",alloc->id);
2893 strm.IndentMore();
2894
2895 strm.Indent("Context: ");
2896 if (!alloc->context.isValid())
2897 strm.Printf("unknown\n");
2898 else
2899 strm.Printf("0x%" PRIx64 "\n", *alloc->context.get());
2900
2901 strm.Indent("Address: ");
2902 if (!alloc->address.isValid())
2903 strm.Printf("unknown\n");
2904 else
2905 strm.Printf("0x%" PRIx64 "\n", *alloc->address.get());
2906
2907 strm.Indent("Data pointer: ");
2908 if (!alloc->data_ptr.isValid())
2909 strm.Printf("unknown\n");
2910 else
2911 strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get());
2912
2913 strm.Indent("Dimensions: ");
2914 if (!alloc->dimension.isValid())
2915 strm.Printf("unknown\n");
2916 else
2917 strm.Printf("(%d, %d, %d)\n", alloc->dimension.get()->dim_1,
2918 alloc->dimension.get()->dim_2,
2919 alloc->dimension.get()->dim_3);
2920
2921 strm.Indent("Data Type: ");
Ewan Crawford8b244e22015-11-30 10:29:49 +00002922 if (!alloc->element.type.isValid() || !alloc->element.type_vec_size.isValid())
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002923 strm.Printf("unknown\n");
2924 else
2925 {
Ewan Crawford8b244e22015-11-30 10:29:49 +00002926 const int vector_size = *alloc->element.type_vec_size.get();
Ewan Crawford2e920712015-12-17 16:40:05 +00002927 Element::DataType type = *alloc->element.type.get();
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002928
Ewan Crawford8b244e22015-11-30 10:29:49 +00002929 if (!alloc->element.type_name.IsEmpty())
2930 strm.Printf("%s\n", alloc->element.type_name.AsCString());
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002931 else
Ewan Crawford2e920712015-12-17 16:40:05 +00002932 {
2933 // Enum value isn't monotonous, so doesn't always index RsDataTypeToString array
2934 if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT)
2935 type = static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1);
2936
2937 if (type >= (sizeof(AllocationDetails::RsDataTypeToString) / sizeof(AllocationDetails::RsDataTypeToString[0]))
2938 || vector_size > 4 || vector_size < 1)
2939 strm.Printf("invalid type\n");
2940 else
2941 strm.Printf("%s\n", AllocationDetails::RsDataTypeToString[static_cast<unsigned int>(type)][vector_size-1]);
2942 }
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002943 }
2944
2945 strm.Indent("Data Kind: ");
Ewan Crawford8b244e22015-11-30 10:29:49 +00002946 if (!alloc->element.type_kind.isValid())
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002947 strm.Printf("unknown\n");
2948 else
2949 {
Ewan Crawford8b244e22015-11-30 10:29:49 +00002950 const Element::DataKind kind = *alloc->element.type_kind.get();
2951 if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV)
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002952 strm.Printf("invalid kind\n");
2953 else
2954 strm.Printf("%s\n", AllocationDetails::RsDataKindToString[static_cast<unsigned int>(kind)]);
2955 }
2956
2957 strm.EOL();
2958 strm.IndentLess();
2959 }
2960 strm.IndentLess();
2961}
2962
Ewan Crawford7dc77712015-09-10 10:08:48 +00002963// Set breakpoints on every kernel found in RS module
2964void
2965RenderScriptRuntime::BreakOnModuleKernels(const RSModuleDescriptorSP rsmodule_sp)
2966{
2967 for (const auto &kernel : rsmodule_sp->m_kernels)
2968 {
2969 // Don't set breakpoint on 'root' kernel
2970 if (strcmp(kernel.m_name.AsCString(), "root") == 0)
2971 continue;
2972
2973 CreateKernelBreakpoint(kernel.m_name);
2974 }
2975}
2976
2977// Method is internally called by the 'kernel breakpoint all' command to
2978// enable or disable breaking on all kernels.
2979//
2980// When do_break is true we want to enable this functionality.
2981// When do_break is false we want to disable it.
2982void
2983RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target)
2984{
Ewan Crawford54782db2015-09-16 10:02:57 +00002985 Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
Ewan Crawford7dc77712015-09-10 10:08:48 +00002986
2987 InitSearchFilter(target);
2988
2989 // Set breakpoints on all the kernels
2990 if (do_break && !m_breakAllKernels)
2991 {
2992 m_breakAllKernels = true;
2993
2994 for (const auto &module : m_rsmodules)
2995 BreakOnModuleKernels(module);
2996
2997 if (log)
2998 log->Printf("RenderScriptRuntime::SetBreakAllKernels(True)"
2999 "- breakpoints set on all currently loaded kernels");
3000 }
3001 else if (!do_break && m_breakAllKernels) // Breakpoints won't be set on any new kernels.
3002 {
3003 m_breakAllKernels = false;
3004
3005 if (log)
3006 log->Printf("RenderScriptRuntime::SetBreakAllKernels(False) - breakpoints no longer automatically set");
3007 }
3008}
3009
3010// Given the name of a kernel this function creates a breakpoint using our
3011// own breakpoint resolver, and returns the Breakpoint shared pointer.
3012BreakpointSP
3013RenderScriptRuntime::CreateKernelBreakpoint(const ConstString& name)
3014{
Ewan Crawford54782db2015-09-16 10:02:57 +00003015 Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
Ewan Crawford7dc77712015-09-10 10:08:48 +00003016
3017 if (!m_filtersp)
3018 {
3019 if (log)
3020 log->Printf("RenderScriptRuntime::CreateKernelBreakpoint - Error: No breakpoint search filter set");
3021 return nullptr;
3022 }
3023
3024 BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name));
3025 BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint(m_filtersp, resolver_sp, false, false, false);
3026
Ewan Crawford54782db2015-09-16 10:02:57 +00003027 // Give RS breakpoints a specific name, so the user can manipulate them as a group.
3028 Error err;
3029 if (!bp->AddName("RenderScriptKernel", err) && log)
3030 log->Printf("RenderScriptRuntime::CreateKernelBreakpoint: Error setting break name, %s", err.AsCString());
3031
Ewan Crawford7dc77712015-09-10 10:08:48 +00003032 return bp;
3033}
3034
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003035// Given an expression for a variable this function tries to calculate the variable's value.
3036// If this is possible it returns true and sets the uint64_t parameter to the variables unsigned value.
3037// Otherwise function returns false.
3038bool
3039RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp, const char* var_name, uint64_t& val)
3040{
3041 Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE));
3042 Error error;
3043 VariableSP var_sp;
3044
3045 // Find variable in stack frame
3046 ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath(var_name,
3047 eNoDynamicValues,
3048 StackFrame::eExpressionPathOptionCheckPtrVsMember |
3049 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
3050 var_sp,
3051 error));
3052 if (!error.Success())
3053 {
3054 if (log)
3055 log->Printf("RenderScriptRuntime::GetFrameVarAsUnsigned - Error, couldn't find '%s' in frame", var_name);
3056
3057 return false;
3058 }
3059
3060 // Find the unsigned int value for the variable
3061 bool success = false;
3062 val = value_sp->GetValueAsUnsigned(0, &success);
3063 if (!success)
3064 {
3065 if (log)
3066 log->Printf("RenderScriptRuntime::GetFrameVarAsUnsigned - Error, couldn't parse '%s' as an unsigned int", var_name);
3067
3068 return false;
3069 }
3070
3071 return true;
3072}
3073
3074// Callback when a kernel breakpoint hits and we're looking for a specific coordinate.
3075// Baton parameter contains a pointer to the target coordinate we want to break on.
3076// Function then checks the .expand frame for the current coordinate and breaks to user if it matches.
3077// Parameter 'break_id' is the id of the Breakpoint which made the callback.
3078// Parameter 'break_loc_id' is the id for the BreakpointLocation which was hit,
3079// a single logical breakpoint can have multiple addresses.
3080bool
3081RenderScriptRuntime::KernelBreakpointHit(void *baton, StoppointCallbackContext *ctx,
3082 user_id_t break_id, user_id_t break_loc_id)
3083{
3084 Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
3085
3086 assert(baton && "Error: null baton in conditional kernel breakpoint callback");
3087
3088 // Coordinate we want to stop on
3089 const int* target_coord = static_cast<const int*>(baton);
3090
3091 if (log)
3092 log->Printf("RenderScriptRuntime::KernelBreakpointHit - Break ID %" PRIu64 ", target coord (%d, %d, %d)",
3093 break_id, target_coord[0], target_coord[1], target_coord[2]);
3094
3095 // Go up one stack frame to .expand kernel
3096 ExecutionContext context(ctx->exe_ctx_ref);
3097 ThreadSP thread_sp = context.GetThreadSP();
3098 if (!thread_sp->SetSelectedFrameByIndex(1))
3099 {
3100 if (log)
3101 log->Printf("RenderScriptRuntime::KernelBreakpointHit - Error, couldn't go up stack frame");
3102
3103 return false;
3104 }
3105
3106 StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
3107 if (!frame_sp)
3108 {
3109 if (log)
3110 log->Printf("RenderScriptRuntime::KernelBreakpointHit - Error, couldn't select .expand stack frame");
3111
3112 return false;
3113 }
3114
3115 // Get values for variables in .expand frame that tell us the current kernel invocation
3116 const char* coord_expressions[] = {"rsIndex", "p->current.y", "p->current.z"};
3117 uint64_t current_coord[3] = {0, 0, 0};
3118
3119 for(int i = 0; i < 3; ++i)
3120 {
3121 if (!GetFrameVarAsUnsigned(frame_sp, coord_expressions[i], current_coord[i]))
3122 return false;
3123
3124 if (log)
3125 log->Printf("RenderScriptRuntime::KernelBreakpointHit, %s = %" PRIu64, coord_expressions[i], current_coord[i]);
3126 }
3127
3128 // Check if the current kernel invocation coordinate matches our target coordinate
3129 if (current_coord[0] == static_cast<uint64_t>(target_coord[0]) &&
3130 current_coord[1] == static_cast<uint64_t>(target_coord[1]) &&
3131 current_coord[2] == static_cast<uint64_t>(target_coord[2]))
3132 {
3133 if (log)
3134 log->Printf("RenderScriptRuntime::KernelBreakpointHit, BREAKING %" PRIu64 ", %" PRIu64 ", %" PRIu64,
3135 current_coord[0], current_coord[1], current_coord[2]);
3136
3137 BreakpointSP breakpoint_sp = context.GetTargetPtr()->GetBreakpointByID(break_id);
3138 assert(breakpoint_sp != nullptr && "Error: Couldn't find breakpoint matching break id for callback");
3139 breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint should only be hit once.
3140 return true;
3141 }
3142
3143 // No match on coordinate
3144 return false;
3145}
3146
3147// Tries to set a breakpoint on the start of a kernel, resolved using the kernel name.
3148// Argument 'coords', represents a three dimensional coordinate which can be used to specify
3149// a single kernel instance to break on. If this is set then we add a callback to the breakpoint.
Ewan Crawford98156582015-09-04 08:56:52 +00003150void
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003151RenderScriptRuntime::PlaceBreakpointOnKernel(Stream &strm, const char* name, const std::array<int,3> coords,
3152 Error& error, TargetSP target)
Colin Riley4640cde2015-06-01 18:23:41 +00003153{
Ewan Crawford98156582015-09-04 08:56:52 +00003154 if (!name)
Colin Riley4640cde2015-06-01 18:23:41 +00003155 {
3156 error.SetErrorString("invalid kernel name");
3157 return;
3158 }
3159
Ewan Crawford7dc77712015-09-10 10:08:48 +00003160 InitSearchFilter(target);
Ewan Crawford98156582015-09-04 08:56:52 +00003161
Colin Riley4640cde2015-06-01 18:23:41 +00003162 ConstString kernel_name(name);
Ewan Crawford7dc77712015-09-10 10:08:48 +00003163 BreakpointSP bp = CreateKernelBreakpoint(kernel_name);
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003164
3165 // We have a conditional breakpoint on a specific coordinate
3166 if (coords[0] != -1)
3167 {
3168 strm.Printf("Conditional kernel breakpoint on coordinate %d, %d, %d", coords[0], coords[1], coords[2]);
3169 strm.EOL();
3170
3171 // Allocate memory for the baton, and copy over coordinate
3172 int* baton = new int[3];
3173 baton[0] = coords[0]; baton[1] = coords[1]; baton[2] = coords[2];
3174
3175 // Create a callback that will be invoked everytime the breakpoint is hit.
3176 // The baton object passed to the handler is the target coordinate we want to break on.
3177 bp->SetCallback(KernelBreakpointHit, baton, true);
3178
3179 // Store a shared pointer to the baton, so the memory will eventually be cleaned up after destruction
3180 m_conditional_breaks[bp->GetID()] = std::shared_ptr<int>(baton);
3181 }
3182
Ewan Crawford98156582015-09-04 08:56:52 +00003183 if (bp)
3184 bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false);
Colin Riley4640cde2015-06-01 18:23:41 +00003185}
3186
3187void
Colin Riley5ec532a2015-04-09 16:49:25 +00003188RenderScriptRuntime::DumpModules(Stream &strm) const
3189{
3190 strm.Printf("RenderScript Modules:");
3191 strm.EOL();
3192 strm.IndentMore();
3193 for (const auto &module : m_rsmodules)
3194 {
Colin Riley4640cde2015-06-01 18:23:41 +00003195 module->Dump(strm);
Colin Riley5ec532a2015-04-09 16:49:25 +00003196 }
3197 strm.IndentLess();
3198}
3199
Ewan Crawford78f339d2015-09-21 10:53:18 +00003200RenderScriptRuntime::ScriptDetails*
3201RenderScriptRuntime::LookUpScript(addr_t address, bool create)
3202{
3203 for (const auto & s : m_scripts)
3204 {
3205 if (s->script.isValid())
3206 if (*s->script == address)
3207 return s.get();
3208 }
3209 if (create)
3210 {
3211 std::unique_ptr<ScriptDetails> s(new ScriptDetails);
3212 s->script = address;
3213 m_scripts.push_back(std::move(s));
Ewan Crawfordd10ca9d2015-09-22 13:36:35 +00003214 return m_scripts.back().get();
Ewan Crawford78f339d2015-09-21 10:53:18 +00003215 }
3216 return nullptr;
3217}
3218
3219RenderScriptRuntime::AllocationDetails*
3220RenderScriptRuntime::LookUpAllocation(addr_t address, bool create)
3221{
3222 for (const auto & a : m_allocations)
3223 {
3224 if (a->address.isValid())
3225 if (*a->address == address)
3226 return a.get();
3227 }
3228 if (create)
3229 {
3230 std::unique_ptr<AllocationDetails> a(new AllocationDetails);
3231 a->address = address;
3232 m_allocations.push_back(std::move(a));
Ewan Crawfordd10ca9d2015-09-22 13:36:35 +00003233 return m_allocations.back().get();
Ewan Crawford78f339d2015-09-21 10:53:18 +00003234 }
3235 return nullptr;
3236}
3237
Colin Riley5ec532a2015-04-09 16:49:25 +00003238void
3239RSModuleDescriptor::Dump(Stream &strm) const
3240{
3241 strm.Indent();
3242 m_module->GetFileSpec().Dump(&strm);
Colin Riley4640cde2015-06-01 18:23:41 +00003243 if(m_module->GetNumCompileUnits())
3244 {
3245 strm.Indent("Debug info loaded.");
3246 }
3247 else
3248 {
3249 strm.Indent("Debug info does not exist.");
3250 }
Colin Riley5ec532a2015-04-09 16:49:25 +00003251 strm.EOL();
3252 strm.IndentMore();
3253 strm.Indent();
Colin Riley189598e2015-04-12 22:05:58 +00003254 strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size()));
Colin Riley5ec532a2015-04-09 16:49:25 +00003255 strm.EOL();
3256 strm.IndentMore();
3257 for (const auto &global : m_globals)
3258 {
3259 global.Dump(strm);
3260 }
3261 strm.IndentLess();
3262 strm.Indent();
Colin Riley189598e2015-04-12 22:05:58 +00003263 strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size()));
Colin Riley5ec532a2015-04-09 16:49:25 +00003264 strm.EOL();
3265 strm.IndentMore();
3266 for (const auto &kernel : m_kernels)
3267 {
3268 kernel.Dump(strm);
3269 }
Colin Riley4640cde2015-06-01 18:23:41 +00003270 strm.Printf("Pragmas: %" PRIu64 , static_cast<uint64_t>(m_pragmas.size()));
3271 strm.EOL();
3272 strm.IndentMore();
3273 for (const auto &key_val : m_pragmas)
3274 {
3275 strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str());
3276 strm.EOL();
3277 }
Colin Riley5ec532a2015-04-09 16:49:25 +00003278 strm.IndentLess(4);
3279}
3280
3281void
3282RSGlobalDescriptor::Dump(Stream &strm) const
3283{
3284 strm.Indent(m_name.AsCString());
Colin Riley4640cde2015-06-01 18:23:41 +00003285 VariableList var_list;
3286 m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list);
3287 if (var_list.GetSize() == 1)
3288 {
3289 auto var = var_list.GetVariableAtIndex(0);
3290 auto type = var->GetType();
3291 if(type)
3292 {
3293 strm.Printf(" - ");
3294 type->DumpTypeName(&strm);
3295 }
3296 else
3297 {
3298 strm.Printf(" - Unknown Type");
3299 }
3300 }
3301 else
3302 {
3303 strm.Printf(" - variable identified, but not found in binary");
3304 const Symbol* s = m_module->m_module->FindFirstSymbolWithNameAndType(m_name, eSymbolTypeData);
3305 if (s)
3306 {
3307 strm.Printf(" (symbol exists) ");
3308 }
3309 }
3310
Colin Riley5ec532a2015-04-09 16:49:25 +00003311 strm.EOL();
3312}
3313
3314void
3315RSKernelDescriptor::Dump(Stream &strm) const
3316{
3317 strm.Indent(m_name.AsCString());
3318 strm.EOL();
3319}
3320
3321class CommandObjectRenderScriptRuntimeModuleProbe : public CommandObjectParsed
3322{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003323public:
Colin Riley5ec532a2015-04-09 16:49:25 +00003324 CommandObjectRenderScriptRuntimeModuleProbe(CommandInterpreter &interpreter)
3325 : CommandObjectParsed(interpreter, "renderscript module probe",
3326 "Initiates a Probe of all loaded modules for kernels and other renderscript objects.",
3327 "renderscript module probe",
Enrico Granatae87764f2015-05-27 05:04:35 +00003328 eCommandRequiresTarget | eCommandRequiresProcess | eCommandProcessMustBeLaunched)
Colin Riley5ec532a2015-04-09 16:49:25 +00003329 {
3330 }
3331
Eugene Zelenko222b9372015-10-27 00:45:06 +00003332 ~CommandObjectRenderScriptRuntimeModuleProbe() override = default;
Colin Riley5ec532a2015-04-09 16:49:25 +00003333
3334 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003335 DoExecute(Args &command, CommandReturnObject &result) override
Colin Riley5ec532a2015-04-09 16:49:25 +00003336 {
3337 const size_t argc = command.GetArgumentCount();
3338 if (argc == 0)
3339 {
3340 Target *target = m_exe_ctx.GetTargetPtr();
3341 RenderScriptRuntime *runtime =
3342 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
3343 auto module_list = target->GetImages();
3344 bool new_rs_details = runtime->ProbeModules(module_list);
3345 if (new_rs_details)
3346 {
3347 result.AppendMessage("New renderscript modules added to runtime model.");
3348 }
3349 result.SetStatus(eReturnStatusSuccessFinishResult);
3350 return true;
3351 }
3352
3353 result.AppendErrorWithFormat("'%s' takes no arguments", m_cmd_name.c_str());
3354 result.SetStatus(eReturnStatusFailed);
3355 return false;
3356 }
3357};
3358
3359class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed
3360{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003361public:
Colin Riley5ec532a2015-04-09 16:49:25 +00003362 CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter)
3363 : CommandObjectParsed(interpreter, "renderscript module dump",
3364 "Dumps renderscript specific information for all modules.", "renderscript module dump",
Enrico Granatae87764f2015-05-27 05:04:35 +00003365 eCommandRequiresProcess | eCommandProcessMustBeLaunched)
Colin Riley5ec532a2015-04-09 16:49:25 +00003366 {
3367 }
3368
Eugene Zelenko222b9372015-10-27 00:45:06 +00003369 ~CommandObjectRenderScriptRuntimeModuleDump() override = default;
Colin Riley5ec532a2015-04-09 16:49:25 +00003370
3371 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003372 DoExecute(Args &command, CommandReturnObject &result) override
Colin Riley5ec532a2015-04-09 16:49:25 +00003373 {
3374 RenderScriptRuntime *runtime =
3375 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
3376 runtime->DumpModules(result.GetOutputStream());
3377 result.SetStatus(eReturnStatusSuccessFinishResult);
3378 return true;
3379 }
3380};
3381
3382class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword
3383{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003384public:
Colin Riley5ec532a2015-04-09 16:49:25 +00003385 CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter)
3386 : CommandObjectMultiword(interpreter, "renderscript module", "Commands that deal with renderscript modules.",
3387 NULL)
3388 {
3389 LoadSubCommand("probe", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleProbe(interpreter)));
3390 LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump(interpreter)));
3391 }
3392
Eugene Zelenko222b9372015-10-27 00:45:06 +00003393 ~CommandObjectRenderScriptRuntimeModule() override = default;
Colin Riley5ec532a2015-04-09 16:49:25 +00003394};
3395
Colin Riley4640cde2015-06-01 18:23:41 +00003396class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed
3397{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003398public:
Colin Riley4640cde2015-06-01 18:23:41 +00003399 CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter)
3400 : CommandObjectParsed(interpreter, "renderscript kernel list",
3401 "Lists renderscript kernel names and associated script resources.", "renderscript kernel list",
3402 eCommandRequiresProcess | eCommandProcessMustBeLaunched)
3403 {
3404 }
3405
Eugene Zelenko222b9372015-10-27 00:45:06 +00003406 ~CommandObjectRenderScriptRuntimeKernelList() override = default;
Colin Riley4640cde2015-06-01 18:23:41 +00003407
3408 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003409 DoExecute(Args &command, CommandReturnObject &result) override
Colin Riley4640cde2015-06-01 18:23:41 +00003410 {
3411 RenderScriptRuntime *runtime =
3412 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
3413 runtime->DumpKernels(result.GetOutputStream());
3414 result.SetStatus(eReturnStatusSuccessFinishResult);
3415 return true;
3416 }
3417};
3418
Ewan Crawford7dc77712015-09-10 10:08:48 +00003419class CommandObjectRenderScriptRuntimeKernelBreakpointSet : public CommandObjectParsed
Colin Riley4640cde2015-06-01 18:23:41 +00003420{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003421public:
Ewan Crawford7dc77712015-09-10 10:08:48 +00003422 CommandObjectRenderScriptRuntimeKernelBreakpointSet(CommandInterpreter &interpreter)
3423 : CommandObjectParsed(interpreter, "renderscript kernel breakpoint set",
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003424 "Sets a breakpoint on a renderscript kernel.", "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]",
3425 eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), m_options(interpreter)
Colin Riley4640cde2015-06-01 18:23:41 +00003426 {
3427 }
3428
Eugene Zelenko222b9372015-10-27 00:45:06 +00003429 ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default;
3430
3431 Options*
3432 GetOptions() override
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003433 {
3434 return &m_options;
3435 }
3436
3437 class CommandOptions : public Options
3438 {
Eugene Zelenko222b9372015-10-27 00:45:06 +00003439 public:
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003440 CommandOptions(CommandInterpreter &interpreter) : Options(interpreter)
3441 {
3442 }
3443
Eugene Zelenko222b9372015-10-27 00:45:06 +00003444 ~CommandOptions() override = default;
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003445
Eugene Zelenko222b9372015-10-27 00:45:06 +00003446 Error
3447 SetOptionValue(uint32_t option_idx, const char *option_arg) override
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003448 {
3449 Error error;
3450 const int short_option = m_getopt_table[option_idx].val;
3451
3452 switch (short_option)
3453 {
3454 case 'c':
3455 if (!ParseCoordinate(option_arg))
3456 error.SetErrorStringWithFormat("Couldn't parse coordinate '%s', should be in format 'x,y,z'.", option_arg);
3457 break;
3458 default:
3459 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
3460 break;
3461 }
3462 return error;
3463 }
3464
3465 // -c takes an argument of the form 'num[,num][,num]'.
3466 // Where 'id_cstr' is this argument with the whitespace trimmed.
3467 // Missing coordinates are defaulted to zero.
3468 bool
3469 ParseCoordinate(const char* id_cstr)
3470 {
3471 RegularExpression regex;
3472 RegularExpression::Match regex_match(3);
3473
3474 bool matched = false;
3475 if(regex.Compile("^([0-9]+),([0-9]+),([0-9]+)$") && regex.Execute(id_cstr, &regex_match))
3476 matched = true;
3477 else if(regex.Compile("^([0-9]+),([0-9]+)$") && regex.Execute(id_cstr, &regex_match))
3478 matched = true;
3479 else if(regex.Compile("^([0-9]+)$") && regex.Execute(id_cstr, &regex_match))
3480 matched = true;
3481 for(uint32_t i = 0; i < 3; i++)
3482 {
3483 std::string group;
3484 if(regex_match.GetMatchAtIndex(id_cstr, i + 1, group))
3485 m_coord[i] = (uint32_t)strtoul(group.c_str(), NULL, 0);
3486 else
3487 m_coord[i] = 0;
3488 }
3489 return matched;
3490 }
3491
3492 void
Eugene Zelenko222b9372015-10-27 00:45:06 +00003493 OptionParsingStarting() override
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003494 {
3495 // -1 means the -c option hasn't been set
3496 m_coord[0] = -1;
3497 m_coord[1] = -1;
3498 m_coord[2] = -1;
3499 }
3500
3501 const OptionDefinition*
Eugene Zelenko222b9372015-10-27 00:45:06 +00003502 GetDefinitions() override
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003503 {
3504 return g_option_table;
3505 }
3506
3507 static OptionDefinition g_option_table[];
3508 std::array<int,3> m_coord;
3509 };
3510
Colin Riley4640cde2015-06-01 18:23:41 +00003511 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003512 DoExecute(Args &command, CommandReturnObject &result) override
Colin Riley4640cde2015-06-01 18:23:41 +00003513 {
3514 const size_t argc = command.GetArgumentCount();
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003515 if (argc < 1)
Colin Riley4640cde2015-06-01 18:23:41 +00003516 {
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003517 result.AppendErrorWithFormat("'%s' takes 1 argument of kernel name, and an optional coordinate.", m_cmd_name.c_str());
Colin Riley4640cde2015-06-01 18:23:41 +00003518 result.SetStatus(eReturnStatusFailed);
Colin Riley4640cde2015-06-01 18:23:41 +00003519 return false;
3520 }
3521
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003522 RenderScriptRuntime *runtime =
3523 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
3524
3525 Error error;
3526 runtime->PlaceBreakpointOnKernel(result.GetOutputStream(), command.GetArgumentAtIndex(0), m_options.m_coord,
3527 error, m_exe_ctx.GetTargetSP());
3528
3529 if (error.Success())
3530 {
3531 result.AppendMessage("Breakpoint(s) created");
3532 result.SetStatus(eReturnStatusSuccessFinishResult);
3533 return true;
3534 }
Colin Riley4640cde2015-06-01 18:23:41 +00003535 result.SetStatus(eReturnStatusFailed);
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003536 result.AppendErrorWithFormat("Error: %s", error.AsCString());
Colin Riley4640cde2015-06-01 18:23:41 +00003537 return false;
Eugene Zelenko222b9372015-10-27 00:45:06 +00003538 }
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003539
Eugene Zelenko222b9372015-10-27 00:45:06 +00003540private:
3541 CommandOptions m_options;
Colin Riley4640cde2015-06-01 18:23:41 +00003542};
3543
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003544OptionDefinition
3545CommandObjectRenderScriptRuntimeKernelBreakpointSet::CommandOptions::g_option_table[] =
3546{
3547 { LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeValue,
3548 "Set a breakpoint on a single invocation of the kernel with specified coordinate.\n"
3549 "Coordinate takes the form 'x[,y][,z] where x,y,z are positive integers representing kernel dimensions. "
3550 "Any unset dimensions will be defaulted to zero."},
3551 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
3552};
3553
Ewan Crawford7dc77712015-09-10 10:08:48 +00003554class CommandObjectRenderScriptRuntimeKernelBreakpointAll : public CommandObjectParsed
3555{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003556public:
Ewan Crawford7dc77712015-09-10 10:08:48 +00003557 CommandObjectRenderScriptRuntimeKernelBreakpointAll(CommandInterpreter &interpreter)
3558 : CommandObjectParsed(interpreter, "renderscript kernel breakpoint all",
3559 "Automatically sets a breakpoint on all renderscript kernels that are or will be loaded.\n"
3560 "Disabling option means breakpoints will no longer be set on any kernels loaded in the future, "
3561 "but does not remove currently set breakpoints.",
3562 "renderscript kernel breakpoint all <enable/disable>",
3563 eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused)
3564 {
3565 }
3566
Eugene Zelenko222b9372015-10-27 00:45:06 +00003567 ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default;
Ewan Crawford7dc77712015-09-10 10:08:48 +00003568
3569 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003570 DoExecute(Args &command, CommandReturnObject &result) override
Ewan Crawford7dc77712015-09-10 10:08:48 +00003571 {
3572 const size_t argc = command.GetArgumentCount();
3573 if (argc != 1)
3574 {
3575 result.AppendErrorWithFormat("'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str());
3576 result.SetStatus(eReturnStatusFailed);
3577 return false;
3578 }
3579
3580 RenderScriptRuntime *runtime =
3581 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript));
3582
3583 bool do_break = false;
3584 const char* argument = command.GetArgumentAtIndex(0);
3585 if (strcmp(argument, "enable") == 0)
3586 {
3587 do_break = true;
3588 result.AppendMessage("Breakpoints will be set on all kernels.");
3589 }
3590 else if (strcmp(argument, "disable") == 0)
3591 {
3592 do_break = false;
3593 result.AppendMessage("Breakpoints will not be set on any new kernels.");
3594 }
3595 else
3596 {
3597 result.AppendErrorWithFormat("Argument must be either 'enable' or 'disable'");
3598 result.SetStatus(eReturnStatusFailed);
3599 return false;
3600 }
3601
3602 runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP());
3603
3604 result.SetStatus(eReturnStatusSuccessFinishResult);
3605 return true;
3606 }
3607};
3608
3609class CommandObjectRenderScriptRuntimeKernelBreakpoint : public CommandObjectMultiword
3610{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003611public:
Ewan Crawford7dc77712015-09-10 10:08:48 +00003612 CommandObjectRenderScriptRuntimeKernelBreakpoint(CommandInterpreter &interpreter)
3613 : CommandObjectMultiword(interpreter, "renderscript kernel", "Commands that generate breakpoints on renderscript kernels.",
3614 nullptr)
3615 {
3616 LoadSubCommand("set", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet(interpreter)));
3617 LoadSubCommand("all", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll(interpreter)));
3618 }
3619
Eugene Zelenko222b9372015-10-27 00:45:06 +00003620 ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default;
Ewan Crawford7dc77712015-09-10 10:08:48 +00003621};
3622
Colin Riley4640cde2015-06-01 18:23:41 +00003623class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword
3624{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003625public:
Colin Riley4640cde2015-06-01 18:23:41 +00003626 CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter)
3627 : CommandObjectMultiword(interpreter, "renderscript kernel", "Commands that deal with renderscript kernels.",
3628 NULL)
3629 {
3630 LoadSubCommand("list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList(interpreter)));
3631 LoadSubCommand("breakpoint", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter)));
3632 }
3633
Eugene Zelenko222b9372015-10-27 00:45:06 +00003634 ~CommandObjectRenderScriptRuntimeKernel() override = default;
Colin Riley4640cde2015-06-01 18:23:41 +00003635};
3636
3637class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed
3638{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003639public:
Colin Riley4640cde2015-06-01 18:23:41 +00003640 CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter)
3641 : CommandObjectParsed(interpreter, "renderscript context dump",
3642 "Dumps renderscript context information.", "renderscript context dump",
3643 eCommandRequiresProcess | eCommandProcessMustBeLaunched)
3644 {
3645 }
3646
Eugene Zelenko222b9372015-10-27 00:45:06 +00003647 ~CommandObjectRenderScriptRuntimeContextDump() override = default;
Colin Riley4640cde2015-06-01 18:23:41 +00003648
3649 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003650 DoExecute(Args &command, CommandReturnObject &result) override
Colin Riley4640cde2015-06-01 18:23:41 +00003651 {
3652 RenderScriptRuntime *runtime =
3653 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
3654 runtime->DumpContexts(result.GetOutputStream());
3655 result.SetStatus(eReturnStatusSuccessFinishResult);
3656 return true;
3657 }
3658};
3659
3660class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword
3661{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003662public:
Colin Riley4640cde2015-06-01 18:23:41 +00003663 CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter)
3664 : CommandObjectMultiword(interpreter, "renderscript context", "Commands that deal with renderscript contexts.",
3665 NULL)
3666 {
3667 LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump(interpreter)));
3668 }
3669
Eugene Zelenko222b9372015-10-27 00:45:06 +00003670 ~CommandObjectRenderScriptRuntimeContext() override = default;
Colin Riley4640cde2015-06-01 18:23:41 +00003671};
3672
Ewan Crawforda0f08672015-10-16 08:28:47 +00003673class CommandObjectRenderScriptRuntimeAllocationDump : public CommandObjectParsed
3674{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003675public:
Ewan Crawforda0f08672015-10-16 08:28:47 +00003676 CommandObjectRenderScriptRuntimeAllocationDump(CommandInterpreter &interpreter)
3677 : CommandObjectParsed(interpreter, "renderscript allocation dump",
3678 "Displays the contents of a particular allocation", "renderscript allocation dump <ID>",
3679 eCommandRequiresProcess | eCommandProcessMustBeLaunched), m_options(interpreter)
3680 {
3681 }
3682
Eugene Zelenko222b9372015-10-27 00:45:06 +00003683 ~CommandObjectRenderScriptRuntimeAllocationDump() override = default;
3684
3685 Options*
3686 GetOptions() override
Ewan Crawforda0f08672015-10-16 08:28:47 +00003687 {
3688 return &m_options;
3689 }
3690
3691 class CommandOptions : public Options
3692 {
Eugene Zelenko222b9372015-10-27 00:45:06 +00003693 public:
Ewan Crawforda0f08672015-10-16 08:28:47 +00003694 CommandOptions(CommandInterpreter &interpreter) : Options(interpreter)
3695 {
3696 }
3697
Eugene Zelenko222b9372015-10-27 00:45:06 +00003698 ~CommandOptions() override = default;
Ewan Crawforda0f08672015-10-16 08:28:47 +00003699
Eugene Zelenko222b9372015-10-27 00:45:06 +00003700 Error
3701 SetOptionValue(uint32_t option_idx, const char *option_arg) override
Ewan Crawforda0f08672015-10-16 08:28:47 +00003702 {
3703 Error error;
3704 const int short_option = m_getopt_table[option_idx].val;
3705
3706 switch (short_option)
3707 {
3708 case 'f':
3709 m_outfile.SetFile(option_arg, true);
3710 if (m_outfile.Exists())
3711 {
3712 m_outfile.Clear();
3713 error.SetErrorStringWithFormat("file already exists: '%s'", option_arg);
3714 }
3715 break;
3716 default:
3717 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
3718 break;
3719 }
3720 return error;
3721 }
3722
3723 void
Eugene Zelenko222b9372015-10-27 00:45:06 +00003724 OptionParsingStarting() override
Ewan Crawforda0f08672015-10-16 08:28:47 +00003725 {
3726 m_outfile.Clear();
3727 }
3728
3729 const OptionDefinition*
Eugene Zelenko222b9372015-10-27 00:45:06 +00003730 GetDefinitions() override
Ewan Crawforda0f08672015-10-16 08:28:47 +00003731 {
3732 return g_option_table;
3733 }
3734
3735 static OptionDefinition g_option_table[];
3736 FileSpec m_outfile;
3737 };
3738
Ewan Crawforda0f08672015-10-16 08:28:47 +00003739 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003740 DoExecute(Args &command, CommandReturnObject &result) override
Ewan Crawforda0f08672015-10-16 08:28:47 +00003741 {
3742 const size_t argc = command.GetArgumentCount();
3743 if (argc < 1)
3744 {
3745 result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. As well as an optional -f argument",
3746 m_cmd_name.c_str());
3747 result.SetStatus(eReturnStatusFailed);
3748 return false;
3749 }
3750
3751 RenderScriptRuntime *runtime =
3752 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript));
3753
3754 const char* id_cstr = command.GetArgumentAtIndex(0);
3755 bool convert_complete = false;
3756 const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
3757 if (!convert_complete)
3758 {
3759 result.AppendErrorWithFormat("invalid allocation id argument '%s'", id_cstr);
3760 result.SetStatus(eReturnStatusFailed);
3761 return false;
3762 }
3763
3764 Stream* output_strm = nullptr;
3765 StreamFile outfile_stream;
3766 const FileSpec &outfile_spec = m_options.m_outfile; // Dump allocation to file instead
3767 if (outfile_spec)
3768 {
3769 // Open output file
3770 char path[256];
3771 outfile_spec.GetPath(path, sizeof(path));
3772 if (outfile_stream.GetFile().Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate).Success())
3773 {
3774 output_strm = &outfile_stream;
3775 result.GetOutputStream().Printf("Results written to '%s'", path);
3776 result.GetOutputStream().EOL();
3777 }
3778 else
3779 {
3780 result.AppendErrorWithFormat("Couldn't open file '%s'", path);
3781 result.SetStatus(eReturnStatusFailed);
3782 return false;
3783 }
3784 }
3785 else
3786 output_strm = &result.GetOutputStream();
3787
3788 assert(output_strm != nullptr);
3789 bool success = runtime->DumpAllocation(*output_strm, m_exe_ctx.GetFramePtr(), id);
3790
3791 if (success)
3792 result.SetStatus(eReturnStatusSuccessFinishResult);
3793 else
3794 result.SetStatus(eReturnStatusFailed);
3795
3796 return true;
3797 }
3798
Eugene Zelenko222b9372015-10-27 00:45:06 +00003799private:
3800 CommandOptions m_options;
Ewan Crawforda0f08672015-10-16 08:28:47 +00003801};
3802
3803OptionDefinition
3804CommandObjectRenderScriptRuntimeAllocationDump::CommandOptions::g_option_table[] =
3805{
3806 { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename,
3807 "Print results to specified file instead of command line."},
3808 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
3809};
3810
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003811class CommandObjectRenderScriptRuntimeAllocationList : public CommandObjectParsed
3812{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003813public:
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003814 CommandObjectRenderScriptRuntimeAllocationList(CommandInterpreter &interpreter)
3815 : CommandObjectParsed(interpreter, "renderscript allocation list",
3816 "List renderscript allocations and their information.", "renderscript allocation list",
3817 eCommandRequiresProcess | eCommandProcessMustBeLaunched), m_options(interpreter)
3818 {
3819 }
3820
Eugene Zelenko222b9372015-10-27 00:45:06 +00003821 ~CommandObjectRenderScriptRuntimeAllocationList() override = default;
3822
3823 Options*
3824 GetOptions() override
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003825 {
3826 return &m_options;
3827 }
3828
3829 class CommandOptions : public Options
3830 {
Eugene Zelenko222b9372015-10-27 00:45:06 +00003831 public:
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003832 CommandOptions(CommandInterpreter &interpreter) : Options(interpreter), m_refresh(false)
3833 {
3834 }
3835
Eugene Zelenko222b9372015-10-27 00:45:06 +00003836 ~CommandOptions() override = default;
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003837
Eugene Zelenko222b9372015-10-27 00:45:06 +00003838 Error
3839 SetOptionValue(uint32_t option_idx, const char *option_arg) override
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003840 {
3841 Error error;
3842 const int short_option = m_getopt_table[option_idx].val;
3843
3844 switch (short_option)
3845 {
3846 case 'r':
3847 m_refresh = true;
3848 break;
3849 default:
3850 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
3851 break;
3852 }
3853 return error;
3854 }
3855
3856 void
Eugene Zelenko222b9372015-10-27 00:45:06 +00003857 OptionParsingStarting() override
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003858 {
3859 m_refresh = false;
3860 }
3861
3862 const OptionDefinition*
Eugene Zelenko222b9372015-10-27 00:45:06 +00003863 GetDefinitions() override
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003864 {
3865 return g_option_table;
3866 }
3867
3868 static OptionDefinition g_option_table[];
3869 bool m_refresh;
3870 };
3871
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003872 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003873 DoExecute(Args &command, CommandReturnObject &result) override
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003874 {
3875 RenderScriptRuntime *runtime =
3876 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript));
3877 runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(), m_options.m_refresh);
3878 result.SetStatus(eReturnStatusSuccessFinishResult);
3879 return true;
3880 }
3881
Eugene Zelenko222b9372015-10-27 00:45:06 +00003882private:
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003883 CommandOptions m_options;
3884};
3885
3886OptionDefinition
3887CommandObjectRenderScriptRuntimeAllocationList::CommandOptions::g_option_table[] =
3888{
3889 { LLDB_OPT_SET_1, false, "refresh", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
3890 "Recompute allocation details."},
3891 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
3892};
3893
Ewan Crawford55232f02015-10-21 08:50:42 +00003894class CommandObjectRenderScriptRuntimeAllocationLoad : public CommandObjectParsed
3895{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003896public:
Ewan Crawford55232f02015-10-21 08:50:42 +00003897 CommandObjectRenderScriptRuntimeAllocationLoad(CommandInterpreter &interpreter)
3898 : CommandObjectParsed(interpreter, "renderscript allocation load",
3899 "Loads renderscript allocation contents from a file.", "renderscript allocation load <ID> <filename>",
3900 eCommandRequiresProcess | eCommandProcessMustBeLaunched)
3901 {
3902 }
3903
Eugene Zelenko222b9372015-10-27 00:45:06 +00003904 ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default;
Ewan Crawford55232f02015-10-21 08:50:42 +00003905
3906 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003907 DoExecute(Args &command, CommandReturnObject &result) override
Ewan Crawford55232f02015-10-21 08:50:42 +00003908 {
3909 const size_t argc = command.GetArgumentCount();
3910 if (argc != 2)
3911 {
3912 result.AppendErrorWithFormat("'%s' takes 2 arguments, an allocation ID and filename to read from.", m_cmd_name.c_str());
3913 result.SetStatus(eReturnStatusFailed);
3914 return false;
3915 }
3916
3917 RenderScriptRuntime *runtime =
3918 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript));
3919
3920 const char* id_cstr = command.GetArgumentAtIndex(0);
3921 bool convert_complete = false;
3922 const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
3923 if (!convert_complete)
3924 {
3925 result.AppendErrorWithFormat ("invalid allocation id argument '%s'", id_cstr);
3926 result.SetStatus (eReturnStatusFailed);
3927 return false;
3928 }
3929
3930 const char* filename = command.GetArgumentAtIndex(1);
3931 bool success = runtime->LoadAllocation(result.GetOutputStream(), id, filename, m_exe_ctx.GetFramePtr());
3932
3933 if (success)
3934 result.SetStatus(eReturnStatusSuccessFinishResult);
3935 else
3936 result.SetStatus(eReturnStatusFailed);
3937
3938 return true;
3939 }
3940};
3941
Ewan Crawford55232f02015-10-21 08:50:42 +00003942class CommandObjectRenderScriptRuntimeAllocationSave : public CommandObjectParsed
3943{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003944public:
Ewan Crawford55232f02015-10-21 08:50:42 +00003945 CommandObjectRenderScriptRuntimeAllocationSave(CommandInterpreter &interpreter)
3946 : CommandObjectParsed(interpreter, "renderscript allocation save",
3947 "Write renderscript allocation contents to a file.", "renderscript allocation save <ID> <filename>",
3948 eCommandRequiresProcess | eCommandProcessMustBeLaunched)
3949 {
3950 }
3951
Eugene Zelenko222b9372015-10-27 00:45:06 +00003952 ~CommandObjectRenderScriptRuntimeAllocationSave() override = default;
Ewan Crawford55232f02015-10-21 08:50:42 +00003953
3954 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003955 DoExecute(Args &command, CommandReturnObject &result) override
Ewan Crawford55232f02015-10-21 08:50:42 +00003956 {
3957 const size_t argc = command.GetArgumentCount();
3958 if (argc != 2)
3959 {
3960 result.AppendErrorWithFormat("'%s' takes 2 arguments, an allocation ID and filename to read from.", m_cmd_name.c_str());
3961 result.SetStatus(eReturnStatusFailed);
3962 return false;
3963 }
3964
3965 RenderScriptRuntime *runtime =
3966 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript));
3967
3968 const char* id_cstr = command.GetArgumentAtIndex(0);
3969 bool convert_complete = false;
3970 const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
3971 if (!convert_complete)
3972 {
3973 result.AppendErrorWithFormat ("invalid allocation id argument '%s'", id_cstr);
3974 result.SetStatus (eReturnStatusFailed);
3975 return false;
3976 }
3977
3978 const char* filename = command.GetArgumentAtIndex(1);
3979 bool success = runtime->SaveAllocation(result.GetOutputStream(), id, filename, m_exe_ctx.GetFramePtr());
3980
3981 if (success)
3982 result.SetStatus(eReturnStatusSuccessFinishResult);
3983 else
3984 result.SetStatus(eReturnStatusFailed);
3985
3986 return true;
3987 }
3988};
3989
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003990class CommandObjectRenderScriptRuntimeAllocation : public CommandObjectMultiword
3991{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003992public:
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003993 CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter)
3994 : CommandObjectMultiword(interpreter, "renderscript allocation", "Commands that deal with renderscript allocations.",
3995 NULL)
3996 {
3997 LoadSubCommand("list", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationList(interpreter)));
Ewan Crawforda0f08672015-10-16 08:28:47 +00003998 LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationDump(interpreter)));
Ewan Crawford55232f02015-10-21 08:50:42 +00003999 LoadSubCommand("save", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationSave(interpreter)));
4000 LoadSubCommand("load", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter)));
Ewan Crawford15f2bd92015-10-06 08:42:32 +00004001 }
4002
Eugene Zelenko222b9372015-10-27 00:45:06 +00004003 ~CommandObjectRenderScriptRuntimeAllocation() override = default;
Ewan Crawford15f2bd92015-10-06 08:42:32 +00004004};
4005
Colin Riley4640cde2015-06-01 18:23:41 +00004006class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed
4007{
Eugene Zelenko222b9372015-10-27 00:45:06 +00004008public:
Colin Riley4640cde2015-06-01 18:23:41 +00004009 CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter)
4010 : CommandObjectParsed(interpreter, "renderscript status",
4011 "Displays current renderscript runtime status.", "renderscript status",
4012 eCommandRequiresProcess | eCommandProcessMustBeLaunched)
4013 {
4014 }
4015
Eugene Zelenko222b9372015-10-27 00:45:06 +00004016 ~CommandObjectRenderScriptRuntimeStatus() override = default;
Colin Riley4640cde2015-06-01 18:23:41 +00004017
4018 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00004019 DoExecute(Args &command, CommandReturnObject &result) override
Colin Riley4640cde2015-06-01 18:23:41 +00004020 {
4021 RenderScriptRuntime *runtime =
4022 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
4023 runtime->Status(result.GetOutputStream());
4024 result.SetStatus(eReturnStatusSuccessFinishResult);
4025 return true;
4026 }
4027};
4028
Colin Riley5ec532a2015-04-09 16:49:25 +00004029class CommandObjectRenderScriptRuntime : public CommandObjectMultiword
4030{
Eugene Zelenko222b9372015-10-27 00:45:06 +00004031public:
Colin Riley5ec532a2015-04-09 16:49:25 +00004032 CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter)
4033 : CommandObjectMultiword(interpreter, "renderscript", "A set of commands for operating on renderscript.",
4034 "renderscript <subcommand> [<subcommand-options>]")
4035 {
4036 LoadSubCommand("module", CommandObjectSP(new CommandObjectRenderScriptRuntimeModule(interpreter)));
Colin Riley4640cde2015-06-01 18:23:41 +00004037 LoadSubCommand("status", CommandObjectSP(new CommandObjectRenderScriptRuntimeStatus(interpreter)));
4038 LoadSubCommand("kernel", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernel(interpreter)));
4039 LoadSubCommand("context", CommandObjectSP(new CommandObjectRenderScriptRuntimeContext(interpreter)));
Ewan Crawford15f2bd92015-10-06 08:42:32 +00004040 LoadSubCommand("allocation", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocation(interpreter)));
Colin Riley5ec532a2015-04-09 16:49:25 +00004041 }
4042
Eugene Zelenko222b9372015-10-27 00:45:06 +00004043 ~CommandObjectRenderScriptRuntime() override = default;
Colin Riley5ec532a2015-04-09 16:49:25 +00004044};
Colin Rileyef20b082015-04-14 07:39:24 +00004045
4046void
4047RenderScriptRuntime::Initiate()
Colin Riley5ec532a2015-04-09 16:49:25 +00004048{
Colin Rileyef20b082015-04-14 07:39:24 +00004049 assert(!m_initiated);
Colin Riley5ec532a2015-04-09 16:49:25 +00004050}
Colin Rileyef20b082015-04-14 07:39:24 +00004051
4052RenderScriptRuntime::RenderScriptRuntime(Process *process)
Ewan Crawford7dc77712015-09-10 10:08:48 +00004053 : lldb_private::CPPLanguageRuntime(process), m_initiated(false), m_debuggerPresentFlagged(false),
4054 m_breakAllKernels(false)
Colin Rileyef20b082015-04-14 07:39:24 +00004055{
Colin Riley4640cde2015-06-01 18:23:41 +00004056 ModulesDidLoad(process->GetTarget().GetImages());
Colin Rileyef20b082015-04-14 07:39:24 +00004057}
Colin Riley4640cde2015-06-01 18:23:41 +00004058
4059lldb::CommandObjectSP
4060RenderScriptRuntime::GetCommandObject(lldb_private::CommandInterpreter& interpreter)
4061{
4062 static CommandObjectSP command_object;
4063 if(!command_object)
4064 {
4065 command_object.reset(new CommandObjectRenderScriptRuntime(interpreter));
4066 }
4067 return command_object;
4068}
4069
Ewan Crawford78f339d2015-09-21 10:53:18 +00004070RenderScriptRuntime::~RenderScriptRuntime() = default;