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