xref: /minix3/sys/lib/libunwind/DwarfInstructions.hpp (revision 0b98e8aad89f2bd4ba80b523d73cf29e9dd82ce1)
1 //===-------------------------- DwarfInstructions.hpp ---------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //
9 //  Processor specific interpretation of DWARF unwind info.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef __DWARF_INSTRUCTIONS_HPP__
14 #define __DWARF_INSTRUCTIONS_HPP__
15 
16 #include <cstdint>
17 #include <cstdlib>
18 
19 #include "dwarf2.h"
20 #include "AddressSpace.hpp"
21 #include "Registers.hpp"
22 #include "DwarfParser.hpp"
23 
24 namespace _Unwind {
25 
26 enum step_result {
27   UNW_STEP_SUCCESS,
28   UNW_STEP_END,
29   UNW_STEP_FAILED
30 };
31 
32 /// DwarfInstructions maps abtract dwarf unwind instructions to a particular
33 /// architecture
34 template <typename A, typename R> class DwarfInstructions {
35 public:
36   typedef typename A::pint_t pint_t;
37   typedef typename A::sint_t sint_t;
38 
39   static step_result stepWithDwarf(A &, pint_t, pint_t, R &, unw_proc_info_t *);
40 
41 private:
42   static pint_t evaluateExpression(pint_t, A &, const R &, pint_t);
43   static pint_t
44   getSavedRegister(A &, const R &, pint_t,
45                    const typename CFI_Parser<A, R>::RegisterLocation &);
46   static pint_t
47   computeRegisterLocation(A &, const R &, pint_t,
48                           const typename CFI_Parser<A, R>::RegisterLocation &);
49 
50   static int lastRestoreReg(const R &) { return R::LAST_RESTORE_REG; }
51 
52   static pint_t getCFA(A &addressSpace,
53                        const typename CFI_Parser<A, R>::PrologInfo &prolog,
54                        const R &registers) {
55     if (prolog.cfaRegister != 0)
56       return registers.getRegister(prolog.cfaRegister) +
57              prolog.cfaRegisterOffset;
58     if (prolog.cfaExpression != 0)
59       return evaluateExpression(prolog.cfaExpression, addressSpace, registers,
60                                 0);
61     assert(0 && "getCFA(): unknown location");
62     __builtin_unreachable();
63   }
64 };
65 
66 template <typename A, typename R>
67 typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
68     A &addressSpace, const R &registers, pint_t cfa,
69     const typename CFI_Parser<A, R>::RegisterLocation &savedReg) {
70   switch (savedReg.location) {
71   case CFI_Parser<A, R>::kRegisterInCFA:
72     return addressSpace.getP(cfa + savedReg.value);
73 
74   case CFI_Parser<A, R>::kRegisterAtExpression:
75     return addressSpace.getP(
76         evaluateExpression(savedReg.value, addressSpace, registers, cfa));
77 
78   case CFI_Parser<A, R>::kRegisterIsExpression:
79     return evaluateExpression(savedReg.value, addressSpace, registers, cfa);
80 
81   case CFI_Parser<A, R>::kRegisterInRegister:
82     return registers.getRegister(savedReg.value);
83 
84   case CFI_Parser<A, R>::kRegisterUnused:
85   case CFI_Parser<A, R>::kRegisterOffsetFromCFA:
86     assert(0 && "unsupported restore location for register");
87   }
88   __builtin_unreachable();
89 }
90 
91 template <typename A, typename R>
92 typename DwarfInstructions<A, R>::pint_t
93 DwarfInstructions<A, R>::computeRegisterLocation(
94     A &addressSpace, const R &registers, pint_t cfa,
95     const typename CFI_Parser<A, R>::RegisterLocation &savedReg) {
96   switch (savedReg.location) {
97   case CFI_Parser<A, R>::kRegisterInCFA:
98     return cfa + savedReg.value;
99 
100   case CFI_Parser<A, R>::kRegisterAtExpression:
101     return evaluateExpression(savedReg.value, addressSpace, registers, cfa);
102 
103   case CFI_Parser<A, R>::kRegisterIsExpression:
104   case CFI_Parser<A, R>::kRegisterUnused:
105   case CFI_Parser<A, R>::kRegisterOffsetFromCFA:
106   case CFI_Parser<A, R>::kRegisterInRegister:
107     assert(0 && "unsupported restore location for float/vector register");
108   }
109   __builtin_unreachable();
110 }
111 
112 template <typename A, typename R>
113 step_result DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
114                                                    pint_t fdeStart,
115                                                    R &registers,
116                                                    unw_proc_info_t *ctx) {
117   typename CFI_Parser<A, R>::FDE_Info fdeInfo;
118   typename CFI_Parser<A, R>::CIE_Info cieInfo;
119   if (!CFI_Parser<A, R>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo,
120                                    ctx))
121     return UNW_STEP_FAILED;
122 
123   typename CFI_Parser<A, R>::PrologInfo prolog;
124   if (!CFI_Parser<A, R>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo,
125                                               pc, &prolog, ctx))
126     return UNW_STEP_FAILED;
127 
128   // Create working copy of the register set.
129   R newRegisters = registers;
130 
131   // Get pointer to CFA by the architecture-specific code.
132   pint_t cfa = getCFA(addressSpace, prolog, registers);
133 
134   // Restore registers according to DWARF instructions
135   pint_t returnAddress = 0;
136   for (int i = 0; i <= lastRestoreReg(newRegisters); ++i) {
137     if (prolog.savedRegisters[i].location == CFI_Parser<A, R>::kRegisterUnused)
138       continue;
139     if (i == (int)cieInfo.returnAddressRegister)
140       returnAddress = getSavedRegister(addressSpace, registers, cfa,
141                                        prolog.savedRegisters[i]);
142     else if (registers.validRegister(i))
143       newRegisters.setRegister(i, getSavedRegister(addressSpace, registers, cfa,
144                                                    prolog.savedRegisters[i]));
145     else if (registers.validFloatVectorRegister(i))
146       newRegisters.copyFloatVectorRegister(
147           i, computeRegisterLocation(addressSpace, registers, cfa,
148                                      prolog.savedRegisters[i]));
149     else
150       return UNW_STEP_FAILED;
151   }
152 
153   // The CFA is defined as the stack pointer at the call site.
154   // Therefore the SP is restored by setting it to the CFA.
155   newRegisters.setSP(cfa);
156   newRegisters.setIP(returnAddress + R::RETURN_OFFSET);
157 
158   // Now replace register set with the working copy.
159   registers = newRegisters;
160 
161   return UNW_STEP_SUCCESS;
162 }
163 
164 template <typename A, typename R>
165 typename A::pint_t
166 DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
167                                             const R &registers,
168                                             pint_t initialStackValue) {
169   pint_t p = expression;
170   pint_t expressionEnd = expression + 20; // Rough estimate
171   uint64_t length = addressSpace.getULEB128(p, expressionEnd);
172   expressionEnd = p + length;
173   pint_t stack[100];
174   pint_t *sp = stack;
175   *(++sp) = initialStackValue;
176 
177   while (p < expressionEnd) {
178     uint8_t opcode = addressSpace.get8(p++);
179     sint_t svalue;
180     pint_t value;
181     uint32_t reg;
182     switch (opcode) {
183     case DW_OP_addr:
184       // push immediate address sized value
185       value = addressSpace.getP(p);
186       p += sizeof(pint_t);
187       *(++sp) = value;
188       break;
189 
190     case DW_OP_deref:
191       // pop stack, dereference, push result
192       value = *sp--;
193       *(++sp) = addressSpace.getP(value);
194       break;
195 
196     case DW_OP_const1u:
197       // push immediate 1 byte value
198       value = addressSpace.get8(p);
199       p += 1;
200       *(++sp) = value;
201       break;
202 
203     case DW_OP_const1s:
204       // push immediate 1 byte signed value
205       svalue = (int8_t)addressSpace.get8(p);
206       p += 1;
207       *(++sp) = svalue;
208       break;
209 
210     case DW_OP_const2u:
211       // push immediate 2 byte value
212       value = addressSpace.get16(p);
213       p += 2;
214       *(++sp) = value;
215       break;
216 
217     case DW_OP_const2s:
218       // push immediate 2 byte signed value
219       svalue = (int16_t)addressSpace.get16(p);
220       p += 2;
221       *(++sp) = svalue;
222       break;
223 
224     case DW_OP_const4u:
225       // push immediate 4 byte value
226       value = addressSpace.get32(p);
227       p += 4;
228       *(++sp) = value;
229       break;
230 
231     case DW_OP_const4s:
232       // push immediate 4 byte signed value
233       svalue = (int32_t)addressSpace.get32(p);
234       p += 4;
235       *(++sp) = svalue;
236       break;
237 
238     case DW_OP_const8u:
239       // push immediate 8 byte value
240       value = addressSpace.get64(p);
241       p += 8;
242       *(++sp) = value;
243       break;
244 
245     case DW_OP_const8s:
246       // push immediate 8 byte signed value
247       value = (int32_t)addressSpace.get64(p);
248       p += 8;
249       *(++sp) = value;
250       break;
251 
252     case DW_OP_constu:
253       // push immediate ULEB128 value
254       value = addressSpace.getULEB128(p, expressionEnd);
255       *(++sp) = value;
256       break;
257 
258     case DW_OP_consts:
259       // push immediate SLEB128 value
260       svalue = addressSpace.getSLEB128(p, expressionEnd);
261       *(++sp) = svalue;
262       break;
263 
264     case DW_OP_dup:
265       // push top of stack
266       value = *sp;
267       *(++sp) = value;
268       break;
269 
270     case DW_OP_drop:
271       // pop
272       --sp;
273       break;
274 
275     case DW_OP_over:
276       // dup second
277       value = sp[-1];
278       *(++sp) = value;
279       break;
280 
281     case DW_OP_pick:
282       // pick from
283       reg = addressSpace.get8(p);
284       p += 1;
285       value = sp[-reg];
286       *(++sp) = value;
287       break;
288 
289     case DW_OP_swap:
290       // swap top two
291       value = sp[0];
292       sp[0] = sp[-1];
293       sp[-1] = value;
294       break;
295 
296     case DW_OP_rot:
297       // rotate top three
298       value = sp[0];
299       sp[0] = sp[-1];
300       sp[-1] = sp[-2];
301       sp[-2] = value;
302       break;
303 
304     case DW_OP_xderef:
305       // pop stack, dereference, push result
306       value = *sp--;
307       *sp = *((uint64_t *)value);
308       break;
309 
310     case DW_OP_abs:
311       svalue = *sp;
312       if (svalue < 0)
313         *sp = -svalue;
314       break;
315 
316     case DW_OP_and:
317       value = *sp--;
318       *sp &= value;
319       break;
320 
321     case DW_OP_div:
322       svalue = *sp--;
323       *sp = *sp / svalue;
324       break;
325 
326     case DW_OP_minus:
327       svalue = *sp--;
328       *sp = *sp - svalue;
329       break;
330 
331     case DW_OP_mod:
332       svalue = *sp--;
333       *sp = *sp % svalue;
334       break;
335 
336     case DW_OP_mul:
337       svalue = *sp--;
338       *sp = *sp * svalue;
339       break;
340 
341     case DW_OP_neg:
342       *sp = 0 - *sp;
343       break;
344 
345     case DW_OP_not:
346       svalue = *sp;
347       *sp = ~svalue;
348       break;
349 
350     case DW_OP_or:
351       value = *sp--;
352       *sp |= value;
353       break;
354 
355     case DW_OP_plus:
356       value = *sp--;
357       *sp += value;
358       break;
359 
360     case DW_OP_plus_uconst:
361       // pop stack, add uelb128 constant, push result
362       *sp += addressSpace.getULEB128(p, expressionEnd);
363       break;
364 
365     case DW_OP_shl:
366       value = *sp--;
367       *sp = *sp << value;
368       break;
369 
370     case DW_OP_shr:
371       value = *sp--;
372       *sp = *sp >> value;
373       break;
374 
375     case DW_OP_shra:
376       value = *sp--;
377       svalue = *sp;
378       *sp = svalue >> value;
379       break;
380 
381     case DW_OP_xor:
382       value = *sp--;
383       *sp ^= value;
384       break;
385 
386     case DW_OP_skip:
387       svalue = (int16_t)addressSpace.get16(p);
388       p += 2;
389       p += svalue;
390       break;
391 
392     case DW_OP_bra:
393       svalue = (int16_t)addressSpace.get16(p);
394       p += 2;
395       if (*sp--)
396         p += svalue;
397       break;
398 
399     case DW_OP_eq:
400       value = *sp--;
401       *sp = (*sp == value);
402       break;
403 
404     case DW_OP_ge:
405       value = *sp--;
406       *sp = (*sp >= value);
407       break;
408 
409     case DW_OP_gt:
410       value = *sp--;
411       *sp = (*sp > value);
412       break;
413 
414     case DW_OP_le:
415       value = *sp--;
416       *sp = (*sp <= value);
417       break;
418 
419     case DW_OP_lt:
420       value = *sp--;
421       *sp = (*sp < value);
422       break;
423 
424     case DW_OP_ne:
425       value = *sp--;
426       *sp = (*sp != value);
427       break;
428 
429     case DW_OP_lit0:
430     case DW_OP_lit1:
431     case DW_OP_lit2:
432     case DW_OP_lit3:
433     case DW_OP_lit4:
434     case DW_OP_lit5:
435     case DW_OP_lit6:
436     case DW_OP_lit7:
437     case DW_OP_lit8:
438     case DW_OP_lit9:
439     case DW_OP_lit10:
440     case DW_OP_lit11:
441     case DW_OP_lit12:
442     case DW_OP_lit13:
443     case DW_OP_lit14:
444     case DW_OP_lit15:
445     case DW_OP_lit16:
446     case DW_OP_lit17:
447     case DW_OP_lit18:
448     case DW_OP_lit19:
449     case DW_OP_lit20:
450     case DW_OP_lit21:
451     case DW_OP_lit22:
452     case DW_OP_lit23:
453     case DW_OP_lit24:
454     case DW_OP_lit25:
455     case DW_OP_lit26:
456     case DW_OP_lit27:
457     case DW_OP_lit28:
458     case DW_OP_lit29:
459     case DW_OP_lit30:
460     case DW_OP_lit31:
461       value = opcode - DW_OP_lit0;
462       *(++sp) = value;
463       break;
464 
465     case DW_OP_reg0:
466     case DW_OP_reg1:
467     case DW_OP_reg2:
468     case DW_OP_reg3:
469     case DW_OP_reg4:
470     case DW_OP_reg5:
471     case DW_OP_reg6:
472     case DW_OP_reg7:
473     case DW_OP_reg8:
474     case DW_OP_reg9:
475     case DW_OP_reg10:
476     case DW_OP_reg11:
477     case DW_OP_reg12:
478     case DW_OP_reg13:
479     case DW_OP_reg14:
480     case DW_OP_reg15:
481     case DW_OP_reg16:
482     case DW_OP_reg17:
483     case DW_OP_reg18:
484     case DW_OP_reg19:
485     case DW_OP_reg20:
486     case DW_OP_reg21:
487     case DW_OP_reg22:
488     case DW_OP_reg23:
489     case DW_OP_reg24:
490     case DW_OP_reg25:
491     case DW_OP_reg26:
492     case DW_OP_reg27:
493     case DW_OP_reg28:
494     case DW_OP_reg29:
495     case DW_OP_reg30:
496     case DW_OP_reg31:
497       reg = opcode - DW_OP_reg0;
498       *(++sp) = registers.getRegister(reg);
499       break;
500 
501     case DW_OP_regx:
502       reg = addressSpace.getULEB128(p, expressionEnd);
503       *(++sp) = registers.getRegister(reg);
504       break;
505 
506     case DW_OP_breg0:
507     case DW_OP_breg1:
508     case DW_OP_breg2:
509     case DW_OP_breg3:
510     case DW_OP_breg4:
511     case DW_OP_breg5:
512     case DW_OP_breg6:
513     case DW_OP_breg7:
514     case DW_OP_breg8:
515     case DW_OP_breg9:
516     case DW_OP_breg10:
517     case DW_OP_breg11:
518     case DW_OP_breg12:
519     case DW_OP_breg13:
520     case DW_OP_breg14:
521     case DW_OP_breg15:
522     case DW_OP_breg16:
523     case DW_OP_breg17:
524     case DW_OP_breg18:
525     case DW_OP_breg19:
526     case DW_OP_breg20:
527     case DW_OP_breg21:
528     case DW_OP_breg22:
529     case DW_OP_breg23:
530     case DW_OP_breg24:
531     case DW_OP_breg25:
532     case DW_OP_breg26:
533     case DW_OP_breg27:
534     case DW_OP_breg28:
535     case DW_OP_breg29:
536     case DW_OP_breg30:
537     case DW_OP_breg31:
538       reg = opcode - DW_OP_breg0;
539       svalue = addressSpace.getSLEB128(p, expressionEnd);
540       *(++sp) = registers.getRegister(reg) + svalue;
541       break;
542 
543     case DW_OP_bregx:
544       reg = addressSpace.getULEB128(p, expressionEnd);
545       svalue = addressSpace.getSLEB128(p, expressionEnd);
546       *(++sp) = registers.getRegister(reg) + svalue;
547       break;
548 
549     case DW_OP_deref_size:
550       // pop stack, dereference, push result
551       value = *sp--;
552       switch (addressSpace.get8(p++)) {
553       case 1:
554         value = addressSpace.get8(value);
555         break;
556       case 2:
557         value = addressSpace.get16(value);
558         break;
559       case 4:
560         value = addressSpace.get32(value);
561         break;
562       case 8:
563         value = addressSpace.get64(value);
564         break;
565       default:
566         assert(0 && "DW_OP_deref_size with bad size");
567       }
568       *(++sp) = value;
569       break;
570 
571     case DW_OP_fbreg:
572     case DW_OP_piece:
573     case DW_OP_xderef_size:
574     case DW_OP_nop:
575     case DW_OP_push_object_addres:
576     case DW_OP_call2:
577     case DW_OP_call4:
578     case DW_OP_call_ref:
579     default:
580       assert(0 && "dwarf opcode not implemented");
581     }
582   }
583   return *sp;
584 }
585 
586 } // namespace _Unwind
587 
588 #endif // __DWARF_INSTRUCTIONS_HPP__
589