ReactOS 0.4.16-dev-2491-g3dc6630
main.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS SDK
3 * LICENSE: BSD Zero Clause License (https://spdx.org/licenses/0BSD)
4 * PURPOSE: Helper pragma implementation for pseh library (amd64)
5 * COPYRIGHT: Copyright 2021 Jérôme Gardou
6 * Copyright 2024 Timo Kreuzer <timo.kreuzer@reactos.org>
7 */
8
9#include <gcc-plugin.h>
10#include <plugin-version.h>
11#include <function.h>
12#include <tree.h>
13#include <c-family/c-pragma.h>
14#include <c-family/c-common.h>
15
16#include <iostream>
17#include <sstream>
18#include <unordered_map>
19#include <vector>
20#include <cstdio>
21
22#if 0 // To enable tracing
23#define trace(...) fprintf(stderr, __VA_ARGS__)
24#else
25#define trace(...)
26#endif
27
28#define is_alpha(c) (((c)>64 && (c)<91) || ((c)>96 && (c)<123))
29
30#if defined(_WIN32) || defined(WIN32)
31#define VISIBLE __declspec(dllexport)
32#else
33#define VISIBLE __attribute__((__visibility__("default")))
34#endif
35
36#define UNUSED __attribute__((__unused__))
37
38int
41
42constexpr size_t k_header_statement_max_size = 20000;
43
45{
47 unsigned int line;
48};
49
51{
52 bool unwind;
53 bool except;
56 size_t count;
57 std::vector<seh_handler> handlers;
58
59 seh_function(struct function* fun)
60 : unwind(false)
61 , except(false)
62 , count(0)
63 {
64 /* Reserve space for our header statement */
65#if 0 // FIXME: crashes on older GCC
67#else
69 memset(buf, 0, sizeof(buf));
70 asm_header_text = build_string(sizeof(buf), buf);
71#endif
72 asm_header = build_stmt(fun->function_start_locus, ASM_EXPR, asm_header_text, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
73 ASM_VOLATILE_P(asm_header) = 1;
74 add_stmt(asm_header);
75 }
76};
77
78static std::unordered_map<struct function*, struct seh_function*> func_seh_map = {};
79
80static
81struct seh_function*
83{
84 auto search = func_seh_map.find(cfun);
85 if (search != func_seh_map.end())
86 return search->second;
87
88 auto seh_fun = new seh_function(cfun);
89 func_seh_map.insert({cfun, seh_fun});
90
91 return seh_fun;
92}
93
94/*
95 * SEH handlerdata is emitted per source function by this plugin.
96 * If such a function gets inlined, GCC concatenates multiple handlerdata
97 * blocks in the caller's xdata. __C_specific_handler expects one block.
98 * Prevent inlining/cloning at the producer side to keep one canonical block.
99 */
100static
101void
103{
104 tree fndecl = current_function_decl;
105
106 if (fndecl == NULL_TREE)
107 return;
108
109 DECL_UNINLINABLE(fndecl) = 1;
110 DECL_DECLARED_INLINE_P(fndecl) = 0;
111}
112
113static
114void
116{
117 tree x, arg, line;
118 std::stringstream label_decl;
119 bool is_except;
120
121 if (!cfun)
122 {
123 error("%<#pragma REACTOS seh%> is not allowed outside functions");
124 return;
125 }
126
127 if ((pragma_lex(&x) != CPP_OPEN_PAREN) ||
128 (pragma_lex(&arg) != CPP_NAME) || // except or finally
129 (pragma_lex(&x) != CPP_COMMA) ||
130 (pragma_lex(&line) != CPP_NUMBER) || // Line number
131 (pragma_lex(&x) != CPP_CLOSE_PAREN) ||
132 (pragma_lex(&x) != CPP_EOF)
133 )
134 {
135 error("%<#pragma REACTOS seh%> needs two parameters%>");
136 return;
137 }
138
139 trace(stderr, "Pragma: %s, %u\n", IDENTIFIER_POINTER(arg), TREE_INT_CST_LOW(line));
140
141 const char* op = IDENTIFIER_POINTER(arg);
142
143 seh_function* seh_fun = get_seh_function();
144 if (strcmp(op, "__seh$$except") == 0)
145 {
146 is_except = true;
147 seh_fun->except = true;
148 }
149 else if (strcmp(op, "__seh$$finally") == 0)
150 {
151 is_except = false;
152 seh_fun->unwind = true;
153 }
154 else
155 {
156 error("Wrong argument for %<#pragma REACTOS seh%>. Expected \"except\" or \"finally\"");
157 return;
158 }
159 seh_fun->count++;
160
161 seh_fun->handlers.push_back({is_except, (unsigned int)TREE_INT_CST_LOW(line)});
162
163 /* Make sure we use a frame pointer. REACTOS' PSEH depends on this */
164 cfun->machine->accesses_prev_frame = 1;
165
166 /* Keep handlerdata generation canonical: one SEH block per function. */
168}
169
170static
171void
172finish_seh_function(void* event_data, void* UNUSED user_data)
173{
174 tree fndef = (tree)event_data;
175 struct function* fun = DECL_STRUCT_FUNCTION(fndef);
176
177 auto search = func_seh_map.find(fun);
178 if (search == func_seh_map.end())
179 return;
180
181 /* Get our SEH details and remove us from the map */
182 seh_function* seh_fun = search->second;
183 func_seh_map.erase(search);
184
185 if (DECL_FUNCTION_PERSONALITY(fndef) != nullptr)
186 {
187 error("Function %s has a personality. Are you mixing SEH with C++ exceptions ?",
188 IDENTIFIER_POINTER(fndef));
189 return;
190 }
191
192 /* Update asm statement */
193 std::stringstream asm_str;
194 asm_str << ".seh_handler __C_specific_handler";
195 if (seh_fun->unwind)
196 asm_str << ", @unwind";
197 if (seh_fun->except)
198 asm_str << ", @except";
199 asm_str << "\n";
200 asm_str << "\t.seh_handlerdata\n";
201 asm_str << "\t.long " << seh_fun->count << "\n";
202
203 for (auto& handler : seh_fun->handlers)
204 {
205 asm_str << "\n\t.rva " << "__seh2$$begin_try__" << handler.line; /* Begin of tried code */
206 asm_str << "\n\t.rva " << "__seh2$$end_try__" << handler.line; /* End of tried code */
207 asm_str << "\n\t.rva " << "__seh2$$filter__" << handler.line; /* Filter function */
208 if (handler.is_except)
209 asm_str << "\n\t.rva " << "__seh2$$begin_except__" << handler.line; /* Called on except */
210 else
211 asm_str << "\n\t.long 0"; /* No unwind handler */
212 }
213 asm_str << "\n\t.seh_code\n";
214
215 strncpy(const_cast<char*>(TREE_STRING_POINTER(seh_fun->asm_header_text)),
216 asm_str.str().c_str(),
217 TREE_STRING_LENGTH(seh_fun->asm_header_text));
218
219 trace(stderr, "ASM: %s\n", asm_str.str().c_str());
220
221 delete seh_fun;
222}
223
224static
225void
227{
228 c_register_pragma("REACTOS", "seh", handle_seh_pragma);
229}
230
231/* Return 0 on success or error code on failure */
232extern "C"
234int plugin_init(struct plugin_name_args *info, /* Argument infor */
235 struct plugin_gcc_version *version) /* Version of GCC */
236{
237 if (!plugin_default_version_check (version, &gcc_version))
238 {
239 std::cerr << "This GCC plugin is for version " << GCCPLUGIN_VERSION_MAJOR << "." << GCCPLUGIN_VERSION_MINOR << "\n";
240 return 1;
241 }
242
243 register_callback(info->base_name, PLUGIN_PRAGMAS, register_seh_pragmas, NULL);
244 register_callback(info->base_name, PLUGIN_FINISH_PARSE_FUNCTION, finish_seh_function, NULL);
245
246 return 0;
247}
struct _tree tree
#define NULL
Definition: types.h:112
UINT op
Definition: effect.c:236
static const WCHAR version[]
Definition: asmname.c:66
static void * user_data
Definition: metahost.c:106
UINT(* handler)(MSIPACKAGE *)
Definition: action.c:7512
#define stderr
#define false
Definition: stdbool.h:25
_ACRTIMP int __cdecl strcmp(const char *, const char *)
Definition: string.c:3319
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
#define error(str)
Definition: mkdosfs.c:1605
static short search(int val, const short *table, int size)
Definition: msg711.c:255
strncpy
Definition: string.h:335
#define memset(x, y, z)
Definition: compat.h:39
#define trace(...)
Definition: main.cpp:25
constexpr size_t k_header_statement_max_size
Definition: main.cpp:42
static void handle_seh_pragma(cpp_reader *UNUSED parser)
Definition: main.cpp:115
static struct seh_function * get_seh_function()
Definition: main.cpp:82
static void register_seh_pragmas(void *UNUSED event_data, void *UNUSED user_data)
Definition: main.cpp:226
int VISIBLE plugin_is_GPL_compatible
Definition: main.cpp:40
static void mark_seh_function_noinline(void)
Definition: main.cpp:102
static std::unordered_map< struct function *, struct seh_function * > func_seh_map
Definition: main.cpp:78
#define UNUSED
Definition: main.cpp:36
static void finish_seh_function(void *event_data, void *UNUSED user_data)
Definition: main.cpp:172
VISIBLE int plugin_init(struct plugin_name_args *info, struct plugin_gcc_version *version)
Definition: main.cpp:234
#define VISIBLE
Definition: main.cpp:33
Definition: parser.c:49
Definition: import.c:81
size_t count
Definition: main.cpp:56
tree asm_header_text
Definition: main.cpp:54
std::vector< seh_handler > handlers
Definition: main.cpp:57
tree asm_header
Definition: main.cpp:55
bool unwind
Definition: main.cpp:52
seh_function(struct function *fun)
Definition: main.cpp:59
bool except
Definition: main.cpp:53
unsigned int line
Definition: main.cpp:47
bool is_except
Definition: main.cpp:46
void * arg
Definition: msvc.h:10