]>
Commit | Line | Data |
---|---|---|
b1f7435d A |
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- |
2 | * | |
3 | * Copyright (c) 2008 Apple Inc. All rights reserved. | |
4 | * | |
5 | * @APPLE_LICENSE_HEADER_START@ | |
6 | * | |
7 | * This file contains Original Code and/or Modifications of Original Code | |
8 | * as defined in and that are subject to the Apple Public Source License | |
9 | * Version 2.0 (the 'License'). You may not use this file except in | |
10 | * compliance with the License. Please obtain a copy of the License at | |
11 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
12 | * file. | |
13 | * | |
14 | * The Original Code and all software distributed under the License are | |
15 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
19 | * Please see the License for the specific language governing rights and | |
20 | * limitations under the License. | |
21 | * | |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | ||
25 | // | |
26 | // processor specific parsing of dwarf unwind instructions | |
27 | // | |
28 | ||
29 | #ifndef __DWARF_INSTRUCTIONS_HPP__ | |
30 | #define __DWARF_INSTRUCTIONS_HPP__ | |
31 | ||
32 | #include <stdint.h> | |
33 | #include <stdio.h> | |
34 | #include <stdlib.h> | |
35 | ||
36 | #include <algorithm> | |
37 | #include <vector> | |
38 | ||
39 | #include <libunwind.h> | |
40 | #include <mach-o/compact_unwind_encoding.h> | |
41 | ||
42 | #include "dwarf2.h" | |
43 | #include "AddressSpace.hpp" | |
44 | #include "Registers.hpp" | |
45 | #include "DwarfParser.hpp" | |
46 | #include "InternalMacros.h" | |
47 | //#include "CompactUnwinder.hpp" | |
48 | ||
49 | #define EXTRACT_BITS(value, mask) \ | |
50 | ( (value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask)))-1) ) | |
51 | ||
52 | #define CFI_INVALID_ADDRESS ((pint_t)(-1)) | |
53 | ||
54 | namespace libunwind { | |
55 | ||
56 | /// | |
57 | /// Used by linker when parsing __eh_frame section | |
58 | /// | |
59 | template <typename A> | |
60 | struct CFI_Reference { | |
61 | typedef typename A::pint_t pint_t; | |
62 | uint8_t encodingOfTargetAddress; | |
63 | uint32_t offsetInCFI; | |
64 | pint_t targetAddress; | |
65 | }; | |
66 | template <typename A> | |
67 | struct CFI_Atom_Info { | |
68 | typedef typename A::pint_t pint_t; | |
69 | pint_t address; | |
70 | uint32_t size; | |
71 | bool isCIE; | |
72 | union { | |
73 | struct { | |
74 | CFI_Reference<A> function; | |
75 | CFI_Reference<A> cie; | |
76 | CFI_Reference<A> lsda; | |
77 | uint32_t compactUnwindInfo; | |
78 | } fdeInfo; | |
79 | struct { | |
80 | CFI_Reference<A> personality; | |
81 | } cieInfo; | |
82 | } u; | |
83 | }; | |
84 | ||
85 | typedef void (*WarnFunc)(void* ref, uint64_t funcAddr, const char* msg); | |
86 | ||
87 | /// | |
88 | /// DwarfInstructions maps abtract dwarf unwind instructions to a particular architecture | |
89 | /// | |
90 | template <typename A, typename R> | |
91 | class DwarfInstructions | |
92 | { | |
93 | public: | |
94 | typedef typename A::pint_t pint_t; | |
95 | typedef typename A::sint_t sint_t; | |
96 | ||
97 | static const char* parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, | |
98 | CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn); | |
99 | ||
100 | ||
101 | static compact_unwind_encoding_t createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart, | |
102 | pint_t* lsda, pint_t* personality, | |
103 | char warningBuffer[1024]); | |
104 | ||
105 | static int stepWithDwarf(A& addressSpace, pint_t pc, pint_t fdeStart, R& registers); | |
106 | ||
107 | private: | |
108 | ||
109 | enum { | |
110 | DW_X86_64_RET_ADDR = 16 | |
111 | }; | |
112 | ||
113 | enum { | |
114 | DW_X86_RET_ADDR = 8 | |
115 | }; | |
116 | ||
117 | static pint_t evaluateExpression(pint_t expression, A& addressSpace, const R& registers, pint_t initialStackValue); | |
118 | static pint_t getSavedRegister(A& addressSpace, const R& registers, pint_t cfa, | |
119 | const typename CFI_Parser<A>::RegisterLocation& savedReg); | |
120 | static double getSavedFloatRegister(A& addressSpace, const R& registers, pint_t cfa, | |
121 | const typename CFI_Parser<A>::RegisterLocation& savedReg); | |
122 | static v128 getSavedVectorRegister(A& addressSpace, const R& registers, pint_t cfa, | |
123 | const typename CFI_Parser<A>::RegisterLocation& savedReg); | |
124 | ||
125 | // x86 specific variants | |
126 | static int lastRestoreReg(const Registers_x86&); | |
127 | static bool isReturnAddressRegister(int regNum, const Registers_x86&); | |
128 | static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_x86&); | |
129 | ||
130 | static uint32_t getEBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure); | |
131 | static compact_unwind_encoding_t encodeToUseDwarf(const Registers_x86&); | |
132 | static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr, | |
133 | const Registers_x86&, const typename CFI_Parser<A>::PrologInfo& prolog, | |
134 | char warningBuffer[1024]); | |
135 | ||
136 | // x86_64 specific variants | |
137 | static int lastRestoreReg(const Registers_x86_64&); | |
138 | static bool isReturnAddressRegister(int regNum, const Registers_x86_64&); | |
139 | static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_x86_64&); | |
140 | ||
141 | static uint32_t getRBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure); | |
142 | static compact_unwind_encoding_t encodeToUseDwarf(const Registers_x86_64&); | |
143 | static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr, | |
144 | const Registers_x86_64&, const typename CFI_Parser<A>::PrologInfo& prolog, | |
145 | char warningBuffer[1024]); | |
146 | ||
147 | // ppc specific variants | |
148 | static int lastRestoreReg(const Registers_ppc&); | |
149 | static bool isReturnAddressRegister(int regNum, const Registers_ppc&); | |
150 | static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_ppc&); | |
151 | static compact_unwind_encoding_t encodeToUseDwarf(const Registers_ppc&); | |
152 | static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr, | |
153 | const Registers_ppc&, const typename CFI_Parser<A>::PrologInfo& prolog, | |
154 | char warningBuffer[1024]); | |
155 | }; | |
156 | ||
157 | ||
158 | ||
159 | ||
160 | template <typename A, typename R> | |
161 | const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, | |
162 | CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn) | |
163 | { | |
164 | typename CFI_Parser<A>::CIE_Info cieInfo; | |
165 | CFI_Atom_Info<A>* entry = infos; | |
166 | CFI_Atom_Info<A>* end = &infos[infosCount]; | |
167 | const pint_t ehSectionEnd = ehSectionStart + sectionLength; | |
168 | for (pint_t p=ehSectionStart; p < ehSectionEnd; ) { | |
169 | pint_t currentCFI = p; | |
170 | uint64_t cfiLength = addressSpace.get32(p); | |
171 | p += 4; | |
172 | if ( cfiLength == 0xffffffff ) { | |
173 | // 0xffffffff means length is really next 8 bytes | |
174 | cfiLength = addressSpace.get64(p); | |
175 | p += 8; | |
176 | } | |
177 | if ( cfiLength == 0 ) | |
178 | return NULL; // end marker | |
179 | if ( entry >= end ) | |
180 | return "too little space allocated for parseCFIs"; | |
181 | pint_t nextCFI = p + cfiLength; | |
182 | uint32_t id = addressSpace.get32(p); | |
183 | if ( id == 0 ) { | |
184 | // is CIE | |
185 | const char* err = CFI_Parser<A>::parseCIE(addressSpace, currentCFI, &cieInfo); | |
186 | if ( err != NULL ) | |
187 | return err; | |
188 | entry->address = currentCFI; | |
189 | entry->size = nextCFI - currentCFI; | |
190 | entry->isCIE = true; | |
191 | entry->u.cieInfo.personality.targetAddress = cieInfo.personality; | |
192 | entry->u.cieInfo.personality.offsetInCFI = cieInfo.personalityOffsetInCIE; | |
193 | entry->u.cieInfo.personality.encodingOfTargetAddress = cieInfo.personalityEncoding; | |
194 | ++entry; | |
195 | } | |
196 | else { | |
197 | // is FDE | |
198 | entry->address = currentCFI; | |
199 | entry->size = nextCFI - currentCFI; | |
200 | entry->isCIE = false; | |
201 | entry->u.fdeInfo.function.targetAddress = CFI_INVALID_ADDRESS; | |
202 | entry->u.fdeInfo.cie.targetAddress = CFI_INVALID_ADDRESS; | |
203 | entry->u.fdeInfo.lsda.targetAddress = CFI_INVALID_ADDRESS; | |
204 | uint32_t ciePointer = addressSpace.get32(p); | |
205 | pint_t cieStart = p-ciePointer; | |
206 | // validate pointer to CIE is within section | |
207 | if ( (cieStart < ehSectionStart) || (cieStart > ehSectionEnd) ) | |
208 | return "FDE points to CIE outside __eh_frame section"; | |
209 | // optimize usual case where cie is same for all FDEs | |
210 | if ( cieStart != cieInfo.cieStart ) { | |
211 | const char* err = CFI_Parser<A>::parseCIE(addressSpace, cieStart, &cieInfo); | |
212 | if ( err != NULL ) | |
213 | return err; | |
214 | } | |
215 | entry->u.fdeInfo.cie.targetAddress = cieStart; | |
216 | entry->u.fdeInfo.cie.offsetInCFI = p-currentCFI; | |
217 | entry->u.fdeInfo.cie.encodingOfTargetAddress = DW_EH_PE_sdata4 | DW_EH_PE_pcrel; | |
218 | p += 4; | |
219 | // parse pc begin and range | |
220 | pint_t offsetOfFunctionAddress = p-currentCFI; | |
221 | pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding); | |
222 | pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F); | |
223 | //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange)); | |
224 | // test if pc is within the function this FDE covers | |
225 | entry->u.fdeInfo.function.targetAddress = pcStart; | |
226 | entry->u.fdeInfo.function.offsetInCFI = offsetOfFunctionAddress; | |
227 | entry->u.fdeInfo.function.encodingOfTargetAddress = cieInfo.pointerEncoding; | |
228 | // check for augmentation length | |
229 | if ( cieInfo.fdesHaveAugmentationData ) { | |
230 | uintptr_t augLen = addressSpace.getULEB128(p, nextCFI); | |
231 | pint_t endOfAug = p + augLen; | |
232 | if ( cieInfo.lsdaEncoding != 0 ) { | |
233 | // peek at value (without indirection). Zero means no lsda | |
234 | pint_t lsdaStart = p; | |
235 | if ( addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding & 0x0F) != 0 ) { | |
236 | // reset pointer and re-parse lsda address | |
237 | p = lsdaStart; | |
238 | pint_t offsetOfLSDAAddress = p-currentCFI; | |
239 | entry->u.fdeInfo.lsda.targetAddress = addressSpace.getEncodedP(p, nextCFI, cieInfo.lsdaEncoding); | |
240 | entry->u.fdeInfo.lsda.offsetInCFI = offsetOfLSDAAddress; | |
241 | entry->u.fdeInfo.lsda.encodingOfTargetAddress = cieInfo.lsdaEncoding; | |
242 | } | |
243 | } | |
244 | p = endOfAug; | |
245 | } | |
246 | // compute compact unwind encoding | |
247 | typename CFI_Parser<A>::FDE_Info fdeInfo; | |
248 | fdeInfo.fdeStart = currentCFI; | |
249 | fdeInfo.fdeLength = nextCFI - currentCFI; | |
250 | fdeInfo.fdeInstructions = p; | |
251 | fdeInfo.pcStart = pcStart; | |
252 | fdeInfo.pcEnd = pcStart + pcRange; | |
253 | fdeInfo.lsda = entry->u.fdeInfo.lsda.targetAddress; | |
254 | typename CFI_Parser<A>::PrologInfo prolog; | |
255 | R dummy; // for proper selection of architecture specific functions | |
256 | if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) { | |
257 | char warningBuffer[1024]; | |
258 | entry->u.fdeInfo.compactUnwindInfo = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer); | |
259 | if ( fdeInfo.lsda != CFI_INVALID_ADDRESS ) | |
260 | entry->u.fdeInfo.compactUnwindInfo |= UNWIND_HAS_LSDA; | |
261 | if ( warningBuffer[0] != '\0' ) | |
262 | warn(ref, fdeInfo.pcStart, warningBuffer); | |
263 | } | |
264 | else { | |
265 | warn(ref, CFI_INVALID_ADDRESS, "dwarf unwind instructions could not be parsed"); | |
266 | entry->u.fdeInfo.compactUnwindInfo = encodeToUseDwarf(dummy); | |
267 | } | |
268 | ++entry; | |
269 | } | |
270 | p = nextCFI; | |
271 | } | |
272 | if ( entry != end ) | |
273 | return "wrong entry count for parseCFIs"; | |
274 | return NULL; // success | |
275 | } | |
276 | ||
277 | ||
278 | ||
279 | ||
280 | template <typename A, typename R> | |
281 | compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart, | |
282 | pint_t* lsda, pint_t* personality, | |
283 | char warningBuffer[1024]) | |
284 | { | |
285 | typename CFI_Parser<A>::FDE_Info fdeInfo; | |
286 | typename CFI_Parser<A>::CIE_Info cieInfo; | |
287 | R dummy; // for proper selection of architecture specific functions | |
288 | if ( CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL ) { | |
289 | typename CFI_Parser<A>::PrologInfo prolog; | |
290 | if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) { | |
291 | *lsda = fdeInfo.lsda; | |
292 | *personality = cieInfo.personality; | |
293 | compact_unwind_encoding_t encoding; | |
294 | encoding = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer); | |
295 | if ( fdeInfo.lsda != 0 ) | |
296 | encoding |= UNWIND_HAS_LSDA; | |
297 | return encoding; | |
298 | } | |
299 | else { | |
300 | strcpy(warningBuffer, "dwarf unwind instructions could not be parsed"); | |
301 | return encodeToUseDwarf(dummy); | |
302 | } | |
303 | } | |
304 | else { | |
305 | strcpy(warningBuffer, "dwarf FDE could not be parsed"); | |
306 | return encodeToUseDwarf(dummy); | |
307 | } | |
308 | } | |
309 | ||
310 | ||
311 | template <typename A, typename R> | |
312 | typename A::pint_t DwarfInstructions<A,R>::getSavedRegister(A& addressSpace, const R& registers, pint_t cfa, | |
313 | const typename CFI_Parser<A>::RegisterLocation& savedReg) | |
314 | { | |
315 | switch ( savedReg.location ) { | |
316 | case CFI_Parser<A>::kRegisterInCFA: | |
317 | return addressSpace.getP(cfa + savedReg.value); | |
318 | ||
319 | case CFI_Parser<A>::kRegisterAtExpression: | |
320 | return addressSpace.getP(evaluateExpression(savedReg.value, addressSpace, registers, cfa)); | |
321 | ||
322 | case CFI_Parser<A>::kRegisterIsExpression: | |
323 | return evaluateExpression(savedReg.value, addressSpace, registers, cfa); | |
324 | ||
325 | case CFI_Parser<A>::kRegisterInRegister: | |
326 | return registers.getRegister(savedReg.value); | |
327 | ||
328 | case CFI_Parser<A>::kRegisterUnused: | |
329 | case CFI_Parser<A>::kRegisterOffsetFromCFA: | |
330 | // FIX ME | |
331 | break; | |
332 | } | |
333 | ABORT("unsupported restore location for register"); | |
334 | } | |
335 | ||
336 | template <typename A, typename R> | |
337 | double DwarfInstructions<A,R>::getSavedFloatRegister(A& addressSpace, const R& registers, pint_t cfa, | |
338 | const typename CFI_Parser<A>::RegisterLocation& savedReg) | |
339 | { | |
340 | switch ( savedReg.location ) { | |
341 | case CFI_Parser<A>::kRegisterInCFA: | |
342 | return addressSpace.getDouble(cfa + savedReg.value); | |
343 | ||
344 | case CFI_Parser<A>::kRegisterAtExpression: | |
345 | return addressSpace.getDouble(evaluateExpression(savedReg.value, addressSpace, registers, cfa)); | |
346 | ||
347 | case CFI_Parser<A>::kRegisterIsExpression: | |
348 | case CFI_Parser<A>::kRegisterUnused: | |
349 | case CFI_Parser<A>::kRegisterOffsetFromCFA: | |
350 | case CFI_Parser<A>::kRegisterInRegister: | |
351 | // FIX ME | |
352 | break; | |
353 | } | |
354 | ABORT("unsupported restore location for float register"); | |
355 | } | |
356 | ||
357 | template <typename A, typename R> | |
358 | v128 DwarfInstructions<A,R>::getSavedVectorRegister(A& addressSpace, const R& registers, pint_t cfa, | |
359 | const typename CFI_Parser<A>::RegisterLocation& savedReg) | |
360 | { | |
361 | switch ( savedReg.location ) { | |
362 | case CFI_Parser<A>::kRegisterInCFA: | |
363 | return addressSpace.getVector(cfa + savedReg.value); | |
364 | ||
365 | case CFI_Parser<A>::kRegisterAtExpression: | |
366 | return addressSpace.getVector(evaluateExpression(savedReg.value, addressSpace, registers, cfa)); | |
367 | ||
368 | case CFI_Parser<A>::kRegisterIsExpression: | |
369 | case CFI_Parser<A>::kRegisterUnused: | |
370 | case CFI_Parser<A>::kRegisterOffsetFromCFA: | |
371 | case CFI_Parser<A>::kRegisterInRegister: | |
372 | // FIX ME | |
373 | break; | |
374 | } | |
375 | ABORT("unsupported restore location for vector register"); | |
376 | } | |
377 | ||
378 | ||
379 | template <typename A, typename R> | |
380 | int DwarfInstructions<A,R>::stepWithDwarf(A& addressSpace, pint_t pc, pint_t fdeStart, R& registers) | |
381 | { | |
382 | //fprintf(stderr, "stepWithDwarf(pc=0x%0llX, fdeStart=0x%0llX)\n", (uint64_t)pc, (uint64_t)fdeStart); | |
383 | typename CFI_Parser<A>::FDE_Info fdeInfo; | |
384 | typename CFI_Parser<A>::CIE_Info cieInfo; | |
385 | if ( CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo, &cieInfo) == NULL ) { | |
386 | typename CFI_Parser<A>::PrologInfo prolog; | |
387 | if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, &prolog) ) { | |
388 | R newRegisters = registers; | |
389 | ||
390 | // get pointer to cfa (architecture specific) | |
391 | pint_t cfa = getCFA(addressSpace, prolog, registers); | |
392 | ||
393 | // restore registers that dwarf says were saved | |
394 | pint_t returnAddress = 0; | |
395 | for (int i=0; i <= lastRestoreReg(newRegisters); ++i) { | |
396 | if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) { | |
397 | if ( registers.validFloatRegister(i) ) | |
398 | newRegisters.setFloatRegister(i, getSavedFloatRegister(addressSpace, registers, cfa, prolog.savedRegisters[i])); | |
399 | else if ( registers.validVectorRegister(i) ) | |
400 | newRegisters.setVectorRegister(i, getSavedVectorRegister(addressSpace, registers, cfa, prolog.savedRegisters[i])); | |
401 | else if ( isReturnAddressRegister(i, registers) ) | |
402 | returnAddress = getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i]); | |
403 | else if ( registers.validRegister(i) ) | |
404 | newRegisters.setRegister(i, getSavedRegister(addressSpace, registers, cfa, prolog.savedRegisters[i])); | |
405 | else | |
406 | return UNW_EBADREG; | |
407 | } | |
408 | } | |
409 | ||
410 | // by definition the CFA is the stack pointer at the call site, so restoring SP means setting it to CFA | |
411 | newRegisters.setSP(cfa); | |
412 | ||
413 | // return address is address after call site instruction, so setting IP to that does a return | |
414 | newRegisters.setIP(returnAddress); | |
415 | ||
416 | // do the actual step by replacing the register set with the new ones | |
417 | registers = newRegisters; | |
418 | ||
419 | return UNW_STEP_SUCCESS; | |
420 | } | |
421 | } | |
422 | return UNW_EBADFRAME; | |
423 | } | |
424 | ||
425 | ||
426 | ||
427 | template <typename A, typename R> | |
428 | typename A::pint_t DwarfInstructions<A,R>::evaluateExpression(pint_t expression, A& addressSpace, | |
429 | const R& registers, pint_t initialStackValue) | |
430 | { | |
431 | const bool log = false; | |
432 | pint_t p = expression; | |
433 | pint_t expressionEnd = expression+20; // just need something until length is read | |
434 | uint64_t length = addressSpace.getULEB128(p, expressionEnd); | |
435 | expressionEnd = p + length; | |
436 | if (log) fprintf(stderr, "evaluateExpression(): length=%llu\n", length); | |
437 | pint_t stack[100]; | |
438 | pint_t* sp = stack; | |
439 | *(++sp) = initialStackValue; | |
440 | ||
441 | while ( p < expressionEnd ) { | |
442 | if (log) { | |
443 | for(pint_t* t = sp; t > stack; --t) { | |
444 | fprintf(stderr, "sp[] = 0x%llX\n", (uint64_t)(*t)); | |
445 | } | |
446 | } | |
447 | uint8_t opcode = addressSpace.get8(p++); | |
448 | sint_t svalue; | |
449 | pint_t value; | |
450 | uint32_t reg; | |
451 | switch (opcode) { | |
452 | case DW_OP_addr: | |
453 | // push immediate address sized value | |
454 | value = addressSpace.getP(p); | |
455 | p += sizeof(pint_t); | |
456 | *(++sp) = value; | |
457 | if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value); | |
458 | break; | |
459 | ||
460 | case DW_OP_deref: | |
461 | // pop stack, dereference, push result | |
462 | value = *sp--; | |
463 | *(++sp) = addressSpace.getP(value); | |
464 | if (log) fprintf(stderr, "dereference 0x%llX\n", (uint64_t)value); | |
465 | break; | |
466 | ||
467 | case DW_OP_const1u: | |
468 | // push immediate 1 byte value | |
469 | value = addressSpace.get8(p); | |
470 | p += 1; | |
471 | *(++sp) = value; | |
472 | if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value); | |
473 | break; | |
474 | ||
475 | case DW_OP_const1s: | |
476 | // push immediate 1 byte signed value | |
477 | svalue = (int8_t)addressSpace.get8(p); | |
478 | p += 1; | |
479 | *(++sp) = svalue; | |
480 | if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue); | |
481 | break; | |
482 | ||
483 | case DW_OP_const2u: | |
484 | // push immediate 2 byte value | |
485 | value = addressSpace.get16(p); | |
486 | p += 2; | |
487 | *(++sp) = value; | |
488 | if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value); | |
489 | break; | |
490 | ||
491 | case DW_OP_const2s: | |
492 | // push immediate 2 byte signed value | |
493 | svalue = (int16_t)addressSpace.get16(p); | |
494 | p += 2; | |
495 | *(++sp) = svalue; | |
496 | if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue); | |
497 | break; | |
498 | ||
499 | case DW_OP_const4u: | |
500 | // push immediate 4 byte value | |
501 | value = addressSpace.get32(p); | |
502 | p += 4; | |
503 | *(++sp) = value; | |
504 | if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value); | |
505 | break; | |
506 | ||
507 | case DW_OP_const4s: | |
508 | // push immediate 4 byte signed value | |
509 | svalue = (int32_t)addressSpace.get32(p); | |
510 | p += 4; | |
511 | *(++sp) = svalue; | |
512 | if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue); | |
513 | break; | |
514 | ||
515 | case DW_OP_const8u: | |
516 | // push immediate 8 byte value | |
517 | value = addressSpace.get64(p); | |
518 | p += 8; | |
519 | *(++sp) = value; | |
520 | if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value); | |
521 | break; | |
522 | ||
523 | case DW_OP_const8s: | |
524 | // push immediate 8 byte signed value | |
525 | value = (int32_t)addressSpace.get64(p); | |
526 | p += 8; | |
527 | *(++sp) = value; | |
528 | if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value); | |
529 | break; | |
530 | ||
531 | case DW_OP_constu: | |
532 | // push immediate ULEB128 value | |
533 | value = addressSpace.getULEB128(p, expressionEnd); | |
534 | *(++sp) = value; | |
535 | if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)value); | |
536 | break; | |
537 | ||
538 | case DW_OP_consts: | |
539 | // push immediate SLEB128 value | |
540 | svalue = addressSpace.getSLEB128(p, expressionEnd); | |
541 | *(++sp) = svalue; | |
542 | if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t)svalue); | |
543 | break; | |
544 | ||
545 | case DW_OP_dup: | |
546 | // push top of stack | |
547 | value = *sp; | |
548 | *(++sp) = value; | |
549 | if (log) fprintf(stderr, "duplicate top of stack\n"); | |
550 | break; | |
551 | ||
552 | case DW_OP_drop: | |
553 | // pop | |
554 | --sp; | |
555 | if (log) fprintf(stderr, "pop top of stack\n"); | |
556 | break; | |
557 | ||
558 | case DW_OP_over: | |
559 | // dup second | |
560 | value = sp[-1]; | |
561 | *(++sp) = value; | |
562 | if (log) fprintf(stderr, "duplicate second in stack\n"); | |
563 | break; | |
564 | ||
565 | case DW_OP_pick: | |
566 | // pick from | |
567 | reg = addressSpace.get8(p); | |
568 | p += 1; | |
569 | value = sp[-reg]; | |
570 | *(++sp) = value; | |
571 | if (log) fprintf(stderr, "duplicate %d in stack\n", reg); | |
572 | break; | |
573 | ||
574 | case DW_OP_swap: | |
575 | // swap top two | |
576 | value = sp[0]; | |
577 | sp[0] = sp[-1]; | |
578 | sp[-1] = value; | |
579 | if (log) fprintf(stderr, "swap top of stack\n"); | |
580 | break; | |
581 | ||
582 | case DW_OP_rot: | |
583 | // rotate top three | |
584 | value = sp[0]; | |
585 | sp[0] = sp[-1]; | |
586 | sp[-1] = sp[-2]; | |
587 | sp[-2] = value; | |
588 | if (log) fprintf(stderr, "rotate top three of stack\n"); | |
589 | break; | |
590 | ||
591 | case DW_OP_xderef: | |
592 | // pop stack, dereference, push result | |
593 | value = *sp--; | |
594 | *sp = *((uint64_t*)value); | |
595 | if (log) fprintf(stderr, "x-dereference 0x%llX\n", (uint64_t)value); | |
596 | break; | |
597 | ||
598 | case DW_OP_abs: | |
599 | svalue = *sp; | |
600 | if ( svalue < 0 ) | |
601 | *sp = -svalue; | |
602 | if (log) fprintf(stderr, "abs\n"); | |
603 | break; | |
604 | ||
605 | case DW_OP_and: | |
606 | value = *sp--; | |
607 | *sp &= value; | |
608 | if (log) fprintf(stderr, "and\n"); | |
609 | break; | |
610 | ||
611 | case DW_OP_div: | |
612 | svalue = *sp--; | |
613 | *sp = *sp / svalue; | |
614 | if (log) fprintf(stderr, "div\n"); | |
615 | break; | |
616 | ||
617 | case DW_OP_minus: | |
618 | svalue = *sp--; | |
619 | *sp = *sp - svalue; | |
620 | if (log) fprintf(stderr, "minus\n"); | |
621 | break; | |
622 | ||
623 | case DW_OP_mod: | |
624 | svalue = *sp--; | |
625 | *sp = *sp % svalue; | |
626 | if (log) fprintf(stderr, "module\n"); | |
627 | break; | |
628 | ||
629 | case DW_OP_mul: | |
630 | svalue = *sp--; | |
631 | *sp = *sp * svalue; | |
632 | if (log) fprintf(stderr, "mul\n"); | |
633 | break; | |
634 | ||
635 | case DW_OP_neg: | |
636 | *sp = 0 - *sp; | |
637 | if (log) fprintf(stderr, "neg\n"); | |
638 | break; | |
639 | ||
640 | case DW_OP_not: | |
641 | svalue = *sp; | |
642 | *sp = ~svalue; | |
643 | if (log) fprintf(stderr, "not\n"); | |
644 | break; | |
645 | ||
646 | case DW_OP_or: | |
647 | value = *sp--; | |
648 | *sp |= value; | |
649 | if (log) fprintf(stderr, "or\n"); | |
650 | break; | |
651 | ||
652 | case DW_OP_plus: | |
653 | value = *sp--; | |
654 | *sp += value; | |
655 | if (log) fprintf(stderr, "plus\n"); | |
656 | break; | |
657 | ||
658 | case DW_OP_plus_uconst: | |
659 | // pop stack, add uelb128 constant, push result | |
660 | *sp += addressSpace.getULEB128(p, expressionEnd); | |
661 | if (log) fprintf(stderr, "add constant\n"); | |
662 | break; | |
663 | ||
664 | case DW_OP_shl: | |
665 | value = *sp--; | |
666 | *sp = *sp << value; | |
667 | if (log) fprintf(stderr, "shift left\n"); | |
668 | break; | |
669 | ||
670 | case DW_OP_shr: | |
671 | value = *sp--; | |
672 | *sp = *sp >> value; | |
673 | if (log) fprintf(stderr, "shift left\n"); | |
674 | break; | |
675 | ||
676 | case DW_OP_shra: | |
677 | value = *sp--; | |
678 | svalue = *sp; | |
679 | *sp = svalue >> value; | |
680 | if (log) fprintf(stderr, "shift left arithmetric\n"); | |
681 | break; | |
682 | ||
683 | case DW_OP_xor: | |
684 | value = *sp--; | |
685 | *sp ^= value; | |
686 | if (log) fprintf(stderr, "xor\n"); | |
687 | break; | |
688 | ||
689 | case DW_OP_skip: | |
690 | svalue = (int16_t)addressSpace.get16(p); | |
691 | p += 2; | |
692 | p += svalue; | |
693 | if (log) fprintf(stderr, "skip %lld\n", (uint64_t)svalue); | |
694 | break; | |
695 | ||
696 | case DW_OP_bra: | |
697 | svalue = (int16_t)addressSpace.get16(p); | |
698 | p += 2; | |
699 | if ( *sp-- ) | |
700 | p += svalue; | |
701 | if (log) fprintf(stderr, "bra %lld\n", (uint64_t)svalue); | |
702 | break; | |
703 | ||
704 | case DW_OP_eq: | |
705 | value = *sp--; | |
706 | *sp = (*sp == value); | |
707 | if (log) fprintf(stderr, "eq\n"); | |
708 | break; | |
709 | ||
710 | case DW_OP_ge: | |
711 | value = *sp--; | |
712 | *sp = (*sp >= value); | |
713 | if (log) fprintf(stderr, "ge\n"); | |
714 | break; | |
715 | ||
716 | case DW_OP_gt: | |
717 | value = *sp--; | |
718 | *sp = (*sp > value); | |
719 | if (log) fprintf(stderr, "gt\n"); | |
720 | break; | |
721 | ||
722 | case DW_OP_le: | |
723 | value = *sp--; | |
724 | *sp = (*sp <= value); | |
725 | if (log) fprintf(stderr, "le\n"); | |
726 | break; | |
727 | ||
728 | case DW_OP_lt: | |
729 | value = *sp--; | |
730 | *sp = (*sp < value); | |
731 | if (log) fprintf(stderr, "lt\n"); | |
732 | break; | |
733 | ||
734 | case DW_OP_ne: | |
735 | value = *sp--; | |
736 | *sp = (*sp != value); | |
737 | if (log) fprintf(stderr, "ne\n"); | |
738 | break; | |
739 | ||
740 | case DW_OP_lit0: | |
741 | case DW_OP_lit1: | |
742 | case DW_OP_lit2: | |
743 | case DW_OP_lit3: | |
744 | case DW_OP_lit4: | |
745 | case DW_OP_lit5: | |
746 | case DW_OP_lit6: | |
747 | case DW_OP_lit7: | |
748 | case DW_OP_lit8: | |
749 | case DW_OP_lit9: | |
750 | case DW_OP_lit10: | |
751 | case DW_OP_lit11: | |
752 | case DW_OP_lit12: | |
753 | case DW_OP_lit13: | |
754 | case DW_OP_lit14: | |
755 | case DW_OP_lit15: | |
756 | case DW_OP_lit16: | |
757 | case DW_OP_lit17: | |
758 | case DW_OP_lit18: | |
759 | case DW_OP_lit19: | |
760 | case DW_OP_lit20: | |
761 | case DW_OP_lit21: | |
762 | case DW_OP_lit22: | |
763 | case DW_OP_lit23: | |
764 | case DW_OP_lit24: | |
765 | case DW_OP_lit25: | |
766 | case DW_OP_lit26: | |
767 | case DW_OP_lit27: | |
768 | case DW_OP_lit28: | |
769 | case DW_OP_lit29: | |
770 | case DW_OP_lit30: | |
771 | case DW_OP_lit31: | |
772 | value = opcode - DW_OP_lit0; | |
773 | *(++sp) = value; | |
774 | if (log) fprintf(stderr, "push literal 0x%llX\n", (uint64_t)value); | |
775 | break; | |
776 | ||
777 | case DW_OP_reg0: | |
778 | case DW_OP_reg1: | |
779 | case DW_OP_reg2: | |
780 | case DW_OP_reg3: | |
781 | case DW_OP_reg4: | |
782 | case DW_OP_reg5: | |
783 | case DW_OP_reg6: | |
784 | case DW_OP_reg7: | |
785 | case DW_OP_reg8: | |
786 | case DW_OP_reg9: | |
787 | case DW_OP_reg10: | |
788 | case DW_OP_reg11: | |
789 | case DW_OP_reg12: | |
790 | case DW_OP_reg13: | |
791 | case DW_OP_reg14: | |
792 | case DW_OP_reg15: | |
793 | case DW_OP_reg16: | |
794 | case DW_OP_reg17: | |
795 | case DW_OP_reg18: | |
796 | case DW_OP_reg19: | |
797 | case DW_OP_reg20: | |
798 | case DW_OP_reg21: | |
799 | case DW_OP_reg22: | |
800 | case DW_OP_reg23: | |
801 | case DW_OP_reg24: | |
802 | case DW_OP_reg25: | |
803 | case DW_OP_reg26: | |
804 | case DW_OP_reg27: | |
805 | case DW_OP_reg28: | |
806 | case DW_OP_reg29: | |
807 | case DW_OP_reg30: | |
808 | case DW_OP_reg31: | |
809 | reg = opcode - DW_OP_reg0; | |
810 | *(++sp) = registers.getRegister(reg); | |
811 | if (log) fprintf(stderr, "push reg %d\n", reg); | |
812 | break; | |
813 | ||
814 | case DW_OP_regx: | |
815 | reg = addressSpace.getULEB128(p, expressionEnd); | |
816 | *(++sp) = registers.getRegister(reg); | |
817 | if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue); | |
818 | break; | |
819 | ||
820 | case DW_OP_breg0: | |
821 | case DW_OP_breg1: | |
822 | case DW_OP_breg2: | |
823 | case DW_OP_breg3: | |
824 | case DW_OP_breg4: | |
825 | case DW_OP_breg5: | |
826 | case DW_OP_breg6: | |
827 | case DW_OP_breg7: | |
828 | case DW_OP_breg8: | |
829 | case DW_OP_breg9: | |
830 | case DW_OP_breg10: | |
831 | case DW_OP_breg11: | |
832 | case DW_OP_breg12: | |
833 | case DW_OP_breg13: | |
834 | case DW_OP_breg14: | |
835 | case DW_OP_breg15: | |
836 | case DW_OP_breg16: | |
837 | case DW_OP_breg17: | |
838 | case DW_OP_breg18: | |
839 | case DW_OP_breg19: | |
840 | case DW_OP_breg20: | |
841 | case DW_OP_breg21: | |
842 | case DW_OP_breg22: | |
843 | case DW_OP_breg23: | |
844 | case DW_OP_breg24: | |
845 | case DW_OP_breg25: | |
846 | case DW_OP_breg26: | |
847 | case DW_OP_breg27: | |
848 | case DW_OP_breg28: | |
849 | case DW_OP_breg29: | |
850 | case DW_OP_breg30: | |
851 | case DW_OP_breg31: | |
852 | reg = opcode - DW_OP_breg0; | |
853 | svalue = addressSpace.getSLEB128(p, expressionEnd); | |
854 | *(++sp) = registers.getRegister(reg) + svalue; | |
855 | if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue); | |
856 | break; | |
857 | ||
858 | case DW_OP_bregx: | |
859 | reg = addressSpace.getULEB128(p, expressionEnd); | |
860 | svalue = addressSpace.getSLEB128(p, expressionEnd); | |
861 | *(++sp) = registers.getRegister(reg) + svalue; | |
862 | if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t)svalue); | |
863 | break; | |
864 | ||
865 | case DW_OP_fbreg: | |
866 | ABORT("DW_OP_fbreg not implemented"); | |
867 | break; | |
868 | ||
869 | case DW_OP_piece: | |
870 | ABORT("DW_OP_piece not implemented"); | |
871 | break; | |
872 | ||
873 | case DW_OP_deref_size: | |
874 | // pop stack, dereference, push result | |
875 | value = *sp--; | |
876 | switch ( addressSpace.get8(p++) ) { | |
877 | case 1: | |
878 | value = addressSpace.get8(value); | |
879 | break; | |
880 | case 2: | |
881 | value = addressSpace.get16(value); | |
882 | break; | |
883 | case 4: | |
884 | value = addressSpace.get32(value); | |
885 | break; | |
886 | case 8: | |
887 | value = addressSpace.get64(value); | |
888 | break; | |
889 | default: | |
890 | ABORT("DW_OP_deref_size with bad size"); | |
891 | } | |
892 | *(++sp) = value; | |
893 | if (log) fprintf(stderr, "sized dereference 0x%llX\n", (uint64_t)value); | |
894 | break; | |
895 | ||
896 | case DW_OP_xderef_size: | |
897 | case DW_OP_nop: | |
898 | case DW_OP_push_object_addres: | |
899 | case DW_OP_call2: | |
900 | case DW_OP_call4: | |
901 | case DW_OP_call_ref: | |
902 | default: | |
903 | ABORT("dwarf opcode not implemented"); | |
904 | } | |
905 | ||
906 | } | |
907 | if (log) fprintf(stderr, "expression evaluates to 0x%llX\n", (uint64_t)*sp); | |
908 | return *sp; | |
909 | } | |
910 | ||
911 | ||
912 | ||
913 | // | |
914 | // x86_64 specific functions | |
915 | // | |
916 | ||
917 | template <typename A, typename R> | |
918 | int DwarfInstructions<A,R>::lastRestoreReg(const Registers_x86_64&) | |
919 | { | |
920 | COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)DW_X86_64_RET_ADDR ); | |
921 | return DW_X86_64_RET_ADDR; | |
922 | } | |
923 | ||
924 | template <typename A, typename R> | |
925 | bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_x86_64&) | |
926 | { | |
927 | return (regNum == DW_X86_64_RET_ADDR); | |
928 | } | |
929 | ||
930 | template <typename A, typename R> | |
931 | typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, | |
932 | const Registers_x86_64& registers) | |
933 | { | |
934 | if ( prolog.cfaRegister != 0 ) | |
935 | return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset; | |
936 | else if ( prolog.cfaExpression != 0 ) | |
937 | return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0); | |
938 | else | |
939 | ABORT("getCFA(): unknown location for x86_64 cfa"); | |
940 | } | |
941 | ||
942 | ||
943 | ||
944 | template <typename A, typename R> | |
945 | compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_x86_64&) | |
946 | { | |
947 | return UNWIND_X86_64_MODE_DWARF; | |
948 | } | |
949 | ||
950 | template <typename A, typename R> | |
951 | compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_x86&) | |
952 | { | |
953 | return UNWIND_X86_MODE_DWARF; | |
954 | } | |
955 | ||
956 | ||
957 | ||
958 | template <typename A, typename R> | |
959 | uint32_t DwarfInstructions<A,R>::getRBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure) | |
960 | { | |
961 | if ( (regOffsetFromBaseOffset < 0) || (regOffsetFromBaseOffset > 32) ) { | |
962 | failure = true; | |
963 | return 0; | |
964 | } | |
965 | unsigned int slotIndex = regOffsetFromBaseOffset/8; | |
966 | ||
967 | switch ( reg ) { | |
968 | case UNW_X86_64_RBX: | |
969 | return UNWIND_X86_64_REG_RBX << (slotIndex*3); | |
970 | case UNW_X86_64_R12: | |
971 | return UNWIND_X86_64_REG_R12 << (slotIndex*3); | |
972 | case UNW_X86_64_R13: | |
973 | return UNWIND_X86_64_REG_R13 << (slotIndex*3); | |
974 | case UNW_X86_64_R14: | |
975 | return UNWIND_X86_64_REG_R14 << (slotIndex*3); | |
976 | case UNW_X86_64_R15: | |
977 | return UNWIND_X86_64_REG_R15 << (slotIndex*3); | |
978 | } | |
979 | ||
980 | // invalid register | |
981 | failure = true; | |
982 | return 0; | |
983 | } | |
984 | ||
985 | ||
986 | ||
987 | template <typename A, typename R> | |
988 | compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr, | |
989 | const Registers_x86_64& r, const typename CFI_Parser<A>::PrologInfo& prolog, | |
990 | char warningBuffer[1024]) | |
991 | { | |
992 | warningBuffer[0] = '\0'; | |
993 | ||
994 | if ( prolog.registerSavedTwiceInCIE == DW_X86_64_RET_ADDR ) { | |
995 | warningBuffer[0] = '\0'; // silently disable conversion to compact unwind by linker | |
996 | return UNWIND_X86_64_MODE_DWARF; | |
997 | } | |
998 | // don't create compact unwind info for unsupported dwarf kinds | |
999 | if ( prolog.registerSavedMoreThanOnce ) { | |
1000 | strcpy(warningBuffer, "register saved more than once (might be shrink wrap)"); | |
1001 | return UNWIND_X86_64_MODE_DWARF; | |
1002 | } | |
1003 | if ( prolog.cfaOffsetWasNegative ) { | |
1004 | strcpy(warningBuffer, "cfa had negative offset (dwarf might contain epilog)"); | |
1005 | return UNWIND_X86_64_MODE_DWARF; | |
1006 | } | |
1007 | if ( prolog.spExtraArgSize != 0 ) { | |
1008 | strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size"); | |
1009 | return UNWIND_X86_64_MODE_DWARF; | |
1010 | } | |
1011 | if ( prolog.sameValueUsed ) { | |
1012 | strcpy(warningBuffer, "dwarf uses DW_CFA_same_value"); | |
1013 | return UNWIND_X86_64_MODE_DWARF; | |
1014 | } | |
1015 | ||
1016 | // figure out which kind of frame this function uses | |
1017 | bool standardRBPframe = ( | |
1018 | (prolog.cfaRegister == UNW_X86_64_RBP) | |
1019 | && (prolog.cfaRegisterOffset == 16) | |
1020 | && (prolog.savedRegisters[UNW_X86_64_RBP].location == CFI_Parser<A>::kRegisterInCFA) | |
1021 | && (prolog.savedRegisters[UNW_X86_64_RBP].value == -16) ); | |
1022 | bool standardRSPframe = (prolog.cfaRegister == UNW_X86_64_RSP); | |
1023 | if ( !standardRBPframe && !standardRSPframe ) { | |
1024 | // no compact encoding for this | |
1025 | strcpy(warningBuffer, "does not use RBP or RSP based frame"); | |
1026 | return UNWIND_X86_64_MODE_DWARF; | |
1027 | } | |
1028 | ||
1029 | // scan which registers are saved | |
1030 | int saveRegisterCount = 0; | |
1031 | bool rbxSaved = false; | |
1032 | bool r12Saved = false; | |
1033 | bool r13Saved = false; | |
1034 | bool r14Saved = false; | |
1035 | bool r15Saved = false; | |
1036 | bool rbpSaved = false; | |
1037 | for (int i=0; i < 64; ++i) { | |
1038 | if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) { | |
1039 | if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) { | |
1040 | sprintf(warningBuffer, "register %d saved somewhere other that in frame", i); | |
1041 | return UNWIND_X86_64_MODE_DWARF; | |
1042 | } | |
1043 | switch (i) { | |
1044 | case UNW_X86_64_RBX: | |
1045 | rbxSaved = true; | |
1046 | ++saveRegisterCount; | |
1047 | break; | |
1048 | case UNW_X86_64_R12: | |
1049 | r12Saved = true; | |
1050 | ++saveRegisterCount; | |
1051 | break; | |
1052 | case UNW_X86_64_R13: | |
1053 | r13Saved = true; | |
1054 | ++saveRegisterCount; | |
1055 | break; | |
1056 | case UNW_X86_64_R14: | |
1057 | r14Saved = true; | |
1058 | ++saveRegisterCount; | |
1059 | break; | |
1060 | case UNW_X86_64_R15: | |
1061 | r15Saved = true; | |
1062 | ++saveRegisterCount; | |
1063 | break; | |
1064 | case UNW_X86_64_RBP: | |
1065 | rbpSaved = true; | |
1066 | ++saveRegisterCount; | |
1067 | break; | |
1068 | case DW_X86_64_RET_ADDR: | |
1069 | break; | |
1070 | default: | |
1071 | sprintf(warningBuffer, "non-standard register %d being saved in prolog", i); | |
1072 | return UNWIND_X86_64_MODE_DWARF; | |
1073 | } | |
1074 | } | |
1075 | } | |
1076 | const int64_t cfaOffsetRBX = prolog.savedRegisters[UNW_X86_64_RBX].value; | |
1077 | const int64_t cfaOffsetR12 = prolog.savedRegisters[UNW_X86_64_R12].value; | |
1078 | const int64_t cfaOffsetR13 = prolog.savedRegisters[UNW_X86_64_R13].value; | |
1079 | const int64_t cfaOffsetR14 = prolog.savedRegisters[UNW_X86_64_R14].value; | |
1080 | const int64_t cfaOffsetR15 = prolog.savedRegisters[UNW_X86_64_R15].value; | |
1081 | const int64_t cfaOffsetRBP = prolog.savedRegisters[UNW_X86_64_RBP].value; | |
1082 | ||
1083 | // encode standard RBP frames | |
1084 | compact_unwind_encoding_t encoding = 0; | |
1085 | if ( standardRBPframe ) { | |
1086 | // | | | |
1087 | // +--------------+ <- CFA | |
1088 | // | ret addr | | |
1089 | // +--------------+ | |
1090 | // | rbp | | |
1091 | // +--------------+ <- rbp | |
1092 | // ~ ~ | |
1093 | // +--------------+ | |
1094 | // | saved reg3 | | |
1095 | // +--------------+ <- CFA - offset+16 | |
1096 | // | saved reg2 | | |
1097 | // +--------------+ <- CFA - offset+8 | |
1098 | // | saved reg1 | | |
1099 | // +--------------+ <- CFA - offset | |
1100 | // | | | |
1101 | // +--------------+ | |
1102 | // | | | |
1103 | // <- rsp | |
1104 | // | |
1105 | encoding = UNWIND_X86_64_MODE_RBP_FRAME; | |
1106 | ||
1107 | // find save location of farthest register from rbp | |
1108 | int furthestCfaOffset = 0; | |
1109 | if ( rbxSaved & (cfaOffsetRBX < furthestCfaOffset) ) | |
1110 | furthestCfaOffset = cfaOffsetRBX; | |
1111 | if ( r12Saved & (cfaOffsetR12 < furthestCfaOffset) ) | |
1112 | furthestCfaOffset = cfaOffsetR12; | |
1113 | if ( r13Saved & (cfaOffsetR13 < furthestCfaOffset) ) | |
1114 | furthestCfaOffset = cfaOffsetR13; | |
1115 | if ( r14Saved & (cfaOffsetR14 < furthestCfaOffset) ) | |
1116 | furthestCfaOffset = cfaOffsetR14; | |
1117 | if ( r15Saved & (cfaOffsetR15 < furthestCfaOffset) ) | |
1118 | furthestCfaOffset = cfaOffsetR15; | |
1119 | ||
1120 | if ( furthestCfaOffset == 0 ) { | |
1121 | // no registers saved, nothing more to encode | |
1122 | return encoding; | |
1123 | } | |
1124 | ||
1125 | // add stack offset to encoding | |
1126 | int rbpOffset = furthestCfaOffset + 16; | |
1127 | int encodedOffset = rbpOffset/(-8); | |
1128 | if ( encodedOffset > 255 ) { | |
1129 | strcpy(warningBuffer, "offset of saved registers too far to encode"); | |
1130 | return UNWIND_X86_64_MODE_DWARF; | |
1131 | } | |
1132 | encoding |= (encodedOffset << __builtin_ctz(UNWIND_X86_64_RBP_FRAME_OFFSET)); | |
1133 | ||
1134 | // add register saved from each stack location | |
1135 | bool encodingFailure = false; | |
1136 | if ( rbxSaved ) | |
1137 | encoding |= getRBPEncodedRegister(UNW_X86_64_RBX, cfaOffsetRBX - furthestCfaOffset, encodingFailure); | |
1138 | if ( r12Saved ) | |
1139 | encoding |= getRBPEncodedRegister(UNW_X86_64_R12, cfaOffsetR12 - furthestCfaOffset, encodingFailure); | |
1140 | if ( r13Saved ) | |
1141 | encoding |= getRBPEncodedRegister(UNW_X86_64_R13, cfaOffsetR13 - furthestCfaOffset, encodingFailure); | |
1142 | if ( r14Saved ) | |
1143 | encoding |= getRBPEncodedRegister(UNW_X86_64_R14, cfaOffsetR14 - furthestCfaOffset, encodingFailure); | |
1144 | if ( r15Saved ) | |
1145 | encoding |= getRBPEncodedRegister(UNW_X86_64_R15, cfaOffsetR15 - furthestCfaOffset, encodingFailure); | |
1146 | ||
1147 | if ( encodingFailure ){ | |
1148 | strcpy(warningBuffer, "saved registers not contiguous"); | |
1149 | return UNWIND_X86_64_MODE_DWARF; | |
1150 | } | |
1151 | ||
1152 | return encoding; | |
1153 | } | |
1154 | else { | |
1155 | // | | | |
1156 | // +--------------+ <- CFA | |
1157 | // | ret addr | | |
1158 | // +--------------+ | |
1159 | // | saved reg1 | | |
1160 | // +--------------+ <- CFA - 16 | |
1161 | // | saved reg2 | | |
1162 | // +--------------+ <- CFA - 24 | |
1163 | // | saved reg3 | | |
1164 | // +--------------+ <- CFA - 32 | |
1165 | // | saved reg4 | | |
1166 | // +--------------+ <- CFA - 40 | |
1167 | // | saved reg5 | | |
1168 | // +--------------+ <- CFA - 48 | |
1169 | // | saved reg6 | | |
1170 | // +--------------+ <- CFA - 56 | |
1171 | // | | | |
1172 | // <- esp | |
1173 | // | |
1174 | ||
1175 | // for RSP based frames we need to encode stack size in unwind info | |
1176 | encoding = UNWIND_X86_64_MODE_STACK_IMMD; | |
1177 | uint64_t stackValue = prolog.cfaRegisterOffset / 8; | |
1178 | uint32_t stackAdjust = 0; | |
1179 | bool immedStackSize = true; | |
1180 | const uint32_t stackMaxImmedValue = EXTRACT_BITS(0xFFFFFFFF,UNWIND_X86_64_FRAMELESS_STACK_SIZE); | |
1181 | if ( stackValue > stackMaxImmedValue ) { | |
1182 | // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function | |
1183 | if ( prolog.codeOffsetAtStackDecrement == 0 ) { | |
1184 | strcpy(warningBuffer, "stack size is large but stack subq instruction not found"); | |
1185 | return UNWIND_X86_64_MODE_DWARF; | |
1186 | } | |
1187 | pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4; | |
1188 | try { | |
1189 | uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns); | |
1190 | stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/8; | |
1191 | } | |
1192 | catch (...) { | |
1193 | strcpy(warningBuffer, "stack size is large but stack subq instruction not found"); | |
1194 | return UNWIND_X86_64_MODE_DWARF; | |
1195 | } | |
1196 | stackValue = functionContentAdjustStackIns - funcAddr; | |
1197 | immedStackSize = false; | |
1198 | if ( stackAdjust > 7 ) { | |
1199 | strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size"); | |
1200 | return UNWIND_X86_64_MODE_DWARF; | |
1201 | } | |
1202 | encoding = UNWIND_X86_64_MODE_STACK_IND; | |
1203 | } | |
1204 | ||
1205 | ||
1206 | // validate that saved registers are all within 6 slots abutting return address | |
1207 | int registers[6]; | |
1208 | for (int i=0; i < 6;++i) | |
1209 | registers[i] = 0; | |
1210 | if ( r15Saved ) { | |
1211 | if ( cfaOffsetR15 < -56 ) { | |
1212 | strcpy(warningBuffer, "r15 is saved too far from return address"); | |
1213 | return UNWIND_X86_64_MODE_DWARF; | |
1214 | } | |
1215 | registers[(cfaOffsetR15+56)/8] = UNWIND_X86_64_REG_R15; | |
1216 | } | |
1217 | if ( r14Saved ) { | |
1218 | if ( cfaOffsetR14 < -56 ) { | |
1219 | strcpy(warningBuffer, "r14 is saved too far from return address"); | |
1220 | return UNWIND_X86_64_MODE_DWARF; | |
1221 | } | |
1222 | registers[(cfaOffsetR14+56)/8] = UNWIND_X86_64_REG_R14; | |
1223 | } | |
1224 | if ( r13Saved ) { | |
1225 | if ( cfaOffsetR13 < -56 ) { | |
1226 | strcpy(warningBuffer, "r13 is saved too far from return address"); | |
1227 | return UNWIND_X86_64_MODE_DWARF; | |
1228 | } | |
1229 | registers[(cfaOffsetR13+56)/8] = UNWIND_X86_64_REG_R13; | |
1230 | } | |
1231 | if ( r12Saved ) { | |
1232 | if ( cfaOffsetR12 < -56 ) { | |
1233 | strcpy(warningBuffer, "r12 is saved too far from return address"); | |
1234 | return UNWIND_X86_64_MODE_DWARF; | |
1235 | } | |
1236 | registers[(cfaOffsetR12+56)/8] = UNWIND_X86_64_REG_R12; | |
1237 | } | |
1238 | if ( rbxSaved ) { | |
1239 | if ( cfaOffsetRBX < -56 ) { | |
1240 | strcpy(warningBuffer, "rbx is saved too far from return address"); | |
1241 | return UNWIND_X86_64_MODE_DWARF; | |
1242 | } | |
1243 | registers[(cfaOffsetRBX+56)/8] = UNWIND_X86_64_REG_RBX; | |
1244 | } | |
1245 | if ( rbpSaved ) { | |
1246 | if ( cfaOffsetRBP < -56 ) { | |
1247 | strcpy(warningBuffer, "rbp is saved too far from return address"); | |
1248 | return UNWIND_X86_64_MODE_DWARF; | |
1249 | } | |
1250 | registers[(cfaOffsetRBP+56)/8] = UNWIND_X86_64_REG_RBP; | |
1251 | } | |
1252 | ||
1253 | // validate that saved registers are contiguous and abut return address on stack | |
1254 | for (int i=0; i < saveRegisterCount; ++i) { | |
1255 | if ( registers[5-i] == 0 ) { | |
1256 | strcpy(warningBuffer, "registers not save contiguously in stack"); | |
1257 | return UNWIND_X86_64_MODE_DWARF; | |
1258 | } | |
1259 | } | |
1260 | ||
1261 | // encode register permutation | |
1262 | // the 10-bits are encoded differently depending on the number of registers saved | |
1263 | int renumregs[6]; | |
1264 | for (int i=6-saveRegisterCount; i < 6; ++i) { | |
1265 | int countless = 0; | |
1266 | for (int j=6-saveRegisterCount; j < i; ++j) { | |
1267 | if ( registers[j] < registers[i] ) | |
1268 | ++countless; | |
1269 | } | |
1270 | renumregs[i] = registers[i] - countless -1; | |
1271 | } | |
1272 | uint32_t permutationEncoding = 0; | |
1273 | switch ( saveRegisterCount ) { | |
1274 | case 6: | |
1275 | permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] + 6*renumregs[2] + 2*renumregs[3] + renumregs[4]); | |
1276 | break; | |
1277 | case 5: | |
1278 | permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] + 6*renumregs[3] + 2*renumregs[4] + renumregs[5]); | |
1279 | break; | |
1280 | case 4: | |
1281 | permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] + 3*renumregs[4] + renumregs[5]); | |
1282 | break; | |
1283 | case 3: | |
1284 | permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] + renumregs[5]); | |
1285 | break; | |
1286 | case 2: | |
1287 | permutationEncoding |= (5*renumregs[4] + renumregs[5]); | |
1288 | break; | |
1289 | case 1: | |
1290 | permutationEncoding |= (renumregs[5]); | |
1291 | break; | |
1292 | } | |
1293 | ||
1294 | encoding |= (stackValue << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_SIZE)); | |
1295 | encoding |= (stackAdjust << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_ADJUST)); | |
1296 | encoding |= (saveRegisterCount << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT)); | |
1297 | encoding |= (permutationEncoding << __builtin_ctz(UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION)); | |
1298 | return encoding; | |
1299 | } | |
1300 | } | |
1301 | ||
1302 | ||
1303 | ||
1304 | ||
1305 | // | |
1306 | // x86 specific functions | |
1307 | // | |
1308 | template <typename A, typename R> | |
1309 | int DwarfInstructions<A,R>::lastRestoreReg(const Registers_x86&) | |
1310 | { | |
1311 | COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)DW_X86_RET_ADDR ); | |
1312 | return DW_X86_RET_ADDR; | |
1313 | } | |
1314 | ||
1315 | template <typename A, typename R> | |
1316 | bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_x86&) | |
1317 | { | |
1318 | return (regNum == DW_X86_RET_ADDR); | |
1319 | } | |
1320 | ||
1321 | template <typename A, typename R> | |
1322 | typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, | |
1323 | const Registers_x86& registers) | |
1324 | { | |
1325 | if ( prolog.cfaRegister != 0 ) | |
1326 | return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset; | |
1327 | else if ( prolog.cfaExpression != 0 ) | |
1328 | return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0); | |
1329 | else | |
1330 | ABORT("getCFA(): unknown location for x86 cfa"); | |
1331 | } | |
1332 | ||
1333 | ||
1334 | ||
1335 | ||
1336 | ||
1337 | template <typename A, typename R> | |
1338 | uint32_t DwarfInstructions<A,R>::getEBPEncodedRegister(uint32_t reg, int32_t regOffsetFromBaseOffset, bool& failure) | |
1339 | { | |
1340 | if ( (regOffsetFromBaseOffset < 0) || (regOffsetFromBaseOffset > 16) ) { | |
1341 | failure = true; | |
1342 | return 0; | |
1343 | } | |
1344 | unsigned int slotIndex = regOffsetFromBaseOffset/4; | |
1345 | ||
1346 | switch ( reg ) { | |
1347 | case UNW_X86_EBX: | |
1348 | return UNWIND_X86_REG_EBX << (slotIndex*3); | |
1349 | case UNW_X86_ECX: | |
1350 | return UNWIND_X86_REG_ECX << (slotIndex*3); | |
1351 | case UNW_X86_EDX: | |
1352 | return UNWIND_X86_REG_EDX << (slotIndex*3); | |
1353 | case UNW_X86_EDI: | |
1354 | return UNWIND_X86_REG_EDI << (slotIndex*3); | |
1355 | case UNW_X86_ESI: | |
1356 | return UNWIND_X86_REG_ESI << (slotIndex*3); | |
1357 | } | |
1358 | ||
1359 | // invalid register | |
1360 | failure = true; | |
1361 | return 0; | |
1362 | } | |
1363 | ||
1364 | template <typename A, typename R> | |
1365 | compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr, | |
1366 | const Registers_x86& r, const typename CFI_Parser<A>::PrologInfo& prolog, | |
1367 | char warningBuffer[1024]) | |
1368 | { | |
1369 | warningBuffer[0] = '\0'; | |
1370 | ||
1371 | if ( prolog.registerSavedTwiceInCIE == DW_X86_RET_ADDR ) { | |
1372 | warningBuffer[0] = '\0'; // silently disable conversion to compact unwind by linker | |
1373 | return UNWIND_X86_64_MODE_DWARF; | |
1374 | } | |
1375 | // don't create compact unwind info for unsupported dwarf kinds | |
1376 | if ( prolog.registerSavedMoreThanOnce ) { | |
1377 | strcpy(warningBuffer, "register saved more than once (might be shrink wrap)"); | |
1378 | return UNWIND_X86_MODE_DWARF; | |
1379 | } | |
1380 | if ( prolog.spExtraArgSize != 0 ) { | |
1381 | strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size"); | |
1382 | return UNWIND_X86_MODE_DWARF; | |
1383 | } | |
1384 | if ( prolog.sameValueUsed ) { | |
1385 | strcpy(warningBuffer, "dwarf uses DW_CFA_same_value"); | |
1386 | return UNWIND_X86_MODE_DWARF; | |
1387 | } | |
1388 | ||
1389 | // figure out which kind of frame this function uses | |
1390 | bool standardEBPframe = ( | |
1391 | (prolog.cfaRegister == UNW_X86_EBP) | |
1392 | && (prolog.cfaRegisterOffset == 8) | |
1393 | && (prolog.savedRegisters[UNW_X86_EBP].location == CFI_Parser<A>::kRegisterInCFA) | |
1394 | && (prolog.savedRegisters[UNW_X86_EBP].value == -8) ); | |
1395 | bool standardESPframe = (prolog.cfaRegister == UNW_X86_ESP); | |
1396 | if ( !standardEBPframe && !standardESPframe ) { | |
1397 | // no compact encoding for this | |
1398 | strcpy(warningBuffer, "does not use EBP or ESP based frame"); | |
1399 | return UNWIND_X86_MODE_DWARF; | |
1400 | } | |
1401 | ||
1402 | // scan which registers are saved | |
1403 | int saveRegisterCount = 0; | |
1404 | bool ebxSaved = false; | |
1405 | bool ecxSaved = false; | |
1406 | bool edxSaved = false; | |
1407 | bool esiSaved = false; | |
1408 | bool ediSaved = false; | |
1409 | bool ebpSaved = false; | |
1410 | for (int i=0; i < 64; ++i) { | |
1411 | if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) { | |
1412 | if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) { | |
1413 | sprintf(warningBuffer, "register %d saved somewhere other that in frame", i); | |
1414 | return UNWIND_X86_MODE_DWARF; | |
1415 | } | |
1416 | switch (i) { | |
1417 | case UNW_X86_EBX: | |
1418 | ebxSaved = true; | |
1419 | ++saveRegisterCount; | |
1420 | break; | |
1421 | case UNW_X86_ECX: | |
1422 | ecxSaved = true; | |
1423 | ++saveRegisterCount; | |
1424 | break; | |
1425 | case UNW_X86_EDX: | |
1426 | edxSaved = true; | |
1427 | ++saveRegisterCount; | |
1428 | break; | |
1429 | case UNW_X86_ESI: | |
1430 | esiSaved = true; | |
1431 | ++saveRegisterCount; | |
1432 | break; | |
1433 | case UNW_X86_EDI: | |
1434 | ediSaved = true; | |
1435 | ++saveRegisterCount; | |
1436 | break; | |
1437 | case UNW_X86_EBP: | |
1438 | ebpSaved = true; | |
1439 | ++saveRegisterCount; | |
1440 | break; | |
1441 | case DW_X86_RET_ADDR: | |
1442 | break; | |
1443 | default: | |
1444 | sprintf(warningBuffer, "non-standard register %d being saved in prolog", i); | |
1445 | return UNWIND_X86_MODE_DWARF; | |
1446 | } | |
1447 | } | |
1448 | } | |
1449 | const int32_t cfaOffsetEBX = prolog.savedRegisters[UNW_X86_EBX].value; | |
1450 | const int32_t cfaOffsetECX = prolog.savedRegisters[UNW_X86_ECX].value; | |
1451 | const int32_t cfaOffsetEDX = prolog.savedRegisters[UNW_X86_EDX].value; | |
1452 | const int32_t cfaOffsetEDI = prolog.savedRegisters[UNW_X86_EDI].value; | |
1453 | const int32_t cfaOffsetESI = prolog.savedRegisters[UNW_X86_ESI].value; | |
1454 | const int32_t cfaOffsetEBP = prolog.savedRegisters[UNW_X86_EBP].value; | |
1455 | ||
1456 | // encode standard RBP frames | |
1457 | compact_unwind_encoding_t encoding = 0; | |
1458 | if ( standardEBPframe ) { | |
1459 | // | | | |
1460 | // +--------------+ <- CFA | |
1461 | // | ret addr | | |
1462 | // +--------------+ | |
1463 | // | ebp | | |
1464 | // +--------------+ <- ebp | |
1465 | // ~ ~ | |
1466 | // +--------------+ | |
1467 | // | saved reg3 | | |
1468 | // +--------------+ <- CFA - offset+8 | |
1469 | // | saved reg2 | | |
1470 | // +--------------+ <- CFA - offset+e | |
1471 | // | saved reg1 | | |
1472 | // +--------------+ <- CFA - offset | |
1473 | // | | | |
1474 | // +--------------+ | |
1475 | // | | | |
1476 | // <- esp | |
1477 | // | |
1478 | encoding = UNWIND_X86_MODE_EBP_FRAME; | |
1479 | ||
1480 | // find save location of farthest register from ebp | |
1481 | int furthestCfaOffset = 0; | |
1482 | if ( ebxSaved & (cfaOffsetEBX < furthestCfaOffset) ) | |
1483 | furthestCfaOffset = cfaOffsetEBX; | |
1484 | if ( ecxSaved & (cfaOffsetECX < furthestCfaOffset) ) | |
1485 | furthestCfaOffset = cfaOffsetECX; | |
1486 | if ( edxSaved & (cfaOffsetEDX < furthestCfaOffset) ) | |
1487 | furthestCfaOffset = cfaOffsetEDX; | |
1488 | if ( ediSaved & (cfaOffsetEDI < furthestCfaOffset) ) | |
1489 | furthestCfaOffset = cfaOffsetEDI; | |
1490 | if ( esiSaved & (cfaOffsetESI < furthestCfaOffset) ) | |
1491 | furthestCfaOffset = cfaOffsetESI; | |
1492 | ||
1493 | if ( furthestCfaOffset == 0 ) { | |
1494 | // no registers saved, nothing more to encode | |
1495 | return encoding; | |
1496 | } | |
1497 | ||
1498 | // add stack offset to encoding | |
1499 | int ebpOffset = furthestCfaOffset + 8; | |
1500 | int encodedOffset = ebpOffset/(-4); | |
1501 | if ( encodedOffset > 255 ) { | |
1502 | strcpy(warningBuffer, "offset of saved registers too far to encode"); | |
1503 | return UNWIND_X86_MODE_DWARF; | |
1504 | } | |
1505 | encoding |= (encodedOffset << __builtin_ctz(UNWIND_X86_EBP_FRAME_OFFSET)); | |
1506 | ||
1507 | // add register saved from each stack location | |
1508 | bool encodingFailure = false; | |
1509 | if ( ebxSaved ) | |
1510 | encoding |= getEBPEncodedRegister(UNW_X86_EBX, cfaOffsetEBX - furthestCfaOffset, encodingFailure); | |
1511 | if ( ecxSaved ) | |
1512 | encoding |= getEBPEncodedRegister(UNW_X86_ECX, cfaOffsetECX - furthestCfaOffset, encodingFailure); | |
1513 | if ( edxSaved ) | |
1514 | encoding |= getEBPEncodedRegister(UNW_X86_EDX, cfaOffsetEDX - furthestCfaOffset, encodingFailure); | |
1515 | if ( ediSaved ) | |
1516 | encoding |= getEBPEncodedRegister(UNW_X86_EDI, cfaOffsetEDI - furthestCfaOffset, encodingFailure); | |
1517 | if ( esiSaved ) | |
1518 | encoding |= getEBPEncodedRegister(UNW_X86_ESI, cfaOffsetESI - furthestCfaOffset, encodingFailure); | |
1519 | ||
1520 | if ( encodingFailure ){ | |
1521 | strcpy(warningBuffer, "saved registers not contiguous"); | |
1522 | return UNWIND_X86_MODE_DWARF; | |
1523 | } | |
1524 | ||
1525 | return encoding; | |
1526 | } | |
1527 | else { | |
1528 | // | | | |
1529 | // +--------------+ <- CFA | |
1530 | // | ret addr | | |
1531 | // +--------------+ | |
1532 | // | saved reg1 | | |
1533 | // +--------------+ <- CFA - 8 | |
1534 | // | saved reg2 | | |
1535 | // +--------------+ <- CFA - 12 | |
1536 | // | saved reg3 | | |
1537 | // +--------------+ <- CFA - 16 | |
1538 | // | saved reg4 | | |
1539 | // +--------------+ <- CFA - 20 | |
1540 | // | saved reg5 | | |
1541 | // +--------------+ <- CFA - 24 | |
1542 | // | saved reg6 | | |
1543 | // +--------------+ <- CFA - 28 | |
1544 | // | | | |
1545 | // <- esp | |
1546 | // | |
1547 | ||
1548 | // for ESP based frames we need to encode stack size in unwind info | |
1549 | encoding = UNWIND_X86_MODE_STACK_IMMD; | |
1550 | uint64_t stackValue = prolog.cfaRegisterOffset / 4; | |
1551 | uint32_t stackAdjust = 0; | |
1552 | bool immedStackSize = true; | |
1553 | const uint32_t stackMaxImmedValue = EXTRACT_BITS(0xFFFFFFFF,UNWIND_X86_FRAMELESS_STACK_SIZE); | |
1554 | if ( stackValue > stackMaxImmedValue ) { | |
1555 | // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function | |
1556 | pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4; | |
1557 | uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns); | |
1558 | stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/4; | |
1559 | stackValue = functionContentAdjustStackIns - funcAddr; | |
1560 | immedStackSize = false; | |
1561 | if ( stackAdjust > 7 ) { | |
1562 | strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size"); | |
1563 | return UNWIND_X86_MODE_DWARF; | |
1564 | } | |
1565 | encoding = UNWIND_X86_MODE_STACK_IND; | |
1566 | } | |
1567 | ||
1568 | ||
1569 | // validate that saved registers are all within 6 slots abutting return address | |
1570 | int registers[6]; | |
1571 | for (int i=0; i < 6;++i) | |
1572 | registers[i] = 0; | |
1573 | if ( ebxSaved ) { | |
1574 | if ( cfaOffsetEBX < -28 ) { | |
1575 | strcpy(warningBuffer, "ebx is saved too far from return address"); | |
1576 | return UNWIND_X86_MODE_DWARF; | |
1577 | } | |
1578 | registers[(cfaOffsetEBX+28)/4] = UNWIND_X86_REG_EBX; | |
1579 | } | |
1580 | if ( ecxSaved ) { | |
1581 | if ( cfaOffsetECX < -28 ) { | |
1582 | strcpy(warningBuffer, "ecx is saved too far from return address"); | |
1583 | return UNWIND_X86_MODE_DWARF; | |
1584 | } | |
1585 | registers[(cfaOffsetECX+28)/4] = UNWIND_X86_REG_ECX; | |
1586 | } | |
1587 | if ( edxSaved ) { | |
1588 | if ( cfaOffsetEDX < -28 ) { | |
1589 | strcpy(warningBuffer, "edx is saved too far from return address"); | |
1590 | return UNWIND_X86_MODE_DWARF; | |
1591 | } | |
1592 | registers[(cfaOffsetEDX+28)/4] = UNWIND_X86_REG_EDX; | |
1593 | } | |
1594 | if ( ediSaved ) { | |
1595 | if ( cfaOffsetEDI < -28 ) { | |
1596 | strcpy(warningBuffer, "edi is saved too far from return address"); | |
1597 | return UNWIND_X86_MODE_DWARF; | |
1598 | } | |
1599 | registers[(cfaOffsetEDI+28)/4] = UNWIND_X86_REG_EDI; | |
1600 | } | |
1601 | if ( esiSaved ) { | |
1602 | if ( cfaOffsetESI < -28 ) { | |
1603 | strcpy(warningBuffer, "esi is saved too far from return address"); | |
1604 | return UNWIND_X86_MODE_DWARF; | |
1605 | } | |
1606 | registers[(cfaOffsetESI+28)/4] = UNWIND_X86_REG_ESI; | |
1607 | } | |
1608 | if ( ebpSaved ) { | |
1609 | if ( cfaOffsetEBP < -28 ) { | |
1610 | strcpy(warningBuffer, "ebp is saved too far from return address"); | |
1611 | return UNWIND_X86_MODE_DWARF; | |
1612 | } | |
1613 | registers[(cfaOffsetEBP+28)/4] = UNWIND_X86_REG_EBP; | |
1614 | } | |
1615 | ||
1616 | // validate that saved registers are contiguous and abut return address on stack | |
1617 | for (int i=0; i < saveRegisterCount; ++i) { | |
1618 | if ( registers[5-i] == 0 ) { | |
1619 | strcpy(warningBuffer, "registers not save contiguously in stack"); | |
1620 | return UNWIND_X86_MODE_DWARF; | |
1621 | } | |
1622 | } | |
1623 | ||
1624 | // encode register permutation | |
1625 | // the 10-bits are encoded differently depending on the number of registers saved | |
1626 | int renumregs[6]; | |
1627 | for (int i=6-saveRegisterCount; i < 6; ++i) { | |
1628 | int countless = 0; | |
1629 | for (int j=6-saveRegisterCount; j < i; ++j) { | |
1630 | if ( registers[j] < registers[i] ) | |
1631 | ++countless; | |
1632 | } | |
1633 | renumregs[i] = registers[i] - countless -1; | |
1634 | } | |
1635 | uint32_t permutationEncoding = 0; | |
1636 | switch ( saveRegisterCount ) { | |
1637 | case 6: | |
1638 | permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] + 6*renumregs[2] + 2*renumregs[3] + renumregs[4]); | |
1639 | break; | |
1640 | case 5: | |
1641 | permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] + 6*renumregs[3] + 2*renumregs[4] + renumregs[5]); | |
1642 | break; | |
1643 | case 4: | |
1644 | permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] + 3*renumregs[4] + renumregs[5]); | |
1645 | break; | |
1646 | case 3: | |
1647 | permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] + renumregs[5]); | |
1648 | break; | |
1649 | case 2: | |
1650 | permutationEncoding |= (5*renumregs[4] + renumregs[5]); | |
1651 | break; | |
1652 | case 1: | |
1653 | permutationEncoding |= (renumregs[5]); | |
1654 | break; | |
1655 | } | |
1656 | ||
1657 | encoding |= (stackValue << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_SIZE)); | |
1658 | encoding |= (stackAdjust << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_ADJUST)); | |
1659 | encoding |= (saveRegisterCount << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_REG_COUNT)); | |
1660 | encoding |= (permutationEncoding << __builtin_ctz(UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION)); | |
1661 | return encoding; | |
1662 | } | |
1663 | } | |
1664 | ||
1665 | ||
1666 | ||
1667 | ||
1668 | ||
1669 | ||
1670 | ||
1671 | // | |
1672 | // ppc specific functions | |
1673 | // | |
1674 | template <typename A, typename R> | |
1675 | int DwarfInstructions<A,R>::lastRestoreReg(const Registers_ppc&) | |
1676 | { | |
1677 | COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)UNW_PPC_SPEFSCR ); | |
1678 | return UNW_PPC_SPEFSCR; | |
1679 | } | |
1680 | ||
1681 | template <typename A, typename R> | |
1682 | bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_ppc&) | |
1683 | { | |
1684 | return (regNum == UNW_PPC_LR); | |
1685 | } | |
1686 | ||
1687 | template <typename A, typename R> | |
1688 | typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, | |
1689 | const Registers_ppc& registers) | |
1690 | { | |
1691 | if ( prolog.cfaRegister != 0 ) | |
1692 | return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset; | |
1693 | else if ( prolog.cfaExpression != 0 ) | |
1694 | return evaluateExpression(prolog.cfaExpression, addressSpace, registers, 0); | |
1695 | else | |
1696 | ABORT("getCFA(): unknown location for ppc cfa"); | |
1697 | } | |
1698 | ||
1699 | ||
1700 | template <typename A, typename R> | |
1701 | compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_ppc&) | |
1702 | { | |
1703 | return UNWIND_X86_MODE_DWARF; | |
1704 | } | |
1705 | ||
1706 | ||
1707 | template <typename A, typename R> | |
1708 | compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr, | |
1709 | const Registers_ppc& r, const typename CFI_Parser<A>::PrologInfo& prolog, | |
1710 | char warningBuffer[1024]) | |
1711 | { | |
1712 | warningBuffer[0] = '\0'; | |
1713 | return UNWIND_X86_MODE_DWARF; | |
1714 | } | |
1715 | ||
1716 | ||
1717 | ||
1718 | ||
1719 | } // namespace libunwind | |
1720 | ||
1721 | ||
1722 | #endif // __DWARF_INSTRUCTIONS_HPP__ | |
1723 | ||
1724 | ||
1725 | ||
1726 |