/src/elfutils/libdw/cfi.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* CFI program execution. |
2 | | Copyright (C) 2009-2010, 2014, 2015 Red Hat, Inc. |
3 | | This file is part of elfutils. |
4 | | |
5 | | This file is free software; you can redistribute it and/or modify |
6 | | it under the terms of either |
7 | | |
8 | | * the GNU Lesser General Public License as published by the Free |
9 | | Software Foundation; either version 3 of the License, or (at |
10 | | your option) any later version |
11 | | |
12 | | or |
13 | | |
14 | | * the GNU General Public License as published by the Free |
15 | | Software Foundation; either version 2 of the License, or (at |
16 | | your option) any later version |
17 | | |
18 | | or both in parallel, as here. |
19 | | |
20 | | elfutils is distributed in the hope that it will be useful, but |
21 | | WITHOUT ANY WARRANTY; without even the implied warranty of |
22 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
23 | | General Public License for more details. |
24 | | |
25 | | You should have received copies of the GNU General Public License and |
26 | | the GNU Lesser General Public License along with this program. If |
27 | | not, see <http://www.gnu.org/licenses/>. */ |
28 | | |
29 | | #ifdef HAVE_CONFIG_H |
30 | | # include <config.h> |
31 | | #endif |
32 | | |
33 | | #include <dwarf.h> |
34 | | #include "libebl.h" |
35 | | #include "cfi.h" |
36 | | #include "memory-access.h" |
37 | | #include "encoded-value.h" |
38 | | #include "system.h" |
39 | | #include <assert.h> |
40 | | #include <stdlib.h> |
41 | | #include <string.h> |
42 | | |
43 | 0 | #define CFI_PRIMARY_MAX 0x3f |
44 | | |
45 | | static Dwarf_Frame * |
46 | | duplicate_frame_state (const Dwarf_Frame *original, |
47 | | Dwarf_Frame *prev) |
48 | 0 | { |
49 | 0 | size_t size = offsetof (Dwarf_Frame, regs[original->nregs]); |
50 | 0 | Dwarf_Frame *copy = malloc (size); |
51 | 0 | if (likely (copy != NULL)) |
52 | 0 | { |
53 | 0 | memcpy (copy, original, size); |
54 | 0 | copy->prev = prev; |
55 | 0 | } |
56 | 0 | return copy; |
57 | 0 | } |
58 | | |
59 | | static inline bool |
60 | | enough_registers (Dwarf_Word reg, Dwarf_Frame **pfs, int *result) |
61 | 0 | { |
62 | | /* Don't allow insanely large register numbers. 268435456 registers |
63 | | should be enough for anybody. And very large values might overflow |
64 | | the array size and offsetof calculations below. */ |
65 | 0 | if (unlikely (reg >= INT32_MAX / sizeof ((*pfs)->regs[0]))) |
66 | 0 | { |
67 | 0 | *result = DWARF_E_INVALID_CFI; |
68 | 0 | return false; |
69 | 0 | } |
70 | | |
71 | 0 | if ((*pfs)->nregs <= reg) |
72 | 0 | { |
73 | 0 | size_t size = offsetof (Dwarf_Frame, regs[reg + 1]); |
74 | 0 | Dwarf_Frame *bigger = realloc (*pfs, size); |
75 | 0 | if (unlikely (bigger == NULL)) |
76 | 0 | { |
77 | 0 | *result = DWARF_E_NOMEM; |
78 | 0 | return false; |
79 | 0 | } |
80 | 0 | else |
81 | 0 | { |
82 | 0 | eu_static_assert (reg_unspecified == 0); |
83 | 0 | memset (bigger->regs + bigger->nregs, 0, |
84 | 0 | (reg + 1 - bigger->nregs) * sizeof bigger->regs[0]); |
85 | 0 | bigger->nregs = reg + 1; |
86 | 0 | *pfs = bigger; |
87 | 0 | } |
88 | 0 | } |
89 | 0 | return true; |
90 | 0 | } |
91 | | |
92 | | static inline void |
93 | | require_cfa_offset (Dwarf_Frame *fs) |
94 | 0 | { |
95 | 0 | if (unlikely (fs->cfa_rule != cfa_offset)) |
96 | 0 | fs->cfa_rule = cfa_invalid; |
97 | 0 | } |
98 | | |
99 | | /* Returns a DWARF_E_* error code, usually NOERROR or INVALID_CFI. |
100 | | Frees *STATE on failure. */ |
101 | | static int |
102 | | execute_cfi (Dwarf_CFI *cache, |
103 | | const struct dwarf_cie *cie, |
104 | | Dwarf_Frame **state, |
105 | | const uint8_t *program, const uint8_t *const end, bool abi_cfi, |
106 | | Dwarf_Addr loc, Dwarf_Addr find_pc) |
107 | 0 | { |
108 | | /* The caller should not give us anything out of range. */ |
109 | 0 | assert (loc <= find_pc); |
110 | | |
111 | 0 | int result = DWARF_E_NOERROR; |
112 | |
|
113 | 0 | #define cfi_assert(ok) do { \ |
114 | 0 | if (likely (ok)) break; \ |
115 | 0 | result = DWARF_E_INVALID_CFI; \ |
116 | 0 | goto out; \ |
117 | 0 | } while (0) |
118 | |
|
119 | 0 | Dwarf_Frame *fs = *state; |
120 | |
|
121 | 0 | #define register_rule(regno, r_rule, r_value) do { \ |
122 | 0 | if (unlikely (! enough_registers (regno, &fs, &result))) \ |
123 | 0 | goto out; \ |
124 | 0 | fs->regs[regno].rule = reg_##r_rule; \ |
125 | 0 | fs->regs[regno].value = (r_value); \ |
126 | 0 | } while (0) |
127 | | |
128 | | /* The AARCH64 DWARF ABI states that register 34 (ra_sign_state) must |
129 | | be initialized to 0. So do it before executing the CFI. */ |
130 | 0 | if (cache->e_machine == EM_AARCH64) |
131 | 0 | { |
132 | 0 | if (unlikely (! enough_registers (DW_AARCH64_RA_SIGN_STATE, &fs, &result))) |
133 | 0 | goto out; |
134 | 0 | fs->regs[DW_AARCH64_RA_SIGN_STATE].value = 0; |
135 | 0 | } |
136 | | |
137 | 0 | while (program < end) |
138 | 0 | { |
139 | 0 | uint8_t opcode = *program++; |
140 | 0 | Dwarf_Word regno; |
141 | 0 | Dwarf_Word offset; |
142 | 0 | Dwarf_Word sf_offset; |
143 | 0 | Dwarf_Word operand = opcode & CFI_PRIMARY_MAX; |
144 | 0 | switch (opcode) |
145 | 0 | { |
146 | | /* These cases move LOC, i.e. "create a new table row". */ |
147 | | |
148 | 0 | case DW_CFA_advance_loc1: |
149 | 0 | operand = *program++; |
150 | 0 | FALLTHROUGH; |
151 | 0 | case DW_CFA_advance_loc + 0 ... DW_CFA_advance_loc + CFI_PRIMARY_MAX: |
152 | 0 | advance_loc: |
153 | 0 | loc += operand * cie->code_alignment_factor; |
154 | 0 | break; |
155 | | |
156 | 0 | case DW_CFA_advance_loc2: |
157 | 0 | cfi_assert (program + 2 <= end); |
158 | 0 | operand = read_2ubyte_unaligned_inc (cache, program); |
159 | 0 | goto advance_loc; |
160 | 0 | case DW_CFA_advance_loc4: |
161 | 0 | cfi_assert (program + 4 <= end); |
162 | 0 | operand = read_4ubyte_unaligned_inc (cache, program); |
163 | 0 | goto advance_loc; |
164 | 0 | case DW_CFA_MIPS_advance_loc8: |
165 | 0 | cfi_assert (program + 8 <= end); |
166 | 0 | operand = read_8ubyte_unaligned_inc (cache, program); |
167 | 0 | goto advance_loc; |
168 | | |
169 | 0 | case DW_CFA_set_loc: |
170 | 0 | if (likely (!read_encoded_value (cache, cie->fde_encoding, |
171 | 0 | &program, &loc))) |
172 | 0 | break; |
173 | 0 | result = INTUSE(dwarf_errno) (); |
174 | 0 | goto out; |
175 | | |
176 | | /* Now all following cases affect this row, but do not touch LOC. |
177 | | These cases end with 'continue'. We only get out of the |
178 | | switch block for the row-copying (LOC-moving) cases above. */ |
179 | | |
180 | 0 | case DW_CFA_def_cfa: |
181 | 0 | get_uleb128 (operand, program, end); |
182 | 0 | cfi_assert (program < end); |
183 | 0 | get_uleb128 (offset, program, end); |
184 | 0 | def_cfa: |
185 | 0 | fs->cfa_rule = cfa_offset; |
186 | 0 | fs->cfa_val_reg = operand; |
187 | 0 | fs->cfa_val_offset = offset; |
188 | | /* Prime the rest of the Dwarf_Op so dwarf_frame_cfa can use it. */ |
189 | 0 | fs->cfa_data.offset.atom = DW_OP_bregx; |
190 | 0 | fs->cfa_data.offset.offset = 0; |
191 | 0 | continue; |
192 | | |
193 | 0 | case DW_CFA_def_cfa_register: |
194 | 0 | get_uleb128 (regno, program, end); |
195 | 0 | require_cfa_offset (fs); |
196 | 0 | fs->cfa_val_reg = regno; |
197 | 0 | continue; |
198 | | |
199 | 0 | case DW_CFA_def_cfa_sf: |
200 | 0 | get_uleb128 (operand, program, end); |
201 | 0 | cfi_assert (program < end); |
202 | 0 | get_sleb128 (sf_offset, program, end); |
203 | 0 | offset = sf_offset * cie->data_alignment_factor; |
204 | 0 | goto def_cfa; |
205 | | |
206 | 0 | case DW_CFA_def_cfa_offset: |
207 | 0 | get_uleb128 (offset, program, end); |
208 | 0 | def_cfa_offset: |
209 | 0 | require_cfa_offset (fs); |
210 | 0 | fs->cfa_val_offset = offset; |
211 | 0 | continue; |
212 | | |
213 | 0 | case DW_CFA_def_cfa_offset_sf: |
214 | 0 | get_sleb128 (sf_offset, program, end); |
215 | 0 | offset = sf_offset * cie->data_alignment_factor; |
216 | 0 | goto def_cfa_offset; |
217 | | |
218 | 0 | case DW_CFA_def_cfa_expression: |
219 | | /* DW_FORM_block is a ULEB128 length followed by that many bytes. */ |
220 | 0 | get_uleb128 (operand, program, end); |
221 | 0 | cfi_assert (operand <= (Dwarf_Word) (end - program)); |
222 | 0 | fs->cfa_rule = cfa_expr; |
223 | 0 | fs->cfa_data.expr.data = (unsigned char *) program; |
224 | 0 | fs->cfa_data.expr.length = operand; |
225 | 0 | program += operand; |
226 | 0 | continue; |
227 | | |
228 | 0 | case DW_CFA_undefined: |
229 | 0 | get_uleb128 (regno, program, end); |
230 | 0 | register_rule (regno, undefined, 0); |
231 | 0 | continue; |
232 | | |
233 | 0 | case DW_CFA_same_value: |
234 | 0 | get_uleb128 (regno, program, end); |
235 | 0 | register_rule (regno, same_value, 0); |
236 | 0 | continue; |
237 | | |
238 | 0 | case DW_CFA_offset_extended: |
239 | 0 | get_uleb128 (operand, program, end); |
240 | 0 | cfi_assert (program < end); |
241 | 0 | FALLTHROUGH; |
242 | 0 | case DW_CFA_offset + 0 ... DW_CFA_offset + CFI_PRIMARY_MAX: |
243 | 0 | get_uleb128 (offset, program, end); |
244 | 0 | offset *= cie->data_alignment_factor; |
245 | 0 | offset_extended: |
246 | 0 | register_rule (operand, offset, offset); |
247 | 0 | continue; |
248 | | |
249 | 0 | case DW_CFA_offset_extended_sf: |
250 | 0 | get_uleb128 (operand, program, end); |
251 | 0 | cfi_assert (program < end); |
252 | 0 | get_sleb128 (sf_offset, program, end); |
253 | 0 | offset_extended_sf: |
254 | 0 | offset = sf_offset * cie->data_alignment_factor; |
255 | 0 | goto offset_extended; |
256 | | |
257 | 0 | case DW_CFA_GNU_negative_offset_extended: |
258 | | /* GNU extension obsoleted by DW_CFA_offset_extended_sf. */ |
259 | 0 | get_uleb128 (operand, program, end); |
260 | 0 | cfi_assert (program < end); |
261 | 0 | get_uleb128 (offset, program, end); |
262 | 0 | sf_offset = -offset; |
263 | 0 | goto offset_extended_sf; |
264 | | |
265 | 0 | case DW_CFA_val_offset: |
266 | 0 | get_uleb128 (operand, program, end); |
267 | 0 | cfi_assert (program < end); |
268 | 0 | get_uleb128 (offset, program, end); |
269 | 0 | offset *= cie->data_alignment_factor; |
270 | 0 | val_offset: |
271 | 0 | register_rule (operand, val_offset, offset); |
272 | 0 | continue; |
273 | | |
274 | 0 | case DW_CFA_val_offset_sf: |
275 | 0 | get_uleb128 (operand, program, end); |
276 | 0 | cfi_assert (program < end); |
277 | 0 | get_sleb128 (sf_offset, program, end); |
278 | 0 | offset = sf_offset * cie->data_alignment_factor; |
279 | 0 | goto val_offset; |
280 | | |
281 | 0 | case DW_CFA_register: |
282 | 0 | get_uleb128 (regno, program, end); |
283 | 0 | cfi_assert (program < end); |
284 | 0 | get_uleb128 (operand, program, end); |
285 | 0 | register_rule (regno, register, operand); |
286 | 0 | continue; |
287 | | |
288 | 0 | case DW_CFA_expression: |
289 | | /* Expression rule relies on section data, abi_cfi cannot use it. */ |
290 | 0 | assert (! abi_cfi); |
291 | 0 | get_uleb128 (regno, program, end); |
292 | 0 | offset = program - (const uint8_t *) cache->data->d.d_buf; |
293 | | /* DW_FORM_block is a ULEB128 length followed by that many bytes. */ |
294 | 0 | cfi_assert (program < end); |
295 | 0 | get_uleb128 (operand, program, end); |
296 | 0 | cfi_assert (operand <= (Dwarf_Word) (end - program)); |
297 | 0 | program += operand; |
298 | 0 | register_rule (regno, expression, offset); |
299 | 0 | continue; |
300 | | |
301 | 0 | case DW_CFA_val_expression: |
302 | | /* Expression rule relies on section data, abi_cfi cannot use it. */ |
303 | 0 | assert (! abi_cfi); |
304 | 0 | get_uleb128 (regno, program, end); |
305 | | /* DW_FORM_block is a ULEB128 length followed by that many bytes. */ |
306 | 0 | offset = program - (const uint8_t *) cache->data->d.d_buf; |
307 | 0 | cfi_assert (program < end); |
308 | 0 | get_uleb128 (operand, program, end); |
309 | 0 | cfi_assert (operand <= (Dwarf_Word) (end - program)); |
310 | 0 | program += operand; |
311 | 0 | register_rule (regno, val_expression, offset); |
312 | 0 | continue; |
313 | | |
314 | 0 | case DW_CFA_restore_extended: |
315 | 0 | get_uleb128 (operand, program, end); |
316 | 0 | FALLTHROUGH; |
317 | 0 | case DW_CFA_restore + 0 ... DW_CFA_restore + CFI_PRIMARY_MAX: |
318 | |
|
319 | 0 | if (unlikely (abi_cfi) && likely (opcode == DW_CFA_restore)) |
320 | 0 | { |
321 | | /* Special case hack to give backend abi_cfi a shorthand. */ |
322 | 0 | cache->default_same_value = true; |
323 | 0 | continue; |
324 | 0 | } |
325 | | |
326 | | /* This can't be used in the CIE's own initial instructions. */ |
327 | 0 | cfi_assert (cie->initial_state != NULL); |
328 | | |
329 | | /* Restore the CIE's initial rule for this register. */ |
330 | 0 | if (unlikely (! enough_registers (operand, &fs, &result))) |
331 | 0 | goto out; |
332 | 0 | if (cie->initial_state->nregs > operand) |
333 | 0 | fs->regs[operand] = cie->initial_state->regs[operand]; |
334 | 0 | else |
335 | 0 | fs->regs[operand].rule = reg_unspecified; |
336 | 0 | continue; |
337 | | |
338 | 0 | case DW_CFA_remember_state: |
339 | 0 | { |
340 | | /* Duplicate the state and chain the copy on. */ |
341 | 0 | Dwarf_Frame *copy = duplicate_frame_state (fs, fs); |
342 | 0 | if (unlikely (copy == NULL)) |
343 | 0 | { |
344 | 0 | result = DWARF_E_NOMEM; |
345 | 0 | goto out; |
346 | 0 | } |
347 | 0 | fs = copy; |
348 | 0 | continue; |
349 | 0 | } |
350 | | |
351 | 0 | case DW_CFA_restore_state: |
352 | 0 | { |
353 | | /* Pop the current state off and use the old one instead. */ |
354 | 0 | Dwarf_Frame *prev = fs->prev; |
355 | 0 | cfi_assert (prev != NULL); |
356 | 0 | free (fs); |
357 | 0 | fs = prev; |
358 | 0 | continue; |
359 | 0 | } |
360 | | |
361 | 0 | case DW_CFA_nop: |
362 | 0 | continue; |
363 | | |
364 | 0 | case DW_CFA_GNU_window_save: /* DW_CFA_AARCH64_negate_ra_state */ |
365 | 0 | if (cache->e_machine == EM_AARCH64) |
366 | 0 | { |
367 | | /* Toggles the return address state, indicating whether |
368 | | the return address is encrypted or not on |
369 | | aarch64. */ |
370 | 0 | if (unlikely (! enough_registers (DW_AARCH64_RA_SIGN_STATE, &fs, &result))) |
371 | 0 | goto out; |
372 | 0 | fs->regs[DW_AARCH64_RA_SIGN_STATE].value ^= 0x1; |
373 | 0 | } |
374 | 0 | else |
375 | 0 | { |
376 | | /* This is magic shorthand used only by SPARC. It's |
377 | | equivalent to a bunch of DW_CFA_register and |
378 | | DW_CFA_offset operations. */ |
379 | 0 | if (unlikely (! enough_registers (31, &fs, &result))) |
380 | 0 | goto out; |
381 | 0 | for (regno = 8; regno < 16; ++regno) |
382 | 0 | { |
383 | | /* Find each %oN in %iN. */ |
384 | 0 | fs->regs[regno].rule = reg_register; |
385 | 0 | fs->regs[regno].value = regno + 16; |
386 | 0 | } |
387 | 0 | unsigned int address_size; |
388 | 0 | address_size = (cache->e_ident[EI_CLASS] == ELFCLASS32 |
389 | 0 | ? 4 : 8); |
390 | 0 | for (; regno < 32; ++regno) |
391 | 0 | { |
392 | | /* Find %l0..%l7 and %i0..%i7 in a block at the CFA. */ |
393 | 0 | fs->regs[regno].rule = reg_offset; |
394 | 0 | fs->regs[regno].value = (regno - 16) * address_size; |
395 | 0 | } |
396 | 0 | } |
397 | 0 | continue; |
398 | | |
399 | 0 | case DW_CFA_GNU_args_size: |
400 | | /* XXX is this useful for anything? */ |
401 | 0 | get_uleb128 (operand, program, end); |
402 | 0 | continue; |
403 | | |
404 | 0 | default: |
405 | 0 | cfi_assert (false); |
406 | 0 | continue; |
407 | 0 | } |
408 | | |
409 | | /* We get here only for the cases that have just moved LOC. */ |
410 | 0 | cfi_assert (cie->initial_state != NULL); |
411 | 0 | if (find_pc >= loc) |
412 | | /* This advance has not yet reached FIND_PC. */ |
413 | 0 | fs->start = loc; |
414 | 0 | else |
415 | 0 | { |
416 | | /* We have just advanced past the address we're looking for. |
417 | | The state currently described is what we want to see. */ |
418 | 0 | fs->end = loc; |
419 | 0 | break; |
420 | 0 | } |
421 | 0 | } |
422 | | |
423 | | /* "The end of the instruction stream can be thought of as a |
424 | | DW_CFA_set_loc (initial_location + address_range) instruction." |
425 | | (DWARF 3.0 Section 6.4.3) |
426 | | |
427 | | When we fall off the end of the program without an advance_loc/set_loc |
428 | | that put us past FIND_PC, the final state left by the FDE program |
429 | | applies to this address (the caller ensured it was inside the FDE). |
430 | | This address (FDE->end) is already in FS->end as set by the caller. */ |
431 | | |
432 | 0 | #undef register_rule |
433 | 0 | #undef cfi_assert |
434 | | |
435 | 0 | out: |
436 | | |
437 | | /* Pop any remembered states left on the stack. */ |
438 | 0 | while (fs->prev != NULL) |
439 | 0 | { |
440 | 0 | Dwarf_Frame *prev = fs->prev; |
441 | 0 | fs->prev = prev->prev; |
442 | 0 | free (prev); |
443 | 0 | } |
444 | |
|
445 | 0 | if (likely (result == DWARF_E_NOERROR)) |
446 | 0 | *state = fs; |
447 | 0 | else |
448 | 0 | free (fs); |
449 | |
|
450 | 0 | return result; |
451 | 0 | } |
452 | | |
453 | | static int |
454 | | cie_cache_initial_state (Dwarf_CFI *cache, struct dwarf_cie *cie) |
455 | 0 | { |
456 | 0 | int result = DWARF_E_NOERROR; |
457 | |
|
458 | 0 | if (likely (cie->initial_state != NULL)) |
459 | 0 | return result; |
460 | | |
461 | | /* This CIE has not been used before. Play out its initial |
462 | | instructions and cache the initial state that results. |
463 | | First we'll let the backend fill in the default initial |
464 | | state for this machine's ABI. */ |
465 | | |
466 | 0 | Dwarf_CIE abi_info = { DW_CIE_ID_64, NULL, NULL, 1, 1, -1, "", NULL, 0, 0 }; |
467 | | |
468 | | /* Make sure we have a backend handle cached. */ |
469 | 0 | if (unlikely (cache->ebl == NULL)) |
470 | 0 | { |
471 | 0 | cache->ebl = ebl_openbackend (cache->data->s->elf); |
472 | 0 | if (unlikely (cache->ebl == NULL)) |
473 | 0 | cache->ebl = (void *) -1l; |
474 | 0 | } |
475 | | |
476 | | /* Fetch the ABI's default CFI program. */ |
477 | 0 | if (likely (cache->ebl != (void *) -1l) |
478 | 0 | && unlikely (ebl_abi_cfi (cache->ebl, &abi_info) < 0)) |
479 | 0 | return DWARF_E_UNKNOWN_ERROR; |
480 | | |
481 | 0 | Dwarf_Frame *cie_fs = calloc (1, sizeof (Dwarf_Frame)); |
482 | 0 | if (unlikely (cie_fs == NULL)) |
483 | 0 | return DWARF_E_NOMEM; |
484 | | |
485 | | /* If the default state of any register is not "undefined" |
486 | | (i.e. call-clobbered), then the backend supplies instructions |
487 | | for the standard initial state. */ |
488 | 0 | if (abi_info.initial_instructions_end > abi_info.initial_instructions) |
489 | 0 | { |
490 | | /* Dummy CIE for backend's instructions. */ |
491 | 0 | struct dwarf_cie abi_cie = |
492 | 0 | { |
493 | 0 | .code_alignment_factor = abi_info.code_alignment_factor, |
494 | 0 | .data_alignment_factor = abi_info.data_alignment_factor, |
495 | 0 | }; |
496 | 0 | result = execute_cfi (cache, &abi_cie, &cie_fs, |
497 | 0 | abi_info.initial_instructions, |
498 | 0 | abi_info.initial_instructions_end, true, |
499 | 0 | 0, (Dwarf_Addr) -1l); |
500 | 0 | } |
501 | | |
502 | | /* Now run the CIE's initial instructions. */ |
503 | 0 | if (cie->initial_instructions_end > cie->initial_instructions |
504 | 0 | && likely (result == DWARF_E_NOERROR)) |
505 | 0 | result = execute_cfi (cache, cie, &cie_fs, |
506 | 0 | cie->initial_instructions, |
507 | 0 | cie->initial_instructions_end, false, |
508 | 0 | 0, (Dwarf_Addr) -1l); |
509 | |
|
510 | 0 | if (likely (result == DWARF_E_NOERROR)) |
511 | 0 | { |
512 | | /* Now we have the initial state of things that all |
513 | | FDEs using this CIE will start from. */ |
514 | 0 | cie_fs->cache = cache; |
515 | 0 | cie->initial_state = cie_fs; |
516 | 0 | } |
517 | |
|
518 | 0 | return result; |
519 | 0 | } |
520 | | |
521 | | int |
522 | | internal_function |
523 | | __libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde, |
524 | | Dwarf_Addr address, Dwarf_Frame **frame) |
525 | 0 | { |
526 | 0 | int result = cie_cache_initial_state (cache, fde->cie); |
527 | 0 | if (likely (result == DWARF_E_NOERROR)) |
528 | 0 | { |
529 | 0 | Dwarf_Frame *fs = duplicate_frame_state (fde->cie->initial_state, NULL); |
530 | 0 | if (unlikely (fs == NULL)) |
531 | 0 | return DWARF_E_NOMEM; |
532 | | |
533 | 0 | fs->fde = fde; |
534 | 0 | fs->start = fde->start; |
535 | 0 | fs->end = fde->end; |
536 | |
|
537 | 0 | result = execute_cfi (cache, fde->cie, &fs, |
538 | 0 | fde->instructions, fde->instructions_end, false, |
539 | 0 | fde->start, address); |
540 | 0 | if (likely (result == DWARF_E_NOERROR)) |
541 | 0 | *frame = fs; |
542 | 0 | } |
543 | 0 | return result; |
544 | 0 | } |