1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #include "osl/diagnose.h" 25 #include "system.h" 26 27 #ifndef HAVE_DLFCN_H 28 29 #if defined(LINUX) || defined(SOLARIS) 30 #define HAVE_DLFCN_H 31 #endif /* LINUX || SOLARIS */ 32 33 #endif /* HAVE_DLFCN_H */ 34 35 36 #ifdef HAVE_DLFCN_H 37 38 #ifndef INCLUDED_DLFCN_H 39 #include <dlfcn.h> 40 #define INCLUDED_DLFCN_H 41 #endif 42 43 #endif /* HAVE_DLFCN_H */ 44 #include "osl/thread.h" 45 46 #ifndef INCLUDED_PTHREAD_H 47 #include <pthread.h> 48 #define INCLUDED_PTHREAD_H 49 #endif 50 51 #ifndef INCLUDED_STDDEF_H 52 #include <stddef.h> 53 #define INCLUDED_STDDEF_H 54 #endif 55 56 #include "printtrace.h" 57 58 /************************************************************************/ 59 /* Internal data structures and functions */ 60 /************************************************************************/ 61 62 static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; 63 64 typedef pfunc_osl_printDebugMessage oslDebugMessageFunc; 65 static oslDebugMessageFunc volatile g_pDebugMessageFunc = 0; 66 67 typedef pfunc_osl_printDetailedDebugMessage oslDetailedDebugMessageFunc; 68 static oslDetailedDebugMessageFunc volatile g_pDetailedDebugMessageFunc = 0; 69 70 static void osl_diagnose_backtrace_Impl ( 71 oslDebugMessageFunc f); 72 73 #define OSL_DIAGNOSE_OUTPUTMESSAGE(f, s) \ 74 ((f != 0) ? (*(f))((s)) : (void)fprintf(stderr, "%s", (s))) 75 76 #if defined (LINUX) || defined (SOLARIS) 77 /************************************************************************/ 78 /* osl_diagnose_frame_Impl */ 79 /************************************************************************/ 80 static void osl_diagnose_frame_Impl ( 81 oslDebugMessageFunc f, 82 int depth, 83 void * pc) 84 { 85 const char *fname = 0, *sname = 0; 86 void *fbase = 0, *saddr = 0; 87 ptrdiff_t offset; 88 char szMessage[1024]; 89 90 #ifdef INCLUDED_DLFCN_H 91 Dl_info dli; 92 if (dladdr (pc, &dli) != 0) 93 { 94 fname = dli.dli_fname; 95 fbase = dli.dli_fbase; 96 sname = dli.dli_sname; 97 saddr = dli.dli_saddr; 98 } 99 #endif /* INCLUDED_DLFCN_H */ 100 101 if (saddr) 102 offset = (ptrdiff_t)(pc) - (ptrdiff_t)(saddr); 103 else if (fbase) 104 offset = (ptrdiff_t)(pc) - (ptrdiff_t)(fbase); 105 else 106 offset = (ptrdiff_t)(pc); 107 108 snprintf (szMessage, sizeof(szMessage), 109 "Backtrace: [%d] %s: %s+0x%" SAL_PRI_PTRDIFFT "x\n", 110 depth, 111 fname ? fname : "<unknown>", 112 sname ? sname : "???", 113 offset); 114 115 OSL_DIAGNOSE_OUTPUTMESSAGE(f, szMessage); 116 } 117 #endif 118 119 /************************************************************************/ 120 /* osl_diagnose_backtrace_Impl */ 121 /************************************************************************/ 122 #if defined(LINUX) 123 124 #include <execinfo.h> 125 126 #define FRAME_COUNT 64 127 #define FRAME_OFFSET 1 128 129 static void osl_diagnose_backtrace_Impl (oslDebugMessageFunc f) 130 { 131 void * ppFrames[FRAME_COUNT]; 132 int i, n; 133 134 n = backtrace (ppFrames, FRAME_COUNT); 135 for (i = FRAME_OFFSET; i < n; i++) 136 { 137 osl_diagnose_frame_Impl (f, (i - FRAME_OFFSET), ppFrames[i]); 138 } 139 } 140 141 #elif defined(SOLARIS) 142 143 #include <pthread.h> 144 #include <setjmp.h> 145 #include <sys/frame.h> 146 147 #if defined(SPARC) 148 149 #if defined IS_LP64 150 151 #define FRAME_PTR_OFFSET 1 152 #define FRAME_OFFSET 0 153 #define STACK_BIAS 0x7ff 154 155 #else 156 157 #define FRAME_PTR_OFFSET 1 158 #define FRAME_OFFSET 0 159 #define STACK_BIAS 0 160 161 #endif 162 163 #elif defined(INTEL) 164 165 #define FRAME_PTR_OFFSET 3 166 #define FRAME_OFFSET 0 167 #define STACK_BIAS 0 168 169 #endif /* (SPARC || INTEL) */ 170 171 static void osl_diagnose_backtrace_Impl (oslDebugMessageFunc f) 172 { 173 jmp_buf ctx; 174 long fpval; 175 struct frame * fp; 176 int i; 177 178 #if defined(SPARC) 179 asm("ta 3"); 180 #endif /* SPARC */ 181 setjmp (ctx); 182 183 fpval = ((long*)(ctx))[FRAME_PTR_OFFSET]; 184 fp = (struct frame*)((char*)(fpval) + STACK_BIAS); 185 186 for (i = 0; (i < FRAME_OFFSET) && (fp != 0); i++) 187 fp = (struct frame*)((char*)(fp->fr_savfp) + STACK_BIAS); 188 189 for (i = 0; (fp != 0) && (fp->fr_savpc != 0); i++) 190 { 191 struct frame * prev = (struct frame*)((char*)(fp->fr_savfp) + STACK_BIAS); 192 osl_diagnose_frame_Impl (f, i, (void*)(fp->fr_savpc)); 193 fp = (prev > fp) ? prev : 0; 194 } 195 } 196 197 #else /* (LINUX || SOLARIS) */ 198 199 static void osl_diagnose_backtrace_Impl (oslDebugMessageFunc f) 200 { 201 /* not yet implemented */ 202 } 203 204 #endif /* (LINUX || SOLARIS) */ 205 206 /************************************************************************/ 207 /* osl_assertFailedLine */ 208 /************************************************************************/ 209 sal_Bool SAL_CALL osl_assertFailedLine ( 210 const sal_Char* pszFileName, 211 sal_Int32 nLine, 212 const sal_Char* pszMessage) 213 { 214 oslDebugMessageFunc f = g_pDebugMessageFunc; 215 char szMessage[1024]; 216 217 // after reporting the assertion, abort if told so by SAL_DIAGNOSE_ABORT, but *not* if 218 // assertions are routed to some external instance 219 char const * env = getenv( "SAL_DIAGNOSE_ABORT" ); 220 sal_Bool const doAbort = ( ( env != NULL ) && ( *env != '\0' ) && ( f == NULL ) ); 221 222 /* If there's a callback for detailed messages, use it */ 223 if ( g_pDetailedDebugMessageFunc != NULL ) 224 { 225 g_pDetailedDebugMessageFunc( pszFileName, nLine, pszMessage ); 226 return sal_False; 227 } 228 229 /* if SAL assertions are disabled in general, stop here */ 230 if ( getenv("DISABLE_SAL_DBGBOX") ) 231 return doAbort; 232 233 /* format message into buffer */ 234 if (pszMessage != 0) 235 { 236 snprintf(szMessage, sizeof(szMessage), 237 "Error: File %s, Line %" SAL_PRIdINT32 ": %s\n", 238 pszFileName, nLine, pszMessage); 239 } 240 else 241 { 242 snprintf(szMessage, sizeof(szMessage), 243 "Error: File %s, Line %" SAL_PRIdINT32 "\n", 244 pszFileName, nLine); 245 } 246 247 /* acquire lock to serialize output message(s) */ 248 pthread_mutex_lock(&g_mutex); 249 250 /* output message buffer */ 251 OSL_DIAGNOSE_OUTPUTMESSAGE(f, szMessage); 252 253 /* output backtrace */ 254 osl_diagnose_backtrace_Impl(f); 255 256 /* release lock and leave */ 257 pthread_mutex_unlock(&g_mutex); 258 259 return doAbort; 260 } 261 262 /************************************************************************/ 263 /* osl_breakDebug */ 264 /************************************************************************/ 265 void SAL_CALL osl_breakDebug() 266 { 267 abort(); 268 } 269 270 /************************************************************************/ 271 /* osl_reportError */ 272 /************************************************************************/ 273 sal_Int32 SAL_CALL osl_reportError ( 274 sal_uInt32 nType, 275 const sal_Char* pszMessage) 276 { 277 (void) nType; /* unused */ 278 fputs(pszMessage, stderr); 279 return 0; 280 } 281 282 /************************************************************************/ 283 /* osl_setDebugMessageFunc */ 284 /************************************************************************/ 285 oslDebugMessageFunc SAL_CALL osl_setDebugMessageFunc ( 286 oslDebugMessageFunc pNewFunc) 287 { 288 oslDebugMessageFunc pOldFunc = g_pDebugMessageFunc; 289 g_pDebugMessageFunc = pNewFunc; 290 return pOldFunc; 291 } 292 293 /************************************************************************/ 294 /* osl_setDetailedDebugMessageFunc */ 295 /************************************************************************/ 296 pfunc_osl_printDetailedDebugMessage SAL_CALL osl_setDetailedDebugMessageFunc ( 297 pfunc_osl_printDetailedDebugMessage pNewFunc) 298 { 299 oslDetailedDebugMessageFunc pOldFunc = g_pDetailedDebugMessageFunc; 300 g_pDetailedDebugMessageFunc = pNewFunc; 301 return pOldFunc; 302 } 303 304 /************************************************************************/ 305 /* osl_trace */ 306 /************************************************************************/ 307 void osl_trace(char const * pszFormat, ...) { 308 va_list args; 309 va_start(args, pszFormat); 310 printTrace((unsigned long) getpid(), pszFormat, args); 311 va_end(args); 312 } 313