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