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