|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
|
3 |
|
4 /* libunwind - a platform-independent unwind library |
|
5 Copyright 2011 Linaro Limited |
|
6 |
|
7 This file is part of libunwind. |
|
8 |
|
9 Permission is hereby granted, free of charge, to any person obtaining |
|
10 a copy of this software and associated documentation files (the |
|
11 "Software"), to deal in the Software without restriction, including |
|
12 without limitation the rights to use, copy, modify, merge, publish, |
|
13 distribute, sublicense, and/or sell copies of the Software, and to |
|
14 permit persons to whom the Software is furnished to do so, subject to |
|
15 the following conditions: |
|
16 |
|
17 The above copyright notice and this permission notice shall be |
|
18 included in all copies or substantial portions of the Software. |
|
19 |
|
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
23 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
|
24 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
|
25 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
|
27 |
|
28 |
|
29 // Copyright (c) 2010, 2011 Google Inc. |
|
30 // All rights reserved. |
|
31 // |
|
32 // Redistribution and use in source and binary forms, with or without |
|
33 // modification, are permitted provided that the following conditions are |
|
34 // met: |
|
35 // |
|
36 // * Redistributions of source code must retain the above copyright |
|
37 // notice, this list of conditions and the following disclaimer. |
|
38 // * Redistributions in binary form must reproduce the above |
|
39 // copyright notice, this list of conditions and the following disclaimer |
|
40 // in the documentation and/or other materials provided with the |
|
41 // distribution. |
|
42 // * Neither the name of Google Inc. nor the names of its |
|
43 // contributors may be used to endorse or promote products derived from |
|
44 // this software without specific prior written permission. |
|
45 // |
|
46 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
47 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
48 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
49 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
50 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
51 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
52 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
53 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
54 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
55 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
56 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
57 |
|
58 |
|
59 // Derived from libunwind, with extensive modifications. |
|
60 // This file is derived from the following files in |
|
61 // toolkit/crashreporter/google-breakpad: |
|
62 // src/common/arm_ex_to_module.h |
|
63 // src/common/memory_range.h |
|
64 // src/common/arm_ex_reader.h |
|
65 |
|
66 #ifndef LulExidxExt_h |
|
67 #define LulExidxExt_h |
|
68 |
|
69 #include "LulMainInt.h" |
|
70 |
|
71 using lul::LExpr; |
|
72 using lul::RuleSet; |
|
73 using lul::SecMap; |
|
74 |
|
75 namespace lul { |
|
76 |
|
77 typedef enum extab_cmd { |
|
78 ARM_EXIDX_CMD_FINISH, |
|
79 ARM_EXIDX_CMD_SUB_FROM_VSP, |
|
80 ARM_EXIDX_CMD_ADD_TO_VSP, |
|
81 ARM_EXIDX_CMD_REG_POP, |
|
82 ARM_EXIDX_CMD_REG_TO_SP, |
|
83 ARM_EXIDX_CMD_VFP_POP, |
|
84 ARM_EXIDX_CMD_WREG_POP, |
|
85 ARM_EXIDX_CMD_WCGR_POP, |
|
86 ARM_EXIDX_CMD_RESERVED, |
|
87 ARM_EXIDX_CMD_REFUSED, |
|
88 } extab_cmd_t; |
|
89 |
|
90 struct exidx_entry { |
|
91 uint32_t addr; |
|
92 uint32_t data; |
|
93 }; |
|
94 |
|
95 struct extab_data { |
|
96 extab_cmd_t cmd; |
|
97 uint32_t data; |
|
98 }; |
|
99 |
|
100 enum extab_cmd_flags { |
|
101 ARM_EXIDX_VFP_SHIFT_16 = 1 << 16, |
|
102 ARM_EXIDX_VFP_FSTMD = 1 << 17, // distinguishes FSTMxxD from FSTMxxX |
|
103 }; |
|
104 |
|
105 // Receives information from arm_ex_reader::ExceptionTableInfo |
|
106 // and adds it to the SecMap object |
|
107 // This is in effect the EXIDX summariser. |
|
108 class ARMExToModule { |
|
109 public: |
|
110 ARMExToModule(SecMap* smap, void(*log)(const char*)) : smap_(smap) |
|
111 , log_(log) { } |
|
112 ~ARMExToModule() { } |
|
113 void AddStackFrame(uintptr_t addr, size_t size); |
|
114 int ImproveStackFrame(const struct extab_data* edata); |
|
115 void DeleteStackFrame(); |
|
116 void SubmitStackFrame(); |
|
117 private: |
|
118 SecMap* smap_; |
|
119 LExpr vsp_; // Always appears to be of the form "sp + offset" |
|
120 RuleSet curr_rules_; // Also holds the address range being summarised |
|
121 // debugging message sink |
|
122 void (*log_)(const char*); |
|
123 int TranslateCmd(const struct extab_data* edata, LExpr& vsp); |
|
124 }; |
|
125 |
|
126 |
|
127 // (derived from) |
|
128 // memory_range.h: Define the google_breakpad::MemoryRange class, which |
|
129 // is a lightweight wrapper with a pointer and a length to encapsulate |
|
130 // a contiguous range of memory. |
|
131 |
|
132 // A lightweight wrapper with a pointer and a length to encapsulate a |
|
133 // contiguous range of memory. It provides helper methods for checked |
|
134 // access of a subrange of the memory. Its implemementation does not |
|
135 // allocate memory or call into libc functions, and is thus safer to use |
|
136 // in a crashed environment. |
|
137 class MemoryRange { |
|
138 public: |
|
139 |
|
140 MemoryRange(const void* data, size_t length) { |
|
141 Set(data, length); |
|
142 } |
|
143 |
|
144 // Sets this memory range to point to |data| and its length to |length|. |
|
145 void Set(const void* data, size_t length) { |
|
146 data_ = reinterpret_cast<const uint8_t*>(data); |
|
147 // Always set |length_| to zero if |data_| is NULL. |
|
148 length_ = data ? length : 0; |
|
149 } |
|
150 |
|
151 // Returns true if this range covers a subrange of |sub_length| bytes |
|
152 // at |sub_offset| bytes of this memory range, or false otherwise. |
|
153 bool Covers(size_t sub_offset, size_t sub_length) const { |
|
154 // The following checks verify that: |
|
155 // 1. sub_offset is within [ 0 .. length_ - 1 ] |
|
156 // 2. sub_offset + sub_length is within |
|
157 // [ sub_offset .. length_ ] |
|
158 return sub_offset < length_ && |
|
159 sub_offset + sub_length >= sub_offset && |
|
160 sub_offset + sub_length <= length_; |
|
161 } |
|
162 |
|
163 // Returns a pointer to the beginning of this memory range. |
|
164 const uint8_t* data() const { return data_; } |
|
165 |
|
166 // Returns the length, in bytes, of this memory range. |
|
167 size_t length() const { return length_; } |
|
168 |
|
169 private: |
|
170 // Pointer to the beginning of this memory range. |
|
171 const uint8_t* data_; |
|
172 |
|
173 // Length, in bytes, of this memory range. |
|
174 size_t length_; |
|
175 }; |
|
176 |
|
177 |
|
178 // This class is a reader for ARM unwind information |
|
179 // from .ARM.exidx and .ARM.extab sections. |
|
180 class ExceptionTableInfo { |
|
181 public: |
|
182 ExceptionTableInfo(const char* exidx, size_t exidx_size, |
|
183 const char* extab, size_t extab_size, |
|
184 uint32_t text_last_svma, |
|
185 lul::ARMExToModule* handler, |
|
186 const char* mapping_addr, |
|
187 uint32_t loading_addr, |
|
188 uintptr_t text_bias, |
|
189 void (*log)(const char*)) |
|
190 : mr_exidx_(lul::MemoryRange(exidx, exidx_size)), |
|
191 mr_extab_(lul::MemoryRange(extab, extab_size)), |
|
192 text_last_svma_(text_last_svma), |
|
193 handler_(handler), mapping_addr_(mapping_addr), |
|
194 loading_addr_(loading_addr), |
|
195 text_bias_(text_bias), |
|
196 log_(log) { } |
|
197 |
|
198 ~ExceptionTableInfo() { } |
|
199 |
|
200 // Parses the entries in .ARM.exidx and possibly |
|
201 // in .ARM.extab tables, reports what we find to |
|
202 // arm_ex_to_module::ARMExToModule. |
|
203 void Start(); |
|
204 |
|
205 private: |
|
206 lul::MemoryRange mr_exidx_; |
|
207 lul::MemoryRange mr_extab_; |
|
208 uint32_t text_last_svma_; |
|
209 lul::ARMExToModule* handler_; |
|
210 const char* mapping_addr_; |
|
211 uint32_t loading_addr_; |
|
212 uintptr_t text_bias_; |
|
213 // debugging message sink |
|
214 void (*log_)(const char*); |
|
215 enum ExExtractResult { |
|
216 ExSuccess, // success |
|
217 ExInBufOverflow, // out-of-range while reading .exidx |
|
218 ExOutBufOverflow, // output buffer is too small |
|
219 ExCantUnwind, // this function is marked CANT_UNWIND |
|
220 ExCantRepresent, // entry valid, but we can't represent it |
|
221 ExInvalid // entry is invalid |
|
222 }; |
|
223 ExExtractResult |
|
224 ExtabEntryExtract(const struct lul::exidx_entry* entry, |
|
225 uint8_t* buf, size_t buf_size, |
|
226 /*OUT*/size_t* buf_used); |
|
227 |
|
228 int ExtabEntryDecode(const uint8_t* buf, size_t buf_size); |
|
229 }; |
|
230 |
|
231 } // namespace lul |
|
232 |
|
233 #endif // LulExidxExt_h |