1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <trace-reader/records.h> 6 7#include <inttypes.h> 8#include <string.h> 9 10#include <fbl/string_buffer.h> 11#include <fbl/string_printf.h> 12 13namespace trace { 14namespace { 15const char* EventScopeToString(EventScope scope) { 16 switch (scope) { 17 case EventScope::kGlobal: 18 return "global"; 19 case EventScope::kProcess: 20 return "process"; 21 case EventScope::kThread: 22 return "thread"; 23 } 24 return "???"; 25} 26 27const char* ThreadStateToString(ThreadState state) { 28 switch (state) { 29 case ThreadState::kNew: 30 return "new"; 31 case ThreadState::kRunning: 32 return "running"; 33 case ThreadState::kSuspended: 34 return "suspended"; 35 case ThreadState::kBlocked: 36 return "blocked"; 37 case ThreadState::kDying: 38 return "dying"; 39 case ThreadState::kDead: 40 return "dead"; 41 } 42 return "???"; 43} 44 45const char* ObjectTypeToString(zx_obj_type_t type) { 46 static_assert(ZX_OBJ_TYPE_LAST == 28, "need to update switch below"); 47 48 switch (type) { 49 case ZX_OBJ_TYPE_PROCESS: 50 return "process"; 51 case ZX_OBJ_TYPE_THREAD: 52 return "thread"; 53 case ZX_OBJ_TYPE_VMO: 54 return "vmo"; 55 case ZX_OBJ_TYPE_CHANNEL: 56 return "channel"; 57 case ZX_OBJ_TYPE_EVENT: 58 return "event"; 59 case ZX_OBJ_TYPE_PORT: 60 return "port"; 61 case ZX_OBJ_TYPE_INTERRUPT: 62 return "interrupt"; 63 case ZX_OBJ_TYPE_PCI_DEVICE: 64 return "pci-device"; 65 case ZX_OBJ_TYPE_LOG: 66 return "log"; 67 case ZX_OBJ_TYPE_SOCKET: 68 return "socket"; 69 case ZX_OBJ_TYPE_RESOURCE: 70 return "resource"; 71 case ZX_OBJ_TYPE_EVENTPAIR: 72 return "event-pair"; 73 case ZX_OBJ_TYPE_JOB: 74 return "job"; 75 case ZX_OBJ_TYPE_VMAR: 76 return "vmar"; 77 case ZX_OBJ_TYPE_FIFO: 78 return "fifo"; 79 case ZX_OBJ_TYPE_GUEST: 80 return "guest"; 81 case ZX_OBJ_TYPE_VCPU: 82 return "vcpu"; 83 case ZX_OBJ_TYPE_TIMER: 84 return "timer"; 85 case ZX_OBJ_TYPE_IOMMU: 86 return "iommu"; 87 case ZX_OBJ_TYPE_BTI: 88 return "bti"; 89 case ZX_OBJ_TYPE_PROFILE: 90 return "profile"; 91 case ZX_OBJ_TYPE_PMT: 92 return "pmt"; 93 case ZX_OBJ_TYPE_SUSPEND_TOKEN: 94 return "suspend-token"; 95 default: 96 return "???"; 97 } 98} 99 100fbl::String FormatArgumentList(const fbl::Vector<trace::Argument>& args) { 101 fbl::StringBuffer<1024> result; 102 103 result.Append('{'); 104 for (size_t i = 0; i < args.size(); i++) { 105 if (i != 0) 106 result.Append(", "); 107 result.Append(args[i].ToString()); 108 } 109 result.Append('}'); 110 111 return result.ToString(); 112} 113} // namespace 114 115fbl::String ProcessThread::ToString() const { 116 return fbl::StringPrintf("%" PRIu64 "/%" PRIu64, 117 process_koid_, thread_koid_); 118} 119 120void ArgumentValue::Destroy() { 121 switch (type_) { 122 case ArgumentType::kString: 123 string_.~String(); 124 break; 125 case ArgumentType::kNull: 126 case ArgumentType::kInt32: 127 case ArgumentType::kUint32: 128 case ArgumentType::kInt64: 129 case ArgumentType::kUint64: 130 case ArgumentType::kDouble: 131 case ArgumentType::kPointer: 132 case ArgumentType::kKoid: 133 break; 134 } 135} 136 137void ArgumentValue::MoveFrom(ArgumentValue&& other) { 138 type_ = other.type_; 139 other.type_ = ArgumentType::kNull; 140 switch (type_) { 141 case ArgumentType::kNull: 142 break; 143 case ArgumentType::kInt32: 144 int32_ = other.int32_; 145 break; 146 case ArgumentType::kUint32: 147 int32_ = other.uint32_; 148 break; 149 case ArgumentType::kInt64: 150 int64_ = other.int64_; 151 break; 152 case ArgumentType::kUint64: 153 int64_ = other.uint64_; 154 break; 155 case ArgumentType::kDouble: 156 double_ = other.double_; 157 break; 158 case ArgumentType::kString: 159 new (&string_) fbl::String(fbl::move(other.string_)); 160 other.string_.~String(); // call destructor because we set other.type_ to kNull 161 break; 162 case ArgumentType::kPointer: 163 pointer_ = other.pointer_; 164 break; 165 case ArgumentType::kKoid: 166 koid_ = other.koid_; 167 break; 168 } 169} 170 171fbl::String ArgumentValue::ToString() const { 172 switch (type_) { 173 case ArgumentType::kNull: 174 return "null"; 175 case ArgumentType::kInt32: 176 return fbl::StringPrintf("int32(%" PRId32 ")", int32_); 177 case ArgumentType::kUint32: 178 return fbl::StringPrintf("uint32(%" PRIu32 ")", uint32_); 179 case ArgumentType::kInt64: 180 return fbl::StringPrintf("int64(%" PRId64 ")", int64_); 181 case ArgumentType::kUint64: 182 return fbl::StringPrintf("uint64(%" PRIu64 ")", uint64_); 183 case ArgumentType::kDouble: 184 return fbl::StringPrintf("double(%f)", double_); 185 case ArgumentType::kString: 186 return fbl::StringPrintf("string(\"%s\")", string_.c_str()); 187 case ArgumentType::kPointer: 188 return fbl::StringPrintf("pointer(%p)", reinterpret_cast<void*>(pointer_)); 189 case ArgumentType::kKoid: 190 return fbl::StringPrintf("koid(%" PRIu64 ")", koid_); 191 } 192 ZX_ASSERT(false); 193} 194 195fbl::String Argument::ToString() const { 196 return fbl::StringPrintf("%s: %s", name_.c_str(), value_.ToString().c_str()); 197} 198 199void MetadataContent::Destroy() { 200 switch (type_) { 201 case MetadataType::kProviderInfo: 202 provider_info_.~ProviderInfo(); 203 break; 204 case MetadataType::kProviderSection: 205 provider_section_.~ProviderSection(); 206 break; 207 case MetadataType::kProviderEvent: 208 provider_event_.~ProviderEvent(); 209 break; 210 } 211} 212 213void MetadataContent::MoveFrom(MetadataContent&& other) { 214 type_ = other.type_; 215 switch (type_) { 216 case MetadataType::kProviderInfo: 217 new (&provider_info_) ProviderInfo(fbl::move(other.provider_info_)); 218 break; 219 case MetadataType::kProviderSection: 220 new (&provider_section_) ProviderSection(fbl::move(other.provider_section_)); 221 break; 222 case MetadataType::kProviderEvent: 223 new (&provider_event_) ProviderEvent(fbl::move(other.provider_event_)); 224 break; 225 } 226} 227 228fbl::String MetadataContent::ToString() const { 229 switch (type_) { 230 case MetadataType::kProviderInfo: 231 return fbl::StringPrintf("ProviderInfo(id: %" PRId32 ", name: \"%s\")", 232 provider_info_.id, provider_info_.name.c_str()); 233 case MetadataType::kProviderSection: 234 return fbl::StringPrintf("ProviderSection(id: %" PRId32 ")", 235 provider_section_.id); 236 case MetadataType::kProviderEvent: { 237 fbl::String name; 238 ProviderEventType type = provider_event_.event; 239 switch (type) { 240 case ProviderEventType::kBufferOverflow: 241 name = "buffer overflow"; 242 break; 243 default: 244 name = fbl::StringPrintf("unknown(%u)", 245 static_cast<unsigned>(type)); 246 break; 247 } 248 return fbl::StringPrintf("ProviderEvent(id: %" PRId32 ", %s)", 249 provider_event_.id, name.c_str()); 250 } 251 } 252 ZX_ASSERT(false); 253} 254 255void EventData::Destroy() { 256 switch (type_) { 257 case EventType::kInstant: 258 instant_.~Instant(); 259 break; 260 case EventType::kCounter: 261 counter_.~Counter(); 262 break; 263 case EventType::kDurationBegin: 264 duration_begin_.~DurationBegin(); 265 break; 266 case EventType::kDurationEnd: 267 duration_end_.~DurationEnd(); 268 break; 269 case EventType::kAsyncBegin: 270 async_begin_.~AsyncBegin(); 271 break; 272 case EventType::kAsyncInstant: 273 async_instant_.~AsyncInstant(); 274 break; 275 case EventType::kAsyncEnd: 276 async_end_.~AsyncEnd(); 277 break; 278 case EventType::kFlowBegin: 279 flow_begin_.~FlowBegin(); 280 break; 281 case EventType::kFlowStep: 282 flow_step_.~FlowStep(); 283 break; 284 case EventType::kFlowEnd: 285 flow_end_.~FlowEnd(); 286 break; 287 } 288} 289 290void EventData::MoveFrom(EventData&& other) { 291 type_ = other.type_; 292 switch (type_) { 293 case EventType::kInstant: 294 new (&instant_) Instant(fbl::move(other.instant_)); 295 break; 296 case EventType::kCounter: 297 new (&counter_) Counter(fbl::move(other.counter_)); 298 break; 299 case EventType::kDurationBegin: 300 new (&duration_begin_) DurationBegin(fbl::move(other.duration_begin_)); 301 break; 302 case EventType::kDurationEnd: 303 new (&duration_end_) DurationEnd(fbl::move(other.duration_end_)); 304 break; 305 case EventType::kAsyncBegin: 306 new (&async_begin_) AsyncBegin(fbl::move(other.async_begin_)); 307 break; 308 case EventType::kAsyncInstant: 309 new (&async_instant_) AsyncInstant(fbl::move(other.async_instant_)); 310 break; 311 case EventType::kAsyncEnd: 312 new (&async_end_) AsyncEnd(fbl::move(other.async_end_)); 313 break; 314 case EventType::kFlowBegin: 315 new (&flow_begin_) FlowBegin(fbl::move(other.flow_begin_)); 316 break; 317 case EventType::kFlowStep: 318 new (&flow_step_) FlowStep(fbl::move(other.flow_step_)); 319 break; 320 case EventType::kFlowEnd: 321 new (&flow_end_) FlowEnd(fbl::move(other.flow_end_)); 322 break; 323 } 324} 325 326fbl::String EventData::ToString() const { 327 switch (type_) { 328 case EventType::kInstant: 329 return fbl::StringPrintf("Instant(scope: %s)", 330 EventScopeToString(instant_.scope)); 331 case EventType::kCounter: 332 return fbl::StringPrintf("Counter(id: %" PRIu64 ")", 333 counter_.id); 334 case EventType::kDurationBegin: 335 return "DurationBegin"; 336 case EventType::kDurationEnd: 337 return "DurationEnd"; 338 case EventType::kAsyncBegin: 339 return fbl::StringPrintf("AsyncBegin(id: %" PRIu64 ")", 340 async_begin_.id); 341 case EventType::kAsyncInstant: 342 return fbl::StringPrintf("AsyncInstant(id: %" PRIu64 ")", 343 async_instant_.id); 344 case EventType::kAsyncEnd: 345 return fbl::StringPrintf("AsyncEnd(id: %" PRIu64 ")", 346 async_end_.id); 347 case EventType::kFlowBegin: 348 return fbl::StringPrintf("FlowBegin(id: %" PRIu64 ")", 349 flow_begin_.id); 350 case EventType::kFlowStep: 351 return fbl::StringPrintf("FlowStep(id: %" PRIu64 ")", 352 flow_step_.id); 353 case EventType::kFlowEnd: 354 return fbl::StringPrintf("FlowEnd(id: %" PRIu64 ")", 355 flow_end_.id); 356 } 357 ZX_ASSERT(false); 358} 359 360void Record::Destroy() { 361 switch (type_) { 362 case RecordType::kMetadata: 363 metadata_.~Metadata(); 364 break; 365 case RecordType::kInitialization: 366 initialization_.~Initialization(); 367 break; 368 case RecordType::kString: 369 string_.~String(); 370 break; 371 case RecordType::kThread: 372 thread_.~Thread(); 373 break; 374 case RecordType::kEvent: 375 event_.~Event(); 376 break; 377 case RecordType::kBlob: 378 blob_.~Blob(); 379 break; 380 case RecordType::kKernelObject: 381 kernel_object_.~KernelObject(); 382 break; 383 case RecordType::kContextSwitch: 384 context_switch_.~ContextSwitch(); 385 break; 386 case RecordType::kLog: 387 log_.~Log(); 388 break; 389 } 390} 391 392void Record::MoveFrom(Record&& other) { 393 type_ = other.type_; 394 switch (type_) { 395 case RecordType::kMetadata: 396 new (&metadata_) Metadata(fbl::move(other.metadata_)); 397 break; 398 case RecordType::kInitialization: 399 new (&initialization_) Initialization(fbl::move(other.initialization_)); 400 break; 401 case RecordType::kString: 402 new (&string_) String(fbl::move(other.string_)); 403 break; 404 case RecordType::kThread: 405 new (&thread_) Thread(fbl::move(other.thread_)); 406 break; 407 case RecordType::kEvent: 408 new (&event_) Event(fbl::move(other.event_)); 409 break; 410 case RecordType::kBlob: 411 new (&blob_) Blob(fbl::move(other.blob_)); 412 break; 413 case RecordType::kKernelObject: 414 new (&kernel_object_) KernelObject(fbl::move(other.kernel_object_)); 415 break; 416 case RecordType::kContextSwitch: 417 new (&context_switch_) ContextSwitch(fbl::move(other.context_switch_)); 418 break; 419 case RecordType::kLog: 420 new (&log_) Log(fbl::move(other.log_)); 421 break; 422 } 423} 424 425fbl::String Record::ToString() const { 426 switch (type_) { 427 case RecordType::kMetadata: 428 return fbl::StringPrintf("Metadata(content: %s)", 429 metadata_.content.ToString().c_str()); 430 case RecordType::kInitialization: 431 return fbl::StringPrintf("Initialization(ticks_per_second: %" PRIu64 ")", 432 initialization_.ticks_per_second); 433 case RecordType::kString: 434 return fbl::StringPrintf("String(index: %" PRIu32 ", \"%s\")", 435 string_.index, string_.string.c_str()); 436 case RecordType::kThread: 437 return fbl::StringPrintf("Thread(index: %" PRIu32 ", %s)", 438 thread_.index, thread_.process_thread.ToString().c_str()); 439 case RecordType::kEvent: 440 return fbl::StringPrintf("Event(ts: %" PRIu64 ", pt: %s, category: \"%s\", name: \"%s\", %s, %s)", 441 event_.timestamp, event_.process_thread.ToString().c_str(), 442 event_.category.c_str(), event_.name.c_str(), 443 event_.data.ToString().c_str(), 444 FormatArgumentList(event_.arguments).c_str()); 445 break; 446 case RecordType::kBlob: 447 // TODO(dje): Could print something like the first 16 bytes of the 448 // payload or some such. 449 return fbl::StringPrintf("Blob(name: %s, size: %zu)", 450 blob_.name.c_str(), blob_.blob_size); 451 case RecordType::kKernelObject: 452 return fbl::StringPrintf("KernelObject(koid: %" PRIu64 ", type: %s, name: \"%s\", %s)", 453 kernel_object_.koid, 454 ObjectTypeToString(kernel_object_.object_type), 455 kernel_object_.name.c_str(), 456 FormatArgumentList(kernel_object_.arguments).c_str()); 457 break; 458 case RecordType::kContextSwitch: 459 return fbl::StringPrintf("ContextSwitch(ts: %" PRIu64 ", cpu: %" PRIu32 460 ", os: %s, opt: %s, ipt: %s" 461 ", oprio: %" PRIu32 ", iprio: %" PRIu32 ")", 462 context_switch_.timestamp, 463 context_switch_.cpu_number, 464 ThreadStateToString(context_switch_.outgoing_thread_state), 465 context_switch_.outgoing_thread.ToString().c_str(), 466 context_switch_.incoming_thread.ToString().c_str(), 467 context_switch_.outgoing_thread_priority, 468 context_switch_.incoming_thread_priority); 469 case RecordType::kLog: 470 return fbl::StringPrintf("Log(ts: %" PRIu64 ", pt: %s, \"%s\")", 471 log_.timestamp, log_.process_thread.ToString().c_str(), 472 log_.message.c_str()); 473 } 474 ZX_ASSERT(false); 475} 476 477} // namespace trace 478