atrace.cpp revision 6f6f3f710b4dec2952298ae65d5f1674535c63f0
1fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/*
2fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Copyright (C) 2012 The Android Open Source Project
3fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *
4fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Licensed under the Apache License, Version 2.0 (the "License");
5fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * you may not use this file except in compliance with the License.
6fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * You may obtain a copy of the License at
7fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *
8fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *      http://www.apache.org/licenses/LICENSE-2.0
9fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *
10fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Unless required by applicable law or agreed to in writing, software
11fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * distributed under the License is distributed on an "AS IS" BASIS,
12fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * See the License for the specific language governing permissions and
14fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * limitations under the License.
15fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis */
16fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
17fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <errno.h>
18fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <fcntl.h>
194edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling#include <getopt.h>
20fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <signal.h>
21fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdarg.h>
22fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdbool.h>
23fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdio.h>
24fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdlib.h>
25fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <sys/sendfile.h>
26fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <time.h>
277b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis#include <zlib.h>
28fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
296eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <binder/IBinder.h>
306eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <binder/IServiceManager.h>
316eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <binder/Parcel.h>
326eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
336eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <cutils/properties.h>
346eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
356eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <utils/String8.h>
366eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <utils/Trace.h>
376eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
386eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisusing namespace android;
396eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
40ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
41ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
426eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisenum { MAX_SYS_FILES = 8 };
436eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
446eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisconst char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
456eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
466eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennistypedef enum { OPT, REQ } requiredness  ;
476eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
486eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstruct TracingCategory {
496eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // The name identifying the category.
506eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    const char* name;
516eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
526eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // A longer description of the category.
536eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    const char* longname;
546eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
556eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // The userland tracing tags that the category enables.
566eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    uint64_t tags;
576eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
586eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // The fname==NULL terminated list of /sys/ files that the category
596eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // enables.
606eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    struct {
616eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        // Whether the file must be writable in order to enable the tracing
626eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        // category.
636eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        requiredness required;
646eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
656eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        // The path to the enable file.
666eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const char* path;
676eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } sysfiles[MAX_SYS_FILES];
686eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis};
696eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
706eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis/* Tracing categories */
716eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic const TracingCategory k_categories[] = {
72b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "gfx",        "Graphics",         ATRACE_TAG_GRAPHICS, { } },
73b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "input",      "Input",            ATRACE_TAG_INPUT, { } },
74b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "view",       "View System",      ATRACE_TAG_VIEW, { } },
75b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "webview",    "WebView",          ATRACE_TAG_WEBVIEW, { } },
76b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "wm",         "Window Manager",   ATRACE_TAG_WINDOW_MANAGER, { } },
77b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "am",         "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
78b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "audio",      "Audio",            ATRACE_TAG_AUDIO, { } },
79b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "video",      "Video",            ATRACE_TAG_VIDEO, { } },
80b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "camera",     "Camera",           ATRACE_TAG_CAMERA, { } },
81b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "hal",        "Hardware Modules", ATRACE_TAG_HAL, { } },
82b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "sched",      "CPU Scheduling",   0, {
83b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
84b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
856eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
86b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "freq",       "CPU Frequency",    0, {
87b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
88b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { OPT,      "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
896eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
90b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "membus",     "Memory Bus Utilization", 0, {
91b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/memory_bus/enable" },
926eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
93b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "idle",       "CPU Idle",         0, {
94b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
956eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
96b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "disk",       "Disk I/O",         0, {
97b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
98b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
99b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
100b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" },
1016eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
102b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "load",       "CPU Load",         0, {
103b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
1046eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
105b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "sync",       "Synchronization",  0, {
106b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/sync/enable" },
1076eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
108b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "workq",      "Kernel Workqueues", 0, {
109b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/workqueue/enable" },
1106eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
1116eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis};
1126eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
113fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Command line options */
114fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic int g_traceDurationSeconds = 5;
115fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceOverwrite = false;
116cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic int g_traceBufferSizeKB = 2048;
1177b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennisstatic bool g_compress = false;
11831be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic bool g_nohup = false;
11931be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic int g_initialSleepSecs = 0;
120e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* g_kernelTraceFuncs = NULL;
121fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
122fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Global state */
123fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceAborted = false;
1246eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool g_categoryEnables[NELEM(k_categories)] = {};
125fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
126fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Sys file paths */
127fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceClockPath =
128fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_clock";
129fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
130cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_traceBufferSizePath =
131cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/buffer_size_kb";
132cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
133fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOverwriteEnablePath =
134fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/options/overwrite";
135fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
136e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_currentTracerPath =
137e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/current_tracer";
138e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
139e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_printTgidPath =
140e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/options/print-tgid";
141e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
142e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_funcgraphAbsTimePath =
143e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/options/funcgraph-abstime";
144e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
145e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_funcgraphCpuPath =
146e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/options/funcgraph-cpu";
147e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
148e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_funcgraphProcPath =
149e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/options/funcgraph-proc";
150e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
151e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_funcgraphFlatPath =
152e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/options/funcgraph-flat";
153e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
154e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_funcgraphDurationPath =
155e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/options/funcgraph-duration";
156e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
157e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_ftraceFilterPath =
158e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/set_ftrace_filter";
159e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
160fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOnPath =
161fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
162fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
163fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracePath =
164fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace";
165fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
166e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis// Check whether a file exists.
167e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennisstatic bool fileExists(const char* filename) {
168e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return access(filename, F_OK) != -1;
169e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis}
170e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis
1716eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Check whether a file is writable.
1726eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool fileIsWritable(const char* filename) {
1736eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return access(filename, W_OK) != -1;
1746eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
1756eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
176e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Truncate a file.
177e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool truncateFile(const char* path)
178fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
17943122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis    // This uses creat rather than truncate because some of the debug kernel
18043122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis    // device nodes (e.g. k_ftraceFilterPath) currently aren't changed by
18143122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis    // calls to truncate, but they are cleared by calls to creat.
18243122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis    int traceFD = creat(path, 0);
18343122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis    if (traceFD == -1) {
184e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", path,
18543122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis            strerror(errno), errno);
186e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        return false;
187e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    }
188e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
18943122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis    close(traceFD);
19043122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis
191e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return true;
192e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
193e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
194e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool _writeStr(const char* filename, const char* str, int flags)
195e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
196e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    int fd = open(filename, flags);
197fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (fd == -1) {
198fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
199fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
200fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
201fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
202fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
203fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
204fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ssize_t len = strlen(str);
205fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (write(fd, str, len) != len) {
206fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
207fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
208fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = false;
209fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
210fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
211fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(fd);
212fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
213fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
214fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
215fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
216e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Write a string to a file, returning true if the write was successful.
217e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool writeStr(const char* filename, const char* str)
218e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
219e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return _writeStr(filename, str, O_WRONLY);
220e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
221e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
222e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Append a string to a file, returning true if the write was successful.
223e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool appendStr(const char* filename, const char* str)
224e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
225e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return _writeStr(filename, str, O_APPEND|O_WRONLY);
226e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
227e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
2286eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys
2296eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// file.
230fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
231fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
232fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(filename, enable ? "1" : "0");
233fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
234fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
2356eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Check whether the category is supported on the device with the current
2366eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// rootness.  A category is supported only if all its required /sys/ files are
2376eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// writable and if enabling the category will enable one or more tracing tags
2386eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// or /sys/ files.
2396eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool isCategorySupported(const TracingCategory& category)
2403169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis{
2416eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    bool ok = category.tags != 0;
2426eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < MAX_SYS_FILES; i++) {
2436eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const char* path = category.sysfiles[i].path;
2446eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        bool req = category.sysfiles[i].required == REQ;
2456eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (path != NULL) {
2466eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (req) {
2476eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (!fileIsWritable(path)) {
2486eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    return false;
2496eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                } else {
2506eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    ok = true;
2516eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
2526eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            } else {
2536eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                ok |= fileIsWritable(path);
2546eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
2556eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
256e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
257e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return ok;
258cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
259cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
2606eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Check whether the category would be supported on the device if the user
2616eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// were root.  This function assumes that root is able to write to any file
2626eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// that exists.  It performs the same logic as isCategorySupported, but it
2636eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// uses file existance rather than writability in the /sys/ file checks.
2646eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool isCategorySupportedForRoot(const TracingCategory& category)
2659ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling{
2666eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    bool ok = category.tags != 0;
2676eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < MAX_SYS_FILES; i++) {
2686eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const char* path = category.sysfiles[i].path;
2696eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        bool req = category.sysfiles[i].required == REQ;
2706eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (path != NULL) {
2716eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (req) {
2726eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (!fileExists(path)) {
2736eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    return false;
2746eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                } else {
2756eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    ok = true;
2766eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
2776eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            } else {
2786eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                ok |= fileExists(path);
2796eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
2806eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
2819ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    }
2829ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    return ok;
2839ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling}
2849ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling
2856eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
2866eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// will cause tracing to stop once the trace buffers have filled up.
2876eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
288ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{
2896eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
290ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}
291ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
292fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable kernel tracing.
293fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTracingEnabled(bool enable)
294fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
295fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
296fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
297fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
298fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Clear the contents of the kernel trace.
299fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool clearTrace()
300fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
301e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return truncateFile(k_tracePath);
302fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
303fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
304cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes.
305cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setTraceBufferSizeKB(int size)
306cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
307cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    char str[32] = "1";
308cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    int len;
309cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    if (size < 1) {
310cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis        size = 1;
311cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    }
312cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    snprintf(str, 32, "%d", size);
313cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    return writeStr(k_traceBufferSizePath, str);
314cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
315cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
316fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
317fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// clock will result in the kernel using a per-CPU local clock.
318fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setGlobalClockEnable(bool enable)
319fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
320fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(k_traceClockPath, enable ? "global" : "local");
321fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
322fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
323e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool setPrintTgidEnableIfPresent(bool enable)
324e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
325e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    if (fileExists(k_printTgidPath)) {
326e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        return setKernelOptionEnable(k_printTgidPath, enable);
327e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    }
328e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return true;
329e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
330e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
3316eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Poke all the binder-enabled processes in the system to get them to re-read
3326eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// their system properties.
3336eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool pokeBinderServices()
3346eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
3356eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    sp<IServiceManager> sm = defaultServiceManager();
3366eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    Vector<String16> services = sm->listServices();
3376eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (size_t i = 0; i < services.size(); i++) {
3386eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        sp<IBinder> obj = sm->checkService(services[i]);
3396eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (obj != NULL) {
3406eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            Parcel data;
3416eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
3426eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    NULL, 0) != OK) {
3436eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (false) {
3446eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    // XXX: For some reason this fails on tablets trying to
3456eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    // poke the "phone" service.  It's not clear whether some
3466eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    // are expected to fail.
3476eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    String8 svc(services[i]);
3486eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    fprintf(stderr, "error poking binder service %s\n",
3496eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                        svc.string());
3506eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    return false;
3516eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
3526eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
3536eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
3546eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
3556eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return true;
3566eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
3576eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
3586eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Set the trace tags that userland tracing uses, and poke the running
3596eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// processes to pick up the new value.
3606eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool setTagsProperty(uint64_t tags)
3616eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
3626eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    char buf[64];
3636eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    snprintf(buf, 64, "%#llx", tags);
3646eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    if (property_set(k_traceTagsProperty, buf) < 0) {
3656eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        fprintf(stderr, "error setting trace tags system property\n");
3666eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        return false;
3676eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
3686eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return pokeBinderServices();
3696eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
3706eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
3716eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Disable all /sys/ enable files.
3726eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool disableKernelTraceEvents() {
3736eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    bool ok = true;
3746eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
3756eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const TracingCategory &c = k_categories[i];
3766eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        for (int j = 0; j < MAX_SYS_FILES; j++) {
3776eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            const char* path = c.sysfiles[j].path;
3786eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (path != NULL && fileIsWritable(path)) {
3796eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                ok &= setKernelOptionEnable(path, false);
3806eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
3816eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
3826eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
3836eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return ok;
3846eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
3856eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
386e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Verify that the comma separated list of functions are being traced by the
387e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// kernel.
388e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool verifyKernelTraceFuncs(const char* funcs)
389e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
390e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    int fd = open(k_ftraceFilterPath, O_RDONLY);
391e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    if (fd == -1) {
392e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
393e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            strerror(errno), errno);
394e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        return false;
395e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    }
396e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
397e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    char buf[4097];
398e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    ssize_t n = read(fd, buf, 4096);
399e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    close(fd);
400e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    if (n == -1) {
401e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath,
402e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            strerror(errno), errno);
403e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        return false;
404e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    }
405e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
406e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    buf[n] = '\0';
407e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    String8 funcList = String8::format("\n%s", buf);
408e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
409e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    // Make sure that every function listed in funcs is in the list we just
410e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    // read from the kernel.
411e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    bool ok = true;
412e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    char* myFuncs = strdup(funcs);
413e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    char* func = strtok(myFuncs, ",");
414e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    while (func) {
415e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        String8 fancyFunc = String8::format("\n%s\n", func);
416e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        bool found = funcList.find(fancyFunc.string(), 0) >= 0;
417e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        if (!found || func[0] == '\0') {
418e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            fprintf(stderr, "error: \"%s\" is not a valid kernel function "
419e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis                "to trace.\n", func);
420e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            ok = false;
421e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        }
422e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        func = strtok(NULL, ",");
423e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    }
424e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    free(myFuncs);
425e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
426e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return ok;
427e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
428e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
429e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Set the comma separated list of functions that the kernel is to trace.
430e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool setKernelTraceFuncs(const char* funcs)
431e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
432e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    bool ok = true;
433e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
434e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    if (funcs == NULL || funcs[0] == '\0') {
435e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        // Disable kernel function tracing.
4366f6f3f710b4dec2952298ae65d5f1674535c63f0Jamie Gennis        if (fileIsWritable(k_currentTracerPath)) {
4376f6f3f710b4dec2952298ae65d5f1674535c63f0Jamie Gennis            ok &= writeStr(k_currentTracerPath, "nop");
4386f6f3f710b4dec2952298ae65d5f1674535c63f0Jamie Gennis        }
4396f6f3f710b4dec2952298ae65d5f1674535c63f0Jamie Gennis        if (fileIsWritable(k_ftraceFilterPath)) {
440e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            ok &= truncateFile(k_ftraceFilterPath);
441e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        }
442e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    } else {
443e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        // Enable kernel function tracing.
444e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        ok &= writeStr(k_currentTracerPath, "function_graph");
445e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
446e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
447e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
448e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        ok &= setKernelOptionEnable(k_funcgraphFlatPath, true);
449e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
450e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        // Set the requested filter functions.
451e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        ok &= truncateFile(k_ftraceFilterPath);
452e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        char* myFuncs = strdup(funcs);
453e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        char* func = strtok(myFuncs, ",");
454e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        while (func) {
455e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            ok &= appendStr(k_ftraceFilterPath, func);
456e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            func = strtok(NULL, ",");
457e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        }
458e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        free(myFuncs);
459e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
460e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        // Verify that the set functions are being traced.
461e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        if (ok) {
462e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            ok &= verifyKernelTraceFuncs(funcs);
463e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        }
464e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    }
465e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
466e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return ok;
467e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
468e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
469e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Set all the kernel tracing settings to the desired state for this trace
470e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// capture.
471e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool setUpTrace()
472fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
473fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
474fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
4756eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Set up the tracing options.
476fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
477cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
478fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setGlobalClockEnable(true);
479e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    ok &= setPrintTgidEnableIfPresent(true);
480e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
481fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
4826eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Set up the tags property.
4836eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    uint64_t tags = 0;
4846eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
4856eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (g_categoryEnables[i]) {
4866eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            const TracingCategory &c = k_categories[i];
4876eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            tags |= c.tags;
4886eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
4896eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
4906eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    ok &= setTagsProperty(tags);
4916eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
4926eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Disable all the sysfs enables.  This is done as a separate loop from
4936eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // the enables to allow the same enable to exist in multiple categories.
4946eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    ok &= disableKernelTraceEvents();
4956eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
4966eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Enable all the sysfs enables that are in an enabled category.
4976eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
4986eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (g_categoryEnables[i]) {
4996eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            const TracingCategory &c = k_categories[i];
5006eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            for (int j = 0; j < MAX_SYS_FILES; j++) {
5016eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                const char* path = c.sysfiles[j].path;
5026eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                bool required = c.sysfiles[j].required == REQ;
5036eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (path != NULL) {
5046eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    if (fileIsWritable(path)) {
5056eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                        ok &= setKernelOptionEnable(path, true);
5066eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    } else if (required) {
5076eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                        fprintf(stderr, "error writing file %s\n", path);
5086eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                        ok = false;
5096eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    }
5106eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
5116eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
5126eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
5134b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    }
5144b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
515fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
516fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
517fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
518e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Reset all the kernel tracing settings to their default state.
519e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic void cleanUpTrace()
520fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
5216eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Disable all tracing that we're able to.
5226eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    disableKernelTraceEvents();
5236eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
5246eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Disable all the trace tags.
5256eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    setTagsProperty(0);
5266eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
527fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Set the options back to their defaults.
528fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTraceOverwriteEnable(true);
529e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    setTraceBufferSizeKB(1);
530fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setGlobalClockEnable(false);
531e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    setPrintTgidEnableIfPresent(false);
532e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    setKernelTraceFuncs(NULL);
533e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
534e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
535e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
536e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Enable tracing in the kernel.
537e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool startTrace()
538e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
539e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return setTracingEnabled(true);
540e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
541cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
542e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Disable tracing in the kernel.
543e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic void stopTrace()
544e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
545e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    setTracingEnabled(false);
546fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
547fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
548fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Read the current kernel trace and write it to stdout.
549fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void dumpTrace()
550fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
551fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
552fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
553fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
554fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
555fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return;
556fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
557fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
5587b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    if (g_compress) {
5597b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        z_stream zs;
5607b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        uint8_t *in, *out;
5617b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        int result, flush;
5627b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
5637b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        bzero(&zs, sizeof(zs));
5647b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
5657b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
5667b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error initializing zlib: %d\n", result);
5677b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            close(traceFD);
5687b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            return;
5697b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
5707b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
5717b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        const size_t bufSize = 64*1024;
5727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        in = (uint8_t*)malloc(bufSize);
5737b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        out = (uint8_t*)malloc(bufSize);
5747b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        flush = Z_NO_FLUSH;
5757b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
5767b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.next_out = out;
5777b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.avail_out = bufSize;
5787b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
5797b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        do {
5807b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
5817b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_in == 0) {
5827b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // More input is needed.
5837b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = read(traceFD, in, bufSize);
5847b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if (result < 0) {
5857b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error reading trace: %s (%d)\n",
5867b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
5877b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END;
5887b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
5897b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else if (result == 0) {
5907b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    flush = Z_FINISH;
5917b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else {
5927b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.next_in = in;
5937b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_in = result;
5947b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
5957b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
5967b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
5977b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_out == 0) {
5987b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // Need to write the output.
5997b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = write(STDOUT_FILENO, out, bufSize);
6007b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if ((size_t)result < bufSize) {
6017b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error writing deflated trace: %s (%d)\n",
6027b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
6037b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END; // skip deflate error message
6047b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_out = bufSize; // skip the final write
6057b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
6067b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
6077b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.next_out = out;
6087b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.avail_out = bufSize;
6097b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
6107b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
6117b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        } while ((result = deflate(&zs, flush)) == Z_OK);
6127b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
6137b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_STREAM_END) {
6147b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error deflating trace: %s\n", zs.msg);
6157b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
6167b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
6177b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (zs.avail_out < bufSize) {
6187b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            size_t bytes = bufSize - zs.avail_out;
6197b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            result = write(STDOUT_FILENO, out, bytes);
6207b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if ((size_t)result < bytes) {
6217b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                fprintf(stderr, "error writing deflated trace: %s (%d)\n",
6227b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                        strerror(errno), errno);
6237b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
6247b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
6257b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
6267b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateEnd(&zs);
6277b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
6287b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error cleaning up zlib: %d\n", result);
6297b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
6307b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
6317b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(in);
6327b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(out);
6337b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    } else {
6347b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        ssize_t sent = 0;
6357b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
6367b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (sent == -1) {
6377b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
6387b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    errno);
6397b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
640fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
641fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
642fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
643fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
644fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
6456eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic void handleSignal(int signo)
646fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
64731be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    if (!g_nohup) {
64831be80f02cddda55e75614884038fa4645b694cdGlenn Kasten        g_traceAborted = true;
64931be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    }
650fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
651fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
6526eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic void registerSigHandler()
6536eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
654fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    struct sigaction sa;
655fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigemptyset(&sa.sa_mask);
656fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_flags = 0;
657fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_handler = handleSignal;
658fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGHUP, &sa, NULL);
659fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGINT, &sa, NULL);
660fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGQUIT, &sa, NULL);
661fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGTERM, &sa, NULL);
662fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
663fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
6646eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool setCategoryEnable(const char* name, bool enable)
6656eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
6666eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
6676eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const TracingCategory& c = k_categories[i];
6686eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (strcmp(name, c.name) == 0) {
6696eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (isCategorySupported(c)) {
6706eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                g_categoryEnables[i] = enable;
6716eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                return true;
6726eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            } else {
6736eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (isCategorySupportedForRoot(c)) {
6746eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    fprintf(stderr, "error: category \"%s\" requires root "
6756eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                            "privileges.\n", name);
6766eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                } else {
6776eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    fprintf(stderr, "error: category \"%s\" is not supported "
6786eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                            "on this device.\n", name);
6796eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
6806eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                return false;
6816eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
6826eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
6836eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
6846eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
6856eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return false;
6866eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
6876eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
6886eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic void listSupportedCategories()
6896eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
6906eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
6916eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const TracingCategory& c = k_categories[i];
6926eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (isCategorySupported(c)) {
6936eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            printf("  %10s - %s\n", c.name, c.longname);
6946eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
6956eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
6966eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
6976eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
6986eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Print the command usage help to stderr.
6996eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic void showHelp(const char *cmd)
7006eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
7016eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    fprintf(stderr, "usage: %s [options] [categories...]\n", cmd);
7026eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    fprintf(stderr, "options include:\n"
7036eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -b N            use a trace buffer size of N KB\n"
7046eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -c              trace into a circular buffer\n"
705e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis                    "  -k fname,...    trace the listed kernel functions\n"
7066eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -n              ignore signals\n"
7076eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -s N            sleep for N seconds before tracing [default 0]\n"
7086eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
7096eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -z              compress the trace dump\n"
7106eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  --async_start   start circular trace and return immediatly\n"
7116eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  --async_dump    dump the current contents of circular trace buffer\n"
7126eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  --async_stop    stop tracing and dump the current contents of circular\n"
7136eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "                    trace buffer\n"
71492573f1ba0d5360d7bfa8ab8935118db7a251f62Jamie Gennis                    "  --list_categories\n"
71592573f1ba0d5360d7bfa8ab8935118db7a251f62Jamie Gennis                    "                  list the available tracing categories\n"
7166eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            );
7176eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
7186eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
719fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisint main(int argc, char **argv)
720fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
7214edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool async = false;
7224edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool traceStart = true;
7234edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool traceStop = true;
7244edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool traceDump = true;
7254b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
726fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
727fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        showHelp(argv[0]);
728fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        exit(0);
729fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
730fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
731fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    for (;;) {
732fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        int ret;
7334edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        int option_index = 0;
7344edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        static struct option long_options[] = {
7354edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            {"async_start",     no_argument, 0,  0 },
7364edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            {"async_stop",      no_argument, 0,  0 },
7374edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            {"async_dump",      no_argument, 0,  0 },
7386eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            {"list_categories", no_argument, 0,  0 },
7396eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            {           0,                0, 0,  0 }
7404edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        };
741fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
742e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        ret = getopt_long(argc, argv, "b:ck:ns:t:z",
7434edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                          long_options, &option_index);
744fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
745fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (ret < 0) {
7466eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            for (int i = optind; i < argc; i++) {
7476eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (!setCategoryEnable(argv[i], true)) {
7486eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
7496eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    exit(1);
7506eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
7516eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
752fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
753fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
754fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
755fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        switch(ret) {
756cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'b':
757cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                g_traceBufferSizeKB = atoi(optarg);
758cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
759cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
760fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'c':
761fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceOverwrite = true;
762fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
763fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
764e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            case 'k':
765e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis                g_kernelTraceFuncs = optarg;
7666f6f3f710b4dec2952298ae65d5f1674535c63f0Jamie Gennis            break;
767e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
76831be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            case 'n':
76931be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                g_nohup = true;
7706f6f3f710b4dec2952298ae65d5f1674535c63f0Jamie Gennis            break;
77131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
772fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 's':
77331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                g_initialSleepSecs = atoi(optarg);
77431be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            break;
77531be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
776fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 't':
777fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceDurationSeconds = atoi(optarg);
778fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
779fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
7807b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            case 'z':
7817b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                g_compress = true;
7827b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            break;
7837b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
7844edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            case 0:
7854edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                if (!strcmp(long_options[option_index].name, "async_start")) {
7864edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    async = true;
7874edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStop = false;
7884edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceDump = false;
7894edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    g_traceOverwrite = true;
7904edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                } else if (!strcmp(long_options[option_index].name, "async_stop")) {
7914edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    async = true;
7924edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStop = false;
7934edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                } else if (!strcmp(long_options[option_index].name, "async_dump")) {
7944edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    async = true;
7954edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStart = false;
7964edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStop = false;
7976eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                } else if (!strcmp(long_options[option_index].name, "list_categories")) {
7986eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    listSupportedCategories();
7996eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    exit(0);
8004edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                }
8016f6f3f710b4dec2952298ae65d5f1674535c63f0Jamie Gennis            break;
8024edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling
803fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            default:
804cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                fprintf(stderr, "\n");
805fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                showHelp(argv[0]);
806fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                exit(-1);
807fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
808fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
809fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
810fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
811fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    registerSigHandler();
812fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
81331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    if (g_initialSleepSecs > 0) {
81431be80f02cddda55e75614884038fa4645b694cdGlenn Kasten        sleep(g_initialSleepSecs);
81531be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    }
81631be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
817e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    bool ok = true;
818e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    ok &= setUpTrace();
819e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    ok &= startTrace();
820fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
8214edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (ok && traceStart) {
822fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        printf("capturing trace...");
823fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fflush(stdout);
824fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
825fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // We clear the trace after starting it because tracing gets enabled for
826fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
827fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
828fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
829fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // another.
830fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = clearTrace();
831fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
8324edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        if (ok && !async) {
833fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            // Sleep to allow the trace to be captured.
834fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            struct timespec timeLeft;
835fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
836fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_nsec = 0;
837fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            do {
838fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                if (g_traceAborted) {
839fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    break;
840fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                }
841fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
842fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
843fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
844fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
845fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Stop the trace and restore the default settings.
8464edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (traceStop)
8476eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        stopTrace();
848fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
8494edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (ok && traceDump) {
850fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (!g_traceAborted) {
851fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf(" done\nTRACE:\n");
852fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
853fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            dumpTrace();
854fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        } else {
855fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf("\ntrace aborted.\n");
856fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
857fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
858fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        clearTrace();
8594edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    } else if (!ok) {
860fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "unable to start tracing\n");
861fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
862fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
863cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // Reset the trace buffer size to 1.
8644edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (traceStop)
865e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        cleanUpTrace();
866cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
867fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return g_traceAborted ? 1 : 0;
868fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
869