1*35238bceSAndroid Build Coastguard Worker /*-------------------------------------------------------------------------
2*35238bceSAndroid Build Coastguard Worker * drawElements Quality Program Helper Library
3*35238bceSAndroid Build Coastguard Worker * -------------------------------------------
4*35238bceSAndroid Build Coastguard Worker *
5*35238bceSAndroid Build Coastguard Worker * Copyright 2014 The Android Open Source Project
6*35238bceSAndroid Build Coastguard Worker *
7*35238bceSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
8*35238bceSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
9*35238bceSAndroid Build Coastguard Worker * You may obtain a copy of the License at
10*35238bceSAndroid Build Coastguard Worker *
11*35238bceSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
12*35238bceSAndroid Build Coastguard Worker *
13*35238bceSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
14*35238bceSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
15*35238bceSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*35238bceSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
17*35238bceSAndroid Build Coastguard Worker * limitations under the License.
18*35238bceSAndroid Build Coastguard Worker *
19*35238bceSAndroid Build Coastguard Worker *//*!
20*35238bceSAndroid Build Coastguard Worker * \file
21*35238bceSAndroid Build Coastguard Worker * \brief System handler handler override
22*35238bceSAndroid Build Coastguard Worker *//*--------------------------------------------------------------------*/
23*35238bceSAndroid Build Coastguard Worker
24*35238bceSAndroid Build Coastguard Worker #include "qpCrashHandler.h"
25*35238bceSAndroid Build Coastguard Worker #include "qpDebugOut.h"
26*35238bceSAndroid Build Coastguard Worker
27*35238bceSAndroid Build Coastguard Worker #include "deThread.h"
28*35238bceSAndroid Build Coastguard Worker #include "deMemory.h"
29*35238bceSAndroid Build Coastguard Worker #include "deString.h"
30*35238bceSAndroid Build Coastguard Worker #include "deMutex.h"
31*35238bceSAndroid Build Coastguard Worker
32*35238bceSAndroid Build Coastguard Worker #include <stdio.h>
33*35238bceSAndroid Build Coastguard Worker #include <stdarg.h>
34*35238bceSAndroid Build Coastguard Worker #include <stdlib.h>
35*35238bceSAndroid Build Coastguard Worker
36*35238bceSAndroid Build Coastguard Worker #if (DE_OS == DE_OS_UNIX)
37*35238bceSAndroid Build Coastguard Worker #include <unistd.h>
38*35238bceSAndroid Build Coastguard Worker #include <errno.h>
39*35238bceSAndroid Build Coastguard Worker #include <inttypes.h>
40*35238bceSAndroid Build Coastguard Worker #if defined(__GLIBC__) || defined(__FreeBSD__)
41*35238bceSAndroid Build Coastguard Worker #include <execinfo.h>
42*35238bceSAndroid Build Coastguard Worker #endif
43*35238bceSAndroid Build Coastguard Worker #endif
44*35238bceSAndroid Build Coastguard Worker
45*35238bceSAndroid Build Coastguard Worker #if 0
46*35238bceSAndroid Build Coastguard Worker #define DBGPRINT(X) qpPrintf X
47*35238bceSAndroid Build Coastguard Worker #else
48*35238bceSAndroid Build Coastguard Worker #define DBGPRINT(X)
49*35238bceSAndroid Build Coastguard Worker #endif
50*35238bceSAndroid Build Coastguard Worker
51*35238bceSAndroid Build Coastguard Worker /* Crash info write helper. */
writeInfoFormat(qpWriteCrashInfoFunc writeFunc,void * userPtr,const char * format,...)52*35238bceSAndroid Build Coastguard Worker static void writeInfoFormat(qpWriteCrashInfoFunc writeFunc, void *userPtr, const char *format, ...)
53*35238bceSAndroid Build Coastguard Worker {
54*35238bceSAndroid Build Coastguard Worker char buf[256];
55*35238bceSAndroid Build Coastguard Worker va_list ap;
56*35238bceSAndroid Build Coastguard Worker
57*35238bceSAndroid Build Coastguard Worker va_start(ap, format);
58*35238bceSAndroid Build Coastguard Worker vsnprintf(buf, sizeof(buf), format, ap);
59*35238bceSAndroid Build Coastguard Worker va_end(ap);
60*35238bceSAndroid Build Coastguard Worker
61*35238bceSAndroid Build Coastguard Worker writeFunc(userPtr, buf);
62*35238bceSAndroid Build Coastguard Worker }
63*35238bceSAndroid Build Coastguard Worker
64*35238bceSAndroid Build Coastguard Worker /* Shared crash info. */
65*35238bceSAndroid Build Coastguard Worker typedef enum qpCrashType_e
66*35238bceSAndroid Build Coastguard Worker {
67*35238bceSAndroid Build Coastguard Worker QP_CRASHTYPE_SEGMENTATION_FAULT = 0,
68*35238bceSAndroid Build Coastguard Worker QP_CRASHTYPE_ASSERT,
69*35238bceSAndroid Build Coastguard Worker QP_CRASHTYPE_UNHANDLED_EXCEPTION,
70*35238bceSAndroid Build Coastguard Worker QP_CRASHTYPE_OTHER,
71*35238bceSAndroid Build Coastguard Worker
72*35238bceSAndroid Build Coastguard Worker QP_CRASHTYPE_LAST
73*35238bceSAndroid Build Coastguard Worker } qpCrashType;
74*35238bceSAndroid Build Coastguard Worker
75*35238bceSAndroid Build Coastguard Worker typedef struct qpCrashInfo_s
76*35238bceSAndroid Build Coastguard Worker {
77*35238bceSAndroid Build Coastguard Worker qpCrashType type;
78*35238bceSAndroid Build Coastguard Worker const char *message;
79*35238bceSAndroid Build Coastguard Worker const char *file;
80*35238bceSAndroid Build Coastguard Worker int line;
81*35238bceSAndroid Build Coastguard Worker } qpCrashInfo;
82*35238bceSAndroid Build Coastguard Worker
qpCrashInfo_init(qpCrashInfo * info)83*35238bceSAndroid Build Coastguard Worker static void qpCrashInfo_init(qpCrashInfo *info)
84*35238bceSAndroid Build Coastguard Worker {
85*35238bceSAndroid Build Coastguard Worker info->type = QP_CRASHTYPE_LAST;
86*35238bceSAndroid Build Coastguard Worker info->message = DE_NULL;
87*35238bceSAndroid Build Coastguard Worker info->file = DE_NULL;
88*35238bceSAndroid Build Coastguard Worker info->line = 0;
89*35238bceSAndroid Build Coastguard Worker }
90*35238bceSAndroid Build Coastguard Worker
qpCrashInfo_set(qpCrashInfo * info,qpCrashType type,const char * message,const char * file,int line)91*35238bceSAndroid Build Coastguard Worker static void qpCrashInfo_set(qpCrashInfo *info, qpCrashType type, const char *message, const char *file, int line)
92*35238bceSAndroid Build Coastguard Worker {
93*35238bceSAndroid Build Coastguard Worker info->type = type;
94*35238bceSAndroid Build Coastguard Worker info->message = message;
95*35238bceSAndroid Build Coastguard Worker info->file = file;
96*35238bceSAndroid Build Coastguard Worker info->line = line;
97*35238bceSAndroid Build Coastguard Worker }
98*35238bceSAndroid Build Coastguard Worker
qpCrashInfo_write(qpCrashInfo * info,qpWriteCrashInfoFunc writeInfo,void * userPtr)99*35238bceSAndroid Build Coastguard Worker static void qpCrashInfo_write(qpCrashInfo *info, qpWriteCrashInfoFunc writeInfo, void *userPtr)
100*35238bceSAndroid Build Coastguard Worker {
101*35238bceSAndroid Build Coastguard Worker switch (info->type)
102*35238bceSAndroid Build Coastguard Worker {
103*35238bceSAndroid Build Coastguard Worker case QP_CRASHTYPE_SEGMENTATION_FAULT:
104*35238bceSAndroid Build Coastguard Worker writeInfoFormat(writeInfo, userPtr, "Segmentation fault: '%s'\n", info->message);
105*35238bceSAndroid Build Coastguard Worker break;
106*35238bceSAndroid Build Coastguard Worker
107*35238bceSAndroid Build Coastguard Worker case QP_CRASHTYPE_UNHANDLED_EXCEPTION:
108*35238bceSAndroid Build Coastguard Worker writeInfoFormat(writeInfo, userPtr, "Unhandled exception: '%s'\n", info->message);
109*35238bceSAndroid Build Coastguard Worker break;
110*35238bceSAndroid Build Coastguard Worker
111*35238bceSAndroid Build Coastguard Worker case QP_CRASHTYPE_ASSERT:
112*35238bceSAndroid Build Coastguard Worker writeInfoFormat(writeInfo, userPtr, "Assertion '%s' failed at %s:%d\n", info->message, info->file, info->line);
113*35238bceSAndroid Build Coastguard Worker break;
114*35238bceSAndroid Build Coastguard Worker
115*35238bceSAndroid Build Coastguard Worker case QP_CRASHTYPE_OTHER:
116*35238bceSAndroid Build Coastguard Worker default:
117*35238bceSAndroid Build Coastguard Worker writeInfoFormat(writeInfo, userPtr, "Crash: '%s'\n", info->message);
118*35238bceSAndroid Build Coastguard Worker break;
119*35238bceSAndroid Build Coastguard Worker }
120*35238bceSAndroid Build Coastguard Worker }
121*35238bceSAndroid Build Coastguard Worker
defaultWriteInfo(void * userPtr,const char * infoString)122*35238bceSAndroid Build Coastguard Worker static void defaultWriteInfo(void *userPtr, const char *infoString)
123*35238bceSAndroid Build Coastguard Worker {
124*35238bceSAndroid Build Coastguard Worker DE_UNREF(userPtr);
125*35238bceSAndroid Build Coastguard Worker qpPrintf("%s", infoString);
126*35238bceSAndroid Build Coastguard Worker }
127*35238bceSAndroid Build Coastguard Worker
defaultCrashHandler(qpCrashHandler * crashHandler,void * userPtr)128*35238bceSAndroid Build Coastguard Worker static void defaultCrashHandler(qpCrashHandler *crashHandler, void *userPtr)
129*35238bceSAndroid Build Coastguard Worker {
130*35238bceSAndroid Build Coastguard Worker DE_UNREF(userPtr);
131*35238bceSAndroid Build Coastguard Worker qpCrashHandler_writeCrashInfo(crashHandler, defaultWriteInfo, DE_NULL);
132*35238bceSAndroid Build Coastguard Worker qpDief("Test process crashed");
133*35238bceSAndroid Build Coastguard Worker }
134*35238bceSAndroid Build Coastguard Worker
135*35238bceSAndroid Build Coastguard Worker #if (DE_OS == DE_OS_WIN32) && (DE_COMPILER == DE_COMPILER_MSC)
136*35238bceSAndroid Build Coastguard Worker
137*35238bceSAndroid Build Coastguard Worker #define WIN32_LEAN_AND_MEAN
138*35238bceSAndroid Build Coastguard Worker #include <windows.h>
139*35238bceSAndroid Build Coastguard Worker
140*35238bceSAndroid Build Coastguard Worker /* DbgHelp.h generates C4091 */
141*35238bceSAndroid Build Coastguard Worker #pragma warning(push)
142*35238bceSAndroid Build Coastguard Worker #pragma warning(disable : 4091)
143*35238bceSAndroid Build Coastguard Worker #include <DbgHelp.h>
144*35238bceSAndroid Build Coastguard Worker #pragma warning(pop)
145*35238bceSAndroid Build Coastguard Worker
146*35238bceSAndroid Build Coastguard Worker struct qpCrashHandler_s
147*35238bceSAndroid Build Coastguard Worker {
148*35238bceSAndroid Build Coastguard Worker qpCrashHandlerFunc crashHandlerFunc;
149*35238bceSAndroid Build Coastguard Worker void *handlerUserPointer;
150*35238bceSAndroid Build Coastguard Worker
151*35238bceSAndroid Build Coastguard Worker deMutex crashHandlerLock;
152*35238bceSAndroid Build Coastguard Worker qpCrashInfo crashInfo;
153*35238bceSAndroid Build Coastguard Worker uintptr_t crashAddress;
154*35238bceSAndroid Build Coastguard Worker
155*35238bceSAndroid Build Coastguard Worker LPTOP_LEVEL_EXCEPTION_FILTER oldExceptionFilter;
156*35238bceSAndroid Build Coastguard Worker };
157*35238bceSAndroid Build Coastguard Worker
158*35238bceSAndroid Build Coastguard Worker qpCrashHandler *g_crashHandler = DE_NULL;
159*35238bceSAndroid Build Coastguard Worker
unhandledExceptionFilter(struct _EXCEPTION_POINTERS * info)160*35238bceSAndroid Build Coastguard Worker static LONG WINAPI unhandledExceptionFilter(struct _EXCEPTION_POINTERS *info)
161*35238bceSAndroid Build Coastguard Worker {
162*35238bceSAndroid Build Coastguard Worker qpCrashType crashType = QP_CRASHTYPE_LAST;
163*35238bceSAndroid Build Coastguard Worker const char *reason = DE_NULL;
164*35238bceSAndroid Build Coastguard Worker
165*35238bceSAndroid Build Coastguard Worker /* Skip breakpoints. */
166*35238bceSAndroid Build Coastguard Worker if (info->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
167*35238bceSAndroid Build Coastguard Worker {
168*35238bceSAndroid Build Coastguard Worker DBGPRINT(("qpCrashHandler::unhandledExceptionFilter(): breakpoint\n"));
169*35238bceSAndroid Build Coastguard Worker return EXCEPTION_CONTINUE_SEARCH;
170*35238bceSAndroid Build Coastguard Worker }
171*35238bceSAndroid Build Coastguard Worker
172*35238bceSAndroid Build Coastguard Worker /* If no handler present (how could that be?), don't handle. */
173*35238bceSAndroid Build Coastguard Worker if (g_crashHandler == DE_NULL)
174*35238bceSAndroid Build Coastguard Worker {
175*35238bceSAndroid Build Coastguard Worker DBGPRINT(("qpCrashHandler::unhandledExceptionFilter(): no crash handler registered\n"));
176*35238bceSAndroid Build Coastguard Worker return EXCEPTION_CONTINUE_SEARCH;
177*35238bceSAndroid Build Coastguard Worker }
178*35238bceSAndroid Build Coastguard Worker
179*35238bceSAndroid Build Coastguard Worker /* If we have a debugger, let it handle the exception. */
180*35238bceSAndroid Build Coastguard Worker if (IsDebuggerPresent())
181*35238bceSAndroid Build Coastguard Worker {
182*35238bceSAndroid Build Coastguard Worker DBGPRINT(("qpCrashHandler::unhandledExceptionFilter(): debugger present\n"));
183*35238bceSAndroid Build Coastguard Worker return EXCEPTION_CONTINUE_SEARCH;
184*35238bceSAndroid Build Coastguard Worker }
185*35238bceSAndroid Build Coastguard Worker
186*35238bceSAndroid Build Coastguard Worker /* Acquire crash handler lock. Otherwise we might get strange behavior when multiple threads enter crash handler simultaneously. */
187*35238bceSAndroid Build Coastguard Worker deMutex_lock(g_crashHandler->crashHandlerLock);
188*35238bceSAndroid Build Coastguard Worker
189*35238bceSAndroid Build Coastguard Worker /* Map crash type. */
190*35238bceSAndroid Build Coastguard Worker switch (info->ExceptionRecord->ExceptionCode)
191*35238bceSAndroid Build Coastguard Worker {
192*35238bceSAndroid Build Coastguard Worker case EXCEPTION_ACCESS_VIOLATION:
193*35238bceSAndroid Build Coastguard Worker crashType = QP_CRASHTYPE_SEGMENTATION_FAULT;
194*35238bceSAndroid Build Coastguard Worker reason = "Access violation";
195*35238bceSAndroid Build Coastguard Worker break;
196*35238bceSAndroid Build Coastguard Worker
197*35238bceSAndroid Build Coastguard Worker case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
198*35238bceSAndroid Build Coastguard Worker crashType = QP_CRASHTYPE_SEGMENTATION_FAULT;
199*35238bceSAndroid Build Coastguard Worker reason = "Array bounds exceeded";
200*35238bceSAndroid Build Coastguard Worker break;
201*35238bceSAndroid Build Coastguard Worker
202*35238bceSAndroid Build Coastguard Worker case EXCEPTION_ILLEGAL_INSTRUCTION:
203*35238bceSAndroid Build Coastguard Worker crashType = QP_CRASHTYPE_OTHER;
204*35238bceSAndroid Build Coastguard Worker reason = "Illegal instruction";
205*35238bceSAndroid Build Coastguard Worker break;
206*35238bceSAndroid Build Coastguard Worker
207*35238bceSAndroid Build Coastguard Worker case EXCEPTION_STACK_OVERFLOW:
208*35238bceSAndroid Build Coastguard Worker crashType = QP_CRASHTYPE_OTHER;
209*35238bceSAndroid Build Coastguard Worker reason = "Stack overflow";
210*35238bceSAndroid Build Coastguard Worker break;
211*35238bceSAndroid Build Coastguard Worker
212*35238bceSAndroid Build Coastguard Worker default:
213*35238bceSAndroid Build Coastguard Worker /* \todo [pyry] Others. */
214*35238bceSAndroid Build Coastguard Worker crashType = QP_CRASHTYPE_OTHER;
215*35238bceSAndroid Build Coastguard Worker reason = "";
216*35238bceSAndroid Build Coastguard Worker break;
217*35238bceSAndroid Build Coastguard Worker }
218*35238bceSAndroid Build Coastguard Worker
219*35238bceSAndroid Build Coastguard Worker /* Store reason. */
220*35238bceSAndroid Build Coastguard Worker qpCrashInfo_set(&g_crashHandler->crashInfo, crashType, reason, __FILE__, __LINE__);
221*35238bceSAndroid Build Coastguard Worker
222*35238bceSAndroid Build Coastguard Worker /* Store win32-specific crash info. */
223*35238bceSAndroid Build Coastguard Worker g_crashHandler->crashAddress = (uintptr_t)info->ExceptionRecord->ExceptionAddress;
224*35238bceSAndroid Build Coastguard Worker
225*35238bceSAndroid Build Coastguard Worker /* Handle the crash. */
226*35238bceSAndroid Build Coastguard Worker DBGPRINT(("qpCrashHandler::unhandledExceptionFilter(): handled quietly\n"));
227*35238bceSAndroid Build Coastguard Worker if (g_crashHandler->crashHandlerFunc != DE_NULL)
228*35238bceSAndroid Build Coastguard Worker g_crashHandler->crashHandlerFunc(g_crashHandler, g_crashHandler->handlerUserPointer);
229*35238bceSAndroid Build Coastguard Worker
230*35238bceSAndroid Build Coastguard Worker /* Release lock. */
231*35238bceSAndroid Build Coastguard Worker deMutex_unlock(g_crashHandler->crashHandlerLock);
232*35238bceSAndroid Build Coastguard Worker
233*35238bceSAndroid Build Coastguard Worker return EXCEPTION_EXECUTE_HANDLER;
234*35238bceSAndroid Build Coastguard Worker }
235*35238bceSAndroid Build Coastguard Worker
assertFailureCallback(const char * expr,const char * file,int line)236*35238bceSAndroid Build Coastguard Worker static void assertFailureCallback(const char *expr, const char *file, int line)
237*35238bceSAndroid Build Coastguard Worker {
238*35238bceSAndroid Build Coastguard Worker /* Don't execute crash handler function if debugger is present. */
239*35238bceSAndroid Build Coastguard Worker if (IsDebuggerPresent())
240*35238bceSAndroid Build Coastguard Worker {
241*35238bceSAndroid Build Coastguard Worker DBGPRINT(("qpCrashHandler::assertFailureCallback(): debugger present\n"));
242*35238bceSAndroid Build Coastguard Worker return;
243*35238bceSAndroid Build Coastguard Worker }
244*35238bceSAndroid Build Coastguard Worker
245*35238bceSAndroid Build Coastguard Worker /* Acquire crash handler lock. */
246*35238bceSAndroid Build Coastguard Worker deMutex_lock(g_crashHandler->crashHandlerLock);
247*35238bceSAndroid Build Coastguard Worker
248*35238bceSAndroid Build Coastguard Worker /* Store info. */
249*35238bceSAndroid Build Coastguard Worker qpCrashInfo_set(&g_crashHandler->crashInfo, QP_CRASHTYPE_ASSERT, expr, file, line);
250*35238bceSAndroid Build Coastguard Worker g_crashHandler->crashAddress = 0;
251*35238bceSAndroid Build Coastguard Worker
252*35238bceSAndroid Build Coastguard Worker /* Handle the crash. */
253*35238bceSAndroid Build Coastguard Worker if (g_crashHandler->crashHandlerFunc != DE_NULL)
254*35238bceSAndroid Build Coastguard Worker g_crashHandler->crashHandlerFunc(g_crashHandler, g_crashHandler->handlerUserPointer);
255*35238bceSAndroid Build Coastguard Worker
256*35238bceSAndroid Build Coastguard Worker /* Release lock. */
257*35238bceSAndroid Build Coastguard Worker deMutex_unlock(g_crashHandler->crashHandlerLock);
258*35238bceSAndroid Build Coastguard Worker }
259*35238bceSAndroid Build Coastguard Worker
qpCrashHandler_create(qpCrashHandlerFunc handlerFunc,void * userPointer)260*35238bceSAndroid Build Coastguard Worker qpCrashHandler *qpCrashHandler_create(qpCrashHandlerFunc handlerFunc, void *userPointer)
261*35238bceSAndroid Build Coastguard Worker {
262*35238bceSAndroid Build Coastguard Worker /* Allocate & initialize. */
263*35238bceSAndroid Build Coastguard Worker qpCrashHandler *handler = (qpCrashHandler *)deCalloc(sizeof(qpCrashHandler));
264*35238bceSAndroid Build Coastguard Worker DBGPRINT(("qpCrashHandler::create() -- Win32\n"));
265*35238bceSAndroid Build Coastguard Worker if (!handler)
266*35238bceSAndroid Build Coastguard Worker return handler;
267*35238bceSAndroid Build Coastguard Worker
268*35238bceSAndroid Build Coastguard Worker DE_ASSERT(g_crashHandler == DE_NULL);
269*35238bceSAndroid Build Coastguard Worker
270*35238bceSAndroid Build Coastguard Worker handler->crashHandlerFunc = handlerFunc ? handlerFunc : defaultCrashHandler;
271*35238bceSAndroid Build Coastguard Worker handler->handlerUserPointer = userPointer;
272*35238bceSAndroid Build Coastguard Worker
273*35238bceSAndroid Build Coastguard Worker /* Create lock for crash handler. \note Has to be recursive or otherwise crash in assert failure causes deadlock. */
274*35238bceSAndroid Build Coastguard Worker {
275*35238bceSAndroid Build Coastguard Worker deMutexAttributes attr;
276*35238bceSAndroid Build Coastguard Worker attr.flags = DE_MUTEX_RECURSIVE;
277*35238bceSAndroid Build Coastguard Worker handler->crashHandlerLock = deMutex_create(&attr);
278*35238bceSAndroid Build Coastguard Worker
279*35238bceSAndroid Build Coastguard Worker if (!handler->crashHandlerLock)
280*35238bceSAndroid Build Coastguard Worker {
281*35238bceSAndroid Build Coastguard Worker deFree(handler);
282*35238bceSAndroid Build Coastguard Worker return DE_NULL;
283*35238bceSAndroid Build Coastguard Worker }
284*35238bceSAndroid Build Coastguard Worker }
285*35238bceSAndroid Build Coastguard Worker
286*35238bceSAndroid Build Coastguard Worker qpCrashInfo_init(&handler->crashInfo);
287*35238bceSAndroid Build Coastguard Worker handler->crashAddress = 0;
288*35238bceSAndroid Build Coastguard Worker
289*35238bceSAndroid Build Coastguard Worker /* Unhandled exception filter. */
290*35238bceSAndroid Build Coastguard Worker handler->oldExceptionFilter = SetUnhandledExceptionFilter(unhandledExceptionFilter);
291*35238bceSAndroid Build Coastguard Worker
292*35238bceSAndroid Build Coastguard Worker /* Prevent nasty error dialog. */
293*35238bceSAndroid Build Coastguard Worker SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
294*35238bceSAndroid Build Coastguard Worker
295*35238bceSAndroid Build Coastguard Worker /* DE_ASSERT callback. */
296*35238bceSAndroid Build Coastguard Worker deSetAssertFailureCallback(assertFailureCallback);
297*35238bceSAndroid Build Coastguard Worker
298*35238bceSAndroid Build Coastguard Worker g_crashHandler = handler;
299*35238bceSAndroid Build Coastguard Worker return handler;
300*35238bceSAndroid Build Coastguard Worker }
301*35238bceSAndroid Build Coastguard Worker
qpCrashHandler_destroy(qpCrashHandler * handler)302*35238bceSAndroid Build Coastguard Worker void qpCrashHandler_destroy(qpCrashHandler *handler)
303*35238bceSAndroid Build Coastguard Worker {
304*35238bceSAndroid Build Coastguard Worker DBGPRINT(("qpCrashHandler::destroy()\n"));
305*35238bceSAndroid Build Coastguard Worker
306*35238bceSAndroid Build Coastguard Worker DE_ASSERT(g_crashHandler == handler);
307*35238bceSAndroid Build Coastguard Worker
308*35238bceSAndroid Build Coastguard Worker deSetAssertFailureCallback(DE_NULL);
309*35238bceSAndroid Build Coastguard Worker SetUnhandledExceptionFilter(handler->oldExceptionFilter);
310*35238bceSAndroid Build Coastguard Worker
311*35238bceSAndroid Build Coastguard Worker g_crashHandler = DE_NULL;
312*35238bceSAndroid Build Coastguard Worker deFree(handler);
313*35238bceSAndroid Build Coastguard Worker }
314*35238bceSAndroid Build Coastguard Worker
315*35238bceSAndroid Build Coastguard Worker enum
316*35238bceSAndroid Build Coastguard Worker {
317*35238bceSAndroid Build Coastguard Worker MAX_NAME_LENGTH = 64
318*35238bceSAndroid Build Coastguard Worker };
319*35238bceSAndroid Build Coastguard Worker
qpCrashHandler_writeCrashInfo(qpCrashHandler * handler,qpWriteCrashInfoFunc writeInfo,void * userPtr)320*35238bceSAndroid Build Coastguard Worker void qpCrashHandler_writeCrashInfo(qpCrashHandler *handler, qpWriteCrashInfoFunc writeInfo, void *userPtr)
321*35238bceSAndroid Build Coastguard Worker {
322*35238bceSAndroid Build Coastguard Worker void *addresses[32];
323*35238bceSAndroid Build Coastguard Worker HANDLE process;
324*35238bceSAndroid Build Coastguard Worker
325*35238bceSAndroid Build Coastguard Worker /* Symbol info struct. */
326*35238bceSAndroid Build Coastguard Worker uint8_t symInfoStorage[sizeof(SYMBOL_INFO) + MAX_NAME_LENGTH];
327*35238bceSAndroid Build Coastguard Worker SYMBOL_INFO *symInfo = (SYMBOL_INFO *)symInfoStorage;
328*35238bceSAndroid Build Coastguard Worker
329*35238bceSAndroid Build Coastguard Worker DE_STATIC_ASSERT(sizeof(TCHAR) == sizeof(uint8_t));
330*35238bceSAndroid Build Coastguard Worker
331*35238bceSAndroid Build Coastguard Worker /* Write basic info. */
332*35238bceSAndroid Build Coastguard Worker qpCrashInfo_write(&handler->crashInfo, writeInfo, userPtr);
333*35238bceSAndroid Build Coastguard Worker
334*35238bceSAndroid Build Coastguard Worker /* Acquire process handle and initialize symbols. */
335*35238bceSAndroid Build Coastguard Worker process = GetCurrentProcess();
336*35238bceSAndroid Build Coastguard Worker
337*35238bceSAndroid Build Coastguard Worker /* Write backtrace. */
338*35238bceSAndroid Build Coastguard Worker if (SymInitialize(process, NULL, TRUE))
339*35238bceSAndroid Build Coastguard Worker {
340*35238bceSAndroid Build Coastguard Worker int batchStart = 0;
341*35238bceSAndroid Build Coastguard Worker int globalFrameNdx = 0;
342*35238bceSAndroid Build Coastguard Worker
343*35238bceSAndroid Build Coastguard Worker /* Initialize symInfo. */
344*35238bceSAndroid Build Coastguard Worker deMemset(symInfo, 0, sizeof(symInfoStorage));
345*35238bceSAndroid Build Coastguard Worker symInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
346*35238bceSAndroid Build Coastguard Worker symInfo->MaxNameLen = MAX_NAME_LENGTH;
347*35238bceSAndroid Build Coastguard Worker
348*35238bceSAndroid Build Coastguard Worker /* Print address and symbol where crash happened. */
349*35238bceSAndroid Build Coastguard Worker if (handler->crashAddress != 0)
350*35238bceSAndroid Build Coastguard Worker {
351*35238bceSAndroid Build Coastguard Worker BOOL symInfoOk = SymFromAddr(process, (DWORD64)handler->crashAddress, 0, symInfo);
352*35238bceSAndroid Build Coastguard Worker
353*35238bceSAndroid Build Coastguard Worker writeInfoFormat(writeInfo, userPtr, " at %p %s%s\n", handler->crashAddress,
354*35238bceSAndroid Build Coastguard Worker symInfoOk ? symInfo->Name : "(unknown)", symInfoOk ? "()" : "");
355*35238bceSAndroid Build Coastguard Worker }
356*35238bceSAndroid Build Coastguard Worker
357*35238bceSAndroid Build Coastguard Worker writeInfo(userPtr, "Backtrace:\n");
358*35238bceSAndroid Build Coastguard Worker
359*35238bceSAndroid Build Coastguard Worker for (;;)
360*35238bceSAndroid Build Coastguard Worker {
361*35238bceSAndroid Build Coastguard Worker int curFrame;
362*35238bceSAndroid Build Coastguard Worker int numInBatch;
363*35238bceSAndroid Build Coastguard Worker
364*35238bceSAndroid Build Coastguard Worker /* Get one batch. */
365*35238bceSAndroid Build Coastguard Worker numInBatch = CaptureStackBackTrace(batchStart, DE_LENGTH_OF_ARRAY(addresses), addresses, NULL);
366*35238bceSAndroid Build Coastguard Worker
367*35238bceSAndroid Build Coastguard Worker for (curFrame = 0; curFrame < numInBatch; curFrame++)
368*35238bceSAndroid Build Coastguard Worker {
369*35238bceSAndroid Build Coastguard Worker BOOL symInfoOk = SymFromAddr(process, (DWORD64)addresses[curFrame], 0, symInfo);
370*35238bceSAndroid Build Coastguard Worker
371*35238bceSAndroid Build Coastguard Worker writeInfoFormat(writeInfo, userPtr, " %2d: %p %s%s\n", globalFrameNdx++, addresses[curFrame],
372*35238bceSAndroid Build Coastguard Worker symInfoOk ? symInfo->Name : "(unknown)", symInfoOk ? "()" : "");
373*35238bceSAndroid Build Coastguard Worker }
374*35238bceSAndroid Build Coastguard Worker
375*35238bceSAndroid Build Coastguard Worker batchStart += numInBatch;
376*35238bceSAndroid Build Coastguard Worker
377*35238bceSAndroid Build Coastguard Worker /* Check if we hit end of stack trace. */
378*35238bceSAndroid Build Coastguard Worker if (numInBatch == 0 || numInBatch < DE_LENGTH_OF_ARRAY(addresses))
379*35238bceSAndroid Build Coastguard Worker break;
380*35238bceSAndroid Build Coastguard Worker }
381*35238bceSAndroid Build Coastguard Worker }
382*35238bceSAndroid Build Coastguard Worker }
383*35238bceSAndroid Build Coastguard Worker
384*35238bceSAndroid Build Coastguard Worker #else /* posix / generic implementation */
385*35238bceSAndroid Build Coastguard Worker
386*35238bceSAndroid Build Coastguard Worker #if defined(QP_USE_SIGNAL_HANDLER)
387*35238bceSAndroid Build Coastguard Worker #include <signal.h>
388*35238bceSAndroid Build Coastguard Worker #endif
389*35238bceSAndroid Build Coastguard Worker
390*35238bceSAndroid Build Coastguard Worker #if defined(QP_USE_SIGNAL_HANDLER)
391*35238bceSAndroid Build Coastguard Worker
392*35238bceSAndroid Build Coastguard Worker typedef struct SignalInfo_s
393*35238bceSAndroid Build Coastguard Worker {
394*35238bceSAndroid Build Coastguard Worker int signalNum;
395*35238bceSAndroid Build Coastguard Worker qpCrashType type;
396*35238bceSAndroid Build Coastguard Worker const char *name;
397*35238bceSAndroid Build Coastguard Worker } SignalInfo;
398*35238bceSAndroid Build Coastguard Worker
399*35238bceSAndroid Build Coastguard Worker static const SignalInfo s_signals[] = {
400*35238bceSAndroid Build Coastguard Worker {SIGABRT, QP_CRASHTYPE_UNHANDLED_EXCEPTION, "SIGABRT"}, {SIGILL, QP_CRASHTYPE_OTHER, "SIGILL"},
401*35238bceSAndroid Build Coastguard Worker {SIGSEGV, QP_CRASHTYPE_SEGMENTATION_FAULT, "SIGSEGV"}, {SIGFPE, QP_CRASHTYPE_OTHER, "SIGFPE"},
402*35238bceSAndroid Build Coastguard Worker {SIGBUS, QP_CRASHTYPE_SEGMENTATION_FAULT, "SIGBUS"}, {SIGPIPE, QP_CRASHTYPE_OTHER, "SIGPIPE"}};
403*35238bceSAndroid Build Coastguard Worker
404*35238bceSAndroid Build Coastguard Worker #endif /* QP_USE_SIGNAL_HANDLER */
405*35238bceSAndroid Build Coastguard Worker
406*35238bceSAndroid Build Coastguard Worker struct qpCrashHandler_s
407*35238bceSAndroid Build Coastguard Worker {
408*35238bceSAndroid Build Coastguard Worker qpCrashHandlerFunc crashHandlerFunc;
409*35238bceSAndroid Build Coastguard Worker void *handlerUserPointer;
410*35238bceSAndroid Build Coastguard Worker
411*35238bceSAndroid Build Coastguard Worker qpCrashInfo crashInfo;
412*35238bceSAndroid Build Coastguard Worker int crashSignal;
413*35238bceSAndroid Build Coastguard Worker
414*35238bceSAndroid Build Coastguard Worker #if defined(QP_USE_SIGNAL_HANDLER)
415*35238bceSAndroid Build Coastguard Worker struct sigaction oldHandlers[DE_LENGTH_OF_ARRAY(s_signals)];
416*35238bceSAndroid Build Coastguard Worker #endif
417*35238bceSAndroid Build Coastguard Worker };
418*35238bceSAndroid Build Coastguard Worker
419*35238bceSAndroid Build Coastguard Worker qpCrashHandler *g_crashHandler = DE_NULL;
420*35238bceSAndroid Build Coastguard Worker
assertFailureCallback(const char * expr,const char * file,int line)421*35238bceSAndroid Build Coastguard Worker static void assertFailureCallback(const char *expr, const char *file, int line)
422*35238bceSAndroid Build Coastguard Worker {
423*35238bceSAndroid Build Coastguard Worker /* Store info. */
424*35238bceSAndroid Build Coastguard Worker qpCrashInfo_set(&g_crashHandler->crashInfo, QP_CRASHTYPE_ASSERT, expr, file, line);
425*35238bceSAndroid Build Coastguard Worker
426*35238bceSAndroid Build Coastguard Worker /* Handle the crash. */
427*35238bceSAndroid Build Coastguard Worker if (g_crashHandler->crashHandlerFunc != DE_NULL)
428*35238bceSAndroid Build Coastguard Worker g_crashHandler->crashHandlerFunc(g_crashHandler, g_crashHandler->handlerUserPointer);
429*35238bceSAndroid Build Coastguard Worker }
430*35238bceSAndroid Build Coastguard Worker
431*35238bceSAndroid Build Coastguard Worker #if defined(QP_USE_SIGNAL_HANDLER)
432*35238bceSAndroid Build Coastguard Worker
getSignalInfo(int sigNum)433*35238bceSAndroid Build Coastguard Worker static const SignalInfo *getSignalInfo(int sigNum)
434*35238bceSAndroid Build Coastguard Worker {
435*35238bceSAndroid Build Coastguard Worker int ndx;
436*35238bceSAndroid Build Coastguard Worker for (ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_signals); ndx++)
437*35238bceSAndroid Build Coastguard Worker {
438*35238bceSAndroid Build Coastguard Worker if (s_signals[ndx].signalNum == sigNum)
439*35238bceSAndroid Build Coastguard Worker return &s_signals[ndx];
440*35238bceSAndroid Build Coastguard Worker }
441*35238bceSAndroid Build Coastguard Worker return DE_NULL;
442*35238bceSAndroid Build Coastguard Worker }
443*35238bceSAndroid Build Coastguard Worker
signalHandler(int sigNum)444*35238bceSAndroid Build Coastguard Worker static void signalHandler(int sigNum)
445*35238bceSAndroid Build Coastguard Worker {
446*35238bceSAndroid Build Coastguard Worker const SignalInfo *info = getSignalInfo(sigNum);
447*35238bceSAndroid Build Coastguard Worker qpCrashType type = info ? info->type : QP_CRASHTYPE_OTHER;
448*35238bceSAndroid Build Coastguard Worker const char *name = info ? info->name : "Unknown signal";
449*35238bceSAndroid Build Coastguard Worker
450*35238bceSAndroid Build Coastguard Worker qpCrashInfo_set(&g_crashHandler->crashInfo, type, name, DE_NULL, 0);
451*35238bceSAndroid Build Coastguard Worker
452*35238bceSAndroid Build Coastguard Worker if (g_crashHandler->crashHandlerFunc != DE_NULL)
453*35238bceSAndroid Build Coastguard Worker g_crashHandler->crashHandlerFunc(g_crashHandler, g_crashHandler->handlerUserPointer);
454*35238bceSAndroid Build Coastguard Worker }
455*35238bceSAndroid Build Coastguard Worker
456*35238bceSAndroid Build Coastguard Worker #endif /* QP_USE_SIGNAL_HANDLER */
457*35238bceSAndroid Build Coastguard Worker
qpCrashHandler_create(qpCrashHandlerFunc handlerFunc,void * userPointer)458*35238bceSAndroid Build Coastguard Worker qpCrashHandler *qpCrashHandler_create(qpCrashHandlerFunc handlerFunc, void *userPointer)
459*35238bceSAndroid Build Coastguard Worker {
460*35238bceSAndroid Build Coastguard Worker /* Allocate & initialize. */
461*35238bceSAndroid Build Coastguard Worker qpCrashHandler *handler = (qpCrashHandler *)deCalloc(sizeof(qpCrashHandler));
462*35238bceSAndroid Build Coastguard Worker DBGPRINT(("qpCrashHandler::create()\n"));
463*35238bceSAndroid Build Coastguard Worker if (!handler)
464*35238bceSAndroid Build Coastguard Worker return handler;
465*35238bceSAndroid Build Coastguard Worker
466*35238bceSAndroid Build Coastguard Worker DE_ASSERT(g_crashHandler == DE_NULL);
467*35238bceSAndroid Build Coastguard Worker
468*35238bceSAndroid Build Coastguard Worker handler->crashHandlerFunc = handlerFunc ? handlerFunc : defaultCrashHandler;
469*35238bceSAndroid Build Coastguard Worker handler->handlerUserPointer = userPointer;
470*35238bceSAndroid Build Coastguard Worker
471*35238bceSAndroid Build Coastguard Worker qpCrashInfo_init(&handler->crashInfo);
472*35238bceSAndroid Build Coastguard Worker
473*35238bceSAndroid Build Coastguard Worker g_crashHandler = handler;
474*35238bceSAndroid Build Coastguard Worker
475*35238bceSAndroid Build Coastguard Worker /* DE_ASSERT callback. */
476*35238bceSAndroid Build Coastguard Worker deSetAssertFailureCallback(assertFailureCallback);
477*35238bceSAndroid Build Coastguard Worker
478*35238bceSAndroid Build Coastguard Worker #if defined(QP_USE_SIGNAL_HANDLER)
479*35238bceSAndroid Build Coastguard Worker /* Register signal handlers. */
480*35238bceSAndroid Build Coastguard Worker {
481*35238bceSAndroid Build Coastguard Worker struct sigaction action;
482*35238bceSAndroid Build Coastguard Worker int sigNdx;
483*35238bceSAndroid Build Coastguard Worker
484*35238bceSAndroid Build Coastguard Worker sigemptyset(&action.sa_mask);
485*35238bceSAndroid Build Coastguard Worker action.sa_handler = signalHandler;
486*35238bceSAndroid Build Coastguard Worker action.sa_flags = 0;
487*35238bceSAndroid Build Coastguard Worker
488*35238bceSAndroid Build Coastguard Worker for (sigNdx = 0; sigNdx < DE_LENGTH_OF_ARRAY(s_signals); sigNdx++)
489*35238bceSAndroid Build Coastguard Worker sigaction(s_signals[sigNdx].signalNum, &action, &handler->oldHandlers[sigNdx]);
490*35238bceSAndroid Build Coastguard Worker }
491*35238bceSAndroid Build Coastguard Worker #endif
492*35238bceSAndroid Build Coastguard Worker
493*35238bceSAndroid Build Coastguard Worker return handler;
494*35238bceSAndroid Build Coastguard Worker }
495*35238bceSAndroid Build Coastguard Worker
qpCrashHandler_destroy(qpCrashHandler * handler)496*35238bceSAndroid Build Coastguard Worker void qpCrashHandler_destroy(qpCrashHandler *handler)
497*35238bceSAndroid Build Coastguard Worker {
498*35238bceSAndroid Build Coastguard Worker DBGPRINT(("qpCrashHandler::destroy()\n"));
499*35238bceSAndroid Build Coastguard Worker
500*35238bceSAndroid Build Coastguard Worker DE_ASSERT(g_crashHandler == handler);
501*35238bceSAndroid Build Coastguard Worker
502*35238bceSAndroid Build Coastguard Worker deSetAssertFailureCallback(DE_NULL);
503*35238bceSAndroid Build Coastguard Worker
504*35238bceSAndroid Build Coastguard Worker #if defined(QP_USE_SIGNAL_HANDLER)
505*35238bceSAndroid Build Coastguard Worker /* Restore old handlers. */
506*35238bceSAndroid Build Coastguard Worker {
507*35238bceSAndroid Build Coastguard Worker int sigNdx;
508*35238bceSAndroid Build Coastguard Worker for (sigNdx = 0; sigNdx < DE_LENGTH_OF_ARRAY(s_signals); sigNdx++)
509*35238bceSAndroid Build Coastguard Worker sigaction(s_signals[sigNdx].signalNum, &handler->oldHandlers[sigNdx], DE_NULL);
510*35238bceSAndroid Build Coastguard Worker }
511*35238bceSAndroid Build Coastguard Worker #endif
512*35238bceSAndroid Build Coastguard Worker
513*35238bceSAndroid Build Coastguard Worker g_crashHandler = DE_NULL;
514*35238bceSAndroid Build Coastguard Worker
515*35238bceSAndroid Build Coastguard Worker deFree(handler);
516*35238bceSAndroid Build Coastguard Worker }
517*35238bceSAndroid Build Coastguard Worker
518*35238bceSAndroid Build Coastguard Worker #if (DE_PTR_SIZE == 8)
519*35238bceSAndroid Build Coastguard Worker #define PTR_FMT "0x%016"
520*35238bceSAndroid Build Coastguard Worker #elif (DE_PTR_SIZE == 4)
521*35238bceSAndroid Build Coastguard Worker #define PTR_FMT "0x%08"
522*35238bceSAndroid Build Coastguard Worker #else
523*35238bceSAndroid Build Coastguard Worker #error Unknwon DE_PTR_SIZE
524*35238bceSAndroid Build Coastguard Worker #endif
525*35238bceSAndroid Build Coastguard Worker
qpCrashHandler_writeCrashInfo(qpCrashHandler * crashHandler,qpWriteCrashInfoFunc writeInfo,void * userPtr)526*35238bceSAndroid Build Coastguard Worker void qpCrashHandler_writeCrashInfo(qpCrashHandler *crashHandler, qpWriteCrashInfoFunc writeInfo, void *userPtr)
527*35238bceSAndroid Build Coastguard Worker {
528*35238bceSAndroid Build Coastguard Worker qpCrashInfo_write(&crashHandler->crashInfo, writeInfo, userPtr);
529*35238bceSAndroid Build Coastguard Worker
530*35238bceSAndroid Build Coastguard Worker #if (DE_OS == DE_OS_UNIX && (defined(__GLIBC__) || defined(__FreeBSD__)))
531*35238bceSAndroid Build Coastguard Worker {
532*35238bceSAndroid Build Coastguard Worker char tmpFileName[] = "backtrace-XXXXXX";
533*35238bceSAndroid Build Coastguard Worker int tmpFile = mkstemp(tmpFileName);
534*35238bceSAndroid Build Coastguard Worker
535*35238bceSAndroid Build Coastguard Worker if (tmpFile == -1)
536*35238bceSAndroid Build Coastguard Worker {
537*35238bceSAndroid Build Coastguard Worker writeInfoFormat(writeInfo, userPtr, "Failed to create tmpfile '%s' for the backtrace %s.", tmpFileName,
538*35238bceSAndroid Build Coastguard Worker strerror(errno));
539*35238bceSAndroid Build Coastguard Worker return;
540*35238bceSAndroid Build Coastguard Worker }
541*35238bceSAndroid Build Coastguard Worker else
542*35238bceSAndroid Build Coastguard Worker {
543*35238bceSAndroid Build Coastguard Worker void *symbols[32];
544*35238bceSAndroid Build Coastguard Worker int symbolCount;
545*35238bceSAndroid Build Coastguard Worker int symbolNdx;
546*35238bceSAndroid Build Coastguard Worker
547*35238bceSAndroid Build Coastguard Worker /* Remove file from filesystem. */
548*35238bceSAndroid Build Coastguard Worker remove(tmpFileName);
549*35238bceSAndroid Build Coastguard Worker
550*35238bceSAndroid Build Coastguard Worker symbolCount = backtrace(symbols, DE_LENGTH_OF_ARRAY(symbols));
551*35238bceSAndroid Build Coastguard Worker backtrace_symbols_fd(symbols, symbolCount, tmpFile);
552*35238bceSAndroid Build Coastguard Worker
553*35238bceSAndroid Build Coastguard Worker if (lseek(tmpFile, 0, SEEK_SET) < 0)
554*35238bceSAndroid Build Coastguard Worker {
555*35238bceSAndroid Build Coastguard Worker writeInfoFormat(writeInfo, userPtr, "Failed to seek to the beginning of the trace file %s.",
556*35238bceSAndroid Build Coastguard Worker strerror(errno));
557*35238bceSAndroid Build Coastguard Worker close(tmpFile);
558*35238bceSAndroid Build Coastguard Worker return;
559*35238bceSAndroid Build Coastguard Worker }
560*35238bceSAndroid Build Coastguard Worker
561*35238bceSAndroid Build Coastguard Worker for (symbolNdx = 0; symbolNdx < symbolCount; symbolNdx++)
562*35238bceSAndroid Build Coastguard Worker {
563*35238bceSAndroid Build Coastguard Worker char nameBuffer[256];
564*35238bceSAndroid Build Coastguard Worker size_t symbolNameLength = 0;
565*35238bceSAndroid Build Coastguard Worker char c;
566*35238bceSAndroid Build Coastguard Worker
567*35238bceSAndroid Build Coastguard Worker {
568*35238bceSAndroid Build Coastguard Worker const int ret = snprintf(nameBuffer, DE_LENGTH_OF_ARRAY(nameBuffer), PTR_FMT PRIXPTR " : ",
569*35238bceSAndroid Build Coastguard Worker (uintptr_t)symbols[symbolNdx]);
570*35238bceSAndroid Build Coastguard Worker
571*35238bceSAndroid Build Coastguard Worker if (ret < 0)
572*35238bceSAndroid Build Coastguard Worker {
573*35238bceSAndroid Build Coastguard Worker writeInfoFormat(writeInfo, userPtr, "Failed to print symbol pointer.");
574*35238bceSAndroid Build Coastguard Worker symbolNameLength = 0;
575*35238bceSAndroid Build Coastguard Worker }
576*35238bceSAndroid Build Coastguard Worker else if (ret >= DE_LENGTH_OF_ARRAY(nameBuffer))
577*35238bceSAndroid Build Coastguard Worker {
578*35238bceSAndroid Build Coastguard Worker symbolNameLength = DE_LENGTH_OF_ARRAY(nameBuffer) - 1;
579*35238bceSAndroid Build Coastguard Worker nameBuffer[DE_LENGTH_OF_ARRAY(nameBuffer) - 1] = '\0';
580*35238bceSAndroid Build Coastguard Worker }
581*35238bceSAndroid Build Coastguard Worker else
582*35238bceSAndroid Build Coastguard Worker symbolNameLength = ret;
583*35238bceSAndroid Build Coastguard Worker }
584*35238bceSAndroid Build Coastguard Worker
585*35238bceSAndroid Build Coastguard Worker for (;;)
586*35238bceSAndroid Build Coastguard Worker {
587*35238bceSAndroid Build Coastguard Worker if (read(tmpFile, &c, 1) == 1)
588*35238bceSAndroid Build Coastguard Worker {
589*35238bceSAndroid Build Coastguard Worker if (c == '\n')
590*35238bceSAndroid Build Coastguard Worker {
591*35238bceSAndroid Build Coastguard Worker /* Flush nameBuffer and move to next symbol. */
592*35238bceSAndroid Build Coastguard Worker nameBuffer[symbolNameLength] = '\0';
593*35238bceSAndroid Build Coastguard Worker writeInfo(userPtr, nameBuffer);
594*35238bceSAndroid Build Coastguard Worker break;
595*35238bceSAndroid Build Coastguard Worker }
596*35238bceSAndroid Build Coastguard Worker else
597*35238bceSAndroid Build Coastguard Worker {
598*35238bceSAndroid Build Coastguard Worker /* Add character to buffer if there is still space left. */
599*35238bceSAndroid Build Coastguard Worker if (symbolNameLength + 1 < DE_LENGTH_OF_ARRAY(nameBuffer))
600*35238bceSAndroid Build Coastguard Worker {
601*35238bceSAndroid Build Coastguard Worker nameBuffer[symbolNameLength] = c;
602*35238bceSAndroid Build Coastguard Worker symbolNameLength++;
603*35238bceSAndroid Build Coastguard Worker }
604*35238bceSAndroid Build Coastguard Worker }
605*35238bceSAndroid Build Coastguard Worker }
606*35238bceSAndroid Build Coastguard Worker else
607*35238bceSAndroid Build Coastguard Worker {
608*35238bceSAndroid Build Coastguard Worker /* Flush nameBuffer. */
609*35238bceSAndroid Build Coastguard Worker nameBuffer[symbolNameLength] = '\0';
610*35238bceSAndroid Build Coastguard Worker writeInfo(userPtr, nameBuffer);
611*35238bceSAndroid Build Coastguard Worker
612*35238bceSAndroid Build Coastguard Worker /* Temp file ended unexpectedly? */
613*35238bceSAndroid Build Coastguard Worker writeInfoFormat(writeInfo, userPtr, "Unexpected EOF reading backtrace file '%s'", tmpFileName);
614*35238bceSAndroid Build Coastguard Worker close(tmpFile);
615*35238bceSAndroid Build Coastguard Worker tmpFile = -1;
616*35238bceSAndroid Build Coastguard Worker
617*35238bceSAndroid Build Coastguard Worker break;
618*35238bceSAndroid Build Coastguard Worker }
619*35238bceSAndroid Build Coastguard Worker }
620*35238bceSAndroid Build Coastguard Worker
621*35238bceSAndroid Build Coastguard Worker if (tmpFile == -1)
622*35238bceSAndroid Build Coastguard Worker break;
623*35238bceSAndroid Build Coastguard Worker }
624*35238bceSAndroid Build Coastguard Worker
625*35238bceSAndroid Build Coastguard Worker if (tmpFile != -1)
626*35238bceSAndroid Build Coastguard Worker close(tmpFile);
627*35238bceSAndroid Build Coastguard Worker }
628*35238bceSAndroid Build Coastguard Worker }
629*35238bceSAndroid Build Coastguard Worker #endif
630*35238bceSAndroid Build Coastguard Worker }
631*35238bceSAndroid Build Coastguard Worker
632*35238bceSAndroid Build Coastguard Worker #endif /* generic */
633