Coverage Report

Created: 2022-01-15 10:30

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- RenderScriptRuntime.cpp -------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "RenderScriptRuntime.h"
10
#include "RenderScriptScriptGroup.h"
11
12
#include "lldb/Breakpoint/StoppointCallbackContext.h"
13
#include "lldb/Core/Debugger.h"
14
#include "lldb/Core/DumpDataExtractor.h"
15
#include "lldb/Core/PluginManager.h"
16
#include "lldb/Core/ValueObjectVariable.h"
17
#include "lldb/DataFormatters/DumpValueObjectOptions.h"
18
#include "lldb/Expression/UserExpression.h"
19
#include "lldb/Host/OptionParser.h"
20
#include "lldb/Interpreter/CommandInterpreter.h"
21
#include "lldb/Interpreter/CommandObjectMultiword.h"
22
#include "lldb/Interpreter/CommandReturnObject.h"
23
#include "lldb/Interpreter/Options.h"
24
#include "lldb/Symbol/Function.h"
25
#include "lldb/Symbol/Symbol.h"
26
#include "lldb/Symbol/Type.h"
27
#include "lldb/Symbol/VariableList.h"
28
#include "lldb/Target/Process.h"
29
#include "lldb/Target/RegisterContext.h"
30
#include "lldb/Target/SectionLoadList.h"
31
#include "lldb/Target/Target.h"
32
#include "lldb/Target/Thread.h"
33
#include "lldb/Utility/Args.h"
34
#include "lldb/Utility/ConstString.h"
35
#include "lldb/Utility/Log.h"
36
#include "lldb/Utility/RegisterValue.h"
37
#include "lldb/Utility/RegularExpression.h"
38
#include "lldb/Utility/Status.h"
39
40
#include "llvm/ADT/StringSwitch.h"
41
42
#include <memory>
43
44
using namespace lldb;
45
using namespace lldb_private;
46
using namespace lldb_renderscript;
47
48
LLDB_PLUGIN_DEFINE(RenderScriptRuntime)
49
50
0
#define FMT_COORD "(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")"
51
52
char RenderScriptRuntime::ID = 0;
53
54
namespace {
55
56
// The empirical_type adds a basic level of validation to arbitrary data
57
// allowing us to track if data has been discovered and stored or not. An
58
// empirical_type will be marked as valid only if it has been explicitly
59
// assigned to.
60
template <typename type_t> class empirical_type {
61
public:
62
  // Ctor. Contents is invalid when constructed.
63
0
  empirical_type() = default;
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<unsigned long long>::empirical_type()
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::Element::DataType>::empirical_type()
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::Element::DataKind>::empirical_type()
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<unsigned int>::empirical_type()
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::ScriptDetails::ScriptType>::empirical_type()
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::empirical_type()
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::AllocationDetails::Dimension>::empirical_type()
64
65
  // Return true and copy contents to out if valid, else return false.
66
0
  bool get(type_t &out) const {
67
0
    if (valid)
68
0
      out = data;
69
0
    return valid;
70
0
  }
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::get(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) const
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<unsigned long long>::get(unsigned long long&) const
71
72
  // Return a pointer to the contents or nullptr if it was not valid.
73
0
  const type_t *get() const { return valid ? &data : nullptr; }
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<unsigned long long>::get() const
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::Element::DataType>::get() const
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::Element::DataKind>::get() const
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<unsigned int>::get() const
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::AllocationDetails::Dimension>::get() const
74
75
  // Assign data explicitly.
76
0
  void set(const type_t in) {
77
0
    data = in;
78
0
    valid = true;
79
0
  }
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<unsigned long long>::set(unsigned long long)
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::ScriptDetails::ScriptType>::set(lldb_private::RenderScriptRuntime::ScriptDetails::ScriptType)
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::set(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::AllocationDetails::Dimension>::set(lldb_private::RenderScriptRuntime::AllocationDetails::Dimension)
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::Element::DataType>::set(lldb_private::RenderScriptRuntime::Element::DataType)
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::Element::DataKind>::set(lldb_private::RenderScriptRuntime::Element::DataKind)
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<unsigned int>::set(unsigned int)
80
81
  // Mark contents as invalid.
82
  void invalidate() { valid = false; }
83
84
  // Returns true if this type contains valid data.
85
0
  bool isValid() const { return valid; }
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<unsigned long long>::isValid() const
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::Element::DataType>::isValid() const
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<unsigned int>::isValid() const
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::Element::DataKind>::isValid() const
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::AllocationDetails::Dimension>::isValid() const
86
87
  // Assignment operator.
88
0
  empirical_type<type_t> &operator=(const type_t in) {
89
0
    set(in);
90
0
    return *this;
91
0
  }
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<unsigned long long>::operator=(unsigned long long)
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::ScriptDetails::ScriptType>::operator=(lldb_private::RenderScriptRuntime::ScriptDetails::ScriptType)
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::operator=(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::AllocationDetails::Dimension>::operator=(lldb_private::RenderScriptRuntime::AllocationDetails::Dimension)
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::Element::DataType>::operator=(lldb_private::RenderScriptRuntime::Element::DataType)
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<lldb_private::RenderScriptRuntime::Element::DataKind>::operator=(lldb_private::RenderScriptRuntime::Element::DataKind)
Unexecuted instantiation: RenderScriptRuntime.cpp:(anonymous namespace)::empirical_type<unsigned int>::operator=(unsigned int)
92
93
  // Dereference operator returns contents.
94
  // Warning: Will assert if not valid so use only when you know data is valid.
95
0
  const type_t &operator*() const {
96
0
    assert(valid);
97
0
    return data;
98
0
  }
99
100
protected:
101
  bool valid = false;
102
  type_t data;
103
};
104
105
// ArgItem is used by the GetArgs() function when reading function arguments
106
// from the target.
107
struct ArgItem {
108
  enum { ePointer, eInt32, eInt64, eLong, eBool } type;
109
110
  uint64_t value;
111
112
0
  explicit operator uint64_t() const { return value; }
113
};
114
115
// Context structure to be passed into GetArgsXXX(), argument reading functions
116
// below.
117
struct GetArgsCtx {
118
  RegisterContext *reg_ctx;
119
  Process *process;
120
};
121
122
0
bool GetArgsX86(const GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
123
0
  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
124
125
0
  Status err;
126
127
  // get the current stack pointer
128
0
  uint64_t sp = ctx.reg_ctx->GetSP();
129
130
0
  for (size_t i = 0; i < num_args; ++i) {
131
0
    ArgItem &arg = arg_list[i];
132
    // advance up the stack by one argument
133
0
    sp += sizeof(uint32_t);
134
    // get the argument type size
135
0
    size_t arg_size = sizeof(uint32_t);
136
    // read the argument from memory
137
0
    arg.value = 0;
138
0
    Status err;
139
0
    size_t read =
140
0
        ctx.process->ReadMemory(sp, &arg.value, sizeof(uint32_t), err);
141
0
    if (read != arg_size || !err.Success()) {
142
0
      LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 " '%s'",
143
0
                __FUNCTION__, uint64_t(i), err.AsCString());
144
0
      return false;
145
0
    }
146
0
  }
147
0
  return true;
148
0
}
149
150
0
bool GetArgsX86_64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
151
0
  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
152
153
  // number of arguments passed in registers
154
0
  static const uint32_t args_in_reg = 6;
155
  // register passing order
156
0
  static const std::array<const char *, args_in_reg> reg_names{
157
0
      {"rdi", "rsi", "rdx", "rcx", "r8", "r9"}};
158
  // argument type to size mapping
159
0
  static const std::array<size_t, 5> arg_size{{
160
0
      8, // ePointer,
161
0
      4, // eInt32,
162
0
      8, // eInt64,
163
0
      8, // eLong,
164
0
      4, // eBool,
165
0
  }};
166
167
0
  Status err;
168
169
  // get the current stack pointer
170
0
  uint64_t sp = ctx.reg_ctx->GetSP();
171
  // step over the return address
172
0
  sp += sizeof(uint64_t);
173
174
  // check the stack alignment was correct (16 byte aligned)
175
0
  if ((sp & 0xf) != 0x0) {
176
0
    LLDB_LOGF(log, "%s - stack misaligned", __FUNCTION__);
177
0
    return false;
178
0
  }
179
180
  // find the start of arguments on the stack
181
0
  uint64_t sp_offset = 0;
182
0
  for (uint32_t i = args_in_reg; i < num_args; ++i) {
183
0
    sp_offset += arg_size[arg_list[i].type];
184
0
  }
185
  // round up to multiple of 16
186
0
  sp_offset = (sp_offset + 0xf) & 0xf;
187
0
  sp += sp_offset;
188
189
0
  for (size_t i = 0; i < num_args; ++i) {
190
0
    bool success = false;
191
0
    ArgItem &arg = arg_list[i];
192
    // arguments passed in registers
193
0
    if (i < args_in_reg) {
194
0
      const RegisterInfo *reg =
195
0
          ctx.reg_ctx->GetRegisterInfoByName(reg_names[i]);
196
0
      RegisterValue reg_val;
197
0
      if (ctx.reg_ctx->ReadRegister(reg, reg_val))
198
0
        arg.value = reg_val.GetAsUInt64(0, &success);
199
0
    }
200
    // arguments passed on the stack
201
0
    else {
202
      // get the argument type size
203
0
      const size_t size = arg_size[arg_list[i].type];
204
      // read the argument from memory
205
0
      arg.value = 0;
206
      // note: due to little endian layout reading 4 or 8 bytes will give the
207
      // correct value.
208
0
      size_t read = ctx.process->ReadMemory(sp, &arg.value, size, err);
209
0
      success = (err.Success() && read == size);
210
      // advance past this argument
211
0
      sp -= size;
212
0
    }
213
    // fail if we couldn't read this argument
214
0
    if (!success) {
215
0
      LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s",
216
0
                __FUNCTION__, uint64_t(i), err.AsCString("n/a"));
217
0
      return false;
218
0
    }
219
0
  }
220
0
  return true;
221
0
}
222
223
0
bool GetArgsArm(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
224
  // number of arguments passed in registers
225
0
  static const uint32_t args_in_reg = 4;
226
227
0
  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
228
229
0
  Status err;
230
231
  // get the current stack pointer
232
0
  uint64_t sp = ctx.reg_ctx->GetSP();
233
234
0
  for (size_t i = 0; i < num_args; ++i) {
235
0
    bool success = false;
236
0
    ArgItem &arg = arg_list[i];
237
    // arguments passed in registers
238
0
    if (i < args_in_reg) {
239
0
      const RegisterInfo *reg = ctx.reg_ctx->GetRegisterInfoAtIndex(i);
240
0
      RegisterValue reg_val;
241
0
      if (ctx.reg_ctx->ReadRegister(reg, reg_val))
242
0
        arg.value = reg_val.GetAsUInt32(0, &success);
243
0
    }
244
    // arguments passed on the stack
245
0
    else {
246
      // get the argument type size
247
0
      const size_t arg_size = sizeof(uint32_t);
248
      // clear all 64bits
249
0
      arg.value = 0;
250
      // read this argument from memory
251
0
      size_t bytes_read =
252
0
          ctx.process->ReadMemory(sp, &arg.value, arg_size, err);
253
0
      success = (err.Success() && bytes_read == arg_size);
254
      // advance the stack pointer
255
0
      sp += sizeof(uint32_t);
256
0
    }
257
    // fail if we couldn't read this argument
258
0
    if (!success) {
259
0
      LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s",
260
0
                __FUNCTION__, uint64_t(i), err.AsCString("n/a"));
261
0
      return false;
262
0
    }
263
0
  }
264
0
  return true;
265
0
}
266
267
0
bool GetArgsAarch64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
268
  // number of arguments passed in registers
269
0
  static const uint32_t args_in_reg = 8;
270
271
0
  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
272
273
0
  for (size_t i = 0; i < num_args; ++i) {
274
0
    bool success = false;
275
0
    ArgItem &arg = arg_list[i];
276
    // arguments passed in registers
277
0
    if (i < args_in_reg) {
278
0
      const RegisterInfo *reg = ctx.reg_ctx->GetRegisterInfoAtIndex(i);
279
0
      RegisterValue reg_val;
280
0
      if (ctx.reg_ctx->ReadRegister(reg, reg_val))
281
0
        arg.value = reg_val.GetAsUInt64(0, &success);
282
0
    }
283
    // arguments passed on the stack
284
0
    else {
285
0
      LLDB_LOGF(log, "%s - reading arguments spilled to stack not implemented",
286
0
                __FUNCTION__);
287
0
    }
288
    // fail if we couldn't read this argument
289
0
    if (!success) {
290
0
      LLDB_LOGF(log, "%s - error reading argument: %" PRIu64, __FUNCTION__,
291
0
                uint64_t(i));
292
0
      return false;
293
0
    }
294
0
  }
295
0
  return true;
296
0
}
297
298
0
bool GetArgsMipsel(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
299
  // number of arguments passed in registers
300
0
  static const uint32_t args_in_reg = 4;
301
  // register file offset to first argument
302
0
  static const uint32_t reg_offset = 4;
303
304
0
  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
305
306
0
  Status err;
307
308
  // find offset to arguments on the stack (+16 to skip over a0-a3 shadow
309
  // space)
310
0
  uint64_t sp = ctx.reg_ctx->GetSP() + 16;
311
312
0
  for (size_t i = 0; i < num_args; ++i) {
313
0
    bool success = false;
314
0
    ArgItem &arg = arg_list[i];
315
    // arguments passed in registers
316
0
    if (i < args_in_reg) {
317
0
      const RegisterInfo *reg =
318
0
          ctx.reg_ctx->GetRegisterInfoAtIndex(i + reg_offset);
319
0
      RegisterValue reg_val;
320
0
      if (ctx.reg_ctx->ReadRegister(reg, reg_val))
321
0
        arg.value = reg_val.GetAsUInt64(0, &success);
322
0
    }
323
    // arguments passed on the stack
324
0
    else {
325
0
      const size_t arg_size = sizeof(uint32_t);
326
0
      arg.value = 0;
327
0
      size_t bytes_read =
328
0
          ctx.process->ReadMemory(sp, &arg.value, arg_size, err);
329
0
      success = (err.Success() && bytes_read == arg_size);
330
      // advance the stack pointer
331
0
      sp += arg_size;
332
0
    }
333
    // fail if we couldn't read this argument
334
0
    if (!success) {
335
0
      LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s",
336
0
                __FUNCTION__, uint64_t(i), err.AsCString("n/a"));
337
0
      return false;
338
0
    }
339
0
  }
340
0
  return true;
341
0
}
342
343
0
bool GetArgsMips64el(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) {
344
  // number of arguments passed in registers
345
0
  static const uint32_t args_in_reg = 8;
346
  // register file offset to first argument
347
0
  static const uint32_t reg_offset = 4;
348
349
0
  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
350
351
0
  Status err;
352
353
  // get the current stack pointer
354
0
  uint64_t sp = ctx.reg_ctx->GetSP();
355
356
0
  for (size_t i = 0; i < num_args; ++i) {
357
0
    bool success = false;
358
0
    ArgItem &arg = arg_list[i];
359
    // arguments passed in registers
360
0
    if (i < args_in_reg) {
361
0
      const RegisterInfo *reg =
362
0
          ctx.reg_ctx->GetRegisterInfoAtIndex(i + reg_offset);
363
0
      RegisterValue reg_val;
364
0
      if (ctx.reg_ctx->ReadRegister(reg, reg_val))
365
0
        arg.value = reg_val.GetAsUInt64(0, &success);
366
0
    }
367
    // arguments passed on the stack
368
0
    else {
369
      // get the argument type size
370
0
      const size_t arg_size = sizeof(uint64_t);
371
      // clear all 64bits
372
0
      arg.value = 0;
373
      // read this argument from memory
374
0
      size_t bytes_read =
375
0
          ctx.process->ReadMemory(sp, &arg.value, arg_size, err);
376
0
      success = (err.Success() && bytes_read == arg_size);
377
      // advance the stack pointer
378
0
      sp += arg_size;
379
0
    }
380
    // fail if we couldn't read this argument
381
0
    if (!success) {
382
0
      LLDB_LOGF(log, "%s - error reading argument: %" PRIu64 ", reason: %s",
383
0
                __FUNCTION__, uint64_t(i), err.AsCString("n/a"));
384
0
      return false;
385
0
    }
386
0
  }
387
0
  return true;
388
0
}
389
390
0
bool GetArgs(ExecutionContext &exe_ctx, ArgItem *arg_list, size_t num_args) {
391
0
  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
392
393
  // verify that we have a target
394
0
  if (!exe_ctx.GetTargetPtr()) {
395
0
    LLDB_LOGF(log, "%s - invalid target", __FUNCTION__);
396
0
    return false;
397
0
  }
398
399
0
  GetArgsCtx ctx = {exe_ctx.GetRegisterContext(), exe_ctx.GetProcessPtr()};
400
0
  assert(ctx.reg_ctx && ctx.process);
401
402
  // dispatch based on architecture
403
0
  switch (exe_ctx.GetTargetPtr()->GetArchitecture().GetMachine()) {
404
0
  case llvm::Triple::ArchType::x86:
405
0
    return GetArgsX86(ctx, arg_list, num_args);
406
407
0
  case llvm::Triple::ArchType::x86_64:
408
0
    return GetArgsX86_64(ctx, arg_list, num_args);
409
410
0
  case llvm::Triple::ArchType::arm:
411
0
    return GetArgsArm(ctx, arg_list, num_args);
412
413
0
  case llvm::Triple::ArchType::aarch64:
414
0
    return GetArgsAarch64(ctx, arg_list, num_args);
415
416
0
  case llvm::Triple::ArchType::mipsel:
417
0
    return GetArgsMipsel(ctx, arg_list, num_args);
418
419
0
  case llvm::Triple::ArchType::mips64el:
420
0
    return GetArgsMips64el(ctx, arg_list, num_args);
421
422
0
  default:
423
    // unsupported architecture
424
0
    if (log) {
425
0
      LLDB_LOGF(log, "%s - architecture not supported: '%s'", __FUNCTION__,
426
0
                exe_ctx.GetTargetRef().GetArchitecture().GetArchitectureName());
427
0
    }
428
0
    return false;
429
0
  }
430
0
}
431
432
0
bool IsRenderScriptScriptModule(ModuleSP module) {
433
0
  if (!module)
434
0
    return false;
435
0
  return module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"),
436
0
                                                eSymbolTypeData) != nullptr;
437
0
}
438
439
0
bool ParseCoordinate(llvm::StringRef coord_s, RSCoordinate &coord) {
440
  // takes an argument of the form 'num[,num][,num]'. Where 'coord_s' is a
441
  // comma separated 1,2 or 3-dimensional coordinate with the whitespace
442
  // trimmed. Missing coordinates are defaulted to zero. If parsing of any
443
  // elements fails the contents of &coord are undefined and `false` is
444
  // returned, `true` otherwise
445
446
0
  llvm::SmallVector<llvm::StringRef, 4> matches;
447
448
0
  if (!RegularExpression("^([0-9]+),([0-9]+),([0-9]+)$")
449
0
           .Execute(coord_s, &matches) &&
450
0
      !RegularExpression("^([0-9]+),([0-9]+)$").Execute(coord_s, &matches) &&
451
0
      !RegularExpression("^([0-9]+)$").Execute(coord_s, &matches))
452
0
    return false;
453
454
0
  auto get_index = [&](size_t idx, uint32_t &i) -> bool {
455
0
    std::string group;
456
0
    errno = 0;
457
0
    if (idx + 1 < matches.size()) {
458
0
      return !llvm::StringRef(matches[idx + 1]).getAsInteger<uint32_t>(10, i);
459
0
    }
460
0
    return true;
461
0
  };
462
463
0
  return get_index(0, coord.x) && get_index(1, coord.y) &&
464
0
         get_index(2, coord.z);
465
0
}
466
467
0
bool SkipPrologue(lldb::ModuleSP &module, Address &addr) {
468
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
469
0
  SymbolContext sc;
470
0
  uint32_t resolved_flags =
471
0
      module->ResolveSymbolContextForAddress(addr, eSymbolContextFunction, sc);
472
0
  if (resolved_flags & eSymbolContextFunction) {
473
0
    if (sc.function) {
474
0
      const uint32_t offset = sc.function->GetPrologueByteSize();
475
0
      ConstString name = sc.GetFunctionName();
476
0
      if (offset)
477
0
        addr.Slide(offset);
478
0
      LLDB_LOGF(log, "%s: Prologue offset for %s is %" PRIu32, __FUNCTION__,
479
0
                name.AsCString(), offset);
480
0
    }
481
0
    return true;
482
0
  } else
483
0
    return false;
484
0
}
485
} // anonymous namespace
486
487
// The ScriptDetails class collects data associated with a single script
488
// instance.
489
struct RenderScriptRuntime::ScriptDetails {
490
0
  ~ScriptDetails() = default;
491
492
  enum ScriptType { eScript, eScriptC };
493
494
  // The derived type of the script.
495
  empirical_type<ScriptType> type;
496
  // The name of the original source file.
497
  empirical_type<std::string> res_name;
498
  // Path to script .so file on the device.
499
  empirical_type<std::string> shared_lib;
500
  // Directory where kernel objects are cached on device.
501
  empirical_type<std::string> cache_dir;
502
  // Pointer to the context which owns this script.
503
  empirical_type<lldb::addr_t> context;
504
  // Pointer to the script object itself.
505
  empirical_type<lldb::addr_t> script;
506
};
507
508
// This Element class represents the Element object in RS, defining the type
509
// associated with an Allocation.
510
struct RenderScriptRuntime::Element {
511
  // Taken from rsDefines.h
512
  enum DataKind {
513
    RS_KIND_USER,
514
    RS_KIND_PIXEL_L = 7,
515
    RS_KIND_PIXEL_A,
516
    RS_KIND_PIXEL_LA,
517
    RS_KIND_PIXEL_RGB,
518
    RS_KIND_PIXEL_RGBA,
519
    RS_KIND_PIXEL_DEPTH,
520
    RS_KIND_PIXEL_YUV,
521
    RS_KIND_INVALID = 100
522
  };
523
524
  // Taken from rsDefines.h
525
  enum DataType {
526
    RS_TYPE_NONE = 0,
527
    RS_TYPE_FLOAT_16,
528
    RS_TYPE_FLOAT_32,
529
    RS_TYPE_FLOAT_64,
530
    RS_TYPE_SIGNED_8,
531
    RS_TYPE_SIGNED_16,
532
    RS_TYPE_SIGNED_32,
533
    RS_TYPE_SIGNED_64,
534
    RS_TYPE_UNSIGNED_8,
535
    RS_TYPE_UNSIGNED_16,
536
    RS_TYPE_UNSIGNED_32,
537
    RS_TYPE_UNSIGNED_64,
538
    RS_TYPE_BOOLEAN,
539
540
    RS_TYPE_UNSIGNED_5_6_5,
541
    RS_TYPE_UNSIGNED_5_5_5_1,
542
    RS_TYPE_UNSIGNED_4_4_4_4,
543
544
    RS_TYPE_MATRIX_4X4,
545
    RS_TYPE_MATRIX_3X3,
546
    RS_TYPE_MATRIX_2X2,
547
548
    RS_TYPE_ELEMENT = 1000,
549
    RS_TYPE_TYPE,
550
    RS_TYPE_ALLOCATION,
551
    RS_TYPE_SAMPLER,
552
    RS_TYPE_SCRIPT,
553
    RS_TYPE_MESH,
554
    RS_TYPE_PROGRAM_FRAGMENT,
555
    RS_TYPE_PROGRAM_VERTEX,
556
    RS_TYPE_PROGRAM_RASTER,
557
    RS_TYPE_PROGRAM_STORE,
558
    RS_TYPE_FONT,
559
560
    RS_TYPE_INVALID = 10000
561
  };
562
563
  std::vector<Element> children; // Child Element fields for structs
564
  empirical_type<lldb::addr_t>
565
      element_ptr; // Pointer to the RS Element of the Type
566
  empirical_type<DataType>
567
      type; // Type of each data pointer stored by the allocation
568
  empirical_type<DataKind>
569
      type_kind; // Defines pixel type if Allocation is created from an image
570
  empirical_type<uint32_t>
571
      type_vec_size; // Vector size of each data point, e.g '4' for uchar4
572
  empirical_type<uint32_t> field_count; // Number of Subelements
573
  empirical_type<uint32_t> datum_size;  // Size of a single Element with padding
574
  empirical_type<uint32_t> padding;     // Number of padding bytes
575
  empirical_type<uint32_t>
576
      array_size;        // Number of items in array, only needed for structs
577
  ConstString type_name; // Name of type, only needed for structs
578
579
  static ConstString 
580
  GetFallbackStructName(); // Print this as the type name of a struct Element
581
                           // If we can't resolve the actual struct name
582
583
0
  bool ShouldRefresh() const {
584
0
    const bool valid_ptr = element_ptr.isValid() && *element_ptr.get() != 0x0;
585
0
    const bool valid_type =
586
0
        type.isValid() && type_vec_size.isValid() && type_kind.isValid();
587
0
    return !valid_ptr || !valid_type || !datum_size.isValid();
588
0
  }
589
};
590
591
// This AllocationDetails class collects data associated with a single
592
// allocation instance.
593
struct RenderScriptRuntime::AllocationDetails {
594
  struct Dimension {
595
    uint32_t dim_1;
596
    uint32_t dim_2;
597
    uint32_t dim_3;
598
    uint32_t cube_map;
599
600
0
    Dimension() {
601
0
      dim_1 = 0;
602
0
      dim_2 = 0;
603
0
      dim_3 = 0;
604
0
      cube_map = 0;
605
0
    }
606
  };
607
608
  // The FileHeader struct specifies the header we use for writing allocations
609
  // to a binary file. Our format begins with the ASCII characters "RSAD",
610
  // identifying the file as an allocation dump. Member variables dims and
611
  // hdr_size are then written consecutively, immediately followed by an
612
  // instance of the ElementHeader struct. Because Elements can contain
613
  // subelements, there may be more than one instance of the ElementHeader
614
  // struct. With this first instance being the root element, and the other
615
  // instances being the root's descendants. To identify which instances are an
616
  // ElementHeader's children, each struct is immediately followed by a
617
  // sequence of consecutive offsets to the start of its child structs. These
618
  // offsets are
619
  // 4 bytes in size, and the 0 offset signifies no more children.
620
  struct FileHeader {
621
    uint8_t ident[4];  // ASCII 'RSAD' identifying the file
622
    uint32_t dims[3];  // Dimensions
623
    uint16_t hdr_size; // Header size in bytes, including all element headers
624
  };
625
626
  struct ElementHeader {
627
    uint16_t type;         // DataType enum
628
    uint32_t kind;         // DataKind enum
629
    uint32_t element_size; // Size of a single element, including padding
630
    uint16_t vector_size;  // Vector width
631
    uint32_t array_size;   // Number of elements in array
632
  };
633
634
  // Monotonically increasing from 1
635
  static uint32_t ID;
636
637
  // Maps Allocation DataType enum and vector size to printable strings using
638
  // mapping from RenderScript numerical types summary documentation
639
  static const char *RsDataTypeToString[][4];
640
641
  // Maps Allocation DataKind enum to printable strings
642
  static const char *RsDataKindToString[];
643
644
  // Maps allocation types to format sizes for printing.
645
  static const uint32_t RSTypeToFormat[][3];
646
647
  // Give each allocation an ID as a way
648
  // for commands to reference it.
649
  const uint32_t id;
650
651
  // Allocation Element type
652
  RenderScriptRuntime::Element element;
653
  // Dimensions of the Allocation
654
  empirical_type<Dimension> dimension;
655
  // Pointer to address of the RS Allocation
656
  empirical_type<lldb::addr_t> address;
657
  // Pointer to the data held by the Allocation
658
  empirical_type<lldb::addr_t> data_ptr;
659
  // Pointer to the RS Type of the Allocation
660
  empirical_type<lldb::addr_t> type_ptr;
661
  // Pointer to the RS Context of the Allocation
662
  empirical_type<lldb::addr_t> context;
663
  // Size of the allocation
664
  empirical_type<uint32_t> size;
665
  // Stride between rows of the allocation
666
  empirical_type<uint32_t> stride;
667
668
  // Give each allocation an id, so we can reference it in user commands.
669
0
  AllocationDetails() : id(ID++) {}
670
671
0
  bool ShouldRefresh() const {
672
0
    bool valid_ptrs = data_ptr.isValid() && *data_ptr.get() != 0x0;
673
0
    valid_ptrs = valid_ptrs && type_ptr.isValid() && *type_ptr.get() != 0x0;
674
0
    return !valid_ptrs || !dimension.isValid() || !size.isValid() ||
675
0
           element.ShouldRefresh();
676
0
  }
677
};
678
679
0
ConstString RenderScriptRuntime::Element::GetFallbackStructName() {
680
0
  static const ConstString FallbackStructName("struct");
681
0
  return FallbackStructName;
682
0
}
683
684
uint32_t RenderScriptRuntime::AllocationDetails::ID = 1;
685
686
const char *RenderScriptRuntime::AllocationDetails::RsDataKindToString[] = {
687
    "User",       "Undefined",   "Undefined", "Undefined",
688
    "Undefined",  "Undefined",   "Undefined", // Enum jumps from 0 to 7
689
    "L Pixel",    "A Pixel",     "LA Pixel",  "RGB Pixel",
690
    "RGBA Pixel", "Pixel Depth", "YUV Pixel"};
