1/* Internal definitions for libdw CFI interpreter.
2   Copyright (C) 2009-2010 Red Hat, Inc.
3   This file is part of Red Hat elfutils.
4
5   Red Hat elfutils is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by the
7   Free Software Foundation; version 2 of the License.
8
9   Red Hat elfutils is distributed in the hope that it will be useful, but
10   WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   General Public License for more details.
13
14   You should have received a copy of the GNU General Public License along
15   with Red Hat elfutils; if not, write to the Free Software Foundation,
16   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
17
18   In addition, as a special exception, Red Hat, Inc. gives You the
19   additional right to link the code of Red Hat elfutils with code licensed
20   under any Open Source Initiative certified open source license
21   (http://www.opensource.org/licenses/index.php) which requires the
22   distribution of source code with any binary distribution and to
23   distribute linked combinations of the two.  Non-GPL Code permitted under
24   this exception must only link to the code of Red Hat elfutils through
25   those well defined interfaces identified in the file named EXCEPTION
26   found in the source code files (the "Approved Interfaces").  The files
27   of Non-GPL Code may instantiate templates or use macros or inline
28   functions from the Approved Interfaces without causing the resulting
29   work to be covered by the GNU General Public License.  Only Red Hat,
30   Inc. may make changes or additions to the list of Approved Interfaces.
31   Red Hat's grant of this exception is conditioned upon your not adding
32   any new exceptions.  If you wish to add a new Approved Interface or
33   exception, please contact Red Hat.  You must obey the GNU General Public
34   License in all respects for all of the Red Hat elfutils code and other
35   code used in conjunction with Red Hat elfutils except the Non-GPL Code
36   covered by this exception.  If you modify this file, you may extend this
37   exception to your version of the file, but you are not obligated to do
38   so.  If you do not wish to provide this exception without modification,
39   you must delete this exception statement from your version and license
40   this file solely under the GPL without exception.
41
42   Red Hat elfutils is an included package of the Open Invention Network.
43   An included package of the Open Invention Network is a package for which
44   Open Invention Network licensees cross-license their patents.  No patent
45   license is granted, either expressly or impliedly, by designation as an
46   included package.  Should you wish to participate in the Open Invention
47   Network licensing program, please visit www.openinventionnetwork.com
48   <http://www.openinventionnetwork.com>.  */
49
50#ifndef _UNWINDP_H
51#define _UNWINDP_H 1
52
53#include "libdwP.h"
54#include "libelfP.h"
55struct ebl;
56
57/* Cached CIE representation.  */
58struct dwarf_cie
59{
60  Dwarf_Off offset;	 /* Our position, as seen in FDEs' CIE_pointer.  */
61
62  Dwarf_Word code_alignment_factor;
63  Dwarf_Sword data_alignment_factor;
64  Dwarf_Word return_address_register;
65
66  size_t fde_augmentation_data_size;
67
68  // play out to initial state
69  const uint8_t *initial_instructions;
70  const uint8_t *initial_instructions_end;
71
72  const Dwarf_Frame *initial_state;
73
74  uint8_t fde_encoding;		/* DW_EH_PE_* for addresses in FDEs.  */
75  uint8_t lsda_encoding;    /* DW_EH_PE_* for LSDA in FDE augmentation.  */
76
77  bool sized_augmentation_data;	/* Saw 'z': FDEs have self-sized data.  */
78  bool signal_frame;		/* Saw 'S': FDE is for a signal frame.  */
79};
80
81/* Cached FDE representation.  */
82struct dwarf_fde
83{
84  struct dwarf_cie *cie;
85
86  /* This FDE describes PC values in [start, end).  */
87  Dwarf_Addr start;
88  Dwarf_Addr end;
89
90  const uint8_t *instructions;
91  const uint8_t *instructions_end;
92};
93
94/* This holds everything we cache about the CFI from each ELF file's
95   .debug_frame or .eh_frame section.  */
96struct Dwarf_CFI_s
97{
98  /* Dwarf handle we came from.  If null, this is .eh_frame data.  */
99  Dwarf *dbg;
100#define CFI_IS_EH(cfi)	((cfi)->dbg == NULL)
101
102  /* Data of the .debug_frame or .eh_frame section.  */
103  Elf_Data_Scn *data;
104  const unsigned char *e_ident;	/* For EI_DATA and EI_CLASS.  */
105
106  Dwarf_Addr frame_vaddr;  /* DW_EH_PE_pcrel, address of frame section.  */
107  Dwarf_Addr textrel;		/* DW_EH_PE_textrel base address.  */
108  Dwarf_Addr datarel;		/* DW_EH_PE_datarel base address.  */
109
110  /* Location of next unread entry in the section.  */
111  Dwarf_Off next_offset;
112
113  /* Search tree for the CIEs, indexed by CIE_pointer (section offset).  */
114  void *cie_tree;
115
116  /* Search tree for the FDEs, indexed by PC address.  */
117  void *fde_tree;
118
119  /* Search tree for parsed DWARF expressions, indexed by raw pointer.  */
120  void *expr_tree;
121
122  /* Backend hook.  */
123  struct ebl *ebl;
124
125  /* Binary search table in .eh_frame_hdr section.  */
126  const uint8_t *search_table;
127  Dwarf_Addr search_table_vaddr;
128  size_t search_table_entries;
129  uint8_t search_table_encoding;
130
131  /* True if the file has a byte order different from the host.  */
132  bool other_byte_order;
133
134  /* Default rule for registers not previously mentioned
135     is same_value, not undefined.  */
136  bool default_same_value;
137};
138
139
140enum dwarf_frame_rule
141  {
142    reg_unspecified,		/* Uninitialized state.  */
143    reg_undefined,		/* DW_CFA_undefined */
144    reg_same_value,		/* DW_CFA_same_value */
145    reg_offset,			/* DW_CFA_offset_extended et al */
146    reg_val_offset,		/* DW_CFA_val_offset et al */
147    reg_register,		/* DW_CFA_register */
148    reg_expression,		/* DW_CFA_expression */
149    reg_val_expression,		/* DW_CFA_val_expression */
150  };
151
152/* This describes what we know about an individual register.  */
153struct dwarf_frame_register
154{
155  enum dwarf_frame_rule rule:3;
156
157  /* The meaning of the value bits depends on the rule:
158
159	Rule			Value
160	----			-----
161	undefined		unused
162	same_value		unused
163	offset(N)		N	(register saved at CFA + value)
164	val_offset(N)		N	(register = CFA + value)
165	register(R)		R	(register = register #value)
166	expression(E)		section offset of DW_FORM_block containing E
167					(register saved at address E computes)
168	val_expression(E)	section offset of DW_FORM_block containing E
169					(register = value E computes)
170  */
171  Dwarf_Sword value:(sizeof (Dwarf_Sword) * 8 - 3);
172};
173
174/* This holds everything we know about the state of the frame
175   at a particular PC location described by an FDE.  */
176struct Dwarf_Frame_s
177{
178  /* This frame description covers PC values in [start, end).  */
179  Dwarf_Addr start;
180  Dwarf_Addr end;
181
182  Dwarf_CFI *cache;
183
184  /* Previous state saved by DW_CFA_remember_state, or .cie->initial_state,
185     or NULL in an initial_state pseudo-frame.  */
186  Dwarf_Frame *prev;
187
188  /* The FDE that generated this frame state.  This points to its CIE,
189     which has the return_address_register and signal_frame flag.  */
190  struct dwarf_fde *fde;
191
192  /* The CFA is unknown, is R+N, or is computed by a DWARF expression.
193     A bogon in the CFI can indicate an invalid/incalculable rule.
194     We store that as cfa_invalid rather than barfing when processing it,
195     so callers can ignore the bogon unless they really need that CFA.  */
196  enum { cfa_undefined, cfa_offset, cfa_expr, cfa_invalid } cfa_rule;
197  union
198  {
199    Dwarf_Op offset;
200    Dwarf_Block expr;
201  } cfa_data;
202  /* We store an offset rule as a DW_OP_bregx operation.  */
203#define cfa_val_reg	cfa_data.offset.number
204#define cfa_val_offset	cfa_data.offset.number2
205
206  size_t nregs;
207  struct dwarf_frame_register regs[];
208};
209
210
211/* Clean up the data structure and all it points to.  */
212extern void __libdw_destroy_frame_cache (Dwarf_CFI *cache)
213  __nonnull_attribute__ (1) internal_function;
214
215/* Enter a CIE encountered while reading through for FDEs.  */
216extern void __libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset,
217				const Dwarf_CIE *info)
218  __nonnull_attribute__ (1, 3) internal_function;
219
220/* Look up a CIE_pointer for random access.  */
221extern struct dwarf_cie *__libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset)
222  __nonnull_attribute__ (1) internal_function;
223
224
225/* Look for an FDE covering the given PC address.  */
226extern struct dwarf_fde *__libdw_find_fde (Dwarf_CFI *cache,
227					   Dwarf_Addr address)
228  __nonnull_attribute__ (1) internal_function;
229
230/* Look for an FDE by its offset in the section.  */
231extern struct dwarf_fde *__libdw_fde_by_offset (Dwarf_CFI *cache,
232						Dwarf_Off offset)
233  __nonnull_attribute__ (1) internal_function;
234
235/* Process the FDE that contains the given PC address,
236   to yield the frame state when stopped there.
237   The return value is a DWARF_E_* error code.  */
238extern int __libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde,
239				     Dwarf_Addr address, Dwarf_Frame **frame)
240  __nonnull_attribute__ (1, 2, 4) internal_function;
241
242
243/* Dummy struct for memory-access.h macros.  */
244#define BYTE_ORDER_DUMMY(var, e_ident)					      \
245  const struct { bool other_byte_order; } var =				      \
246    { ((BYTE_ORDER == LITTLE_ENDIAN && e_ident[EI_DATA] == ELFDATA2MSB)       \
247       || (BYTE_ORDER == BIG_ENDIAN && e_ident[EI_DATA] == ELFDATA2LSB)) }
248
249
250INTDECL (dwarf_next_cfi)
251INTDECL (dwarf_getcfi)
252INTDECL (dwarf_getcfi_elf)
253INTDECL (dwarf_cfi_end)
254INTDECL (dwarf_cfi_addrframe)
255
256#endif	/* unwindP.h */
257