Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / unwindarm64.cpp
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
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX                                                                           XX
8 XX                              UnwindInfo                                   XX
9 XX                                                                           XX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
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_)
22 int 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
32 void Compiler::unwindPush(regNumber reg)
33 {
34     unreached(); // use one of the unwindSaveReg* functions instead.
35 }
36
37 void 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
69 void 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
94 void Compiler::unwindSaveReg(regNumber reg, unsigned offset)
95 {
96     unreached();
97 }
98
99 void 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).
123 void 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.
189 void 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
261 void 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
300 void 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
339 void 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
349 void 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
355 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
356 XX                                                                           XX
357 XX  Unwind Info Debug helpers                                                XX
358 XX                                                                           XX
359 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
360 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
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
367 unsigned 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
397 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
398 XX                                                                           XX
399 XX  Unwind Info Support Classes                                              XX
400 XX                                                                           XX
401 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
402 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
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.
414 unsigned 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
436 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
437 XX                                                                           XX
438 XX  Debug dumpers                                                            XX
439 XX                                                                           XX
440 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
441 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
442 */
443
444 #ifdef DEBUG
445
446 // start is 0-based index from LSB, length is number of bits
447 DWORD 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
460 void 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_