Commit | Line | Data |
---|---|---|
e2803273 TT |
1 | /* Definitions for expressions in GDB |
2 | ||
3 | Copyright (C) 2020 Free Software Foundation, Inc. | |
4 | ||
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | #ifndef EXPOP_H | |
21 | #define EXPOP_H | |
22 | ||
23 | #include "block.h" | |
24 | #include "c-lang.h" | |
25 | #include "cp-abi.h" | |
26 | #include "expression.h" | |
27 | #include "objfiles.h" | |
28 | #include "gdbsupport/traits.h" | |
29 | #include "gdbsupport/enum-flags.h" | |
30 | ||
31 | struct agent_expr; | |
32 | struct axs_value; | |
33 | ||
75f9892d TT |
34 | extern void gen_expr_binop (struct expression *exp, |
35 | enum exp_opcode op, | |
36 | expr::operation *lhs, expr::operation *rhs, | |
37 | struct agent_expr *ax, struct axs_value *value); | |
38 | extern void gen_expr_structop (struct expression *exp, | |
39 | enum exp_opcode op, | |
40 | expr::operation *lhs, | |
41 | const char *name, | |
42 | struct agent_expr *ax, struct axs_value *value); | |
43 | ||
d5ab122c TT |
44 | extern struct value *eval_op_scope (struct type *expect_type, |
45 | struct expression *exp, | |
46 | enum noside noside, | |
47 | struct type *type, const char *string); | |
48 | ||
e2803273 TT |
49 | namespace expr |
50 | { | |
51 | ||
52 | /* The check_objfile overloads are used to check whether a particular | |
53 | component of some operation references an objfile. The passed-in | |
54 | objfile will never be a debug objfile. */ | |
55 | ||
56 | /* See if EXP_OBJFILE matches OBJFILE. */ | |
57 | static inline bool | |
58 | check_objfile (struct objfile *exp_objfile, struct objfile *objfile) | |
59 | { | |
60 | if (exp_objfile->separate_debug_objfile_backlink) | |
61 | exp_objfile = exp_objfile->separate_debug_objfile_backlink; | |
62 | return exp_objfile == objfile; | |
63 | } | |
64 | ||
65 | static inline bool | |
66 | check_objfile (struct type *type, struct objfile *objfile) | |
67 | { | |
68 | struct objfile *ty_objfile = type->objfile_owner (); | |
69 | if (ty_objfile != nullptr) | |
70 | return check_objfile (ty_objfile, objfile); | |
71 | return false; | |
72 | } | |
73 | ||
74 | static inline bool | |
75 | check_objfile (struct symbol *sym, struct objfile *objfile) | |
76 | { | |
77 | return check_objfile (symbol_objfile (sym), objfile); | |
78 | } | |
79 | ||
80 | static inline bool | |
81 | check_objfile (const struct block *block, struct objfile *objfile) | |
82 | { | |
83 | return check_objfile (block_objfile (block), objfile); | |
84 | } | |
85 | ||
86 | static inline bool | |
87 | check_objfile (minimal_symbol *minsym, struct objfile *objfile) | |
88 | { | |
89 | /* This may seem strange but minsyms are only used with an objfile | |
90 | as well. */ | |
91 | return false; | |
92 | } | |
93 | ||
94 | static inline bool | |
95 | check_objfile (internalvar *ivar, struct objfile *objfile) | |
96 | { | |
97 | return false; | |
98 | } | |
99 | ||
100 | static inline bool | |
101 | check_objfile (const std::string &str, struct objfile *objfile) | |
102 | { | |
103 | return false; | |
104 | } | |
105 | ||
106 | static inline bool | |
107 | check_objfile (const operation_up &op, struct objfile *objfile) | |
108 | { | |
109 | return op->uses_objfile (objfile); | |
110 | } | |
111 | ||
112 | static inline bool | |
113 | check_objfile (enum exp_opcode val, struct objfile *objfile) | |
114 | { | |
115 | return false; | |
116 | } | |
117 | ||
118 | static inline bool | |
119 | check_objfile (ULONGEST val, struct objfile *objfile) | |
120 | { | |
121 | return false; | |
122 | } | |
123 | ||
124 | template<typename T> | |
125 | static inline bool | |
126 | check_objfile (enum_flags<T> val, struct objfile *objfile) | |
127 | { | |
128 | return false; | |
129 | } | |
130 | ||
131 | template<typename T> | |
132 | static inline bool | |
133 | check_objfile (const std::vector<T> &collection, struct objfile *objfile) | |
134 | { | |
135 | for (const auto &item : collection) | |
136 | { | |
137 | if (check_objfile (item, objfile)) | |
138 | return true; | |
139 | } | |
140 | return false; | |
141 | } | |
142 | ||
143 | template<typename S, typename T> | |
144 | static inline bool | |
145 | check_objfile (const std::pair<S, T> &item, struct objfile *objfile) | |
146 | { | |
147 | return (check_objfile (item.first, objfile) | |
148 | || check_objfile (item.second, objfile)); | |
149 | } | |
150 | ||
de401988 TT |
151 | static inline void |
152 | dump_for_expression (struct ui_file *stream, int depth, | |
153 | const operation_up &op) | |
154 | { | |
155 | op->dump (stream, depth); | |
156 | } | |
157 | ||
158 | extern void dump_for_expression (struct ui_file *stream, int depth, | |
159 | enum exp_opcode op); | |
160 | extern void dump_for_expression (struct ui_file *stream, int depth, | |
161 | const std::string &str); | |
162 | extern void dump_for_expression (struct ui_file *stream, int depth, | |
163 | struct type *type); | |
164 | extern void dump_for_expression (struct ui_file *stream, int depth, | |
165 | CORE_ADDR addr); | |
166 | extern void dump_for_expression (struct ui_file *stream, int depth, | |
167 | internalvar *ivar); | |
168 | extern void dump_for_expression (struct ui_file *stream, int depth, | |
169 | symbol *sym); | |
170 | extern void dump_for_expression (struct ui_file *stream, int depth, | |
171 | minimal_symbol *msym); | |
172 | extern void dump_for_expression (struct ui_file *stream, int depth, | |
173 | const block *bl); | |
174 | extern void dump_for_expression (struct ui_file *stream, int depth, | |
175 | type_instance_flags flags); | |
176 | extern void dump_for_expression (struct ui_file *stream, int depth, | |
177 | enum c_string_type_values flags); | |
178 | extern void dump_for_expression (struct ui_file *stream, int depth, | |
179 | enum range_flag flags); | |
180 | extern void dump_for_expression (struct ui_file *stream, int depth, | |
181 | objfile *objf); | |
182 | ||
183 | template<typename T> | |
184 | void | |
185 | dump_for_expression (struct ui_file *stream, int depth, | |
186 | const std::vector<T> &vals) | |
187 | { | |
188 | fprintf_filtered (stream, _("%*sVector:\n"), depth, ""); | |
189 | for (auto &item : vals) | |
190 | dump_for_expression (stream, depth + 1, item); | |
191 | } | |
192 | ||
193 | template<typename X, typename Y> | |
194 | void | |
195 | dump_for_expression (struct ui_file *stream, int depth, | |
196 | const std::pair<X, Y> &vals) | |
197 | { | |
198 | dump_for_expression (stream, depth, vals.first); | |
199 | dump_for_expression (stream, depth, vals.second); | |
200 | } | |
201 | ||
e2803273 TT |
202 | /* Base class for most concrete operations. This class holds data, |
203 | specified via template parameters, and supplies generic | |
204 | implementations of the 'dump' and 'uses_objfile' methods. */ | |
205 | template<typename... Arg> | |
206 | class tuple_holding_operation : public operation | |
207 | { | |
208 | public: | |
209 | ||
210 | explicit tuple_holding_operation (Arg... args) | |
211 | : m_storage (std::forward<Arg> (args)...) | |
212 | { | |
213 | } | |
214 | ||
215 | DISABLE_COPY_AND_ASSIGN (tuple_holding_operation); | |
216 | ||
217 | bool uses_objfile (struct objfile *objfile) const override | |
218 | { | |
219 | return do_check_objfile<0, Arg...> (objfile, m_storage); | |
220 | } | |
221 | ||
222 | void dump (struct ui_file *stream, int depth) const override | |
223 | { | |
de401988 TT |
224 | dump_for_expression (stream, depth, opcode ()); |
225 | do_dump<0, Arg...> (stream, depth + 1, m_storage); | |
e2803273 TT |
226 | } |
227 | ||
228 | protected: | |
229 | ||
230 | /* Storage for the data. */ | |
231 | std::tuple<Arg...> m_storage; | |
232 | ||
233 | private: | |
234 | ||
235 | /* do_dump does the work of dumping the data. */ | |
236 | template<int I, typename... T> | |
237 | typename std::enable_if<I == sizeof... (T), void>::type | |
238 | do_dump (struct ui_file *stream, int depth, const std::tuple<T...> &value) | |
239 | const | |
240 | { | |
241 | } | |
242 | ||
243 | template<int I, typename... T> | |
244 | typename std::enable_if<I < sizeof... (T), void>::type | |
245 | do_dump (struct ui_file *stream, int depth, const std::tuple<T...> &value) | |
246 | const | |
247 | { | |
de401988 | 248 | dump_for_expression (stream, depth, std::get<I> (value)); |
e2803273 TT |
249 | do_dump<I + 1, T...> (stream, depth, value); |
250 | } | |
251 | ||
252 | /* do_check_objfile does the work of checking whether this object | |
253 | refers to OBJFILE. */ | |
254 | template<int I, typename... T> | |
255 | typename std::enable_if<I == sizeof... (T), bool>::type | |
256 | do_check_objfile (struct objfile *objfile, const std::tuple<T...> &value) | |
257 | const | |
258 | { | |
259 | return false; | |
260 | } | |
261 | ||
262 | template<int I, typename... T> | |
263 | typename std::enable_if<I < sizeof... (T), bool>::type | |
264 | do_check_objfile (struct objfile *objfile, const std::tuple<T...> &value) | |
265 | const | |
266 | { | |
267 | if (check_objfile (std::get<I> (value), objfile)) | |
268 | return true; | |
269 | return do_check_objfile<I + 1, T...> (objfile, value); | |
270 | } | |
271 | }; | |
272 | ||
273 | /* The check_constant overloads are used to decide whether a given | |
274 | concrete operation is a constant. This is done by checking the | |
275 | operands. */ | |
276 | ||
277 | static inline bool | |
278 | check_constant (const operation_up &item) | |
279 | { | |
280 | return item->constant_p (); | |
281 | } | |
282 | ||
283 | static inline bool | |
284 | check_constant (struct minimal_symbol *msym) | |
285 | { | |
286 | return false; | |
287 | } | |
288 | ||
289 | static inline bool | |
290 | check_constant (struct type *type) | |
291 | { | |
292 | return true; | |
293 | } | |
294 | ||
295 | static inline bool | |
296 | check_constant (const struct block *block) | |
297 | { | |
298 | return true; | |
299 | } | |
300 | ||
301 | static inline bool | |
302 | check_constant (const std::string &str) | |
303 | { | |
304 | return true; | |
305 | } | |
306 | ||
307 | static inline bool | |
308 | check_constant (struct objfile *objfile) | |
309 | { | |
310 | return true; | |
311 | } | |
312 | ||
313 | static inline bool | |
314 | check_constant (ULONGEST cst) | |
315 | { | |
316 | return true; | |
317 | } | |
318 | ||
319 | static inline bool | |
320 | check_constant (struct symbol *sym) | |
321 | { | |
322 | enum address_class sc = SYMBOL_CLASS (sym); | |
323 | return (sc == LOC_BLOCK | |
324 | || sc == LOC_CONST | |
325 | || sc == LOC_CONST_BYTES | |
326 | || sc == LOC_LABEL); | |
327 | } | |
328 | ||
329 | template<typename T> | |
330 | static inline bool | |
331 | check_constant (const std::vector<T> &collection) | |
332 | { | |
333 | for (const auto &item : collection) | |
334 | if (!check_constant (item)) | |
335 | return false; | |
336 | return true; | |
337 | } | |
338 | ||
339 | template<typename S, typename T> | |
340 | static inline bool | |
341 | check_constant (const std::pair<S, T> &item) | |
342 | { | |
343 | return check_constant (item.first) && check_constant (item.second); | |
344 | } | |
345 | ||
346 | /* Base class for concrete operations. This class supplies an | |
347 | implementation of 'constant_p' that works by checking the | |
348 | operands. */ | |
349 | template<typename... Arg> | |
350 | class maybe_constant_operation | |
351 | : public tuple_holding_operation<Arg...> | |
352 | { | |
353 | public: | |
354 | ||
355 | using tuple_holding_operation<Arg...>::tuple_holding_operation; | |
356 | ||
357 | bool constant_p () const override | |
358 | { | |
359 | return do_check_constant<0, Arg...> (this->m_storage); | |
360 | } | |
361 | ||
362 | private: | |
363 | ||
364 | template<int I, typename... T> | |
365 | typename std::enable_if<I == sizeof... (T), bool>::type | |
366 | do_check_constant (const std::tuple<T...> &value) const | |
367 | { | |
368 | return true; | |
369 | } | |
370 | ||
371 | template<int I, typename... T> | |
372 | typename std::enable_if<I < sizeof... (T), bool>::type | |
373 | do_check_constant (const std::tuple<T...> &value) const | |
374 | { | |
375 | if (!check_constant (std::get<I> (value))) | |
376 | return false; | |
377 | return do_check_constant<I + 1, T...> (value); | |
378 | } | |
379 | }; | |
380 | ||
cae26a0c TT |
381 | /* A floating-point constant. The constant is encoded in the target |
382 | format. */ | |
383 | ||
384 | typedef std::array<gdb_byte, 16> float_data; | |
385 | ||
386 | /* An operation that holds a floating-point constant of a given | |
387 | type. | |
388 | ||
389 | This does not need the facilities provided by | |
390 | tuple_holding_operation, so it does not use it. */ | |
391 | class float_const_operation | |
392 | : public operation | |
393 | { | |
394 | public: | |
395 | ||
396 | float_const_operation (struct type *type, float_data data) | |
397 | : m_type (type), | |
398 | m_data (data) | |
399 | { | |
400 | } | |
401 | ||
402 | value *evaluate (struct type *expect_type, | |
403 | struct expression *exp, | |
404 | enum noside noside) override | |
405 | { | |
406 | return value_from_contents (m_type, m_data.data ()); | |
407 | } | |
408 | ||
409 | enum exp_opcode opcode () const override | |
410 | { return OP_FLOAT; } | |
411 | ||
412 | bool constant_p () const override | |
413 | { return true; } | |
414 | ||
415 | void dump (struct ui_file *stream, int depth) const override; | |
416 | ||
417 | private: | |
418 | ||
419 | struct type *m_type; | |
420 | float_data m_data; | |
421 | }; | |
422 | ||
d5ab122c TT |
423 | class scope_operation |
424 | : public maybe_constant_operation<struct type *, std::string> | |
425 | { | |
426 | public: | |
427 | ||
428 | using maybe_constant_operation::maybe_constant_operation; | |
429 | ||
430 | value *evaluate (struct type *expect_type, | |
431 | struct expression *exp, | |
432 | enum noside noside) override | |
433 | { | |
434 | return eval_op_scope (expect_type, exp, noside, | |
435 | std::get<0> (m_storage), | |
436 | std::get<1> (m_storage).c_str ()); | |
437 | } | |
438 | ||
439 | value *evaluate_for_address (struct expression *exp, | |
440 | enum noside noside) override; | |
441 | ||
442 | enum exp_opcode opcode () const override | |
443 | { return OP_SCOPE; } | |
444 | ||
445 | protected: | |
446 | ||
447 | void do_generate_ax (struct expression *exp, | |
448 | struct agent_expr *ax, | |
449 | struct axs_value *value, | |
450 | struct type *cast_type) | |
451 | override; | |
452 | }; | |
453 | ||
d336c29e TT |
454 | class long_const_operation |
455 | : public tuple_holding_operation<struct type *, LONGEST> | |
456 | { | |
457 | public: | |
458 | ||
459 | using tuple_holding_operation::tuple_holding_operation; | |
460 | ||
461 | value *evaluate (struct type *expect_type, | |
462 | struct expression *exp, | |
463 | enum noside noside) override | |
464 | { | |
465 | return value_from_longest (std::get<0> (m_storage), | |
466 | std::get<1> (m_storage)); | |
467 | } | |
468 | ||
469 | enum exp_opcode opcode () const override | |
470 | { return OP_LONG; } | |
471 | ||
472 | bool constant_p () const override | |
473 | { return true; } | |
474 | ||
475 | protected: | |
476 | ||
477 | void do_generate_ax (struct expression *exp, | |
478 | struct agent_expr *ax, | |
479 | struct axs_value *value, | |
480 | struct type *cast_type) | |
481 | override; | |
482 | }; | |
483 | ||
e2803273 TT |
484 | } /* namespace expr */ |
485 | ||
486 | #endif /* EXPOP_H */ |