aboutsummaryrefslogtreecommitdiff
path: root/gas/config/obj-coff-seh.h
blob: 42b00f56258bcff6e68b6820754cfefb8f034bea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/* Short overview:
  There are at the moment three different function entry formats preset.
  The first is the MIPS one. The second version
  is for ARM, PPC, SH3, and SH4 mainly for Windows CE.
  The third is the IA64 and x64 version. Note, the IA64 isn't implemented yet,
  but to find information about it, please see specification about IA64 on
  http://download.intel.com/design/Itanium/Downloads/245358.pdf file.

  The first version has just entries in the pdata section: BeginAddress,
  EndAddress, ExceptionHandler, HandlerData, and PrologueEndAddress. Each
  value is a pointer to the corresponding data and has size of 4 bytes.

  The second variant has the following entries in the pdata section.
  BeginAddress, PrologueLength (8 bits), EndAddress (22 bits),
  Use-32-bit-instruction (1 bit), and Exception-Handler-Exists (1 bit).
  If the FunctionLength is zero, or the Exception-Handler-Exists bit
  is true, a PDATA_EH block is placed directly before function entry.

  The third version has a function entry block of BeginAddress (RVA),
  EndAddress (RVA), and UnwindData (RVA). The description of the
  prologue, excepetion-handler, and additional SEH data is stored
  within the UNWIND_DATA field in the xdata section.

  The pseudos:
  .seh_proc <fct_name>
  .seh_endprologue
  .seh_handler <handler>[,<handler-data>]]
  .seh_eh
  .seh_32/.seh_no32
  .seh_endproc
  .seh_setframe <reg>,<offset>
  .seh_stackalloc
  .seh_pushreg
  .seh_savereg
  .seh_savemm
  .seh_savexmm
  .seh_pushframe
  .seh_scope
  */

/* architecture specific pdata/xdata handling.  */
#define SEH_CMDS \
        {"seh_proc", obj_coff_seh_proc, 0}, \
        {"seh_endproc", obj_coff_seh_endproc, 0}, \
        {"seh_pushreg", obj_coff_seh_push, 0}, \
        {"seh_savereg", obj_coff_seh_save, 0}, \
        {"seh_savemm", obj_coff_seh_save, 1}, \
        {"seh_savexmm", obj_coff_seh_save, 2}, \
        {"seh_pushframe", obj_coff_seh_push, 1}, \
        {"seh_endprologue", obj_coff_seh_endprologue, 0}, \
        {"seh_setframe", obj_coff_seh_setframe, 0}, \
        {"seh_stackalloc", obj_coff_seh_stack_alloc, 0}, \
	{"seh_handler", obj_coff_seh_handler, 0}, \
	{"seh_eh", obj_coff_seh_eh, 0}, \
	{"seh_32", obj_coff_seh_32, 1}, \
	{"seh_no32", obj_coff_seh_32, 0}, \
	{"seh_scope", obj_coff_seh_scope, 0},

/* Type definitions.  */

typedef struct seh_prologue_element
{
  symbolS *pc_addr;
  char *pc_symbol;
  int kind;
  int reg;
  bfd_vma offset;
} seh_prologue_element;

typedef struct seh_scope_elem {
  char *begin_addr;
  char *end_addr;
  char *handler_addr;
  char *jump_addr;
} seh_scope_elem;

typedef struct seh_context
{
  struct seh_context *next;
  /* Was record alread processed.  */
  int done;
  /* Function name.  */
  char *func_name;
  /* BeginAddress.  */
  char *start_symbol;
  symbolS *start_addr;
  bfd_vma start_offset;
  /* EndAddress.  */
  char *end_symbol;
  symbolS *end_addr;
  bfd_vma end_offset;
  /* PrologueEnd.  */
  char *endprologue_symbol;
  symbolS *endprologue_addr;
  bfd_vma endprologue_offset;
  /* ExceptionHandler.  */
  char *handler_name;
  /* ExceptionHandlerData.  */
  char *handler_data_name;
  int handler_written;
  /* WinCE specific data.  */
  int use_instruction_32;

  /* the bfd to store data within.  */
  bfd *abfd;
  /* the current section to generate data within.  */
  asection *section;
  /* Relocations for section.  */
  unsigned int count_reloc;
  /* Symbols within section.  */
  unsigned int count_syms;
  /* Iterator for text lable generation.  */
  unsigned int tlbl_count;
  /* Iterator for xdata lable generation.  */
  unsigned int xlbl_count;
  /* The name of the first xdata label.  */
  char *xdata_first;
  /* FIelds used for x64 generation of chained information.  */
  char **xdata_names;
  char **xdata_pcsyms;
  int *xdata_elm_start;
  /* Size and offset within current generated xdata section.  */
  size_t xdata_sz;
  size_t xdata_offset;
  /* x64 framereg and frame offset information.  */
  int framereg;
  bfd_vma frameoff;
  /* Information about x64 specific unwind data fields.  */
  size_t elems_count;
  size_t elems_max;
  seh_prologue_element *elems;
  size_t scope_max;
  size_t scope_count;
  seh_scope_elem *scopes;
} seh_context;

typedef enum seh_kind {
  seh_kind_unknown = 0,
  seh_kind_mips = 1,  /* Used for MIPS and x86 pdata generation.  */
  seh_kind_arm = 2,   /* Used for ARM, PPC, SH3, and SH4 pdata (PDATA_EH) generation.  */
  seh_kind_x64 = 3    /* Used for IA64 and x64 pdata/xdata generation.  */
} seh_kind;

/* Forward declarations.  */
static void obj_coff_seh_stack_alloc (int);
static void obj_coff_seh_setframe (int);
static void obj_coff_seh_endprologue (int);
static void obj_coff_seh_save  (int);
static void obj_coff_seh_push  (int);
static void obj_coff_seh_endproc  (int);
static void obj_coff_seh_eh (int);
static void obj_coff_seh_32 (int);
static void obj_coff_seh_proc  (int);
static void obj_coff_seh_handler (int);
static void obj_coff_seh_scope (int);
static int seh_read_offset (const char *, bfd_vma *);
static int seh_x64_read_reg (const char *, int, int *);
static void seh_x64_make_prologue_element (int, int, bfd_vma);
static void make_function_entry_pdata (seh_context *c);

#define UNDSEC (asection *) &bfd_und_section