ObjFW  Check-in [974d386554]

Overview
Comment:runtime/exception.m: Forward foreign exceptions

This allows handling C++ exceptions.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 974d38655424ab33fbd489419206bf8659d0132e6b29d009fefeaf5853d7081d
User & Date: js on 2016-07-18 18:45:17
Other Links: manifest | tags
Context
2016-07-18
18:53
ObjFW.h: Fix missing imports check-in: 6a4f4bcde1 user: js tags: trunk
18:45
runtime/exception.m: Forward foreign exceptions check-in: 974d386554 user: js tags: trunk
2016-07-11
19:04
Windows improvements for of_dl{open,sym,close} check-in: c91508ddfb user: js tags: trunk
Changes

Modified configure.ac from [14d6dc27f7] to [63d666586e].

402
403
404
405
406
407
408



409
410
411
412
413
414
415
])

case "$host_os" in
	darwin*)
		AC_SUBST(LDFLAGS_REEXPORT, ["-Wl,-reexport-lobjfw"])
		AS_IF([test x"$objc_runtime" = x"Apple runtime"], [
			AC_SUBST(REEXPORT_LIBOBJC, ["-Wl,-reexport-lobjc"])



		])
		;;
esac

AC_C_BIGENDIAN([
	AC_DEFINE(OF_BIG_ENDIAN, 1, [Whether we are big endian])
])







>
>
>







402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
])

case "$host_os" in
	darwin*)
		AC_SUBST(LDFLAGS_REEXPORT, ["-Wl,-reexport-lobjfw"])
		AS_IF([test x"$objc_runtime" = x"Apple runtime"], [
			AC_SUBST(REEXPORT_LIBOBJC, ["-Wl,-reexport-lobjc"])
		])
		AS_IF([test x"$objc_runtime" = x"ObjFW runtime"], [
			LDFLAGS="$LDFLAGS -Wl,-U,___gxx_personality_v0"
		])
		;;
esac

AC_C_BIGENDIAN([
	AC_DEFINE(OF_BIG_ENDIAN, 1, [Whether we are big endian])
])

Modified src/runtime/exception.m from [30cec995ef] to [438f4d8af0].

25
26
27
28
29
30
31
32

33
34

35
36
37
38

39
40
41
42
43
44
45
46













47



48
49
50
51
52
53
54

#import "runtime.h"
#import "runtime-private.h"

#import "macros.h"

#if defined(HAVE_DWARF_EXCEPTIONS)
# define PERSONALITY __gnu_objc_personality_v0

#elif defined(HAVE_SJLJ_EXCEPTIONS)
# define PERSONALITY __gnu_objc_personality_sj0

# define _Unwind_RaiseException _Unwind_SjLj_RaiseException
# define __builtin_eh_return_data_regno(i) (i)
#elif defined(HAVE_SEH_EXCEPTIONS)
# define PERSONALITY gnu_objc_personality

#else
# error Unknown exception type!
#endif

#if defined(OF_ARM) && !defined(__ARM_DWARF_EH__)
# define HAVE_ARM_EHABI_EXCEPTIONS
#endif














static const uint64_t objc_exception_class = 0x474E55434F424A43; /* GNUCOBJC */




#define _UA_SEARCH_PHASE  0x01
#define _UA_CLEANUP_PHASE 0x02
#define _UA_HANDLER_FRAME 0x04
#define _UA_FORCE_UNWIND  0x08

#define DW_EH_PE_absptr	  0x00







|
>

|
>



|
>








>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

#import "runtime.h"
#import "runtime-private.h"

#import "macros.h"

