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 "src/trace_processor/importers/fuchsia/fuchsia_trace_utils.h"
18
19 namespace perfetto {
20 namespace trace_processor {
21 namespace fuchsia_trace_utils {
22
23 namespace {
24 constexpr uint32_t kInlineStringMarker = 0x8000;
25 constexpr uint32_t kInlineStringLengthMask = 0x7FFF;
26 } // namespace
27
IsInlineString(uint32_t string_ref)28 bool IsInlineString(uint32_t string_ref) {
29 // Treat a string ref of 0 (the empty string) as inline. The empty string is
30 // not a true entry in the string table.
31 return (string_ref & kInlineStringMarker) || (string_ref == 0);
32 }
33
IsInlineThread(uint32_t thread_ref)34 bool IsInlineThread(uint32_t thread_ref) {
35 return thread_ref == 0;
36 }
37
38 // Converts a tick count to nanoseconds. Returns -1 if the result would not
39 // fit in a nonnegative int64_t. Negative timestamps are not allowed by the
40 // Fuchsia trace format. Also returns -1 if ticks_per_second is zero.
TicksToNs(uint64_t ticks,uint64_t ticks_per_second)41 int64_t TicksToNs(uint64_t ticks, uint64_t ticks_per_second) {
42 uint64_t ticks_hi = ticks >> 32;
43 uint64_t ticks_lo = ticks & ((uint64_t(1) << 32) - 1);
44 uint64_t ns_per_sec = 1000000000;
45 if (ticks_per_second == 0) {
46 return -1;
47 }
48 // This multiplication may overflow.
49 uint64_t result_hi = ticks_hi * ((ns_per_sec << 32) / ticks_per_second);
50 if (ticks_hi != 0 &&
51 result_hi / ticks_hi != ((ns_per_sec << 32) / ticks_per_second)) {
52 return -1;
53 }
54 // This computation never overflows, because ticks_lo is less than 2^32, and
55 // ns_per_sec = 10^9 < 2^32.
56 uint64_t result_lo = ticks_lo * ns_per_sec / ticks_per_second;
57 // Performing addition before the cast avoids undefined behavior.
58 int64_t result = static_cast<int64_t>(result_hi + result_lo);
59 // Check for addition overflow.
60 if (result < 0) {
61 return -1;
62 }
63 return result;
64 }
65
ToStorageVariadic(TraceStorage * storage) const66 Variadic ArgValue::ToStorageVariadic(TraceStorage* storage) const {
67 switch (type_) {
68 case ArgType::kNull:
69 return Variadic::String(storage->InternString("null"));
70 case ArgType::kInt32:
71 return Variadic::Integer(static_cast<int64_t>(int32_));
72 case ArgType::kUint32:
73 return Variadic::Integer(static_cast<int64_t>(uint32_));
74 case ArgType::kInt64:
75 return Variadic::Integer(int64_);
76 case ArgType::kUint64:
77 return Variadic::Integer(static_cast<int64_t>(uint64_));
78 case ArgType::kDouble:
79 return Variadic::Real(double_);
80 case ArgType::kString:
81 return Variadic::String(string_);
82 case ArgType::kPointer:
83 return Variadic::Integer(static_cast<int64_t>(pointer_));
84 case ArgType::kKoid:
85 return Variadic::Integer(static_cast<int64_t>(koid_));
86 case ArgType::kUnknown:
87 return Variadic::String(storage->InternString("unknown"));
88 }
89 PERFETTO_FATAL("Not reached"); // Make GCC happy.
90 }
91
WordIndex()92 size_t RecordCursor::WordIndex() {
93 return word_index_;
94 }
95
SetWordIndex(size_t index)96 void RecordCursor::SetWordIndex(size_t index) {
97 word_index_ = index;
98 }
99
ReadTimestamp(uint64_t ticks_per_second,int64_t * ts_out)100 bool RecordCursor::ReadTimestamp(uint64_t ticks_per_second, int64_t* ts_out) {
101 const uint8_t* ts_data;
102 if (!ReadWords(1, &ts_data)) {
103 return false;
104 }
105 if (ts_out != nullptr) {
106 uint64_t ticks;
107 memcpy(&ticks, ts_data, sizeof(uint64_t));
108 *ts_out = TicksToNs(ticks, ticks_per_second);
109 }
110 return true;
111 }
112
ReadInlineString(uint32_t string_ref_or_len,base::StringView * string_out)113 bool RecordCursor::ReadInlineString(uint32_t string_ref_or_len,
114 base::StringView* string_out) {
115 // Note that this works correctly for the empty string, where string_ref is 0.
116 size_t len = string_ref_or_len & kInlineStringLengthMask;
117 size_t len_words = (len + 7) / 8;
118 const uint8_t* string_data;
119 if (!ReadWords(len_words, &string_data)) {
120 return false;
121 }
122 if (string_out != nullptr) {
123 *string_out =
124 base::StringView(reinterpret_cast<const char*>(string_data), len);
125 }
126 return true;
127 }
128
ReadInlineThread(ThreadInfo * thread_out)129 bool RecordCursor::ReadInlineThread(ThreadInfo* thread_out) {
130 const uint8_t* thread_data;
131 if (!ReadWords(2, &thread_data)) {
132 return false;
133 }
134 if (thread_out != nullptr) {
135 memcpy(&thread_out->pid, thread_data, sizeof(uint64_t));
136 memcpy(&thread_out->tid, thread_data + sizeof(uint64_t), sizeof(uint64_t));
137 }
138 return true;
139 }
140
ReadInt64(int64_t * out)141 bool RecordCursor::ReadInt64(int64_t* out) {
142 const uint8_t* out_data;
143 if (!ReadWords(1, &out_data)) {
144 return false;
145 }
146 if (out != nullptr) {
147 memcpy(out, out_data, sizeof(int64_t));
148 }
149 return true;
150 }
151
ReadUint64(uint64_t * out)152 bool RecordCursor::ReadUint64(uint64_t* out) {
153 const uint8_t* out_data;
154 if (!ReadWords(1, &out_data)) {
155 return false;
156 }
157 if (out != nullptr) {
158 memcpy(out, out_data, sizeof(uint64_t));
159 }
160 return true;
161 }
162
ReadDouble(double * out)163 bool RecordCursor::ReadDouble(double* out) {
164 static_assert(sizeof(double) == sizeof(uint64_t), "double must be 64 bits");
165
166 const uint8_t* out_data;
167 if (!ReadWords(1, &out_data)) {
168 return false;
169 }
170 if (out != nullptr) {
171 memcpy(out, out_data, sizeof(double));
172 }
173 return true;
174 }
175
ReadWords(size_t num_words,const uint8_t ** data_out)176 bool RecordCursor::ReadWords(size_t num_words, const uint8_t** data_out) {
177 const uint8_t* data = begin_ + sizeof(uint64_t) * word_index_;
178 // This addition is unconditional so that callers with data_out == nullptr do
179 // not necessarily have to check the return value, as future calls will fail
180 // due to attempting to read out of bounds.
181 word_index_ += num_words;
182 if (data + sizeof(uint64_t) * num_words <= end_) {
183 if (data_out != nullptr) {
184 *data_out = data;
185 }
186 return true;
187 } else {
188 return false;
189 }
190 }
191
192 } // namespace fuchsia_trace_utils
193 } // namespace trace_processor
194 } // namespace perfetto
195