Bug Summary

File:tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
Warning:line 67, column 29
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name RenderScriptRuntime.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-7/lib/clang/7.0.0 -D HAVE_ROUND -D LLDB_CONFIGURATION_RELEASE -D LLDB_USE_BUILTIN_DEMANGLER -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-7~svn326246/build-llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime -I /build/llvm-toolchain-snapshot-7~svn326246/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime -I /build/llvm-toolchain-snapshot-7~svn326246/build-llvm/tools/lldb/include -I /build/llvm-toolchain-snapshot-7~svn326246/tools/lldb/include -I /build/llvm-toolchain-snapshot-7~svn326246/build-llvm/include -I /build/llvm-toolchain-snapshot-7~svn326246/include -I /usr/include/python2.7 -I /build/llvm-toolchain-snapshot-7~svn326246/tools/clang/include -I /build/llvm-toolchain-snapshot-7~svn326246/build-llvm/tools/lldb/../clang/include -I /build/llvm-toolchain-snapshot-7~svn326246/tools/lldb/source/. -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/backward -internal-isystem /usr/include/clang/7.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-strict-aliasing -Wno-deprecated-register -Wno-vla-extension -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-7~svn326246/build-llvm/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-02-28-041547-14988-1 -x c++ /build/llvm-toolchain-snapshot-7~svn326246/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp

/build/llvm-toolchain-snapshot-7~svn326246/tools/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp

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

/usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/shared_ptr.h