691
692
const char *RenderScriptRuntime::AllocationDetails::RsDataTypeToString[][4] = {
693
    {"None", "None", "None", "None"},
694
    {"half", "half2", "half3", "half4"},
695
    {"float", "float2", "float3", "float4"},
696
    {"double", "double2", "double3", "double4"},
697
    {"char", "char2", "char3", "char4"},
698
    {"short", "short2", "short3", "short4"},
699
    {"int", "int2", "int3", "int4"},
700
    {"long", "long2", "long3", "long4"},
701
    {"uchar", "uchar2", "uchar3", "uchar4"},
702
    {"ushort", "ushort2", "ushort3", "ushort4"},
703
    {"uint", "uint2", "uint3", "uint4"},
704
    {"ulong", "ulong2", "ulong3", "ulong4"},
705
    {"bool", "bool2", "bool3", "bool4"},
706
    {"packed_565", "packed_565", "packed_565", "packed_565"},
707
    {"packed_5551", "packed_5551", "packed_5551", "packed_5551"},
708
    {"packed_4444", "packed_4444", "packed_4444", "packed_4444"},
709
    {"rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4", "rs_matrix4x4"},
710
    {"rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3", "rs_matrix3x3"},
711
    {"rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2", "rs_matrix2x2"},
712
713
    // Handlers
714
    {"RS Element", "RS Element", "RS Element", "RS Element"},
715
    {"RS Type", "RS Type", "RS Type", "RS Type"},
716
    {"RS Allocation", "RS Allocation", "RS Allocation", "RS Allocation"},
717
    {"RS Sampler", "RS Sampler", "RS Sampler", "RS Sampler"},
718
    {"RS Script", "RS Script", "RS Script", "RS Script"},
719
720
    // Deprecated
721
    {"RS Mesh", "RS Mesh", "RS Mesh", "RS Mesh"},
722
    {"RS Program Fragment", "RS Program Fragment", "RS Program Fragment",
723
     "RS Program Fragment"},
724
    {"RS Program Vertex", "RS Program Vertex", "RS Program Vertex",
725
     "RS Program Vertex"},
726
    {"RS Program Raster", "RS Program Raster", "RS Program Raster",
727
     "RS Program Raster"},
728
    {"RS Program Store", "RS Program Store", "RS Program Store",
729
     "RS Program Store"},
730
    {"RS Font", "RS Font", "RS Font", "RS Font"}};
731
732
// Used as an index into the RSTypeToFormat array elements
733
enum TypeToFormatIndex { eFormatSingle = 0, eFormatVector, eElementSize };
734
735
// { format enum of single element, format enum of element vector, size of
736
// element}
737
const uint32_t RenderScriptRuntime::AllocationDetails::RSTypeToFormat[][3] = {
738
    // RS_TYPE_NONE
739
    {eFormatHex, eFormatHex, 1},
740
    // RS_TYPE_FLOAT_16
741
    {eFormatFloat, eFormatVectorOfFloat16, 2},
742
    // RS_TYPE_FLOAT_32
743
    {eFormatFloat, eFormatVectorOfFloat32, sizeof(float)},
744
    // RS_TYPE_FLOAT_64
745
    {eFormatFloat, eFormatVectorOfFloat64, sizeof(double)},
746
    // RS_TYPE_SIGNED_8
747
    {eFormatDecimal, eFormatVectorOfSInt8, sizeof(int8_t)},
748
    // RS_TYPE_SIGNED_16
749
    {eFormatDecimal, eFormatVectorOfSInt16, sizeof(int16_t)},
750
    // RS_TYPE_SIGNED_32
751
    {eFormatDecimal, eFormatVectorOfSInt32, sizeof(int32_t)},
752
    // RS_TYPE_SIGNED_64
753
    {eFormatDecimal, eFormatVectorOfSInt64, sizeof(int64_t)},
754
    // RS_TYPE_UNSIGNED_8
755
    {eFormatDecimal, eFormatVectorOfUInt8, sizeof(uint8_t)},
756
    // RS_TYPE_UNSIGNED_16
757
    {eFormatDecimal, eFormatVectorOfUInt16, sizeof(uint16_t)},
758
    // RS_TYPE_UNSIGNED_32
759
    {eFormatDecimal, eFormatVectorOfUInt32, sizeof(uint32_t)},
760
    // RS_TYPE_UNSIGNED_64
761
    {eFormatDecimal, eFormatVectorOfUInt64, sizeof(uint64_t)},
762
    // RS_TYPE_BOOL
763
    {eFormatBoolean, eFormatBoolean, 1},
764
    // RS_TYPE_UNSIGNED_5_6_5
765
    {eFormatHex, eFormatHex, sizeof(uint16_t)},
766
    // RS_TYPE_UNSIGNED_5_5_5_1
767
    {eFormatHex, eFormatHex, sizeof(uint16_t)},
768
    // RS_TYPE_UNSIGNED_4_4_4_4
769
    {eFormatHex, eFormatHex, sizeof(uint16_t)},
770
    // RS_TYPE_MATRIX_4X4
771
    {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 16},
772
    // RS_TYPE_MATRIX_3X3
773
    {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 9},
774
    // RS_TYPE_MATRIX_2X2
775
    {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 4}};
776
777
// Static Functions
778
LanguageRuntime *
779
RenderScriptRuntime::CreateInstance(Process *process,
780
194k
                                    lldb::LanguageType language) {
781
782
194k
  if (language == eLanguageTypeExtRenderScript)
783
0
    return new RenderScriptRuntime(process);
784
194k
  else
785
194k
    return nullptr;
786
194k
}
787
788
// Callback with a module to search for matching symbols. We first check that
789
// the module contains RS kernels. Then look for a symbol which matches our
790
// kernel name. The breakpoint address is finally set using the address of this
791
// symbol.
792
Searcher::CallbackReturn
793
RSBreakpointResolver::SearchCallback(SearchFilter &filter,
794
0
                                     SymbolContext &context, Address *) {
795
0
  BreakpointSP breakpoint_sp = GetBreakpoint();
796
0
  assert(breakpoint_sp);
797
798
0
  ModuleSP module = context.module_sp;
799
800
0
  if (!module || !IsRenderScriptScriptModule(module))
801
0
    return Searcher::eCallbackReturnContinue;
802
803
  // Attempt to set a breakpoint on the kernel name symbol within the module
804
  // library. If it's not found, it's likely debug info is unavailable - try to
805
  // set a breakpoint on <name>.expand.
806
0
  const Symbol *kernel_sym =
807
0
      module->FindFirstSymbolWithNameAndType(m_kernel_name, eSymbolTypeCode);
808
0
  if (!kernel_sym) {
809
0
    std::string kernel_name_expanded(m_kernel_name.AsCString());
810
0
    kernel_name_expanded.append(".expand");
811
0
    kernel_sym = module->FindFirstSymbolWithNameAndType(
812
0
        ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode);
813
0
  }
814
815
0
  if (kernel_sym) {
816
0
    Address bp_addr = kernel_sym->GetAddress();
817
0
    if (filter.AddressPasses(bp_addr))
818
0
      breakpoint_sp->AddLocation(bp_addr);
819
0
  }
820
821
0
  return Searcher::eCallbackReturnContinue;
822
0
}
823
824
Searcher::CallbackReturn
825
RSReduceBreakpointResolver::SearchCallback(lldb_private::SearchFilter &filter,
826
                                           lldb_private::SymbolContext &context,
827
0
                                           Address *) {
828
0
  BreakpointSP breakpoint_sp = GetBreakpoint();
829
0
  assert(breakpoint_sp);
830
831
  // We need to have access to the list of reductions currently parsed, as
832
  // reduce names don't actually exist as symbols in a module. They are only
833
  // identifiable by parsing the .rs.info packet, or finding the expand symbol.
834
  // We therefore need access to the list of parsed rs modules to properly
835
  // resolve reduction names.
836
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
837
0
  ModuleSP module = context.module_sp;
838
839
0
  if (!module || !IsRenderScriptScriptModule(module))
840
0
    return Searcher::eCallbackReturnContinue;
841
842
0
  if (!m_rsmodules)
843
0
    return Searcher::eCallbackReturnContinue;
844
845
0
  for (const auto &module_desc : *m_rsmodules) {
846
0
    if (module_desc->m_module != module)
847
0
      continue;
848
849
0
    for (const auto &reduction : module_desc->m_reductions) {
850
0
      if (reduction.m_reduce_name != m_reduce_name)
851
0
        continue;
852
853
0
      std::array<std::pair<ConstString, int>, 5> funcs{
854
0
          {{reduction.m_init_name, eKernelTypeInit},
855
0
           {reduction.m_accum_name, eKernelTypeAccum},
856
0
           {reduction.m_comb_name, eKernelTypeComb},
857
0
           {reduction.m_outc_name, eKernelTypeOutC},
858
0
           {reduction.m_halter_name, eKernelTypeHalter}}};
859
860
0
      for (const auto &kernel : funcs) {
861
        // Skip constituent functions that don't match our spec
862
0
        if (!(m_kernel_types & kernel.second))
863
0
          continue;
864
865
0
        const auto kernel_name = kernel.first;
866
0
        const auto symbol = module->FindFirstSymbolWithNameAndType(
867
0
            kernel_name, eSymbolTypeCode);
868
0
        if (!symbol)
869
0
          continue;
870
871
0
        auto address = symbol->GetAddress();
872
0
        if (filter.AddressPasses(address)) {
873
0
          bool new_bp;
874
0
          if (!SkipPrologue(module, address)) {
875
0
            LLDB_LOGF(log, "%s: Error trying to skip prologue", __FUNCTION__);
876
0
          }
877
0
          breakpoint_sp->AddLocation(address, &new_bp);
878
0
          LLDB_LOGF(log, "%s: %s reduction breakpoint on %s in %s",
879
0
                    __FUNCTION__, new_bp ? "new" : "existing",
880
0
                    kernel_name.GetCString(),
881
0
                    address.GetModule()->GetFileSpec().GetCString());
882
0
        }
883
0
      }
884
0
    }
885
0
  }
886
0
  return eCallbackReturnContinue;
887
0
}
888
889
Searcher::CallbackReturn RSScriptGroupBreakpointResolver::SearchCallback(
890
0
    SearchFilter &filter, SymbolContext &context, Address *addr) {
891
892
0
  BreakpointSP breakpoint_sp = GetBreakpoint();
893
0
  if (!breakpoint_sp)
894
0
    return eCallbackReturnContinue;
895
896
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
897
0
  ModuleSP &module = context.module_sp;
898
899
0
  if (!module || !IsRenderScriptScriptModule(module))
900
0
    return Searcher::eCallbackReturnContinue;
901
902
0
  std::vector<std::string> names;
903
0
  Breakpoint& breakpoint = *breakpoint_sp;
904
0
  breakpoint.GetNames(names);
905
0
  if (names.empty())
906
0
    return eCallbackReturnContinue;
907
908
0
  for (auto &name : names) {
909
0
    const RSScriptGroupDescriptorSP sg = FindScriptGroup(ConstString(name));
910
0
    if (!sg) {
911
0
      LLDB_LOGF(log, "%s: could not find script group for %s", __FUNCTION__,
912
0
                name.c_str());
913
0
      continue;
914
0
    }
915
916
0
    LLDB_LOGF(log, "%s: Found ScriptGroup for %s", __FUNCTION__, name.c_str());
917
918
0
    for (const RSScriptGroupDescriptor::Kernel &k : sg->m_kernels) {
919
0
      if (log) {
920
0
        LLDB_LOGF(log, "%s: Adding breakpoint for %s", __FUNCTION__,
921
0
                  k.m_name.AsCString());
922
0
        LLDB_LOGF(log, "%s: Kernel address 0x%" PRIx64, __FUNCTION__, k.m_addr);
923
0
      }
924
925
0
      const lldb_private::Symbol *sym =
926
0
          module->FindFirstSymbolWithNameAndType(k.m_name, eSymbolTypeCode);
927
0
      if (!sym) {
928
0
        LLDB_LOGF(log, "%s: Unable to find symbol for %s", __FUNCTION__,
929
0
                  k.m_name.AsCString());
930
0
        continue;
931
0
      }
932
933
0
      if (log) {
934
0
        LLDB_LOGF(log, "%s: Found symbol name is %s", __FUNCTION__,
935
0
                  sym->GetName().AsCString());
936
0
      }
937
938
0
      auto address = sym->GetAddress();
939
0
      if (!SkipPrologue(module, address)) {
940
0
        LLDB_LOGF(log, "%s: Error trying to skip prologue", __FUNCTION__);
941
0
      }
942
943
0
      bool new_bp;
944
0
      breakpoint.AddLocation(address, &new_bp);
945
946
0
      LLDB_LOGF(log, "%s: Placed %sbreakpoint on %s", __FUNCTION__,
947
0
                new_bp ? "new " : "", k.m_name.AsCString());
948
949
      // exit after placing the first breakpoint if we do not intend to stop on
950
      // all kernels making up this script group
951
0
      if (!m_stop_on_all)
952
0
        break;
953
0
    }
954
0
  }
955
956
0
  return eCallbackReturnContinue;
957
0
}
958
959
3.43k
void RenderScriptRuntime::Initialize() {
960
3.43k
  PluginManager::RegisterPlugin(GetPluginNameStatic(),
961
3.43k
                                "RenderScript language support", CreateInstance,
962
3.43k
                                GetCommandObject);
963
3.43k
}
964
965
3.43k
void RenderScriptRuntime::Terminate() {
966
3.43k
  PluginManager::UnregisterPlugin(CreateInstance);
967
3.43k
}
968
969
RenderScriptRuntime::ModuleKind
970
0
RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp) {
971
0
  if (module_sp) {
972
0
    if (IsRenderScriptScriptModule(module_sp))
973
0
      return eModuleKindKernelObj;
974
975
    // Is this the main RS runtime library
976
0
    const ConstString rs_lib("libRS.so");
977
0
    if (module_sp->GetFileSpec().GetFilename() == rs_lib) {
978
0
      return eModuleKindLibRS;
979
0
    }
980
981
0
    const ConstString rs_driverlib("libRSDriver.so");
982
0
    if (module_sp->GetFileSpec().GetFilename() == rs_driverlib) {
983
0
      return eModuleKindDriver;
984
0
    }
985
986
0
    const ConstString rs_cpureflib("libRSCpuRef.so");
987
0
    if (module_sp->GetFileSpec().GetFilename() == rs_cpureflib) {
988
0
      return eModuleKindImpl;
989
0
    }
990
0
  }
991
0
  return eModuleKindIgnored;
992
0
}
993
994
bool RenderScriptRuntime::IsRenderScriptModule(
995
0
    const lldb::ModuleSP &module_sp) {
996
0
  return GetModuleKind(module_sp) != eModuleKindIgnored;
997
0
}
998
999
0
void RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list) {
1000
0
  std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
1001
1002
0
  size_t num_modules = module_list.GetSize();
1003
0
  for (size_t i = 0; i < num_modules; i++) {
1004
0
    auto mod = module_list.GetModuleAtIndex(i);
1005
0
    if (IsRenderScriptModule(mod)) {
1006
0
      LoadModule(mod);
1007
0
    }
1008
0
  }
1009
0
}
1010
1011
bool RenderScriptRuntime::GetDynamicTypeAndAddress(
1012
    ValueObject &in_value, lldb::DynamicValueType use_dynamic,
1013
    TypeAndOrName &class_type_or_name, Address &address,
1014
0
    Value::ValueType &value_type) {
1015
0
  return false;
1016
0
}
1017
1018
TypeAndOrName
1019
RenderScriptRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
1020
0
                                      ValueObject &static_value) {
1021
0
  return type_and_or_name;
1022
0
}
1023
1024
0
bool RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
1025
0
  return false;
1026
0
}
1027
1028
lldb::BreakpointResolverSP
1029
RenderScriptRuntime::CreateExceptionResolver(const lldb::BreakpointSP &bp,
1030
0
                                             bool catch_bp, bool throw_bp) {
1031
0
  BreakpointResolverSP resolver_sp;
1032
0
  return resolver_sp;
1033
0
}
1034
1035
const RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] =
1036
    {
1037
        // rsdScript
1038
        {"rsdScriptInit", "_Z13rsdScriptInitPKN7android12renderscript7ContextEP"
1039
                          "NS0_7ScriptCEPKcS7_PKhjj",
1040
         "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_"
1041
         "7ScriptCEPKcS7_PKhmj",
1042
         0, RenderScriptRuntime::eModuleKindDriver,
1043
         &lldb_private::RenderScriptRuntime::CaptureScriptInit},
1044
        {"rsdScriptInvokeForEachMulti",
1045
         "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0"
1046
         "_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall",
1047
         "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0"
1048
         "_6ScriptEjPPKNS0_10AllocationEmPS6_PKvmPK12RsScriptCall",
1049
         0, RenderScriptRuntime::eModuleKindDriver,
1050
         &lldb_private::RenderScriptRuntime::CaptureScriptInvokeForEachMulti},
1051
        {"rsdScriptSetGlobalVar", "_Z21rsdScriptSetGlobalVarPKN7android12render"
1052
                                  "script7ContextEPKNS0_6ScriptEjPvj",
1053
         "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_"
1054
         "6ScriptEjPvm",
1055
         0, RenderScriptRuntime::eModuleKindDriver,
1056
         &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar},
1057
1058
        // rsdAllocation
1059
        {"rsdAllocationInit", "_Z17rsdAllocationInitPKN7android12renderscript7C"
1060
                              "ontextEPNS0_10AllocationEb",
1061
         "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_"
1062
         "10AllocationEb",
1063
         0, RenderScriptRuntime::eModuleKindDriver,
1064
         &lldb_private::RenderScriptRuntime::CaptureAllocationInit},
1065
        {"rsdAllocationRead2D",
1066
         "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_"
1067
         "10AllocationEjjj23RsAllocationCubemapFacejjPvjj",
1068
         "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_"
1069
         "10AllocationEjjj23RsAllocationCubemapFacejjPvmm",
1070
         0, RenderScriptRuntime::eModuleKindDriver, nullptr},
1071
        {"rsdAllocationDestroy", "_Z20rsdAllocationDestroyPKN7android12rendersc"
1072
                                 "ript7ContextEPNS0_10AllocationE",
1073
         "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_"
1074
         "10AllocationE",
1075
         0, RenderScriptRuntime::eModuleKindDriver,
1076
         &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy},
1077
1078
        // renderscript script groups
1079
        {"rsdDebugHintScriptGroup2", "_ZN7android12renderscript21debugHintScrip"
1080
                                     "tGroup2EPKcjPKPFvPK24RsExpandKernelDriver"
1081
                                     "InfojjjEj",
1082
         "_ZN7android12renderscript21debugHintScriptGroup2EPKcjPKPFvPK24RsExpan"
1083
         "dKernelDriverInfojjjEj",
1084
         0, RenderScriptRuntime::eModuleKindImpl,
1085
         &lldb_private::RenderScriptRuntime::CaptureDebugHintScriptGroup2}};
1086
1087
const size_t RenderScriptRuntime::s_runtimeHookCount =
1088
    sizeof(s_runtimeHookDefns) / sizeof(s_runtimeHookDefns[0]);
