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) || defined(FREEBSD) 30 #define HAVE_DLFCN_H 31 #endif /* LINUX || SOLARIS || FREEBSD */ 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) || defined(FREEBSD) 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 #elif defined(FREEBSD) 198 199 #include <setjmp.h> 200 #include "backtrace.h" /* for struct frame */ 201 202 #if defined(X86) || defined(X86_64) 203 204 #define FRAME_PTR_OFFSET 3 205 #define FRAME_OFFSET 0 206 207 #endif /* (X86 || X86_64) */ 208 209 static void osl_diagnose_backtrace_Impl (oslDebugMessageFunc f) 210 { 211 struct frame * fp; 212 jmp_buf ctx; 213 int i; 214 215 setjmp (ctx); 216 fp = (struct frame*)(((long*)(ctx))[FRAME_PTR_OFFSET]); 217 218 for (i = 0; (i < FRAME_OFFSET) && (fp != 0); i++) 219 fp = fp->fr_savfp; 220 221 for (i = 0; (fp != 0) && (fp->fr_savpc != 0); i++) 222 { 223 struct frame * prev = fp->fr_savfp; 224 osl_diagnose_frame_Impl (f, i, (void*)(fp->fr_savpc)); 225 fp = (prev > fp) ? prev : 0; 226 } 227 } 228 229 #else /* (LINUX || SOLARIS || FREEBSD) */ 230 231 static void osl_diagnose_backtrace_Impl (oslDebugMessageFunc f) 232 { 233 /* not yet implemented */ 234 } 235 236 #endif /* (LINUX || SOLARIS || FREEBSD) */ 237 238 /************************************************************************/ 239 /* osl_assertFailedLine */ 240 /************************************************************************/ 241 sal_Bool SAL_CALL osl_assertFailedLine ( 242 const sal_Char* pszFileName, 243 sal_Int32 nLine, 244 const sal_Char* pszMessage) 245 { 246 oslDebugMessageFunc f = g_pDebugMessageFunc; 247 char szMessage[1024]; 248 249 // after reporting the assertion, abort if told so by SAL_DIAGNOSE_ABORT, but *not* if 250 // assertions are routed to some external instance 251 char const * env = getenv( "SAL_DIAGNOSE_ABORT" ); 252 sal_Bool const doAbort = ( ( env != NULL ) && ( *env != '\0' ) && ( f == NULL ) ); 253 254 /* If there's a callback for detailed messages, use it */ 255 if ( g_pDetailedDebugMessageFunc != NULL ) 256 { 257 g_pDetailedDebugMessageFunc( pszFileName, nLine, pszMessage ); 258 return sal_False; 259 } 260 261 /* if SAL assertions are disabled in general, stop here */ 262 if ( getenv("DISABLE_SAL_DBGBOX") ) 263 return doAbort; 264 265 /* format message into buffer */ 266 if (pszMessage != 0) 267 { 268 snprintf(szMessage, sizeof(szMessage), 269 "Error: File %s, Line %" SAL_PRIdINT32 ": %s\n", 270 pszFileName, nLine, pszMessage); 271 } 272 else 273 { 274 snprintf(szMessage, sizeof(szMessage), 275 "Error: File %s, Line %" SAL_PRIdINT32 "\n", 276 pszFileName, nLine); 277 } 278 279 /* acquire lock to serialize output message(s) */ 280 pthread_mutex_lock(&g_mutex); 281 282 /* output message buffer */ 283 OSL_DIAGNOSE_OUTPUTMESSAGE(f, szMessage); 284 285 /* output backtrace */ 286 osl_diagnose_backtrace_Impl(f); 287 288 /* release lock and leave */ 289 pthread_mutex_unlock(&g_mutex); 290 291 return doAbort; 292 } 293 294 /************************************************************************/ 295 /* osl_breakDebug */ 296 /************************************************************************/ 297 void SAL_CALL osl_breakDebug() 298 { 299 abort(); 300 } 301 302 /************************************************************************/ 303 /* osl_reportError */ 304 /************************************************************************/ 305 sal_Int32 SAL_CALL osl_reportError ( 306 sal_uInt32 nType, 307 const sal_Char* pszMessage) 308 { 309 (void) nType; /* unused */ 310 fputs(pszMessage, stderr); 311 return 0; 312 } 313 314 /************************************************************************/ 315 /* osl_setDebugMessageFunc */ 316 /************************************************************************/ 317 oslDebugMessageFunc SAL_CALL osl_setDebugMessageFunc ( 318 oslDebugMessageFunc pNewFunc) 319 { 320 oslDebugMessageFunc pOldFunc = g_pDebugMessageFunc; 321 g_pDebugMessageFunc = pNewFunc; 322 return pOldFunc; 323 } 324 325 /************************************************************************/ 326 /* osl_setDetailedDebugMessageFunc */ 327 /************************************************************************/ 328 pfunc_osl_printDetailedDebugMessage SAL_CALL osl_setDetailedDebugMessageFunc ( 329 pfunc_osl_printDetailedDebugMessage pNewFunc) 330 { 331 oslDetailedDebugMessageFunc pOldFunc = g_pDetailedDebugMessageFunc; 332 g_pDetailedDebugMessageFunc = pNewFunc; 333 return pOldFunc; 334 } 335 336 /************************************************************************/ 337 /* osl_trace */ 338 /************************************************************************/ 339 void osl_trace(char const * pszFormat, ...) { 340 va_list args; 341 va_start(args, pszFormat); 342 printTrace((unsigned long) getpid(), pszFormat, args); 343 va_end(args); 344 } 345