xref: /aosp_15_r20/external/deqp/framework/qphelper/qpCrashHandler.c (revision 35238bce31c2a825756842865a792f8cf7f89930)
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