1089
1090
bool RenderScriptRuntime::HookCallback(void *baton,
1091
                                       StoppointCallbackContext *ctx,
1092
                                       lldb::user_id_t break_id,
1093
0
                                       lldb::user_id_t break_loc_id) {
1094
0
  RuntimeHook *hook = (RuntimeHook *)baton;
1095
0
  ExecutionContext exe_ctx(ctx->exe_ctx_ref);
1096
1097
0
  RenderScriptRuntime *lang_rt = llvm::cast<RenderScriptRuntime>(
1098
0
      exe_ctx.GetProcessPtr()->GetLanguageRuntime(
1099
0
          eLanguageTypeExtRenderScript));
1100
1101
0
  lang_rt->HookCallback(hook, exe_ctx);
1102
1103
0
  return false;
1104
0
}
1105
1106
void RenderScriptRuntime::HookCallback(RuntimeHook *hook,
1107
0
                                       ExecutionContext &exe_ctx) {
1108
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1109
1110
0
  LLDB_LOGF(log, "%s - '%s'", __FUNCTION__, hook->defn->name);
1111
1112
0
  if (hook->defn->grabber) {
1113
0
    (this->*(hook->defn->grabber))(hook, exe_ctx);
1114
0
  }
1115
0
}
1116
1117
void RenderScriptRuntime::CaptureDebugHintScriptGroup2(
1118
0
    RuntimeHook *hook_info, ExecutionContext &context) {
1119
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1120
1121
0
  enum {
1122
0
    eGroupName = 0,
1123
0
    eGroupNameSize,
1124
0
    eKernel,
1125
0
    eKernelCount,
1126
0
  };
1127
1128
0
  std::array<ArgItem, 4> args{{
1129
0
      {ArgItem::ePointer, 0}, // const char         *groupName
1130
0
      {ArgItem::eInt32, 0},   // const uint32_t      groupNameSize
1131
0
      {ArgItem::ePointer, 0}, // const ExpandFuncTy *kernel
1132
0
      {ArgItem::eInt32, 0},   // const uint32_t      kernelCount
1133
0
  }};
1134
1135
0
  if (!GetArgs(context, args.data(), args.size())) {
1136
0
    LLDB_LOGF(log, "%s - Error while reading the function parameters",
1137
0
              __FUNCTION__);
1138
0
    return;
1139
0
  } else if (log) {
1140
0
    LLDB_LOGF(log, "%s - groupName    : 0x%" PRIx64, __FUNCTION__,
1141
0
              addr_t(args[eGroupName]));
1142
0
    LLDB_LOGF(log, "%s - groupNameSize: %" PRIu64, __FUNCTION__,
1143
0
              uint64_t(args[eGroupNameSize]));
1144
0
    LLDB_LOGF(log, "%s - kernel       : 0x%" PRIx64, __FUNCTION__,
1145
0
              addr_t(args[eKernel]));
1146
0
    LLDB_LOGF(log, "%s - kernelCount  : %" PRIu64, __FUNCTION__,
1147
0
              uint64_t(args[eKernelCount]));
1148
0
  }
1149
1150
  // parse script group name
1151
0
  ConstString group_name;
1152
0
  {
1153
0
    Status err;
1154
0
    const uint64_t len = uint64_t(args[eGroupNameSize]);
1155
0
    std::unique_ptr<char[]> buffer(new char[uint32_t(len + 1)]);
1156
0
    m_process->ReadMemory(addr_t(args[eGroupName]), buffer.get(), len, err);
1157
0
    buffer.get()[len] = '\0';
1158
0
    if (!err.Success()) {
1159
0
      LLDB_LOGF(log, "Error reading scriptgroup name from target");
1160
0
      return;
1161
0
    } else {
1162
0
      LLDB_LOGF(log, "Extracted scriptgroup name %s", buffer.get());
1163
0
    }
1164
    // write back the script group name
1165
0
    group_name.SetCString(buffer.get());
1166
0
  }
1167
1168
  // create or access existing script group
1169
0
  RSScriptGroupDescriptorSP group;
1170
0
  {
1171
    // search for existing script group
1172
0
    for (auto sg : m_scriptGroups) {
1173
0
      if (sg->m_name == group_name) {
1174
0
        group = sg;
1175
0
        break;
1176
0
      }
1177
0
    }
1178
0
    if (!group) {
1179
0
      group = std::make_shared<RSScriptGroupDescriptor>();
1180
0
      group->m_name = group_name;
1181
0
      m_scriptGroups.push_back(group);
1182
0
    } else {
1183
      // already have this script group
1184
0
      LLDB_LOGF(log, "Attempt to add duplicate script group %s",
1185
0
                group_name.AsCString());
1186
0
      return;
1187
0
    }
1188
0
  }
1189
0
  assert(group);
1190
1191
0
  const uint32_t target_ptr_size = m_process->GetAddressByteSize();
1192
0
  std::vector<addr_t> kernels;
1193
  // parse kernel addresses in script group
1194
0
  for (uint64_t i = 0; i < uint64_t(args[eKernelCount]); ++i) {
1195
0
    RSScriptGroupDescriptor::Kernel kernel;
1196
    // extract script group kernel addresses from the target
1197
0
    const addr_t ptr_addr = addr_t(args[eKernel]) + i * target_ptr_size;
1198
0
    uint64_t kernel_addr = 0;
1199
0
    Status err;
1200
0
    size_t read =
1201
0
        m_process->ReadMemory(ptr_addr, &kernel_addr, target_ptr_size, err);
1202
0
    if (!err.Success() || read != target_ptr_size) {
1203
0
      LLDB_LOGF(log, "Error parsing kernel address %" PRIu64 " in script group",
1204
0
                i);
1205
0
      return;
1206
0
    }
1207
0
    LLDB_LOGF(log, "Extracted scriptgroup kernel address - 0x%" PRIx64,
1208
0
              kernel_addr);
1209
0
    kernel.m_addr = kernel_addr;
1210
1211
    // try to resolve the associated kernel name
1212
0
    if (!ResolveKernelName(kernel.m_addr, kernel.m_name)) {
1213
0
      LLDB_LOGF(log, "Parsed scriptgroup kernel %" PRIu64 " - 0x%" PRIx64, i,
1214
0
                kernel_addr);
1215
0
      return;
1216
0
    }
1217
1218
    // try to find the non '.expand' function
1219
0
    {
1220
0
      const llvm::StringRef expand(".expand");
1221
0
      const llvm::StringRef name_ref = kernel.m_name.GetStringRef();
1222
0
      if (name_ref.endswith(expand)) {
1223
0
        const ConstString base_kernel(name_ref.drop_back(expand.size()));
1224
        // verify this function is a valid kernel
1225
0
        if (IsKnownKernel(base_kernel)) {
1226
0
          kernel.m_name = base_kernel;
1227
0
          LLDB_LOGF(log, "%s - found non expand version '%s'", __FUNCTION__,
1228
0
                    base_kernel.GetCString());
1229
0
        }
1230
0
      }
1231
0
    }
1232
    // add to a list of script group kernels we know about
1233
0
    group->m_kernels.push_back(kernel);
1234
0
  }
1235
1236
  // Resolve any pending scriptgroup breakpoints
1237
0
  {
1238
0
    Target &target = m_process->GetTarget();
1239
0
    const BreakpointList &list = target.GetBreakpointList();
1240
0
    const size_t num_breakpoints = list.GetSize();
1241
0
    LLDB_LOGF(log, "Resolving %zu breakpoints", num_breakpoints);
1242
0
    for (size_t i = 0; i < num_breakpoints; ++i) {
1243
0
      const BreakpointSP bp = list.GetBreakpointAtIndex(i);
1244
0
      if (bp) {
1245
0
        if (bp->MatchesName(group_name.AsCString())) {
1246
0
          LLDB_LOGF(log, "Found breakpoint with name %s",
1247
0
                    group_name.AsCString());
1248
0
          bp->ResolveBreakpoint();
1249
0
        }
1250
0
      }
1251
0
    }
1252
0
  }
1253
0
}
1254
1255
void RenderScriptRuntime::CaptureScriptInvokeForEachMulti(
1256
0
    RuntimeHook *hook, ExecutionContext &exe_ctx) {
1257
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1258
1259
0
  enum {
1260
0
    eRsContext = 0,
1261
0
    eRsScript,
1262
0
    eRsSlot,
1263
0
    eRsAIns,
1264
0
    eRsInLen,
1265
0
    eRsAOut,
1266
0
    eRsUsr,
1267
0
    eRsUsrLen,
1268
0
    eRsSc,
1269
0
  };
1270
1271
0
  std::array<ArgItem, 9> args{{
1272
0
      ArgItem{ArgItem::ePointer, 0}, // const Context       *rsc
1273
0
      ArgItem{ArgItem::ePointer, 0}, // Script              *s
1274
0
      ArgItem{ArgItem::eInt32, 0},   // uint32_t             slot
1275
0
      ArgItem{ArgItem::ePointer, 0}, // const Allocation   **aIns
1276
0
      ArgItem{ArgItem::eInt32, 0},   // size_t               inLen
1277
0
      ArgItem{ArgItem::ePointer, 0}, // Allocation          *aout
1278
0
      ArgItem{ArgItem::ePointer, 0}, // const void          *usr
1279
0
      ArgItem{ArgItem::eInt32, 0},   // size_t               usrLen
1280
0
      ArgItem{ArgItem::ePointer, 0}, // const RsScriptCall  *sc
1281
0
  }};
1282
1283
0
  bool success = GetArgs(exe_ctx, &args[0], args.size());
1284
0
  if (!success) {
1285
0
    LLDB_LOGF(log, "%s - Error while reading the function parameters",
1286
0
              __FUNCTION__);
1287
0
    return;
1288
0
  }
1289
1290
0
  const uint32_t target_ptr_size = m_process->GetAddressByteSize();
1291
0
  Status err;
1292
0
  std::vector<uint64_t> allocs;
1293
1294
  // traverse allocation list
1295
0
  for (uint64_t i = 0; i < uint64_t(args[eRsInLen]); ++i) {
1296
    // calculate offest to allocation pointer
1297
0
    const addr_t addr = addr_t(args[eRsAIns]) + i * target_ptr_size;
1298
1299
    // Note: due to little endian layout, reading 32bits or 64bits into res
1300
    // will give the correct results.
1301
0
    uint64_t result = 0;
1302
0
    size_t read = m_process->ReadMemory(addr, &result, target_ptr_size, err);
1303
0
    if (read != target_ptr_size || !err.Success()) {
1304
0
      LLDB_LOGF(log,
1305
0
                "%s - Error while reading allocation list argument %" PRIu64,
1306
0
                __FUNCTION__, i);
1307
0
    } else {
1308
0
      allocs.push_back(result);
1309
0
    }
1310
0
  }
1311
1312
  // if there is an output allocation track it
1313
0
  if (uint64_t alloc_out = uint64_t(args[eRsAOut])) {
1314
0
    allocs.push_back(alloc_out);
1315
0
  }
1316
1317
  // for all allocations we have found
1318
0
  for (const uint64_t alloc_addr : allocs) {
1319
0
    AllocationDetails *alloc = LookUpAllocation(alloc_addr);
1320
0
    if (!alloc)
1321
0
      alloc = CreateAllocation(alloc_addr);
1322
1323
0
    if (alloc) {
1324
      // save the allocation address
1325
0
      if (alloc->address.isValid()) {
1326
        // check the allocation address we already have matches
1327
0
        assert(*alloc->address.get() == alloc_addr);
1328
0
      } else {
1329
0
        alloc->address = alloc_addr;
1330
0
      }
1331
1332
      // save the context
1333
0
      if (log) {
1334
0
        if (alloc->context.isValid() &&
1335
0
            *alloc->context.get() != addr_t(args[eRsContext]))
1336
0
          LLDB_LOGF(log, "%s - Allocation used by multiple contexts",
1337
0
                    __FUNCTION__);
1338
0
      }
1339
0
      alloc->context = addr_t(args[eRsContext]);
1340
0
    }
1341
0
  }
1342
1343
  // make sure we track this script object
1344
0
  if (lldb_private::RenderScriptRuntime::ScriptDetails *script =
1345
0
          LookUpScript(addr_t(args[eRsScript]), true)) {
1346
0
    if (log) {
1347
0
      if (script->context.isValid() &&
1348
0
          *script->context.get() != addr_t(args[eRsContext]))
1349
0
        LLDB_LOGF(log, "%s - Script used by multiple contexts", __FUNCTION__);
1350
0
    }
1351
0
    script->context = addr_t(args[eRsContext]);
1352
0
  }
1353
0
}
1354
1355
void RenderScriptRuntime::CaptureSetGlobalVar(RuntimeHook *hook,
1356
0
                                              ExecutionContext &context) {
1357
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1358
1359
0
  enum {
1360
0
    eRsContext,
1361
0
    eRsScript,
1362
0
    eRsId,
1363
0
    eRsData,
1364
0
    eRsLength,
1365
0
  };
1366
1367
0
  std::array<ArgItem, 5> args{{
1368
0
      ArgItem{ArgItem::ePointer, 0}, // eRsContext
1369
0
      ArgItem{ArgItem::ePointer, 0}, // eRsScript
1370
0
      ArgItem{ArgItem::eInt32, 0},   // eRsId
1371
0
      ArgItem{ArgItem::ePointer, 0}, // eRsData
1372
0
      ArgItem{ArgItem::eInt32, 0},   // eRsLength
1373
0
  }};
1374
1375
0
  bool success = GetArgs(context, &args[0], args.size());
1376
0
  if (!success) {
1377
0
    LLDB_LOGF(log, "%s - error reading the function parameters.", __FUNCTION__);
1378
0
    return;
1379
0
  }
1380
1381
0
  if (log) {
1382
0
    LLDB_LOGF(log,
1383
0
              "%s - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64
1384
0
              ":%" PRIu64 "bytes.",
1385
0
              __FUNCTION__, uint64_t(args[eRsContext]),
1386
0
              uint64_t(args[eRsScript]), uint64_t(args[eRsId]),
1387
0
              uint64_t(args[eRsData]), uint64_t(args[eRsLength]));
1388
1389
0
    addr_t script_addr = addr_t(args[eRsScript]);
1390
0
    if (m_scriptMappings.find(script_addr) != m_scriptMappings.end()) {
1391
0
      auto rsm = m_scriptMappings[script_addr];
1392
0
      if (uint64_t(args[eRsId]) < rsm->m_globals.size()) {
1393
0
        auto rsg = rsm->m_globals[uint64_t(args[eRsId])];
1394
0
        LLDB_LOGF(log, "%s - Setting of '%s' within '%s' inferred",
1395
0
                  __FUNCTION__, rsg.m_name.AsCString(),
1396
0
                  rsm->m_module->GetFileSpec().GetFilename().AsCString());
1397
0
      }
1398
0
    }
1399
0
  }
1400
0
}
1401
1402
void RenderScriptRuntime::CaptureAllocationInit(RuntimeHook *hook,
1403
0
                                                ExecutionContext &exe_ctx) {
1404
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1405
1406
0
  enum { eRsContext, eRsAlloc, eRsForceZero };
1407
1408
0
  std::array<ArgItem, 3> args{{
1409
0
      ArgItem{ArgItem::ePointer, 0}, // eRsContext
1410
0
      ArgItem{ArgItem::ePointer, 0}, // eRsAlloc
1411
0
      ArgItem{ArgItem::eBool, 0},    // eRsForceZero
1412
0
  }};
1413
1414
0
  bool success = GetArgs(exe_ctx, &args[0], args.size());
1415
0
  if (!success) {
1416
0
    LLDB_LOGF(log, "%s - error while reading the function parameters",
1417
0
              __FUNCTION__);
1418
0
    return;
1419
0
  }
1420
1421
0
  LLDB_LOGF(log, "%s - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .",
1422
0
            __FUNCTION__, uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc]),
1423
0
            uint64_t(args[eRsForceZero]));
1424
1425
0
  AllocationDetails *alloc = CreateAllocation(uint64_t(args[eRsAlloc]));
1426
0
  if (alloc)
1427
0
    alloc->context = uint64_t(args[eRsContext]);
1428
0
}
1429
1430
void RenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook *hook,
1431
0
                                                   ExecutionContext &exe_ctx) {
1432
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1433
1434
0
  enum {
1435
0
    eRsContext,
1436
0
    eRsAlloc,
1437
0
  };
1438
1439
0
  std::array<ArgItem, 2> args{{
1440
0
      ArgItem{ArgItem::ePointer, 0}, // eRsContext
1441
0
      ArgItem{ArgItem::ePointer, 0}, // eRsAlloc
1442
0
  }};
1443
1444
0
  bool success = GetArgs(exe_ctx, &args[0], args.size());
1445
0
  if (!success) {
1446
0
    LLDB_LOGF(log, "%s - error while reading the function parameters.",
1447
0
              __FUNCTION__);
1448
0
    return;
1449
0
  }
1450
1451
0
  LLDB_LOGF(log, "%s - 0x%" PRIx64 ", 0x%" PRIx64 ".", __FUNCTION__,
1452
0
            uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc]));
1453
1454
0
  for (auto iter = m_allocations.begin(); iter != m_allocations.end(); ++iter) {
1455
0
    auto &allocation_up = *iter; // get the unique pointer
1456
0
    if (allocation_up->address.isValid() &&
1457
0
        *allocation_up->address.get() == addr_t(args[eRsAlloc])) {
1458
0
      m_allocations.erase(iter);
1459
0
      LLDB_LOGF(log, "%s - deleted allocation entry.", __FUNCTION__);
1460
0
      return;
1461
0
    }
1462
0
  }
1463
1464
0
  LLDB_LOGF(log, "%s - couldn't find destroyed allocation.", __FUNCTION__);
1465
0
}
1466
1467
void RenderScriptRuntime::CaptureScriptInit(RuntimeHook *hook,
1468
0
                                            ExecutionContext &exe_ctx) {
1469
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1470
1471
0
  Status err;
1472
0
  Process *process = exe_ctx.GetProcessPtr();
1473
1474
0
  enum { eRsContext, eRsScript, eRsResNamePtr, eRsCachedDirPtr };
1475
1476
0
  std::array<ArgItem, 4> args{
1477
0
      {ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0},
1478
0
       ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}}};
1479
0
  bool success = GetArgs(exe_ctx, &args[0], args.size());
1480
0
  if (!success) {
1481
0
    LLDB_LOGF(log, "%s - error while reading the function parameters.",
1482
0
              __FUNCTION__);
1483
0
    return;
1484
0
  }
1485
1486
0
  std::string res_name;
1487
0
  process->ReadCStringFromMemory(addr_t(args[eRsResNamePtr]), res_name, err);
1488
0
  if (err.Fail()) {
1489
0
    LLDB_LOGF(log, "%s - error reading res_name: %s.", __FUNCTION__,
1490
0
              err.AsCString());
1491
0
  }
1492
1493
0
  std::string cache_dir;
1494
0
  process->ReadCStringFromMemory(addr_t(args[eRsCachedDirPtr]), cache_dir, err);
1495
0
  if (err.Fail()) {
1496
0
    LLDB_LOGF(log, "%s - error reading cache_dir: %s.", __FUNCTION__,
1497
0
              err.AsCString());
1498
0
  }
1499
1500
0
  LLDB_LOGF(log, "%s - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .",
1501
0
            __FUNCTION__, uint64_t(args[eRsContext]), uint64_t(args[eRsScript]),
1502
0
            res_name.c_str(), cache_dir.c_str());
1503
1504
0
  if (res_name.size() > 0) {
1505
0
    StreamString strm;
1506
0
    strm.Printf("librs.%s.so", res_name.c_str());
1507
1508
0
    ScriptDetails *script = LookUpScript(addr_t(args[eRsScript]), true);
1509
0
    if (script) {
1510
0
      script->type = ScriptDetails::eScriptC;
1511
0
      script->cache_dir = cache_dir;
1512
0
      script->res_name = res_name;
1513
0
      script->shared_lib = std::string(strm.GetString());
1514
0
      script->context = addr_t(args[eRsContext]);
1515
0
    }
1516
1517
0
    LLDB_LOGF(log,
1518
0
              "%s - '%s' tagged with context 0x%" PRIx64
1519
0
              " and script 0x%" PRIx64 ".",
1520
0
              __FUNCTION__, strm.GetData(), uint64_t(args[eRsContext]),
1521
0
              uint64_t(args[eRsScript]));
1522
0
  } else if (log) {
1523
0
    LLDB_LOGF(log, "%s - resource name invalid, Script not tagged.",
1524
0
              __FUNCTION__);
1525
0
  }
