blob: 8e5d31b663500334895cad9693ccc2c2cccf9e3b [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 {
584 "rsdScriptInvokeForEach", // name
585 "_Z22rsdScriptInvokeForEachPKN7android12renderscript7ContextEPNS0_6ScriptEjPKNS0_10AllocationEPS6_PKvjPK12RsScriptCall", // symbol name 32bit
586 "_Z22rsdScriptInvokeForEachPKN7android12renderscript7ContextEPNS0_6ScriptEjPKNS0_10AllocationEPS6_PKvmPK12RsScriptCall", // symbol name 64bit
587 0, // version
588 RenderScriptRuntime::eModuleKindDriver, // type
589 nullptr // handler
590 },
591 {
592 "rsdScriptInvokeForEachMulti", // name
593 "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall", // symbol name 32bit
594 "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0_6ScriptEjPPKNS0_10AllocationEmPS6_PKvmPK12RsScriptCall", // symbol name 64bit
595 0, // version
596 RenderScriptRuntime::eModuleKindDriver, // type
597 nullptr // handler
598 },
599 {
600 "rsdScriptInvokeFunction", // name
601 "_Z23rsdScriptInvokeFunctionPKN7android12renderscript7ContextEPNS0_6ScriptEjPKvj", // symbol name 32bit
602 "_Z23rsdScriptInvokeFunctionPKN7android12renderscript7ContextEPNS0_6ScriptEjPKvm", // symbol name 64bit
603 0, // version
604 RenderScriptRuntime::eModuleKindDriver, // type
605 nullptr // handler
606 },
607 {
608 "rsdScriptSetGlobalVar", // name
609 "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_6ScriptEjPvj", // symbol name 32bit
610 "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_6ScriptEjPvm", // symbol name 64bit
611 0, // version
612 RenderScriptRuntime::eModuleKindDriver, // type
613 &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar1 // handler
614 },
Colin Riley4640cde2015-06-01 18:23:41 +0000615
616 //rsdAllocation
Aidan Dodds82780282015-09-18 16:49:39 +0000617 {
618 "rsdAllocationInit", // name
619 "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_10AllocationEb", // symbol name 32bit
620 "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_10AllocationEb", // symbol name 64bit
621 0, // version
622 RenderScriptRuntime::eModuleKindDriver, // type
623 &lldb_private::RenderScriptRuntime::CaptureAllocationInit1 // handler
624 },
625 {
626 "rsdAllocationRead2D", //name
627 "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_10AllocationEjjj23RsAllocationCubemapFacejjPvjj", // symbol name 32bit
628 "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_10AllocationEjjj23RsAllocationCubemapFacejjPvmm", // symbol name 64bit
629 0, // version
630 RenderScriptRuntime::eModuleKindDriver, // type
631 nullptr // handler
632 },
Ewan Crawforde69df382015-12-09 16:01:58 +0000633 {
634 "rsdAllocationDestroy", // name
635 "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_10AllocationE", // symbol name 32bit
636 "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_10AllocationE", // symbol name 64bit
637 0, // version
638 RenderScriptRuntime::eModuleKindDriver, // type
639 &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy // handler
640 },
Colin Riley4640cde2015-06-01 18:23:41 +0000641};
Colin Riley4640cde2015-06-01 18:23:41 +0000642
Eugene Zelenko222b9372015-10-27 00:45:06 +0000643const size_t RenderScriptRuntime::s_runtimeHookCount = sizeof(s_runtimeHookDefns)/sizeof(s_runtimeHookDefns[0]);
Colin Riley4640cde2015-06-01 18:23:41 +0000644
645bool
646RenderScriptRuntime::HookCallback(void *baton, StoppointCallbackContext *ctx, lldb::user_id_t break_id, lldb::user_id_t break_loc_id)
647{
648 RuntimeHook* hook_info = (RuntimeHook*)baton;
649 ExecutionContext context(ctx->exe_ctx_ref);
650
651 RenderScriptRuntime *lang_rt = (RenderScriptRuntime *)context.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
652
653 lang_rt->HookCallback(hook_info, context);
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000654
Colin Riley4640cde2015-06-01 18:23:41 +0000655 return false;
656}
657
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000658void
Colin Riley4640cde2015-06-01 18:23:41 +0000659RenderScriptRuntime::HookCallback(RuntimeHook* hook_info, ExecutionContext& context)
660{
661 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
662
Aidan Dodds82780282015-09-18 16:49:39 +0000663 if (log)
Colin Riley4640cde2015-06-01 18:23:41 +0000664 log->Printf ("RenderScriptRuntime::HookCallback - '%s' .", hook_info->defn->name);
665
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000666 if (hook_info->defn->grabber)
Colin Riley4640cde2015-06-01 18:23:41 +0000667 {
668 (this->*(hook_info->defn->grabber))(hook_info, context);
669 }
670}
671
Colin Riley4640cde2015-06-01 18:23:41 +0000672bool
Aidan Dodds82780282015-09-18 16:49:39 +0000673RenderScriptRuntime::GetArgSimple(ExecutionContext &context, uint32_t arg, uint64_t *data)
Colin Riley4640cde2015-06-01 18:23:41 +0000674{
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000675 // Get a positional integer argument.
676 // Given an ExecutionContext, ``context`` which should be a RenderScript
677 // frame, get the value of the positional argument ``arg`` and save its value
678 // to the address pointed to by ``data``.
679 // returns true on success, false otherwise.
680 // If unsuccessful, the value pointed to by ``data`` is undefined. Otherwise,
681 // ``data`` will be set to the value of the the given ``arg``.
682 // NOTE: only natural width integer arguments for the machine are supported.
683 // Behaviour with non primitive arguments is undefined.
684
Colin Riley4640cde2015-06-01 18:23:41 +0000685 if (!data)
686 return false;
687
Aidan Dodds82780282015-09-18 16:49:39 +0000688 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
Colin Riley4640cde2015-06-01 18:23:41 +0000689 Error error;
690 RegisterContext* reg_ctx = context.GetRegisterContext();
691 Process* process = context.GetProcessPtr();
Aidan Dodds82780282015-09-18 16:49:39 +0000692 bool success = false; // return value
Colin Riley4640cde2015-06-01 18:23:41 +0000693
Aidan Dodds82780282015-09-18 16:49:39 +0000694 if (!context.GetTargetPtr())
Colin Riley4640cde2015-06-01 18:23:41 +0000695 {
Aidan Dodds82780282015-09-18 16:49:39 +0000696 if (log)
697 log->Printf("RenderScriptRuntime::GetArgSimple - Invalid target");
698
699 return false;
Colin Riley4640cde2015-06-01 18:23:41 +0000700 }
Aidan Dodds82780282015-09-18 16:49:39 +0000701
702 switch (context.GetTargetPtr()->GetArchitecture().GetMachine())
Colin Riley4640cde2015-06-01 18:23:41 +0000703 {
Aidan Dodds82780282015-09-18 16:49:39 +0000704 case llvm::Triple::ArchType::x86:
Colin Riley4640cde2015-06-01 18:23:41 +0000705 {
706 uint64_t sp = reg_ctx->GetSP();
Aidan Dodds82780282015-09-18 16:49:39 +0000707 uint32_t offset = (1 + arg) * sizeof(uint32_t);
708 uint32_t result = 0;
709 process->ReadMemory(sp + offset, &result, sizeof(uint32_t), error);
710 if (error.Fail())
Colin Riley4640cde2015-06-01 18:23:41 +0000711 {
Aidan Dodds82780282015-09-18 16:49:39 +0000712 if (log)
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000713 log->Printf("RenderScriptRuntime::GetArgSimple - error reading X86 stack: %s.", error.AsCString());
Aidan Dodds82780282015-09-18 16:49:39 +0000714 }
715 else
716 {
717 *data = result;
718 success = true;
719 }
Aidan Dodds82780282015-09-18 16:49:39 +0000720 break;
721 }
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000722 case llvm::Triple::ArchType::x86_64:
723 {
724 // amd64 has 6 integer registers, and 8 XMM registers for parameter passing.
725 // Surplus args are spilled onto the stack.
726 // rdi, rsi, rdx, rcx, r8, r9, (zmm0 - 7 for vectors)
727 // ref: AMD64 ABI Draft 0.99.6 – October 7, 2013 – 10:35; Figure 3.4. Retrieved from
728 // http://www.x86-64.org/documentation/abi.pdf
729 if (arg > 5)
730 {
731 if (log)
732 log->Warning("X86_64 register spill is not supported.");
733 break;
734 }
735 const char * regnames[] = {"rdi", "rsi", "rdx", "rcx", "r8", "r9"};
736 assert((sizeof(regnames) / sizeof(const char *)) > arg);
737 const RegisterInfo *rArg = reg_ctx->GetRegisterInfoByName(regnames[arg]);
738 RegisterValue rVal;
739 success = reg_ctx->ReadRegister(rArg, rVal);
740 if (success)
741 {
742 *data = rVal.GetAsUInt64(0u, &success);
743 }
744 else
745 {
746 if (log)
747 log->Printf("RenderScriptRuntime::GetArgSimple - error reading x86_64 register: %d.", arg);
748 }
749 break;
750 }
Aidan Dodds82780282015-09-18 16:49:39 +0000751 case llvm::Triple::ArchType::arm:
752 {
753 // arm 32 bit
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000754 // first 4 arguments are passed via registers
Aidan Dodds82780282015-09-18 16:49:39 +0000755 if (arg < 4)
756 {
757 const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg);
758 RegisterValue rVal;
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000759 success = reg_ctx->ReadRegister(rArg, rVal);
760 if (success)
761 {
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000762 (*data) = rVal.GetAsUInt32(0u, &success);
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000763 }
764 else
765 {
766 if (log)
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000767 log->Printf("RenderScriptRuntime::GetArgSimple - error reading ARM register: %d.", arg);
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000768 }
Aidan Dodds82780282015-09-18 16:49:39 +0000769 }
770 else
771 {
772 uint64_t sp = reg_ctx->GetSP();
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000773 uint32_t offset = (arg-4) * sizeof(uint32_t);
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000774 uint32_t value = 0;
775 size_t bytes_read = process->ReadMemory(sp + offset, &value, sizeof(value), error);
776 if (error.Fail() || bytes_read != sizeof(value))
Colin Riley4640cde2015-06-01 18:23:41 +0000777 {
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000778 if (log)
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000779 log->Printf("RenderScriptRuntime::GetArgSimple - error reading ARM stack: %s.", error.AsCString());
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000780 }
781 else
782 {
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000783 *data = value;
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000784 success = true;
Colin Riley4640cde2015-06-01 18:23:41 +0000785 }
786 }
Aidan Dodds82780282015-09-18 16:49:39 +0000787 break;
788 }
789 case llvm::Triple::ArchType::aarch64:
790 {
791 // arm 64 bit
792 // first 8 arguments are in the registers
793 if (arg < 8)
794 {
795 const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg);
796 RegisterValue rVal;
797 success = reg_ctx->ReadRegister(rArg, rVal);
798 if (success)
799 {
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000800 *data = rVal.GetAsUInt64(0u, &success);
Aidan Dodds82780282015-09-18 16:49:39 +0000801 }
802 else
803 {
804 if (log)
805 log->Printf("RenderScriptRuntime::GetArgSimple() - AARCH64 - Error while reading the argument #%d", arg);
806 }
807 }
808 else
809 {
810 // @TODO: need to find the argument in the stack
811 if (log)
812 log->Printf("RenderScriptRuntime::GetArgSimple - AARCH64 - FOR #ARG >= 8 NOT IMPLEMENTED YET. Argument number: %d", arg);
813 }
814 break;
815 }
Aidan Dodds74b396d2015-11-12 17:39:42 +0000816 case llvm::Triple::ArchType::mipsel:
817 {
Aidan Dodds74b396d2015-11-12 17:39:42 +0000818 // read from the registers
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000819 // first 4 arguments are passed in registers
Aidan Dodds74b396d2015-11-12 17:39:42 +0000820 if (arg < 4){
821 const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg + 4);
822 RegisterValue rVal;
823 success = reg_ctx->ReadRegister(rArg, rVal);
824 if (success)
825 {
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000826 *data = rVal.GetAsUInt64(0u, &success);
Aidan Dodds74b396d2015-11-12 17:39:42 +0000827 }
828 else
829 {
830 if (log)
831 log->Printf("RenderScriptRuntime::GetArgSimple() - Mips - Error while reading the argument #%d", arg);
832 }
Aidan Dodds74b396d2015-11-12 17:39:42 +0000833 }
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000834 // arguments > 4 are read from the stack
Aidan Dodds74b396d2015-11-12 17:39:42 +0000835 else
836 {
837 uint64_t sp = reg_ctx->GetSP();
838 uint32_t offset = arg * sizeof(uint32_t);
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000839 uint32_t value = 0;
840 size_t bytes_read = process->ReadMemory(sp + offset, &value, sizeof(value), error);
841 if (error.Fail() || bytes_read != sizeof(value))
Aidan Dodds74b396d2015-11-12 17:39:42 +0000842 {
843 if (log)
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000844 log->Printf("RenderScriptRuntime::GetArgSimple - error reading Mips stack: %s.", error.AsCString());
Aidan Dodds74b396d2015-11-12 17:39:42 +0000845 }
846 else
847 {
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000848 *data = value;
Aidan Dodds74b396d2015-11-12 17:39:42 +0000849 success = true;
850 }
851 }
Aidan Dodds74b396d2015-11-12 17:39:42 +0000852 break;
853 }
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000854 case llvm::Triple::ArchType::mips64el:
855 {
856 // read from the registers
857 if (arg < 8)
858 {
859 const RegisterInfo* rArg = reg_ctx->GetRegisterInfoAtIndex(arg + 4);
860 RegisterValue rVal;
861 success = reg_ctx->ReadRegister(rArg, rVal);
862 if (success)
863 {
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000864 (*data) = rVal.GetAsUInt64(0u, &success);
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000865 }
866 else
867 {
868 if (log)
869 log->Printf("RenderScriptRuntime::GetArgSimple - Mips64 - Error reading the argument #%d", arg);
870 }
871 }
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000872 // arguments > 8 are read from the stack
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000873 else
874 {
875 uint64_t sp = reg_ctx->GetSP();
876 uint32_t offset = (arg - 8) * sizeof(uint64_t);
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000877 uint64_t value = 0;
878 size_t bytes_read = process->ReadMemory(sp + offset, &value, sizeof(value), error);
879 if (error.Fail() || bytes_read != sizeof(value))
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000880 {
881 if (log)
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000882 log->Printf("RenderScriptRuntime::GetArgSimple - Mips64 - Error reading Mips64 stack: %s.", error.AsCString());
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000883 }
884 else
885 {
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000886 *data = value;
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000887 success = true;
888 }
889 }
Ewan Crawford02f1c5d2015-10-22 09:01:05 +0000890 break;
891 }
Aidan Dodds82780282015-09-18 16:49:39 +0000892 default:
893 {
894 // invalid architecture
895 if (log)
896 log->Printf("RenderScriptRuntime::GetArgSimple - Architecture not supported");
Aidan Dodds82780282015-09-18 16:49:39 +0000897 }
Colin Riley4640cde2015-06-01 18:23:41 +0000898 }
Aidan Dodds82780282015-09-18 16:49:39 +0000899
Ewan Crawfordcdfb1482015-12-11 13:49:21 +0000900 if (!success)
901 {
902 if (log)
903 log->Printf("RenderScriptRuntime::GetArgSimple - failed to get argument at index %" PRIu32, arg);
904 }
Aidan Dodds82780282015-09-18 16:49:39 +0000905 return success;
Colin Riley4640cde2015-06-01 18:23:41 +0000906}
907
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000908void
Colin Riley4640cde2015-06-01 18:23:41 +0000909RenderScriptRuntime::CaptureSetGlobalVar1(RuntimeHook* hook_info, ExecutionContext& context)
910{
911 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000912
Colin Riley4640cde2015-06-01 18:23:41 +0000913 //Context, Script, int, data, length
914
Aidan Dodds82780282015-09-18 16:49:39 +0000915 uint64_t rs_context_u64 = 0U;
916 uint64_t rs_script_u64 = 0U;
917 uint64_t rs_id_u64 = 0U;
918 uint64_t rs_data_u64 = 0U;
919 uint64_t rs_length_u64 = 0U;
Colin Riley4640cde2015-06-01 18:23:41 +0000920
Aidan Dodds82780282015-09-18 16:49:39 +0000921 bool success =
922 GetArgSimple(context, 0, &rs_context_u64) &&
923 GetArgSimple(context, 1, &rs_script_u64) &&
924 GetArgSimple(context, 2, &rs_id_u64) &&
925 GetArgSimple(context, 3, &rs_data_u64) &&
926 GetArgSimple(context, 4, &rs_length_u64);
Colin Riley4640cde2015-06-01 18:23:41 +0000927
Aidan Dodds82780282015-09-18 16:49:39 +0000928 if (!success)
929 {
930 if (log)
931 log->Printf("RenderScriptRuntime::CaptureSetGlobalVar1 - Error while reading the function parameters");
932 return;
933 }
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000934
Aidan Dodds82780282015-09-18 16:49:39 +0000935 if (log)
Colin Riley4640cde2015-06-01 18:23:41 +0000936 {
937 log->Printf ("RenderScriptRuntime::CaptureSetGlobalVar1 - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64 ":%" PRIu64 "bytes.",
Aidan Dodds82780282015-09-18 16:49:39 +0000938 rs_context_u64, rs_script_u64, rs_id_u64, rs_data_u64, rs_length_u64);
Colin Riley4640cde2015-06-01 18:23:41 +0000939
Aidan Dodds82780282015-09-18 16:49:39 +0000940 addr_t script_addr = (addr_t)rs_script_u64;
Colin Riley4640cde2015-06-01 18:23:41 +0000941 if (m_scriptMappings.find( script_addr ) != m_scriptMappings.end())
942 {
943 auto rsm = m_scriptMappings[script_addr];
Aidan Dodds82780282015-09-18 16:49:39 +0000944 if (rs_id_u64 < rsm->m_globals.size())
Colin Riley4640cde2015-06-01 18:23:41 +0000945 {
Aidan Dodds82780282015-09-18 16:49:39 +0000946 auto rsg = rsm->m_globals[rs_id_u64];
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000947 log->Printf ("RenderScriptRuntime::CaptureSetGlobalVar1 - Setting of '%s' within '%s' inferred", rsg.m_name.AsCString(),
Colin Riley4640cde2015-06-01 18:23:41 +0000948 rsm->m_module->GetFileSpec().GetFilename().AsCString());
949 }
950 }
951 }
952}
953
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000954void
Colin Riley4640cde2015-06-01 18:23:41 +0000955RenderScriptRuntime::CaptureAllocationInit1(RuntimeHook* hook_info, ExecutionContext& context)
956{
957 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
Aidan Dodds35e7b1a2016-01-06 15:43:52 +0000958
Colin Riley4640cde2015-06-01 18:23:41 +0000959 //Context, Alloc, bool
960
Aidan Dodds82780282015-09-18 16:49:39 +0000961 uint64_t rs_context_u64 = 0U;
962 uint64_t rs_alloc_u64 = 0U;
963 uint64_t rs_forceZero_u64 = 0U;
Colin Riley4640cde2015-06-01 18:23:41 +0000964
Aidan Dodds82780282015-09-18 16:49:39 +0000965 bool success =
966 GetArgSimple(context, 0, &rs_context_u64) &&
967 GetArgSimple(context, 1, &rs_alloc_u64) &&
968 GetArgSimple(context, 2, &rs_forceZero_u64);
969 if (!success) // error case
970 {
971 if (log)
972 log->Printf("RenderScriptRuntime::CaptureAllocationInit1 - Error while reading the function parameters");
973 return; // abort
974 }
975
976 if (log)
Colin Riley4640cde2015-06-01 18:23:41 +0000977 log->Printf ("RenderScriptRuntime::CaptureAllocationInit1 - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .",
Aidan Dodds82780282015-09-18 16:49:39 +0000978 rs_context_u64, rs_alloc_u64, rs_forceZero_u64);
Ewan Crawford78f339d2015-09-21 10:53:18 +0000979
980 AllocationDetails* alloc = LookUpAllocation(rs_alloc_u64, true);
981 if (alloc)
982 alloc->context = rs_context_u64;
Colin Riley4640cde2015-06-01 18:23:41 +0000983}
984
Ewan Crawforde69df382015-12-09 16:01:58 +0000985void
986RenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook* hook_info, ExecutionContext& context)
987{
988 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
989
990 // Context, Alloc
991 uint64_t rs_context_u64 = 0U;
992 uint64_t rs_alloc_u64 = 0U;
993
994 bool success = GetArgSimple(context, 0, &rs_context_u64) && GetArgSimple(context, 1, &rs_alloc_u64);
995 if (!success) // error case
996 {
997 if (log)
998 log->Printf("RenderScriptRuntime::CaptureAllocationDestroy - Error while reading the function parameters");
999 return; // abort
1000 }
1001
1002 if (log)
1003 log->Printf("RenderScriptRuntime::CaptureAllocationDestroy - 0x%" PRIx64 ", 0x%" PRIx64 ".",
1004 rs_context_u64, rs_alloc_u64);
1005
1006 for (auto iter = m_allocations.begin(); iter != m_allocations.end(); ++iter)
1007 {
1008 auto& allocation_ap = *iter; // get the unique pointer
1009 if (allocation_ap->address.isValid() && *allocation_ap->address.get() == rs_alloc_u64)
1010 {
1011 m_allocations.erase(iter);
1012 if (log)
1013 log->Printf("RenderScriptRuntime::CaptureAllocationDestroy - Deleted allocation entry");
1014 return;
1015 }
1016 }
1017
1018 if (log)
1019 log->Printf("RenderScriptRuntime::CaptureAllocationDestroy - Couldn't find destroyed allocation");
1020}
1021
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001022void
Colin Riley4640cde2015-06-01 18:23:41 +00001023RenderScriptRuntime::CaptureScriptInit1(RuntimeHook* hook_info, ExecutionContext& context)
1024{
1025 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1026
1027 //Context, Script, resname Str, cachedir Str
1028 Error error;
1029 Process* process = context.GetProcessPtr();
1030
Aidan Dodds82780282015-09-18 16:49:39 +00001031 uint64_t rs_context_u64 = 0U;
1032 uint64_t rs_script_u64 = 0U;
1033 uint64_t rs_resnameptr_u64 = 0U;
1034 uint64_t rs_cachedirptr_u64 = 0U;
Colin Riley4640cde2015-06-01 18:23:41 +00001035
1036 std::string resname;
1037 std::string cachedir;
1038
Aidan Dodds82780282015-09-18 16:49:39 +00001039 // read the function parameters
1040 bool success =
1041 GetArgSimple(context, 0, &rs_context_u64) &&
1042 GetArgSimple(context, 1, &rs_script_u64) &&
1043 GetArgSimple(context, 2, &rs_resnameptr_u64) &&
1044 GetArgSimple(context, 3, &rs_cachedirptr_u64);
Colin Riley4640cde2015-06-01 18:23:41 +00001045
Aidan Dodds82780282015-09-18 16:49:39 +00001046 if (!success)
1047 {
1048 if (log)
1049 log->Printf("RenderScriptRuntime::CaptureScriptInit1 - Error while reading the function parameters");
1050 return;
1051 }
1052
1053 process->ReadCStringFromMemory((lldb::addr_t)rs_resnameptr_u64, resname, error);
Colin Riley4640cde2015-06-01 18:23:41 +00001054 if (error.Fail())
1055 {
Aidan Dodds82780282015-09-18 16:49:39 +00001056 if (log)
Colin Riley4640cde2015-06-01 18:23:41 +00001057 log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - error reading resname: %s.", error.AsCString());
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001058
Colin Riley4640cde2015-06-01 18:23:41 +00001059 }
1060
Aidan Dodds82780282015-09-18 16:49:39 +00001061 process->ReadCStringFromMemory((lldb::addr_t)rs_cachedirptr_u64, cachedir, error);
Colin Riley4640cde2015-06-01 18:23:41 +00001062 if (error.Fail())
1063 {
Aidan Dodds82780282015-09-18 16:49:39 +00001064 if (log)
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001065 log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - error reading cachedir: %s.", error.AsCString());
Colin Riley4640cde2015-06-01 18:23:41 +00001066 }
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001067
Colin Riley4640cde2015-06-01 18:23:41 +00001068 if (log)
1069 log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .",
Aidan Dodds82780282015-09-18 16:49:39 +00001070 rs_context_u64, rs_script_u64, resname.c_str(), cachedir.c_str());
Colin Riley4640cde2015-06-01 18:23:41 +00001071
1072 if (resname.size() > 0)
1073 {
1074 StreamString strm;
1075 strm.Printf("librs.%s.so", resname.c_str());
1076
Ewan Crawford78f339d2015-09-21 10:53:18 +00001077 ScriptDetails* script = LookUpScript(rs_script_u64, true);
1078 if (script)
1079 {
1080 script->type = ScriptDetails::eScriptC;
1081 script->cacheDir = cachedir;
1082 script->resName = resname;
1083 script->scriptDyLib = strm.GetData();
1084 script->context = addr_t(rs_context_u64);
1085 }
Colin Riley4640cde2015-06-01 18:23:41 +00001086
1087 if (log)
1088 log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - '%s' tagged with context 0x%" PRIx64 " and script 0x%" PRIx64 ".",
Aidan Dodds82780282015-09-18 16:49:39 +00001089 strm.GetData(), rs_context_u64, rs_script_u64);
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001090 }
Colin Riley4640cde2015-06-01 18:23:41 +00001091 else if (log)
1092 {
1093 log->Printf ("RenderScriptRuntime::CaptureScriptInit1 - resource name invalid, Script not tagged");
1094 }
Colin Riley4640cde2015-06-01 18:23:41 +00001095}
1096
Colin Riley4640cde2015-06-01 18:23:41 +00001097void
1098RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, ModuleKind kind)
1099{
1100 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1101
1102 if (!module)
1103 {
1104 return;
1105 }
1106
Aidan Dodds82780282015-09-18 16:49:39 +00001107 Target &target = GetProcess()->GetTarget();
1108 llvm::Triple::ArchType targetArchType = target.GetArchitecture().GetMachine();
1109
1110 if (targetArchType != llvm::Triple::ArchType::x86
1111 && targetArchType != llvm::Triple::ArchType::arm
Ewan Crawford02f1c5d2015-10-22 09:01:05 +00001112 && targetArchType != llvm::Triple::ArchType::aarch64
Aidan Dodds74b396d2015-11-12 17:39:42 +00001113 && targetArchType != llvm::Triple::ArchType::mipsel
Ewan Crawford02f1c5d2015-10-22 09:01:05 +00001114 && targetArchType != llvm::Triple::ArchType::mips64el
Ewan Crawfordcdfb1482015-12-11 13:49:21 +00001115 && targetArchType != llvm::Triple::ArchType::x86_64
Ewan Crawford02f1c5d2015-10-22 09:01:05 +00001116 )
Colin Riley4640cde2015-06-01 18:23:41 +00001117 {
1118 if (log)
Aidan Dodds74b396d2015-11-12 17:39:42 +00001119 log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Unable to hook runtime. Only X86, ARM, Mips supported currently.");
Colin Riley4640cde2015-06-01 18:23:41 +00001120
1121 return;
1122 }
1123
Aidan Dodds82780282015-09-18 16:49:39 +00001124 uint32_t archByteSize = target.GetArchitecture().GetAddressByteSize();
Colin Riley4640cde2015-06-01 18:23:41 +00001125
1126 for (size_t idx = 0; idx < s_runtimeHookCount; idx++)
1127 {
1128 const HookDefn* hook_defn = &s_runtimeHookDefns[idx];
1129 if (hook_defn->kind != kind) {
1130 continue;
1131 }
1132
Aidan Dodds82780282015-09-18 16:49:39 +00001133 const char* symbol_name = (archByteSize == 4) ? hook_defn->symbol_name_m32 : hook_defn->symbol_name_m64;
1134
1135 const Symbol *sym = module->FindFirstSymbolWithNameAndType(ConstString(symbol_name), eSymbolTypeCode);
1136 if (!sym){
1137 if (log){
1138 log->Printf("RenderScriptRuntime::LoadRuntimeHooks - ERROR: Symbol '%s' related to the function %s not found", symbol_name, hook_defn->name);
1139 }
1140 continue;
1141 }
Colin Riley4640cde2015-06-01 18:23:41 +00001142
Greg Clayton358cf1e2015-06-25 21:46:34 +00001143 addr_t addr = sym->GetLoadAddress(&target);
Colin Riley4640cde2015-06-01 18:23:41 +00001144 if (addr == LLDB_INVALID_ADDRESS)
1145 {
Aidan Dodds82780282015-09-18 16:49:39 +00001146 if (log)
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001147 log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Unable to resolve the address of hook function '%s' with symbol '%s'.",
Aidan Dodds82780282015-09-18 16:49:39 +00001148 hook_defn->name, symbol_name);
Colin Riley4640cde2015-06-01 18:23:41 +00001149 continue;
1150 }
Aidan Dodds82780282015-09-18 16:49:39 +00001151 else
1152 {
1153 if (log)
1154 log->Printf("RenderScriptRuntime::LoadRuntimeHooks - Function %s, address resolved at 0x%" PRIx64, hook_defn->name, addr);
1155 }
Colin Riley4640cde2015-06-01 18:23:41 +00001156
1157 RuntimeHookSP hook(new RuntimeHook());
1158 hook->address = addr;
1159 hook->defn = hook_defn;
1160 hook->bp_sp = target.CreateBreakpoint(addr, true, false);
1161 hook->bp_sp->SetCallback(HookCallback, hook.get(), true);
1162 m_runtimeHooks[addr] = hook;
1163 if (log)
1164 {
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00001165 log->Printf ("RenderScriptRuntime::LoadRuntimeHooks - Successfully hooked '%s' in '%s' version %" PRIu64 " at 0x%" PRIx64 ".",
Colin Riley4640cde2015-06-01 18:23:41 +00001166 hook_defn->name, module->GetFileSpec().GetFilename().AsCString(), (uint64_t)hook_defn->version, (uint64_t)addr);
1167 }
1168 }
1169}
1170
1171void
1172RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp)
1173{
1174 if (!rsmodule_sp)
1175 return;
1176
1177 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1178
1179 const ModuleSP module = rsmodule_sp->m_module;
1180 const FileSpec& file = module->GetPlatformFileSpec();
Ewan Crawford78f339d2015-09-21 10:53:18 +00001181
1182 // Iterate over all of the scripts that we currently know of.
1183 // Note: We cant push or pop to m_scripts here or it may invalidate rs_script.
1184 for (const auto & rs_script : m_scripts)
Colin Riley4640cde2015-06-01 18:23:41 +00001185 {
Ewan Crawford78f339d2015-09-21 10:53:18 +00001186 // Extract the expected .so file path for this script.
1187 std::string dylib;
1188 if (!rs_script->scriptDyLib.get(dylib))
1189 continue;
1190
1191 // Only proceed if the module that has loaded corresponds to this script.
1192 if (file.GetFilename() != ConstString(dylib.c_str()))
1193 continue;
1194
1195 // Obtain the script address which we use as a key.
1196 lldb::addr_t script;
1197 if (!rs_script->script.get(script))
1198 continue;
1199
1200 // If we have a script mapping for the current script.
1201 if (m_scriptMappings.find(script) != m_scriptMappings.end())
Colin Riley4640cde2015-06-01 18:23:41 +00001202 {
Ewan Crawford78f339d2015-09-21 10:53:18 +00001203 // if the module we have stored is different to the one we just received.
1204 if (m_scriptMappings[script] != rsmodule_sp)
Colin Riley4640cde2015-06-01 18:23:41 +00001205 {
Colin Riley4640cde2015-06-01 18:23:41 +00001206 if (log)
Ewan Crawford78f339d2015-09-21 10:53:18 +00001207 log->Printf ("RenderScriptRuntime::FixupScriptDetails - Error: script %" PRIx64 " wants reassigned to new rsmodule '%s'.",
1208 (uint64_t)script, rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
Colin Riley4640cde2015-06-01 18:23:41 +00001209 }
1210 }
Ewan Crawford78f339d2015-09-21 10:53:18 +00001211 // We don't have a script mapping for the current script.
1212 else
1213 {
1214 // Obtain the script resource name.
1215 std::string resName;
1216 if (rs_script->resName.get(resName))
1217 // Set the modules resource name.
1218 rsmodule_sp->m_resname = resName;
1219 // Add Script/Module pair to map.
1220 m_scriptMappings[script] = rsmodule_sp;
1221 if (log)
1222 log->Printf ("RenderScriptRuntime::FixupScriptDetails - script %" PRIx64 " associated with rsmodule '%s'.",
1223 (uint64_t)script, rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
1224 }
Colin Riley4640cde2015-06-01 18:23:41 +00001225 }
Colin Riley4640cde2015-06-01 18:23:41 +00001226}
1227
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001228// Uses the Target API to evaluate the expression passed as a parameter to the function
1229// The result of that expression is returned an unsigned 64 bit int, via the result* paramter.
1230// Function returns true on success, and false on failure
1231bool
1232RenderScriptRuntime::EvalRSExpression(const char* expression, StackFrame* frame_ptr, uint64_t* result)
1233{
1234 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1235 if (log)
1236 log->Printf("RenderScriptRuntime::EvalRSExpression(%s)", expression);
1237
1238 ValueObjectSP expr_result;
1239 // Perform the actual expression evaluation
1240 GetProcess()->GetTarget().EvaluateExpression(expression, frame_ptr, expr_result);
1241
1242 if (!expr_result)
1243 {
1244 if (log)
1245 log->Printf("RenderScriptRuntime::EvalRSExpression - Error: Couldn't evaluate expression");
1246 return false;
1247 }
1248
1249 // The result of the expression is invalid
1250 if (!expr_result->GetError().Success())
1251 {
1252 Error err = expr_result->GetError();
1253 if (err.GetError() == UserExpression::kNoResult) // Expression returned void, so this is actually a success
1254 {
1255 if (log)
1256 log->Printf("RenderScriptRuntime::EvalRSExpression - Expression returned void");
1257
1258 result = nullptr;
1259 return true;
1260 }
1261
1262 if (log)
1263 log->Printf("RenderScriptRuntime::EvalRSExpression - Error evaluating expression result: %s", err.AsCString());
1264 return false;
1265 }
1266
1267 bool success = false;
1268 *result = expr_result->GetValueAsUnsigned(0, &success); // We only read the result as an unsigned int.
1269
1270 if (!success)
1271 {
1272 if (log)
1273 log->Printf("RenderScriptRuntime::EvalRSExpression - Error: Couldn't convert expression result to unsigned int");
1274 return false;
1275 }
1276
1277 return true;
1278}
1279
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001280namespace // anonymous
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001281{
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001282 // max length of an expanded expression
1283 const int jit_max_expr_size = 768;
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001284
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001285 // Format strings containing the expressions we may need to evaluate.
1286 const char runtimeExpressions[][256] =
1287 {
1288 // Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap)
1289 "(int*)_Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocationCubemapFace(0x%lx, %u, %u, %u, 0, 0)",
1290
1291 // Type* rsaAllocationGetType(Context*, Allocation*)
1292 "(void*)rsaAllocationGetType(0x%lx, 0x%lx)",
1293
1294 // rsaTypeGetNativeData(Context*, Type*, void* typeData, size)
1295 // Pack the data in the following way mHal.state.dimX; mHal.state.dimY; mHal.state.dimZ;
1296 // mHal.state.lodCount; mHal.state.faces; mElement; into typeData
1297 // Need to specify 32 or 64 bit for uint_t since this differs between devices
1298 "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[0]", // X dim
1299 "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[1]", // Y dim
1300 "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[2]", // Z dim
1301 "uint%u_t data[6]; (void*)rsaTypeGetNativeData(0x%lx, 0x%lx, data, 6); data[5]", // Element ptr
1302
1303 // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size)
1304 // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into elemData
1305 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[0]", // Type
1306 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[1]", // Kind
1307 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[3]", // Vector Size
1308 "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%lx, 0x%lx, data, 5); data[4]", // Field Count
1309
1310 // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t *ids, const char **names,
1311 // size_t *arraySizes, uint32_t dataSize)
1312 // Needed for Allocations of structs to gather details about fields/Subelements
1313 "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];"
1314 "(void*)rsaElementGetSubElements(0x%lx, 0x%lx, ids, names, arr_size, %u); ids[%u]", // Element* of field
1315
1316 "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];"
1317 "(void*)rsaElementGetSubElements(0x%lx, 0x%lx, ids, names, arr_size, %u); names[%u]", // Name of field
1318
1319 "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];"
1320 "(void*)rsaElementGetSubElements(0x%lx, 0x%lx, ids, names, arr_size, %u); arr_size[%u]" // Array size of field
1321 };
1322
1323
1324 // Temporary workaround for MIPS, until the compiler emits the JAL instruction when invoking directly the function.
1325 // At the moment, when evaluating an expression involving a function call, the LLVM codegen for Mips emits a JAL
1326 // instruction, which is able to jump in the range +/- 128MB with respect to the current program counter ($pc). If
1327 // the requested function happens to reside outside the above region, the function address will be truncated and the
1328 // function invocation will fail. This is a problem in the RS plugin as we rely on the RS API to probe the number and
1329 // the nature of allocations. A proper solution in the MIPS compiler is currently being investigated. As temporary
1330 // work around for this context, we'll invoke the RS API through function pointers, which cause the compiler to emit a
1331 // register based JALR instruction.
1332 const char runtimeExpressions_mips[][512] =
1333 {
1334 // Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap)
1335 "int* (*f) (void*, int, int, int, int, int) = (int* (*) (void*, int, int, int, int, int)) "
1336 "_Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocationCubemapFace; "
1337 "(int*) f((void*) 0x%lx, %u, %u, %u, 0, 0)",
1338
1339 // Type* rsaAllocationGetType(Context*, Allocation*)
1340 "void* (*f) (void*, void*) = (void* (*) (void*, void*)) rsaAllocationGetType; (void*) f((void*) 0x%lx, (void*) 0x%lx)",
1341
1342 // rsaTypeGetNativeData(Context*, Type*, void* typeData, size)
1343 // Pack the data in the following way mHal.state.dimX; mHal.state.dimY; mHal.state.dimZ;
1344 // mHal.state.lodCount; mHal.state.faces; mElement; into typeData
1345 // Need to specify 32 or 64 bit for uint_t since this differs between devices
1346 "uint%u_t data[6]; void* (*f)(void*, void*, uintptr_t*, uint32_t) = (void* (*)(void*, void*, uintptr_t*, uint32_t)) "
1347 "rsaTypeGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 6); data[0]",
1348 "uint%u_t data[6]; void* (*f)(void*, void*, uintptr_t*, uint32_t) = (void* (*)(void*, void*, uintptr_t*, uint32_t)) "
1349 "rsaTypeGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 6); data[1]",
1350 "uint%u_t data[6]; void* (*f)(void*, void*, uintptr_t*, uint32_t) = (void* (*)(void*, void*, uintptr_t*, uint32_t)) "
1351 "rsaTypeGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 6); data[2]",
1352 "uint%u_t data[6]; void* (*f)(void*, void*, uintptr_t*, uint32_t) = (void* (*)(void*, void*, uintptr_t*, uint32_t)) "
1353 "rsaTypeGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 6); data[5]",
1354
1355 // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size)
1356 // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into elemData
1357 "uint32_t data[5]; void* (*f)(void*, void*, uint32_t*, uint32_t) = (void* (*)(void*, void*, uint32_t*, uint32_t)) "
1358 "rsaElementGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 5); data[0]", // Type
1359 "uint32_t data[5]; void* (*f)(void*, void*, uint32_t*, uint32_t) = (void* (*)(void*, void*, uint32_t*, uint32_t)) "
1360 "rsaElementGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 5); data[1]", // Kind
1361 "uint32_t data[5]; void* (*f)(void*, void*, uint32_t*, uint32_t) = (void* (*)(void*, void*, uint32_t*, uint32_t)) "
1362 "rsaElementGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 5); data[3]", // Vector size
1363 "uint32_t data[5]; void* (*f)(void*, void*, uint32_t*, uint32_t) = (void* (*)(void*, void*, uint32_t*, uint32_t)) "
1364 "rsaElementGetNativeData; (void*) f((void*) 0x%lx, (void*) 0x%lx, data, 5); data[4]", // Field count
1365
1366 // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t *ids, const char **names,
1367 // size_t *arraySizes, uint32_t dataSize)
1368 // Needed for Allocations of structs to gather details about fields/Subelements
1369 "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];"
1370 "void* (*f) (void*, void*, uintptr_t*, const char**, size_t*, uint32_t) = "
1371 "(void* (*) (void*, void*, uintptr_t*, const char**, size_t*, uint32_t)) rsaElementGetSubElements;"
1372 "(void*) f((void*) 0x%lx, (void*) 0x%lx, (uintptr_t*) ids, names, arr_size, (uint32_t) %u);"
1373 "ids[%u]", // Element* of field
1374 "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];"
1375 "void* (*f) (void*, void*, uintptr_t*, const char**, size_t*, uint32_t) = "
1376 "(void* (*) (void*, void*, uintptr_t*, const char**, size_t*, uint32_t)) rsaElementGetSubElements;"
1377 "(void*) f((void*) 0x%lx, (void*) 0x%lx, (uintptr_t*) ids, names, arr_size, (uint32_t) %u);"
1378 "names[%u]", // Name of field
1379 "void* ids[%u]; const char* names[%u]; size_t arr_size[%u];"
1380 "void* (*f) (void*, void*, uintptr_t*, const char**, size_t*, uint32_t) = "
1381 "(void* (*) (void*, void*, uintptr_t*, const char**, size_t*, uint32_t)) rsaElementGetSubElements;"
1382 "(void*) f((void*) 0x%lx, (void*) 0x%lx, (uintptr_t*) ids, names, arr_size, (uint32_t) %u);"
1383 "arr_size[%u]" // Array size of field
1384 };
1385
1386} // end of the anonymous namespace
1387
1388
1389// Retrieve the string to JIT for the given expression
1390const char*
1391RenderScriptRuntime::JITTemplate(ExpressionStrings e)
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001392{
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001393 // be nice to your Mips friend when adding new expression strings
1394 static_assert(sizeof(runtimeExpressions)/sizeof(runtimeExpressions[0]) ==
1395 sizeof(runtimeExpressions_mips)/sizeof(runtimeExpressions_mips[0]),
1396 "#runtimeExpressions != #runtimeExpressions_mips");
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001397
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001398 assert((e >= eExprGetOffsetPtr && e <= eExprSubelementsArrSize) &&
1399 "Expression string out of bounds");
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001400
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001401 llvm::Triple::ArchType arch = GetTargetRef().GetArchitecture().GetMachine();
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001402
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001403 // mips JAL workaround
1404 if(arch == llvm::Triple::ArchType::mips64el || arch == llvm::Triple::ArchType::mipsel)
1405 return runtimeExpressions_mips[e];
1406 else
1407 return runtimeExpressions[e];
1408}
Ewan Crawford8b244e22015-11-30 10:29:49 +00001409
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001410
1411// JITs the RS runtime for the internal data pointer of an allocation.
1412// Is passed x,y,z coordinates for the pointer to a specific element.
1413// Then sets the data_ptr member in Allocation with the result.
1414// Returns true on success, false otherwise
1415bool
1416RenderScriptRuntime::JITDataPointer(AllocationDetails* allocation, StackFrame* frame_ptr,
1417 unsigned int x, unsigned int y, unsigned int z)
1418{
1419 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1420
1421 if (!allocation->address.isValid())
1422 {
1423 if (log)
1424 log->Printf("RenderScriptRuntime::JITDataPointer - Failed to find allocation details");
1425 return false;
1426 }
1427
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001428 const char* expr_cstr = JITTemplate(eExprGetOffsetPtr);
1429 char buffer[jit_max_expr_size];
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001430
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001431 int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->address.get(), x, y, z);
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001432 if (chars_written < 0)
1433 {
1434 if (log)
1435 log->Printf("RenderScriptRuntime::JITDataPointer - Encoding error in snprintf()");
1436 return false;
1437 }
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001438 else if (chars_written >= jit_max_expr_size)
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001439 {
1440 if (log)
1441 log->Printf("RenderScriptRuntime::JITDataPointer - Expression too long");
1442 return false;
1443 }
1444
1445 uint64_t result = 0;
1446 if (!EvalRSExpression(buffer, frame_ptr, &result))
1447 return false;
1448
1449 addr_t mem_ptr = static_cast<lldb::addr_t>(result);
1450 allocation->data_ptr = mem_ptr;
1451
1452 return true;
1453}
1454
1455// JITs the RS runtime for the internal pointer to the RS Type of an allocation
1456// Then sets the type_ptr member in Allocation with the result.
1457// Returns true on success, false otherwise
1458bool
1459RenderScriptRuntime::JITTypePointer(AllocationDetails* allocation, StackFrame* frame_ptr)
1460{
1461 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1462
1463 if (!allocation->address.isValid() || !allocation->context.isValid())
1464 {
1465 if (log)
1466 log->Printf("RenderScriptRuntime::JITTypePointer - Failed to find allocation details");
1467 return false;
1468 }
1469
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001470 const char* expr_cstr = JITTemplate(eExprAllocGetType);
1471 char buffer[jit_max_expr_size];
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001472
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001473 int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->context.get(), *allocation->address.get());
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001474 if (chars_written < 0)
1475 {
1476 if (log)
1477 log->Printf("RenderScriptRuntime::JITDataPointer - Encoding error in snprintf()");
1478 return false;
1479 }
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001480 else if (chars_written >= jit_max_expr_size)
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001481 {
1482 if (log)
1483 log->Printf("RenderScriptRuntime::JITTypePointer - Expression too long");
1484 return false;
1485 }
1486
1487 uint64_t result = 0;
1488 if (!EvalRSExpression(buffer, frame_ptr, &result))
1489 return false;
1490
1491 addr_t type_ptr = static_cast<lldb::addr_t>(result);
1492 allocation->type_ptr = type_ptr;
1493
1494 return true;
1495}
1496
1497// JITs the RS runtime for information about the dimensions and type of an allocation
1498// Then sets dimension and element_ptr members in Allocation with the result.
1499// Returns true on success, false otherwise
1500bool
1501RenderScriptRuntime::JITTypePacked(AllocationDetails* allocation, StackFrame* frame_ptr)
1502{
1503 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1504
1505 if (!allocation->type_ptr.isValid() || !allocation->context.isValid())
1506 {
1507 if (log)
1508 log->Printf("RenderScriptRuntime::JITTypePacked - Failed to find allocation details");
1509 return false;
1510 }
1511
1512 // Expression is different depending on if device is 32 or 64 bit
1513 uint32_t archByteSize = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
1514 const unsigned int bits = archByteSize == 4 ? 32 : 64;
1515
1516 // We want 4 elements from packed data
1517 const unsigned int num_exprs = 4;
1518 assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1) && "Invalid number of expressions");
1519
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001520 char buffer[num_exprs][jit_max_expr_size];
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001521 uint64_t results[num_exprs];
1522
1523 for (unsigned int i = 0; i < num_exprs; ++i)
1524 {
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001525 const char* expr_cstr = JITTemplate((ExpressionStrings) (eExprTypeDimX + i));
1526 int chars_written = snprintf(buffer[i], jit_max_expr_size, expr_cstr, bits,
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001527 *allocation->context.get(), *allocation->type_ptr.get());
1528 if (chars_written < 0)
1529 {
1530 if (log)
1531 log->Printf("RenderScriptRuntime::JITDataPointer - Encoding error in snprintf()");
1532 return false;
1533 }
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001534 else if (chars_written >= jit_max_expr_size)
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001535 {
1536 if (log)
1537 log->Printf("RenderScriptRuntime::JITTypePacked - Expression too long");
1538 return false;
1539 }
1540
1541 // Perform expression evaluation
1542 if (!EvalRSExpression(buffer[i], frame_ptr, &results[i]))
1543 return false;
1544 }
1545
1546 // Assign results to allocation members
1547 AllocationDetails::Dimension dims;
1548 dims.dim_1 = static_cast<uint32_t>(results[0]);
1549 dims.dim_2 = static_cast<uint32_t>(results[1]);
1550 dims.dim_3 = static_cast<uint32_t>(results[2]);
1551 allocation->dimension = dims;
1552
1553 addr_t elem_ptr = static_cast<lldb::addr_t>(results[3]);
Ewan Crawford8b244e22015-11-30 10:29:49 +00001554 allocation->element.element_ptr = elem_ptr;
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001555
1556 if (log)
1557 log->Printf("RenderScriptRuntime::JITTypePacked - dims (%u, %u, %u) Element*: 0x%" PRIx64,
1558 dims.dim_1, dims.dim_2, dims.dim_3, elem_ptr);
1559
1560 return true;
1561}
1562
1563// JITs the RS runtime for information about the Element of an allocation
Ewan Crawford8b244e22015-11-30 10:29:49 +00001564// Then sets type, type_vec_size, field_count and type_kind members in Element with the result.
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001565// Returns true on success, false otherwise
1566bool
Ewan Crawford8b244e22015-11-30 10:29:49 +00001567RenderScriptRuntime::JITElementPacked(Element& elem, const lldb::addr_t context, StackFrame* frame_ptr)
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001568{
1569 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1570
Ewan Crawford8b244e22015-11-30 10:29:49 +00001571 if (!elem.element_ptr.isValid())
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001572 {
1573 if (log)
1574 log->Printf("RenderScriptRuntime::JITElementPacked - Failed to find allocation details");
1575 return false;
1576 }
1577
Ewan Crawford8b244e22015-11-30 10:29:49 +00001578 // We want 4 elements from packed data
1579 const unsigned int num_exprs = 4;
1580 assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1) && "Invalid number of expressions");
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001581
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001582 char buffer[num_exprs][jit_max_expr_size];
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001583 uint64_t results[num_exprs];
1584
1585 for (unsigned int i = 0; i < num_exprs; i++)
1586 {
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001587 const char* expr_cstr = JITTemplate((ExpressionStrings) (eExprElementType + i));
1588 int chars_written = snprintf(buffer[i], jit_max_expr_size, expr_cstr, context, *elem.element_ptr.get());
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001589 if (chars_written < 0)
1590 {
1591 if (log)
Ewan Crawford8b244e22015-11-30 10:29:49 +00001592 log->Printf("RenderScriptRuntime::JITElementPacked - Encoding error in snprintf()");
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001593 return false;
1594 }
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001595 else if (chars_written >= jit_max_expr_size)
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001596 {
1597 if (log)
1598 log->Printf("RenderScriptRuntime::JITElementPacked - Expression too long");
1599 return false;
1600 }
1601
1602 // Perform expression evaluation
1603 if (!EvalRSExpression(buffer[i], frame_ptr, &results[i]))
1604 return false;
1605 }
1606
1607 // Assign results to allocation members
Ewan Crawford8b244e22015-11-30 10:29:49 +00001608 elem.type = static_cast<RenderScriptRuntime::Element::DataType>(results[0]);
1609 elem.type_kind = static_cast<RenderScriptRuntime::Element::DataKind>(results[1]);
1610 elem.type_vec_size = static_cast<uint32_t>(results[2]);
1611 elem.field_count = static_cast<uint32_t>(results[3]);
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001612
1613 if (log)
Ewan Crawford8b244e22015-11-30 10:29:49 +00001614 log->Printf("RenderScriptRuntime::JITElementPacked - data type %u, pixel type %u, vector size %u, field count %u",
1615 *elem.type.get(), *elem.type_kind.get(), *elem.type_vec_size.get(), *elem.field_count.get());
1616
1617 // If this Element has subelements then JIT rsaElementGetSubElements() for details about its fields
1618 if (*elem.field_count.get() > 0 && !JITSubelements(elem, context, frame_ptr))
1619 return false;
1620
1621 return true;
1622}
1623
1624// JITs the RS runtime for information about the subelements/fields of a struct allocation
1625// This is necessary for infering the struct type so we can pretty print the allocation's contents.
1626// Returns true on success, false otherwise
1627bool
1628RenderScriptRuntime::JITSubelements(Element& elem, const lldb::addr_t context, StackFrame* frame_ptr)
1629{
1630 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1631
1632 if (!elem.element_ptr.isValid() || !elem.field_count.isValid())
1633 {
1634 if (log)
1635 log->Printf("RenderScriptRuntime::JITSubelements - Failed to find allocation details");
1636 return false;
1637 }
1638
1639 const short num_exprs = 3;
1640 assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1) && "Invalid number of expressions");
1641
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001642 char expr_buffer[jit_max_expr_size];
Ewan Crawford8b244e22015-11-30 10:29:49 +00001643 uint64_t results;
1644
1645 // Iterate over struct fields.
1646 const uint32_t field_count = *elem.field_count.get();
1647 for (unsigned int field_index = 0; field_index < field_count; ++field_index)
1648 {
1649 Element child;
1650 for (unsigned int expr_index = 0; expr_index < num_exprs; ++expr_index)
1651 {
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001652 const char* expr_cstr = JITTemplate((ExpressionStrings) (eExprSubelementsId + expr_index));
1653 int chars_written = snprintf(expr_buffer, jit_max_expr_size, expr_cstr,
Ewan Crawford8b244e22015-11-30 10:29:49 +00001654 field_count, field_count, field_count,
1655 context, *elem.element_ptr.get(), field_count, field_index);
1656 if (chars_written < 0)
1657 {
1658 if (log)
1659 log->Printf("RenderScriptRuntime::JITSubelements - Encoding error in snprintf()");
1660 return false;
1661 }
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001662 else if (chars_written >= jit_max_expr_size)
Ewan Crawford8b244e22015-11-30 10:29:49 +00001663 {
1664 if (log)
1665 log->Printf("RenderScriptRuntime::JITSubelements - Expression too long");
1666 return false;
1667 }
1668
1669 // Perform expression evaluation
1670 if (!EvalRSExpression(expr_buffer, frame_ptr, &results))
1671 return false;
1672
1673 if (log)
1674 log->Printf("RenderScriptRuntime::JITSubelements - Expr result 0x%" PRIx64, results);
1675
1676 switch(expr_index)
1677 {
1678 case 0: // Element* of child
1679 child.element_ptr = static_cast<addr_t>(results);
1680 break;
1681 case 1: // Name of child
1682 {
1683 lldb::addr_t address = static_cast<addr_t>(results);
1684 Error err;
1685 std::string name;
1686 GetProcess()->ReadCStringFromMemory(address, name, err);
1687 if (!err.Fail())
1688 child.type_name = ConstString(name);
1689 else
1690 {
1691 if (log)
1692 log->Printf("RenderScriptRuntime::JITSubelements - Warning: Couldn't read field name");
1693 }
1694 break;
1695 }
1696 case 2: // Array size of child
1697 child.array_size = static_cast<uint32_t>(results);
1698 break;
1699 }
1700 }
1701
1702 // We need to recursively JIT each Element field of the struct since
1703 // structs can be nested inside structs.
1704 if (!JITElementPacked(child, context, frame_ptr))
1705 return false;
1706 elem.children.push_back(child);
1707 }
1708
1709 // Try to infer the name of the struct type so we can pretty print the allocation contents.
1710 FindStructTypeName(elem, frame_ptr);
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001711
1712 return true;
1713}
1714
Ewan Crawforda0f08672015-10-16 08:28:47 +00001715// JITs the RS runtime for the address of the last element in the allocation.
1716// The `elem_size` paramter represents the size of a single element, including padding.
1717// Which is needed as an offset from the last element pointer.
1718// Using this offset minus the starting address we can calculate the size of the allocation.
1719// Returns true on success, false otherwise
1720bool
Ewan Crawford8b244e22015-11-30 10:29:49 +00001721RenderScriptRuntime::JITAllocationSize(AllocationDetails* allocation, StackFrame* frame_ptr)
Ewan Crawforda0f08672015-10-16 08:28:47 +00001722{
1723 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1724
1725 if (!allocation->address.isValid() || !allocation->dimension.isValid()
Ewan Crawford8b244e22015-11-30 10:29:49 +00001726 || !allocation->data_ptr.isValid() || !allocation->element.datum_size.isValid())
Ewan Crawforda0f08672015-10-16 08:28:47 +00001727 {
1728 if (log)
1729 log->Printf("RenderScriptRuntime::JITAllocationSize - Failed to find allocation details");
1730 return false;
1731 }
1732
Ewan Crawforda0f08672015-10-16 08:28:47 +00001733 // Find dimensions
1734 unsigned int dim_x = allocation->dimension.get()->dim_1;
1735 unsigned int dim_y = allocation->dimension.get()->dim_2;
1736 unsigned int dim_z = allocation->dimension.get()->dim_3;
1737
Ewan Crawford8b244e22015-11-30 10:29:49 +00001738 // Our plan of jitting the last element address doesn't seem to work for struct Allocations
1739 // Instead try to infer the size ourselves without any inter element padding.
1740 if (allocation->element.children.size() > 0)
1741 {
1742 if (dim_x == 0) dim_x = 1;
1743 if (dim_y == 0) dim_y = 1;
1744 if (dim_z == 0) dim_z = 1;
1745
1746 allocation->size = dim_x * dim_y * dim_z * *allocation->element.datum_size.get();
1747
1748 if (log)
1749 log->Printf("RenderScriptRuntime::JITAllocationSize - Infered size of struct allocation %u", *allocation->size.get());
1750
1751 return true;
1752 }
1753
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001754 const char* expr_cstr = JITTemplate(eExprGetOffsetPtr);
1755 char buffer[jit_max_expr_size];
Ewan Crawford8b244e22015-11-30 10:29:49 +00001756
Ewan Crawforda0f08672015-10-16 08:28:47 +00001757 // Calculate last element
1758 dim_x = dim_x == 0 ? 0 : dim_x - 1;
1759 dim_y = dim_y == 0 ? 0 : dim_y - 1;
1760 dim_z = dim_z == 0 ? 0 : dim_z - 1;
1761
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001762 int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->address.get(),
Ewan Crawforda0f08672015-10-16 08:28:47 +00001763 dim_x, dim_y, dim_z);
1764 if (chars_written < 0)
1765 {
1766 if (log)
1767 log->Printf("RenderScriptRuntime::JITAllocationSize - Encoding error in snprintf()");
1768 return false;
1769 }
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001770 else if (chars_written >= jit_max_expr_size)
Ewan Crawforda0f08672015-10-16 08:28:47 +00001771 {
1772 if (log)
1773 log->Printf("RenderScriptRuntime::JITAllocationSize - Expression too long");
1774 return false;
1775 }
1776
1777 uint64_t result = 0;
1778 if (!EvalRSExpression(buffer, frame_ptr, &result))
1779 return false;
1780
1781 addr_t mem_ptr = static_cast<lldb::addr_t>(result);
1782 // Find pointer to last element and add on size of an element
Ewan Crawford8b244e22015-11-30 10:29:49 +00001783 allocation->size = static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()) + *allocation->element.datum_size.get();
Ewan Crawforda0f08672015-10-16 08:28:47 +00001784
1785 return true;
1786}
1787
1788// JITs the RS runtime for information about the stride between rows in the allocation.
1789// This is done to detect padding, since allocated memory is 16-byte aligned.
1790// Returns true on success, false otherwise
1791bool
1792RenderScriptRuntime::JITAllocationStride(AllocationDetails* allocation, StackFrame* frame_ptr)
1793{
1794 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1795
1796 if (!allocation->address.isValid() || !allocation->data_ptr.isValid())
1797 {
1798 if (log)
1799 log->Printf("RenderScriptRuntime::JITAllocationStride - Failed to find allocation details");
1800 return false;
1801 }
1802
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001803 const char* expr_cstr = JITTemplate(eExprGetOffsetPtr);
1804 char buffer[jit_max_expr_size];
Ewan Crawforda0f08672015-10-16 08:28:47 +00001805
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001806 int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->address.get(),
Ewan Crawforda0f08672015-10-16 08:28:47 +00001807 0, 1, 0);
1808 if (chars_written < 0)
1809 {
1810 if (log)
1811 log->Printf("RenderScriptRuntime::JITAllocationStride - Encoding error in snprintf()");
1812 return false;
1813 }
Ewan Crawfordb1651b82015-12-07 13:50:32 +00001814 else if (chars_written >= jit_max_expr_size)
Ewan Crawforda0f08672015-10-16 08:28:47 +00001815 {
1816 if (log)
1817 log->Printf("RenderScriptRuntime::JITAllocationStride - Expression too long");
1818 return false;
1819 }
1820
1821 uint64_t result = 0;
1822 if (!EvalRSExpression(buffer, frame_ptr, &result))
1823 return false;
1824
1825 addr_t mem_ptr = static_cast<lldb::addr_t>(result);
1826 allocation->stride = static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get());
1827
1828 return true;
1829}
1830
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001831// JIT all the current runtime info regarding an allocation
1832bool
1833RenderScriptRuntime::RefreshAllocation(AllocationDetails* allocation, StackFrame* frame_ptr)
1834{
1835 // GetOffsetPointer()
1836 if (!JITDataPointer(allocation, frame_ptr))
1837 return false;
1838
1839 // rsaAllocationGetType()
1840 if (!JITTypePointer(allocation, frame_ptr))
1841 return false;
1842
1843 // rsaTypeGetNativeData()
1844 if (!JITTypePacked(allocation, frame_ptr))
1845 return false;
1846
1847 // rsaElementGetNativeData()
Ewan Crawford8b244e22015-11-30 10:29:49 +00001848 if (!JITElementPacked(allocation->element, *allocation->context.get(), frame_ptr))
Ewan Crawford15f2bd92015-10-06 08:42:32 +00001849 return false;
1850
Ewan Crawford8b244e22015-11-30 10:29:49 +00001851 // Sets the datum_size member in Element
1852 SetElementSize(allocation->element);
1853
Ewan Crawford55232f02015-10-21 08:50:42 +00001854 // Use GetOffsetPointer() to infer size of the allocation
Ewan Crawford8b244e22015-11-30 10:29:49 +00001855 if (!JITAllocationSize(allocation, frame_ptr))
Ewan Crawford55232f02015-10-21 08:50:42 +00001856 return false;
1857
1858 return true;
1859}
1860
Ewan Crawford8b244e22015-11-30 10:29:49 +00001861// Function attempts to set the type_name member of the paramaterised Element object.
1862// This string should be the name of the struct type the Element represents.
1863// We need this string for pretty printing the Element to users.
1864void
1865RenderScriptRuntime::FindStructTypeName(Element& elem, StackFrame* frame_ptr)
Ewan Crawford55232f02015-10-21 08:50:42 +00001866{
Ewan Crawford8b244e22015-11-30 10:29:49 +00001867 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1868
1869 if (!elem.type_name.IsEmpty()) // Name already set
1870 return;
1871 else
Adrian McCarthyfe06b5a2015-11-30 22:18:43 +00001872 elem.type_name = Element::GetFallbackStructName(); // Default type name if we don't succeed
Ewan Crawford8b244e22015-11-30 10:29:49 +00001873
1874 // Find all the global variables from the script rs modules
1875 VariableList variable_list;
1876 for (auto module_sp : m_rsmodules)
1877 module_sp->m_module->FindGlobalVariables(RegularExpression("."), true, UINT32_MAX, variable_list);
1878
1879 // Iterate over all the global variables looking for one with a matching type to the Element.
1880 // We make the assumption a match exists since there needs to be a global variable to reflect the
1881 // struct type back into java host code.
1882 for (uint32_t var_index = 0; var_index < variable_list.GetSize(); ++var_index)
1883 {
1884 const VariableSP var_sp(variable_list.GetVariableAtIndex(var_index));
1885 if (!var_sp)
1886 continue;
1887
1888 ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp);
1889 if (!valobj_sp)
1890 continue;
1891
1892 // Find the number of variable fields.
1893 // If it has no fields, or more fields than our Element, then it can't be the struct we're looking for.
1894 // Don't check for equality since RS can add extra struct members for padding.
1895 size_t num_children = valobj_sp->GetNumChildren();
1896 if (num_children > elem.children.size() || num_children == 0)
1897 continue;
1898
1899 // Iterate over children looking for members with matching field names.
1900 // If all the field names match, this is likely the struct we want.
1901 //
1902 // TODO: This could be made more robust by also checking children data sizes, or array size
1903 bool found = true;
1904 for (size_t child_index = 0; child_index < num_children; ++child_index)
1905 {
1906 ValueObjectSP child = valobj_sp->GetChildAtIndex(child_index, true);
1907 if (!child || (child->GetName() != elem.children[child_index].type_name))
1908 {
1909 found = false;
1910 break;
1911 }
1912 }
1913
1914 // RS can add extra struct members for padding in the format '#rs_padding_[0-9]+'
1915 if (found && num_children < elem.children.size())
1916 {
1917 const unsigned int size_diff = elem.children.size() - num_children;
1918 if (log)
1919 log->Printf("RenderScriptRuntime::FindStructTypeName - %u padding struct entries", size_diff);
1920
1921 for (unsigned int padding_index = 0; padding_index < size_diff; ++padding_index)
1922 {
1923 const ConstString& name = elem.children[num_children + padding_index].type_name;
1924 if (strcmp(name.AsCString(), "#rs_padding") < 0)
1925 found = false;
1926 }
1927 }
1928
1929 // We've found a global var with matching type
1930 if (found)
1931 {
1932 // Dereference since our Element type isn't a pointer.
1933 if (valobj_sp->IsPointerType())
1934 {
1935 Error err;
1936 ValueObjectSP deref_valobj = valobj_sp->Dereference(err);
1937 if (!err.Fail())
1938 valobj_sp = deref_valobj;
1939 }
1940
1941 // Save name of variable in Element.
1942 elem.type_name = valobj_sp->GetTypeName();
1943 if (log)
1944 log->Printf("RenderScriptRuntime::FindStructTypeName - Element name set to %s", elem.type_name.AsCString());
1945
1946 return;
1947 }
1948 }
1949}
1950
1951// Function sets the datum_size member of Element. Representing the size of a single instance including padding.
1952// Assumes the relevant allocation information has already been jitted.
1953void
1954RenderScriptRuntime::SetElementSize(Element& elem)
1955{
1956 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1957 const Element::DataType type = *elem.type.get();
Ewan Crawford2e920712015-12-17 16:40:05 +00001958 assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT
Ewan Crawford55232f02015-10-21 08:50:42 +00001959 && "Invalid allocation type");
1960
Ewan Crawford8b244e22015-11-30 10:29:49 +00001961 const unsigned int vec_size = *elem.type_vec_size.get();
1962 unsigned int data_size = 0;
Ewan Crawford2e920712015-12-17 16:40:05 +00001963 unsigned int padding = 0;
Ewan Crawford55232f02015-10-21 08:50:42 +00001964
Ewan Crawford8b244e22015-11-30 10:29:49 +00001965 // Element is of a struct type, calculate size recursively.
1966 if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0))
1967 {
1968 for (Element& child : elem.children)
1969 {
1970 SetElementSize(child);
1971 const unsigned int array_size = child.array_size.isValid() ? *child.array_size.get() : 1;
1972 data_size += *child.datum_size.get() * array_size;
1973 }
1974 }
Ewan Crawford2e920712015-12-17 16:40:05 +00001975 else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 || type == Element::RS_TYPE_UNSIGNED_5_5_5_1 ||
1976 type == Element::RS_TYPE_UNSIGNED_4_4_4_4) // These have been packed already
1977 {
1978 data_size = AllocationDetails::RSTypeToFormat[type][eElementSize];
1979 }
1980 else if (type < Element::RS_TYPE_ELEMENT)
1981 {
Ewan Crawford8b244e22015-11-30 10:29:49 +00001982 data_size = vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize];
Ewan Crawford2e920712015-12-17 16:40:05 +00001983 if (vec_size == 3)
1984 padding = AllocationDetails::RSTypeToFormat[type][eElementSize];
1985 }
1986 else
1987 data_size = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
Ewan Crawford8b244e22015-11-30 10:29:49 +00001988
1989 elem.padding = padding;
1990 elem.datum_size = data_size + padding;
1991 if (log)
1992 log->Printf("RenderScriptRuntime::SetElementSize - element size set to %u", data_size + padding);
Ewan Crawford55232f02015-10-21 08:50:42 +00001993}
1994
1995// Given an allocation, this function copies the allocation contents from device into a buffer on the heap.
1996// Returning a shared pointer to the buffer containing the data.
1997std::shared_ptr<uint8_t>
1998RenderScriptRuntime::GetAllocationData(AllocationDetails* allocation, StackFrame* frame_ptr)
1999{
2000 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2001
2002 // JIT all the allocation details
Ewan Crawford8b590622015-12-10 10:20:39 +00002003 if (allocation->shouldRefresh())
Ewan Crawford55232f02015-10-21 08:50:42 +00002004 {
2005 if (log)
2006 log->Printf("RenderScriptRuntime::GetAllocationData - Allocation details not calculated yet, jitting info");
2007
2008 if (!RefreshAllocation(allocation, frame_ptr))
2009 {
2010 if (log)
2011 log->Printf("RenderScriptRuntime::GetAllocationData - Couldn't JIT allocation details");
2012 return nullptr;
2013 }
2014 }
2015
Ewan Crawford8b244e22015-11-30 10:29:49 +00002016 assert(allocation->data_ptr.isValid() && allocation->element.type.isValid() && allocation->element.type_vec_size.isValid()
Ewan Crawford55232f02015-10-21 08:50:42 +00002017 && allocation->size.isValid() && "Allocation information not available");
2018
2019 // Allocate a buffer to copy data into
2020 const unsigned int size = *allocation->size.get();
2021 std::shared_ptr<uint8_t> buffer(new uint8_t[size]);
2022 if (!buffer)
2023 {
2024 if (log)
2025 log->Printf("RenderScriptRuntime::GetAllocationData - Couldn't allocate a %u byte buffer", size);
2026 return nullptr;
2027 }
2028
2029 // Read the inferior memory
2030 Error error;
2031 lldb::addr_t data_ptr = *allocation->data_ptr.get();
2032 GetProcess()->ReadMemory(data_ptr, buffer.get(), size, error);
2033 if (error.Fail())
2034 {
2035 if (log)
2036 log->Printf("RenderScriptRuntime::GetAllocationData - '%s' Couldn't read %u bytes of allocation data from 0x%" PRIx64,
2037 error.AsCString(), size, data_ptr);
2038 return nullptr;
2039 }
2040
2041 return buffer;
2042}
2043
2044// Function copies data from a binary file into an allocation.
2045// There is a header at the start of the file, FileHeader, before the data content itself.
2046// Information from this header is used to display warnings to the user about incompatabilities
2047bool
2048RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, const char* filename, StackFrame* frame_ptr)
2049{
2050 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2051
2052 // Find allocation with the given id
2053 AllocationDetails* alloc = FindAllocByID(strm, alloc_id);
2054 if (!alloc)
2055 return false;
2056
2057 if (log)
2058 log->Printf("RenderScriptRuntime::LoadAllocation - Found allocation 0x%" PRIx64, *alloc->address.get());
2059
2060 // JIT all the allocation details
Ewan Crawford8b590622015-12-10 10:20:39 +00002061 if (alloc->shouldRefresh())
Ewan Crawford55232f02015-10-21 08:50:42 +00002062 {
2063 if (log)
2064 log->Printf("RenderScriptRuntime::LoadAllocation - Allocation details not calculated yet, jitting info");
2065
2066 if (!RefreshAllocation(alloc, frame_ptr))
2067 {
2068 if (log)
2069 log->Printf("RenderScriptRuntime::LoadAllocation - Couldn't JIT allocation details");
Sylvestre Ledru4cfc9192015-10-26 08:49:04 +00002070 return false;
Ewan Crawford55232f02015-10-21 08:50:42 +00002071 }
2072 }
2073
Ewan Crawford8b244e22015-11-30 10:29:49 +00002074 assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && alloc->element.type_vec_size.isValid()
2075 && alloc->size.isValid() && alloc->element.datum_size.isValid() && "Allocation information not available");
Ewan Crawford55232f02015-10-21 08:50:42 +00002076
2077 // Check we can read from file
2078 FileSpec file(filename, true);
2079 if (!file.Exists())
2080 {
2081 strm.Printf("Error: File %s does not exist", filename);
2082 strm.EOL();
2083 return false;
2084 }
2085
2086 if (!file.Readable())
2087 {
2088 strm.Printf("Error: File %s does not have readable permissions", filename);
2089 strm.EOL();
2090 return false;
2091 }
2092
2093 // Read file into data buffer
2094 DataBufferSP data_sp(file.ReadFileContents());
2095
2096 // Cast start of buffer to FileHeader and use pointer to read metadata
2097 void* file_buffer = data_sp->GetBytes();
Ewan Crawford26e52a72016-01-07 10:19:09 +00002098 if (file_buffer == NULL || data_sp->GetByteSize() <
2099 (sizeof(AllocationDetails::FileHeader) + sizeof(AllocationDetails::ElementHeader)))
2100 {
2101 strm.Printf("Error: File %s does not contain enough data for header", filename);
2102 strm.EOL();
2103 return false;
2104 }
2105 const AllocationDetails::FileHeader* file_header = static_cast<AllocationDetails::FileHeader*>(file_buffer);
Ewan Crawford55232f02015-10-21 08:50:42 +00002106
Ewan Crawford26e52a72016-01-07 10:19:09 +00002107 // Check file starts with ascii characters "RSAD"
2108 if (file_header->ident[0] != 'R' || file_header->ident[1] != 'S' || file_header->ident[2] != 'A'
2109 || file_header->ident[3] != 'D')
2110 {
2111 strm.Printf("Error: File doesn't contain identifier for an RS allocation dump. Are you sure this is the correct file?");
2112 strm.EOL();
2113 return false;
2114 }
2115
2116 // Look at the type of the root element in the header
2117 AllocationDetails::ElementHeader root_element_header;
2118 memcpy(&root_element_header, static_cast<uint8_t*>(file_buffer) + sizeof(AllocationDetails::FileHeader),
2119 sizeof(AllocationDetails::ElementHeader));
Ewan Crawford55232f02015-10-21 08:50:42 +00002120
2121 if (log)
2122 log->Printf("RenderScriptRuntime::LoadAllocation - header type %u, element size %u",
Ewan Crawford26e52a72016-01-07 10:19:09 +00002123 root_element_header.type, root_element_header.element_size);
Ewan Crawford55232f02015-10-21 08:50:42 +00002124
2125 // Check if the target allocation and file both have the same number of bytes for an Element
Ewan Crawford26e52a72016-01-07 10:19:09 +00002126 if (*alloc->element.datum_size.get() != root_element_header.element_size)
Ewan Crawford55232f02015-10-21 08:50:42 +00002127 {
2128 strm.Printf("Warning: Mismatched Element sizes - file %u bytes, allocation %u bytes",
Ewan Crawford26e52a72016-01-07 10:19:09 +00002129 root_element_header.element_size, *alloc->element.datum_size.get());
Ewan Crawford55232f02015-10-21 08:50:42 +00002130 strm.EOL();
2131 }
2132
Ewan Crawford26e52a72016-01-07 10:19:09 +00002133 // Check if the target allocation and file both have the same type
2134 const unsigned int alloc_type = static_cast<unsigned int>(*alloc->element.type.get());
2135 const unsigned int file_type = root_element_header.type;
2136
2137 if (file_type > Element::RS_TYPE_FONT)
2138 {
2139 strm.Printf("Warning: File has unknown allocation type");
2140 strm.EOL();
2141 }
2142 else if (alloc_type != file_type)
Ewan Crawford55232f02015-10-21 08:50:42 +00002143 {
Ewan Crawford2e920712015-12-17 16:40:05 +00002144 // Enum value isn't monotonous, so doesn't always index RsDataTypeToString array
Ewan Crawford26e52a72016-01-07 10:19:09 +00002145 unsigned int printable_target_type_index = alloc_type;
2146 unsigned int printable_head_type_index = file_type;
2147 if (alloc_type >= Element::RS_TYPE_ELEMENT && alloc_type <= Element::RS_TYPE_FONT)
Ewan Crawford2e920712015-12-17 16:40:05 +00002148 printable_target_type_index = static_cast<Element::DataType>(
Ewan Crawford26e52a72016-01-07 10:19:09 +00002149 (alloc_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1);
Ewan Crawford2e920712015-12-17 16:40:05 +00002150
Ewan Crawford26e52a72016-01-07 10:19:09 +00002151 if (file_type >= Element::RS_TYPE_ELEMENT && file_type <= Element::RS_TYPE_FONT)
Ewan Crawford2e920712015-12-17 16:40:05 +00002152 printable_head_type_index = static_cast<Element::DataType>(
Ewan Crawford26e52a72016-01-07 10:19:09 +00002153 (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1);
Ewan Crawford2e920712015-12-17 16:40:05 +00002154
2155 const char* file_type_cstr = AllocationDetails::RsDataTypeToString[printable_head_type_index][0];
2156 const char* target_type_cstr = AllocationDetails::RsDataTypeToString[printable_target_type_index][0];
Ewan Crawford55232f02015-10-21 08:50:42 +00002157
2158 strm.Printf("Warning: Mismatched Types - file '%s' type, allocation '%s' type",
Ewan Crawford2e920712015-12-17 16:40:05 +00002159 file_type_cstr, target_type_cstr);
Ewan Crawford55232f02015-10-21 08:50:42 +00002160 strm.EOL();
2161 }
2162
Ewan Crawford26e52a72016-01-07 10:19:09 +00002163 // Advance buffer past header
2164 file_buffer = static_cast<uint8_t*>(file_buffer) + file_header->hdr_size;
2165
Ewan Crawford55232f02015-10-21 08:50:42 +00002166 // Calculate size of allocation data in file
Ewan Crawford26e52a72016-01-07 10:19:09 +00002167 size_t length = data_sp->GetByteSize() - file_header->hdr_size;
Ewan Crawford55232f02015-10-21 08:50:42 +00002168
2169 // Check if the target allocation and file both have the same total data size.
2170 const unsigned int alloc_size = *alloc->size.get();
2171 if (alloc_size != length)
2172 {
2173 strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64 " bytes, allocation 0x%x bytes",
Jason Molendaeba832b2015-10-29 00:13:42 +00002174 (uint64_t) length, alloc_size);
Ewan Crawford55232f02015-10-21 08:50:42 +00002175 strm.EOL();
2176 length = alloc_size < length ? alloc_size : length; // Set length to copy to minimum
2177 }
2178
2179 // Copy file data from our buffer into the target allocation.
2180 lldb::addr_t alloc_data = *alloc->data_ptr.get();
2181 Error error;
2182 size_t bytes_written = GetProcess()->WriteMemory(alloc_data, file_buffer, length, error);
2183 if (!error.Success() || bytes_written != length)
2184 {
2185 strm.Printf("Error: Couldn't write data to allocation %s", error.AsCString());
2186 strm.EOL();
2187 return false;
2188 }
2189
2190 strm.Printf("Contents of file '%s' read into allocation %u", filename, alloc->id);
2191 strm.EOL();
2192
2193 return true;
2194}
2195
Ewan Crawford26e52a72016-01-07 10:19:09 +00002196// Function takes as parameters a byte buffer, which will eventually be written to file as the element header,
2197// an offset into that buffer, and an Element that will be saved into the buffer at the parametrised offset.
2198// Return value is the new offset after writing the element into the buffer.
2199// Elements are saved to the file as the ElementHeader struct followed by offsets to the structs of all the element's children.
2200size_t
2201RenderScriptRuntime::PopulateElementHeaders(const std::shared_ptr<uint8_t> header_buffer, size_t offset, const Element& elem)
2202{
2203 // File struct for an element header with all the relevant details copied from elem.
2204 // We assume members are valid already.
2205 AllocationDetails::ElementHeader elem_header;
2206 elem_header.type = *elem.type.get();
2207 elem_header.kind = *elem.type_kind.get();
2208 elem_header.element_size = *elem.datum_size.get();
2209 elem_header.vector_size = *elem.type_vec_size.get();
2210 elem_header.array_size = elem.array_size.isValid() ? *elem.array_size.get() : 0;
2211 const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader);
2212
2213 // Copy struct into buffer and advance offset
2214 // We assume that header_buffer has been checked for NULL before this method is called
2215 memcpy(header_buffer.get() + offset, &elem_header, elem_header_size);
2216 offset += elem_header_size;
2217
2218 // Starting offset of child ElementHeader struct
2219 size_t child_offset = offset + ((elem.children.size() + 1) * sizeof(uint32_t));
2220 for (const RenderScriptRuntime::Element& child : elem.children)
2221 {
2222 // Recursively populate the buffer with the element header structs of children.
2223 // Then save the offsets where they were set after the parent element header.
2224 memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t));
2225 offset += sizeof(uint32_t);
2226
2227 child_offset = PopulateElementHeaders(header_buffer, child_offset, child);
2228 }
2229
2230 // Zero indicates no more children
2231 memset(header_buffer.get() + offset, 0, sizeof(uint32_t));
2232
2233 return child_offset;
2234}
2235
2236// Given an Element object this function returns the total size needed in the file header to store the element's details.
2237// Taking into account the size of the element header struct, plus the offsets to all the element's children.
2238// Function is recursive so that the size of all ancestors is taken into account.
2239size_t
2240RenderScriptRuntime::CalculateElementHeaderSize(const Element& elem)
2241{
2242 size_t size = (elem.children.size() + 1) * sizeof(uint32_t); // Offsets to children plus zero terminator
2243 size += sizeof(AllocationDetails::ElementHeader); // Size of header struct with type details
2244
2245 // Calculate recursively for all descendants
2246 for (const Element& child : elem.children)
2247 size += CalculateElementHeaderSize(child);
2248
2249 return size;
2250}
2251
Ewan Crawford55232f02015-10-21 08:50:42 +00002252// Function copies allocation contents into a binary file.
2253// This file can then be loaded later into a different allocation.
2254// There is a header, FileHeader, before the allocation data containing meta-data.
2255bool
2256RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, const char* filename, StackFrame* frame_ptr)
2257{
2258 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2259
2260 // Find allocation with the given id
2261 AllocationDetails* alloc = FindAllocByID(strm, alloc_id);
2262 if (!alloc)
2263 return false;
2264
2265 if (log)
2266 log->Printf("RenderScriptRuntime::SaveAllocation - Found allocation 0x%" PRIx64, *alloc->address.get());
2267
2268 // JIT all the allocation details
Ewan Crawford8b590622015-12-10 10:20:39 +00002269 if (alloc->shouldRefresh())
Ewan Crawford55232f02015-10-21 08:50:42 +00002270 {
2271 if (log)
2272 log->Printf("RenderScriptRuntime::SaveAllocation - Allocation details not calculated yet, jitting info");
2273
2274 if (!RefreshAllocation(alloc, frame_ptr))
2275 {
2276 if (log)
2277 log->Printf("RenderScriptRuntime::SaveAllocation - Couldn't JIT allocation details");
Sylvestre Ledru4cfc9192015-10-26 08:49:04 +00002278 return false;
Ewan Crawford55232f02015-10-21 08:50:42 +00002279 }
2280 }
2281
Ewan Crawford8b244e22015-11-30 10:29:49 +00002282 assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && alloc->element.type_vec_size.isValid() && alloc->element.datum_size.get()
2283 && alloc->element.type_kind.isValid() && alloc->dimension.isValid() && "Allocation information not available");
Ewan Crawford55232f02015-10-21 08:50:42 +00002284
2285 // Check we can create writable file
2286 FileSpec file_spec(filename, true);
2287 File file(file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate | File::eOpenOptionTruncate);
2288 if (!file)
2289 {
2290 strm.Printf("Error: Failed to open '%s' for writing", filename);
2291 strm.EOL();
2292 return false;
2293 }
2294
2295 // Read allocation into buffer of heap memory
2296 const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
2297 if (!buffer)
2298 {
2299 strm.Printf("Error: Couldn't read allocation data into buffer");
2300 strm.EOL();
2301 return false;
2302 }
2303
2304 // Create the file header
2305 AllocationDetails::FileHeader head;
2306 head.ident[0] = 'R'; head.ident[1] = 'S'; head.ident[2] = 'A'; head.ident[3] = 'D';
Ewan Crawford2d623282015-10-21 10:27:10 +00002307 head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1);
2308 head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2);
2309 head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3);
Ewan Crawford26e52a72016-01-07 10:19:09 +00002310
2311 const size_t element_header_size = CalculateElementHeaderSize(alloc->element);
2312 assert((sizeof(AllocationDetails::FileHeader) + element_header_size) < UINT16_MAX && "Element header too large");
2313 head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) + element_header_size);
Ewan Crawford55232f02015-10-21 08:50:42 +00002314
2315 // Write the file header
2316 size_t num_bytes = sizeof(AllocationDetails::FileHeader);
Ewan Crawford26e52a72016-01-07 10:19:09 +00002317 if (log)
2318 log->Printf("RenderScriptRuntime::SaveAllocation - Writing File Header, 0x%zX bytes", num_bytes);
2319
2320 Error err = file.Write(&head, num_bytes);
2321 if (!err.Success())
2322 {
2323 strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename);
2324 strm.EOL();
2325 return false;
2326 }
2327
2328 // Create the headers describing the element type of the allocation.
2329 std::shared_ptr<uint8_t> element_header_buffer(new uint8_t[element_header_size]);
2330 if (element_header_buffer == nullptr)
2331 {
2332 strm.Printf("Internal Error: Couldn't allocate %zu bytes on the heap", element_header_size);
2333 strm.EOL();
2334 return false;
2335 }
2336
2337 PopulateElementHeaders(element_header_buffer, 0, alloc->element);
2338
2339 // Write headers for allocation element type to file
2340 num_bytes = element_header_size;
2341 if (log)
2342 log->Printf("RenderScriptRuntime::SaveAllocation - Writing Element Headers, 0x%zX bytes", num_bytes);
2343
2344 err = file.Write(element_header_buffer.get(), num_bytes);
Ewan Crawford55232f02015-10-21 08:50:42 +00002345 if (!err.Success())
2346 {
2347 strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename);
2348 strm.EOL();
2349 return false;
2350 }
2351
2352 // Write allocation data to file
2353 num_bytes = static_cast<size_t>(*alloc->size.get());
2354 if (log)
Ewan Crawford26e52a72016-01-07 10:19:09 +00002355 log->Printf("RenderScriptRuntime::SaveAllocation - Writing 0x%zX bytes", num_bytes);
Ewan Crawford55232f02015-10-21 08:50:42 +00002356
2357 err = file.Write(buffer.get(), num_bytes);
2358 if (!err.Success())
2359 {
2360 strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename);
2361 strm.EOL();
2362 return false;
2363 }
2364
2365 strm.Printf("Allocation written to file '%s'", filename);
2366 strm.EOL();
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002367 return true;
2368}
2369
Colin Riley5ec532a2015-04-09 16:49:25 +00002370bool
2371RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp)
2372{
Colin Riley4640cde2015-06-01 18:23:41 +00002373 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2374
Colin Riley5ec532a2015-04-09 16:49:25 +00002375 if (module_sp)
2376 {
2377 for (const auto &rs_module : m_rsmodules)
2378 {
Colin Riley4640cde2015-06-01 18:23:41 +00002379 if (rs_module->m_module == module_sp)
Ewan Crawford7dc77712015-09-10 10:08:48 +00002380 {
2381 // Check if the user has enabled automatically breaking on
2382 // all RS kernels.
2383 if (m_breakAllKernels)
2384 BreakOnModuleKernels(rs_module);
2385
Colin Riley5ec532a2015-04-09 16:49:25 +00002386 return false;
Ewan Crawford7dc77712015-09-10 10:08:48 +00002387 }
Colin Riley5ec532a2015-04-09 16:49:25 +00002388 }
Colin Rileyef20b082015-04-14 07:39:24 +00002389 bool module_loaded = false;
2390 switch (GetModuleKind(module_sp))
Colin Riley5ec532a2015-04-09 16:49:25 +00002391 {
Colin Rileyef20b082015-04-14 07:39:24 +00002392 case eModuleKindKernelObj:
2393 {
Colin Riley4640cde2015-06-01 18:23:41 +00002394 RSModuleDescriptorSP module_desc;
2395 module_desc.reset(new RSModuleDescriptor(module_sp));
2396 if (module_desc->ParseRSInfo())
Colin Rileyef20b082015-04-14 07:39:24 +00002397 {
2398 m_rsmodules.push_back(module_desc);
2399 module_loaded = true;
2400 }
Colin Riley4640cde2015-06-01 18:23:41 +00002401 if (module_loaded)
2402 {
2403 FixupScriptDetails(module_desc);
2404 }
Colin Rileyef20b082015-04-14 07:39:24 +00002405 break;
2406 }
2407 case eModuleKindDriver:
Colin Riley4640cde2015-06-01 18:23:41 +00002408 {
2409 if (!m_libRSDriver)
2410 {
2411 m_libRSDriver = module_sp;
2412 LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver);
2413 }
2414 break;
2415 }
Colin Rileyef20b082015-04-14 07:39:24 +00002416 case eModuleKindImpl:
Colin Riley4640cde2015-06-01 18:23:41 +00002417 {
2418 m_libRSCpuRef = module_sp;
2419 break;
2420 }
Colin Rileyef20b082015-04-14 07:39:24 +00002421 case eModuleKindLibRS:
Colin Riley4640cde2015-06-01 18:23:41 +00002422 {
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002423 if (!m_libRS)
Colin Riley4640cde2015-06-01 18:23:41 +00002424 {
2425 m_libRS = module_sp;
2426 static ConstString gDbgPresentStr("gDebuggerPresent");
2427 const Symbol* debug_present = m_libRS->FindFirstSymbolWithNameAndType(gDbgPresentStr, eSymbolTypeData);
2428 if (debug_present)
2429 {
2430 Error error;
2431 uint32_t flag = 0x00000001U;
2432 Target &target = GetProcess()->GetTarget();
Greg Clayton358cf1e2015-06-25 21:46:34 +00002433 addr_t addr = debug_present->GetLoadAddress(&target);
Colin Riley4640cde2015-06-01 18:23:41 +00002434 GetProcess()->WriteMemory(addr, &flag, sizeof(flag), error);
2435 if(error.Success())
2436 {
2437 if (log)
2438 log->Printf ("RenderScriptRuntime::LoadModule - Debugger present flag set on debugee");
2439
2440 m_debuggerPresentFlagged = true;
2441 }
2442 else if (log)
2443 {
2444 log->Printf ("RenderScriptRuntime::LoadModule - Error writing debugger present flags '%s' ", error.AsCString());
2445 }
2446 }
2447 else if (log)
2448 {
2449 log->Printf ("RenderScriptRuntime::LoadModule - Error writing debugger present flags - symbol not found");
2450 }
2451 }
2452 break;
2453 }
Colin Rileyef20b082015-04-14 07:39:24 +00002454 default:
2455 break;
Colin Riley5ec532a2015-04-09 16:49:25 +00002456 }
Colin Rileyef20b082015-04-14 07:39:24 +00002457 if (module_loaded)
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002458 Update();
Colin Rileyef20b082015-04-14 07:39:24 +00002459 return module_loaded;
Colin Riley5ec532a2015-04-09 16:49:25 +00002460 }
2461 return false;
2462}
2463
Colin Rileyef20b082015-04-14 07:39:24 +00002464void
2465RenderScriptRuntime::Update()
2466{
2467 if (m_rsmodules.size() > 0)
2468 {
2469 if (!m_initiated)
2470 {
2471 Initiate();
2472 }
2473 }
2474}
2475
Colin Riley5ec532a2015-04-09 16:49:25 +00002476// The maximum line length of an .rs.info packet
2477#define MAXLINE 500
2478
2479// The .rs.info symbol in renderscript modules contains a string which needs to be parsed.
2480// The string is basic and is parsed on a line by line basis.
2481bool
2482RSModuleDescriptor::ParseRSInfo()
2483{
2484 const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData);
2485 if (info_sym)
2486 {
Greg Clayton358cf1e2015-06-25 21:46:34 +00002487 const addr_t addr = info_sym->GetAddressRef().GetFileAddress();
Colin Riley5ec532a2015-04-09 16:49:25 +00002488 const addr_t size = info_sym->GetByteSize();
2489 const FileSpec fs = m_module->GetFileSpec();
2490
2491 DataBufferSP buffer = fs.ReadFileContents(addr, size);
2492
2493 if (!buffer)
2494 return false;
2495
2496 std::string info((const char *)buffer->GetBytes());
2497
2498 std::vector<std::string> info_lines;
Bruce Mitchenere8433cc2015-09-01 23:57:17 +00002499 size_t lpos = info.find('\n');
Colin Riley5ec532a2015-04-09 16:49:25 +00002500 while (lpos != std::string::npos)
2501 {
2502 info_lines.push_back(info.substr(0, lpos));
2503 info = info.substr(lpos + 1);
Bruce Mitchenere8433cc2015-09-01 23:57:17 +00002504 lpos = info.find('\n');
Colin Riley5ec532a2015-04-09 16:49:25 +00002505 }
2506 size_t offset = 0;
2507 while (offset < info_lines.size())
2508 {
2509 std::string line = info_lines[offset];
2510 // Parse directives
2511 uint32_t numDefns = 0;
2512 if (sscanf(line.c_str(), "exportVarCount: %u", &numDefns) == 1)
2513 {
2514 while (numDefns--)
Colin Riley4640cde2015-06-01 18:23:41 +00002515 m_globals.push_back(RSGlobalDescriptor(this, info_lines[++offset].c_str()));
Colin Riley5ec532a2015-04-09 16:49:25 +00002516 }
2517 else if (sscanf(line.c_str(), "exportFuncCount: %u", &numDefns) == 1)
2518 {
2519 }
2520 else if (sscanf(line.c_str(), "exportForEachCount: %u", &numDefns) == 1)
2521 {
2522 char name[MAXLINE];
2523 while (numDefns--)
2524 {
2525 uint32_t slot = 0;
2526 name[0] = '\0';
2527 if (sscanf(info_lines[++offset].c_str(), "%u - %s", &slot, &name[0]) == 2)
2528 {
Colin Riley4640cde2015-06-01 18:23:41 +00002529 m_kernels.push_back(RSKernelDescriptor(this, name, slot));
2530 }
2531 }
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002532 }
Colin Riley4640cde2015-06-01 18:23:41 +00002533 else if (sscanf(line.c_str(), "pragmaCount: %u", &numDefns) == 1)
2534 {
2535 char name[MAXLINE];
2536 char value[MAXLINE];
2537 while (numDefns--)
2538 {
2539 name[0] = '\0';
2540 value[0] = '\0';
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002541 if (sscanf(info_lines[++offset].c_str(), "%s - %s", &name[0], &value[0]) != 0
Colin Riley4640cde2015-06-01 18:23:41 +00002542 && (name[0] != '\0'))
2543 {
2544 m_pragmas[std::string(name)] = value;
Colin Riley5ec532a2015-04-09 16:49:25 +00002545 }
2546 }
2547 }
2548 else if (sscanf(line.c_str(), "objectSlotCount: %u", &numDefns) == 1)
2549 {
2550 }
2551
2552 offset++;
2553 }
2554 return m_kernels.size() > 0;
2555 }
2556 return false;
2557}
2558
2559bool
2560RenderScriptRuntime::ProbeModules(const ModuleList module_list)
2561{
2562 bool rs_found = false;
2563 size_t num_modules = module_list.GetSize();
2564 for (size_t i = 0; i < num_modules; i++)
2565 {
2566 auto module = module_list.GetModuleAtIndex(i);
2567 rs_found |= LoadModule(module);
2568 }
2569 return rs_found;
2570}
2571
2572void
Colin Riley4640cde2015-06-01 18:23:41 +00002573RenderScriptRuntime::Status(Stream &strm) const
2574{
2575 if (m_libRS)
2576 {
2577 strm.Printf("Runtime Library discovered.");
2578 strm.EOL();
2579 }
2580 if (m_libRSDriver)
2581 {
2582 strm.Printf("Runtime Driver discovered.");
2583 strm.EOL();
2584 }
2585 if (m_libRSCpuRef)
2586 {
2587 strm.Printf("CPU Reference Implementation discovered.");
2588 strm.EOL();
2589 }
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002590
Colin Riley4640cde2015-06-01 18:23:41 +00002591 if (m_runtimeHooks.size())
2592 {
2593 strm.Printf("Runtime functions hooked:");
2594 strm.EOL();
2595 for (auto b : m_runtimeHooks)
2596 {
2597 strm.Indent(b.second->defn->name);
2598 strm.EOL();
2599 }
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002600 }
Colin Riley4640cde2015-06-01 18:23:41 +00002601 else
2602 {
2603 strm.Printf("Runtime is not hooked.");
2604 strm.EOL();
2605 }
2606}
2607
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002608void
Colin Riley4640cde2015-06-01 18:23:41 +00002609RenderScriptRuntime::DumpContexts(Stream &strm) const
2610{
2611 strm.Printf("Inferred RenderScript Contexts:");
2612 strm.EOL();
2613 strm.IndentMore();
2614
2615 std::map<addr_t, uint64_t> contextReferences;
2616
Ewan Crawford78f339d2015-09-21 10:53:18 +00002617 // Iterate over all of the currently discovered scripts.
2618 // Note: We cant push or pop from m_scripts inside this loop or it may invalidate script.
2619 for (const auto & script : m_scripts)
Colin Riley4640cde2015-06-01 18:23:41 +00002620 {
Ewan Crawford78f339d2015-09-21 10:53:18 +00002621 if (!script->context.isValid())
2622 continue;
2623 lldb::addr_t context = *script->context;
2624
2625 if (contextReferences.find(context) != contextReferences.end())
Colin Riley4640cde2015-06-01 18:23:41 +00002626 {
Ewan Crawford78f339d2015-09-21 10:53:18 +00002627 contextReferences[context]++;
Colin Riley4640cde2015-06-01 18:23:41 +00002628 }
2629 else
2630 {
Ewan Crawford78f339d2015-09-21 10:53:18 +00002631 contextReferences[context] = 1;
Colin Riley4640cde2015-06-01 18:23:41 +00002632 }
2633 }
2634
2635 for (const auto& cRef : contextReferences)
2636 {
2637 strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances", cRef.first, cRef.second);
2638 strm.EOL();
2639 }
2640 strm.IndentLess();
2641}
2642
Aidan Dodds35e7b1a2016-01-06 15:43:52 +00002643void
Colin Riley4640cde2015-06-01 18:23:41 +00002644RenderScriptRuntime::DumpKernels(Stream &strm) const
2645{
2646 strm.Printf("RenderScript Kernels:");
2647 strm.EOL();
2648 strm.IndentMore();
2649 for (const auto &module : m_rsmodules)
2650 {
2651 strm.Printf("Resource '%s':",module->m_resname.c_str());
2652 strm.EOL();
2653 for (const auto &kernel : module->m_kernels)
2654 {
2655 strm.Indent(kernel.m_name.AsCString());
2656 strm.EOL();
2657 }
2658 }
2659 strm.IndentLess();
2660}
2661
Ewan Crawforda0f08672015-10-16 08:28:47 +00002662RenderScriptRuntime::AllocationDetails*
2663RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id)
2664{
2665 AllocationDetails* alloc = nullptr;
2666
2667 // See if we can find allocation using id as an index;
2668 if (alloc_id <= m_allocations.size() && alloc_id != 0
2669 && m_allocations[alloc_id-1]->id == alloc_id)
2670 {
2671 alloc = m_allocations[alloc_id-1].get();
2672 return alloc;
2673 }
2674
2675 // Fallback to searching
2676 for (const auto & a : m_allocations)
2677 {
2678 if (a->id == alloc_id)
2679 {
2680 alloc = a.get();
2681 break;
2682 }
2683 }
2684
2685 if (alloc == nullptr)
2686 {
2687 strm.Printf("Error: Couldn't find allocation with id matching %u", alloc_id);
2688 strm.EOL();
2689 }
2690
2691 return alloc;
2692}
2693
2694// Prints the contents of an allocation to the output stream, which may be a file
2695bool
2696RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame* frame_ptr, const uint32_t id)
2697{
2698 Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2699
2700 // Check we can find the desired allocation
2701 AllocationDetails* alloc = FindAllocByID(strm, id);
2702 if (!alloc)
2703 return false; // FindAllocByID() will print error message for us here
2704
2705 if (log)
2706 log->Printf("RenderScriptRuntime::DumpAllocation - Found allocation 0x%" PRIx64, *alloc->address.get());
2707
2708 // Check we have information about the allocation, if not calculate it
Ewan Crawford8b590622015-12-10 10:20:39 +00002709 if (alloc->shouldRefresh())
Ewan Crawforda0f08672015-10-16 08:28:47 +00002710 {
2711 if (log)
2712 log->Printf("RenderScriptRuntime::DumpAllocation - Allocation details not calculated yet, jitting info");
2713
2714 // JIT all the allocation information
2715 if (!RefreshAllocation(alloc, frame_ptr))
2716 {
2717 strm.Printf("Error: Couldn't JIT allocation details");
2718 strm.EOL();
2719 return false;
2720 }
2721 }
2722
2723 // Establish format and size of each data element
Ewan Crawford8b244e22015-11-30 10:29:49 +00002724 const unsigned int vec_size = *alloc->element.type_vec_size.get();
2725 const Element::DataType type = *alloc->element.type.get();
Ewan Crawforda0f08672015-10-16 08:28:47 +00002726
Ewan Crawford2e920712015-12-17 16:40:05 +00002727 assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT
Ewan Crawforda0f08672015-10-16 08:28:47 +00002728 && "Invalid allocation type");
2729
Ewan Crawford2e920712015-12-17 16:40:05 +00002730 lldb::Format format;
2731 if (type >= Element::RS_TYPE_ELEMENT)
2732 format = eFormatHex;
2733 else
2734 format = vec_size == 1 ? static_cast<lldb::Format>(AllocationDetails::RSTypeToFormat[type][eFormatSingle])
2735 : static_cast<lldb::Format>(AllocationDetails::RSTypeToFormat[type][eFormatVector]);
Ewan Crawforda0f08672015-10-16 08:28:47 +00002736
Ewan Crawford8b244e22015-11-30 10:29:49 +00002737 const unsigned int data_size = *alloc->element.datum_size.get();
Ewan Crawforda0f08672015-10-16 08:28:47 +00002738
2739 if (log)
Ewan Crawford8b244e22015-11-30 10:29:49 +00002740 log->Printf("RenderScriptRuntime::DumpAllocation - Element size %u bytes, including padding", data_size);
Ewan Crawforda0f08672015-10-16 08:28:47 +00002741
Ewan Crawford55232f02015-10-21 08:50:42 +00002742 // Allocate a buffer to copy data into
2743 std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
2744 if (!buffer)
2745 {
Ewan Crawford2e920712015-12-17 16:40:05 +00002746 strm.Printf("Error: Couldn't read allocation data");
Ewan Crawford55232f02015-10-21 08:50:42 +00002747 strm.EOL();
2748 return false;
2749 }
2750
Ewan Crawforda0f08672015-10-16 08:28:47 +00002751 // Calculate stride between rows as there may be padding at end of rows since
2752 // allocated memory is 16-byte aligned
2753 if (!alloc->stride.isValid())
2754 {
2755 if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension
2756 alloc->stride = 0;
2757 else if (!JITAllocationStride(alloc, frame_ptr))
2758 {
2759 strm.Printf("Error: Couldn't calculate allocation row stride");
2760 strm.EOL();
2761 return false;
2762 }
2763 }
2764 const unsigned int stride = *alloc->stride.get();
Ewan Crawford8b244e22015-11-30 10:29:49 +00002765 const unsigned int size = *alloc->size.get(); // Size of whole allocation
2766 const unsigned int padding = alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0;
Ewan Crawforda0f08672015-10-16 08:28:47 +00002767 if (log)
Ewan Crawford8b244e22015-11-30 10:29:49 +00002768 log->Printf("RenderScriptRuntime::DumpAllocation - stride %u bytes, size %u bytes, padding %u", stride, size, padding);
Ewan Crawforda0f08672015-10-16 08:28:47 +00002769
Ewan Crawforda0f08672015-10-16 08:28:47 +00002770 // Find dimensions used to index loops, so need to be non-zero
2771 unsigned int dim_x = alloc->dimension.get()->dim_1;
2772 dim_x = dim_x == 0 ? 1 : dim_x;
2773
2774 unsigned int dim_y = alloc->dimension.get()->dim_2;
2775 dim_y = dim_y == 0 ? 1 : dim_y;
2776
2777 unsigned int dim_z = alloc->dimension.get()->dim_3;
2778 dim_z = dim_z == 0 ? 1 : dim_z;
2779
Ewan Crawford55232f02015-10-21 08:50:42 +00002780 // Use data extractor to format output
2781 const uint32_t archByteSize = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
2782 DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(), archByteSize);
2783
Ewan Crawforda0f08672015-10-16 08:28:47 +00002784 unsigned int offset = 0; // Offset in buffer to next element to be printed
2785 unsigned int prev_row = 0; // Offset to the start of the previous row
2786
2787 // Iterate over allocation dimensions, printing results to user
2788 strm.Printf("Data (X, Y, Z):");
2789 for (unsigned int z = 0; z < dim_z; ++z)
2790 {
2791 for (unsigned int y = 0; y < dim_y; ++y)
2792 {
2793 // Use stride to index start of next row.
2794 if (!(y==0 && z==0))
2795 offset = prev_row + stride;
2796 prev_row = offset;
2797
2798 // Print each element in the row individually
2799 for (unsigned int x = 0; x < dim_x; ++x)
2800 {
2801 strm.Printf("\n(%u, %u, %u) = ", x, y, z);
Ewan Crawford8b244e22015-11-30 10:29:49 +00002802 if ((type == Element::RS_TYPE_NONE) && (alloc->element.children.size() > 0) &&
Adrian McCarthyfe06b5a2015-11-30 22:18:43 +00002803 (alloc->element.type_name != Element::GetFallbackStructName()))
Ewan Crawford8b244e22015-11-30 10:29:49 +00002804 {
2805 // Here we are dumping an Element of struct type.
2806 // This is done using expression evaluation with the name of the struct type and pointer to element.
2807
2808 // Don't print the name of the resulting expression, since this will be '$[0-9]+'
2809 DumpValueObjectOptions expr_options;
2810 expr_options.SetHideName(true);
2811
2812 // Setup expression as derefrencing a pointer cast to element address.
Ewan Crawfordb1651b82015-12-07 13:50:32 +00002813 char expr_char_buffer[jit_max_expr_size];
2814 int chars_written = snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64,
Ewan Crawford8b244e22015-11-30 10:29:49 +00002815 alloc->element.type_name.AsCString(), *alloc->data_ptr.get() + offset);
2816
Ewan Crawfordb1651b82015-12-07 13:50:32 +00002817 if (chars_written < 0 || chars_written >= jit_max_expr_size)
Ewan Crawford8b244e22015-11-30 10:29:49 +00002818 {
2819 if (log)
2820 log->Printf("RenderScriptRuntime::DumpAllocation- Error in snprintf()");
2821 continue;
2822 }
2823
2824 // Evaluate expression
2825 ValueObjectSP expr_result;
2826 GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer, frame_ptr, expr_result);
2827
2828 // Print the results to our stream.
2829 expr_result->Dump(strm, expr_options);
2830 }
2831 else
2832 {
2833 alloc_data.Dump(&strm, offset, format, data_size - padding, 1, 1, LLDB_INVALID_ADDRESS, 0, 0);
2834 }
2835 offset += data_size;
Ewan Crawforda0f08672015-10-16 08:28:47 +00002836 }
2837 }
2838 }
2839 strm.EOL();
2840
Ewan Crawforda0f08672015-10-16 08:28:47 +00002841 return true;
2842}
2843
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002844// Prints infomation regarding all the currently loaded allocations.
2845// These details are gathered by jitting the runtime, which has as latency.
2846void
2847RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame* frame_ptr, bool recompute)
2848{
2849 strm.Printf("RenderScript Allocations:");
2850 strm.EOL();
2851 strm.IndentMore();
2852
2853 for (auto &alloc : m_allocations)
2854 {
2855 // JIT the allocation info if we haven't done it, or the user forces us to.
Ewan Crawford8b590622015-12-10 10:20:39 +00002856 bool do_refresh = alloc->shouldRefresh() || recompute;
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002857
2858 // JIT current allocation information
2859 if (do_refresh && !RefreshAllocation(alloc.get(), frame_ptr))
2860 {
2861 strm.Printf("Error: Couldn't evaluate details for allocation %u\n", alloc->id);
2862 continue;
2863 }
2864
2865 strm.Printf("%u:\n",alloc->id);
2866 strm.IndentMore();
2867
2868 strm.Indent("Context: ");
2869 if (!alloc->context.isValid())
2870 strm.Printf("unknown\n");
2871 else
2872 strm.Printf("0x%" PRIx64 "\n", *alloc->context.get());
2873
2874 strm.Indent("Address: ");
2875 if (!alloc->address.isValid())
2876 strm.Printf("unknown\n");
2877 else
2878 strm.Printf("0x%" PRIx64 "\n", *alloc->address.get());
2879
2880 strm.Indent("Data pointer: ");
2881 if (!alloc->data_ptr.isValid())
2882 strm.Printf("unknown\n");
2883 else
2884 strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get());
2885
2886 strm.Indent("Dimensions: ");
2887 if (!alloc->dimension.isValid())
2888 strm.Printf("unknown\n");
2889 else
2890 strm.Printf("(%d, %d, %d)\n", alloc->dimension.get()->dim_1,
2891 alloc->dimension.get()->dim_2,
2892 alloc->dimension.get()->dim_3);
2893
2894 strm.Indent("Data Type: ");
Ewan Crawford8b244e22015-11-30 10:29:49 +00002895 if (!alloc->element.type.isValid() || !alloc->element.type_vec_size.isValid())
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002896 strm.Printf("unknown\n");
2897 else
2898 {
Ewan Crawford8b244e22015-11-30 10:29:49 +00002899 const int vector_size = *alloc->element.type_vec_size.get();
Ewan Crawford2e920712015-12-17 16:40:05 +00002900 Element::DataType type = *alloc->element.type.get();
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002901
Ewan Crawford8b244e22015-11-30 10:29:49 +00002902 if (!alloc->element.type_name.IsEmpty())
2903 strm.Printf("%s\n", alloc->element.type_name.AsCString());
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002904 else
Ewan Crawford2e920712015-12-17 16:40:05 +00002905 {
2906 // Enum value isn't monotonous, so doesn't always index RsDataTypeToString array
2907 if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT)
2908 type = static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + 1);
2909
2910 if (type >= (sizeof(AllocationDetails::RsDataTypeToString) / sizeof(AllocationDetails::RsDataTypeToString[0]))
2911 || vector_size > 4 || vector_size < 1)
2912 strm.Printf("invalid type\n");
2913 else
2914 strm.Printf("%s\n", AllocationDetails::RsDataTypeToString[static_cast<unsigned int>(type)][vector_size-1]);
2915 }
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002916 }
2917
2918 strm.Indent("Data Kind: ");
Ewan Crawford8b244e22015-11-30 10:29:49 +00002919 if (!alloc->element.type_kind.isValid())
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002920 strm.Printf("unknown\n");
2921 else
2922 {
Ewan Crawford8b244e22015-11-30 10:29:49 +00002923 const Element::DataKind kind = *alloc->element.type_kind.get();
2924 if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV)
Ewan Crawford15f2bd92015-10-06 08:42:32 +00002925 strm.Printf("invalid kind\n");
2926 else
2927 strm.Printf("%s\n", AllocationDetails::RsDataKindToString[static_cast<unsigned int>(kind)]);
2928 }
2929
2930 strm.EOL();
2931 strm.IndentLess();
2932 }
2933 strm.IndentLess();
2934}
2935
Ewan Crawford7dc77712015-09-10 10:08:48 +00002936// Set breakpoints on every kernel found in RS module
2937void
2938RenderScriptRuntime::BreakOnModuleKernels(const RSModuleDescriptorSP rsmodule_sp)
2939{
2940 for (const auto &kernel : rsmodule_sp->m_kernels)
2941 {
2942 // Don't set breakpoint on 'root' kernel
2943 if (strcmp(kernel.m_name.AsCString(), "root") == 0)
2944 continue;
2945
2946 CreateKernelBreakpoint(kernel.m_name);
2947 }
2948}
2949
2950// Method is internally called by the 'kernel breakpoint all' command to
2951// enable or disable breaking on all kernels.
2952//
2953// When do_break is true we want to enable this functionality.
2954// When do_break is false we want to disable it.
2955void
2956RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target)
2957{
Ewan Crawford54782db2015-09-16 10:02:57 +00002958 Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
Ewan Crawford7dc77712015-09-10 10:08:48 +00002959
2960 InitSearchFilter(target);
2961
2962 // Set breakpoints on all the kernels
2963 if (do_break && !m_breakAllKernels)
2964 {
2965 m_breakAllKernels = true;
2966
2967 for (const auto &module : m_rsmodules)
2968 BreakOnModuleKernels(module);
2969
2970 if (log)
2971 log->Printf("RenderScriptRuntime::SetBreakAllKernels(True)"
2972 "- breakpoints set on all currently loaded kernels");
2973 }
2974 else if (!do_break && m_breakAllKernels) // Breakpoints won't be set on any new kernels.
2975 {
2976 m_breakAllKernels = false;
2977
2978 if (log)
2979 log->Printf("RenderScriptRuntime::SetBreakAllKernels(False) - breakpoints no longer automatically set");
2980 }
2981}
2982
2983// Given the name of a kernel this function creates a breakpoint using our
2984// own breakpoint resolver, and returns the Breakpoint shared pointer.
2985BreakpointSP
2986RenderScriptRuntime::CreateKernelBreakpoint(const ConstString& name)
2987{
Ewan Crawford54782db2015-09-16 10:02:57 +00002988 Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
Ewan Crawford7dc77712015-09-10 10:08:48 +00002989
2990 if (!m_filtersp)
2991 {
2992 if (log)
2993 log->Printf("RenderScriptRuntime::CreateKernelBreakpoint - Error: No breakpoint search filter set");
2994 return nullptr;
2995 }
2996
2997 BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name));
2998 BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint(m_filtersp, resolver_sp, false, false, false);
2999
Ewan Crawford54782db2015-09-16 10:02:57 +00003000 // Give RS breakpoints a specific name, so the user can manipulate them as a group.
3001 Error err;
3002 if (!bp->AddName("RenderScriptKernel", err) && log)
3003 log->Printf("RenderScriptRuntime::CreateKernelBreakpoint: Error setting break name, %s", err.AsCString());
3004
Ewan Crawford7dc77712015-09-10 10:08:48 +00003005 return bp;
3006}
3007
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003008// Given an expression for a variable this function tries to calculate the variable's value.
3009// If this is possible it returns true and sets the uint64_t parameter to the variables unsigned value.
3010// Otherwise function returns false.
3011bool
3012RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp, const char* var_name, uint64_t& val)
3013{
3014 Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE));
3015 Error error;
3016 VariableSP var_sp;
3017
3018 // Find variable in stack frame
3019 ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath(var_name,
3020 eNoDynamicValues,
3021 StackFrame::eExpressionPathOptionCheckPtrVsMember |
3022 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
3023 var_sp,
3024 error));
3025 if (!error.Success())
3026 {
3027 if (log)
3028 log->Printf("RenderScriptRuntime::GetFrameVarAsUnsigned - Error, couldn't find '%s' in frame", var_name);
3029
3030 return false;
3031 }
3032
3033 // Find the unsigned int value for the variable
3034 bool success = false;
3035 val = value_sp->GetValueAsUnsigned(0, &success);
3036 if (!success)
3037 {
3038 if (log)
3039 log->Printf("RenderScriptRuntime::GetFrameVarAsUnsigned - Error, couldn't parse '%s' as an unsigned int", var_name);
3040
3041 return false;
3042 }
3043
3044 return true;
3045}
3046
3047// Callback when a kernel breakpoint hits and we're looking for a specific coordinate.
3048// Baton parameter contains a pointer to the target coordinate we want to break on.
3049// Function then checks the .expand frame for the current coordinate and breaks to user if it matches.
3050// Parameter 'break_id' is the id of the Breakpoint which made the callback.
3051// Parameter 'break_loc_id' is the id for the BreakpointLocation which was hit,
3052// a single logical breakpoint can have multiple addresses.
3053bool
3054RenderScriptRuntime::KernelBreakpointHit(void *baton, StoppointCallbackContext *ctx,
3055 user_id_t break_id, user_id_t break_loc_id)
3056{
3057 Log* log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
3058
3059 assert(baton && "Error: null baton in conditional kernel breakpoint callback");
3060
3061 // Coordinate we want to stop on
3062 const int* target_coord = static_cast<const int*>(baton);
3063
3064 if (log)
3065 log->Printf("RenderScriptRuntime::KernelBreakpointHit - Break ID %" PRIu64 ", target coord (%d, %d, %d)",
3066 break_id, target_coord[0], target_coord[1], target_coord[2]);
3067
3068 // Go up one stack frame to .expand kernel
3069 ExecutionContext context(ctx->exe_ctx_ref);
3070 ThreadSP thread_sp = context.GetThreadSP();
3071 if (!thread_sp->SetSelectedFrameByIndex(1))
3072 {
3073 if (log)
3074 log->Printf("RenderScriptRuntime::KernelBreakpointHit - Error, couldn't go up stack frame");
3075
3076 return false;
3077 }
3078
3079 StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
3080 if (!frame_sp)
3081 {
3082 if (log)
3083 log->Printf("RenderScriptRuntime::KernelBreakpointHit - Error, couldn't select .expand stack frame");
3084
3085 return false;
3086 }
3087
3088 // Get values for variables in .expand frame that tell us the current kernel invocation
3089 const char* coord_expressions[] = {"rsIndex", "p->current.y", "p->current.z"};
3090 uint64_t current_coord[3] = {0, 0, 0};
3091
3092 for(int i = 0; i < 3; ++i)
3093 {
3094 if (!GetFrameVarAsUnsigned(frame_sp, coord_expressions[i], current_coord[i]))
3095 return false;
3096
3097 if (log)
3098 log->Printf("RenderScriptRuntime::KernelBreakpointHit, %s = %" PRIu64, coord_expressions[i], current_coord[i]);
3099 }
3100
3101 // Check if the current kernel invocation coordinate matches our target coordinate
3102 if (current_coord[0] == static_cast<uint64_t>(target_coord[0]) &&
3103 current_coord[1] == static_cast<uint64_t>(target_coord[1]) &&
3104 current_coord[2] == static_cast<uint64_t>(target_coord[2]))
3105 {
3106 if (log)
3107 log->Printf("RenderScriptRuntime::KernelBreakpointHit, BREAKING %" PRIu64 ", %" PRIu64 ", %" PRIu64,
3108 current_coord[0], current_coord[1], current_coord[2]);
3109
3110 BreakpointSP breakpoint_sp = context.GetTargetPtr()->GetBreakpointByID(break_id);
3111 assert(breakpoint_sp != nullptr && "Error: Couldn't find breakpoint matching break id for callback");
3112 breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint should only be hit once.
3113 return true;
3114 }
3115
3116 // No match on coordinate
3117 return false;
3118}
3119
3120// Tries to set a breakpoint on the start of a kernel, resolved using the kernel name.
3121// Argument 'coords', represents a three dimensional coordinate which can be used to specify
3122// 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 +00003123void
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003124RenderScriptRuntime::PlaceBreakpointOnKernel(Stream &strm, const char* name, const std::array<int,3> coords,
3125 Error& error, TargetSP target)
Colin Riley4640cde2015-06-01 18:23:41 +00003126{
Ewan Crawford98156582015-09-04 08:56:52 +00003127 if (!name)
Colin Riley4640cde2015-06-01 18:23:41 +00003128 {
3129 error.SetErrorString("invalid kernel name");
3130 return;
3131 }
3132
Ewan Crawford7dc77712015-09-10 10:08:48 +00003133 InitSearchFilter(target);
Ewan Crawford98156582015-09-04 08:56:52 +00003134
Colin Riley4640cde2015-06-01 18:23:41 +00003135 ConstString kernel_name(name);
Ewan Crawford7dc77712015-09-10 10:08:48 +00003136 BreakpointSP bp = CreateKernelBreakpoint(kernel_name);
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003137
3138 // We have a conditional breakpoint on a specific coordinate
3139 if (coords[0] != -1)
3140 {
3141 strm.Printf("Conditional kernel breakpoint on coordinate %d, %d, %d", coords[0], coords[1], coords[2]);
3142 strm.EOL();
3143
3144 // Allocate memory for the baton, and copy over coordinate
3145 int* baton = new int[3];
3146 baton[0] = coords[0]; baton[1] = coords[1]; baton[2] = coords[2];
3147
3148 // Create a callback that will be invoked everytime the breakpoint is hit.
3149 // The baton object passed to the handler is the target coordinate we want to break on.
3150 bp->SetCallback(KernelBreakpointHit, baton, true);
3151
3152 // Store a shared pointer to the baton, so the memory will eventually be cleaned up after destruction
3153 m_conditional_breaks[bp->GetID()] = std::shared_ptr<int>(baton);
3154 }
3155
Ewan Crawford98156582015-09-04 08:56:52 +00003156 if (bp)
3157 bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false);
Colin Riley4640cde2015-06-01 18:23:41 +00003158}
3159
3160void
Colin Riley5ec532a2015-04-09 16:49:25 +00003161RenderScriptRuntime::DumpModules(Stream &strm) const
3162{
3163 strm.Printf("RenderScript Modules:");
3164 strm.EOL();
3165 strm.IndentMore();
3166 for (const auto &module : m_rsmodules)
3167 {
Colin Riley4640cde2015-06-01 18:23:41 +00003168 module->Dump(strm);
Colin Riley5ec532a2015-04-09 16:49:25 +00003169 }
3170 strm.IndentLess();
3171}
3172
Ewan Crawford78f339d2015-09-21 10:53:18 +00003173RenderScriptRuntime::ScriptDetails*
3174RenderScriptRuntime::LookUpScript(addr_t address, bool create)
3175{
3176 for (const auto & s : m_scripts)
3177 {
3178 if (s->script.isValid())
3179 if (*s->script == address)
3180 return s.get();
3181 }
3182 if (create)
3183 {
3184 std::unique_ptr<ScriptDetails> s(new ScriptDetails);
3185 s->script = address;
3186 m_scripts.push_back(std::move(s));
Ewan Crawfordd10ca9d2015-09-22 13:36:35 +00003187 return m_scripts.back().get();
Ewan Crawford78f339d2015-09-21 10:53:18 +00003188 }
3189 return nullptr;
3190}
3191
3192RenderScriptRuntime::AllocationDetails*
3193RenderScriptRuntime::LookUpAllocation(addr_t address, bool create)
3194{
3195 for (const auto & a : m_allocations)
3196 {
3197 if (a->address.isValid())
3198 if (*a->address == address)
3199 return a.get();
3200 }
3201 if (create)
3202 {
3203 std::unique_ptr<AllocationDetails> a(new AllocationDetails);
3204 a->address = address;
3205 m_allocations.push_back(std::move(a));
Ewan Crawfordd10ca9d2015-09-22 13:36:35 +00003206 return m_allocations.back().get();
Ewan Crawford78f339d2015-09-21 10:53:18 +00003207 }
3208 return nullptr;
3209}
3210
Colin Riley5ec532a2015-04-09 16:49:25 +00003211void
3212RSModuleDescriptor::Dump(Stream &strm) const
3213{
3214 strm.Indent();
3215 m_module->GetFileSpec().Dump(&strm);
Colin Riley4640cde2015-06-01 18:23:41 +00003216 if(m_module->GetNumCompileUnits())
3217 {
3218 strm.Indent("Debug info loaded.");
3219 }
3220 else
3221 {
3222 strm.Indent("Debug info does not exist.");
3223 }
Colin Riley5ec532a2015-04-09 16:49:25 +00003224 strm.EOL();
3225 strm.IndentMore();
3226 strm.Indent();
Colin Riley189598e2015-04-12 22:05:58 +00003227 strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size()));
Colin Riley5ec532a2015-04-09 16:49:25 +00003228 strm.EOL();
3229 strm.IndentMore();
3230 for (const auto &global : m_globals)
3231 {
3232 global.Dump(strm);
3233 }
3234 strm.IndentLess();
3235 strm.Indent();
Colin Riley189598e2015-04-12 22:05:58 +00003236 strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size()));
Colin Riley5ec532a2015-04-09 16:49:25 +00003237 strm.EOL();
3238 strm.IndentMore();
3239 for (const auto &kernel : m_kernels)
3240 {
3241 kernel.Dump(strm);
3242 }
Colin Riley4640cde2015-06-01 18:23:41 +00003243 strm.Printf("Pragmas: %" PRIu64 , static_cast<uint64_t>(m_pragmas.size()));
3244 strm.EOL();
3245 strm.IndentMore();
3246 for (const auto &key_val : m_pragmas)
3247 {
3248 strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str());
3249 strm.EOL();
3250 }
Colin Riley5ec532a2015-04-09 16:49:25 +00003251 strm.IndentLess(4);
3252}
3253
3254void
3255RSGlobalDescriptor::Dump(Stream &strm) const
3256{
3257 strm.Indent(m_name.AsCString());
Colin Riley4640cde2015-06-01 18:23:41 +00003258 VariableList var_list;
3259 m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list);
3260 if (var_list.GetSize() == 1)
3261 {
3262 auto var = var_list.GetVariableAtIndex(0);
3263 auto type = var->GetType();
3264 if(type)
3265 {
3266 strm.Printf(" - ");
3267 type->DumpTypeName(&strm);
3268 }
3269 else
3270 {
3271 strm.Printf(" - Unknown Type");
3272 }
3273 }
3274 else
3275 {
3276 strm.Printf(" - variable identified, but not found in binary");
3277 const Symbol* s = m_module->m_module->FindFirstSymbolWithNameAndType(m_name, eSymbolTypeData);
3278 if (s)
3279 {
3280 strm.Printf(" (symbol exists) ");
3281 }
3282 }
3283
Colin Riley5ec532a2015-04-09 16:49:25 +00003284 strm.EOL();
3285}
3286
3287void
3288RSKernelDescriptor::Dump(Stream &strm) const
3289{
3290 strm.Indent(m_name.AsCString());
3291 strm.EOL();
3292}
3293
3294class CommandObjectRenderScriptRuntimeModuleProbe : public CommandObjectParsed
3295{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003296public:
Colin Riley5ec532a2015-04-09 16:49:25 +00003297 CommandObjectRenderScriptRuntimeModuleProbe(CommandInterpreter &interpreter)
3298 : CommandObjectParsed(interpreter, "renderscript module probe",
3299 "Initiates a Probe of all loaded modules for kernels and other renderscript objects.",
3300 "renderscript module probe",
Enrico Granatae87764f2015-05-27 05:04:35 +00003301 eCommandRequiresTarget | eCommandRequiresProcess | eCommandProcessMustBeLaunched)
Colin Riley5ec532a2015-04-09 16:49:25 +00003302 {
3303 }
3304
Eugene Zelenko222b9372015-10-27 00:45:06 +00003305 ~CommandObjectRenderScriptRuntimeModuleProbe() override = default;
Colin Riley5ec532a2015-04-09 16:49:25 +00003306
3307 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003308 DoExecute(Args &command, CommandReturnObject &result) override
Colin Riley5ec532a2015-04-09 16:49:25 +00003309 {
3310 const size_t argc = command.GetArgumentCount();
3311 if (argc == 0)
3312 {
3313 Target *target = m_exe_ctx.GetTargetPtr();
3314 RenderScriptRuntime *runtime =
3315 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
3316 auto module_list = target->GetImages();
3317 bool new_rs_details = runtime->ProbeModules(module_list);
3318 if (new_rs_details)
3319 {
3320 result.AppendMessage("New renderscript modules added to runtime model.");
3321 }
3322 result.SetStatus(eReturnStatusSuccessFinishResult);
3323 return true;
3324 }
3325
3326 result.AppendErrorWithFormat("'%s' takes no arguments", m_cmd_name.c_str());
3327 result.SetStatus(eReturnStatusFailed);
3328 return false;
3329 }
3330};
3331
3332class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed
3333{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003334public:
Colin Riley5ec532a2015-04-09 16:49:25 +00003335 CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter)
3336 : CommandObjectParsed(interpreter, "renderscript module dump",
3337 "Dumps renderscript specific information for all modules.", "renderscript module dump",
Enrico Granatae87764f2015-05-27 05:04:35 +00003338 eCommandRequiresProcess | eCommandProcessMustBeLaunched)
Colin Riley5ec532a2015-04-09 16:49:25 +00003339 {
3340 }
3341
Eugene Zelenko222b9372015-10-27 00:45:06 +00003342 ~CommandObjectRenderScriptRuntimeModuleDump() override = default;
Colin Riley5ec532a2015-04-09 16:49:25 +00003343
3344 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003345 DoExecute(Args &command, CommandReturnObject &result) override
Colin Riley5ec532a2015-04-09 16:49:25 +00003346 {
3347 RenderScriptRuntime *runtime =
3348 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
3349 runtime->DumpModules(result.GetOutputStream());
3350 result.SetStatus(eReturnStatusSuccessFinishResult);
3351 return true;
3352 }
3353};
3354
3355class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword
3356{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003357public:
Colin Riley5ec532a2015-04-09 16:49:25 +00003358 CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter)
3359 : CommandObjectMultiword(interpreter, "renderscript module", "Commands that deal with renderscript modules.",
3360 NULL)
3361 {
3362 LoadSubCommand("probe", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleProbe(interpreter)));
3363 LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump(interpreter)));
3364 }
3365
Eugene Zelenko222b9372015-10-27 00:45:06 +00003366 ~CommandObjectRenderScriptRuntimeModule() override = default;
Colin Riley5ec532a2015-04-09 16:49:25 +00003367};
3368
Colin Riley4640cde2015-06-01 18:23:41 +00003369class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed
3370{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003371public:
Colin Riley4640cde2015-06-01 18:23:41 +00003372 CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter)
3373 : CommandObjectParsed(interpreter, "renderscript kernel list",
3374 "Lists renderscript kernel names and associated script resources.", "renderscript kernel list",
3375 eCommandRequiresProcess | eCommandProcessMustBeLaunched)
3376 {
3377 }
3378
Eugene Zelenko222b9372015-10-27 00:45:06 +00003379 ~CommandObjectRenderScriptRuntimeKernelList() override = default;
Colin Riley4640cde2015-06-01 18:23:41 +00003380
3381 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003382 DoExecute(Args &command, CommandReturnObject &result) override
Colin Riley4640cde2015-06-01 18:23:41 +00003383 {
3384 RenderScriptRuntime *runtime =
3385 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
3386 runtime->DumpKernels(result.GetOutputStream());
3387 result.SetStatus(eReturnStatusSuccessFinishResult);
3388 return true;
3389 }
3390};
3391
Ewan Crawford7dc77712015-09-10 10:08:48 +00003392class CommandObjectRenderScriptRuntimeKernelBreakpointSet : public CommandObjectParsed
Colin Riley4640cde2015-06-01 18:23:41 +00003393{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003394public:
Ewan Crawford7dc77712015-09-10 10:08:48 +00003395 CommandObjectRenderScriptRuntimeKernelBreakpointSet(CommandInterpreter &interpreter)
3396 : CommandObjectParsed(interpreter, "renderscript kernel breakpoint set",
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003397 "Sets a breakpoint on a renderscript kernel.", "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]",
3398 eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), m_options(interpreter)
Colin Riley4640cde2015-06-01 18:23:41 +00003399 {
3400 }
3401
Eugene Zelenko222b9372015-10-27 00:45:06 +00003402 ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default;
3403
3404 Options*
3405 GetOptions() override
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003406 {
3407 return &m_options;
3408 }
3409
3410 class CommandOptions : public Options
3411 {
Eugene Zelenko222b9372015-10-27 00:45:06 +00003412 public:
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003413 CommandOptions(CommandInterpreter &interpreter) : Options(interpreter)
3414 {
3415 }
3416
Eugene Zelenko222b9372015-10-27 00:45:06 +00003417 ~CommandOptions() override = default;
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003418
Eugene Zelenko222b9372015-10-27 00:45:06 +00003419 Error
3420 SetOptionValue(uint32_t option_idx, const char *option_arg) override
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003421 {
3422 Error error;
3423 const int short_option = m_getopt_table[option_idx].val;
3424
3425 switch (short_option)
3426 {
3427 case 'c':
3428 if (!ParseCoordinate(option_arg))
3429 error.SetErrorStringWithFormat("Couldn't parse coordinate '%s', should be in format 'x,y,z'.", option_arg);
3430 break;
3431 default:
3432 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
3433 break;
3434 }
3435 return error;
3436 }
3437
3438 // -c takes an argument of the form 'num[,num][,num]'.
3439 // Where 'id_cstr' is this argument with the whitespace trimmed.
3440 // Missing coordinates are defaulted to zero.
3441 bool
3442 ParseCoordinate(const char* id_cstr)
3443 {
3444 RegularExpression regex;
3445 RegularExpression::Match regex_match(3);
3446
3447 bool matched = false;
3448 if(regex.Compile("^([0-9]+),([0-9]+),([0-9]+)$") && regex.Execute(id_cstr, &regex_match))
3449 matched = true;
3450 else if(regex.Compile("^([0-9]+),([0-9]+)$") && regex.Execute(id_cstr, &regex_match))
3451 matched = true;
3452 else if(regex.Compile("^([0-9]+)$") && regex.Execute(id_cstr, &regex_match))
3453 matched = true;
3454 for(uint32_t i = 0; i < 3; i++)
3455 {
3456 std::string group;
3457 if(regex_match.GetMatchAtIndex(id_cstr, i + 1, group))
3458 m_coord[i] = (uint32_t)strtoul(group.c_str(), NULL, 0);
3459 else
3460 m_coord[i] = 0;
3461 }
3462 return matched;
3463 }
3464
3465 void
Eugene Zelenko222b9372015-10-27 00:45:06 +00003466 OptionParsingStarting() override
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003467 {
3468 // -1 means the -c option hasn't been set
3469 m_coord[0] = -1;
3470 m_coord[1] = -1;
3471 m_coord[2] = -1;
3472 }
3473
3474 const OptionDefinition*
Eugene Zelenko222b9372015-10-27 00:45:06 +00003475 GetDefinitions() override
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003476 {
3477 return g_option_table;
3478 }
3479
3480 static OptionDefinition g_option_table[];
3481 std::array<int,3> m_coord;
3482 };
3483
Colin Riley4640cde2015-06-01 18:23:41 +00003484 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003485 DoExecute(Args &command, CommandReturnObject &result) override
Colin Riley4640cde2015-06-01 18:23:41 +00003486 {
3487 const size_t argc = command.GetArgumentCount();
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003488 if (argc < 1)
Colin Riley4640cde2015-06-01 18:23:41 +00003489 {
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003490 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 +00003491 result.SetStatus(eReturnStatusFailed);
Colin Riley4640cde2015-06-01 18:23:41 +00003492 return false;
3493 }
3494
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003495 RenderScriptRuntime *runtime =
3496 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
3497
3498 Error error;
3499 runtime->PlaceBreakpointOnKernel(result.GetOutputStream(), command.GetArgumentAtIndex(0), m_options.m_coord,
3500 error, m_exe_ctx.GetTargetSP());
3501
3502 if (error.Success())
3503 {
3504 result.AppendMessage("Breakpoint(s) created");
3505 result.SetStatus(eReturnStatusSuccessFinishResult);
3506 return true;
3507 }
Colin Riley4640cde2015-06-01 18:23:41 +00003508 result.SetStatus(eReturnStatusFailed);
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003509 result.AppendErrorWithFormat("Error: %s", error.AsCString());
Colin Riley4640cde2015-06-01 18:23:41 +00003510 return false;
Eugene Zelenko222b9372015-10-27 00:45:06 +00003511 }
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003512
Eugene Zelenko222b9372015-10-27 00:45:06 +00003513private:
3514 CommandOptions m_options;
Colin Riley4640cde2015-06-01 18:23:41 +00003515};
3516
Ewan Crawford018f5a7e2015-10-26 14:04:37 +00003517OptionDefinition
3518CommandObjectRenderScriptRuntimeKernelBreakpointSet::CommandOptions::g_option_table[] =
3519{
3520 { LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeValue,
3521 "Set a breakpoint on a single invocation of the kernel with specified coordinate.\n"
3522 "Coordinate takes the form 'x[,y][,z] where x,y,z are positive integers representing kernel dimensions. "
3523 "Any unset dimensions will be defaulted to zero."},
3524 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
3525};
3526
Ewan Crawford7dc77712015-09-10 10:08:48 +00003527class CommandObjectRenderScriptRuntimeKernelBreakpointAll : public CommandObjectParsed
3528{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003529public:
Ewan Crawford7dc77712015-09-10 10:08:48 +00003530 CommandObjectRenderScriptRuntimeKernelBreakpointAll(CommandInterpreter &interpreter)
3531 : CommandObjectParsed(interpreter, "renderscript kernel breakpoint all",
3532 "Automatically sets a breakpoint on all renderscript kernels that are or will be loaded.\n"
3533 "Disabling option means breakpoints will no longer be set on any kernels loaded in the future, "
3534 "but does not remove currently set breakpoints.",
3535 "renderscript kernel breakpoint all <enable/disable>",
3536 eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused)
3537 {
3538 }
3539
Eugene Zelenko222b9372015-10-27 00:45:06 +00003540 ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default;
Ewan Crawford7dc77712015-09-10 10:08:48 +00003541
3542 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003543 DoExecute(Args &command, CommandReturnObject &result) override
Ewan Crawford7dc77712015-09-10 10:08:48 +00003544 {
3545 const size_t argc = command.GetArgumentCount();
3546 if (argc != 1)
3547 {
3548 result.AppendErrorWithFormat("'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str());
3549 result.SetStatus(eReturnStatusFailed);
3550 return false;
3551 }
3552
3553 RenderScriptRuntime *runtime =
3554 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript));
3555
3556 bool do_break = false;
3557 const char* argument = command.GetArgumentAtIndex(0);
3558 if (strcmp(argument, "enable") == 0)
3559 {
3560 do_break = true;
3561 result.AppendMessage("Breakpoints will be set on all kernels.");
3562 }
3563 else if (strcmp(argument, "disable") == 0)
3564 {
3565 do_break = false;
3566 result.AppendMessage("Breakpoints will not be set on any new kernels.");
3567 }
3568 else
3569 {
3570 result.AppendErrorWithFormat("Argument must be either 'enable' or 'disable'");
3571 result.SetStatus(eReturnStatusFailed);
3572 return false;
3573 }
3574
3575 runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP());
3576
3577 result.SetStatus(eReturnStatusSuccessFinishResult);
3578 return true;
3579 }
3580};
3581
3582class CommandObjectRenderScriptRuntimeKernelBreakpoint : public CommandObjectMultiword
3583{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003584public:
Ewan Crawford7dc77712015-09-10 10:08:48 +00003585 CommandObjectRenderScriptRuntimeKernelBreakpoint(CommandInterpreter &interpreter)
3586 : CommandObjectMultiword(interpreter, "renderscript kernel", "Commands that generate breakpoints on renderscript kernels.",
3587 nullptr)
3588 {
3589 LoadSubCommand("set", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet(interpreter)));
3590 LoadSubCommand("all", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll(interpreter)));
3591 }
3592
Eugene Zelenko222b9372015-10-27 00:45:06 +00003593 ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default;
Ewan Crawford7dc77712015-09-10 10:08:48 +00003594};
3595
Colin Riley4640cde2015-06-01 18:23:41 +00003596class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword
3597{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003598public:
Colin Riley4640cde2015-06-01 18:23:41 +00003599 CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter)
3600 : CommandObjectMultiword(interpreter, "renderscript kernel", "Commands that deal with renderscript kernels.",
3601 NULL)
3602 {
3603 LoadSubCommand("list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList(interpreter)));
3604 LoadSubCommand("breakpoint", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter)));
3605 }
3606
Eugene Zelenko222b9372015-10-27 00:45:06 +00003607 ~CommandObjectRenderScriptRuntimeKernel() override = default;
Colin Riley4640cde2015-06-01 18:23:41 +00003608};
3609
3610class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed
3611{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003612public:
Colin Riley4640cde2015-06-01 18:23:41 +00003613 CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter)
3614 : CommandObjectParsed(interpreter, "renderscript context dump",
3615 "Dumps renderscript context information.", "renderscript context dump",
3616 eCommandRequiresProcess | eCommandProcessMustBeLaunched)
3617 {
3618 }
3619
Eugene Zelenko222b9372015-10-27 00:45:06 +00003620 ~CommandObjectRenderScriptRuntimeContextDump() override = default;
Colin Riley4640cde2015-06-01 18:23:41 +00003621
3622 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003623 DoExecute(Args &command, CommandReturnObject &result) override
Colin Riley4640cde2015-06-01 18:23:41 +00003624 {
3625 RenderScriptRuntime *runtime =
3626 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
3627 runtime->DumpContexts(result.GetOutputStream());
3628 result.SetStatus(eReturnStatusSuccessFinishResult);
3629 return true;
3630 }
3631};
3632
3633class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword
3634{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003635public:
Colin Riley4640cde2015-06-01 18:23:41 +00003636 CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter)
3637 : CommandObjectMultiword(interpreter, "renderscript context", "Commands that deal with renderscript contexts.",
3638 NULL)
3639 {
3640 LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump(interpreter)));
3641 }
3642
Eugene Zelenko222b9372015-10-27 00:45:06 +00003643 ~CommandObjectRenderScriptRuntimeContext() override = default;
Colin Riley4640cde2015-06-01 18:23:41 +00003644};
3645
Ewan Crawforda0f08672015-10-16 08:28:47 +00003646class CommandObjectRenderScriptRuntimeAllocationDump : public CommandObjectParsed
3647{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003648public:
Ewan Crawforda0f08672015-10-16 08:28:47 +00003649 CommandObjectRenderScriptRuntimeAllocationDump(CommandInterpreter &interpreter)
3650 : CommandObjectParsed(interpreter, "renderscript allocation dump",
3651 "Displays the contents of a particular allocation", "renderscript allocation dump <ID>",
3652 eCommandRequiresProcess | eCommandProcessMustBeLaunched), m_options(interpreter)
3653 {
3654 }
3655
Eugene Zelenko222b9372015-10-27 00:45:06 +00003656 ~CommandObjectRenderScriptRuntimeAllocationDump() override = default;
3657
3658 Options*
3659 GetOptions() override
Ewan Crawforda0f08672015-10-16 08:28:47 +00003660 {
3661 return &m_options;
3662 }
3663
3664 class CommandOptions : public Options
3665 {
Eugene Zelenko222b9372015-10-27 00:45:06 +00003666 public:
Ewan Crawforda0f08672015-10-16 08:28:47 +00003667 CommandOptions(CommandInterpreter &interpreter) : Options(interpreter)
3668 {
3669 }
3670
Eugene Zelenko222b9372015-10-27 00:45:06 +00003671 ~CommandOptions() override = default;
Ewan Crawforda0f08672015-10-16 08:28:47 +00003672
Eugene Zelenko222b9372015-10-27 00:45:06 +00003673 Error
3674 SetOptionValue(uint32_t option_idx, const char *option_arg) override
Ewan Crawforda0f08672015-10-16 08:28:47 +00003675 {
3676 Error error;
3677 const int short_option = m_getopt_table[option_idx].val;
3678
3679 switch (short_option)
3680 {
3681 case 'f':
3682 m_outfile.SetFile(option_arg, true);
3683 if (m_outfile.Exists())
3684 {
3685 m_outfile.Clear();
3686 error.SetErrorStringWithFormat("file already exists: '%s'", option_arg);
3687 }
3688 break;
3689 default:
3690 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
3691 break;
3692 }
3693 return error;
3694 }
3695
3696 void
Eugene Zelenko222b9372015-10-27 00:45:06 +00003697 OptionParsingStarting() override
Ewan Crawforda0f08672015-10-16 08:28:47 +00003698 {
3699 m_outfile.Clear();
3700 }
3701
3702 const OptionDefinition*
Eugene Zelenko222b9372015-10-27 00:45:06 +00003703 GetDefinitions() override
Ewan Crawforda0f08672015-10-16 08:28:47 +00003704 {
3705 return g_option_table;
3706 }
3707
3708 static OptionDefinition g_option_table[];
3709 FileSpec m_outfile;
3710 };
3711
Ewan Crawforda0f08672015-10-16 08:28:47 +00003712 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003713 DoExecute(Args &command, CommandReturnObject &result) override
Ewan Crawforda0f08672015-10-16 08:28:47 +00003714 {
3715 const size_t argc = command.GetArgumentCount();
3716 if (argc < 1)
3717 {
3718 result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. As well as an optional -f argument",
3719 m_cmd_name.c_str());
3720 result.SetStatus(eReturnStatusFailed);
3721 return false;
3722 }
3723
3724 RenderScriptRuntime *runtime =
3725 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript));
3726
3727 const char* id_cstr = command.GetArgumentAtIndex(0);
3728 bool convert_complete = false;
3729 const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
3730 if (!convert_complete)
3731 {
3732 result.AppendErrorWithFormat("invalid allocation id argument '%s'", id_cstr);
3733 result.SetStatus(eReturnStatusFailed);
3734 return false;
3735 }
3736
3737 Stream* output_strm = nullptr;
3738 StreamFile outfile_stream;
3739 const FileSpec &outfile_spec = m_options.m_outfile; // Dump allocation to file instead
3740 if (outfile_spec)
3741 {
3742 // Open output file
3743 char path[256];
3744 outfile_spec.GetPath(path, sizeof(path));
3745 if (outfile_stream.GetFile().Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate).Success())
3746 {
3747 output_strm = &outfile_stream;
3748 result.GetOutputStream().Printf("Results written to '%s'", path);
3749 result.GetOutputStream().EOL();
3750 }
3751 else
3752 {
3753 result.AppendErrorWithFormat("Couldn't open file '%s'", path);
3754 result.SetStatus(eReturnStatusFailed);
3755 return false;
3756 }
3757 }
3758 else
3759 output_strm = &result.GetOutputStream();
3760
3761 assert(output_strm != nullptr);
3762 bool success = runtime->DumpAllocation(*output_strm, m_exe_ctx.GetFramePtr(), id);
3763
3764 if (success)
3765 result.SetStatus(eReturnStatusSuccessFinishResult);
3766 else
3767 result.SetStatus(eReturnStatusFailed);
3768
3769 return true;
3770 }
3771
Eugene Zelenko222b9372015-10-27 00:45:06 +00003772private:
3773 CommandOptions m_options;
Ewan Crawforda0f08672015-10-16 08:28:47 +00003774};
3775
3776OptionDefinition
3777CommandObjectRenderScriptRuntimeAllocationDump::CommandOptions::g_option_table[] =
3778{
3779 { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename,
3780 "Print results to specified file instead of command line."},
3781 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
3782};
3783
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003784class CommandObjectRenderScriptRuntimeAllocationList : public CommandObjectParsed
3785{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003786public:
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003787 CommandObjectRenderScriptRuntimeAllocationList(CommandInterpreter &interpreter)
3788 : CommandObjectParsed(interpreter, "renderscript allocation list",
3789 "List renderscript allocations and their information.", "renderscript allocation list",
3790 eCommandRequiresProcess | eCommandProcessMustBeLaunched), m_options(interpreter)
3791 {
3792 }
3793
Eugene Zelenko222b9372015-10-27 00:45:06 +00003794 ~CommandObjectRenderScriptRuntimeAllocationList() override = default;
3795
3796 Options*
3797 GetOptions() override
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003798 {
3799 return &m_options;
3800 }
3801
3802 class CommandOptions : public Options
3803 {
Eugene Zelenko222b9372015-10-27 00:45:06 +00003804 public:
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003805 CommandOptions(CommandInterpreter &interpreter) : Options(interpreter), m_refresh(false)
3806 {
3807 }
3808
Eugene Zelenko222b9372015-10-27 00:45:06 +00003809 ~CommandOptions() override = default;
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003810
Eugene Zelenko222b9372015-10-27 00:45:06 +00003811 Error
3812 SetOptionValue(uint32_t option_idx, const char *option_arg) override
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003813 {
3814 Error error;
3815 const int short_option = m_getopt_table[option_idx].val;
3816
3817 switch (short_option)
3818 {
3819 case 'r':
3820 m_refresh = true;
3821 break;
3822 default:
3823 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
3824 break;
3825 }
3826 return error;
3827 }
3828
3829 void
Eugene Zelenko222b9372015-10-27 00:45:06 +00003830 OptionParsingStarting() override
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003831 {
3832 m_refresh = false;
3833 }
3834
3835 const OptionDefinition*
Eugene Zelenko222b9372015-10-27 00:45:06 +00003836 GetDefinitions() override
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003837 {
3838 return g_option_table;
3839 }
3840
3841 static OptionDefinition g_option_table[];
3842 bool m_refresh;
3843 };
3844
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003845 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003846 DoExecute(Args &command, CommandReturnObject &result) override
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003847 {
3848 RenderScriptRuntime *runtime =
3849 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript));
3850 runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(), m_options.m_refresh);
3851 result.SetStatus(eReturnStatusSuccessFinishResult);
3852 return true;
3853 }
3854
Eugene Zelenko222b9372015-10-27 00:45:06 +00003855private:
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003856 CommandOptions m_options;
3857};
3858
3859OptionDefinition
3860CommandObjectRenderScriptRuntimeAllocationList::CommandOptions::g_option_table[] =
3861{
3862 { LLDB_OPT_SET_1, false, "refresh", 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone,
3863 "Recompute allocation details."},
3864 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
3865};
3866
Ewan Crawford55232f02015-10-21 08:50:42 +00003867class CommandObjectRenderScriptRuntimeAllocationLoad : public CommandObjectParsed
3868{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003869public:
Ewan Crawford55232f02015-10-21 08:50:42 +00003870 CommandObjectRenderScriptRuntimeAllocationLoad(CommandInterpreter &interpreter)
3871 : CommandObjectParsed(interpreter, "renderscript allocation load",
3872 "Loads renderscript allocation contents from a file.", "renderscript allocation load <ID> <filename>",
3873 eCommandRequiresProcess | eCommandProcessMustBeLaunched)
3874 {
3875 }
3876
Eugene Zelenko222b9372015-10-27 00:45:06 +00003877 ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default;
Ewan Crawford55232f02015-10-21 08:50:42 +00003878
3879 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003880 DoExecute(Args &command, CommandReturnObject &result) override
Ewan Crawford55232f02015-10-21 08:50:42 +00003881 {
3882 const size_t argc = command.GetArgumentCount();
3883 if (argc != 2)
3884 {
3885 result.AppendErrorWithFormat("'%s' takes 2 arguments, an allocation ID and filename to read from.", m_cmd_name.c_str());
3886 result.SetStatus(eReturnStatusFailed);
3887 return false;
3888 }
3889
3890 RenderScriptRuntime *runtime =
3891 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript));
3892
3893 const char* id_cstr = command.GetArgumentAtIndex(0);
3894 bool convert_complete = false;
3895 const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
3896 if (!convert_complete)
3897 {
3898 result.AppendErrorWithFormat ("invalid allocation id argument '%s'", id_cstr);
3899 result.SetStatus (eReturnStatusFailed);
3900 return false;
3901 }
3902
3903 const char* filename = command.GetArgumentAtIndex(1);
3904 bool success = runtime->LoadAllocation(result.GetOutputStream(), id, filename, m_exe_ctx.GetFramePtr());
3905
3906 if (success)
3907 result.SetStatus(eReturnStatusSuccessFinishResult);
3908 else
3909 result.SetStatus(eReturnStatusFailed);
3910
3911 return true;
3912 }
3913};
3914
Ewan Crawford55232f02015-10-21 08:50:42 +00003915class CommandObjectRenderScriptRuntimeAllocationSave : public CommandObjectParsed
3916{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003917public:
Ewan Crawford55232f02015-10-21 08:50:42 +00003918 CommandObjectRenderScriptRuntimeAllocationSave(CommandInterpreter &interpreter)
3919 : CommandObjectParsed(interpreter, "renderscript allocation save",
3920 "Write renderscript allocation contents to a file.", "renderscript allocation save <ID> <filename>",
3921 eCommandRequiresProcess | eCommandProcessMustBeLaunched)
3922 {
3923 }
3924
Eugene Zelenko222b9372015-10-27 00:45:06 +00003925 ~CommandObjectRenderScriptRuntimeAllocationSave() override = default;
Ewan Crawford55232f02015-10-21 08:50:42 +00003926
3927 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003928 DoExecute(Args &command, CommandReturnObject &result) override
Ewan Crawford55232f02015-10-21 08:50:42 +00003929 {
3930 const size_t argc = command.GetArgumentCount();
3931 if (argc != 2)
3932 {
3933 result.AppendErrorWithFormat("'%s' takes 2 arguments, an allocation ID and filename to read from.", m_cmd_name.c_str());
3934 result.SetStatus(eReturnStatusFailed);
3935 return false;
3936 }
3937
3938 RenderScriptRuntime *runtime =
3939 static_cast<RenderScriptRuntime *>(m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript));
3940
3941 const char* id_cstr = command.GetArgumentAtIndex(0);
3942 bool convert_complete = false;
3943 const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete);
3944 if (!convert_complete)
3945 {
3946 result.AppendErrorWithFormat ("invalid allocation id argument '%s'", id_cstr);
3947 result.SetStatus (eReturnStatusFailed);
3948 return false;
3949 }
3950
3951 const char* filename = command.GetArgumentAtIndex(1);
3952 bool success = runtime->SaveAllocation(result.GetOutputStream(), id, filename, m_exe_ctx.GetFramePtr());
3953
3954 if (success)
3955 result.SetStatus(eReturnStatusSuccessFinishResult);
3956 else
3957 result.SetStatus(eReturnStatusFailed);
3958
3959 return true;
3960 }
3961};
3962
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003963class CommandObjectRenderScriptRuntimeAllocation : public CommandObjectMultiword
3964{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003965public:
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003966 CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter)
3967 : CommandObjectMultiword(interpreter, "renderscript allocation", "Commands that deal with renderscript allocations.",
3968 NULL)
3969 {
3970 LoadSubCommand("list", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationList(interpreter)));
Ewan Crawforda0f08672015-10-16 08:28:47 +00003971 LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationDump(interpreter)));
Ewan Crawford55232f02015-10-21 08:50:42 +00003972 LoadSubCommand("save", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationSave(interpreter)));
3973 LoadSubCommand("load", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter)));
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003974 }
3975
Eugene Zelenko222b9372015-10-27 00:45:06 +00003976 ~CommandObjectRenderScriptRuntimeAllocation() override = default;
Ewan Crawford15f2bd92015-10-06 08:42:32 +00003977};
3978
Colin Riley4640cde2015-06-01 18:23:41 +00003979class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed
3980{
Eugene Zelenko222b9372015-10-27 00:45:06 +00003981public:
Colin Riley4640cde2015-06-01 18:23:41 +00003982 CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter)
3983 : CommandObjectParsed(interpreter, "renderscript status",
3984 "Displays current renderscript runtime status.", "renderscript status",
3985 eCommandRequiresProcess | eCommandProcessMustBeLaunched)
3986 {
3987 }
3988
Eugene Zelenko222b9372015-10-27 00:45:06 +00003989 ~CommandObjectRenderScriptRuntimeStatus() override = default;
Colin Riley4640cde2015-06-01 18:23:41 +00003990
3991 bool
Eugene Zelenko222b9372015-10-27 00:45:06 +00003992 DoExecute(Args &command, CommandReturnObject &result) override
Colin Riley4640cde2015-06-01 18:23:41 +00003993 {
3994 RenderScriptRuntime *runtime =
3995 (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript);
3996 runtime->Status(result.GetOutputStream());
3997 result.SetStatus(eReturnStatusSuccessFinishResult);
3998 return true;
3999 }
4000};
4001
Colin Riley5ec532a2015-04-09 16:49:25 +00004002class CommandObjectRenderScriptRuntime : public CommandObjectMultiword
4003{
Eugene Zelenko222b9372015-10-27 00:45:06 +00004004public:
Colin Riley5ec532a2015-04-09 16:49:25 +00004005 CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter)
4006 : CommandObjectMultiword(interpreter, "renderscript", "A set of commands for operating on renderscript.",
4007 "renderscript <subcommand> [<subcommand-options>]")
4008 {
4009 LoadSubCommand("module", CommandObjectSP(new CommandObjectRenderScriptRuntimeModule(interpreter)));
Colin Riley4640cde2015-06-01 18:23:41 +00004010 LoadSubCommand("status", CommandObjectSP(new CommandObjectRenderScriptRuntimeStatus(interpreter)));
4011 LoadSubCommand("kernel", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernel(interpreter)));
4012 LoadSubCommand("context", CommandObjectSP(new CommandObjectRenderScriptRuntimeContext(interpreter)));
Ewan Crawford15f2bd92015-10-06 08:42:32 +00004013 LoadSubCommand("allocation", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocation(interpreter)));
Colin Riley5ec532a2015-04-09 16:49:25 +00004014 }
4015
Eugene Zelenko222b9372015-10-27 00:45:06 +00004016 ~CommandObjectRenderScriptRuntime() override = default;
Colin Riley5ec532a2015-04-09 16:49:25 +00004017};
Colin Rileyef20b082015-04-14 07:39:24 +00004018
4019void
4020RenderScriptRuntime::Initiate()
Colin Riley5ec532a2015-04-09 16:49:25 +00004021{
Colin Rileyef20b082015-04-14 07:39:24 +00004022 assert(!m_initiated);
Colin Riley5ec532a2015-04-09 16:49:25 +00004023}
Colin Rileyef20b082015-04-14 07:39:24 +00004024
4025RenderScriptRuntime::RenderScriptRuntime(Process *process)
Ewan Crawford7dc77712015-09-10 10:08:48 +00004026 : lldb_private::CPPLanguageRuntime(process), m_initiated(false), m_debuggerPresentFlagged(false),
4027 m_breakAllKernels(false)
Colin Rileyef20b082015-04-14 07:39:24 +00004028{
Colin Riley4640cde2015-06-01 18:23:41 +00004029 ModulesDidLoad(process->GetTarget().GetImages());
Colin Rileyef20b082015-04-14 07:39:24 +00004030}
Colin Riley4640cde2015-06-01 18:23:41 +00004031
4032lldb::CommandObjectSP
4033RenderScriptRuntime::GetCommandObject(lldb_private::CommandInterpreter& interpreter)
4034{
4035 static CommandObjectSP command_object;
4036 if(!command_object)
4037 {
4038 command_object.reset(new CommandObjectRenderScriptRuntime(interpreter));
4039 }
4040 return command_object;
4041}
4042
Ewan Crawford78f339d2015-09-21 10:53:18 +00004043RenderScriptRuntime::~RenderScriptRuntime() = default;