1//===--- EHPersonality.cpp - Shared EH personality descriptions -----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "clang/CodeGenUtils/EHPersonality.h"
10#include "clang/AST/Decl.h"
11#include "clang/Basic/CodeGenOptions.h"
12#include "clang/Basic/LangOptions.h"
13#include "clang/Basic/TargetInfo.h"
14
15namespace clang::CodeGenUtils {
16
17const EHPersonality EHPersonality::GNU_C = {.PersonalityFn: "__gcc_personality_v0", .CatchallRethrowFn: nullptr};
18const EHPersonality EHPersonality::GNU_C_SJLJ = {.PersonalityFn: "__gcc_personality_sj0",
19 .CatchallRethrowFn: nullptr};
20const EHPersonality EHPersonality::GNU_C_SEH = {.PersonalityFn: "__gcc_personality_seh0",
21 .CatchallRethrowFn: nullptr};
22const EHPersonality EHPersonality::NeXT_ObjC = {.PersonalityFn: "__objc_personality_v0",
23 .CatchallRethrowFn: nullptr};
24const EHPersonality EHPersonality::GNU_CPlusPlus = {.PersonalityFn: "__gxx_personality_v0",
25 .CatchallRethrowFn: nullptr};
26const EHPersonality EHPersonality::GNU_CPlusPlus_SJLJ = {
27 .PersonalityFn: "__gxx_personality_sj0", .CatchallRethrowFn: nullptr};
28const EHPersonality EHPersonality::GNU_CPlusPlus_SEH = {
29 .PersonalityFn: "__gxx_personality_seh0", .CatchallRethrowFn: nullptr};
30const EHPersonality EHPersonality::GNU_ObjC = {.PersonalityFn: "__gnu_objc_personality_v0",
31 .CatchallRethrowFn: "objc_exception_throw"};
32const EHPersonality EHPersonality::GNU_ObjC_SJLJ = {
33 .PersonalityFn: "__gnu_objc_personality_sj0", .CatchallRethrowFn: "objc_exception_throw"};
34const EHPersonality EHPersonality::GNU_ObjC_SEH = {
35 .PersonalityFn: "__gnu_objc_personality_seh0", .CatchallRethrowFn: "objc_exception_throw"};
36const EHPersonality EHPersonality::GNU_ObjCXX = {
37 .PersonalityFn: "__gnustep_objcxx_personality_v0", .CatchallRethrowFn: nullptr};
38const EHPersonality EHPersonality::GNUstep_ObjC = {
39 .PersonalityFn: "__gnustep_objc_personality_v0", .CatchallRethrowFn: nullptr};
40const EHPersonality EHPersonality::MSVC_except_handler = {.PersonalityFn: "_except_handler3",
41 .CatchallRethrowFn: nullptr};
42const EHPersonality EHPersonality::MSVC_C_specific_handler = {
43 .PersonalityFn: "__C_specific_handler", .CatchallRethrowFn: nullptr};
44const EHPersonality EHPersonality::MSVC_CxxFrameHandler3 = {
45 .PersonalityFn: "__CxxFrameHandler3", .CatchallRethrowFn: nullptr};
46const EHPersonality EHPersonality::GNU_Wasm_CPlusPlus = {
47 .PersonalityFn: "__gxx_wasm_personality_v0", .CatchallRethrowFn: nullptr};
48const EHPersonality EHPersonality::XL_CPlusPlus = {.PersonalityFn: "__xlcxx_personality_v1",
49 .CatchallRethrowFn: nullptr};
50const EHPersonality EHPersonality::ZOS_CPlusPlus = {.PersonalityFn: "__zos_cxx_personality_v2",
51 .CatchallRethrowFn: nullptr};
52
53static const EHPersonality &getCPersonality(const TargetInfo &Target,
54 const CodeGenOptions &CGOpts) {
55 const llvm::Triple &T = Target.getTriple();
56 if (T.isWindowsMSVCEnvironment())
57 return EHPersonality::MSVC_CxxFrameHandler3;
58 if (CGOpts.hasSjLjExceptions())
59 return EHPersonality::GNU_C_SJLJ;
60 if (CGOpts.hasDWARFExceptions())
61 return EHPersonality::GNU_C;
62 if (CGOpts.hasSEHExceptions())
63 return EHPersonality::GNU_C_SEH;
64 return EHPersonality::GNU_C;
65}
66
67static const EHPersonality &getObjCPersonality(const TargetInfo &Target,
68 const CodeGenOptions &CGOpts,
69 const LangOptions &L) {
70 const llvm::Triple &T = Target.getTriple();
71 if (T.isWindowsMSVCEnvironment())
72 return EHPersonality::MSVC_CxxFrameHandler3;
73 if (T.isWasm())
74 return EHPersonality::GNU_Wasm_CPlusPlus;
75
76 switch (L.ObjCRuntime.getKind()) {
77 case ObjCRuntime::FragileMacOSX:
78 return getCPersonality(Target, CGOpts);
79 case ObjCRuntime::MacOSX:
80 case ObjCRuntime::iOS:
81 case ObjCRuntime::WatchOS:
82 return EHPersonality::NeXT_ObjC;
83 case ObjCRuntime::GNUstep:
84 if (T.isOSCygMing())
85 return EHPersonality::GNU_CPlusPlus_SEH;
86 if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
87 return EHPersonality::GNUstep_ObjC;
88 [[fallthrough]];
89 case ObjCRuntime::GCC:
90 case ObjCRuntime::ObjFW:
91 if (CGOpts.hasSjLjExceptions())
92 return EHPersonality::GNU_ObjC_SJLJ;
93 if (CGOpts.hasSEHExceptions())
94 return EHPersonality::GNU_ObjC_SEH;
95 return EHPersonality::GNU_ObjC;
96 }
97 llvm_unreachable("bad runtime kind");
98}
99
100const EHPersonality &getCXXEHPersonality(const TargetInfo &Target,
101 const CodeGenOptions &CGOpts) {
102 const llvm::Triple &T = Target.getTriple();
103 if (T.isWindowsMSVCEnvironment())
104 return EHPersonality::MSVC_CxxFrameHandler3;
105 if (T.isOSAIX())
106 return EHPersonality::XL_CPlusPlus;
107 if (CGOpts.hasSjLjExceptions())
108 return EHPersonality::GNU_CPlusPlus_SJLJ;
109 if (CGOpts.hasDWARFExceptions())
110 return EHPersonality::GNU_CPlusPlus;
111 if (CGOpts.hasSEHExceptions())
112 return EHPersonality::GNU_CPlusPlus_SEH;
113 if (CGOpts.hasWasmExceptions())
114 return EHPersonality::GNU_Wasm_CPlusPlus;
115 if (T.isOSzOS())
116 return EHPersonality::ZOS_CPlusPlus;
117 return EHPersonality::GNU_CPlusPlus;
118}
119
120/// Determines the personality function to use when both C++
121/// and Objective-C exceptions are being caught.
122static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target,
123 const CodeGenOptions &CGOpts,
124 const LangOptions &L) {
125 auto Triple = Target.getTriple();
126 if (Triple.isWindowsMSVCEnvironment())
127 return EHPersonality::MSVC_CxxFrameHandler3;
128 if (Triple.isWasm())
129 return EHPersonality::GNU_Wasm_CPlusPlus;
130
131 switch (L.ObjCRuntime.getKind()) {
132 // In the fragile ABI, just use C++ exception handling and hope
133 // they're not doing crazy exception mixing.
134 case ObjCRuntime::FragileMacOSX:
135 return getCXXEHPersonality(Target, CGOpts);
136
137 // The ObjC personality defers to the C++ personality for non-ObjC
138 // handlers. Unlike the C++ case, we use the same personality
139 // function on targets using (backend-driven) SJLJ EH.
140 case ObjCRuntime::MacOSX:
141 case ObjCRuntime::iOS:
142 case ObjCRuntime::WatchOS:
143 return getObjCPersonality(Target, CGOpts, L);
144
145 case ObjCRuntime::GNUstep:
146 if (Triple.isOSCygMing())
147 return EHPersonality::GNU_CPlusPlus_SEH;
148 return EHPersonality::GNU_ObjCXX;
149
150 // The GCC runtime's personality function inherently doesn't support
151 // mixed EH. Use the ObjC personality just to avoid returning null.
152 case ObjCRuntime::GCC:
153 case ObjCRuntime::ObjFW:
154 return getObjCPersonality(Target, CGOpts, L);
155 }
156 llvm_unreachable("bad runtime kind");
157}
158
159static const EHPersonality &getSEHPersonalityMSVC(const llvm::Triple &T) {
160 if (T.getArch() == llvm::Triple::x86)
161 return EHPersonality::MSVC_except_handler;
162 return EHPersonality::MSVC_C_specific_handler;
163}
164
165const EHPersonality &getEHPersonality(const TargetInfo &Target,
166 const LangOptions &LangOpts,
167 const CodeGenOptions &CGOpts,
168 const FunctionDecl *FD) {
169 // Functions using SEH get an SEH personality.
170 if (FD && FD->usesSEHTry())
171 return getSEHPersonalityMSVC(T: Target.getTriple());
172
173 if (LangOpts.ObjC)
174 return LangOpts.CPlusPlus ? getObjCXXPersonality(Target, CGOpts, L: LangOpts)
175 : getObjCPersonality(Target, CGOpts, L: LangOpts);
176 return LangOpts.CPlusPlus ? getCXXEHPersonality(Target, CGOpts)
177 : getCPersonality(Target, CGOpts);
178}
179
180} // namespace clang::CodeGenUtils
181