1// Copyright (C) 2012 The Android Open Source Project
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
7// 1. Redistributions of source code must retain the above copyright
8//    notice, this list of conditions and the following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright
10//    notice, this list of conditions and the following disclaimer in the
11//    documentation and/or other materials provided with the distribution.
12// 3. Neither the name of the project nor the names of its contributors
13//    may be used to endorse or promote products derived from this software
14//    without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19// ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26// SUCH DAMAGE.
27//===----------------------------------------------------------------------===//
28//
29//                     The LLVM Compiler Infrastructure
30//
31// This file is dual licensed under the MIT and the University of Illinois Open
32// Source Licenses. See LICENSE.TXT for details.
33//
34//
35//  This file implements the "Exception Handling APIs"
36//  http://www.codesourcery.com/public/cxx-abi/abi-eh.html
37//  http://www.intel.com/design/itanium/downloads/245358.htm
38//
39//===----------------------------------------------------------------------===//
40
41#include <cstdlib>
42#include <endian.h>
43#include "dwarf_helper.h"
44
45#if !defined(__BYTE_ORDER) || \
46    !defined(__LITTLE_ENDIAN) || !defined(__BIG_ENDIAN)
47#error "Endianness testing macros are not defined"
48#endif
49
50#if __BYTE_ORDER != __LITTLE_ENDIAN && __BYTE_ORDER != __BIG_ENDIAN
51#error "Unsupported endianness"
52#endif
53
54namespace __cxxabiv1 {
55
56  uintptr_t readULEB128(const uint8_t** data) {
57    uintptr_t result = 0;
58    uintptr_t shift = 0;
59    unsigned char byte;
60    const uint8_t *p = *data;
61    do {
62      byte = *p++;
63      result |= static_cast<uintptr_t>(byte & 0x7F) << shift;
64      shift += 7;
65    } while (byte & 0x80);
66    *data = p;
67    return result;
68  }
69
70  intptr_t readSLEB128(const uint8_t** data) {
71    uintptr_t result = 0;
72    uintptr_t shift = 0;
73    unsigned char byte;
74    const uint8_t *p = *data;
75    do {
76      byte = *p++;
77      result |= static_cast<uintptr_t>(byte & 0x7F) << shift;
78      shift += 7;
79    } while (byte & 0x80);
80    *data = p;
81    if ((byte & 0x40) && (shift < (sizeof(result) << 3))) {
82      result |= static_cast<uintptr_t>(~0) << shift;
83    }
84    return static_cast<intptr_t>(result);
85  }
86
87  static inline uint16_t readUData2(const uint8_t* data) {
88#if __BYTE_ORDER == __LITTLE_ENDIAN
89    return ((static_cast<uint16_t>(data[0])) |
90            (static_cast<uint16_t>(data[1]) << 8));
91#elif __BYTE_ORDER == __BIG_ENDIAN
92    return ((static_cast<uint16_t>(data[0]) << 8) |
93            (static_cast<uint16_t>(data[1])));
94#endif
95  }
96
97  static inline uint32_t readUData4(const uint8_t* data) {
98#if __BYTE_ORDER == __LITTLE_ENDIAN
99    return ((static_cast<uint32_t>(data[0])) |
100            (static_cast<uint32_t>(data[1]) << 8) |
101            (static_cast<uint32_t>(data[2]) << 16) |
102            (static_cast<uint32_t>(data[3]) << 24));
103#elif __BYTE_ORDER == __BIG_ENDIAN
104    return ((static_cast<uint32_t>(data[0]) << 24) |
105            (static_cast<uint32_t>(data[1]) << 16) |
106            (static_cast<uint32_t>(data[2]) << 8) |
107            (static_cast<uint32_t>(data[3])));
108#endif
109  }
110
111  static inline uint64_t readUData8(const uint8_t* data) {
112#if __BYTE_ORDER == __LITTLE_ENDIAN
113    return ((static_cast<uint64_t>(data[0])) |
114            (static_cast<uint64_t>(data[1]) << 8) |
115            (static_cast<uint64_t>(data[2]) << 16) |
116            (static_cast<uint64_t>(data[3]) << 24) |
117            (static_cast<uint64_t>(data[4]) << 32) |
118            (static_cast<uint64_t>(data[5]) << 40) |
119            (static_cast<uint64_t>(data[6]) << 48) |
120            (static_cast<uint64_t>(data[7]) << 56));
121#elif __BYTE_ORDER == __BIG_ENDIAN
122    return ((static_cast<uint64_t>(data[0]) << 56) |
123            (static_cast<uint64_t>(data[1]) << 48) |
124            (static_cast<uint64_t>(data[2]) << 40) |
125            (static_cast<uint64_t>(data[3]) << 32) |
126            (static_cast<uint64_t>(data[4]) << 24) |
127            (static_cast<uint64_t>(data[5]) << 16) |
128            (static_cast<uint64_t>(data[6]) << 8) |
129            (static_cast<uint64_t>(data[7])));
130#endif
131  }
132
133  static inline uintptr_t readAbsPtr(const uint8_t* data) {
134    if (sizeof(uintptr_t) == 4) {
135      return static_cast<uintptr_t>(readUData4(data));
136    } else if (sizeof(uintptr_t) == 8) {
137      return static_cast<uintptr_t>(readUData8(data));
138    } else {
139      abort();
140    }
141  }
142
143  uintptr_t readEncodedPointer(const uint8_t** data,
144                               uint8_t encoding) {
145    uintptr_t result = 0;
146    if (encoding == DW_EH_PE_omit) {
147      return result;
148    }
149    const uint8_t* p = *data;
150
151    switch (encoding & 0x0F) {
152    default:
153      abort();
154      break;
155    case DW_EH_PE_absptr:
156      result = readAbsPtr(p);
157      p += sizeof(uintptr_t);
158      break;
159    case DW_EH_PE_uleb128:
160      result = readULEB128(&p);
161      break;
162    case DW_EH_PE_sleb128:
163      result = static_cast<uintptr_t>(readSLEB128(&p));
164      break;
165    case DW_EH_PE_udata2:
166      result = readUData2(p);
167      p += sizeof(uint16_t);
168      break;
169    case DW_EH_PE_udata4:
170      result = readUData4(p);
171      p += sizeof(uint32_t);
172      break;
173    case DW_EH_PE_udata8:
174      result = static_cast<uintptr_t>(readUData8(p));
175      p += sizeof(uint64_t);
176      break;
177    case DW_EH_PE_sdata2:
178      result = static_cast<uintptr_t>(static_cast<int16_t>(readUData2(p)));
179      p += sizeof(int16_t);
180      break;
181    case DW_EH_PE_sdata4:
182      result = static_cast<uintptr_t>(static_cast<int32_t>(readUData4(p)));
183      p += sizeof(int32_t);
184      break;
185    case DW_EH_PE_sdata8:
186      result = static_cast<uintptr_t>(static_cast<int64_t>(readUData8(p)));
187      p += sizeof(int64_t);
188      break;
189    }
190
191    switch (encoding & 0x70) {
192    default:
193      abort();
194      break;
195    case DW_EH_PE_absptr:
196      break;
197    case DW_EH_PE_pcrel:
198      if (result) {
199        result += (uintptr_t)(*data);
200      }
201      break;
202    }
203
204    // finally, apply indirection
205    if (result && (encoding & DW_EH_PE_indirect)) {
206      result = *(reinterpret_cast<uintptr_t*>(result));
207    }
208    *data = p;
209    return result;
210  }
211
212} // namespace __cxxabiv1
213