ETStackTraceRecorder documentation

Authors

Quentin Mathe (qmathe@club-internet.fr)
A debug utility to record stack traces in relation to an instance.

Copyright: (C) 2010 Quentin Mathe


Contents -

  1. Software documentation for the ETStackTrace class
  2. Software documentation for the ETStackTraceRecorder class
  3. Software documentation for the NSObject(ETStackTraceRecorderConveniency) category

Software documentation for the ETStackTrace class

ETStackTrace : NSObject

Declared in:
ETStackTraceRecorder.h

@group Debugging

Represents a stack trace built from an array of call stack symbols.

You usually don't need to instantiate stack trace objects directly, ETStackTraceRecorder does it.


Instance Variables

Method summary

init 

- (id) init;
This is a designated initialiser for the class.

Returns a new stack trace initialized with the call stack symbols of the current thread.


numberOfFrames 

- (NSUInteger) numberOfFrames;

Returns the number of stack frames.




Instance Variables for ETStackTrace Class

_callStackSymbols

@protected NSArray* _callStackSymbols;
Warning the underscore at the start of the name of this instance variable indicates that, even though it is not technically private, it is intended for internal use within the package, and you should not use the variable in other code.




Software documentation for the ETStackTraceRecorder class

ETStackTraceRecorder : NSObject

Declared in:
ETStackTraceRecorder.h

@group Debugging

A stack trace recorder allows to snapshot the call stack symbols and inspect these snapshots later on.

You invoke -recordForObject: to snapshot the current call stack symbols and -recordedStackTracesForObject: to get all the call stack traces recorded until now.

A stack trace recorder is very handy to debug memory management issues. e.g. You can easily discover where an over-released object was allocated in a vein similar to malloc_history on Mac OS X.
Take note that +enableAllocationRecordingForClass: is only available on GNUstep and the example detailed below doesn't apply to Mac OS X where you must use malloc_history instead.
To get meaningfull backtrace on GNUstep, you must install the GNU bin utils (e.g. binutils-dev package on Ubuntu) and configure GNUstep Base with --enable-bfd.
Be aware that the resulting gnustep-base library will be GPL-licensed and transively all the code that links it will become GPL-licensed too.

@section Use Case Example

For a retain/release crash, note the instance class that got double-released, then add in main() or equivalent:

[[ETStackTraceRecorder sharedInstance] enableAllocationRecordingForClass: [MyClass class]];

To prevent the instance to be deallocated, set NSZombieEnabled to YES (e.g. export NSZombieEnabled YES in the shell). Finally compile and run the program in GDB and at crash time, type on the GDB prompt:

po [[ETStackTraceRecorder sharedInstance] recordedStackTracesForObject: instance] firstObject]

Where instance is the instance address or a variable pointing on the instance. Then GDB prints the stack trace which points back to the code that allocated the instance.
You can also put a breakpoint on -[NSZombie forwardInvocation:], but take note that NSZombie doesn't respond to -recordedStackTraces (at least on GNUstep).

@section Thread Safety

ETStackTraceRecorder is thread-safe (not fully yet), multiple threads can invoke -recordForObject: .

Method summary

sharedInstance 

+ (id) sharedInstance;

@taskunit Initialization

Returns the shared stack trace recorder.

Returns the shared stack trace recorder.


disableAllocationRecordingForClass: 

- (void) disableAllocationRecordingForClass: (Class)aClass;

Disables the recording of the stack trace every time +allocWithZone: is called on the given class.

Doesn't apply subclasses. See -enableAllocationRecordingForClass: for more details.


enableAllocationRecordingForClass: 

- (void) enableAllocationRecordingForClass: (Class)aClass;

@taskunit Object Allocation Recording

Enables the recording of the stack trace every time +allocWithZone: is called on the given class.

Doesn't apply to subclasses. e.g. Using NSObject as argument won't trigger the allocation recording for every instances.
You must pass concrete subclasses to record class cluster allocations. e.g. GSDictionary for NSDictionary.

For now, using this method on other recorders than the one returned by +sharedInstance is not supported.

To detect object allocations, the receiver sets up alloc/dealloc callbacks with GSSetDebugAllocationFunctions() . You cannot use these hooks in your code and at the same time record the allocation with ETStackTraceRecorder.

Enables the recording of the stack trace every time +allocWithZone: is called on the given class.

Doesn't apply to subclasses. e.g. Using NSObject as argument won't trigger the allocation recording for every instances.
You must pass concrete subclasses to record class cluster allocations. e.g. GSDictionary for NSDictionary.

For now, using this method on other recorders than the one returned by +sharedInstance is not supported.

To detect object allocations, the receiver sets up alloc/dealloc callbacks with GSSetDebugAllocationFunctions() . You cannot use these hooks in your code and at the same time record the allocation with ETStackTraceRecorder.


init 

- (id) init;
This is a designated initialiser for the class.

Initializes and returns a new stack trace recorder.


recordForObject: 

- (void) recordForObject: (id)anObject;

@taskunit Recording and Accessing Stack Traces

Records the call stack symbols in relation to the given object.

Records the call stack symbols in relation to the given object.


recordedStackTracesForObject: 

- (NSArray*) recordedStackTracesForObject: (id)anObject;

Returns an array of stack traces previous recorded with -recordForObject: for the given object.

When no stack traces have been recorded for the given object, returns an empty array.


Software documentation for the NSObject(ETStackTraceRecorderConveniency) category

NSObject(ETStackTraceRecorderConveniency)

Declared in:
ETStackTraceRecorder.h

@group Debugging

Some conveniency methods which makes easier to work with the shared stack trace recorder instance.

For example, in GDB you can type [self recordStackTrace] to keep a trace of the current call stack.
And you can print all the stack traces recorded for the current object with 'po [[self recordedStackTraces] stringValue]'.

Method summary

recordStackTrace 

- (void) recordStackTrace;

Records the call stack symbols with the shared stack trace recorder.


recordedStackTraces 

- (NSArray*) recordedStackTraces;

Returns an array of stack traces previously recorded with the shared stack trace recorded for the receiver.