#if defined(HAVE_DWARF_EXCEPTIONS)
# define PERSONALITY	 __gnu_objc_personality_v0
# define CXX_PERSONALITY __gxx_personality_v0
#elif defined(HAVE_SJLJ_EXCEPTIONS)
# define PERSONALITY	 __gnu_objc_personality_sj0
# define CXX_PERSONALITY __gxx_personality_sj0
# define _Unwind_RaiseException _Unwind_SjLj_RaiseException
# define __builtin_eh_return_data_regno(i) (i)
#elif defined(HAVE_SEH_EXCEPTIONS)
# define PERSONALITY	 gnu_objc_personality
# define CXX_PERSONALITY __gxx_personality_seh0
#else
# error Unknown exception type!
#endif

#if defined(OF_ARM) && !defined(__ARM_DWARF_EH__)
# define HAVE_ARM_EHABI_EXCEPTIONS
#endif

#ifndef HAVE_ARM_EHABI_EXCEPTIONS
# define PERSONALITY_FUNC(func)						\
	_Unwind_Reason_Code						\
	func(int version, int actions, uint64_t ex_class,		\
	    struct _Unwind_Exception *ex, struct _Unwind_Context *ctx)
# define CALL_PERSONALITY(func) func(version, actions, ex_class, ex, ctx)
#else
# define PERSONALITY_FUNC(func)						\
	_Unwind_Reason_Code						\
	func(uint32_t state, struct _Unwind_Exception *ex,		\
	    struct _Unwind_Context *ctx)
# define CALL_PERSONALITY(func) func(state, ex, ctx)
#endif

#define GNUCOBJC_EXCEPTION_CLASS UINT64_C(0x474E55434F424A43) /* GNUCOBJC */
#define GNUCCXX0_EXCEPTION_CLASS UINT64_C(0x474E5543432B2B00) /* GNUCC++\0 */
#define CLNGCXX0_EXCEPTION_CLASS UINT64_C(0x434C4E47432B2B00) /* CLNGC++\0 */

#define _UA_SEARCH_PHASE  0x01
#define _UA_CLEANUP_PHASE 0x02
#define _UA_HANDLER_FRAME 0x04
#define _UA_FORCE_UNWIND  0x08

#define DW_EH_PE_absptr	  0x00
191
192
193
194
195
196
197


198
199
200
201
202
203
204
static inline void
_Unwind_SetIP(struct _Unwind_Context *ctx, uintptr_t value)
{
	uintptr_t thumb = _Unwind_GetGR(ctx, 15) & 1;
	_Unwind_SetGR(ctx, 15, (value | thumb));
}
#endif



#ifdef HAVE_SEH_EXCEPTIONS
extern EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void*,
    PCONTEXT, PDISPATCHER_CONTEXT, _Unwind_Reason_Code(*)(int, int, uint64_t,
    struct _Unwind_Exception*, struct _Unwind_Context*));
#endif








>
>







210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
static inline void
_Unwind_SetIP(struct _Unwind_Context *ctx, uintptr_t value)
{
	uintptr_t thumb = _Unwind_GetGR(ctx, 15) & 1;
	_Unwind_SetGR(ctx, 15, (value | thumb));
}
#endif

extern PERSONALITY_FUNC(CXX_PERSONALITY) __attribute__((__weak__));

#ifdef HAVE_SEH_EXCEPTIONS
extern EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void*,
    PCONTEXT, PDISPATCHER_CONTEXT, _Unwind_Reason_Code(*)(int, int, uint64_t,
    struct _Unwind_Exception*, struct _Unwind_Context*));
#endif

504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523

524
525
526
527
528
529
530
		else if (filter < 0)
			OBJC_ERROR("Invalid filter!")
	} while (displacement != 0);

	return 0;
}

#ifndef HAVE_ARM_EHABI_EXCEPTIONS
# ifdef HAVE_SEH_EXCEPTIONS
static
# endif
_Unwind_Reason_Code
PERSONALITY(int version, int actions, uint64_t ex_class,
    struct _Unwind_Exception *ex, struct _Unwind_Context *ctx)
{
#else
_Unwind_Reason_Code
PERSONALITY(uint32_t state, struct _Unwind_Exception *ex,
    struct _Unwind_Context *ctx)
{