1526
0
}
1527
1528
void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module,
1529
0
                                           ModuleKind kind) {
1530
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1531
1532
0
  if (!module) {
1533
0
    return;
1534
0
  }
1535
1536
0
  Target &target = GetProcess()->GetTarget();
1537
0
  const llvm::Triple::ArchType machine = target.GetArchitecture().GetMachine();
1538
1539
0
  if (machine != llvm::Triple::ArchType::x86 &&
1540
0
      machine != llvm::Triple::ArchType::arm &&
1541
0
      machine != llvm::Triple::ArchType::aarch64 &&
1542
0
      machine != llvm::Triple::ArchType::mipsel &&
1543
0
      machine != llvm::Triple::ArchType::mips64el &&
1544
0
      machine != llvm::Triple::ArchType::x86_64) {
1545
0
    LLDB_LOGF(log, "%s - unable to hook runtime functions.", __FUNCTION__);
1546
0
    return;
1547
0
  }
1548
1549
0
  const uint32_t target_ptr_size =
1550
0
      target.GetArchitecture().GetAddressByteSize();
1551
1552
0
  std::array<bool, s_runtimeHookCount> hook_placed;
1553
0
  hook_placed.fill(false);
1554
1555
0
  for (size_t idx = 0; idx < s_runtimeHookCount; idx++) {
1556
0
    const HookDefn *hook_defn = &s_runtimeHookDefns[idx];
1557
0
    if (hook_defn->kind != kind) {
1558
0
      continue;
1559
0
    }
1560
1561
0
    const char *symbol_name = (target_ptr_size == 4)
1562
0
                                  ? hook_defn->symbol_name_m32
1563
0
                                  : hook_defn->symbol_name_m64;
1564
1565
0
    const Symbol *sym = module->FindFirstSymbolWithNameAndType(
1566
0
        ConstString(symbol_name), eSymbolTypeCode);
1567
0
    if (!sym) {
1568
0
      if (log) {
1569
0
        LLDB_LOGF(log, "%s - symbol '%s' related to the function %s not found",
1570
0
                  __FUNCTION__, symbol_name, hook_defn->name);
1571
0
      }
1572
0
      continue;
1573
0
    }
1574
1575
0
    addr_t addr = sym->GetLoadAddress(&target);
1576
0
    if (addr == LLDB_INVALID_ADDRESS) {
1577
0
      LLDB_LOGF(log,
1578
0
                "%s - unable to resolve the address of hook function '%s' "
1579
0
                "with symbol '%s'.",
1580
0
                __FUNCTION__, hook_defn->name, symbol_name);
1581
0
      continue;
1582
0
    } else {
1583
0
      LLDB_LOGF(log, "%s - function %s, address resolved at 0x%" PRIx64,
1584
0
                __FUNCTION__, hook_defn->name, addr);
1585
0
    }
1586
1587
0
    RuntimeHookSP hook(new RuntimeHook());
1588
0
    hook->address = addr;
1589
0
    hook->defn = hook_defn;
1590
0
    hook->bp_sp = target.CreateBreakpoint(addr, true, false);
1591
0
    hook->bp_sp->SetCallback(HookCallback, hook.get(), true);
1592
0
    m_runtimeHooks[addr] = hook;
1593
0
    if (log) {
1594
0
      LLDB_LOGF(log,
1595
0
                "%s - successfully hooked '%s' in '%s' version %" PRIu64
1596
0
                " at 0x%" PRIx64 ".",
1597
0
                __FUNCTION__, hook_defn->name,
1598
0
                module->GetFileSpec().GetFilename().AsCString(),
1599
0
                (uint64_t)hook_defn->version, (uint64_t)addr);
1600
0
    }
1601
0
    hook_placed[idx] = true;
1602
0
  }
1603
1604
  // log any unhooked function
1605
0
  if (log) {
1606
0
    for (size_t i = 0; i < hook_placed.size(); ++i) {
1607
0
      if (hook_placed[i])
1608
0
        continue;
1609
0
      const HookDefn &hook_defn = s_runtimeHookDefns[i];
1610
0
      if (hook_defn.kind != kind)
1611
0
        continue;
1612
0
      LLDB_LOGF(log, "%s - function %s was not hooked", __FUNCTION__,
1613
0
                hook_defn.name);
1614
0
    }
1615
0
  }
1616
0
}
1617
1618
0
void RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp) {
1619
0
  if (!rsmodule_sp)
1620
0
    return;
1621
1622
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1623
1624
0
  const ModuleSP module = rsmodule_sp->m_module;
1625
0
  const FileSpec &file = module->GetPlatformFileSpec();
1626
1627
  // Iterate over all of the scripts that we currently know of. Note: We cant
1628
  // push or pop to m_scripts here or it may invalidate rs_script.
1629
0
  for (const auto &rs_script : m_scripts) {
1630
    // Extract the expected .so file path for this script.
1631
0
    std::string shared_lib;
1632
0
    if (!rs_script->shared_lib.get(shared_lib))
1633
0
      continue;
1634
1635
    // Only proceed if the module that has loaded corresponds to this script.
1636
0
    if (file.GetFilename() != ConstString(shared_lib.c_str()))
1637
0
      continue;
1638
1639
    // Obtain the script address which we use as a key.
1640
0
    lldb::addr_t script;
1641
0
    if (!rs_script->script.get(script))
1642
0
      continue;
1643
1644
    // If we have a script mapping for the current script.
1645
0
    if (m_scriptMappings.find(script) != m_scriptMappings.end()) {
1646
      // if the module we have stored is different to the one we just received.
1647
0
      if (m_scriptMappings[script] != rsmodule_sp) {
1648
0
        LLDB_LOGF(
1649
0
            log,
1650
0
            "%s - script %" PRIx64 " wants reassigned to new rsmodule '%s'.",
1651
0
            __FUNCTION__, (uint64_t)script,
1652
0
            rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
1653
0
      }
1654
0
    }
1655
    // We don't have a script mapping for the current script.
1656
0
    else {
1657
      // Obtain the script resource name.
1658
0
      std::string res_name;
1659
0
      if (rs_script->res_name.get(res_name))
1660
        // Set the modules resource name.
1661
0
        rsmodule_sp->m_resname = res_name;
1662
      // Add Script/Module pair to map.
1663
0
      m_scriptMappings[script] = rsmodule_sp;
1664
0
      LLDB_LOGF(log, "%s - script %" PRIx64 " associated with rsmodule '%s'.",
1665
0
                __FUNCTION__, (uint64_t)script,
1666
0
                rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString());
1667
0
    }
1668
0
  }
1669
0
}
1670
1671
// Uses the Target API to evaluate the expression passed as a parameter to the
1672
// function The result of that expression is returned an unsigned 64 bit int,
1673
// via the result* parameter. Function returns true on success, and false on
1674
// failure
1675
bool RenderScriptRuntime::EvalRSExpression(const char *expr,
1676
                                           StackFrame *frame_ptr,
1677
0
                                           uint64_t *result) {
1678
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1679
0
  LLDB_LOGF(log, "%s(%s)", __FUNCTION__, expr);
1680
1681
0
  ValueObjectSP expr_result;
1682
0
  EvaluateExpressionOptions options;
1683
0
  options.SetLanguage(lldb::eLanguageTypeC_plus_plus);
1684
  // Perform the actual expression evaluation
1685
0
  auto &target = GetProcess()->GetTarget();
1686
0
  target.EvaluateExpression(expr, frame_ptr, expr_result, options);
1687
1688
0
  if (!expr_result) {
1689
0
    LLDB_LOGF(log, "%s: couldn't evaluate expression.", __FUNCTION__);
1690
0
    return false;
1691
0
  }
1692
1693
  // The result of the expression is invalid
1694
0
  if (!expr_result->GetError().Success()) {
1695
0
    Status err = expr_result->GetError();
1696
    // Expression returned is void, so this is actually a success
1697
0
    if (err.GetError() == UserExpression::kNoResult) {
1698
0
      LLDB_LOGF(log, "%s - expression returned void.", __FUNCTION__);
1699
1700
0
      result = nullptr;
1701
0
      return true;
1702
0
    }
1703
1704
0
    LLDB_LOGF(log, "%s - error evaluating expression result: %s", __FUNCTION__,
1705
0
              err.AsCString());
1706
0
    return false;
1707
0
  }
1708
1709
0
  bool success = false;
1710
  // We only read the result as an uint32_t.
1711
0
  *result = expr_result->GetValueAsUnsigned(0, &success);
1712
1713
0
  if (!success) {
1714
0
    LLDB_LOGF(log, "%s - couldn't convert expression result to uint32_t",
1715
0
              __FUNCTION__);
1716
0
    return false;
1717
0
  }
1718
1719
0
  return true;
1720
0
}
1721
1722
namespace {
1723
// Used to index expression format strings
1724
enum ExpressionStrings {
1725
  eExprGetOffsetPtr = 0,
1726
  eExprAllocGetType,
1727
  eExprTypeDimX,
1728
  eExprTypeDimY,
1729
  eExprTypeDimZ,
1730
  eExprTypeElemPtr,
1731
  eExprElementType,
1732
  eExprElementKind,
1733
  eExprElementVec,
1734
  eExprElementFieldCount,
1735
  eExprSubelementsId,
1736
  eExprSubelementsName,
1737
  eExprSubelementsArrSize,
1738
1739
  _eExprLast // keep at the end, implicit size of the array runtime_expressions
1740
};
1741
1742
// max length of an expanded expression
1743
const int jit_max_expr_size = 512;
1744
1745
// Retrieve the string to JIT for the given expression
1746
0
#define JIT_TEMPLATE_CONTEXT "void* ctxt = (void*)rsDebugGetContextWrapper(0x%" PRIx64 "); "
1747
0
const char *JITTemplate(ExpressionStrings e) {
1748
  // Format strings containing the expressions we may need to evaluate.
1749
0
  static std::array<const char *, _eExprLast> runtime_expressions = {
1750
0
      {// Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap)
1751
0
       "(int*)_"
1752
0
       "Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocation"
1753
0
       "CubemapFace"
1754
0
       "(0x%" PRIx64 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", 0, 0)", // eExprGetOffsetPtr
1755
1756
       // Type* rsaAllocationGetType(Context*, Allocation*)
1757
0
       JIT_TEMPLATE_CONTEXT "(void*)rsaAllocationGetType(ctxt, 0x%" PRIx64 ")", // eExprAllocGetType
1758
1759
       // rsaTypeGetNativeData(Context*, Type*, void* typeData, size) Pack the
1760
       // data in the following way mHal.state.dimX; mHal.state.dimY;
1761
       // mHal.state.dimZ; mHal.state.lodCount; mHal.state.faces; mElement;
1762
       // into typeData Need to specify 32 or 64 bit for uint_t since this
1763
       // differs between devices
1764
0
       JIT_TEMPLATE_CONTEXT
1765
0
       "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
1766
0
       ", 0x%" PRIx64 ", data, 6); data[0]", // eExprTypeDimX
1767
0
       JIT_TEMPLATE_CONTEXT
1768
0
       "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
1769
0
       ", 0x%" PRIx64 ", data, 6); data[1]", // eExprTypeDimY
1770
0
       JIT_TEMPLATE_CONTEXT
1771
0
       "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
1772
0
       ", 0x%" PRIx64 ", data, 6); data[2]", // eExprTypeDimZ
1773
0
       JIT_TEMPLATE_CONTEXT
1774
0
       "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(ctxt"
1775
0
       ", 0x%" PRIx64 ", data, 6); data[5]", // eExprTypeElemPtr
1776
1777
       // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size)
1778
       // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into
1779
       // elemData
1780
0
       JIT_TEMPLATE_CONTEXT
1781
0
       "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
1782
0
       ", 0x%" PRIx64 ", data, 5); data[0]", // eExprElementType
1783
0
       JIT_TEMPLATE_CONTEXT
1784
0
       "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
1785
0
       ", 0x%" PRIx64 ", data, 5); data[1]", // eExprElementKind
1786
0
       JIT_TEMPLATE_CONTEXT
1787
0
       "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
1788
0
       ", 0x%" PRIx64 ", data, 5); data[3]", // eExprElementVec
1789
0
       JIT_TEMPLATE_CONTEXT
1790
0
       "uint32_t data[5]; (void*)rsaElementGetNativeData(ctxt"
1791
0
       ", 0x%" PRIx64 ", data, 5); data[4]", // eExprElementFieldCount
1792
1793
       // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t
1794
       // *ids, const char **names, size_t *arraySizes, uint32_t dataSize)
1795
       // Needed for Allocations of structs to gather details about
1796
       // fields/Subelements Element* of field
1797
0
       JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
1798
0
       "]; size_t arr_size[%" PRIu32 "];"
1799
0
       "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64
1800
0
       ", ids, names, arr_size, %" PRIu32 "); ids[%" PRIu32 "]", // eExprSubelementsId
1801
1802
       // Name of field
1803
0
       JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
1804
0
       "]; size_t arr_size[%" PRIu32 "];"
1805
0
       "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64
1806
0
       ", ids, names, arr_size, %" PRIu32 "); names[%" PRIu32 "]", // eExprSubelementsName
1807
1808
       // Array size of field
1809
0
       JIT_TEMPLATE_CONTEXT "void* ids[%" PRIu32 "]; const char* names[%" PRIu32
1810
0
       "]; size_t arr_size[%" PRIu32 "];"
1811
0
       "(void*)rsaElementGetSubElements(ctxt, 0x%" PRIx64
1812
0
       ", ids, names, arr_size, %" PRIu32 "); arr_size[%" PRIu32 "]"}}; // eExprSubelementsArrSize
1813
1814
0
  return runtime_expressions[e];
1815
0
}
1816
} // end of the anonymous namespace
1817
1818
// JITs the RS runtime for the internal data pointer of an allocation. Is
1819
// passed x,y,z coordinates for the pointer to a specific element. Then sets
1820
// the data_ptr member in Allocation with the result. Returns true on success,
1821
// false otherwise
1822
bool RenderScriptRuntime::JITDataPointer(AllocationDetails *alloc,
1823
                                         StackFrame *frame_ptr, uint32_t x,
1824
0
                                         uint32_t y, uint32_t z) {
1825
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1826
1827
0
  if (!alloc->address.isValid()) {
1828
0
    LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
1829
0
    return false;
1830
0
  }
1831
1832
0
  const char *fmt_str = JITTemplate(eExprGetOffsetPtr);
1833
0
  char expr_buf[jit_max_expr_size];
1834
1835
0
  int written = snprintf(expr_buf, jit_max_expr_size, fmt_str,
1836
0
                         *alloc->address.get(), x, y, z);
1837
0
  if (written < 0) {
1838
0
    LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
1839
0
    return false;
1840
0
  } else if (written >= jit_max_expr_size) {
1841
0
    LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
1842
0
    return false;
1843
0
  }
1844
1845
0
  uint64_t result = 0;
1846
0
  if (!EvalRSExpression(expr_buf, frame_ptr, &result))
1847
0
    return false;
1848
1849
0
  addr_t data_ptr = static_cast<lldb::addr_t>(result);
1850
0
  alloc->data_ptr = data_ptr;
1851
1852
0
  return true;
1853
0
}
1854
1855
// JITs the RS runtime for the internal pointer to the RS Type of an allocation
1856
// Then sets the type_ptr member in Allocation with the result. Returns true on
1857
// success, false otherwise
1858
bool RenderScriptRuntime::JITTypePointer(AllocationDetails *alloc,
1859
0
                                         StackFrame *frame_ptr) {
1860
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1861
1862
0
  if (!alloc->address.isValid() || !alloc->context.isValid()) {
1863
0
    LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
1864
0
    return false;
1865
0
  }
1866
1867
0
  const char *fmt_str = JITTemplate(eExprAllocGetType);
1868
0
  char expr_buf[jit_max_expr_size];
1869
1870
0
  int written = snprintf(expr_buf, jit_max_expr_size, fmt_str,
1871
0
                         *alloc->context.get(), *alloc->address.get());
1872
0
  if (written < 0) {
1873
0
    LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
1874
0
    return false;
1875
0
  } else if (written >= jit_max_expr_size) {
1876
0
    LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
1877
0
    return false;
1878
0
  }
1879
1880
0
  uint64_t result = 0;
1881
0
  if (!EvalRSExpression(expr_buf, frame_ptr, &result))
1882
0
    return false;
1883
1884
0
  addr_t type_ptr = static_cast<lldb::addr_t>(result);
1885
0
  alloc->type_ptr = type_ptr;
1886
1887
0
  return true;
1888
0
}
1889
1890
// JITs the RS runtime for information about the dimensions and type of an
1891
// allocation Then sets dimension and element_ptr members in Allocation with
1892
// the result. Returns true on success, false otherwise
1893
bool RenderScriptRuntime::JITTypePacked(AllocationDetails *alloc,
1894
0
                                        StackFrame *frame_ptr) {
1895
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1896
1897
0
  if (!alloc->type_ptr.isValid() || !alloc->context.isValid()) {
1898
0
    LLDB_LOGF(log, "%s - Failed to find allocation details.", __FUNCTION__);
1899
0
    return false;
1900
0
  }
1901
1902
  // Expression is different depending on if device is 32 or 64 bit
1903
0
  uint32_t target_ptr_size =
1904
0
      GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
1905
0
  const uint32_t bits = target_ptr_size == 4 ? 32 : 64;
1906
1907
  // We want 4 elements from packed data
1908
0
  const uint32_t num_exprs = 4;
1909
0
  static_assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1),
1910
0
                "Invalid number of expressions");
1911
1912
0
  char expr_bufs[num_exprs][jit_max_expr_size];
1913
0
  uint64_t results[num_exprs];
1914
1915
0
  for (uint32_t i = 0; i < num_exprs; ++i) {
1916
0
    const char *fmt_str = JITTemplate(ExpressionStrings(eExprTypeDimX + i));
1917
0
    int written = snprintf(expr_bufs[i], jit_max_expr_size, fmt_str,
1918
0
                           *alloc->context.get(), bits, *alloc->type_ptr.get());
1919
0
    if (written < 0) {
1920
0
      LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
1921
0
      return false;
1922
0
    } else if (written >= jit_max_expr_size) {
1923
0
      LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
1924
0
      return false;
1925
0
    }
1926
1927
    // Perform expression evaluation
1928
0
    if (!EvalRSExpression(expr_bufs[i], frame_ptr, &results[i]))
1929
0
      return false;
1930
0
  }
1931
1932
  // Assign results to allocation members
1933
0
  AllocationDetails::Dimension dims;
1934
0
  dims.dim_1 = static_cast<uint32_t>(results[0]);
1935
0
  dims.dim_2 = static_cast<uint32_t>(results[1]);
1936
0
  dims.dim_3 = static_cast<uint32_t>(results[2]);
1937
0
  alloc->dimension = dims;
1938
1939
0
  addr_t element_ptr = static_cast<lldb::addr_t>(results[3]);
1940
0
  alloc->element.element_ptr = element_ptr;
1941
1942
0
  LLDB_LOGF(log,
1943
0
            "%s - dims (%" PRIu32 ", %" PRIu32 ", %" PRIu32
1944
0
            ") Element*: 0x%" PRIx64 ".",
1945
0
            __FUNCTION__, dims.dim_1, dims.dim_2, dims.dim_3, element_ptr);
1946
1947
0
  return true;
1948
0
}
1949
1950
// JITs the RS runtime for information about the Element of an allocation Then
1951
// sets type, type_vec_size, field_count and type_kind members in Element with
1952
// the result. Returns true on success, false otherwise
1953
bool RenderScriptRuntime::JITElementPacked(Element &elem,
1954
                                           const lldb::addr_t context,
1955
0
                                           StackFrame *frame_ptr) {
1956
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
1957
1958
0
  if (!elem.element_ptr.isValid()) {
1959
0
    LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
1960
0
    return false;
1961
0
  }
1962
1963
  // We want 4 elements from packed data
1964
0
  const uint32_t num_exprs = 4;
1965
0
  static_assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1),
1966
0
                "Invalid number of expressions");
1967
1968
0
  char expr_bufs[num_exprs][jit_max_expr_size];
1969
0
  uint64_t results[num_exprs];
1970
1971
0
  for (uint32_t i = 0; i < num_exprs; i++) {
1972
0
    const char *fmt_str = JITTemplate(ExpressionStrings(eExprElementType + i));
1973
0
    int written = snprintf(expr_bufs[i], jit_max_expr_size, fmt_str, context,
1974
0
                           *elem.element_ptr.get());
1975
0
    if (written < 0) {
1976
0
      LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
1977
0
      return false;
1978
0
    } else if (written >= jit_max_expr_size) {
1979
0
      LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
1980
0
      return false;
1981
0
    }
1982
1983
    // Perform expression evaluation
1984
0
    if (!EvalRSExpression(expr_bufs[i], frame_ptr, &results[i]))
1985
0
      return false;
1986
0
  }
1987
1988
  // Assign results to allocation members
1989
0
  elem.type = static_cast<RenderScriptRuntime::Element::DataType>(results[0]);
1990
0
  elem.type_kind =
1991
0
      static_cast<RenderScriptRuntime::Element::DataKind>(results[1]);
1992
0
  elem.type_vec_size = static_cast<uint32_t>(results[2]);
1993
0
  elem.field_count = static_cast<uint32_t>(results[3]);
1994
1995
0
  LLDB_LOGF(log,
1996
0
            "%s - data type %" PRIu32 ", pixel type %" PRIu32
1997
0
            ", vector size %" PRIu32 ", field count %" PRIu32,
1998
0
            __FUNCTION__, *elem.type.get(), *elem.type_kind.get(),
1999
0
            *elem.type_vec_size.get(), *elem.field_count.get());
2000
2001
  // If this Element has subelements then JIT rsaElementGetSubElements() for
2002
  // details about its fields
2003
0
  return !(*elem.field_count.get() > 0 &&
2004
0
           !JITSubelements(elem, context, frame_ptr));
2005
0
}
2006
2007
// JITs the RS runtime for information about the subelements/fields of a struct
2008
// allocation This is necessary for infering the struct type so we can pretty
2009
// print the allocation's contents. Returns true on success, false otherwise
2010
bool RenderScriptRuntime::JITSubelements(Element &elem,
2011
                                         const lldb::addr_t context,
2012
0
                                         StackFrame *frame_ptr) {
2013
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2014
2015
0
  if (!elem.element_ptr.isValid() || !elem.field_count.isValid()) {
2016
0
    LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
2017
0
    return false;
2018
0
  }
2019
2020
0
  const short num_exprs = 3;
2021
0
  static_assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1),
2022
0
                "Invalid number of expressions");
2023
2024
0
  char expr_buffer[jit_max_expr_size];
2025
0
  uint64_t results;
2026
2027
  // Iterate over struct fields.
2028
0
  const uint32_t field_count = *elem.field_count.get();
2029
0
  for (uint32_t field_index = 0; field_index < field_count; ++field_index) {
2030
0
    Element child;
2031
0
    for (uint32_t expr_index = 0; expr_index < num_exprs; ++expr_index) {
2032
0
      const char *fmt_str =
2033
0
          JITTemplate(ExpressionStrings(eExprSubelementsId + expr_index));
2034
0
      int written = snprintf(expr_buffer, jit_max_expr_size, fmt_str,
2035
0
                             context, field_count, field_count, field_count,
2036
0
                             *elem.element_ptr.get(), field_count, field_index);
2037
0
      if (written < 0) {
2038
0
        LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
2039
0
        return false;
2040
0
      } else if (written >= jit_max_expr_size) {
2041
0
        LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
2042
0
        return false;
2043
0
      }
2044
2045
      // Perform expression evaluation
2046
0
      if (!EvalRSExpression(expr_buffer, frame_ptr, &results))
2047
0
        return false;
2048
2049
0
      LLDB_LOGF(log, "%s - expr result 0x%" PRIx64 ".", __FUNCTION__, results);
2050
2051
0
      switch (expr_index) {
2052
0
      case 0: // Element* of child
2053
0
        child.element_ptr = static_cast<addr_t>(results);
2054
0
        break;
2055
0
      case 1: // Name of child
2056
0
      {
2057
0
        lldb::addr_t address = static_cast<addr_t>(results);
2058
0
        Status err;
2059
0
        std::string name;
2060
0
        GetProcess()->ReadCStringFromMemory(address, name, err);
2061
0
        if (!err.Fail())
2062
0
          child.type_name = ConstString(name);
2063
0
        else {
2064
0
          LLDB_LOGF(log, "%s - warning: Couldn't read field name.",
2065
0
                    __FUNCTION__);
2066
0
        }
2067
0
        break;
2068
0
      }
2069
0
      case 2: // Array size of child
2070
0
        child.array_size = static_cast<uint32_t>(results);
2071
0
        break;
2072
0
      }
2073
0
    }
2074
2075
    // We need to recursively JIT each Element field of the struct since
2076
    // structs can be nested inside structs.
2077
0
    if (!JITElementPacked(child, context, frame_ptr))
2078
0
      return false;
2079
0
    elem.children.push_back(child);
2080
0
  }
2081
2082
  // Try to infer the name of the struct type so we can pretty print the
2083
  // allocation contents.
2084
0
  FindStructTypeName(elem, frame_ptr);
2085
2086
0
  return true;
2087
0
}
2088
2089
// JITs the RS runtime for the address of the last element in the allocation.
2090
// The `elem_size` parameter represents the size of a single element, including
2091
// padding. Which is needed as an offset from the last element pointer. Using
2092
// this offset minus the starting address we can calculate the size of the
2093
// allocation. Returns true on success, false otherwise
2094
bool RenderScriptRuntime::JITAllocationSize(AllocationDetails *alloc,
2095
0
                                            StackFrame *frame_ptr) {
2096
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2097
2098
0
  if (!alloc->address.isValid() || !alloc->dimension.isValid() ||
2099
0
      !alloc->data_ptr.isValid() || !alloc->element.datum_size.isValid()) {
2100
0
    LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
2101
0
    return false;
2102
0
  }
2103
2104
  // Find dimensions
2105
0
  uint32_t dim_x = alloc->dimension.get()->dim_1;
2106
0
  uint32_t dim_y = alloc->dimension.get()->dim_2;
2107
0
  uint32_t dim_z = alloc->dimension.get()->dim_3;
2108
2109
  // Our plan of jitting the last element address doesn't seem to work for
2110
  // struct Allocations` Instead try to infer the size ourselves without any
2111
  // inter element padding.
2112
0
  if (alloc->element.children.size() > 0) {
2113
0
    if (dim_x == 0)
2114
0
      dim_x = 1;
2115
0
    if (dim_y == 0)
2116
0
      dim_y = 1;
2117
0
    if (dim_z == 0)
2118
0
      dim_z = 1;
2119
2120
0
    alloc->size = dim_x * dim_y * dim_z * *alloc->element.datum_size.get();
2121
2122
0
    LLDB_LOGF(log, "%s - inferred size of struct allocation %" PRIu32 ".",
2123
0
              __FUNCTION__, *alloc->size.get());
2124
0
    return true;
2125
0
  }
2126
2127
0
  const char *fmt_str = JITTemplate(eExprGetOffsetPtr);
2128
0
  char expr_buf[jit_max_expr_size];
2129
2130
  // Calculate last element
2131
0
  dim_x = dim_x == 0 ? 0 : dim_x - 1;
2132
0
  dim_y = dim_y == 0 ? 0 : dim_y - 1;
2133
0
  dim_z = dim_z == 0 ? 0 : dim_z - 1;
2134
2135
0
  int written = snprintf(expr_buf, jit_max_expr_size, fmt_str,
2136
0
                         *alloc->address.get(), dim_x, dim_y, dim_z);
2137
0
  if (written < 0) {
2138
0
    LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
2139
0
    return false;
2140
0
  } else if (written >= jit_max_expr_size) {
2141
0
    LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
2142
0
    return false;
2143
0
  }
2144
2145
0
  uint64_t result = 0;
2146
0
  if (!EvalRSExpression(expr_buf, frame_ptr, &result))
2147
0
    return false;
2148
2149
0
  addr_t mem_ptr = static_cast<lldb::addr_t>(result);
2150
  // Find pointer to last element and add on size of an element
2151
0
  alloc->size = static_cast<uint32_t>(mem_ptr - *alloc->data_ptr.get()) +
2152
0
                *alloc->element.datum_size.get();
2153
2154
0
  return true;
2155
0
}
2156
2157
// JITs the RS runtime for information about the stride between rows in the
2158
// allocation. This is done to detect padding, since allocated memory is
2159
// 16-byte aligned. Returns true on success, false otherwise
2160
bool RenderScriptRuntime::JITAllocationStride(AllocationDetails *alloc,
2161
0
                                              StackFrame *frame_ptr) {
2162
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2163
2164
0
  if (!alloc->address.isValid() || !alloc->data_ptr.isValid()) {
2165
0
    LLDB_LOGF(log, "%s - failed to find allocation details.", __FUNCTION__);
2166
0
    return false;
2167
0
  }
2168
2169
0
  const char *fmt_str = JITTemplate(eExprGetOffsetPtr);
2170
0
  char expr_buf[jit_max_expr_size];
2171
2172
0
  int written = snprintf(expr_buf, jit_max_expr_size, fmt_str,
2173
0
                         *alloc->address.get(), 0, 1, 0);
2174
0
  if (written < 0) {
2175
0
    LLDB_LOGF(log, "%s - encoding error in snprintf().", __FUNCTION__);
2176
0
    return false;
2177
0
  } else if (written >= jit_max_expr_size) {
2178
0
    LLDB_LOGF(log, "%s - expression too long.", __FUNCTION__);
2179
0
    return false;
2180
0
  }
2181
2182
0
  uint64_t result = 0;
2183
0
  if (!EvalRSExpression(expr_buf, frame_ptr, &result))
2184
0
    return false;
2185
2186
0
  addr_t mem_ptr = static_cast<lldb::addr_t>(result);
2187
0
  alloc->stride = static_cast<uint32_t>(mem_ptr - *alloc->data_ptr.get());
2188
2189
0
  return true;
2190
0
}
2191
2192
// JIT all the current runtime info regarding an allocation
2193
bool RenderScriptRuntime::RefreshAllocation(AllocationDetails *alloc,
2194
0
                                            StackFrame *frame_ptr) {
2195
  // GetOffsetPointer()
2196
0
  if (!JITDataPointer(alloc, frame_ptr))
2197
0
    return false;
2198
2199
  // rsaAllocationGetType()
2200
0
  if (!JITTypePointer(alloc, frame_ptr))
2201
0
    return false;
2202
2203
  // rsaTypeGetNativeData()
2204
0
  if (!JITTypePacked(alloc, frame_ptr))
2205
0
    return false;
2206
2207
  // rsaElementGetNativeData()
2208
0
  if (!JITElementPacked(alloc->element, *alloc->context.get(), frame_ptr))
2209
0
    return false;
2210
2211
  // Sets the datum_size member in Element
2212
0
  SetElementSize(alloc->element);
2213
2214
  // Use GetOffsetPointer() to infer size of the allocation
2215
0
  return JITAllocationSize(alloc, frame_ptr);
2216
0
}
2217
2218
// Function attempts to set the type_name member of the parameterised Element
2219
// object. This string should be the name of the struct type the Element
2220
// represents. We need this string for pretty printing the Element to users.
2221
void RenderScriptRuntime::FindStructTypeName(Element &elem,
2222
0
                                             StackFrame *frame_ptr) {
2223
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2224
2225
0
  if (!elem.type_name.IsEmpty()) // Name already set
2226
0
    return;
2227
0
  else
2228
0
    elem.type_name = Element::GetFallbackStructName(); // Default type name if
2229
                                                       // we don't succeed
2230
2231
  // Find all the global variables from the script rs modules
2232
0
  VariableList var_list;
2233
0
  for (auto module_sp : m_rsmodules)
2234
0
    module_sp->m_module->FindGlobalVariables(
2235
0
        RegularExpression(llvm::StringRef(".")), UINT32_MAX, var_list);
2236
2237
  // Iterate over all the global variables looking for one with a matching type
2238
  // to the Element. We make the assumption a match exists since there needs to
2239
  // be a global variable to reflect the struct type back into java host code.
2240
0
  for (const VariableSP &var_sp : var_list) {
2241
0
    if (!var_sp)
2242
0
      continue;
2243
2244
0
    ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp);
2245
0
    if (!valobj_sp)
2246
0
      continue;
2247
2248
    // Find the number of variable fields.
2249
    // If it has no fields, or more fields than our Element, then it can't be
2250
    // the struct we're looking for. Don't check for equality since RS can add
2251
    // extra struct members for padding.
2252
0
    size_t num_children = valobj_sp->GetNumChildren();
2253
0
    if (num_children > elem.children.size() || num_children == 0)
2254
0
      continue;
2255
2256
    // Iterate over children looking for members with matching field names. If
2257
    // all the field names match, this is likely the struct we want.
2258
    //   TODO: This could be made more robust by also checking children data
2259
    //   sizes, or array size
2260
0
    bool found = true;
2261
0
    for (size_t i = 0; i < num_children; ++i) {
2262
0
      ValueObjectSP child = valobj_sp->GetChildAtIndex(i, true);
2263
0
      if (!child || (child->GetName() != elem.children[i].type_name)) {
2264
0
        found = false;
2265
0
        break;
2266
0
      }
2267
0
    }
2268
2269
    // RS can add extra struct members for padding in the format
2270
    // '#rs_padding_[0-9]+'
2271
0
    if (found && num_children < elem.children.size()) {
2272
0
      const uint32_t size_diff = elem.children.size() - num_children;
2273
0
      LLDB_LOGF(log, "%s - %" PRIu32 " padding struct entries", __FUNCTION__,
2274
0
                size_diff);
2275
2276
0
      for (uint32_t i = 0; i < size_diff; ++i) {
2277
0
        ConstString name = elem.children[num_children + i].type_name;
2278
0
        if (strcmp(name.AsCString(), "#rs_padding") < 0)
2279
0
          found = false;
2280
0
      }
2281
0
    }
2282
2283
    // We've found a global variable with matching type
2284
0
    if (found) {
2285
      // Dereference since our Element type isn't a pointer.
2286
0
      if (valobj_sp->IsPointerType()) {
2287
0
        Status err;
2288
0
        ValueObjectSP deref_valobj = valobj_sp->Dereference(err);
2289
0
        if (!err.Fail())
2290
0
          valobj_sp = deref_valobj;
2291
0
      }
2292
2293
      // Save name of variable in Element.
2294
0
      elem.type_name = valobj_sp->GetTypeName();
2295
0
      LLDB_LOGF(log, "%s - element name set to %s", __FUNCTION__,
2296
0
                elem.type_name.AsCString());
2297
2298
0
      return;
2299
0
    }
2300
0
  }
