ObjFW  Check-in [f93fae010f]

Overview
Comment:OFException: Provide stack trace addresses
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: f93fae010f845d4978351ae5f77f719bf1aa737a631d21622b595de240a0409e
User & Date: js on 2022-09-29 21:26:08
Other Links: manifest | tags
Context
2022-09-29
21:53
OFURI: Make query items an array of pairs check-in: bd6dd6dd00 user: js tags: trunk
21:26
OFException: Provide stack trace addresses check-in: f93fae010f user: js tags: trunk
20:27
OFLocale: Rename a few methods check-in: 915bfc7431 user: js tags: trunk
Changes

Modified src/OFObject.m from [1199f442fe] to [da1d529dc6].

40
41
42
43
44
45
46

47
48
49
50
51
52
53
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54







+







#import "OFRunLoop.h"
#if !defined(OF_HAVE_ATOMIC_OPS) && defined(OF_HAVE_THREADS)
# import "OFPlainMutex.h"	/* For OFSpinlock */
#endif
#import "OFString.h"
#import "OFThread.h"
#import "OFTimer.h"
#import "OFValue.h"

#import "OFAllocFailedException.h"
#import "OFEnumerationMutationException.h"
#import "OFInitializationFailedException.h"
#import "OFInvalidArgumentException.h"
#import "OFNotImplementedException.h"
#import "OFOutOfMemoryException.h"
248
249
250
251
252
253
254
255


256
257
258
259
260
261
262





263



264
265
266
267


























268
269
270
271
272
273
274
249
250
251
252
253
254
255

256
257
258
259
260
261
262


263
264
265
266
267
268
269
270
271




272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304







-
+
+





-
-
+
+
+
+
+

+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







}

