1/** NSException - Object encapsulation of a general exception handler 2 Copyright (C) 1993-2013 Free Software Foundation, Inc. 3 4 Written by: Adam Fedor <fedor@boulder.colorado.edu> 5 Date: Mar 1995 6 7 This file is part of the GNUstep Base Library. 8 9 This library is free software; you can redistribute it and/or 10 modify it under the terms of the GNU Lesser General Public 11 License as published by the Free Software Foundation; either 12 version 2 of the License, or (at your option) any later version. 13 14 This library is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 Lesser General Public License for more details. 18 19 You should have received a copy of the GNU Lesser General Public 20 License along with this library; if not, write to the Free 21 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 Boston, MA 02110 USA. 23 24 $Date$ $Revision$ 25*/ 26 27#import "common.h" 28#define EXPOSE_NSException_IVARS 1 29#define EXPOSE_NSThread_IVARS 1 30#import "GSPrivate.h" 31#import "Foundation/NSEnumerator.h" 32#import "Foundation/NSException.h" 33#import "Foundation/NSArray.h" 34#import "Foundation/NSCoder.h" 35#import "Foundation/NSData.h" 36#import "Foundation/NSLock.h" 37#import "Foundation/NSNull.h" 38#import "Foundation/NSThread.h" 39#import "Foundation/NSLock.h" 40#import "Foundation/NSDictionary.h" 41#import "Foundation/NSValue.h" 42#import "GNUstepBase/NSString+GNUstepBase.h" 43 44#import "GSPThread.h" 45 46#ifdef __GNUSTEP_RUNTIME__ 47#include <objc/hooks.h> 48#endif 49 50#ifdef HAVE_SET_UNCAUGHT_EXCEPTION_HANDLER 51#include <objc/objc-exception.h> 52#endif 53 54#ifdef HAVE_MALLOC_H 55#if !defined(__OpenBSD__) 56#include <malloc.h> 57#endif 58#endif 59#ifdef HAVE_ALLOCA_H 60#include <alloca.h> 61#endif 62 63#include <stdio.h> 64 65#ifdef HAVE_BACKTRACE 66#include <execinfo.h> 67#endif 68 69/* 70 * Turn off USE_BFD if we don't have bfd support for it. 71 */ 72#if !(defined(HAVE_BFD_H) && defined(HAVE_LIBBFD) && defined(HAVE_LIBIBERTY)) 73# if defined(USE_BFD) 74# undef USE_BFD 75# endif 76#endif 77 78#if defined(_WIN32) && !defined(USE_BFD) 79#include <windows.h> 80#if defined(HAVE_DBGHELP_H) 81#include <dbghelp.h> 82#else 83/* Supply the relevant bits from dbghelp.h if we could't find the header. 84 */ 85#define SYMOPT_UNDNAME 0x00000002 86#define SYMOPT_DEFERRED_LOADS 0x00000004 87typedef struct _SYMBOL_INFO { 88 ULONG SizeOfStruct; 89 ULONG TypeIndex; 90 uint64_t Reserved[2]; 91 ULONG Index; 92 ULONG Size; 93 uint64_t ModBase; 94 ULONG Flags; 95 uint64_t Value; 96 uint64_t Address; 97 ULONG Register; 98 ULONG Scope; 99 ULONG Tag; 100 ULONG NameLen; 101 ULONG MaxNameLen; 102 TCHAR Name[1]; 103} SYMBOL_INFO; 104#endif 105#endif 106 107static NSUncaughtExceptionHandler *_NSUncaughtExceptionHandler = 0; 108 109#define _e_info (((id*)_reserved)[0]) 110#define _e_stack (((id*)_reserved)[1]) 111 112 113@interface NSException (GSPrivate) 114- (GSStackTrace*) _callStack; 115@end 116 117 118#if defined(_WIN32) 119#if defined(USE_BFD) 120static NSString * 121GSPrivateBaseAddress(void *addr, void **base) 122{ 123 MEMORY_BASIC_INFORMATION info; 124 125 /* Found a note saying that according to Matt Pietrek's "Under the Hood" 126 * column for the April 1997 issue of Microsoft Systems Journal, the 127 * allocation base returned by VirtualQuery can be used as the handle 128 * to obtain module information for a loaded library. 129 */ 130 if (VirtualQuery (addr, &info, sizeof(info)) != 0) 131 { 132 HMODULE handle = (HMODULE) info.AllocationBase; 133 unichar path[MAX_PATH+1]; 134 135 if (GetModuleFileNameW(handle, path, sizeof(path)-1) != 0) 136 { 137 path[sizeof(path)-1] = '\0'; 138 139 *base = info.BaseAddress; 140 return [NSString stringWithCharacters: path length: wcslen(path)]; 141 } 142 } 143 return nil; 144} 145#endif /* USE_BFD */ 146#else /* _WIN32 */ 147 148#include <dlfcn.h> 149 150#if defined(USE_BFD) 151static NSString * 152GSPrivateBaseAddress(void *addr, void **base) 153{ 154#ifdef HAVE_DLADDR 155 Dl_info info; 156 157 if (!dladdr(addr, &info)) 158 return nil; 159 160 *base = info.dli_fbase; 161 162 return [NSString stringWithUTF8String: info.dli_fname]; 163#else 164 return nil; 165#endif 166} 167#endif /* USE_BFD */ 168#endif /* _WIN32 */ 169 170#if defined(USE_BFD) 171 172// GSStackTrace inspired by FYStackTrace.m 173// created by Wim Oudshoorn on Mon 11-Apr-2006 174// reworked by Lloyd Dupont @ NovaMind.com on 4-May-2006 175 176#include <bfd.h> 177 178@class GSBinaryFileInfo; 179 180@interface GSFunctionInfo : NSObject 181{ 182 void *_address; 183 NSString *_fileName; 184 NSString *_functionName; 185 int _lineNo; 186 GSBinaryFileInfo *_module; 187} 188- (void*) address; 189- (NSString *) fileName; 190- (NSString *) function; 191- (id) initWithModule: (GSBinaryFileInfo*)module 192 address: (void*)address 193 file: (NSString*)file 194 function: (NSString*)function 195 line: (int)lineNo; 196- (int) lineNumber; 197- (GSBinaryFileInfo*) module; 198 199@end 200 201 202@interface GSBinaryFileInfo : NSObject 203{ 204 NSString *_fileName; 205 bfd *_abfd; 206 asymbol **_symbols; 207 long _symbolCount; 208} 209- (NSString *) fileName; 210- (GSFunctionInfo *) functionForAddress: (void*) address; 211- (id) initWithBinaryFile: (NSString *)fileName; 212- (id) init; // return info for the current executing process 213 214@end 215 216 217 218@implementation GSFunctionInfo 219 220- (void*) address 221{ 222 return _address; 223} 224 225- (oneway void) dealloc 226{ 227 DESTROY(_module); 228 DESTROY(_fileName); 229 DESTROY(_functionName); 230 [super dealloc]; 231} 232 233- (NSString *) description 234{ 235 return [NSString stringWithFormat: @"(%@: %p) %@ %@: %d", 236 [_module fileName], _address, _functionName, _fileName, _lineNo]; 237} 238 239- (NSString *) fileName 240{ 241 return _fileName; 242} 243 244- (NSString *) function 245{ 246 return _functionName; 247} 248 249- (id) init 250{ 251 DESTROY(self); 252 return nil; 253} 254 255- (id) initWithModule: (GSBinaryFileInfo*)module 256 address: (void*)address 257 file: (NSString*)file 258 function: (NSString*)function 259 line: (int)lineNo 260{ 261 _module = RETAIN(module); 262 _address = address; 263 _fileName = [file copy]; 264 _functionName = [function copy]; 265 _lineNo = lineNo; 266 267 return self; 268} 269 270- (int) lineNumber 271{ 272 return _lineNo; 273} 274 275- (GSBinaryFileInfo *) module 276{ 277 return _module; 278} 279 280@end 281 282 283 284@implementation GSBinaryFileInfo 285 286+ (GSBinaryFileInfo*) infoWithBinaryFile: (NSString *)fileName 287{ 288 return [[[self alloc] initWithBinaryFile: fileName] autorelease]; 289} 290 291+ (void) initialize 292{ 293 static BOOL first = YES; 294 295 if (first == NO) 296 { 297 return; 298 } 299 first = NO; 300 bfd_init (); 301} 302 303- (oneway void) dealloc 304{ 305 DESTROY(_fileName); 306 if (_abfd) 307 { 308 bfd_close (_abfd); 309 _abfd = NULL; 310 } 311 if (_symbols) 312 { 313 free(_symbols); 314 _symbols = NULL; 315 } 316 [super dealloc]; 317} 318 319- (NSString *) fileName 320{ 321 return _fileName; 322} 323 324- (id) init 325{ 326 NSString *processName; 327 328 processName = [[[NSProcessInfo processInfo] arguments] objectAtIndex: 0]; 329 return [self initWithBinaryFile: processName]; 330} 331 332- (id) initWithBinaryFile: (NSString *)fileName 333{ 334 int neededSpace; 335 336 // 1st initialize the bfd 337 if ([fileName length] == 0) 338 { 339 //NSLog (@"GSBinaryFileInfo: No File"); 340 DESTROY(self); 341 return nil; 342 } 343 _fileName = [fileName copy]; 344 _abfd = bfd_openr ([fileName cString], NULL); 345 if (!_abfd) 346 { 347 //NSLog (@"GSBinaryFileInfo: No Binary Info"); 348 DESTROY(self); 349 return nil; 350 } 351 if (!bfd_check_format_matches (_abfd, bfd_object, NULL)) 352 { 353 //NSLog (@"GSBinaryFileInfo: BFD format object error"); 354 DESTROY(self); 355 return nil; 356 } 357 358 // second read the symbols from it 359 if (!(bfd_get_file_flags (_abfd) & HAS_SYMS)) 360 { 361 //NSLog (@"GSBinaryFileInfo: BFD does not contain any symbols"); 362 DESTROY(self); 363 return nil; 364 } 365 366 neededSpace = bfd_get_symtab_upper_bound (_abfd); 367 if (neededSpace < 0) 368 { 369 //NSLog (@"GSBinaryFileInfo: BFD error while deducing needed space"); 370 DESTROY(self); 371 return nil; 372 } 373 if (neededSpace == 0) 374 { 375 //NSLog (@"GSBinaryFileInfo: BFD no space for symbols needed"); 376 DESTROY(self); 377 return nil; 378 } 379 _symbols = malloc (neededSpace); 380 if (!_symbols) 381 { 382 //NSLog (@"GSBinaryFileInfo: Can't allocate buffer"); 383 DESTROY(self); 384 return nil; 385 } 386 _symbolCount = bfd_canonicalize_symtab (_abfd, _symbols); 387 if (_symbolCount < 0) 388 { 389 //NSLog (@"GSBinaryFileInfo: BFD error while reading symbols"); 390 DESTROY(self); 391 return nil; 392 } 393 394 return self; 395} 396 397struct SearchAddressStruct 398{ 399 void *theAddress; 400 GSBinaryFileInfo *module; 401 asymbol **symbols; 402 GSFunctionInfo *theInfo; 403}; 404 405static void find_address (bfd *abfd, asection *section, 406 struct SearchAddressStruct *info) 407{ 408 bfd_vma address; 409 bfd_vma vma; 410 unsigned size; 411 const char *fileName = 0; 412 const char *functionName = 0; 413 unsigned line = 0; 414 415 if (info->theInfo) 416 { 417 return; 418 } 419 if (!(bfd_get_section_flags (abfd, section) & SEC_ALLOC)) 420 { 421 return; // Only debug in this section 422 } 423 if (bfd_get_section_flags (abfd, section) & SEC_DATA) 424 { 425 return; // Only data in this section 426 } 427 428 address = (bfd_vma) (uintptr_t)info->theAddress; 429 430 vma = bfd_get_section_vma (abfd, section); 431 432#if defined(bfd_get_section_size_before_reloc) 433 size = bfd_get_section_size_before_reloc (section); // recent 434#elif defined(bfd_get_section_size) 435 size = bfd_get_section_size (section); // less recent 436#else 437 size = bfd_section_size (abfd, section); // older version 438#endif 439 440 if (address < vma || address >= vma + size) 441 { 442 return; 443 } 444 445 446 if (bfd_find_nearest_line (abfd, section, info->symbols, 447 address - vma, &fileName, &functionName, &line)) 448 { 449 GSFunctionInfo *fi; 450 NSString *file = nil; 451 NSString *func = nil; 452 453 if (fileName != 0) 454 { 455 file = [NSString stringWithCString: fileName 456 encoding: [NSString defaultCStringEncoding]]; 457 } 458 if (functionName != 0) 459 { 460 func = [NSString stringWithCString: functionName 461 encoding: [NSString defaultCStringEncoding]]; 462 } 463 fi = [GSFunctionInfo alloc]; 464 fi = [fi initWithModule: info->module 465 address: info->theAddress 466 file: file 467 function: func 468 line: line]; 469 [fi autorelease]; 470 info->theInfo = fi; 471 } 472} 473 474- (GSFunctionInfo *) functionForAddress: (void*) address 475{ 476 struct SearchAddressStruct searchInfo = 477 { address, self, _symbols, nil }; 478 479 bfd_map_over_sections (_abfd, 480 (void (*) (bfd *, asection *, void *)) find_address, &searchInfo); 481 return searchInfo.theInfo; 482} 483 484@end 485 486static pthread_mutex_t modLock; 487static NSMutableDictionary *stackModules = nil; 488 489// initialize stack trace info 490static id 491GSLoadModule(NSString *fileName) 492{ 493 GSBinaryFileInfo *module = nil; 494 495 (void)pthread_mutex_lock(&modLock); 496 497 if (stackModules == nil) 498 { 499 NSEnumerator *enumerator; 500 NSBundle *bundle; 501 502 stackModules = [NSMutableDictionary new]; 503 504 /* 505 * Try to ensure we have the main, base and gui library bundles. 506 */ 507 [NSBundle mainBundle]; 508 [NSBundle bundleForClass: [NSObject class]]; 509 [NSBundle bundleForClass: NSClassFromString(@"NSView")]; 510 511 /* 512 * Add file info for all bundles with code. 513 */ 514 enumerator = [[NSBundle allBundles] objectEnumerator]; 515 while ((bundle = [enumerator nextObject]) != nil) 516 { 517 if ([bundle load] == YES) 518 { 519 GSLoadModule([bundle executablePath]); 520 } 521 } 522 } 523 524 if ([fileName length] > 0) 525 { 526 module = [stackModules objectForKey: fileName]; 527 if (module == nil) 528 { 529 module = [GSBinaryFileInfo infoWithBinaryFile: fileName]; 530 if (module == nil) 531 { 532 module = (id)[NSNull null]; 533 } 534 if ([stackModules objectForKey: fileName] == nil) 535 { 536 [stackModules setObject: module forKey: fileName]; 537 } 538 else 539 { 540 module = [stackModules objectForKey: fileName]; 541 } 542 } 543 } 544 (void)pthread_mutex_unlock(&modLock); 545 546 if (module == (id)[NSNull null]) 547 { 548 module = nil; 549 } 550 return module; 551} 552 553static NSArray* 554GSListModules() 555{ 556 NSArray *result; 557 558 GSLoadModule(nil); // initialise 559 (void)pthread_mutex_lock(&modLock); 560 result = [stackModules allValues]; 561 (void)pthread_mutex_unlock(&modLock); 562 return result; 563} 564 565#endif /* USE_BFD */ 566 567 568#if defined(HAVE_UNWIND_H) && !defined(HAVE_BACKTRACE) 569 570#include <unwind.h> 571#if !defined(_WIN32) 572#include <dlfcn.h> 573#endif 574 575struct GSBacktraceState 576{ 577 void **current; 578 void **end; 579}; 580 581static _Unwind_Reason_Code 582GSUnwindCallback(struct _Unwind_Context* context, void* arg) 583{ 584 struct GSBacktraceState *state = (struct GSBacktraceState*)arg; 585 uintptr_t pc = _Unwind_GetIP(context); 586 if (pc) { 587 if (state->current == state->end) { 588 return _URC_END_OF_STACK; 589 } else { 590 *state->current++ = (void*)pc; 591 } 592 } 593 return 0; //_URC_OK/_URC_NO_REASON 594} 595 596#endif /* HAVE_UNWIND_H && !HAVE_BACKTRACE */ 597 598 599#if defined(_WIN32) && !defined(USE_BFD) 600typedef USHORT (WINAPI *CaptureStackBackTraceType)(ULONG,ULONG,PVOID*,PULONG); 601typedef BOOL (WINAPI *SymInitializeType)(HANDLE,char*,BOOL); 602typedef DWORD (WINAPI *SymSetOptionsType)(DWORD); 603typedef BOOL (WINAPI *SymFromAddrType)(HANDLE,DWORD64,PDWORD64,SYMBOL_INFO*); 604 605static CaptureStackBackTraceType capture = 0; 606static SymInitializeType initSym = 0; 607static SymSetOptionsType optSym = 0; 608static SymFromAddrType fromSym = 0; 609static HANDLE hProcess = 0; 610static pthread_mutex_t traceLock; 611#define MAXFRAMES 62 /* Limitation of windows-xp */ 612#else 613#define MAXFRAMES 128 /* 1KB buffer on 64bit machine */ 614#endif 615 616 617#if !defined(HAVE_BUILTIN_EXTRACT_RETURN_ADDRESS) 618# define __builtin_extract_return_address(X) X 619#endif 620 621#define _NS_FRAME_HACK(a) \ 622case a: env->addr = __builtin_frame_address(a + 1); break; 623#define _NS_RETURN_HACK(a) \ 624case a: env->addr = (__builtin_frame_address(a + 1) ? \ 625__builtin_extract_return_address(__builtin_return_address(a + 1)) : 0); break; 626 627/* 628 * The following horrible signal handling code is a workaround for the fact 629 * that the __builtin_frame_address() and __builtin_return_address() 630 * functions are not reliable (at least not on my EM64T based system) and 631 * will sometimes walk off the stack and access illegal memory locations. 632 * In order to prevent such an occurrance from crashing the application, 633 * we use sigsetjmp() and siglongjmp() to ensure that we can recover, and 634 * we keep the jump buffer in thread-local memory to avoid possible thread 635 * safety issues. 636 * Of course this will fail horribly if an exception occurs in one of the 637 * few methods we use to manage the per-thread jump buffer. 638 */ 639#if defined(HAVE_SYS_SIGNAL_H) 640# include <sys/signal.h> 641#elif defined(HAVE_SIGNAL_H) 642# include <signal.h> 643#endif 644 645#if defined(_WIN32) 646#ifndef SIGBUS 647#define SIGBUS SIGILL 648#endif 649#endif 650 651/* sigsetjmp may be a function or a macro. The test for the function is 652 * done at configure time so we can tell here if either is available. 653 */ 654#if !defined(HAVE_SIGSETJMP) && !defined(sigsetjmp) 655#define siglongjmp(A,B) longjmp(A,B) 656#define sigsetjmp(A,B) setjmp(A) 657#define sigjmp_buf jmp_buf 658#endif 659 660typedef struct { 661 sigjmp_buf buf; 662 void *addr; 663 void (*bus)(int); 664 void (*segv)(int); 665} jbuf_type; 666 667static jbuf_type * 668jbuf() 669{ 670 NSMutableData *d; 671 NSMutableDictionary *dict; 672 673 dict = [[NSThread currentThread] threadDictionary]; 674 d = [dict objectForKey: @"GSjbuf"]; 675 if (d == nil) 676 { 677 d = [[NSMutableData alloc] initWithLength: sizeof(jbuf_type)]; 678 [dict setObject: d forKey: @"GSjbuf"]; 679 RELEASE(d); 680 } 681 return (jbuf_type*)[d mutableBytes]; 682} 683 684static void 685recover(int sig) 686{ 687 siglongjmp(jbuf()->buf, 1); 688} 689 690void * 691NSFrameAddress(NSUInteger offset) 692{ 693 jbuf_type *env; 694 695 env = jbuf(); 696 if (sigsetjmp(env->buf, 1) == 0) 697 { 698 env->segv = signal(SIGSEGV, recover); 699 env->bus = signal(SIGBUS, recover); 700 switch (offset) 701 { 702 _NS_FRAME_HACK(0); _NS_FRAME_HACK(1); _NS_FRAME_HACK(2); 703 _NS_FRAME_HACK(3); _NS_FRAME_HACK(4); _NS_FRAME_HACK(5); 704 _NS_FRAME_HACK(6); _NS_FRAME_HACK(7); _NS_FRAME_HACK(8); 705 _NS_FRAME_HACK(9); _NS_FRAME_HACK(10); _NS_FRAME_HACK(11); 706 _NS_FRAME_HACK(12); _NS_FRAME_HACK(13); _NS_FRAME_HACK(14); 707 _NS_FRAME_HACK(15); _NS_FRAME_HACK(16); _NS_FRAME_HACK(17); 708 _NS_FRAME_HACK(18); _NS_FRAME_HACK(19); _NS_FRAME_HACK(20); 709 _NS_FRAME_HACK(21); _NS_FRAME_HACK(22); _NS_FRAME_HACK(23); 710 _NS_FRAME_HACK(24); _NS_FRAME_HACK(25); _NS_FRAME_HACK(26); 711 _NS_FRAME_HACK(27); _NS_FRAME_HACK(28); _NS_FRAME_HACK(29); 712 _NS_FRAME_HACK(30); _NS_FRAME_HACK(31); _NS_FRAME_HACK(32); 713 _NS_FRAME_HACK(33); _NS_FRAME_HACK(34); _NS_FRAME_HACK(35); 714 _NS_FRAME_HACK(36); _NS_FRAME_HACK(37); _NS_FRAME_HACK(38); 715 _NS_FRAME_HACK(39); _NS_FRAME_HACK(40); _NS_FRAME_HACK(41); 716 _NS_FRAME_HACK(42); _NS_FRAME_HACK(43); _NS_FRAME_HACK(44); 717 _NS_FRAME_HACK(45); _NS_FRAME_HACK(46); _NS_FRAME_HACK(47); 718 _NS_FRAME_HACK(48); _NS_FRAME_HACK(49); _NS_FRAME_HACK(50); 719 _NS_FRAME_HACK(51); _NS_FRAME_HACK(52); _NS_FRAME_HACK(53); 720 _NS_FRAME_HACK(54); _NS_FRAME_HACK(55); _NS_FRAME_HACK(56); 721 _NS_FRAME_HACK(57); _NS_FRAME_HACK(58); _NS_FRAME_HACK(59); 722 _NS_FRAME_HACK(60); _NS_FRAME_HACK(61); _NS_FRAME_HACK(62); 723 _NS_FRAME_HACK(63); _NS_FRAME_HACK(64); _NS_FRAME_HACK(65); 724 _NS_FRAME_HACK(66); _NS_FRAME_HACK(67); _NS_FRAME_HACK(68); 725 _NS_FRAME_HACK(69); _NS_FRAME_HACK(70); _NS_FRAME_HACK(71); 726 _NS_FRAME_HACK(72); _NS_FRAME_HACK(73); _NS_FRAME_HACK(74); 727 _NS_FRAME_HACK(75); _NS_FRAME_HACK(76); _NS_FRAME_HACK(77); 728 _NS_FRAME_HACK(78); _NS_FRAME_HACK(79); _NS_FRAME_HACK(80); 729 _NS_FRAME_HACK(81); _NS_FRAME_HACK(82); _NS_FRAME_HACK(83); 730 _NS_FRAME_HACK(84); _NS_FRAME_HACK(85); _NS_FRAME_HACK(86); 731 _NS_FRAME_HACK(87); _NS_FRAME_HACK(88); _NS_FRAME_HACK(89); 732 _NS_FRAME_HACK(90); _NS_FRAME_HACK(91); _NS_FRAME_HACK(92); 733 _NS_FRAME_HACK(93); _NS_FRAME_HACK(94); _NS_FRAME_HACK(95); 734 _NS_FRAME_HACK(96); _NS_FRAME_HACK(97); _NS_FRAME_HACK(98); 735 _NS_FRAME_HACK(99); 736 default: env->addr = NULL; break; 737 } 738 signal(SIGSEGV, env->segv); 739 signal(SIGBUS, env->bus); 740 } 741 else 742 { 743 env = jbuf(); 744 signal(SIGSEGV, env->segv); 745 signal(SIGBUS, env->bus); 746 env->addr = NULL; 747 } 748 return env->addr; 749} 750 751NSUInteger NSCountFrames(void) 752{ 753 jbuf_type *env; 754 755 env = jbuf(); 756 if (sigsetjmp(env->buf, 1) == 0) 757 { 758 env->segv = signal(SIGSEGV, recover); 759 env->bus = signal(SIGBUS, recover); 760 env->addr = 0; 761 762#define _NS_COUNT_HACK(X) if (__builtin_frame_address(X + 1) == 0) \ 763 goto done; else env->addr = (void*)(X + 1); 764 765 _NS_COUNT_HACK(0); _NS_COUNT_HACK(1); _NS_COUNT_HACK(2); 766 _NS_COUNT_HACK(3); _NS_COUNT_HACK(4); _NS_COUNT_HACK(5); 767 _NS_COUNT_HACK(6); _NS_COUNT_HACK(7); _NS_COUNT_HACK(8); 768 _NS_COUNT_HACK(9); _NS_COUNT_HACK(10); _NS_COUNT_HACK(11); 769 _NS_COUNT_HACK(12); _NS_COUNT_HACK(13); _NS_COUNT_HACK(14); 770 _NS_COUNT_HACK(15); _NS_COUNT_HACK(16); _NS_COUNT_HACK(17); 771 _NS_COUNT_HACK(18); _NS_COUNT_HACK(19); _NS_COUNT_HACK(20); 772 _NS_COUNT_HACK(21); _NS_COUNT_HACK(22); _NS_COUNT_HACK(23); 773 _NS_COUNT_HACK(24); _NS_COUNT_HACK(25); _NS_COUNT_HACK(26); 774 _NS_COUNT_HACK(27); _NS_COUNT_HACK(28); _NS_COUNT_HACK(29); 775 _NS_COUNT_HACK(30); _NS_COUNT_HACK(31); _NS_COUNT_HACK(32); 776 _NS_COUNT_HACK(33); _NS_COUNT_HACK(34); _NS_COUNT_HACK(35); 777 _NS_COUNT_HACK(36); _NS_COUNT_HACK(37); _NS_COUNT_HACK(38); 778 _NS_COUNT_HACK(39); _NS_COUNT_HACK(40); _NS_COUNT_HACK(41); 779 _NS_COUNT_HACK(42); _NS_COUNT_HACK(43); _NS_COUNT_HACK(44); 780 _NS_COUNT_HACK(45); _NS_COUNT_HACK(46); _NS_COUNT_HACK(47); 781 _NS_COUNT_HACK(48); _NS_COUNT_HACK(49); _NS_COUNT_HACK(50); 782 _NS_COUNT_HACK(51); _NS_COUNT_HACK(52); _NS_COUNT_HACK(53); 783 _NS_COUNT_HACK(54); _NS_COUNT_HACK(55); _NS_COUNT_HACK(56); 784 _NS_COUNT_HACK(57); _NS_COUNT_HACK(58); _NS_COUNT_HACK(59); 785 _NS_COUNT_HACK(60); _NS_COUNT_HACK(61); _NS_COUNT_HACK(62); 786 _NS_COUNT_HACK(63); _NS_COUNT_HACK(64); _NS_COUNT_HACK(65); 787 _NS_COUNT_HACK(66); _NS_COUNT_HACK(67); _NS_COUNT_HACK(68); 788 _NS_COUNT_HACK(69); _NS_COUNT_HACK(70); _NS_COUNT_HACK(71); 789 _NS_COUNT_HACK(72); _NS_COUNT_HACK(73); _NS_COUNT_HACK(74); 790 _NS_COUNT_HACK(75); _NS_COUNT_HACK(76); _NS_COUNT_HACK(77); 791 _NS_COUNT_HACK(78); _NS_COUNT_HACK(79); _NS_COUNT_HACK(80); 792 _NS_COUNT_HACK(81); _NS_COUNT_HACK(82); _NS_COUNT_HACK(83); 793 _NS_COUNT_HACK(84); _NS_COUNT_HACK(85); _NS_COUNT_HACK(86); 794 _NS_COUNT_HACK(87); _NS_COUNT_HACK(88); _NS_COUNT_HACK(89); 795 _NS_COUNT_HACK(90); _NS_COUNT_HACK(91); _NS_COUNT_HACK(92); 796 _NS_COUNT_HACK(93); _NS_COUNT_HACK(94); _NS_COUNT_HACK(95); 797 _NS_COUNT_HACK(96); _NS_COUNT_HACK(97); _NS_COUNT_HACK(98); 798 _NS_COUNT_HACK(99); 799 800done: 801 signal(SIGSEGV, env->segv); 802 signal(SIGBUS, env->bus); 803 } 804 else 805 { 806 env = jbuf(); 807 signal(SIGSEGV, env->segv); 808 signal(SIGBUS, env->bus); 809 } 810 811 return (uintptr_t)env->addr; 812} 813 814void * 815NSReturnAddress(NSUInteger offset) 816{ 817 jbuf_type *env; 818 819 env = jbuf(); 820 if (sigsetjmp(env->buf, 1) == 0) 821 { 822 env->segv = signal(SIGSEGV, recover); 823 env->bus = signal(SIGBUS, recover); 824 switch (offset) 825 { 826 _NS_RETURN_HACK(0); _NS_RETURN_HACK(1); _NS_RETURN_HACK(2); 827 _NS_RETURN_HACK(3); _NS_RETURN_HACK(4); _NS_RETURN_HACK(5); 828 _NS_RETURN_HACK(6); _NS_RETURN_HACK(7); _NS_RETURN_HACK(8); 829 _NS_RETURN_HACK(9); _NS_RETURN_HACK(10); _NS_RETURN_HACK(11); 830 _NS_RETURN_HACK(12); _NS_RETURN_HACK(13); _NS_RETURN_HACK(14); 831 _NS_RETURN_HACK(15); _NS_RETURN_HACK(16); _NS_RETURN_HACK(17); 832 _NS_RETURN_HACK(18); _NS_RETURN_HACK(19); _NS_RETURN_HACK(20); 833 _NS_RETURN_HACK(21); _NS_RETURN_HACK(22); _NS_RETURN_HACK(23); 834 _NS_RETURN_HACK(24); _NS_RETURN_HACK(25); _NS_RETURN_HACK(26); 835 _NS_RETURN_HACK(27); _NS_RETURN_HACK(28); _NS_RETURN_HACK(29); 836 _NS_RETURN_HACK(30); _NS_RETURN_HACK(31); _NS_RETURN_HACK(32); 837 _NS_RETURN_HACK(33); _NS_RETURN_HACK(34); _NS_RETURN_HACK(35); 838 _NS_RETURN_HACK(36); _NS_RETURN_HACK(37); _NS_RETURN_HACK(38); 839 _NS_RETURN_HACK(39); _NS_RETURN_HACK(40); _NS_RETURN_HACK(41); 840 _NS_RETURN_HACK(42); _NS_RETURN_HACK(43); _NS_RETURN_HACK(44); 841 _NS_RETURN_HACK(45); _NS_RETURN_HACK(46); _NS_RETURN_HACK(47); 842 _NS_RETURN_HACK(48); _NS_RETURN_HACK(49); _NS_RETURN_HACK(50); 843 _NS_RETURN_HACK(51); _NS_RETURN_HACK(52); _NS_RETURN_HACK(53); 844 _NS_RETURN_HACK(54); _NS_RETURN_HACK(55); _NS_RETURN_HACK(56); 845 _NS_RETURN_HACK(57); _NS_RETURN_HACK(58); _NS_RETURN_HACK(59); 846 _NS_RETURN_HACK(60); _NS_RETURN_HACK(61); _NS_RETURN_HACK(62); 847 _NS_RETURN_HACK(63); _NS_RETURN_HACK(64); _NS_RETURN_HACK(65); 848 _NS_RETURN_HACK(66); _NS_RETURN_HACK(67); _NS_RETURN_HACK(68); 849 _NS_RETURN_HACK(69); _NS_RETURN_HACK(70); _NS_RETURN_HACK(71); 850 _NS_RETURN_HACK(72); _NS_RETURN_HACK(73); _NS_RETURN_HACK(74); 851 _NS_RETURN_HACK(75); _NS_RETURN_HACK(76); _NS_RETURN_HACK(77); 852 _NS_RETURN_HACK(78); _NS_RETURN_HACK(79); _NS_RETURN_HACK(80); 853 _NS_RETURN_HACK(81); _NS_RETURN_HACK(82); _NS_RETURN_HACK(83); 854 _NS_RETURN_HACK(84); _NS_RETURN_HACK(85); _NS_RETURN_HACK(86); 855 _NS_RETURN_HACK(87); _NS_RETURN_HACK(88); _NS_RETURN_HACK(89); 856 _NS_RETURN_HACK(90); _NS_RETURN_HACK(91); _NS_RETURN_HACK(92); 857 _NS_RETURN_HACK(93); _NS_RETURN_HACK(94); _NS_RETURN_HACK(95); 858 _NS_RETURN_HACK(96); _NS_RETURN_HACK(97); _NS_RETURN_HACK(98); 859 _NS_RETURN_HACK(99); 860 default: env->addr = NULL; break; 861 } 862 signal(SIGSEGV, env->segv); 863 signal(SIGBUS, env->bus); 864 } 865 else 866 { 867 env = jbuf(); 868 signal(SIGSEGV, env->segv); 869 signal(SIGBUS, env->bus); 870 env->addr = NULL; 871 } 872 873 return env->addr; 874} 875 876unsigned 877GSPrivateReturnAddresses(NSUInteger **returns) 878{ 879 unsigned numReturns; 880#if defined(HAVE_BACKTRACE) 881 void *addr[MAXFRAMES*sizeof(void*)]; 882 883 numReturns = backtrace(addr, MAXFRAMES); 884 if (numReturns > 0) 885 { 886 *returns = malloc(numReturns * sizeof(void*)); 887 memcpy(*returns, addr, numReturns * sizeof(void*)); 888 } 889#elif defined(HAVE_UNWIND_H) 890 void *addr[MAXFRAMES]; 891 892 struct GSBacktraceState state = {addr, addr + MAXFRAMES}; 893 _Unwind_Backtrace(GSUnwindCallback, &state); 894 895 numReturns = state.current - addr; 896 if (numReturns > 0) 897 { 898 *returns = malloc(numReturns * sizeof(void*)); 899 memcpy(*returns, addr, numReturns * sizeof(void*)); 900 } 901#elif defined(_WIN32) && !defined(USE_BFD) 902 NSUInteger addr[MAXFRAMES]; 903 904 (void)pthread_mutex_lock(&traceLock); 905 if (0 == hProcess) 906 { 907 hProcess = GetCurrentProcess(); 908 909 if (0 == capture) 910 { 911 HANDLE hModule; 912 913 hModule = LoadLibrary("kernel32.dll"); 914 if (0 == hModule) 915 { 916 fprintf(stderr, "Failed to load kernel32.dll with error: %d\n", 917 (int)GetLastError()); 918 (void)pthread_mutex_unlock(&traceLock); 919 return 0; 920 } 921 capture = (CaptureStackBackTraceType)GetProcAddress( 922 hModule, "RtlCaptureStackBackTrace"); 923 if (0 == capture) 924 { 925 fprintf(stderr, "Failed to find RtlCaptureStackBackTrace: %d\n", 926 (int)GetLastError()); 927 (void)pthread_mutex_unlock(&traceLock); 928 return 0; 929 } 930 hModule = LoadLibrary("dbghelp.dll"); 931 if (0 == hModule) 932 { 933 fprintf(stderr, "Failed to load dbghelp.dll with error: %d\n", 934 (int)GetLastError()); 935 (void)pthread_mutex_unlock(&traceLock); 936 return 0; 937 } 938 optSym = (SymSetOptionsType)GetProcAddress( 939 hModule, "SymSetOptions"); 940 if (0 == optSym) 941 { 942 fprintf(stderr, "Failed to find SymSetOptions: %d\n", 943 (int)GetLastError()); 944 (void)pthread_mutex_unlock(&traceLock); 945 return 0; 946 } 947 initSym = (SymInitializeType)GetProcAddress( 948 hModule, "SymInitialize"); 949 if (0 == initSym) 950 { 951 fprintf(stderr, "Failed to find SymInitialize: %d\n", 952 (int)GetLastError()); 953 (void)pthread_mutex_unlock(&traceLock); 954 return 0; 955 } 956 fromSym = (SymFromAddrType)GetProcAddress( 957 hModule, "SymFromAddr"); 958 if (0 == fromSym) 959 { 960 fprintf(stderr, "Failed to find SymFromAddr: %d\n", 961 (int)GetLastError()); 962 (void)pthread_mutex_unlock(&traceLock); 963 return 0; 964 } 965 } 966 967 (optSym)(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); 968 969 if (!(initSym)(hProcess, NULL, TRUE)) 970 { 971 fprintf(stderr, "SymInitialize failed with error: %d\n", 972 (int)GetLastError()); 973 fromSym = 0; 974 (void)pthread_mutex_unlock(&traceLock); 975 return 0; 976 } 977 } 978 if (0 == capture) 979 { 980 (void)pthread_mutex_unlock(&traceLock); 981 return 0; 982 } 983 984 numReturns = (capture)(0, MAXFRAMES, (void**)addr, NULL); 985 if (numReturns > 0) 986 { 987 *returns = malloc(numReturns * sizeof(void*)); 988 memcpy(*returns, addr, numReturns * sizeof(void*)); 989 } 990 991 (void)pthread_mutex_unlock(&traceLock); 992 993#else 994 int n; 995 996 n = NSCountFrames(); 997 /* There should be more frame addresses than return addresses. 998 */ 999 if (n > 0) 1000 { 1001 n--; 1002 } 1003 if (n > 0) 1004 { 1005 n--; 1006 } 1007 1008 if ((numReturns = n) > 0) 1009 { 1010 jbuf_type *env; 1011 1012 *returns = malloc(numReturns * sizeof(void*)); 1013 1014 env = jbuf(); 1015 if (sigsetjmp(env->buf, 1) == 0) 1016 { 1017 unsigned i; 1018 1019 env->segv = signal(SIGSEGV, recover); 1020 env->bus = signal(SIGBUS, recover); 1021 1022 for (i = 0; i < n; i++) 1023 { 1024 switch (i) 1025 { 1026 _NS_RETURN_HACK(0); _NS_RETURN_HACK(1); _NS_RETURN_HACK(2); 1027 _NS_RETURN_HACK(3); _NS_RETURN_HACK(4); _NS_RETURN_HACK(5); 1028 _NS_RETURN_HACK(6); _NS_RETURN_HACK(7); _NS_RETURN_HACK(8); 1029 _NS_RETURN_HACK(9); _NS_RETURN_HACK(10); _NS_RETURN_HACK(11); 1030 _NS_RETURN_HACK(12); _NS_RETURN_HACK(13); _NS_RETURN_HACK(14); 1031 _NS_RETURN_HACK(15); _NS_RETURN_HACK(16); _NS_RETURN_HACK(17); 1032 _NS_RETURN_HACK(18); _NS_RETURN_HACK(19); _NS_RETURN_HACK(20); 1033 _NS_RETURN_HACK(21); _NS_RETURN_HACK(22); _NS_RETURN_HACK(23); 1034 _NS_RETURN_HACK(24); _NS_RETURN_HACK(25); _NS_RETURN_HACK(26); 1035 _NS_RETURN_HACK(27); _NS_RETURN_HACK(28); _NS_RETURN_HACK(29); 1036 _NS_RETURN_HACK(30); _NS_RETURN_HACK(31); _NS_RETURN_HACK(32); 1037 _NS_RETURN_HACK(33); _NS_RETURN_HACK(34); _NS_RETURN_HACK(35); 1038 _NS_RETURN_HACK(36); _NS_RETURN_HACK(37); _NS_RETURN_HACK(38); 1039 _NS_RETURN_HACK(39); _NS_RETURN_HACK(40); _NS_RETURN_HACK(41); 1040 _NS_RETURN_HACK(42); _NS_RETURN_HACK(43); _NS_RETURN_HACK(44); 1041 _NS_RETURN_HACK(45); _NS_RETURN_HACK(46); _NS_RETURN_HACK(47); 1042 _NS_RETURN_HACK(48); _NS_RETURN_HACK(49); _NS_RETURN_HACK(50); 1043 _NS_RETURN_HACK(51); _NS_RETURN_HACK(52); _NS_RETURN_HACK(53); 1044 _NS_RETURN_HACK(54); _NS_RETURN_HACK(55); _NS_RETURN_HACK(56); 1045 _NS_RETURN_HACK(57); _NS_RETURN_HACK(58); _NS_RETURN_HACK(59); 1046 _NS_RETURN_HACK(60); _NS_RETURN_HACK(61); _NS_RETURN_HACK(62); 1047 _NS_RETURN_HACK(63); _NS_RETURN_HACK(64); _NS_RETURN_HACK(65); 1048 _NS_RETURN_HACK(66); _NS_RETURN_HACK(67); _NS_RETURN_HACK(68); 1049 _NS_RETURN_HACK(69); _NS_RETURN_HACK(70); _NS_RETURN_HACK(71); 1050 _NS_RETURN_HACK(72); _NS_RETURN_HACK(73); _NS_RETURN_HACK(74); 1051 _NS_RETURN_HACK(75); _NS_RETURN_HACK(76); _NS_RETURN_HACK(77); 1052 _NS_RETURN_HACK(78); _NS_RETURN_HACK(79); _NS_RETURN_HACK(80); 1053 _NS_RETURN_HACK(81); _NS_RETURN_HACK(82); _NS_RETURN_HACK(83); 1054 _NS_RETURN_HACK(84); _NS_RETURN_HACK(85); _NS_RETURN_HACK(86); 1055 _NS_RETURN_HACK(87); _NS_RETURN_HACK(88); _NS_RETURN_HACK(89); 1056 _NS_RETURN_HACK(90); _NS_RETURN_HACK(91); _NS_RETURN_HACK(92); 1057 _NS_RETURN_HACK(93); _NS_RETURN_HACK(94); _NS_RETURN_HACK(95); 1058 _NS_RETURN_HACK(96); _NS_RETURN_HACK(97); _NS_RETURN_HACK(98); 1059 _NS_RETURN_HACK(99); 1060 default: env->addr = 0; break; 1061 } 1062 if (env->addr == 0) 1063 { 1064 break; 1065 } 1066 memcpy(&(*returns)[i], env->addr, sizeof(void*)); 1067 } 1068 signal(SIGSEGV, env->segv); 1069 signal(SIGBUS, env->bus); 1070 } 1071 else 1072 { 1073 env = jbuf(); 1074 signal(SIGSEGV, env->segv); 1075 signal(SIGBUS, env->bus); 1076 } 1077 } 1078#endif 1079 return numReturns; 1080} 1081 1082 1083@implementation GSStackTrace : NSObject 1084 1085/** Offset from the top of the stack (when we generate a trace) to the 1086 * first frame likely to be of interest for debugging. 1087 */ 1088#define FrameOffset 4 1089 1090+ (void) initialize 1091{ 1092#if defined(_WIN32) && !defined(USE_BFD) 1093 GS_INIT_RECURSIVE_MUTEX(traceLock); 1094#endif 1095#if defined(USE_BFD) 1096 GS_INIT_RECURSIVE_MUTEX(modLock); 1097#endif 1098} 1099 1100- (NSArray*) addresses 1101{ 1102 if (nil == addresses && numReturns > FrameOffset) 1103 { 1104 ENTER_POOL 1105 NSInteger count = numReturns - FrameOffset; 1106 NSValue *objects[count]; 1107 NSUInteger index; 1108 void **ptrs = (void **)returns; 1109 1110 for (index = 0; index < count; index++) 1111 { 1112 objects[index] = [NSValue valueWithPointer: ptrs[FrameOffset+index]]; 1113 } 1114 addresses = [[NSArray alloc] initWithObjects: objects count: count]; 1115 LEAVE_POOL 1116 } 1117 return addresses; 1118} 1119 1120- (oneway void) dealloc 1121{ 1122 DESTROY(addresses); 1123 DESTROY(symbols); 1124 if (returns != NULL) 1125 { 1126 free(returns); 1127 returns = NULL; 1128 } 1129 [super dealloc]; 1130} 1131 1132- (NSString*) description 1133{ 1134 NSMutableString *result; 1135 NSArray *s; 1136 int i; 1137 int n; 1138 1139 result = [NSMutableString string]; 1140 s = [self symbols]; 1141 n = [s count]; 1142 for (i = 0; i < n; i++) 1143 { 1144 NSString *line = [s objectAtIndex: i]; 1145 1146 [result appendFormat: @"%3d: %@\n", i, line]; 1147 } 1148 return result; 1149} 1150 1151- (id) init 1152{ 1153 return self; 1154} 1155 1156- (NSArray*) symbols 1157{ 1158 if (nil == symbols && numReturns > FrameOffset) 1159 { 1160 NSInteger count = numReturns - FrameOffset; 1161 NSUInteger i; 1162 1163#if defined(USE_BFD) 1164 void **ptrs = (void**)&returns[FrameOffset]; 1165 NSMutableArray *a; 1166 1167 a = [[NSMutableArray alloc] initWithCapacity: count]; 1168 1169 for (i = 0; i < count; i++) 1170 { 1171 GSFunctionInfo *aFrame = nil; 1172 void *address = (void*)*ptrs++; 1173 void *base; 1174 NSString *modulePath; 1175 GSBinaryFileInfo *bfi; 1176 1177 modulePath = GSPrivateBaseAddress(address, &base); 1178 if (modulePath != nil && (bfi = GSLoadModule(modulePath)) != nil) 1179 { 1180 aFrame = [bfi functionForAddress: (void*)(address - base)]; 1181 if (aFrame == nil) 1182 { 1183 /* We know we have the right module but function lookup 1184 * failed ... perhaps we need to use the absolute 1185 * address rather than offest by 'base' in this case. 1186 */ 1187 aFrame = [bfi functionForAddress: address]; 1188 } 1189 } 1190 else 1191 { 1192 NSArray *modules; 1193 int j; 1194 int m; 1195 1196 modules = GSListModules(); 1197 m = [modules count]; 1198 for (j = 0; j < m; j++) 1199 { 1200 bfi = [modules objectAtIndex: j]; 1201 1202 if ((id)bfi != (id)[NSNull null]) 1203 { 1204 aFrame = [bfi functionForAddress: address]; 1205 if (aFrame != nil) 1206 { 1207 break; 1208 } 1209 } 1210 } 1211 } 1212 1213 // not found (?!), add an 'unknown' function 1214 if (aFrame == nil) 1215 { 1216 aFrame = [GSFunctionInfo alloc]; 1217 [aFrame initWithModule: nil 1218 address: address 1219 file: nil 1220 function: nil 1221 line: 0]; 1222 [aFrame autorelease]; 1223 } 1224 [a addObject: [aFrame description]]; 1225 } 1226 symbols = [a copy]; 1227 [a release]; 1228#elif defined(_WIN32) 1229 void **ptrs = (void**)&returns[FrameOffset]; 1230 SYMBOL_INFO *symbol; 1231 NSString *syms[MAXFRAMES]; 1232 1233 symbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO) 1234 + 1024 * sizeof(char), 1); 1235 symbol->MaxNameLen = 1024; 1236 symbol->SizeOfStruct = sizeof(SYMBOL_INFO); 1237 1238 (void)pthread_mutex_lock(&traceLock); 1239 for (i = 0; i < count; i++) 1240 { 1241 NSUInteger addr = (NSUInteger)*ptrs++; 1242 1243 if ((fromSym)(hProcess, (DWORD64)addr, 0, symbol)) 1244 { 1245 syms[i] = [NSString stringWithFormat: 1246 @"%s - %p", symbol->Name, addr]; 1247 } 1248 else 1249 { 1250 syms[i] = [NSString stringWithFormat: 1251 @"unknown - %p", symbol->Name, addr]; 1252 } 1253 } 1254 (void)pthread_mutex_unlock(&traceLock); 1255 free(symbol); 1256 1257 symbols = [[NSArray alloc] initWithObjects: syms count: count]; 1258#elif defined(HAVE_BACKTRACE) 1259 void **ptrs = (void**)&returns[FrameOffset]; 1260 char **strs; 1261 NSString **symbolArray; 1262 1263 strs = backtrace_symbols(ptrs, count); 1264 symbolArray = alloca(count * sizeof(NSString*)); 1265 for (i = 0; i < count; i++) 1266 { 1267 symbolArray[i] = [NSString stringWithUTF8String: strs[i]]; 1268 } 1269 symbols = [[NSArray alloc] initWithObjects: symbolArray count: count]; 1270 free(strs); 1271#elif defined(HAVE_UNWIND_H) 1272 void **ptrs = (void**)&returns[FrameOffset]; 1273 NSString **symbolArray; 1274 1275 symbolArray = alloca(count * sizeof(NSString*)); 1276 for (i = 0; i < count; i++) 1277 { 1278 const void *addr = ptrs[i]; 1279 Dl_info info; 1280 if (dladdr(addr, &info)) { 1281 const char *libname = "unknown"; 1282 if (info.dli_fname) { 1283 // strip library path 1284 char *delim = strrchr(info.dli_fname, '/'); 1285 libname = delim ? delim + 1 : info.dli_fname; 1286 } 1287 if (info.dli_sname) { 1288 symbolArray[i] = [NSString stringWithFormat: 1289 @"%lu: %p %s %s + %d", (unsigned long)i, addr, libname, 1290 info.dli_sname, (int)(addr - info.dli_saddr)]; 1291 } else { 1292 symbolArray[i] = [NSString stringWithFormat: 1293 @"%lu: %p %s unknown", (unsigned long)i, addr, libname]; 1294 } 1295 } else { 1296 symbolArray[i] = [NSString stringWithFormat: 1297 @"%lu: %p unknown", (unsigned long)i, addr]; 1298 } 1299 } 1300 symbols = [[NSArray alloc] initWithObjects: symbolArray count: count]; 1301#else 1302 NSMutableArray *a; 1303 1304 symbols = a = [[self addresses] mutableCopy]; 1305 for (i = 0; i < count; i++) 1306 { 1307 NSString *s; 1308 1309 s = [[NSString alloc] initWithFormat: @"%p: symbol not available", 1310 [[a objectAtIndex: i] pointerValue]]; 1311 [a replaceObjectAtIndex: i withObject: s]; 1312 RELEASE(s); 1313 } 1314#endif 1315 } 1316 return symbols; 1317} 1318 1319- (void) trace 1320{ 1321 DESTROY(addresses); 1322 DESTROY(symbols); 1323 if (returns != NULL) 1324 { 1325 free(returns); 1326 returns = NULL; 1327 } 1328 numReturns = GSPrivateReturnAddresses(&returns); 1329} 1330 1331@end 1332 1333 1334NSString* const NSCharacterConversionException 1335 = @"NSCharacterConversionException"; 1336 1337NSString* const NSGenericException 1338 = @"NSGenericException"; 1339 1340NSString* const NSInternalInconsistencyException 1341 = @"NSInternalInconsistencyException"; 1342 1343NSString* const NSInvalidArgumentException 1344 = @"NSInvalidArgumentException"; 1345 1346NSString* const NSMallocException 1347 = @"NSMallocException"; 1348 1349NSString* const NSOldStyleException 1350 = @"NSOldStyleException"; 1351 1352NSString* const NSParseErrorException 1353 = @"NSParseErrorException"; 1354 1355NSString* const NSRangeException 1356 = @"NSRangeException"; 1357 1358static void _terminate() 1359{ 1360 BOOL shouldAbort; 1361 1362#ifdef DEBUG 1363 shouldAbort = YES; // abort() by default. 1364#else 1365 shouldAbort = NO; // exit() by default. 1366#endif 1367 shouldAbort = GSPrivateEnvironmentFlag("CRASH_ON_ABORT", shouldAbort); 1368 if (shouldAbort == YES) 1369 { 1370 abort(); 1371 } 1372 else 1373 { 1374 exit(1); 1375 } 1376} 1377 1378static void 1379_NSFoundationUncaughtExceptionHandler (NSException *exception) 1380{ 1381 NSAutoreleasePool *pool = [NSAutoreleasePool new]; 1382 1383 fprintf(stderr, "%s: Uncaught exception %s, reason: %s\n", 1384 GSPrivateArgZero(), 1385 [[exception name] lossyCString], [[exception reason] lossyCString]); 1386 fflush(stderr); /* NEEDED UNDER MINGW */ 1387 if (GSPrivateEnvironmentFlag("GNUSTEP_STACK_TRACE", NO) == YES 1388 || GSPrivateDefaultsFlag(GSExceptionStackTrace) == YES) 1389 { 1390 fprintf(stderr, "Stack\n%s\n", 1391 [[[exception _callStack] description] lossyCString]); 1392 } 1393 fflush(stderr); /* NEEDED UNDER MINGW */ 1394 [pool drain]; 1395 _terminate(); 1396} 1397 1398static void 1399callUncaughtHandler(id value) 1400{ 1401 if (_NSUncaughtExceptionHandler != NULL) 1402 { 1403 (*_NSUncaughtExceptionHandler)(value); 1404 } 1405 /* The uncaught exception handler which is set has not exited, 1406 * so we MUST call the builtin handler, (normal behavior of MacOS-X). 1407 * The standard handler is guaranteed to exit/abort, which is the 1408 * required behavior for OSX compatibility. 1409 * NB Cocoa's Exception Handling framework might bypass this behavior 1410 * somehow (it's not clear if it does that or simply wraps various 1411 * things with its own exception handlers thus preventing the 1412 * uncaught handler from ever being needed) ... if anyone contributes 1413 * an implementation, perhaps we could integrate it here. 1414 */ 1415 _NSFoundationUncaughtExceptionHandler(value); 1416} 1417 1418@implementation NSException 1419 1420+ (void) initialize 1421{ 1422 if (self == [NSException class]) 1423 { 1424#if defined(_NATIVE_OBJC_EXCEPTIONS) 1425# ifdef HAVE_SET_UNCAUGHT_EXCEPTION_HANDLER 1426 objc_setUncaughtExceptionHandler(callUncaughtHandler); 1427# elif defined(HAVE_UNEXPECTED) 1428 _objc_unexpected_exception = callUncaughtHandler; 1429# elif defined(HAVE_SET_UNEXPECTED) 1430 objc_set_unexpected(callUncaughtHandler); 1431# endif 1432#endif 1433 } 1434} 1435 1436+ (NSException*) exceptionWithName: (NSString*)name 1437 reason: (NSString*)reason 1438 userInfo: (NSDictionary*)userInfo 1439{ 1440 return AUTORELEASE([[self alloc] initWithName: name reason: reason 1441 userInfo: userInfo]); 1442} 1443 1444+ (void) raise: (NSString*)name 1445 format: (NSString*)format,... 1446{ 1447 va_list args; 1448 1449 va_start(args, format); 1450 [self raise: name format: format arguments: args]; 1451 // This probably doesn't matter, but va_end won't get called 1452 va_end(args); 1453 while (1); // does not return 1454} 1455 1456+ (void) raise: (NSString*)name 1457 format: (NSString*)format 1458 arguments: (va_list)argList 1459{ 1460 NSString *reason; 1461 NSException *except; 1462 1463 reason = [NSString stringWithFormat: format arguments: argList]; 1464 except = [self exceptionWithName: name reason: reason userInfo: nil]; 1465 [except raise]; 1466 while (1); // does not return 1467} 1468 1469/* For OSX compatibility -init returns nil. 1470 */ 1471- (id) init 1472{ 1473 DESTROY(self); 1474 return nil; 1475} 1476 1477- (id) initWithName: (NSString*)name 1478 reason: (NSString*)reason 1479 userInfo: (NSDictionary*)userInfo 1480{ 1481 ASSIGN(_e_name, name); 1482 ASSIGN(_e_reason, reason); 1483 if (userInfo != nil) 1484 { 1485 if (_reserved == 0) 1486 { 1487 _reserved = NSZoneCalloc([self zone], 2, sizeof(id)); 1488 } 1489 ASSIGN(_e_info, userInfo); 1490 } 1491 return self; 1492} 1493 1494- (NSArray*) callStackReturnAddresses 1495{ 1496 if (_reserved == 0) 1497 { 1498 return nil; 1499 } 1500 return [_e_stack addresses]; 1501} 1502 1503- (NSArray *) callStackSymbols 1504{ 1505 if (_reserved == 0) 1506 { 1507 return nil; 1508 } 1509 return [_e_stack symbols]; 1510} 1511 1512- (void) dealloc 1513{ 1514 DESTROY(_e_name); 1515 DESTROY(_e_reason); 1516 if (_reserved != 0) 1517 { 1518 DESTROY(_e_info); 1519 DESTROY(_e_stack); 1520 NSZoneFree([self zone], _reserved); 1521 _reserved = 0; 1522 } 1523 [super dealloc]; 1524} 1525 1526- (NSString*) description 1527{ 1528 NSAutoreleasePool *pool = [NSAutoreleasePool new]; 1529 NSString *result; 1530 1531 if (_e_name == nil) 1532 { 1533 [NSException raise: NSInvalidArgumentException 1534 format: @"Atttempt to use uninitialised NSException"]; 1535 } 1536 if (_reserved != 0) 1537 { 1538 if (_e_stack != nil 1539 && (GSPrivateEnvironmentFlag("GNUSTEP_STACK_TRACE", NO) == YES 1540 || GSPrivateDefaultsFlag(GSExceptionStackTrace) == YES)) 1541 { 1542 if (_e_info != nil) 1543 { 1544 result = [NSString stringWithFormat: 1545 @"%@ NAME:%@ REASON:%@ INFO:%@ STACK:%@", 1546 [super description], _e_name, _e_reason, _e_info, _e_stack]; 1547 } 1548 else 1549 { 1550 result = [NSString stringWithFormat: 1551 @"%@ NAME:%@ REASON:%@ STACK:%@", 1552 [super description], _e_name, _e_reason, _e_stack]; 1553 } 1554 } 1555 else 1556 { 1557 result = [NSString stringWithFormat: 1558 @"%@ NAME:%@ REASON:%@ INFO:%@", 1559 [super description], _e_name, _e_reason, _e_info]; 1560 } 1561 } 1562 else 1563 { 1564 result = [NSString stringWithFormat: @"%@ NAME:%@ REASON:%@", 1565 [super description], _e_name, _e_reason]; 1566 } 1567 [result retain]; 1568 [pool drain]; 1569 return [result autorelease]; 1570} 1571 1572- (void) raise 1573{ 1574 if (_reserved == 0) 1575 { 1576 _reserved = NSZoneCalloc([self zone], 2, sizeof(id)); 1577 } 1578 if (nil == _e_stack) 1579 { 1580 // Only set the stack when first raised 1581 _e_stack = [GSStackTrace new]; 1582 [_e_stack trace]; 1583 } 1584 1585#if defined(_NATIVE_OBJC_EXCEPTIONS) 1586 @throw self; 1587#else 1588{ 1589 NSThread *thread; 1590 NSHandler *handler; 1591 1592 thread = GSCurrentThread(); 1593 handler = thread->_exception_handler; 1594 if (NULL == handler) 1595 { 1596 static int recursion = 0; 1597 1598 /* 1599 * Set/check a counter to prevent recursive uncaught exceptions. 1600 * Allow a little recursion in case we have different handlers 1601 * being tried. 1602 */ 1603 if (recursion++ > 3) 1604 { 1605 fprintf(stderr, 1606 "recursion encountered handling uncaught exception\n"); 1607 fflush(stderr); /* NEEDED UNDER MINGW */ 1608 _terminate(); 1609 } 1610 1611 /* 1612 * Call the uncaught exception handler (if there is one). 1613 * The calls the built-in default handler to terminate the program! 1614 */ 1615 callUncaughtHandler(self); 1616 } 1617 else 1618 { 1619 thread->_exception_handler = handler->next; 1620 handler->exception = self; 1621 longjmp(handler->jumpState, 1); 1622 } 1623} 1624#endif 1625 while (1); // does not return 1626} 1627 1628- (NSString*) name 1629{ 1630 if (_e_name != nil) 1631 { 1632 return _e_name; 1633 } 1634 else 1635 { 1636 return NSStringFromClass([self class]); 1637 } 1638} 1639 1640- (NSString*) reason 1641{ 1642 if (_e_reason != nil) 1643 { 1644 return _e_reason; 1645 } 1646 else 1647 { 1648 return @"unspecified reason"; 1649 } 1650} 1651 1652- (NSDictionary*) userInfo 1653{ 1654 if (_reserved == 0) 1655 { 1656 return nil; 1657 } 1658 return _e_info; 1659} 1660 1661- (Class) classForPortCoder 1662{ 1663 return [self class]; 1664} 1665 1666- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder 1667{ 1668 return self; 1669} 1670 1671- (void) encodeWithCoder: (NSCoder*)aCoder 1672{ 1673 id info = (_reserved == 0) ? nil : _e_info; 1674 1675 [aCoder encodeValueOfObjCType: @encode(id) at: &_e_name]; 1676 [aCoder encodeValueOfObjCType: @encode(id) at: &_e_reason]; 1677 [aCoder encodeValueOfObjCType: @encode(id) at: &info]; 1678} 1679 1680- (id) initWithCoder: (NSCoder*)aDecoder 1681{ 1682 id info; 1683 1684 [aDecoder decodeValueOfObjCType: @encode(id) at: &_e_name]; 1685 [aDecoder decodeValueOfObjCType: @encode(id) at: &_e_reason]; 1686 [aDecoder decodeValueOfObjCType: @encode(id) at: &info]; 1687 if (info != nil) 1688 { 1689 if (_reserved == 0) 1690 { 1691 _reserved = NSZoneCalloc([self zone], 2, sizeof(id)); 1692 } 1693 _e_info = info; 1694 } 1695 return self; 1696} 1697 1698- (id) copyWithZone: (NSZone*)zone 1699{ 1700 if (NSShouldRetainWithZone(self, zone)) 1701 { 1702 return RETAIN(self); 1703 } 1704 else 1705 { 1706 return [[[self class] alloc] initWithName: [self name] 1707 reason: [self reason] 1708 userInfo: [self userInfo]]; 1709 } 1710} 1711 1712@end 1713 1714@implementation NSException (GSPrivate) 1715 1716- (GSStackTrace*) _callStack 1717{ 1718 if (_reserved == 0) 1719 { 1720 return nil; 1721 } 1722 return _e_stack; 1723} 1724 1725@end 1726 1727@implementation NSThread (CallStackSymbols) 1728 1729+ (NSArray *) callStackSymbols 1730{ 1731 GSStackTrace *stackTrace = AUTORELEASE([GSStackTrace new]); 1732 [stackTrace trace]; 1733 return [stackTrace symbols]; 1734} 1735 1736@end 1737 1738void 1739_NSAddHandler (NSHandler* handler) 1740{ 1741 NSThread *thread; 1742 1743 thread = GSCurrentThread(); 1744#if defined(_WIN32) && defined(DEBUG) 1745 if (thread->_exception_handler 1746 && IsBadReadPtr(thread->_exception_handler, sizeof(NSHandler))) 1747 { 1748 fprintf(stderr, "ERROR: Current exception handler is bogus.\n"); 1749 } 1750#endif 1751 handler->next = thread->_exception_handler; 1752 thread->_exception_handler = handler; 1753} 1754 1755void 1756_NSRemoveHandler (NSHandler* handler) 1757{ 1758 NSThread *thread; 1759 1760 thread = GSCurrentThread(); 1761#if defined(DEBUG) 1762 if (thread->_exception_handler != handler) 1763 { 1764 fprintf(stderr, "ERROR: Removing exception handler that is not on top " 1765 "of the stack. (You probably called return in an NS_DURING block.)\n"); 1766 } 1767#if defined(_WIN32) 1768 if (IsBadReadPtr(handler, sizeof(NSHandler))) 1769 { 1770 fprintf(stderr, "ERROR: Could not remove exception handler, " 1771 "handler is bad pointer.\n"); 1772 thread->_exception_handler = 0; 1773 return; 1774 } 1775 if (handler->next && IsBadReadPtr(handler->next, sizeof(NSHandler))) 1776 { 1777 fprintf(stderr, "ERROR: Could not restore exception handler, " 1778 "handler->next is bad pointer.\n"); 1779 thread->_exception_handler = 0; 1780 return; 1781 } 1782#endif 1783#endif 1784 thread->_exception_handler = handler->next; 1785} 1786 1787NSUncaughtExceptionHandler * 1788NSGetUncaughtExceptionHandler() 1789{ 1790 return _NSUncaughtExceptionHandler; 1791} 1792 1793void 1794NSSetUncaughtExceptionHandler(NSUncaughtExceptionHandler *handler) 1795{ 1796 _NSUncaughtExceptionHandler = handler; 1797} 1798