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