ReactOS  0.4.15-dev-3163-gf17c2c0
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.html)
4  * PURPOSE: Helper pragma implementation for pseh library (amd64)
5  * COPYRIGHT: Copyright 2021 Jérôme Gardou
6  */
7 
8 #include <gcc-plugin.h>
9 #include <plugin-version.h>
10 #include <function.h>
11 #include <tree.h>
12 #include <c-family/c-pragma.h>
13 #include <c-family/c-common.h>
14 
15 #include <iostream>
16 #include <sstream>
17 #include <unordered_map>
18 #include <vector>
19 
20 #define is_alpha(c) (((c)>64 && (c)<91) || ((c)>96 && (c)<123))
21 
22 #if defined(_WIN32) || defined(WIN32)
23 #define VISIBLE __declspec(dllexport)
24 #else
25 #define VISIBLE __attribute__((__visibility__("default")))
26 #endif
27 
28 #define UNUSED __attribute__((__unused__))
29 
30 int
31 VISIBLE
33 
35 {
36  bool unwind;
37  bool except;
40  size_t count;
41 
42  seh_function(struct function* fun)
43  : unwind(false)
44  , except(false)
45  , count(0)
46  {
47  /* Reserve space for our header statement */
48  char buf[256];
49  memset(buf, 0, sizeof(buf));
50  asm_header_text = build_string(sizeof(buf), buf);
51  asm_header = build_stmt(fun->function_start_locus, ASM_EXPR, asm_header_text, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
52  ASM_VOLATILE_P(asm_header) = 1;
53  add_stmt(asm_header);
54  }
55 };
56 
57 static std::unordered_map<struct function*, struct seh_function*> func_seh_map = {};
58 
59 static
60 struct seh_function*
62 {
63  auto search = func_seh_map.find(cfun);
64  if (search != func_seh_map.end())
65  return search->second;
66 
67  auto seh_fun = new seh_function(cfun);
68  func_seh_map.insert({cfun, seh_fun});
69 
70  return seh_fun;
71 }
72 
73 static
74 void
76 {
77  tree x, arg;
78  std::stringstream label_decl;
79 
80  if (!cfun)
81  {
82  error("%<#pragma REACTOS seh%> is not allowed outside functions");
83  return;
84  }
85 
86  if ((pragma_lex(&x) != CPP_OPEN_PAREN) ||
87  (pragma_lex(&arg) != CPP_NAME) ||
88  (pragma_lex(&x) != CPP_CLOSE_PAREN) ||
89  (pragma_lex(&x) != CPP_EOF))
90  {
91  error("%<#pragma REACTOS seh%> needs one parameter%>");
92  return;
93  }
94 
95  const char* op = IDENTIFIER_POINTER(arg);
96 
97  seh_function* seh_fun = get_seh_function();
98  if (strcmp(op, "except") == 0)
99  seh_fun->except = true;
100  else if (strcmp(op, "finally") == 0)
101  seh_fun->unwind = true;
102  else
103  {
104  error("Wrong argument for %<#pragma REACTOS seh%>. Expected \"except\" or \"finally\"");
105  return;
106  }
107  seh_fun->count++;
108 
109  /* Make sure we use a frame pointer. REACTOS' PSEH depends on this */
110  cfun->machine->accesses_prev_frame = 1;
111 }
112 
113 static
114 void
115 finish_seh_function(void* event_data, void* UNUSED user_data)
116 {
117  tree fndef = (tree)event_data;
118  struct function* fun = DECL_STRUCT_FUNCTION(fndef);
119 
120  auto search = func_seh_map.find(fun);
121  if (search == func_seh_map.end())
122  return;
123 
124  /* Get our SEH details and remove us from the map */
125  seh_function* seh_fun = search->second;
126  func_seh_map.erase(search);
127 
128  if (DECL_FUNCTION_PERSONALITY(fndef) != nullptr)
129  {
130  error("Function %s has a personality. Are you mixing SEH with C++ exceptions ?",
131  IDENTIFIER_POINTER(fndef));
132  return;
133  }
134 
135  /* Update asm statement */
136  std::stringstream asm_str;
137  asm_str << ".seh_handler __C_specific_handler";
138  if (seh_fun->unwind)
139  asm_str << ", @unwind";
140  if (seh_fun->except)
141  asm_str << ", @except";
142  asm_str << "\n";
143  asm_str << "\t.seh_handlerdata\n";
144  asm_str << "\t.long " << seh_fun->count << "\n";
145  asm_str << "\t.seh_code";
146 
147  strncpy(const_cast<char*>(TREE_STRING_POINTER(seh_fun->asm_header_text)),
148  asm_str.str().c_str(),
149  TREE_STRING_LENGTH(seh_fun->asm_header_text));
150 
151  delete seh_fun;
152 }
153 
154 static
155 void
156 register_seh_pragmas(void* UNUSED event_data, void* UNUSED user_data)
157 {
158  c_register_pragma("REACTOS", "seh", handle_seh_pragma);
159 }
160 
161 /* Return 0 on success or error code on failure */
162 extern "C"
163 VISIBLE
164 int plugin_init(struct plugin_name_args *info, /* Argument infor */
165  struct plugin_gcc_version *version) /* Version of GCC */
166 {
167  if (!plugin_default_version_check (version, &gcc_version))
168  {
169  std::cerr << "This GCC plugin is for version " << GCCPLUGIN_VERSION_MAJOR << "." << GCCPLUGIN_VERSION_MINOR << "\n";
170  return 1;
171  }
172 
173  register_callback(info->base_name, PLUGIN_PRAGMAS, register_seh_pragmas, NULL);
174  register_callback(info->base_name, PLUGIN_FINISH_PARSE_FUNCTION, finish_seh_function, NULL);
175 
176  return 0;
177 }
static void handle_seh_pragma(cpp_reader *UNUSED parser)
Definition: main.cpp:75
seh_function(struct function *fun)
Definition: main.cpp:42
static short search(int val, const short *table, int size)
Definition: msg711.c:255
struct _tree tree
char * strncpy(char *DstString, const char *SrcString, ACPI_SIZE Count)
Definition: utclib.c:427
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
void * arg
Definition: msvc.h:10
static void finish_seh_function(void *event_data, void *UNUSED user_data)
Definition: main.cpp:115
bool except
Definition: main.cpp:37
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
void error(const std::string &err)
Definition: main.cpp:99
tree asm_header_text
Definition: main.cpp:38
tree asm_header
Definition: main.cpp:39
static std::unordered_map< struct function *, struct seh_function * > func_seh_map
Definition: main.cpp:57
bool unwind
Definition: main.cpp:36
static const WCHAR version[]
Definition: asmname.c:66
#define UNUSED
Definition: main.cpp:28
int VISIBLE plugin_is_GPL_compatible
Definition: main.cpp:32
_STLP_DECLSPEC _Stl_aligned_buffer< ostream > cerr
Definition: iostream.cpp:102
VISIBLE int plugin_init(struct plugin_name_args *info, struct plugin_gcc_version *version)
Definition: main.cpp:164
UINT op
Definition: effect.c:236
static void register_seh_pragmas(void *UNUSED event_data, void *UNUSED user_data)
Definition: main.cpp:156
static struct seh_function * get_seh_function()
Definition: main.cpp:61
#define VISIBLE
Definition: main.cpp:25
Definition: stddef.h:5
#define NULL
Definition: types.h:112
Definition: import.c:85
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
basic_stringstream< char, char_traits< char >, allocator< char > > stringstream
Definition: _iosfwd.h:128
#define memset(x, y, z)
Definition: compat.h:39
size_t count
Definition: main.cpp:40