2301
0
}
2302
2303
// Function sets the datum_size member of Element. Representing the size of a
2304
// single instance including padding. Assumes the relevant allocation
2305
// information has already been jitted.
2306
0
void RenderScriptRuntime::SetElementSize(Element &elem) {
2307
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2308
0
  const Element::DataType type = *elem.type.get();
2309
0
  assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT &&
2310
0
         "Invalid allocation type");
2311
2312
0
  const uint32_t vec_size = *elem.type_vec_size.get();
2313
0
  uint32_t data_size = 0;
2314
0
  uint32_t padding = 0;
2315
2316
  // Element is of a struct type, calculate size recursively.
2317
0
  if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) {
2318
0
    for (Element &child : elem.children) {
2319
0
      SetElementSize(child);
2320
0
      const uint32_t array_size =
2321
0
          child.array_size.isValid() ? *child.array_size.get() : 1;
2322
0
      data_size += *child.datum_size.get() * array_size;
2323
0
    }
2324
0
  }
2325
  // These have been packed already
2326
0
  else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 ||
2327
0
           type == Element::RS_TYPE_UNSIGNED_5_5_5_1 ||
2328
0
           type == Element::RS_TYPE_UNSIGNED_4_4_4_4) {
2329
0
    data_size = AllocationDetails::RSTypeToFormat[type][eElementSize];
2330
0
  } else if (type < Element::RS_TYPE_ELEMENT) {
2331
0
    data_size =
2332
0
        vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize];
2333
0
    if (vec_size == 3)
2334
0
      padding = AllocationDetails::RSTypeToFormat[type][eElementSize];
2335
0
  } else
2336
0
    data_size =
2337
0
        GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
2338
2339
0
  elem.padding = padding;
2340
0
  elem.datum_size = data_size + padding;
2341
0
  LLDB_LOGF(log, "%s - element size set to %" PRIu32, __FUNCTION__,
2342
0
            data_size + padding);
2343
0
}
2344
2345
// Given an allocation, this function copies the allocation contents from
2346
// device into a buffer on the heap. Returning a shared pointer to the buffer
2347
// containing the data.
2348
std::shared_ptr<uint8_t>
2349
RenderScriptRuntime::GetAllocationData(AllocationDetails *alloc,
2350
0
                                       StackFrame *frame_ptr) {
2351
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2352
2353
  // JIT all the allocation details
2354
0
  if (alloc->ShouldRefresh()) {
2355
0
    LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info",
2356
0
              __FUNCTION__);
2357
2358
0
    if (!RefreshAllocation(alloc, frame_ptr)) {
2359
0
      LLDB_LOGF(log, "%s - couldn't JIT allocation details", __FUNCTION__);
2360
0
      return nullptr;
2361
0
    }
2362
0
  }
2363
2364
0
  assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
2365
0
         alloc->element.type_vec_size.isValid() && alloc->size.isValid() &&
2366
0
         "Allocation information not available");
2367
2368
  // Allocate a buffer to copy data into
2369
0
  const uint32_t size = *alloc->size.get();
2370
0
  std::shared_ptr<uint8_t> buffer(new uint8_t[size]);
2371
0
  if (!buffer) {
2372
0
    LLDB_LOGF(log, "%s - couldn't allocate a %" PRIu32 " byte buffer",
2373
0
              __FUNCTION__, size);
2374
0
    return nullptr;
2375
0
  }
2376
2377
  // Read the inferior memory
2378
0
  Status err;
2379
0
  lldb::addr_t data_ptr = *alloc->data_ptr.get();
2380
0
  GetProcess()->ReadMemory(data_ptr, buffer.get(), size, err);
2381
0
  if (err.Fail()) {
2382
0
    LLDB_LOGF(log,
2383
0
              "%s - '%s' Couldn't read %" PRIu32
2384
0
              " bytes of allocation data from 0x%" PRIx64,
2385
0
              __FUNCTION__, err.AsCString(), size, data_ptr);
2386
0
    return nullptr;
2387
0
  }
2388
2389
0
  return buffer;
2390
0
}
2391
2392
// Function copies data from a binary file into an allocation. There is a
2393
// header at the start of the file, FileHeader, before the data content itself.
2394
// Information from this header is used to display warnings to the user about
2395
// incompatibilities
2396
bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id,
2397
                                         const char *path,
2398
0
                                         StackFrame *frame_ptr) {
2399
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2400
2401
  // Find allocation with the given id
2402
0
  AllocationDetails *alloc = FindAllocByID(strm, alloc_id);
2403
0
  if (!alloc)
2404
0
    return false;
2405
2406
0
  LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64, __FUNCTION__,
2407
0
            *alloc->address.get());
2408
2409
  // JIT all the allocation details
2410
0
  if (alloc->ShouldRefresh()) {
2411
0
    LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.",
2412
0
              __FUNCTION__);
2413
2414
0
    if (!RefreshAllocation(alloc, frame_ptr)) {
2415
0
      LLDB_LOGF(log, "%s - couldn't JIT allocation details", __FUNCTION__);
2416
0
      return false;
2417
0
    }
2418
0
  }
2419
2420
0
  assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
2421
0
         alloc->element.type_vec_size.isValid() && alloc->size.isValid() &&
2422
0
         alloc->element.datum_size.isValid() &&
2423
0
         "Allocation information not available");
2424
2425
  // Check we can read from file
2426
0
  FileSpec file(path);
2427
0
  FileSystem::Instance().Resolve(file);
2428
0
  if (!FileSystem::Instance().Exists(file)) {
2429
0
    strm.Printf("Error: File %s does not exist", path);
2430
0
    strm.EOL();
2431
0
    return false;
2432
0
  }
2433
2434
0
  if (!FileSystem::Instance().Readable(file)) {
2435
0
    strm.Printf("Error: File %s does not have readable permissions", path);
2436
0
    strm.EOL();
2437
0
    return false;
2438
0
  }
2439
2440
  // Read file into data buffer
2441
0
  auto data_sp = FileSystem::Instance().CreateDataBuffer(file.GetPath());
2442
2443
  // Cast start of buffer to FileHeader and use pointer to read metadata
2444
0
  void *file_buf = data_sp->GetBytes();
2445
0
  if (file_buf == nullptr ||
2446
0
      data_sp->GetByteSize() < (sizeof(AllocationDetails::FileHeader) +
2447
0
                                sizeof(AllocationDetails::ElementHeader))) {
2448
0
    strm.Printf("Error: File %s does not contain enough data for header", path);
2449
0
    strm.EOL();
2450
0
    return false;
2451
0
  }
2452
0
  const AllocationDetails::FileHeader *file_header =
2453
0
      static_cast<AllocationDetails::FileHeader *>(file_buf);
2454
2455
  // Check file starts with ascii characters "RSAD"
2456
0
  if (memcmp(file_header->ident, "RSAD", 4)) {
2457
0
    strm.Printf("Error: File doesn't contain identifier for an RS allocation "
2458
0
                "dump. Are you sure this is the correct file?");
2459
0
    strm.EOL();
2460
0
    return false;
2461
0
  }
2462
2463
  // Look at the type of the root element in the header
2464
0
  AllocationDetails::ElementHeader root_el_hdr;
2465
0
  memcpy(&root_el_hdr, static_cast<uint8_t *>(file_buf) +
2466
0
                           sizeof(AllocationDetails::FileHeader),
2467
0
         sizeof(AllocationDetails::ElementHeader));
2468
2469
0
  LLDB_LOGF(log, "%s - header type %" PRIu32 ", element size %" PRIu32,
2470
0
            __FUNCTION__, root_el_hdr.type, root_el_hdr.element_size);
2471
2472
  // Check if the target allocation and file both have the same number of bytes
2473
  // for an Element
2474
0
  if (*alloc->element.datum_size.get() != root_el_hdr.element_size) {
2475
0
    strm.Printf("Warning: Mismatched Element sizes - file %" PRIu32
2476
0
                " bytes, allocation %" PRIu32 " bytes",
2477
0
                root_el_hdr.element_size, *alloc->element.datum_size.get());
2478
0
    strm.EOL();
2479
0
  }
2480
2481
  // Check if the target allocation and file both have the same type
2482
0
  const uint32_t alloc_type = static_cast<uint32_t>(*alloc->element.type.get());
2483
0
  const uint32_t file_type = root_el_hdr.type;
2484
2485
0
  if (file_type > Element::RS_TYPE_FONT) {
2486
0
    strm.Printf("Warning: File has unknown allocation type");
2487
0
    strm.EOL();
2488
0
  } else if (alloc_type != file_type) {
2489
    // Enum value isn't monotonous, so doesn't always index RsDataTypeToString
2490
    // array
2491
0
    uint32_t target_type_name_idx = alloc_type;
2492
0
    uint32_t head_type_name_idx = file_type;
2493
0
    if (alloc_type >= Element::RS_TYPE_ELEMENT &&
2494
0
        alloc_type <= Element::RS_TYPE_FONT)
2495
0
      target_type_name_idx = static_cast<Element::DataType>(
2496
0
          (alloc_type - Element::RS_TYPE_ELEMENT) +
2497
0
          Element::RS_TYPE_MATRIX_2X2 + 1);
2498
2499
0
    if (file_type >= Element::RS_TYPE_ELEMENT &&
2500
0
        file_type <= Element::RS_TYPE_FONT)
2501
0
      head_type_name_idx = static_cast<Element::DataType>(
2502
0
          (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 +
2503
0
          1);
2504
2505
0
    const char *head_type_name =
2506
0
        AllocationDetails::RsDataTypeToString[head_type_name_idx][0];
2507
0
    const char *target_type_name =
2508
0
        AllocationDetails::RsDataTypeToString[target_type_name_idx][0];
2509
2510
0
    strm.Printf(
2511
0
        "Warning: Mismatched Types - file '%s' type, allocation '%s' type",
2512
0
        head_type_name, target_type_name);
2513
0
    strm.EOL();
2514
0
  }
2515
2516
  // Advance buffer past header
2517
0
  file_buf = static_cast<uint8_t *>(file_buf) + file_header->hdr_size;
2518
2519
  // Calculate size of allocation data in file
2520
0
  size_t size = data_sp->GetByteSize() - file_header->hdr_size;
2521
2522
  // Check if the target allocation and file both have the same total data
2523
  // size.
2524
0
  const uint32_t alloc_size = *alloc->size.get();
2525
0
  if (alloc_size != size) {
2526
0
    strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64
2527
0
                " bytes, allocation 0x%" PRIx32 " bytes",
2528
0
                (uint64_t)size, alloc_size);
2529
0
    strm.EOL();
2530
    // Set length to copy to minimum
2531
0
    size = alloc_size < size ? alloc_size : size;
2532
0
  }
2533
2534
  // Copy file data from our buffer into the target allocation.
2535
0
  lldb::addr_t alloc_data = *alloc->data_ptr.get();
2536
0
  Status err;
2537
0
  size_t written = GetProcess()->WriteMemory(alloc_data, file_buf, size, err);
2538
0
  if (!err.Success() || written != size) {
2539
0
    strm.Printf("Error: Couldn't write data to allocation %s", err.AsCString());
2540
0
    strm.EOL();
2541
0
    return false;
2542
0
  }
2543
2544
0
  strm.Printf("Contents of file '%s' read into allocation %" PRIu32, path,
2545
0
              alloc->id);
2546
0
  strm.EOL();
2547
2548
0
  return true;
2549
0
}
2550
2551
// Function takes as parameters a byte buffer, which will eventually be written
2552
// to file as the element header, an offset into that buffer, and an Element
2553
// that will be saved into the buffer at the parametrised offset. Return value
2554
// is the new offset after writing the element into the buffer. Elements are
2555
// saved to the file as the ElementHeader struct followed by offsets to the
2556
// structs of all the element's children.
2557
size_t RenderScriptRuntime::PopulateElementHeaders(
2558
    const std::shared_ptr<uint8_t> header_buffer, size_t offset,
2559
0
    const Element &elem) {
2560
  // File struct for an element header with all the relevant details copied
2561
  // from elem. We assume members are valid already.
2562
0
  AllocationDetails::ElementHeader elem_header;
2563
0
  elem_header.type = *elem.type.get();
2564
0
  elem_header.kind = *elem.type_kind.get();
2565
0
  elem_header.element_size = *elem.datum_size.get();
2566
0
  elem_header.vector_size = *elem.type_vec_size.get();
2567
0
  elem_header.array_size =
2568
0
      elem.array_size.isValid() ? *elem.array_size.get() : 0;
2569
0
  const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader);
2570
2571
  // Copy struct into buffer and advance offset We assume that header_buffer
2572
  // has been checked for nullptr before this method is called
2573
0
  memcpy(header_buffer.get() + offset, &elem_header, elem_header_size);
2574
0
  offset += elem_header_size;
2575
2576
  // Starting offset of child ElementHeader struct
2577
0
  size_t child_offset =
2578
0
      offset + ((elem.children.size() + 1) * sizeof(uint32_t));
2579
0
  for (const RenderScriptRuntime::Element &child : elem.children) {
2580
    // Recursively populate the buffer with the element header structs of
2581
    // children. Then save the offsets where they were set after the parent
2582
    // element header.
2583
0
    memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t));
2584
0
    offset += sizeof(uint32_t);
2585
2586
0
    child_offset = PopulateElementHeaders(header_buffer, child_offset, child);
2587
0
  }
2588
2589
  // Zero indicates no more children
2590
0
  memset(header_buffer.get() + offset, 0, sizeof(uint32_t));
2591
2592
0
  return child_offset;
2593
0
}
2594
2595
// Given an Element object this function returns the total size needed in the
2596
// file header to store the element's details. Taking into account the size of
2597
// the element header struct, plus the offsets to all the element's children.
2598
// Function is recursive so that the size of all ancestors is taken into
2599
// account.
2600
0
size_t RenderScriptRuntime::CalculateElementHeaderSize(const Element &elem) {
2601
  // Offsets to children plus zero terminator
2602
0
  size_t size = (elem.children.size() + 1) * sizeof(uint32_t);
2603
  // Size of header struct with type details
2604
0
  size += sizeof(AllocationDetails::ElementHeader);
2605
2606
  // Calculate recursively for all descendants
2607
0
  for (const Element &child : elem.children)
2608
0
    size += CalculateElementHeaderSize(child);
2609
2610
0
  return size;
2611
0
}
2612
2613
// Function copies allocation contents into a binary file. This file can then
2614
// be loaded later into a different allocation. There is a header, FileHeader,
2615
// before the allocation data containing meta-data.
2616
bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id,
2617
                                         const char *path,
2618
0
                                         StackFrame *frame_ptr) {
2619
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2620
2621
  // Find allocation with the given id
2622
0
  AllocationDetails *alloc = FindAllocByID(strm, alloc_id);
2623
0
  if (!alloc)
2624
0
    return false;
2625
2626
0
  LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64 ".", __FUNCTION__,
2627
0
            *alloc->address.get());
2628
2629
  // JIT all the allocation details
2630
0
  if (alloc->ShouldRefresh()) {
2631
0
    LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.",
2632
0
              __FUNCTION__);
2633
2634
0
    if (!RefreshAllocation(alloc, frame_ptr)) {
2635
0
      LLDB_LOGF(log, "%s - couldn't JIT allocation details.", __FUNCTION__);
2636
0
      return false;
2637
0
    }
2638
0
  }
2639
2640
0
  assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() &&
2641
0
         alloc->element.type_vec_size.isValid() &&
2642
0
         alloc->element.datum_size.get() &&
2643
0
         alloc->element.type_kind.isValid() && alloc->dimension.isValid() &&
2644
0
         "Allocation information not available");
2645
2646
  // Check we can create writable file
2647
0
  FileSpec file_spec(path);
2648
0
  FileSystem::Instance().Resolve(file_spec);
2649
0
  auto file = FileSystem::Instance().Open(
2650
0
      file_spec, File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate |
2651
0
                     File::eOpenOptionTruncate);
2652
2653
0
  if (!file) {
2654
0
    std::string error = llvm::toString(file.takeError());
2655
0
    strm.Printf("Error: Failed to open '%s' for writing: %s", path,
2656
0
                error.c_str());
2657
0
    strm.EOL();
2658
0
    return false;
2659
0
  }
2660
2661
  // Read allocation into buffer of heap memory
2662
0
  const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
2663
0
  if (!buffer) {
2664
0
    strm.Printf("Error: Couldn't read allocation data into buffer");
2665
0
    strm.EOL();
2666
0
    return false;
2667
0
  }
2668
2669
  // Create the file header
2670
0
  AllocationDetails::FileHeader head;
2671
0
  memcpy(head.ident, "RSAD", 4);
2672
0
  head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1);
2673
0
  head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2);
2674
0
  head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3);
2675
2676
0
  const size_t element_header_size = CalculateElementHeaderSize(alloc->element);
2677
0
  assert((sizeof(AllocationDetails::FileHeader) + element_header_size) <
2678
0
             UINT16_MAX &&
2679
0
         "Element header too large");
2680
0
  head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) +
2681
0
                                        element_header_size);
2682
2683
  // Write the file header
2684
0
  size_t num_bytes = sizeof(AllocationDetails::FileHeader);
2685
0
  LLDB_LOGF(log, "%s - writing File Header, 0x%" PRIx64 " bytes", __FUNCTION__,
2686
0
            (uint64_t)num_bytes);
2687
2688
0
  Status err = file.get()->Write(&head, num_bytes);
2689
0
  if (!err.Success()) {
2690
0
    strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path);
2691
0
    strm.EOL();
2692
0
    return false;
2693
0
  }
2694
2695
  // Create the headers describing the element type of the allocation.
2696
0
  std::shared_ptr<uint8_t> element_header_buffer(
2697
0
      new uint8_t[element_header_size]);
2698
0
  if (element_header_buffer == nullptr) {
2699
0
    strm.Printf("Internal Error: Couldn't allocate %" PRIu64
2700
0
                " bytes on the heap",
2701
0
                (uint64_t)element_header_size);
2702
0
    strm.EOL();
2703
0
    return false;
2704
0
  }
2705
2706
0
  PopulateElementHeaders(element_header_buffer, 0, alloc->element);
2707
2708
  // Write headers for allocation element type to file
2709
0
  num_bytes = element_header_size;
2710
0
  LLDB_LOGF(log, "%s - writing element headers, 0x%" PRIx64 " bytes.",
2711
0
            __FUNCTION__, (uint64_t)num_bytes);
2712
2713
0
  err = file.get()->Write(element_header_buffer.get(), num_bytes);
2714
0
  if (!err.Success()) {
2715
0
    strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path);
2716
0
    strm.EOL();
2717
0
    return false;
2718
0
  }
2719
2720
  // Write allocation data to file
2721
0
  num_bytes = static_cast<size_t>(*alloc->size.get());
2722
0
  LLDB_LOGF(log, "%s - writing 0x%" PRIx64 " bytes", __FUNCTION__,
2723
0
            (uint64_t)num_bytes);
2724
2725
0
  err = file.get()->Write(buffer.get(), num_bytes);
2726
0
  if (!err.Success()) {
2727
0
    strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), path);
2728
0
    strm.EOL();
2729
0
    return false;
2730
0
  }
2731
2732
0
  strm.Printf("Allocation written to file '%s'", path);
2733
0
  strm.EOL();
2734
0
  return true;
2735
0
}
2736
2737
0
bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) {
2738
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2739
2740
0
  if (module_sp) {
2741
0
    for (const auto &rs_module : m_rsmodules) {
2742
0
      if (rs_module->m_module == module_sp) {
2743
        // Check if the user has enabled automatically breaking on all RS
2744
        // kernels.
2745
0
        if (m_breakAllKernels)
2746
0
          BreakOnModuleKernels(rs_module);
2747
2748
0
        return false;
2749
0
      }
2750
0
    }
2751
0
    bool module_loaded = false;
2752
0
    switch (GetModuleKind(module_sp)) {
2753
0
    case eModuleKindKernelObj: {
2754
0
      RSModuleDescriptorSP module_desc;
2755
0
      module_desc = std::make_shared<RSModuleDescriptor>(module_sp);
2756
0
      if (module_desc->ParseRSInfo()) {
2757
0
        m_rsmodules.push_back(module_desc);
2758
0
        module_desc->WarnIfVersionMismatch(GetProcess()
2759
0
                                               ->GetTarget()
2760
0
                                               .GetDebugger()
2761
0
                                               .GetAsyncOutputStream()
2762
0
                                               .get());
2763
0
        module_loaded = true;
2764
0
      }
2765
0
      if (module_loaded) {
2766
0
        FixupScriptDetails(module_desc);
2767
0
      }
2768
0
      break;
2769
0
    }
2770
0
    case eModuleKindDriver: {
2771
0
      if (!m_libRSDriver) {
2772
0
        m_libRSDriver = module_sp;
2773
0
        LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver);
2774
0
      }
2775
0
      break;
2776
0
    }
2777
0
    case eModuleKindImpl: {
2778
0
      if (!m_libRSCpuRef) {
2779
0
        m_libRSCpuRef = module_sp;
2780
0
        LoadRuntimeHooks(m_libRSCpuRef, RenderScriptRuntime::eModuleKindImpl);
2781
0
      }
2782
0
      break;
2783
0
    }
2784
0
    case eModuleKindLibRS: {
2785
0
      if (!m_libRS) {
2786
0
        m_libRS = module_sp;
2787
0
        static ConstString gDbgPresentStr("gDebuggerPresent");
2788
0
        const Symbol *debug_present = m_libRS->FindFirstSymbolWithNameAndType(
2789
0
            gDbgPresentStr, eSymbolTypeData);
2790
0
        if (debug_present) {
2791
0
          Status err;
2792
0
          uint32_t flag = 0x00000001U;
2793
0
          Target &target = GetProcess()->GetTarget();
2794
0
          addr_t addr = debug_present->GetLoadAddress(&target);
2795
0
          GetProcess()->WriteMemory(addr, &flag, sizeof(flag), err);
2796
0
          if (err.Success()) {
2797
0
            LLDB_LOGF(log, "%s - debugger present flag set on debugee.",
2798
0
                      __FUNCTION__);
2799
2800
0
            m_debuggerPresentFlagged = true;
2801
0
          } else if (log) {
2802
0
            LLDB_LOGF(log, "%s - error writing debugger present flags '%s' ",
2803
0
                      __FUNCTION__, err.AsCString());
2804
0
          }
2805
0
        } else if (log) {
2806
0
          LLDB_LOGF(
2807
0
              log,
2808
0
              "%s - error writing debugger present flags - symbol not found",
2809
0
              __FUNCTION__);
2810
0
        }
2811
0
      }
2812
0
      break;
2813
0
    }
2814
0
    default:
2815
0
      break;
2816
0
    }
2817
0
    if (module_loaded)
2818
0
      Update();
2819
0
    return module_loaded;
2820
0
  }
2821
0
  return false;
