2001-12-17 14:31:42 +00:00
/ * * NSException - Object encapsulation of a general exception handler
1999-04-21 20:16:25 +00:00
Copyright ( C ) 1993 , 1994 , 1996 , 1997 , 1999 Free Software Foundation , Inc .
1995-03-18 17:15:15 +00:00
Written by : Adam Fedor < fedor @ boulder . colorado . edu >
Date : Mar 1995
1996-05-12 00:56:10 +00:00
This file is part of the GNUstep Base Library .
1995-03-18 17:15:15 +00:00
This library is free software ; you can redistribute it and / or
2007-09-14 11:36:11 +00:00
modify it under the terms of the GNU Lesser General Public
1995-03-18 17:15:15 +00:00
License as published by the Free Software Foundation ; either
2008-06-08 10:38:33 +00:00
version 2 of the License , or ( at your option ) any later version .
1999-04-21 20:16:25 +00:00
1995-03-18 17:15:15 +00:00
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Library General Public License for more details .
2007-09-14 11:36:11 +00:00
You should have received a copy of the GNU Lesser General Public
1995-03-18 17:15:15 +00:00
License along with this library ; if not , write to the Free
2006-05-08 15:30:52 +00:00
Software Foundation , Inc . , 51 Franklin Street , Fifth Floor ,
Boston , MA 02111 USA .
2001-12-18 16:54:15 +00:00
$ Date $ $ Revision $
1995-03-18 17:15:15 +00:00
* /
1996-05-28 18:27:40 +00:00
2010-02-19 08:12:46 +00:00
# import "common.h"
2010-02-14 10:48:10 +00:00
# define EXPOSE_NSException _IVARS 1
2010-02-24 10:23:47 +00:00
# define EXPOSE_NSThread _IVARS 1
2007-12-03 14:13:57 +00:00
# import "GSPrivate.h"
2010-02-14 10:48:10 +00:00
# import "Foundation/NSBundle.h"
2007-11-29 20:53:26 +00:00
# import "Foundation/NSEnumerator.h"
# import "Foundation/NSException.h"
# import "Foundation/NSArray.h"
# import "Foundation/NSCoder.h"
# import "Foundation/NSNull.h"
# import "Foundation/NSThread.h"
# import "Foundation/NSLock.h"
# import "Foundation/NSDictionary.h"
# import "Foundation/NSValue.h"
2010-02-14 10:48:10 +00:00
# import "GNUstepBase/NSString+GNUstepBase.h"
2010-07-15 09:59:01 +00:00
# ifdef __GNUSTEP _RUNTIME __
# include < objc / hooks . h >
# endif
2010-12-23 02:23:05 +00:00
# ifdef HAVE_SET _UNCAUGHT _EXCEPTION _HANDLER
# include < objc / objc - exception . h >
# endif
2010-03-16 06:11:00 +00:00
# ifdef HAVE_MALLOC _H
# include < malloc . h >
# endif
2010-02-25 19:05:21 +00:00
# ifdef HAVE_ALLOCA _H
# include < alloca . h >
# endif
2001-05-31 22:39:16 +00:00
# include < stdio . h >
2010-01-24 17:13:03 +00:00
2009-09-11 16:14:45 +00:00
# ifdef HAVE_BACKTRACE
# include < execinfo . h >
2010-01-24 17:13:03 +00:00
# ifdef USE_BINUTILS
# undef USE_BINUTILS
# endif
# else
# ifndef USE_BINUTILS
# define USE_BINUTILS 1
# endif
2009-09-11 16:14:45 +00:00
# endif
2002-03-27 09:55:57 +00:00
2010-02-08 20:33:40 +00:00
static NSUncaughtExceptionHandler * _NSUncaughtExceptionHandler = 0 ;
2007-12-05 16:13:24 +00:00
# define _e _info ( ( ( id * ) _reserved ) [ 0 ] )
# define _e _stack ( ( ( id * ) _reserved ) [ 1 ] )
2007-02-06 11:47:32 +00:00
/ * This is the GNU name for the CTOR list * /
2007-02-04 08:43:16 +00:00
2009-09-11 16:14:45 +00:00
@ interface GSStackTrace : NSObject
2006-05-08 15:30:52 +00:00
{
2010-01-24 17:13:03 +00:00
NSArray * symbols ;
NSArray * addresses ;
2006-05-08 15:30:52 +00:00
}
2009-09-11 19:19:05 +00:00
- ( NSArray * ) addresses ;
2009-09-11 16:14:45 +00:00
- ( NSArray * ) symbols ;
2010-01-24 17:13:03 +00:00
2006-05-08 15:30:52 +00:00
@ end
2010-01-24 17:13:03 +00:00
@ interface NSException ( GSPrivate )
- ( GSStackTrace * ) _callStack ;
2006-05-08 15:30:52 +00:00
@ end
2010-01-24 17:13:03 +00:00
/ *
* Turn off USE_BINUTILS if we don ' t have bfd support for it .
* /
# if ! ( defined ( HAVE_BFD _H ) && defined ( HAVE_LIBBFD ) && defined ( HAVE_LIBIBERTY ) )
# if defined ( USE_BINUTILS )
# undef USE_BINUTILS
# endif
# endif
2006-05-08 15:30:52 +00:00
2010-03-19 12:10:11 +00:00
# if defined ( __MINGW __ )
2010-01-24 17:13:03 +00:00
# if defined ( USE_BINUTILS )
static NSString *
GSPrivateBaseAddress ( void * addr , void * * base )
2006-05-08 15:30:52 +00:00
{
2010-01-25 09:58:52 +00:00
MEMORY_BASIC _INFORMATION info ;
/ * Found a note saying that according to Matt Pietrek ' s "Under the Hood"
* column for the April 1997 issue of Microsoft Systems Journal , the
* allocation base returned by VirtualQuery can be used as the handle
* to obtain module information for a loaded library .
* /
if ( VirtualQuery ( addr , & info , sizeof ( info ) ) ! = 0 )
{
2010-02-03 09:31:59 +00:00
HMODULE handle = ( HMODULE ) info . AllocationBase ;
2010-01-25 09:58:52 +00:00
unichar path [ MAX_PATH + 1 ] ;
if ( GetModuleFileNameW ( handle , path , sizeof ( path ) -1 ) ! = 0 )
{
path [ sizeof ( path ) -1 ] = ' \ 0 ' ;
* base = info . BaseAddress ;
2010-02-03 09:31:59 +00:00
return [ NSString stringWithCharacters : path length : wcslen ( path ) ] ;
2010-01-25 09:58:52 +00:00
}
}
2010-01-24 17:13:03 +00:00
return nil ;
2006-05-08 15:30:52 +00:00
}
2010-01-24 17:13:03 +00:00
# endif / * USE_BINUTILS * /
2010-03-19 12:10:11 +00:00
# else / * __MINGW __ * /
2010-01-24 17:13:03 +00:00
# include < dlfcn . h >
# if defined ( USE_BINUTILS )
static NSString *
GSPrivateBaseAddress ( void * addr , void * * base )
{
# ifdef HAVE_DLADDR
Dl_info info ;
if ( ! dladdr ( addr , & info ) )
return nil ;
* base = info . dli_fbase ;
return [ NSString stringWithUTF8String : info . dli_fname ] ;
# else
return nil ;
# endif
}
# endif / * USE_BINUTILS * /
2010-03-19 12:10:11 +00:00
# endif / * __MINGW __ * /
2010-01-24 17:13:03 +00:00
# if defined ( USE_BINUTILS )
// GSStackTrace inspired by FYStackTrace . m
// created by Wim Oudshoorn on Mon 11 - Apr -2006
// reworked by Lloyd Dupont @ NovaMind . com on 4 - May -2006
# include < bfd . h >
@ class GSBinaryFileInfo ;
@ interface GSFunctionInfo : NSObject
{
void * _address ;
NSString * _fileName ;
NSString * _functionName ;
int _lineNo ;
GSBinaryFileInfo * _module ;
}
- ( void * ) address ;
- ( NSString * ) fileName ;
- ( NSString * ) function ;
- ( id ) initWithModule : ( GSBinaryFileInfo * ) module
address : ( void * ) address
file : ( NSString * ) file
function : ( NSString * ) function
line : ( int ) lineNo ;
- ( int ) lineNumber ;
- ( GSBinaryFileInfo * ) module ;
@ end
@ interface GSBinaryFileInfo : NSObject
2006-05-08 15:30:52 +00:00
{
2010-01-24 17:13:03 +00:00
NSString * _fileName ;
bfd * _abfd ;
asymbol * * _symbols ;
long _symbolCount ;
2006-05-08 15:30:52 +00:00
}
2010-01-24 17:13:03 +00:00
- ( NSString * ) fileName ;
- ( GSFunctionInfo * ) functionForAddress : ( void * ) address ;
- ( id ) initWithBinaryFile : ( NSString * ) fileName ;
- ( id ) init ; // return info for the current executing process
@ end
@ implementation GSFunctionInfo
- ( void * ) address
2006-05-08 15:30:52 +00:00
{
2010-01-24 17:13:03 +00:00
return _address ;
2006-05-08 15:30:52 +00:00
}
2010-01-24 17:13:03 +00:00
2006-05-08 15:30:52 +00:00
- ( oneway void ) dealloc
{
2010-01-24 17:13:03 +00:00
DESTROY ( _module ) ;
DESTROY ( _fileName ) ;
DESTROY ( _functionName ) ;
2009-09-11 19:19:05 +00:00
[ super dealloc ] ;
2006-05-08 15:30:52 +00:00
}
2010-01-24 17:13:03 +00:00
- ( NSString * ) description
{
return [ NSString stringWithFormat : @ "(%@: %p) %@ %@: %d" ,
[ _module fileName ] , _address , _functionName , _fileName , _lineNo ] ;
}
- ( NSString * ) fileName
2006-05-08 15:30:52 +00:00
{
2010-01-24 17:13:03 +00:00
return _fileName ;
}
- ( NSString * ) function
{
return _functionName ;
}
2009-09-11 19:19:05 +00:00
2010-01-24 17:13:03 +00:00
- ( id ) init
{
2010-02-25 18:49:31 +00:00
DESTROY ( self ) ;
2010-01-24 17:13:03 +00:00
return nil ;
}
- ( id ) initWithModule : ( GSBinaryFileInfo * ) module
address : ( void * ) address
file : ( NSString * ) file
function : ( NSString * ) function
line : ( int ) lineNo
{
_module = RETAIN ( module ) ;
_address = address ;
_fileName = [ file copy ] ;
_functionName = [ function copy ] ;
_lineNo = lineNo ;
return self ;
}
- ( int ) lineNumber
{
return _lineNo ;
}
- ( GSBinaryFileInfo * ) module
{
return _module ;
}
@ end
@ implementation GSBinaryFileInfo
+ ( GSBinaryFileInfo * ) infoWithBinaryFile : ( NSString * ) fileName
{
return [ [ [ self alloc ] initWithBinaryFile : fileName ] autorelease ] ;
}
+ ( void ) initialize
{
static BOOL first = YES ;
if ( first = = NO )
2009-09-11 19:19:05 +00:00
{
2010-01-24 17:13:03 +00:00
return ;
2009-09-11 19:19:05 +00:00
}
2010-01-24 17:13:03 +00:00
first = NO ;
bfd_init ( ) ;
2006-05-08 15:30:52 +00:00
}
2010-01-24 17:13:03 +00:00
- ( oneway void ) dealloc
2006-05-08 15:30:52 +00:00
{
2010-01-24 17:13:03 +00:00
DESTROY ( _fileName ) ;
if ( _abfd )
2009-09-11 19:19:05 +00:00
{
2010-01-24 17:13:03 +00:00
bfd_close ( _abfd ) ;
_abfd = NULL ;
}
if ( _symbols )
{
objc_free ( _symbols ) ;
_symbols = NULL ;
}
[ super dealloc ] ;
}
2009-09-11 19:19:05 +00:00
2010-01-24 17:13:03 +00:00
- ( NSString * ) fileName
{
return _fileName ;
}
- ( id ) init
{
NSString * processName ;
processName = [ [ [ NSProcessInfo processInfo ] arguments ] objectAtIndex : 0 ] ;
return [ self initWithBinaryFile : processName ] ;
}
- ( id ) initWithBinaryFile : ( NSString * ) fileName
{
int neededSpace ;
// 1 st initialize the bfd
if ( [ fileName length ] = = 0 )
{
// NSLog ( @ "GSBinaryFileInfo: No File" ) ;
2010-02-25 18:49:31 +00:00
DESTROY ( self ) ;
2010-01-24 17:13:03 +00:00
return nil ;
}
_fileName = [ fileName copy ] ;
_abfd = bfd_openr ( [ fileName cString ] , NULL ) ;
if ( ! _abfd )
{
// NSLog ( @ "GSBinaryFileInfo: No Binary Info" ) ;
2010-02-25 18:49:31 +00:00
DESTROY ( self ) ;
2010-01-24 17:13:03 +00:00
return nil ;
}
if ( ! bfd_check _format _matches ( _abfd , bfd_object , NULL ) )
{
// NSLog ( @ "GSBinaryFileInfo: BFD format object error" ) ;
2010-02-25 18:49:31 +00:00
DESTROY ( self ) ;
2010-01-24 17:13:03 +00:00
return nil ;
}
// second read the symbols from it
if ( ! ( bfd_get _file _flags ( _abfd ) & HAS_SYMS ) )
{
// NSLog ( @ "GSBinaryFileInfo: BFD does not contain any symbols" ) ;
2010-02-25 18:49:31 +00:00
DESTROY ( self ) ;
2010-01-24 17:13:03 +00:00
return nil ;
}
neededSpace = bfd_get _symtab _upper _bound ( _abfd ) ;
if ( neededSpace < 0 )
{
// NSLog ( @ "GSBinaryFileInfo: BFD error while deducing needed space" ) ;
2010-02-25 18:49:31 +00:00
DESTROY ( self ) ;
2010-01-24 17:13:03 +00:00
return nil ;
}
if ( neededSpace = = 0 )
{
// NSLog ( @ "GSBinaryFileInfo: BFD no space for symbols needed" ) ;
2010-02-25 18:49:31 +00:00
DESTROY ( self ) ;
2010-01-24 17:13:03 +00:00
return nil ;
}
_symbols = objc_malloc ( neededSpace ) ;
if ( ! _symbols )
{
// NSLog ( @ "GSBinaryFileInfo: Can't allocate buffer" ) ;
2010-02-25 18:49:31 +00:00
DESTROY ( self ) ;
2010-01-24 17:13:03 +00:00
return nil ;
}
_symbolCount = bfd_canonicalize _symtab ( _abfd , _symbols ) ;
if ( _symbolCount < 0 )
{
// NSLog ( @ "GSBinaryFileInfo: BFD error while reading symbols" ) ;
2010-02-25 18:49:31 +00:00
DESTROY ( self ) ;
2010-01-24 17:13:03 +00:00
return nil ;
}
return self ;
}
struct SearchAddressStruct
{
void * theAddress ;
GSBinaryFileInfo * module ;
asymbol * * symbols ;
GSFunctionInfo * theInfo ;
} ;
static void find_address ( bfd * abfd , asection * section ,
struct SearchAddressStruct * info )
{
bfd_vma address ;
bfd_vma vma ;
unsigned size ;
const char * fileName = 0 ;
const char * functionName = 0 ;
unsigned line = 0 ;
if ( info -> theInfo )
{
return ;
}
if ( ! ( bfd_get _section _flags ( abfd , section ) & SEC_ALLOC ) )
{
return ; // Only debug in this section
}
if ( bfd_get _section _flags ( abfd , section ) & SEC_DATA )
{
return ; // Only data in this section
}
address = ( bfd_vma ) ( uintptr_t ) info -> theAddress ;
vma = bfd_get _section _vma ( abfd , section ) ;
# if defined ( bfd_get _section _size _before _reloc )
size = bfd_get _section _size _before _reloc ( section ) ; // recent
# elif defined ( bfd_get _section _size )
size = bfd_get _section _size ( section ) ; // less recent
# else
size = bfd_section _size ( abfd , section ) ; // older version
# endif
if ( address < vma || address >= vma + size )
{
return ;
}
if ( bfd_find _nearest _line ( abfd , section , info -> symbols ,
address - vma , & fileName , & functionName , & line ) )
{
GSFunctionInfo * fi ;
NSString * file = nil ;
NSString * func = nil ;
if ( fileName ! = 0 )
{
file = [ NSString stringWithCString : fileName
encoding : [ NSString defaultCStringEncoding ] ] ;
2006-05-08 15:30:52 +00:00
}
2010-01-24 17:13:03 +00:00
if ( functionName ! = 0 )
{
func = [ NSString stringWithCString : functionName
encoding : [ NSString defaultCStringEncoding ] ] ;
}
fi = [ GSFunctionInfo alloc ] ;
fi = [ fi initWithModule : info -> module
address : info -> theAddress
file : file
function : func
line : line ] ;
[ fi autorelease ] ;
info -> theInfo = fi ;
2009-09-11 19:19:05 +00:00
}
2007-02-04 08:43:16 +00:00
}
2010-01-24 17:13:03 +00:00
- ( GSFunctionInfo * ) functionForAddress : ( void * ) address
{
struct SearchAddressStruct searchInfo =
{ address , self , _symbols , nil } ;
bfd_map _over _sections ( _abfd ,
( void (*) (bfd *, asection *, void *) ) find_address , & searchInfo ) ;
return searchInfo . theInfo ;
}
@ end
static NSRecursiveLock * modLock = nil ;
static NSMutableDictionary * stackModules = nil ;
// initialize stack trace info
static id
GSLoadModule ( NSString * fileName )
2006-05-08 15:30:52 +00:00
{
2010-01-24 17:13:03 +00:00
GSBinaryFileInfo * module = nil ;
[ modLock lock ] ;
if ( stackModules = = nil )
2009-09-11 19:19:05 +00:00
{
2010-01-24 17:13:03 +00:00
NSEnumerator * enumerator ;
NSBundle * bundle ;
2009-09-11 19:19:05 +00:00
2010-01-24 17:13:03 +00:00
stackModules = [ NSMutableDictionary new ] ;
/ *
* Try to ensure we have the main , base and gui library bundles .
* /
[ NSBundle mainBundle ] ;
[ NSBundle bundleForClass : [ NSObject class ] ] ;
[ NSBundle bundleForClass : NSClassFromString ( @ "NSView" ) ] ;
/ *
* Add file info for all bundles with code .
* /
enumerator = [ [ NSBundle allBundles ] objectEnumerator ] ;
while ( ( bundle = [ enumerator nextObject ] ) ! = nil )
{
if ( [ bundle load ] = = YES )
{
GSLoadModule ( [ bundle executablePath ] ) ;
}
}
}
if ( [ fileName length ] > 0 )
{
module = [ stackModules objectForKey : fileName ] ;
if ( module = = nil )
2009-09-11 16:14:45 +00:00
{
2010-01-24 17:13:03 +00:00
module = [ GSBinaryFileInfo infoWithBinaryFile : fileName ] ;
if ( module = = nil )
{
module = ( id ) [ NSNull null ] ;
}
if ( [ stackModules objectForKey : fileName ] = = nil )
{
[ stackModules setObject : module forKey : fileName ] ;
}
else
{
module = [ stackModules objectForKey : fileName ] ;
}
2006-05-08 15:30:52 +00:00
}
2009-09-11 19:19:05 +00:00
}
2010-01-24 17:13:03 +00:00
[ modLock unlock ] ;
if ( module = = ( id ) [ NSNull null ] )
{
module = nil ;
}
return module ;
}
static NSArray *
GSListModules ( )
{
NSArray * result ;
GSLoadModule ( nil ) ; // initialise
[ modLock lock ] ;
result = [ stackModules allValues ] ;
[ modLock unlock ] ;
return result ;
}
# endif / * USE_BINUTILS * /
@ implementation GSStackTrace : NSObject
- ( NSArray * ) addresses
{
return addresses ;
}
- ( oneway void ) dealloc
{
DESTROY ( addresses ) ;
DESTROY ( symbols ) ;
[ super dealloc ] ;
2006-05-08 15:30:52 +00:00
}
2010-01-24 17:13:03 +00:00
- ( NSString * ) description
{
NSMutableString * result ;
NSArray * s ;
int i ;
int n ;
result = [ NSMutableString string ] ;
s = [ self symbols ] ;
n = [ s count ] ;
for ( i = 0 ; i < n ; i + + )
{
NSString * line = [ s objectAtIndex : i ] ;
[ result appendFormat : @ "%3d: %@\n" , i , line ] ;
}
return result ;
}
2009-09-11 16:14:45 +00:00
// grab the current stack
- ( id ) init
2006-05-08 15:30:52 +00:00
{
2010-01-24 17:13:03 +00:00
# if defined ( HAVE_BACKTRACE )
void * * addr ;
id * vals ;
int count ;
int i ;
addr = calloc ( sizeof ( void * ) , 1024 ) ;
count = backtrace ( addr , 1024 ) ;
addr = realloc ( addr , count * sizeof ( void * ) ) ;
vals = alloca ( count * sizeof ( id ) ) ;
for ( i = 0 ; i < count ; i + + )
{
vals [ i ] = [ NSNumber numberWithUnsignedInteger :
( NSUInteger ) addr [ i ] ] ;
}
addresses = [ [ NSArray alloc ] initWithObjects : vals count : count ] ;
free ( addr ) ;
# else
addresses = [ GSPrivateStackAddresses ( ) copy ] ;
# endif
2009-09-11 19:19:05 +00:00
return self ;
2006-05-08 15:30:52 +00:00
}
2010-01-24 17:13:03 +00:00
- ( NSArray * ) symbols
{
# if defined ( HAVE_BACKTRACE )
if ( nil = = symbols )
{
char * * strs ;
void * * addr ;
NSString * * symbolArray ;
unsigned count ;
int i ;
count = [ addresses count ] ;
addr = alloca ( count * sizeof ( void * ) ) ;
for ( i = 0 ; i < count ; i + + )
{
addr [ i ] = ( void * ) [ [ addresses objectAtIndex : i ] unsignedIntegerValue ] ;
}
strs = backtrace_symbols ( addr , count ) ;
symbolArray = alloca ( count * sizeof ( NSString * ) ) ;
for ( i = 0 ; i < count ; i + + )
{
symbolArray [ i ] = [ NSString stringWithUTF8String : strs [ i ] ] ;
}
symbols = [ [ NSArray alloc ] initWithObjects : symbolArray count : count ] ;
free ( strs ) ;
}
# elif defined ( USE_BINUTILS )
if ( nil = = symbols )
{
NSMutableArray * a ;
int i ;
int n ;
n = [ addresses count ] ;
a = [ [ NSMutableArray alloc ] initWithCapacity : n ] ;
2006-05-08 15:30:52 +00:00
2010-01-24 17:13:03 +00:00
for ( i = 0 ; i < n ; i + + )
{
GSFunctionInfo * aFrame = nil ;
void * address ;
void * base ;
NSString * modulePath ;
GSBinaryFileInfo * bfi ;
address = ( void * ) [ [ addresses objectAtIndex : i ] pointerValue ] ;
modulePath = GSPrivateBaseAddress ( address , & base ) ;
if ( modulePath ! = nil && ( bfi = GSLoadModule ( modulePath ) ) ! = nil )
{
aFrame = [ bfi functionForAddress : ( void * ) ( address - base ) ] ;
if ( aFrame = = nil )
{
2010-01-25 09:58:52 +00:00
/ * We know we have the right module but function lookup
2010-01-24 17:13:03 +00:00
* failed . . . perhaps we need to use the absolute
* address rather than offest by ' base ' in this case .
* /
aFrame = [ bfi functionForAddress : address ] ;
}
}
else
{
NSArray * modules ;
int j ;
int m ;
modules = GSListModules ( ) ;
m = [ modules count ] ;
for ( j = 0 ; j < m ; j + + )
{
bfi = [ modules objectAtIndex : j ] ;
if ( ( id ) bfi ! = ( id ) [ NSNull null ] )
{
aFrame = [ bfi functionForAddress : address ] ;
if ( aFrame ! = nil )
{
break ;
}
}
}
}
// not found ( ? ! ) , add an ' unknown ' function
if ( aFrame = = nil )
{
aFrame = [ GSFunctionInfo alloc ] ;
[ aFrame initWithModule : nil
address : address
file : nil
function : nil
line : 0 ] ;
[ aFrame autorelease ] ;
}
[ a addObject : [ aFrame description ] ] ;
}
symbols = [ a copy ] ;
[ a release ] ;
}
2009-09-11 16:14:45 +00:00
# endif
2010-01-24 17:13:03 +00:00
return symbols ;
}
@ end
2006-05-08 15:30:52 +00:00
2008-03-17 05:45:55 +00:00
NSString * const NSCharacterConversionException
= @ "NSCharacterConversionException" ;
2002-06-09 11:47:45 +00:00
NSString * const NSGenericException
2002-06-09 11:36:13 +00:00
= @ "NSGenericException" ;
2002-06-09 11:47:45 +00:00
NSString * const NSInternalInconsistencyException
2002-06-09 11:36:13 +00:00
= @ "NSInternalInconsistencyException" ;
2002-06-09 11:47:45 +00:00
NSString * const NSInvalidArgumentException
2002-06-09 11:36:13 +00:00
= @ "NSInvalidArgumentException" ;
2002-06-09 11:47:45 +00:00
NSString * const NSMallocException
2002-06-09 11:36:13 +00:00
= @ "NSMallocException" ;
2008-03-17 05:45:55 +00:00
NSString * const NSOldStyleException
= @ "NSOldStyleException" ;
2002-06-09 11:36:13 +00:00
2002-06-09 11:47:45 +00:00
NSString * const NSParseErrorException
2002-06-09 11:36:13 +00:00
= @ "NSParseErrorException" ;
2008-03-17 05:45:55 +00:00
NSString * const NSRangeException
= @ "NSRangeException" ;
2005-07-01 08:53:32 +00:00
static void _terminate ( )
1995-03-18 17:15:15 +00:00
{
2010-01-24 17:13:03 +00:00
BOOL shouldAbort ;
2001-01-25 08:05:52 +00:00
# ifdef DEBUG
2005-07-01 08:53:32 +00:00
shouldAbort = YES ; // abort ( ) by default .
2001-01-25 08:05:52 +00:00
# else
2005-07-01 08:53:32 +00:00
shouldAbort = NO ; // exit ( ) by default .
2001-01-25 08:05:52 +00:00
# endif
2006-10-20 10:56:27 +00:00
shouldAbort = GSPrivateEnvironmentFlag ( "CRASH_ON_ABORT" , shouldAbort ) ;
2005-07-01 08:53:32 +00:00
if ( shouldAbort = = YES )
2001-01-25 08:05:52 +00:00
{
abort ( ) ;
}
else
{
exit ( 1 ) ;
}
1995-03-18 17:15:15 +00:00
}
2005-07-01 08:53:32 +00:00
static void
_NSFoundationUncaughtExceptionHandler ( NSException * exception )
{
2007-12-06 13:39:03 +00:00
CREATE_AUTORELEASE _POOL ( pool ) ;
2006-10-09 14:00:01 +00:00
fprintf ( stderr , "%s: Uncaught exception %s, reason: %s\n" ,
2006-10-20 10:56:27 +00:00
GSPrivateArgZero ( ) ,
2005-07-01 08:53:32 +00:00
[ [ exception name ] lossyCString ] , [ [ exception reason ] lossyCString ] ) ;
fflush ( stderr ) ; / * NEEDED UNDER MINGW * /
2007-12-06 09:29:22 +00:00
if ( GSPrivateEnvironmentFlag ( "GNUSTEP_STACK_TRACE" , NO ) = = YES )
2007-02-04 08:43:16 +00:00
{
2009-09-11 19:19:05 +00:00
fprintf ( stderr , "Stack\n%s\n" ,
[ [ [ exception _callStack ] description ] lossyCString ] ) ;
2007-02-04 08:43:16 +00:00
}
fflush ( stderr ) ; / * NEEDED UNDER MINGW * /
2007-12-06 13:39:03 +00:00
RELEASE ( pool ) ;
2005-07-01 08:53:32 +00:00
_terminate ( ) ;
}
2008-11-28 15:38:48 +00:00
static void
callUncaughtHandler ( id value )
{
if ( _NSUncaughtExceptionHandler ! = NULL )
{
( * _NSUncaughtExceptionHandler ) ( value ) ;
}
2010-02-08 20:24:12 +00:00
/ * The uncaught exception handler which is set has not exited ,
* so we MUST call the builtin handler , ( normal behavior of MacOS - X ) .
* The standard handler is guaranteed to exit / abort , which is the
* required behavior for OSX compatibility .
* NB Cocoa ' s Exception Handling framework might bypass this behavior
* somehow ( it ' s not clear if it does that or simply wraps various
* things with its own exception handlers thus preventing the
* uncaught handler from ever being needed ) . . . if anyone contributes
* an implementation , perhaps we could integrate it here .
* /
2010-02-08 17:52:36 +00:00
_NSFoundationUncaughtExceptionHandler ( value ) ;
2008-11-28 15:38:48 +00:00
}
1995-03-18 17:15:15 +00:00
@ implementation NSException
2007-02-06 11:47:32 +00:00
+ ( void ) initialize
{
2010-01-24 17:13:03 +00:00
# if defined ( USE_BINUTILS )
if ( modLock = = nil )
{
modLock = [ NSRecursiveLock new ] ;
}
NSLog ( @ "WARNING this copy of gnustep-base has been built with libbfd to provide symbolic stacktrace support. This means that the license of this copy of gnustep-base is GPL rather than the normal LGPL license (since libbfd is released under the GPL license). If this is not what you want, please obtain a copy of gnustep-base which was not configured with the --enable-bfd option" ) ;
# endif / * USE_BINUTILS * /
2010-12-23 02:23:05 +00:00
# if defined ( _NATIVE _OBJC _EXCEPTIONS )
# ifdef HAVE_SET _UNCAUGHT _EXCEPTION _HANDLER
objc_setUncaughtExceptionHandler ( callUncaughtHandler ) ;
# elif defined ( HAVE_UNEXPECTED )
2010-03-11 07:22:10 +00:00
_objc _unexpected _exception = callUncaughtHandler ;
2010-12-23 02:23:05 +00:00
# elif defined ( HAVE_SET _UNEXPECTED )
2008-11-28 15:38:48 +00:00
objc_set _unexpected ( callUncaughtHandler ) ;
2010-12-23 02:23:05 +00:00
# endif
2008-11-28 15:38:48 +00:00
# endif
return ;
}
2007-02-06 11:47:32 +00:00
2000-04-05 14:21:05 +00:00
+ ( NSException * ) exceptionWithName : ( NSString * ) name
reason : ( NSString * ) reason
userInfo : ( NSDictionary * ) userInfo
1995-03-18 17:15:15 +00:00
{
1999-04-21 20:16:25 +00:00
return AUTORELEASE ( [ [ self alloc ] initWithName : name reason : reason
2002-01-03 10:01:25 +00:00
userInfo : userInfo ] ) ;
1995-03-18 17:15:15 +00:00
}
2000-04-05 14:21:05 +00:00
+ ( void ) raise : ( NSString * ) name
format : ( NSString * ) format , . . .
1995-03-18 17:15:15 +00:00
{
1999-04-21 20:16:25 +00:00
va_list args ;
1995-03-18 17:15:15 +00:00
1999-04-21 20:16:25 +00:00
va_start ( args , format ) ;
[ self raise : name format : format arguments : args ] ;
2002-10-27 01:38:30 +00:00
// This probably doesn ' t matter , but va_end won ' t get called
1999-04-21 20:16:25 +00:00
va_end ( args ) ;
1995-03-18 17:15:15 +00:00
}
2000-04-05 14:21:05 +00:00
+ ( void ) raise : ( NSString * ) name
format : ( NSString * ) format
arguments : ( va_list ) argList
1995-03-18 17:15:15 +00:00
{
1999-04-21 20:16:25 +00:00
NSString * reason ;
NSException * except ;
reason = [ NSString stringWithFormat : format arguments : argList ] ;
except = [ self exceptionWithName : name reason : reason userInfo : nil ] ;
[ except raise ] ;
1995-03-18 17:15:15 +00:00
}
2010-01-24 17:13:03 +00:00
/ * For OSX compatibility - init returns nil .
* /
- ( id ) init
{
2010-02-25 18:49:31 +00:00
DESTROY ( self ) ;
2010-01-24 17:13:03 +00:00
return nil ;
}
2000-04-05 14:21:05 +00:00
- ( id ) initWithName : ( NSString * ) name
reason : ( NSString * ) reason
userInfo : ( NSDictionary * ) userInfo
1995-03-18 17:15:15 +00:00
{
1999-09-16 07:21:34 +00:00
ASSIGN ( _e _name , name ) ;
ASSIGN ( _e _reason , reason ) ;
2007-12-05 16:13:24 +00:00
if ( userInfo ! = nil )
{
2010-01-24 17:13:03 +00:00
if ( _reserved = = 0 )
{
_reserved = NSZoneCalloc ( [ self zone ] , 2 , sizeof ( id ) ) ;
}
2007-12-05 16:13:24 +00:00
ASSIGN ( _e _info , userInfo ) ;
}
1999-04-21 20:16:25 +00:00
return self ;
1995-03-18 17:15:15 +00:00
}
2010-01-24 06:53:49 +00:00
2007-12-05 16:13:24 +00:00
- ( NSArray * ) callStackReturnAddresses
{
2010-01-24 17:13:03 +00:00
if ( _reserved = = 0 )
{
return nil ;
}
2009-09-11 16:14:45 +00:00
return [ _e _stack addresses ] ;
}
2010-01-24 17:13:03 +00:00
2009-09-11 19:19:05 +00:00
- ( NSArray * ) callStackSymbols
2009-09-11 16:14:45 +00:00
{
2010-01-24 17:13:03 +00:00
if ( _reserved = = 0 )
{
return nil ;
}
2009-09-11 19:19:05 +00:00
return [ _e _stack symbols ] ;
2009-09-11 16:14:45 +00:00
}
2007-12-05 16:13:24 +00:00
2000-04-05 14:21:05 +00:00
- ( void ) dealloc
1997-09-13 17:52:31 +00:00
{
1999-09-16 07:21:34 +00:00
DESTROY ( _e _name ) ;
DESTROY ( _e _reason ) ;
2007-12-05 16:13:24 +00:00
if ( _reserved ! = 0 )
{
DESTROY ( _e _info ) ;
DESTROY ( _e _stack ) ;
NSZoneFree ( [ self zone ] , _reserved ) ;
_reserved = 0 ;
}
1997-09-13 17:52:31 +00:00
[ super dealloc ] ;
}
2010-03-14 05:37:49 +00:00
- ( NSString * ) description
{
CREATE_AUTORELEASE _POOL ( pool ) ;
NSString * result ;
if ( _e _name = = nil )
{
[ NSException raise : NSInvalidArgumentException
format : @ "Atttempt to use uninitialised NSException" ] ;
}
if ( _reserved ! = 0 )
{
if ( _e _stack ! = nil
&& GSPrivateEnvironmentFlag ( "GNUSTEP_STACK_TRACE" , NO ) = = YES )
{
if ( _e _info ! = nil )
{
result = [ NSString stringWithFormat :
@ "%@ NAME:%@ REASON:%@ INFO:%@ STACK:%@" ,
[ super description ] , _e _name , _e _reason , _e _info , _e _stack ] ;
}
else
{
result = [ NSString stringWithFormat :
@ "%@ NAME:%@ REASON:%@ STACK:%@" ,
[ super description ] , _e _name , _e _reason , _e _stack ] ;
}
}
else
{
result = [ NSString stringWithFormat :
@ "%@ NAME:%@ REASON:%@ INFO:%@" ,
[ super description ] , _e _name , _e _reason , _e _info ] ;
}
}
else
{
result = [ NSString stringWithFormat : @ "%@ NAME:%@ REASON:%@" ,
[ super description ] , _e _name , _e _reason ] ;
}
IF_NO _GC ( [ result retain ] ; )
IF_NO _GC ( DESTROY ( pool ) ; )
return AUTORELEASE ( result ) ;
}
2000-04-05 14:21:05 +00:00
- ( void ) raise
1995-03-18 17:15:15 +00:00
{
2007-12-05 16:13:24 +00:00
if ( _reserved = = 0 )
{
_reserved = NSZoneCalloc ( [ self zone ] , 2 , sizeof ( id ) ) ;
}
2010-01-24 17:13:03 +00:00
_e _stack = [ GSStackTrace new ] ;
2008-10-29 06:19:17 +00:00
2010-03-08 12:07:11 +00:00
# if defined ( _NATIVE _OBJC _EXCEPTIONS )
2006-05-08 15:30:52 +00:00
@ throw self ;
# else
2010-03-08 12:07:11 +00:00
{
NSThread * thread ;
NSHandler * handler ;
2010-02-24 10:23:47 +00:00
thread = GSCurrentThread ( ) ;
1999-04-21 20:16:25 +00:00
handler = thread -> _exception _handler ;
2011-02-10 10:52:54 +00:00
if ( NULL = = handler )
1999-04-21 20:16:25 +00:00
{
2007-05-15 12:53:33 +00:00
static int recursion = 0 ;
2005-07-01 08:53:32 +00:00
/ *
2007-05-15 12:53:33 +00:00
* Set / check a counter to prevent recursive uncaught exceptions .
* Allow a little recursion in case we have different handlers
* being tried .
2005-07-01 08:53:32 +00:00
* /
2007-05-15 12:53:33 +00:00
if ( recursion + + > 3 )
2005-07-01 08:53:32 +00:00
{
fprintf ( stderr ,
"recursion encountered handling uncaught exception\n" ) ;
fflush ( stderr ) ; / * NEEDED UNDER MINGW * /
_terminate ( ) ;
}
/ *
* Call the uncaught exception handler ( if there is one ) .
2010-02-08 20:24:12 +00:00
* The calls the built - in default handler to terminate the program !
2005-07-01 08:53:32 +00:00
* /
2008-11-28 15:38:48 +00:00
callUncaughtHandler ( self ) ;
1999-04-21 20:16:25 +00:00
}
2011-02-10 10:52:54 +00:00
else
{
thread -> _exception _handler = handler -> next ;
handler -> exception = self ;
longjmp ( handler -> jumpState , 1 ) ;
}
2010-03-08 12:07:11 +00:00
}
2006-04-26 14:15:03 +00:00
# endif
1995-03-18 17:15:15 +00:00
}
2000-04-05 14:21:05 +00:00
- ( NSString * ) name
1995-03-18 17:15:15 +00:00
{
2000-09-07 16:53:14 +00:00
if ( _e _name ! = nil )
{
return _e _name ;
}
else
{
return NSStringFromClass ( [ self class ] ) ;
}
1995-03-18 17:15:15 +00:00
}
2000-04-05 14:21:05 +00:00
- ( NSString * ) reason
1995-03-18 17:15:15 +00:00
{
2000-09-07 16:53:14 +00:00
if ( _e _reason ! = nil )
{
return _e _reason ;
}
else
{
return @ "unspecified reason" ;
}
1995-03-18 17:15:15 +00:00
}
2000-04-05 14:21:05 +00:00
- ( NSDictionary * ) userInfo
1995-03-18 17:15:15 +00:00
{
2007-12-05 16:13:24 +00:00
if ( _reserved = = 0 )
{
return nil ;
}
1999-09-16 07:21:34 +00:00
return _e _info ;
1995-03-18 17:15:15 +00:00
}
1998-10-17 18:56:49 +00:00
- ( Class ) classForPortCoder
{
return [ self class ] ;
}
1999-04-21 20:16:25 +00:00
- ( id ) replacementObjectForPortCoder : ( NSPortCoder * ) aCoder
1998-10-17 18:56:49 +00:00
{
1999-04-21 20:16:25 +00:00
return self ;
1998-10-17 18:56:49 +00:00
}
1995-03-18 17:15:15 +00:00
1999-04-21 20:16:25 +00:00
- ( void ) encodeWithCoder : ( NSCoder * ) aCoder
1995-03-18 17:15:15 +00:00
{
2007-12-05 16:13:24 +00:00
id info = ( _reserved = = 0 ) ? nil : _e _info ;
1999-09-16 07:21:34 +00:00
[ aCoder encodeValueOfObjCType : @ encode ( id ) at : & _e _name ] ;
[ aCoder encodeValueOfObjCType : @ encode ( id ) at : & _e _reason ] ;
2007-12-05 16:13:24 +00:00
[ aCoder encodeValueOfObjCType : @ encode ( id ) at : & info ] ;
1995-03-18 17:15:15 +00:00
}
1999-04-21 20:16:25 +00:00
- ( id ) initWithCoder : ( NSCoder * ) aDecoder
1995-03-18 17:15:15 +00:00
{
2007-12-05 16:13:24 +00:00
id info ;
1999-09-16 07:21:34 +00:00
[ aDecoder decodeValueOfObjCType : @ encode ( id ) at : & _e _name ] ;
[ aDecoder decodeValueOfObjCType : @ encode ( id ) at : & _e _reason ] ;
2007-12-05 16:13:24 +00:00
[ aDecoder decodeValueOfObjCType : @ encode ( id ) at : & info ] ;
if ( info ! = nil )
{
if ( _reserved = = 0 )
{
_reserved = NSZoneCalloc ( [ self zone ] , 2 , sizeof ( id ) ) ;
}
_e _info = info ;
}
1999-04-21 20:16:25 +00:00
return self ;
1995-03-18 17:15:15 +00:00
}
2000-04-05 14:21:05 +00:00
- ( id ) copyWithZone : ( NSZone * ) zone
1995-03-18 17:15:15 +00:00
{
1999-04-21 20:16:25 +00:00
if ( NSShouldRetainWithZone ( self , zone ) )
2007-12-05 16:13:24 +00:00
{
return RETAIN ( self ) ;
}
1999-04-21 20:16:25 +00:00
else
2007-12-05 16:13:24 +00:00
{
return [ [ [ self class ] alloc ] initWithName : [ self name ]
reason : [ self reason ]
userInfo : [ self userInfo ] ] ;
}
1995-03-18 17:15:15 +00:00
}
@ end
2010-01-24 17:13:03 +00:00
@ implementation NSException ( GSPrivate )
- ( GSStackTrace * ) _callStack
{
if ( _reserved = = 0 )
{
return nil ;
}
return _e _stack ;
}
@ end
1995-03-18 17:15:15 +00:00
1999-04-21 20:16:25 +00:00
void
2000-04-05 14:21:05 +00:00
_NSAddHandler ( NSHandler * handler )
1995-03-18 17:15:15 +00:00
{
2010-02-24 10:23:47 +00:00
NSThread * thread ;
1995-03-18 17:15:15 +00:00
2010-02-24 10:23:47 +00:00
thread = GSCurrentThread ( ) ;
2010-03-19 12:10:11 +00:00
# if defined ( __MINGW __ ) && defined ( DEBUG )
2005-10-23 15:11:19 +00:00
if ( thread -> _exception _handler
&& IsBadReadPtr ( thread -> _exception _handler , sizeof ( NSHandler ) ) )
{
2005-10-23 21:30:24 +00:00
fprintf ( stderr , "ERROR: Current exception handler is bogus.\n" ) ;
2005-10-23 15:11:19 +00:00
}
# endif
1999-04-19 14:29:52 +00:00
handler -> next = thread -> _exception _handler ;
thread -> _exception _handler = handler ;
1995-03-18 17:15:15 +00:00
}
1999-04-21 20:16:25 +00:00
void
2000-04-05 14:21:05 +00:00
_NSRemoveHandler ( NSHandler * handler )
1995-03-18 17:15:15 +00:00
{
2010-02-24 10:23:47 +00:00
NSThread * thread ;
1995-03-18 17:15:15 +00:00
2010-02-24 10:23:47 +00:00
thread = GSCurrentThread ( ) ;
2005-10-23 15:11:19 +00:00
# if defined ( DEBUG )
if ( thread -> _exception _handler ! = handler )
{
2005-10-23 15:14:35 +00:00
fprintf ( stderr , "ERROR: Removing exception handler that is not on top "
2005-10-23 21:30:24 +00:00
"of the stack. (You probably called return in an NS_DURING block.)\n" ) ;
2005-10-23 15:11:19 +00:00
}
2010-03-19 12:10:11 +00:00
# if defined ( __MINGW __ )
2005-10-23 15:11:19 +00:00
if ( IsBadReadPtr ( handler , sizeof ( NSHandler ) ) )
{
2005-10-23 15:14:35 +00:00
fprintf ( stderr , "ERROR: Could not remove exception handler, "
2005-10-23 21:30:24 +00:00
"handler is bad pointer.\n" ) ;
2005-10-23 15:11:19 +00:00
thread -> _exception _handler = 0 ;
return ;
}
if ( handler -> next && IsBadReadPtr ( handler -> next , sizeof ( NSHandler ) ) )
{
2005-10-23 15:14:35 +00:00
fprintf ( stderr , "ERROR: Could not restore exception handler, "
2005-10-23 21:30:24 +00:00
"handler->next is bad pointer.\n" ) ;
2005-10-23 15:11:19 +00:00
thread -> _exception _handler = 0 ;
return ;
}
# endif
# endif
thread -> _exception _handler = handler -> next ;
1997-03-03 19:51:04 +00:00
}
2008-06-23 07:15:10 +00:00
NSUncaughtExceptionHandler *
NSGetUncaughtExceptionHandler ( )
{
return _NSUncaughtExceptionHandler ;
}
void
NSSetUncaughtExceptionHandler ( NSUncaughtExceptionHandler * handler )
{
_NSUncaughtExceptionHandler = handler ;
}