]> git.cworth.org Git - apitrace/blob - common/trace_writer_local.cpp
Use ids for frames.
[apitrace] / common / trace_writer_local.cpp
1 /**************************************************************************
2  *
3  * Copyright 2007-2011 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 #include <assert.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "os.hpp"
34 #include "os_thread.hpp"
35 #include "os_string.hpp"
36 #include "trace_file.hpp"
37 #include "trace_writer_local.hpp"
38 #include "trace_format.hpp"
39 #include "trace_backtrace.hpp"
40
41
42 namespace trace {
43
44
45 static const char *memcpy_args[3] = {"dest", "src", "n"};
46 const FunctionSig memcpy_sig = {0, "memcpy", 3, memcpy_args};
47
48 static const char *malloc_args[1] = {"size"};
49 const FunctionSig malloc_sig = {1, "malloc", 1, malloc_args};
50
51 static const char *free_args[1] = {"ptr"};
52 const FunctionSig free_sig = {2, "free", 1, free_args};
53
54 static const char *realloc_args[2] = {"ptr", "size"};
55 const FunctionSig realloc_sig = {3, "realloc", 2, realloc_args};
56
57
58 static void exceptionCallback(void)
59 {
60     localWriter.flush();
61 }
62
63
64 LocalWriter::LocalWriter() :
65     acquired(0)
66 {
67     // Install the signal handlers as early as possible, to prevent
68     // interfering with the application's signal handling.
69     os::setExceptionCallback(exceptionCallback);
70 }
71
72 LocalWriter::~LocalWriter()
73 {
74     os::resetExceptionCallback();
75 }
76
77 void
78 LocalWriter::open(void) {
79     os::String szFileName;
80
81     const char *lpFileName;
82
83     lpFileName = getenv("TRACE_FILE");
84     if (!lpFileName) {
85         static unsigned dwCounter = 0;
86
87         os::String process = os::getProcessName();
88 #ifdef _WIN32
89         process.trimExtension();
90 #endif
91         process.trimDirectory();
92
93 #ifdef ANDROID
94         os::String prefix = "/data";
95 #else
96         os::String prefix = os::getCurrentDir();
97 #endif
98         prefix.join(process);
99
100         for (;;) {
101             FILE *file;
102
103             if (dwCounter)
104                 szFileName = os::String::format("%s.%u.trace", prefix.str(), dwCounter);
105             else
106                 szFileName = os::String::format("%s.trace", prefix.str());
107
108             lpFileName = szFileName;
109             file = fopen(lpFileName, "rb");
110             if (file == NULL)
111                 break;
112
113             fclose(file);
114
115             ++dwCounter;
116         }
117     }
118
119     os::log("apitrace: tracing to %s\n", lpFileName);
120
121     if (!Writer::open(lpFileName)) {
122         os::log("apitrace: error: failed to open %s\n", lpFileName);
123         os::abort();
124     }
125
126 #if 0
127     // For debugging the exception handler
128     *((int *)0) = 0;
129 #endif
130 }
131
132 static uintptr_t next_thread_num = 1;
133
134 static OS_THREAD_SPECIFIC_PTR(void)
135 thread_num;
136
137 unsigned LocalWriter::beginEnter(const FunctionSig *sig, bool fake) {
138     mutex.lock();
139     ++acquired;
140
141     if (!m_file->isOpened()) {
142         open();
143     }
144
145     // Although thread_num is a void *, we actually use it as a uintptr_t
146     uintptr_t this_thread_num =
147         reinterpret_cast<uintptr_t>(static_cast<void *>(thread_num));
148     if (!this_thread_num) {
149         this_thread_num = next_thread_num++;
150         thread_num = reinterpret_cast<void *>(this_thread_num);
151     }
152
153     assert(this_thread_num);
154     unsigned thread_id = this_thread_num - 1;
155     unsigned call_no = Writer::beginEnter(sig, thread_id);
156     if (!fake) {
157         std::vector<RawStackFrame> backtrace = get_backtrace();
158         beginBacktrace(backtrace.size());
159         for (unsigned i = 0; i < backtrace.size(); ++i) {
160             writeStackFrame(&backtrace[i]);
161         }
162         endBacktrace();
163     }
164     return call_no;
165 }
166
167 void LocalWriter::endEnter(void) {
168     Writer::endEnter();
169     --acquired;
170     mutex.unlock();
171 }
172
173 void LocalWriter::beginLeave(unsigned call) {
174     mutex.lock();
175     ++acquired;
176     Writer::beginLeave(call);
177 }
178
179 void LocalWriter::endLeave(void) {
180     Writer::endLeave();
181     --acquired;
182     mutex.unlock();
183 }
184
185 void LocalWriter::flush(void) {
186     /*
187      * Do nothing if the mutex is already acquired (e.g., if a segfault happen
188      * while writing the file) as state could be inconsistent, therefore yield
189      * inconsistent trace files and/or repeated segfaults till infinity.
190      */
191
192     mutex.lock();
193     if (acquired) {
194         os::log("apitrace: ignoring exception while tracing\n");
195     } else {
196         ++acquired;
197         if (m_file->isOpened()) {
198             os::log("apitrace: flushing trace due to an exception\n");
199             m_file->flush();
200         }
201         --acquired;
202     }
203     mutex.unlock();
204 }
205
206
207 LocalWriter localWriter;
208
209
210 } /* namespace trace */
211