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