|
1 |
|
2 /* libunwind - a platform-independent unwind library |
|
3 Copyright 2011 Linaro Limited |
|
4 |
|
5 This file is part of libunwind. |
|
6 |
|
7 Permission is hereby granted, free of charge, to any person obtaining |
|
8 a copy of this software and associated documentation files (the |
|
9 "Software"), to deal in the Software without restriction, including |
|
10 without limitation the rights to use, copy, modify, merge, publish, |
|
11 distribute, sublicense, and/or sell copies of the Software, and to |
|
12 permit persons to whom the Software is furnished to do so, subject to |
|
13 the following conditions: |
|
14 |
|
15 The above copyright notice and this permission notice shall be |
|
16 included in all copies or substantial portions of the Software. |
|
17 |
|
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
|
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
|
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
|
25 |
|
26 // Copyright (c) 2010 Google Inc. |
|
27 // All rights reserved. |
|
28 // |
|
29 // Redistribution and use in source and binary forms, with or without |
|
30 // modification, are permitted provided that the following conditions are |
|
31 // met: |
|
32 // |
|
33 // * Redistributions of source code must retain the above copyright |
|
34 // notice, this list of conditions and the following disclaimer. |
|
35 // * Redistributions in binary form must reproduce the above |
|
36 // copyright notice, this list of conditions and the following disclaimer |
|
37 // in the documentation and/or other materials provided with the |
|
38 // distribution. |
|
39 // * Neither the name of Google Inc. nor the names of its |
|
40 // contributors may be used to endorse or promote products derived from |
|
41 // this software without specific prior written permission. |
|
42 // |
|
43 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
44 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
45 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
46 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
47 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
48 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
49 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
50 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
51 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
52 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
53 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
54 |
|
55 |
|
56 // Derived from libunwind, with extensive modifications. |
|
57 |
|
58 #include "common/unique_string.h" |
|
59 #include "common/arm_ex_to_module.h" |
|
60 |
|
61 #include <stdio.h> |
|
62 #include <assert.h> |
|
63 |
|
64 // For big-picture comments on how the EXIDX reader works, |
|
65 // see arm_ex_reader.cc. |
|
66 |
|
67 #define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f) |
|
68 #define ARM_EXBUF_COUNT(x) ((x) & 0x0f) |
|
69 #define ARM_EXBUF_END(x) (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x)) |
|
70 |
|
71 using google_breakpad::ustr__pc; |
|
72 using google_breakpad::ustr__lr; |
|
73 using google_breakpad::ustr__sp; |
|
74 using google_breakpad::ustr__ZDra; |
|
75 using google_breakpad::ustr__ZDcfa; |
|
76 using google_breakpad::Module; |
|
77 using google_breakpad::ToUniqueString; |
|
78 using google_breakpad::UniqueString; |
|
79 |
|
80 namespace arm_ex_to_module { |
|
81 |
|
82 // Translate command from extab_data to command for Module. |
|
83 int ARMExToModule::TranslateCmd(const struct extab_data* edata, |
|
84 Module::StackFrameEntry* entry, |
|
85 Module::Expr& vsp) { |
|
86 int ret = 0; |
|
87 switch (edata->cmd) { |
|
88 case ARM_EXIDX_CMD_FINISH: |
|
89 /* Copy LR to PC if there isn't currently a rule for PC in force. */ |
|
90 if (entry->initial_rules.find(ustr__pc()) |
|
91 == entry->initial_rules.end()) { |
|
92 if (entry->initial_rules.find(ustr__lr()) |
|
93 == entry->initial_rules.end()) { |
|
94 entry->initial_rules[ustr__pc()] = Module::Expr(ustr__lr(), |
|
95 0, false); // "lr" |
|
96 } else { |
|
97 entry->initial_rules[ustr__pc()] = entry->initial_rules[ustr__lr()]; |
|
98 } |
|
99 } |
|
100 break; |
|
101 case ARM_EXIDX_CMD_SUB_FROM_VSP: |
|
102 vsp = vsp.add_delta(- static_cast<long>(edata->data)); |
|
103 break; |
|
104 case ARM_EXIDX_CMD_ADD_TO_VSP: |
|
105 vsp = vsp.add_delta(static_cast<long>(edata->data)); |
|
106 break; |
|
107 case ARM_EXIDX_CMD_REG_POP: |
|
108 for (unsigned int i = 0; i < 16; i++) { |
|
109 if (edata->data & (1 << i)) { |
|
110 entry->initial_rules[ToUniqueString(regnames[i])] = vsp.deref(); |
|
111 vsp = vsp.add_delta(4); |
|
112 } |
|
113 } |
|
114 /* Set cfa in case the SP got popped. */ |
|
115 if (edata->data & (1 << 13)) { |
|
116 vsp = entry->initial_rules[ustr__sp()]; |
|
117 } |
|
118 break; |
|
119 case ARM_EXIDX_CMD_REG_TO_SP: { |
|
120 assert (edata->data < 16); |
|
121 const char* const regname = regnames[edata->data]; |
|
122 const UniqueString* regname_us = ToUniqueString(regname); |
|
123 if (entry->initial_rules.find(regname_us) == entry->initial_rules.end()) { |
|
124 entry->initial_rules[ustr__sp()] = Module::Expr(regname_us, |
|
125 0, false); // "regname" |
|
126 } else { |
|
127 entry->initial_rules[ustr__sp()] = entry->initial_rules[regname_us]; |
|
128 } |
|
129 vsp = entry->initial_rules[ustr__sp()]; |
|
130 break; |
|
131 } |
|
132 case ARM_EXIDX_CMD_VFP_POP: |
|
133 /* Don't recover VFP registers, but be sure to adjust the stack |
|
134 pointer. */ |
|
135 for (unsigned int i = ARM_EXBUF_START(edata->data); |
|
136 i <= ARM_EXBUF_END(edata->data); i++) { |
|
137 vsp = vsp.add_delta(8); |
|
138 } |
|
139 if (!(edata->data & ARM_EXIDX_VFP_FSTMD)) { |
|
140 vsp = vsp.add_delta(4); |
|
141 } |
|
142 break; |
|
143 case ARM_EXIDX_CMD_WREG_POP: |
|
144 for (unsigned int i = ARM_EXBUF_START(edata->data); |
|
145 i <= ARM_EXBUF_END(edata->data); i++) { |
|
146 vsp = vsp.add_delta(8); |
|
147 } |
|
148 break; |
|
149 case ARM_EXIDX_CMD_WCGR_POP: |
|
150 // Pop wCGR registers under mask {wCGR3,2,1,0}, hence "i < 4" |
|
151 for (unsigned int i = 0; i < 4; i++) { |
|
152 if (edata->data & (1 << i)) { |
|
153 vsp = vsp.add_delta(4); |
|
154 } |
|
155 } |
|
156 break; |
|
157 case ARM_EXIDX_CMD_REFUSED: |
|
158 case ARM_EXIDX_CMD_RESERVED: |
|
159 ret = -1; |
|
160 break; |
|
161 } |
|
162 return ret; |
|
163 } |
|
164 |
|
165 void ARMExToModule::AddStackFrame(uintptr_t addr, size_t size) { |
|
166 stack_frame_entry_ = new Module::StackFrameEntry; |
|
167 stack_frame_entry_->address = addr; |
|
168 stack_frame_entry_->size = size; |
|
169 Module::Expr sp_expr = Module::Expr(ustr__sp(), 0, false); // "sp" |
|
170 stack_frame_entry_->initial_rules[ustr__ZDcfa()] = sp_expr; // ".cfa" |
|
171 vsp_ = sp_expr; |
|
172 } |
|
173 |
|
174 int ARMExToModule::ImproveStackFrame(const struct extab_data* edata) { |
|
175 return TranslateCmd(edata, stack_frame_entry_, vsp_) ; |
|
176 } |
|
177 |
|
178 void ARMExToModule::DeleteStackFrame() { |
|
179 delete stack_frame_entry_; |
|
180 } |
|
181 |
|
182 void ARMExToModule::SubmitStackFrame() { |
|
183 // return address always winds up in pc |
|
184 stack_frame_entry_->initial_rules[ustr__ZDra()] // ".ra" |
|
185 = stack_frame_entry_->initial_rules[ustr__pc()]; |
|
186 // the final value of vsp is the new value of sp |
|
187 stack_frame_entry_->initial_rules[ustr__sp()] = vsp_; |
|
188 module_->AddStackFrameEntry(stack_frame_entry_); |
|
189 } |
|
190 |
|
191 } // namespace arm_ex_to_module |