1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7XX XX
8XX UnwindInfo XX
9XX XX
10XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12*/
13
14#include "jitpch.h"
15#ifdef _MSC_VER
16#pragma hdrstop
17#endif
18
19#if defined(_TARGET_ARM64_)
20
21#if defined(_TARGET_UNIX_)
22int Compiler::mapRegNumToDwarfReg(regNumber reg)
23{
24 int dwarfReg = DWARF_REG_ILLEGAL;
25
26 NYI("CFI codes");
27
28 return dwarfReg;
29}
30#endif // _TARGET_ARM_
31
32void Compiler::unwindPush(regNumber reg)
33{
34 unreached(); // use one of the unwindSaveReg* functions instead.
35}
36
37void Compiler::unwindAllocStack(unsigned size)
38{
39 UnwindInfo* pu = &funCurrentFunc()->uwi;
40
41 assert(size % 16 == 0);
42 unsigned x = size / 16;
43
44 if (x <= 0x1F)
45 {
46 // alloc_s: 000xxxxx: allocate small stack with size < 128 (2^5 * 16)
47 // TODO-Review: should say size < 512
48
49 pu->AddCode((BYTE)x);
50 }
51 else if (x <= 0x7FF)
52 {
53 // alloc_m: 11000xxx | xxxxxxxx: allocate large stack with size < 16k (2^11 * 16)
54 // TODO-Review: should say size < 32K
55
56 pu->AddCode(0xC0 | (BYTE)(x >> 8), (BYTE)x);
57 }
58 else
59 {
60 // alloc_l: 11100000 | xxxxxxxx | xxxxxxxx | xxxxxxxx : allocate large stack with size < 256M (2^24 * 16)
61 //
62 // For large stack size, the most significant bits
63 // are stored first (and next to the opCode) per the unwind spec.
64
65 pu->AddCode(0xE0, (BYTE)(x >> 16), (BYTE)(x >> 8), (BYTE)x);
66 }
67}
68
69void Compiler::unwindSetFrameReg(regNumber reg, unsigned offset)
70{
71 UnwindInfo* pu = &funCurrentFunc()->uwi;
72
73 if (offset == 0)
74 {
75 assert(reg == REG_FP);
76
77 // set_fp: 11100001 : set up r29 : with : mov r29, sp
78 pu->AddCode(0xE1);
79 }
80 else
81 {
82 // add_fp: 11100010 | xxxxxxxx : set up r29 with : add r29, sp, #x * 8
83
84 assert(reg == REG_FP);
85 assert((offset % 8) == 0);
86
87 unsigned x = offset / 8;
88 assert(x <= 0xFF);
89
90 pu->AddCode(0xE2, (BYTE)x);
91 }
92}
93
94void Compiler::unwindSaveReg(regNumber reg, unsigned offset)
95{
96 unreached();
97}
98
99void Compiler::unwindNop()
100{
101 UnwindInfo* pu = &funCurrentFunc()->uwi;
102
103#ifdef DEBUG
104 if (verbose)
105 {
106 printf("unwindNop: adding NOP\n");
107 }
108#endif
109
110 INDEBUG(pu->uwiAddingNOP = true);
111
112 // nop: 11100011: no unwind operation is required.
113 pu->AddCode(0xE3);
114
115 INDEBUG(pu->uwiAddingNOP = false);
116}
117
118// unwindSaveRegPair: save a register pair to the stack at the specified byte offset (which must be positive,
119// a multiple of 8 from 0 to 504). Note that for ARM64 unwind codes, reg2 must be exactly one register higher than reg1,
120// except for the case of a pair including LR, in which case reg1 must be either FP or R19/R21/R23/R25/R27 (note that it
121// can't be even, such as R20, because that would mean R19 was saved separately, instead of saving <R19,R20> as a pair,
122// which we should do instead).
123void Compiler::unwindSaveRegPair(regNumber reg1, regNumber reg2, int offset)
124{
125 UnwindInfo* pu = &funCurrentFunc()->uwi;
126
127 // stp reg1, reg2, [sp, #offset]
128
129 // offset for store pair in prolog must be positive and a multiple of 8.
130 assert(0 <= offset && offset <= 504);
131 assert((offset % 8) == 0);
132
133 int z = offset / 8;
134 assert(0 <= z && z <= 0x3F);
135
136 if (reg1 == REG_FP)
137 {
138 // save_fplr: 01zzzzzz: save <r29,lr> pair at [sp+#Z*8], offset <= 504
139
140 assert(reg2 == REG_LR);
141
142 pu->AddCode(0x40 | (BYTE)z);
143 }
144 else if (reg2 == REG_LR)
145 {
146 // save_lrpair: 1101011x | xxzzzzzz: save pair <r19 + 2 * #X, lr> at [sp + #Z * 8], offset <= 504
147
148 assert(REG_R19 <= reg1 && // first legal pair: R19, LR
149 reg1 <= REG_R27); // last legal pair: R27, LR
150
151 BYTE x = (BYTE)(reg1 - REG_R19);
152 assert((x % 2) == 0); // only legal reg1: R19, R21, R23, R25, R27
153 x /= 2;
154 assert(0 <= x && x <= 0x7);
155
156 pu->AddCode(0xD6 | (BYTE)(x >> 2), (BYTE)(x << 6) | (BYTE)z);
157 }
158 else if (emitter::isGeneralRegister(reg1))
159 {
160 // save_regp: 110010xx | xxzzzzzz: save r(19 + #X) pair at [sp + #Z * 8], offset <= 504
161
162 assert(REG_NEXT(reg1) == reg2);
163 assert(REG_R19 <= reg1 && // first legal pair: R19, R20
164 reg1 <= REG_R27); // last legal pair: R27, R28 (FP is never saved without LR)
165
166 BYTE x = (BYTE)(reg1 - REG_R19);
167 assert(0 <= x && x <= 0xF);
168
169 pu->AddCode(0xC8 | (BYTE)(x >> 2), (BYTE)(x << 6) | (BYTE)z);
170 }
171 else
172 {
173 // save_fregp: 1101100x | xxzzzzzz : save pair d(8 + #X) at [sp + #Z * 8], offset <= 504
174
175 assert(REG_NEXT(reg1) == reg2);
176 assert(REG_V8 <= reg1 && // first legal pair: V8, V9
177 reg1 <= REG_V14); // last legal pair: V14, V15
178
179 BYTE x = (BYTE)(reg1 - REG_V8);
180 assert(0 <= x && x <= 0x7);
181
182 pu->AddCode(0xD8 | (BYTE)(x >> 2), (BYTE)(x << 6) | (BYTE)z);
183 }
184}
185
186// unwindSaveRegPairPreindexed: save a register pair to the stack at the specified byte offset (which must be negative,
187// a multiple of 8 from -512 to -8). Note that for ARM64 unwind codes, reg2 must be exactly one register higher than
188// reg1.
189void Compiler::unwindSaveRegPairPreindexed(regNumber reg1, regNumber reg2, int offset)
190{
191 UnwindInfo* pu = &funCurrentFunc()->uwi;
192
193 // stp reg1, reg2, [sp, #offset]!
194
195 // pre-indexed offset in prolog must be negative and a multiple of 8.
196 assert(offset < 0);
197 assert((offset % 8) == 0);
198
199 if (reg1 == REG_FP)
200 {
201 // save_fplr_x: 10zzzzzz: save <r29,lr> pair at [sp-(#Z+1)*8]!, pre-indexed offset >= -512
202
203 assert(-512 <= offset);
204 int z = (-offset) / 8 - 1;
205 assert(0 <= z && z <= 0x3F);
206
207 assert(reg2 == REG_LR);
208
209 pu->AddCode(0x80 | (BYTE)z);
210 }
211 else if ((reg1 == REG_R19) &&
212 (-256 <= offset)) // If the offset is between -512 and -256, we use the save_regp_x unwind code.
213 {
214 // save_r19r20_x: 001zzzzz: save <r19,r20> pair at [sp-#Z*8]!, pre-indexed offset >= -248
215 // NOTE: I'm not sure why we allow Z==0 here; seems useless, and the calculation of offset is different from the
216 // other cases.
217
218 int z = (-offset) / 8;
219 assert(0 <= z && z <= 0x1F);
220
221 assert(reg2 == REG_R20);
222
223 pu->AddCode(0x20 | (BYTE)z);
224 }
225 else if (emitter::isGeneralRegister(reg1))
226 {
227 // save_regp_x: 110011xx | xxzzzzzz: save pair r(19 + #X) at [sp - (#Z + 1) * 8]!, pre-indexed offset >= -512
228
229 assert(-512 <= offset);
230 int z = (-offset) / 8 - 1;
231 assert(0 <= z && z <= 0x3F);
232
233 assert(REG_NEXT(reg1) == reg2);
234 assert(REG_R19 <= reg1 && // first legal pair: R19, R20
235 reg1 <= REG_R27); // last legal pair: R27, R28 (FP is never saved without LR)
236
237 BYTE x = (BYTE)(reg1 - REG_R19);
238 assert(0 <= x && x <= 0xF);
239
240 pu->AddCode(0xCC | (BYTE)(x >> 2), (BYTE)(x << 6) | (BYTE)z);
241 }
242 else
243 {
244 // save_fregp_x: 1101101x | xxzzzzzz : save pair d(8 + #X), at [sp - (#Z + 1) * 8]!, pre-indexed offset >= -512
245
246 assert(-512 <= offset);
247 int z = (-offset) / 8 - 1;
248 assert(0 <= z && z <= 0x3F);
249
250 assert(REG_NEXT(reg1) == reg2);
251 assert(REG_V8 <= reg1 && // first legal pair: V8, V9
252 reg1 <= REG_V14); // last legal pair: V14, V15
253
254 BYTE x = (BYTE)(reg1 - REG_V8);
255 assert(0 <= x && x <= 0x7);
256
257 pu->AddCode(0xDA | (BYTE)(x >> 2), (BYTE)(x << 6) | (BYTE)z);
258 }
259}
260
261void Compiler::unwindSaveReg(regNumber reg, int offset)
262{
263 UnwindInfo* pu = &funCurrentFunc()->uwi;
264
265 // str reg, [sp, #offset]
266
267 // offset for store in prolog must be positive and a multiple of 8.
268 assert(0 <= offset && offset <= 504);
269 assert((offset % 8) == 0);
270
271 int z = offset / 8;
272 assert(0 <= z && z <= 0x3F);
273
274 if (emitter::isGeneralRegister(reg))
275 {
276 // save_reg: 110100xx | xxzzzzzz: save reg r(19 + #X) at [sp + #Z * 8], offset <= 504
277
278 assert(REG_R19 <= reg && // first legal register: R19
279 reg <= REG_LR); // last legal register: LR
280
281 BYTE x = (BYTE)(reg - REG_R19);
282 assert(0 <= x && x <= 0xF);
283
284 pu->AddCode(0xD0 | (BYTE)(x >> 2), (BYTE)(x << 6) | (BYTE)z);
285 }
286 else
287 {
288 // save_freg: 1101110x | xxzzzzzz : save reg d(8 + #X) at [sp + #Z * 8], offset <= 504
289
290 assert(REG_V8 <= reg && // first legal register: V8
291 reg <= REG_V15); // last legal register: V15
292
293 BYTE x = (BYTE)(reg - REG_V8);
294 assert(0 <= x && x <= 0x7);
295
296 pu->AddCode(0xDC | (BYTE)(x >> 2), (BYTE)(x << 6) | (BYTE)z);
297 }
298}
299
300void Compiler::unwindSaveRegPreindexed(regNumber reg, int offset)
301{
302 UnwindInfo* pu = &funCurrentFunc()->uwi;
303
304 // str reg, [sp, #offset]!
305
306 // pre-indexed offset in prolog must be negative and a multiple of 8.
307 assert(-256 <= offset && offset < 0);
308 assert((offset % 8) == 0);
309
310 int z = (-offset) / 8 - 1;
311 assert(0 <= z && z <= 0x1F);
312
313 if (emitter::isGeneralRegister(reg))
314 {
315 // save_reg_x: 1101010x | xxxzzzzz: save reg r(19 + #X) at [sp - (#Z + 1) * 8]!, pre-indexed offset >= -256
316
317 assert(REG_R19 <= reg && // first legal register: R19
318 reg <= REG_LR); // last legal register: LR
319
320 BYTE x = (BYTE)(reg - REG_R19);
321 assert(0 <= x && x <= 0xF);
322
323 pu->AddCode(0xD4 | (BYTE)(x >> 3), (BYTE)(x << 5) | (BYTE)z);
324 }
325 else
326 {
327 // save_freg_x: 11011110 | xxxzzzzz : save reg d(8 + #X) at [sp - (#Z + 1) * 8]!, pre - indexed offset >= -256
328
329 assert(REG_V8 <= reg && // first legal register: V8
330 reg <= REG_V15); // last legal register: V15
331
332 BYTE x = (BYTE)(reg - REG_V8);
333 assert(0 <= x && x <= 0x7);
334
335 pu->AddCode(0xDE, (BYTE)(x << 5) | (BYTE)z);
336 }
337}
338
339void Compiler::unwindSaveNext()
340{
341 UnwindInfo* pu = &funCurrentFunc()->uwi;
342
343 // We're saving the next register pair. The caller is responsible for ensuring this is correct!
344
345 // save_next: 11100110 : save next non - volatile Int or FP register pair.
346 pu->AddCode(0xE6);
347}
348
349void Compiler::unwindReturn(regNumber reg)
350{
351 // Nothing to do; we will always have at least one trailing "end" opcode in our padding.
352}
353
354/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
355XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
356XX XX
357XX Unwind Info Debug helpers XX
358XX XX
359XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
360XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
361*/
362
363#ifdef DEBUG
364
365// Return the size of the unwind code (from 1 to 4 bytes), given the first byte of the unwind bytes
366
367unsigned GetUnwindSizeFromUnwindHeader(BYTE b1)
368{
369 static BYTE s_UnwindSize[256] = {
370 // array of unwind sizes, in bytes (as specified in the ARM unwind specification)
371 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00-0F
372 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10-1F
373 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 20-2F
374 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 30-3F
375 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40-4F
376 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 50-5F
377 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60-6F
378 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 70-7F
379 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80-8F
380 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 90-9F
381 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A0-AF
382 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B0-BF
383 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0-CF
384 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, // D0-DF
385 4, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E0-EF
386 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F0-FF
387 };
388
389 unsigned size = s_UnwindSize[b1];
390 assert(1 <= size && size <= 4);
391 return size;
392}
393
394#endif // DEBUG
395
396/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
397XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
398XX XX
399XX Unwind Info Support Classes XX
400XX XX
401XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
402XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
403*/
404
405///////////////////////////////////////////////////////////////////////////////
406//
407// UnwindCodesBase
408//
409///////////////////////////////////////////////////////////////////////////////
410
411#ifdef DEBUG
412
413// Walk the prolog codes and calculate the size of the prolog or epilog, in bytes.
414unsigned UnwindCodesBase::GetCodeSizeFromUnwindCodes(bool isProlog)
415{
416 BYTE* pCodesStart = GetCodes();
417 BYTE* pCodes = pCodesStart;
418 unsigned size = 0;
419 for (;;)
420 {
421 BYTE b1 = *pCodes;
422 if (IsEndCode(b1))
423 {
424 break; // We hit an "end" code; we're done
425 }
426 size += 4; // All codes represent 4 byte instructions.
427 pCodes += GetUnwindSizeFromUnwindHeader(b1);
428 assert(pCodes - pCodesStart < 256); // 255 is the absolute maximum number of code bytes allowed
429 }
430 return size;
431}
432
433#endif // DEBUG
434
435/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
436XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
437XX XX
438XX Debug dumpers XX
439XX XX
440XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
441XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
442*/
443
444#ifdef DEBUG
445
446// start is 0-based index from LSB, length is number of bits
447DWORD ExtractBits(DWORD dw, DWORD start, DWORD length)
448{
449 return (dw >> start) & ((1 << length) - 1);
450}
451
452// Dump the unwind data.
453// Arguments:
454// isHotCode: true if this unwind data is for the hot section
455// startOffset: byte offset of the code start that this unwind data represents
456// endOffset: byte offset of the code end that this unwind data represents
457// pHeader: pointer to the unwind data blob
458// unwindBlockSize: size in bytes of the unwind data blob
459
460void DumpUnwindInfo(Compiler* comp,
461 bool isHotCode,
462 UNATIVE_OFFSET startOffset,
463 UNATIVE_OFFSET endOffset,
464 const BYTE* const pHeader,
465 ULONG unwindBlockSize)
466{
467 printf("Unwind Info%s:\n", isHotCode ? "" : " COLD");
468
469 // pHeader is not guaranteed to be aligned. We put four 0xFF end codes at the end
470 // to provide padding, and round down to get a multiple of 4 bytes in size.
471 DWORD UNALIGNED* pdw = (DWORD UNALIGNED*)pHeader;
472 DWORD dw;
473
474 dw = *pdw++;
475
476 DWORD codeWords = ExtractBits(dw, 27, 5);
477 DWORD epilogCount = ExtractBits(dw, 22, 5);
478 DWORD EBit = ExtractBits(dw, 21, 1);
479 DWORD XBit = ExtractBits(dw, 20, 1);
480 DWORD Vers = ExtractBits(dw, 18, 2);
481 DWORD functionLength = ExtractBits(dw, 0, 18);
482
483 printf(" >> Start offset : 0x%06x (not in unwind data)\n", comp->dspOffset(startOffset));
484 printf(" >> End offset : 0x%06x (not in unwind data)\n", comp->dspOffset(endOffset));
485 printf(" Code Words : %u\n", codeWords);
486 printf(" Epilog Count : %u\n", epilogCount);
487 printf(" E bit : %u\n", EBit);
488 printf(" X bit : %u\n", XBit);
489 printf(" Vers : %u\n", Vers);
490 printf(" Function Length : %u (0x%05x) Actual length = %u (0x%06x)\n", functionLength, functionLength,
491 functionLength * 4, functionLength * 4);
492
493 assert(functionLength * 4 == endOffset - startOffset);
494
495 if (codeWords == 0 && epilogCount == 0)
496 {
497 // We have an extension word specifying a larger number of Code Words or Epilog Counts
498 // than can be specified in the header word.
499
500 dw = *pdw++;
501
502 codeWords = ExtractBits(dw, 16, 8);
503 epilogCount = ExtractBits(dw, 0, 16);
504 assert((dw & 0xF0000000) == 0); // reserved field should be zero
505
506 printf(" ---- Extension word ----\n");
507 printf(" Extended Code Words : %u\n", codeWords);
508 printf(" Extended Epilog Count : %u\n", epilogCount);
509 }
510
511 bool epilogStartAt[1024] = {}; // One byte per possible epilog start index; initialized to false
512
513 if (EBit == 0)
514 {
515 // We have an array of epilog scopes
516
517 printf(" ---- Epilog scopes ----\n");
518 if (epilogCount == 0)
519 {
520 printf(" No epilogs\n");
521 }
522 else
523 {
524 for (DWORD scope = 0; scope < epilogCount; scope++)
525 {
526 dw = *pdw++;
527
528 DWORD epilogStartOffset = ExtractBits(dw, 0, 18);
529 DWORD res = ExtractBits(dw, 18, 4);
530 DWORD epilogStartIndex = ExtractBits(dw, 22, 10);
531
532 // Note that epilogStartOffset for a funclet is the offset from the beginning
533 // of the current funclet, not the offset from the beginning of the main function.
534 // To help find it when looking through JitDump output, also show the offset from
535 // the beginning of the main function.
536 DWORD epilogStartOffsetFromMainFunctionBegin = epilogStartOffset * 4 + startOffset;
537
538 assert(res == 0);
539
540 printf(" ---- Scope %d\n", scope);
541 printf(" Epilog Start Offset : %u (0x%05x) Actual offset = %u (0x%06x) Offset from main "
542 "function begin = %u (0x%06x)\n",
543 comp->dspOffset(epilogStartOffset), comp->dspOffset(epilogStartOffset),
544 comp->dspOffset(epilogStartOffset * 4), comp->dspOffset(epilogStartOffset * 4),
545 comp->dspOffset(epilogStartOffsetFromMainFunctionBegin),
546 comp->dspOffset(epilogStartOffsetFromMainFunctionBegin));
547 printf(" Epilog Start Index : %u (0x%02x)\n", epilogStartIndex, epilogStartIndex);
548
549 epilogStartAt[epilogStartIndex] = true; // an epilog starts at this offset in the unwind codes
550 }
551 }
552 }
553 else
554 {
555 printf(" --- One epilog, unwind codes at %u\n", epilogCount);
556 assert(epilogCount < ArrLen(epilogStartAt));
557 epilogStartAt[epilogCount] = true; // the one and only epilog starts its unwind codes at this offset
558 }
559
560 // Dump the unwind codes
561
562 printf(" ---- Unwind codes ----\n");
563
564 DWORD countOfUnwindCodes = codeWords * 4;
565 PBYTE pUnwindCode = (PBYTE)pdw;
566 BYTE b1, b2, b3, b4;
567 DWORD x, z;
568 for (DWORD i = 0; i < countOfUnwindCodes; i++)
569 {
570 // Does this byte start an epilog sequence? If so, note that fact.
571 if (epilogStartAt[i])
572 {
573 printf(" ---- Epilog start at index %u ----\n", i);
574 }
575
576 b1 = *pUnwindCode++;
577
578 if ((b1 & 0xE0) == 0)
579 {
580 // alloc_s: 000xxxxx: allocate small stack with size < 128 (2^5 * 16)
581 // TODO-Review:should say size < 512
582 x = b1 & 0x1F;
583 printf(" %02X alloc_s #%u (0x%02X); sub sp, sp, #%u (0x%03X)\n", b1, x, x, x * 16, x * 16);
584 }
585 else if ((b1 & 0xE0) == 0x20)
586 {
587 // save_r19r20_x: 001zzzzz: save <r19,r20> pair at [sp-#Z*8]!, pre-indexed offset >= -248
588 z = b1 & 0x1F;
589 printf(" %02X save_r19r20_x #%u (0x%02X); stp %s, %s, [sp, #-%u]!\n", b1, z, z,
590 getRegName(REG_R19), getRegName(REG_R20), z * 8);
591 }
592 else if ((b1 & 0xC0) == 0x40)
593 {
594 // save_fplr: 01zzzzzz: save <r29,lr> pair at [sp+#Z*8], offset <= 504
595 z = b1 & 0x3F;
596 printf(" %02X save_fplr #%u (0x%02X); stp %s, %s, [sp, #%u]\n", b1, z, z, getRegName(REG_FP),
597 getRegName(REG_LR), z * 8);
598 }
599 else if ((b1 & 0xC0) == 0x80)
600 {
601 // save_fplr_x: 10zzzzzz: save <r29,lr> pair at [sp-(#Z+1)*8]!, pre-indexed offset >= -512
602 z = b1 & 0x3F;
603 printf(" %02X save_fplr_x #%u (0x%02X); stp %s, %s, [sp, #-%u]!\n", b1, z, z,
604 getRegName(REG_FP), getRegName(REG_LR), (z + 1) * 8);
605 }
606 else if ((b1 & 0xF8) == 0xC0)
607 {
608 // alloc_m: 11000xxx | xxxxxxxx: allocate large stack with size < 16k (2^11 * 16)
609 // TODO-Review: should save size < 32K
610 assert(i + 1 < countOfUnwindCodes);
611 b2 = *pUnwindCode++;
612 i++;
613
614 x = ((DWORD)(b1 & 0x7) << 8) | (DWORD)b2;
615
616 printf(" %02X %02X alloc_m #%u (0x%03X); sub sp, sp, #%u (0x%04X)\n", b1, b2, x, x, x * 16,
617 x * 16);
618 }
619 else if ((b1 & 0xFC) == 0xC8)
620 {
621 // save_regp: 110010xx | xxzzzzzz: save r(19 + #X) pair at [sp + #Z * 8], offset <= 504
622 assert(i + 1 < countOfUnwindCodes);
623 b2 = *pUnwindCode++;
624 i++;
625
626 x = ((DWORD)(b1 & 0x3) << 2) | (DWORD)(b2 >> 6);
627 z = (DWORD)(b2 & 0x3F);
628
629 printf(" %02X %02X save_regp X#%u Z#%u (0x%02X); stp %s, %s, [sp, #%u]\n", b1, b2, x, z, z,
630 getRegName(REG_R19 + x), getRegName(REG_R19 + x + 1), z * 8);
631 }
632 else if ((b1 & 0xFC) == 0xCC)
633 {
634 // save_regp_x: 110011xx | xxzzzzzz: save pair r(19 + #X) at [sp - (#Z + 1) * 8]!, pre-indexed offset >=
635 // -512
636 assert(i + 1 < countOfUnwindCodes);
637 b2 = *pUnwindCode++;
638 i++;
639
640 x = ((DWORD)(b1 & 0x3) << 2) | (DWORD)(b2 >> 6);
641 z = (DWORD)(b2 & 0x3F);
642
643 printf(" %02X %02X save_regp_x X#%u Z#%u (0x%02X); stp %s, %s, [sp, #-%u]!\n", b1, b2, x, z, z,
644 getRegName(REG_R19 + x), getRegName(REG_R19 + x + 1), (z + 1) * 8);
645 }
646 else if ((b1 & 0xFC) == 0xD0)
647 {
648 // save_reg: 110100xx | xxzzzzzz: save reg r(19 + #X) at [sp + #Z * 8], offset <= 504
649 assert(i + 1 < countOfUnwindCodes);
650 b2 = *pUnwindCode++;
651 i++;
652
653 x = ((DWORD)(b1 & 0x3) << 2) | (DWORD)(b2 >> 6);
654 z = (DWORD)(b2 & 0x3F);
655
656 printf(" %02X %02X save_reg X#%u Z#%u (0x%02X); str %s, [sp, #%u]\n", b1, b2, x, z, z,
657 getRegName(REG_R19 + x), z * 8);
658 }
659 else if ((b1 & 0xFE) == 0xD4)
660 {
661 // save_reg_x: 1101010x | xxxzzzzz: save reg r(19 + #X) at [sp - (#Z + 1) * 8]!, pre-indexed offset >= -256
662 assert(i + 1 < countOfUnwindCodes);
663 b2 = *pUnwindCode++;
664 i++;
665
666 x = ((DWORD)(b1 & 0x1) << 3) | (DWORD)(b2 >> 5);
667 z = (DWORD)(b2 & 0x1F);
668
669 printf(" %02X %02X save_reg_x X#%u Z#%u (0x%02X); str %s, [sp, #-%u]!\n", b1, b2, x, z, z,
670 getRegName(REG_R19 + x), (z + 1) * 8);
671 }
672 else if ((b1 & 0xFE) == 0xD6)
673 {
674 // save_lrpair: 1101011x | xxzzzzzz: save pair <r19 + 2 * #X, lr> at [sp + #Z * 8], offset <= 504
675 assert(i + 1 < countOfUnwindCodes);
676 b2 = *pUnwindCode++;
677 i++;
678
679 x = ((DWORD)(b1 & 0x1) << 2) | (DWORD)(b2 >> 6);
680 z = (DWORD)(b2 & 0x3F);
681
682 printf(" %02X %02X save_lrpair X#%u Z#%u (0x%02X); stp %s, %s, [sp, #%u]\n", b1, b2, x, z, z,
683 getRegName(REG_R19 + 2 * x), getRegName(REG_LR), z * 8);
684 }
685 else if ((b1 & 0xFE) == 0xD8)
686 {
687 // save_fregp: 1101100x | xxzzzzzz : save pair d(8 + #X) at [sp + #Z * 8], offset <= 504
688 assert(i + 1 < countOfUnwindCodes);
689 b2 = *pUnwindCode++;
690 i++;
691
692 x = ((DWORD)(b1 & 0x1) << 2) | (DWORD)(b2 >> 6);
693 z = (DWORD)(b2 & 0x3F);
694
695 printf(" %02X %02X save_fregp X#%u Z#%u (0x%02X); stp %s, %s, [sp, #%u]\n", b1, b2, x, z, z,
696 getRegName(REG_V8 + x, true), getRegName(REG_V8 + x + 1, true), z * 8);
697 }
698 else if ((b1 & 0xFE) == 0xDA)
699 {
700 // save_fregp_x: 1101101x | xxzzzzzz : save pair d(8 + #X), at [sp - (#Z + 1) * 8]!, pre-indexed offset >=
701 // -512
702 assert(i + 1 < countOfUnwindCodes);
703 b2 = *pUnwindCode++;
704 i++;
705
706 x = ((DWORD)(b1 & 0x1) << 2) | (DWORD)(b2 >> 6);
707 z = (DWORD)(b2 & 0x3F);
708
709 printf(" %02X %02X save_fregp_x X#%u Z#%u (0x%02X); stp %s, %s, [sp, #-%u]!\n", b1, b2, x, z, z,
710 getRegName(REG_V8 + x, true), getRegName(REG_V8 + x + 1, true), (z + 1) * 8);
711 }
712 else if ((b1 & 0xFE) == 0xDC)
713 {
714 // save_freg: 1101110x | xxzzzzzz : save reg d(8 + #X) at [sp + #Z * 8], offset <= 504
715 assert(i + 1 < countOfUnwindCodes);
716 b2 = *pUnwindCode++;
717 i++;
718
719 x = ((DWORD)(b1 & 0x1) << 2) | (DWORD)(b2 >> 6);
720 z = (DWORD)(b2 & 0x3F);
721
722 printf(" %02X %02X save_freg X#%u Z#%u (0x%02X); str %s, [sp, #%u]\n", b1, b2, x, z, z,
723 getRegName(REG_V8 + x, true), z * 8);
724 }
725 else if (b1 == 0xDE)
726 {
727 // save_freg_x: 11011110 | xxxzzzzz : save reg d(8 + #X) at [sp - (#Z + 1) * 8]!, pre - indexed offset >=
728 // -256
729 assert(i + 1 < countOfUnwindCodes);
730 b2 = *pUnwindCode++;
731 i++;
732
733 x = (DWORD)(b2 >> 5);
734 z = (DWORD)(b2 & 0x1F);
735
736 printf(" %02X %02X save_freg_x X#%u Z#%u (0x%02X); str %s, [sp, #-%u]!\n", b1, b2, x, z, z,
737 getRegName(REG_V8 + x, true), (z + 1) * 8);
738 }
739 else if (b1 == 0xE0)
740 {
741 // alloc_l: 11100000 | xxxxxxxx | xxxxxxxx | xxxxxxxx : allocate large stack with size < 256M (2^24 * 16)
742 assert(i + 3 < countOfUnwindCodes);
743 b2 = *pUnwindCode++;
744 b3 = *pUnwindCode++;
745 b4 = *pUnwindCode++;
746 i += 3;
747
748 x = ((DWORD)b2 << 16) | ((DWORD)b3 << 8) | (DWORD)b4;
749
750 printf(" %02X %02X %02X %02X alloc_l %u (0x%06X); sub sp, sp, #%u (%06X)\n", b1, b2, b3, b4, x, x,
751 x * 16, x * 16);
752 }
753 else if (b1 == 0xE1)
754 {
755 // set_fp: 11100001 : set up r29 : with : mov r29, sp
756
757 printf(" %02X set_fp; mov %s, sp\n", b1, getRegName(REG_FP));
758 }
759 else if (b1 == 0xE2)
760 {
761 // add_fp: 11100010 | xxxxxxxx : set up r29 with : add r29, sp, #x * 8
762 assert(i + 1 < countOfUnwindCodes);
763 b2 = *pUnwindCode++;
764 i++;
765
766 x = (DWORD)b2;
767
768 printf(" %02X %02X add_fp %u (0x%02X); add %s, sp, #%u\n", b1, b2, x, x, getRegName(REG_FP),
769 x * 8);
770 }
771 else if (b1 == 0xE3)
772 {
773 // nop: 11100011: no unwind operation is required.
774
775 printf(" %02X nop\n", b1);
776 }
777 else if (b1 == 0xE4)
778 {
779 // end: 11100100 : end of unwind code
780
781 printf(" %02X end\n", b1);
782 }
783 else if (b1 == 0xE5)
784 {
785 // end_c: 11100101 : end of unwind code in current chained scope.
786
787 printf(" %02X end_c\n", b1);
788 }
789 else if (b1 == 0xE6)
790 {
791 // save_next: 11100110 : save next non - volatile Int or FP register pair.
792
793 printf(" %02X save_next\n", b1);
794 }
795 else
796 {
797 // Unknown / reserved unwind code
798 assert(!"Internal error decoding unwind codes");
799 }
800 }
801
802 pdw += codeWords;
803 assert((PBYTE)pdw == pUnwindCode);
804 assert((PBYTE)pdw == pHeader + unwindBlockSize);
805
806 assert(XBit == 0); // We don't handle the case where exception data is present, such as the Exception Handler RVA
807
808 printf("\n");
809}
810
811#endif // DEBUG
812
813#endif // _TARGET_ARM64_
814