ReactOS 0.4.15-dev-8058-ga7cbb60
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
94static
95void
97{
98 tree x, arg, line;
99 std::stringstream label_decl;
100 bool is_except;
101
102 if (!cfun)
103 {
104 error("%<#pragma REACTOS seh%> is not allowed outside functions");
105 return;
106 }
107
108 if ((pragma_lex(&x) != CPP_OPEN_PAREN) ||
109 (pragma_lex(&arg) != CPP_NAME) || // except or finally
110 (pragma_lex(&x) != CPP_COMMA) ||
111 (pragma_lex(&line) != CPP_NUMBER) || // Line number
112 (pragma_lex(&x) != CPP_CLOSE_PAREN) ||
113 (pragma_lex(&x) != CPP_EOF)
114 )
115 {
116 error("%<#pragma REACTOS seh%> needs two parameters%>");
117 return;
118 }
119
120 trace(stderr, "Pragma: %s, %u\n", IDENTIFIER_POINTER(arg), TREE_INT_CST_LOW(line));
121
122 const char* op = IDENTIFIER_POINTER(arg);
123
124 seh_function* seh_fun = get_seh_function();
125 if (strcmp(op, "__seh$$except") == 0)
126 {
127 is_except = true;
128 seh_fun->except = true;
129 }
130 else if (strcmp(op, "__seh$$finally") == 0)
131 {
132 is_except = false;
133 seh_fun->unwind = true;
134 }
135 else
136 {
137 error("Wrong argument for %<#pragma REACTOS seh%>. Expected \"except\" or \"finally\"");
138 return;
139 }
140 seh_fun->count++;
141
142 seh_fun->handlers.push_back({is_except, (unsigned int)TREE_INT_CST_LOW(line)});
143
144 /* Make sure we use a frame pointer. REACTOS' PSEH depends on this */
145 cfun->machine->accesses_prev_frame = 1;
146}
147
148static
149void
150finish_seh_function(void* event_data, void* UNUSED user_data)
151{
152 tree fndef = (tree)event_data;
153 struct function* fun = DECL_STRUCT_FUNCTION(fndef);
154
155 auto search = func_seh_map.find(fun);
156 if (search == func_seh_map.end())
157 return;
158
159 /* Get our SEH details and remove us from the map */
160 seh_function* seh_fun = search->second;
161 func_seh_map.erase(search);
162
163 if (DECL_FUNCTION_PERSONALITY(fndef) != nullptr)
164 {
165 error("Function %s has a personality. Are you mixing SEH with C++ exceptions ?",
166 IDENTIFIER_POINTER(fndef));
167 return;
168 }
169
170 /* Update asm statement */
171 std::stringstream asm_str;
172 asm_str << ".seh_handler __C_specific_handler";
173 if (seh_fun->unwind)
174 asm_str << ", @unwind";
175 if (seh_fun->except)
176 asm_str << ", @except";
177 asm_str << "\n";
178 asm_str << "\t.seh_handlerdata\n";
179 asm_str << "\t.long " << seh_fun->count << "\n";
180
181 for (auto& handler : seh_fun->handlers)
182 {
183 asm_str << "\n\t.rva " << "__seh2$$begin_try__" << handler.line; /* Begin of tried code */
184 asm_str << "\n\t.rva " << "__seh2$$end_try__" << handler.line; /* End of tried code */
185 asm_str << "\n\t.rva " << "__seh2$$filter__" << handler.line; /* Filter function */
186 if (handler.is_except)
187 asm_str << "\n\t.rva " << "__seh2$$begin_except__" << handler.line; /* Called on except */
188 else
189 asm_str << "\n\t.long 0"; /* No unwind handler */
190 }
191 asm_str << "\n\t.seh_code\n";
192
193 strncpy(const_cast<char*>(TREE_STRING_POINTER(seh_fun->asm_header_text)),
194 asm_str.str().c_str(),
195 TREE_STRING_LENGTH(seh_fun->asm_header_text));
196
197 trace(stderr, "ASM: %s\n", asm_str.str().c_str());
198
199 delete seh_fun;
200}
201
202static
203void
204register_seh_pragmas(void* UNUSED event_data, void* UNUSED user_data)
205{
206 c_register_pragma("REACTOS", "seh", handle_seh_pragma);
207}
208
209/* Return 0 on success or error code on failure */
210extern "C"
212int plugin_init(struct plugin_name_args *info, /* Argument infor */
213 struct plugin_gcc_version *version) /* Version of GCC */
214{
215 if (!plugin_default_version_check (version, &gcc_version))
216 {
217 std::cerr << "This GCC plugin is for version " << GCCPLUGIN_VERSION_MAJOR << "." << GCCPLUGIN_VERSION_MINOR << "\n";
218 return 1;
219 }
220
221 register_callback(info->base_name, PLUGIN_PRAGMAS, register_seh_pragmas, NULL);
222 register_callback(info->base_name, PLUGIN_FINISH_PARSE_FUNCTION, finish_seh_function, NULL);
223
224 return 0;
225}
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
char * strncpy(char *DstString, const char *SrcString, ACPI_SIZE Count)
Definition: utclib.c:427
struct _tree tree
#define NULL
Definition: types.h:112
UINT op
Definition: effect.c:236
static const WCHAR version[]
Definition: asmname.c:66
UINT(* handler)(MSIPACKAGE *)
Definition: action.c:7482
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 stderr
Definition: stdio.h:100
#define error(str)
Definition: mkdosfs.c:1605
static short search(int val, const short *table, int size)
Definition: msg711.c:255
#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:96
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:204
int VISIBLE plugin_is_GPL_compatible
Definition: main.cpp:40
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:150
VISIBLE int plugin_init(struct plugin_name_args *info, struct plugin_gcc_version *version)
Definition: main.cpp:212
#define VISIBLE
Definition: main.cpp:33
#define false
Definition: stdbool.h:37
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