	int version = 1;
	uint64_t ex_class = ex->class;
	int actions;

	switch (state) {
	case 0:	/* _US_VIRTUAL_UNWIND_FRAME */
		actions = _UA_SEARCH_PHASE;







<
|

|
<
|
<

<
<
<
<
<
>







525
526
527
528
529
530
531

532
533
534

535

536





537
538
539
540
541
542
543
544
		else if (filter < 0)
			OBJC_ERROR("Invalid filter!")
	} while (displacement != 0);

	return 0;
}


#ifdef HAVE_SEH_EXCEPTIONS
static
#endif

PERSONALITY_FUNC(PERSONALITY)

{





#ifdef HAVE_ARM_EHABI_EXCEPTIONS
	int version = 1;
	uint64_t ex_class = ex->class;
	int actions;

	switch (state) {
	case 0:	/* _US_VIRTUAL_UNWIND_FRAME */
		actions = _UA_SEARCH_PHASE;
539
540
541
542
543
544
545
546
547
548
549
550
551















552
553
554
555
556
557
558
	default:
		return _URC_FAILURE;
	}

	_Unwind_SetGR(ctx, 12, (uintptr_t)ex);
#endif
	struct objc_exception *e = (struct objc_exception*)ex;
	bool foreign = (ex_class != objc_exception_class);
	const uint8_t *lsda_addr, *actionrecords;
	struct lsda lsda;
	uintptr_t landingpad = 0;
	uint8_t found = 0;
	intptr_t filter = 0;
















	if (version != 1 || ctx == NULL)
		return _URC_FATAL_PHASE1_ERROR;

	/*
	 * We already cached everything we found in phase 1, so we only need
	 * to install the context in phase 2.







|





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
	default:
		return _URC_FAILURE;
	}

	_Unwind_SetGR(ctx, 12, (uintptr_t)ex);
#endif
	struct objc_exception *e = (struct objc_exception*)ex;
	bool foreign = (ex_class != GNUCOBJC_EXCEPTION_CLASS);
	const uint8_t *lsda_addr, *actionrecords;
	struct lsda lsda;
	uintptr_t landingpad = 0;
	uint8_t found = 0;
	intptr_t filter = 0;

	if (foreign) {
		switch (ex_class) {
		case GNUCCXX0_EXCEPTION_CLASS:
		case CLNGCXX0_EXCEPTION_CLASS:
			if (__gxx_personality_v0 != NULL)
				return CALL_PERSONALITY(CXX_PERSONALITY);
			break;
		}

		/*
		 * None matched or none available - we'll try to handle it
		 * anyway, but will most likely fail.
		 */
	}

	if (version != 1 || ctx == NULL)
		return _URC_FATAL_PHASE1_ERROR;

	/*
	 * We already cached everything we found in phase 1, so we only need
	 * to install the context in phase 2.
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
{
	struct objc_exception *e;

	if ((e = malloc(sizeof(*e))) == NULL)
		OBJC_ERROR("Not enough memory to allocate exception!")

	memset(e, 0, sizeof(*e));
	e->exception.class = objc_exception_class;
	e->exception.cleanup = cleanup;
	e->object = object;

	if (_Unwind_RaiseException(&e->exception) == _URC_END_OF_STACK &&
	    uncaught_exception_handler != NULL)
		uncaught_exception_handler(object);








|







667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
{
	struct objc_exception *e;

	if ((e = malloc(sizeof(*e))) == NULL)
		OBJC_ERROR("Not enough memory to allocate exception!")

	memset(e, 0, sizeof(*e));
	e->exception.class = GNUCOBJC_EXCEPTION_CLASS;
	e->exception.cleanup = cleanup;
	e->object = object;

	if (_Unwind_RaiseException(&e->exception) == _URC_END_OF_STACK &&
	    uncaught_exception_handler != NULL)
		uncaught_exception_handler(object);