#if !defined(OF_APPLE_RUNTIME) || defined(__OBJC2__)
static void
uncaughtExceptionHandler(id exception)
{
	OFString *description = [exception description];
	OFArray *backtrace = nil;
	OFArray OF_GENERIC(OFValue *) *stackTraceAddresses = nil;
	OFArray OF_GENERIC(OFString *) *stackTraceSymbols = nil;
	OFStringEncoding encoding = [OFLocale encoding];

	fprintf(stderr, "\nRuntime error: Unhandled exception:\n%s\n",
	    [description cStringWithEncoding: encoding]);

	if ([exception respondsToSelector: @selector(backtrace)])
		backtrace = [exception backtrace];
	if ([exception respondsToSelector: @selector(stackTraceAddresses)])
		stackTraceAddresses = [exception stackTraceAddresses];

	if (stackTraceAddresses != nil) {
		size_t count = stackTraceAddresses.count;

		if ([exception respondsToSelector:
		    @selector(stackTraceSymbols)])
			stackTraceSymbols = [exception stackTraceSymbols];
	if (backtrace != nil) {
		OFString *s = [backtrace componentsJoinedByString: @"\n  "];
		fprintf(stderr, "\nBacktrace:\n  %s\n\n",
		    [s cStringWithEncoding: encoding]);

		if (stackTraceSymbols.count != count)
			stackTraceSymbols = nil;

		fputs("\nBacktrace:\n", stderr);

		if (stackTraceSymbols != nil) {
			for (size_t i = 0; i < count; i++) {
				void *address = [[stackTraceAddresses
				    objectAtIndex: i] pointerValue];
				const char *symbol = [[stackTraceSymbols
				    objectAtIndex: i]
				    cStringWithEncoding: encoding];

				fprintf(stderr, "  %p  %s\n", address, symbol);
			}
		} else {
			for (size_t i = 0; i < count; i++) {
				void *address = [[stackTraceAddresses
				    objectAtIndex: i] pointerValue];

				fprintf(stderr, "  %p\n", address);
			}
		}

		fputs("\n", stderr);
	}

	abort();
}
#endif

static void

Modified src/exceptions/OFException.h from [6d2e250849] to [e7c0836484].

18
19
20
21
22
23
24
25
26


27
28

29
30
31
32
33
34
35
18
19
20
21
22
23
24


25
26
27

28
29
30
31
32
33
34
35







-
-
+
+

-
+







#ifdef OF_WINDOWS
# include <windows.h>
#endif

OF_ASSUME_NONNULL_BEGIN

@class OFArray OF_GENERIC(ObjectType);
@class OFMutableArray OF_GENERIC(ObjectType);
@class OFString;
@class OFString;
@class OFValue;

#define OFBacktraceSize 16
#define OFStackTraceSize 16

#if defined(OF_WINDOWS) && defined(OF_HAVE_SOCKETS)
# ifndef EADDRINUSE
#  define EADDRINUSE WSAEADDRINUSE
# endif
# ifndef EADDRNOTAVAIL
#  define EADDRNOTAVAIL WSAEADDRNOTAVAIL
145
146
147
148
149
150
151
152

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172



173





174




175
176

177
178
179
180
181
182
183
145
146
147
148
149
150
151

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170


171
172
173
174
175
176
177
178
179

180
181
182
183
184

185
186
187
188
189
190
191
192







-
+


















-
-
+
+
+

+
+
+
+
+
-
+
+
+
+

-
+







 * @brief The base class for all exceptions in ObjFW
 *
 * The OFException class is the base class for all exceptions in ObjFW, except
 * the OFAllocFailedException.
 */
@interface OFException: OFObject
{
	void *_backtrace[OFBacktraceSize];
	void *_stackTrace[OFStackTraceSize];
	OF_RESERVE_IVARS(OFException, 4)
}

/**
 * @brief Creates a new, autoreleased exception.
 *
 * @return A new, autoreleased exception
 */
+ (instancetype)exception;

/**
 * @brief Returns a description of the exception.
 *
 * @return A description of the exception
 */
- (OFString *)description;

/**
 * @brief Returns a backtrace of when the exception was created or nil if no
 *	  backtrace is available.
 * @brief Returns a stack trace of when the exception was created or `nil` if
 *	  no stack trace is available. The returned array contains OFValues
 *	  with @ref OFValue#pointerValue set to the address.
 *
 * @return The stack trace as array of addresses
 */
- (nullable OFArray OF_GENERIC(OFValue *) *)stackTraceAddresses;

/**
 * @return A backtrace of when the exception was created
 * @brief Returns a stack trace of when the exception was created or `nil` if
 *	  no stack trace symbols are available.
 *
 * @return The stack trace as array of symbols
 */
- (nullable OFArray OF_GENERIC(OFString *) *)backtrace;
- (nullable OFArray OF_GENERIC(OFString *) *)stackTraceSymbols;
@end

#ifdef __cplusplus
extern "C" {
#endif
extern OFString *OFStrError(int errNo);
#ifdef OF_WINDOWS

Modified src/exceptions/OFException.m from [21f1fa3002] to [700714ee53].

28
29
30
31
32
33
34

35
36
37
38
39
40
41
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42







+







#import "OFArray.h"
#import "OFLocale.h"
#ifdef OF_HAVE_THREADS
# import "OFPlainMutex.h"
#endif
#import "OFString.h"
#import "OFSystemInfo.h"
#import "OFValue.h"

#import "OFInitializationFailedException.h"
#import "OFLockFailedException.h"
#import "OFUnlockFailedException.h"

#if defined(OF_WINDOWS) && defined(OF_HAVE_SOCKETS)
# include <winerror.h>
254
255
256
257
258
259
260
261

262
263
264
265
266
267
268
255
256
257
258
259
260
261

262
263
264
265
266
267
268
269







-
+








#ifdef HAVE__UNWIND_BACKTRACE
static _Unwind_Reason_Code
backtraceCallback(struct _Unwind_Context *ctx, void *data)
{
	struct BacktraceCtx *bt = data;

	if (bt->i < OFBacktraceSize) {
	if (bt->i < OFStackTraceSize) {
# ifndef HAVE_ARM_EHABI_EXCEPTIONS
		bt->backtrace[bt->i++] = (void *)_Unwind_GetIP(ctx);
# else
		uintptr_t ip;

		_Unwind_VRS_Get(ctx, 0, 15, 0, &ip);
		bt->backtrace[bt->i++] = (void *)(ip & ~1);
283
284
285
286
287
288
289
290

291
292
293
294
295
296
297
298
299
300
301
302
303
304

305
306
307

308
309
310

311
312























313
314
315



316
317
318
319
320
321





322
323
324
325
326





327
328
329

330
331

332
333
334
335


336
337
338
339
340

341
342

343
344
345
346
347
284
285
286
287
288
289
290

291
292
293
294
295
296
297
298
299
300
301
302
303
304

305
306
307

308
309
310
311
312


313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337

338
339
340
341
342




343
344
345
346
347
348




349
350
351
352
353
354


355
356

357
358



359
360
361
362
363
364

365
366

367
368
369
370
371
372







-
+













-
+


-
+



+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


-
+
+
+


-
-
-
-
+
+
+
+
+

-
-
-
-
+
+
+
+
+

-
-
+

-
+

-
-
-
+
+




-
+

-
+





#ifdef HAVE__UNWIND_BACKTRACE
- (instancetype)init
{
	struct BacktraceCtx ctx;

	self = [super init];

	ctx.backtrace = _backtrace;
	ctx.backtrace = _stackTrace;
	ctx.i = 0;
	_Unwind_Backtrace(backtraceCallback, &ctx);

	return self;
}
#endif

- (OFString *)description
{
	return [OFString stringWithFormat:
	    @"An exception of type %@ occurred!", self.class];
}

- (OFArray OF_GENERIC(OFString *) *)backtrace
- (OFArray OF_GENERIC(OFValue *) *)stackTraceAddresses
{
#ifdef HAVE__UNWIND_BACKTRACE
	OFMutableArray OF_GENERIC(OFString *) *backtrace =
	OFMutableArray OF_GENERIC(OFValue *) *stackTrace =
	    [OFMutableArray array];
	void *pool = objc_autoreleasePoolPush();

	for (uint_fast8_t i = 0; i < OFStackTraceSize &&
	for (uint8_t i = 0; i < OFBacktraceSize && _backtrace[i] != NULL; i++) {
# ifdef HAVE_DLADDR
	    _stackTrace[i] != NULL; i++)
		[stackTrace addObject:
		    [OFValue valueWithPointer: _stackTrace[i]]];

	objc_autoreleasePoolPop(pool);

	[stackTrace makeImmutable];

	return stackTrace;
#else
	return nil;
#endif
}

- (OFArray OF_GENERIC(OFString *) *)stackTraceSymbols
{
#if defined(HAVE__UNWIND_BACKTRACE) && defined(HAVE_DLADDR)
	OFMutableArray OF_GENERIC(OFString *) *stackTrace =
	    [OFMutableArray array];
	void *pool = objc_autoreleasePoolPush();

	for (uint_fast8_t i = 0; i < OFStackTraceSize &&
	    _stackTrace[i] != NULL; i++) {
		Dl_info info;

		if (dladdr(_backtrace[i], &info)) {
		if (dladdr(_stackTrace[i], &info)) {
			ptrdiff_t offset = (char *)_stackTrace[i] -
			    (char *)info.dli_saddr;
			OFString *frame;

			if (info.dli_sname != NULL) {
				ptrdiff_t offset = (char *)_backtrace[i] -
				    (char *)info.dli_saddr;

			if (info.dli_fname != NULL && info.dli_sname != NULL)
				frame = [OFString stringWithFormat:
				    @"%s`%s+%td",
				    info.dli_fname, info.dli_sname, offset];
			else if (info.dli_sname != NULL)
				frame = [OFString stringWithFormat:
				    @"%p <%s+%td> at %s",
				    _backtrace[i], info.dli_sname, offset,
				    info.dli_fname];
			} else
				    @"%s+%td", info.dli_sname, offset];
			else if (info.dli_fname != NULL)
				frame = [OFString stringWithFormat:
				    @"%s`%p", info.dli_fname, _stackTrace[i]];
			else
				frame = [OFString stringWithFormat:
				    @"%p <?" @"?> at %s",
				    _backtrace[i], info.dli_fname];
				    @"%p", _stackTrace[i]];

			[backtrace addObject: frame];
			[stackTrace addObject: frame];
		} else
# endif
			[backtrace addObject:
			    [OFString stringWithFormat: @"%p", _backtrace[i]]];
			[stackTrace addObject:
			    [OFString stringWithFormat: @"%p", _stackTrace[i]]];
	}

	objc_autoreleasePoolPop(pool);

	[backtrace makeImmutable];
	[stackTrace makeImmutable];

	return backtrace;
	return stackTrace;
#else
	return nil;
#endif
}
@end