2822
0
}
2823
2824
0
void RenderScriptRuntime::Update() {
2825
0
  if (m_rsmodules.size() > 0) {
2826
0
    if (!m_initiated) {
2827
0
      Initiate();
2828
0
    }
2829
0
  }
2830
0
}
2831
2832
0
void RSModuleDescriptor::WarnIfVersionMismatch(lldb_private::Stream *s) const {
2833
0
  if (!s)
2834
0
    return;
2835
2836
0
  if (m_slang_version.empty() || m_bcc_version.empty()) {
2837
0
    s->PutCString("WARNING: Unknown bcc or slang (llvm-rs-cc) version; debug "
2838
0
                  "experience may be unreliable");
2839
0
    s->EOL();
2840
0
  } else if (m_slang_version != m_bcc_version) {
2841
0
    s->Printf("WARNING: The debug info emitted by the slang frontend "
2842
0
              "(llvm-rs-cc) used to build this module (%s) does not match the "
2843
0
              "version of bcc used to generate the debug information (%s). "
2844
0
              "This is an unsupported configuration and may result in a poor "
2845
0
              "debugging experience; proceed with caution",
2846
0
              m_slang_version.c_str(), m_bcc_version.c_str());
2847
0
    s->EOL();
2848
0
  }
2849
0
}
2850
2851
bool RSModuleDescriptor::ParsePragmaCount(llvm::StringRef *lines,
2852
0
                                          size_t n_lines) {
2853
  // Skip the pragma prototype line
2854
0
  ++lines;
2855
0
  for (; n_lines--; ++lines) {
2856
0
    const auto kv_pair = lines->split(" - ");
2857
0
    m_pragmas[kv_pair.first.trim().str()] = kv_pair.second.trim().str();
2858
0
  }
2859
0
  return true;
2860
0
}
2861
2862
bool RSModuleDescriptor::ParseExportReduceCount(llvm::StringRef *lines,
2863
0
                                                size_t n_lines) {
2864
  // The list of reduction kernels in the `.rs.info` symbol is of the form
2865
  // "signature - accumulatordatasize - reduction_name - initializer_name -
2866
  // accumulator_name - combiner_name - outconverter_name - halter_name" Where
2867
  // a function is not explicitly named by the user, or is not generated by the
2868
  // compiler, it is named "." so the dash separated list should always be 8
2869
  // items long
2870
0
  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
2871
  // Skip the exportReduceCount line
2872
0
  ++lines;
2873
0
  for (; n_lines--; ++lines) {
2874
0
    llvm::SmallVector<llvm::StringRef, 8> spec;
2875
0
    lines->split(spec, " - ");
2876
0
    if (spec.size() != 8) {
2877
0
      if (spec.size() < 8) {
2878
0
        if (log)
2879
0
          log->Error("Error parsing RenderScript reduction spec. wrong number "
2880
0
                     "of fields");
2881
0
        return false;
2882
0
      } else if (log)
2883
0
        log->Warning("Extraneous members in reduction spec: '%s'",
2884
0
                     lines->str().c_str());
2885
0
    }
2886
2887
0
    const auto sig_s = spec[0];
2888
0
    uint32_t sig;
2889
0
    if (sig_s.getAsInteger(10, sig)) {
2890
0
      if (log)
2891
0
        log->Error("Error parsing Renderscript reduction spec: invalid kernel "
2892
0
                   "signature: '%s'",
2893
0
                   sig_s.str().c_str());
2894
0
      return false;
2895
0
    }
2896
2897
0
    const auto accum_data_size_s = spec[1];
2898
0
    uint32_t accum_data_size;
2899
0
    if (accum_data_size_s.getAsInteger(10, accum_data_size)) {
2900
0
      if (log)
2901
0
        log->Error("Error parsing Renderscript reduction spec: invalid "
2902
0
                   "accumulator data size %s",
2903
0
                   accum_data_size_s.str().c_str());
2904
0
      return false;
2905
0
    }
2906
2907
0
    LLDB_LOGF(log, "Found RenderScript reduction '%s'", spec[2].str().c_str());
2908
2909
0
    m_reductions.push_back(RSReductionDescriptor(this, sig, accum_data_size,
2910
0
                                                 spec[2], spec[3], spec[4],
2911
0
                                                 spec[5], spec[6], spec[7]));
2912
0
  }
2913
0
  return true;
2914
0
}
2915
2916
bool RSModuleDescriptor::ParseVersionInfo(llvm::StringRef *lines,
2917
0
                                          size_t n_lines) {
2918
  // Skip the versionInfo line
2919
0
  ++lines;
2920
0
  for (; n_lines--; ++lines) {
2921
    // We're only interested in bcc and slang versions, and ignore all other
2922
    // versionInfo lines
2923
0
    const auto kv_pair = lines->split(" - ");
2924
0
    if (kv_pair.first == "slang")
2925
0
      m_slang_version = kv_pair.second.str();
2926
0
    else if (kv_pair.first == "bcc")
2927
0
      m_bcc_version = kv_pair.second.str();
2928
0
  }
2929
0
  return true;
2930
0
}
2931
2932
bool RSModuleDescriptor::ParseExportForeachCount(llvm::StringRef *lines,
2933
0
                                                 size_t n_lines) {
2934
  // Skip the exportForeachCount line
2935
0
  ++lines;
2936
0
  for (; n_lines--; ++lines) {
2937
0
    uint32_t slot;
2938
    // `forEach` kernels are listed in the `.rs.info` packet as a "slot - name"
2939
    // pair per line
2940
0
    const auto kv_pair = lines->split(" - ");
2941
0
    if (kv_pair.first.getAsInteger(10, slot))
2942
0
      return false;
2943
0
    m_kernels.push_back(RSKernelDescriptor(this, kv_pair.second, slot));
2944
0
  }
2945
0
  return true;
2946
0
}
2947
2948
bool RSModuleDescriptor::ParseExportVarCount(llvm::StringRef *lines,
2949
0
                                             size_t n_lines) {
2950
  // Skip the ExportVarCount line
2951
0
  ++lines;
2952
0
  for (; n_lines--; ++lines)
2953
0
    m_globals.push_back(RSGlobalDescriptor(this, *lines));
2954
0
  return true;
2955
0
}
2956
2957
// The .rs.info symbol in renderscript modules contains a string which needs to
2958
// be parsed. The string is basic and is parsed on a line by line basis.
2959
0
bool RSModuleDescriptor::ParseRSInfo() {
2960
0
  assert(m_module);
2961
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
2962
0
  const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType(
2963
0
      ConstString(".rs.info"), eSymbolTypeData);
2964
0
  if (!info_sym)
2965
0
    return false;
2966
2967
0
  const addr_t addr = info_sym->GetAddressRef().GetFileAddress();
2968
0
  if (addr == LLDB_INVALID_ADDRESS)
2969
0
    return false;
2970
2971
0
  const addr_t size = info_sym->GetByteSize();
2972
0
  const FileSpec fs = m_module->GetFileSpec();
2973
2974
0
  auto buffer =
2975
0
      FileSystem::Instance().CreateDataBuffer(fs.GetPath(), size, addr);
2976
0
  if (!buffer)
2977
0
    return false;
2978
2979
  // split rs.info. contents into lines
2980
0
  llvm::SmallVector<llvm::StringRef, 128> info_lines;
2981
0
  {
2982
0
    const llvm::StringRef raw_rs_info((const char *)buffer->GetBytes());
2983
0
    raw_rs_info.split(info_lines, '\n');
2984
0
    LLDB_LOGF(log, "'.rs.info symbol for '%s':\n%s",
2985
0
              m_module->GetFileSpec().GetCString(), raw_rs_info.str().c_str());
2986
0
  }
2987
2988
0
  enum {
2989
0
    eExportVar,
2990
0
    eExportForEach,
2991
0
    eExportReduce,
2992
0
    ePragma,
2993
0
    eBuildChecksum,
2994
0
    eObjectSlot,
2995
0
    eVersionInfo,
2996
0
  };
2997
2998
0
  const auto rs_info_handler = [](llvm::StringRef name) -> int {
2999
0
    return llvm::StringSwitch<int>(name)
3000
        // The number of visible global variables in the script
3001
0
        .Case("exportVarCount", eExportVar)
3002
        // The number of RenderScrip `forEach` kernels __attribute__((kernel))
3003
0
        .Case("exportForEachCount", eExportForEach)
3004
        // The number of generalreductions: This marked in the script by
3005
        // `#pragma reduce()`
3006
0
        .Case("exportReduceCount", eExportReduce)
3007
        // Total count of all RenderScript specific `#pragmas` used in the
3008
        // script
3009
0
        .Case("pragmaCount", ePragma)
3010
0
        .Case("objectSlotCount", eObjectSlot)
3011
0
        .Case("versionInfo", eVersionInfo)
3012
0
        .Default(-1);
3013
0
  };
3014
3015
  // parse all text lines of .rs.info
3016
0
  for (auto line = info_lines.begin(); line != info_lines.end(); ++line) {
3017
0
    const auto kv_pair = line->split(": ");
3018
0
    const auto key = kv_pair.first;
3019
0
    const auto val = kv_pair.second.trim();
3020
3021
0
    const auto handler = rs_info_handler(key);
3022
0
    if (handler == -1)
3023
0
      continue;
3024
    // getAsInteger returns `true` on an error condition - we're only
3025
    // interested in numeric fields at the moment
3026
0
    uint64_t n_lines;
3027
0
    if (val.getAsInteger(10, n_lines)) {
3028
0
      LLDB_LOGV(log, "Failed to parse non-numeric '.rs.info' section {0}",
3029
0
                line->str());
3030
0
      continue;
3031
0
    }
3032
0
    if (info_lines.end() - (line + 1) < (ptrdiff_t)n_lines)
3033
0
      return false;
3034
3035
0
    bool success = false;
3036
0
    switch (handler) {
3037
0
    case eExportVar:
3038
0
      success = ParseExportVarCount(line, n_lines);
3039
0
      break;
3040
0
    case eExportForEach:
3041
0
      success = ParseExportForeachCount(line, n_lines);
3042
0
      break;
3043
0
    case eExportReduce:
3044
0
      success = ParseExportReduceCount(line, n_lines);
3045
0
      break;
3046
0
    case ePragma:
3047
0
      success = ParsePragmaCount(line, n_lines);
3048
0
      break;
3049
0
    case eVersionInfo:
3050
0
      success = ParseVersionInfo(line, n_lines);
3051
0
      break;
3052
0
    default: {
3053
0
      LLDB_LOGF(log, "%s - skipping .rs.info field '%s'", __FUNCTION__,
3054
0
                line->str().c_str());
3055
0
      continue;
3056
0
    }
3057
0
    }
3058
0
    if (!success)
3059
0
      return false;
3060
0
    line += n_lines;
3061
0
  }
3062
0
  return info_lines.size() > 0;
3063
0
}
3064
3065
0
void RenderScriptRuntime::DumpStatus(Stream &strm) const {
3066
0
  if (m_libRS) {
3067
0
    strm.Printf("Runtime Library discovered.");
3068
0
    strm.EOL();
3069
0
  }
3070
0
  if (m_libRSDriver) {
3071
0
    strm.Printf("Runtime Driver discovered.");
3072
0
    strm.EOL();
3073
0
  }
3074
0
  if (m_libRSCpuRef) {
3075
0
    strm.Printf("CPU Reference Implementation discovered.");
3076
0
    strm.EOL();
3077
0
  }
3078
3079
0
  if (m_runtimeHooks.size()) {
3080
0
    strm.Printf("Runtime functions hooked:");
3081
0
    strm.EOL();
3082
0
    for (auto b : m_runtimeHooks) {
3083
0
      strm.Indent(b.second->defn->name);
3084
0
      strm.EOL();
3085
0
    }
3086
0
  } else {
3087
0
    strm.Printf("Runtime is not hooked.");
3088
0
    strm.EOL();
3089
0
  }
3090
0
}
3091
3092
0
void RenderScriptRuntime::DumpContexts(Stream &strm) const {
3093
0
  strm.Printf("Inferred RenderScript Contexts:");
3094
0
  strm.EOL();
3095
0
  strm.IndentMore();
3096
3097
0
  std::map<addr_t, uint64_t> contextReferences;
3098
3099
  // Iterate over all of the currently discovered scripts. Note: We cant push
3100
  // or pop from m_scripts inside this loop or it may invalidate script.
3101
0
  for (const auto &script : m_scripts) {
3102
0
    if (!script->context.isValid())
3103
0
      continue;
3104
0
    lldb::addr_t context = *script->context;
3105
3106
0
    if (contextReferences.find(context) != contextReferences.end()) {
3107
0
      contextReferences[context]++;
3108
0
    } else {
3109
0
      contextReferences[context] = 1;
3110
0
    }
3111
0
  }
3112
3113
0
  for (const auto &cRef : contextReferences) {
3114
0
    strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances",
3115
0
                cRef.first, cRef.second);
3116
0
    strm.EOL();
3117
0
  }
3118
0
  strm.IndentLess();
3119
0
}
3120
3121
0
void RenderScriptRuntime::DumpKernels(Stream &strm) const {
3122
0
  strm.Printf("RenderScript Kernels:");
3123
0
  strm.EOL();
3124
0
  strm.IndentMore();
3125
0
  for (const auto &module : m_rsmodules) {
3126
0
    strm.Printf("Resource '%s':", module->m_resname.c_str());
3127
0
    strm.EOL();
3128
0
    for (const auto &kernel : module->m_kernels) {
3129
0
      strm.Indent(kernel.m_name.GetStringRef());
3130
0
      strm.EOL();
3131
0
    }
3132
0
  }
3133
0
  strm.IndentLess();
3134
0
}
3135
3136
RenderScriptRuntime::AllocationDetails *
3137
0
RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) {
3138
0
  AllocationDetails *alloc = nullptr;
3139
3140
  // See if we can find allocation using id as an index;
3141
0
  if (alloc_id <= m_allocations.size() && alloc_id != 0 &&
3142
0
      m_allocations[alloc_id - 1]->id == alloc_id) {
3143
0
    alloc = m_allocations[alloc_id - 1].get();
3144
0
    return alloc;
3145
0
  }
3146
3147
  // Fallback to searching
3148
0
  for (const auto &a : m_allocations) {
3149
0
    if (a->id == alloc_id) {
3150
0
      alloc = a.get();
3151
0
      break;
3152
0
    }
3153
0
  }
3154
3155
0
  if (alloc == nullptr) {
3156
0
    strm.Printf("Error: Couldn't find allocation with id matching %" PRIu32,
3157
0
                alloc_id);
3158
0
    strm.EOL();
3159
0
  }
3160
3161
0
  return alloc;
3162
0
}
3163
3164
// Prints the contents of an allocation to the output stream, which may be a
3165
// file
3166
bool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr,
3167
0
                                         const uint32_t id) {
3168
0
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
3169
3170
  // Check we can find the desired allocation
3171
0
  AllocationDetails *alloc = FindAllocByID(strm, id);
3172
0
  if (!alloc)
3173
0
    return false; // FindAllocByID() will print error message for us here
3174
3175
0
  LLDB_LOGF(log, "%s - found allocation 0x%" PRIx64, __FUNCTION__,
3176
0
            *alloc->address.get());
3177
3178
  // Check we have information about the allocation, if not calculate it
3179
0
  if (alloc->ShouldRefresh()) {
3180
0
    LLDB_LOGF(log, "%s - allocation details not calculated yet, jitting info.",
3181
0
              __FUNCTION__);
3182
3183
    // JIT all the allocation information
3184
0
    if (!RefreshAllocation(alloc, frame_ptr)) {
3185
0
      strm.Printf("Error: Couldn't JIT allocation details");
3186
0
      strm.EOL();
3187
0
      return false;
3188
0
    }
3189
0
  }
3190
3191
  // Establish format and size of each data element
3192
0
  const uint32_t vec_size = *alloc->element.type_vec_size.get();
3193
0
  const Element::DataType type = *alloc->element.type.get();
3194
3195
0
  assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT &&
3196
0
         "Invalid allocation type");
3197
3198
0
  lldb::Format format;
3199
0
  if (type >= Element::RS_TYPE_ELEMENT)
3200
0
    format = eFormatHex;
3201
0
  else
3202
0
    format = vec_size == 1
3203
0
                 ? static_cast<lldb::Format>(
3204
0
                       AllocationDetails::RSTypeToFormat[type][eFormatSingle])
3205
0
                 : static_cast<lldb::Format>(
3206
0
                       AllocationDetails::RSTypeToFormat[type][eFormatVector]);
3207
3208
0
  const uint32_t data_size = *alloc->element.datum_size.get();
3209
3210
0
  LLDB_LOGF(log, "%s - element size %" PRIu32 " bytes, including padding",
3211
0
            __FUNCTION__, data_size);
3212
3213
  // Allocate a buffer to copy data into
3214
0
  std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr);
3215
0
  if (!buffer) {
3216
0
    strm.Printf("Error: Couldn't read allocation data");
3217
0
    strm.EOL();
3218
0
    return false;
3219
0
  }
3220
3221
  // Calculate stride between rows as there may be padding at end of rows since
3222
  // allocated memory is 16-byte aligned
3223
0
  if (!alloc->stride.isValid()) {
3224
0
    if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension
3225
0
      alloc->stride = 0;
3226
0
    else if (!JITAllocationStride(alloc, frame_ptr)) {
3227
0
      strm.Printf("Error: Couldn't calculate allocation row stride");
3228
0
      strm.EOL();
3229
0
      return false;
3230
0
    }
3231
0
  }
3232
0
  const uint32_t stride = *alloc->stride.get();
3233
0
  const uint32_t size = *alloc->size.get(); // Size of whole allocation
3234
0
  const uint32_t padding =
3235
0
      alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0;
3236
0
  LLDB_LOGF(log,
3237
0
            "%s - stride %" PRIu32 " bytes, size %" PRIu32
3238
0
            " bytes, padding %" PRIu32,
3239
0
            __FUNCTION__, stride, size, padding);
3240
3241
  // Find dimensions used to index loops, so need to be non-zero
3242
0
  uint32_t dim_x = alloc->dimension.get()->dim_1;
3243
0
  dim_x = dim_x == 0 ? 1 : dim_x;
3244
3245
0
  uint32_t dim_y = alloc->dimension.get()->dim_2;
3246
0
  dim_y = dim_y == 0 ? 1 : dim_y;
3247
3248
0
  uint32_t dim_z = alloc->dimension.get()->dim_3;
3249
0
  dim_z = dim_z == 0 ? 1 : dim_z;
3250
3251
  // Use data extractor to format output
3252
0
  const uint32_t target_ptr_size =
3253
0
      GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize();
3254
0
  DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(),
3255
0
                           target_ptr_size);
3256
3257
0
  uint32_t offset = 0;   // Offset in buffer to next element to be printed
3258
0
  uint32_t prev_row = 0; // Offset to the start of the previous row
3259
3260
  // Iterate over allocation dimensions, printing results to user
3261
0
  strm.Printf("Data (X, Y, Z):");
3262
0
  for (uint32_t z = 0; z < dim_z; ++z) {
3263
0
    for (uint32_t y = 0; y < dim_y; ++y) {
3264
      // Use stride to index start of next row.
3265
0
      if (!(y == 0 && z == 0))
3266
0
        offset = prev_row + stride;
3267
0
      prev_row = offset;
3268
3269
      // Print each element in the row individually
3270
0
      for (uint32_t x = 0; x < dim_x; ++x) {
3271
0
        strm.Printf("\n(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") = ", x, y, z);
3272
0
        if ((type == Element::RS_TYPE_NONE) &&
3273
0
            (alloc->element.children.size() > 0) &&
3274
0
            (alloc->element.type_name != Element::GetFallbackStructName())) {
3275
          // Here we are dumping an Element of struct type. This is done using
3276
          // expression evaluation with the name of the struct type and pointer
3277
          // to element. Don't print the name of the resulting expression,
3278
          // since this will be '$[0-9]+'
3279
0
          DumpValueObjectOptions expr_options;
3280
0
          expr_options.SetHideName(true);
3281
3282
          // Setup expression as dereferencing a pointer cast to element
3283
          // address.
3284
0
          char expr_char_buffer[jit_max_expr_size];
3285
0
          int written =
3286
0
              snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64,
3287
0
                       alloc->element.type_name.AsCString(),
3288
0
                       *alloc->data_ptr.get() + offset);
3289
3290
0
          if (written < 0 || written >= jit_max_expr_size) {
3291
0
            LLDB_LOGF(log, "%s - error in snprintf().", __FUNCTION__);
3292
0
            continue;
3293
0
          }
3294
3295
          // Evaluate expression
3296
0
          ValueObjectSP expr_result;
3297
0
          GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer,
3298
0
                                                       frame_ptr, expr_result);
3299
3300
          // Print the results to our stream.
3301
0
          expr_result->Dump(strm, expr_options);
3302
0
        } else {
3303
0
          DumpDataExtractor(alloc_data, &strm, offset, format,
3304
0
                            data_size - padding, 1, 1, LLDB_INVALID_ADDRESS, 0,
3305
0
                            0);
3306
0
        }
3307
0
        offset += data_size;
3308
0
      }
3309
0
    }
3310
0
  }
3311
0
  strm.EOL();
3312
3313
0
  return true;
3314
0
}
3315
3316
// Function recalculates all our cached information about allocations by
3317
// jitting the RS runtime regarding each allocation we know about. Returns true
3318
// if all allocations could be recomputed, false otherwise.
3319
bool RenderScriptRuntime::RecomputeAllAllocations(Stream &strm,
3320
0
                                                  StackFrame *frame_ptr) {
3321
0
  bool success = true;
3322
0
  for (auto &alloc : m_allocations) {
3323
    // JIT current allocation information
3324
0
    if (!RefreshAllocation(alloc.get(), frame_ptr)) {
3325
0
      strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32
3326
0
                  "\n",
3327
0
                  alloc->id);
3328
0
      success = false;
3329
0
    }
3330
0
  }
3331
3332
0
  if (success)
3333
0
    strm.Printf("All allocations successfully recomputed");
3334
0
  strm.EOL();
3335
3336
0
  return success;
3337
0
}
3338
3339
// Prints information regarding currently loaded allocations. These details are
3340
// gathered by jitting the runtime, which has as latency. Index parameter
3341
// specifies a single allocation ID to print, or a zero value to print them all
3342
void RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame *frame_ptr,
3343
0
                                          const uint32_t index) {
3344
0
  strm.Printf("RenderScript Allocations:");
3345
0
  strm.EOL();
3346
0
  strm.IndentMore();
3347
3348
0
  for (auto &alloc : m_allocations) {
3349
    // index will only be zero if we want to print all allocations
3350
0
    if (index != 0 && index != alloc->id)
3351
0
      continue;
3352
3353
    // JIT current allocation information
3354
0
    if (alloc->ShouldRefresh() && !RefreshAllocation(alloc.get(), frame_ptr)) {
3355
0
      strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32,
3356
0
                  alloc->id);
3357
0
      strm.EOL();
3358
0
      continue;
3359
0
    }
3360
3361
0
    strm.Printf("%" PRIu32 ":", alloc->id);
3362
0
    strm.EOL();
3363
0
    strm.IndentMore();
3364
3365
0
    strm.Indent("Context: ");
3366
0
    if (!alloc->context.isValid())
3367
0
      strm.Printf("unknown\n");
3368
0
    else
3369
0
      strm.Printf("0x%" PRIx64 "\n", *alloc->context.get());
3370
3371
0
    strm.Indent("Address: ");
3372
0
    if (!alloc->address.isValid())
3373
0
      strm.Printf("unknown\n");
3374
0
    else
3375
0
      strm.Printf("0x%" PRIx64 "\n", *alloc->address.get());
3376
3377
0
    strm.Indent("Data pointer: ");
3378
0
    if (!alloc->data_ptr.isValid())
3379
0
      strm.Printf("unknown\n");
3380
0
    else
3381
0
      strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get());
3382
3383
0
    strm.Indent("Dimensions: ");
3384
0
    if (!alloc->dimension.isValid())
3385
0
      strm.Printf("unknown\n");
3386
0
    else
3387
0
      strm.Printf("(%" PRId32 ", %" PRId32 ", %" PRId32 ")\n",
3388
0
                  alloc->dimension.get()->dim_1, alloc->dimension.get()->dim_2,
3389
0
                  alloc->dimension.get()->dim_3);
3390
3391
0
    strm.Indent("Data Type: ");
3392
0
    if (!alloc->element.type.isValid() ||
3393
0
        !alloc->element.type_vec_size.isValid())
3394
0
      strm.Printf("unknown\n");
3395
0
    else {
3396
0
      const int vector_size = *alloc->element.type_vec_size.get();
3397
0
      Element::DataType type = *alloc->element.type.get();
3398
3399
0
      if (!alloc->element.type_name.IsEmpty())
3400
0
        strm.Printf("%s\n", alloc->element.type_name.AsCString());
3401
0
      else {
3402
        // Enum value isn't monotonous, so doesn't always index
3403
        // RsDataTypeToString array
3404
0
        if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT)
3405
0
          type =
3406
0
              static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) +
3407
0
                                             Element::RS_TYPE_MATRIX_2X2 + 1);
3408
3409
0
        if (type >= (sizeof(AllocationDetails::RsDataTypeToString) /
3410
0
                     sizeof(AllocationDetails::RsDataTypeToString[0])) ||
3411
0
            vector_size > 4 || vector_size < 1)
3412
0
          strm.Printf("invalid type\n");
3413
0
        else
3414
0
          strm.Printf(
3415
0
              "%s\n",
3416
0
              AllocationDetails::RsDataTypeToString[static_cast<uint32_t>(type)]
3417
0
                                                   [vector_size - 1]);
3418
0
      }
3419
0
    }
