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:
Richard Frith-MacDonald 2007-12-03 14:13:57 +00:00
parent 2fffab15b7
commit 9c36ec10dd
5 changed files with 234 additions and 66 deletions

View file

@ -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>
* Source/NSDecimal.m (GSDecimalDouble): Use NAN when available.

View file

@ -378,6 +378,11 @@ void GSPrivateNotifyIdle(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).
*/
unsigned

View file

@ -29,6 +29,7 @@
#include "config.h"
#include <stdio.h>
#include "GSPrivate.h"
#include "GNUstepBase/GSLock.h"
#include "Foundation/NSArray.h"
#include "Foundation/NSData.h"
@ -38,6 +39,7 @@
#include "Foundation/NSNotification.h"
#include "Foundation/NSNotificationQueue.h"
#include "Foundation/NSThread.h"
#include "Foundation/NSValue.h"
typedef struct {
Class class;
@ -854,15 +856,6 @@ GSDebugMethodMsg(id obj, SEL sel, const char *file, int line, NSString *fmt)
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_RETURN_HACK(a) case a: val = __builtin_return_address(a + 1); break;
@ -893,7 +886,7 @@ jbuf()
if (d == nil)
{
d = [[NSMutableData alloc] initWithLength:
sizeof(jmp_buf) + sizeof(void(*)(int))];
sizeof(jmp_buf) + sizeof(void(*)(int)) + sizeof(void*)];
[[[NSThread currentThread] threadDictionary] setObject: d
forKey: @"GSjbuf"];
RELEASE(d);
@ -920,7 +913,9 @@ NSFrameAddress(int offset)
if (setjmp(*env) == 0)
{
old = signal(SIGSEGV, recover);
memcpy(env + 1, &old, sizeof(old));
val = (void*)env;
val += sizeof(jmp_buf);
memcpy(val, &old, sizeof(old));
switch (offset)
{
_NS_FRAME_HACK(0); _NS_FRAME_HACK(1); _NS_FRAME_HACK(2);
@ -963,14 +958,88 @@ NSFrameAddress(int offset)
}
else
{
env = jbuf();
memcpy(&old, env + 1, sizeof(old));
val = jbuf();
val += sizeof(jmp_buf);
memcpy(&old, val, sizeof(old));
signal(SIGSEGV, old);
val = NULL;
}
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 *
NSReturnAddress(int offset)
{
@ -982,7 +1051,9 @@ NSReturnAddress(int offset)
if (setjmp(*env) == 0)
{
old = signal(SIGSEGV, recover);
memcpy(env + 1, &old, sizeof(old));
val = (void*)env;
val += sizeof(jmp_buf);
memcpy(val, &old, sizeof(old));
switch (offset)
{
_NS_RETURN_HACK(0); _NS_RETURN_HACK(1); _NS_RETURN_HACK(2);
@ -1025,8 +1096,9 @@ NSReturnAddress(int offset)
}
else
{
env = jbuf();
memcpy(&old, env + 1, sizeof(old));
val = jbuf();
val += sizeof(jmp_buf);
memcpy(&old, val, sizeof(old));
signal(SIGSEGV, old);
val = NULL;
}
@ -1034,6 +1106,84 @@ NSReturnAddress(int offset)
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)
{

View file

@ -25,6 +25,7 @@
*/
#import "config.h"
#import "GSPrivate.h"
#import "GNUstepBase/preface.h"
#import <Foundation/NSDebug.h>
#import <Foundation/NSBundle.h>
@ -55,6 +56,7 @@ typedef struct { @defs(NSThread) } *TInfo;
- (NSMutableArray*) frames;
- (id) frameAt: (unsigned)index;
- (unsigned) frameCount;
- (id) initWithAddresses: (NSArray*)stack;
- (NSEnumerator*) reverseEnumerator;
@end
@ -561,17 +563,24 @@ GSListModules()
// grab the current stack
- (id) init
{
NSMutableArray *stack = GSPrivateStackAddresses();
return [self initWithAddresses: stack];
}
- (id) initWithAddresses: (NSArray*)stack
{
#if defined(STACKSYMBOLS)
int i;
int n;
frames = [[NSMutableArray alloc] init];
n = NSCountFrames();
n = [stack count];
frames = [[NSMutableArray alloc] initWithCapacity: n];
#if defined(STACKSYMBOLS)
for (i = 0; i < n; i++)
{
GSFunctionInfo *aFrame = nil;
void *address = NSReturnAddress(i);
void *address = [[stack objectAtIndex: i] pointerValue];
void *base;
NSString *modulePath = GSPrivateBaseAddress(address, &base);
GSBinaryFileInfo *bfi;
@ -628,12 +637,7 @@ GSListModules()
[frames addObject: aFrame];
}
#else
for (i = 0; i < n; i++)
{
void *address = NSReturnAddress(i);
[frames addObject: [NSValue valueWithPointer: address]];
}
frames = [stack copy];
#endif
return self;
@ -646,35 +650,6 @@ GSListModules()
@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
= @"NSGenericException";
@ -697,8 +672,6 @@ NSString* const NSCharacterConversionException
NSString* const NSParseErrorException
= @"NSParseErrorException";
#include "GSPrivate.h"
static void _terminate()
{
BOOL shouldAbort;
@ -826,7 +799,7 @@ _NSFoundationUncaughtExceptionHandler (NSException *exception)
RELEASE(_e_info);
_e_info = m;
}
[m setObject: [GSStackTrace currentStack] forKey: @"GSStackTraceKey"];
[m setObject: GSPrivateStackAddresses() forKey: @"GSStackTraceKey"];
}
#endif
@ -948,11 +921,41 @@ _NSFoundationUncaughtExceptionHandler (NSException *exception)
- (NSString*) description
{
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];
}
else
return [NSString stringWithFormat: @"%@ NAME:%@ REASON:%@",
{
return [NSString stringWithFormat: @"%@ NAME:%@ REASON:%@",
[super description], _e_name, _e_reason];
}
}
@end

View file

@ -484,12 +484,9 @@ gnustep_base_thread_callback(void)
+ (NSArray*) callStackReturnAddresses
{
/* NB. This method is actually implemented in a category in
* The NSException.m file as the stack trace code there is
* able to set up an array of stack addresses and we don't
* want to duplicate the code.
*/
return [self notImplemented: _cmd];
NSMutableArray *stack = GSPrivateStackAddresses();
return stack;
}
/**