Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
6f765c4b61e8f831c980e4fa9c320d5e1542fa39
[simgrid.git] / src / mc / inspect / DwarfExpression.cpp
1 /* Copyright (c) 2014-2022. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include <cstddef>
7 #include <cstdint>
8 #include <unordered_set>
9
10 #include "src/mc/AddressSpace.hpp"
11 #include "src/mc/inspect/DwarfExpression.hpp"
12 #include "src/mc/inspect/Frame.hpp"
13 #include "src/mc/inspect/LocationList.hpp"
14 #include "src/mc/inspect/ObjectInformation.hpp"
15 #include "src/mc/inspect/mc_dwarf.hpp"
16 #include "src/mc/mc_private.hpp"
17
18 namespace simgrid {
19 namespace dwarf {
20
21 void execute(const Dwarf_Op* ops, std::size_t n, const ExpressionContext& context, ExpressionStack& stack)
22 {
23   for (size_t i = 0; i != n; ++i) {
24     const Dwarf_Op* op = ops + i;
25     std::uint8_t atom  = op->atom;
26     intptr_t first;
27     intptr_t second;
28
29     switch (atom) {
30         // Push the CFA (Canonical Frame Address):
31       case DW_OP_call_frame_cfa:
32         /* See 6.4 of DWARF4 (http://dwarfstd.org/doc/DWARF4.pdf#page=140):
33          *
34          * > Typically, the CFA is defined to be the value of the stack
35          * > pointer at the call site in the previous frame (which may be
36          * > different from its value on entry to the current frame).
37          *
38          * We need to unwind the frame in order to get the SP of the parent
39          * frame.
40          *
41          * Warning: the CFA returned by libunwind (UNW_X86_64_RSP, etc.)
42          * is the SP of the *current* frame. */
43         if (context.cursor) {
44           // Get frame:
45           unw_cursor_t cursor = *(context.cursor);
46           unw_step(&cursor);
47
48           unw_word_t res;
49           unw_get_reg(&cursor, UNW_REG_SP, &res);
50           stack.push(res);
51           break;
52         }
53         throw evaluation_error("Missing cursor");
54
55         // Frame base:
56       case DW_OP_fbreg:
57         stack.push((std::uintptr_t)context.frame_base + op->number);
58         break;
59
60         // Address from the base address of this ELF object.
61         // Push the address on the stack (base_address + argument).
62       case DW_OP_addr:
63         if (context.object_info) {
64           Dwarf_Off addr = (Dwarf_Off)(std::uintptr_t)context.object_info->base_address() + op->number;
65           stack.push(addr);
66           break;
67         }
68         throw evaluation_error("No base address");
69
70         // ***** Stack manipulation:
71
72         // Push another copy/duplicate the value at the top of the stack:
73       case DW_OP_dup:
74         stack.dup();
75         break;
76
77         // Pop/drop the top of the stack:
78       case DW_OP_drop:
79         (void)stack.pop();
80         break;
81
82       case DW_OP_swap:
83         stack.swap();
84         break;
85
86         // Duplicate the value under the top of the stack:
87       case DW_OP_over:
88         stack.push(stack.top(1));
89         break;
90
91         // ***** Operations:
92         // Those usually take the top of the stack and the next value as argument
93         // and replace the top of the stack with the computed value
94         // (stack.top() += stack.before_top()).
95
96       case DW_OP_plus:
97         first  = stack.pop();
98         second = stack.pop();
99         stack.push(first + second);
100         break;
101
102       case DW_OP_mul:
103         first  = stack.pop();
104         second = stack.pop();
105         stack.push(first * second);
106         break;
107
108       case DW_OP_plus_uconst:
109         stack.top() += op->number;
110         break;
111
112       case DW_OP_not:
113         stack.top() = ~stack.top();
114         break;
115
116       case DW_OP_neg:
117         stack.top() = -(intptr_t)stack.top();
118         break;
119
120       case DW_OP_minus:
121         first  = stack.pop();
122         second = stack.pop();
123         stack.push(second - first);
124         break;
125
126       case DW_OP_and:
127         first  = stack.pop();
128         second = stack.pop();
129         stack.push(first & second);
130         break;
131
132       case DW_OP_or:
133         first  = stack.pop();
134         second = stack.pop();
135         stack.push(first | second);
136         break;
137
138       case DW_OP_xor:
139         first  = stack.pop();
140         second = stack.pop();
141         stack.push(first ^ second);
142         break;
143
144       case DW_OP_nop:
145         break;
146
147         // ***** Deference (memory fetch)
148
149       case DW_OP_deref_size:
150         throw evaluation_error("Unsupported operation");
151
152       case DW_OP_deref:
153         // Computed address:
154         if (not context.address_space)
155           throw evaluation_error("Missing address space");
156         context.address_space->read_bytes(&stack.top(), sizeof(uintptr_t), mc::remote(stack.top()));
157         break;
158
159       default:
160
161         // Registers:
162         if (static const std::unordered_set<uint8_t> registers =
163                 {DW_OP_breg0,  DW_OP_breg1,  DW_OP_breg2,  DW_OP_breg3,  DW_OP_breg4,  DW_OP_breg5,  DW_OP_breg6,
164                  DW_OP_breg7,  DW_OP_breg8,  DW_OP_breg9,  DW_OP_breg10, DW_OP_breg11, DW_OP_breg12, DW_OP_breg13,
165                  DW_OP_breg14, DW_OP_breg15, DW_OP_breg16, DW_OP_breg17, DW_OP_breg18, DW_OP_breg19, DW_OP_breg20,
166                  DW_OP_breg21, DW_OP_breg22, DW_OP_breg23, DW_OP_breg24, DW_OP_breg25, DW_OP_breg26, DW_OP_breg27,
167                  DW_OP_breg28, DW_OP_breg29, DW_OP_breg30, DW_OP_breg31};
168             registers.count(atom) > 0) {
169           // Push register + constant:
170           int register_id = dwarf_register_to_libunwind(op->atom - DW_OP_breg0);
171           unw_word_t res;
172           if (not context.cursor)
173             throw evaluation_error("Missing stack context");
174           unw_get_reg(context.cursor, register_id, &res);
175           stack.push(res + op->number);
176           break;
177         }
178
179         // ***** Constants:
180
181         // Short constant literals:
182         if (static const std::unordered_set<uint8_t> literals = {DW_OP_lit0,  DW_OP_lit1,  DW_OP_lit2,  DW_OP_lit3,
183                                                                  DW_OP_lit4,  DW_OP_lit5,  DW_OP_lit6,  DW_OP_lit7,
184                                                                  DW_OP_lit8,  DW_OP_lit9,  DW_OP_lit10, DW_OP_lit11,
185                                                                  DW_OP_lit12, DW_OP_lit13, DW_OP_lit14, DW_OP_lit15,
186                                                                  DW_OP_lit16, DW_OP_lit17, DW_OP_lit18, DW_OP_lit19,
187                                                                  DW_OP_lit20, DW_OP_lit21, DW_OP_lit22, DW_OP_lit23,
188                                                                  DW_OP_lit24, DW_OP_lit25, DW_OP_lit26, DW_OP_lit27,
189                                                                  DW_OP_lit28, DW_OP_lit29, DW_OP_lit30, DW_OP_lit31};
190             literals.count(atom) > 0) {
191           // Push a literal/constant on the stack:
192           stack.push(atom - DW_OP_lit0);
193           break;
194         }
195
196         // General constants:
197         if (static const std::unordered_set<uint8_t> constants = {DW_OP_const1u, DW_OP_const2u, DW_OP_const4u,
198                                                                   DW_OP_const8u, DW_OP_const1s, DW_OP_const2s,
199                                                                   DW_OP_const4s, DW_OP_const8s, DW_OP_constu,
200                                                                   DW_OP_consts};
201             constants.count(atom) > 0) {
202           // Push the constant argument on the stack.
203           stack.push(op->number);
204           break;
205         }
206
207         // Not handled:
208         throw evaluation_error("Unsupported operation");
209     }
210   }
211 }
212
213 } // namespace dwarf
214 } // namespace simgrid