eh_frame.cpp
Go to the documentation of this file.
1 //
2 // Bareflank Unwind Library
3 //
4 // Copyright (C) 2015 Assured Information Security, Inc.
5 // Author: Rian Quinn <quinnr@ainfosec.com>
6 // Author: Brendan Kerrigan <kerriganb@ainfosec.com>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 
22 #include <log.h>
23 #include <misc.h>
24 #include <abort.h>
25 #include <dwarf4.h>
26 #include <eh_frame.h>
27 
28 // -----------------------------------------------------------------------------
29 // Helpers
30 // -----------------------------------------------------------------------------
31 
32 uint64_t
33 decode_pointer(char **addr, uint64_t encoding)
34 {
35  uint64_t result = 0;
36 
37  if (encoding == DW_EH_PE_omit)
38  return 0;
39 
40  // The following are defined in the DWARF Exception Header Encodings
41  // section 10.5.1. For some reason, GCC adds a 0x80 to the upper 4 bits
42  // that are not documented in the LSB. Thefore, only 3 of the upper 4 bits
43  // are actually used.
44 
45  switch (encoding & 0x70)
46  {
47  case DW_EH_PE_absptr:
48  break;
49 
50  case DW_EH_PE_pcrel:
51  result += reinterpret_cast<uint64_t>(*addr);
52  break;
53 
54  case DW_EH_PE_textrel:
55  ABORT("DW_EH_PE_textrel pointer encodings not supported");
56  break;
57 
58  case DW_EH_PE_datarel:
59  ABORT("DW_EH_PE_datarel pointer encodings not supported");
60  break;
61 
62  case DW_EH_PE_funcrel:
63  ABORT("DW_EH_PE_funcrel pointer encodings not supported");
64  break;
65 
66  case DW_EH_PE_aligned:
67  ABORT("DW_EH_PE_aligned pointer encodings not supported");
68  break;
69 
70  default:
71  ABORT("unknown upper pointer encoding bits");
72  }
73 
74  switch (encoding & 0x0F)
75  {
76  case DW_EH_PE_absptr:
77  result += *reinterpret_cast<uintptr_t *>(*addr);
78  *addr += sizeof(void *);
79  break;
80 
81  case DW_EH_PE_uleb128:
82  result += dwarf4::decode_uleb128(addr);
83  break;
84 
85  case DW_EH_PE_udata2:
86  result += *reinterpret_cast<uint16_t *>(*addr);
87  *addr += sizeof(uint16_t);
88  break;
89 
90  case DW_EH_PE_udata4:
91  result += *reinterpret_cast<uint32_t *>(*addr);
92  *addr += sizeof(uint32_t);
93  break;
94 
95  case DW_EH_PE_udata8:
96  result += *reinterpret_cast<uint64_t *>(*addr);
97  *addr += sizeof(uint64_t);
98  break;
99 
100  case DW_EH_PE_sleb128:
101  result = add_offset(result, dwarf4::decode_sleb128(addr));
102  break;
103 
104  case DW_EH_PE_sdata2:
105  result = add_offset(result, *reinterpret_cast<int16_t *>(*addr));
106  *addr += sizeof(int16_t);
107  break;
108 
109  case DW_EH_PE_sdata4:
110  result = add_offset(result, *reinterpret_cast<int32_t *>(*addr));
111  *addr += sizeof(int32_t);
112  break;
113 
114  case DW_EH_PE_sdata8:
115  result = add_offset(result, *reinterpret_cast<int64_t *>(*addr));
116  *addr += sizeof(int64_t);
117  break;
118 
119  default:
120  ABORT("unknown lower pointer encoding bits");
121  }
122 
123  return result;
124 }
125 
126 // -----------------------------------------------------------------------------
127 // CIE / FDE Common
128 // -----------------------------------------------------------------------------
129 
131  m_is_cie(false),
132  m_entry_start(nullptr),
133  m_entry_end(nullptr),
134  m_payload_start(nullptr),
135  m_payload_end(nullptr),
136  m_eh_frame{nullptr, 0}
137 {
138 }
139 
141  m_is_cie(false),
142  m_entry_start(nullptr),
143  m_entry_end(nullptr),
144  m_payload_start(nullptr),
145  m_payload_end(nullptr),
146  m_eh_frame(eh_frame)
147 {
148 }
149 
151 {
152  if (m_entry_start == nullptr)
153  return *this;
154 
155  if (m_entry_end + 4 < reinterpret_cast<char *>(m_eh_frame.addr) + m_eh_frame.size)
157  else
158  parse(nullptr);
159 
160  return *this;
161 }
162 
163 void
165 {
166  auto len = 0ULL;
167 
168  if ((m_entry_start = addr) == nullptr)
169  goto failure;
170 
172  goto failure;
173 
174  if (*reinterpret_cast<uint32_t *>(m_entry_start) != 0xFFFFFFFF)
175  {
176  len = *reinterpret_cast<uint32_t *>(m_entry_start + 0);
178  }
179  else
180  {
181  len = *reinterpret_cast<uint64_t *>(m_entry_start + 4);
183  }
184 
185  if (len == 0)
186  goto failure;
187 
190 
191  if (m_entry_end > reinterpret_cast<char *>(m_eh_frame.addr) + m_eh_frame.size)
192  goto failure;
193 
194  m_is_cie = (*reinterpret_cast<uint32_t *>(m_payload_start) == 0);
195  return;
196 
197 failure:
198 
199  m_is_cie = false;
200  m_entry_start = nullptr;
201  m_entry_end = nullptr;
202  m_payload_start = nullptr;
203  m_payload_end = nullptr;
204 }
205 
206 // -----------------------------------------------------------------------------
207 // Common Information Entry Record (CIE)
208 // -----------------------------------------------------------------------------
209 
211  m_augmentation_string(nullptr),
212  m_code_alignment(0),
213  m_data_alignment(0),
214  m_return_address_reg(0),
215  m_pointer_encoding(0),
216  m_lsda_encoding(0),
217  m_personality_encoding(0),
218  m_personality_function(0),
219  m_initial_instructions(nullptr)
220 {
221 }
222 
224  common_entry(eh_frame),
225 
226  m_augmentation_string(nullptr),
227  m_code_alignment(0),
228  m_data_alignment(0),
229  m_return_address_reg(0),
230  m_pointer_encoding(0),
231  m_lsda_encoding(0),
232  m_personality_encoding(0),
233  m_personality_function(0),
234  m_initial_instructions(nullptr)
235 {
236  non_virtual_parse(reinterpret_cast<char *>(eh_frame.addr));
237 }
238 
240  common_entry(eh_frame),
241 
242  m_augmentation_string(nullptr),
243  m_code_alignment(0),
244  m_data_alignment(0),
245  m_return_address_reg(0),
246  m_pointer_encoding(0),
247  m_lsda_encoding(0),
248  m_personality_encoding(0),
249  m_personality_function(0),
250  m_initial_instructions(nullptr)
251 {
252  non_virtual_parse(reinterpret_cast<char *>(addr));
253 }
254 
255 void
257 {
258  non_virtual_parse(addr);
259 }
260 
261 void
263 {
265 
266  if (!*this)
267  return;
268 
269  if (!is_cie())
270  return;
271 
272  auto p = payload_start();
273 
274  p += sizeof(uint32_t);
275  p += sizeof(uint8_t);
276 
278 
279  while (*p++ != 0);
280 
284 
285  if (m_augmentation_string[0] == 'z')
286  {
287  auto len = dwarf4::decode_uleb128(&p);
288 
289  for (auto i = 1U; m_augmentation_string[i] != 0 && i <= len; i++)
290  {
291  switch (m_augmentation_string[i])
292  {
293  case 'L':
294  m_lsda_encoding = *reinterpret_cast<uint8_t *>(p++);
295  break;
296 
297  case 'P':
298  m_personality_encoding = *reinterpret_cast<uint8_t *>(p++);
301  break;
302 
303  case 'R':
304  m_pointer_encoding = *reinterpret_cast<uint8_t *>(p++);
305  break;
306 
307  default:
308  ABORT("unknown augmentation string character");
309  }
310  }
311  }
312 
314 }
315 
316 // -----------------------------------------------------------------------------
317 // Frame Description Entry Record (FDE)
318 // -----------------------------------------------------------------------------
319 
321  m_pc_begin(0),
322  m_pc_range(0),
323  m_lsda(0),
324  m_instructions(nullptr)
325 {
326 }
327 
329  common_entry(eh_frame),
330 
331  m_pc_begin(0),
332  m_pc_range(0),
333  m_lsda(0),
334  m_instructions(nullptr)
335 {
336  non_virtual_parse(reinterpret_cast<char *>(eh_frame.addr));
337 }
338 
340  common_entry(eh_frame),
341 
342  m_pc_begin(0),
343  m_pc_range(0),
344  m_lsda(0),
345  m_instructions(nullptr)
346 {
347  non_virtual_parse(reinterpret_cast<char *>(addr));
348 }
349 
350 void
352 {
353  non_virtual_parse(addr);
354 }
355 
356 void
358 {
360 
361  if (!*this)
362  return;
363 
364  if (!is_fde())
365  return;
366 
367  auto p = payload_start();
368  auto p_cie = reinterpret_cast<char *>(reinterpret_cast<uint64_t>(p) - *reinterpret_cast<uint32_t *>(p));
369 
370  m_cie = ci_entry(eh_frame(), p_cie);
371  p += sizeof(uint32_t);
372 
373  m_pc_begin = decode_pointer(&p, m_cie.pointer_encoding());
374  m_pc_range = decode_pointer(&p, m_cie.pointer_encoding() & 0xF);
375 
376  if (m_cie.augmentation_string(0) == 'z')
377  {
378  auto len = dwarf4::decode_uleb128(&p);
379 
380  for (auto i = 1U; m_cie.augmentation_string(i) != 0 && i <= len; i++)
381  {
382  switch (m_cie.augmentation_string(i))
383  {
384  case 'L':
385  m_lsda = decode_pointer(&p, m_cie.lsda_encoding());
386  break;
387 
388  case 'P':
389  break;
390 
391  case 'R':
392  break;
393 
394  default:
395  ABORT("unknown augmentation string character");
396  }
397  }
398  }
399 
400  m_instructions = p;
401 }
402 
403 // -----------------------------------------------------------------------------
404 // Exception Handler Framework (eh_frame)
405 // -----------------------------------------------------------------------------
406 
407 fd_entry
409 {
410  auto eh_frame_list = get_eh_frame_list();
411 
412  for (auto m = 0U; m < MAX_NUM_MODULES; m++)
413  {
414  for (auto fde = fd_entry(eh_frame_list[m]); fde; ++fde)
415  {
416  if (fde.is_cie())
417  continue;
418 
419  if (fde.is_in_range(state->get_ip()))
420  return fde;
421  }
422  }
423 
424  log("ERROR: An exception was thrown, but the unwinder was unable to "
425  "locate a stack frame for RIP = %p. Possible reasons include\n",
426  reinterpret_cast<void *>(state->get_ip()));
427  log(" - Throwing from a destructor\n");
428  log(" - Throwing from a function labeled noexcept\n");
429  log(" - Bug in the unwinder\n");
430  log("\n\nAborting!!!\n\n")
431 
432  state->dump();
433 
434  return fd_entry();
435 }
void parse(char *addr) override
Definition: eh_frame.cpp:351
char augmentation_string(uint64_t index) const
Definition: eh_frame.h:415
void non_virtual_parse(char *addr)
Definition: eh_frame.cpp:164
#define DW_EH_PE_textrel
Definition: eh_frame.h:110
char * m_entry_end
Definition: eh_frame.h:334
uint64_t m_personality_function
Definition: eh_frame.h:495
#define DW_EH_PE_aligned
Definition: eh_frame.h:113
uint64_t m_return_address_reg
Definition: eh_frame.h:491
#define DW_EH_PE_funcrel
Definition: eh_frame.h:112
static uint64_t decode_uleb128(char **addr)
Definition: dwarf4.cpp:1644
uint64_t pointer_encoding() const
Definition: eh_frame.h:449
char * m_payload_start
Definition: eh_frame.h:336
#define DW_EH_PE_pcrel
Definition: eh_frame.h:109
int64_t m_data_alignment
Definition: eh_frame.h:490
uint64_t m_pointer_encoding
Definition: eh_frame.h:492
struct eh_frame_t * get_eh_frame_list() noexcept
Definition: test.cpp:75
#define ABORT(a)
Definition: abort.h:51
bool m_is_cie
Definition: eh_frame.h:331
Definition: eh_frame.h:360
void * addr
Definition: eh_frame_list.h:45
#define DW_EH_PE_datarel
Definition: eh_frame.h:111
#define DW_EH_PE_sdata4
Definition: eh_frame.h:105
static int64_t decode_sleb128(char **addr)
Definition: dwarf4.cpp:1622
#define DW_EH_PE_sdata8
Definition: eh_frame.h:106
virtual void dump() const
Definition: registers.h:154
uint64_t decode_pointer(char **addr, uint64_t encoding)
Definition: eh_frame.cpp:33
char * m_initial_instructions
Definition: eh_frame.h:496
void parse(char *addr) override
Definition: eh_frame.cpp:256
void non_virtual_parse(char *addr)
Definition: eh_frame.cpp:262
#define DW_EH_PE_udata4
Definition: eh_frame.h:101
uint64_t add_offset(uint64_t value, int64_t offset)
Definition: misc.h:32
#define MAX_NUM_MODULES
Definition: constants.h:177
#define DW_EH_PE_udata8
Definition: eh_frame.h:102
bool is_fde() const
Definition: eh_frame.h:285
constexpr const auto addr
Definition: cpuid_x64.h:80
static fd_entry find_fde(register_state *state)
Definition: eh_frame.cpp:408
char * payload_start() const
Definition: eh_frame.h:307
uint64_t m_code_alignment
Definition: eh_frame.h:489
#define DW_EH_PE_uleb128
Definition: eh_frame.h:99
ci_entry()
Definition: eh_frame.cpp:210
#define DW_EH_PE_udata2
Definition: eh_frame.h:100
bool is_cie() const
Definition: eh_frame.h:278
void non_virtual_parse(char *addr)
Definition: eh_frame.cpp:357
#define DW_EH_PE_omit
Definition: eh_frame.h:116
fd_entry()
Definition: eh_frame.cpp:320
common_entry & operator++()
Definition: eh_frame.cpp:150
virtual void parse(char *addr)=0
common_entry()
Definition: eh_frame.cpp:130
eh_frame_t m_eh_frame
Definition: eh_frame.h:339
const char * m_augmentation_string
Definition: eh_frame.h:488
#define DW_EH_PE_sleb128
Definition: eh_frame.h:103
char * m_payload_end
Definition: eh_frame.h:337
uint64_t size
Definition: eh_frame_list.h:46
Definition: eh_frame.h:219
#define log(...)
Definition: log.h:32
Definition: eh_frame.h:510
virtual uint64_t get_ip() const
Definition: registers.h:75
char * m_entry_start
Definition: eh_frame.h:333
#define DW_EH_PE_sdata2
Definition: eh_frame.h:104
eh_frame_t eh_frame() const
Definition: eh_frame.h:323
uint64_t lsda_encoding() const
Definition: eh_frame.h:456
uint64_t m_personality_encoding
Definition: eh_frame.h:494
uint64_t m_lsda_encoding
Definition: eh_frame.h:493
#define DW_EH_PE_absptr
Definition: eh_frame.h:98