mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 16:30:41 +00:00
Improved stacktrace/debug handling.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@25667 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
697bbcaaad
commit
a0b3607dd6
5 changed files with 234 additions and 66 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
||||||
|
2007-12-03 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
* Source/NSDebug.m:
|
||||||
|
* Source/GSPrivate.h:
|
||||||
|
* Source/NSException.m:
|
||||||
|
* Source/NSThread.m:
|
||||||
|
Rewrite some stackframe handling code for greater efficiency.
|
||||||
|
When raising an exception, just get the current stack and don't
|
||||||
|
bother translating addresses to method/function information until
|
||||||
|
needed by the -description method. Improves performance of
|
||||||
|
exception handling and eliminates the possibility of a recursive
|
||||||
|
exception due to a problem in the stacktrace code.
|
||||||
|
|
||||||
2007-12-02 David Ayers <ayers@fsfe.org>
|
2007-12-02 David Ayers <ayers@fsfe.org>
|
||||||
|
|
||||||
* Source/NSDecimal.m (GSDecimalDouble): Use NAN when available.
|
* Source/NSDecimal.m (GSDecimalDouble): Use NAN when available.
|
||||||
|
|
|
@ -378,6 +378,11 @@ void GSPrivateNotifyIdle(void) GS_ATTRIB_PRIVATE;
|
||||||
*/
|
*/
|
||||||
BOOL GSPrivateNotifyMore(void) GS_ATTRIB_PRIVATE;
|
BOOL GSPrivateNotifyMore(void) GS_ATTRIB_PRIVATE;
|
||||||
|
|
||||||
|
/* Function to return the current stack return addresses.
|
||||||
|
*/
|
||||||
|
NSMutableArray *
|
||||||
|
GSPrivateStackAddresses(void) GS_ATTRIB_PRIVATE;
|
||||||
|
|
||||||
/* Function to return the hash value for a small integer (used by NSNumber).
|
/* Function to return the hash value for a small integer (used by NSNumber).
|
||||||
*/
|
*/
|
||||||
unsigned
|
unsigned
|
||||||
|
|
182
Source/NSDebug.m
182
Source/NSDebug.m
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include "GSPrivate.h"
|
||||||
#include "GNUstepBase/GSLock.h"
|
#include "GNUstepBase/GSLock.h"
|
||||||
#include "Foundation/NSArray.h"
|
#include "Foundation/NSArray.h"
|
||||||
#include "Foundation/NSData.h"
|
#include "Foundation/NSData.h"
|
||||||
|
@ -38,6 +39,7 @@
|
||||||
#include "Foundation/NSNotification.h"
|
#include "Foundation/NSNotification.h"
|
||||||
#include "Foundation/NSNotificationQueue.h"
|
#include "Foundation/NSNotificationQueue.h"
|
||||||
#include "Foundation/NSThread.h"
|
#include "Foundation/NSThread.h"
|
||||||
|
#include "Foundation/NSValue.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Class class;
|
Class class;
|
||||||
|
@ -854,15 +856,6 @@ GSDebugMethodMsg(id obj, SEL sel, const char *file, int line, NSString *fmt)
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned NSCountFrames(void)
|
|
||||||
{
|
|
||||||
unsigned x = 0;
|
|
||||||
|
|
||||||
while (NSFrameAddress(x + 1)) x++;
|
|
||||||
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define _NS_FRAME_HACK(a) case a: val = __builtin_frame_address(a + 1); break;
|
#define _NS_FRAME_HACK(a) case a: val = __builtin_frame_address(a + 1); break;
|
||||||
#define _NS_RETURN_HACK(a) case a: val = __builtin_return_address(a + 1); break;
|
#define _NS_RETURN_HACK(a) case a: val = __builtin_return_address(a + 1); break;
|
||||||
|
|
||||||
|
@ -893,7 +886,7 @@ jbuf()
|
||||||
if (d == nil)
|
if (d == nil)
|
||||||
{
|
{
|
||||||
d = [[NSMutableData alloc] initWithLength:
|
d = [[NSMutableData alloc] initWithLength:
|
||||||
sizeof(jmp_buf) + sizeof(void(*)(int))];
|
sizeof(jmp_buf) + sizeof(void(*)(int)) + sizeof(void*)];
|
||||||
[[[NSThread currentThread] threadDictionary] setObject: d
|
[[[NSThread currentThread] threadDictionary] setObject: d
|
||||||
forKey: @"GSjbuf"];
|
forKey: @"GSjbuf"];
|
||||||
RELEASE(d);
|
RELEASE(d);
|
||||||
|
@ -920,7 +913,9 @@ NSFrameAddress(int offset)
|
||||||
if (setjmp(*env) == 0)
|
if (setjmp(*env) == 0)
|
||||||
{
|
{
|
||||||
old = signal(SIGSEGV, recover);
|
old = signal(SIGSEGV, recover);
|
||||||
memcpy(env + 1, &old, sizeof(old));
|
val = (void*)env;
|
||||||
|
val += sizeof(jmp_buf);
|
||||||
|
memcpy(val, &old, sizeof(old));
|
||||||
switch (offset)
|
switch (offset)
|
||||||
{
|
{
|
||||||
_NS_FRAME_HACK(0); _NS_FRAME_HACK(1); _NS_FRAME_HACK(2);
|
_NS_FRAME_HACK(0); _NS_FRAME_HACK(1); _NS_FRAME_HACK(2);
|
||||||
|
@ -963,14 +958,88 @@ NSFrameAddress(int offset)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
env = jbuf();
|
val = jbuf();
|
||||||
memcpy(&old, env + 1, sizeof(old));
|
val += sizeof(jmp_buf);
|
||||||
|
memcpy(&old, val, sizeof(old));
|
||||||
signal(SIGSEGV, old);
|
signal(SIGSEGV, old);
|
||||||
val = NULL;
|
val = NULL;
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned NSCountFrames(void)
|
||||||
|
{
|
||||||
|
jmp_buf *env;
|
||||||
|
void (*old)(int);
|
||||||
|
void *val;
|
||||||
|
|
||||||
|
env = jbuf();
|
||||||
|
if (setjmp(*env) == 0)
|
||||||
|
{
|
||||||
|
unsigned *loc;
|
||||||
|
|
||||||
|
old = signal(SIGSEGV, recover);
|
||||||
|
val = (void*)env;
|
||||||
|
val += sizeof(jmp_buf);
|
||||||
|
memcpy(val, &old, sizeof(old));
|
||||||
|
val += sizeof(old);
|
||||||
|
loc = (unsigned*)val;
|
||||||
|
*loc = 0;
|
||||||
|
|
||||||
|
#define _NS_COUNT_HACK(X) if (__builtin_frame_address(X + 1) == 0) \
|
||||||
|
goto done; else *loc = X + 1;
|
||||||
|
|
||||||
|
_NS_COUNT_HACK(0); _NS_COUNT_HACK(1); _NS_COUNT_HACK(2);
|
||||||
|
_NS_COUNT_HACK(3); _NS_COUNT_HACK(4); _NS_COUNT_HACK(5);
|
||||||
|
_NS_COUNT_HACK(6); _NS_COUNT_HACK(7); _NS_COUNT_HACK(8);
|
||||||
|
_NS_COUNT_HACK(9); _NS_COUNT_HACK(10); _NS_COUNT_HACK(11);
|
||||||
|
_NS_COUNT_HACK(12); _NS_COUNT_HACK(13); _NS_COUNT_HACK(14);
|
||||||
|
_NS_COUNT_HACK(15); _NS_COUNT_HACK(16); _NS_COUNT_HACK(17);
|
||||||
|
_NS_COUNT_HACK(18); _NS_COUNT_HACK(19); _NS_COUNT_HACK(20);
|
||||||
|
_NS_COUNT_HACK(21); _NS_COUNT_HACK(22); _NS_COUNT_HACK(23);
|
||||||
|
_NS_COUNT_HACK(24); _NS_COUNT_HACK(25); _NS_COUNT_HACK(26);
|
||||||
|
_NS_COUNT_HACK(27); _NS_COUNT_HACK(28); _NS_COUNT_HACK(29);
|
||||||
|
_NS_COUNT_HACK(30); _NS_COUNT_HACK(31); _NS_COUNT_HACK(32);
|
||||||
|
_NS_COUNT_HACK(33); _NS_COUNT_HACK(34); _NS_COUNT_HACK(35);
|
||||||
|
_NS_COUNT_HACK(36); _NS_COUNT_HACK(37); _NS_COUNT_HACK(38);
|
||||||
|
_NS_COUNT_HACK(39); _NS_COUNT_HACK(40); _NS_COUNT_HACK(41);
|
||||||
|
_NS_COUNT_HACK(42); _NS_COUNT_HACK(43); _NS_COUNT_HACK(44);
|
||||||
|
_NS_COUNT_HACK(45); _NS_COUNT_HACK(46); _NS_COUNT_HACK(47);
|
||||||
|
_NS_COUNT_HACK(48); _NS_COUNT_HACK(49); _NS_COUNT_HACK(50);
|
||||||
|
_NS_COUNT_HACK(51); _NS_COUNT_HACK(52); _NS_COUNT_HACK(53);
|
||||||
|
_NS_COUNT_HACK(54); _NS_COUNT_HACK(55); _NS_COUNT_HACK(56);
|
||||||
|
_NS_COUNT_HACK(57); _NS_COUNT_HACK(58); _NS_COUNT_HACK(59);
|
||||||
|
_NS_COUNT_HACK(60); _NS_COUNT_HACK(61); _NS_COUNT_HACK(62);
|
||||||
|
_NS_COUNT_HACK(63); _NS_COUNT_HACK(64); _NS_COUNT_HACK(65);
|
||||||
|
_NS_COUNT_HACK(66); _NS_COUNT_HACK(67); _NS_COUNT_HACK(68);
|
||||||
|
_NS_COUNT_HACK(69); _NS_COUNT_HACK(70); _NS_COUNT_HACK(71);
|
||||||
|
_NS_COUNT_HACK(72); _NS_COUNT_HACK(73); _NS_COUNT_HACK(74);
|
||||||
|
_NS_COUNT_HACK(75); _NS_COUNT_HACK(76); _NS_COUNT_HACK(77);
|
||||||
|
_NS_COUNT_HACK(78); _NS_COUNT_HACK(79); _NS_COUNT_HACK(80);
|
||||||
|
_NS_COUNT_HACK(81); _NS_COUNT_HACK(82); _NS_COUNT_HACK(83);
|
||||||
|
_NS_COUNT_HACK(84); _NS_COUNT_HACK(85); _NS_COUNT_HACK(86);
|
||||||
|
_NS_COUNT_HACK(87); _NS_COUNT_HACK(88); _NS_COUNT_HACK(89);
|
||||||
|
_NS_COUNT_HACK(90); _NS_COUNT_HACK(91); _NS_COUNT_HACK(92);
|
||||||
|
_NS_COUNT_HACK(93); _NS_COUNT_HACK(94); _NS_COUNT_HACK(95);
|
||||||
|
_NS_COUNT_HACK(96); _NS_COUNT_HACK(97); _NS_COUNT_HACK(98);
|
||||||
|
_NS_COUNT_HACK(99);
|
||||||
|
|
||||||
|
done:
|
||||||
|
signal(SIGSEGV, old);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
env = jbuf();
|
||||||
|
val = (void*)env;
|
||||||
|
val += sizeof(jmp_buf);
|
||||||
|
memcpy(&old, val, sizeof(old));
|
||||||
|
signal(SIGSEGV, old);
|
||||||
|
}
|
||||||
|
|
||||||
|
val = (void*)env + sizeof(jmp_buf) + sizeof(old);
|
||||||
|
return *(unsigned*)val;
|
||||||
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
NSReturnAddress(int offset)
|
NSReturnAddress(int offset)
|
||||||
{
|
{
|
||||||
|
@ -982,7 +1051,9 @@ NSReturnAddress(int offset)
|
||||||
if (setjmp(*env) == 0)
|
if (setjmp(*env) == 0)
|
||||||
{
|
{
|
||||||
old = signal(SIGSEGV, recover);
|
old = signal(SIGSEGV, recover);
|
||||||
memcpy(env + 1, &old, sizeof(old));
|
val = (void*)env;
|
||||||
|
val += sizeof(jmp_buf);
|
||||||
|
memcpy(val, &old, sizeof(old));
|
||||||
switch (offset)
|
switch (offset)
|
||||||
{
|
{
|
||||||
_NS_RETURN_HACK(0); _NS_RETURN_HACK(1); _NS_RETURN_HACK(2);
|
_NS_RETURN_HACK(0); _NS_RETURN_HACK(1); _NS_RETURN_HACK(2);
|
||||||
|
@ -1025,8 +1096,9 @@ NSReturnAddress(int offset)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
env = jbuf();
|
val = jbuf();
|
||||||
memcpy(&old, env + 1, sizeof(old));
|
val += sizeof(jmp_buf);
|
||||||
|
memcpy(&old, val, sizeof(old));
|
||||||
signal(SIGSEGV, old);
|
signal(SIGSEGV, old);
|
||||||
val = NULL;
|
val = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1034,6 +1106,84 @@ NSReturnAddress(int offset)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NSMutableArray *
|
||||||
|
GSPrivateStackAddresses(void)
|
||||||
|
{
|
||||||
|
unsigned n = NSCountFrames();
|
||||||
|
NSMutableArray *stack = [NSMutableArray arrayWithCapacity: n];
|
||||||
|
unsigned i;
|
||||||
|
jmp_buf *env;
|
||||||
|
void (*old)(int);
|
||||||
|
void *val;
|
||||||
|
|
||||||
|
env = jbuf();
|
||||||
|
if (setjmp(*env) == 0)
|
||||||
|
{
|
||||||
|
old = signal(SIGSEGV, recover);
|
||||||
|
val = (void*)env;
|
||||||
|
val += sizeof(jmp_buf);
|
||||||
|
memcpy(val, &old, sizeof(old));
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
_NS_RETURN_HACK(0); _NS_RETURN_HACK(1); _NS_RETURN_HACK(2);
|
||||||
|
_NS_RETURN_HACK(3); _NS_RETURN_HACK(4); _NS_RETURN_HACK(5);
|
||||||
|
_NS_RETURN_HACK(6); _NS_RETURN_HACK(7); _NS_RETURN_HACK(8);
|
||||||
|
_NS_RETURN_HACK(9); _NS_RETURN_HACK(10); _NS_RETURN_HACK(11);
|
||||||
|
_NS_RETURN_HACK(12); _NS_RETURN_HACK(13); _NS_RETURN_HACK(14);
|
||||||
|
_NS_RETURN_HACK(15); _NS_RETURN_HACK(16); _NS_RETURN_HACK(17);
|
||||||
|
_NS_RETURN_HACK(18); _NS_RETURN_HACK(19); _NS_RETURN_HACK(20);
|
||||||
|
_NS_RETURN_HACK(21); _NS_RETURN_HACK(22); _NS_RETURN_HACK(23);
|
||||||
|
_NS_RETURN_HACK(24); _NS_RETURN_HACK(25); _NS_RETURN_HACK(26);
|
||||||
|
_NS_RETURN_HACK(27); _NS_RETURN_HACK(28); _NS_RETURN_HACK(29);
|
||||||
|
_NS_RETURN_HACK(30); _NS_RETURN_HACK(31); _NS_RETURN_HACK(32);
|
||||||
|
_NS_RETURN_HACK(33); _NS_RETURN_HACK(34); _NS_RETURN_HACK(35);
|
||||||
|
_NS_RETURN_HACK(36); _NS_RETURN_HACK(37); _NS_RETURN_HACK(38);
|
||||||
|
_NS_RETURN_HACK(39); _NS_RETURN_HACK(40); _NS_RETURN_HACK(41);
|
||||||
|
_NS_RETURN_HACK(42); _NS_RETURN_HACK(43); _NS_RETURN_HACK(44);
|
||||||
|
_NS_RETURN_HACK(45); _NS_RETURN_HACK(46); _NS_RETURN_HACK(47);
|
||||||
|
_NS_RETURN_HACK(48); _NS_RETURN_HACK(49); _NS_RETURN_HACK(50);
|
||||||
|
_NS_RETURN_HACK(51); _NS_RETURN_HACK(52); _NS_RETURN_HACK(53);
|
||||||
|
_NS_RETURN_HACK(54); _NS_RETURN_HACK(55); _NS_RETURN_HACK(56);
|
||||||
|
_NS_RETURN_HACK(57); _NS_RETURN_HACK(58); _NS_RETURN_HACK(59);
|
||||||
|
_NS_RETURN_HACK(60); _NS_RETURN_HACK(61); _NS_RETURN_HACK(62);
|
||||||
|
_NS_RETURN_HACK(63); _NS_RETURN_HACK(64); _NS_RETURN_HACK(65);
|
||||||
|
_NS_RETURN_HACK(66); _NS_RETURN_HACK(67); _NS_RETURN_HACK(68);
|
||||||
|
_NS_RETURN_HACK(69); _NS_RETURN_HACK(70); _NS_RETURN_HACK(71);
|
||||||
|
_NS_RETURN_HACK(72); _NS_RETURN_HACK(73); _NS_RETURN_HACK(74);
|
||||||
|
_NS_RETURN_HACK(75); _NS_RETURN_HACK(76); _NS_RETURN_HACK(77);
|
||||||
|
_NS_RETURN_HACK(78); _NS_RETURN_HACK(79); _NS_RETURN_HACK(80);
|
||||||
|
_NS_RETURN_HACK(81); _NS_RETURN_HACK(82); _NS_RETURN_HACK(83);
|
||||||
|
_NS_RETURN_HACK(84); _NS_RETURN_HACK(85); _NS_RETURN_HACK(86);
|
||||||
|
_NS_RETURN_HACK(87); _NS_RETURN_HACK(88); _NS_RETURN_HACK(89);
|
||||||
|
_NS_RETURN_HACK(90); _NS_RETURN_HACK(91); _NS_RETURN_HACK(92);
|
||||||
|
_NS_RETURN_HACK(93); _NS_RETURN_HACK(94); _NS_RETURN_HACK(95);
|
||||||
|
_NS_RETURN_HACK(96); _NS_RETURN_HACK(97); _NS_RETURN_HACK(98);
|
||||||
|
_NS_RETURN_HACK(99);
|
||||||
|
default: val = 0; break;
|
||||||
|
}
|
||||||
|
if (val == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
[stack addObject: [NSValue valueWithPointer: val]];
|
||||||
|
}
|
||||||
|
signal(SIGSEGV, old);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
env = jbuf();
|
||||||
|
val = (void*)env;
|
||||||
|
val += sizeof(jmp_buf);
|
||||||
|
memcpy(&old, val, sizeof(old));
|
||||||
|
signal(SIGSEGV, old);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *_NSPrintForDebugger(id object)
|
const char *_NSPrintForDebugger(id object)
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "config.h"
|
#import "config.h"
|
||||||
|
#import "GSPrivate.h"
|
||||||
#import "GNUstepBase/preface.h"
|
#import "GNUstepBase/preface.h"
|
||||||
#import <Foundation/NSDebug.h>
|
#import <Foundation/NSDebug.h>
|
||||||
#import <Foundation/NSBundle.h>
|
#import <Foundation/NSBundle.h>
|
||||||
|
@ -55,6 +56,7 @@ typedef struct { @defs(NSThread) } *TInfo;
|
||||||
- (NSMutableArray*) frames;
|
- (NSMutableArray*) frames;
|
||||||
- (id) frameAt: (unsigned)index;
|
- (id) frameAt: (unsigned)index;
|
||||||
- (unsigned) frameCount;
|
- (unsigned) frameCount;
|
||||||
|
- (id) initWithAddresses: (NSArray*)stack;
|
||||||
- (NSEnumerator*) reverseEnumerator;
|
- (NSEnumerator*) reverseEnumerator;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -561,17 +563,24 @@ GSListModules()
|
||||||
// grab the current stack
|
// grab the current stack
|
||||||
- (id) init
|
- (id) init
|
||||||
{
|
{
|
||||||
|
NSMutableArray *stack = GSPrivateStackAddresses();
|
||||||
|
|
||||||
|
return [self initWithAddresses: stack];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithAddresses: (NSArray*)stack
|
||||||
|
{
|
||||||
|
#if defined(STACKSYMBOLS)
|
||||||
int i;
|
int i;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
frames = [[NSMutableArray alloc] init];
|
n = [stack count];
|
||||||
n = NSCountFrames();
|
frames = [[NSMutableArray alloc] initWithCapacity: n];
|
||||||
|
|
||||||
#if defined(STACKSYMBOLS)
|
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
GSFunctionInfo *aFrame = nil;
|
GSFunctionInfo *aFrame = nil;
|
||||||
void *address = NSReturnAddress(i);
|
void *address = [[stack objectAtIndex: i] pointerValue];
|
||||||
void *base;
|
void *base;
|
||||||
NSString *modulePath = GSPrivateBaseAddress(address, &base);
|
NSString *modulePath = GSPrivateBaseAddress(address, &base);
|
||||||
GSBinaryFileInfo *bfi;
|
GSBinaryFileInfo *bfi;
|
||||||
|
@ -628,12 +637,7 @@ GSListModules()
|
||||||
[frames addObject: aFrame];
|
[frames addObject: aFrame];
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
for (i = 0; i < n; i++)
|
frames = [stack copy];
|
||||||
{
|
|
||||||
void *address = NSReturnAddress(i);
|
|
||||||
|
|
||||||
[frames addObject: [NSValue valueWithPointer: address]];
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
@ -646,35 +650,6 @@ GSListModules()
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a stack trace and convert it to an array of return addresses.
|
|
||||||
*/
|
|
||||||
@interface NSThread (Frames)
|
|
||||||
+ (NSArray*) callStackReturnAddresses;
|
|
||||||
@end
|
|
||||||
@implementation NSThread (Frames)
|
|
||||||
+ (NSArray*) callStackReturnAddresses
|
|
||||||
{
|
|
||||||
NSMutableArray *frames = [[GSStackTrace currentStack] frames];
|
|
||||||
#if defined(STACKSYMBOLS)
|
|
||||||
unsigned count = [frames count];
|
|
||||||
|
|
||||||
while (count-- > 0)
|
|
||||||
{
|
|
||||||
GSFunctionInfo *info = [frames objectAtIndex: count];
|
|
||||||
NSValue *address;
|
|
||||||
|
|
||||||
address = [NSValue valueWithPointer: [info address]];
|
|
||||||
[frames replaceObjectAtIndex: count
|
|
||||||
withObject: address];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return frames;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
NSString* const NSGenericException
|
NSString* const NSGenericException
|
||||||
= @"NSGenericException";
|
= @"NSGenericException";
|
||||||
|
@ -697,8 +672,6 @@ NSString* const NSCharacterConversionException
|
||||||
NSString* const NSParseErrorException
|
NSString* const NSParseErrorException
|
||||||
= @"NSParseErrorException";
|
= @"NSParseErrorException";
|
||||||
|
|
||||||
#include "GSPrivate.h"
|
|
||||||
|
|
||||||
static void _terminate()
|
static void _terminate()
|
||||||
{
|
{
|
||||||
BOOL shouldAbort;
|
BOOL shouldAbort;
|
||||||
|
@ -826,7 +799,7 @@ _NSFoundationUncaughtExceptionHandler (NSException *exception)
|
||||||
RELEASE(_e_info);
|
RELEASE(_e_info);
|
||||||
_e_info = m;
|
_e_info = m;
|
||||||
}
|
}
|
||||||
[m setObject: [GSStackTrace currentStack] forKey: @"GSStackTraceKey"];
|
[m setObject: GSPrivateStackAddresses() forKey: @"GSStackTraceKey"];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -948,11 +921,41 @@ _NSFoundationUncaughtExceptionHandler (NSException *exception)
|
||||||
- (NSString*) description
|
- (NSString*) description
|
||||||
{
|
{
|
||||||
if (_e_info)
|
if (_e_info)
|
||||||
return [NSString stringWithFormat: @"%@ NAME:%@ REASON:%@ INFO:%@",
|
{
|
||||||
|
/* Convert stack information from an array of addresses to a stacktrace
|
||||||
|
* for display.
|
||||||
|
*/
|
||||||
|
#if defined(STACKSYMBOLS)
|
||||||
|
id o;
|
||||||
|
|
||||||
|
o = [_e_info objectForKey: @"GSStackTraceKey"];
|
||||||
|
if ([o isKindOfClass: [NSArray class]] == YES)
|
||||||
|
{
|
||||||
|
NSMutableDictionary *m;
|
||||||
|
|
||||||
|
o = [[GSStackTrace alloc] initWithAddresses: o];
|
||||||
|
if ([_e_info isKindOfClass: [NSMutableDictionary class]] == YES)
|
||||||
|
{
|
||||||
|
m = (NSMutableDictionary*)_e_info;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m = [_e_info mutableCopy];
|
||||||
|
RELEASE(_e_info);
|
||||||
|
_e_info = m;
|
||||||
|
}
|
||||||
|
[m setObject: o forKey: @"GSStackTraceKey"];
|
||||||
|
RELEASE(o);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return [NSString stringWithFormat: @"%@ NAME:%@ REASON:%@ INFO:%@",
|
||||||
[super description], _e_name, _e_reason, _e_info];
|
[super description], _e_name, _e_reason, _e_info];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return [NSString stringWithFormat: @"%@ NAME:%@ REASON:%@",
|
{
|
||||||
|
return [NSString stringWithFormat: @"%@ NAME:%@ REASON:%@",
|
||||||
[super description], _e_name, _e_reason];
|
[super description], _e_name, _e_reason];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -484,12 +484,9 @@ gnustep_base_thread_callback(void)
|
||||||
|
|
||||||
+ (NSArray*) callStackReturnAddresses
|
+ (NSArray*) callStackReturnAddresses
|
||||||
{
|
{
|
||||||
/* NB. This method is actually implemented in a category in
|
NSMutableArray *stack = GSPrivateStackAddresses();
|
||||||
* The NSException.m file as the stack trace code there is
|
|
||||||
* able to set up an array of stack addresses and we don't
|
return stack;
|
||||||
* want to duplicate the code.
|
|
||||||
*/
|
|
||||||
return [self notImplemented: _cmd];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue