1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "perfetto/trace_processor/trace_blob.h"
18
19 #include <stdlib.h>
20 #include <string.h>
21
22 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
23 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
24 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
25 #include <sys/mman.h>
26 #endif
27
28 #include <algorithm>
29
30 #include "perfetto/base/compiler.h"
31 #include "perfetto/base/logging.h"
32 #include "perfetto/ext/base/scoped_mmap.h"
33 #include "perfetto/ext/base/utils.h"
34 #include "perfetto/trace_processor/basic_types.h"
35 #include "perfetto/trace_processor/ref_counted.h"
36
37 namespace perfetto {
38 namespace trace_processor {
39
40 // static
Allocate(size_t size)41 TraceBlob TraceBlob::Allocate(size_t size) {
42 TraceBlob blob(Ownership::kHeapBuf, new uint8_t[size], size);
43 PERFETTO_CHECK(blob.data_);
44 return blob;
45 }
46
47 // static
CopyFrom(const void * src,size_t size)48 TraceBlob TraceBlob::CopyFrom(const void* src, size_t size) {
49 TraceBlob blob = Allocate(size);
50 const uint8_t* src_u8 = static_cast<const uint8_t*>(src);
51 std::copy(src_u8, src_u8 + size, blob.data_);
52 return blob;
53 }
54
55 // static
TakeOwnership(std::unique_ptr<uint8_t[]> buf,size_t size)56 TraceBlob TraceBlob::TakeOwnership(std::unique_ptr<uint8_t[]> buf,
57 size_t size) {
58 PERFETTO_CHECK(buf);
59 return TraceBlob(Ownership::kHeapBuf, buf.release(), size);
60 }
61
62 // static
FromMmap(base::ScopedMmap mapped)63 TraceBlob TraceBlob::FromMmap(base::ScopedMmap mapped) {
64 PERFETTO_CHECK(mapped.IsValid());
65 TraceBlob blob(Ownership::kNullOrMmaped, static_cast<uint8_t*>(mapped.data()),
66 mapped.length());
67 blob.mapping_ = std::make_unique<base::ScopedMmap>(std::move(mapped));
68 return blob;
69 }
70
71 // static
FromMmap(void * data,size_t size)72 TraceBlob TraceBlob::FromMmap(void* data, size_t size) {
73 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
74 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
75 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
76 PERFETTO_CHECK(data);
77 TraceBlob blob(Ownership::kNullOrMmaped, static_cast<uint8_t*>(data), size);
78 blob.mapping_ = std::make_unique<base::ScopedMmap>(
79 base::ScopedMmap::InheritMmappedRange(data, size));
80 return blob;
81 #else
82 base::ignore_result(data);
83 base::ignore_result(size);
84 PERFETTO_FATAL("mmap not supported");
85 #endif
86 }
87
TraceBlob(Ownership ownership,uint8_t * data,size_t size)88 TraceBlob::TraceBlob(Ownership ownership, uint8_t* data, size_t size)
89 : ownership_(ownership), data_(data), size_(size) {}
90
~TraceBlob()91 TraceBlob::~TraceBlob() {
92 switch (ownership_) {
93 case Ownership::kHeapBuf:
94 delete[] data_;
95 break;
96
97 case Ownership::kNullOrMmaped:
98 if (mapping_) {
99 PERFETTO_CHECK(mapping_->reset());
100 }
101 break;
102 }
103 data_ = nullptr;
104 size_ = 0;
105 }
106
TraceBlob(TraceBlob && other)107 TraceBlob::TraceBlob(TraceBlob&& other) noexcept
108 : RefCounted(std::move(other)) {
109 static_assert(
110 sizeof(*this) == base::AlignUp<sizeof(void*)>(
111 sizeof(data_) + sizeof(size_) + sizeof(ownership_) +
112 sizeof(mapping_) + sizeof(RefCounted)),
113 "TraceBlob move constructor needs updating");
114 data_ = other.data_;
115 size_ = other.size_;
116 ownership_ = other.ownership_;
117 mapping_ = std::move(other.mapping_);
118 other.data_ = nullptr;
119 other.size_ = 0;
120 other.ownership_ = Ownership::kNullOrMmaped;
121 other.mapping_ = nullptr;
122 }
123
operator =(TraceBlob && other)124 TraceBlob& TraceBlob::operator=(TraceBlob&& other) noexcept {
125 if (this == &other)
126 return *this;
127 this->~TraceBlob();
128 new (this) TraceBlob(std::move(other));
129 return *this;
130 }
131
132 } // namespace trace_processor
133 } // namespace perfetto
134