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>
2092dc3fc52cf097bd105460cf377779bdcf146d62Mark Salyzyn#include <inttypes.h>
21fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <signal.h>
22fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdarg.h>
23fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdbool.h>
24fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdio.h>
25fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdlib.h>
26fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <sys/sendfile.h>
27fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <time.h>
287b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis#include <zlib.h>
29fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
306eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <binder/IBinder.h>
316eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <binder/IServiceManager.h>
326eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <binder/Parcel.h>
336eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
346eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <cutils/properties.h>
356eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
366eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <utils/String8.h>
376eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <utils/Trace.h>
386eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
396eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisusing namespace android;
406eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
41ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
42ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
4326dbcbe01367a8d4b0ca89c8590758aa72ee045cMohamad Ayyashenum { MAX_SYS_FILES = 10 };
446eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
456eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisconst char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
46f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennisconst char* k_traceAppCmdlineProperty = "debug.atrace.app_cmdlines";
476eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
486eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennistypedef enum { OPT, REQ } requiredness  ;
496eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
506eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstruct TracingCategory {
516eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // The name identifying the category.
526eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    const char* name;
536eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
546eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // A longer description of the category.
556eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    const char* longname;
566eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
576eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // The userland tracing tags that the category enables.
586eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    uint64_t tags;
596eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
606eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // The fname==NULL terminated list of /sys/ files that the category
616eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // enables.
626eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    struct {
636eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        // Whether the file must be writable in order to enable the tracing
646eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        // category.
656eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        requiredness required;
666eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
676eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        // The path to the enable file.
686eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const char* path;
696eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } sysfiles[MAX_SYS_FILES];
706eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis};
716eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
726eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis/* Tracing categories */
736eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic const TracingCategory k_categories[] = {
74b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "gfx",        "Graphics",         ATRACE_TAG_GRAPHICS, { } },
75b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "input",      "Input",            ATRACE_TAG_INPUT, { } },
76b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "view",       "View System",      ATRACE_TAG_VIEW, { } },
77b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "webview",    "WebView",          ATRACE_TAG_WEBVIEW, { } },
78b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "wm",         "Window Manager",   ATRACE_TAG_WINDOW_MANAGER, { } },
79b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "am",         "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
8070ec2941530766bdca09ef2983a3ff794c028ee6Patrick Auchter    { "sm",         "Sync Manager",     ATRACE_TAG_SYNC_MANAGER, { } },
81b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "audio",      "Audio",            ATRACE_TAG_AUDIO, { } },
82b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "video",      "Video",            ATRACE_TAG_VIDEO, { } },
83b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "camera",     "Camera",           ATRACE_TAG_CAMERA, { } },
84b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "hal",        "Hardware Modules", ATRACE_TAG_HAL, { } },
853200b0bf507936ecf43784191880e4e91c54568cJeff Brown    { "app",        "Application",      ATRACE_TAG_APP, { } },
869380d78c98d8b8fbce9ade5881fab7134fadc015Dianne Hackborn    { "res",        "Resource Loading", ATRACE_TAG_RESOURCES, { } },
87eff2e8d2374692213204468433e3d96e7472ea02Jamie Gennis    { "dalvik",     "Dalvik VM",        ATRACE_TAG_DALVIK, { } },
88f0f2841d95a26247dfa0b31a6bfa8b010fe89aa2Tim Murray    { "rs",         "RenderScript",     ATRACE_TAG_RS, { } },
89750aa9743c0c4c592213fbb39b8d328bd0075fd6Brigid Smith    { "bionic",     "Bionic C Library", ATRACE_TAG_BIONIC, { } },
903200b0bf507936ecf43784191880e4e91c54568cJeff Brown    { "power",      "Power Management", ATRACE_TAG_POWER, { } },
91b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "sched",      "CPU Scheduling",   0, {
92b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
93b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
946eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
95f440d398faad3bafe2e7f365c62163aca45e36a3Dan Willemsen    { "irq",        "IRQ Events",   0, {
96f440d398faad3bafe2e7f365c62163aca45e36a3Dan Willemsen        { REQ,      "/sys/kernel/debug/tracing/events/irq/enable" },
97f440d398faad3bafe2e7f365c62163aca45e36a3Dan Willemsen    } },
98b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "freq",       "CPU Frequency",    0, {
99b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
100b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { OPT,      "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
1016eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
102b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "membus",     "Memory Bus Utilization", 0, {
103b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/memory_bus/enable" },
1046eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
105b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "idle",       "CPU Idle",         0, {
106b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
1076eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
108b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "disk",       "Disk I/O",         0, {
109e80d32c3c2ec4f2acc917c92c9c943e81de80496Greg Hackmann        { OPT,      "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable" },
110e80d32c3c2ec4f2acc917c92c9c943e81de80496Greg Hackmann        { OPT,      "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable" },
111e80d32c3c2ec4f2acc917c92c9c943e81de80496Greg Hackmann        { OPT,      "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable" },
112e80d32c3c2ec4f2acc917c92c9c943e81de80496Greg Hackmann        { OPT,      "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable" },
113e80d32c3c2ec4f2acc917c92c9c943e81de80496Greg Hackmann        { OPT,      "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable" },
114e80d32c3c2ec4f2acc917c92c9c943e81de80496Greg Hackmann        { OPT,      "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable" },
115e80d32c3c2ec4f2acc917c92c9c943e81de80496Greg Hackmann        { OPT,      "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
116e80d32c3c2ec4f2acc917c92c9c943e81de80496Greg Hackmann        { OPT,      "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
117b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
118b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" },
1196eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
120d3fa5616160c53d5bec8cd91d65f3732413c1a56Ken Sumrall    { "mmc",        "eMMC commands",    0, {
121d3fa5616160c53d5bec8cd91d65f3732413c1a56Ken Sumrall        { REQ,      "/sys/kernel/debug/tracing/events/mmc/enable" },
122d3fa5616160c53d5bec8cd91d65f3732413c1a56Ken Sumrall    } },
123b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "load",       "CPU Load",         0, {
124b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
1256eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
126b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "sync",       "Synchronization",  0, {
127b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/sync/enable" },
1286eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
129b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis    { "workq",      "Kernel Workqueues", 0, {
130b2a89e3155969e5bc9653966069d6dbabdd3f623Jamie Gennis        { REQ,      "/sys/kernel/debug/tracing/events/workqueue/enable" },
1316eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
132580407f1075fe97d7466724f71cc03816b7404feColin Cross    { "memreclaim", "Kernel Memory Reclaim", 0, {
133580407f1075fe97d7466724f71cc03816b7404feColin Cross        { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
134580407f1075fe97d7466724f71cc03816b7404feColin Cross        { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
135580407f1075fe97d7466724f71cc03816b7404feColin Cross        { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable" },
136580407f1075fe97d7466724f71cc03816b7404feColin Cross        { REQ,      "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable" },
137580407f1075fe97d7466724f71cc03816b7404feColin Cross    } },
1386eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis};
1396eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
140fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Command line options */
141fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic int g_traceDurationSeconds = 5;
142fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceOverwrite = false;
143cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic int g_traceBufferSizeKB = 2048;
1447b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennisstatic bool g_compress = false;
14531be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic bool g_nohup = false;
14631be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic int g_initialSleepSecs = 0;
147e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* g_kernelTraceFuncs = NULL;
148f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennisstatic const char* g_debugAppCmdLine = "";
149fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
150fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Global state */
151fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceAborted = false;
1526eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool g_categoryEnables[NELEM(k_categories)] = {};
153fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
154fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Sys file paths */
155fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceClockPath =
156fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_clock";
157fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
158cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_traceBufferSizePath =
159cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/buffer_size_kb";
160cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
161fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOverwriteEnablePath =
162fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/options/overwrite";
163fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
164e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_currentTracerPath =
165e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/current_tracer";
166e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
167e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_printTgidPath =
168e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/options/print-tgid";
169e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
170e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_funcgraphAbsTimePath =
171e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/options/funcgraph-abstime";
172e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
173e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_funcgraphCpuPath =
174e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/options/funcgraph-cpu";
175e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
176e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_funcgraphProcPath =
177e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/options/funcgraph-proc";
178e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
179e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_funcgraphFlatPath =
180e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/options/funcgraph-flat";
181e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
182e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_funcgraphDurationPath =
183e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/options/funcgraph-duration";
184e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
185e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic const char* k_ftraceFilterPath =
186e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    "/sys/kernel/debug/tracing/set_ftrace_filter";
187e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
188fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOnPath =
189fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
190fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
191fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracePath =
192fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace";
193fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
194e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis// Check whether a file exists.
195e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennisstatic bool fileExists(const char* filename) {
196e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return access(filename, F_OK) != -1;
197e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis}
198e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis
1996eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Check whether a file is writable.
2006eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool fileIsWritable(const char* filename) {
2016eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return access(filename, W_OK) != -1;
2026eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
2036eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
204e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Truncate a file.
205e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool truncateFile(const char* path)
206fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
20743122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis    // This uses creat rather than truncate because some of the debug kernel
20843122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis    // device nodes (e.g. k_ftraceFilterPath) currently aren't changed by
20943122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis    // calls to truncate, but they are cleared by calls to creat.
21043122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis    int traceFD = creat(path, 0);
21143122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis    if (traceFD == -1) {
212e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", path,
21343122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis            strerror(errno), errno);
214e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        return false;
215e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    }
216e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
21743122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis    close(traceFD);
21843122e7e672eb170334a4467dd41cf4bd545bae5Jamie Gennis
219e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return true;
220e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
221e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
222e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool _writeStr(const char* filename, const char* str, int flags)
223e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
224e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    int fd = open(filename, flags);
225fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (fd == -1) {
226fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
227fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
228fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
229fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
230fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
231fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
232fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ssize_t len = strlen(str);
233fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (write(fd, str, len) != len) {
234fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
235fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
236fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = false;
237fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
238fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
239fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(fd);
240fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
241fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
242fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
243fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
244e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Write a string to a file, returning true if the write was successful.
245e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool writeStr(const char* filename, const char* str)
246e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
247e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return _writeStr(filename, str, O_WRONLY);
248e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
249e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
250e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Append a string to a file, returning true if the write was successful.
251e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool appendStr(const char* filename, const char* str)
252e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
253e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return _writeStr(filename, str, O_APPEND|O_WRONLY);
254e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
255e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
2566eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys
2576eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// file.
258fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
259fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
260fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(filename, enable ? "1" : "0");
261fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
262fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
2636eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Check whether the category is supported on the device with the current
2646eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// rootness.  A category is supported only if all its required /sys/ files are
2656eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// writable and if enabling the category will enable one or more tracing tags
2666eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// or /sys/ files.
2676eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool isCategorySupported(const TracingCategory& category)
2683169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis{
2696eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    bool ok = category.tags != 0;
2706eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < MAX_SYS_FILES; i++) {
2716eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const char* path = category.sysfiles[i].path;
2726eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        bool req = category.sysfiles[i].required == REQ;
2736eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (path != NULL) {
2746eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (req) {
2756eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (!fileIsWritable(path)) {
2766eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    return false;
2776eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                } else {
2786eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    ok = true;
2796eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
2806eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            } else {
2816eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                ok |= fileIsWritable(path);
2826eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
2836eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
284e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
285e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return ok;
286cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
287cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
2886eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Check whether the category would be supported on the device if the user
2896eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// were root.  This function assumes that root is able to write to any file
2906eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// that exists.  It performs the same logic as isCategorySupported, but it
2916eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// uses file existance rather than writability in the /sys/ file checks.
2926eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool isCategorySupportedForRoot(const TracingCategory& category)
2939ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling{
2946eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    bool ok = category.tags != 0;
2956eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < MAX_SYS_FILES; i++) {
2966eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const char* path = category.sysfiles[i].path;
2976eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        bool req = category.sysfiles[i].required == REQ;
2986eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (path != NULL) {
2996eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (req) {
3006eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (!fileExists(path)) {
3016eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    return false;
3026eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                } else {
3036eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    ok = true;
3046eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
3056eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            } else {
3066eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                ok |= fileExists(path);
3076eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
3086eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
3099ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    }
3109ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    return ok;
3119ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling}
3129ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling
3136eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
3146eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// will cause tracing to stop once the trace buffers have filled up.
3156eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
316ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{
3176eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
318ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}
319ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
320fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable kernel tracing.
321fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTracingEnabled(bool enable)
322fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
323fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
324fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
325fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
326fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Clear the contents of the kernel trace.
327fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool clearTrace()
328fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
329e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return truncateFile(k_tracePath);
330fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
331fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
332cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes.
333cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setTraceBufferSizeKB(int size)
334cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
335cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    char str[32] = "1";
336cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    int len;
337cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    if (size < 1) {
338cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis        size = 1;
339cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    }
340cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    snprintf(str, 32, "%d", size);
341cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    return writeStr(k_traceBufferSizePath, str);
342cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
343cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
344b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross// Read the trace_clock sysfs file and return true if it matches the requested
345b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross// value.  The trace_clock file format is:
346b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross// local [global] counter uptime perf
347b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Crossstatic bool isTraceClock(const char *mode)
348b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross{
349b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    int fd = open(k_traceClockPath, O_RDONLY);
350b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    if (fd == -1) {
351b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross        fprintf(stderr, "error opening %s: %s (%d)\n", k_traceClockPath,
352b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross            strerror(errno), errno);
353b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross        return false;
354b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    }
355b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross
356b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    char buf[4097];
357b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    ssize_t n = read(fd, buf, 4096);
358b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    close(fd);
359b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    if (n == -1) {
360b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross        fprintf(stderr, "error reading %s: %s (%d)\n", k_traceClockPath,
361b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross            strerror(errno), errno);
362b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross        return false;
363b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    }
364b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    buf[n] = '\0';
365b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross
366b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    char *start = strchr(buf, '[');
367b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    if (start == NULL) {
368b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross        return false;
369b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    }
370b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    start++;
371b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross
372b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    char *end = strchr(start, ']');
373b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    if (end == NULL) {
374b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross        return false;
375b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    }
376b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    *end = '\0';
377b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross
378b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    return strcmp(mode, start) == 0;
379b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross}
380b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross
381fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
382fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// clock will result in the kernel using a per-CPU local clock.
383b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross// Any write to the trace_clock sysfs file will reset the buffer, so only
384b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross// update it if the requested value is not the current value.
385fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setGlobalClockEnable(bool enable)
386fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
387b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    const char *clock = enable ? "global" : "local";
388b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross
389b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    if (isTraceClock(clock)) {
390b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross        return true;
391b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    }
392b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross
393b1ce49b2ed9ea953a7f534b4f36b6acb56fc0749Colin Cross    return writeStr(k_traceClockPath, clock);
394fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
395fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
396e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool setPrintTgidEnableIfPresent(bool enable)
397e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
398e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    if (fileExists(k_printTgidPath)) {
399e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        return setKernelOptionEnable(k_printTgidPath, enable);
400e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    }
401e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return true;
402e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
403e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
4046eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Poke all the binder-enabled processes in the system to get them to re-read
4056eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// their system properties.
4066eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool pokeBinderServices()
4076eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
4086eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    sp<IServiceManager> sm = defaultServiceManager();
4096eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    Vector<String16> services = sm->listServices();
4106eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (size_t i = 0; i < services.size(); i++) {
4116eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        sp<IBinder> obj = sm->checkService(services[i]);
4126eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (obj != NULL) {
4136eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            Parcel data;
4146eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
4156eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    NULL, 0) != OK) {
4166eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (false) {
4176eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    // XXX: For some reason this fails on tablets trying to
4186eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    // poke the "phone" service.  It's not clear whether some
4196eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    // are expected to fail.
4206eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    String8 svc(services[i]);
4216eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    fprintf(stderr, "error poking binder service %s\n",
4226eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                        svc.string());
4236eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    return false;
4246eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
4256eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
4266eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
4276eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
4286eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return true;
4296eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
4306eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
4316eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Set the trace tags that userland tracing uses, and poke the running
4326eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// processes to pick up the new value.
4336eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool setTagsProperty(uint64_t tags)
4346eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
4356eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    char buf[64];
43692dc3fc52cf097bd105460cf377779bdcf146d62Mark Salyzyn    snprintf(buf, 64, "%#" PRIx64, tags);
4376eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    if (property_set(k_traceTagsProperty, buf) < 0) {
4386eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        fprintf(stderr, "error setting trace tags system property\n");
4396eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        return false;
4406eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
441f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis    return true;
442f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis}
443f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis
444f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis// Set the system property that indicates which apps should perform
445f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis// application-level tracing.
446f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennisstatic bool setAppCmdlineProperty(const char* cmdline)
447f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis{
448f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis    if (property_set(k_traceAppCmdlineProperty, cmdline) < 0) {
449f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis        fprintf(stderr, "error setting trace app system property\n");
450f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis        return false;
451f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis    }
452f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis    return true;
4536eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
4546eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
4556eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Disable all /sys/ enable files.
4566eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool disableKernelTraceEvents() {
4576eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    bool ok = true;
4586eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
4596eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const TracingCategory &c = k_categories[i];
4606eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        for (int j = 0; j < MAX_SYS_FILES; j++) {
4616eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            const char* path = c.sysfiles[j].path;
4626eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (path != NULL && fileIsWritable(path)) {
4636eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                ok &= setKernelOptionEnable(path, false);
4646eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
4656eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
4666eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
4676eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return ok;
4686eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
4696eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
470e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Verify that the comma separated list of functions are being traced by the
471e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// kernel.
472e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool verifyKernelTraceFuncs(const char* funcs)
473e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
474e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    int fd = open(k_ftraceFilterPath, O_RDONLY);
475e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    if (fd == -1) {
476e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
477e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            strerror(errno), errno);
478e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        return false;
479e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    }
480e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
481e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    char buf[4097];
482e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    ssize_t n = read(fd, buf, 4096);
483e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    close(fd);
484e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    if (n == -1) {
485e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath,
486e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            strerror(errno), errno);
487e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        return false;
488e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    }
489e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
490e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    buf[n] = '\0';
491e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    String8 funcList = String8::format("\n%s", buf);
492e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
493e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    // Make sure that every function listed in funcs is in the list we just
494e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    // read from the kernel.
495e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    bool ok = true;
496e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    char* myFuncs = strdup(funcs);
497e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    char* func = strtok(myFuncs, ",");
498e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    while (func) {
499e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        String8 fancyFunc = String8::format("\n%s\n", func);
500e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        bool found = funcList.find(fancyFunc.string(), 0) >= 0;
501e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        if (!found || func[0] == '\0') {
502e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            fprintf(stderr, "error: \"%s\" is not a valid kernel function "
503e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis                "to trace.\n", func);
504e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            ok = false;
505e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        }
506e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        func = strtok(NULL, ",");
507e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    }
508e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    free(myFuncs);
509e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
510e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return ok;
511e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
512e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
513e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Set the comma separated list of functions that the kernel is to trace.
514e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool setKernelTraceFuncs(const char* funcs)
515e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
516e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    bool ok = true;
517e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
518e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    if (funcs == NULL || funcs[0] == '\0') {
519e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        // Disable kernel function tracing.
5206f6f3f710b4dec2952298ae65d5f1674535c63f0Jamie Gennis        if (fileIsWritable(k_currentTracerPath)) {
5216f6f3f710b4dec2952298ae65d5f1674535c63f0Jamie Gennis            ok &= writeStr(k_currentTracerPath, "nop");
5226f6f3f710b4dec2952298ae65d5f1674535c63f0Jamie Gennis        }
5236f6f3f710b4dec2952298ae65d5f1674535c63f0Jamie Gennis        if (fileIsWritable(k_ftraceFilterPath)) {
524e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            ok &= truncateFile(k_ftraceFilterPath);
525e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        }
526e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    } else {
527e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        // Enable kernel function tracing.
528e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        ok &= writeStr(k_currentTracerPath, "function_graph");
529e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
530e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
531e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
532e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        ok &= setKernelOptionEnable(k_funcgraphFlatPath, true);
533e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
534e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        // Set the requested filter functions.
535e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        ok &= truncateFile(k_ftraceFilterPath);
536e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        char* myFuncs = strdup(funcs);
537e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        char* func = strtok(myFuncs, ",");
538e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        while (func) {
539e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            ok &= appendStr(k_ftraceFilterPath, func);
540e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            func = strtok(NULL, ",");
541e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        }
542e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        free(myFuncs);
543e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
544e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        // Verify that the set functions are being traced.
545e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        if (ok) {
546e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            ok &= verifyKernelTraceFuncs(funcs);
547e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        }
548e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    }
549e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
550e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return ok;
551e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
552e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
553e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Set all the kernel tracing settings to the desired state for this trace
554e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// capture.
555e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool setUpTrace()
556fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
557fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
558fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
5596eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Set up the tracing options.
560fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
561cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
562fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setGlobalClockEnable(true);
563e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    ok &= setPrintTgidEnableIfPresent(true);
564e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
565fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
5666eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Set up the tags property.
5676eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    uint64_t tags = 0;
5686eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
5696eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (g_categoryEnables[i]) {
5706eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            const TracingCategory &c = k_categories[i];
5716eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            tags |= c.tags;
5726eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
5736eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
5746eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    ok &= setTagsProperty(tags);
575f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis    ok &= setAppCmdlineProperty(g_debugAppCmdLine);
576f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis    ok &= pokeBinderServices();
5776eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
5786eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Disable all the sysfs enables.  This is done as a separate loop from
5796eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // the enables to allow the same enable to exist in multiple categories.
5806eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    ok &= disableKernelTraceEvents();
5816eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
5826eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Enable all the sysfs enables that are in an enabled category.
5836eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
5846eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (g_categoryEnables[i]) {
5856eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            const TracingCategory &c = k_categories[i];
5866eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            for (int j = 0; j < MAX_SYS_FILES; j++) {
5876eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                const char* path = c.sysfiles[j].path;
5886eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                bool required = c.sysfiles[j].required == REQ;
5896eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (path != NULL) {
5906eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    if (fileIsWritable(path)) {
5916eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                        ok &= setKernelOptionEnable(path, true);
5926eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    } else if (required) {
5936eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                        fprintf(stderr, "error writing file %s\n", path);
5946eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                        ok = false;
5956eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    }
5966eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
5976eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
5986eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
5994b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    }
6004b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
601fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
602fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
603fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
604e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Reset all the kernel tracing settings to their default state.
605e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic void cleanUpTrace()
606fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
6076eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Disable all tracing that we're able to.
6086eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    disableKernelTraceEvents();
6096eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
610f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis    // Reset the system properties.
6116eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    setTagsProperty(0);
612f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis    setAppCmdlineProperty("");
613f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis    pokeBinderServices();
6146eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
615fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Set the options back to their defaults.
616fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTraceOverwriteEnable(true);
617e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    setTraceBufferSizeKB(1);
618fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setGlobalClockEnable(false);
619e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    setPrintTgidEnableIfPresent(false);
620e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    setKernelTraceFuncs(NULL);
621e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
622e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
623e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
624e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Enable tracing in the kernel.
625e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic bool startTrace()
626e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
627e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    return setTracingEnabled(true);
628e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis}
629cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
630e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis// Disable tracing in the kernel.
631e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennisstatic void stopTrace()
632e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis{
633e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    setTracingEnabled(false);
634fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
635fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
636fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Read the current kernel trace and write it to stdout.
637fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void dumpTrace()
638fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
639fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
640fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
641fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
642fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
643fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return;
644fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
645fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
6467b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    if (g_compress) {
6477b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        z_stream zs;
6487b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        uint8_t *in, *out;
6497b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        int result, flush;
6507b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
6517b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        bzero(&zs, sizeof(zs));
6527b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
6537b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
6547b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error initializing zlib: %d\n", result);
6557b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            close(traceFD);
6567b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            return;
6577b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
6587b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
6597b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        const size_t bufSize = 64*1024;
6607b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        in = (uint8_t*)malloc(bufSize);
6617b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        out = (uint8_t*)malloc(bufSize);
6627b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        flush = Z_NO_FLUSH;
6637b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
6647b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.next_out = out;
6657b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.avail_out = bufSize;
6667b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
6677b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        do {
6687b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
6697b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_in == 0) {
6707b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // More input is needed.
6717b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = read(traceFD, in, bufSize);
6727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if (result < 0) {
6737b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error reading trace: %s (%d)\n",
6747b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
6757b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END;
6767b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
6777b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else if (result == 0) {
6787b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    flush = Z_FINISH;
6797b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else {
6807b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.next_in = in;
6817b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_in = result;
6827b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
6837b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
6847b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
6857b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_out == 0) {
6867b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // Need to write the output.
6877b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = write(STDOUT_FILENO, out, bufSize);
6887b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if ((size_t)result < bufSize) {
6897b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error writing deflated trace: %s (%d)\n",
6907b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
6917b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END; // skip deflate error message
6927b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_out = bufSize; // skip the final write
6937b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
6947b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
6957b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.next_out = out;
6967b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.avail_out = bufSize;
6977b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
6987b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
6997b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        } while ((result = deflate(&zs, flush)) == Z_OK);
7007b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
7017b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_STREAM_END) {
7027b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error deflating trace: %s\n", zs.msg);
7037b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
7047b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
7057b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (zs.avail_out < bufSize) {
7067b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            size_t bytes = bufSize - zs.avail_out;
7077b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            result = write(STDOUT_FILENO, out, bytes);
7087b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if ((size_t)result < bytes) {
7097b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                fprintf(stderr, "error writing deflated trace: %s (%d)\n",
7107b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                        strerror(errno), errno);
7117b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
7127b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
7137b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
7147b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateEnd(&zs);
7157b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
7167b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error cleaning up zlib: %d\n", result);
7177b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
7187b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
7197b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(in);
7207b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(out);
7217b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    } else {
7227b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        ssize_t sent = 0;
7237b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
7247b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (sent == -1) {
7257b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
7267b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    errno);
7277b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
728fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
729fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
730fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
731fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
732fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
73392dc3fc52cf097bd105460cf377779bdcf146d62Mark Salyzynstatic void handleSignal(int /*signo*/)
734fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
73531be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    if (!g_nohup) {
73631be80f02cddda55e75614884038fa4645b694cdGlenn Kasten        g_traceAborted = true;
73731be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    }
738fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
739fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
7406eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic void registerSigHandler()
7416eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
742fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    struct sigaction sa;
743fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigemptyset(&sa.sa_mask);
744fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_flags = 0;
745fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_handler = handleSignal;
746fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGHUP, &sa, NULL);
747fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGINT, &sa, NULL);
748fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGQUIT, &sa, NULL);
749fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGTERM, &sa, NULL);
750fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
751fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
7526eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool setCategoryEnable(const char* name, bool enable)
7536eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
7546eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
7556eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const TracingCategory& c = k_categories[i];
7566eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (strcmp(name, c.name) == 0) {
7576eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (isCategorySupported(c)) {
7586eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                g_categoryEnables[i] = enable;
7596eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                return true;
7606eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            } else {
7616eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (isCategorySupportedForRoot(c)) {
7626eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    fprintf(stderr, "error: category \"%s\" requires root "
7636eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                            "privileges.\n", name);
7646eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                } else {
7656eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    fprintf(stderr, "error: category \"%s\" is not supported "
7666eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                            "on this device.\n", name);
7676eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
7686eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                return false;
7696eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
7706eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
7716eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
7726eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
7736eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return false;
7746eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
7756eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
7766eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic void listSupportedCategories()
7776eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
7786eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
7796eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const TracingCategory& c = k_categories[i];
7806eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (isCategorySupported(c)) {
7816eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            printf("  %10s - %s\n", c.name, c.longname);
7826eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
7836eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
7846eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
7856eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
7866eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Print the command usage help to stderr.
7876eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic void showHelp(const char *cmd)
7886eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
7896eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    fprintf(stderr, "usage: %s [options] [categories...]\n", cmd);
7906eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    fprintf(stderr, "options include:\n"
791f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis                    "  -a appname      enable app-level tracing for a comma "
792f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis                        "separated list of cmdlines\n"
7936eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -b N            use a trace buffer size of N KB\n"
7946eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -c              trace into a circular buffer\n"
795e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis                    "  -k fname,...    trace the listed kernel functions\n"
7966eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -n              ignore signals\n"
7976eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -s N            sleep for N seconds before tracing [default 0]\n"
7986eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
7996eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -z              compress the trace dump\n"
8006eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  --async_start   start circular trace and return immediatly\n"
8016eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  --async_dump    dump the current contents of circular trace buffer\n"
8026eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  --async_stop    stop tracing and dump the current contents of circular\n"
8036eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "                    trace buffer\n"
80492573f1ba0d5360d7bfa8ab8935118db7a251f62Jamie Gennis                    "  --list_categories\n"
80592573f1ba0d5360d7bfa8ab8935118db7a251f62Jamie Gennis                    "                  list the available tracing categories\n"
8066eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            );
8076eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
8086eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
809fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisint main(int argc, char **argv)
810fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
8114edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool async = false;
8124edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool traceStart = true;
8134edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool traceStop = true;
8144edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool traceDump = true;
8154b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
816fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
817fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        showHelp(argv[0]);
818fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        exit(0);
819fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
820fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
821fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    for (;;) {
822fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        int ret;
8234edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        int option_index = 0;
8244edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        static struct option long_options[] = {
8254edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            {"async_start",     no_argument, 0,  0 },
8264edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            {"async_stop",      no_argument, 0,  0 },
8274edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            {"async_dump",      no_argument, 0,  0 },
8286eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            {"list_categories", no_argument, 0,  0 },
8296eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            {           0,                0, 0,  0 }
8304edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        };
831fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
832f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis        ret = getopt_long(argc, argv, "a:b:ck:ns:t:z",
8334edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                          long_options, &option_index);
834fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
835fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (ret < 0) {
8366eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            for (int i = optind; i < argc; i++) {
8376eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (!setCategoryEnable(argv[i], true)) {
8386eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
8396eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    exit(1);
8406eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
8416eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
842fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
843fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
844fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
845fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        switch(ret) {
846f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis            case 'a':
847f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis                g_debugAppCmdLine = optarg;
848f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis            break;
849f7f29c8f9d56dc908e501ae789e418a9974b6bceJamie Gennis
850cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'b':
851cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                g_traceBufferSizeKB = atoi(optarg);
852cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
853cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
854fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'c':
855fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceOverwrite = true;
856fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
857fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
858e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis            case 'k':
859e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis                g_kernelTraceFuncs = optarg;
8606f6f3f710b4dec2952298ae65d5f1674535c63f0Jamie Gennis            break;
861e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis
86231be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            case 'n':
86331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                g_nohup = true;
8646f6f3f710b4dec2952298ae65d5f1674535c63f0Jamie Gennis            break;
86531be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
866fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 's':
86731be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                g_initialSleepSecs = atoi(optarg);
86831be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            break;
86931be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
870fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 't':
871fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceDurationSeconds = atoi(optarg);
872fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
873fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
8747b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            case 'z':
8757b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                g_compress = true;
8767b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            break;
8777b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
8784edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            case 0:
8794edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                if (!strcmp(long_options[option_index].name, "async_start")) {
8804edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    async = true;
8814edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStop = false;
8824edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceDump = false;
8834edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    g_traceOverwrite = true;
8844edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                } else if (!strcmp(long_options[option_index].name, "async_stop")) {
8854edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    async = true;
8864edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStop = false;
8874edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                } else if (!strcmp(long_options[option_index].name, "async_dump")) {
8884edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    async = true;
8894edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStart = false;
8904edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStop = false;
8916eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                } else if (!strcmp(long_options[option_index].name, "list_categories")) {
8926eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    listSupportedCategories();
8936eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    exit(0);
8944edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                }
8956f6f3f710b4dec2952298ae65d5f1674535c63f0Jamie Gennis            break;
8964edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling
897fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            default:
898cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                fprintf(stderr, "\n");
899fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                showHelp(argv[0]);
900fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                exit(-1);
901fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
902fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
903fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
904fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
905fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    registerSigHandler();
906fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
90731be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    if (g_initialSleepSecs > 0) {
90831be80f02cddda55e75614884038fa4645b694cdGlenn Kasten        sleep(g_initialSleepSecs);
90931be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    }
91031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
911e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    bool ok = true;
912e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    ok &= setUpTrace();
913e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis    ok &= startTrace();
914fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
9154edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (ok && traceStart) {
916fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        printf("capturing trace...");
917fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fflush(stdout);
918fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
919fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // We clear the trace after starting it because tracing gets enabled for
920fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
921fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
922fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
923fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // another.
924fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = clearTrace();
925fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
9264edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        if (ok && !async) {
927fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            // Sleep to allow the trace to be captured.
928fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            struct timespec timeLeft;
929fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
930fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_nsec = 0;
931fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            do {
932fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                if (g_traceAborted) {
933fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    break;
934fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                }
935fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
936fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
937fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
938fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
939fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Stop the trace and restore the default settings.
9404edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (traceStop)
9416eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        stopTrace();
942fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
9434edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (ok && traceDump) {
944fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (!g_traceAborted) {
945fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf(" done\nTRACE:\n");
946fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
947fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            dumpTrace();
948fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        } else {
949fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf("\ntrace aborted.\n");
950fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
951fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
952fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        clearTrace();
9534edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    } else if (!ok) {
954fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "unable to start tracing\n");
955fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
956fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
957cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // Reset the trace buffer size to 1.
9584edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (traceStop)
959e9b8cfb63297b14253c5b464190fc5752457a38eJamie Gennis        cleanUpTrace();
960cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
961fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return g_traceAborted ? 1 : 0;
962fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
963