1// shared_ptr and weak_ptr implementation -*- C++ -*-
2
3// Copyright (C) 2007-2017 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25// GCC Note: Based on files from version 1.32.0 of the Boost library.
26
27// shared_count.hpp
28// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
29
30// shared_ptr.hpp
31// Copyright (C) 1998, 1999 Greg Colvin and Beman Dawes.
32// Copyright (C) 2001, 2002, 2003 Peter Dimov
33
34// weak_ptr.hpp
35// Copyright (C) 2001, 2002, 2003 Peter Dimov
36
37// enable_shared_from_this.hpp
38// Copyright (C) 2002 Peter Dimov
39
40// Distributed under the Boost Software License, Version 1.0. (See
41// accompanying file LICENSE_1_0.txt or copy at
42// http://www.boost.org/LICENSE_1_0.txt)
43
44/** @file
45 * This is an internal header file, included by other library headers.
46 * Do not attempt to use it directly. @headername{memory}
47 */
48
49#ifndef _SHARED_PTR_H1
50#define _SHARED_PTR_H1 1
51
52#include <bits/shared_ptr_base.h>
53
54namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
55{
56_GLIBCXX_BEGIN_NAMESPACE_VERSION
57
58 /**
59 * @addtogroup pointer_abstractions
60 * @{
61 */
62
63 /// 20.7.2.2.11 shared_ptr I/O
64 template<typename _Ch, typename _Tr, typename _Tp, _Lock_policy _Lp>
65 inline std::basic_ostream<_Ch, _Tr>&
66 operator<<(std::basic_ostream<_Ch, _Tr>& __os,
67 const __shared_ptr<_Tp, _Lp>& __p)
68 {
69 __os << __p.get();
70 return __os;
71 }
72
73 /// 20.7.2.2.10 shared_ptr get_deleter
74 template<typename _Del, typename _Tp, _Lock_policy _Lp>
75 inline _Del*
76 get_deleter(const __shared_ptr<_Tp, _Lp>& __p) noexcept
77 {
78#if __cpp_rtti199711
79 return static_cast<_Del*>(__p._M_get_deleter(typeid(_Del)));
80#else
81 return 0;
82#endif
83 }
84
85
86 /**
87 * @brief A smart pointer with reference-counted copy semantics.
88 *
89 * The object pointed to is deleted when the last shared_ptr pointing to
90 * it is destroyed or reset.
91 */
92 template<typename _Tp>
93 class shared_ptr : public __shared_ptr<_Tp>
94 {
95 template<typename... _Args>
96 using _Constructible = typename enable_if<
97 is_constructible<__shared_ptr<_Tp>, _Args...>::value
98 >::type;
99
100 template<typename _Arg>
101 using _Assignable = typename enable_if<
102 is_assignable<__shared_ptr<_Tp>&, _Arg>::value, shared_ptr&
103 >::type;
104
105 public:
106
107 using element_type = typename __shared_ptr<_Tp>::element_type;
108
109#if __cplusplus201103L > 201402L
110# define __cpp_lib_shared_ptr_weak_type 201606
111 using weak_type = weak_ptr<_Tp>;
112#endif
113 /**
114 * @brief Construct an empty %shared_ptr.
115 * @post use_count()==0 && get()==0
116 */
117 constexpr shared_ptr() noexcept : __shared_ptr<_Tp>() { }
118
119 shared_ptr(const shared_ptr&) noexcept = default;
120
121 /**
122 * @brief Construct a %shared_ptr that owns the pointer @a __p.
123 * @param __p A pointer that is convertible to element_type*.
124 * @post use_count() == 1 && get() == __p
125 * @throw std::bad_alloc, in which case @c delete @a __p is called.
126 */
127 template<typename _Yp, typename = _Constructible<_Yp*>>
128 explicit
129 shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }
130
131 /**
132 * @brief Construct a %shared_ptr that owns the pointer @a __p
133 * and the deleter @a __d.
134 * @param __p A pointer.
135 * @param __d A deleter.
136 * @post use_count() == 1 && get() == __p
137 * @throw std::bad_alloc, in which case @a __d(__p) is called.
138 *
139 * Requirements: _Deleter's copy constructor and destructor must
140 * not throw
141 *
142 * __shared_ptr will release __p by calling __d(__p)
143 */
144 template<typename _Yp, typename _Deleter,
145 typename = _Constructible<_Yp*, _Deleter>>
146 shared_ptr(_Yp* __p, _Deleter __d)
147 : __shared_ptr<_Tp>(__p, std::move(__d)) { }
148
149 /**
150 * @brief Construct a %shared_ptr that owns a null pointer
151 * and the deleter @a __d.
152 * @param __p A null pointer constant.
153 * @param __d A deleter.
154 * @post use_count() == 1 && get() == __p
155 * @throw std::bad_alloc, in which case @a __d(__p) is called.
156 *
157 * Requirements: _Deleter's copy constructor and destructor must
158 * not throw
159 *
160 * The last owner will call __d(__p)
161 */
162 template<typename _Deleter>
163 shared_ptr(nullptr_t __p, _Deleter __d)
164 : __shared_ptr<_Tp>(__p, std::move(__d)) { }
165
166 /**
167 * @brief Construct a %shared_ptr that owns the pointer @a __p
168 * and the deleter @a __d.
169 * @param __p A pointer.
170 * @param __d A deleter.
171 * @param __a An allocator.
172 * @post use_count() == 1 && get() == __p
173 * @throw std::bad_alloc, in which case @a __d(__p) is called.
174 *
175 * Requirements: _Deleter's copy constructor and destructor must
176 * not throw _Alloc's copy constructor and destructor must not
177 * throw.
178 *
179 * __shared_ptr will release __p by calling __d(__p)
180 */
181 template<typename _Yp, typename _Deleter, typename _Alloc,
182 typename = _Constructible<_Yp*, _Deleter, _Alloc>>
183 shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
184 : __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { }
185
186 /**
187 * @brief Construct a %shared_ptr that owns a null pointer
188 * and the deleter @a __d.
189 * @param __p A null pointer constant.
190 * @param __d A deleter.
191 * @param __a An allocator.
192 * @post use_count() == 1 && get() == __p
193 * @throw std::bad_alloc, in which case @a __d(__p) is called.
194 *
195 * Requirements: _Deleter's copy constructor and destructor must
196 * not throw _Alloc's copy constructor and destructor must not
197 * throw.
198 *
199 * The last owner will call __d(__p)
200 */
201 template<typename _Deleter, typename _Alloc>
202 shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
203 : __shared_ptr<_Tp>(__p, std::move(__d), std::move(__a)) { }
204
205 // Aliasing constructor
206
207 /**
208 * @brief Constructs a %shared_ptr instance that stores @a __p
209 * and shares ownership with @a __r.
210 * @param __r A %shared_ptr.
211 * @param __p A pointer that will remain valid while @a *__r is valid.
212 * @post get() == __p && use_count() == __r.use_count()
213 *
214 * This can be used to construct a @c shared_ptr to a sub-object
215 * of an object managed by an existing @c shared_ptr.
216 *
217 * @code
218 * shared_ptr< pair<int,int> > pii(new pair<int,int>());
219 * shared_ptr<int> pi(pii, &pii->first);
220 * assert(pii.use_count() == 2);
221 * @endcode
222 */
223 template<typename _Yp>
224 shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) noexcept
225 : __shared_ptr<_Tp>(__r, __p) { }
226
227 /**
228 * @brief If @a __r is empty, constructs an empty %shared_ptr;
229 * otherwise construct a %shared_ptr that shares ownership
230 * with @a __r.
231 * @param __r A %shared_ptr.
232 * @post get() == __r.get() && use_count() == __r.use_count()
233 */
234 template<typename _Yp,
235 typename = _Constructible<const shared_ptr<_Yp>&>>
236 shared_ptr(const shared_ptr<_Yp>& __r) noexcept
237 : __shared_ptr<_Tp>(__r) { }
238
239 /**
240 * @brief Move-constructs a %shared_ptr instance from @a __r.
241 * @param __r A %shared_ptr rvalue.
242 * @post *this contains the old value of @a __r, @a __r is empty.
243 */
244 shared_ptr(shared_ptr&& __r) noexcept
245 : __shared_ptr<_Tp>(std::move(__r)) { }
246
247 /**
248 * @brief Move-constructs a %shared_ptr instance from @a __r.
249 * @param __r A %shared_ptr rvalue.
250 * @post *this contains the old value of @a __r, @a __r is empty.
251 */
252 template<typename _Yp, typename = _Constructible<shared_ptr<_Yp>>>
253 shared_ptr(shared_ptr<_Yp>&& __r) noexcept
254 : __shared_ptr<_Tp>(std::move(__r)) { }
255
256 /**
257 * @brief Constructs a %shared_ptr that shares ownership with @a __r
258 * and stores a copy of the pointer stored in @a __r.
259 * @param __r A weak_ptr.
260 * @post use_count() == __r.use_count()
261 * @throw bad_weak_ptr when __r.expired(),
262 * in which case the constructor has no effect.
263 */
264 template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>>
265 explicit shared_ptr(const weak_ptr<_Yp>& __r)
266 : __shared_ptr<_Tp>(__r) { }
267
268#if _GLIBCXX_USE_DEPRECATED1
269 template<typename _Yp, typename = _Constructible<auto_ptr<_Yp>>>
270 shared_ptr(auto_ptr<_Yp>&& __r);
271#endif
272
273 // _GLIBCXX_RESOLVE_LIB_DEFECTS
274 // 2399. shared_ptr's constructor from unique_ptr should be constrained
275 template<typename _Yp, typename _Del,
276 typename = _Constructible<unique_ptr<_Yp, _Del>>>
277 shared_ptr(unique_ptr<_Yp, _Del>&& __r)
278 : __shared_ptr<_Tp>(std::move(__r)) { }
279
280#if __cplusplus201103L <= 201402L && _GLIBCXX_USE_DEPRECATED1
281 // This non-standard constructor exists to support conversions that
282 // were possible in C++11 and C++14 but are ill-formed in C++17.
283 // If an exception is thrown this constructor has no effect.
284 template<typename _Yp, typename _Del,
285 _Constructible<unique_ptr<_Yp, _Del>, __sp_array_delete>* = 0>
286 shared_ptr(unique_ptr<_Yp, _Del>&& __r)
287 : __shared_ptr<_Tp>(std::move(__r), __sp_array_delete()) { }
288#endif
289
290 /**
291 * @brief Construct an empty %shared_ptr.
292 * @post use_count() == 0 && get() == nullptr
293 */
294 constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { }
295
296 shared_ptr& operator=(const shared_ptr&) noexcept = default;
13
Calling defaulted copy assignment operator for '__shared_ptr'
30
Returning; memory was released
41
Calling defaulted copy assignment operator for '__shared_ptr'
297
298 template<typename _Yp>
299 _Assignable<const shared_ptr<_Yp>&>
300 operator=(const shared_ptr<_Yp>& __r) noexcept
301 {
302 this->__shared_ptr<_Tp>::operator=(__r);
303 return *this;
304 }
305
306#if _GLIBCXX_USE_DEPRECATED1
307 template<typename _Yp>
308 _Assignable<auto_ptr<_Yp>>
309 operator=(auto_ptr<_Yp>&& __r)
310 {
311 this->__shared_ptr<_Tp>::operator=(std::move(__r));
312 return *this;
313 }
314#endif
315
316 shared_ptr&
317 operator=(shared_ptr&& __r) noexcept
318 {
319 this->__shared_ptr<_Tp>::operator=(std::move(__r));
320 return *this;
321 }
322
323 template<class _Yp>
324 _Assignable<shared_ptr<_Yp>>
325 operator=(shared_ptr<_Yp>&& __r) noexcept
326 {
327 this->__shared_ptr<_Tp>::operator=(std::move(__r));
328 return *this;
329 }
330
331 template<typename _Yp, typename _Del>
332 _Assignable<unique_ptr<_Yp, _Del>>
333 operator=(unique_ptr<_Yp, _Del>&& __r)
334 {
335 this->__shared_ptr<_Tp>::operator=(std::move(__r));
336 return *this;
337 }
338
339 private:
340 // This constructor is non-standard, it is used by allocate_shared.
341 template<typename _Alloc, typename... _Args>
342 shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
343 _Args&&... __args)
344 : __shared_ptr<_Tp>(__tag, __a, std::forward<_Args>(__args)...)
345 { }
346
347 template<typename _Yp, typename _Alloc, typename... _Args>
348 friend shared_ptr<_Yp>
349 allocate_shared(const _Alloc& __a, _Args&&... __args);
350
351 // This constructor is non-standard, it is used by weak_ptr::lock().
352 shared_ptr(const weak_ptr<_Tp>& __r, std::nothrow_t)
353 : __shared_ptr<_Tp>(__r, std::nothrow) { }
354
355 friend class weak_ptr<_Tp>;
356 };
357
358#if __cpp_deduction_guides >= 201606
359 template<typename _Tp>
360 shared_ptr(weak_ptr<_Tp>) -> shared_ptr<_Tp>;
361 template<typename _Tp, typename _Del>
362 shared_ptr(unique_ptr<_Tp, _Del>) -> shared_ptr<_Tp>;
363#endif
364
365 // 20.7.2.2.7 shared_ptr comparisons
366 template<typename _Tp, typename _Up>
367 inline bool
368 operator==(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
369 { return __a.get() == __b.get(); }
370
371 template<typename _Tp>
372 inline bool
373 operator==(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
374 { return !__a; }
375
376 template<typename _Tp>
377 inline bool
378 operator==(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
379 { return !__a; }
380
381 template<typename _Tp, typename _Up>
382 inline bool
383 operator!=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
384 { return __a.get() != __b.get(); }
385
386 template<typename _Tp>
387 inline bool
388 operator!=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
389 { return (bool)__a; }
390
391 template<typename _Tp>
392 inline bool
393 operator!=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
394 { return (bool)__a; }
395
396 template<typename _Tp, typename _Up>
397 inline bool
398 operator<(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
399 {
400 using _Tp_elt = typename shared_ptr<_Tp>::element_type;
401 using _Up_elt = typename shared_ptr<_Up>::element_type;
402 using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type;
403 return less<_Vp>()(__a.get(), __b.get());
404 }
405
406 template<typename _Tp>
407 inline bool
408 operator<(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
409 {
410 using _Tp_elt = typename shared_ptr<_Tp>::element_type;
411 return less<_Tp_elt*>()(__a.get(), nullptr);
412 }
413
414 template<typename _Tp>
415 inline bool
416 operator<(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
417 {
418 using _Tp_elt = typename shared_ptr<_Tp>::element_type;
419 return less<_Tp_elt*>()(nullptr, __a.get());
420 }
421
422 template<typename _Tp, typename _Up>
423 inline bool
424 operator<=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
425 { return !(__b < __a); }
426
427 template<typename _Tp>
428 inline bool
429 operator<=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
430 { return !(nullptr < __a); }
431
432 template<typename _Tp>
433 inline bool
434 operator<=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
435 { return !(__a < nullptr); }
436
437 template<typename _Tp, typename _Up>
438 inline bool
439 operator>(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
440 { return (__b < __a); }
441
442 template<typename _Tp>
443 inline bool
444 operator>(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
445 { return nullptr < __a; }
446
447 template<typename _Tp>
448 inline bool
449 operator>(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
450 { return __a < nullptr; }
451
452 template<typename _Tp, typename _Up>
453 inline bool
454 operator>=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
455 { return !(__a < __b); }
456
457 template<typename _Tp>
458 inline bool
459 operator>=(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
460 { return !(__a < nullptr); }
461
462 template<typename _Tp>
463 inline bool
464 operator>=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
465 { return !(nullptr < __a); }
466
467 template<typename _Tp>
468 struct less<shared_ptr<_Tp>> : public _Sp_less<shared_ptr<_Tp>>
469 { };
470
471 // 20.7.2.2.8 shared_ptr specialized algorithms.
472 template<typename _Tp>
473 inline void
474 swap(shared_ptr<_Tp>& __a, shared_ptr<_Tp>& __b) noexcept
475 { __a.swap(__b); }
476
477 // 20.7.2.2.9 shared_ptr casts.
478 template<typename _Tp, typename _Up>
479 inline shared_ptr<_Tp>
480 static_pointer_cast(const shared_ptr<_Up>& __r) noexcept
481 {
482 using _Sp = shared_ptr<_Tp>;
483 return _Sp(__r, static_cast<typename _Sp::element_type*>(__r.get()));
484 }
485
486 template<typename _Tp, typename _Up>
487 inline shared_ptr<_Tp>
488 const_pointer_cast(const shared_ptr<_Up>& __r) noexcept
489 {
490 using _Sp = shared_ptr<_Tp>;
491 return _Sp(__r, const_cast<typename _Sp::element_type*>(__r.get()));
492 }
493
494 template<typename _Tp, typename _Up>
495 inline shared_ptr<_Tp>
496 dynamic_pointer_cast(const shared_ptr<_Up>& __r) noexcept
497 {
498 using _Sp = shared_ptr<_Tp>;
499 if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get()))
500 return _Sp(__r, __p);
501 return _Sp();
502 }
503
504#if __cplusplus201103L > 201402L
505 template<typename _Tp, typename _Up>
506 inline shared_ptr<_Tp>
507 reinterpret_pointer_cast(const shared_ptr<_Up>& __r) noexcept
508 {
509 using _Sp = shared_ptr<_Tp>;
510 return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get()));
511 }
512#endif
513
514 /**
515 * @brief A smart pointer with weak semantics.
516 *
517 * With forwarding constructors and assignment operators.
518 */
519 template<typename _Tp>
520 class weak_ptr : public __weak_ptr<_Tp>
521 {
522 template<typename _Arg>
523 using _Constructible = typename enable_if<
524 is_constructible<__weak_ptr<_Tp>, _Arg>::value
525 >::type;
526
527 template<typename _Arg>
528 using _Assignable = typename enable_if<
529 is_assignable<__weak_ptr<_Tp>&, _Arg>::value, weak_ptr&
530 >::type;
531
532 public:
533 constexpr weak_ptr() noexcept = default;
534
535 template<typename _Yp,
536 typename = _Constructible<const shared_ptr<_Yp>&>>
537 weak_ptr(const shared_ptr<_Yp>& __r) noexcept
538 : __weak_ptr<_Tp>(__r) { }
539
540 weak_ptr(const weak_ptr&) noexcept = default;
541
542 template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>>
543 weak_ptr(const weak_ptr<_Yp>& __r) noexcept
544 : __weak_ptr<_Tp>(__r) { }
545
546 weak_ptr(weak_ptr&&) noexcept = default;
547
548 template<typename _Yp, typename = _Constructible<weak_ptr<_Yp>>>
549 weak_ptr(weak_ptr<_Yp>&& __r) noexcept
550 : __weak_ptr<_Tp>(std::move(__r)) { }
551
552 weak_ptr&
553 operator=(const weak_ptr& __r) noexcept = default;
554
555 template<typename _Yp>
556 _Assignable<const weak_ptr<_Yp>&>
557 operator=(const weak_ptr<_Yp>& __r) noexcept
558 {
559 this->__weak_ptr<_Tp>::operator=(__r);
560 return *this;
561 }
562
563 template<typename _Yp>
564 _Assignable<const shared_ptr<_Yp>&>
565 operator=(const shared_ptr<_Yp>& __r) noexcept
566 {
567 this->__weak_ptr<_Tp>::operator=(__r);
568 return *this;
569 }
570
571 weak_ptr&
572 operator=(weak_ptr&& __r) noexcept = default;
573
574 template<typename _Yp>
575 _Assignable<weak_ptr<_Yp>>
576 operator=(weak_ptr<_Yp>&& __r) noexcept
577 {
578 this->__weak_ptr<_Tp>::operator=(std::move(__r));
579 return *this;
580 }
581
582 shared_ptr<_Tp>
583 lock() const noexcept
584 { return shared_ptr<_Tp>(*this, std::nothrow); }
585 };
586
587#if __cpp_deduction_guides >= 201606
588 template<typename _Tp>
589 weak_ptr(shared_ptr<_Tp>) -> weak_ptr<_Tp>;
590#endif
591
592 // 20.7.2.3.6 weak_ptr specialized algorithms.
593 template<typename _Tp>
594 inline void
595 swap(weak_ptr<_Tp>& __a, weak_ptr<_Tp>& __b) noexcept
596 { __a.swap(__b); }
597
598
599 /// Primary template owner_less
600 template<typename _Tp = void>
601 struct owner_less;
602
603 /// Void specialization of owner_less
604 template<>
605 struct owner_less<void> : _Sp_owner_less<void, void>
606 { };
607
608 /// Partial specialization of owner_less for shared_ptr.
609 template<typename _Tp>
610 struct owner_less<shared_ptr<_Tp>>
611 : public _Sp_owner_less<shared_ptr<_Tp>, weak_ptr<_Tp>>
612 { };
613
614 /// Partial specialization of owner_less for weak_ptr.
615 template<typename _Tp>
616 struct owner_less<weak_ptr<_Tp>>
617 : public _Sp_owner_less<weak_ptr<_Tp>, shared_ptr<_Tp>>
618 { };
619
620 /**
621 * @brief Base class allowing use of member function shared_from_this.
622 */
623 template<typename _Tp>
624 class enable_shared_from_this
625 {
626 protected:
627 constexpr enable_shared_from_this() noexcept { }
628
629 enable_shared_from_this(const enable_shared_from_this&) noexcept { }
630
631 enable_shared_from_this&
632 operator=(const enable_shared_from_this&) noexcept
633 { return *this; }
634
635 ~enable_shared_from_this() { }
636
637 public:
638 shared_ptr<_Tp>
639 shared_from_this()
640 { return shared_ptr<_Tp>(this->_M_weak_this); }
641
642 shared_ptr<const _Tp>
643 shared_from_this() const
644 { return shared_ptr<const _Tp>(this->_M_weak_this); }
645
646#if __cplusplus201103L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11
647#define __cpp_lib_enable_shared_from_this 201603
648 weak_ptr<_Tp>
649 weak_from_this() noexcept
650 { return this->_M_weak_this; }
651
652 weak_ptr<const _Tp>
653 weak_from_this() const noexcept
654 { return this->_M_weak_this; }
655#endif
656
657 private:
658 template<typename _Tp1>
659 void
660 _M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const noexcept
661 { _M_weak_this._M_assign(__p, __n); }
662
663 // Found by ADL when this is an associated class.
664 friend const enable_shared_from_this*
665 __enable_shared_from_this_base(const __shared_count<>&,
666 const enable_shared_from_this* __p)
667 { return __p; }
668
669 template<typename, _Lock_policy>
670 friend class __shared_ptr;
671
672 mutable weak_ptr<_Tp> _M_weak_this;
673 };
674
675 /**
676 * @brief Create an object that is owned by a shared_ptr.
677 * @param __a An allocator.
678 * @param __args Arguments for the @a _Tp object's constructor.
679 * @return A shared_ptr that owns the newly created object.
680 * @throw An exception thrown from @a _Alloc::allocate or from the
681 * constructor of @a _Tp.
682 *
683 * A copy of @a __a will be used to allocate memory for the shared_ptr
684 * and the new object.
685 */
686 template<typename _Tp, typename _Alloc, typename... _Args>
687 inline shared_ptr<_Tp>
688 allocate_shared(const _Alloc& __a, _Args&&... __args)
689 {
690 return shared_ptr<_Tp>(_Sp_make_shared_tag(), __a,
691 std::forward<_Args>(__args)...);
692 }
693
694 /**
695 * @brief Create an object that is owned by a shared_ptr.
696 * @param __args Arguments for the @a _Tp object's constructor.
697 * @return A shared_ptr that owns the newly created object.
698 * @throw std::bad_alloc, or an exception thrown from the
699 * constructor of @a _Tp.
700 */
701 template<typename _Tp, typename... _Args>
702 inline shared_ptr<_Tp>
703 make_shared(_Args&&... __args)
704 {
705 typedef typename std::remove_const<_Tp>::type _Tp_nc;
706 return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(),
707 std::forward<_Args>(__args)...);
708 }
709
710 /// std::hash specialization for shared_ptr.
711 template<typename _Tp>
712 struct hash<shared_ptr<_Tp>>
713 : public __hash_base<size_t, shared_ptr<_Tp>>
714 {
715 size_t
716 operator()(const shared_ptr<_Tp>& __s) const noexcept
717 {
718 return std::hash<typename shared_ptr<_Tp>::element_type*>()(__s.get());
719 }
720 };
721
722 // @} group pointer_abstractions
723
724_GLIBCXX_END_NAMESPACE_VERSION
725} // namespace
726
727#endif // _SHARED_PTR_H

/usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/shared_ptr_base.h

1// shared_ptr and weak_ptr implementation details -*- C++ -*-
2
3// Copyright (C) 2007-2017 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25// GCC Note: Based on files from version 1.32.0 of the Boost library.
26
27// shared_count.hpp
28// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
29
30// shared_ptr.hpp
31// Copyright (C) 1998, 1999 Greg Colvin and Beman Dawes.
32// Copyright (C) 2001, 2002, 2003 Peter Dimov
33
34// weak_ptr.hpp
35// Copyright (C) 2001, 2002, 2003 Peter Dimov
36
37// enable_shared_from_this.hpp
38// Copyright (C) 2002 Peter Dimov
39
40// Distributed under the Boost Software License, Version 1.0. (See
41// accompanying file LICENSE_1_0.txt or copy at
42// http://www.boost.org/LICENSE_1_0.txt)
43
44/** @file bits/shared_ptr_base.h
45 * This is an internal header file, included by other library headers.
46 * Do not attempt to use it directly. @headername{memory}
47 */
48
49#ifndef _SHARED_PTR_BASE_H1
50#define _SHARED_PTR_BASE_H1 1
51
52#if __cpp_rtti199711
53# include <typeinfo>
54#endif
55#include <bits/allocated_ptr.h>
56#include <bits/refwrap.h>
57#include <bits/stl_function.h>
58#include <ext/aligned_buffer.h>
59
60namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
61{
62_GLIBCXX_BEGIN_NAMESPACE_VERSION
63
64#if _GLIBCXX_USE_DEPRECATED1
65 template<typename> class auto_ptr;
66#endif
67
68 /**
69 * @brief Exception possibly thrown by @c shared_ptr.
70 * @ingroup exceptions
71 */
72 class bad_weak_ptr : public std::exception
73 {
74 public:
75 virtual char const* what() const noexcept;
76
77 virtual ~bad_weak_ptr() noexcept;
78 };
79
80 // Substitute for bad_weak_ptr object in the case of -fno-exceptions.
81 inline void
82 __throw_bad_weak_ptr()
83 { _GLIBCXX_THROW_OR_ABORT(bad_weak_ptr())(__builtin_abort()); }
84
85 using __gnu_cxx::_Lock_policy;
86 using __gnu_cxx::__default_lock_policy;
87 using __gnu_cxx::_S_single;
88 using __gnu_cxx::_S_mutex;
89 using __gnu_cxx::_S_atomic;
90
91 // Empty helper class except when the template argument is _S_mutex.
92 template<_Lock_policy _Lp>
93 class _Mutex_base
94 {
95 protected:
96 // The atomic policy uses fully-fenced builtins, single doesn't care.
97 enum { _S_need_barriers = 0 };
98 };
99
100 template<>
101 class _Mutex_base<_S_mutex>
102 : public __gnu_cxx::__mutex
103 {
104 protected:
105 // This policy is used when atomic builtins are not available.
106 // The replacement atomic operations might not have the necessary
107 // memory barriers.
108 enum { _S_need_barriers = 1 };
109 };
110
111 template<_Lock_policy _Lp = __default_lock_policy>
112 class _Sp_counted_base
113 : public _Mutex_base<_Lp>
114 {
115 public:
116 _Sp_counted_base() noexcept
117 : _M_use_count(1), _M_weak_count(1) { }
118
119 virtual
120 ~_Sp_counted_base() noexcept
121 { }
122
123 // Called when _M_use_count drops to zero, to release the resources
124 // managed by *this.
125 virtual void
126 _M_dispose() noexcept = 0;
127
128 // Called when _M_weak_count drops to zero.
129 virtual void
130 _M_destroy() noexcept
131 { delete this; }
26
Memory is released
132
133 virtual void*
134 _M_get_deleter(const std::type_info&) noexcept = 0;
135
136 void
137 _M_add_ref_copy()
138 { __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); }
139
140 void
141 _M_add_ref_lock();
142
143 bool
144 _M_add_ref_lock_nothrow();
145
146 void
147 _M_release() noexcept
148 {
149 // Be race-detector-friendly. For more info see bits/c++config.
150 _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_use_count);
151 if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1)
20
Assuming the condition is true
21
Taking true branch
47
Calling '__exchange_and_add_dispatch'
152 {
153 _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_use_count);
154 _M_dispose();
155 // There must be a memory barrier between dispose() and destroy()
156 // to ensure that the effects of dispose() are observed in the
157 // thread that runs destroy().
158 // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html
159 if (_Mutex_base<_Lp>::_S_need_barriers)
22
Taking false branch
160 {
161 __atomic_thread_fence (__ATOMIC_ACQ_REL4);
162 }
163
164 // Be race-detector-friendly. For more info see bits/c++config.
165 _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
166 if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count,
23
Assuming the condition is true
24
Taking true branch
167 -1) == 1)
168 {
169 _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
170 _M_destroy();
25
Calling '_Sp_counted_base::_M_destroy'
27
Returning; memory was released
171 }
172 }
173 }
174
175 void
176 _M_weak_add_ref() noexcept
177 { __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); }
178
179 void
180 _M_weak_release() noexcept
181 {
182 // Be race-detector-friendly. For more info see bits/c++config.
183 _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_weak_count);
184 if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
185 {
186 _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_weak_count);
187 if (_Mutex_base<_Lp>::_S_need_barriers)
188 {
189 // See _M_release(),
190 // destroy() must observe results of dispose()
191 __atomic_thread_fence (__ATOMIC_ACQ_REL4);
192 }
193 _M_destroy();
194 }
195 }
196
197 long
198 _M_get_use_count() const noexcept
199 {
200 // No memory barrier is used here so there is no synchronization
201 // with other threads.
202 return __atomic_load_n(&_M_use_count, __ATOMIC_RELAXED0);
203 }
204
205 private:
206 _Sp_counted_base(_Sp_counted_base const&) = delete;
207 _Sp_counted_base& operator=(_Sp_counted_base const&) = delete;
208
209 _Atomic_word _M_use_count; // #shared
210 _Atomic_word _M_weak_count; // #weak + (#shared != 0)
211 };
212
213 template<>
214 inline void
215 _Sp_counted_base<_S_single>::
216 _M_add_ref_lock()
217 {
218 if (_M_use_count == 0)
219 __throw_bad_weak_ptr();
220 ++_M_use_count;
221 }
222
223 template<>
224 inline void
225 _Sp_counted_base<_S_mutex>::
226 _M_add_ref_lock()
227 {
228 __gnu_cxx::__scoped_lock sentry(*this);
229 if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
230 {
231 _M_use_count = 0;
232 __throw_bad_weak_ptr();
233 }
234 }
235
236 template<>
237 inline void
238 _Sp_counted_base<_S_atomic>::
239 _M_add_ref_lock()
240 {
241 // Perform lock-free add-if-not-zero operation.
242 _Atomic_word __count = _M_get_use_count();
243 do
244 {
245 if (__count == 0)
246 __throw_bad_weak_ptr();
247 // Replace the current counter value with the old value + 1, as
248 // long as it's not changed meanwhile.
249 }
250 while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1,
251 true, __ATOMIC_ACQ_REL4,
252 __ATOMIC_RELAXED0));
253 }
254
255 template<>
256 inline bool
257 _Sp_counted_base<_S_single>::
258 _M_add_ref_lock_nothrow()
259 {
260 if (_M_use_count == 0)
261 return false;
262 ++_M_use_count;
263 return true;
264 }
265
266 template<>
267 inline bool
268 _Sp_counted_base<_S_mutex>::
269 _M_add_ref_lock_nothrow()
270 {
271 __gnu_cxx::__scoped_lock sentry(*this);
272 if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
273 {
274 _M_use_count = 0;
275 return false;
276 }
277 return true;
278 }
279
280 template<>
281 inline bool
282 _Sp_counted_base<_S_atomic>::
283 _M_add_ref_lock_nothrow()
284 {
285 // Perform lock-free add-if-not-zero operation.
286 _Atomic_word __count = _M_get_use_count();
287 do
288 {
289 if (__count == 0)
290 return false;
291 // Replace the current counter value with the old value + 1, as
292 // long as it's not changed meanwhile.
293 }
294 while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1,
295 true, __ATOMIC_ACQ_REL4,
296 __ATOMIC_RELAXED0));
297 return true;
298 }
299
300 template<>
301 inline void
302 _Sp_counted_base<_S_single>::_M_add_ref_copy()
303 { ++_M_use_count; }
304
305 template<>
306 inline void
307 _Sp_counted_base<_S_single>::_M_release() noexcept
308 {
309 if (--_M_use_count == 0)
310 {
311 _M_dispose();
312 if (--_M_weak_count == 0)
313 _M_destroy();
314 }
315 }
316
317 template<>
318 inline void
319 _Sp_counted_base<_S_single>::_M_weak_add_ref() noexcept
320 { ++_M_weak_count; }
321
322 template<>
323 inline void
324 _Sp_counted_base<_S_single>::_M_weak_release() noexcept
325 {
326 if (--_M_weak_count == 0)
327 _M_destroy();
328 }
329
330 template<>
331 inline long
332 _Sp_counted_base<_S_single>::_M_get_use_count() const noexcept
333 { return _M_use_count; }
334
335
336 // Forward declarations.
337 template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
338 class __shared_ptr;
339
340 template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
341 class __weak_ptr;
342
343 template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
344 class __enable_shared_from_this;
345
346 template<typename _Tp>
347 class shared_ptr;
348
349 template<typename _Tp>
350 class weak_ptr;
351
352 template<typename _Tp>
353 struct owner_less;
354
355 template<typename _Tp>
356 class enable_shared_from_this;
357
358 template<_Lock_policy _Lp = __default_lock_policy>
359 class __weak_count;
360
361 template<_Lock_policy _Lp = __default_lock_policy>
362 class __shared_count;
363
364
365 // Counted ptr with no deleter or allocator support
366 template<typename _Ptr, _Lock_policy _Lp>
367 class _Sp_counted_ptr final : public _Sp_counted_base<_Lp>
368 {
369 public:
370 explicit
371 _Sp_counted_ptr(_Ptr __p) noexcept
372 : _M_ptr(__p) { }
373
374 virtual void
375 _M_dispose() noexcept
376 { delete _M_ptr; }
377
378 virtual void
379 _M_destroy() noexcept
380 { delete this; }
381
382 virtual void*
383 _M_get_deleter(const std::type_info&) noexcept
384 { return nullptr; }
385
386 _Sp_counted_ptr(const _Sp_counted_ptr&) = delete;
387 _Sp_counted_ptr& operator=(const _Sp_counted_ptr&) = delete;
388
389 private:
390 _Ptr _M_ptr;
391 };
392
393 template<>
394 inline void
395 _Sp_counted_ptr<nullptr_t, _S_single>::_M_dispose() noexcept { }
396
397 template<>
398 inline void
399 _Sp_counted_ptr<nullptr_t, _S_mutex>::_M_dispose() noexcept { }
400
401 template<>
402 inline void
403 _Sp_counted_ptr<nullptr_t, _S_atomic>::_M_dispose() noexcept { }
404
405 template<int _Nm, typename _Tp,
406 bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>
407 struct _Sp_ebo_helper;
408
409 /// Specialization using EBO.
410 template<int _Nm, typename _Tp>
411 struct _Sp_ebo_helper<_Nm, _Tp, true> : private _Tp
412 {
413 explicit _Sp_ebo_helper(const _Tp& __tp) : _Tp(__tp) { }
414 explicit _Sp_ebo_helper(_Tp&& __tp) : _Tp(std::move(__tp)) { }
415
416 static _Tp&
417 _S_get(_Sp_ebo_helper& __eboh) { return static_cast<_Tp&>(__eboh); }
418 };
419
420 /// Specialization not using EBO.
421 template<int _Nm, typename _Tp>
422 struct _Sp_ebo_helper<_Nm, _Tp, false>
423 {
424 explicit _Sp_ebo_helper(const _Tp& __tp) : _M_tp(__tp) { }
425 explicit _Sp_ebo_helper(_Tp&& __tp) : _M_tp(std::move(__tp)) { }
426
427 static _Tp&
428 _S_get(_Sp_ebo_helper& __eboh)
429 { return __eboh._M_tp; }
430
431 private:
432 _Tp _M_tp;
433 };
434
435 // Support for custom deleter and/or allocator
436 template<typename _Ptr, typename _Deleter, typename _Alloc, _Lock_policy _Lp>
437 class _Sp_counted_deleter final : public _Sp_counted_base<_Lp>
438 {
439 class _Impl : _Sp_ebo_helper<0, _Deleter>, _Sp_ebo_helper<1, _Alloc>
440 {
441 typedef _Sp_ebo_helper<0, _Deleter> _Del_base;
442 typedef _Sp_ebo_helper<1, _Alloc> _Alloc_base;
443
444 public:
445 _Impl(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept
446 : _M_ptr(__p), _Del_base(std::move(__d)), _Alloc_base(__a)
447 { }
448
449 _Deleter& _M_del() noexcept { return _Del_base::_S_get(*this); }
450 _Alloc& _M_alloc() noexcept { return _Alloc_base::_S_get(*this); }
451
452 _Ptr _M_ptr;
453 };
454
455 public:
456 using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_deleter>;
457
458 // __d(__p) must not throw.
459 _Sp_counted_deleter(_Ptr __p, _Deleter __d) noexcept
460 : _M_impl(__p, std::move(__d), _Alloc()) { }
461
462 // __d(__p) must not throw.
463 _Sp_counted_deleter(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept
464 : _M_impl(__p, std::move(__d), __a) { }
465
466 ~_Sp_counted_deleter() noexcept { }
467
468 virtual void
469 _M_dispose() noexcept
470 { _M_impl._M_del()(_M_impl._M_ptr); }
471
472 virtual void
473 _M_destroy() noexcept
474 {
475 __allocator_type __a(_M_impl._M_alloc());
476 __allocated_ptr<__allocator_type> __guard_ptr{ __a, this };
477 this->~_Sp_counted_deleter();
478 }
479
480 virtual void*
481 _M_get_deleter(const std::type_info& __ti) noexcept
482 {
483#if __cpp_rtti199711
484 // _GLIBCXX_RESOLVE_LIB_DEFECTS
485 // 2400. shared_ptr's get_deleter() should use addressof()
486 return __ti == typeid(_Deleter)
487 ? std::__addressof(_M_impl._M_del())
488 : nullptr;
489#else
490 return nullptr;
491#endif
492 }
493
494 private:
495 _Impl _M_impl;
496 };
497
498 // helpers for make_shared / allocate_shared
499
500 struct _Sp_make_shared_tag { };
501
502 template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
503 class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>
504 {
505 class _Impl : _Sp_ebo_helper<0, _Alloc>
506 {
507 typedef _Sp_ebo_helper<0, _Alloc> _A_base;
508
509 public:
510 explicit _Impl(_Alloc __a) noexcept : _A_base(__a) { }
511
512 _Alloc& _M_alloc() noexcept { return _A_base::_S_get(*this); }
513
514 __gnu_cxx::__aligned_buffer<_Tp> _M_storage;
515 };
516
517 public:
518 using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_ptr_inplace>;
519
520 template<typename... _Args>
521 _Sp_counted_ptr_inplace(_Alloc __a, _Args&&... __args)
522 : _M_impl(__a)
523 {
524 // _GLIBCXX_RESOLVE_LIB_DEFECTS
525 // 2070. allocate_shared should use allocator_traits<A>::construct
526 allocator_traits<_Alloc>::construct(__a, _M_ptr(),
527 std::forward<_Args>(__args)...); // might throw
528 }
529
530 ~_Sp_counted_ptr_inplace() noexcept { }
531
532 virtual void
533 _M_dispose() noexcept
534 {
535 allocator_traits<_Alloc>::destroy(_M_impl._M_alloc(), _M_ptr());
536 }
537
538 // Override because the allocator needs to know the dynamic type
539 virtual void
540 _M_destroy() noexcept
541 {
542 __allocator_type __a(_M_impl._M_alloc());
543 __allocated_ptr<__allocator_type> __guard_ptr{ __a, this };
544 this->~_Sp_counted_ptr_inplace();
545 }
546
547 // Sneaky trick so __shared_ptr can get the managed pointer
548 virtual void*
549 _M_get_deleter(const std::type_info& __ti) noexcept
550 {
551#if __cpp_rtti199711
552 if (__ti == typeid(_Sp_make_shared_tag))
553 return const_cast<typename remove_cv<_Tp>::type*>(_M_ptr());
554#endif
555 return nullptr;
556 }
557
558 private:
559 _Tp* _M_ptr() noexcept { return _M_impl._M_storage._M_ptr(); }
560
561 _Impl _M_impl;
562 };
563
564 // The default deleter for shared_ptr<T[]> and shared_ptr<T[N]>.
565 struct __sp_array_delete
566 {
567 template<typename _Yp>
568 void operator()(_Yp* __p) const { delete[] __p; }
569 };
570
571 template<_Lock_policy _Lp>
572 class __shared_count
573 {
574 public:
575 constexpr __shared_count() noexcept : _M_pi(0)
576 { }
577
578 template<typename _Ptr>
579 explicit
580 __shared_count(_Ptr __p) : _M_pi(0)
581 {
582 __tryif (true)
583 {
584 _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
585 }
586 __catch(...)if (false)
587 {
588 delete __p;
589 __throw_exception_again;
590 }
591 }
592
593 template<typename _Ptr>
594 __shared_count(_Ptr __p, /* is_array = */ false_type)
595 : __shared_count(__p)
596 { }
597
598 template<typename _Ptr>
599 __shared_count(_Ptr __p, /* is_array = */ true_type)
600 : __shared_count(__p, __sp_array_delete{}, allocator<void>())
601 { }
602
603 template<typename _Ptr, typename _Deleter>
604 __shared_count(_Ptr __p, _Deleter __d)
605 : __shared_count(__p, std::move(__d), allocator<void>())
606 { }
607
608 template<typename _Ptr, typename _Deleter, typename _Alloc>
609 __shared_count(_Ptr __p, _Deleter __d, _Alloc __a) : _M_pi(0)
610 {
611 typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type;
612 __tryif (true)
613 {
614 typename _Sp_cd_type::__allocator_type __a2(__a);
615 auto __guard = std::__allocate_guarded(__a2);
616 _Sp_cd_type* __mem = __guard.get();
617 ::new (__mem) _Sp_cd_type(__p, std::move(__d), std::move(__a));
618 _M_pi = __mem;
619 __guard = nullptr;
620 }
621 __catch(...)if (false)
622 {
623 __d(__p); // Call _Deleter on __p.
624 __throw_exception_again;
625 }
626 }
627
628 template<typename _Tp, typename _Alloc, typename... _Args>
629 __shared_count(_Sp_make_shared_tag, _Tp*, const _Alloc& __a,
630 _Args&&... __args)
631 : _M_pi(0)
632 {
633 typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type;
634 typename _Sp_cp_type::__allocator_type __a2(__a);
635 auto __guard = std::__allocate_guarded(__a2);
636 _Sp_cp_type* __mem = __guard.get();
637 ::new (__mem) _Sp_cp_type(std::move(__a),
638 std::forward<_Args>(__args)...);
639 _M_pi = __mem;
640 __guard = nullptr;
641 }
642
643#if _GLIBCXX_USE_DEPRECATED1
644 // Special case for auto_ptr<_Tp> to provide the strong guarantee.
645 template<typename _Tp>
646 explicit
647 __shared_count(std::auto_ptr<_Tp>&& __r);
648#endif
649
650 // Special case for unique_ptr<_Tp,_Del> to provide the strong guarantee.
651 template<typename _Tp, typename _Del>
652 explicit
653 __shared_count(std::unique_ptr<_Tp, _Del>&& __r) : _M_pi(0)
654 {
655 // _GLIBCXX_RESOLVE_LIB_DEFECTS
656 // 2415. Inconsistency between unique_ptr and shared_ptr
657 if (__r.get() == nullptr)
658 return;
659
660 using _Ptr = typename unique_ptr<_Tp, _Del>::pointer;
661 using _Del2 = typename conditional<is_reference<_Del>::value,
662 reference_wrapper<typename remove_reference<_Del>::type>,
663 _Del>::type;
664 using _Sp_cd_type
665 = _Sp_counted_deleter<_Ptr, _Del2, allocator<void>, _Lp>;
666 using _Alloc = allocator<_Sp_cd_type>;
667 using _Alloc_traits = allocator_traits<_Alloc>;
668 _Alloc __a;
669 _Sp_cd_type* __mem = _Alloc_traits::allocate(__a, 1);
670 _Alloc_traits::construct(__a, __mem, __r.release(),
671 __r.get_deleter()); // non-throwing
672 _M_pi = __mem;
673 }
674
675 // Throw bad_weak_ptr when __r._M_get_use_count() == 0.
676 explicit __shared_count(const __weak_count<_Lp>& __r);
677
678 // Does not throw if __r._M_get_use_count() == 0, caller must check.
679 explicit __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t);
680
681 ~__shared_count() noexcept
682 {
683 if (_M_pi != nullptr)
684 _M_pi->_M_release();
685 }
686
687 __shared_count(const __shared_count& __r) noexcept
688 : _M_pi(__r._M_pi)
689 {
690 if (_M_pi != 0)
691 _M_pi->_M_add_ref_copy();
692 }
693
694 __shared_count&
695 operator=(const __shared_count& __r) noexcept
696 {
697 _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
698 if (__tmp != _M_pi)
15
Taking true branch
43
Taking true branch
699 {
700 if (__tmp != 0)
16
Assuming '__tmp' is equal to null
17
Taking false branch
44
Taking false branch
701 __tmp->_M_add_ref_copy();
702 if (_M_pi != 0)
18
Taking true branch
45
Taking true branch
703 _M_pi->_M_release();
19
Calling '_Sp_counted_base::_M_release'
28
Returning; memory was released
46
Calling '_Sp_counted_base::_M_release'
704 _M_pi = __tmp;
705 }
706 return *this;
707 }
708
709 void
710 _M_swap(__shared_count& __r) noexcept
711 {
712 _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
713 __r._M_pi = _M_pi;
714 _M_pi = __tmp;
715 }
716
717 long
718 _M_get_use_count() const noexcept
719 { return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0; }
720
721 bool
722 _M_unique() const noexcept
723 { return this->_M_get_use_count() == 1; }
724
725 void*
726 _M_get_deleter(const std::type_info& __ti) const noexcept
727 { return _M_pi ? _M_pi->_M_get_deleter(__ti) : nullptr; }
728
729 bool
730 _M_less(const __shared_count& __rhs) const noexcept
731 { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }
732
733 bool
734 _M_less(const __weak_count<_Lp>& __rhs) const noexcept
735 { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }
736
737 // Friend function injected into enclosing namespace and found by ADL
738 friend inline bool
739 operator==(const __shared_count& __a, const __shared_count& __b) noexcept
740 { return __a._M_pi == __b._M_pi; }
741
742 private:
743 friend class __weak_count<_Lp>;
744
745 _Sp_counted_base<_Lp>* _M_pi;
746 };
747
748
749 template<_Lock_policy _Lp>
750 class __weak_count
751 {
752 public:
753 constexpr __weak_count() noexcept : _M_pi(nullptr)
754 { }
755
756 __weak_count(const __shared_count<_Lp>& __r) noexcept
757 : _M_pi(__r._M_pi)
758 {
759 if (_M_pi != nullptr)
760 _M_pi->_M_weak_add_ref();
761 }
762
763 __weak_count(const __weak_count& __r) noexcept
764 : _M_pi(__r._M_pi)
765 {
766 if (_M_pi != nullptr)
767 _M_pi->_M_weak_add_ref();
768 }
769
770 __weak_count(__weak_count&& __r) noexcept
771 : _M_pi(__r._M_pi)
772 { __r._M_pi = nullptr; }
773
774 ~__weak_count() noexcept
775 {
776 if (_M_pi != nullptr)
777 _M_pi->_M_weak_release();
778 }
779
780 __weak_count&
781 operator=(const __shared_count<_Lp>& __r) noexcept
782 {
783 _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
784 if (__tmp != nullptr)
785 __tmp->_M_weak_add_ref();
786 if (_M_pi != nullptr)
787 _M_pi->_M_weak_release();
788 _M_pi = __tmp;
789 return *this;
790 }
791
792 __weak_count&
793 operator=(const __weak_count& __r) noexcept
794 {
795 _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
796 if (__tmp != nullptr)
797 __tmp->_M_weak_add_ref();
798 if (_M_pi != nullptr)
799 _M_pi->_M_weak_release();
800 _M_pi = __tmp;
801 return *this;
802 }
803
804 __weak_count&
805 operator=(__weak_count&& __r) noexcept
806 {
807 if (_M_pi != nullptr)
808 _M_pi->_M_weak_release();
809 _M_pi = __r._M_pi;
810 __r._M_pi = nullptr;
811 return *this;
812 }
813
814 void
815 _M_swap(__weak_count& __r) noexcept
816 {
817 _Sp_counted_base<_Lp>* __tmp = __r._M_pi;
818 __r._M_pi = _M_pi;
819 _M_pi = __tmp;
820 }
821
822 long
823 _M_get_use_count() const noexcept
824 { return _M_pi != nullptr ? _M_pi->_M_get_use_count() : 0; }
825
826 bool
827 _M_less(const __weak_count& __rhs) const noexcept
828 { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }
829
830 bool
831 _M_less(const __shared_count<_Lp>& __rhs) const noexcept
832 { return std::less<_Sp_counted_base<_Lp>*>()(this->_M_pi, __rhs._M_pi); }
833
834 // Friend function injected into enclosing namespace and found by ADL
835 friend inline bool
836 operator==(const __weak_count& __a, const __weak_count& __b) noexcept
837 { return __a._M_pi == __b._M_pi; }
838
839 private:
840 friend class __shared_count<_Lp>;
841
842 _Sp_counted_base<_Lp>* _M_pi;
843 };
844
845 // Now that __weak_count is defined we can define this constructor:
846 template<_Lock_policy _Lp>
847 inline
848 __shared_count<_Lp>::__shared_count(const __weak_count<_Lp>& __r)
849 : _M_pi(__r._M_pi)
850 {
851 if (_M_pi != nullptr)
852 _M_pi->_M_add_ref_lock();
853 else
854 __throw_bad_weak_ptr();
855 }
856
857 // Now that __weak_count is defined we can define this constructor:
858 template<_Lock_policy _Lp>
859 inline
860 __shared_count<_Lp>::
861 __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t)
862 : _M_pi(__r._M_pi)
863 {
864 if (_M_pi != nullptr)
865 if (!_M_pi->_M_add_ref_lock_nothrow())
866 _M_pi = nullptr;
867 }
868
869#define __cpp_lib_shared_ptr_arrays201603 201603
870
871 // Helper traits for shared_ptr of array:
872
873 // A pointer type Y* is said to be compatible with a pointer type T* when
874 // either Y* is convertible to T* or Y is U[N] and T is U cv [].
875 template<typename _Yp_ptr, typename _Tp_ptr>
876 struct __sp_compatible_with
877 : false_type
878 { };
879
880 template<typename _Yp, typename _Tp>
881 struct __sp_compatible_with<_Yp*, _Tp*>
882 : is_convertible<_Yp*, _Tp*>::type
883 { };
884
885 template<typename _Up, size_t _Nm>
886 struct __sp_compatible_with<_Up(*)[_Nm], _Up(*)[]>
887 : true_type
888 { };
889
890 template<typename _Up, size_t _Nm>
891 struct __sp_compatible_with<_Up(*)[_Nm], const _Up(*)[]>
892 : true_type
893 { };
894
895 template<typename _Up, size_t _Nm>
896 struct __sp_compatible_with<_Up(*)[_Nm], volatile _Up(*)[]>
897 : true_type
898 { };
899
900 template<typename _Up, size_t _Nm>
901 struct __sp_compatible_with<_Up(*)[_Nm], const volatile _Up(*)[]>
902 : true_type
903 { };
904
905 // Test conversion from Y(*)[N] to U(*)[N] without forming invalid type Y[N].
906 template<typename _Up, size_t _Nm, typename _Yp, typename = void>
907 struct __sp_is_constructible_arrN
908 : false_type
909 { };
910
911 template<typename _Up, size_t _Nm, typename _Yp>
912 struct __sp_is_constructible_arrN<_Up, _Nm, _Yp, __void_t<_Yp[_Nm]>>
913 : is_convertible<_Yp(*)[_Nm], _Up(*)[_Nm]>::type
914 { };
915
916 // Test conversion from Y(*)[] to U(*)[] without forming invalid type Y[].
917 template<typename _Up, typename _Yp, typename = void>
918 struct __sp_is_constructible_arr
919 : false_type
920 { };
921
922 template<typename _Up, typename _Yp>
923 struct __sp_is_constructible_arr<_Up, _Yp, __void_t<_Yp[]>>
924 : is_convertible<_Yp(*)[], _Up(*)[]>::type
925 { };
926
927 // Trait to check if shared_ptr<T> can be constructed from Y*.
928 template<typename _Tp, typename _Yp>
929 struct __sp_is_constructible;
930
931 // When T is U[N], Y(*)[N] shall be convertible to T*;
932 template<typename _Up, size_t _Nm, typename _Yp>
933 struct __sp_is_constructible<_Up[_Nm], _Yp>
934 : __sp_is_constructible_arrN<_Up, _Nm, _Yp>::type
935 { };
936
937 // when T is U[], Y(*)[] shall be convertible to T*;
938 template<typename _Up, typename _Yp>
939 struct __sp_is_constructible<_Up[], _Yp>
940 : __sp_is_constructible_arr<_Up, _Yp>::type
941 { };
942
943 // otherwise, Y* shall be convertible to T*.
944 template<typename _Tp, typename _Yp>
945 struct __sp_is_constructible
946 : is_convertible<_Yp*, _Tp*>::type
947 { };
948
949
950 // Define operator* and operator-> for shared_ptr<T>.
951 template<typename _Tp, _Lock_policy _Lp,
952 bool = is_array<_Tp>::value, bool = is_void<_Tp>::value>
953 class __shared_ptr_access
954 {
955 public:
956 using element_type = _Tp;
957
958 element_type&
959 operator*() const noexcept
960 {
961 __glibcxx_assert(_M_get() != nullptr);
962 return *_M_get();
963 }
964
965 element_type*
966 operator->() const noexcept
967 {
968 _GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr);
969 return _M_get();
970 }
971
972 private:
973 element_type*
974 _M_get() const noexcept
975 { return static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); }
976 };
977
978 // Define operator-> for shared_ptr<cv void>.
979 template<typename _Tp, _Lock_policy _Lp>
980 class __shared_ptr_access<_Tp, _Lp, false, true>
981 {
982 public:
983 using element_type = _Tp;
984
985 element_type*
986 operator->() const noexcept
987 {
988 auto __ptr = static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get();
989 _GLIBCXX_DEBUG_PEDASSERT(__ptr != nullptr);
990 return __ptr;
991 }
992 };
993
994 // Define operator[] for shared_ptr<T[]> and shared_ptr<T[N]>.
995 template<typename _Tp, _Lock_policy _Lp>
996 class __shared_ptr_access<_Tp, _Lp, true, false>
997 {
998 public:
999 using element_type = typename remove_extent<_Tp>::type;
1000
1001#if __cplusplus201103L <= 201402L
1002 [[__deprecated__("shared_ptr<T[]>::operator* is absent from C++17")]]
1003 element_type&
1004 operator*() const noexcept
1005 {
1006 __glibcxx_assert(_M_get() != nullptr);
1007 return *_M_get();
1008 }
1009
1010 [[__deprecated__("shared_ptr<T[]>::operator-> is absent from C++17")]]
1011 element_type*
1012 operator->() const noexcept
1013 {
1014 _GLIBCXX_DEBUG_PEDASSERT(_M_get() != nullptr);
1015 return _M_get();
1016 }
1017#endif
1018
1019 element_type&
1020 operator[](ptrdiff_t __i) const
1021 {
1022 __glibcxx_assert(_M_get() != nullptr);
1023 __glibcxx_assert(!extent<_Tp>::value || __i < extent<_Tp>::value);
1024 return _M_get()[__i];
1025 }
1026
1027 private:
1028 element_type*
1029 _M_get() const noexcept
1030 { return static_cast<const __shared_ptr<_Tp, _Lp>*>(this)->get(); }
1031 };
1032
1033 template<typename _Tp, _Lock_policy _Lp>
1034 class __shared_ptr
1035 : public __shared_ptr_access<_Tp, _Lp>
1036 {
1037 public:
1038 using element_type = typename remove_extent<_Tp>::type;
1039
1040 private:
1041 // Constraint for taking ownership of a pointer of type _Yp*:
1042 template<typename _Yp>
1043 using _SafeConv
1044 = typename enable_if<__sp_is_constructible<_Tp, _Yp>::value>::type;
1045
1046 // Constraint for construction from shared_ptr and weak_ptr:
1047 template<typename _Yp, typename _Res = void>
1048 using _Compatible = typename
1049 enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type;
1050
1051 // Constraint for assignment from shared_ptr and weak_ptr:
1052 template<typename _Yp>
1053 using _Assignable = _Compatible<_Yp, __shared_ptr&>;
1054
1055 // Constraint for construction from unique_ptr:
1056 template<typename _Yp, typename _Del, typename _Res = void,
1057 typename _Ptr = typename unique_ptr<_Yp, _Del>::pointer>
1058 using _UniqCompatible = typename enable_if<__and_<
1059 __sp_compatible_with<_Yp*, _Tp*>, is_convertible<_Ptr, element_type*>
1060 >::value, _Res>::type;
1061
1062 // Constraint for assignment from unique_ptr:
1063 template<typename _Yp, typename _Del>
1064 using _UniqAssignable = _UniqCompatible<_Yp, _Del, __shared_ptr&>;
1065
1066 public:
1067
1068#if __cplusplus201103L > 201402L
1069 using weak_type = __weak_ptr<_Tp, _Lp>;
1070#endif
1071
1072 constexpr __shared_ptr() noexcept
1073 : _M_ptr(0), _M_refcount()
1074 { }
1075
1076 template<typename _Yp, typename = _SafeConv<_Yp>>
1077 explicit
1078 __shared_ptr(_Yp* __p)
1079 : _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type())
1080 {
1081 static_assert( !is_void<_Yp>::value, "incomplete type" );
1082 static_assert( sizeof(_Yp) > 0, "incomplete type" );
1083 _M_enable_shared_from_this_with(__p);
1084 }
1085
1086 template<typename _Yp, typename _Deleter, typename = _SafeConv<_Yp>>
1087 __shared_ptr(_Yp* __p, _Deleter __d)
1088 : _M_ptr(__p), _M_refcount(__p, std::move(__d))
1089 {
1090 static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
1091 "deleter expression d(p) is well-formed");
1092 _M_enable_shared_from_this_with(__p);
1093 }
1094
1095 template<typename _Yp, typename _Deleter, typename _Alloc,
1096 typename = _SafeConv<_Yp>>
1097 __shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
1098 : _M_ptr(__p), _M_refcount(__p, std::move(__d), std::move(__a))
1099 {
1100 static_assert(__is_invocable<_Deleter&, _Yp*&>::value,
1101 "deleter expression d(p) is well-formed");
1102 _M_enable_shared_from_this_with(__p);
1103 }
1104
1105 template<typename _Deleter>
1106 __shared_ptr(nullptr_t __p, _Deleter __d)
1107 : _M_ptr(0), _M_refcount(__p, std::move(__d))
1108 { }
1109
1110 template<typename _Deleter, typename _Alloc>
1111 __shared_ptr(nullptr_t __p, _Deleter __d, _Alloc __a)
1112 : _M_ptr(0), _M_refcount(__p, std::move(__d), std::move(__a))
1113 { }
1114
1115 template<typename _Yp>
1116 __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r,
1117 element_type* __p) noexcept
1118 : _M_ptr(__p), _M_refcount(__r._M_refcount) // never throws
1119 { }
1120
1121 __shared_ptr(const __shared_ptr&) noexcept = default;
1122 __shared_ptr& operator=(const __shared_ptr&) noexcept = default;
14
Calling copy assignment operator for '__shared_count'
29
Returning; memory was released
42
Calling copy assignment operator for '__shared_count'
1123 ~__shared_ptr() = default;
1124
1125 template<typename _Yp, typename = _Compatible<_Yp>>
1126 __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept
1127 : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount)
1128 { }
1129
1130 __shared_ptr(__shared_ptr&& __r) noexcept
1131 : _M_ptr(__r._M_ptr), _M_refcount()
1132 {
1133 _M_refcount._M_swap(__r._M_refcount);
1134 __r._M_ptr = 0;
1135 }
1136
1137 template<typename _Yp, typename = _Compatible<_Yp>>
1138 __shared_ptr(__shared_ptr<_Yp, _Lp>&& __r) noexcept
1139 : _M_ptr(__r._M_ptr), _M_refcount()
1140 {
1141 _M_refcount._M_swap(__r._M_refcount);
1142 __r._M_ptr = 0;
1143 }
1144
1145 template<typename _Yp, typename = _Compatible<_Yp>>
1146 explicit __shared_ptr(const __weak_ptr<_Yp, _Lp>& __r)
1147 : _M_refcount(__r._M_refcount) // may throw
1148 {
1149 // It is now safe to copy __r._M_ptr, as
1150 // _M_refcount(__r._M_refcount) did not throw.
1151 _M_ptr = __r._M_ptr;
1152 }
1153
1154 // If an exception is thrown this constructor has no effect.
1155 template<typename _Yp, typename _Del,
1156 typename = _UniqCompatible<_Yp, _Del>>
1157 __shared_ptr(unique_ptr<_Yp, _Del>&& __r)
1158 : _M_ptr(__r.get()), _M_refcount()
1159 {
1160 auto __raw = _S_raw_ptr(__r.get());
1161 _M_refcount = __shared_count<_Lp>(std::move(__r));
1162 _M_enable_shared_from_this_with(__raw);
1163 }
1164
1165#if __cplusplus201103L <= 201402L && _GLIBCXX_USE_DEPRECATED1
1166 protected:
1167 // If an exception is thrown this constructor has no effect.
1168 template<typename _Tp1, typename _Del,
1169 typename enable_if<__and_<
1170 __not_<is_array<_Tp>>, is_array<_Tp1>,
1171 is_convertible<typename unique_ptr<_Tp1, _Del>::pointer, _Tp*>
1172 >::value, bool>::type = true>
1173 __shared_ptr(unique_ptr<_Tp1, _Del>&& __r, __sp_array_delete)
1174 : _M_ptr(__r.get()), _M_refcount()
1175 {
1176 auto __raw = _S_raw_ptr(__r.get());
1177 _M_refcount = __shared_count<_Lp>(std::move(__r));
1178 _M_enable_shared_from_this_with(__raw);
1179 }
1180 public:
1181#endif
1182
1183#if _GLIBCXX_USE_DEPRECATED1
1184 // Postcondition: use_count() == 1 and __r.get() == 0
1185 template<typename _Yp, typename = _Compatible<_Yp>>
1186 __shared_ptr(auto_ptr<_Yp>&& __r);
1187#endif
1188
1189 constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { }
1190
1191 template<typename _Yp>
1192 _Assignable<_Yp>
1193 operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept
1194 {
1195 _M_ptr = __r._M_ptr;
1196 _M_refcount = __r._M_refcount; // __shared_count::op= doesn't throw
1197 return *this;
1198 }
1199
1200#if _GLIBCXX_USE_DEPRECATED1
1201 template<typename _Yp>
1202 _Assignable<_Yp>
1203 operator=(auto_ptr<_Yp>&& __r)
1204 {
1205 __shared_ptr(std::move(__r)).swap(*this);
1206 return *this;
1207 }
1208#endif
1209
1210 __shared_ptr&
1211 operator=(__shared_ptr&& __r) noexcept
1212 {
1213 __shared_ptr(std::move(__r)).swap(*this);
1214 return *this;
1215 }
1216
1217 template<class _Yp>
1218 _Assignable<_Yp>
1219 operator=(__shared_ptr<_Yp, _Lp>&& __r) noexcept
1220 {
1221 __shared_ptr(std::move(__r)).swap(*this);
1222 return *this;
1223 }
1224
1225 template<typename _Yp, typename _Del>
1226 _UniqAssignable<_Yp, _Del>
1227 operator=(unique_ptr<_Yp, _Del>&& __r)
1228 {
1229 __shared_ptr(std::move(__r)).swap(*this);
1230 return *this;
1231 }
1232
1233 void
1234 reset() noexcept
1235 { __shared_ptr().swap(*this); }
1236
1237 template<typename _Yp>
1238 _SafeConv<_Yp>
1239 reset(_Yp* __p) // _Yp must be complete.
1240 {
1241 // Catch self-reset errors.
1242 __glibcxx_assert(__p == 0 || __p != _M_ptr);
1243 __shared_ptr(__p).swap(*this);
1244 }
1245
1246 template<typename _Yp, typename _Deleter>
1247 _SafeConv<_Yp>
1248 reset(_Yp* __p, _Deleter __d)
1249 { __shared_ptr(__p, std::move(__d)).swap(*this); }
1250
1251 template<typename _Yp, typename _Deleter, typename _Alloc>
1252 _SafeConv<_Yp>
1253 reset(_Yp* __p, _Deleter __d, _Alloc __a)
1254 { __shared_ptr(__p, std::move(__d), std::move(__a)).swap(*this); }
1255
1256 element_type*
1257 get() const noexcept
1258 { return _M_ptr; }
1259
1260 explicit operator bool() const // never throws
1261 { return _M_ptr == 0 ? false : true; }
1262
1263 bool
1264 unique() const noexcept
1265 { return _M_refcount._M_unique(); }
1266
1267 long
1268 use_count() const noexcept
1269 { return _M_refcount._M_get_use_count(); }
1270
1271 void
1272 swap(__shared_ptr<_Tp, _Lp>& __other) noexcept
1273 {
1274 std::swap(_M_ptr, __other._M_ptr);
1275 _M_refcount._M_swap(__other._M_refcount);
1276 }
1277
1278 template<typename _Tp1>
1279 bool
1280 owner_before(__shared_ptr<_Tp1, _Lp> const& __rhs) const noexcept
1281 { return _M_refcount._M_less(__rhs._M_refcount); }
1282
1283 template<typename _Tp1>
1284 bool
1285 owner_before(__weak_ptr<_Tp1, _Lp> const& __rhs) const noexcept
1286 { return _M_refcount._M_less(__rhs._M_refcount); }
1287
1288#if __cpp_rtti199711
1289 protected:
1290 // This constructor is non-standard, it is used by allocate_shared.
1291 template<typename _Alloc, typename... _Args>
1292 __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
1293 _Args&&... __args)
1294 : _M_ptr(), _M_refcount(__tag, (_Tp*)0, __a,
1295 std::forward<_Args>(__args)...)
1296 {
1297 // _M_ptr needs to point to the newly constructed object.
1298 // This relies on _Sp_counted_ptr_inplace::_M_get_deleter.
1299 void* __p = _M_refcount._M_get_deleter(typeid(__tag));
1300 _M_ptr = static_cast<_Tp*>(__p);
1301 _M_enable_shared_from_this_with(_M_ptr);
1302 }
1303#else
1304 template<typename _Alloc>
1305 struct _Deleter
1306 {
1307 void operator()(typename _Alloc::value_type* __ptr)
1308 {
1309 __allocated_ptr<_Alloc> __guard{ _M_alloc, __ptr };
1310 allocator_traits<_Alloc>::destroy(_M_alloc, __guard.get());
1311 }
1312 _Alloc _M_alloc;
1313 };
1314
1315 template<typename _Alloc, typename... _Args>
1316 __shared_ptr(_Sp_make_shared_tag __tag, const _Alloc& __a,
1317 _Args&&... __args)
1318 : _M_ptr(), _M_refcount()
1319 {
1320 typedef typename allocator_traits<_Alloc>::template
1321 rebind_traits<typename std::remove_cv<_Tp>::type> __traits;
1322 _Deleter<typename __traits::allocator_type> __del = { __a };
1323 auto __guard = std::__allocate_guarded(__del._M_alloc);
1324 auto __ptr = __guard.get();
1325 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1326 // 2070. allocate_shared should use allocator_traits<A>::construct
1327 __traits::construct(__del._M_alloc, __ptr,
1328 std::forward<_Args>(__args)...);
1329 __guard = nullptr;
1330 __shared_count<_Lp> __count(__ptr, __del, __del._M_alloc);
1331 _M_refcount._M_swap(__count);
1332 _M_ptr = __ptr;
1333 _M_enable_shared_from_this_with(_M_ptr);
1334 }
1335#endif
1336
1337 template<typename _Tp1, _Lock_policy _Lp1, typename _Alloc,
1338 typename... _Args>
1339 friend __shared_ptr<_Tp1, _Lp1>
1340 __allocate_shared(const _Alloc& __a, _Args&&... __args);
1341
1342 // This constructor is used by __weak_ptr::lock() and
1343 // shared_ptr::shared_ptr(const weak_ptr&, std::nothrow_t).
1344 __shared_ptr(const __weak_ptr<_Tp, _Lp>& __r, std::nothrow_t)
1345 : _M_refcount(__r._M_refcount, std::nothrow)
1346 {
1347 _M_ptr = _M_refcount._M_get_use_count() ? __r._M_ptr : nullptr;
1348 }
1349
1350 friend class __weak_ptr<_Tp, _Lp>;
1351
1352 private:
1353
1354 template<typename _Yp>
1355 using __esft_base_t = decltype(__enable_shared_from_this_base(
1356 std::declval<const __shared_count<_Lp>&>(),
1357 std::declval<_Yp*>()));
1358
1359 // Detect an accessible and unambiguous enable_shared_from_this base.
1360 template<typename _Yp, typename = void>
1361 struct __has_esft_base
1362 : false_type { };
1363
1364 template<typename _Yp>
1365 struct __has_esft_base<_Yp, __void_t<__esft_base_t<_Yp>>>
1366 : __not_<is_array<_Tp>> { }; // No enable shared_from_this for arrays
1367
1368 template<typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type>
1369 typename enable_if<__has_esft_base<_Yp2>::value>::type
1370 _M_enable_shared_from_this_with(_Yp* __p) noexcept
1371 {
1372 if (auto __base = __enable_shared_from_this_base(_M_refcount, __p))
1373 __base->_M_weak_assign(const_cast<_Yp2*>(__p), _M_refcount);
1374 }
1375
1376 template<typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type>
1377 typename enable_if<!__has_esft_base<_Yp2>::value>::type
1378 _M_enable_shared_from_this_with(_Yp*) noexcept
1379 { }
1380
1381 void*
1382 _M_get_deleter(const std::type_info& __ti) const noexcept
1383 { return _M_refcount._M_get_deleter(__ti); }
1384
1385 template<typename _Tp1>
1386 static _Tp1*
1387 _S_raw_ptr(_Tp1* __ptr)
1388 { return __ptr; }
1389
1390 template<typename _Tp1>
1391 static auto
1392 _S_raw_ptr(_Tp1 __ptr) -> decltype(std::__addressof(*__ptr))
1393 { return std::__addressof(*__ptr); }
1394
1395 template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
1396 template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;
1397
1398 template<typename _Del, typename _Tp1, _Lock_policy _Lp1>
1399 friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&) noexcept;
1400
1401 element_type* _M_ptr; // Contained pointer.
1402 __shared_count<_Lp> _M_refcount; // Reference counter.
1403 };
1404
1405
1406 // 20.7.2.2.7 shared_ptr comparisons
1407 template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
1408 inline bool
1409 operator==(const __shared_ptr<_Tp1, _Lp>& __a,
1410 const __shared_ptr<_Tp2, _Lp>& __b) noexcept
1411 { return __a.get() == __b.get(); }
1412
1413 template<typename _Tp, _Lock_policy _Lp>
1414 inline bool
1415 operator==(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
1416 { return !__a; }
1417
1418 template<typename _Tp, _Lock_policy _Lp>
1419 inline bool
1420 operator==(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
1421 { return !__a; }
1422
1423 template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
1424 inline bool
1425 operator!=(const __shared_ptr<_Tp1, _Lp>& __a,
1426 const __shared_ptr<_Tp2, _Lp>& __b) noexcept
1427 { return __a.get() != __b.get(); }
1428
1429 template<typename _Tp, _Lock_policy _Lp>
1430 inline bool
1431 operator!=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
1432 { return (bool)__a; }
1433
1434 template<typename _Tp, _Lock_policy _Lp>
1435 inline bool
1436 operator!=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
1437 { return (bool)__a; }
1438
1439 template<typename _Tp, typename _Up, _Lock_policy _Lp>
1440 inline bool
1441 operator<(const __shared_ptr<_Tp, _Lp>& __a,
1442 const __shared_ptr<_Up, _Lp>& __b) noexcept
1443 {
1444 using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type;
1445 using _Up_elt = typename __shared_ptr<_Up, _Lp>::element_type;
1446 using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type;
1447 return less<_Vp>()(__a.get(), __b.get());
1448 }
1449
1450 template<typename _Tp, _Lock_policy _Lp>
1451 inline bool
1452 operator<(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
1453 {
1454 using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type;
1455 return less<_Tp_elt*>()(__a.get(), nullptr);
1456 }
1457
1458 template<typename _Tp, _Lock_policy _Lp>
1459 inline bool
1460 operator<(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
1461 {
1462 using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type;
1463 return less<_Tp_elt*>()(nullptr, __a.get());
1464 }
1465
1466 template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
1467 inline bool
1468 operator<=(const __shared_ptr<_Tp1, _Lp>& __a,
1469 const __shared_ptr<_Tp2, _Lp>& __b) noexcept
1470 { return !(__b < __a); }
1471
1472 template<typename _Tp, _Lock_policy _Lp>
1473 inline bool
1474 operator<=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
1475 { return !(nullptr < __a); }
1476
1477 template<typename _Tp, _Lock_policy _Lp>
1478 inline bool
1479 operator<=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
1480 { return !(__a < nullptr); }
1481
1482 template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
1483 inline bool
1484 operator>(const __shared_ptr<_Tp1, _Lp>& __a,
1485 const __shared_ptr<_Tp2, _Lp>& __b) noexcept
1486 { return (__b < __a); }
1487
1488 template<typename _Tp, _Lock_policy _Lp>
1489 inline bool
1490 operator>(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
1491 { return nullptr < __a; }
1492
1493 template<typename _Tp, _Lock_policy _Lp>
1494 inline bool
1495 operator>(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
1496 { return __a < nullptr; }
1497
1498 template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
1499 inline bool
1500 operator>=(const __shared_ptr<_Tp1, _Lp>& __a,
1501 const __shared_ptr<_Tp2, _Lp>& __b) noexcept
1502 { return !(__a < __b); }
1503
1504 template<typename _Tp, _Lock_policy _Lp>
1505 inline bool
1506 operator>=(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
1507 { return !(__a < nullptr); }
1508
1509 template<typename _Tp, _Lock_policy _Lp>
1510 inline bool
1511 operator>=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
1512 { return !(nullptr < __a); }
1513
1514 template<typename _Sp>
1515 struct _Sp_less : public binary_function<_Sp, _Sp, bool>
1516 {
1517 bool
1518 operator()(const _Sp& __lhs, const _Sp& __rhs) const noexcept
1519 {
1520 typedef typename _Sp::element_type element_type;
1521 return std::less<element_type*>()(__lhs.get(), __rhs.get());
1522 }
1523 };
1524
1525 template<typename _Tp, _Lock_policy _Lp>
1526 struct less<__shared_ptr<_Tp, _Lp>>
1527 : public _Sp_less<__shared_ptr<_Tp, _Lp>>
1528 { };
1529
1530 // 20.7.2.2.8 shared_ptr specialized algorithms.
1531 template<typename _Tp, _Lock_policy _Lp>
1532 inline void
1533 swap(__shared_ptr<_Tp, _Lp>& __a, __shared_ptr<_Tp, _Lp>& __b) noexcept
1534 { __a.swap(__b); }
1535
1536 // 20.7.2.2.9 shared_ptr casts
1537
1538 // The seemingly equivalent code:
1539 // shared_ptr<_Tp, _Lp>(static_cast<_Tp*>(__r.get()))
1540 // will eventually result in undefined behaviour, attempting to
1541 // delete the same object twice.
1542 /// static_pointer_cast
1543 template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
1544 inline __shared_ptr<_Tp, _Lp>
1545 static_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
1546 {
1547 using _Sp = __shared_ptr<_Tp, _Lp>;
1548 return _Sp(__r, static_cast<typename _Sp::element_type*>(__r.get()));
1549 }
1550
1551 // The seemingly equivalent code:
1552 // shared_ptr<_Tp, _Lp>(const_cast<_Tp*>(__r.get()))
1553 // will eventually result in undefined behaviour, attempting to
1554 // delete the same object twice.
1555 /// const_pointer_cast
1556 template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
1557 inline __shared_ptr<_Tp, _Lp>
1558 const_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
1559 {
1560 using _Sp = __shared_ptr<_Tp, _Lp>;
1561 return _Sp(__r, const_cast<typename _Sp::element_type*>(__r.get()));
1562 }
1563
1564 // The seemingly equivalent code:
1565 // shared_ptr<_Tp, _Lp>(dynamic_cast<_Tp*>(__r.get()))
1566 // will eventually result in undefined behaviour, attempting to
1567 // delete the same object twice.
1568 /// dynamic_pointer_cast
1569 template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
1570 inline __shared_ptr<_Tp, _Lp>
1571 dynamic_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
1572 {
1573 using _Sp = __shared_ptr<_Tp, _Lp>;
1574 if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get()))
1575 return _Sp(__r, __p);
1576 return _Sp();
1577 }
1578
1579#if __cplusplus201103L > 201402L
1580 template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
1581 inline __shared_ptr<_Tp, _Lp>
1582 reinterpret_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
1583 {
1584 using _Sp = __shared_ptr<_Tp, _Lp>;
1585 return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get()));
1586 }
1587#endif
1588
1589 template<typename _Tp, _Lock_policy _Lp>
1590 class __weak_ptr
1591 {
1592 template<typename _Yp, typename _Res = void>
1593 using _Compatible = typename
1594 enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type;
1595
1596 // Constraint for assignment from shared_ptr and weak_ptr:
1597 template<typename _Yp>
1598 using _Assignable = _Compatible<_Yp, __weak_ptr&>;
1599
1600 public:
1601 using element_type = typename remove_extent<_Tp>::type;
1602
1603 constexpr __weak_ptr() noexcept
1604 : _M_ptr(nullptr), _M_refcount()
1605 { }
1606
1607 __weak_ptr(const __weak_ptr&) noexcept = default;
1608
1609 ~__weak_ptr() = default;
1610
1611 // The "obvious" converting constructor implementation:
1612 //
1613 // template<typename _Tp1>
1614 // __weak_ptr(const __weak_ptr<_Tp1, _Lp>& __r)
1615 // : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) // never throws
1616 // { }
1617 //
1618 // has a serious problem.
1619 //
1620 // __r._M_ptr may already have been invalidated. The _M_ptr(__r._M_ptr)
1621 // conversion may require access to *__r._M_ptr (virtual inheritance).
1622 //
1623 // It is not possible to avoid spurious access violations since
1624 // in multithreaded programs __r._M_ptr may be invalidated at any point.
1625 template<typename _Yp, typename = _Compatible<_Yp>>
1626 __weak_ptr(const __weak_ptr<_Yp, _Lp>& __r) noexcept
1627 : _M_refcount(__r._M_refcount)
1628 { _M_ptr = __r.lock().get(); }
1629
1630 template<typename _Yp, typename = _Compatible<_Yp>>
1631 __weak_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept
1632 : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount)
1633 { }
1634
1635 __weak_ptr(__weak_ptr&& __r) noexcept
1636 : _M_ptr(__r._M_ptr), _M_refcount(std::move(__r._M_refcount))
1637 { __r._M_ptr = nullptr; }
1638
1639 template<typename _Yp, typename = _Compatible<_Yp>>
1640 __weak_ptr(__weak_ptr<_Yp, _Lp>&& __r) noexcept
1641 : _M_ptr(__r.lock().get()), _M_refcount(std::move(__r._M_refcount))
1642 { __r._M_ptr = nullptr; }
1643
1644 __weak_ptr&
1645 operator=(const __weak_ptr& __r) noexcept = default;
1646
1647 template<typename _Yp>
1648 _Assignable<_Yp>
1649 operator=(const __weak_ptr<_Yp, _Lp>& __r) noexcept
1650 {
1651 _M_ptr = __r.lock().get();
1652 _M_refcount = __r._M_refcount;
1653 return *this;
1654 }
1655
1656 template<typename _Yp>
1657 _Assignable<_Yp>
1658 operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept
1659 {
1660 _M_ptr = __r._M_ptr;
1661 _M_refcount = __r._M_refcount;
1662 return *this;
1663 }
1664
1665 __weak_ptr&
1666 operator=(__weak_ptr&& __r) noexcept
1667 {
1668 _M_ptr = __r._M_ptr;
1669 _M_refcount = std::move(__r._M_refcount);
1670 __r._M_ptr = nullptr;
1671 return *this;
1672 }
1673
1674 template<typename _Yp>
1675 _Assignable<_Yp>
1676 operator=(__weak_ptr<_Yp, _Lp>&& __r) noexcept
1677 {
1678 _M_ptr = __r.lock().get();
1679 _M_refcount = std::move(__r._M_refcount);
1680 __r._M_ptr = nullptr;
1681 return *this;
1682 }
1683
1684 __shared_ptr<_Tp, _Lp>
1685 lock() const noexcept
1686 { return __shared_ptr<element_type, _Lp>(*this, std::nothrow); }
1687
1688 long
1689 use_count() const noexcept
1690 { return _M_refcount._M_get_use_count(); }
1691
1692 bool
1693 expired() const noexcept
1694 { return _M_refcount._M_get_use_count() == 0; }
1695
1696 template<typename _Tp1>
1697 bool
1698 owner_before(const __shared_ptr<_Tp1, _Lp>& __rhs) const noexcept
1699 { return _M_refcount._M_less(__rhs._M_refcount); }
1700
1701 template<typename _Tp1>
1702 bool
1703 owner_before(const __weak_ptr<_Tp1, _Lp>& __rhs) const noexcept
1704 { return _M_refcount._M_less(__rhs._M_refcount); }
1705
1706 void
1707 reset() noexcept
1708 { __weak_ptr().swap(*this); }
1709
1710 void
1711 swap(__weak_ptr& __s) noexcept
1712 {
1713 std::swap(_M_ptr, __s._M_ptr);
1714 _M_refcount._M_swap(__s._M_refcount);
1715 }
1716
1717 private:
1718 // Used by __enable_shared_from_this.
1719 void
1720 _M_assign(_Tp* __ptr, const __shared_count<_Lp>& __refcount) noexcept
1721 {
1722 if (use_count() == 0)
1723 {
1724 _M_ptr = __ptr;
1725 _M_refcount = __refcount;
1726 }
1727 }
1728
1729 template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
1730 template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;
1731 friend class __enable_shared_from_this<_Tp, _Lp>;
1732 friend class enable_shared_from_this<_Tp>;
1733
1734 element_type* _M_ptr; // Contained pointer.
1735 __weak_count<_Lp> _M_refcount; // Reference counter.
1736 };
1737
1738 // 20.7.2.3.6 weak_ptr specialized algorithms.
1739 template<typename _Tp, _Lock_policy _Lp>
1740 inline void
1741 swap(__weak_ptr<_Tp, _Lp>& __a, __weak_ptr<_Tp, _Lp>& __b) noexcept
1742 { __a.swap(__b); }
1743
1744 template<typename _Tp, typename _Tp1>
1745 struct _Sp_owner_less : public binary_function<_Tp, _Tp, bool>
1746 {
1747 bool
1748 operator()(const _Tp& __lhs, const _Tp& __rhs) const noexcept
1749 { return __lhs.owner_before(__rhs); }
1750
1751 bool
1752 operator()(const _Tp& __lhs, const _Tp1& __rhs) const noexcept
1753 { return __lhs.owner_before(__rhs); }
1754
1755 bool
1756 operator()(const _Tp1& __lhs, const _Tp& __rhs) const noexcept
1757 { return __lhs.owner_before(__rhs); }
1758 };
1759
1760 template<>
1761 struct _Sp_owner_less<void, void>
1762 {
1763 template<typename _Tp, typename _Up>
1764 auto
1765 operator()(const _Tp& __lhs, const _Up& __rhs) const noexcept
1766 -> decltype(__lhs.owner_before(__rhs))
1767 { return __lhs.owner_before(__rhs); }
1768
1769 using is_transparent = void;
1770 };
1771
1772 template<typename _Tp, _Lock_policy _Lp>
1773 struct owner_less<__shared_ptr<_Tp, _Lp>>
1774 : public _Sp_owner_less<__shared_ptr<_Tp, _Lp>, __weak_ptr<_Tp, _Lp>>
1775 { };
1776
1777 template<typename _Tp, _Lock_policy _Lp>
1778 struct owner_less<__weak_ptr<_Tp, _Lp>>
1779 : public _Sp_owner_less<__weak_ptr<_Tp, _Lp>, __shared_ptr<_Tp, _Lp>>
1780 { };
1781
1782
1783 template<typename _Tp, _Lock_policy _Lp>
1784 class __enable_shared_from_this
1785 {
1786 protected:
1787 constexpr __enable_shared_from_this() noexcept { }
1788
1789 __enable_shared_from_this(const __enable_shared_from_this&) noexcept { }
1790
1791 __enable_shared_from_this&
1792 operator=(const __enable_shared_from_this&) noexcept
1793 { return *this; }
1794
1795 ~__enable_shared_from_this() { }
1796
1797 public:
1798 __shared_ptr<_Tp, _Lp>
1799 shared_from_this()
1800 { return __shared_ptr<_Tp, _Lp>(this->_M_weak_this); }
1801
1802 __shared_ptr<const _Tp, _Lp>
1803 shared_from_this() const
1804 { return __shared_ptr<const _Tp, _Lp>(this->_M_weak_this); }
1805
1806#if __cplusplus201103L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11
1807 __weak_ptr<_Tp, _Lp>
1808 weak_from_this() noexcept
1809 { return this->_M_weak_this; }
1810
1811 __weak_ptr<const _Tp, _Lp>
1812 weak_from_this() const noexcept
1813 { return this->_M_weak_this; }
1814#endif
1815
1816 private:
1817 template<typename _Tp1>
1818 void
1819 _M_weak_assign(_Tp1* __p, const __shared_count<_Lp>& __n) const noexcept
1820 { _M_weak_this._M_assign(__p, __n); }
1821
1822 friend const __enable_shared_from_this*
1823 __enable_shared_from_this_base(const __shared_count<_Lp>&,
1824 const __enable_shared_from_this* __p)
1825 { return __p; }
1826
1827 template<typename, _Lock_policy>
1828 friend class __shared_ptr;
1829
1830 mutable __weak_ptr<_Tp, _Lp> _M_weak_this;
1831 };
1832
1833 template<typename _Tp, _Lock_policy _Lp, typename _Alloc, typename... _Args>
1834 inline __shared_ptr<_Tp, _Lp>
1835 __allocate_shared(const _Alloc& __a, _Args&&... __args)
1836 {
1837 return __shared_ptr<_Tp, _Lp>(_Sp_make_shared_tag(), __a,
1838 std::forward<_Args>(__args)...);
1839 }
1840
1841 template<typename _Tp, _Lock_policy _Lp, typename... _Args>
1842 inline __shared_ptr<_Tp, _Lp>
1843 __make_shared(_Args&&... __args)
1844 {
1845 typedef typename std::remove_const<_Tp>::type _Tp_nc;
1846 return std::__allocate_shared<_Tp, _Lp>(std::allocator<_Tp_nc>(),
1847 std::forward<_Args>(__args)...);
1848 }
1849
1850 /// std::hash specialization for __shared_ptr.
1851 template<typename _Tp, _Lock_policy _Lp>
1852 struct hash<__shared_ptr<_Tp, _Lp>>
1853 : public __hash_base<size_t, __shared_ptr<_Tp, _Lp>>
1854 {
1855 size_t
1856 operator()(const __shared_ptr<_Tp, _Lp>& __s) const noexcept
1857 {
1858 return hash<typename __shared_ptr<_Tp, _Lp>::element_type*>()(
1859 __s.get());
1860 }
1861 };
1862
1863_GLIBCXX_END_NAMESPACE_VERSION
1864} // namespace
1865
1866#endif // _SHARED_PTR_BASE_H

/usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/ext/atomicity.h

1// Support for atomic operations -*- C++ -*-
2
3// Copyright (C) 2004-2017 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file ext/atomicity.h
26 * This file is a GNU extension to the Standard C++ Library.
27 */
28
29#ifndef _GLIBCXX_ATOMICITY_H1
30#define _GLIBCXX_ATOMICITY_H1 1
31
32#pragma GCC system_header
33
34#include <bits/c++config.h>
35#include <bits/gthr.h>
36#include <bits/atomic_word.h>
37
38namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
39{
40_GLIBCXX_BEGIN_NAMESPACE_VERSION
41
42 // Functions for portable atomic access.
43 // To abstract locking primitives across all thread policies, use:
44 // __exchange_and_add_dispatch
45 // __atomic_add_dispatch
46#ifdef _GLIBCXX_ATOMIC_BUILTINS1
47 static inline _Atomic_word
48 __exchange_and_add(volatile _Atomic_word* __mem, int __val)
49 { return __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL4); }
50
51 static inline void
52 __atomic_add(volatile _Atomic_word* __mem, int __val)
53 { __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL4); }
54#else
55 _Atomic_word
56 __attribute__ ((__unused__))
57 __exchange_and_add(volatile _Atomic_word*, int) throw ();
58
59 void
60 __attribute__ ((__unused__))
61 __atomic_add(volatile _Atomic_word*, int) throw ();
62#endif
63
64 static inline _Atomic_word
65 __exchange_and_add_single(_Atomic_word* __mem, int __val)
66 {
67 _Atomic_word __result = *__mem;
50
Use of memory after it is freed
68 *__mem += __val;
69 return __result;
70 }
71
72 static inline void
73 __atomic_add_single(_Atomic_word* __mem, int __val)
74 { *__mem += __val; }
75
76 static inline _Atomic_word
77 __attribute__ ((__unused__))
78 __exchange_and_add_dispatch(_Atomic_word* __mem, int __val)
79 {
80#ifdef __GTHREADS1
81 if (__gthread_active_p())
48
Taking false branch
82 return __exchange_and_add(__mem, __val);
83 else
84 return __exchange_and_add_single(__mem, __val);
49
Calling '__exchange_and_add_single'
85#else
86 return __exchange_and_add_single(__mem, __val);
87#endif
88 }
89
90 static inline void
91 __attribute__ ((__unused__))
92 __atomic_add_dispatch(_Atomic_word* __mem, int __val)
93 {
94#ifdef __GTHREADS1
95 if (__gthread_active_p())
96 __atomic_add(__mem, __val);
97 else
98 __atomic_add_single(__mem, __val);
99#else
100 __atomic_add_single(__mem, __val);
101#endif
102 }
103
104_GLIBCXX_END_NAMESPACE_VERSION
105} // namespace
106
107// Even if the CPU doesn't need a memory barrier, we need to ensure
108// that the compiler doesn't reorder memory accesses across the
109// barriers.
110#ifndef _GLIBCXX_READ_MEM_BARRIER__atomic_thread_fence (2)
111#define _GLIBCXX_READ_MEM_BARRIER__atomic_thread_fence (2) __atomic_thread_fence (__ATOMIC_ACQUIRE2)
112#endif
113#ifndef _GLIBCXX_WRITE_MEM_BARRIER__atomic_thread_fence (3)
114#define _GLIBCXX_WRITE_MEM_BARRIER__atomic_thread_fence (3) __atomic_thread_fence (__ATOMIC_RELEASE3)
115#endif
116
117#endif