/src/elfutils/backends/i386_unwind.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Get previous frame state for an existing frame state using frame pointers. |
2 | | Copyright (C) 2017 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 <stdlib.h> |
34 | | #include <assert.h> |
35 | | |
36 | | #define BACKEND i386_ |
37 | | #include "libebl_CPU.h" |
38 | | |
39 | | /* Register numbers for frame and stack pointers. We take advantage of |
40 | | them being next to each other when calling getfunc and setfunc. */ |
41 | 0 | #define ESP 4 |
42 | | #define EBP (ESP + 1) |
43 | | |
44 | | /* Most basic frame pointer chasing with EBP as frame pointer. |
45 | | PC = *(FP + 4), SP = FP + 8, FP = *FP. */ |
46 | | bool |
47 | | i386_unwind (Ebl *ebl __attribute__ ((unused)), |
48 | | Dwarf_Addr pc __attribute__ ((unused)), |
49 | | ebl_tid_registers_t *setfunc, ebl_tid_registers_get_t *getfunc, |
50 | | ebl_pid_memory_read_t *readfunc, void *arg, |
51 | | bool *signal_framep __attribute__ ((unused))) |
52 | 0 | { |
53 | | /* sp = 0, fp = 1 */ |
54 | 0 | Dwarf_Word regs[2]; |
55 | | |
56 | | /* Get current stack and frame pointers. */ |
57 | 0 | if (! getfunc (ESP, 2, regs, arg)) |
58 | 0 | return false; |
59 | | |
60 | 0 | Dwarf_Word sp = regs[0]; |
61 | 0 | Dwarf_Word fp = regs[1]; |
62 | | |
63 | | /* Sanity check. We only support traditional stack frames. */ |
64 | 0 | if (fp == 0 || sp == 0 || fp < sp) |
65 | 0 | return false; |
66 | | |
67 | | /* Get the return address from the stack, it is our new pc. */ |
68 | 0 | Dwarf_Word ret_addr; |
69 | 0 | if (! readfunc (fp + 4, &ret_addr, arg) || ret_addr == 0) |
70 | 0 | return false; |
71 | | |
72 | | /* Get new sp and fp. Sanity check again. */ |
73 | 0 | sp = fp + 8; |
74 | 0 | if (! readfunc (fp, &fp, arg) || fp == 0 || sp >= fp) |
75 | 0 | return false; |
76 | | |
77 | | /* Set new sp, fp and pc. */ |
78 | 0 | regs[0] = sp; |
79 | 0 | regs[1] = fp; |
80 | 0 | if (! setfunc (ESP, 2, regs, arg) || ! setfunc (-1, 1, &ret_addr, arg)) |
81 | 0 | return false; |
82 | | |
83 | 0 | return true; |
84 | 0 | } |