xref: /netbsd-src/sys/lib/libunwind/DwarfInstructions.hpp (revision 364f0c0b54a731a4d74b9f756266b596636c3624)
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 
lastRestoreReg(const R &)50   static int lastRestoreReg(const R &) { return R::LAST_RESTORE_REG; }
51 
getCFA(A & addressSpace,const typename CFI_Parser<A,R>::PrologInfo & prolog,const R & registers)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>
getSavedRegister(A & addressSpace,const R & registers,pint_t cfa,const typename CFI_Parser<A,R>::RegisterLocation & savedReg)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
computeRegisterLocation(A & addressSpace,const R & registers,pint_t cfa,const typename CFI_Parser<A,R>::RegisterLocation & savedReg)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>
stepWithDwarf(A & addressSpace,pint_t pc,pint_t fdeStart,R & registers,unw_proc_info_t * ctx)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   returnAddress += R::RETURN_OFFSET;
157   returnAddress &= ~R::RETURN_MASK;
158   newRegisters.setIP(returnAddress);
159 
160   // Now replace register set with the working copy.
161   registers = newRegisters;
162 
163   return UNW_STEP_SUCCESS;
164 }
165 
166 template <typename A, typename R>
167 typename A::pint_t
evaluateExpression(pint_t expression,A & addressSpace,const R & registers,pint_t initialStackValue)168 DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
169                                             const R &registers,
170                                             pint_t initialStackValue) {
171   pint_t p = expression;
172   pint_t expressionEnd = expression + 20; // Rough estimate
173   uint64_t length = addressSpace.getULEB128(p, expressionEnd);
174   expressionEnd = p + length;
175   pint_t stack[100];
176   pint_t *sp = stack;
177   *(++sp) = initialStackValue;
178 
179   while (p < expressionEnd) {
180     uint8_t opcode = addressSpace.get8(p++);
181     sint_t svalue;
182     pint_t value;
183     uint32_t reg;
184     switch (opcode) {
185     case DW_OP_addr:
186       // push immediate address sized value
187       value = addressSpace.getP(p);
188       p += sizeof(pint_t);
189       *(++sp) = value;
190       break;
191 
192     case DW_OP_deref:
193       // pop stack, dereference, push result
194       value = *sp--;
195       *(++sp) = addressSpace.getP(value);
196       break;
197 
198     case DW_OP_const1u:
199       // push immediate 1 byte value
200       value = addressSpace.get8(p);
201       p += 1;
202       *(++sp) = value;
203       break;
204 
205     case DW_OP_const1s:
206       // push immediate 1 byte signed value
207       svalue = (int8_t)addressSpace.get8(p);
208       p += 1;
209       *(++sp) = svalue;
210       break;
211 
212     case DW_OP_const2u:
213       // push immediate 2 byte value
214       value = addressSpace.get16(p);
215       p += 2;
216       *(++sp) = value;
217       break;
218 
219     case DW_OP_const2s:
220       // push immediate 2 byte signed value
221       svalue = (int16_t)addressSpace.get16(p);
222       p += 2;
223       *(++sp) = svalue;
224       break;
225 
226     case DW_OP_const4u:
227       // push immediate 4 byte value
228       value = addressSpace.get32(p);
229       p += 4;
230       *(++sp) = value;
231       break;
232 
233     case DW_OP_const4s:
234       // push immediate 4 byte signed value
235       svalue = (int32_t)addressSpace.get32(p);
236       p += 4;
237       *(++sp) = svalue;
238       break;
239 
240     case DW_OP_const8u:
241       // push immediate 8 byte value
242       value = addressSpace.get64(p);
243       p += 8;
244       *(++sp) = value;
245       break;
246 
247     case DW_OP_const8s:
248       // push immediate 8 byte signed value
249       value = (int32_t)addressSpace.get64(p);
250       p += 8;
251       *(++sp) = value;
252       break;
253 
254     case DW_OP_constu:
255       // push immediate ULEB128 value
256       value = addressSpace.getULEB128(p, expressionEnd);
257       *(++sp) = value;
258       break;
259 
260     case DW_OP_consts:
261       // push immediate SLEB128 value
262       svalue = addressSpace.getSLEB128(p, expressionEnd);
263       *(++sp) = svalue;
264       break;
265 
266     case DW_OP_dup:
267       // push top of stack
268       value = *sp;
269       *(++sp) = value;
270       break;
271 
272     case DW_OP_drop:
273       // pop
274       --sp;
275       break;
276 
277     case DW_OP_over:
278       // dup second
279       value = sp[-1];
280       *(++sp) = value;
281       break;
282 
283     case DW_OP_pick:
284       // pick from
285       reg = addressSpace.get8(p);
286       p += 1;
287       value = sp[-reg];
288       *(++sp) = value;
289       break;
290 
291     case DW_OP_swap:
292       // swap top two
293       value = sp[0];
294       sp[0] = sp[-1];
295       sp[-1] = value;
296       break;
297 
298     case DW_OP_rot:
299       // rotate top three
300       value = sp[0];
301       sp[0] = sp[-1];
302       sp[-1] = sp[-2];
303       sp[-2] = value;
304       break;
305 
306     case DW_OP_xderef:
307       // pop stack, dereference, push result
308       value = *sp--;
309       *sp = *((uint64_t *)value);
310       break;
311 
312     case DW_OP_abs:
313       svalue = *sp;
314       if (svalue < 0)
315         *sp = -svalue;
316       break;
317 
318     case DW_OP_and:
319       value = *sp--;
320       *sp &= value;
321       break;
322 
323     case DW_OP_div:
324       svalue = *sp--;
325       *sp = *sp / svalue;
326       break;
327 
328     case DW_OP_minus:
329       svalue = *sp--;
330       *sp = *sp - svalue;
331       break;
332 
333     case DW_OP_mod:
334       svalue = *sp--;
335       *sp = *sp % svalue;
336       break;
337 
338     case DW_OP_mul:
339       svalue = *sp--;
340       *sp = *sp * svalue;
341       break;
342 
343     case DW_OP_neg:
344       *sp = 0 - *sp;
345       break;
346 
347     case DW_OP_not:
348       svalue = *sp;
349       *sp = ~svalue;
350       break;
351 
352     case DW_OP_or:
353       value = *sp--;
354       *sp |= value;
355       break;
356 
357     case DW_OP_plus:
358       value = *sp--;
359       *sp += value;
360       break;
361 
362     case DW_OP_plus_uconst:
363       // pop stack, add uelb128 constant, push result
364       *sp += addressSpace.getULEB128(p, expressionEnd);
365       break;
366 
367     case DW_OP_shl:
368       value = *sp--;
369       *sp = *sp << value;
370       break;
371 
372     case DW_OP_shr:
373       value = *sp--;
374       *sp = *sp >> value;
375       break;
376 
377     case DW_OP_shra:
378       value = *sp--;
379       svalue = *sp;
380       *sp = svalue >> value;
381       break;
382 
383     case DW_OP_xor:
384       value = *sp--;
385       *sp ^= value;
386       break;
387 
388     case DW_OP_skip:
389       svalue = (int16_t)addressSpace.get16(p);
390       p += 2;
391       p += svalue;
392       break;
393 
394     case DW_OP_bra:
395       svalue = (int16_t)addressSpace.get16(p);
396       p += 2;
397       if (*sp--)
398         p += svalue;
399       break;
400 
401     case DW_OP_eq:
402       value = *sp--;
403       *sp = (*sp == value);
404       break;
405 
406     case DW_OP_ge:
407       value = *sp--;
408       *sp = (*sp >= value);
409       break;
410 
411     case DW_OP_gt:
412       value = *sp--;
413       *sp = (*sp > value);
414       break;
415 
416     case DW_OP_le:
417       value = *sp--;
418       *sp = (*sp <= value);
419       break;
420 
421     case DW_OP_lt:
422       value = *sp--;
423       *sp = (*sp < value);
424       break;
425 
426     case DW_OP_ne:
427       value = *sp--;
428       *sp = (*sp != value);
429       break;
430 
431     case DW_OP_lit0:
432     case DW_OP_lit1:
433     case DW_OP_lit2:
434     case DW_OP_lit3:
435     case DW_OP_lit4:
436     case DW_OP_lit5:
437     case DW_OP_lit6:
438     case DW_OP_lit7:
439     case DW_OP_lit8:
440     case DW_OP_lit9:
441     case DW_OP_lit10:
442     case DW_OP_lit11:
443     case DW_OP_lit12:
444     case DW_OP_lit13:
445     case DW_OP_lit14:
446     case DW_OP_lit15:
447     case DW_OP_lit16:
448     case DW_OP_lit17:
449     case DW_OP_lit18:
450     case DW_OP_lit19:
451     case DW_OP_lit20:
452     case DW_OP_lit21:
453     case DW_OP_lit22:
454     case DW_OP_lit23:
455     case DW_OP_lit24:
456     case DW_OP_lit25:
457     case DW_OP_lit26:
458     case DW_OP_lit27:
459     case DW_OP_lit28:
460     case DW_OP_lit29:
461     case DW_OP_lit30:
462     case DW_OP_lit31:
463       value = opcode - DW_OP_lit0;
464       *(++sp) = value;
465       break;
466 
467     case DW_OP_reg0:
468     case DW_OP_reg1:
469     case DW_OP_reg2:
470     case DW_OP_reg3:
471     case DW_OP_reg4:
472     case DW_OP_reg5:
473     case DW_OP_reg6:
474     case DW_OP_reg7:
475     case DW_OP_reg8:
476     case DW_OP_reg9:
477     case DW_OP_reg10:
478     case DW_OP_reg11:
479     case DW_OP_reg12:
480     case DW_OP_reg13:
481     case DW_OP_reg14:
482     case DW_OP_reg15:
483     case DW_OP_reg16:
484     case DW_OP_reg17:
485     case DW_OP_reg18:
486     case DW_OP_reg19:
487     case DW_OP_reg20:
488     case DW_OP_reg21:
489     case DW_OP_reg22:
490     case DW_OP_reg23:
491     case DW_OP_reg24:
492     case DW_OP_reg25:
493     case DW_OP_reg26:
494     case DW_OP_reg27:
495     case DW_OP_reg28:
496     case DW_OP_reg29:
497     case DW_OP_reg30:
498     case DW_OP_reg31:
499       reg = opcode - DW_OP_reg0;
500       *(++sp) = registers.getRegister(reg);
501       break;
502 
503     case DW_OP_regx:
504       reg = addressSpace.getULEB128(p, expressionEnd);
505       *(++sp) = registers.getRegister(reg);
506       break;
507 
508     case DW_OP_breg0:
509     case DW_OP_breg1:
510     case DW_OP_breg2:
511     case DW_OP_breg3:
512     case DW_OP_breg4:
513     case DW_OP_breg5:
514     case DW_OP_breg6:
515     case DW_OP_breg7:
516     case DW_OP_breg8:
517     case DW_OP_breg9:
518     case DW_OP_breg10:
519     case DW_OP_breg11:
520     case DW_OP_breg12:
521     case DW_OP_breg13:
522     case DW_OP_breg14:
523     case DW_OP_breg15:
524     case DW_OP_breg16:
525     case DW_OP_breg17:
526     case DW_OP_breg18:
527     case DW_OP_breg19:
528     case DW_OP_breg20:
529     case DW_OP_breg21:
530     case DW_OP_breg22:
531     case DW_OP_breg23:
532     case DW_OP_breg24:
533     case DW_OP_breg25:
534     case DW_OP_breg26:
535     case DW_OP_breg27:
536     case DW_OP_breg28:
537     case DW_OP_breg29:
538     case DW_OP_breg30:
539     case DW_OP_breg31:
540       reg = opcode - DW_OP_breg0;
541       svalue = addressSpace.getSLEB128(p, expressionEnd);
542       *(++sp) = registers.getRegister(reg) + svalue;
543       break;
544 
545     case DW_OP_bregx:
546       reg = addressSpace.getULEB128(p, expressionEnd);
547       svalue = addressSpace.getSLEB128(p, expressionEnd);
548       *(++sp) = registers.getRegister(reg) + svalue;
549       break;
550 
551     case DW_OP_deref_size:
552       // pop stack, dereference, push result
553       value = *sp--;
554       switch (addressSpace.get8(p++)) {
555       case 1:
556         value = addressSpace.get8(value);
557         break;
558       case 2:
559         value = addressSpace.get16(value);
560         break;
561       case 4:
562         value = addressSpace.get32(value);
563         break;
564       case 8:
565         value = addressSpace.get64(value);
566         break;
567       default:
568         assert(0 && "DW_OP_deref_size with bad size");
569       }
570       *(++sp) = value;
571       break;
572 
573     case DW_OP_fbreg:
574     case DW_OP_piece:
575     case DW_OP_xderef_size:
576     case DW_OP_nop:
577     case DW_OP_push_object_addres:
578     case DW_OP_call2:
579     case DW_OP_call4:
580     case DW_OP_call_ref:
581     default:
582       assert(0 && "dwarf opcode not implemented");
583     }
584   }
585   return *sp;
586 }
587 
588 } // namespace _Unwind
589 
590 #endif // __DWARF_INSTRUCTIONS_HPP__
591