• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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