3420
3421
0
    strm.Indent("Data Kind: ");
3422
0
    if (!alloc->element.type_kind.isValid())
3423
0
      strm.Printf("unknown\n");
3424
0
    else {
3425
0
      const Element::DataKind kind = *alloc->element.type_kind.get();
3426
0
      if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV)
3427
0
        strm.Printf("invalid kind\n");
3428
0
      else
3429
0
        strm.Printf(
3430
0
            "%s\n",
3431
0
            AllocationDetails::RsDataKindToString[static_cast<uint32_t>(kind)]);
3432
0
    }
3433
3434
0
    strm.EOL();
3435
0
    strm.IndentLess();
3436
0
  }
3437
0
  strm.IndentLess();
3438
0
}
3439
3440
// Set breakpoints on every kernel found in RS module
3441
void RenderScriptRuntime::BreakOnModuleKernels(
3442
0
    const RSModuleDescriptorSP rsmodule_sp) {
3443
0
  for (const auto &kernel : rsmodule_sp->m_kernels) {
3444
    // Don't set breakpoint on 'root' kernel
3445
0
    if (strcmp(kernel.m_name.AsCString(), "root") == 0)
3446
0
      continue;
3447
3448
0
    CreateKernelBreakpoint(kernel.m_name);
3449
0
  }
3450
0
}
3451
3452
// Method is internally called by the 'kernel breakpoint all' command to enable
3453
// or disable breaking on all kernels. When do_break is true we want to enable
3454
// this functionality. When do_break is false we want to disable it.
3455
0
void RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) {
3456
0
  Log *log(
3457
0
      GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
3458
3459
0
  InitSearchFilter(target);
3460
3461
  // Set breakpoints on all the kernels
3462
0
  if (do_break && !m_breakAllKernels) {
3463
0
    m_breakAllKernels = true;
3464
3465
0
    for (const auto &module : m_rsmodules)
3466
0
      BreakOnModuleKernels(module);
3467
3468
0
    LLDB_LOGF(log,
3469
0
              "%s(True) - breakpoints set on all currently loaded kernels.",
3470
0
              __FUNCTION__);
3471
0
  } else if (!do_break &&
3472
0
             m_breakAllKernels) // Breakpoints won't be set on any new kernels.
3473
0
  {
3474
0
    m_breakAllKernels = false;
3475
3476
0
    LLDB_LOGF(log, "%s(False) - breakpoints no longer automatically set.",
3477
0
              __FUNCTION__);
3478
0
  }
3479
0
}
3480
3481
// Given the name of a kernel this function creates a breakpoint using our own
3482
// breakpoint resolver, and returns the Breakpoint shared pointer.
3483
BreakpointSP
3484
0
RenderScriptRuntime::CreateKernelBreakpoint(ConstString name) {
3485
0
  Log *log(
3486
0
      GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
3487
3488
0
  if (!m_filtersp) {
3489
0
    LLDB_LOGF(log, "%s - error, no breakpoint search filter set.",
3490
0
              __FUNCTION__);
3491
0
    return nullptr;
3492
0
  }
3493
3494
0
  BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name));
3495
0
  Target &target = GetProcess()->GetTarget();
3496
0
  BreakpointSP bp = target.CreateBreakpoint(
3497
0
      m_filtersp, resolver_sp, false, false, false);
3498
3499
  // Give RS breakpoints a specific name, so the user can manipulate them as a
3500
  // group.
3501
0
  Status err;
3502
0
  target.AddNameToBreakpoint(bp, "RenderScriptKernel", err);
3503
0
  if (err.Fail() && log)
3504
0
    LLDB_LOGF(log, "%s - error setting break name, '%s'.", __FUNCTION__,
3505
0
              err.AsCString());
3506
3507
0
  return bp;
3508
0
}
3509
3510
BreakpointSP
3511
RenderScriptRuntime::CreateReductionBreakpoint(ConstString name,
3512
0
                                               int kernel_types) {
3513
0
  Log *log(
3514
0
      GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
3515
3516
0
  if (!m_filtersp) {
3517
0
    LLDB_LOGF(log, "%s - error, no breakpoint search filter set.",
3518
0
              __FUNCTION__);
3519
0
    return nullptr;
3520
0
  }
3521
3522
0
  BreakpointResolverSP resolver_sp(new RSReduceBreakpointResolver(
3523
0
      nullptr, name, &m_rsmodules, kernel_types));
3524
0
  Target &target = GetProcess()->GetTarget();
3525
0
  BreakpointSP bp = target.CreateBreakpoint(
3526
0
      m_filtersp, resolver_sp, false, false, false);
3527
3528
  // Give RS breakpoints a specific name, so the user can manipulate them as a
3529
  // group.
3530
0
  Status err;
3531
0
  target.AddNameToBreakpoint(bp, "RenderScriptReduction", err);
3532
0
  if (err.Fail() && log)
3533
0
    LLDB_LOGF(log, "%s - error setting break name, '%s'.", __FUNCTION__,
3534
0
              err.AsCString());
3535
3536
0
  return bp;
3537
0
}
3538
3539
// Given an expression for a variable this function tries to calculate the
3540
// variable's value. If this is possible it returns true and sets the uint64_t
3541
// parameter to the variables unsigned value. Otherwise function returns false.
3542
bool RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp,
3543
                                                const char *var_name,
3544
0
                                                uint64_t &val) {
3545
0
  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE));
3546
0
  Status err;
3547
0
  VariableSP var_sp;
3548
3549
  // Find variable in stack frame
3550
0
  ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath(
3551
0
      var_name, eNoDynamicValues,
3552
0
      StackFrame::eExpressionPathOptionCheckPtrVsMember |
3553
0
          StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
3554
0
      var_sp, err));
3555
0
  if (!err.Success()) {
3556
0
    LLDB_LOGF(log, "%s - error, couldn't find '%s' in frame", __FUNCTION__,
3557
0
              var_name);
3558
0
    return false;
3559
0
  }
3560
3561
  // Find the uint32_t value for the variable
3562
0
  bool success = false;
3563
0
  val = value_sp->GetValueAsUnsigned(0, &success);
3564
0
  if (!success) {
3565
0
    LLDB_LOGF(log, "%s - error, couldn't parse '%s' as an uint32_t.",
3566
0
              __FUNCTION__, var_name);
3567
0
    return false;
3568
0
  }
3569
3570
0
  return true;
3571
0
}
3572
3573
// Function attempts to find the current coordinate of a kernel invocation by
3574
// investigating the values of frame variables in the .expand function. These
3575
// coordinates are returned via the coord array reference parameter. Returns
3576
// true if the coordinates could be found, and false otherwise.
3577
bool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord,
3578
0
                                              Thread *thread_ptr) {
3579
0
  static const char *const x_expr = "rsIndex";
3580
0
  static const char *const y_expr = "p->current.y";
3581
0
  static const char *const z_expr = "p->current.z";
3582
3583
0
  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE));
3584
3585
0
  if (!thread_ptr) {
3586
0
    LLDB_LOGF(log, "%s - Error, No thread pointer", __FUNCTION__);
3587
3588
0
    return false;
3589
0
  }
3590
3591
  // Walk the call stack looking for a function whose name has the suffix
3592
  // '.expand' and contains the variables we're looking for.
3593
0
  for (uint32_t i = 0; i < thread_ptr->GetStackFrameCount(); ++i) {
3594
0
    if (!thread_ptr->SetSelectedFrameByIndex(i))
3595
0
      continue;
3596
3597
0
    StackFrameSP frame_sp = thread_ptr->GetSelectedFrame();
3598
0
    if (!frame_sp)
3599
0
      continue;
3600
3601
    // Find the function name
3602
0
    const SymbolContext sym_ctx =
3603
0
        frame_sp->GetSymbolContext(eSymbolContextFunction);
3604
0
    const ConstString func_name = sym_ctx.GetFunctionName();
3605
0
    if (!func_name)
3606
0
      continue;
3607
3608
0
    LLDB_LOGF(log, "%s - Inspecting function '%s'", __FUNCTION__,
3609
0
              func_name.GetCString());
3610
3611
    // Check if function name has .expand suffix
3612
0
    if (!func_name.GetStringRef().endswith(".expand"))
3613
0
      continue;
3614
3615
0
    LLDB_LOGF(log, "%s - Found .expand function '%s'", __FUNCTION__,
3616
0
              func_name.GetCString());
3617
3618
    // Get values for variables in .expand frame that tell us the current
3619
    // kernel invocation
3620
0
    uint64_t x, y, z;
3621
0
    bool found = GetFrameVarAsUnsigned(frame_sp, x_expr, x) &&
3622
0
                 GetFrameVarAsUnsigned(frame_sp, y_expr, y) &&
3623
0
                 GetFrameVarAsUnsigned(frame_sp, z_expr, z);
3624
3625
0
    if (found) {
3626
      // The RenderScript runtime uses uint32_t for these vars. If they're not
3627
      // within bounds, our frame parsing is garbage
3628
0
      assert(x <= UINT32_MAX && y <= UINT32_MAX && z <= UINT32_MAX);
3629
0
      coord.x = (uint32_t)x;
3630
0
      coord.y = (uint32_t)y;
3631
0
      coord.z = (uint32_t)z;
3632
0
      return true;
3633
0
    }
3634
0
  }
3635
0
  return false;
3636
0
}
3637
3638
// Callback when a kernel breakpoint hits and we're looking for a specific
3639
// coordinate. Baton parameter contains a pointer to the target coordinate we
3640
// want to break on. Function then checks the .expand frame for the current
3641
// coordinate and breaks to user if it matches. Parameter 'break_id' is the id
3642
// of the Breakpoint which made the callback. Parameter 'break_loc_id' is the
3643
// id for the BreakpointLocation which was hit, a single logical breakpoint can
3644
// have multiple addresses.
3645
bool RenderScriptRuntime::KernelBreakpointHit(void *baton,
3646
                                              StoppointCallbackContext *ctx,
3647
                                              user_id_t break_id,
3648
0
                                              user_id_t break_loc_id) {
3649
0
  Log *log(
3650
0
      GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
3651
3652
0
  assert(baton &&
3653
0
         "Error: null baton in conditional kernel breakpoint callback");
3654
3655
  // Coordinate we want to stop on
3656
0
  RSCoordinate target_coord = *static_cast<RSCoordinate *>(baton);
3657
3658
0
  LLDB_LOGF(log, "%s - Break ID %" PRIu64 ", " FMT_COORD, __FUNCTION__,
3659
0
            break_id, target_coord.x, target_coord.y, target_coord.z);
3660
3661
  // Select current thread
3662
0
  ExecutionContext context(ctx->exe_ctx_ref);
3663
0
  Thread *thread_ptr = context.GetThreadPtr();
3664
0
  assert(thread_ptr && "Null thread pointer");
3665
3666
  // Find current kernel invocation from .expand frame variables
3667
0
  RSCoordinate current_coord{};
3668
0
  if (!GetKernelCoordinate(current_coord, thread_ptr)) {
3669
0
    LLDB_LOGF(log, "%s - Error, couldn't select .expand stack frame",
3670
0
              __FUNCTION__);
3671
0
    return false;
3672
0
  }
3673
3674
0
  LLDB_LOGF(log, "%s - " FMT_COORD, __FUNCTION__, current_coord.x,
3675
0
            current_coord.y, current_coord.z);
3676
3677
  // Check if the current kernel invocation coordinate matches our target
3678
  // coordinate
3679
0
  if (target_coord == current_coord) {
3680
0
    LLDB_LOGF(log, "%s, BREAKING " FMT_COORD, __FUNCTION__, current_coord.x,
3681
0
              current_coord.y, current_coord.z);
3682
3683
0
    BreakpointSP breakpoint_sp =
3684
0
        context.GetTargetPtr()->GetBreakpointByID(break_id);
3685
0
    assert(breakpoint_sp != nullptr &&
3686
0
           "Error: Couldn't find breakpoint matching break id for callback");
3687
0
    breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint
3688
                                      // should only be hit once.
3689
0
    return true;
3690
0
  }
3691
3692
  // No match on coordinate
3693
0
  return false;
3694
0
}
3695
3696
void RenderScriptRuntime::SetConditional(BreakpointSP bp, Stream &messages,
3697
0
                                         const RSCoordinate &coord) {
3698
0
  messages.Printf("Conditional kernel breakpoint on coordinate " FMT_COORD,
3699
0
                  coord.x, coord.y, coord.z);
3700
0
  messages.EOL();
3701
3702
  // Allocate memory for the baton, and copy over coordinate
3703
0
  RSCoordinate *baton = new RSCoordinate(coord);
3704
3705
  // Create a callback that will be invoked every time the breakpoint is hit.
3706
  // The baton object passed to the handler is the target coordinate we want to
3707
  // break on.
3708
0
  bp->SetCallback(KernelBreakpointHit, baton, true);
3709
3710
  // Store a shared pointer to the baton, so the memory will eventually be
3711
  // cleaned up after destruction
3712
0
  m_conditional_breaks[bp->GetID()] = std::unique_ptr<RSCoordinate>(baton);
3713
0
}
3714
3715
// Tries to set a breakpoint on the start of a kernel, resolved using the
3716
// kernel name. Argument 'coords', represents a three dimensional coordinate
3717
// which can be used to specify a single kernel instance to break on. If this
3718
// is set then we add a callback to the breakpoint.
3719
bool RenderScriptRuntime::PlaceBreakpointOnKernel(TargetSP target,
3720
                                                  Stream &messages,
3721
                                                  const char *name,
3722
0
                                                  const RSCoordinate *coord) {
3723
0
  if (!name)
3724
0
    return false;
3725
3726
0
  InitSearchFilter(target);
3727
3728
0
  ConstString kernel_name(name);
3729
0
  BreakpointSP bp = CreateKernelBreakpoint(kernel_name);
3730
0
  if (!bp)
3731
0
    return false;
3732
3733
  // We have a conditional breakpoint on a specific coordinate
3734
0
  if (coord)
3735
0
    SetConditional(bp, messages, *coord);
3736
3737
0
  bp->GetDescription(&messages, lldb::eDescriptionLevelInitial, false);
3738
3739
0
  return true;
3740
0
}
3741
3742
BreakpointSP
3743
RenderScriptRuntime::CreateScriptGroupBreakpoint(ConstString name,
3744
0
                                                 bool stop_on_all) {
3745
0
  Log *log(
3746
0
      GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS));
3747
3748
0
  if (!m_filtersp) {
3749
0
    LLDB_LOGF(log, "%s - error, no breakpoint search filter set.",
3750
0
              __FUNCTION__);
3751
0
    return nullptr;
3752
0
  }
3753
3754
0
  BreakpointResolverSP resolver_sp(new RSScriptGroupBreakpointResolver(
3755
0
      nullptr, name, m_scriptGroups, stop_on_all));
3756
0
  Target &target = GetProcess()->GetTarget();
3757
0
  BreakpointSP bp = target.CreateBreakpoint(
3758
0
      m_filtersp, resolver_sp, false, false, false);
3759
  // Give RS breakpoints a specific name, so the user can manipulate them as a
3760
  // group.
3761
0
  Status err;
3762
0
  target.AddNameToBreakpoint(bp, name.GetCString(), err);
3763
0
  if (err.Fail() && log)
3764
0
    LLDB_LOGF(log, "%s - error setting break name, '%s'.", __FUNCTION__,
3765
0
              err.AsCString());
3766
  // ask the breakpoint to resolve itself
3767
0
  bp->ResolveBreakpoint();
3768
0
  return bp;
3769
0
}
3770
3771
bool RenderScriptRuntime::PlaceBreakpointOnScriptGroup(TargetSP target,
3772
                                                       Stream &strm,
3773
                                                       ConstString name,
3774
0
                                                       bool multi) {
3775
0
  InitSearchFilter(target);
3776
0
  BreakpointSP bp = CreateScriptGroupBreakpoint(name, multi);
3777
0
  if (bp)
3778
0
    bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false);
3779
0
  return bool(bp);
3780
0
}
3781
3782
bool RenderScriptRuntime::PlaceBreakpointOnReduction(TargetSP target,
3783
                                                     Stream &messages,
3784
                                                     const char *reduce_name,
3785
                                                     const RSCoordinate *coord,
3786
0
                                                     int kernel_types) {
3787
0
  if (!reduce_name)
3788
0
    return false;
3789
3790
0
  InitSearchFilter(target);
3791
0
  BreakpointSP bp =
3792
0
      CreateReductionBreakpoint(ConstString(reduce_name), kernel_types);
3793
0
  if (!bp)
3794
0
    return false;
3795
3796
0
  if (coord)
3797
0
    SetConditional(bp, messages, *coord);
3798
3799
0
  bp->GetDescription(&messages, lldb::eDescriptionLevelInitial, false);
3800
3801
0
  return true;
3802
0
}
3803
3804
0
void RenderScriptRuntime::DumpModules(Stream &strm) const {
3805
0
  strm.Printf("RenderScript Modules:");
3806
0
  strm.EOL();
3807
0
  strm.IndentMore();
3808
0
  for (const auto &module : m_rsmodules) {
3809
0
    module->Dump(strm);
3810
0
  }
3811
0
  strm.IndentLess();
3812
0
}
3813
3814
RenderScriptRuntime::ScriptDetails *
3815
0
RenderScriptRuntime::LookUpScript(addr_t address, bool create) {
3816
0
  for (const auto &s : m_scripts) {
3817
0
    if (s->script.isValid())
3818
0
      if (*s->script == address)
3819
0
        return s.get();
3820
0
  }
3821
0
  if (create) {
3822
0
    std::unique_ptr<ScriptDetails> s(new ScriptDetails);
3823
0
    s->script = address;
3824
0
    m_scripts.push_back(std::move(s));
3825
0
    return m_scripts.back().get();
3826
0
  }
3827
0
  return nullptr;
3828
0
}
3829
3830
RenderScriptRuntime::AllocationDetails *
3831
0
RenderScriptRuntime::LookUpAllocation(addr_t address) {
3832
0
  for (const auto &a : m_allocations) {
3833
0
    if (a->address.isValid())
3834
0
      if (*a->address == address)
3835
0
        return a.get();
3836
0
  }
3837
0
  return nullptr;
3838
0
}
3839
3840
RenderScriptRuntime::AllocationDetails *
3841
0
RenderScriptRuntime::CreateAllocation(addr_t address) {
3842
0
  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
3843
3844
  // Remove any previous allocation which contains the same address
3845
0
  auto it = m_allocations.begin();
3846
0
  while (it != m_allocations.end()) {
3847
0
    if (*((*it)->address) == address) {
3848
0
      LLDB_LOGF(log, "%s - Removing allocation id: %d, address: 0x%" PRIx64,
3849
0
                __FUNCTION__, (*it)->id, address);
3850
3851
0
      it = m_allocations.erase(it);
3852
0
    } else {
3853
0
      it++;
3854
0
    }
3855
0
  }
3856
3857
0
  std::unique_ptr<AllocationDetails> a(new AllocationDetails);
3858
0
  a->address = address;
3859
0
  m_allocations.push_back(std::move(a));
3860
0
  return m_allocations.back().get();
3861
0
}
3862
3863
bool RenderScriptRuntime::ResolveKernelName(lldb::addr_t kernel_addr,
3864
0
                                            ConstString &name) {
3865
0
  Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS);
3866
3867
0
  Target &target = GetProcess()->GetTarget();
3868
0
  Address resolved;
3869
  // RenderScript module
3870
0
  if (!target.GetSectionLoadList().ResolveLoadAddress(kernel_addr, resolved)) {
3871
0
    LLDB_LOGF(log, "%s: unable to resolve 0x%" PRIx64 " to a loaded symbol",
3872
0
              __FUNCTION__, kernel_addr);
3873
0
    return false;
3874
0
  }
3875
3876
0
  Symbol *sym = resolved.CalculateSymbolContextSymbol();
3877
0
  if (!sym)
3878
0
    return false;
3879
3880
0
  name = sym->GetName();
3881
0
  assert(IsRenderScriptModule(resolved.CalculateSymbolContextModule()));
3882
0
  LLDB_LOGF(log, "%s: 0x%" PRIx64 " resolved to the symbol '%s'", __FUNCTION__,
3883
0
            kernel_addr, name.GetCString());
3884
0
  return true;
3885
0
}
3886
3887
0
void RSModuleDescriptor::Dump(Stream &strm) const {
3888
0
  int indent = strm.GetIndentLevel();
3889
3890
0
  strm.Indent();
3891
0
  m_module->GetFileSpec().Dump(strm.AsRawOstream());
3892
0
  strm.Indent(m_module->GetNumCompileUnits() ? "Debug info loaded."
3893
0
                                             : "Debug info does not exist.");
3894
0
  strm.EOL();
3895
0
  strm.IndentMore();
3896
3897
0
  strm.Indent();
3898
0
  strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size()));
3899
0
  strm.EOL();
3900
0
  strm.IndentMore();
3901
0
  for (const auto &global : m_globals) {
3902
0
    global.Dump(strm);
3903
0
  }
3904
0
  strm.IndentLess();
3905
3906
0
  strm.Indent();
3907
0
  strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size()));
3908
0
  strm.EOL();
3909
0
  strm.IndentMore();
3910
0
  for (const auto &kernel : m_kernels) {
3911
0
    kernel.Dump(strm);
3912
0
  }
3913
0
  strm.IndentLess();
3914
3915
0
  strm.Indent();
3916
0
  strm.Printf("Pragmas: %" PRIu64, static_cast<uint64_t>(m_pragmas.size()));
3917
0
  strm.EOL();
3918
0
  strm.IndentMore();
3919
0
  for (const auto &key_val : m_pragmas) {
3920
0
    strm.Indent();
3921
0
    strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str());
3922
0
    strm.EOL();
3923
0
  }
3924
0
  strm.IndentLess();
3925
3926
0
  strm.Indent();
3927
0
  strm.Printf("Reductions: %" PRIu64,
3928
0
              static_cast<uint64_t>(m_reductions.size()));
3929
0
  strm.EOL();
3930
0
  strm.IndentMore();
3931
0
  for (const auto &reduction : m_reductions) {
3932
0
    reduction.Dump(strm);
3933
0
  }
3934
3935
0
  strm.SetIndentLevel(indent);
3936
0
}
3937
3938
0
void RSGlobalDescriptor::Dump(Stream &strm) const {
3939
0
  strm.Indent(m_name.GetStringRef());
3940
0
  VariableList var_list;
3941
0
  m_module->m_module->FindGlobalVariables(m_name, CompilerDeclContext(), 1U,
3942
0
                                          var_list);
3943
0
  if (var_list.GetSize() == 1) {
3944
0
    auto var = var_list.GetVariableAtIndex(0);
3945
0
    auto type = var->GetType();
3946
0
    if (type) {
3947
0
      strm.Printf(" - ");
3948
0
      type->DumpTypeName(&strm);
3949
0
    } else {
3950
0
      strm.Printf(" - Unknown Type");
3951
0
    }
3952
0
  } else {
3953
0
    strm.Printf(" - variable identified, but not found in binary");
3954
0
    const Symbol *s = m_module->m_module->FindFirstSymbolWithNameAndType(
3955
0
        m_name, eSymbolTypeData);
3956
0
    if (s) {
3957
0
      strm.Printf(" (symbol exists) ");
3958
0
    }
3959
0
  }
3960
3961
0
  strm.EOL();
3962
0
}
3963
3964
0
void RSKernelDescriptor::Dump(Stream &strm) const {
3965
0
  strm.Indent(m_name.GetStringRef());
3966
0
  strm.EOL();
3967
0
}
3968
3969
0
void RSReductionDescriptor::Dump(lldb_private::Stream &stream) const {
3970
0
  stream.Indent(m_reduce_name.GetStringRef());
3971
0
  stream.IndentMore();
3972
0
  stream.EOL();
3973
0
  stream.Indent();
3974
0
  stream.Printf("accumulator: %s", m_accum_name.AsCString());
3975
0
  stream.EOL();
3976
0
  stream.Indent();
3977
0
  stream.Printf("initializer: %s", m_init_name.AsCString());
3978
0
  stream.EOL();
3979
0
  stream.Indent();
3980
0
  stream.Printf("combiner: %s", m_comb_name.AsCString());
3981
0
  stream.EOL();
3982
0
  stream.Indent();
3983
0
  stream.Printf("outconverter: %s", m_outc_name.AsCString());
3984
0
  stream.EOL();
3985
  // XXX This is currently unspecified by RenderScript, and unused
3986
  // stream.Indent();
3987
  // stream.Printf("halter: '%s'", m_init_name.AsCString());
3988
  // stream.EOL();
3989
0
  stream.IndentLess();
3990
0
}
3991
3992
class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed {
3993
public:
3994
  CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter)
3995
      : CommandObjectParsed(
3996
            interpreter, "renderscript module dump",
3997
            "Dumps renderscript specific information for all modules.",
3998
            "renderscript module dump",
3999
5.93k
            eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
4000
4001
5.92k
  ~CommandObjectRenderScriptRuntimeModuleDump() override = default;
4002
4003
0
  bool DoExecute(Args &command, CommandReturnObject &result) override {
4004
0
    RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>(
4005
0
        m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4006
0
            eLanguageTypeExtRenderScript));
4007
0
    runtime->DumpModules(result.GetOutputStream());
4008
0
    result.SetStatus(eReturnStatusSuccessFinishResult);
4009
0
    return true;
4010
0
  }
4011
};
4012
4013
class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword {
4014
public:
4015
  CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter)
