1 /* radare - LGPL - Copyright 2019 - thestr4ng3r */
2 
3 #include <r_parse.h>
4 
5 #include <mpc.h>
6 
7 struct r_parse_ctype_t {
8 	mpc_parser_t *integerlit;
9 	mpc_parser_t *identifier;
10 	mpc_parser_t *qualifier;
11 	mpc_parser_t *pointer;
12 	mpc_parser_t *array;
13 	mpc_parser_t *type;
14 };
15 
16 #define ALL_PARSERS(ctype) ctype->integerlit, ctype->identifier, ctype->qualifier, ctype->pointer, ctype->array, ctype->type
17 #define ALL_PARSERS_COUNT 6
18 
19 static const char *lang =
20 	"integerlit : /0x[0-9A-Fa-f]+/ | /[0-9]+/;"
21 	"identifier : (\"struct\" | \"union\" | \"enum\")? /[a-zA-Z_][0-9a-zA-Z_]+/;"
22 	"qualifier  : \"const\";"
23 	"pointer    : <qualifier>? '*';"
24 	"array      : '[' <integerlit> ']';"
25 	"type       : <qualifier>? <identifier> (<pointer> | <array>)*;";
26 
27 
r_parse_ctype_new(void)28 R_API RParseCType *r_parse_ctype_new(void) {
29 	RParseCType *ctype = R_NEW (RParseCType);
30 	if (!ctype) {
31 		return NULL;
32 	}
33 
34 	ctype->integerlit = mpc_new ("integerlit");
35 	ctype->identifier = mpc_new ("identifier");
36 	ctype->qualifier = mpc_new ("qualifier");
37 	ctype->pointer = mpc_new ("pointer");
38 	ctype->array = mpc_new ("array");
39 	ctype->type = mpc_new ("type");
40 
41 	mpc_err_t *err = mpca_lang (MPCA_LANG_DEFAULT, lang, ALL_PARSERS (ctype), NULL);
42 	if (err) {
43 		mpc_err_print (err);
44 		mpc_err_delete (err);
45 		r_parse_ctype_free (ctype);
46 		return NULL;
47 	}
48 
49 	return ctype;
50 }
51 
r_parse_ctype_free(RParseCType * ctype)52 R_API void r_parse_ctype_free(RParseCType *ctype) {
53 	if (!ctype) {
54 		return;
55 	}
56 	mpc_cleanup (ALL_PARSERS_COUNT, ALL_PARSERS (ctype));
57 	free (ctype);
58 }
59 
is_qualifier_const(mpc_ast_t * a)60 static bool is_qualifier_const(mpc_ast_t *a) {
61 	return strcmp (a->tag, "qualifier|string") == 0
62 		&& a->contents
63 		&& strcmp (a->contents, "const") == 0;
64 }
65 
is_identifier_string(mpc_ast_t * a)66 static bool is_identifier_string(mpc_ast_t *a) {
67 	return strcmp (a->tag, "identifier|regex") == 0
68 		&& a->contents;
69 }
70 
is_identifier_kind(mpc_ast_t * a)71 static bool is_identifier_kind(mpc_ast_t *a) {
72 	return strcmp (a->tag, "identifier|>") == 0
73 		&& a->children_num == 2
74 		&& strcmp (a->children[0]->tag, "string") == 0
75 		&& a->children[0]->contents
76 		&& strcmp (a->children[1]->tag, "regex") == 0
77 		&& a->children[1]->contents;
78 }
79 
is_non_const_pointer(mpc_ast_t * a)80 static bool is_non_const_pointer(mpc_ast_t *a) {
81 	return strcmp (a->tag, "pointer|char") == 0
82 		&& a->contents
83 		&& strcmp (a->contents, "*") == 0;
84 }
85 
is_const_pointer(mpc_ast_t * a)86 static bool is_const_pointer(mpc_ast_t *a) {
87 	return strcmp (a->tag, "pointer|>") == 0
88 		&& a->children_num == 2
89 		&& is_qualifier_const (a->children[0])
90 		&& strcmp (a->children[1]->tag, "char") == 0
91 		&& a->children[1]->contents
92 		&& strcmp (a->children[1]->contents, "*") == 0;
93 }
94 
is_array(mpc_ast_t * a)95 static bool is_array(mpc_ast_t *a) {
96 	return strcmp (a->tag, "array|>") == 0
97 		&& a->children_num == 3
98 		&& strcmp (a->children[0]->tag, "char") == 0
99 		&& a->children[0]->contents
100 		&& strcmp (a->children[0]->contents, "[") == 0
101 		&& strcmp (a->children[1]->tag, "integerlit|regex") == 0
102 		&& a->children[1]->contents
103 		&& strcmp (a->children[2]->tag, "char") == 0
104 		&& a->children[2]->contents
105 		&& strcmp (a->children[2]->contents, "]") == 0;
106 }
107 
ctype_convert_ast(mpc_ast_t * a)108 static RParseCTypeType *ctype_convert_ast(mpc_ast_t *a) {
109 	bool is_const = false;
110 	RParseCTypeType *cur = NULL;
111 	int i;
112 	for (i = 0; i < a->children_num; i++) {
113 		mpc_ast_t *child = a->children[i];
114 
115 		// const
116 		if (is_qualifier_const (child)) {
117 			is_const = true;
118 		}
119 
120 		// (struct|union|enum)? <identifier>
121 		else if (r_str_startswith (child->tag, "identifier|")) {
122 			if (cur) {
123 				// identifier should always be the innermost type
124 				goto beach;
125 			}
126 			cur = R_NEW0 (RParseCTypeType);
127 			if (!cur) {
128 				goto beach;
129 			}
130 			cur->kind = R_PARSE_CTYPE_TYPE_KIND_IDENTIFIER;
131 			cur->identifier.is_const = is_const;
132 			cur->identifier.kind = R_PARSE_CTYPE_IDENTIFIER_KIND_UNSPECIFIED;
133 			if (is_identifier_string (child)) {
134 				cur->identifier.name = strdup (child->contents);
135 			} else if (is_identifier_kind (child)) {
136 				if (strcmp (child->children[0]->contents, "struct") == 0) {
137 					cur->identifier.kind = R_PARSE_CTYPE_IDENTIFIER_KIND_STRUCT;
138 				} else if (strcmp (child->children[0]->contents, "union") == 0) {
139 					cur->identifier.kind = R_PARSE_CTYPE_IDENTIFIER_KIND_UNION;
140 				} else if (strcmp (child->children[0]->contents, "enum") == 0) {
141 					cur->identifier.kind = R_PARSE_CTYPE_IDENTIFIER_KIND_ENUM;
142 				}
143 				cur->identifier.name = strdup (child->children[1]->contents);
144 			} else {
145 				goto beach;
146 			}
147 			if (!cur->identifier.name) {
148 				goto beach;
149 			}
150 			is_const = false;
151 		}
152 
153 		// <identifier>
154 		else if (is_identifier_string (child)) {
155 			if (cur) {
156 				// identifier should always be the innermost type
157 				goto beach;
158 			}
159 			cur = R_NEW0 (RParseCTypeType);
160 			if (!cur) {
161 				goto beach;
162 			}
163 			cur->kind = R_PARSE_CTYPE_TYPE_KIND_IDENTIFIER;
164 			cur->identifier.kind = R_PARSE_CTYPE_IDENTIFIER_KIND_UNSPECIFIED;
165 			cur->identifier.is_const = is_const;
166 			cur->identifier.name = strdup (child->contents);
167 			if (!cur->identifier.name) {
168 				goto beach;
169 			}
170 			is_const = false;
171 		}
172 
173 		// *
174 		else if (is_non_const_pointer (child)) {
175 			RParseCTypeType *pointer = R_NEW0 (RParseCTypeType);
176 			if (!pointer) {
177 				goto beach;
178 			}
179 			pointer->kind = R_PARSE_CTYPE_TYPE_KIND_POINTER;
180 			pointer->pointer.is_const = false;
181 			pointer->pointer.type = cur;
182 			cur = pointer;
183 		}
184 
185 		// const *
186 		else if (is_const_pointer (child)) {
187 			RParseCTypeType *pointer = R_NEW0 (RParseCTypeType);
188 			if (!pointer) {
189 				goto beach;
190 			}
191 			pointer->kind = R_PARSE_CTYPE_TYPE_KIND_POINTER;
192 			pointer->pointer.is_const = true;
193 			pointer->pointer.type = cur;
194 			cur = pointer;
195 		}
196 
197 		// <array>
198 		else if (is_array (child)) {
199 			RParseCTypeType *array = R_NEW0 (RParseCTypeType);
200 			if (!array) {
201 				goto beach;
202 			}
203 			array->kind = R_PARSE_CTYPE_TYPE_KIND_ARRAY;
204 			array->array.count = strtoull (child->children[1]->contents, NULL, 0);
205 			array->array.type = cur;
206 			cur = array;
207 		}
208 
209 		else {
210 			goto beach;
211 		}
212 	}
213 
214 	return cur;
215 beach:
216 	r_parse_ctype_type_free (cur);
217 	return NULL;
218 }
219 
r_parse_ctype_parse(RParseCType * ctype,const char * str,char ** error)220 R_API RParseCTypeType *r_parse_ctype_parse(RParseCType *ctype, const char *str, char **error) {
221 	mpc_result_t r;
222 	if (mpc_parse ("<string>", str, ctype->type, &r)) {
223 		RParseCTypeType *ret = ctype_convert_ast (r.output);
224 		if (error) {
225 			*error = !ret ? strdup ("internal error") : NULL;
226 		}
227 		mpc_ast_delete (r.output);
228 		return ret;
229 	} else {
230 		if (error) {
231 			*error = mpc_err_string (r.error);
232 		}
233 		mpc_err_delete (r.error);
234 		return NULL;
235 	}
236 }
237 
r_parse_ctype_type_free(RParseCTypeType * type)238 R_API void r_parse_ctype_type_free(RParseCTypeType *type) {
239 	if (!type) {
240 		return;
241 	}
242 	switch (type->kind) {
243 	case R_PARSE_CTYPE_TYPE_KIND_IDENTIFIER:
244 		free (type->identifier.name);
245 		break;
246 	case R_PARSE_CTYPE_TYPE_KIND_POINTER:
247 		r_parse_ctype_type_free (type->pointer.type);
248 		break;
249 	case R_PARSE_CTYPE_TYPE_KIND_ARRAY:
250 		r_parse_ctype_type_free (type->array.type);
251 		break;
252 	}
253 	free (type);
254 }
255