]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. | |
3 | * Copyright (C) 2014 Samsung Electronics | |
4 | * Copyright (C) 2014 University of Szeged | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * | |
15 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
16 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
18 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
19 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 | * | |
27 | * ============================================================================== | |
28 | * | |
29 | * University of Illinois/NCSA | |
30 | * Open Source License | |
31 | * | |
32 | * Copyright (c) 2009-2014 by the contributors of LLVM/libc++abi project. | |
33 | * | |
34 | * All rights reserved. | |
35 | * | |
36 | * Developed by: | |
37 | * | |
38 | * LLVM Team | |
39 | * | |
40 | * University of Illinois at Urbana-Champaign | |
41 | * | |
42 | * http://llvm.org | |
43 | * | |
44 | * Permission is hereby granted, free of charge, to any person obtaining a copy of | |
45 | * this software and associated documentation files (the "Software"), to deal with | |
46 | * the Software without restriction, including without limitation the rights to | |
47 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | |
48 | * of the Software, and to permit persons to whom the Software is furnished to do | |
49 | * so, subject to the following conditions: | |
50 | * | |
51 | * * Redistributions of source code must retain the above copyright notice, | |
52 | * this list of conditions and the following disclaimers. | |
53 | * | |
54 | * * Redistributions in binary form must reproduce the above copyright notice, | |
55 | * this list of conditions and the following disclaimers in the | |
56 | * documentation and/or other materials provided with the distribution. | |
57 | * | |
58 | * * Neither the names of the LLVM Team, University of Illinois at | |
59 | * Urbana-Champaign, nor the names of its contributors may be used to | |
60 | * endorse or promote products derived from this Software without specific | |
61 | * prior written permission. | |
62 | * | |
63 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
64 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | |
65 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
66 | * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
67 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
68 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE | |
69 | * SOFTWARE. | |
70 | * | |
71 | * ============================================================================== | |
72 | * | |
73 | * Copyright (c) 2009-2014 by the contributors of LLVM/libc++abi project. | |
74 | * | |
75 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
76 | * of this software and associated documentation files (the "Software"), to deal | |
77 | * in the Software without restriction, including without limitation the rights | |
78 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
79 | * copies of the Software, and to permit persons to whom the Software is | |
80 | * furnished to do so, subject to the following conditions: | |
81 | * | |
82 | * The above copyright notice and this permission notice shall be included in | |
83 | * all copies or substantial portions of the Software. | |
84 | * | |
85 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
86 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
87 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
88 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
89 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
90 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
91 | * THE SOFTWARE. | |
92 | */ | |
93 | ||
94 | #include "config.h" | |
95 | #include "FTLUnwindInfo.h" | |
96 | ||
97 | #if ENABLE(FTL_JIT) | |
98 | ||
99 | #if OS(DARWIN) | |
100 | #include <mach-o/compact_unwind_encoding.h> | |
101 | #endif | |
102 | #include <wtf/ListDump.h> | |
103 | ||
104 | namespace JSC { namespace FTL { | |
105 | ||
106 | UnwindInfo::UnwindInfo() { } | |
107 | UnwindInfo::~UnwindInfo() { } | |
108 | ||
109 | ||
110 | namespace { | |
111 | #if OS(DARWIN) | |
112 | struct CompactUnwind { | |
113 | void* function; | |
114 | uint32_t size; | |
115 | compact_unwind_encoding_t encoding; | |
116 | void* personality; | |
117 | void* lsda; | |
118 | }; | |
119 | #elif OS(LINUX) | |
120 | // DWARF unwind instructions | |
121 | enum { | |
122 | DW_CFA_nop = 0x0, | |
123 | DW_CFA_set_loc = 0x1, | |
124 | DW_CFA_advance_loc1 = 0x2, | |
125 | DW_CFA_advance_loc2 = 0x3, | |
126 | DW_CFA_advance_loc4 = 0x4, | |
127 | DW_CFA_offset_extended = 0x5, | |
128 | DW_CFA_def_cfa = 0xC, | |
129 | DW_CFA_def_cfa_register = 0xD, | |
130 | DW_CFA_def_cfa_offset = 0xE, | |
131 | DW_CFA_offset_extended_sf = 0x11, | |
132 | DW_CFA_def_cfa_sf = 0x12, | |
133 | DW_CFA_def_cfa_offset_sf = 0x13, | |
134 | // high 2 bits are 0x1, lower 6 bits are delta | |
135 | DW_CFA_advance_loc = 0x40, | |
136 | // high 2 bits are 0x2, lower 6 bits are register | |
137 | DW_CFA_offset = 0x80 | |
138 | }; | |
139 | ||
140 | enum { | |
141 | DW_CFA_operand_mask = 0x3F // low 6 bits mask for opcode-encoded operands in DW_CFA_advance_loc and DW_CFA_offset | |
142 | }; | |
143 | ||
144 | // FSF exception handling Pointer-Encoding constants | |
145 | enum { | |
146 | DW_EH_PE_ptr = 0x00, | |
147 | DW_EH_PE_uleb128 = 0x01, | |
148 | DW_EH_PE_udata2 = 0x02, | |
149 | DW_EH_PE_udata4 = 0x03, | |
150 | DW_EH_PE_udata8 = 0x04, | |
151 | DW_EH_PE_sleb128 = 0x09, | |
152 | DW_EH_PE_sdata2 = 0x0A, | |
153 | DW_EH_PE_sdata4 = 0x0B, | |
154 | DW_EH_PE_sdata8 = 0x0C, | |
155 | DW_EH_PE_absptr = 0x00, | |
156 | DW_EH_PE_pcrel = 0x10, | |
157 | DW_EH_PE_indirect = 0x80 | |
158 | }; | |
159 | ||
160 | enum { | |
161 | DW_EH_PE_relative_mask = 0x70 | |
162 | }; | |
163 | ||
164 | // 64-bit x86_64 registers | |
165 | enum { | |
166 | UNW_X86_64_rbx = 3, | |
167 | UNW_X86_64_rbp = 6, | |
168 | UNW_X86_64_r12 = 12, | |
169 | UNW_X86_64_r13 = 13, | |
170 | UNW_X86_64_r14 = 14, | |
171 | UNW_X86_64_r15 = 15 | |
172 | }; | |
173 | ||
174 | enum { | |
175 | DW_X86_64_RET_addr = 16 | |
176 | }; | |
177 | ||
178 | enum { | |
179 | UNW_ARM64_x0 = 0, | |
180 | UNW_ARM64_x1 = 1, | |
181 | UNW_ARM64_x2 = 2, | |
182 | UNW_ARM64_x3 = 3, | |
183 | UNW_ARM64_x4 = 4, | |
184 | UNW_ARM64_x5 = 5, | |
185 | UNW_ARM64_x6 = 6, | |
186 | UNW_ARM64_x7 = 7, | |
187 | UNW_ARM64_x8 = 8, | |
188 | UNW_ARM64_x9 = 9, | |
189 | UNW_ARM64_x10 = 10, | |
190 | UNW_ARM64_x11 = 11, | |
191 | UNW_ARM64_x12 = 12, | |
192 | UNW_ARM64_x13 = 13, | |
193 | UNW_ARM64_x14 = 14, | |
194 | UNW_ARM64_x15 = 15, | |
195 | UNW_ARM64_x16 = 16, | |
196 | UNW_ARM64_x17 = 17, | |
197 | UNW_ARM64_x18 = 18, | |
198 | UNW_ARM64_x19 = 19, | |
199 | UNW_ARM64_x20 = 20, | |
200 | UNW_ARM64_x21 = 21, | |
201 | UNW_ARM64_x22 = 22, | |
202 | UNW_ARM64_x23 = 23, | |
203 | UNW_ARM64_x24 = 24, | |
204 | UNW_ARM64_x25 = 25, | |
205 | UNW_ARM64_x26 = 26, | |
206 | UNW_ARM64_x27 = 27, | |
207 | UNW_ARM64_x28 = 28, | |
208 | UNW_ARM64_fp = 29, | |
209 | UNW_ARM64_x30 = 30, | |
210 | UNW_ARM64_sp = 31, | |
211 | UNW_ARM64_v0 = 64, | |
212 | UNW_ARM64_v1 = 65, | |
213 | UNW_ARM64_v2 = 66, | |
214 | UNW_ARM64_v3 = 67, | |
215 | UNW_ARM64_v4 = 68, | |
216 | UNW_ARM64_v5 = 69, | |
217 | UNW_ARM64_v6 = 70, | |
218 | UNW_ARM64_v7 = 71, | |
219 | UNW_ARM64_v8 = 72, | |
220 | UNW_ARM64_v9 = 73, | |
221 | UNW_ARM64_v10 = 74, | |
222 | UNW_ARM64_v11 = 75, | |
223 | UNW_ARM64_v12 = 76, | |
224 | UNW_ARM64_v13 = 77, | |
225 | UNW_ARM64_v14 = 78, | |
226 | UNW_ARM64_v15 = 79, | |
227 | UNW_ARM64_v16 = 80, | |
228 | UNW_ARM64_v17 = 81, | |
229 | UNW_ARM64_v18 = 82, | |
230 | UNW_ARM64_v19 = 83, | |
231 | UNW_ARM64_v20 = 84, | |
232 | UNW_ARM64_v21 = 85, | |
233 | UNW_ARM64_v22 = 86, | |
234 | UNW_ARM64_v23 = 87, | |
235 | UNW_ARM64_v24 = 88, | |
236 | UNW_ARM64_v25 = 89, | |
237 | UNW_ARM64_v26 = 90, | |
238 | UNW_ARM64_v27 = 91, | |
239 | UNW_ARM64_v28 = 92, | |
240 | UNW_ARM64_v29 = 93, | |
241 | UNW_ARM64_v30 = 94, | |
242 | UNW_ARM64_v31 = 95 | |
243 | }; | |
244 | ||
245 | static uint8_t get8(uintptr_t addr) { return *((uint8_t*)addr); } | |
246 | static uint16_t get16(uintptr_t addr) { return *((uint16_t*)addr); } | |
247 | static uint32_t get32(uintptr_t addr) { return *((uint32_t*)addr); } | |
248 | static uint64_t get64(uintptr_t addr) { return *((uint64_t*)addr); } | |
249 | ||
250 | static uintptr_t getP(uintptr_t addr) | |
251 | { | |
252 | // FIXME: add support for 32 bit pointers on 32 bit architectures | |
253 | return get64(addr); | |
254 | } | |
255 | ||
256 | static uint64_t getULEB128(uintptr_t& addr, uintptr_t end) | |
257 | { | |
258 | const uint8_t* p = (uint8_t*)addr; | |
259 | const uint8_t* pend = (uint8_t*)end; | |
260 | uint64_t result = 0; | |
261 | int bit = 0; | |
262 | do { | |
263 | uint64_t b; | |
264 | ||
265 | RELEASE_ASSERT(p != pend); // truncated uleb128 expression | |
266 | ||
267 | b = *p & 0x7f; | |
268 | ||
269 | RELEASE_ASSERT(!(bit >= 64 || b << bit >> bit != b)); // malformed uleb128 expression | |
270 | ||
271 | result |= b << bit; | |
272 | bit += 7; | |
273 | } while (*p++ >= 0x80); | |
274 | addr = (uintptr_t)p; | |
275 | return result; | |
276 | } | |
277 | ||
278 | static int64_t getSLEB128(uintptr_t& addr, uintptr_t end) | |
279 | { | |
280 | const uint8_t* p = (uint8_t*)addr; | |
281 | const uint8_t* pend = (uint8_t*)end; | |
282 | ||
283 | int64_t result = 0; | |
284 | int bit = 0; | |
285 | uint8_t byte; | |
286 | do { | |
287 | RELEASE_ASSERT(p != pend); // truncated sleb128 expression | |
288 | ||
289 | byte = *p++; | |
290 | result |= ((byte & 0x7f) << bit); | |
291 | bit += 7; | |
292 | } while (byte & 0x80); | |
293 | // sign extend negative numbers | |
294 | if ((byte & 0x40)) | |
295 | result |= (-1LL) << bit; | |
296 | addr = (uintptr_t)p; | |
297 | return result; | |
298 | } | |
299 | ||
300 | static uintptr_t getEncodedP(uintptr_t& addr, uintptr_t end, uint8_t encoding) | |
301 | { | |
302 | uintptr_t startAddr = addr; | |
303 | const uint8_t* p = (uint8_t*)addr; | |
304 | uintptr_t result; | |
305 | ||
306 | // first get value | |
307 | switch (encoding & 0x0F) { | |
308 | case DW_EH_PE_ptr: | |
309 | result = getP(addr); | |
310 | p += sizeof(uintptr_t); | |
311 | addr = (uintptr_t)p; | |
312 | break; | |
313 | case DW_EH_PE_uleb128: | |
314 | result = getULEB128(addr, end); | |
315 | break; | |
316 | case DW_EH_PE_udata2: | |
317 | result = get16(addr); | |
318 | p += 2; | |
319 | addr = (uintptr_t)p; | |
320 | break; | |
321 | case DW_EH_PE_udata4: | |
322 | result = get32(addr); | |
323 | p += 4; | |
324 | addr = (uintptr_t)p; | |
325 | break; | |
326 | case DW_EH_PE_udata8: | |
327 | result = get64(addr); | |
328 | p += 8; | |
329 | addr = (uintptr_t)p; | |
330 | break; | |
331 | case DW_EH_PE_sleb128: | |
332 | result = getSLEB128(addr, end); | |
333 | break; | |
334 | case DW_EH_PE_sdata2: | |
335 | result = (int16_t)get16(addr); | |
336 | p += 2; | |
337 | addr = (uintptr_t)p; | |
338 | break; | |
339 | case DW_EH_PE_sdata4: | |
340 | result = (int32_t)get32(addr); | |
341 | p += 4; | |
342 | addr = (uintptr_t)p; | |
343 | break; | |
344 | case DW_EH_PE_sdata8: | |
345 | result = get64(addr); | |
346 | p += 8; | |
347 | addr = (uintptr_t)p; | |
348 | break; | |
349 | default: | |
350 | RELEASE_ASSERT_NOT_REACHED(); // unknown pointer encoding | |
351 | } | |
352 | ||
353 | // then add relative offset | |
354 | switch (encoding & DW_EH_PE_relative_mask) { | |
355 | case DW_EH_PE_absptr: | |
356 | // do nothing | |
357 | break; | |
358 | case DW_EH_PE_pcrel: | |
359 | result += startAddr; | |
360 | break; | |
361 | default: | |
362 | RELEASE_ASSERT_NOT_REACHED(); // unsupported or unknown pointer encoding | |
363 | } | |
364 | ||
365 | if (encoding & DW_EH_PE_indirect) | |
366 | result = getP(result); | |
367 | ||
368 | return result; | |
369 | } | |
370 | ||
371 | // Information encoded in a CIE (Common Information Entry) | |
372 | struct CIE_Info { | |
373 | uintptr_t cieStart; | |
374 | uintptr_t cieLength; | |
375 | uintptr_t cieInstructions; | |
376 | uint8_t pointerEncoding; | |
377 | uint8_t lsdaEncoding; | |
378 | uint8_t personalityEncoding; | |
379 | uint8_t personalityOffsetInCIE; | |
380 | uintptr_t personality; | |
381 | int dataAlignFactor; | |
382 | bool fdesHaveAugmentationData; | |
383 | }; | |
384 | ||
385 | // Information about an FDE (Frame Description Entry) | |
386 | struct FDE_Info { | |
387 | uintptr_t fdeStart; | |
388 | uintptr_t fdeLength; | |
389 | uintptr_t fdeInstructions; | |
390 | uintptr_t lsda; | |
391 | }; | |
392 | ||
393 | // Information about a frame layout and registers saved determined | |
394 | // by "running" the dwarf FDE "instructions" | |
395 | #if CPU(ARM64) | |
396 | enum { MaxRegisterNumber = 120 }; | |
397 | #elif CPU(X86_64) | |
398 | enum { MaxRegisterNumber = 17 }; | |
399 | #else | |
400 | #error "Unrecognized architecture" | |
401 | #endif | |
402 | ||
403 | struct RegisterLocation { | |
404 | bool saved; | |
405 | int64_t offset; | |
406 | }; | |
407 | ||
408 | struct PrologInfo { | |
409 | uint32_t cfaRegister; | |
410 | int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset | |
411 | RegisterLocation savedRegisters[MaxRegisterNumber]; // from where to restore registers | |
412 | }; | |
413 | ||
414 | static void parseCIE(uintptr_t cie, CIE_Info* cieInfo) | |
415 | { | |
416 | cieInfo->pointerEncoding = 0; | |
417 | cieInfo->lsdaEncoding = 0; | |
418 | cieInfo->personalityEncoding = 0; | |
419 | cieInfo->personalityOffsetInCIE = 0; | |
420 | cieInfo->personality = 0; | |
421 | cieInfo->dataAlignFactor = 0; | |
422 | cieInfo->fdesHaveAugmentationData = false; | |
423 | cieInfo->cieStart = cie; | |
424 | ||
425 | uintptr_t p = cie; | |
426 | uint64_t cieLength = get32(p); | |
427 | p += 4; | |
428 | uintptr_t cieContentEnd = p + cieLength; | |
429 | if (cieLength == 0xffffffff) { | |
430 | // 0xffffffff means length is really next 8 bytes | |
431 | cieLength = get64(p); | |
432 | p += 8; | |
433 | cieContentEnd = p + cieLength; | |
434 | } | |
435 | ||
436 | RELEASE_ASSERT(cieLength); | |
437 | ||
438 | // CIE ID is always 0 | |
439 | RELEASE_ASSERT(!get32(p)); // CIE ID is not zero | |
440 | p += 4; | |
441 | // Version is always 1 or 3 | |
442 | uint8_t version = get8(p); | |
443 | RELEASE_ASSERT((version == 1) || (version == 3)); // CIE version is not 1 or 3 | |
444 | ||
445 | ++p; | |
446 | // save start of augmentation string and find end | |
447 | uintptr_t strStart = p; | |
448 | while (get8(p)) | |
449 | ++p; | |
450 | ++p; | |
451 | // parse code aligment factor | |
452 | getULEB128(p, cieContentEnd); | |
453 | // parse data alignment factor | |
454 | cieInfo->dataAlignFactor = getSLEB128(p, cieContentEnd); | |
455 | // parse return address register | |
456 | getULEB128(p, cieContentEnd); | |
457 | // parse augmentation data based on augmentation string | |
458 | if (get8(strStart) == 'z') { | |
459 | // parse augmentation data length | |
460 | getULEB128(p, cieContentEnd); | |
461 | for (uintptr_t s = strStart; get8(s) != '\0'; ++s) { | |
462 | switch (get8(s)) { | |
463 | case 'z': | |
464 | cieInfo->fdesHaveAugmentationData = true; | |
465 | break; | |
466 | case 'P': // FIXME: should assert on personality (just to keep in sync with the CU behaviour) | |
467 | cieInfo->personalityEncoding = get8(p); | |
468 | ++p; | |
469 | cieInfo->personalityOffsetInCIE = p - cie; | |
470 | cieInfo->personality = getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding); | |
471 | break; | |
472 | case 'L': // FIXME: should assert on LSDA (just to keep in sync with the CU behaviour) | |
473 | cieInfo->lsdaEncoding = get8(p); | |
474 | ++p; | |
475 | break; | |
476 | case 'R': | |
477 | cieInfo->pointerEncoding = get8(p); | |
478 | ++p; | |
479 | break; | |
480 | default: | |
481 | // ignore unknown letters | |
482 | break; | |
483 | } | |
484 | } | |
485 | } | |
486 | cieInfo->cieLength = cieContentEnd - cieInfo->cieStart; | |
487 | cieInfo->cieInstructions = p; | |
488 | } | |
489 | ||
490 | static void findFDE(uintptr_t pc, uintptr_t ehSectionStart, uint32_t sectionLength, FDE_Info* fdeInfo, CIE_Info* cieInfo) | |
491 | { | |
492 | uintptr_t p = ehSectionStart; | |
493 | const uintptr_t ehSectionEnd = p + sectionLength; | |
494 | while (p < ehSectionEnd) { | |
495 | uintptr_t currentCFI = p; | |
496 | uint64_t cfiLength = get32(p); | |
497 | p += 4; | |
498 | if (cfiLength == 0xffffffff) { | |
499 | // 0xffffffff means length is really next 8 bytes | |
500 | cfiLength = get64(p); | |
501 | p += 8; | |
502 | } | |
503 | RELEASE_ASSERT(cfiLength); // end marker reached before finding FDE for pc | |
504 | ||
505 | uint32_t id = get32(p); | |
506 | if (!id) { | |
507 | // skip over CIEs | |
508 | p += cfiLength; | |
509 | } else { | |
510 | // process FDE to see if it covers pc | |
511 | uintptr_t nextCFI = p + cfiLength; | |
512 | uint32_t ciePointer = get32(p); | |
513 | uintptr_t cieStart = p - ciePointer; | |
514 | // validate pointer to CIE is within section | |
515 | RELEASE_ASSERT((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)); // malformed FDE. CIE is bad | |
516 | ||
517 | parseCIE(cieStart, cieInfo); | |
518 | ||
519 | p += 4; | |
520 | // parse pc begin and range | |
521 | uintptr_t pcStart = getEncodedP(p, nextCFI, cieInfo->pointerEncoding); | |
522 | uintptr_t pcRange = getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); | |
523 | ||
524 | // test if pc is within the function this FDE covers | |
525 | // if pc is not in begin/range, skip this FDE | |
526 | if ((pcStart <= pc) && (pc < pcStart+pcRange)) { | |
527 | // parse rest of info | |
528 | fdeInfo->lsda = 0; | |
529 | // check for augmentation length | |
530 | if (cieInfo->fdesHaveAugmentationData) { | |
531 | uintptr_t augLen = getULEB128(p, nextCFI); | |
532 | uintptr_t endOfAug = p + augLen; | |
533 | if (cieInfo->lsdaEncoding) { | |
534 | // peek at value (without indirection). Zero means no lsda | |
535 | uintptr_t lsdaStart = p; | |
536 | if (getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F)) { | |
537 | // reset pointer and re-parse lsda address | |
538 | p = lsdaStart; | |
539 | fdeInfo->lsda = getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); | |
540 | } | |
541 | } | |
542 | p = endOfAug; | |
543 | } | |
544 | fdeInfo->fdeStart = currentCFI; | |
545 | fdeInfo->fdeLength = nextCFI - currentCFI; | |
546 | fdeInfo->fdeInstructions = p; | |
547 | ||
548 | return; // FDE found | |
549 | } | |
550 | ||
551 | p = nextCFI; | |
552 | } | |
553 | } | |
554 | ||
555 | RELEASE_ASSERT_NOT_REACHED(); // no FDE found for pc | |
556 | } | |
557 | ||
558 | static void executeDefCFARegister(uint64_t reg, PrologInfo* results) | |
559 | { | |
560 | RELEASE_ASSERT(reg <= MaxRegisterNumber); // reg too big | |
561 | results->cfaRegister = reg; | |
562 | } | |
563 | ||
564 | static void executeDefCFAOffset(int64_t offset, PrologInfo* results) | |
565 | { | |
566 | RELEASE_ASSERT(offset <= 0x80000000); // cfa has negative offset (dwarf might contain epilog) | |
567 | results->cfaRegisterOffset = offset; | |
568 | } | |
569 | ||
570 | static void executeOffset(uint64_t reg, int64_t offset, PrologInfo *results) | |
571 | { | |
572 | if (reg > MaxRegisterNumber) | |
573 | return; | |
574 | ||
575 | RELEASE_ASSERT(!results->savedRegisters[reg].saved); | |
576 | results->savedRegisters[reg].saved = true; | |
577 | results->savedRegisters[reg].offset = offset; | |
578 | } | |
579 | ||
580 | static void parseInstructions(uintptr_t instructions, uintptr_t instructionsEnd, const CIE_Info& cieInfo, PrologInfo* results) | |
581 | { | |
582 | uintptr_t p = instructions; | |
583 | ||
584 | // see Dwarf Spec, section 6.4.2 for details on unwind opcodes | |
585 | while ((p < instructionsEnd)) { | |
586 | uint64_t reg; | |
587 | uint8_t opcode = get8(p); | |
588 | uint8_t operand; | |
589 | ++p; | |
590 | switch (opcode) { | |
591 | case DW_CFA_nop: | |
592 | break; | |
593 | case DW_CFA_set_loc: | |
594 | getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding); | |
595 | break; | |
596 | case DW_CFA_advance_loc1: | |
597 | p += 1; | |
598 | break; | |
599 | case DW_CFA_advance_loc2: | |
600 | p += 2; | |
601 | break; | |
602 | case DW_CFA_advance_loc4: | |
603 | p += 4; | |
604 | break; | |
605 | case DW_CFA_def_cfa: | |
606 | executeDefCFARegister(getULEB128(p, instructionsEnd), results); | |
607 | executeDefCFAOffset(getULEB128(p, instructionsEnd), results); | |
608 | break; | |
609 | case DW_CFA_def_cfa_sf: | |
610 | executeDefCFARegister(getULEB128(p, instructionsEnd), results); | |
611 | executeDefCFAOffset(getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results); | |
612 | break; | |
613 | case DW_CFA_def_cfa_register: | |
614 | executeDefCFARegister(getULEB128(p, instructionsEnd), results); | |
615 | break; | |
616 | case DW_CFA_def_cfa_offset: | |
617 | executeDefCFAOffset(getULEB128(p, instructionsEnd), results); | |
618 | break; | |
619 | case DW_CFA_def_cfa_offset_sf: | |
620 | executeDefCFAOffset(getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results); | |
621 | break; | |
622 | case DW_CFA_offset_extended: | |
623 | reg = getULEB128(p, instructionsEnd); | |
624 | executeOffset(reg, getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results); | |
625 | break; | |
626 | case DW_CFA_offset_extended_sf: | |
627 | reg = getULEB128(p, instructionsEnd); | |
628 | executeOffset(reg, getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results); | |
629 | break; | |
630 | default: | |
631 | operand = opcode & DW_CFA_operand_mask; | |
632 | switch (opcode & ~DW_CFA_operand_mask) { | |
633 | case DW_CFA_offset: | |
634 | executeOffset(operand, getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results); | |
635 | break; | |
636 | case DW_CFA_advance_loc: | |
637 | break; | |
638 | default: | |
639 | RELEASE_ASSERT_NOT_REACHED(); // unknown or unsupported CFA opcode | |
640 | } | |
641 | } | |
642 | } | |
643 | } | |
644 | ||
645 | static void parseFDEInstructions(const FDE_Info& fdeInfo, const CIE_Info& cieInfo, PrologInfo* results) | |
646 | { | |
647 | // clear results | |
648 | bzero(results, sizeof(PrologInfo)); | |
649 | ||
650 | // parse CIE then FDE instructions | |
651 | parseInstructions(cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength, cieInfo, results); | |
652 | parseInstructions(fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, results); | |
653 | } | |
654 | #endif | |
655 | } // anonymous namespace | |
656 | ||
657 | bool UnwindInfo::parse(void* section, size_t size, GeneratedFunction generatedFunction) | |
658 | { | |
659 | m_registers.clear(); | |
660 | RELEASE_ASSERT(!!section); | |
661 | if (!section) | |
662 | return false; | |
663 | ||
664 | #if OS(DARWIN) | |
665 | RELEASE_ASSERT(size >= sizeof(CompactUnwind)); | |
666 | ||
667 | CompactUnwind* data = bitwise_cast<CompactUnwind*>(section); | |
668 | ||
669 | RELEASE_ASSERT(!data->personality); // We don't know how to handle this. | |
670 | RELEASE_ASSERT(!data->lsda); // We don't know how to handle this. | |
671 | RELEASE_ASSERT(data->function == generatedFunction); // The unwind data better be for our function. | |
672 | ||
673 | compact_unwind_encoding_t encoding = data->encoding; | |
674 | RELEASE_ASSERT(!(encoding & UNWIND_IS_NOT_FUNCTION_START)); | |
675 | RELEASE_ASSERT(!(encoding & UNWIND_HAS_LSDA)); | |
676 | RELEASE_ASSERT(!(encoding & UNWIND_PERSONALITY_MASK)); | |
677 | ||
678 | #if CPU(X86_64) | |
679 | RELEASE_ASSERT((encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_RBP_FRAME); | |
680 | ||
681 | int32_t offset = -((encoding & UNWIND_X86_64_RBP_FRAME_OFFSET) >> 16) * 8; | |
682 | uint32_t nextRegisters = encoding; | |
683 | for (unsigned i = 5; i--;) { | |
684 | uint32_t currentRegister = nextRegisters & 7; | |
685 | nextRegisters >>= 3; | |
686 | ||
687 | switch (currentRegister) { | |
688 | case UNWIND_X86_64_REG_NONE: | |
689 | break; | |
690 | ||
691 | case UNWIND_X86_64_REG_RBX: | |
692 | m_registers.append(RegisterAtOffset(X86Registers::ebx, offset)); | |
693 | break; | |
694 | ||
695 | case UNWIND_X86_64_REG_R12: | |
696 | m_registers.append(RegisterAtOffset(X86Registers::r12, offset)); | |
697 | break; | |
698 | ||
699 | case UNWIND_X86_64_REG_R13: | |
700 | m_registers.append(RegisterAtOffset(X86Registers::r13, offset)); | |
701 | break; | |
702 | ||
703 | case UNWIND_X86_64_REG_R14: | |
704 | m_registers.append(RegisterAtOffset(X86Registers::r14, offset)); | |
705 | break; | |
706 | ||
707 | case UNWIND_X86_64_REG_R15: | |
708 | m_registers.append(RegisterAtOffset(X86Registers::r15, offset)); | |
709 | break; | |
710 | ||
711 | case UNWIND_X86_64_REG_RBP: | |
712 | m_registers.append(RegisterAtOffset(X86Registers::ebp, offset)); | |
713 | break; | |
714 | ||
715 | default: | |
716 | RELEASE_ASSERT_NOT_REACHED(); | |
717 | } | |
718 | ||
719 | offset += 8; | |
720 | } | |
721 | #elif CPU(ARM64) | |
722 | RELEASE_ASSERT((encoding & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_FRAME); | |
723 | ||
724 | m_registers.append(RegisterAtOffset(ARM64Registers::fp, 0)); | |
725 | ||
726 | int32_t offset = 0; | |
727 | if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { | |
728 | m_registers.append(RegisterAtOffset(ARM64Registers::x19, offset -= 8)); | |
729 | m_registers.append(RegisterAtOffset(ARM64Registers::x20, offset -= 8)); | |
730 | } | |
731 | if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { | |
732 | m_registers.append(RegisterAtOffset(ARM64Registers::x21, offset -= 8)); | |
733 | m_registers.append(RegisterAtOffset(ARM64Registers::x22, offset -= 8)); | |
734 | } | |
735 | if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { | |
736 | m_registers.append(RegisterAtOffset(ARM64Registers::x23, offset -= 8)); | |
737 | m_registers.append(RegisterAtOffset(ARM64Registers::x24, offset -= 8)); | |
738 | } | |
739 | if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { | |
740 | m_registers.append(RegisterAtOffset(ARM64Registers::x25, offset -= 8)); | |
741 | m_registers.append(RegisterAtOffset(ARM64Registers::x26, offset -= 8)); | |
742 | } | |
743 | if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { | |
744 | m_registers.append(RegisterAtOffset(ARM64Registers::x27, offset -= 8)); | |
745 | m_registers.append(RegisterAtOffset(ARM64Registers::x28, offset -= 8)); | |
746 | } | |
747 | if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { | |
748 | m_registers.append(RegisterAtOffset(ARM64Registers::q8, offset -= 8)); | |
749 | m_registers.append(RegisterAtOffset(ARM64Registers::q9, offset -= 8)); | |
750 | } | |
751 | if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { | |
752 | m_registers.append(RegisterAtOffset(ARM64Registers::q10, offset -= 8)); | |
753 | m_registers.append(RegisterAtOffset(ARM64Registers::q11, offset -= 8)); | |
754 | } | |
755 | if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { | |
756 | m_registers.append(RegisterAtOffset(ARM64Registers::q12, offset -= 8)); | |
757 | m_registers.append(RegisterAtOffset(ARM64Registers::q13, offset -= 8)); | |
758 | } | |
759 | if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { | |
760 | m_registers.append(RegisterAtOffset(ARM64Registers::q14, offset -= 8)); | |
761 | m_registers.append(RegisterAtOffset(ARM64Registers::q15, offset -= 8)); | |
762 | } | |
763 | #else | |
764 | #error "Unrecognized architecture" | |
765 | #endif | |
766 | ||
767 | #elif OS(LINUX) | |
768 | FDE_Info fdeInfo; | |
769 | CIE_Info cieInfo; | |
770 | PrologInfo prolog; | |
771 | ||
772 | findFDE((uintptr_t)generatedFunction, (uintptr_t)section, size, &fdeInfo, &cieInfo); | |
773 | parseFDEInstructions(fdeInfo, cieInfo, &prolog); | |
774 | ||
775 | #if CPU(X86_64) | |
776 | RELEASE_ASSERT(prolog.cfaRegister == UNW_X86_64_rbp); | |
777 | RELEASE_ASSERT(prolog.cfaRegisterOffset == 16); | |
778 | RELEASE_ASSERT(prolog.savedRegisters[UNW_X86_64_rbp].saved); | |
779 | RELEASE_ASSERT(prolog.savedRegisters[UNW_X86_64_rbp].offset == -prolog.cfaRegisterOffset); | |
780 | ||
781 | for (int i = 0; i < MaxRegisterNumber; ++i) { | |
782 | if (prolog.savedRegisters[i].saved) { | |
783 | switch (i) { | |
784 | case UNW_X86_64_rbx: | |
785 | m_registers.append(RegisterAtOffset(X86Registers::ebx, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
786 | break; | |
787 | case UNW_X86_64_r12: | |
788 | m_registers.append(RegisterAtOffset(X86Registers::r12, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
789 | break; | |
790 | case UNW_X86_64_r13: | |
791 | m_registers.append(RegisterAtOffset(X86Registers::r13, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
792 | break; | |
793 | case UNW_X86_64_r14: | |
794 | m_registers.append(RegisterAtOffset(X86Registers::r14, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
795 | break; | |
796 | case UNW_X86_64_r15: | |
797 | m_registers.append(RegisterAtOffset(X86Registers::r15, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
798 | break; | |
799 | case UNW_X86_64_rbp: | |
800 | m_registers.append(RegisterAtOffset(X86Registers::ebp, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
801 | break; | |
802 | case DW_X86_64_RET_addr: | |
803 | break; | |
804 | default: | |
805 | RELEASE_ASSERT_NOT_REACHED(); // non-standard register being saved in prolog | |
806 | } | |
807 | } | |
808 | } | |
809 | #elif CPU(ARM64) | |
810 | RELEASE_ASSERT(prolog.cfaRegister == UNW_ARM64_fp); | |
811 | RELEASE_ASSERT(prolog.cfaRegisterOffset == 16); | |
812 | RELEASE_ASSERT(prolog.savedRegisters[UNW_ARM64_fp].saved); | |
813 | RELEASE_ASSERT(prolog.savedRegisters[UNW_ARM64_fp].offset == -prolog.cfaRegisterOffset); | |
814 | ||
815 | for (int i = 0; i < MaxRegisterNumber; ++i) { | |
816 | if (prolog.savedRegisters[i].saved) { | |
817 | switch (i) { | |
818 | case UNW_ARM64_x0: | |
819 | m_registers.append(RegisterAtOffset(ARM64Registers::x0, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
820 | break; | |
821 | case UNW_ARM64_x1: | |
822 | m_registers.append(RegisterAtOffset(ARM64Registers::x1, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
823 | break; | |
824 | case UNW_ARM64_x2: | |
825 | m_registers.append(RegisterAtOffset(ARM64Registers::x2, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
826 | break; | |
827 | case UNW_ARM64_x3: | |
828 | m_registers.append(RegisterAtOffset(ARM64Registers::x3, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
829 | break; | |
830 | case UNW_ARM64_x4: | |
831 | m_registers.append(RegisterAtOffset(ARM64Registers::x4, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
832 | break; | |
833 | case UNW_ARM64_x5: | |
834 | m_registers.append(RegisterAtOffset(ARM64Registers::x5, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
835 | break; | |
836 | case UNW_ARM64_x6: | |
837 | m_registers.append(RegisterAtOffset(ARM64Registers::x6, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
838 | break; | |
839 | case UNW_ARM64_x7: | |
840 | m_registers.append(RegisterAtOffset(ARM64Registers::x7, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
841 | break; | |
842 | case UNW_ARM64_x8: | |
843 | m_registers.append(RegisterAtOffset(ARM64Registers::x8, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
844 | break; | |
845 | case UNW_ARM64_x9: | |
846 | m_registers.append(RegisterAtOffset(ARM64Registers::x9, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
847 | break; | |
848 | case UNW_ARM64_x10: | |
849 | m_registers.append(RegisterAtOffset(ARM64Registers::x10, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
850 | break; | |
851 | case UNW_ARM64_x11: | |
852 | m_registers.append(RegisterAtOffset(ARM64Registers::x11, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
853 | break; | |
854 | case UNW_ARM64_x12: | |
855 | m_registers.append(RegisterAtOffset(ARM64Registers::x12, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
856 | break; | |
857 | case UNW_ARM64_x13: | |
858 | m_registers.append(RegisterAtOffset(ARM64Registers::x13, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
859 | break; | |
860 | case UNW_ARM64_x14: | |
861 | m_registers.append(RegisterAtOffset(ARM64Registers::x14, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
862 | break; | |
863 | case UNW_ARM64_x15: | |
864 | m_registers.append(RegisterAtOffset(ARM64Registers::x15, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
865 | break; | |
866 | case UNW_ARM64_x16: | |
867 | m_registers.append(RegisterAtOffset(ARM64Registers::x16, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
868 | break; | |
869 | case UNW_ARM64_x17: | |
870 | m_registers.append(RegisterAtOffset(ARM64Registers::x17, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
871 | break; | |
872 | case UNW_ARM64_x18: | |
873 | m_registers.append(RegisterAtOffset(ARM64Registers::x18, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
874 | break; | |
875 | case UNW_ARM64_x19: | |
876 | m_registers.append(RegisterAtOffset(ARM64Registers::x19, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
877 | break; | |
878 | case UNW_ARM64_x20: | |
879 | m_registers.append(RegisterAtOffset(ARM64Registers::x20, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
880 | break; | |
881 | case UNW_ARM64_x21: | |
882 | m_registers.append(RegisterAtOffset(ARM64Registers::x21, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
883 | break; | |
884 | case UNW_ARM64_x22: | |
885 | m_registers.append(RegisterAtOffset(ARM64Registers::x22, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
886 | break; | |
887 | case UNW_ARM64_x23: | |
888 | m_registers.append(RegisterAtOffset(ARM64Registers::x23, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
889 | break; | |
890 | case UNW_ARM64_x24: | |
891 | m_registers.append(RegisterAtOffset(ARM64Registers::x24, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
892 | break; | |
893 | case UNW_ARM64_x25: | |
894 | m_registers.append(RegisterAtOffset(ARM64Registers::x25, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
895 | break; | |
896 | case UNW_ARM64_x26: | |
897 | m_registers.append(RegisterAtOffset(ARM64Registers::x26, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
898 | break; | |
899 | case UNW_ARM64_x27: | |
900 | m_registers.append(RegisterAtOffset(ARM64Registers::x27, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
901 | break; | |
902 | case UNW_ARM64_x28: | |
903 | m_registers.append(RegisterAtOffset(ARM64Registers::x28, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
904 | break; | |
905 | case UNW_ARM64_fp: | |
906 | m_registers.append(RegisterAtOffset(ARM64Registers::fp, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
907 | break; | |
908 | case UNW_ARM64_x30: | |
909 | m_registers.append(RegisterAtOffset(ARM64Registers::x30, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
910 | break; | |
911 | case UNW_ARM64_sp: | |
912 | m_registers.append(RegisterAtOffset(ARM64Registers::sp, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
913 | break; | |
914 | case UNW_ARM64_v0: | |
915 | m_registers.append(RegisterAtOffset(ARM64Registers::q0, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
916 | break; | |
917 | case UNW_ARM64_v1: | |
918 | m_registers.append(RegisterAtOffset(ARM64Registers::q1, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
919 | break; | |
920 | case UNW_ARM64_v2: | |
921 | m_registers.append(RegisterAtOffset(ARM64Registers::q2, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
922 | break; | |
923 | case UNW_ARM64_v3: | |
924 | m_registers.append(RegisterAtOffset(ARM64Registers::q3, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
925 | break; | |
926 | case UNW_ARM64_v4: | |
927 | m_registers.append(RegisterAtOffset(ARM64Registers::q4, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
928 | break; | |
929 | case UNW_ARM64_v5: | |
930 | m_registers.append(RegisterAtOffset(ARM64Registers::q5, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
931 | break; | |
932 | case UNW_ARM64_v6: | |
933 | m_registers.append(RegisterAtOffset(ARM64Registers::q6, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
934 | break; | |
935 | case UNW_ARM64_v7: | |
936 | m_registers.append(RegisterAtOffset(ARM64Registers::q7, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
937 | break; | |
938 | case UNW_ARM64_v8: | |
939 | m_registers.append(RegisterAtOffset(ARM64Registers::q8, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
940 | break; | |
941 | case UNW_ARM64_v9: | |
942 | m_registers.append(RegisterAtOffset(ARM64Registers::q9, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
943 | break; | |
944 | case UNW_ARM64_v10: | |
945 | m_registers.append(RegisterAtOffset(ARM64Registers::q10, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
946 | break; | |
947 | case UNW_ARM64_v11: | |
948 | m_registers.append(RegisterAtOffset(ARM64Registers::q11, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
949 | break; | |
950 | case UNW_ARM64_v12: | |
951 | m_registers.append(RegisterAtOffset(ARM64Registers::q12, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
952 | break; | |
953 | case UNW_ARM64_v13: | |
954 | m_registers.append(RegisterAtOffset(ARM64Registers::q13, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
955 | break; | |
956 | case UNW_ARM64_v14: | |
957 | m_registers.append(RegisterAtOffset(ARM64Registers::q14, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
958 | break; | |
959 | case UNW_ARM64_v15: | |
960 | m_registers.append(RegisterAtOffset(ARM64Registers::q15, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
961 | break; | |
962 | case UNW_ARM64_v16: | |
963 | m_registers.append(RegisterAtOffset(ARM64Registers::q16, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
964 | break; | |
965 | case UNW_ARM64_v17: | |
966 | m_registers.append(RegisterAtOffset(ARM64Registers::q17, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
967 | break; | |
968 | case UNW_ARM64_v18: | |
969 | m_registers.append(RegisterAtOffset(ARM64Registers::q18, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
970 | break; | |
971 | case UNW_ARM64_v19: | |
972 | m_registers.append(RegisterAtOffset(ARM64Registers::q19, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
973 | break; | |
974 | case UNW_ARM64_v20: | |
975 | m_registers.append(RegisterAtOffset(ARM64Registers::q20, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
976 | break; | |
977 | case UNW_ARM64_v21: | |
978 | m_registers.append(RegisterAtOffset(ARM64Registers::q21, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
979 | break; | |
980 | case UNW_ARM64_v22: | |
981 | m_registers.append(RegisterAtOffset(ARM64Registers::q22, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
982 | break; | |
983 | case UNW_ARM64_v23: | |
984 | m_registers.append(RegisterAtOffset(ARM64Registers::q23, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
985 | break; | |
986 | case UNW_ARM64_v24: | |
987 | m_registers.append(RegisterAtOffset(ARM64Registers::q24, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
988 | break; | |
989 | case UNW_ARM64_v25: | |
990 | m_registers.append(RegisterAtOffset(ARM64Registers::q25, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
991 | break; | |
992 | case UNW_ARM64_v26: | |
993 | m_registers.append(RegisterAtOffset(ARM64Registers::q26, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
994 | break; | |
995 | case UNW_ARM64_v27: | |
996 | m_registers.append(RegisterAtOffset(ARM64Registers::q27, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
997 | break; | |
998 | case UNW_ARM64_v28: | |
999 | m_registers.append(RegisterAtOffset(ARM64Registers::q28, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
1000 | break; | |
1001 | case UNW_ARM64_v29: | |
1002 | m_registers.append(RegisterAtOffset(ARM64Registers::q29, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
1003 | break; | |
1004 | case UNW_ARM64_v30: | |
1005 | m_registers.append(RegisterAtOffset(ARM64Registers::q30, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
1006 | break; | |
1007 | case UNW_ARM64_v31: | |
1008 | m_registers.append(RegisterAtOffset(ARM64Registers::q31, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset)); | |
1009 | break; | |
1010 | default: | |
1011 | RELEASE_ASSERT_NOT_REACHED(); // non-standard register being saved in prolog | |
1012 | } | |
1013 | } | |
1014 | } | |
1015 | #else | |
1016 | #error "Unrecognized architecture" | |
1017 | #endif | |
1018 | ||
1019 | #endif | |
1020 | std::sort(m_registers.begin(), m_registers.end()); | |
1021 | return true; | |
1022 | } | |
1023 | ||
1024 | void UnwindInfo::dump(PrintStream& out) const | |
1025 | { | |
1026 | out.print(listDump(m_registers)); | |
1027 | } | |
1028 | ||
1029 | RegisterAtOffset* UnwindInfo::find(Reg reg) const | |
1030 | { | |
1031 | return tryBinarySearch<RegisterAtOffset, Reg>(m_registers, m_registers.size(), reg, RegisterAtOffset::getReg); | |
1032 | } | |
1033 | ||
1034 | unsigned UnwindInfo::indexOf(Reg reg) const | |
1035 | { | |
1036 | if (RegisterAtOffset* pointer = find(reg)) | |
1037 | return pointer - m_registers.begin(); | |
1038 | return UINT_MAX; | |
1039 | } | |
1040 | ||
1041 | } } // namespace JSC::FTL | |
1042 | ||
1043 | #endif // ENABLE(FTL_JIT) | |
1044 |