4016
      : CommandObjectMultiword(interpreter, "renderscript module",
4017
                               "Commands that deal with RenderScript modules.",
4018
5.93k
                               nullptr) {
4019
5.93k
    LoadSubCommand(
4020
5.93k
        "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump(
4021
5.93k
                    interpreter)));
4022
5.93k
  }
4023
4024
5.92k
  ~CommandObjectRenderScriptRuntimeModule() override = default;
4025
};
4026
4027
class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed {
4028
public:
4029
  CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter)
4030
      : CommandObjectParsed(
4031
            interpreter, "renderscript kernel list",
4032
            "Lists renderscript kernel names and associated script resources.",
4033
            "renderscript kernel list",
4034
5.93k
            eCommandRequiresProcess | eCommandProcessMustBeLaunched) {}
4035
4036
5.92k
  ~CommandObjectRenderScriptRuntimeKernelList() override = default;
4037
4038
0
  bool DoExecute(Args &command, CommandReturnObject &result) override {
4039
0
    RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>(
4040
0
        m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4041
0
            eLanguageTypeExtRenderScript));
4042
0
    runtime->DumpKernels(result.GetOutputStream());
4043
0
    result.SetStatus(eReturnStatusSuccessFinishResult);
4044
0
    return true;
4045
0
  }
4046
};
4047
4048
static constexpr OptionDefinition g_renderscript_reduction_bp_set_options[] = {
4049
    {LLDB_OPT_SET_1, false, "function-role", 't',
4050
     OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOneLiner,
4051
     "Break on a comma separated set of reduction kernel types "
4052
     "(accumulator,outcoverter,combiner,initializer"},
4053
    {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument,
4054
     nullptr, {}, 0, eArgTypeValue,
4055
     "Set a breakpoint on a single invocation of the kernel with specified "
4056
     "coordinate.\n"
4057
     "Coordinate takes the form 'x[,y][,z] where x,y,z are positive "
4058
     "integers representing kernel dimensions. "
4059
     "Any unset dimensions will be defaulted to zero."}};
4060
4061
class CommandObjectRenderScriptRuntimeReductionBreakpointSet
4062
    : public CommandObjectParsed {
4063
public:
4064
  CommandObjectRenderScriptRuntimeReductionBreakpointSet(
4065
      CommandInterpreter &interpreter)
4066
      : CommandObjectParsed(
4067
            interpreter, "renderscript reduction breakpoint set",
4068
            "Set a breakpoint on named RenderScript general reductions",
4069
            "renderscript reduction breakpoint set  <kernel_name> [-t "
4070
            "<reduction_kernel_type,...>]",
4071
            eCommandRequiresProcess | eCommandProcessMustBeLaunched |
4072
                eCommandProcessMustBePaused),
4073
5.93k
        m_options(){};
4074
4075
  class CommandOptions : public Options {
4076
  public:
4077
5.93k
    CommandOptions() : Options() {}
4078
4079
5.92k
    ~CommandOptions() override = default;
4080
4081
    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
4082
0
                          ExecutionContext *exe_ctx) override {
4083
0
      Status err;
4084
0
      StreamString err_str;
4085
0
      const int short_option = m_getopt_table[option_idx].val;
4086
0
      switch (short_option) {
4087
0
      case 't':
4088
0
        if (!ParseReductionTypes(option_arg, err_str))
4089
0
          err.SetErrorStringWithFormat(
4090
0
              "Unable to deduce reduction types for %s: %s",
4091
0
              option_arg.str().c_str(), err_str.GetData());
4092
0
        break;
4093
0
      case 'c': {
4094
0
        auto coord = RSCoordinate{};
4095
0
        if (!ParseCoordinate(option_arg, coord))
4096
0
          err.SetErrorStringWithFormat("unable to parse coordinate for %s",
4097
0
                                       option_arg.str().c_str());
4098
0
        else {
4099
0
          m_have_coord = true;
4100
0
          m_coord = coord;
4101
0
        }
4102
0
        break;
4103
0
      }
4104
0
      default:
4105
0
        err.SetErrorStringWithFormat("Invalid option '-%c'", short_option);
4106
0
      }
4107
0
      return err;
4108
0
    }
4109
4110
0
    void OptionParsingStarting(ExecutionContext *exe_ctx) override {
4111
0
      m_have_coord = false;
4112
0
    }
4113
4114
0
    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
4115
0
      return llvm::makeArrayRef(g_renderscript_reduction_bp_set_options);
4116
0
    }
4117
4118
    bool ParseReductionTypes(llvm::StringRef option_val,
4119
0
                             StreamString &err_str) {
4120
0
      m_kernel_types = RSReduceBreakpointResolver::eKernelTypeNone;
4121
0
      const auto reduce_name_to_type = [](llvm::StringRef name) -> int {
4122
0
        return llvm::StringSwitch<int>(name)
4123
0
            .Case("accumulator", RSReduceBreakpointResolver::eKernelTypeAccum)
4124
0
            .Case("initializer", RSReduceBreakpointResolver::eKernelTypeInit)
4125
0
            .Case("outconverter", RSReduceBreakpointResolver::eKernelTypeOutC)
4126
0
            .Case("combiner", RSReduceBreakpointResolver::eKernelTypeComb)
4127
0
            .Case("all", RSReduceBreakpointResolver::eKernelTypeAll)
4128
            // Currently not exposed by the runtime
4129
            // .Case("halter", RSReduceBreakpointResolver::eKernelTypeHalter)
4130
0
            .Default(0);
4131
0
      };
4132
4133
      // Matching a comma separated list of known words is fairly
4134
      // straightforward with PCRE, but we're using ERE, so we end up with a
4135
      // little ugliness...
4136
0
      RegularExpression match_type_list(
4137
0
          llvm::StringRef("^([[:alpha:]]+)(,[[:alpha:]]+){0,4}$"));
4138
4139
0
      assert(match_type_list.IsValid());
4140
4141
0
      if (!match_type_list.Execute(option_val)) {
4142
0
        err_str.PutCString(
4143
0
            "a comma-separated list of kernel types is required");
4144
0
        return false;
4145
0
      }
4146
4147
      // splitting on commas is much easier with llvm::StringRef than regex
4148
0
      llvm::SmallVector<llvm::StringRef, 5> type_names;
4149
0
      llvm::StringRef(option_val).split(type_names, ',');
4150
4151
0
      for (const auto &name : type_names) {
4152
0
        const int type = reduce_name_to_type(name);
4153
0
        if (!type) {
4154
0
          err_str.Printf("unknown kernel type name %s", name.str().c_str());
4155
0
          return false;
4156
0
        }
4157
0
        m_kernel_types |= type;
4158
0
      }
4159
4160
0
      return true;
4161
0
    }
4162
4163
    int m_kernel_types = RSReduceBreakpointResolver::eKernelTypeAll;
4164
    llvm::StringRef m_reduce_name;
4165
    RSCoordinate m_coord;
4166
    bool m_have_coord;
4167
  };
4168
4169
0
  Options *GetOptions() override { return &m_options; }
4170
4171
0
  bool DoExecute(Args &command, CommandReturnObject &result) override {
4172
0
    const size_t argc = command.GetArgumentCount();
4173
0
    if (argc < 1) {
4174
0
      result.AppendErrorWithFormat("'%s' takes 1 argument of reduction name, "
4175
0
                                   "and an optional kernel type list",
4176
0
                                   m_cmd_name.c_str());
4177
0
      return false;
4178
0
    }
4179
4180
0
    RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4181
0
        m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4182
0
            eLanguageTypeExtRenderScript));
4183
4184
0
    auto &outstream = result.GetOutputStream();
4185
0
    auto name = command.GetArgumentAtIndex(0);
4186
0
    auto &target = m_exe_ctx.GetTargetSP();
4187
0
    auto coord = m_options.m_have_coord ? &m_options.m_coord : nullptr;
4188
0
    if (!runtime->PlaceBreakpointOnReduction(target, outstream, name, coord,
4189
0
                                             m_options.m_kernel_types)) {
4190
0
      result.AppendError("Error: unable to place breakpoint on reduction");
4191
0
      return false;
4192
0
    }
4193
0
    result.AppendMessage("Breakpoint(s) created");
4194
0
    result.SetStatus(eReturnStatusSuccessFinishResult);
4195
0
    return true;
4196
0
  }
4197
4198
private:
4199
  CommandOptions m_options;
4200
};
4201
4202
static constexpr OptionDefinition g_renderscript_kernel_bp_set_options[] = {
4203
    {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument,
4204
     nullptr, {}, 0, eArgTypeValue,
4205
     "Set a breakpoint on a single invocation of the kernel with specified "
4206
     "coordinate.\n"
4207
     "Coordinate takes the form 'x[,y][,z] where x,y,z are positive "
4208
     "integers representing kernel dimensions. "
4209
     "Any unset dimensions will be defaulted to zero."}};
4210
4211
class CommandObjectRenderScriptRuntimeKernelBreakpointSet
4212
    : public CommandObjectParsed {
4213
public:
4214
  CommandObjectRenderScriptRuntimeKernelBreakpointSet(
4215
      CommandInterpreter &interpreter)
4216
      : CommandObjectParsed(
4217
            interpreter, "renderscript kernel breakpoint set",
4218
            "Sets a breakpoint on a renderscript kernel.",
4219
            "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]",
4220
            eCommandRequiresProcess | eCommandProcessMustBeLaunched |
4221
                eCommandProcessMustBePaused),
4222
5.93k
        m_options() {}
4223
4224
5.92k
  ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default;
4225
4226
0
  Options *GetOptions() override { return &m_options; }
4227
4228
  class CommandOptions : public Options {
4229
  public:
4230
5.93k
    CommandOptions() : Options() {}
4231
4232
5.92k
    ~CommandOptions() override = default;
4233
4234
    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
4235
0
                          ExecutionContext *exe_ctx) override {
4236
0
      Status err;
4237
0
      const int short_option = m_getopt_table[option_idx].val;
4238
4239
0
      switch (short_option) {
4240
0
      case 'c': {
4241
0
        auto coord = RSCoordinate{};
4242
0
        if (!ParseCoordinate(option_arg, coord))
4243
0
          err.SetErrorStringWithFormat(
4244
0
              "Couldn't parse coordinate '%s', should be in format 'x,y,z'.",
4245
0
              option_arg.str().c_str());
4246
0
        else {
4247
0
          m_have_coord = true;
4248
0
          m_coord = coord;
4249
0
        }
4250
0
        break;
4251
0
      }
4252
0
      default:
4253
0
        err.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
4254
0
        break;
4255
0
      }
4256
0
      return err;
4257
0
    }
4258
4259
0
    void OptionParsingStarting(ExecutionContext *exe_ctx) override {
4260
0
      m_have_coord = false;
4261
0
    }
4262
4263
0
    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
4264
0
      return llvm::makeArrayRef(g_renderscript_kernel_bp_set_options);
4265
0
    }
4266
4267
    RSCoordinate m_coord;
4268
    bool m_have_coord;
4269
  };
4270
4271
0
  bool DoExecute(Args &command, CommandReturnObject &result) override {
4272
0
    const size_t argc = command.GetArgumentCount();
4273
0
    if (argc < 1) {
4274
0
      result.AppendErrorWithFormat(
4275
0
          "'%s' takes 1 argument of kernel name, and an optional coordinate.",
4276
0
          m_cmd_name.c_str());
4277
0
      return false;
4278
0
    }
4279
4280
0
    RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>(
4281
0
        m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4282
0
            eLanguageTypeExtRenderScript));
4283
4284
0
    auto &outstream = result.GetOutputStream();
4285
0
    auto &target = m_exe_ctx.GetTargetSP();
4286
0
    auto name = command.GetArgumentAtIndex(0);
4287
0
    auto coord = m_options.m_have_coord ? &m_options.m_coord : nullptr;
4288
0
    if (!runtime->PlaceBreakpointOnKernel(target, outstream, name, coord)) {
4289
0
      result.AppendErrorWithFormat(
4290
0
          "Error: unable to set breakpoint on kernel '%s'", name);
4291
0
      return false;
4292
0
    }
4293
4294
0
    result.AppendMessage("Breakpoint(s) created");
4295
0
    result.SetStatus(eReturnStatusSuccessFinishResult);
4296
0
    return true;
4297
0
  }
4298
4299
private:
4300
  CommandOptions m_options;
4301
};
4302
4303
class CommandObjectRenderScriptRuntimeKernelBreakpointAll
4304
    : public CommandObjectParsed {
4305
public:
4306
  CommandObjectRenderScriptRuntimeKernelBreakpointAll(
4307
      CommandInterpreter &interpreter)
4308
      : CommandObjectParsed(
4309
            interpreter, "renderscript kernel breakpoint all",
4310
            "Automatically sets a breakpoint on all renderscript kernels that "
4311
            "are or will be loaded.\n"
4312
            "Disabling option means breakpoints will no longer be set on any "
4313
            "kernels loaded in the future, "
4314
            "but does not remove currently set breakpoints.",
4315
            "renderscript kernel breakpoint all <enable/disable>",
4316
            eCommandRequiresProcess | eCommandProcessMustBeLaunched |
4317
5.93k
                eCommandProcessMustBePaused) {}
4318
4319
5.92k
  ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default;
4320
4321
0
  bool DoExecute(Args &command, CommandReturnObject &result) override {
4322
0
    const size_t argc = command.GetArgumentCount();
4323
0
    if (argc != 1) {
4324
0
      result.AppendErrorWithFormat(
4325
0
          "'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str());
4326
0
      return false;
4327
0
    }
4328
4329
0
    RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4330
0
        m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4331
0
            eLanguageTypeExtRenderScript));
4332
4333
0
    bool do_break = false;
4334
0
    const char *argument = command.GetArgumentAtIndex(0);
4335
0
    if (strcmp(argument, "enable") == 0) {
4336
0
      do_break = true;
4337
0
      result.AppendMessage("Breakpoints will be set on all kernels.");
4338
0
    } else if (strcmp(argument, "disable") == 0) {
4339
0
      do_break = false;
4340
0
      result.AppendMessage("Breakpoints will not be set on any new kernels.");
4341
0
    } else {
4342
0
      result.AppendErrorWithFormat(
4343
0
          "Argument must be either 'enable' or 'disable'");
4344
0
      return false;
4345
0
    }
4346
4347
0
    runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP());
4348
4349
0
    result.SetStatus(eReturnStatusSuccessFinishResult);
4350
0
    return true;
4351
0
  }
4352
};
4353
4354
class CommandObjectRenderScriptRuntimeReductionBreakpoint
4355
    : public CommandObjectMultiword {
4356
public:
4357
  CommandObjectRenderScriptRuntimeReductionBreakpoint(
4358
      CommandInterpreter &interpreter)
4359
      : CommandObjectMultiword(interpreter, "renderscript reduction breakpoint",
4360
                               "Commands that manipulate breakpoints on "
4361
                               "renderscript general reductions.",
4362
5.93k
                               nullptr) {
4363
5.93k
    LoadSubCommand(
4364
5.93k
        "set", CommandObjectSP(
4365
5.93k
                   new CommandObjectRenderScriptRuntimeReductionBreakpointSet(
4366
5.93k
                       interpreter)));
4367
5.93k
  }
4368
4369
5.92k
  ~CommandObjectRenderScriptRuntimeReductionBreakpoint() override = default;
4370
};
4371
4372
class CommandObjectRenderScriptRuntimeKernelCoordinate
4373
    : public CommandObjectParsed {
4374
public:
4375
  CommandObjectRenderScriptRuntimeKernelCoordinate(
4376
      CommandInterpreter &interpreter)
4377
      : CommandObjectParsed(
4378
            interpreter, "renderscript kernel coordinate",
4379
            "Shows the (x,y,z) coordinate of the current kernel invocation.",
4380
            "renderscript kernel coordinate",
4381
            eCommandRequiresProcess | eCommandProcessMustBeLaunched |
4382
5.93k
                eCommandProcessMustBePaused) {}
4383
4384
5.92k
  ~CommandObjectRenderScriptRuntimeKernelCoordinate() override = default;
4385
4386
0
  bool DoExecute(Args &command, CommandReturnObject &result) override {
4387
0
    RSCoordinate coord{};
4388
0
    bool success = RenderScriptRuntime::GetKernelCoordinate(
4389
0
        coord, m_exe_ctx.GetThreadPtr());
4390
0
    Stream &stream = result.GetOutputStream();
4391
4392
0
    if (success) {
4393
0
      stream.Printf("Coordinate: " FMT_COORD, coord.x, coord.y, coord.z);
4394
0
      stream.EOL();
4395
0
      result.SetStatus(eReturnStatusSuccessFinishResult);
4396
0
    } else {
4397
0
      stream.Printf("Error: Coordinate could not be found.");
4398
0
      stream.EOL();
4399
0
      result.SetStatus(eReturnStatusFailed);
4400
0
    }
4401
0
    return true;
4402
0
  }
4403
};
4404
4405
class CommandObjectRenderScriptRuntimeKernelBreakpoint
4406
    : public CommandObjectMultiword {
4407
public:
4408
  CommandObjectRenderScriptRuntimeKernelBreakpoint(
4409
      CommandInterpreter &interpreter)
4410
      : CommandObjectMultiword(
4411
            interpreter, "renderscript kernel",
4412
            "Commands that generate breakpoints on renderscript kernels.",
4413
5.93k
            nullptr) {
4414
5.93k
    LoadSubCommand(
4415
5.93k
        "set",
4416
5.93k
        CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet(
4417
5.93k
            interpreter)));
4418
5.93k
    LoadSubCommand(
4419
5.93k
        "all",
4420
5.93k
        CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll(
4421
5.93k
            interpreter)));
4422
5.93k
  }
4423
4424
5.92k
  ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default;
4425
};
4426
4427
class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword {
4428
public:
4429
  CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter)
4430
      : CommandObjectMultiword(interpreter, "renderscript kernel",
4431
                               "Commands that deal with RenderScript kernels.",
4432
5.93k
                               nullptr) {
4433
5.93k
    LoadSubCommand(
4434
5.93k
        "list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList(
4435
5.93k
                    interpreter)));
4436
5.93k
    LoadSubCommand(
4437
5.93k
        "coordinate",
4438
5.93k
        CommandObjectSP(
4439
5.93k
            new CommandObjectRenderScriptRuntimeKernelCoordinate(interpreter)));
4440
5.93k
    LoadSubCommand(
4441
5.93k
        "breakpoint",
4442
5.93k
        CommandObjectSP(
4443
5.93k
            new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter)));
4444
5.93k
  }
4445
4446
5.92k
  ~CommandObjectRenderScriptRuntimeKernel() override = default;
4447
};
4448
4449
class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed {
4450
public:
4451
  CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter)
4452
      : CommandObjectParsed(interpreter, "renderscript context dump",
4453
                            "Dumps renderscript context information.",
4454
                            "renderscript context dump",
4455
                            eCommandRequiresProcess |
4456
5.93k
                                eCommandProcessMustBeLaunched) {}
4457
4458
5.92k
  ~CommandObjectRenderScriptRuntimeContextDump() override = default;
4459
4460
0
  bool DoExecute(Args &command, CommandReturnObject &result) override {
4461
0
    RenderScriptRuntime *runtime = llvm::cast<RenderScriptRuntime>(
4462
0
        m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4463
0
            eLanguageTypeExtRenderScript));
4464
0
    runtime->DumpContexts(result.GetOutputStream());
4465
0
    result.SetStatus(eReturnStatusSuccessFinishResult);
4466
0
    return true;
4467
0
  }
4468
};
4469
4470
static constexpr OptionDefinition g_renderscript_runtime_alloc_dump_options[] = {
4471
    {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument,
4472
     nullptr, {}, 0, eArgTypeFilename,
4473
     "Print results to specified file instead of command line."}};
4474
4475
class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword {
4476
public:
4477
  CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter)
4478
      : CommandObjectMultiword(interpreter, "renderscript context",
4479
                               "Commands that deal with RenderScript contexts.",
4480
5.93k
                               nullptr) {
4481
5.93k
    LoadSubCommand(
4482
5.93k
        "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump(
4483
5.93k
                    interpreter)));
4484
5.93k
  }
4485
4486
5.92k
  ~CommandObjectRenderScriptRuntimeContext() override = default;
4487
};
4488
4489
class CommandObjectRenderScriptRuntimeAllocationDump
4490
    : public CommandObjectParsed {
4491
public:
4492
  CommandObjectRenderScriptRuntimeAllocationDump(
4493
      CommandInterpreter &interpreter)
4494
      : CommandObjectParsed(interpreter, "renderscript allocation dump",
4495
                            "Displays the contents of a particular allocation",
4496
                            "renderscript allocation dump <ID>",
4497
                            eCommandRequiresProcess |
4498
                                eCommandProcessMustBeLaunched),
4499
5.93k
        m_options() {}
4500
4501
5.92k
  ~CommandObjectRenderScriptRuntimeAllocationDump() override = default;
4502
4503
0
  Options *GetOptions() override { return &m_options; }
4504
4505
  class CommandOptions : public Options {
4506
  public:
4507
5.93k
    CommandOptions() : Options() {}
4508
4509
5.92k
    ~CommandOptions() override = default;
4510
4511
    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
4512
0
                          ExecutionContext *exe_ctx) override {
4513
0
      Status err;
4514
0
      const int short_option = m_getopt_table[option_idx].val;
4515
4516
0
      switch (short_option) {
4517
0
      case 'f':
4518
0
        m_outfile.SetFile(option_arg, FileSpec::Style::native);
4519
0
        FileSystem::Instance().Resolve(m_outfile);
4520
0
        if (FileSystem::Instance().Exists(m_outfile)) {
4521
0
          m_outfile.Clear();
4522
0
          err.SetErrorStringWithFormat("file already exists: '%s'",
4523
0
                                       option_arg.str().c_str());
4524
0
        }
4525
0
        break;
4526
0
      default:
4527
0
        err.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
4528
0
        break;
4529
0
      }
4530
0
      return err;
4531
0
    }
4532
4533
0
    void OptionParsingStarting(ExecutionContext *exe_ctx) override {
4534
0
      m_outfile.Clear();
4535
0
    }
4536
4537
0
    llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
4538
0
      return llvm::makeArrayRef(g_renderscript_runtime_alloc_dump_options);
4539
0
    }
4540
4541
    FileSpec m_outfile;
4542
  };
4543
4544
0
  bool DoExecute(Args &command, CommandReturnObject &result) override {
4545
0
    const size_t argc = command.GetArgumentCount();
4546
0
    if (argc < 1) {
4547
0
      result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. "
4548
0
                                   "As well as an optional -f argument",
4549
0
                                   m_cmd_name.c_str());
4550
0
      return false;
4551
0
    }
4552
4553
0
    RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>(
4554
0
        m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(
4555
0
            eLanguageTypeExtRenderScript));
4556
4557
0
    const char *id_cstr = command.GetArgumentAtIndex(0);
4558
0
    uint32_t id;
4559
0
    if (!llvm::to_integer(id_cstr, id)) {
4560
0
      result.AppendErrorWithFormat("invalid allocation id argument '%s'",
4561
0
                                   id_cstr);
4562
0
      return false;
4563
0
    }
4564
4565
0
    Stream *output_stream_p = nullptr;
4566
0
    std::unique_ptr<Stream> output_stream_storage;
4567
4568
0
    const FileSpec &outfile_spec =
4569
0
        m_options.m_outfile; // Dump allocation to file instead
4570
0
    if (outfile_spec) {
4571
      // Open output file
4572
0
      std::string path = outfile_spec.GetPath();
4573
0
      auto file = FileSystem::Instance().Open(outfile_spec,
4574
0
                                              File::eOpenOptionWriteOnly |
4575
0
                                                  File::eOpenOptionCanCreate);
4576
0
      if (file) {
4577
0
        output_stream_storage =
4578
0
            std::make_unique<StreamFile>(std::move(file.get()));
4579
0
        output_stream_p = output_stream_storage.get();
4580
0
        result.GetOutputStream().Printf("Results written to '%s'",
4581
0
                                        path.c_str());
4582
0
        result.GetOutputStream().EOL();
4583
0
      } else {
4584
0
        std::string error = llvm::toString(file.takeError());
4585
0
        result.AppendErrorWithFormat("Couldn't open file '%s': %s",
4586
0
                                     path.c_str(), error.c_str());
4587
0
        return false;
4588
0
      }
4589
0
    } else
4590
0
      output_stream_p = &result.GetOutputStream();
4591
4592
0
    assert(output_stream_p != nullptr);
4593
0
    bool dumped =
4594
0
        runtime->DumpAllocation(*output_stream_p, m_exe_ctx.GetFramePtr(), id);
4595
4596
0
    if (dumped)
4597
0
      result.SetStatus(eReturnStatusSuccessFinishResult);
4598
0
    else
4599
0
      result.SetStatus(eReturnStatusFailed);
4600
4601
0
    return true;
4602
0
  }
4603
4604
private:
4605
  CommandOptions m_options;
4606
};
4607
4608
static constexpr OptionDefinition g_renderscript_runtime_alloc_list_options[] = {
4609
    {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument, nullptr,
4610
     {}, 0, eArgTypeIndex,
4611
     "Only show details of a single allocation with specified id."}};
4612
4613
class CommandObjectRenderScriptRuntimeAllocationList
4614
    : public CommandObjectParsed {
4615
public:
4616
  CommandObjectRenderScriptRuntimeAllocationList(
4617